[vlc-commits] dxva: split the directx related parts from the pool/va parts
Steve Lhomme
git at videolan.org
Thu Jun 22 17:26:26 CEST 2017
vlc | branch: master | Steve Lhomme <robux4 at videolabs.io> | 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 <jb at videolan.org>
> 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 <geal at videolan.org>
+ * Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
+ * Steve Lhomme <robux4 at gmail.com>
+ *
+ * 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 <geal at videolan.org>
+ * Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
+ * Steve Lhomme <robux4 at gmail.com>
+ *
+ * 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 <geal at videolan.org>
+ * Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
+ * Steve Lhomme <robux4 at gmail.com>
+ *
+ * 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 */
More information about the vlc-commits
mailing list