[vlc-devel] [PATCH] DXVA2: output an opaque pixel format with D3D9 surfaces internally (v2)
Jean-Baptiste Kempf
jb at videolan.org
Tue Apr 21 18:36:03 CEST 2015
On 20 Apr, Steve Lhomme wrote :
> include/vlc_fourcc.h | 3 +
> modules/codec/Makefile.am | 2 +-
> modules/codec/avcodec/dxva2.c | 438 +++++++++++++++++++++++++++--------
> modules/codec/avcodec/dxva2.h | 69 ++++++
> modules/codec/avcodec/video.c | 15 --
> modules/video_output/msw/direct3d9.c | 291 +++++++++++++----------
> src/misc/fourcc.c | 3 +
Please split this patch in 3: core, decoder, video output.
The core part looks OK.
> index 23f575a..6acfb92 100644
> --- a/modules/codec/avcodec/dxva2.c
> +++ b/modules/codec/avcodec/dxva2.c
> @@ -41,7 +41,8 @@
> #include <vlc_fourcc.h>
> #include <vlc_cpu.h>
> #include <vlc_plugin.h>
> -#include <vlc_codecs.h>
> +#include <vlc_codec.h>
> +#include <vlc_filter.h>
>
> #include <libavcodec/avcodec.h>
> # define DXVA2API_USE_BITFIELDS
> @@ -51,16 +52,25 @@
> #include "avcodec.h"
> #include "va.h"
> #include "../../video_chroma/copy.h"
> +#include "../../demux/asf/libasf_guid.h"
You should not need this, but vlc_codecs.h
> +static int OpenConverter( vlc_object_t * );
> +static void CloseConverter( vlc_object_t * );
Converter is usually a bad name, if I may say.
> + add_submodule()
> + set_description( N_("DXA9 to I420,YV12,NV12") )
This is hard to translate (aka, impossible).
> typedef struct {
> const char *name;
> - D3DFORMAT format;
> - vlc_fourcc_t codec;
> + D3DFORMAT format; /* D3D format */
> + vlc_fourcc_t fourcc; /* VLC fourcc */
> } d3d_format_t;
Usually, I'd prefer that you split renames in a different patch. :)
> @@ -329,7 +331,7 @@ struct vlc_va_sys_t
> /* Video service */
> IDirectXVideoDecoderService *vs;
> GUID input;
> - D3DFORMAT render;
> + const d3d_format_t *p_render;
By curiosity, what was missing in D3DFORMAT ?
This is a change important in the patch, and I am too stupid to see the
reason.
> - vlc_va_surface_t surface[VA_DXVA2_MAX_SURFACE_COUNT];
> + vlc_va_t *va;
> +
> + /* surfaces in the GPU user space */
> + picture_sys_t surface[VA_DXVA2_MAX_SURFACE_COUNT];
> LPDIRECT3DSURFACE9 hw_surface[VA_DXVA2_MAX_SURFACE_COUNT];
> +
> + picture_pool_setup_sys_t pool_cookie;
What is this pool_cookie?
> +static void CopySurface( picture_t *p_dst, picture_t *p_src )
> +{
> + picture_sys_t *p_src_sys = p_src->p_sys;
> + picture_sys_t *p_dst_sys = p_dst->p_sys;
> +
> + if (!p_dst_sys)
> + return;
> +
> + LPDIRECT3DSURFACE9 source = p_src_sys->surface;
> + LPDIRECT3DSURFACE9 output = p_dst_sys->surface;
> +
> + HRESULT hr = IDirect3DDevice9_StretchRect( p_src_sys->surface_device, source, NULL, output, NULL, D3DTEXF_NONE);
> + if (FAILED(hr)) {
> + //msg_Err( p_src_sys->p_va, "Failed to copy the hw surface to the decoder surface (hr=0x%0lx)", hr );
> + }
> +}
What is this function actually doing?
I'd love some comments/documentation on that.
> +void DestroySurface(picture_t *p_pic)
> +{
> + picture_sys_t *p_pic_sys = p_pic->p_sys;
> + IDirect3DSurface9_Release( p_pic_sys->surface );
> + free( p_pic_sys );
> + p_pic->p_sys = NULL;
> +}
> +
> +static int LockOutputSurface(picture_t *p_pic)
> +{
> + IDirect3DSurface9_AddRef( p_pic->p_sys->surface );
> + return VLC_SUCCESS;
> +}
> +
> +static void UnlockOutputSurface(picture_t *p_pic)
> +{
> + IDirect3DSurface9_Release( p_pic->p_sys->surface );
> +}
> +
> +static void DestroySurfacePool(void *p_pool_gc_sys)
> +{
> + picture_pool_configuration_t *p_pool = p_pool_gc_sys;
> + free( p_pool );
> +}
> +
> +static picture_pool_configuration_t *CreateSurfacePoolConfig(picture_pool_setup_sys_t *p_sys, const video_format_t *fmt, unsigned count)
> +{
> + vlc_va_sys_t *sys = p_sys->p_va_sys;
> + LPDIRECT3DSURFACE9 hw_surfaces[count];
> + picture_sys_t *p_sys_pictures[count];
VLA? beurk.
> + picture_pool_configuration_t *p_pool = NULL;
> + picture_t **pictures = NULL;
> +
> + memset(p_sys_pictures, 0, count * sizeof(picture_sys_t *));
> +
> + p_pool = calloc(1, sizeof(picture_pool_configuration_t));
> + if ( p_pool == NULL )
> + goto error;
> +
> + pictures = calloc(count, sizeof(picture_t*));
> + if ( pictures == NULL )
> + goto error;
> +
> + if (FAILED(IDirectXVideoDecoderService_CreateSurface(sys->vs,
> + sys->surface_width,
> + sys->surface_height,
> + count - 1,
> + sys->p_render->format,
> + D3DPOOL_DEFAULT,
> + 0,
> + DXVA2_VideoDecoderRenderTarget,
> + hw_surfaces,
> + NULL))) {
> + msg_Err(sys->va, "IDirectXVideoAccelerationService_CreateSurface display failed");
> + goto error;
> + }
> + p_pool->picture_count = count;
> +
> + for (unsigned i = 0; i < count; ++i)
> + {
> + p_sys_pictures[i] = calloc(1, sizeof(picture_sys_t));
> + if ( p_sys_pictures[i] == NULL )
> + goto error;
> + p_sys_pictures[i]->surface = hw_surfaces[i];
> + p_sys_pictures[i]->surface_device = sys->d3ddev;
> + p_sys_pictures[i]->index = i;
> + if ( sys->b_thread_safe )
> + p_sys_pictures[i]->p_lock = &sys->surface_lock;
> +
> + picture_resource_t pic_resource = {
> + .p_sys = p_sys_pictures[i],
> + .pf_destroy = DestroySurface,
> + };
> + pictures[i] = picture_NewFromResource( fmt, &pic_resource );
> + if ( pictures[i] == NULL)
> + goto error;
> + }
> +
> + p_pool->picture = pictures;
> + p_pool->lock = LockOutputSurface;
> + p_pool->unlock = UnlockOutputSurface;
> + p_pool->gc.pf_destroy = DestroySurfacePool;
> + p_pool->gc.p_sys = p_pool;
> +
> + return p_pool;
> +
> +error:
> + for (unsigned i = 0; i < p_pool->picture_count; ++i)
> + {
> + IDirect3DSurface9_Release( hw_surfaces[i] );
> + }
> + for (unsigned i = 0; i < count; ++i)
> + {
> + if (p_sys_pictures != NULL && p_sys_pictures[i] != NULL)
> + free( p_sys_pictures[i] );
> + if (pictures != NULL && pictures[i] != NULL)
> + picture_Release( pictures[i] );
> + }
> + if ( pictures != NULL )
> + free( pictures );
> + if ( p_pool != NULL )
> + free( p_pool );
> +
> + return NULL;
> +}
>
> /* */
> static int Setup(vlc_va_t *va, AVCodecContext *avctx, vlc_fourcc_t *chroma, picture_pool_setup_t *output_init)
> @@ -385,7 +511,6 @@ static int Setup(vlc_va_t *va, AVCodecContext *avctx, vlc_fourcc_t *chroma, pict
> goto ok;
>
> /* */
> - DxDestroyVideoConversion(sys);
> DxDestroyVideoDecoder(sys);
>
> avctx->hwaccel_context = NULL;
> @@ -408,39 +533,57 @@ static int Setup(vlc_va_t *va, AVCodecContext *avctx, vlc_fourcc_t *chroma, pict
> sys->hw.surface = sys->hw_surface;
>
> /* */
> - DxCreateVideoConversion(sys);
> + sys->output = sys->p_render->format;
>
> /* */
> ok:
> + switch(sys->p_render->format)
> + {
> + case MAKEFOURCC('N','V','1','2'):
> + case MAKEFOURCC('Y','V','1','2'):
> + case MAKEFOURCC('I','M','C','3'):
> + *chroma = VLC_CODEC_D3D9_OPAQUE;
> + break;
> + default:
> + return VLC_EGENERIC;
> + }
> avctx->hwaccel_context = &sys->hw;
> - const d3d_format_t *output = D3dFindFormat(sys->output);
> - *chroma = output->codec;
> + output_init->pf_create_config = CreateSurfacePoolConfig;
> + sys->pool_cookie.p_va_sys = sys;
> + sys->pool_cookie.d3ddev = sys->d3ddev;
> + sys->pool_cookie.d3dobj = sys->d3dobj;
> + sys->pool_cookie.d3dpp = sys->d3dpp;
> + output_init->p_sys = &sys->pool_cookie;
>
> return VLC_SUCCESS;
> }
>
> -static int Extract(vlc_va_t *va, picture_t *picture, void *opaque,
> - uint8_t *data)
> +struct dxva_opaque
> {
> - vlc_va_sys_t *sys = va->sys;
> - LPDIRECT3DSURFACE9 d3d = (LPDIRECT3DSURFACE9)(uintptr_t)data;
> + picture_sys_t *p_dxva_surface;
> + vlc_va_sys_t *p_ sys;
> +};
What is this dxva_opaque ?
> - if (!sys->surface_cache.buffer)
> - return VLC_EGENERIC;
>
> - /* */
> - assert(sys->output == MAKEFOURCC('Y','V','1','2'));
> +static void DXA9_I420 (filter_t *p_filter, picture_t *src, picture_t *dst)
> +{
> + copy_cache_t *p_copy_cache = (copy_cache_t*) p_filter->p_sys;
> +
> + LPDIRECT3DSURFACE9 d3d = src->p_sys->surface;
> + D3DSURFACE_DESC desc;
> + if (FAILED( IDirect3DSurface9_GetDesc(d3d, &desc) ))
> + return;
>
> /* */
> D3DLOCKED_RECT lock;
> if (FAILED(IDirect3DSurface9_LockRect(d3d, &lock, NULL, D3DLOCK_READONLY))) {
> - msg_Err(va, "Failed to lock surface");
> - return VLC_EGENERIC;
> + msg_Err(p_filter, "Failed to lock surface");
> + return;
> }
>
> - if (sys->render == MAKEFOURCC('Y','V','1','2') ||
> - sys->render == MAKEFOURCC('I','M','C','3')) {
> - bool imc3 = sys->render == MAKEFOURCC('I','M','C','3');
> + if (desc.Format == MAKEFOURCC('Y','V','1','2') ||
> + desc.Format == MAKEFOURCC('I','M','C','3')) {
> + bool imc3 = desc.Format == MAKEFOURCC('I','M','C','3');
> size_t chroma_pitch = imc3 ? lock.Pitch : (lock.Pitch / 2);
>
> size_t pitch[3] = {
> @@ -451,9 +594,9 @@ static int Extract(vlc_va_t *va, picture_t *picture, void *opaque,
>
> uint8_t *plane[3] = {
> (uint8_t*)lock.pBits,
> - (uint8_t*)lock.pBits + pitch[0] * sys->surface_height,
> - (uint8_t*)lock.pBits + pitch[0] * sys->surface_height
> - + pitch[1] * sys->surface_height / 2,
> + (uint8_t*)lock.pBits + pitch[0] * src->format.i_height,
> + (uint8_t*)lock.pBits + pitch[0] * src->format.i_height
> + + pitch[1] * src->format.i_height / 2,
> };
>
> if (imc3) {
> @@ -461,25 +604,61 @@ static int Extract(vlc_va_t *va, picture_t *picture, void *opaque,
> plane[1] = plane[2];
> plane[2] = V;
> }
> - CopyFromYv12(picture, plane, pitch, sys->width, sys->height,
> - &sys->surface_cache);
> + CopyFromYv12(dst, plane, pitch, src->format.i_width, src->format.i_visible_height,
> + p_copy_cache);
> } else {
> - assert(sys->render == MAKEFOURCC('N','V','1','2'));
> + assert(desc.Format == MAKEFOURCC('N','V','1','2'));
> uint8_t *plane[2] = {
> lock.pBits,
> - (uint8_t*)lock.pBits + lock.Pitch * sys->surface_height
> + (uint8_t*)lock.pBits + lock.Pitch * src->format.i_height
> };
> size_t pitch[2] = {
> lock.Pitch,
> lock.Pitch,
> };
> - CopyFromNv12(picture, plane, pitch, sys->width, sys->height,
> - &sys->surface_cache);
> + CopyFromNv12(dst, plane, pitch, src->format.i_width, src->format.i_visible_height,
> + p_copy_cache);
> }
>
> /* */
> IDirect3DSurface9_UnlockRect(d3d);
> - (void) opaque;
> +}
> +
> +static int Extract(vlc_va_t *va, picture_t *picture, void *opaque,
> + uint8_t *data)
> +{
> + struct dxva_opaque *p_output = opaque;
> +
> + vlc_va_sys_t *sys = va->sys;
> + LPDIRECT3DSURFACE9 source = (LPDIRECT3DSURFACE9)(uintptr_t)data;
> +
> + LPDIRECT3DSURFACE9 output = picture->p_sys->surface;
> +
> + assert(source == p_output->p_dxva_surface->surface);
> +
> + picture->pf_copy_private = CopySurface;
> +
> + /* */
> + if ( picture->p_sys->p_lock )
> + vlc_mutex_lock( picture->p_sys->p_lock );
> +
> + HRESULT hr;
> +#if 0
> + RECT outputRect;
> + outputRect.top = 0;
> + outputRect.left = 0;
> + outputRect.right = picture->format.i_visible_width;
> + outputRect.bottom = picture->format.i_visible_height;
> +#endif
> + hr = IDirect3DDevice9_StretchRect( sys->d3ddev, source, NULL, output, NULL, D3DTEXF_NONE);
> + if (FAILED(hr)) {
> + msg_Err(va, "Failed to copy the hw surface to the decoder surface (hr=0x%0lx)", hr );
> + }
> +
> + /* */
> + if ( picture->p_sys->p_lock )
> + vlc_mutex_unlock( picture->p_sys->p_lock );
> +
> return VLC_SUCCESS;
> }
>
> @@ -498,30 +677,31 @@ static int Get(vlc_va_t *va, void **opaque, uint8_t **data)
> return VLC_EGENERIC;
> }
>
> + struct dxva_opaque *p_output = malloc(sizeof(*p_output));
> + *opaque = p_output;
> + p_output->p_sys = sys;
> +
> if ( sys->b_thread_safe )
> vlc_mutex_lock( &sys->surface_lock );
>
> /* Grab an unused surface, in case none are, try the oldest
> * XXX using the oldest is a workaround in case a problem happens with libavcodec */
> - unsigned i, old;
> - for (i = 0, old = 0; i < sys->surface_count; i++) {
> - vlc_va_surface_t *surface = &sys->surface[i];
> -
> - if (!surface->refcount)
> - break;
> -
> - if (surface->order < sys->surface[old].order)
> - old = i;
> + unsigned i;
> + picture_sys_t *oldest = NULL;
> + for (i = 0; i < sys->surface_count; i++) {
> + picture_sys_t *surface = &sys->surface[i];
> + if (!surface->refcount && (!oldest || surface->order < oldest->order))
> + oldest = surface;
> }
> - if (i >= sys->surface_count)
> - i = old;
> -
> - vlc_va_surface_t *surface = &sys->surface[i];
> -
> - surface->refcount = 1;
> - surface->order = sys->surface_order++;
> - *data = (void *)surface->d3d;
> - *opaque = surface;
> + if ( oldest == NULL )
> + {
> + msg_Warn(va, "%lx could not find an unused surface, use oldest index", GetCurrentThreadId());
> + oldest = &sys->surface[0];
> + }
> + *data = (void *)oldest->surface;
> + p_output->p_dxva_surface = oldest;
> + p_output->p_dxva_surface->refcount++;
> + assert( p_output->p_dxva_surface->refcount == 1 );
>
> if ( sys->b_thread_safe )
> vlc_mutex_unlock( &sys->surface_lock );
> @@ -531,23 +711,27 @@ static int Get(vlc_va_t *va, void **opaque, uint8_t **data)
>
> static void Release(void *opaque, uint8_t *data)
> {
> - vlc_va_surface_t *surface = opaque;
> - if ( surface->p_lock )
> - vlc_mutex_lock( surface->p_lock );
> + VLC_UNUSED( data );
>
> - surface->refcount--;
> - (void) data;
> + struct dxva_opaque *p_output = opaque;
> + if ( p_output->p_dxva_surface->p_lock )
> + vlc_mutex_lock( p_output->p_dxva_surface->p_lock );
>
> - if ( surface->p_lock )
> - vlc_mutex_unlock( surface->p_lock );
> + p_output->p_dxva_surface->refcount--;
> + p_output->p_dxva_surface->order = p_output->p_sys->surface_order++;
> +
> + if ( p_output->p_dxva_surface->p_lock )
> + vlc_mutex_unlock( p_output->p_dxva_surface->p_lock );
> +
> + free( p_output );
> }
>
> static void Close(vlc_va_t *va, AVCodecContext *ctx)
> {
> + VLC_UNUSED( ctx );
> +
> vlc_va_sys_t *sys = va->sys;
>
> - (void) ctx;
> - DxDestroyVideoConversion(sys);
> DxDestroyVideoDecoder(sys);
> DxDestroyVideoService(sys);
> D3dDestroyDeviceManager(sys);
> @@ -566,6 +750,8 @@ static void Close(vlc_va_t *va, AVCodecContext *ctx)
>
> static int Open(vlc_va_t *va, AVCodecContext *ctx, const es_format_t *fmt)
> {
> + VLC_UNUSED( fmt );
> +
> vlc_va_sys_t *sys = calloc(1, sizeof (*sys));
> if (unlikely(sys == NULL))
> return VLC_ENOMEM;
> @@ -609,7 +795,7 @@ static int Open(vlc_va_t *va, AVCodecContext *ctx, const es_format_t *fmt)
> }
>
> /* */
> - if (DxFindVideoServiceConversion(va, &sys->input, &sys->render)) {
> + if (DxFindVideoServiceConversion(va, &sys->input, &sys->p_render)) {
> msg_Err(va, "DxFindVideoServiceConversion failed");
> goto error;
> }
> @@ -663,6 +849,35 @@ static int D3dCreateDevice(vlc_va_t *va)
> ZeroMemory(d3dai, sizeof(*d3dai));
> }
>
> + /*
> + ** Get the current desktop display mode, so we can set up a back
> + ** buffer of the same format
> + */
> + D3DDISPLAYMODE d3ddm;
> + HRESULT hr = IDirect3D9_GetAdapterDisplayMode(sys->d3dobj,
> + D3DADAPTER_DEFAULT, &d3ddm);
> + if (FAILED(hr)) {
> + msg_Err(va, "Could not read adapter display mode. (hr=0x%0lx)", hr);
> + return VLC_EGENERIC;
> + }
> +
> + UINT AdapterToUse = D3DADAPTER_DEFAULT;
> + D3DDEVTYPE DeviceType = D3DDEVTYPE_HAL;
> +
> +#ifndef NDEBUG
> + // Look for 'NVIDIA PerfHUD' adapter
> + // If it is present, override default settings
> + for (UINT Adapter=0; Adapter< IDirect3D9_GetAdapterCount(d3dobj); ++Adapter) {
> + D3DADAPTER_IDENTIFIER9 Identifier;
> + HRESULT Res = IDirect3D9_GetAdapterIdentifier(d3dobj,Adapter,0,&Identifier);
> + if (SUCCEEDED(Res) && strstr(Identifier.Description,"PerfHUD") != 0) {
> + AdapterToUse = Adapter;
> + DeviceType = D3DDEVTYPE_REF;
> + break;
> + }
> + }
> +#endif
> +
> /* */
> D3DPRESENT_PARAMETERS *d3dpp = &sys->d3dpp;
> ZeroMemory(d3dpp, sizeof(*d3dpp));
> @@ -672,18 +887,20 @@ static int D3dCreateDevice(vlc_va_t *va)
> d3dpp->SwapEffect = D3DSWAPEFFECT_DISCARD;
> d3dpp->MultiSampleType = D3DMULTISAMPLE_NONE;
> d3dpp->PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
> - d3dpp->BackBufferCount = 0; /* FIXME what to put here */
> - d3dpp->BackBufferFormat = D3DFMT_X8R8G8B8; /* FIXME what to put here */
> - d3dpp->BackBufferWidth = 0;
> - d3dpp->BackBufferHeight = 0;
> + d3dpp->BackBufferCount = 1;
> + d3dpp->BackBufferFormat = d3ddm.Format;
> + d3dpp->BackBufferWidth = __MAX((unsigned int)GetSystemMetrics(SM_CXVIRTUALSCREEN),
> + d3ddm.Width);
> + d3dpp->BackBufferHeight = __MAX((unsigned int)GetSystemMetrics(SM_CYVIRTUALSCREEN),
> + d3ddm.Height);
> d3dpp->EnableAutoDepthStencil = FALSE;
>
> /* Direct3D needs a HWND to create a device, even without using ::Present
> this HWND is used to alert Direct3D when there's a change of focus window.
> For now, use GetDesktopWindow, as it looks harmless */
> LPDIRECT3DDEVICE9 d3ddev;
> - if (FAILED(IDirect3D9_CreateDevice(d3dobj, D3DADAPTER_DEFAULT,
> - D3DDEVTYPE_HAL, GetDesktopWindow(),
> + if (FAILED(IDirect3D9_CreateDevice(d3dobj, AdapterToUse,
> + DeviceType, d3dpp->hDeviceWindow,
> D3DCREATE_SOFTWARE_VERTEXPROCESSING |
> D3DCREATE_MULTITHREADED,
> d3dpp, &d3ddev))) {
> @@ -838,7 +1055,7 @@ static void DxDestroyVideoService(vlc_va_sys_t *va)
> /**
> * Find the best suited decoder mode GUID and render format.
> */
> -static int DxFindVideoServiceConversion(vlc_va_t *va, GUID *input, D3DFORMAT *output)
> +static int DxFindVideoServiceConversion(vlc_va_t *va, GUID *input, const d3d_format_t **output)
> {
> vlc_va_sys_t *sys = va->sys;
>
> @@ -951,7 +1168,7 @@ static int DxFindVideoServiceConversion(vlc_va_t *va, GUID *input, D3DFORMAT *ou
> /* We have our solution */
> msg_Dbg(va, "Using '%s' to decode to '%s'", mode->name, format->name);
> *input = *mode->guid;
> - *output = format->format;
> + *output = format;
> CoTaskMemFree(output_list);
> CoTaskMemFree(input_list);
> return VLC_SUCCESS;
> @@ -1018,7 +1235,7 @@ static int DxCreateVideoDecoder(vlc_va_t *va, int codec_id,
> sys->surface_width,
> sys->surface_height,
> sys->surface_count - 1,
> - sys->render,
> + sys->p_render->format,
> D3DPOOL_DEFAULT,
> 0,
> DXVA2_VideoDecoderRenderTarget,
> @@ -1029,13 +1246,16 @@ static int DxCreateVideoDecoder(vlc_va_t *va, int codec_id,
> return VLC_EGENERIC;
> }
> for (unsigned i = 0; i < sys->surface_count; i++) {
> - vlc_va_surface_t *surface = &sys->surface[i];
> - surface->d3d = sys->hw_surface[i];
> - surface->refcount = 0;
> - surface->order = 0;
> + picture_sys_t *p_picture = &sys->surface[i];
> + p_picture->surface = sys->hw_surface[i];
> + p_picture->surface_device = sys->d3ddev;
> + p_picture->refcount = 0;
> + p_picture->index = i;
> + p_picture->order = i;
> if ( sys->b_thread_safe )
> - surface->p_lock = &sys->surface_lock;
> + p_picture->p_lock = &sys->surface_lock;
> }
> + sys->surface_order = sys->surface_count;
> msg_Dbg(va, "IDirectXVideoAccelerationService_CreateSurface succeed with %d surfaces (%dx%d)",
> sys->surface_count, fmt->i_width, fmt->i_height);
>
> @@ -1044,7 +1264,7 @@ static int DxCreateVideoDecoder(vlc_va_t *va, int codec_id,
> ZeroMemory(&dsc, sizeof(dsc));
> dsc.SampleWidth = fmt->i_width;
> dsc.SampleHeight = fmt->i_height;
> - dsc.Format = sys->render;
> + dsc.Format = sys->p_render->format;
> if (fmt->i_frame_rate > 0 && fmt->i_frame_rate_base > 0) {
> dsc.InputSampleFreq.Numerator = fmt->i_frame_rate;
> dsc.InputSampleFreq.Denominator = fmt->i_frame_rate_base;
> @@ -1139,7 +1359,7 @@ static void DxDestroyVideoDecoder(vlc_va_sys_t *va)
> va->decoder = NULL;
>
> for (unsigned i = 0; i < va->surface_count; i++)
> - IDirect3DSurface9_Release(va->surface[i].d3d);
> + IDirect3DSurface9_Release( va->hw_surface[i] );
> va->surface_count = 0;
> }
>
> @@ -1149,21 +1369,37 @@ static int DxResetVideoDecoder(vlc_va_t *va)
> return VLC_EGENERIC;
> }
>
> -static void DxCreateVideoConversion(vlc_va_sys_t *va)
> +VIDEO_FILTER_WRAPPER (DXA9_I420)
> +
> +static int OpenConverter( vlc_object_t *obj )
> {
> - switch (va->render) {
> - case MAKEFOURCC('N','V','1','2'):
> - case MAKEFOURCC('I','M','C','3'):
> - va->output = MAKEFOURCC('Y','V','1','2');
> - break;
> - default:
> - va->output = va->render;
> - break;
> - }
> - CopyInitCache(&va->surface_cache, va->surface_width);
> + filter_t *p_filter = (filter_t *)obj;
> + if ( p_filter->fmt_in.video.i_height != p_filter->fmt_out.video.i_height
> + || p_filter->fmt_in.video.i_width != p_filter->fmt_out.video.i_width )
> + return VLC_EGENERIC;
> +
> + if ( p_filter->fmt_out.video.i_chroma != VLC_CODEC_I420
> + && p_filter->fmt_out.video.i_chroma != VLC_CODEC_YV12
> + && p_filter->fmt_out.video.i_chroma != VLC_CODEC_NV12 )
> + return VLC_EGENERIC;
> +
> + if ( p_filter->fmt_in.video.i_chroma == VLC_CODEC_D3D9_OPAQUE )
> + p_filter->pf_video_filter = DXA9_I420_Filter;
> + else
> + return VLC_EGENERIC;
> +
> + copy_cache_t *p_copy_cache = calloc(1, sizeof(*p_copy_cache));
Unchecked calloc :)
> + CopyInitCache(p_copy_cache, p_filter->fmt_in.video.i_width );
> + p_filter->p_sys = (filter_sys_t*) p_copy_cache;
> +
> + return VLC_SUCCESS;
> }
>
> -static void DxDestroyVideoConversion(vlc_va_sys_t *va)
> +static void CloseConverter( vlc_object_t *obj )
> {
> - CopyCleanCache(&va->surface_cache);
> + filter_t *p_filter = (filter_t *)obj;
> + copy_cache_t *p_copy_cache = (copy_cache_t*) p_filter->p_sys;
> + CopyCleanCache(p_copy_cache);
> + free( p_copy_cache );
> + p_filter->p_sys = NULL;
> }
> diff --git a/modules/codec/avcodec/dxva2.h b/modules/codec/avcodec/dxva2.h
> new file mode 100644
> index 0000000..b4fd0ff
> --- /dev/null
> +++ b/modules/codec/avcodec/dxva2.h
> @@ -0,0 +1,69 @@
> +/*****************************************************************************
> + * dxva2.c: Video Acceleration helpers
> + *****************************************************************************
> + * Copyright (C) 2009 Geoffroy Couprie
> + * Copyright (C) 2009 Laurent Aimar
> + * $Id$
> + *
> + * Authors: Geoffroy Couprie <geal at videolan.org>
> + * Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
> + *
> + * 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_DXVA2_H_
> +#define AVCODEC_DXVA2_H_
> +
> +#ifdef HAVE_CONFIG_H
> +# include "config.h"
> +#endif
> +
> +# if _WIN32_WINNT < 0x600
> +/* dxva2 needs Vista support */
> +# undef _WIN32_WINNT
> +# define _WIN32_WINNT 0x600
> +# endif
> +
> +#include <vlc_common.h>
> +#include <vlc_picture.h>
> +
> +#include "va.h"
> +
> +#include <d3d9.h>
> +
> +struct picture_pool_setup_sys_t {
> + vlc_va_sys_t *p_va_sys;
> + /* shared objects between the decoder and the d3d9 vout */
> + LPDIRECT3D9 d3dobj;
> + LPDIRECT3DDEVICE9 d3ddev;
> + D3DPRESENT_PARAMETERS d3dpp;
> +};
They are stored in the picture_pool_sys, and not in the picture_sys?
Or are they the same (d3ddev)?
> +struct picture_sys_t
> +{
> + LPDIRECT3DSURFACE9 surface;
> + LPDIRECT3DDEVICE9 surface_device;
> +
> + /* D3D9 vout stuff */
> + picture_t *fallback;
> +
> + /* DXVA2 decoder stuff */
> + int refcount;
> + unsigned int order;
> + unsigned int index;
> + vlc_mutex_t *p_lock;
> +};
> index fbbd719..1790587 100644
> --- a/modules/codec/avcodec/video.c
> +++ b/modules/codec/avcodec/video.c
> @@ -396,21 +396,6 @@ int InitVideoDec( decoder_t *p_dec, AVCodecContext *p_context,
> break;
> }
>
> - /* Workaround: frame multithreading is not compatible with
> - * DXVA2. When a frame is being copied to host memory, the frame
> - * is locked and cannot be used as a reference frame
> - * simultaneously and thus decoding fails for some frames. This
> - * causes major image corruption. */
> -# if defined(_WIN32)
> - char *avcodec_hw = var_InheritString( p_dec, "avcodec-hw" );
> - if( avcodec_hw == NULL || strcasecmp( avcodec_hw, "none" ) )
> - {
> - msg_Warn( p_dec, "threaded frame decoding is not compatible with DXVA2, disabled" );
> - p_context->thread_type &= ~FF_THREAD_FRAME;
> - }
> - free( avcodec_hw );
> -# endif
I do not think this is in the right patch.
> diff --git a/modules/video_output/msw/direct3d9.c b/modules/video_output/msw/direct3d9.c
> index db96275..20943b9 100644
> --- a/modules/video_output/msw/direct3d9.c
> +++ b/modules/video_output/msw/direct3d9.c
Please split this :)
With my kindest regards,
--
Jean-Baptiste Kempf
http://www.jbkempf.com/ - +33 672 704 734
Sent from my Electronic Device
More information about the vlc-devel
mailing list