[vlc-devel] [PATCH] direct3d9: add VLC_CODEC_D3D9_OPAQUE_10B to decode 4:2:0 10 bits with DVXA2

Steve Lhomme robux4 at videolabs.io
Fri Jul 29 17:09:03 CEST 2016


---
 include/vlc_fourcc.h                   |  3 ++-
 modules/codec/avcodec/dxva2.c          | 42 +++++++++++++++++++++++++++++-----
 modules/codec/avcodec/va.c             |  9 +++++++-
 modules/video_output/win32/direct3d9.c | 29 +++++++++++++++++------
 src/misc/fourcc.c                      |  2 +-
 5 files changed, 69 insertions(+), 16 deletions(-)

diff --git a/include/vlc_fourcc.h b/include/vlc_fourcc.h
index 9a7a95c..06e0bba 100644
--- a/include/vlc_fourcc.h
+++ b/include/vlc_fourcc.h
@@ -346,7 +346,8 @@
 #define VLC_CODEC_MMAL_OPAQUE     VLC_FOURCC('M','M','A','L')
 
 /* DXVA2 opaque video surface for use with D3D9 */
-#define VLC_CODEC_D3D9_OPAQUE     VLC_FOURCC('D','X','A','9')
+#define VLC_CODEC_D3D9_OPAQUE     VLC_FOURCC('D','X','A','9') /* 4:2:0  8 bpc */
+#define VLC_CODEC_D3D9_OPAQUE_10B VLC_FOURCC('D','X','A','0') /* 4:2:0 10 bpc */
 
 /* D3D11VA opaque video surface for use with D3D11 */
 #define VLC_CODEC_D3D11_OPAQUE          VLC_FOURCC('D','X','1','1') /* 4:2:0  8 bpc */
diff --git a/modules/codec/avcodec/dxva2.c b/modules/codec/avcodec/dxva2.c
index ff05db0..936e1df 100644
--- a/modules/codec/avcodec/dxva2.c
+++ b/modules/codec/avcodec/dxva2.c
@@ -91,6 +91,7 @@ static const d3d_format_t d3d_formats[] = {
     { "YV12",   MAKEFOURCC('Y','V','1','2'),    VLC_CODEC_YV12 },
     { "NV12",   MAKEFOURCC('N','V','1','2'),    VLC_CODEC_NV12 },
     { "IMC3",   MAKEFOURCC('I','M','C','3'),    VLC_CODEC_YV12 },
+    { "P010",   MAKEFOURCC('P','0','1','0'),    VLC_CODEC_P010 },
 
     { NULL, 0, 0 }
 };
@@ -107,6 +108,7 @@ static const d3d_format_t *D3dFindFormat(D3DFORMAT format)
 struct vlc_va_sys_t
 {
     directx_sys_t         dx_sys;
+    vlc_fourcc_t          i_chroma;
 
     /* DLL */
     HINSTANCE             hd3d9_dll;
@@ -176,7 +178,7 @@ static picture_t *video_new_buffer(filter_t *p_filter)
 }
 
 static filter_t *CreateFilter( vlc_object_t *p_this, const es_format_t *p_fmt_in,
-                               vlc_fourcc_t fmt_out )
+                               vlc_fourcc_t src_chroma )
 {
     filter_t *p_filter;
 
@@ -186,9 +188,20 @@ static filter_t *CreateFilter( vlc_object_t *p_this, const es_format_t *p_fmt_in
 
     p_filter->owner.video.buffer_new = (picture_t *(*)(filter_t *))video_new_buffer;
 
+    vlc_fourcc_t fmt_out;
+    switch (src_chroma)
+    {
+    case VLC_CODEC_D3D9_OPAQUE_10B:
+        fmt_out = VLC_CODEC_P010;
+        break;
+    case VLC_CODEC_D3D9_OPAQUE:
+        fmt_out = VLC_CODEC_YV12;
+        break;
+    }
+
     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_in.i_codec  = p_filter->fmt_in.video.i_chroma  = VLC_CODEC_D3D9_OPAQUE;
+    p_filter->fmt_in.i_codec  = p_filter->fmt_in.video.i_chroma  = src_chroma;
     p_filter->fmt_out.i_codec = p_filter->fmt_out.video.i_chroma = fmt_out;
     p_filter->p_module = module_need( p_filter, "video filter2", NULL, false );
 
@@ -207,7 +220,7 @@ static void Setup(vlc_va_t *va, vlc_fourcc_t *chroma)
 {
     vlc_va_sys_t *sys = va->sys;
 
-    *chroma = sys->filter == NULL ? VLC_CODEC_D3D9_OPAQUE : VLC_CODEC_YV12;
+    *chroma = sys->filter == NULL ? sys->i_chroma : VLC_CODEC_YV12;
 }
 
 void SetupAVCodecContext(vlc_va_t *va)
@@ -228,7 +241,8 @@ static int Extract(vlc_va_t *va, picture_t *picture, uint8_t *data)
 {
     directx_sys_t *dx_sys = &va->sys->dx_sys;
     LPDIRECT3DSURFACE9 d3d = (LPDIRECT3DSURFACE9)(uintptr_t)data;
-    if (picture->format.i_chroma == VLC_CODEC_D3D9_OPAQUE)
+    if ( picture->format.i_chroma == VLC_CODEC_D3D9_OPAQUE ||
+         picture->format.i_chroma == VLC_CODEC_D3D9_OPAQUE_10B )
     {
         picture_sys_t *p_sys = picture->p_sys;
         LPDIRECT3DSURFACE9 output = p_sys->surface;
@@ -308,6 +322,20 @@ static void Close(vlc_va_t *va, AVCodecContext *ctx)
     free(sys);
 }
 
+vlc_fourcc_t d3d9va_fourcc(enum PixelFormat swfmt)
+{
+    switch (swfmt)
+    {
+        case AV_PIX_FMT_YUV420P10LE:
+            return VLC_CODEC_D3D9_OPAQUE_10B;
+        case AV_PIX_FMT_YUVJ420P:
+        case AV_PIX_FMT_YUV420P:
+            return VLC_CODEC_D3D9_OPAQUE;
+        default:
+            return VLC_CODEC_D3D9_OPAQUE;
+    }
+}
+
 static int Open(vlc_va_t *va, AVCodecContext *ctx, enum PixelFormat pix_fmt,
                 const es_format_t *fmt, picture_sys_t *p_sys)
 {
@@ -351,13 +379,15 @@ static int Open(vlc_va_t *va, AVCodecContext *ctx, enum PixelFormat pix_fmt,
     if (p_sys!=NULL)
         IDirect3DSurface9_GetDevice(p_sys->surface, (IDirect3DDevice9**) &dx_sys->d3ddev );
 
+    sys->i_chroma = d3d9va_fourcc(ctx->sw_pix_fmt);
+
     err = directx_va_Open(va, &sys->dx_sys, ctx, fmt, true);
     if (err!=VLC_SUCCESS)
         goto error;
 
     if (p_sys == NULL)
     {
-        sys->filter = CreateFilter( VLC_OBJECT(va), fmt, VLC_CODEC_YV12);
+        sys->filter = CreateFilter( VLC_OBJECT(va), fmt, sys->i_chroma);
         if (sys->filter == NULL)
             goto error;
     }
@@ -790,7 +820,7 @@ static int DxResetVideoDecoder(vlc_va_t *va)
 static picture_t *DxAllocPicture(vlc_va_t *va, const video_format_t *fmt, unsigned index)
 {
     video_format_t src_fmt = *fmt;
-    src_fmt.i_chroma = VLC_CODEC_D3D9_OPAQUE;
+    src_fmt.i_chroma = va->sys->i_chroma;
     picture_sys_t *pic_sys = calloc(1, sizeof(*pic_sys));
     if (unlikely(pic_sys == NULL))
         return NULL;
diff --git a/modules/codec/avcodec/va.c b/modules/codec/avcodec/va.c
index 0ca991a..8a6b549 100644
--- a/modules/codec/avcodec/va.c
+++ b/modules/codec/avcodec/va.c
@@ -41,7 +41,14 @@ 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_D3D9_OPAQUE;
+            switch (swfmt)
+            {
+                case AV_PIX_FMT_YUV420P10LE:
+                    return VLC_CODEC_D3D9_OPAQUE_10B;
+                default:
+                    return VLC_CODEC_D3D9_OPAQUE;
+            }
+            break;
 
 #if LIBAVUTIL_VERSION_CHECK(54, 13, 1, 24, 100)
         case AV_PIX_FMT_D3D11VA_VLD:
diff --git a/modules/video_output/win32/direct3d9.c b/modules/video_output/win32/direct3d9.c
index 9372875..1f86c70 100644
--- a/modules/video_output/win32/direct3d9.c
+++ b/modules/video_output/win32/direct3d9.c
@@ -153,6 +153,18 @@ static void Direct3D9RenderScene(vout_display_t *vd, d3d_region_t *, int, d3d_re
 /* */
 static int DesktopCallback(vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void *);
 
+static bool is_d3d9_opaque(vlc_fourcc_t chroma)
+{
+    switch (chroma)
+    {
+    case VLC_CODEC_D3D9_OPAQUE:
+    case VLC_CODEC_D3D9_OPAQUE_10B:
+        return true;
+    default:
+        return false;
+    }
+}
+
 /**
  * It creates a Direct3D vout display.
  */
@@ -202,10 +214,10 @@ static int Open(vlc_object_t *object)
 
     /* */
     vout_display_info_t info = vd->info;
-    info.is_slow = fmt.i_chroma != VLC_CODEC_D3D9_OPAQUE;
+    info.is_slow = !is_d3d9_opaque(fmt.i_chroma);
     info.has_double_click = true;
     info.has_hide_mouse = false;
-    info.has_pictures_invalid = fmt.i_chroma != VLC_CODEC_D3D9_OPAQUE;
+    info.has_pictures_invalid = !is_d3d9_opaque(fmt.i_chroma);
     info.has_event_thread = true;
     if (var_InheritBool(vd, "direct3d9-hw-blending") &&
         sys->d3dregion_format != D3DFMT_UNKNOWN &&
@@ -291,6 +303,8 @@ static picture_pool_t *Pool(vout_display_t *vd, unsigned count)
     pictures = calloc(count, sizeof(*pictures));
     if (!pictures)
         goto error;
+
+    D3DFORMAT format = vd->fmt.i_chroma == VLC_CODEC_D3D9_OPAQUE_10B ? MAKEFOURCC('P','0','1','0') : MAKEFOURCC('N','V','1','2');
     for (picture_count = 0; picture_count < count; ++picture_count)
     {
         picture_sys_t *picsys = malloc(sizeof(*picsys));
@@ -300,7 +314,7 @@ static picture_pool_t *Pool(vout_display_t *vd, unsigned count)
         HRESULT hr = IDirect3DDevice9_CreateOffscreenPlainSurface(vd->sys->d3ddev,
                                                           vd->fmt.i_width,
                                                           vd->fmt.i_height,
-                                                          MAKEFOURCC('N','V','1','2'),
+                                                          format,
                                                           D3DPOOL_DEFAULT,
                                                           &picsys->surface,
                                                           NULL);
@@ -352,7 +366,7 @@ static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpic
      *  The clean way would be to release the picture (and ensure that
      * the vout doesn't keep a reference). But because of the vout
      * wrapper, we can't */
-    if ( picture->format.i_chroma != VLC_CODEC_D3D9_OPAQUE )
+    if ( !is_d3d9_opaque(picture->format.i_chroma) )
         Direct3D9UnlockSurface(picture);
 
     /* check if device is still available */
@@ -418,7 +432,7 @@ static void Display(vout_display_t *vd, picture_t *picture, subpicture_t *subpic
     }
 
     /* XXX See Prepare() */
-    if ( picture->format.i_chroma != VLC_CODEC_D3D9_OPAQUE )
+    if ( !is_d3d9_opaque(picture->format.i_chroma) )
         Direct3D9LockSurface(picture);
     picture_Release(picture);
     if (subpicture)
@@ -965,6 +979,7 @@ static const d3d_format_t d3d_formats[] = {
     { "YV12",       MAKEFOURCC('Y','V','1','2'),    VLC_CODEC_J420,  0,0,0 },
     { "NV12",       MAKEFOURCC('N','V','1','2'),    VLC_CODEC_NV12,  0,0,0 },
     { "DXA9",       MAKEFOURCC('N','V','1','2'),    VLC_CODEC_D3D9_OPAQUE,  0,0,0 },
+    { "DXA9_10",    MAKEFOURCC('P','0','1','0'),    VLC_CODEC_D3D9_OPAQUE_10B,  0,0,0 },
     { "UYVY",       D3DFMT_UYVY,    VLC_CODEC_UYVY,  0,0,0 },
     { "YUY2",       D3DFMT_YUY2,    VLC_CODEC_YUYV,  0,0,0 },
     { "X8R8G8B8",   D3DFMT_X8R8G8B8,VLC_CODEC_RGB32, 0xff0000, 0x00ff00, 0x0000ff },
@@ -986,7 +1001,7 @@ static const d3d_format_t *Direct3DFindFormat(vout_display_t *vd, vlc_fourcc_t c
         const vlc_fourcc_t *list;
         const vlc_fourcc_t dxva_chroma[] = {chroma, 0};
 
-        if (pass == 0 && chroma == VLC_CODEC_D3D9_OPAQUE)
+        if (pass == 0 && is_d3d9_opaque(chroma))
             list = dxva_chroma;
         else if (pass == 0 && sys->allow_hw_yuv && vlc_fourcc_IsYUV(chroma))
             list = vlc_fourcc_GetYUVFallback(chroma);
@@ -1074,7 +1089,7 @@ static int Direct3D9CreatePool(vout_display_t *vd, video_format_t *fmt)
     fmt->i_gmask  = d3dfmt->gmask;
     fmt->i_bmask  = d3dfmt->bmask;
 
-    if ( fmt->i_chroma == VLC_CODEC_D3D9_OPAQUE )
+    if ( is_d3d9_opaque(fmt->i_chroma) )
         /* a DXA9 pool will be created when needed */
         return VLC_SUCCESS;
 
diff --git a/src/misc/fourcc.c b/src/misc/fourcc.c
index 45ac301..9e42045 100644
--- a/src/misc/fourcc.c
+++ b/src/misc/fourcc.c
@@ -664,7 +664,7 @@ static const struct
     { { VLC_CODEC_ANDROID_OPAQUE, VLC_CODEC_MMAL_OPAQUE,
         VLC_CODEC_D3D9_OPAQUE,    VLC_CODEC_D3D11_OPAQUE },
                                                FAKE_FMT() },
-    { { VLC_CODEC_D3D11_OPAQUE_10B },
+    { { VLC_CODEC_D3D11_OPAQUE_10B, VLC_CODEC_D3D9_OPAQUE_10B },
                                                FAKE_FMT() },
     { { VLC_CODEC_CVPX_OPAQUE },               FAKE_FMT() },
 
-- 
2.8.2



More information about the vlc-devel mailing list