From d5348a66dc7dcc22d4e6b905caa7e92468f25b94 Mon Sep 17 00:00:00 2001 From: Kevin Mitchell Date: Mon, 15 Feb 2016 11:15:17 -0800 Subject: 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 --- video/decode/dxva2.c | 65 +++++++++++++++++++++++++++------------------------- video/dxva2.c | 56 ++++++++------------------------------------ video/dxva2.h | 6 ++--- 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 -- cgit v1.2.3