From 9e4b317e8f47cafdbbbf8fdb4fe800e764065956 Mon Sep 17 00:00:00 2001 From: Martin Pulec Date: Fri, 14 Aug 2020 15:11:21 +0200 Subject: [PATCH] File cap.: use UG conversion + codec opt Use UltraGrid covnversion if available instead of swscale. Added codec option --- src/libavcodec_common.c | 13 +++++++++++++ src/libavcodec_common.h | 1 + src/video_capture/file.c | 41 ++++++++++++++++++++++++++++++++-------- 3 files changed, 47 insertions(+), 8 deletions(-) diff --git a/src/libavcodec_common.c b/src/libavcodec_common.c index 4d9380341..122f1579f 100644 --- a/src/libavcodec_common.c +++ b/src/libavcodec_common.c @@ -2138,6 +2138,19 @@ const struct av_to_uv_conversion *get_av_to_uv_conversions() { return av_to_uv_conversions; } +av_to_uv_convert_p get_av_to_uv_conversion(int av_codec, codec_t uv_codec) { + for (const struct av_to_uv_conversion *conversions = get_av_to_uv_conversions(); + conversions->convert != 0; conversions++) { + if (conversions->av_codec == av_codec && + conversions->uv_codec == uv_codec) { + return conversions->convert; + } + } + + return NULL; +} + + #ifdef HAVE_SWSCALE /** * Simplified version of this: https://cpp.hotexamples.com/examples/-/-/av_opt_set_int/cpp-av_opt_set_int-function-examples.html diff --git a/src/libavcodec_common.h b/src/libavcodec_common.h index 3fdc810d4..6211ce479 100644 --- a/src/libavcodec_common.h +++ b/src/libavcodec_common.h @@ -207,6 +207,7 @@ struct av_to_uv_conversion { ///< not have codec for eg. 4:4:4 UYVY). }; +av_to_uv_convert_p get_av_to_uv_conversion(int av_codec, codec_t uv_codec); const struct av_to_uv_conversion *get_av_to_uv_conversions(void); codec_t get_av_to_ug_codec(enum AVCodecID av_codec); diff --git a/src/video_capture/file.c b/src/video_capture/file.c index 3c51cb2c7..dfcbb980a 100644 --- a/src/video_capture/file.c +++ b/src/video_capture/file.c @@ -88,11 +88,15 @@ struct vidcap_state_lavf_decoder { char *src_filename; AVFormatContext *fmt_ctx; AVCodecContext *aud_ctx, *vid_ctx; + struct SwsContext *sws_ctx; + av_to_uv_convert_p conv_uv; + bool failed; bool loop; bool new_msg; bool no_decode; + codec_t convert_to; bool paused; bool use_audio; @@ -118,12 +122,14 @@ struct vidcap_state_lavf_decoder { static void vidcap_file_show_help() { color_out(0, "Usage:\n"); color_out(COLOR_OUT_BOLD | COLOR_OUT_RED, "\t-t file:"); - color_out(COLOR_OUT_BOLD, "[:loop][:nodecode]\n"); + color_out(COLOR_OUT_BOLD, "[:loop][:nodecode][:codec=]\n"); color_out(0, "\t\twhere\n"); color_out(COLOR_OUT_BOLD, "\tloop\n"); color_out(0, "\t\tloop the playback\n"); color_out(COLOR_OUT_BOLD, "\tnodecode\n"); color_out(0, "\t\tdon't decompress the video (may not work because required data for correct decompess are in container or UG doesn't recognize the codec)\n"); + color_out(COLOR_OUT_BOLD, "\tcodec\n"); + color_out(0, "\t\tcodec to decode to\n"); } static void vidcap_file_common_cleanup(struct vidcap_state_lavf_decoder *s) { @@ -318,8 +324,13 @@ static void *vidcap_file_worker(void *state) { * this is required since rawvideo expects non aligned data */ int video_dst_linesize[4] = { vc_get_linesize(out->tiles[0].width, out->color_spec) }; uint8_t *dst[4] = { (uint8_t *) out->tiles[0].data }; - sws_scale(s->sws_ctx, (const uint8_t * const *) frame->data, frame->linesize, 0, - frame->height, dst, video_dst_linesize); + if (s->conv_uv) { + int rgb_shift[] = {0, 8, 16}; + s->conv_uv(out->tiles[0].data, frame, out->tiles[0].width, out->tiles[0].height, video_dst_linesize[0], rgb_shift); + } else { + sws_scale(s->sws_ctx, (const uint8_t * const *) frame->data, frame->linesize, 0, + frame->height, dst, video_dst_linesize); + } av_frame_free(&frame); out->callbacks.dispose = vf_free; } @@ -359,6 +370,12 @@ static bool vidcap_file_parse_fmt(struct vidcap_state_lavf_decoder *s, const cha s->no_decode = true; } else if (strcmp(item, "opportunistic_audio") == 0) { *opportunistic_audio = true; + } else if (strncmp(item, "codec=", strlen("codec=")) == 0) { + char *codec_name = item + strlen("codec="); + if ((s->convert_to = get_codec_from_name(codec_name)) == VIDEO_CODEC_NONE) { + log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unknown option: %s\n", codec_name); + return false; + } } else { log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unknown option: %s\n", item); return false; @@ -428,6 +445,7 @@ static int vidcap_file_init(struct vidcap_params *params, void **state) { struct vidcap_state_lavf_decoder *s = calloc(1, sizeof (struct vidcap_state_lavf_decoder)); s->audio_stream_idx = -1; s->video_stream_idx = -1; + s->convert_to = UYVY; CHECK(pthread_mutex_init(&s->audio_frame_lock, NULL)); CHECK(pthread_mutex_init(&s->lock, NULL)); CHECK(pthread_cond_init(&s->frame_consumed, NULL)); @@ -500,7 +518,7 @@ static int vidcap_file_init(struct vidcap_params *params, void **state) { s->video_desc.height = st->codecpar->height; s->video_desc.fps = (double) st->r_frame_rate.num / st->r_frame_rate.den; s->video_desc.tile_count = 1; -fprintf(stderr, "%d %d\n", s->video_desc.width, s->video_desc.height); + log_msg(LOG_LEVEL_VERBOSE, MOD_NAME "Video size: %dx%d\n", s->video_desc.width, s->video_desc.height); if (s->no_decode) { s->video_desc.color_spec = get_av_to_ug_codec(s->fmt_ctx->streams[s->video_stream_idx]->codecpar->codec_id); @@ -511,16 +529,23 @@ fprintf(stderr, "%d %d\n", s->video_desc.width, s->video_desc.height); return VIDCAP_INIT_FAIL; } } else { - s->video_desc.color_spec = UYVY; + s->video_desc.color_spec = s->convert_to; s->vid_ctx = vidcap_file_open_dec_ctx(dec, st); if (!s->vid_ctx) { vidcap_file_common_cleanup(s); return VIDCAP_INIT_FAIL; } - s->sws_ctx = sws_getContext(s->video_desc.width, s->video_desc.height, s->vid_ctx->pix_fmt, - s->video_desc.width, s->video_desc.height, get_ug_to_av_pixfmt(s->video_desc.color_spec), - 0, NULL, NULL, NULL); + if ((s->conv_uv = get_av_to_uv_conversion(s->vid_ctx->pix_fmt, s->video_desc.color_spec)) == NULL) { + s->sws_ctx = sws_getContext(s->video_desc.width, s->video_desc.height, s->vid_ctx->pix_fmt, + s->video_desc.width, s->video_desc.height, get_ug_to_av_pixfmt(s->video_desc.color_spec), + 0, NULL, NULL, NULL); + if (s->sws_ctx == NULL) { + log_msg(LOG_LEVEL_ERROR, MOD_NAME "Cannot find neither UltraGrid nor swscale conversion!\n"); + vidcap_file_common_cleanup(s); + return VIDCAP_INIT_FAIL; + } + } } s->video_desc.interlacing = PROGRESSIVE; /// @todo other modes }