diff options
Diffstat (limited to 'video/decode/vd_lavc.c')
-rw-r--r-- | video/decode/vd_lavc.c | 218 |
1 files changed, 125 insertions, 93 deletions
diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c index 4660d813b5..1aaca6b335 100644 --- a/video/decode/vd_lavc.c +++ b/video/decode/vd_lavc.c @@ -29,7 +29,7 @@ #include <libavutil/pixdesc.h> #include "mpv_talloc.h" -#include "config.h" +#include "common/global.h" #include "common/msg.h" #include "options/options.h" #include "misc/bstr.h" @@ -38,12 +38,12 @@ #include "video/fmt-conversion.h" -#include "vd.h" +#include "filters/f_decoder_wrapper.h" +#include "filters/filter_internal.h" #include "video/hwdec.h" #include "video/img_format.h" #include "video/mp_image.h" #include "video/mp_image_pool.h" -#include "video/decode/dec_video.h" #include "demux/demux.h" #include "demux/stheader.h" #include "demux/packet.h" @@ -53,8 +53,8 @@ #include "options/m_option.h" -static void init_avctx(struct dec_video *vd); -static void uninit_avctx(struct dec_video *vd); +static void init_avctx(struct mp_filter *vd); +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, @@ -147,6 +147,7 @@ struct hwdec_info { typedef struct lavc_ctx { struct mp_log *log; struct MPOpts *opts; + struct mp_codec_params *codec; AVCodecContext *avctx; AVFrame *pic; bool use_hwdec; @@ -154,6 +155,7 @@ typedef struct lavc_ctx { AVRational codec_timebase; enum AVDiscard skip_frame; bool flushing; + bool eof_returned; const char *decoder; bool hwdec_requested; bool hwdec_failed; @@ -174,6 +176,7 @@ typedef struct lavc_ctx { int max_delay_queue; // From VO + struct vo *vo; struct mp_hwdec_devices *hwdec_devs; // Wrapped AVHWDeviceContext* used for decoding. @@ -191,6 +194,8 @@ typedef struct lavc_ctx { bool dr_failed; struct mp_image_pool *dr_pool; int dr_imgfmt, dr_w, dr_h, dr_stride_align; + + struct mp_decoder public; } vd_ffmpeg_ctx; // Things not included in this list will be tried last, in random order. @@ -355,9 +360,10 @@ static void add_all_hwdec_methods(struct hwdec_info **infos, int *num_infos) qsort(*infos, *num_infos, sizeof(struct hwdec_info), hwdec_compare); } -static bool hwdec_codec_allowed(struct dec_video *vd, const char *codec) +static bool hwdec_codec_allowed(struct mp_filter *vd, const char *codec) { - bstr s = bstr0(vd->opts->hwdec_codecs); + vd_ffmpeg_ctx *ctx = vd->priv; + bstr s = bstr0(ctx->opts->hwdec_codecs); while (s.len) { bstr item; bstr_split_tok(s, ",", &item, &s); @@ -367,10 +373,11 @@ static bool hwdec_codec_allowed(struct dec_video *vd, const char *codec) return false; } -static AVBufferRef *hwdec_create_dev(struct dec_video *vd, +static AVBufferRef *hwdec_create_dev(struct mp_filter *vd, struct hwdec_info *hwdec, bool autoprobe) { + vd_ffmpeg_ctx *ctx = vd->priv; assert(hwdec->lavc_device); if (hwdec->copying) { @@ -386,21 +393,21 @@ static AVBufferRef *hwdec_create_dev(struct dec_video *vd, av_hwdevice_ctx_create(&ref, hwdec->lavc_device, NULL, NULL, 0); return ref; } - } else if (vd->hwdec_devs) { - hwdec_devices_request_all(vd->hwdec_devs); - return hwdec_devices_get_lavc(vd->hwdec_devs, hwdec->lavc_device); + } else if (ctx->hwdec_devs) { + hwdec_devices_request_all(ctx->hwdec_devs); + return hwdec_devices_get_lavc(ctx->hwdec_devs, hwdec->lavc_device); } return NULL; } // Select if and which hwdec to use. Also makes sure to get the decode device. -static void select_and_set_hwdec(struct dec_video *vd) +static void select_and_set_hwdec(struct mp_filter *vd) { vd_ffmpeg_ctx *ctx = vd->priv; - const char *codec = vd->codec->codec; + const char *codec = ctx->codec->codec; - bstr opt = bstr0(vd->opts->hwdec_api); + bstr opt = bstr0(ctx->opts->hwdec_api); bool hwdec_requested = !bstr_equals0(opt, "no"); bool hwdec_auto_all = bstr_equals0(opt, "auto") || @@ -454,8 +461,8 @@ static void select_and_set_hwdec(struct dec_video *vd) } else if (!hwdec->copying) { // Most likely METHOD_INTERNAL, which often use delay-loaded // VO support as well. - if (vd->hwdec_devs) - hwdec_devices_request_all(vd->hwdec_devs); + if (ctx->hwdec_devs) + hwdec_devices_request_all(ctx->hwdec_devs); } ctx->use_hwdec = true; @@ -503,17 +510,7 @@ int hwdec_validate_opt(struct mp_log *log, const m_option_t *opt, return 0; } -static void uninit(struct dec_video *vd) -{ - vd_ffmpeg_ctx *ctx = vd->priv; - - uninit_avctx(vd); - - pthread_mutex_destroy(&ctx->dr_lock); - talloc_free(vd->priv); -} - -static void force_fallback(struct dec_video *vd) +static void force_fallback(struct mp_filter *vd) { vd_ffmpeg_ctx *ctx = vd->priv; @@ -523,7 +520,7 @@ static void force_fallback(struct dec_video *vd) init_avctx(vd); } -static void reinit(struct dec_video *vd) +static void reinit(struct mp_filter *vd) { vd_ffmpeg_ctx *ctx = vd->priv; @@ -537,33 +534,11 @@ static void reinit(struct dec_video *vd) force_fallback(vd); } -static int init(struct dec_video *vd, const char *decoder) -{ - vd_ffmpeg_ctx *ctx; - ctx = vd->priv = talloc_zero(NULL, vd_ffmpeg_ctx); - ctx->log = vd->log; - ctx->opts = vd->opts; - ctx->decoder = talloc_strdup(ctx, decoder); - ctx->hwdec_devs = vd->hwdec_devs; - ctx->hwdec_swpool = mp_image_pool_new(ctx); - ctx->dr_pool = mp_image_pool_new(ctx); - - pthread_mutex_init(&ctx->dr_lock, NULL); - - reinit(vd); - - if (!ctx->avctx) { - uninit(vd); - return 0; - } - return 1; -} - -static void init_avctx(struct dec_video *vd) +static void init_avctx(struct mp_filter *vd) { vd_ffmpeg_ctx *ctx = vd->priv; - struct vd_lavc_params *lavc_param = vd->opts->vd_lavc_params; - struct mp_codec_params *c = vd->codec; + struct vd_lavc_params *lavc_param = ctx->opts->vd_lavc_params; + struct mp_codec_params *c = ctx->codec; assert(!ctx->avctx); @@ -580,7 +555,7 @@ static void init_avctx(struct dec_video *vd) const AVCodecDescriptor *desc = avcodec_descriptor_get(lavc_codec->id); ctx->intra_only = desc && (desc->props & AV_CODEC_PROP_INTRA_ONLY); - ctx->codec_timebase = mp_get_codec_timebase(vd->codec); + ctx->codec_timebase = mp_get_codec_timebase(ctx->codec); // This decoder does not read pkt_timebase correctly yet. if (strstr(lavc_codec->name, "_mmal")) @@ -632,7 +607,7 @@ static void init_avctx(struct dec_video *vd) mp_set_avcodec_threads(vd->log, avctx, lavc_param->threads); } - if (!ctx->use_hwdec && vd->vo && lavc_param->dr) { + if (!ctx->use_hwdec && ctx->vo && lavc_param->dr) { avctx->opaque = vd; avctx->get_buffer2 = get_buffer2_direct; avctx->thread_safe_callbacks = 1; @@ -685,7 +660,7 @@ error: uninit_avctx(vd); } -static void reset_avctx(struct dec_video *vd) +static void reset_avctx(struct mp_filter *vd) { vd_ffmpeg_ctx *ctx = vd->priv; @@ -695,7 +670,7 @@ static void reset_avctx(struct dec_video *vd) ctx->hwdec_request_reinit = false; } -static void flush_all(struct dec_video *vd) +static void flush_all(struct mp_filter *vd) { vd_ffmpeg_ctx *ctx = vd->priv; @@ -714,7 +689,7 @@ static void flush_all(struct dec_video *vd) reset_avctx(vd); } -static void uninit_avctx(struct dec_video *vd) +static void uninit_avctx(struct mp_filter *vd) { vd_ffmpeg_ctx *ctx = vd->priv; @@ -734,7 +709,7 @@ static void uninit_avctx(struct dec_video *vd) ctx->use_hwdec = false; } -static int init_generic_hwaccel(struct dec_video *vd, enum AVPixelFormat hw_fmt) +static int init_generic_hwaccel(struct mp_filter *vd, enum AVPixelFormat hw_fmt) { struct lavc_ctx *ctx = vd->priv; AVBufferRef *new_frames_ctx = NULL; @@ -756,8 +731,8 @@ static int init_generic_hwaccel(struct dec_video *vd, enum AVPixelFormat hw_fmt) AVHWFramesContext *new_fctx = (void *)new_frames_ctx->data; - if (vd->opts->hwdec_image_format) - new_fctx->sw_format = imgfmt2pixfmt(vd->opts->hwdec_image_format); + if (ctx->opts->hwdec_image_format) + new_fctx->sw_format = imgfmt2pixfmt(ctx->opts->hwdec_image_format); // 1 surface is already included by libavcodec. The field is 0 if the // hwaccel supports dynamic surface allocation. @@ -808,7 +783,7 @@ error: static enum AVPixelFormat get_format_hwdec(struct AVCodecContext *avctx, const enum AVPixelFormat *fmt) { - struct dec_video *vd = avctx->opaque; + struct mp_filter *vd = avctx->opaque; vd_ffmpeg_ctx *ctx = vd->priv; MP_VERBOSE(vd, "Pixel formats supported by decoder:"); @@ -853,7 +828,7 @@ static enum AVPixelFormat get_format_hwdec(struct AVCodecContext *avctx, static int get_buffer2_direct(AVCodecContext *avctx, AVFrame *pic, int flags) { - struct dec_video *vd = avctx->opaque; + struct mp_filter *vd = avctx->opaque; vd_ffmpeg_ctx *p = vd->priv; pthread_mutex_lock(&p->dr_lock); @@ -893,7 +868,7 @@ 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(vd->vo, imgfmt, w, h, stride_align); + img = vo_get_image(p->vo, imgfmt, w, h, stride_align); if (!img) { MP_DBG(p, "...failed..\n"); goto fallback; @@ -932,7 +907,7 @@ fallback: return avcodec_default_get_buffer2(avctx, pic, flags); } -static bool prepare_decoding(struct dec_video *vd) +static bool prepare_decoding(struct mp_filter *vd) { vd_ffmpeg_ctx *ctx = vd->priv; AVCodecContext *avctx = ctx->avctx; @@ -959,7 +934,7 @@ static bool prepare_decoding(struct dec_video *vd) return true; } -static void handle_err(struct dec_video *vd) +static void handle_err(struct mp_filter *vd) { vd_ffmpeg_ctx *ctx = vd->priv; struct vd_lavc_params *opts = ctx->opts->vd_lavc_params; @@ -973,7 +948,7 @@ static void handle_err(struct dec_video *vd) } } -static bool do_send_packet(struct dec_video *vd, struct demux_packet *pkt) +static bool do_send_packet(struct mp_filter *vd, struct demux_packet *pkt) { vd_ffmpeg_ctx *ctx = vd->priv; AVCodecContext *avctx = ctx->avctx; @@ -1001,7 +976,7 @@ static bool do_send_packet(struct dec_video *vd, struct demux_packet *pkt) return true; } -static bool send_packet(struct dec_video *vd, struct demux_packet *pkt) +static bool send_packet(struct mp_filter *vd, struct demux_packet *pkt) { vd_ffmpeg_ctx *ctx = vd->priv; @@ -1017,7 +992,7 @@ static bool send_packet(struct dec_video *vd, struct demux_packet *pkt) } // Returns whether decoder is still active (!EOF state). -static bool decode_frame(struct dec_video *vd) +static bool decode_frame(struct mp_filter *vd) { vd_ffmpeg_ctx *ctx = vd->priv; AVCodecContext *avctx = ctx->avctx; @@ -1040,15 +1015,6 @@ static bool decode_frame(struct dec_video *vd) ctx->hwdec_fail_count = 0; - AVFrameSideData *sd = NULL; - sd = av_frame_get_side_data(ctx->pic, AV_FRAME_DATA_A53_CC); - if (sd) { - struct demux_packet *cc = new_demux_packet_from(sd->data, sd->size); - cc->pts = vd->codec_pts; - cc->dts = vd->codec_dts; - demuxer_feed_caption(vd->header, cc); - } - struct mp_image *mpi = mp_image_from_av_frame(ctx->pic); if (!mpi) { av_frame_unref(ctx->pic); @@ -1069,12 +1035,10 @@ static bool decode_frame(struct dec_video *vd) return true; } -static bool receive_frame(struct dec_video *vd, struct mp_image **out_image) +static bool receive_frame(struct mp_filter *vd, struct mp_frame *out_frame) { vd_ffmpeg_ctx *ctx = vd->priv; - assert(!*out_image); - bool progress = decode_frame(vd); if (ctx->hwdec_failed) { @@ -1132,17 +1096,14 @@ static bool receive_frame(struct dec_video *vd, struct mp_image **out_image) ctx->hw_probing = false; } - *out_image = res; + *out_frame = MAKE_FRAME(MP_FRAME_VIDEO, res); return true; } -static int control(struct dec_video *vd, int cmd, void *arg) +static int control(struct mp_filter *vd, enum dec_ctrl cmd, void *arg) { vd_ffmpeg_ctx *ctx = vd->priv; switch (cmd) { - case VDCTRL_RESET: - flush_all(vd); - return CONTROL_TRUE; case VDCTRL_SET_FRAMEDROP: ctx->framedrop_flags = *(int *)arg; return CONTROL_TRUE; @@ -1172,17 +1133,88 @@ static int control(struct dec_video *vd, int cmd, void *arg) return CONTROL_UNKNOWN; } +static void process(struct mp_filter *vd) +{ + vd_ffmpeg_ctx *ctx = vd->priv; + + lavc_process(vd, &ctx->eof_returned, send_packet, receive_frame); +} + +static void reset(struct mp_filter *vd) +{ + vd_ffmpeg_ctx *ctx = vd->priv; + + flush_all(vd); + + ctx->eof_returned = false; + ctx->framedrop_flags = 0; +} + +static void destroy(struct mp_filter *vd) +{ + vd_ffmpeg_ctx *ctx = vd->priv; + + uninit_avctx(vd); + + pthread_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, +}; + +static struct mp_decoder *create(struct mp_filter *parent, + struct mp_codec_params *codec, + const char *decoder) +{ + struct mp_filter *vd = mp_filter_create(parent, &vd_lavc_filter); + if (!vd) + return NULL; + + mp_filter_add_pin(vd, MP_PIN_IN, "in"); + mp_filter_add_pin(vd, MP_PIN_OUT, "out"); + + vd->log = mp_log_new(vd, parent->log, NULL); + + vd_ffmpeg_ctx *ctx = vd->priv; + ctx->log = vd->log; + ctx->opts = vd->global->opts; + ctx->codec = codec; + ctx->decoder = talloc_strdup(ctx, decoder); + ctx->hwdec_swpool = mp_image_pool_new(ctx); + ctx->dr_pool = mp_image_pool_new(ctx); + + ctx->public.f = vd; + ctx->public.control = control; + + pthread_mutex_init(&ctx->dr_lock, NULL); + + // hwdec/DR + struct mp_stream_info *info = mp_filter_find_stream_info(vd); + if (info) { + ctx->hwdec_devs = info->hwdec_devs; + ctx->vo = info->dr_vo; + } + + reinit(vd); + + if (!ctx->avctx) { + talloc_free(vd); + return NULL; + } + return &ctx->public; +} + static void add_decoders(struct mp_decoder_list *list) { mp_add_lavc_decoders(list, AVMEDIA_TYPE_VIDEO); } -const struct vd_functions mpcodecs_vd_ffmpeg = { - .name = "lavc", +const struct mp_decoder_fns vd_lavc = { + .create = create, .add_decoders = add_decoders, - .init = init, - .uninit = uninit, - .control = control, - .send_packet = send_packet, - .receive_frame = receive_frame, }; |