summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Mitchell <kevmitch@gmail.com>2016-02-15 11:15:17 -0800
committerKevin Mitchell <kevmitch@gmail.com>2016-02-16 12:36:56 -0800
commitd5348a66dc7dcc22d4e6b905caa7e92468f25b94 (patch)
tree6ef8beb28f367b8c6fa252966b02656d016a03b3
parent01743f4ecd42b2974072d31604c2e91941488dd8 (diff)
downloadmpv-d5348a66dc7dcc22d4e6b905caa7e92468f25b94.tar.bz2
mpv-d5348a66dc7dcc22d4e6b905caa7e92468f25b94.tar.xz
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
-rw-r--r--video/decode/dxva2.c65
-rw-r--r--video/dxva2.c56
-rw-r--r--video/dxva2.h6
3 files changed, 46 insertions, 81 deletions
diff --git a/video/decode/dxva2.c b/video/decode/dxva2.c
index a11c916a5c..76f95b0db6 100644
--- a/video/decode/dxva2.c
+++ b/video/decode/dxva2.c
@@ -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->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->num_surfaces = hwdec_get_max_refs(s) + ADDITIONAL_SURFACES;
- hr = IDirectXVideoDecoderService_CreateVideoDecoder(ctx->decoder_service, &device_guid,
- &desc, &decoder->config, surfaces,
- num_surfaces, &decoder->decoder);
+ 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,
+ 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;
diff --git a/video/dxva2.c b/video/dxva2.c
index ee8ff00431..8e31a45b57 100644
--- a/video/dxva2.c
+++ b/video/dxva2.c
@@ -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);
-}
diff --git a/video/dxva2.h b/video/dxva2.h
index 66bcddcdb8..b52767da44 100644
--- a/video/dxva2.h
+++ b/video/dxva2.h
@@ -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