mirror of
https://github.com/mpv-player/mpv
synced 2025-02-19 22:36:55 +00: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:
parent
01743f4ecd
commit
d5348a66dc
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user