0
0
mirror of https://github.com/mpv-player/mpv.git synced 2024-09-20 12:02:23 +02:00

dxva2: another attempt at using mp_image pool

Apparently, some drivers require you to allocate all of the decoder d3d surfaces
at once. This commit changes the strategy from allocating surfaces as needed via
mp_image_pool_set_allocator, to allocating all the surfaces in one call to
IDirectXVideoDecoderService_CreateSurface and adding them to the pool with
mp_image_pool_add.

fixes #2822
This commit is contained in:
Kevin Mitchell 2016-02-15 11:15:17 -08:00
parent 01743f4ecd
commit d5348a66dc
3 changed files with 45 additions and 80 deletions

View File

@ -102,6 +102,8 @@ static const dxva2_mode dxva2_modes[] = {
struct dxva2_decoder {
DXVA2_ConfigPictureDecode config;
IDirectXVideoDecoder *decoder;
LPDIRECT3DSURFACE9 *surfaces;
int num_surfaces;
struct mp_image_pool *pool;
};
@ -398,6 +400,11 @@ static void dxva2_destroy_decoder(void *arg)
struct dxva2_decoder *decoder = arg;
if (decoder->decoder)
IDirectXVideoDecoder_Release(decoder->decoder);
if (decoder->surfaces) {
for (int i = 0; i < decoder->num_surfaces; i++)
IDirect3DSurface9_Release(decoder->surfaces[i]);
}
}
static int dxva2_create_decoder(struct lavc_ctx *s, int w, int h,
@ -413,9 +420,7 @@ static int dxva2_create_decoder(struct lavc_ctx *s, int w, int h,
DXVA2_VideoDesc desc = { 0 };
HRESULT hr;
struct dxva2_decoder *decoder;
int surface_alignment, num_surfaces;
struct mp_image **imgs;
LPDIRECT3DSURFACE9 *surfaces;
int surface_alignment;
int ret = -1;
hr = IDirectXVideoDecoderService_GetDecoderDeviceGuids(ctx->decoder_service, &guid_count, &guid_list);
@ -528,44 +533,42 @@ static int dxva2_create_decoder(struct lavc_ctx *s, int w, int h,
else
surface_alignment = 16;
num_surfaces = hwdec_get_max_refs(s) + ADDITIONAL_SURFACES;
decoder->num_surfaces = hwdec_get_max_refs(s) + ADDITIONAL_SURFACES;
decoder->pool = talloc_steal(decoder, mp_image_pool_new(num_surfaces));
dxva2_pool_set_allocator(decoder->pool, ctx->decoder_service,
target_format, surface_alignment);
// Preallocate images from the pool so the surfaces can be used to create
// the decoder and passed to ffmpeg in the dxva_ctx. The mp_images
// themselves will be freed (returned to the pool) along with the temporary
// talloc context on exit from this function.
imgs = talloc_array(tmp, struct mp_image *, num_surfaces);
surfaces = talloc_array(decoder->pool, LPDIRECT3DSURFACE9, num_surfaces);
for (i = 0; i < num_surfaces; i++) {
imgs[i] = talloc_steal(
imgs, mp_image_pool_get(decoder->pool, IMGFMT_DXVA2, w, h));
surfaces[i] = d3d9_surface_in_mp_image(imgs[i]);
decoder->surfaces = talloc_array(decoder, LPDIRECT3DSURFACE9, decoder->num_surfaces);
hr = IDirectXVideoDecoderService_CreateSurface(
ctx->decoder_service,
FFALIGN(w, surface_alignment), FFALIGN(h, surface_alignment),
decoder->num_surfaces - 1, target_format, D3DPOOL_DEFAULT, 0,
DXVA2_VideoDecoderRenderTarget, decoder->surfaces, NULL);
if (FAILED(hr)) {
MP_ERR(ctx, "Failed to create %d video surfaces\n",
decoder->num_surfaces);
goto fail;
}
hr = IDirectXVideoDecoderService_CreateVideoDecoder(ctx->decoder_service, &device_guid,
&desc, &decoder->config, surfaces,
num_surfaces, &decoder->decoder);
hr = IDirectXVideoDecoderService_CreateVideoDecoder(
ctx->decoder_service, &device_guid, &desc, &decoder->config,
decoder->surfaces, decoder->num_surfaces, &decoder->decoder);
if (FAILED(hr)) {
MP_ERR(ctx, "Failed to create DXVA2 video decoder\n");
goto fail;
}
// According to ffmpeg_dxva2.c, the surfaces must not outlive the
// IDirectXVideoDecoder they were used to create. This adds a reference for
// each one of them, which is released on final mp_image destruction.
for (i = 0; i < num_surfaces; i++)
dxva2_img_ref_decoder(imgs[i], decoder->decoder);
decoder->pool = talloc_steal(decoder, mp_image_pool_new(decoder->num_surfaces));
for (i = 0; i < decoder->num_surfaces; i++) {
struct mp_image *img = dxva2_new_ref(decoder->decoder, decoder->surfaces[i], w, h);
if (!img) {
MP_ERR(ctx, "Failed to create DXVA2 image\n");
goto fail;
}
mp_image_pool_add(decoder->pool, img);
}
// Pass required information on to ffmpeg.
dxva_ctx->cfg = &decoder->config;
dxva_ctx->decoder = decoder->decoder;
dxva_ctx->surface = surfaces;
dxva_ctx->surface_count = num_surfaces;
dxva_ctx->surface = decoder->surfaces;
dxva_ctx->surface_count = decoder->num_surfaces;
if (IsEqualGUID(&device_guid, &DXVADDI_Intel_ModeH264_E))
dxva_ctx->workaround |= FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO;

View File

@ -37,17 +37,7 @@ LPDIRECT3DSURFACE9 d3d9_surface_in_mp_image(struct mp_image *mpi)
(LPDIRECT3DSURFACE9)mpi->planes[3] : NULL;
}
void dxva2_img_ref_decoder(struct mp_image *mpi, IDirectXVideoDecoder *decoder)
{
assert(mpi->imgfmt == IMGFMT_DXVA2);
struct dxva2_surface *surface = (struct dxva2_surface *)mpi->planes[0];
if (surface->decoder)
IDirectXVideoDecoder_Release(surface->decoder);
surface->decoder = decoder;
IDirectXVideoDecoder_AddRef(surface->decoder);
}
static void dxva2_pool_release_img(void *arg)
static void dxva2_release_img(void *arg)
{
struct dxva2_surface *surface = arg;
if (surface->surface)
@ -65,15 +55,10 @@ static void dxva2_pool_release_img(void *arg)
talloc_free(surface);
}
struct pool_alloc_ctx {
IDirectXVideoDecoderService *decoder_service;
D3DFORMAT target_format;
int surface_alignment;
};
static struct mp_image *dxva2_pool_alloc_img(void *arg, int fmt, int w, int h)
struct mp_image *dxva2_new_ref(IDirectXVideoDecoder *decoder,
LPDIRECT3DSURFACE9 d3d9_surface, int w, int h)
{
if (fmt != IMGFMT_DXVA2)
if (!decoder || !d3d9_surface)
return NULL;
struct dxva2_surface *surface = talloc_zero(NULL, struct dxva2_surface);
@ -84,39 +69,18 @@ static struct mp_image *dxva2_pool_alloc_img(void *arg, int fmt, int w, int h)
if (!surface->d3dlib || !surface->dxva2lib)
goto fail;
struct pool_alloc_ctx *alloc_ctx = arg;
HRESULT hr = IDirectXVideoDecoderService_CreateSurface(
alloc_ctx->decoder_service,
FFALIGN(w, alloc_ctx->surface_alignment),
FFALIGN(h, alloc_ctx->surface_alignment),
0, alloc_ctx->target_format, D3DPOOL_DEFAULT, 0,
DXVA2_VideoDecoderRenderTarget,
&surface->surface, NULL);
if (FAILED(hr))
goto fail;
surface->surface = d3d9_surface;
IDirect3DSurface9_AddRef(surface->surface);
surface->decoder = decoder;
IDirectXVideoDecoder_AddRef(surface->decoder);
struct mp_image mpi = {0};
mp_image_setfmt(&mpi, IMGFMT_DXVA2);
mp_image_set_size(&mpi, w, h);
mpi.planes[0] = (void *)surface;
mpi.planes[3] = (void *)surface->surface;
return mp_image_new_custom_ref(&mpi, surface, dxva2_pool_release_img);
return mp_image_new_custom_ref(&mpi, surface, dxva2_release_img);
fail:
dxva2_pool_release_img(surface);
dxva2_release_img(surface);
return NULL;
}
void dxva2_pool_set_allocator(struct mp_image_pool *pool,
IDirectXVideoDecoderService *decoder_service,
D3DFORMAT target_format, int surface_alignment)
{
struct pool_alloc_ctx *alloc_ctx = talloc_ptrtype(pool, alloc_ctx);
*alloc_ctx = (struct pool_alloc_ctx){
decoder_service = decoder_service,
target_format = target_format,
surface_alignment = surface_alignment
};
mp_image_pool_set_allocator(pool, dxva2_pool_alloc_img, alloc_ctx);
mp_image_pool_set_lru(pool);
}

View File

@ -25,10 +25,8 @@ struct mp_image;
struct mp_image_pool;
LPDIRECT3DSURFACE9 d3d9_surface_in_mp_image(struct mp_image *mpi);
void dxva2_img_ref_decoder(struct mp_image *mpi, IDirectXVideoDecoder *decoder);
void dxva2_pool_set_allocator(struct mp_image_pool *pool,
IDirectXVideoDecoderService *decoder_service,
D3DFORMAT target_format, int surface_alignment);
struct mp_image *dxva2_new_ref(IDirectXVideoDecoder *decoder,
LPDIRECT3DSURFACE9 d3d9_surface, int w, int h);
#endif