From 588b2f48e5ade8cfb45370ab1dec8cbd109b5d7f Mon Sep 17 00:00:00 2001 From: Aman Gupta Date: Thu, 14 Jul 2016 11:14:22 -0700 Subject: videotoolbox: add --hwdec=videotoolbox-copy for h/w accelerated decoding with video filters --- DOCS/man/options.rst | 1 + options/options.c | 1 + video/decode/vd_lavc.c | 2 + video/decode/videotoolbox.c | 122 ++++++++++++++++++++++++++++++++++++++++---- video/hwdec.h | 1 + 5 files changed, 118 insertions(+), 9 deletions(-) diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index f8f3565ce5..9a251aeacd 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -586,6 +586,7 @@ Video :vaapi: requires ``--vo=opengl`` or ``--vo=vaapi`` (Linux only) :vaapi-copy: copies video back into system RAM (Linux with Intel GPUs only) :videotoolbox: requires ``--vo=opengl`` (OS X 10.8 and up only) + :videotoolbox-copy: copies video back into system RAM (OS X 10.8 and up only) :dxva2: requires ``--vo=opengl:backend=angle`` or ``--vo=opengl:backend=dxinterop`` (Windows only) :dxva2-copy: copies video back to system RAM (Windows only) diff --git a/options/options.c b/options/options.c index e58eea1bc9..89ee24a829 100644 --- a/options/options.c +++ b/options/options.c @@ -85,6 +85,7 @@ const struct m_opt_choice_alternatives mp_hwdec_names[] = { {"auto-copy", HWDEC_AUTO_COPY}, {"vdpau", HWDEC_VDPAU}, {"videotoolbox",HWDEC_VIDEOTOOLBOX}, + {"videotoolbox-copy",HWDEC_VIDEOTOOLBOX_COPY}, {"vaapi", HWDEC_VAAPI}, {"vaapi-copy", HWDEC_VAAPI_COPY}, {"dxva2", HWDEC_DXVA2}, diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c index 5962f883cd..eb63e58e92 100644 --- a/video/decode/vd_lavc.c +++ b/video/decode/vd_lavc.c @@ -126,6 +126,7 @@ const struct m_sub_options vd_lavc_conf = { 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_videotoolbox_copy; 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; @@ -158,6 +159,7 @@ static const struct vd_lavc_hwdec *const hwdec_list[] = { #endif #if HAVE_VIDEOTOOLBOX_HWACCEL &mp_vd_lavc_videotoolbox, + &mp_vd_lavc_videotoolbox_copy, #endif #if HAVE_VAAPI_HWACCEL &mp_vd_lavc_vaapi, diff --git a/video/decode/videotoolbox.c b/video/decode/videotoolbox.c index c69d5e89e6..355017ffd4 100644 --- a/video/decode/videotoolbox.c +++ b/video/decode/videotoolbox.c @@ -24,14 +24,16 @@ #include "common/msg.h" #include "video/mp_image.h" #include "video/decode/lavc.h" +#include "video/mp_image_pool.h" #include "config.h" +struct priv { + struct mp_image_pool *sw_pool; +}; -static int probe(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec, +static int probe_copy(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec, const char *codec) { - if (!hwdec_devices_load(ctx->hwdec_devs, HWDEC_VIDEOTOOLBOX)) - return HWDEC_ERR_NO_CTX; switch (mp_codec_to_av_codec_id(codec)) { case AV_CODEC_ID_H264: case AV_CODEC_ID_H263: @@ -45,8 +47,19 @@ static int probe(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec, return 0; } +static int probe(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec, + const char *codec) +{ + if (!hwdec_devices_load(ctx->hwdec_devs, HWDEC_VIDEOTOOLBOX)) + return HWDEC_ERR_NO_CTX; + return probe_copy(ctx, hwdec, codec); +} + static int init(struct lavc_ctx *ctx) { + struct priv *p = talloc_ptrtype(NULL, p); + p->sw_pool = talloc_steal(p, mp_image_pool_new(17)); + ctx->hwdec_priv = p; return 0; } @@ -82,15 +95,10 @@ static void print_videotoolbox_error(struct mp_log *log, int lev, char *message, mp_msg(log, lev, "%s: %d\n", message, error_code); } -static int init_decoder(struct lavc_ctx *ctx, int w, int h) +static int init_decoder_common(struct lavc_ctx *ctx, int w, int h, AVVideotoolboxContext *vtctx) { av_videotoolbox_default_free(ctx->avctx); - AVVideotoolboxContext *vtctx = av_videotoolbox_alloc_context(); - - struct mp_vt_ctx *vt = hwdec_devices_load(ctx->hwdec_devs, HWDEC_VIDEOTOOLBOX); - vtctx->cv_pix_fmt_type = vt->get_vt_fmt(vt); - int err = av_videotoolbox_default_init2(ctx->avctx, vtctx); if (err < 0) { print_videotoolbox_error(ctx->log, MSGL_ERR, "failed to init videotoolbox decoder", err); @@ -100,10 +108,94 @@ static int init_decoder(struct lavc_ctx *ctx, int w, int h) return 0; } +static int init_decoder(struct lavc_ctx *ctx, int w, int h) +{ + AVVideotoolboxContext *vtctx = av_videotoolbox_alloc_context(); + struct mp_vt_ctx *vt = hwdec_devices_load(ctx->hwdec_devs, HWDEC_VIDEOTOOLBOX); + vtctx->cv_pix_fmt_type = vt->get_vt_fmt(vt); + + return init_decoder_common(ctx, w, h, vtctx); +} + +static int init_decoder_copy(struct lavc_ctx *ctx, int w, int h) +{ + return init_decoder_common(ctx, w, h, NULL); +} + static void uninit(struct lavc_ctx *ctx) { if (ctx->avctx) av_videotoolbox_default_free(ctx->avctx); + + struct priv *p = ctx->hwdec_priv; + if (!p) + return; + + talloc_free(p->sw_pool); + p->sw_pool = NULL; + + talloc_free(p); + ctx->hwdec_priv = NULL; +} + +static struct mp_image *copy_image(struct lavc_ctx *ctx, struct mp_image *hw_image) +{ + if (hw_image->imgfmt != IMGFMT_VIDEOTOOLBOX) + return hw_image; + + struct priv *p = ctx->hwdec_priv; + struct mp_image *image = NULL; + CVPixelBufferRef pbuf = (CVPixelBufferRef)hw_image->planes[3]; + CVPixelBufferLockBaseAddress(pbuf, kCVPixelBufferLock_ReadOnly); + size_t width = CVPixelBufferGetWidth(pbuf); + size_t height = CVPixelBufferGetHeight(pbuf); + uint32_t cvpixfmt = CVPixelBufferGetPixelFormatType(pbuf); + int pixfmt = 0; + switch (cvpixfmt) { + case kCVPixelFormatType_420YpCbCr8Planar: + pixfmt = IMGFMT_420P; + break; + case kCVPixelFormatType_422YpCbCr8: + pixfmt = IMGFMT_UYVY; + break; + case kCVPixelFormatType_32BGRA: + pixfmt = IMGFMT_RGB0; + break; + case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange: + pixfmt = IMGFMT_NV12; + break; + default: + goto unlock; + } + + struct mp_image img = {0}; + mp_image_setfmt(&img, pixfmt); + mp_image_set_size(&img, width, height); + + if (CVPixelBufferIsPlanar(pbuf)) { + int planes = CVPixelBufferGetPlaneCount(pbuf); + for (int i = 0; i < planes; i++) { + img.planes[i] = CVPixelBufferGetBaseAddressOfPlane(pbuf, i); + img.stride[i] = CVPixelBufferGetBytesPerRowOfPlane(pbuf, i); + } + } else { + img.planes[0] = CVPixelBufferGetBaseAddress(pbuf); + img.stride[0] = CVPixelBufferGetBytesPerRow(pbuf); + } + + mp_image_copy_attributes(&img, hw_image); + + image = mp_image_pool_new_copy(p->sw_pool, &img); + +unlock: + CVPixelBufferUnlockBaseAddress(pbuf, kCVPixelBufferLock_ReadOnly); + + if (image) { + talloc_free(hw_image); + return image; + } else { + return hw_image; + } } static struct mp_image *process_image(struct lavc_ctx *ctx, struct mp_image *img) @@ -124,3 +216,15 @@ const struct vd_lavc_hwdec mp_vd_lavc_videotoolbox = { .init_decoder = init_decoder, .process_image = process_image, }; + +const struct vd_lavc_hwdec mp_vd_lavc_videotoolbox_copy = { + .type = HWDEC_VIDEOTOOLBOX_COPY, + .copying = true, + .image_format = IMGFMT_VIDEOTOOLBOX, + .probe = probe_copy, + .init = init, + .uninit = uninit, + .init_decoder = init_decoder_copy, + .process_image = copy_image, + .delay_queue = HWDEC_DELAY_QUEUE_COUNT, +}; diff --git a/video/hwdec.h b/video/hwdec.h index 5d563c983b..4d99076f16 100644 --- a/video/hwdec.h +++ b/video/hwdec.h @@ -12,6 +12,7 @@ enum hwdec_type { HWDEC_AUTO_COPY, HWDEC_VDPAU, HWDEC_VIDEOTOOLBOX, + HWDEC_VIDEOTOOLBOX_COPY, HWDEC_VAAPI, HWDEC_VAAPI_COPY, HWDEC_DXVA2, -- cgit v1.2.3