From 71b09be04056d9a505f32c71375ebc327d842ae4 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 9 Mar 2013 20:21:12 +0100 Subject: video: prepare for libavcodec refcounting Some minor refactoring and moving code around. There should be no functional changes. --- video/decode/vd_lavc.c | 86 +++++++++++++++++++++++--------------------------- video/mp_image.c | 53 ++++++++++++++++++++++--------- video/mp_image.h | 7 +++- 3 files changed, 84 insertions(+), 62 deletions(-) (limited to 'video') diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c index 4922f57387..874dd12694 100644 --- a/video/decode/vd_lavc.c +++ b/video/decode/vd_lavc.c @@ -61,8 +61,7 @@ static int 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); @@ -274,17 +273,18 @@ 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 (lavc_codec->capabilities & CODEC_CAP_DR1) { + ctx->do_dr1 = true; + avctx->get_buffer = mp_codec_get_buffer; + avctx->release_buffer = mp_codec_release_buffer; + } } if (avctx->thread_count == 0) { @@ -525,6 +525,12 @@ 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; +} + static void fb_ref(void *b) { mp_buffer_ref(b); @@ -540,6 +546,31 @@ static bool fb_is_unique(void *b) return mp_buffer_is_unique(b); } +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; +} + 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) @@ -585,48 +616,11 @@ 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; diff --git a/video/mp_image.c b/video/mp_image.c index 78becf28ea..57124eab11 100644 --- a/video/mp_image.c +++ b/video/mp_image.c @@ -29,10 +29,11 @@ #include "talloc.h" -#include "video/img_format.h" -#include "video/mp_image.h" -#include "video/sws_utils.h" -#include "video/memcpy_pic.h" +#include "img_format.h" +#include "mp_image.h" +#include "sws_utils.h" +#include "memcpy_pic.h" +#include "fmt-conversion.h" struct m_refcount { void *arg; @@ -41,7 +42,7 @@ struct m_refcount { // External refcounted object (such as libavcodec DR buffers). This assumes // that the actual data is managed by the external object, not by // m_refcount. The .ext_* calls use that external object's refcount - // primitives. It usually doesn't make sense to set both .free and .ext_*. + // primitives. void (*ext_ref)(void *arg); void (*ext_unref)(void *arg); bool (*ext_is_unique)(void *arg); @@ -236,23 +237,18 @@ struct mp_image *mp_image_new_ref(struct mp_image *img) struct mp_image *mp_image_new_custom_ref(struct mp_image *img, void *free_arg, void (*free)(void *arg)) { - struct mp_image *new = talloc_ptrtype(NULL, new); - talloc_set_destructor(new, mp_image_destructor); - *new = *img; - - new->refcount = m_refcount_new(); - new->refcount->free = free; - new->refcount->arg = free_arg; - return new; + return mp_image_new_external_ref(img, free_arg, NULL, NULL, NULL, free); } // Return a reference counted reference to img. ref/unref/is_unique are used to // connect to an external refcounting API. It is assumed that the new object -// has an initial reference to that external API. +// has an initial reference to that external API. If free is given, that is +// called after the last unref. All function pointers are optional. struct mp_image *mp_image_new_external_ref(struct mp_image *img, void *arg, void (*ref)(void *arg), void (*unref)(void *arg), - bool (*is_unique)(void *arg)) + bool (*is_unique)(void *arg), + void (*free)(void *arg)) { struct mp_image *new = talloc_ptrtype(NULL, new); talloc_set_destructor(new, mp_image_destructor); @@ -262,6 +258,7 @@ struct mp_image *mp_image_new_external_ref(struct mp_image *img, void *arg, new->refcount->ext_ref = ref; new->refcount->ext_unref = unref; new->refcount->ext_is_unique = is_unique; + new->refcount->free = free; new->refcount->arg = arg; return new; } @@ -436,3 +433,29 @@ void mp_image_set_colorspace_details(struct mp_image *image, image->levels = MP_CSP_LEVELS_PC; } } + +// Copy properties and data of the AVFrame into the mp_image, without taking +// care of memory management issues. +void mp_image_copy_fields_from_av_frame(struct mp_image *dst, + struct AVFrame *src) +{ + mp_image_setfmt(dst, pixfmt2imgfmt(src->format)); + mp_image_set_size(dst, src->width, src->height); + + for (int i = 0; i < 4; i++) { + dst->planes[i] = src->data[i]; + dst->stride[i] = src->linesize[i]; + } + + dst->qscale = src->qscale_table; + dst->qstride = src->qstride; + dst->pict_type = src->pict_type; + dst->qscale_type = src->qscale_type; + dst->fields = MP_IMGFIELD_ORDERED; + if (src->interlaced_frame) + dst->fields |= MP_IMGFIELD_INTERLACED; + if (src->top_field_first) + dst->fields |= MP_IMGFIELD_TOP_FIRST; + if (src->repeat_pict == 1) + dst->fields |= MP_IMGFIELD_REPEAT_FIRST; +} diff --git a/video/mp_image.h b/video/mp_image.h index 6ba9393671..3fe2429445 100644 --- a/video/mp_image.h +++ b/video/mp_image.h @@ -117,7 +117,8 @@ struct mp_image *mp_image_new_custom_ref(struct mp_image *img, void *arg, struct mp_image *mp_image_new_external_ref(struct mp_image *img, void *arg, void (*ref)(void *arg), void (*unref)(void *arg), - bool (*is_unique)(void *arg)); + bool (*is_unique)(void *arg), + void (*free)(void *arg)); enum mp_csp mp_image_csp(struct mp_image *img); enum mp_csp_levels mp_image_levels(struct mp_image *img); @@ -126,6 +127,10 @@ struct mp_csp_details; void mp_image_set_colorspace_details(struct mp_image *image, struct mp_csp_details *csp); +struct AVFrame; +void mp_image_copy_fields_from_av_frame(struct mp_image *dst, + struct AVFrame *src); + // align must be a power of two (align >= 1), v >= 0 #define MP_ALIGN_UP(v, align) FFALIGN(v, align) #define MP_ALIGN_DOWN(v, align) ((v) & ~((align) - 1)) -- cgit v1.2.3