[vlc-devel] [PATCH] DXVA2: output an opaque pixel format with D3D9 surfaces internally (v2)
Steve Lhomme
robux4 at videolabs.io
Wed Apr 22 10:16:43 CEST 2015
Yes, this is a big patch :)
I can at least split the addition VLC_CODEC_D3D9_OPAQUE into a
separate patch. It's just moving the surface to planes into a filter
rather than doing it internally. That will make the changes related to
the direct rendering more obvious.
On Tue, Apr 21, 2015 at 6:36 PM, Jean-Baptiste Kempf <jb at videolan.org> wrote:
> 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.
When I was using 3 different chroma depending on the surface type, it
was necessary to know which variant was used. It may not be needed
anymore.
>> - 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?
A pointer to this structure is passed in the picture_pool_setup_t
callback. It contains all the data needed to create the pool of D3D9
surfaces properly. The pointer is valid as long as the va decoder is
alive.
>> +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.
I'll have to check if it's still needed. When the decoder gets
picture_t it does a picture_Copy and push that copy in the vout FIFO.
That's where we copy the pixels from the decoder surface (internal to
avcodec/dxva2) to the decoder pool allocated by vout_wrapper.
>> +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 :)
Oops
>> + 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)?
They are the same.
>> +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.
After this patch is (not going to be) applied, this hack is not needed
anymore. So I suppose it's related but I can split it submit it once
we have a working solution in master.
>> 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 :)
ok
More information about the vlc-devel
mailing list