[vlc-commits] video_chroma:d3d9: add a module to convert from CPU to GPU textures
Steve Lhomme
git at videolan.org
Tue Jun 13 15:02:10 CEST 2017
vlc | branch: master | Steve Lhomme <robux4 at videolabs.io> | Tue Jun 6 16:49:59 2017 +0200| [718a32856a7aff325da91f3c27f443d4665def20] | committer: Jean-Baptiste Kempf
video_chroma:d3d9: add a module to convert from CPU to GPU textures
And set a picture->context as if it's coming from the decoder, otherwise
snapshots won't work.
Signed-off-by: Jean-Baptiste Kempf <jb at videolan.org>
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=718a32856a7aff325da91f3c27f443d4665def20
---
modules/video_chroma/Makefile.am | 2 +-
modules/video_chroma/dxa9.c | 316 ++++++++++++++++++++++++++++++++++++---
2 files changed, 300 insertions(+), 18 deletions(-)
diff --git a/modules/video_chroma/Makefile.am b/modules/video_chroma/Makefile.am
index fd95f7a719..14195e8f04 100644
--- a/modules/video_chroma/Makefile.am
+++ b/modules/video_chroma/Makefile.am
@@ -115,7 +115,7 @@ endif
# DXVA2
libdxa9_plugin_la_SOURCES = video_chroma/dxa9.c \
- video_chroma/d3d9_fmt.h video_chroma/copy.c video_chroma/copy.h
+ video_chroma/d3d9_fmt.h video_chroma/copy.c video_chroma/copy.h
if HAVE_AVCODEC_DXVA2
chroma_LTLIBRARIES += \
diff --git a/modules/video_chroma/dxa9.c b/modules/video_chroma/dxa9.c
index ca30f93563..26dd5d6f92 100644
--- a/modules/video_chroma/dxa9.c
+++ b/modules/video_chroma/dxa9.c
@@ -33,25 +33,26 @@
#include <vlc_plugin.h>
#include <vlc_filter.h>
#include <vlc_picture.h>
+#include <vlc_modules.h>
#include "copy.h"
-static int OpenConverter( vlc_object_t * );
-static void CloseConverter( vlc_object_t * );
-
-/*****************************************************************************
- * Module descriptor.
- *****************************************************************************/
-vlc_module_begin ()
- set_description( N_("Conversions from DxVA2 to YUV") )
- set_capability( "video converter", 10 )
- set_callbacks( OpenConverter, CloseConverter )
-vlc_module_end ()
-
#include <windows.h>
#include <d3d9.h>
#include "d3d9_fmt.h"
+struct filter_sys_t {
+ /* GPU to CPU */
+ copy_cache_t cache;
+
+ /* CPU to GPU */
+ IDirect3DDevice9 *d3ddev;
+ filter_t *filter;
+ picture_t *staging;
+
+ HINSTANCE hd3d_dll;
+};
+
static bool GetLock(filter_t *p_filter, LPDIRECT3DSURFACE9 d3d,
D3DLOCKED_RECT *p_lock, D3DSURFACE_DESC *p_desc)
{
@@ -162,12 +163,136 @@ static void DXA9_NV12(filter_t *p_filter, picture_t *src, picture_t *dst)
IDirect3DSurface9_UnlockRect(p_sys->surface);
}
+static void DestroyPicture(picture_t *picture)
+{
+ picture_sys_t *p_sys = picture->p_sys;
+ ReleasePictureSys( p_sys );
+ free(p_sys);
+ free(picture);
+}
+
+static void DeleteFilter( filter_t * p_filter )
+{
+ if( p_filter->p_module )
+ module_unneed( p_filter, p_filter->p_module );
+
+ es_format_Clean( &p_filter->fmt_in );
+ es_format_Clean( &p_filter->fmt_out );
+
+ vlc_object_release( p_filter );
+}
+
+static picture_t *NewBuffer(filter_t *p_filter)
+{
+ filter_t *p_parent = p_filter->owner.sys;
+ return p_parent->p_sys->staging;
+}
+
+static filter_t *CreateFilter( vlc_object_t *p_this, const es_format_t *p_fmt_in,
+ vlc_fourcc_t dst_chroma )
+{
+ filter_t *p_filter;
+
+ p_filter = vlc_object_create( p_this, sizeof(filter_t) );
+ if (unlikely(p_filter == NULL))
+ return NULL;
+
+ p_filter->b_allow_fmt_out_change = false;
+ p_filter->owner.video.buffer_new = NewBuffer;
+ p_filter->owner.sys = p_this;
+
+ es_format_InitFromVideo( &p_filter->fmt_in, &p_fmt_in->video );
+ es_format_InitFromVideo( &p_filter->fmt_out, &p_fmt_in->video );
+ p_filter->fmt_out.i_codec = p_filter->fmt_out.video.i_chroma = dst_chroma;
+ p_filter->p_module = module_need( p_filter, "video converter", NULL, false );
+
+ if( !p_filter->p_module )
+ {
+ msg_Dbg( p_filter, "no video converter found" );
+ DeleteFilter( p_filter );
+ return NULL;
+ }
+
+ return p_filter;
+}
+
+struct d3d_pic_context
+{
+ picture_context_t s;
+};
+
+static void d3d9_pic_context_destroy(struct picture_context_t *ctx)
+{
+ struct va_pic_context *pic_ctx = (struct va_pic_context*)ctx;
+ ReleasePictureSys(&pic_ctx->picsys);
+ free(pic_ctx);
+}
+
+static struct picture_context_t *d3d9_pic_context_copy(struct picture_context_t *ctx)
+{
+ struct va_pic_context *src_ctx = (struct va_pic_context*)ctx;
+ struct va_pic_context *pic_ctx = calloc(1, sizeof(*pic_ctx));
+ if (unlikely(pic_ctx==NULL))
+ return NULL;
+ pic_ctx->s.destroy = d3d9_pic_context_destroy;
+ pic_ctx->s.copy = d3d9_pic_context_copy;
+ pic_ctx->picsys = src_ctx->picsys;
+ AcquirePictureSys(&pic_ctx->picsys);
+ return &pic_ctx->s;
+}
+
+static void YV12_D3D9(filter_t *p_filter, picture_t *src, picture_t *dst)
+{
+ filter_sys_t *sys = (filter_sys_t*) p_filter->p_sys;
+ picture_sys_t *p_sys = dst->p_sys;
+
+ D3DSURFACE_DESC texDesc;
+ IDirect3DSurface9_GetDesc( p_sys->surface, &texDesc);
+
+ D3DLOCKED_RECT d3drect;
+ HRESULT hr = IDirect3DSurface9_LockRect(sys->staging->p_sys->surface, &d3drect, NULL, 0);
+ if (FAILED(hr))
+ return;
+
+ picture_UpdatePlanes(sys->staging, d3drect.pBits, d3drect.Pitch);
+
+ picture_Hold( src );
+ sys->filter->pf_video_filter(sys->filter, src);
+
+ IDirect3DSurface9_UnlockRect(sys->staging->p_sys->surface);
+
+ RECT visibleSource = {
+ .right = dst->format.i_width, .bottom = dst->format.i_height,
+ };
+ IDirect3DDevice9_StretchRect( sys->d3ddev,
+ sys->staging->p_sys->surface, &visibleSource,
+ dst->p_sys->surface, &visibleSource,
+ D3DTEXF_NONE );
+
+ if (dst->context == NULL)
+ {
+ struct va_pic_context *pic_ctx = calloc(1, sizeof(*pic_ctx));
+ if (likely(pic_ctx))
+ {
+ pic_ctx->s.destroy = d3d9_pic_context_destroy;
+ pic_ctx->s.copy = d3d9_pic_context_copy;
+ pic_ctx->picsys = *dst->p_sys;
+ AcquirePictureSys(&pic_ctx->picsys);
+ dst->context = &pic_ctx->s;
+ }
+ }
+}
+
VIDEO_FILTER_WRAPPER (DXA9_YV12)
VIDEO_FILTER_WRAPPER (DXA9_NV12)
+VIDEO_FILTER_WRAPPER (YV12_D3D9)
static int OpenConverter( vlc_object_t *obj )
{
filter_t *p_filter = (filter_t *)obj;
+ HINSTANCE hd3d_dll = NULL;
+ int err = VLC_EGENERIC;
+
if ( p_filter->fmt_in.video.i_chroma != VLC_CODEC_D3D9_OPAQUE )
return VLC_EGENERIC;
@@ -187,13 +312,146 @@ static int OpenConverter( vlc_object_t *obj )
return VLC_EGENERIC;
}
- copy_cache_t *p_copy_cache = calloc(1, sizeof(*p_copy_cache));
- if (!p_copy_cache)
+ hd3d_dll = LoadLibrary(TEXT("D3D9.DLL"));
+ if (unlikely(!hd3d_dll)) {
+ msg_Warn(p_filter, "cannot load d3d9.dll, aborting");
+ goto done;
+ }
+
+ filter_sys_t *p_sys = calloc(1, sizeof(filter_sys_t));
+ if (!p_sys)
return VLC_ENOMEM;
- CopyInitCache(p_copy_cache, p_filter->fmt_in.video.i_width );
- p_filter->p_sys = (filter_sys_t*) p_copy_cache;
+ CopyInitCache(&p_sys->cache, p_filter->fmt_in.video.i_width );
+ p_filter->p_sys = p_sys;
+ err = VLC_SUCCESS;
+
+done:
+ if (err != VLC_SUCCESS)
+ {
+ if (hd3d_dll)
+ FreeLibrary(hd3d_dll);
+ }
+ return err;
+}
+
+static int OpenFromCPU( vlc_object_t *obj )
+{
+ filter_t *p_filter = (filter_t *)obj;
+ int err = VLC_EGENERIC;
+ LPDIRECT3DSURFACE9 texture = NULL;
+ IDirect3DDevice9 *d3ddev = NULL;
+ filter_t *p_cpu_filter = NULL;
+ picture_t *p_dst = NULL;
+ HINSTANCE hd3d_dll = NULL;
+ video_format_t fmt_staging;
+
+ if ( p_filter->fmt_out.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_in.video.i_chroma ) {
+ case VLC_CODEC_I420:
+ case VLC_CODEC_YV12:
+ p_filter->pf_video_filter = YV12_D3D9_Filter;
+ break;
+ default:
+ return VLC_EGENERIC;
+ }
+
+ picture_t *peek = filter_NewPicture(p_filter);
+ if (peek == NULL)
+ return VLC_EGENERIC;
+ if (!peek->p_sys)
+ {
+ msg_Dbg(p_filter, "D3D9 opaque without a texture");
+ return VLC_EGENERIC;
+ }
+
+ video_format_Init(&fmt_staging, 0);
+ D3DSURFACE_DESC texDesc;
+ IDirect3DSurface9_GetDesc( peek->p_sys->surface, &texDesc);
+ vlc_fourcc_t d3d_fourcc = texDesc.Format;
+ if (d3d_fourcc == 0)
+ goto done;
+
+ if ( p_filter->fmt_in.video.i_chroma != d3d_fourcc )
+ {
+ picture_resource_t res;
+ res.pf_destroy = DestroyPicture;
+ res.p_sys = calloc(1, sizeof(picture_sys_t));
+ if (res.p_sys == NULL) {
+ err = VLC_ENOMEM;
+ goto done;
+ }
+
+ video_format_Copy(&fmt_staging, &p_filter->fmt_out.video);
+ fmt_staging.i_chroma = d3d_fourcc;
+ fmt_staging.i_height = texDesc.Height;
+ fmt_staging.i_width = texDesc.Width;
+
+ p_dst = picture_NewFromResource(&fmt_staging, &res);
+ if (p_dst == NULL) {
+ msg_Err(p_filter, "Failed to map create the temporary picture.");
+ goto done;
+ }
+ picture_Setup(p_dst, &p_dst->format);
+
+ IDirect3DSurface9_GetDevice(peek->p_sys->surface, &d3ddev);
+ HRESULT hr = IDirect3DDevice9_CreateOffscreenPlainSurface(d3ddev,
+ p_dst->format.i_width,
+ p_dst->format.i_height,
+ texDesc.Format,
+ D3DPOOL_DEFAULT,
+ &texture,
+ NULL);
+ if (FAILED(hr)) {
+ msg_Err(p_filter, "Failed to create a %4.4s staging texture to extract surface pixels (hr=0x%0lx)", (char *)texDesc.Format, hr );
+ goto done;
+ }
+ res.p_sys->surface = texture;
+ IDirect3DSurface9_AddRef(texture);
+
+ p_cpu_filter = CreateFilter(VLC_OBJECT(p_filter), &p_filter->fmt_in, p_dst->format.i_chroma);
+ if (!p_cpu_filter)
+ goto done;
+ }
+
+ hd3d_dll = LoadLibrary(TEXT("D3D9.DLL"));
+ if (unlikely(!hd3d_dll)) {
+ msg_Warn(p_filter, "cannot load d3d9.dll, aborting");
+ goto done;
+ }
- return VLC_SUCCESS;
+ filter_sys_t *p_sys = calloc(1, sizeof(filter_sys_t));
+ if (!p_sys) {
+ err = VLC_ENOMEM;
+ goto done;
+ }
+ p_sys->d3ddev = d3ddev;
+ p_sys->filter = p_cpu_filter;
+ p_sys->staging = p_dst;
+ p_sys->hd3d_dll = hd3d_dll;
+ p_filter->p_sys = p_sys;
+ err = VLC_SUCCESS;
+
+done:
+ video_format_Clean(&fmt_staging);
+ picture_Release(peek);
+ if (err != VLC_SUCCESS)
+ {
+ if (d3ddev)
+ IDirect3DDevice9_Release(d3ddev);
+ if (p_cpu_filter)
+ DeleteFilter( p_cpu_filter );
+ if (texture)
+ IDirect3DSurface9_Release(texture);
+ if (hd3d_dll)
+ FreeLibrary(hd3d_dll);
+ }
+ return err;
}
static void CloseConverter( vlc_object_t *obj )
@@ -204,3 +462,27 @@ static void CloseConverter( vlc_object_t *obj )
free( p_copy_cache );
p_filter->p_sys = NULL;
}
+
+static void CloseFromCPU( vlc_object_t *obj )
+{
+ filter_t *p_filter = (filter_t *)obj;
+ filter_sys_t *p_sys = (filter_sys_t*) p_filter->p_sys;
+ DeleteFilter(p_sys->filter);
+ picture_Release(p_sys->staging);
+ IDirect3DDevice9_Release(p_sys->d3ddev);
+ FreeLibrary(p_sys->hd3d_dll);
+ free( p_sys );
+ p_filter->p_sys = NULL;
+}
+
+/*****************************************************************************
+ * Module descriptor.
+ *****************************************************************************/
+vlc_module_begin ()
+ set_description( N_("Conversions from DxVA2 to YUV") )
+ set_capability( "video converter", 10 )
+ set_callbacks( OpenConverter, CloseConverter )
+ add_submodule()
+ set_callbacks( OpenFromCPU, CloseFromCPU )
+ set_capability( "video converter", 10 )
+vlc_module_end ()
More information about the vlc-commits
mailing list