mirror of
https://github.com/mpv-player/mpv
synced 2025-03-11 08:37:59 +00:00
hwdec: add VideoToolbox support
VDA is being deprecated in OS X 10.11 so this is needed to keep hwdec working. The code needs libavcodec support which was added recently (to FFmpeg git, libav doesn't support it). Signed-off-by: Stefano Pigozzi <stefano.pigozzi@gmail.com>
This commit is contained in:
parent
417e256c21
commit
31b5a211f4
@ -85,6 +85,7 @@ const struct m_opt_choice_alternatives mp_hwdec_names[] = {
|
||||
{"auto", HWDEC_AUTO},
|
||||
{"vdpau", HWDEC_VDPAU},
|
||||
{"vda", HWDEC_VDA},
|
||||
{"videotoolbox",HWDEC_VIDEOTOOLBOX},
|
||||
{"vaapi", HWDEC_VAAPI},
|
||||
{"vaapi-copy", HWDEC_VAAPI_COPY},
|
||||
{"dxva2-copy", HWDEC_DXVA2_COPY},
|
||||
|
@ -117,6 +117,7 @@ const struct m_sub_options vd_lavc_conf = {
|
||||
|
||||
const struct vd_lavc_hwdec mp_vd_lavc_vdpau;
|
||||
const struct vd_lavc_hwdec mp_vd_lavc_vda;
|
||||
const struct vd_lavc_hwdec mp_vd_lavc_videotoolbox;
|
||||
const struct vd_lavc_hwdec mp_vd_lavc_vaapi;
|
||||
const struct vd_lavc_hwdec mp_vd_lavc_vaapi_copy;
|
||||
const struct vd_lavc_hwdec mp_vd_lavc_dxva2_copy;
|
||||
@ -129,6 +130,9 @@ static const struct vd_lavc_hwdec *const hwdec_list[] = {
|
||||
#if HAVE_VDPAU_HWACCEL
|
||||
&mp_vd_lavc_vdpau,
|
||||
#endif
|
||||
#if HAVE_VIDEOTOOLBOX_HWACCEL
|
||||
&mp_vd_lavc_videotoolbox,
|
||||
#endif
|
||||
#if HAVE_VDA_HWACCEL
|
||||
&mp_vd_lavc_vda,
|
||||
#endif
|
||||
|
115
video/decode/videotoolbox.c
Normal file
115
video/decode/videotoolbox.c
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* This file is part of mpv.
|
||||
*
|
||||
* Copyright (c) 2015 Sebastien Zwickert
|
||||
*
|
||||
* mpv is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <libavcodec/version.h>
|
||||
#include <libavcodec/videotoolbox.h>
|
||||
|
||||
#include "common/av_common.h"
|
||||
#include "common/msg.h"
|
||||
#include "video/mp_image.h"
|
||||
#include "video/decode/lavc.h"
|
||||
#include "config.h"
|
||||
|
||||
|
||||
static int probe(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info,
|
||||
const char *decoder)
|
||||
{
|
||||
hwdec_request_api(info, "videotoolbox");
|
||||
if (!info || !info->hwctx)
|
||||
return HWDEC_ERR_NO_CTX;
|
||||
switch (mp_codec_to_av_codec_id(decoder)) {
|
||||
case AV_CODEC_ID_H264:
|
||||
case AV_CODEC_ID_H263:
|
||||
case AV_CODEC_ID_MPEG1VIDEO:
|
||||
case AV_CODEC_ID_MPEG2VIDEO:
|
||||
case AV_CODEC_ID_MPEG4:
|
||||
break;
|
||||
default:
|
||||
return HWDEC_ERR_NO_CODEC;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init(struct lavc_ctx *ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct videotoolbox_error {
|
||||
int code;
|
||||
char *reason;
|
||||
};
|
||||
|
||||
static const struct videotoolbox_error videotoolbox_errors[] = {
|
||||
{ AVERROR(ENOSYS),
|
||||
"Hardware doesn't support accelerated decoding for this stream"
|
||||
" or Videotoolbox decoder is not available at the moment (another"
|
||||
" application is using it)."
|
||||
},
|
||||
{ AVERROR(EINVAL),
|
||||
"Invalid configuration provided to VTDecompressionSessionCreate" },
|
||||
{ AVERROR_INVALIDDATA,
|
||||
"Generic error returned by the decoder layer. The cause can be Videotoolbox"
|
||||
" found errors in the bitstream." },
|
||||
{ 0, NULL },
|
||||
};
|
||||
|
||||
static void print_videotoolbox_error(struct mp_log *log, int lev, char *message,
|
||||
int error_code)
|
||||
{
|
||||
for (int n = 0; videotoolbox_errors[n].code < 0; n++)
|
||||
if (videotoolbox_errors[n].code == error_code) {
|
||||
mp_msg(log, lev, "%s: %s (%d)\n",
|
||||
message, videotoolbox_errors[n].reason, error_code);
|
||||
return;
|
||||
}
|
||||
|
||||
mp_msg(log, lev, "%s: %d\n", message, error_code);
|
||||
}
|
||||
|
||||
static int init_decoder(struct lavc_ctx *ctx, int fmt, int w, int h)
|
||||
{
|
||||
av_videotoolbox_default_free(ctx->avctx);
|
||||
|
||||
AVVideotoolboxContext *vtctx = av_videotoolbox_alloc_context();
|
||||
vtctx->cv_pix_fmt_type = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
|
||||
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);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uninit(struct lavc_ctx *ctx)
|
||||
{
|
||||
if (ctx->avctx)
|
||||
av_videotoolbox_default_free(ctx->avctx);
|
||||
}
|
||||
|
||||
const struct vd_lavc_hwdec mp_vd_lavc_videotoolbox = {
|
||||
.type = HWDEC_VIDEOTOOLBOX,
|
||||
.image_format = IMGFMT_VIDEOTOOLBOX,
|
||||
.probe = probe,
|
||||
.init = init,
|
||||
.uninit = uninit,
|
||||
.init_decoder = init_decoder,
|
||||
};
|
@ -120,6 +120,9 @@ static const struct {
|
||||
{IMGFMT_VDPAU, AV_PIX_FMT_VDPAU},
|
||||
#if HAVE_VDA_HWACCEL
|
||||
{IMGFMT_VDA, AV_PIX_FMT_VDA},
|
||||
#endif
|
||||
#if HAVE_VIDEOTOOLBOX_HWACCEL
|
||||
{IMGFMT_VIDEOTOOLBOX, AV_PIX_FMT_VIDEOTOOLBOX},
|
||||
#endif
|
||||
{IMGFMT_VAAPI, AV_PIX_FMT_VAAPI_VLD},
|
||||
{IMGFMT_DXVA2, AV_PIX_FMT_DXVA2_VLD},
|
||||
|
@ -11,6 +11,7 @@ enum hwdec_type {
|
||||
HWDEC_NONE = 0,
|
||||
HWDEC_VDPAU = 1,
|
||||
HWDEC_VDA = 2,
|
||||
HWDEC_VIDEOTOOLBOX = 3,
|
||||
HWDEC_VAAPI = 4,
|
||||
HWDEC_VAAPI_COPY = 5,
|
||||
HWDEC_DXVA2_COPY = 6,
|
||||
|
@ -36,6 +36,7 @@ static const struct mp_imgfmt_entry mp_imgfmt_list[] = {
|
||||
{"vdpau_output", IMGFMT_VDPAU_OUTPUT},
|
||||
// FFmpeg names have an annoying "_vld" suffix
|
||||
{"vda", IMGFMT_VDA},
|
||||
{"videotoolbox", IMGFMT_VIDEOTOOLBOX},
|
||||
{"vaapi", IMGFMT_VAAPI},
|
||||
// names below this are not preferred over the FFmpeg names
|
||||
// the "none" entry makes mp_imgfmt_to_name prefer FFmpeg names
|
||||
|
@ -203,6 +203,7 @@ enum mp_imgfmt {
|
||||
IMGFMT_VDPAU, // VdpVideoSurface
|
||||
IMGFMT_VDPAU_OUTPUT, // VdpOutputSurface
|
||||
IMGFMT_VDA,
|
||||
IMGFMT_VIDEOTOOLBOX,
|
||||
IMGFMT_VAAPI,
|
||||
IMGFMT_DXVA2, // IDirect3DSurface9 (NV12)
|
||||
IMGFMT_MMAL, // MMAL_BUFFER_HEADER_T
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
extern const struct gl_hwdec_driver gl_hwdec_vaglx;
|
||||
extern const struct gl_hwdec_driver gl_hwdec_vda;
|
||||
extern const struct gl_hwdec_driver gl_hwdec_videotoolbox;
|
||||
extern const struct gl_hwdec_driver gl_hwdec_vdpau;
|
||||
extern const struct gl_hwdec_driver gl_hwdec_dxva2;
|
||||
|
||||
@ -46,6 +47,9 @@ static const struct gl_hwdec_driver *const mpgl_hwdec_drivers[] = {
|
||||
#endif
|
||||
#if HAVE_DXVA2_HWACCEL
|
||||
&gl_hwdec_dxva2,
|
||||
#endif
|
||||
#if HAVE_VIDEOTOOLBOX_GL
|
||||
&gl_hwdec_videotoolbox,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
@ -85,7 +85,7 @@ static struct mp_image *download_image(struct mp_hwdec_ctx *ctx,
|
||||
struct mp_image *hw_image,
|
||||
struct mp_image_pool *swpool)
|
||||
{
|
||||
if (hw_image->imgfmt != IMGFMT_VDA)
|
||||
if (hw_image->imgfmt != IMGFMT_VDA || hw_image->imgfmt != IMGFMT_VIDEOTOOLBOX)
|
||||
return NULL;
|
||||
|
||||
CVPixelBufferRef pbuf = (CVPixelBufferRef)hw_image->planes[3];
|
||||
@ -129,26 +129,19 @@ static bool check_hwdec(struct gl_hwdec *hw)
|
||||
return true;
|
||||
}
|
||||
|
||||
static int create(struct gl_hwdec *hw)
|
||||
static int create_common(struct gl_hwdec *hw, struct vda_format *format)
|
||||
{
|
||||
struct priv *p = talloc_zero(hw, struct priv);
|
||||
|
||||
hw->priv = p;
|
||||
hw->gl_texture_target = GL_TEXTURE_RECTANGLE;
|
||||
|
||||
#if HAVE_VDA_DEFAULT_INIT2
|
||||
struct vda_format *f = vda_get_gl_format_from_imgfmt(IMGFMT_NV12);
|
||||
#else
|
||||
struct vda_format *f = vda_get_gl_format_from_imgfmt(IMGFMT_UYVY);
|
||||
#endif
|
||||
|
||||
hw->converted_imgfmt = f->imgfmt;
|
||||
hw->converted_imgfmt = format->imgfmt;
|
||||
|
||||
if (!check_hwdec(hw))
|
||||
return -1;
|
||||
|
||||
hw->hwctx = &p->hwctx;
|
||||
hw->hwctx->type = HWDEC_VDA;
|
||||
hw->hwctx->download_image = download_image;
|
||||
|
||||
GL *gl = hw->gl;
|
||||
@ -157,6 +150,36 @@ static int create(struct gl_hwdec *hw)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if HAVE_VDA_GL
|
||||
static int create_vda(struct gl_hwdec *hw)
|
||||
{
|
||||
#if HAVE_VDA_DEFAULT_INIT2
|
||||
struct vda_format *f = vda_get_gl_format_from_imgfmt(IMGFMT_NV12);
|
||||
#else
|
||||
struct vda_format *f = vda_get_gl_format_from_imgfmt(IMGFMT_UYVY);
|
||||
#endif
|
||||
if (create_common(hw, f))
|
||||
return -1;
|
||||
|
||||
hw->hwctx->type = HWDEC_VDA;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if HAVE_VIDEOTOOLBOX_GL
|
||||
static int create_videotoolbox(struct gl_hwdec *hw)
|
||||
{
|
||||
struct vda_format *f = vda_get_gl_format_from_imgfmt(IMGFMT_NV12);
|
||||
if (create_common(hw, f))
|
||||
return -1;
|
||||
|
||||
hw->hwctx->type = HWDEC_VIDEOTOOLBOX;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int reinit(struct gl_hwdec *hw, struct mp_image_params *params)
|
||||
{
|
||||
params->imgfmt = hw->driver->imgfmt;
|
||||
@ -219,11 +242,24 @@ static void destroy(struct gl_hwdec *hw)
|
||||
gl->DeleteTextures(MP_MAX_PLANES, p->gl_planes);
|
||||
}
|
||||
|
||||
#if HAVE_VDA_GL
|
||||
const struct gl_hwdec_driver gl_hwdec_vda = {
|
||||
.api_name = "vda",
|
||||
.imgfmt = IMGFMT_VDA,
|
||||
.create = create,
|
||||
.create = create_vda,
|
||||
.reinit = reinit,
|
||||
.map_image = map_image,
|
||||
.destroy = destroy,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if HAVE_VIDEOTOOLBOX_GL
|
||||
const struct gl_hwdec_driver gl_hwdec_videotoolbox = {
|
||||
.api_name = "videotoolbox",
|
||||
.imgfmt = IMGFMT_VIDEOTOOLBOX,
|
||||
.create = create_videotoolbox,
|
||||
.reinit = reinit,
|
||||
.map_image = map_image,
|
||||
.destroy = destroy,
|
||||
};
|
||||
#endif
|
||||
|
19
wscript
19
wscript
@ -727,6 +727,25 @@ hwaccel_features = [
|
||||
'desc': 'VDA with OpenGL',
|
||||
'deps': [ 'gl-cocoa', 'vda-hwaccel' ],
|
||||
'func': check_true
|
||||
}, {
|
||||
'name': '--videotoolbox-hwaccel',
|
||||
'desc': 'libavcodec videotoolbox hwaccel',
|
||||
'func': compose_checks(
|
||||
check_headers('VideoToolbox/VideoToolbox.h'),
|
||||
check_statement('libavcodec/videotoolbox.h',
|
||||
'av_videotoolbox_alloc_context()',
|
||||
framework='IOSurface',
|
||||
use='libav')),
|
||||
} , {
|
||||
'name': '--videotoolbox-gl',
|
||||
'desc': 'Videotoolbox with OpenGL',
|
||||
'deps': [ 'gl-cocoa', 'videotoolbox-hwaccel' ],
|
||||
'func': check_true
|
||||
} , {
|
||||
'name': 'videotoolbox-vda-gl',
|
||||
'desc': 'Videotoolbox or VDA with OpenGL',
|
||||
'deps': [ 'videotoolbox-gl', 'vda-gl' ],
|
||||
'func': check_true
|
||||
}, {
|
||||
'name': '--vdpau-hwaccel',
|
||||
'desc': 'libavcodec VDPAU hwaccel',
|
||||
|
@ -292,6 +292,7 @@ def build(ctx):
|
||||
( "video/decode/vaapi.c", "vaapi-hwaccel" ),
|
||||
( "video/decode/vd_lavc.c" ),
|
||||
( "video/decode/vda.c", "vda-hwaccel" ),
|
||||
( "video/decode/videotoolbox.c", "videotoolbox-hwaccel" ),
|
||||
( "video/decode/vdpau.c", "vdpau-hwaccel" ),
|
||||
( "video/decode/vdpau_old.c", "vdpau-old-hwaccel" ),
|
||||
( "video/filter/vf.c" ),
|
||||
@ -335,7 +336,7 @@ def build(ctx):
|
||||
( "video/out/gl_hwdec.c", "gl" ),
|
||||
( "video/out/gl_hwdec_dxva2.c", "gl-win32" ),
|
||||
( "video/out/gl_hwdec_vaglx.c", "vaapi-glx" ),
|
||||
( "video/out/gl_hwdec_vda.c", "vda-gl" ),
|
||||
( "video/out/gl_hwdec_vda.c", "videotoolbox-vda-gl" ),
|
||||
( "video/out/gl_hwdec_vdpau.c", "vdpau-gl-x11" ),
|
||||
( "video/out/gl_lcms.c", "gl" ),
|
||||
( "video/out/gl_osd.c", "gl" ),
|
||||
|
Loading…
Reference in New Issue
Block a user