diff options
Diffstat (limited to 'video/decode/vd_lavc.c')
-rw-r--r-- | video/decode/vd_lavc.c | 212 |
1 files changed, 137 insertions, 75 deletions
diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c index 4922f57387..8a989feea7 100644 --- a/video/decode/vd_lavc.c +++ b/video/decode/vd_lavc.c @@ -59,10 +59,9 @@ #include "core/m_option.h" -static int init_avctx(sh_video_t *sh, const char *decoder, struct hwdec *hwdec); +static void init_avctx(sh_video_t *sh, const char *decoder, struct hwdec *hwdec); static void uninit_avctx(sh_video_t *sh); -static int get_buffer_hwdec(AVCodecContext *avctx, AVFrame *pic); -static void release_buffer_hwdec(AVCodecContext *avctx, AVFrame *pic); +static void setup_refcounting_hw(struct AVCodecContext *s); static void draw_slice_hwdec(struct AVCodecContext *s, const AVFrame *src, int offset[4], int y, int type, int height); @@ -168,16 +167,18 @@ static int init(sh_video_t *sh, const char *decoder) } } - if (!init_avctx(sh, decoder, hwdec)) { + init_avctx(sh, decoder, hwdec); + if (!ctx->avctx) { if (ctx->software_fallback_decoder) { mp_tmsg(MSGT_DECVIDEO, MSGL_ERR, "Error initializing hardware " "decoding, falling back to software decoding.\n"); decoder = ctx->software_fallback_decoder; ctx->software_fallback_decoder = NULL; - if (!init_avctx(sh, decoder, NULL)) { - uninit(sh); - return 0; - } + init_avctx(sh, decoder, NULL); + } + if (!ctx->avctx) { + uninit(sh); + return 0; } } return 1; @@ -241,12 +242,14 @@ static void set_from_bih(AVCodecContext *avctx, uint32_t format, avctx->coded_height = bih->biHeight; } -static int init_avctx(sh_video_t *sh, const char *decoder, struct hwdec *hwdec) +static void init_avctx(sh_video_t *sh, const char *decoder, struct hwdec *hwdec) { vd_ffmpeg_ctx *ctx = sh->context; struct lavc_param *lavc_param = &sh->opts->lavc_param; bool mp_rawvideo = false; + assert(!ctx->avctx); + if (strcmp(decoder, "mp-rawvideo") == 0) { mp_rawvideo = true; decoder = "rawvideo"; @@ -254,7 +257,7 @@ static int init_avctx(sh_video_t *sh, const char *decoder, struct hwdec *hwdec) AVCodec *lavc_codec = avcodec_find_decoder_by_name(decoder); if (!lavc_codec) - return 0; + return; ctx->do_dr1 = ctx->do_hw_dr1 = 0; ctx->pix_fmt = PIX_FMT_NONE; @@ -274,17 +277,22 @@ static int init_avctx(sh_video_t *sh, const char *decoder, struct hwdec *hwdec) ctx->do_hw_dr1 = true; avctx->thread_count = 1; avctx->get_format = get_format_hwdec; - avctx->get_buffer = get_buffer_hwdec; - avctx->release_buffer = release_buffer_hwdec; + setup_refcounting_hw(avctx); if (ctx->hwdec->api == HWDEC_VDPAU) { avctx->draw_horiz_band = draw_slice_hwdec; avctx->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD; } - } else if (lavc_codec->capabilities & CODEC_CAP_DR1) { - ctx->do_dr1 = true; - avctx->get_buffer = mp_codec_get_buffer; - avctx->release_buffer = mp_codec_release_buffer; + } else { +#if HAVE_AVUTIL_REFCOUNTING + avctx->refcounted_frames = 1; +#else + if (lavc_codec->capabilities & CODEC_CAP_DR1) { + ctx->do_dr1 = true; + avctx->get_buffer = mp_codec_get_buffer; + avctx->release_buffer = mp_codec_release_buffer; + } +#endif } if (avctx->thread_count == 0) { @@ -321,8 +329,8 @@ static int init_avctx(sh_video_t *sh, const char *decoder, struct hwdec *hwdec) mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Your options /%s/ look like gibberish to me pal\n", lavc_param->avopt); - uninit(sh); - return 0; + uninit_avctx(sh); + return; } } @@ -352,9 +360,8 @@ static int init_avctx(sh_video_t *sh, const char *decoder, struct hwdec *hwdec) if (avcodec_open2(avctx, lavc_codec, NULL) < 0) { mp_tmsg(MSGT_DECVIDEO, MSGL_ERR, "Could not open codec.\n"); uninit_avctx(sh); - return 0; + return; } - return 1; } static void uninit_avctx(sh_video_t *sh) @@ -370,10 +377,12 @@ static void uninit_avctx(sh_video_t *sh) av_freep(&avctx->slice_offset); } - av_freep(&avctx); + av_freep(&ctx->avctx); avcodec_free_frame(&ctx->pic); +#if !HAVE_AVUTIL_REFCOUNTING mp_buffer_pool_free(&ctx->dr1_buffer_pool); +#endif } static void uninit(sh_video_t *sh) @@ -466,9 +475,8 @@ static void draw_slice_hwdec(struct AVCodecContext *s, vf->control(vf, VFCTRL_HWDEC_DECODER_RENDER, state_ptr); } -static int get_buffer_hwdec(AVCodecContext *avctx, AVFrame *pic) +static struct mp_image *get_surface_hwdec(struct sh_video *sh, AVFrame *pic) { - sh_video_t *sh = avctx->opaque; vd_ffmpeg_ctx *ctx = sh->context; /* Decoders using ffmpeg's hwaccel architecture (everything except vdpau) @@ -484,10 +492,10 @@ static int get_buffer_hwdec(AVCodecContext *avctx, AVFrame *pic) */ int imgfmt = pixfmt2imgfmt(pic->format); if (!IMGFMT_IS_HWACCEL(imgfmt)) - return -1; + return NULL; if (init_vo(sh, pic) < 0) - return -1; + return NULL; assert(IMGFMT_IS_HWACCEL(ctx->best_csp)); @@ -495,11 +503,52 @@ static int get_buffer_hwdec(AVCodecContext *avctx, AVFrame *pic) struct vf_instance *vf = sh->vfilter; vf->control(vf, VFCTRL_HWDEC_ALLOC_SURFACE, &mpi); + + if (mpi) { + for (int i = 0; i < 4; i++) + pic->data[i] = mpi->planes[i]; + } + + return mpi; +} + +#if HAVE_AVUTIL_REFCOUNTING + +static void free_mpi(void *opaque, uint8_t *data) +{ + struct mp_image *mpi = opaque; + talloc_free(mpi); +} + +static int get_buffer2_hwdec(AVCodecContext *avctx, AVFrame *pic, int flags) +{ + sh_video_t *sh = avctx->opaque; + + struct mp_image *mpi = get_surface_hwdec(sh, pic); + if (!mpi) + return -1; + + pic->buf[0] = av_buffer_create(NULL, 0, free_mpi, mpi, 0); + + return 0; +} + +static void setup_refcounting_hw(AVCodecContext *avctx) +{ + avctx->get_buffer2 = get_buffer2_hwdec; + avctx->refcounted_frames = 1; +} + +#else /* HAVE_AVUTIL_REFCOUNTING */ + +static int get_buffer_hwdec(AVCodecContext *avctx, AVFrame *pic) +{ + sh_video_t *sh = avctx->opaque; + + struct mp_image *mpi = get_surface_hwdec(sh, pic); if (!mpi) return -1; - for (int i = 0; i < 4; i++) - pic->data[i] = mpi->planes[i]; pic->opaque = mpi; pic->type = FF_BUFFER_TYPE_USER; @@ -525,6 +574,29 @@ static void release_buffer_hwdec(AVCodecContext *avctx, AVFrame *pic) pic->data[i] = NULL; } +static void setup_refcounting_hw(AVCodecContext *avctx) +{ + avctx->get_buffer = get_buffer_hwdec; + avctx->release_buffer = release_buffer_hwdec; +} + +#endif /* HAVE_AVUTIL_REFCOUNTING */ + +#if HAVE_AVUTIL_REFCOUNTING + +static struct mp_image *image_from_decoder(struct sh_video *sh) +{ + vd_ffmpeg_ctx *ctx = sh->context; + AVFrame *pic = ctx->pic; + + struct mp_image *img = mp_image_from_av_frame(pic); + av_frame_unref(pic); + + return img; +} + +#else /* HAVE_AVUTIL_REFCOUNTING */ + static void fb_ref(void *b) { mp_buffer_ref(b); @@ -540,9 +612,35 @@ static bool fb_is_unique(void *b) return mp_buffer_is_unique(b); } -static int decode(struct sh_video *sh, struct demux_packet *packet, void *data, - int len, int flags, double *reordered_pts, - struct mp_image **out_image) +static struct mp_image *image_from_decoder(struct sh_video *sh) +{ + vd_ffmpeg_ctx *ctx = sh->context; + AVFrame *pic = ctx->pic; + + struct mp_image new = {0}; + mp_image_copy_fields_from_av_frame(&new, pic); + + struct mp_image *mpi; + if (ctx->do_hw_dr1 && pic->opaque) { + mpi = pic->opaque; // reordered frame + assert(mpi); + mpi = mp_image_new_ref(mpi); + mp_image_copy_attributes(mpi, &new); + } else if (ctx->do_dr1 && pic->opaque) { + struct FrameBuffer *fb = pic->opaque; + mp_buffer_ref(fb); // initial reference for mpi + mpi = mp_image_new_external_ref(&new, fb, fb_ref, fb_unref, + fb_is_unique, NULL); + } else { + mpi = mp_image_pool_new_copy(ctx->non_dr1_pool, &new); + } + return mpi; +} + +#endif /* HAVE_AVUTIL_REFCOUNTING */ + +static int decode(struct sh_video *sh, struct demux_packet *packet, + int flags, double *reordered_pts, struct mp_image **out_image) { int got_picture = 0; int ret; @@ -559,8 +657,8 @@ static int decode(struct sh_video *sh, struct demux_packet *packet, void *data, avctx->skip_frame = ctx->skip_frame; av_init_packet(&pkt); - pkt.data = data; - pkt.size = len; + pkt.data = packet ? packet->buffer : NULL; + pkt.size = packet ? packet->len : 0; /* Some codecs (ZeroCodec, some cases of PNG) may want keyframe info * from demuxer. */ if (packet && packet->keyframe) @@ -585,63 +683,26 @@ static int decode(struct sh_video *sh, struct demux_packet *packet, void *data, if (init_vo(sh, pic) < 0) return -1; - struct mp_image *mpi = NULL; - if (ctx->do_hw_dr1 && pic->opaque) { - mpi = pic->opaque; // reordered frame - assert(mpi); - mpi = mp_image_new_ref(mpi); - } - - if (!mpi) { - struct mp_image new = {0}; - mp_image_set_size(&new, pic->width, pic->height); - mp_image_setfmt(&new, ctx->best_csp); - for (int i = 0; i < 4; i++) { - new.planes[i] = pic->data[i]; - new.stride[i] = pic->linesize[i]; - } - if (ctx->do_dr1 && pic->opaque) { - struct FrameBuffer *fb = pic->opaque; - mp_buffer_ref(fb); // initial reference for mpi - mpi = mp_image_new_external_ref(&new, fb, fb_ref, fb_unref, - fb_is_unique); - } else { - mpi = mp_image_pool_get(ctx->non_dr1_pool, new.imgfmt, - new.w, new.h); - mp_image_copy(mpi, &new); - } - } - + struct mp_image *mpi = image_from_decoder(sh); assert(mpi->planes[0]); mpi->colorspace = sh->colorspace; mpi->levels = sh->color_range; - mpi->qscale = pic->qscale_table; - mpi->qstride = pic->qstride; - mpi->pict_type = pic->pict_type; - mpi->qscale_type = pic->qscale_type; - mpi->fields = MP_IMGFIELD_ORDERED; - if (pic->interlaced_frame) - mpi->fields |= MP_IMGFIELD_INTERLACED; - if (pic->top_field_first) - mpi->fields |= MP_IMGFIELD_TOP_FIRST; - if (pic->repeat_pict == 1) - mpi->fields |= MP_IMGFIELD_REPEAT_FIRST; *out_image = mpi; return 1; } static struct mp_image *decode_with_fallback(struct sh_video *sh, - struct demux_packet *packet, void *data, - int len, int flags, double *reordered_pts) + struct demux_packet *packet, + int flags, double *reordered_pts) { vd_ffmpeg_ctx *ctx = sh->context; if (!ctx->avctx) return NULL; struct mp_image *mpi = NULL; - int res = decode(sh, packet, data, len, flags, reordered_pts, &mpi); + int res = decode(sh, packet, flags, reordered_pts, &mpi); if (res >= 0) return mpi; @@ -653,9 +714,10 @@ static struct mp_image *decode_with_fallback(struct sh_video *sh, "decoding, falling back to software decoding.\n"); const char *decoder = ctx->software_fallback_decoder; ctx->software_fallback_decoder = NULL; - if (init_avctx(sh, decoder, NULL)) { + init_avctx(sh, decoder, NULL); + if (ctx->avctx) { mpi = NULL; - decode(sh, packet, data, len, flags, reordered_pts, &mpi); + decode(sh, packet, flags, reordered_pts, &mpi); return mpi; } } |