vd_lavc: use avcodec_fill_hw_frames_parameters() API

This removes the need for codec- and API-specific knowledge in the
libavcodec hardware acceleration API user. For mpv, this removes the
need for vd_lavc_hwdec.pixfmt_map and a few other things. (For now, we
still keep the "old" parts for the sake of supporting older Libav, and
FFgarbage.)
This commit is contained in:
wm4 2017-10-27 17:22:32 +02:00
parent 4701c5ba4f
commit f36d152eb7
3 changed files with 118 additions and 2 deletions

View File

@ -80,6 +80,18 @@ bool d3d11_check_decoding(ID3D11Device *dev)
return !FAILED(hr) && (supported & D3D11_BIND_DECODER);
}
#if HAVE_AVCODEC_HW_FRAMES_PARAMS
void d3d_hwframes_refine(struct lavc_ctx *ctx, AVBufferRef *hw_frames_ctx)
{
AVHWFramesContext *fctx = (void *)hw_frames_ctx->data;
if (fctx->format == AV_PIX_FMT_D3D11) {
AVD3D11VAFramesContext *hwctx = fctx->hwctx;
hwctx->BindFlags |= D3D11_BIND_SHADER_RESOURCE;
}
}
#else
void d3d_hwframes_refine(struct lavc_ctx *ctx, AVBufferRef *hw_frames_ctx)
{
AVHWFramesContext *fctx = (void *)hw_frames_ctx->data;
@ -119,6 +131,7 @@ void d3d_hwframes_refine(struct lavc_ctx *ctx, AVBufferRef *hw_frames_ctx)
hwctx->BindFlags |= D3D11_BIND_SHADER_RESOURCE;
}
}
#endif
AVBufferRef *d3d11_wrap_device_ref(ID3D11Device *device)
{

View File

@ -730,6 +730,101 @@ static void update_image_params(struct dec_video *vd, AVFrame *frame,
params->stereo_in = vd->codec->stereo_mode;
}
#if HAVE_AVCODEC_HW_FRAMES_PARAMS
static int init_generic_hwaccel(struct dec_video *vd, enum AVPixelFormat hw_fmt)
{
struct lavc_ctx *ctx = vd->priv;
struct vd_lavc_hwdec *hwdec = ctx->hwdec;
AVBufferRef *new_frames_ctx = NULL;
if (!ctx->hwdec_dev)
goto error;
if (!hwdec->set_hwframes)
return 0;
if (!ctx->hwdec_dev->av_device_ref) {
MP_ERR(ctx, "Missing device context.\n");
goto error;
}
if (avcodec_get_hw_frames_parameters(ctx->avctx,
ctx->hwdec_dev->av_device_ref, hw_fmt, &new_frames_ctx) < 0)
{
MP_VERBOSE(ctx, "Hardware decoding of this stream is unsupported?\n");
goto error;
}
AVHWFramesContext *new_fctx = (void *)new_frames_ctx->data;
if (hwdec->image_format == IMGFMT_VIDEOTOOLBOX)
new_fctx->sw_format = imgfmt2pixfmt(vd->opts->videotoolbox_format);
// The video output might not support all formats.
// Note that supported_formats==NULL means any are accepted.
int *render_formats = ctx->hwdec_dev->supported_formats;
if (render_formats) {
int mp_format = pixfmt2imgfmt(new_fctx->sw_format);
bool found = false;
for (int n = 0; render_formats[n]; n++) {
if (render_formats[n] == mp_format) {
found = true;
break;
}
}
if (!found) {
MP_WARN(ctx, "Surface format %s not supported for direct rendering.\n",
mp_imgfmt_to_name(mp_format));
goto error;
}
}
// 1 surface is already included by libavcodec. The field is 0 if the
// hwaccel supports dynamic surface allocation.
if (new_fctx->initial_pool_size)
new_fctx->initial_pool_size += HWDEC_EXTRA_SURFACES - 1;
if (ctx->hwdec->hwframes_refine)
ctx->hwdec->hwframes_refine(ctx, new_frames_ctx);
// We might be able to reuse a previously allocated frame pool.
if (ctx->cached_hw_frames_ctx) {
AVHWFramesContext *old_fctx = (void *)ctx->cached_hw_frames_ctx->data;
if (new_fctx->format != old_fctx->format ||
new_fctx->sw_format != old_fctx->sw_format ||
new_fctx->width != old_fctx->width ||
new_fctx->height != old_fctx->height ||
new_fctx->initial_pool_size != old_fctx->initial_pool_size)
av_buffer_unref(&ctx->cached_hw_frames_ctx);
}
if (!ctx->cached_hw_frames_ctx) {
if (av_hwframe_ctx_init(new_frames_ctx) < 0) {
MP_ERR(ctx, "Failed to allocate hw frames.\n");
goto error;
}
ctx->cached_hw_frames_ctx = new_frames_ctx;
new_frames_ctx = NULL;
}
ctx->avctx->hw_frames_ctx = av_buffer_ref(ctx->cached_hw_frames_ctx);
if (!ctx->avctx->hw_frames_ctx)
goto error;
av_buffer_unref(&new_frames_ctx);
return 0;
error:
av_buffer_unref(&new_frames_ctx);
av_buffer_unref(&ctx->cached_hw_frames_ctx);
return -1;
}
#else
// Allocate and set AVCodecContext.hw_frames_ctx. Also caches them on redundant
// calls (useful because seeks issue get_format, which clears hw_frames_ctx).
// device_ctx: reference to an AVHWDeviceContext
@ -788,7 +883,7 @@ int hwdec_setup_hw_frames_ctx(struct lavc_ctx *ctx, AVBufferRef *device_ctx,
return ctx->avctx->hw_frames_ctx ? 0 : -1;
}
static int init_generic_hwaccel(struct dec_video *vd)
static int init_generic_hwaccel(struct dec_video *vd, enum AVPixelFormat hw_fmt)
{
struct lavc_ctx *ctx = vd->priv;
struct vd_lavc_hwdec *hwdec = ctx->hwdec;
@ -861,6 +956,8 @@ static int init_generic_hwaccel(struct dec_video *vd)
av_sw_format, pool_size);
}
#endif
static enum AVPixelFormat get_format_hwdec(struct AVCodecContext *avctx,
const enum AVPixelFormat *fmt)
{
@ -885,7 +982,7 @@ static enum AVPixelFormat get_format_hwdec(struct AVCodecContext *avctx,
for (int i = 0; fmt[i] != AV_PIX_FMT_NONE; i++) {
if (ctx->hwdec->image_format == pixfmt2imgfmt(fmt[i])) {
if (ctx->hwdec->generic_hwaccel) {
if (init_generic_hwaccel(vd) < 0)
if (init_generic_hwaccel(vd, fmt[i]) < 0)
break;
select = fmt[i];
break;

View File

@ -508,6 +508,12 @@ FFmpeg/Libav libraries. You need at least {0}. Aborting.".format(libav_versions_
'func': check_statement('libavutil/spherical.h',
'AV_SPHERICAL_EQUIRECTANGULAR',
use='libav'),
}, {
'name': 'avcodec-hw-frames-params',
'desc': 'libavcodec avcodec_get_hw_frames_parameters()',
'func': check_statement('libavcodec/avcodec.h',
'avcodec_get_hw_frames_parameters(0,0,0,0)',
use='libav'),
},
]