diff --git a/src/capture_filter/matrix2.c b/src/capture_filter/matrix2.c index c9339b00f..53ee18cc5 100644 --- a/src/capture_filter/matrix2.c +++ b/src/capture_filter/matrix2.c @@ -34,14 +34,22 @@ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + * @file + * @todo + * * support for RGB formats + */ #include // for errno +#include // for bool, false, true +#include // for uint16_t #include // for NULL, free, calloc #include // for strcmp, memcpy #include "capture_filter.h" // for CAPTURE_FILTER_AB... #include "debug.h" // for LOG_LEVEL_ERROR, MSG #include "lib_common.h" // for REGISTER_MODULE +#include "pixfmt_conv.h" // for get_decoder_from_to #include "types.h" // for tile, video_frame #include "utils/color_out.h" // for color_printf, TBOLD #include "utils/macros.h" // for STR_LEN, snprintf_ch @@ -67,6 +75,8 @@ struct state_capture_filter_matrix2 { double transform_matrix[MATRIX_VOL]; void *vo_pp_out_buffer; ///< buffer to write to if we use vo_pp wrapper ///< (otherwise unused) + void *y416_tmp_buffer; + size_t y416_tmp_buffer_sz; }; static void @@ -83,7 +93,9 @@ usage(void) "matrix [a b c; d e f; g h i], decimals.\n" "Coefficients are applied to unpacked pixels (eg. on Y Cb " "and Cr channels of UYVY).\n"); - color_printf("\nCurrently only " TBOLD("UYVY") " is supported.\n"); + color_printf("\n" TBOLD("Note: ") "Currently only " TBOLD( + "YCbCr") " codecs are supported. " + "Let us know if interested in " TBOLD("RGB") " ones.\n"); color_printf( "\nSee also " TBOLD("matrix") " capture filter/postprocessor.\n"); color_printf("\n"); @@ -146,26 +158,15 @@ init(struct module *parent, const char *cfg, void **state) static void done(void *state) { + struct state_capture_filter_matrix2 *s = state; + free(s->y416_tmp_buffer); free(state); } -static struct video_frame * -filter(void *state, struct video_frame *in) +static void +apply_to_uyvy(struct state_capture_filter_matrix2 *s, struct video_frame *in, + struct video_frame *out) { - struct state_capture_filter_matrix2 *s = state; - struct video_desc desc = video_desc_from_frame(in); - struct video_frame *out = vf_alloc_desc(desc); - if (s->vo_pp_out_buffer) { - out->tiles[0].data = s->vo_pp_out_buffer; - } else { - out->tiles[0].data = malloc(out->tiles[0].data_len); - out->callbacks.data_deleter = vf_data_deleter; - } - out->callbacks.dispose = vf_free; - - if (in->color_spec != UYVY) { - MSG(ERROR, "Sorry, only UYVY supported by now.\n"); - } unsigned char *in_data = (unsigned char *) in->tiles[0].data; unsigned char *out_data = (unsigned char *) out->tiles[0].data; @@ -192,9 +193,83 @@ filter(void *state, struct video_frame *in) s->transform_matrix[1] * u + s->transform_matrix[2] * v; } +} - VIDEO_FRAME_DISPOSE(in); +static bool +convert_apply_y416(struct state_capture_filter_matrix2 *s, + struct video_frame *in, struct video_frame *out) +{ + decoder_t from = get_decoder_from_to(in->color_spec, Y416); + decoder_t to = get_decoder_from_to(Y416, in->color_spec); + if (from == NULL || to == NULL) { + return false; + } + + const size_t tmp_len = + vc_get_datalen(in->tiles[0].width, in->tiles[0].height, Y416); + if (s->y416_tmp_buffer_sz <= tmp_len) { + free(s->y416_tmp_buffer); + s->y416_tmp_buffer = malloc(tmp_len); + s->y416_tmp_buffer_sz = tmp_len; + } + from((unsigned char *) s->y416_tmp_buffer, + (unsigned char *) in->tiles[0].data, (int) tmp_len, 0, 0, 0); + uint16_t *data = s->y416_tmp_buffer; + for (unsigned int i = 0; i < tmp_len; i += 8) { + double u = data[0] - (1 << 15); + double y = data[1] - (1 << 12); + double v = data[2] - (1 << 15); + // U + *data++ = (1 << 15) + s->transform_matrix[3] * y + + s->transform_matrix[4] * u + + s->transform_matrix[5] * v; + // Y + *data++ = (1 << 12) + s->transform_matrix[0] * y + + s->transform_matrix[1] * u + + s->transform_matrix[2] * v; + // V + *data++ = (1 << 15) + s->transform_matrix[6] * y + + s->transform_matrix[7] * u + + s->transform_matrix[8] * v; + // A + *data++ = 0xFFFF; + } + + to((unsigned char *) out->tiles[0].data, + (unsigned char *) s->y416_tmp_buffer, (int) tmp_len, DEFAULT_R_SHIFT, + DEFAULT_G_SHIFT, DEFAULT_B_SHIFT); + return true; +} + +static struct video_frame * +filter(void *state, struct video_frame *in) +{ + struct state_capture_filter_matrix2 *s = state; + struct video_desc desc = video_desc_from_frame(in); + struct video_frame *out = vf_alloc_desc(desc); + if (s->vo_pp_out_buffer) { + out->tiles[0].data = s->vo_pp_out_buffer; + } else { + out->tiles[0].data = malloc(out->tiles[0].data_len); + out->callbacks.data_deleter = vf_data_deleter; + } + out->callbacks.dispose = vf_free; + + if (in->color_spec == UYVY) { + apply_to_uyvy(s, in, out); + } else { + if (codec_is_a_rgb(in->color_spec) || + !convert_apply_y416(s, in, out)) { + MSG(ERROR, + "Sorry, only UYVY and YCbCr modes convertible to " + "and from Y416 are supported by now (have %s).\n", + get_codec_name(in->color_spec)); + VIDEO_FRAME_DISPOSE(in); + return out; + } + } + VIDEO_FRAME_DISPOSE(in); return out; } diff --git a/src/libavcodec/from_lavc_vid_conv.c b/src/libavcodec/from_lavc_vid_conv.c index 1bbbef6b2..eba5df34e 100644 --- a/src/libavcodec/from_lavc_vid_conv.c +++ b/src/libavcodec/from_lavc_vid_conv.c @@ -3024,10 +3024,12 @@ get_cs_for_conv(AVFrame *f, codec_t interm_pf, codec_t out_pf) "UltraGrid!\n", av_color_space_name(f->colorspace)); } - if (src_601 && get_default_cs() != CS_601_LIM) { + const bool have_pp = tok_in_argv(uv_argv, "y601_to_y709"); + if (src_601 && get_default_cs() != CS_601_LIM && !have_pp) { MSG(WARNING, "Got %s CS but not converted - consider \"--param " - "color-601\" as a hint for supported displays\n", + "color-601\" as a hint for supported displays or " + "\"-p matrix2:y601_to_y709\"\n", av_color_space_name(f->colorspace)); } return CS_DFL; // doesn't matter - won't be used anyways