diff options
Diffstat (limited to 'video/decode/vd_lavc.c')
-rw-r--r-- | video/decode/vd_lavc.c | 199 |
1 files changed, 124 insertions, 75 deletions
diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c index f47e72a1cd..0520c3a4fd 100644 --- a/video/decode/vd_lavc.c +++ b/video/decode/vd_lavc.c @@ -41,6 +41,7 @@ #include "video/img_format.h" #include "video/filter/vf.h" #include "video/decode/dec_video.h" +#include "demux/demux.h" #include "demux/stheader.h" #include "demux/packet.h" #include "video/csputils.h" @@ -123,6 +124,7 @@ extern const struct vd_lavc_hwdec mp_vd_lavc_vdpau; extern const struct vd_lavc_hwdec mp_vd_lavc_videotoolbox; extern const struct vd_lavc_hwdec mp_vd_lavc_vaapi; extern const struct vd_lavc_hwdec mp_vd_lavc_vaapi_copy; +extern const struct vd_lavc_hwdec mp_vd_lavc_dxva2; extern const struct vd_lavc_hwdec mp_vd_lavc_dxva2_copy; extern const struct vd_lavc_hwdec mp_vd_lavc_rpi; @@ -141,6 +143,7 @@ static const struct vd_lavc_hwdec *const hwdec_list[] = { &mp_vd_lavc_vaapi_copy, #endif #if HAVE_DXVA2_HWACCEL + &mp_vd_lavc_dxva2, &mp_vd_lavc_dxva2_copy, #endif NULL @@ -276,35 +279,22 @@ static void uninit(struct dec_video *vd) static bool force_fallback(struct dec_video *vd) { vd_ffmpeg_ctx *ctx = vd->priv; - if (!ctx->software_fallback_decoder) + if (!ctx->hwdec) return false; uninit_avctx(vd); int lev = ctx->hwdec_notified ? MSGL_WARN : MSGL_V; mp_msg(vd->log, lev, "Falling back to software decoding.\n"); - const char *decoder = ctx->software_fallback_decoder; - ctx->software_fallback_decoder = NULL; - init_avctx(vd, decoder, NULL); + init_avctx(vd, ctx->decoder, NULL); return true; } -static int init(struct dec_video *vd, const char *decoder) +static void reinit(struct dec_video *vd) { - vd_ffmpeg_ctx *ctx; - ctx = vd->priv = talloc_zero(NULL, vd_ffmpeg_ctx); - ctx->log = vd->log; - ctx->opts = vd->opts; + vd_ffmpeg_ctx *ctx = vd->priv; + const char *decoder = ctx->decoder; - if (bstr_endswith0(bstr0(decoder), "_vdpau")) { - MP_WARN(vd, "VDPAU decoder '%s' was requested. " - "This way of enabling hardware\ndecoding is not supported " - "anymore. Use --hwdec=vdpau instead.\nThe --hwdec-codec=... " - "option can be used to restrict which codecs are\nenabled, " - "otherwise all hardware decoding is tried for all codecs.\n", - decoder); - uninit(vd); - return 0; - } + uninit_avctx(vd); struct vd_lavc_hwdec *hwdec = NULL; @@ -325,7 +315,6 @@ static int init(struct dec_video *vd, const char *decoder) } if (hwdec) { - ctx->software_fallback_decoder = talloc_strdup(ctx, decoder); if (hwdec->get_codec) decoder = hwdec->get_codec(ctx, decoder); MP_VERBOSE(vd, "Trying hardware decoding.\n"); @@ -334,14 +323,35 @@ static int init(struct dec_video *vd, const char *decoder) } init_avctx(vd, decoder, hwdec); - if (!ctx->avctx) { + if (!ctx->avctx) force_fallback(vd); - if (!ctx->avctx) { - uninit(vd); - return 0; - } +} + +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); + + if (bstr_endswith0(bstr0(decoder), "_vdpau")) { + MP_WARN(vd, "VDPAU decoder '%s' was requested. " + "This way of enabling hardware\ndecoding is not supported " + "anymore. Use --hwdec=vdpau instead.\nThe --hwdec-codec=... " + "option can be used to restrict which codecs are\nenabled, " + "otherwise all hardware decoding is tried for all codecs.\n", + decoder); + uninit(vd); + return 0; } + reinit(vd); + + if (!ctx->avctx) { + uninit(vd); + return 0; + } return 1; } @@ -351,8 +361,7 @@ static void init_avctx(struct dec_video *vd, const char *decoder, vd_ffmpeg_ctx *ctx = vd->priv; struct vd_lavc_params *lavc_param = vd->opts->vd_lavc_params; bool mp_rawvideo = false; - struct sh_stream *sh = vd->header; - struct mp_codec_params *c = sh->codec; + struct mp_codec_params *c = vd->codec; assert(!ctx->avctx); @@ -367,6 +376,10 @@ static void init_avctx(struct dec_video *vd, const char *decoder, ctx->hwdec_info = vd->hwdec_info; + ctx->codec_timebase = (AVRational){0}; + if (strstr(decoder, "_mmal")) + ctx->codec_timebase = (AVRational){1, 1000000}; + ctx->pix_fmt = AV_PIX_FMT_NONE; ctx->hwdec = hwdec; ctx->hwdec_fmt = 0; @@ -390,6 +403,10 @@ static void init_avctx(struct dec_video *vd, const char *decoder, avctx->get_buffer2 = get_buffer2_hwdec; if (ctx->hwdec->init(ctx) < 0) goto error; + // This can increase efficiency by not blocking on the hardware + // pipeline by reading back immediately after decoding. + if (ctx->hwdec->process_image) + ctx->max_delay_queue = HWDEC_DELAY_QUEUE_COUNT; } else { mp_set_avcodec_threads(vd->log, avctx, lavc_param->threads); } @@ -448,21 +465,33 @@ static void reset_avctx(struct dec_video *vd) { vd_ffmpeg_ctx *ctx = vd->priv; - if (ctx->avctx) + if (ctx->avctx && avcodec_is_open(ctx->avctx)) avcodec_flush_buffers(ctx->avctx); ctx->flushing = false; } +static void flush_all(struct dec_video *vd) +{ + vd_ffmpeg_ctx *ctx = vd->priv; + + for (int n = 0; n < ctx->num_delay_queue; n++) + talloc_free(ctx->delay_queue[n]); + ctx->num_delay_queue = 0; + + reset_avctx(vd); +} + static void uninit_avctx(struct dec_video *vd) { vd_ffmpeg_ctx *ctx = vd->priv; - AVCodecContext *avctx = ctx->avctx; - if (avctx) { - if (avctx->codec && avcodec_close(avctx) < 0) - MP_ERR(vd, "Could not close codec.\n"); + flush_all(vd); + av_frame_free(&ctx->pic); - av_freep(&avctx->extradata); + if (ctx->avctx) { + if (avcodec_close(ctx->avctx) < 0) + MP_ERR(vd, "Could not close codec.\n"); + av_freep(&ctx->avctx->extradata); } if (ctx->hwdec && ctx->hwdec->uninit) @@ -471,11 +500,9 @@ static void uninit_avctx(struct dec_video *vd) av_freep(&ctx->avctx); - av_frame_free(&ctx->pic); - - ctx->flushing = false; ctx->hwdec_failed = false; ctx->hwdec_fail_count = 0; + ctx->max_delay_queue = 0; } static void update_image_params(struct dec_video *vd, AVFrame *frame, @@ -483,22 +510,11 @@ static void update_image_params(struct dec_video *vd, AVFrame *frame, { vd_ffmpeg_ctx *ctx = vd->priv; struct MPOpts *opts = ctx->opts; - int width = frame->width; - int height = frame->height; - int pix_fmt = frame->format; - - if (pix_fmt != ctx->pix_fmt) { - ctx->pix_fmt = pix_fmt; - ctx->best_csp = pixfmt2imgfmt(pix_fmt); - if (!ctx->best_csp) - MP_ERR(vd, "lavc pixel format %s not supported.\n", - av_get_pix_fmt_name(pix_fmt)); - } *out_params = (struct mp_image_params) { - .imgfmt = ctx->best_csp, - .w = width, - .h = height, + .imgfmt = pixfmt2imgfmt(frame->format), + .w = frame->width, + .h = frame->height, .p_w = frame->sample_aspect_ratio.num, .p_h = frame->sample_aspect_ratio.den, .colorspace = avcol_spc_to_mp_csp(ctx->avctx->colorspace), @@ -507,8 +523,8 @@ static void update_image_params(struct dec_video *vd, AVFrame *frame, .gamma = avcol_trc_to_mp_csp_trc(ctx->avctx->color_trc), .chroma_location = avchroma_location_to_mp(ctx->avctx->chroma_sample_location), - .rotate = vd->header->codec->rotate, - .stereo_in = vd->header->codec->stereo_mode, + .rotate = vd->codec->rotate, + .stereo_in = vd->codec->stereo_mode, }; if (opts->video_rotate < 0) { @@ -584,7 +600,7 @@ static int get_buffer2_hwdec(AVCodecContext *avctx, AVFrame *pic, int flags) vd_ffmpeg_ctx *ctx = vd->priv; int imgfmt = pixfmt2imgfmt(pic->format); - if (!IMGFMT_IS_HWACCEL(imgfmt) || !ctx->hwdec) + if (!ctx->hwdec || ctx->hwdec_fmt != imgfmt) ctx->hwdec_failed = true; /* Hardware decoding failed, and we will trigger a proper fallback later @@ -617,6 +633,22 @@ static int get_buffer2_hwdec(AVCodecContext *avctx, AVFrame *pic, int flags) return 0; } +static struct mp_image *read_output(struct dec_video *vd) +{ + vd_ffmpeg_ctx *ctx = vd->priv; + + if (!ctx->num_delay_queue) + return NULL; + + struct mp_image *res = ctx->delay_queue[0]; + MP_TARRAY_REMOVE_AT(ctx->delay_queue, ctx->num_delay_queue, 0); + + if (ctx->hwdec && ctx->hwdec->process_image) + res = ctx->hwdec->process_image(ctx, res); + + return mp_img_swap_to_native(res); +} + static void decode(struct dec_video *vd, struct demux_packet *packet, int flags, struct mp_image **out_image) { @@ -625,6 +657,7 @@ static void decode(struct dec_video *vd, struct demux_packet *packet, vd_ffmpeg_ctx *ctx = vd->priv; AVCodecContext *avctx = ctx->avctx; struct vd_lavc_params *opts = ctx->opts->vd_lavc_params; + AVRational *tb = ctx->codec_timebase.num ? &ctx->codec_timebase : NULL; AVPacket pkt; if (!avctx) @@ -638,7 +671,7 @@ static void decode(struct dec_video *vd, struct demux_packet *packet, avctx->skip_frame = ctx->skip_frame; } - mp_set_av_packet(&pkt, packet, NULL); + mp_set_av_packet(&pkt, packet, tb); ctx->flushing |= !pkt.data; // Reset decoder if hw state got reset, or new data comes during flushing. @@ -669,28 +702,48 @@ static void decode(struct dec_video *vd, struct demux_packet *packet, return; } + if (packet) { + // always fully consumed + packet->len = 0; + } + // Skipped frame, or delayed output due to multithreaded decoding. - if (!got_picture) + if (!got_picture) { + if (!packet) + *out_image = read_output(vd); return; + } ctx->hwdec_fail_count = 0; - struct mp_image_params params; - update_image_params(vd, ctx->pic, ¶ms); - vd->codec_pts = mp_pts_from_av(ctx->pic->pkt_pts, NULL); - vd->codec_dts = mp_pts_from_av(ctx->pic->pkt_dts, NULL); + 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; + cc->pos = -1; + demuxer_feed_caption(vd->header, cc); + } struct mp_image *mpi = mp_image_from_av_frame(ctx->pic); - av_frame_unref(ctx->pic); - if (!mpi) + if (!mpi) { + av_frame_unref(ctx->pic); return; + } assert(mpi->planes[0] || mpi->planes[3]); + mpi->pts = mp_pts_from_av(ctx->pic->pkt_pts, tb); + mpi->dts = mp_pts_from_av(ctx->pic->pkt_dts, tb); + + struct mp_image_params params; + update_image_params(vd, ctx->pic, ¶ms); mp_image_set_params(mpi, ¶ms); - if (ctx->hwdec && ctx->hwdec->process_image) - mpi = ctx->hwdec->process_image(ctx, mpi); + av_frame_unref(ctx->pic); - *out_image = mp_img_swap_to_native(mpi); + MP_TARRAY_APPEND(ctx, ctx->delay_queue, ctx->num_delay_queue, mpi); + if (ctx->num_delay_queue > ctx->max_delay_queue) + *out_image = read_output(vd); } static struct mp_image *decode_with_fallback(struct dec_video *vd, @@ -726,32 +779,28 @@ static int control(struct dec_video *vd, int cmd, void *arg) vd_ffmpeg_ctx *ctx = vd->priv; switch (cmd) { case VDCTRL_RESET: - reset_avctx(vd); + flush_all(vd); return CONTROL_TRUE; - case VDCTRL_QUERY_UNSEEN_FRAMES: { + case VDCTRL_GET_BFRAMES: { AVCodecContext *avctx = ctx->avctx; if (!avctx) break; if (ctx->hwdec && ctx->hwdec->type == HWDEC_RPI) break; // MMAL has arbitrary buffering, thus unknown - int delay = avctx->has_b_frames; - assert(delay >= 0); - if (avctx->active_thread_type & FF_THREAD_FRAME) - delay += avctx->thread_count - 1; - *(int *)arg = delay; + *(int *)arg = avctx->has_b_frames; return CONTROL_TRUE; } case VDCTRL_GET_HWDEC: { - int hwdec = ctx->hwdec ? ctx->hwdec->type : 0; - if (!ctx->software_fallback_decoder) - hwdec = 0; - *(int *)arg = hwdec; + *(int *)arg = ctx->hwdec ? ctx->hwdec->type : 0; return CONTROL_TRUE; } case VDCTRL_FORCE_HWDEC_FALLBACK: if (force_fallback(vd)) return ctx->avctx ? CONTROL_OK : CONTROL_ERROR; return CONTROL_FALSE; + case VDCTRL_REINIT: + reinit(vd); + return CONTROL_TRUE; } return CONTROL_UNKNOWN; } |