[vlc-devel] [PATCH] DXVA2: output D3D9 GPU surfaces
Steve Lhomme
robUx4 at videolabs.io
Tue Apr 28 16:52:10 CEST 2015
also provide a filter to convert these surfaces to regular planes
---
modules/codec/Makefile.am | 3 +-
modules/codec/avcodec/dxva2.c | 203 ++++++++++++++++++++++++++++++++----------
modules/codec/avcodec/va.c | 2 +-
3 files changed, 159 insertions(+), 49 deletions(-)
diff --git a/modules/codec/Makefile.am b/modules/codec/Makefile.am
index e5f7ed8..3efdcac 100644
--- a/modules/codec/Makefile.am
+++ b/modules/codec/Makefile.am
@@ -342,7 +342,8 @@ endif
libdxva2_plugin_la_SOURCES = \
video_chroma/copy.c video_chroma/copy.h \
- codec/avcodec/dxva2.c codec/h264_nal.c codec/h264_nal.h
+ codec/avcodec/dxva2.c codec/h264_nal.c codec/h264_nal.h \
+ ../src/win32/direct3d9_pool.c ../src/win32/direct3d9_pool.h
libdxva2_plugin_la_LIBADD = -lole32 -lshlwapi -luuid
if HAVE_AVCODEC_DXVA2
codec_LTLIBRARIES += libdxva2_plugin.la
diff --git a/modules/codec/avcodec/dxva2.c b/modules/codec/avcodec/dxva2.c
index 482810c..a55fddf 100644
--- a/modules/codec/avcodec/dxva2.c
+++ b/modules/codec/avcodec/dxva2.c
@@ -42,6 +42,7 @@
#include <vlc_cpu.h>
#include <vlc_plugin.h>
#include <vlc_codecs.h>
+#include <vlc_filter.h>
#include <libavcodec/avcodec.h>
# define DXVA2API_USE_BITFIELDS
@@ -57,12 +58,19 @@ static int Open(vlc_va_t *, AVCodecContext *, enum PixelFormat,
const es_format_t *, picture_sys_t *p_sys);
static void Close(vlc_va_t *, AVCodecContext *);
+static int OpenConverter( vlc_object_t * );
+static void CloseConverter( vlc_object_t * );
+
vlc_module_begin()
set_description(N_("DirectX Video Acceleration (DXVA) 2.0"))
set_capability("hw decoder", 0)
set_category(CAT_INPUT)
set_subcategory(SUBCAT_INPUT_VCODEC)
set_callbacks(Open, Close)
+ add_submodule()
+ set_description( N_("DXA9 to I420,YV12,NV12") )
+ set_capability( "video filter2", 10 )
+ set_callbacks( OpenConverter, CloseConverter )
vlc_module_end()
#include <windows.h>
@@ -366,6 +374,11 @@ struct vlc_va_sys_t
LPDIRECT3DSURFACE9 hw_surface[VA_DXVA2_MAX_SURFACE_COUNT];
};
+struct picture_sys_t
+{
+ LPDIRECT3DSURFACE9 surface;
+};
+
/* */
static int D3dCreateDevice(vlc_va_t *);
static void D3dDestroyDevice(vlc_va_sys_t *);
@@ -385,9 +398,6 @@ static int DxResetVideoDecoder(vlc_va_t *);
static bool profile_supported(const dxva2_mode_t *mode, const es_format_t *fmt);
-static void DxCreateVideoConversion(vlc_va_sys_t *);
-static void DxDestroyVideoConversion(vlc_va_sys_t *);
-
/* */
static int Setup(vlc_va_t *va, AVCodecContext *avctx, vlc_fourcc_t *chroma)
{
@@ -398,7 +408,6 @@ static int Setup(vlc_va_t *va, AVCodecContext *avctx, vlc_fourcc_t *chroma)
goto ok;
/* */
- DxDestroyVideoConversion(sys);
DxDestroyVideoDecoder(sys);
avctx->hwaccel_context = NULL;
@@ -421,38 +430,38 @@ static int Setup(vlc_va_t *va, AVCodecContext *avctx, vlc_fourcc_t *chroma)
sys->hw.surface = sys->hw_surface;
/* */
- DxCreateVideoConversion(sys);
-
- /* */
ok:
avctx->hwaccel_context = &sys->hw;
- const d3d_format_t *output = D3dFindFormat(sys->output);
- *chroma = output->codec;
+ *chroma = VLC_CODEC_D3D9_OPAQUE;
return VLC_SUCCESS;
}
-static int Extract(vlc_va_t *va, picture_t *picture, uint8_t *data)
+static void DXA9_YV12(filter_t *p_filter, picture_t *src, picture_t *dst)
{
- vlc_va_sys_t *sys = va->sys;
- LPDIRECT3DSURFACE9 d3d = (LPDIRECT3DSURFACE9)(uintptr_t)data;
+ copy_cache_t *p_copy_cache = (copy_cache_t*) p_filter->p_sys;
- if (!sys->surface_cache.buffer)
- return VLC_EGENERIC;
-
- /* */
- assert(sys->output == MAKEFOURCC('Y','V','1','2'));
+ 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 (dst->format.i_chroma == VLC_CODEC_I420) {
+ uint8_t *tmp = dst->p[1].p_pixels;
+ dst->p[1].p_pixels = dst->p[2].p_pixels;
+ dst->p[2].p_pixels = tmp;
+ }
+
+ 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] = {
@@ -463,9 +472,9 @@ static int Extract(vlc_va_t *va, picture_t *picture, uint8_t *data)
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) {
@@ -473,24 +482,95 @@ static int Extract(vlc_va_t *va, picture_t *picture, uint8_t *data)
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 if (desc.Format == MAKEFOURCC('N','V','1','2')) {
+ uint8_t *plane[2] = {
+ lock.pBits,
+ (uint8_t*)lock.pBits + lock.Pitch * src->format.i_visible_height
+ };
+ size_t pitch[2] = {
+ lock.Pitch,
+ lock.Pitch,
+ };
+ CopyFromNv12(dst, plane, pitch, src->format.i_width, src->format.i_visible_height,
+ p_copy_cache);
} else {
- assert(sys->render == MAKEFOURCC('N','V','1','2'));
+ msg_Err(p_filter, "Unsupported DXA9 conversion from 0x%08X to YV12", desc.Format);
+ }
+
+ if (dst->format.i_chroma == VLC_CODEC_I420) {
+ uint8_t *tmp = dst->p[1].p_pixels;
+ dst->p[1].p_pixels = dst->p[2].p_pixels;
+ dst->p[2].p_pixels = tmp;
+ }
+
+ /* */
+ IDirect3DSurface9_UnlockRect(d3d);
+}
+
+static void DXA9_NV12(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(p_filter, "Failed to lock surface");
+ return;
+ }
+
+ if (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_visible_height
};
size_t pitch[2] = {
lock.Pitch,
lock.Pitch,
};
- CopyFromNv12(picture, plane, pitch, sys->width, sys->height,
- &sys->surface_cache);
+ CopyFromNv12ToNv12(dst, plane, pitch, src->format.i_width, src->format.i_visible_height,
+ p_copy_cache);
+ } else {
+ msg_Err(p_filter, "Unsupported DXA9 conversion from 0x%08X to NV12", desc.Format);
}
/* */
IDirect3DSurface9_UnlockRect(d3d);
+}
+
+static int Extract(vlc_va_t *va, picture_t *picture, uint8_t *data)
+{
+ vlc_va_sys_t *sys = va->sys;
+ LPDIRECT3DSURFACE9 d3d = (LPDIRECT3DSURFACE9)(uintptr_t)data;
+ picture_sys_t *p_sys = picture->p_sys;
+ LPDIRECT3DSURFACE9 output = p_sys->surface;
+
+ assert(d3d != output);
+#ifndef NDEBUG
+ LPDIRECT3DDEVICE9 srcDevice, dstDevice;
+ IDirect3DSurface9_GetDevice(d3d, &srcDevice);
+ IDirect3DSurface9_GetDevice(output, &dstDevice);
+ assert(srcDevice == dstDevice);
+#endif
+
+ HRESULT hr;
+ RECT visibleSource;
+ visibleSource.left = 0;
+ visibleSource.top = 0;
+ visibleSource.right = picture->format.i_visible_width;
+ visibleSource.bottom = picture->format.i_visible_height;
+ hr = IDirect3DDevice9_StretchRect( sys->d3ddev, d3d, &visibleSource, output, &visibleSource, D3DTEXF_NONE);
+ if (FAILED(hr)) {
+ msg_Err(va, "Failed to copy the hw surface to the decoder surface (hr=0x%0lx)", hr );
+ return VLC_EGENERIC;
+ }
+
return VLC_SUCCESS;
}
@@ -557,7 +637,6 @@ static void Close(vlc_va_t *va, AVCodecContext *ctx)
vlc_va_sys_t *sys = va->sys;
(void) ctx;
- DxDestroyVideoConversion(sys);
DxDestroyVideoDecoder(sys);
DxDestroyVideoService(sys);
D3dDestroyDeviceManager(sys);
@@ -603,12 +682,20 @@ static int Open(vlc_va_t *va, AVCodecContext *ctx, enum PixelFormat pix_fmt,
}
msg_Dbg(va, "DLLs loaded");
- /* */
- if (D3dCreateDevice(va)) {
- msg_Err(va, "Failed to create Direct3D device");
- goto error;
+ sys->d3ddev = NULL;
+ if (p_sys!=NULL)
+ IDirect3DSurface9_GetDevice(p_sys->surface, &sys->d3ddev);
+
+ if (sys->d3ddev) {
+ msg_Dbg(va, "Reusing D3D9 device");
+ } else {
+ /* */
+ if (D3dCreateDevice(va)) {
+ msg_Err(va, "Failed to create Direct3D device");
+ goto error;
+ }
+ msg_Dbg(va, "D3dCreateDevice succeed");
}
- msg_Dbg(va, "D3dCreateDevice succeed");
if (D3dCreateDeviceManager(va)) {
msg_Err(va, "D3dCreateDeviceManager failed");
@@ -1148,21 +1235,43 @@ static int DxResetVideoDecoder(vlc_va_t *va)
return VLC_EGENERIC;
}
-static void DxCreateVideoConversion(vlc_va_sys_t *va)
+VIDEO_FILTER_WRAPPER (DXA9_YV12)
+VIDEO_FILTER_WRAPPER (DXA9_NV12)
+
+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');
+ filter_t *p_filter = (filter_t *)obj;
+ if ( p_filter->fmt_in.video.i_chroma != VLC_CODEC_D3D9_OPAQUE )
+ return VLC_EGENERIC;
+
+ 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;
+
+ switch( p_filter->fmt_out.video.i_chroma ) {
+ case VLC_CODEC_I420:
+ case VLC_CODEC_YV12:
+ p_filter->pf_video_filter = DXA9_YV12_Filter;
break;
- default:
- va->output = va->render;
+ case VLC_CODEC_NV12:
+ p_filter->pf_video_filter = DXA9_NV12_Filter;
break;
+ default:
+ return VLC_EGENERIC;
}
- CopyInitCache(&va->surface_cache, va->surface_width);
+
+ copy_cache_t *p_copy_cache = calloc(1, sizeof(*p_copy_cache));
+ 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/va.c b/modules/codec/avcodec/va.c
index 413574d..f9e94e6 100644
--- a/modules/codec/avcodec/va.c
+++ b/modules/codec/avcodec/va.c
@@ -41,7 +41,7 @@ vlc_fourcc_t vlc_va_GetChroma(enum PixelFormat hwfmt, enum PixelFormat swfmt)
return VLC_CODEC_YV12;
case AV_PIX_FMT_DXVA2_VLD:
- return VLC_CODEC_YV12;
+ return VLC_CODEC_D3D9_OPAQUE;
#if (LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(53, 14, 0))
case AV_PIX_FMT_VDA_VLD:
return VLC_CODEC_UYVY;
--
2.3.2
More information about the vlc-devel
mailing list