From 514d8a7c9dfde2acc89ee4d19dd9db6b9db5b882 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 9 Mar 2013 20:50:06 +0100 Subject: video: make use of libavcodec refcounting Now lavc_dr1.c is not used anymore if libavcodec is recent enough. --- Makefile | 4 ++- configure | 13 +++++++++ video/decode/lavc.h | 10 ++++--- video/decode/vd_lavc.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++---- video/mp_image.c | 28 ++++++++++++++++++ video/mp_image.h | 1 + 6 files changed, 122 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 21c9f74bbb..3c445c771a 100644 --- a/Makefile +++ b/Makefile @@ -115,6 +115,9 @@ SOURCES-$(VDPAU) += video/out/vo_vdpau.c SOURCES-$(X11) += video/out/vo_x11.c video/out/x11_common.c SOURCES-$(XV) += video/out/vo_xv.c +ifeq ($(HAVE_AVUTIL_REFCOUNTING),no) + SOURCES-yes += video/decode/lavc_dr1.c +endif SOURCES = talloc.c \ audio/format.c \ @@ -230,7 +233,6 @@ SOURCES = talloc.c \ video/mp_image_pool.c \ video/sws_utils.c \ video/decode/dec_video.c \ - video/decode/lavc_dr1.c \ video/decode/vd.c \ video/decode/vd_lavc.c \ video/filter/vf.c \ diff --git a/configure b/configure index c674a55bf1..15a41ade7f 100755 --- a/configure +++ b/configure @@ -2713,6 +2713,17 @@ fi echores "$_avcodec_is_decoder_api" +echocheck "libavutil ref-counting API" +_avutil_has_refcounting=no +statement_check libavutil/frame.h 'av_frame_unref(NULL)' && _avutil_has_refcounting=yes +if test "$_avutil_has_refcounting" = yes ; then + def_avutil_has_refcounting='#define HAVE_AVUTIL_REFCOUNTING 1' +else + def_avutil_has_refcounting='#define HAVE_AVUTIL_REFCOUNTING 0' +fi +echores "$_avutil_has_refcounting" + + echocheck "libavfilter >= 3.17.0" if test "$libavfilter" = auto ; then libavfilter=no @@ -3046,6 +3057,7 @@ GL_X11 = $_gl_x11 GL_WAYLAND = $_gl_wayland HAVE_POSIX_SELECT = $_posix_select HAVE_SYS_MMAN_H = $_mman +HAVE_AVUTIL_REFCOUNTING = $_avutil_has_refcounting JACK = $_jack JOYSTICK = $_joystick JPEG = $_jpeg @@ -3212,6 +3224,7 @@ $def_zlib $def_avcodec_codec_desc_api $def_avcodec_is_decoder_api +$def_avutil_has_refcounting $def_libpostproc $def_libavdevice $def_libavfilter diff --git a/video/decode/lavc.h b/video/decode/lavc.h index d23c3e85f6..41701be1d6 100644 --- a/video/decode/lavc.h +++ b/video/decode/lavc.h @@ -5,6 +5,8 @@ #include +#include "config.h" + #include "demux/stheader.h" #include "video/mp_image.h" @@ -13,25 +15,25 @@ typedef struct ffmpeg_ctx { AVFrame *pic; struct hwdec *hwdec; enum PixelFormat pix_fmt; - int do_hw_dr1, do_dr1; + int do_hw_dr1; int vo_initialized; int best_csp; AVRational last_sample_aspect_ratio; enum AVDiscard skip_frame; const char *software_fallback_decoder; + + bool do_dr1; struct FramePool *dr1_buffer_pool; struct mp_image_pool *non_dr1_pool; } vd_ffmpeg_ctx; +// lavc_dr1.c int mp_codec_get_buffer(AVCodecContext *s, AVFrame *frame); void mp_codec_release_buffer(AVCodecContext *s, AVFrame *frame); - struct FrameBuffer; - void mp_buffer_ref(struct FrameBuffer *buffer); void mp_buffer_unref(struct FrameBuffer *buffer); bool mp_buffer_is_unique(struct FrameBuffer *buffer); - void mp_buffer_pool_free(struct FramePool **pool); #endif diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c index 874dd12694..9e334334cc 100644 --- a/video/decode/vd_lavc.c +++ b/video/decode/vd_lavc.c @@ -280,11 +280,15 @@ static int init_avctx(sh_video_t *sh, const char *decoder, struct hwdec *hwdec) SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD; } } 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) { @@ -373,7 +377,9 @@ static void uninit_avctx(sh_video_t *sh) av_freep(&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 +472,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 +489,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 +500,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; @@ -531,6 +577,23 @@ static void setup_refcounting_hw(AVCodecContext *avctx) 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); @@ -571,6 +634,8 @@ static struct mp_image *image_from_decoder(struct sh_video *sh) return mpi; } +#endif /* HAVE_AVUTIL_REFCOUNTING */ + 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) diff --git a/video/mp_image.c b/video/mp_image.c index 57124eab11..72da838822 100644 --- a/video/mp_image.c +++ b/video/mp_image.c @@ -459,3 +459,31 @@ void mp_image_copy_fields_from_av_frame(struct mp_image *dst, if (src->repeat_pict == 1) dst->fields |= MP_IMGFIELD_REPEAT_FIRST; } + +#if HAVE_AVUTIL_REFCOUNTING + +static void frame_free(void *p) +{ + AVFrame *frame = p; + av_frame_free(&frame); +} + +static bool frame_is_unique(void *p) +{ + AVFrame *frame = p; + return av_frame_is_writable(frame); +} + +// Create a new mp_image reference to av_frame. +struct mp_image *mp_image_from_av_frame(struct AVFrame *av_frame) +{ + AVFrame *new_ref = av_frame_clone(av_frame); + if (!new_ref) + abort(); // OOM + struct mp_image t = {0}; + mp_image_copy_fields_from_av_frame(&t, new_ref); + return mp_image_new_external_ref(&t, new_ref, NULL, NULL, frame_is_unique, + frame_free); +} + +#endif /* HAVE_AVUTIL_REFCOUNTING */ diff --git a/video/mp_image.h b/video/mp_image.h index 3fe2429445..85adac65f0 100644 --- a/video/mp_image.h +++ b/video/mp_image.h @@ -130,6 +130,7 @@ void mp_image_set_colorspace_details(struct mp_image *image, struct AVFrame; void mp_image_copy_fields_from_av_frame(struct mp_image *dst, struct AVFrame *src); +struct mp_image *mp_image_from_av_frame(struct AVFrame *av_frame); // align must be a power of two (align >= 1), v >= 0 #define MP_ALIGN_UP(v, align) FFALIGN(v, align) -- cgit v1.2.3