diff options
Diffstat (limited to 'video/decode')
-rw-r--r-- | video/decode/vd_lavc.c | 447 |
1 files changed, 306 insertions, 141 deletions
diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c index 15eab18bf9..05b66edbd8 100644 --- a/video/decode/vd_lavc.c +++ b/video/decode/vd_lavc.c @@ -18,24 +18,23 @@ #include <float.h> #include <stdio.h> #include <stdlib.h> -#include <pthread.h> #include <assert.h> #include <stdbool.h> #include <libavcodec/avcodec.h> +#include <libavformat/version.h> #include <libavutil/common.h> #include <libavutil/hwcontext.h> #include <libavutil/opt.h> #include <libavutil/intreadwrite.h> #include <libavutil/pixdesc.h> -#include "config.h" - #include "mpv_talloc.h" #include "common/global.h" #include "common/msg.h" #include "options/m_config.h" #include "options/options.h" +#include "osdep/threads.h" #include "misc/bstr.h" #include "common/av_common.h" #include "common/codecs.h" @@ -63,28 +62,30 @@ static void uninit_avctx(struct mp_filter *vd); static int get_buffer2_direct(AVCodecContext *avctx, AVFrame *pic, int flags); static enum AVPixelFormat get_format_hwdec(struct AVCodecContext *avctx, const enum AVPixelFormat *pix_fmt); -static int hwdec_validate_opt(struct mp_log *log, const m_option_t *opt, - struct bstr name, struct bstr param); +static int hwdec_opt_help(struct mp_log *log, const m_option_t *opt, + struct bstr name); #define HWDEC_DELAY_QUEUE_COUNT 2 #define OPT_BASE_STRUCT struct vd_lavc_params struct vd_lavc_params { - int fast; - int show_all; + bool fast; + int film_grain; + bool show_all; int skip_loop_filter; int skip_idct; int skip_frame; int framedrop; int threads; - int bitexact; - int old_x264; - int check_hw_profile; + bool bitexact; + bool old_x264; + bool apply_cropping; + bool check_hw_profile; int software_fallback; char **avopts; int dr; - char *hwdec_api; + char **hwdec_api; char *hwdec_codecs; int hwdec_image_format; int hwdec_extra_frames; @@ -103,21 +104,26 @@ static const struct m_opt_choice_alternatives discard_names[] = { const struct m_sub_options vd_lavc_conf = { .opts = (const m_option_t[]){ - {"vd-lavc-fast", OPT_FLAG(fast)}, - {"vd-lavc-show-all", OPT_FLAG(show_all)}, + {"vd-lavc-fast", OPT_BOOL(fast)}, + {"vd-lavc-film-grain", OPT_CHOICE(film_grain, + {"auto", -1}, {"cpu", 0}, {"gpu", 1})}, + {"vd-lavc-show-all", OPT_BOOL(show_all)}, {"vd-lavc-skiploopfilter", OPT_DISCARD(skip_loop_filter)}, {"vd-lavc-skipidct", OPT_DISCARD(skip_idct)}, {"vd-lavc-skipframe", OPT_DISCARD(skip_frame)}, {"vd-lavc-framedrop", OPT_DISCARD(framedrop)}, {"vd-lavc-threads", OPT_INT(threads), M_RANGE(0, DBL_MAX)}, - {"vd-lavc-bitexact", OPT_FLAG(bitexact)}, - {"vd-lavc-assume-old-x264", OPT_FLAG(old_x264)}, - {"vd-lavc-check-hw-profile", OPT_FLAG(check_hw_profile)}, + {"vd-lavc-bitexact", OPT_BOOL(bitexact)}, + {"vd-lavc-assume-old-x264", OPT_BOOL(old_x264)}, + {"vd-lavc-check-hw-profile", OPT_BOOL(check_hw_profile)}, {"vd-lavc-software-fallback", OPT_CHOICE(software_fallback, {"no", INT_MAX}, {"yes", 1}), M_RANGE(1, INT_MAX)}, {"vd-lavc-o", OPT_KEYVALUELIST(avopts)}, - {"vd-lavc-dr", OPT_FLAG(dr)}, - {"hwdec", OPT_STRING_VALIDATE(hwdec_api, hwdec_validate_opt), + {"vd-lavc-dr", OPT_CHOICE(dr, + {"auto", -1}, {"no", 0}, {"yes", 1})}, + {"vd-apply-cropping", OPT_BOOL(apply_cropping)}, + {"hwdec", OPT_STRINGLIST(hwdec_api), + .help = hwdec_opt_help, .flags = M_OPT_OPTIONAL_PARAM | UPDATE_HWDEC}, {"hwdec-codecs", OPT_STRING(hwdec_codecs)}, {"hwdec-image-format", OPT_IMAGEFORMAT(hwdec_image_format)}, @@ -126,21 +132,22 @@ const struct m_sub_options vd_lavc_conf = { }, .size = sizeof(struct vd_lavc_params), .defaults = &(const struct vd_lavc_params){ - .show_all = 0, - .check_hw_profile = 1, + .film_grain = -1 /*auto*/, + .check_hw_profile = true, .software_fallback = 3, .skip_loop_filter = AVDISCARD_DEFAULT, .skip_idct = AVDISCARD_DEFAULT, .skip_frame = AVDISCARD_DEFAULT, .framedrop = AVDISCARD_NONREF, - .dr = 1, - .hwdec_api = "no", - .hwdec_codecs = "h264,vc1,hevc,vp8,vp9,av1", + .dr = -1, + .hwdec_api = (char *[]){"no", NULL,}, + .hwdec_codecs = "h264,vc1,hevc,vp8,vp9,av1,prores", // Maximum number of surfaces the player wants to buffer. This number // might require adjustment depending on whatever the player does; // for example, if vo_gpu increases the number of reference surfaces for // interpolation, this value has to be increased too. .hwdec_extra_frames = 6, + .apply_cropping = true, }, }; @@ -167,8 +174,11 @@ typedef struct lavc_ctx { struct mp_codec_params *codec; AVCodecContext *avctx; AVFrame *pic; + AVPacket *avpkt; bool use_hwdec; struct hwdec_info hwdec; // valid only if use_hwdec==true + bstr *attempted_hwdecs; + int num_attempted_hwdecs; AVRational codec_timebase; enum AVDiscard skip_frame; bool flushing; @@ -176,6 +186,7 @@ typedef struct lavc_ctx { const char *decoder; bool hwdec_failed; bool hwdec_notified; + bool force_eof; bool intra_only; int framedrop_flags; @@ -206,7 +217,7 @@ typedef struct lavc_ctx { AVBufferRef *cached_hw_frames_ctx; // --- The following fields are protected by dr_lock. - pthread_mutex_t dr_lock; + mp_mutex dr_lock; bool dr_failed; struct mp_image_pool *dr_pool; int dr_imgfmt, dr_w, dr_h, dr_stride_align; @@ -228,16 +239,20 @@ struct autoprobe_info { const struct autoprobe_info hwdec_autoprobe_info[] = { {"d3d11va", HWDEC_FLAG_AUTO | HWDEC_FLAG_WHITELIST}, {"dxva2", HWDEC_FLAG_AUTO}, - {"dxva2-copy", HWDEC_FLAG_AUTO | HWDEC_FLAG_WHITELIST}, {"d3d11va-copy", HWDEC_FLAG_AUTO | HWDEC_FLAG_WHITELIST}, + {"dxva2-copy", HWDEC_FLAG_AUTO | HWDEC_FLAG_WHITELIST}, {"nvdec", HWDEC_FLAG_AUTO | HWDEC_FLAG_WHITELIST}, {"nvdec-copy", HWDEC_FLAG_AUTO | HWDEC_FLAG_WHITELIST}, {"vaapi", HWDEC_FLAG_AUTO | HWDEC_FLAG_WHITELIST}, {"vaapi-copy", HWDEC_FLAG_AUTO | HWDEC_FLAG_WHITELIST}, {"vdpau", HWDEC_FLAG_AUTO}, {"vdpau-copy", HWDEC_FLAG_AUTO | HWDEC_FLAG_WHITELIST}, + {"drm", HWDEC_FLAG_AUTO | HWDEC_FLAG_WHITELIST}, + {"drm-copy", HWDEC_FLAG_AUTO | HWDEC_FLAG_WHITELIST}, {"mmal", HWDEC_FLAG_AUTO}, {"mmal-copy", HWDEC_FLAG_AUTO | HWDEC_FLAG_WHITELIST}, + {"mediacodec", HWDEC_FLAG_AUTO}, + {"mediacodec-copy", HWDEC_FLAG_AUTO | HWDEC_FLAG_WHITELIST}, {"videotoolbox", HWDEC_FLAG_AUTO | HWDEC_FLAG_WHITELIST}, {"videotoolbox-copy", HWDEC_FLAG_AUTO | HWDEC_FLAG_WHITELIST}, {0} @@ -257,9 +272,12 @@ static int hwdec_compare(const void *p1, const void *p2) // List non-copying entries first, so --hwdec=auto takes them. if (h1->copying != h2->copying) return h1->copying ? 1 : -1; - // Order by autoprobe preferrence order. + // Order by autoprobe preference order. if (h1->auto_pos != h2->auto_pos) return h1->auto_pos > h2->auto_pos ? 1 : -1; + // Put hwdecs without hw_device_ctx last + if ((!!h1->lavc_device) != (!!h2->lavc_device)) + return h1->lavc_device ? -1 : 1; // Fallback sort order to make sorting stable. return h1->rank > h2->rank ? 1 :-1; } @@ -430,8 +448,18 @@ static AVBufferRef *hwdec_create_dev(struct mp_filter *vd, return ref; } } else if (ctx->hwdec_devs) { - hwdec_devices_request_all(ctx->hwdec_devs); - return hwdec_devices_get_lavc(ctx->hwdec_devs, hwdec->lavc_device); + int imgfmt = pixfmt2imgfmt(hwdec->pix_fmt); + struct hwdec_imgfmt_request params = { + .imgfmt = imgfmt, + .probing = autoprobe, + }; + hwdec_devices_request_for_img_fmt(ctx->hwdec_devs, ¶ms); + + const struct mp_hwdec_ctx *hw_ctx = + hwdec_devices_get_by_imgfmt(ctx->hwdec_devs, imgfmt); + + if (hw_ctx && hw_ctx->av_device_ref) + return av_buffer_ref(hw_ctx->av_device_ref); } return NULL; @@ -445,83 +473,119 @@ static void select_and_set_hwdec(struct mp_filter *vd) m_config_cache_update(ctx->opts_cache); - bstr opt = bstr0(ctx->opts->hwdec_api); - - bool hwdec_requested = !bstr_equals0(opt, "no"); - bool hwdec_auto_all = bstr_equals0(opt, "auto") || - bstr_equals0(opt, "yes") || - bstr_equals0(opt, ""); - bool hwdec_auto_safe = bstr_equals0(opt, "auto-safe") || - bstr_equals0(opt, "auto-copy-safe"); - bool hwdec_auto_copy = bstr_equals0(opt, "auto-copy") || - bstr_equals0(opt, "auto-copy-safe"); - bool hwdec_auto = hwdec_auto_all || hwdec_auto_copy || hwdec_auto_safe; - - if (!hwdec_requested) { - MP_VERBOSE(vd, "No hardware decoding requested.\n"); - } else if (!hwdec_codec_allowed(vd, codec)) { - MP_VERBOSE(vd, "Not trying to use hardware decoding: codec %s is not " - "on whitelist.\n", codec); - } else { - struct hwdec_info *hwdecs = NULL; - int num_hwdecs = 0; - add_all_hwdec_methods(&hwdecs, &num_hwdecs); - - for (int n = 0; n < num_hwdecs; n++) { - struct hwdec_info *hwdec = &hwdecs[n]; + struct hwdec_info *hwdecs = NULL; + int num_hwdecs = 0; + add_all_hwdec_methods(&hwdecs, &num_hwdecs); + + char **hwdec_api = ctx->opts->hwdec_api; + for (int i = 0; hwdec_api[i]; i++) { + bstr opt = bstr0(hwdec_api[i]); + + bool hwdec_requested = !bstr_equals0(opt, "no"); + bool hwdec_auto_all = bstr_equals0(opt, "auto") || + bstr_equals0(opt, ""); + bool hwdec_auto_safe = bstr_equals0(opt, "auto-safe") || + bstr_equals0(opt, "auto-copy-safe") || + bstr_equals0(opt, "yes"); + bool hwdec_auto_copy = bstr_equals0(opt, "auto-copy") || + bstr_equals0(opt, "auto-copy-safe"); + bool hwdec_auto = hwdec_auto_all || hwdec_auto_copy || hwdec_auto_safe; + + if (!hwdec_requested) { + MP_VERBOSE(vd, "No hardware decoding requested.\n"); + break; + } else if (!hwdec_codec_allowed(vd, codec)) { + MP_VERBOSE(vd, "Not trying to use hardware decoding: codec %s is not " + "on whitelist.\n", codec); + break; + } else { + bool hwdec_name_supported = false; // relevant only if !hwdec_auto + for (int n = 0; n < num_hwdecs; n++) { + struct hwdec_info *hwdec = &hwdecs[n]; - const char *hw_codec = mp_codec_from_av_codec_id(hwdec->codec->id); - if (!hw_codec || strcmp(hw_codec, codec) != 0) - continue; + if (!hwdec_auto && !(bstr_equals0(opt, hwdec->method_name) || + bstr_equals0(opt, hwdec->name))) + continue; + hwdec_name_supported = true; + + bool already_attempted = false; + for (int j = 0; j < ctx->num_attempted_hwdecs; j++) { + if (bstr_equals0(ctx->attempted_hwdecs[j], hwdec->name)) { + MP_DBG(vd, "Skipping previously attempted hwdec: %s\n", + hwdec->name); + already_attempted = true; + break; + } + } + if (already_attempted) + continue; - if (!hwdec_auto && !(bstr_equals0(opt, hwdec->method_name) || - bstr_equals0(opt, hwdec->name))) - continue; + const char *hw_codec = mp_codec_from_av_codec_id(hwdec->codec->id); + if (!hw_codec || strcmp(hw_codec, codec) != 0) + continue; - if (hwdec_auto_safe && !(hwdec->flags & HWDEC_FLAG_WHITELIST)) - continue; + if (hwdec_auto_safe && !(hwdec->flags & HWDEC_FLAG_WHITELIST)) + continue; - MP_VERBOSE(vd, "Looking at hwdec %s...\n", hwdec->name); + MP_VERBOSE(vd, "Looking at hwdec %s...\n", hwdec->name); - if (hwdec_auto_copy && !hwdec->copying) { - MP_VERBOSE(vd, "Not using this for auto-copy.\n"); - continue; - } + /* + * Past this point, any kind of failure that results in us + * looking for a new hwdec should not lead to use trying this + * hwdec again - so add it to the list, regardless of whether + * initialisation will succeed or not. + */ + MP_TARRAY_APPEND(ctx, ctx->attempted_hwdecs, + ctx->num_attempted_hwdecs, + bstrdup(ctx, bstr0(hwdec->name))); - if (hwdec->lavc_device) { - ctx->hwdec_dev = hwdec_create_dev(vd, hwdec, hwdec_auto); - if (!ctx->hwdec_dev) { - MP_VERBOSE(vd, "Could not create device.\n"); + if (hwdec_auto_copy && !hwdec->copying) { + MP_VERBOSE(vd, "Not using this for auto-copy.\n"); continue; } - const struct hwcontext_fns *fns = - hwdec_get_hwcontext_fns(hwdec->lavc_device); - if (fns && fns->is_emulated && fns->is_emulated(ctx->hwdec_dev)) { - if (hwdec_auto) { - MP_VERBOSE(vd, "Not using emulated API.\n"); - av_buffer_unref(&ctx->hwdec_dev); + if (hwdec->lavc_device) { + ctx->hwdec_dev = hwdec_create_dev(vd, hwdec, hwdec_auto); + if (!ctx->hwdec_dev) { + MP_VERBOSE(vd, "Could not create device.\n"); continue; } - MP_WARN(vd, "Using emulated hardware decoding API.\n"); + + const struct hwcontext_fns *fns = + hwdec_get_hwcontext_fns(hwdec->lavc_device); + if (fns && fns->is_emulated && fns->is_emulated(ctx->hwdec_dev)) { + if (hwdec_auto) { + MP_VERBOSE(vd, "Not using emulated API.\n"); + av_buffer_unref(&ctx->hwdec_dev); + continue; + } + MP_WARN(vd, "Using emulated hardware decoding API.\n"); + } + } else if (!hwdec->copying) { + // Most likely METHOD_INTERNAL, which often use delay-loaded + // VO support as well. + if (ctx->hwdec_devs) { + struct hwdec_imgfmt_request params = { + .imgfmt = pixfmt2imgfmt(hwdec->pix_fmt), + .probing = hwdec_auto, + }; + hwdec_devices_request_for_img_fmt( + ctx->hwdec_devs, ¶ms); + } } - } else if (!hwdec->copying) { - // Most likely METHOD_INTERNAL, which often use delay-loaded - // VO support as well. - if (ctx->hwdec_devs) - hwdec_devices_request_all(ctx->hwdec_devs); - } - ctx->use_hwdec = true; - ctx->hwdec = *hwdec; - break; + ctx->use_hwdec = true; + ctx->hwdec = *hwdec; + break; + } + if (ctx->use_hwdec) + break; + else if (!hwdec_auto && !hwdec_name_supported) + MP_WARN(vd, "Unsupported hwdec: %.*s\n", BSTR_P(opt)); } - - talloc_free(hwdecs); - - if (!ctx->use_hwdec) - MP_VERBOSE(vd, "No hardware decoding available for this codec.\n"); } + talloc_free(hwdecs); + if (ctx->use_hwdec) { MP_VERBOSE(vd, "Trying hardware decoding via %s.\n", ctx->hwdec.name); @@ -529,37 +593,41 @@ static void select_and_set_hwdec(struct mp_filter *vd) MP_VERBOSE(vd, "Using underlying hw-decoder '%s'\n", ctx->hwdec.codec->name); } else { - MP_VERBOSE(vd, "Using software decoding.\n"); + // If software fallback is disabled and we get here, all hwdec must + // have failed. Tell the ctx to always force an eof. + if (ctx->opts->software_fallback == INT_MAX) { + MP_WARN(ctx, "Software decoding fallback is disabled.\n"); + ctx->force_eof = true; + } else { + MP_VERBOSE(vd, "Using software decoding.\n"); + } } } -static int hwdec_validate_opt(struct mp_log *log, const m_option_t *opt, - struct bstr name, struct bstr param) +static int hwdec_opt_help(struct mp_log *log, const m_option_t *opt, + struct bstr name) { - if (bstr_equals0(param, "help")) { - struct hwdec_info *hwdecs = NULL; - int num_hwdecs = 0; - add_all_hwdec_methods(&hwdecs, &num_hwdecs); + struct hwdec_info *hwdecs = NULL; + int num_hwdecs = 0; + add_all_hwdec_methods(&hwdecs, &num_hwdecs); - mp_info(log, "Valid values (with alternative full names):\n"); + mp_info(log, "Valid values (with alternative full names):\n"); - for (int n = 0; n < num_hwdecs; n++) { - struct hwdec_info *hwdec = &hwdecs[n]; + for (int n = 0; n < num_hwdecs; n++) { + struct hwdec_info *hwdec = &hwdecs[n]; - mp_info(log, " %s (%s)\n", hwdec->method_name, hwdec->name); - } + mp_info(log, " %s (%s)\n", hwdec->method_name, hwdec->name); + } - talloc_free(hwdecs); + talloc_free(hwdecs); - mp_info(log, " auto (yes '')\n"); - mp_info(log, " no\n"); - mp_info(log, " auto-safe\n"); - mp_info(log, " auto-copy\n"); - mp_info(log, " auto-copy-safe\n"); + mp_info(log, " auto (yes '')\n"); + mp_info(log, " no\n"); + mp_info(log, " auto-safe\n"); + mp_info(log, " auto-copy\n"); + mp_info(log, " auto-copy-safe\n"); - return M_OPT_EXIT; - } - return 0; + return M_OPT_EXIT; } static void force_fallback(struct mp_filter *vd) @@ -568,7 +636,9 @@ static void force_fallback(struct mp_filter *vd) uninit_avctx(vd); int lev = ctx->hwdec_notified ? MSGL_WARN : MSGL_V; - mp_msg(vd->log, lev, "Falling back to software decoding.\n"); + mp_msg(vd->log, lev, "Attempting next decoding method after failure of %.*s.\n", + BSTR_P(ctx->attempted_hwdecs[ctx->num_attempted_hwdecs - 1])); + select_and_set_hwdec(vd); init_avctx(vd); } @@ -578,12 +648,25 @@ static void reinit(struct mp_filter *vd) uninit_avctx(vd); + /* + * Reset attempted hwdecs so that if the hwdec list is reconfigured + * we attempt all of them from the beginning. The most practical + * reason for this is that ctrl+h toggles between `no` and + * `auto-safe`, and we want to reevaluate from a clean slate each time. + */ + TA_FREEP(&ctx->attempted_hwdecs); + ctx->num_attempted_hwdecs = 0; + ctx->hwdec_notified = false; + select_and_set_hwdec(vd); bool use_hwdec = ctx->use_hwdec; init_avctx(vd); - if (!ctx->avctx && use_hwdec) - force_fallback(vd); + if (!ctx->avctx && use_hwdec) { + do { + force_fallback(vd); + } while (!ctx->avctx); + } } static void init_avctx(struct mp_filter *vd) @@ -629,6 +712,10 @@ static void init_avctx(struct mp_filter *vd) if (!ctx->pic) goto error; + ctx->avpkt = av_packet_alloc(); + if (!ctx->avpkt) + goto error; + if (ctx->use_hwdec) { avctx->opaque = vd; avctx->thread_count = 1; @@ -636,6 +723,17 @@ static void init_avctx(struct mp_filter *vd) if (!lavc_param->check_hw_profile) avctx->hwaccel_flags |= AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH; +#ifdef AV_HWACCEL_FLAG_UNSAFE_OUTPUT + /* + * This flag primarily exists for nvdec which has a very limited + * output frame pool, which can get exhausted if consumers don't + * release frames quickly. However, as an implementation + * requirement, we have to copy the frames anyway, so we don't + * need this extra implicit copy. + */ + avctx->hwaccel_flags |= AV_HWACCEL_FLAG_UNSAFE_OUTPUT; +#endif + if (ctx->hwdec.use_hw_device) { if (ctx->hwdec_dev) avctx->hw_device_ctx = av_buffer_ref(ctx->hwdec_dev); @@ -661,7 +759,11 @@ static void init_avctx(struct mp_filter *vd) if (!ctx->use_hwdec && ctx->vo && lavc_param->dr) { avctx->opaque = vd; avctx->get_buffer2 = get_buffer2_direct; - avctx->thread_safe_callbacks = 1; +#if LIBAVCODEC_VERSION_MAJOR < 60 + AV_NOWARN_DEPRECATED({ + avctx->thread_safe_callbacks = 1; + }); +#endif } avctx->flags |= lavc_param->bitexact ? AV_CODEC_FLAG_BITEXACT : 0; @@ -673,10 +775,41 @@ static void init_avctx(struct mp_filter *vd) avctx->skip_loop_filter = lavc_param->skip_loop_filter; avctx->skip_idct = lavc_param->skip_idct; avctx->skip_frame = lavc_param->skip_frame; + avctx->apply_cropping = lavc_param->apply_cropping; if (lavc_codec->id == AV_CODEC_ID_H264 && lavc_param->old_x264) av_opt_set(avctx, "x264_build", "150", AV_OPT_SEARCH_CHILDREN); +#ifndef AV_CODEC_EXPORT_DATA_FILM_GRAIN + if (ctx->opts->film_grain == 1) + MP_WARN(vd, "GPU film grain requested, but FFmpeg too old to expose " + "film grain parameters. Please update to latest master, " + "or at least to release 4.4.\n"); +#else + switch(ctx->opts->film_grain) { + case 0: /*CPU*/ + // default lavc flags handle film grain within the decoder. + break; + case 1: /*GPU*/ + if (!ctx->vo || + (ctx->vo && !(ctx->vo->driver->caps & VO_CAP_FILM_GRAIN))) { + MP_MSG(vd, ctx->vo ? MSGL_WARN : MSGL_V, + "GPU film grain requested, but VO %s, expect wrong output.\n", + ctx->vo ? + "does not support applying film grain" : + "is not available at decoder initialization to verify support"); + } + + avctx->export_side_data |= AV_CODEC_EXPORT_DATA_FILM_GRAIN; + break; + default: + if (ctx->vo && (ctx->vo->driver->caps & VO_CAP_FILM_GRAIN)) + avctx->export_side_data |= AV_CODEC_EXPORT_DATA_FILM_GRAIN; + + break; + } +#endif + mp_set_avopts(vd->log, avctx, lavc_param->avopts); // Do this after the above avopt handling in case it changes values @@ -696,9 +829,8 @@ static void init_avctx(struct mp_filter *vd) // x264 build number (encoded in a SEI element), needed to enable a // workaround for broken 4:4:4 streams produced by older x264 versions. if (lavc_codec->id == AV_CODEC_ID_H264 && c->first_packet) { - AVPacket avpkt; - mp_set_av_packet(&avpkt, c->first_packet, &ctx->codec_timebase); - avcodec_send_packet(avctx, &avpkt); + mp_set_av_packet(ctx->avpkt, c->first_packet, &ctx->codec_timebase); + avcodec_send_packet(avctx, ctx->avpkt); avcodec_receive_frame(avctx, ctx->pic); av_frame_unref(ctx->pic); avcodec_flush_buffers(ctx->avctx); @@ -746,6 +878,7 @@ static void uninit_avctx(struct mp_filter *vd) flush_all(vd); av_frame_free(&ctx->pic); + mp_free_av_packet(&ctx->avpkt); av_buffer_unref(&ctx->cached_hw_frames_ctx); avcodec_free_context(&ctx->avctx); @@ -876,7 +1009,7 @@ static int get_buffer2_direct(AVCodecContext *avctx, AVFrame *pic, int flags) struct mp_filter *vd = avctx->opaque; vd_ffmpeg_ctx *p = vd->priv; - pthread_mutex_lock(&p->dr_lock); + mp_mutex_lock(&p->dr_lock); int w = pic->width; int h = pic->height; @@ -889,6 +1022,13 @@ static int get_buffer2_direct(AVCodecContext *avctx, AVFrame *pic, int flags) for (int n = 0; n < AV_NUM_DATA_POINTERS; n++) stride_align = MPMAX(stride_align, linesize_align[n]); + // Note: texel sizes may be NPOT, so use full lcm instead of max + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pic->format); + if (!(desc->flags & AV_PIX_FMT_FLAG_BITSTREAM)) { + for (int n = 0; n < desc->nb_components; n++) + stride_align = mp_lcm(stride_align, desc->comp[n].step); + } + int imgfmt = pixfmt2imgfmt(pic->format); if (!imgfmt) goto fallback; @@ -912,8 +1052,10 @@ static int get_buffer2_direct(AVCodecContext *avctx, AVFrame *pic, int flags) struct mp_image *img = mp_image_pool_get_no_alloc(p->dr_pool, imgfmt, w, h); if (!img) { - MP_DBG(p, "Allocating new DR image...\n"); - img = vo_get_image(p->vo, imgfmt, w, h, stride_align); + bool host_cached = p->opts->dr == -1; // auto + int dr_flags = host_cached ? VO_DR_FLAG_HOST_CACHED : 0; + MP_DBG(p, "Allocating new%s DR image...\n", host_cached ? " (host-cached)" : ""); + img = vo_get_image(p->vo, imgfmt, w, h, stride_align, dr_flags); if (!img) { MP_DBG(p, "...failed..\n"); goto fallback; @@ -939,7 +1081,7 @@ static int get_buffer2_direct(AVCodecContext *avctx, AVFrame *pic, int flags) } talloc_free(img); - pthread_mutex_unlock(&p->dr_lock); + mp_mutex_unlock(&p->dr_lock); return 0; @@ -947,7 +1089,7 @@ fallback: if (!p->dr_failed) MP_VERBOSE(p, "DR failed - disabling.\n"); p->dr_failed = true; - pthread_mutex_unlock(&p->dr_lock); + mp_mutex_unlock(&p->dr_lock); return avcodec_default_get_buffer2(avctx, pic, flags); } @@ -1011,10 +1153,9 @@ static int send_packet(struct mp_filter *vd, struct demux_packet *pkt) if (avctx->skip_frame == AVDISCARD_ALL) return 0; - AVPacket avpkt; - mp_set_av_packet(&avpkt, pkt, &ctx->codec_timebase); + mp_set_av_packet(ctx->avpkt, pkt, &ctx->codec_timebase); - int ret = avcodec_send_packet(avctx, pkt ? &avpkt : NULL); + int ret = avcodec_send_packet(avctx, pkt ? ctx->avpkt : NULL); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) return ret; @@ -1035,7 +1176,6 @@ static void send_queued_packet(struct mp_filter *vd) vd_ffmpeg_ctx *ctx = vd->priv; assert(ctx->num_requeue_packets); - assert(!ctx->hw_probing); if (send_packet(vd, ctx->requeue_packets[0]) != AVERROR(EAGAIN)) { talloc_free(ctx->requeue_packets[0]); @@ -1049,7 +1189,7 @@ static int decode_frame(struct mp_filter *vd) vd_ffmpeg_ctx *ctx = vd->priv; AVCodecContext *avctx = ctx->avctx; - if (!avctx) + if (!avctx || ctx->force_eof) return AVERROR_EOF; prepare_decoding(vd); @@ -1075,6 +1215,8 @@ static int decode_frame(struct mp_filter *vd) return ret; } + mp_codec_info_from_av(avctx, ctx->codec); + // If something was decoded successfully, it must return a frame with valid // data. assert(ctx->pic->buf[0]); @@ -1098,7 +1240,11 @@ static int decode_frame(struct mp_filter *vd) mpi->dts = mp_pts_from_av(ctx->pic->pkt_dts, &ctx->codec_timebase); mpi->pkt_duration = +#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(59, 30, 100) + mp_pts_from_av(ctx->pic->duration, &ctx->codec_timebase); +#else mp_pts_from_av(ctx->pic->pkt_duration, &ctx->codec_timebase); +#endif av_frame_unref(ctx->pic); @@ -1113,13 +1259,25 @@ static int receive_frame(struct mp_filter *vd, struct mp_frame *out_frame) int ret = decode_frame(vd); if (ctx->hwdec_failed) { - // Failed hardware decoding? Try again in software. + // Failed hardware decoding? Try the next one, and eventually software. struct demux_packet **pkts = ctx->sent_packets; int num_pkts = ctx->num_sent_packets; ctx->sent_packets = NULL; ctx->num_sent_packets = 0; - force_fallback(vd); + /* + * We repeatedly force_fallback until we get an avctx, because there are + * certain hwdecs that are really full decoders, and so if these fail, + * they also fail to give us a valid avctx, and the early return path + * here will simply give up on decoding completely if there is no + * decoder. We should never hit an infinite loop as the hwdec list is + * finite and we will eventually exhaust it and fall back to software + * decoding (and in practice, most hwdecs are hwaccels and so the + * decoder will successfully init even if the hwaccel fails later.) + */ + do { + force_fallback(vd); + } while (!ctx->avctx); ctx->requeue_packets = pkts; ctx->num_requeue_packets = num_pkts; @@ -1130,11 +1288,11 @@ static int receive_frame(struct mp_filter *vd, struct mp_frame *out_frame) if (ret == AVERROR(EAGAIN) && ctx->num_requeue_packets) return 0; // force retry, so send_queued_packet() gets called - if (!ctx->num_delay_queue) + if (ctx->num_delay_queue <= ctx->max_delay_queue && ret != AVERROR_EOF) return ret; - if (ctx->num_delay_queue <= ctx->max_delay_queue && ret != AVERROR_EOF) - return AVERROR(EAGAIN); + if (!ctx->num_delay_queue) + return ret; struct mp_image *res = ctx->delay_queue[0]; MP_TARRAY_REMOVE_AT(ctx->delay_queue, ctx->num_delay_queue, 0); @@ -1183,6 +1341,10 @@ static int control(struct mp_filter *vd, enum dec_ctrl cmd, void *arg) case VDCTRL_SET_FRAMEDROP: ctx->framedrop_flags = *(int *)arg; return CONTROL_TRUE; + case VDCTRL_CHECK_FORCED_EOF: { + *(bool *)arg = ctx->force_eof; + return CONTROL_TRUE; + } case VDCTRL_GET_BFRAMES: { AVCodecContext *avctx = ctx->avctx; if (!avctx) @@ -1209,14 +1371,14 @@ static int control(struct mp_filter *vd, enum dec_ctrl cmd, void *arg) return CONTROL_UNKNOWN; } -static void process(struct mp_filter *vd) +static void vd_lavc_process(struct mp_filter *vd) { vd_ffmpeg_ctx *ctx = vd->priv; lavc_process(vd, &ctx->state, send_packet, receive_frame); } -static void reset(struct mp_filter *vd) +static void vd_lavc_reset(struct mp_filter *vd) { vd_ffmpeg_ctx *ctx = vd->priv; @@ -1226,21 +1388,21 @@ static void reset(struct mp_filter *vd) ctx->framedrop_flags = 0; } -static void destroy(struct mp_filter *vd) +static void vd_lavc_destroy(struct mp_filter *vd) { vd_ffmpeg_ctx *ctx = vd->priv; uninit_avctx(vd); - pthread_mutex_destroy(&ctx->dr_lock); + mp_mutex_destroy(&ctx->dr_lock); } static const struct mp_filter_info vd_lavc_filter = { .name = "vd_lavc", .priv_size = sizeof(vd_ffmpeg_ctx), - .process = process, - .reset = reset, - .destroy = destroy, + .process = vd_lavc_process, + .reset = vd_lavc_reset, + .destroy = vd_lavc_destroy, }; static struct mp_decoder *create(struct mp_filter *parent, @@ -1268,7 +1430,7 @@ static struct mp_decoder *create(struct mp_filter *parent, ctx->public.f = vd; ctx->public.control = control; - pthread_mutex_init(&ctx->dr_lock, NULL); + mp_mutex_init(&ctx->dr_lock); // hwdec/DR struct mp_stream_info *info = mp_filter_find_stream_info(vd); @@ -1283,6 +1445,9 @@ static struct mp_decoder *create(struct mp_filter *parent, talloc_free(vd); return NULL; } + + codec->codec_desc = ctx->avctx->codec_descriptor->long_name; + return &ctx->public; } |