vlc | branch: master | Steve Lhomme <[email protected]> | Fri Jun 2 13:49:45 2017 +0200| [f7d5f497bb847f23178846cec12b6fdd0e85efd0] | committer: Jean-Baptiste Kempf
dxva: split the directx related parts from the pool/va parts Signed-off-by: Jean-Baptiste Kempf <[email protected]> > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=f7d5f497bb847f23178846cec12b6fdd0e85efd0 --- modules/codec/Makefile.am | 2 + modules/codec/avcodec/d3d11va.c | 69 +++++----- modules/codec/avcodec/directx_va.c | 153 +-------------------- modules/codec/avcodec/directx_va.h | 50 +------ modules/codec/avcodec/dxva2.c | 56 ++++---- modules/codec/avcodec/va_surface.c | 198 ++++++++++++++++++++++++++++ modules/codec/avcodec/va_surface.h | 40 ++++++ modules/codec/avcodec/va_surface_internal.h | 88 +++++++++++++ 8 files changed, 399 insertions(+), 257 deletions(-) diff --git a/modules/codec/Makefile.am b/modules/codec/Makefile.am index 27e0270fa3..c3bb6d207a 100644 --- a/modules/codec/Makefile.am +++ b/modules/codec/Makefile.am @@ -404,6 +404,7 @@ endif libdxva2_plugin_la_SOURCES = \ codec/avcodec/dxva2.c codec/avcodec/directx_va.c codec/avcodec/directx_va.h \ + codec/avcodec/va_surface.c codec/avcodec/va_surface.h codec/avcodec/va_surface_internal.h \ packetizer/h264_nal.c packetizer/h264_nal.h \ packetizer/hevc_nal.c packetizer/hevc_nal.h \ video_chroma/d3d9_fmt.h @@ -414,6 +415,7 @@ endif libd3d11va_plugin_la_SOURCES = \ codec/avcodec/d3d11va.c codec/avcodec/directx_va.c codec/avcodec/directx_va.h \ + codec/avcodec/va_surface.c codec/avcodec/va_surface.h codec/avcodec/va_surface_internal.h \ video_chroma/d3d11_fmt.h video_chroma/dxgi_fmt.c video_chroma/dxgi_fmt.h \ packetizer/h264_nal.c packetizer/h264_nal.h \ packetizer/hevc_nal.c packetizer/hevc_nal.h diff --git a/modules/codec/avcodec/d3d11va.c b/modules/codec/avcodec/d3d11va.c index 909fc01927..5389584bc2 100644 --- a/modules/codec/avcodec/d3d11va.c +++ b/modules/codec/avcodec/d3d11va.c @@ -165,8 +165,8 @@ void SetupAVCodecContext(vlc_va_t *va) sys->hw.video_context = sys->d3dvidctx; sys->hw.decoder = dx_sys->decoder; sys->hw.cfg = &sys->cfg; - sys->hw.surface_count = dx_sys->surface_count; - sys->hw.surface = dx_sys->hw_surface; + sys->hw.surface_count = dx_sys->va_pool.surface_count; + sys->hw.surface = dx_sys->va_pool.hw_surface; sys->hw.context_mutex = sys->context_mutex; if (IsEqualGUID(&dx_sys->input, &DXVA_Intel_H264_NoFGT_ClearVideo)) @@ -178,7 +178,7 @@ static int Extract(vlc_va_t *va, picture_t *output, uint8_t *data) VLC_UNUSED(va); VLC_UNUSED(data); struct va_pic_context *pic_ctx = (struct va_pic_context*)output->context; if (!va->sys->b_extern_pool) - directx_va_AddRef(pic_ctx->va_surface); + va_surface_AddRef(pic_ctx->va_surface); assert(data == (void*)pic_ctx->picsys.decoder); return VLC_SUCCESS; } @@ -205,7 +205,7 @@ static void d3d11_pic_context_destroy(struct picture_context_t *opaque) { struct va_pic_context *pic_ctx = (struct va_pic_context*)opaque; if (pic_ctx->va_surface) - directx_va_Release(pic_ctx->va_surface); + va_surface_Release(pic_ctx->va_surface); ReleasePictureSys(&pic_ctx->picsys); free(pic_ctx); } @@ -295,7 +295,7 @@ static int Get(vlc_va_t *va, picture_t *pic, uint8_t **data) #endif { ID3D11ShaderResourceView *resourceView[D3D11_MAX_SHADER_VIEW]; - vlc_va_surface_t *va_surface = directx_va_Get(va, &va->sys->dx_sys); + vlc_va_surface_t *va_surface = va_pool_Get(va, &va->sys->dx_sys.va_pool); if (unlikely(va_surface==NULL)) return VLC_EGENERIC; @@ -318,7 +318,7 @@ static int Get(vlc_va_t *va, picture_t *pic, uint8_t **data) ID3D11Resource_Release(p_resource); if (unlikely(pic_ctx==NULL)) { - directx_va_Release(va_surface); + va_surface_Release(va_surface); return VLC_ENOMEM; } pic->context = &pic_ctx->s; @@ -360,7 +360,7 @@ static void ReleasePic(void *opaque, uint8_t *data) (void)data; picture_t *pic = opaque; struct va_pic_context *pic_ctx = (struct va_pic_context*)pic->context; - directx_va_Release(pic_ctx->va_surface); + va_surface_Release(pic_ctx->va_surface); picture_Release(pic); } @@ -383,14 +383,14 @@ static int Open(vlc_va_t *va, AVCodecContext *ctx, enum PixelFormat pix_fmt, dx_sys = &sys->dx_sys; - dx_sys->pf_check_device = CheckDevice; - dx_sys->pf_create_device = D3dCreateDevice; - dx_sys->pf_destroy_device = D3dDestroyDevice; - dx_sys->pf_create_video_service = DxCreateVideoService; - dx_sys->pf_destroy_video_service = DxDestroyVideoService; - dx_sys->pf_create_decoder_surfaces = DxCreateDecoderSurfaces; - dx_sys->pf_destroy_surfaces = DxDestroySurfaces; - dx_sys->pf_setup_avcodec_ctx = SetupAVCodecContext; + dx_sys->va_pool.pf_check_device = CheckDevice; + dx_sys->va_pool.pf_create_device = D3dCreateDevice; + dx_sys->va_pool.pf_destroy_device = D3dDestroyDevice; + dx_sys->va_pool.pf_create_video_service = DxCreateVideoService; + dx_sys->va_pool.pf_destroy_video_service = DxDestroyVideoService; + dx_sys->va_pool.pf_create_decoder_surfaces = DxCreateDecoderSurfaces; + dx_sys->va_pool.pf_destroy_surfaces = DxDestroySurfaces; + dx_sys->va_pool.pf_setup_avcodec_ctx = SetupAVCodecContext; dx_sys->pf_get_input_list = DxGetInputList; dx_sys->pf_setup_output = DxSetupOutput; dx_sys->psz_decoder_dll = TEXT("D3D11.DLL"); @@ -803,7 +803,7 @@ static int DxCreateDecoderSurfaces(vlc_va_t *va, int codec_id, for (surface_idx = 0; surface_idx < surface_count; surface_idx++) { picture_t *pic = decoder_NewPicture( (decoder_t*) va->obj.parent ); sys->extern_pics[surface_idx] = pic; - dx_sys->hw_surface[surface_idx] = NULL; + dx_sys->va_pool.hw_surface[surface_idx] = NULL; if (pic==NULL) { msg_Warn(va, "not enough decoder pictures %d out of %d", surface_idx, surface_count); @@ -846,17 +846,17 @@ static int DxCreateDecoderSurfaces(vlc_va_t *va, int codec_id, AllocateShaderView(VLC_OBJECT(va), dx_sys->d3ddev, textureFmt, pic->p_sys->texture, pic->p_sys->slice_index, pic->p_sys->resourceView); - dx_sys->hw_surface[surface_idx] = pic->p_sys->decoder; + dx_sys->va_pool.hw_surface[surface_idx] = pic->p_sys->decoder; } if (!sys->b_extern_pool) { for (size_t i = 0; i < surface_idx; ++i) { - if (dx_sys->hw_surface[i]) + if (dx_sys->va_pool.hw_surface[i]) { - ID3D11VideoDecoderOutputView_Release(dx_sys->hw_surface[i]); - dx_sys->hw_surface[i] = NULL; + ID3D11VideoDecoderOutputView_Release(dx_sys->va_pool.hw_surface[i]); + dx_sys->va_pool.hw_surface[i] = NULL; } if (sys->extern_pics[i]) { @@ -875,8 +875,8 @@ static int DxCreateDecoderSurfaces(vlc_va_t *va, int codec_id, { D3D11_TEXTURE2D_DESC texDesc; ZeroMemory(&texDesc, sizeof(texDesc)); - texDesc.Width = dx_sys->surface_width; - texDesc.Height = dx_sys->surface_height; + texDesc.Width = dx_sys->va_pool.surface_width; + texDesc.Height = dx_sys->va_pool.surface_height; texDesc.MipLevels = 1; texDesc.Format = sys->render; texDesc.SampleDesc.Count = 1; @@ -896,17 +896,17 @@ static int DxCreateDecoderSurfaces(vlc_va_t *va, int codec_id, return VLC_EGENERIC; } - unsigned i; - for (i = 0; i < surface_count; i++) { - sys->extern_pics[i] = NULL; - viewDesc.Texture2D.ArraySlice = i; + unsigned surface_idx; + for (surface_idx = 0; surface_idx < surface_count; surface_idx++) { + sys->extern_pics[surface_idx] = NULL; + viewDesc.Texture2D.ArraySlice = surface_idx; hr = ID3D11VideoDevice_CreateVideoDecoderOutputView( dx_sys->d3ddec, (ID3D11Resource*) p_texture, &viewDesc, - &dx_sys->hw_surface[i] ); + &dx_sys->va_pool.hw_surface[surface_idx] ); if (FAILED(hr)) { - msg_Err(va, "CreateVideoDecoderOutputView %d failed. (hr=0x%0lx)", i, hr); + msg_Err(va, "CreateVideoDecoderOutputView %d failed. (hr=0x%0lx)", surface_idx, hr); ID3D11Texture2D_Release(p_texture); return VLC_EGENERIC; } @@ -914,12 +914,13 @@ static int DxCreateDecoderSurfaces(vlc_va_t *va, int codec_id, if (texDesc.BindFlags & D3D11_BIND_SHADER_RESOURCE) { ID3D11Texture2D *textures[D3D11_MAX_SHADER_VIEW] = {p_texture, p_texture}; - AllocateShaderView(VLC_OBJECT(va), dx_sys->d3ddev, textureFmt, textures, i, &sys->resourceView[i * D3D11_MAX_SHADER_VIEW]); + AllocateShaderView(VLC_OBJECT(va), dx_sys->d3ddev, textureFmt, textures, surface_idx, + &sys->resourceView[surface_idx * D3D11_MAX_SHADER_VIEW]); } } } msg_Dbg(va, "ID3D11VideoDecoderOutputView succeed with %d surfaces (%dx%d)", - surface_count, dx_sys->surface_width, dx_sys->surface_height); + surface_count, dx_sys->va_pool.surface_width, dx_sys->va_pool.surface_height); D3D11_VIDEO_DECODER_DESC decoderDesc; ZeroMemory(&decoderDesc, sizeof(decoderDesc)); @@ -994,15 +995,15 @@ static int DxCreateDecoderSurfaces(vlc_va_t *va, int codec_id, static void DxDestroySurfaces(vlc_va_t *va) { directx_sys_t *dx_sys = &va->sys->dx_sys; - if (dx_sys->surface_count && !va->sys->b_extern_pool) { + if (dx_sys->va_pool.surface_count && !va->sys->b_extern_pool) { ID3D11Resource *p_texture; - ID3D11VideoDecoderOutputView_GetResource( dx_sys->hw_surface[0], &p_texture ); + ID3D11VideoDecoderOutputView_GetResource( dx_sys->va_pool.hw_surface[0], &p_texture ); ID3D11Resource_Release(p_texture); ID3D11Resource_Release(p_texture); } - for (unsigned i = 0; i < dx_sys->surface_count; i++) + for (unsigned i = 0; i < dx_sys->va_pool.surface_count; i++) { - ID3D11VideoDecoderOutputView_Release( dx_sys->hw_surface[i] ); + ID3D11VideoDecoderOutputView_Release( dx_sys->va_pool.hw_surface[i] ); for (int j = 0; j < D3D11_MAX_SHADER_VIEW; j++) { if (va->sys->resourceView[i*D3D11_MAX_SHADER_VIEW + j]) diff --git a/modules/codec/avcodec/directx_va.c b/modules/codec/avcodec/directx_va.c index f98a91e4cd..172044d8b7 100644 --- a/modules/codec/avcodec/directx_va.c +++ b/modules/codec/avcodec/directx_va.c @@ -262,7 +262,6 @@ static const directx_va_mode_t DXVA_MODES[] = { }; static int FindVideoServiceConversion(vlc_va_t *, directx_sys_t *, const es_format_t *fmt); -static void DestroyVideoDecoder(vlc_va_t *, directx_sys_t *); char *directx_va_GetDecoderName(const GUID *guid) { @@ -282,24 +281,8 @@ int directx_va_Setup(vlc_va_t *va, directx_sys_t *dx_sys, AVCodecContext *avctx) { int surface_alignment = 16; unsigned surface_count = 2; - unsigned i = dx_sys->surface_count; - int err = VLC_EGENERIC; - if (dx_sys->width == avctx->coded_width && dx_sys->height == avctx->coded_height - && dx_sys->decoder != NULL) - goto done; - - /* */ - DestroyVideoDecoder(va, dx_sys); - - avctx->hwaccel_context = NULL; - if (avctx->coded_width <= 0 || avctx->coded_height <= 0) - return VLC_EGENERIC; - - /* */ - msg_Dbg(va, "directx_va_Setup id %d %dx%d", dx_sys->codec_id, avctx->coded_width, avctx->coded_height); - - switch ( dx_sys->codec_id ) + switch ( dx_sys->va_pool.codec_id ) { case AV_CODEC_ID_MPEG2VIDEO: /* decoding MPEG-2 requires additional alignment on some Intel GPUs, @@ -323,120 +306,13 @@ int directx_va_Setup(vlc_va_t *va, directx_sys_t *dx_sys, AVCodecContext *avctx) if ( avctx->active_thread_type & FF_THREAD_FRAME ) surface_count += avctx->thread_count; - if (surface_count > MAX_SURFACE_COUNT) - return VLC_EGENERIC; - -#define ALIGN(x, y) (((x) + ((y) - 1)) & ~((y) - 1)) - dx_sys->width = avctx->coded_width; - dx_sys->height = avctx->coded_height; - dx_sys->surface_width = ALIGN(dx_sys->width, surface_alignment); - dx_sys->surface_height = ALIGN(dx_sys->height, surface_alignment); - - /* FIXME transmit a video_format_t by VaSetup directly */ - video_format_t fmt; - memset(&fmt, 0, sizeof(fmt)); - fmt.i_width = dx_sys->width; - fmt.i_height = dx_sys->height; - fmt.i_frame_rate = avctx->framerate.num; - fmt.i_frame_rate_base = avctx->framerate.den; - - if (dx_sys->pf_create_decoder_surfaces(va, dx_sys->codec_id, &fmt, surface_count)) - return VLC_EGENERIC; - - if (avctx->coded_width != dx_sys->surface_width || - avctx->coded_height != dx_sys->surface_height) - msg_Warn( va, "surface dimensions (%dx%d) differ from avcodec dimensions (%dx%d)", - dx_sys->surface_width, dx_sys->surface_height, - avctx->coded_width, avctx->coded_height); - - for (i = 0; i < surface_count; i++) { - vlc_va_surface_t *surface = malloc(sizeof(*surface)); - if (unlikely(surface==NULL)) - { - err = VLC_ENOMEM; - goto done; - } - atomic_init(&surface->refcount, 1); - dx_sys->surface[i] = surface; - } - - dx_sys->pf_setup_avcodec_ctx(va); - err = VLC_SUCCESS; - -done: - dx_sys->surface_count = i; - return err; -} - -void DestroyVideoDecoder(vlc_va_t *va, directx_sys_t *dx_sys) -{ - dx_sys->pf_destroy_surfaces(va); - - for (unsigned i = 0; i < dx_sys->surface_count; i++) - { - IUnknown_Release( dx_sys->hw_surface[i] ); - directx_va_Release(dx_sys->surface[i]); - } - - dx_sys->surface_count = 0; -} - -static vlc_va_surface_t *GetSurface(directx_sys_t *dx_sys) -{ - for (unsigned i = 0; i < dx_sys->surface_count; i++) { - vlc_va_surface_t *surface = dx_sys->surface[i]; - uintptr_t expected = 1; - - if (atomic_compare_exchange_strong(&surface->refcount, &expected, 2)) - { - /* TODO do a copy to allow releasing locally and keep forward alive atomic_fetch_sub(&surface->refs, 1);*/ - surface->decoderSurface = dx_sys->hw_surface[i]; - return surface; - } - } - return NULL; -} - -vlc_va_surface_t *directx_va_Get(vlc_va_t *va, directx_sys_t *dx_sys) -{ - /* Check the device */ - if (dx_sys->pf_check_device(va)!=VLC_SUCCESS) - return NULL; - - unsigned tries = (CLOCK_FREQ + VOUT_OUTMEM_SLEEP) / VOUT_OUTMEM_SLEEP; - vlc_va_surface_t *field; - - while ((field = GetSurface(dx_sys)) == NULL) - { - if (--tries == 0) - return NULL; - /* Pool empty. Wait for some time as in src/input/decoder.c. - * XXX: Both this and the core should use a semaphore or a CV. */ - msleep(VOUT_OUTMEM_SLEEP); - } - return field; -} - -void directx_va_AddRef(vlc_va_surface_t *surface) -{ - atomic_fetch_add(&surface->refcount, 1); -} - -void directx_va_Release(vlc_va_surface_t *surface) -{ - if (atomic_fetch_sub(&surface->refcount, 1) != 1) - return; - free(surface); + return va_pool_Setup(va, &dx_sys->va_pool, avctx, + surface_count, surface_alignment); } void directx_va_Close(vlc_va_t *va, directx_sys_t *dx_sys) { - DestroyVideoDecoder(va, dx_sys); - dx_sys->pf_destroy_video_service(va); - if (dx_sys->pf_destroy_device_manager) - dx_sys->pf_destroy_device_manager(va); - dx_sys->pf_destroy_device(va); - + va_pool_Close(va, &dx_sys->va_pool); if (dx_sys->hdecoder_dll) FreeLibrary(dx_sys->hdecoder_dll); } @@ -444,8 +320,6 @@ void directx_va_Close(vlc_va_t *va, directx_sys_t *dx_sys) int directx_va_Open(vlc_va_t *va, directx_sys_t *dx_sys, AVCodecContext *ctx, const es_format_t *fmt, bool b_dll) { - dx_sys->codec_id = ctx->codec_id; - if (b_dll) { /* Load dll*/ dx_sys->hdecoder_dll = LoadLibrary(dx_sys->psz_decoder_dll); @@ -456,23 +330,8 @@ int directx_va_Open(vlc_va_t *va, directx_sys_t *dx_sys, msg_Dbg(va, "DLLs loaded"); } - /* */ - if (dx_sys->pf_create_device(va)) { - msg_Err(va, "Failed to create DirectX device"); + if (va_pool_Open(va, &dx_sys->va_pool, ctx, fmt) != VLC_SUCCESS) goto error; - } - msg_Dbg(va, "CreateDevice succeed"); - - if (dx_sys->pf_create_device_manager && - dx_sys->pf_create_device_manager(va) != VLC_SUCCESS) { - msg_Err(va, "CreateDeviceManager failed"); - goto error; - } - - if (dx_sys->pf_create_video_service(va)) { - msg_Err(va, "CreateVideoService failed"); - goto error; - } /* */ if (FindVideoServiceConversion(va, dx_sys, fmt)) { @@ -545,7 +404,7 @@ static int FindVideoServiceConversion(vlc_va_t *va, directx_sys_t *dx_sys, const /* Try all supported mode by our priority */ const directx_va_mode_t *mode = DXVA_MODES; for (; mode->name; ++mode) { - if (!mode->codec || mode->codec != dx_sys->codec_id) + if (!mode->codec || mode->codec != dx_sys->va_pool.codec_id) continue; /* */ diff --git a/modules/codec/avcodec/directx_va.h b/modules/codec/avcodec/directx_va.h index d9e5bc15ce..43a40a1af8 100644 --- a/modules/codec/avcodec/directx_va.h +++ b/modules/codec/avcodec/directx_va.h @@ -42,11 +42,7 @@ #include <unknwn.h> #include <stdatomic.h> -/* */ -struct vlc_va_surface_t { - atomic_uintptr_t refcount; - D3D_DecoderSurface *decoderSurface; -}; +#include "va_surface_internal.h" typedef struct input_list_t { void (*pf_release)(struct input_list_t *); @@ -57,9 +53,7 @@ typedef struct input_list_t { #define MAX_SURFACE_COUNT (64) typedef struct { - int codec_id; - int width; - int height; + va_pool_t va_pool; /* DLL */ HINSTANCE hdecoder_dll; @@ -75,28 +69,6 @@ typedef struct /* Video decoder */ D3D_DecoderType *decoder; - /* */ - unsigned surface_count; - int surface_width; - int surface_height; - - vlc_va_surface_t *surface[MAX_SURFACE_COUNT]; - D3D_DecoderSurface *hw_surface[MAX_SURFACE_COUNT]; - - /** - * Check that the decoder device is still available - */ - int (*pf_check_device)(vlc_va_t *); - - int (*pf_create_device)(vlc_va_t *); - void (*pf_destroy_device)(vlc_va_t *); - - int (*pf_create_device_manager)(vlc_va_t *); - void (*pf_destroy_device_manager)(vlc_va_t *); - - int (*pf_create_video_service)(vlc_va_t *); - void (*pf_destroy_video_service)(vlc_va_t *); - /** * Read the list of possible input GUIDs */ @@ -107,29 +79,11 @@ typedef struct */ int (*pf_setup_output)(vlc_va_t *, const GUID *input, const video_format_t *fmt); - /** - * Create the DirectX surfaces in hw_surface and the decoder in decoder - */ - int (*pf_create_decoder_surfaces)(vlc_va_t *, int codec_id, - const video_format_t *fmt, - unsigned surface_count); - /** - * Destroy resources allocated with the surfaces and the associated decoder - */ - void (*pf_destroy_surfaces)(vlc_va_t *); - /** - * Set the avcodec hw context after the decoder is created - */ - void (*pf_setup_avcodec_ctx)(vlc_va_t *); - } directx_sys_t; int directx_va_Open(vlc_va_t *, directx_sys_t *, AVCodecContext *ctx, const es_format_t *fmt, bool b_dll); void directx_va_Close(vlc_va_t *, directx_sys_t *); int directx_va_Setup(vlc_va_t *, directx_sys_t *, AVCodecContext *avctx); -vlc_va_surface_t *directx_va_Get(vlc_va_t *, directx_sys_t *); -void directx_va_AddRef(vlc_va_surface_t *surface); -void directx_va_Release(vlc_va_surface_t *surface); char *directx_va_GetDecoderName(const GUID *guid); #endif /* AVCODEC_DIRECTX_VA_H */ diff --git a/modules/codec/avcodec/dxva2.c b/modules/codec/avcodec/dxva2.c index 61d35ea555..6b431a924a 100644 --- a/modules/codec/avcodec/dxva2.c +++ b/modules/codec/avcodec/dxva2.c @@ -167,8 +167,8 @@ void SetupAVCodecContext(vlc_va_t *va) sys->hw.decoder = dx_sys->decoder; sys->hw.cfg = &sys->cfg; - sys->hw.surface_count = dx_sys->surface_count; - sys->hw.surface = dx_sys->hw_surface; + sys->hw.surface_count = dx_sys->va_pool.surface_count; + sys->hw.surface = dx_sys->va_pool.hw_surface; if (IsEqualGUID(&dx_sys->input, &DXVA_Intel_H264_NoFGT_ClearVideo)) sys->hw.workaround |= FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO; @@ -178,7 +178,7 @@ static int Extract(vlc_va_t *va, picture_t *picture, uint8_t *data) { VLC_UNUSED(va); VLC_UNUSED(data); struct va_pic_context *pic_ctx = (struct va_pic_context*)picture->context; - directx_va_AddRef(pic_ctx->va_surface); + va_surface_AddRef(pic_ctx->va_surface); return VLC_SUCCESS; } @@ -204,7 +204,7 @@ static void d3d9_pic_context_destroy(struct picture_context_t *opaque) if (pic_ctx->va_surface) { ReleasePictureSys(&pic_ctx->picsys); - directx_va_Release(pic_ctx->va_surface); + va_surface_Release(pic_ctx->va_surface); free(pic_ctx); } } @@ -223,7 +223,7 @@ static struct picture_context_t *CreatePicContext(vlc_va_surface_t *va_surface) if (unlikely(pic_ctx==NULL)) return NULL; pic_ctx->va_surface = va_surface; - directx_va_AddRef(pic_ctx->va_surface); + va_surface_AddRef(pic_ctx->va_surface); pic_ctx->s.destroy = d3d9_pic_context_destroy; pic_ctx->s.copy = d3d9_pic_context_copy; pic_ctx->picsys.surface = va_surface->decoderSurface; @@ -233,11 +233,11 @@ static struct picture_context_t *CreatePicContext(vlc_va_surface_t *va_surface) static int Get(vlc_va_t *va, picture_t *pic, uint8_t **data) { - vlc_va_surface_t *va_surface = directx_va_Get(va, &va->sys->dx_sys); + vlc_va_surface_t *va_surface = va_pool_Get(va, &va->sys->dx_sys.va_pool); if (unlikely(va_surface==NULL)) return VLC_EGENERIC; pic->context = CreatePicContext(va_surface); - directx_va_Release(va_surface); + va_surface_Release(va_surface); if (unlikely(pic->context==NULL)) return VLC_EGENERIC; *data = (uint8_t*)va_surface->decoderSurface; @@ -278,7 +278,7 @@ static void ReleasePic(void *opaque, uint8_t *data) (void)data; picture_t *pic = opaque; struct va_pic_context *pic_ctx = (struct va_pic_context*)pic->context; - directx_va_Release(pic_ctx->va_surface); + va_surface_Release(pic_ctx->va_surface); picture_Release(pic); } @@ -304,16 +304,16 @@ static int Open(vlc_va_t *va, AVCodecContext *ctx, enum PixelFormat pix_fmt, dx_sys = &sys->dx_sys; - dx_sys->pf_check_device = CheckDevice; - dx_sys->pf_create_device = D3dCreateDevice; - dx_sys->pf_destroy_device = D3dDestroyDevice; - dx_sys->pf_create_device_manager = D3dCreateDeviceManager; - dx_sys->pf_destroy_device_manager = D3dDestroyDeviceManager; - dx_sys->pf_create_video_service = DxCreateVideoService; - dx_sys->pf_destroy_video_service = DxDestroyVideoService; - dx_sys->pf_create_decoder_surfaces = DxCreateVideoDecoder; - dx_sys->pf_destroy_surfaces = DxDestroyVideoDecoder; - dx_sys->pf_setup_avcodec_ctx = SetupAVCodecContext; + dx_sys->va_pool.pf_check_device = CheckDevice; + dx_sys->va_pool.pf_create_device = D3dCreateDevice; + dx_sys->va_pool.pf_destroy_device = D3dDestroyDevice; + dx_sys->va_pool.pf_create_device_manager = D3dCreateDeviceManager; + dx_sys->va_pool.pf_destroy_device_manager = D3dDestroyDeviceManager; + dx_sys->va_pool.pf_create_video_service = DxCreateVideoService; + dx_sys->va_pool.pf_destroy_video_service = DxDestroyVideoService; + dx_sys->va_pool.pf_create_decoder_surfaces = DxCreateVideoDecoder; + dx_sys->va_pool.pf_destroy_surfaces = DxDestroyVideoDecoder; + dx_sys->va_pool.pf_setup_avcodec_ctx = SetupAVCodecContext; dx_sys->pf_get_input_list = DxGetInputList; dx_sys->pf_setup_output = DxSetupOutput; dx_sys->psz_decoder_dll = TEXT("DXVA2.DLL"); @@ -654,26 +654,26 @@ static int DxCreateVideoDecoder(vlc_va_t *va, int codec_id, HRESULT hr; hr = IDirectXVideoDecoderService_CreateSurface(sys->d3ddec, - sys->surface_width, - sys->surface_height, + sys->va_pool.surface_width, + sys->va_pool.surface_height, surface_count - 1, p_sys->render, D3DPOOL_DEFAULT, 0, DXVA2_VideoDecoderRenderTarget, - sys->hw_surface, + sys->va_pool.hw_surface, NULL); if (FAILED(hr)) { msg_Err(va, "IDirectXVideoAccelerationService_CreateSurface %d failed (hr=0x%0lx)", surface_count - 1, hr); return VLC_EGENERIC; } msg_Dbg(va, "IDirectXVideoAccelerationService_CreateSurface succeed with %d surfaces (%dx%d)", - surface_count, sys->surface_width, sys->surface_height); + surface_count, sys->va_pool.surface_width, sys->va_pool.surface_height); IDirect3DSurface9 *tstCrash; hr = IDirectXVideoDecoderService_CreateSurface(sys->d3ddec, - sys->surface_width, - sys->surface_height, + sys->va_pool.surface_width, + sys->va_pool.surface_height, 0, p_sys->render, D3DPOOL_DEFAULT, @@ -684,7 +684,7 @@ static int DxCreateVideoDecoder(vlc_va_t *va, int codec_id, if (FAILED(hr)) { msg_Err(va, "extra buffer impossible, avoid a crash (hr=0x%0lx)", hr); for (unsigned i = 0; i < surface_count; i++) - IDirect3DSurface9_Release( sys->hw_surface[i] ); + IDirect3DSurface9_Release( sys->va_pool.hw_surface[i] ); return VLC_EGENERIC; } IDirect3DSurface9_Release(tstCrash); @@ -727,7 +727,7 @@ static int DxCreateVideoDecoder(vlc_va_t *va, int codec_id, &cfg_list))) { msg_Err(va, "IDirectXVideoDecoderService_GetDecoderConfigurations failed"); for (unsigned i = 0; i < surface_count; i++) - IDirect3DSurface9_Release( sys->hw_surface[i] ); + IDirect3DSurface9_Release( sys->va_pool.hw_surface[i] ); return VLC_EGENERIC; } msg_Dbg(va, "we got %d decoder configurations", cfg_count); @@ -769,12 +769,12 @@ static int DxCreateVideoDecoder(vlc_va_t *va, int codec_id, &sys->input, &dsc, &p_sys->cfg, - sys->hw_surface, + sys->va_pool.hw_surface, surface_count, &decoder))) { msg_Err(va, "IDirectXVideoDecoderService_CreateVideoDecoder failed"); for (unsigned i = 0; i < surface_count; i++) - IDirect3DSurface9_Release( sys->hw_surface[i] ); + IDirect3DSurface9_Release( sys->va_pool.hw_surface[i] ); return VLC_EGENERIC; } sys->decoder = decoder; diff --git a/modules/codec/avcodec/va_surface.c b/modules/codec/avcodec/va_surface.c new file mode 100644 index 0000000000..795f9690e0 --- /dev/null +++ b/modules/codec/avcodec/va_surface.c @@ -0,0 +1,198 @@ +/***************************************************************************** + * va_surface.c: libavcodec Generic Video Acceleration helpers + ***************************************************************************** + * Copyright (C) 2009 Geoffroy Couprie + * Copyright (C) 2009 Laurent Aimar + * Copyright (C) 2015 Steve Lhomme + * + * Authors: Geoffroy Couprie <[email protected]> + * Laurent Aimar <fenrir _AT_ videolan _DOT_ org> + * Steve Lhomme <[email protected]> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <assert.h> + +#include <vlc_common.h> +#include <vlc_codecs.h> +#include <vlc_codec.h> + + +#define D3D_DecoderSurface void +typedef struct vlc_va_surface_t vlc_va_surface_t; +#include "va_surface_internal.h" + +#include "avcodec.h" + +static void DestroyVideoDecoder(vlc_va_t *va, va_pool_t *va_pool) +{ + va_pool->pf_destroy_surfaces(va); + va_pool->surface_count = 0; +} + +/* */ +int va_pool_Setup(vlc_va_t *va, va_pool_t *va_pool, AVCodecContext *avctx, unsigned count, int alignment) +{ + int err = VLC_ENOMEM; + unsigned i = va_pool->surface_count; + + if (avctx->coded_width <= 0 || avctx->coded_height <= 0) + return VLC_EGENERIC; + + assert((alignment & (alignment - 1)) == 0); /* power of 2 */ +#define ALIGN(x, y) (((x) + ((y) - 1)) & ~((y) - 1)) + int surface_width = ALIGN(avctx->coded_width, alignment); + int surface_height = ALIGN(avctx->coded_height, alignment); + + if (avctx->coded_width != surface_width || avctx->coded_height != surface_height) + msg_Warn( va, "surface dimensions (%dx%d) differ from avcodec dimensions (%dx%d)", + surface_width, surface_height, + avctx->coded_width, avctx->coded_height); + + if (va_pool->surface_width == surface_width && va_pool->surface_height == surface_height) + { + err = VLC_SUCCESS; + goto done; + } + + /* */ + DestroyVideoDecoder(va, va_pool); + + /* */ + msg_Dbg(va, "va_pool_Setup id %d %dx%d count: %d", avctx->codec_id, avctx->coded_width, avctx->coded_height, count); + + if (count > MAX_SURFACE_COUNT) + return VLC_EGENERIC; + + /* FIXME transmit a video_format_t by VaSetup directly */ + video_format_t fmt; + memset(&fmt, 0, sizeof(fmt)); + fmt.i_width = surface_width; + fmt.i_height = surface_height; + fmt.i_frame_rate = avctx->framerate.num; + fmt.i_frame_rate_base = avctx->framerate.den; + + if (va_pool->pf_create_decoder_surfaces(va, avctx->codec_id, &fmt, count)) + return VLC_EGENERIC; + + for (i = 0; i < count; i++) { + vlc_va_surface_t *surface = malloc(sizeof(*surface)); + if (unlikely(surface==NULL)) + goto done; + atomic_init(&surface->refcount, 1); + va_pool->surface[i] = surface; + } + + va_pool->surface_width = surface_width; + va_pool->surface_height = surface_height; + + va_pool->pf_setup_avcodec_ctx(va); + err = VLC_SUCCESS; + +done: + va_pool->surface_count = i; + return err; +} + +static vlc_va_surface_t *GetSurface(va_pool_t *va_pool) +{ + for (unsigned i = 0; i < va_pool->surface_count; i++) { + vlc_va_surface_t *surface = va_pool->surface[i]; + uintptr_t expected = 1; + + if (atomic_compare_exchange_strong(&surface->refcount, &expected, 2)) + { + /* TODO do a copy to allow releasing locally and keep forward alive atomic_fetch_sub(&surface->refs, 1);*/ + surface->decoderSurface = va_pool->hw_surface[i]; + return surface; + } + } + return NULL; +} + +vlc_va_surface_t *va_pool_Get(vlc_va_t *va, va_pool_t *va_pool) +{ + /* Check the device */ + if (va_pool->pf_check_device(va)!=VLC_SUCCESS) + return NULL; + + unsigned tries = (CLOCK_FREQ + VOUT_OUTMEM_SLEEP) / VOUT_OUTMEM_SLEEP; + vlc_va_surface_t *field; + + while ((field = GetSurface(va_pool)) == NULL) + { + if (--tries == 0) + return NULL; + /* Pool empty. Wait for some time as in src/input/decoder.c. + * XXX: Both this and the core should use a semaphore or a CV. */ + msleep(VOUT_OUTMEM_SLEEP); + } + return field; +} + +void va_surface_AddRef(vlc_va_surface_t *surface) +{ + atomic_fetch_add(&surface->refcount, 1); +} + +void va_surface_Release(vlc_va_surface_t *surface) +{ + if (atomic_fetch_sub(&surface->refcount, 1) != 1) + return; + free(surface); +} + +void va_pool_Close(vlc_va_t *va, va_pool_t *va_pool) +{ + DestroyVideoDecoder(va, va_pool); + va_pool->pf_destroy_video_service(va); + if (va_pool->pf_destroy_device_manager) + va_pool->pf_destroy_device_manager(va); + va_pool->pf_destroy_device(va); +} + +int va_pool_Open(vlc_va_t *va, va_pool_t *va_pool, + AVCodecContext *ctx, const es_format_t *fmt) +{ + va_pool->codec_id = ctx->codec_id; + + /* */ + if (va_pool->pf_create_device(va)) { + msg_Err(va, "Failed to create device"); + goto error; + } + msg_Dbg(va, "CreateDevice succeed"); + + if (va_pool->pf_create_device_manager && + va_pool->pf_create_device_manager(va) != VLC_SUCCESS) { + msg_Err(va, "CreateDeviceManager failed"); + goto error; + } + + if (va_pool->pf_create_video_service(va)) { + msg_Err(va, "CreateVideoService failed"); + goto error; + } + + return VLC_SUCCESS; + +error: + return VLC_EGENERIC; +} + diff --git a/modules/codec/avcodec/va_surface.h b/modules/codec/avcodec/va_surface.h new file mode 100644 index 0000000000..ccd8602588 --- /dev/null +++ b/modules/codec/avcodec/va_surface.h @@ -0,0 +1,40 @@ +/***************************************************************************** + * directx_va.h: DirectX Generic Video Acceleration helpers + ***************************************************************************** + * Copyright (C) 2009 Geoffroy Couprie + * Copyright (C) 2009 Laurent Aimar + * Copyright (C) 2015 Steve Lhomme + * + * Authors: Geoffroy Couprie <[email protected]> + * Laurent Aimar <fenrir _AT_ videolan _DOT_ org> + * Steve Lhomme <[email protected]> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#ifndef AVCODEC_VA_SURFACE_H +#define AVCODEC_VA_SURFACE_H + +#include <vlc_common.h> + +#include <stdatomic.h> + +/* */ +struct vlc_va_surface_t { + atomic_uintptr_t refcount; + D3D_DecoderSurface *decoderSurface; +}; + +#endif /* AVCODEC_VA_SURFACE_H */ diff --git a/modules/codec/avcodec/va_surface_internal.h b/modules/codec/avcodec/va_surface_internal.h new file mode 100644 index 0000000000..0f41406df2 --- /dev/null +++ b/modules/codec/avcodec/va_surface_internal.h @@ -0,0 +1,88 @@ +/***************************************************************************** + * va_surface_internal.h: libavcodec Generic Video Acceleration helpers + ***************************************************************************** + * Copyright (C) 2009 Geoffroy Couprie + * Copyright (C) 2009 Laurent Aimar + * Copyright (C) 2015 Steve Lhomme + * + * Authors: Geoffroy Couprie <[email protected]> + * Laurent Aimar <fenrir _AT_ videolan _DOT_ org> + * Steve Lhomme <[email protected]> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#ifndef AVCODEC_VA_SURFACE_INTERNAL_H +#define AVCODEC_VA_SURFACE_INTERNAL_H + +#include "va_surface.h" + +#include <libavcodec/avcodec.h> +#include "va.h" + +#define MAX_SURFACE_COUNT (64) +typedef struct +{ + int codec_id; + int width; + int height; + + /* */ + unsigned surface_count; + int surface_width; + int surface_height; + + vlc_va_surface_t *surface[MAX_SURFACE_COUNT]; + D3D_DecoderSurface *hw_surface[MAX_SURFACE_COUNT]; + + /** + * Check that the decoder device is still available + */ + int (*pf_check_device)(vlc_va_t *); + + int (*pf_create_device)(vlc_va_t *); + void (*pf_destroy_device)(vlc_va_t *); + + int (*pf_create_device_manager)(vlc_va_t *); + void (*pf_destroy_device_manager)(vlc_va_t *); + + int (*pf_create_video_service)(vlc_va_t *); + void (*pf_destroy_video_service)(vlc_va_t *); + + /** + * Create the DirectX surfaces in hw_surface and the decoder in decoder + */ + int (*pf_create_decoder_surfaces)(vlc_va_t *, int codec_id, + const video_format_t *fmt, + unsigned surface_count); + /** + * Destroy resources allocated with the surfaces and the associated decoder + */ + void (*pf_destroy_surfaces)(vlc_va_t *); + /** + * Set the avcodec hw context after the decoder is created + */ + void (*pf_setup_avcodec_ctx)(vlc_va_t *); + +} va_pool_t; + +int va_pool_Open(vlc_va_t *, va_pool_t *, AVCodecContext *, const es_format_t *); +void va_pool_Close(vlc_va_t *va, va_pool_t *); +int va_pool_Setup(vlc_va_t *, va_pool_t *, AVCodecContext *, unsigned count, int alignment); +vlc_va_surface_t *va_pool_Get(vlc_va_t *, va_pool_t *); +void va_surface_AddRef(vlc_va_surface_t *surface); +void va_surface_Release(vlc_va_surface_t *surface); + +#endif /* AVCODEC_VA_SURFACE_INTERNAL_H */ _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
