[vlc-commits] [Git][videolan/vlc][master] 10 commits: access: screen: set the output DTS on the proper tick

François Cartegnie (@fcartegnie) gitlab at videolan.org
Thu Mar 10 22:36:20 UTC 2022



François Cartegnie pushed to branch master at VideoLAN / VLC


Commits:
d13e08b0 by Steve Lhomme at 2022-03-10T22:17:51+00:00
access: screen: set the output DTS on the proper tick

If the capture took too long we need to adjust which frame the capture belongs
to.

- - - - -
7915f5d3 by Steve Lhomme at 2022-03-10T22:17:51+00:00
access: screen: turn the sub-function calls into operations

Simplify the close callback which only needs to clean the screen_data_t.

- - - - -
90ac4d16 by Steve Lhomme at 2022-03-10T22:17:51+00:00
d3d11_fmt: allow creating pictures with shared texture

This is useful when textures come from a different Adapter/GPU or the bogus
access with GPU output.

- - - - -
cd62b12b by Steve Lhomme at 2022-03-10T22:17:51+00:00
access: split the Windows and Mac modules

- - - - -
9179497c by Steve Lhomme at 2022-03-10T22:17:51+00:00
access: add a screen graber from DXGI rather than the GDI

The DXGI code is always compiled on Windows as it's only using calls available
since Windows 7, although IDXGIOutputDuplication will not be available.

The block_t sent contains a D3D11-based picture_t that can be used without
any additional copy using the shared handle.

- - - - -
73895883 by Steve Lhomme at 2022-03-10T22:17:51+00:00
hw:d3d11: add a filter to turn D3D11 block into a picture

- - - - -
3fe7d92e by Steve Lhomme at 2022-03-10T22:17:51+00:00
access: screen: move the win32 cursor blending code in the GDI code

- - - - -
0afe4c14 by Steve Lhomme at 2022-03-10T22:17:51+00:00
access: screen: fix code usage depending on the defines

- - - - -
33fd050e by Steve Lhomme at 2022-03-10T22:17:51+00:00
access: screen: move the screen-display-id/screen-index handling in mac code

- - - - -
a84e2e72 by Steve Lhomme at 2022-03-10T22:17:51+00:00
access: screen: limit the mouse to win32

The mac module shouldn't present the mouse options if it doesn't handle them.

- - - - -


15 changed files:

- modules/access/Makefile.am
- + modules/access/screen/dxgi.cpp
- modules/access/screen/mac.c
- modules/access/screen/screen.c
- modules/access/screen/screen.h
- modules/access/screen/win32.c
- modules/hw/d3d11/Makefile.am
- + modules/hw/d3d11/d3d11_decoder.cpp
- modules/hw/d3d11/d3d11_deinterlace.c
- modules/hw/d3d11/d3d11_filters.c
- modules/hw/d3d11/d3d11_filters.h
- modules/hw/d3d11/d3d11_surface.c
- modules/video_chroma/d3d11_fmt.c
- modules/video_chroma/d3d11_fmt.h
- modules/video_output/win32/direct3d11.cpp


Changes:

=====================================
modules/access/Makefile.am
=====================================
@@ -196,16 +196,24 @@ BUILT_SOURCES += access/screen/screenshooter-client-protocol.h
 access_LTLIBRARIES += libwl_screenshooter_plugin.la
 endif
 
-libscreen_plugin_la_SOURCES = access/screen/screen.c access/screen/screen.h
-libscreen_plugin_la_LDFLAGS = $(AM_LDFLAGS)
+libscreen_win_plugin_la_SOURCES = access/screen/screen.c access/screen/screen.h \
+	access/screen/dxgi.cpp
+libscreen_win_plugin_la_LIBADD = libd3d11_common.la $(LIBCOM) -luuid
+if HAVE_WINSTORE
+libscreen_win_plugin_la_LIBADD += -ld3d11
+endif
 if HAVE_WIN32_DESKTOP
-libscreen_plugin_la_SOURCES += access/screen/win32.c
-libscreen_plugin_la_LIBADD = -lgdi32
-access_LTLIBRARIES += libscreen_plugin.la
+libscreen_win_plugin_la_SOURCES += access/screen/win32.c
+libscreen_win_plugin_la_LIBADD += -lgdi32
 endif
+if HAVE_WIN32
+access_LTLIBRARIES += libscreen_win_plugin.la
+endif
+
 if HAVE_MAC_SCREEN
-libscreen_plugin_la_SOURCES += access/screen/mac.c
-libscreen_plugin_la_LDFLAGS += "-Wl,-framework,OpenGL,-framework,ApplicationServices"
+libscreen_plugin_la_SOURCES = access/screen/screen.c access/screen/screen.h \
+	access/screen/mac.c
+libscreen_plugin_la_LDFLAGS = $(AM_LDFLAGS) "-Wl,-framework,OpenGL,-framework,ApplicationServices"
 access_LTLIBRARIES += libscreen_plugin.la
 endif
 


=====================================
modules/access/screen/dxgi.cpp
=====================================
@@ -0,0 +1,304 @@
+/*****************************************************************************
+ * dxgi.cpp: Screen capture module for DXGI.
+ *****************************************************************************
+ * Copyright (C) 2018-2022 VLC authors and VideoLAN
+ *
+ * Authors: Steve Lhomme <robux4 at gmail.com>
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+
+#include "screen.h"
+
+#include "../../video_chroma/d3d11_fmt.h"
+
+#include <d3d11_1.h>
+
+#include <new>
+
+#include <wrl/client.h>
+using Microsoft::WRL::ComPtr;
+
+struct screen_data_t
+{
+    const d3d_format_t             *output_format = nullptr;
+    vlc_video_context              *vctx = nullptr;
+
+    int screen_x = 0;
+    int screen_y = 0;
+
+    ComPtr<IDXGIOutputDuplication> duplication;
+
+    ~screen_data_t()
+    {
+        if (vctx)
+            vlc_video_context_Release(vctx);
+    }
+};
+
+static void CaptureBlockRelease( block_t *p_block )
+{
+    block_sys_d3d11_t *d3d11_block = D3D11BLOCK_FROM_BLOCK(p_block);
+    picture_Release(d3d11_block->d3d11_pic);
+    delete d3d11_block;
+}
+
+static block_t *screen_Capture(demux_t *p_demux)
+{
+    demux_sys_t *p_sys = static_cast<demux_sys_t*>(p_demux->p_sys);
+    screen_data_t *p_data = p_sys->p_data;
+    block_sys_d3d11_t *d3d11_block = new (std::nothrow) block_sys_d3d11_t();
+    ComPtr<IDXGIResource> resource;
+    ComPtr<ID3D11Resource> d3d11res;
+    picture_sys_d3d11_t *pic_sys;
+    D3D11_BOX copyBox;
+
+    if( unlikely(d3d11_block == nullptr) )
+        return nullptr;
+
+    d3d11_decoder_device_t *d3d_dev = GetD3D11OpaqueContext(p_data->vctx);
+
+    static const struct vlc_frame_callbacks cbs = {
+        CaptureBlockRelease,
+    };
+    block_Init( &d3d11_block->self, &cbs, nullptr, 1 );
+
+    d3d11_block->d3d11_pic = D3D11_AllocPicture(VLC_OBJECT(p_demux),
+                                                &p_sys->fmt.video, p_data->vctx,
+                                                true, p_data->output_format);
+    if ( d3d11_block->d3d11_pic == nullptr )
+    {
+        msg_Err(p_demux, "Failed to allocate the output texture");
+        goto error;
+    }
+
+    DXGI_OUTDUPL_FRAME_INFO frameInfo;
+    HRESULT hr;
+    hr = p_data->duplication->AcquireNextFrame(1000, &frameInfo, &resource);
+    if (FAILED(hr))
+    {
+        msg_Err(p_demux, "Failed to capture a frame. (hr=0x%lX)", hr);
+        goto error;
+    }
+
+#if defined(SCREEN_SUBSCREEN) && !defined(VLC_WINSTORE_APP)
+    if( p_sys->b_follow_mouse )
+    {
+        POINT pos;
+        GetCursorPos( &pos );
+        pos.x -= p_data->screen_x;
+        pos.y -= p_data->screen_y;
+        FollowMouse( p_sys, pos.x, pos.y );
+    }
+#endif // SCREEN_SUBSCREEN && !VLC_WINSTORE_APP
+
+    /* copy the texture into the block texture */
+    hr = resource.As(&d3d11res);
+    if (unlikely(FAILED(hr)))
+    {
+        msg_Err(p_demux, "Failed to get the texture. (hr=0x%lX)", hr);
+        goto error;
+    }
+    pic_sys = ActiveD3D11PictureSys(d3d11_block->d3d11_pic);
+#ifdef SCREEN_SUBSCREEN
+    copyBox.left   = p_sys->i_left;
+    copyBox.right  = copyBox.left + p_sys->i_width;
+    copyBox.top    = p_sys->i_top;
+    copyBox.bottom = copyBox.top + p_sys->i_height;
+#else // !SCREEN_SUBSCREEN
+    copyBox.left   = 0;
+    copyBox.right  = p_sys->fmt.video.i_width;
+    copyBox.top    = 0;
+    copyBox.bottom = p_sys->fmt.video.i_height;
+#endif // !SCREEN_SUBSCREEN
+    copyBox.front = 0;
+    copyBox.back = 1;
+    d3d11_device_lock( &d3d_dev->d3d_dev );
+    d3d_dev->d3d_dev.d3dcontext->CopySubresourceRegion(
+                                              pic_sys->resource[KNOWN_DXGI_INDEX], 0,
+                                              0, 0, 0,
+                                              d3d11res.Get(), 0,
+                                              &copyBox);
+    p_data->duplication->ReleaseFrame();
+
+    // TODO mouse blending
+
+    d3d11_device_unlock( &d3d_dev->d3d_dev );
+
+    return &d3d11_block->self;
+error:
+    if (d3d11_block->d3d11_pic)
+        picture_Release(d3d11_block->d3d11_pic);
+    delete d3d11_block;
+    return nullptr;
+}
+
+static void screen_CloseCapture(screen_data_t *p_data)
+{
+    delete p_data;
+}
+
+int screen_InitCaptureDXGI(demux_t *p_demux)
+{
+    demux_sys_t *p_sys = static_cast<demux_sys_t*>(p_demux->p_sys);
+    screen_data_t *p_data;
+    vlc_decoder_device *dec_dev;
+    HRESULT hr;
+
+    if (var_CreateGetInteger( p_demux, "screen-fragment-size" ) != 0)
+    {
+        msg_Dbg(p_demux, "screen-fragment-size not supported in DXGI");
+        return VLC_ENOTSUP;
+    }
+
+    char *mousefile = var_InheritString( p_demux, "screen-mouse-image" );
+    free( mousefile );
+    if (mousefile)
+    {
+        msg_Dbg(p_demux, "screen-mouse-image not supported in DXGI");
+        return VLC_ENOTSUP;
+    }
+
+#ifdef VLC_WINSTORE_APP
+    if (p_sys->b_follow_mouse)
+    {
+        msg_Dbg(p_demux, "screen-follow-mouse not supported in UWP DXGI");
+        return VLC_ENOTSUP;
+    }
+#endif // VLC_WINSTORE_APP
+
+    p_data = new (std::nothrow) screen_data_t();
+    if (unlikely(p_data == nullptr))
+        return VLC_ENOMEM;
+
+#ifndef VLC_WINSTORE_APP
+    p_data->screen_x = GetSystemMetrics( SM_XVIRTUALSCREEN );
+    p_data->screen_y = GetSystemMetrics( SM_YVIRTUALSCREEN );
+#endif
+
+    dec_dev = vlc_decoder_device_Create(VLC_OBJECT(p_demux), nullptr);
+    d3d11_decoder_device_t *d3d11_dev = GetD3D11OpaqueDevice(dec_dev);
+    if (d3d11_dev == nullptr)
+    {
+        msg_Err(p_demux, "incompatible decoder device.");
+    }
+    else
+    {
+        ComPtr<ID3D11Device1> d3d11VLC1;
+        hr = d3d11_dev->d3d_dev.d3ddevice->QueryInterface(IID_GRAPHICS_PPV_ARGS(&d3d11VLC1));
+        if (FAILED(hr)) {
+            msg_Warn(p_demux, "D3D11 device cannot share textures. (hr=0x%lX)", hr);
+            goto error;
+        }
+
+        ComPtr<IDXGIDevice> pDXGIDevice;
+        HRESULT hr = d3d11_dev->d3d_dev.d3ddevice->QueryInterface(IID_GRAPHICS_PPV_ARGS(&pDXGIDevice));
+        if (FAILED(hr)) {
+            goto error;
+        }
+
+        ComPtr<IDXGIAdapter> adapter;
+        hr = pDXGIDevice->GetAdapter(&adapter);
+        if (FAILED(hr)) {
+            goto error;
+        }
+
+        ComPtr<IDXGIOutput1> output1;
+        for (UINT j=0; output1.Get()==nullptr; j++)
+        {
+            ComPtr<IDXGIOutput> output;
+            hr = adapter->EnumOutputs(j, &output);
+            if (FAILED(hr))
+                break;
+
+            hr = output.As(&output1);
+            if (FAILED(hr))
+                continue;
+
+            hr = output1->DuplicateOutput(d3d11_dev->d3d_dev.d3ddevice, &p_data->duplication);
+            if (FAILED(hr))
+                output1.Reset();
+        }
+    }
+
+    if (!p_data->duplication)
+        goto error;
+
+    DXGI_OUTDUPL_DESC outDesc;
+    p_data->duplication->GetDesc(&outDesc);
+
+    for (p_data->output_format = DxgiGetRenderFormatList();
+         p_data->output_format->name != nullptr; ++p_data->output_format)
+    {
+        if (p_data->output_format->formatTexture == outDesc.ModeDesc.Format &&
+            is_d3d11_opaque(p_data->output_format->fourcc))
+            break;
+    }
+    if (unlikely(!p_data->output_format->name))
+    {
+        msg_Err(p_demux, "Unknown texture format %d", outDesc.ModeDesc.Format);
+        goto error;
+    }
+
+    p_data->vctx = D3D11CreateVideoContext(dec_dev, p_data->output_format->formatTexture);
+    vlc_decoder_device_Release(dec_dev);
+    dec_dev = nullptr;
+    if (unlikely(p_data->vctx == nullptr))
+        goto error;
+
+    es_format_Init( &p_sys->fmt, VIDEO_ES, p_data->output_format->fourcc );
+    p_sys->fmt.video.i_visible_width    =
+    p_sys->fmt.video.i_width            = outDesc.ModeDesc.Width;
+    p_sys->fmt.video.i_visible_height   =
+    p_sys->fmt.video.i_height           = outDesc.ModeDesc.Height;
+    p_sys->fmt.video.i_bits_per_pixel   = 4 * p_data->output_format->bitsPerChannel; /* FIXME */
+    p_sys->fmt.video.i_sar_num = p_sys->fmt.video.i_sar_den = 1;
+    p_sys->fmt.video.i_chroma           = p_sys->fmt.i_codec;
+    p_sys->fmt.video.color_range        = COLOR_RANGE_FULL;
+    p_sys->fmt.video.i_frame_rate       = outDesc.ModeDesc.RefreshRate.Numerator;
+    p_sys->fmt.video.i_frame_rate_base  = outDesc.ModeDesc.RefreshRate.Denominator;
+    DxgiFormatMask( outDesc.ModeDesc.Format, &p_sys->fmt.video );
+
+    p_sys->p_data = p_data;
+    static const screen_capture_operations ops = {
+        screen_Capture, screen_CloseCapture,
+    };
+    p_sys->ops = &ops;
+
+    return VLC_SUCCESS;
+error:
+    if (dec_dev)
+        vlc_decoder_device_Release(dec_dev);
+    delete p_data;
+    return VLC_EGENERIC;
+}
+
+int screen_InitCapture(demux_t *p_demux)
+{
+    int ret = screen_InitCaptureDXGI(p_demux);
+    if (ret == VLC_SUCCESS)
+        return VLC_SUCCESS;
+#if defined(_WIN32) && !defined(VLC_WINSTORE_APP)
+    return screen_InitCaptureGDI(p_demux);
+#else
+    return ret;
+#endif
+}


=====================================
modules/access/screen/mac.c
=====================================
@@ -42,6 +42,10 @@
 extern int CGSMainConnectionID();
 extern CGImageRef CGSCreateRegisteredCursorImage(int, char*, CGPoint*);
 
+static void screen_CloseCapture(screen_data_t *);
+static block_t *screen_Capture(demux_t *);
+
+
 struct screen_data_t
 {
     block_t *p_block;
@@ -69,11 +73,16 @@ int screen_InitCapture(demux_t *p_demux)
     demux_sys_t *p_sys = p_demux->p_sys;
     screen_data_t *p_data;
     CGLError returnedError;
+    unsigned int i_display_id;
+    unsigned int i_screen_index;
 
     p_sys->p_data = p_data = calloc(1, sizeof(screen_data_t));
     if (!p_data)
         return VLC_ENOMEM;
 
+    i_display_id = var_CreateGetInteger( p_demux, "screen-display-id" );
+    i_screen_index = var_CreateGetInteger( p_demux, "screen-index" );
+
     /* fetch the screen we should capture */
     p_data->display_id = kCGDirectMainDisplay;
     p_data->rate = var_InheritFloat(p_demux, "screen-fps");
@@ -85,15 +94,15 @@ int screen_InitCapture(demux_t *p_demux)
         ids = vlc_alloc(displayCount, sizeof(CGDirectDisplayID));
         returnedError = CGGetOnlineDisplayList(displayCount, ids, &displayCount);
         if (!returnedError) {
-            if (p_sys->i_display_id > 0) {
+            if (i_display_id > 0) {
                 for (unsigned int i = 0; i < displayCount; i++) {
-                    if (p_sys->i_display_id == ids[i]) {
+                    if (i_display_id == ids[i]) {
                         p_data->display_id = ids[i];
                         break;
                     }
                 }
-            } else if (p_sys->i_screen_index > 0 && p_sys->i_screen_index <= displayCount)
-                p_data->display_id = ids[p_sys->i_screen_index - 1];
+            } else if (i_screen_index > 0 && i_screen_index <= displayCount)
+                p_data->display_id = ids[i_screen_index - 1];
         }
         free(ids);
     }
@@ -105,9 +114,12 @@ int screen_InitCapture(demux_t *p_demux)
     p_data->screen_width = rect.size.width;
     p_data->screen_height = rect.size.height;
 
+#ifdef SCREEN_SUBSCREEN
     p_data->width = p_sys->i_width;
     p_data->height = p_sys->i_height;
-    if (p_data->width <= 0 || p_data->height <= 0) {
+    if (p_data->width <= 0 || p_data->height <= 0)
+#endif
+    {
         p_data->width = p_data->screen_width;
         p_data->height = p_data->screen_height;
     }
@@ -128,14 +140,16 @@ int screen_InitCapture(demux_t *p_demux)
     p_sys->fmt.video.i_frame_rate      = 1000 * p_data->rate;
     p_sys->fmt.video.i_frame_rate_base = 1000;
 
+    static const struct screen_capture_operations ops = {
+        screen_Capture, screen_CloseCapture,
+    };
+    p_sys->ops = &ops;
+
     return VLC_SUCCESS;
 }
 
-int screen_CloseCapture(demux_t *p_demux)
+static static void screen_CloseCapture(screen_data_t *p_data)
 {
-    demux_sys_t *p_sys = p_demux->p_sys;
-    screen_data_t *p_data = p_sys->p_data;
-
     if (p_data->offscreen_context)
         CFRelease(p_data->offscreen_context);
 
@@ -146,8 +160,6 @@ int screen_CloseCapture(demux_t *p_demux)
         block_Release(p_data->p_block);
 
     free(p_data);
-
-    return VLC_SUCCESS;
 }
 
 block_t *screen_Capture(demux_t *p_demux)
@@ -168,11 +180,16 @@ block_t *screen_Capture(demux_t *p_demux)
     cursor_pos.x -= p_data->screen_left;
     cursor_pos.y -= p_data->screen_top;
 
+#ifdef SCREEN_SUBSCREEN
     if (p_sys->b_follow_mouse)
         FollowMouse(p_sys, cursor_pos.x, cursor_pos.y);
 
     capture_rect.origin.x = p_sys->i_left;
     capture_rect.origin.y = p_sys->i_top;
+#else // !SCREEN_SUBSCREEN
+    capture_rect.origin.x = 0;
+    capture_rect.origin.y = 0;
+#endif // !SCREEN_SUBSCREEN
     capture_rect.size.width = p_data->width;
     capture_rect.size.height = p_data->height;
 
@@ -219,9 +236,15 @@ block_t *screen_Capture(demux_t *p_demux)
     CGRect cursor_rect;
     cursor_rect.size.width = CGImageGetWidth(cursor_image);
     cursor_rect.size.height = CGImageGetHeight(cursor_image);
+#ifdef SCREEN_SUBSCREEN
     cursor_rect.origin.x = cursor_pos.x - p_sys->i_left - outHotSpot.x;
     cursor_rect.origin.y = p_data->offscreen_rect.size.height
         - (cursor_pos.y + cursor_rect.size.height - p_sys->i_top - outHotSpot.y);
+#else // !SCREEN_SUBSCREEN
+    cursor_rect.origin.x = cursor_pos.x - outHotSpot.x;
+    cursor_rect.origin.y = p_data->offscreen_rect.size.height
+        - (cursor_pos.y + cursor_rect.size.height - outHotSpot.y);
+#endif // !SCREEN_SUBSCREEN
 
     CGContextDrawImage(p_data->offscreen_context, p_data->offscreen_rect, image);
     CGContextDrawImage(p_data->offscreen_context, cursor_rect, cursor_image);


=====================================
modules/access/screen/screen.c
=====================================
@@ -35,6 +35,9 @@
 #include <vlc_filter.h>
 #include <vlc_url.h>
 #include "screen.h"
+#ifdef SCREEN_MOUSE
+#   include <vlc_image.h>
+#endif
 
 /*****************************************************************************
  * Module descriptor
@@ -75,7 +78,7 @@
     "capture." )
 #endif
 
-#ifdef SCREEN_DISPLAY_ID
+#ifdef __APPLE__
 #define DISPLAY_ID_TEXT N_( "Display ID" )
 #define DISPLAY_ID_LONGTEXT N_( \
     "Display ID. If not specified, main display ID is used." )
@@ -118,7 +121,7 @@ vlc_module_begin ()
     add_integer( "screen-fragment-size", 0, FRAGS_TEXT, FRAGS_LONGTEXT )
 #endif
 
-#ifdef SCREEN_DISPLAY_ID
+#ifdef __APPLE__
     add_integer( "screen-display-id", 0, DISPLAY_ID_TEXT, DISPLAY_ID_LONGTEXT )
     add_integer( "screen-index", 0, INDEX_TEXT, INDEX_LONGTEXT )
 #endif
@@ -163,11 +166,6 @@ static int Open( vlc_object_t *p_this )
     p_sys->i_height = var_CreateGetInteger( p_demux, "screen-height" );
 #endif
 
-#ifdef SCREEN_DISPLAY_ID
-    p_sys->i_display_id = var_CreateGetInteger( p_demux, "screen-display-id" );
-    p_sys->i_screen_index = var_CreateGetInteger( p_demux, "screen-index" );
-#endif
-
     if( screen_InitCapture( p_demux ) != VLC_SUCCESS )
     {
         free( p_sys );
@@ -256,16 +254,11 @@ static void Close( vlc_object_t *p_this )
     demux_t     *p_demux = (demux_t*)p_this;
     demux_sys_t *p_sys = p_demux->p_sys;
 
-    screen_CloseCapture( p_demux );
+    if (p_sys->ops)
+        p_sys->ops->close( p_sys->p_data );
 #ifdef SCREEN_MOUSE
     if( p_sys->p_mouse )
         picture_Release( p_sys->p_mouse );
-    if( p_sys->p_blend )
-    {
-        filter_Close( p_sys->p_blend );
-        module_unneed( p_sys->p_blend, p_sys->p_blend->p_module );
-        vlc_object_delete(p_sys->p_blend);
-    }
 #endif
     free( p_sys );
 }
@@ -281,17 +274,22 @@ static int Demux( demux_t *p_demux )
     if( !p_sys->i_next_date ) p_sys->i_next_date = vlc_tick_now();
 
     /* Frame skipping if necessary */
-    while( vlc_tick_now() >= p_sys->i_next_date + p_sys->i_incr )
-        p_sys->i_next_date += p_sys->i_incr;
+    int64_t extra_frames;
+    extra_frames = (vlc_tick_now() - p_sys->i_next_date) / p_sys->i_incr;
+    p_sys->i_next_date += extra_frames * p_sys->i_incr;
 
     vlc_tick_wait( p_sys->i_next_date );
-    p_block = screen_Capture( p_demux );
+    p_block = p_sys->ops->capture( p_demux );
     if( !p_block )
     {
         p_sys->i_next_date += p_sys->i_incr;
         return 1;
     }
 
+    // ensure the output DTS matches our ticks if the capture took too long
+    extra_frames = (vlc_tick_now() - p_sys->i_next_date) / p_sys->i_incr;
+    p_sys->i_next_date += extra_frames * p_sys->i_incr;
+
     p_block->i_dts = p_block->i_pts = p_sys->i_next_date;
 
     es_out_SetPCR( p_demux->out, p_block->i_pts );
@@ -350,66 +348,3 @@ void FollowMouse( demux_sys_t *p_sys, int i_x, int i_y )
     p_sys->i_screen_height - p_sys->i_height );
 }
 #endif
-
-#ifdef SCREEN_MOUSE
-void RenderCursor( demux_t *p_demux, int i_x, int i_y,
-                   uint8_t *p_dst )
-{
-    demux_sys_t *p_sys = p_demux->p_sys;
-    if( !p_sys->dst.i_planes )
-        picture_Setup( &p_sys->dst, &p_sys->fmt.video );
-
-    if( !p_sys->dst.i_planes )
-        return;
-
-#ifdef _WIN32
-    /* Bitmaps here created by CreateDIBSection: stride rounded up to the nearest DWORD */
-    p_sys->dst.p[ 0 ].i_pitch = p_sys->dst.p[ 0 ].i_visible_pitch =
-        ( ( ( ( p_sys->fmt.video.i_width * p_sys->fmt.video.i_bits_per_pixel ) + 31 ) & ~31 ) >> 3 );
-#endif
-
-    if( !p_sys->p_blend )
-    {
-        p_sys->p_blend = vlc_object_create( p_demux, sizeof(filter_t) );
-        if( p_sys->p_blend )
-        {
-            es_format_Init( &p_sys->p_blend->fmt_in, VIDEO_ES,
-                            VLC_CODEC_RGBA );
-            p_sys->p_blend->fmt_in.video = p_sys->p_mouse->format;
-            p_sys->p_blend->fmt_out = p_sys->fmt;
-            p_sys->p_blend->p_module =
-                module_need( p_sys->p_blend, "video blending", NULL, false );
-            if( !p_sys->p_blend->p_module )
-            {
-                msg_Err( p_demux, "Could not load video blending module" );
-                vlc_object_delete(p_sys->p_blend);
-                p_sys->p_blend = NULL;
-            }
-            assert( p_sys->p_blend->ops != NULL );
-        }
-    }
-    if( p_sys->p_blend )
-    {
-        p_sys->dst.p->p_pixels = p_dst;
-        p_sys->p_blend->ops->blend_video( p_sys->p_blend,
-                                        &p_sys->dst,
-                                        p_sys->p_mouse,
-#ifdef SCREEN_SUBSCREEN
-                                        i_x-p_sys->i_left,
-#else
-                                        i_x,
-#endif
-#ifdef SCREEN_SUBSCREEN
-                                        i_y-p_sys->i_top,
-#else
-                                        i_y,
-#endif
-                                        255 );
-    }
-    else
-    {
-        picture_Release( p_sys->p_mouse );
-        p_sys->p_mouse = NULL;
-    }
-}
-#endif


=====================================
modules/access/screen/screen.h
=====================================
@@ -25,19 +25,23 @@
 #include <vlc_access.h>
 #include <vlc_demux.h>
 
-#ifdef __APPLE__
-#   define SCREEN_DISPLAY_ID
-#endif
-
 #define SCREEN_SUBSCREEN
+#ifdef _WIN32
 #define SCREEN_MOUSE
+#endif
 
-#ifdef SCREEN_MOUSE
-#   include <vlc_image.h>
+#ifdef __cplusplus
+extern "C" {
 #endif
 
 typedef struct screen_data_t screen_data_t;
 
+struct screen_capture_operations
+{
+    block_t* (*capture)( demux_t * );
+    void (*close)( screen_data_t * );
+};
+
 typedef struct
 {
     es_format_t fmt;
@@ -62,25 +66,22 @@ typedef struct
 
 #ifdef SCREEN_MOUSE
     picture_t *p_mouse;
-    filter_t *p_blend;
     picture_t dst;
 #endif
 
-#ifdef SCREEN_DISPLAY_ID
-  unsigned int i_display_id;
-  unsigned int i_screen_index;
-#endif
-
     screen_data_t *p_data;
+    const struct screen_capture_operations *ops;
 } demux_sys_t;
 
 int      screen_InitCapture ( demux_t * );
-int      screen_CloseCapture( demux_t * );
-block_t *screen_Capture( demux_t * );
+#if defined(_WIN32) && !defined(VLC_WINSTORE_APP)
+int      screen_InitCaptureGDI ( demux_t * );
+#endif
 
 #ifdef SCREEN_SUBSCREEN
 void FollowMouse( demux_sys_t *, int, int );
 #endif
-#ifdef SCREEN_MOUSE
-void RenderCursor( demux_t *, int, int, uint8_t * );
+
+#ifdef __cplusplus
+}
 #endif


=====================================
modules/access/screen/win32.c
=====================================
@@ -29,9 +29,16 @@
 #endif
 
 #include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_modules.h>                 /* module_need for "video blending" */
+#include <vlc_filter.h>
 
 #include "screen.h"
 
+
+static void screen_CloseCapture(screen_data_t *);
+static block_t *screen_Capture(demux_t *);
+
 struct screen_data_t
 {
     HDC hdc_src;
@@ -44,8 +51,13 @@ struct screen_data_t
     int i_fragment_size;
     int i_fragment;
     block_t *p_block;
+
+#ifdef SCREEN_MOUSE
+    filter_t *p_blend;
+#endif
 };
 
+#if defined(SCREEN_SUBSCREEN) || defined(SCREEN_MOUSE)
 /*
  * In screen coordinates the origin is the upper-left corner of the primary
  * display, and points can have negative x/y when other displays are located
@@ -69,7 +81,9 @@ static inline void FromScreenCoordinates( demux_t *p_demux, POINT *p_point )
     p_point->x += p_data->ptl.x;
     p_point->y += p_data->ptl.y;
 }
+#endif
 
+#if defined(SCREEN_SUBSCREEN)
 static inline void ToScreenCoordinates( demux_t *p_demux, POINT *p_point )
 {
     demux_sys_t *p_sys = p_demux->p_sys;
@@ -77,8 +91,9 @@ static inline void ToScreenCoordinates( demux_t *p_demux, POINT *p_point )
     p_point->x -= p_data->ptl.x;
     p_point->y -= p_data->ptl.y;
 }
+#endif
 
-int screen_InitCapture( demux_t *p_demux )
+int screen_InitCaptureGDI( demux_t *p_demux )
 {
     demux_sys_t *p_sys = p_demux->p_sys;
     screen_data_t *p_data;
@@ -162,14 +177,16 @@ int screen_InitCapture( demux_t *p_demux )
     p_data->ptl.x = - GetSystemMetrics( SM_XVIRTUALSCREEN );
     p_data->ptl.y = - GetSystemMetrics( SM_YVIRTUALSCREEN );
 
+    static const struct screen_capture_operations ops = {
+        screen_Capture, screen_CloseCapture,
+    };
+    p_sys->ops = &ops;
+
     return VLC_SUCCESS;
 }
 
-int screen_CloseCapture( demux_t *p_demux )
+void screen_CloseCapture( screen_data_t *p_data )
 {
-    demux_sys_t *p_sys = p_demux->p_sys;
-    screen_data_t *p_data = p_sys->p_data;
-
     if( p_data->p_block ) block_Release( p_data->p_block );
 
     if( p_data->hgdi_backup)
@@ -177,9 +194,17 @@ int screen_CloseCapture( demux_t *p_demux )
 
     DeleteDC( p_data->hdc_dst );
     ReleaseDC( 0, p_data->hdc_src );
-    free( p_data );
 
-    return VLC_SUCCESS;
+#ifdef SCREEN_MOUSE
+    if( p_data->p_blend )
+    {
+        filter_Close( p_data->p_blend );
+        module_unneed( p_data->p_blend, p_data->p_blend->p_module );
+        vlc_object_delete(p_data->p_blend);
+    }
+#endif
+
+    free( p_data );
 }
 
 struct block_sys_t
@@ -275,6 +300,65 @@ error:
     return NULL;
 }
 
+#ifdef SCREEN_MOUSE
+static void RenderCursor( demux_t *p_demux, int i_x, int i_y,
+                          uint8_t *p_dst )
+{
+    demux_sys_t *p_sys = p_demux->p_sys;
+    screen_data_t *p_data = p_sys->p_data;
+    if( !p_sys->dst.i_planes )
+        picture_Setup( &p_sys->dst, &p_sys->fmt.video );
+
+    if( !p_sys->dst.i_planes )
+        return;
+
+    /* Bitmaps here created by CreateDIBSection: stride rounded up to the nearest DWORD */
+    p_sys->dst.p[ 0 ].i_pitch = p_sys->dst.p[ 0 ].i_visible_pitch =
+        ( ( ( ( p_sys->fmt.video.i_width * p_sys->fmt.video.i_bits_per_pixel ) + 31 ) & ~31 ) >> 3 );
+
+    if( !p_data->p_blend )
+    {
+        p_data->p_blend = vlc_object_create( p_demux, sizeof(filter_t) );
+        if( p_data->p_blend )
+        {
+            es_format_Init( &p_data->p_blend->fmt_in, VIDEO_ES,
+                            VLC_CODEC_RGBA );
+            p_data->p_blend->fmt_in.video = p_sys->p_mouse->format;
+            p_data->p_blend->fmt_out = p_sys->fmt;
+            p_data->p_blend->p_module =
+                module_need( p_data->p_blend, "video blending", NULL, false );
+            if( !p_data->p_blend->p_module )
+            {
+                msg_Err( p_demux, "Could not load video blending module" );
+                vlc_object_delete(p_data->p_blend);
+                p_data->p_blend = NULL;
+                picture_Release( p_sys->p_mouse );
+                p_sys->p_mouse = NULL;
+            }
+            assert( p_data->p_blend->ops != NULL );
+        }
+    }
+    if( p_data->p_blend )
+    {
+        p_sys->dst.p->p_pixels = p_dst;
+        p_data->p_blend->ops->blend_video( p_data->p_blend,
+                                        &p_sys->dst,
+                                        p_sys->p_mouse,
+#ifdef SCREEN_SUBSCREEN
+                                        i_x-p_sys->i_left,
+#else
+                                        i_x,
+#endif
+#ifdef SCREEN_SUBSCREEN
+                                        i_y-p_sys->i_top,
+#else
+                                        i_y,
+#endif
+                                        255 );
+    }
+}
+#endif
+
 block_t *screen_Capture( demux_t *p_demux )
 {
     demux_sys_t *p_sys = p_demux->p_sys;
@@ -289,16 +373,24 @@ block_t *screen_Capture( demux_t *p_demux )
         }
     }
 
+    POINT pos;
+#if defined(SCREEN_SUBSCREEN) || defined(SCREEN_MOUSE)
+    GetCursorPos( &pos );
+    FromScreenCoordinates( p_demux, &pos );
+#endif // SCREEN_SUBSCREEN || SCREEN_MOUSE
+#if defined(SCREEN_SUBSCREEN)
     if( p_sys->b_follow_mouse )
     {
-        POINT pos;
-        GetCursorPos( &pos );
-        FromScreenCoordinates( p_demux, &pos );
         FollowMouse( p_sys, pos.x, pos.y );
     }
+#endif // SCREEN_SUBSCREEN
 
+#if defined(SCREEN_SUBSCREEN)
     POINT top_left = { p_sys->i_left, p_sys->i_top };
     ToScreenCoordinates( p_demux, &top_left );
+#else // !SCREEN_SUBSCREEN
+    POINT top_left = { 0, 0 };
+#endif // !SCREEN_SUBSCREEN
 
     if( !BitBlt( p_data->hdc_dst, 0,
                  p_data->i_fragment * p_data->i_fragment_size,
@@ -320,6 +412,7 @@ block_t *screen_Capture( demux_t *p_demux )
         p_data->i_fragment = 0;
         p_data->p_block = 0;
 
+#ifdef SCREEN_MOUSE
         if( p_sys->p_mouse )
         {
             POINT pos;
@@ -329,6 +422,7 @@ block_t *screen_Capture( demux_t *p_demux )
             RenderCursor( p_demux, pos.x, pos.y,
                           p_block->p_buffer );
         }
+#endif
 
         return p_block;
     }


=====================================
modules/hw/d3d11/Makefile.am
=====================================
@@ -3,6 +3,7 @@ d3d11dir = $(pluginsdir)/d3d11
 libdirect3d11_filters_plugin_la_SOURCES = hw/d3d11/d3d11_filters.h \
     hw/d3d11/d3d11_filters.c \
     hw/d3d11/d3d11_deinterlace.c \
+    hw/d3d11/d3d11_decoder.cpp \
     hw/d3d11/d3d11_device.c \
     hw/d3d11/d3d11_surface.c \
     hw/d3d11/d3d11_processor.c hw/d3d11/d3d11_processor.h


=====================================
modules/hw/d3d11/d3d11_decoder.cpp
=====================================
@@ -0,0 +1,300 @@
+/*****************************************************************************
+ * d3d11_decoder.cpp : D3D11 GPU block to picture decoder
+ *****************************************************************************
+ * Copyright © 2018-2022 VLC authors, VideoLAN and VideoLabs
+ *
+ * Authors: Steve Lhomme <robux4 at gmail.com>
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_codec.h>
+#include <vlc_picture.h>
+#include <vlc_modules.h>
+
+#include "d3d11_filters.h"
+#include <dxgi1_2.h>
+#include <d3d11_1.h>
+
+#include <new>
+#include <wrl/client.h>
+using Microsoft::WRL::ComPtr;
+
+struct d3d11_dec_sys {
+    date_t             pts;
+    const d3d_format_t *output_format = nullptr;
+    vlc_video_context  *vctx = nullptr;
+    vlc_decoder_device *dec_dev = nullptr;
+
+    ~d3d11_dec_sys()
+    {
+        if (vctx)
+            vlc_video_context_Release(vctx);
+        if (dec_dev)
+            vlc_decoder_device_Release(dec_dev);
+    }
+};
+
+static block_t *DecodeBlock( decoder_t *p_dec, block_t *p_block )
+{
+    d3d11_dec_sys *p_sys = static_cast<d3d11_dec_sys*>(p_dec->p_sys);
+
+    if( p_block->i_flags & (BLOCK_FLAG_CORRUPTED|BLOCK_FLAG_DISCONTINUITY) )
+    {
+        date_Set( &p_sys->pts, p_block->i_dts );
+        if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
+        {
+            block_Release( p_block );
+            return nullptr;
+        }
+    }
+
+    if( p_block->i_pts <= VLC_TICK_INVALID && p_block->i_dts <= VLC_TICK_INVALID &&
+        !date_Get( &p_sys->pts ) )
+    {
+        /* We've just started the stream, wait for the first PTS. */
+        block_Release( p_block );
+        return nullptr;
+    }
+
+    /* Date management: If there is a pts avaliable, use that. */
+    if( p_block->i_pts > VLC_TICK_INVALID )
+    {
+        date_Set( &p_sys->pts, p_block->i_pts );
+    }
+    else if( p_block->i_dts > VLC_TICK_INVALID )
+    {
+        /* NB, davidf doesn't quite agree with this in general, it is ok
+         * for rawvideo since it is in order (ie pts=dts), however, it
+         * may not be ok for an out-of-order codec, so don't copy this
+         * without thinking */
+        date_Set( &p_sys->pts, p_block->i_dts );
+    }
+
+    return p_block;
+}
+
+static int DecodeFrame( decoder_t *p_dec, block_t *p_block )
+{
+    if( p_block == nullptr ) // No Drain needed
+        return VLCDEC_SUCCESS;
+
+    p_block = DecodeBlock( p_dec, p_block );
+    if( p_block == nullptr )
+        return VLCDEC_SUCCESS;
+
+    HRESULT hr;
+    ComPtr<ID3D11Resource> d3d11res;
+    d3d11_dec_sys *p_sys = static_cast<d3d11_dec_sys*>(p_dec->p_sys);
+    picture_t *p_pic = D3D11BLOCK_FROM_BLOCK(p_block)->d3d11_pic;
+    assert( p_pic != nullptr );
+    picture_sys_d3d11_t *src_sys = ActiveD3D11PictureSys(p_pic);
+
+    if (unlikely(p_sys->output_format == nullptr))
+    {
+        D3D11_TEXTURE2D_DESC outDesc;
+        src_sys->texture[0]->GetDesc(&outDesc);
+
+        for (p_sys->output_format = DxgiGetRenderFormatList();
+            p_sys->output_format->name != nullptr; ++p_sys->output_format)
+        {
+            if (p_sys->output_format->formatTexture == outDesc.Format &&
+                is_d3d11_opaque(p_sys->output_format->fourcc))
+                break;
+        }
+        if (unlikely(!p_sys->output_format->name))
+        {
+            msg_Err(p_dec, "Unknown texture format %d", outDesc.Format);
+            block_Release( p_block );
+            return VLC_EGENERIC;
+        }
+    }
+
+    if (unlikely(p_sys->vctx == nullptr))
+    {
+        p_sys->vctx =
+            D3D11CreateVideoContext(p_sys->dec_dev, p_sys->output_format->formatTexture);
+        if (!p_sys->vctx)
+        {
+            block_Release( p_block );
+            return VLC_EGENERIC;
+        }
+
+        if( decoder_UpdateVideoOutput( p_dec, p_sys->vctx ) != VLC_SUCCESS )
+        {
+            block_Release( p_block );
+            return VLCDEC_SUCCESS;
+        }
+    }
+
+    p_pic->date = date_Get( &p_sys->pts );
+    date_Increment( &p_sys->pts, 1 );
+
+    if( p_block->i_flags & BLOCK_FLAG_INTERLACED_MASK )
+    {
+        p_pic->b_progressive = false;
+        p_pic->i_nb_fields = (p_block->i_flags & BLOCK_FLAG_SINGLE_FIELD) ? 1 : 2;
+        if( p_block->i_flags & BLOCK_FLAG_TOP_FIELD_FIRST )
+            p_pic->b_top_field_first = true;
+        else
+            p_pic->b_top_field_first = false;
+    }
+    else
+        p_pic->b_progressive = true;
+
+    // replace the texture shared the DXGI device by a texture for our device
+    assert(src_sys->sharedHandle != INVALID_HANDLE_VALUE);
+    assert(src_sys->processorInput == nullptr);
+    assert(src_sys->processorOutput == nullptr);
+    assert(src_sys->texture[1] == nullptr);
+
+    d3d11_decoder_device_t *dev_sys = GetD3D11OpaqueDevice(p_sys->dec_dev);
+    ComPtr<ID3D11Device1> d3d11VLC1;
+    dev_sys->d3d_dev.d3ddevice->QueryInterface(IID_GRAPHICS_PPV_ARGS(&d3d11VLC1));
+
+    picture_sys_d3d11_t *pic_sys = ActiveD3D11PictureSys(p_pic);
+
+    ID3D11Texture2D* sharedTex;
+    hr = d3d11VLC1->OpenSharedResource1(pic_sys->sharedHandle, IID_GRAPHICS_PPV_ARGS(&sharedTex));
+
+    ID3D11Texture2D *srcTex = src_sys->texture[0];
+    auto *srcVctx = p_pic->context->vctx;
+    src_sys->texture[0] = sharedTex;
+    p_pic->context->vctx = vlc_video_context_Hold(p_sys->vctx);
+    srcTex->Release();
+    vlc_video_context_Release(srcVctx);
+
+    for (int j = 0; j < DXGI_MAX_SHADER_VIEW; j++)
+    {
+        if (src_sys->renderSrc[j])
+            src_sys->renderSrc[j]->Release();
+    }
+    D3D11_AllocateResourceView(p_dec, dev_sys->d3d_dev.d3ddevice, p_sys->output_format,
+                               src_sys->texture, src_sys->slice_index, src_sys->renderSrc);
+
+    picture_Hold( p_pic ); // hold the picture we got from the block
+    block_Release( p_block );
+    decoder_QueueVideo( p_dec, p_pic );
+    return VLCDEC_SUCCESS;
+}
+
+static void Flush( decoder_t *p_dec )
+{
+    d3d11_dec_sys *p_sys = static_cast<d3d11_dec_sys*>(p_dec->p_sys);
+
+    date_Set( &p_sys->pts, VLC_TICK_INVALID );
+}
+
+void D3D11CloseBlockDecoder( vlc_object_t *obj )
+{
+    decoder_t *p_dec = (decoder_t *)obj;
+    d3d11_dec_sys *p_sys = static_cast<d3d11_dec_sys*>(p_dec->p_sys);
+    delete p_sys;
+}
+
+int D3D11OpenBlockDecoder( vlc_object_t *obj )
+{
+    decoder_t *p_dec = (decoder_t *)obj;
+
+    if ( !is_d3d11_opaque(p_dec->fmt_in.video.i_chroma) )
+        return VLC_EGENERIC;
+    if( p_dec->fmt_in.video.i_width <= 0 || p_dec->fmt_in.video.i_height == 0 )
+    {
+        msg_Err( p_dec, "invalid display size %dx%d",
+                 p_dec->fmt_in.video.i_width, p_dec->fmt_in.video.i_height );
+        return VLC_EGENERIC;
+    }
+
+    vlc_decoder_device *dec_dev = decoder_GetDecoderDevice(p_dec);
+    if (dec_dev == nullptr)
+        return VLC_ENOTSUP;
+    auto dev_sys = GetD3D11OpaqueDevice(dec_dev);
+    if (dev_sys == nullptr)
+    {
+        vlc_decoder_device_Release(dec_dev);
+        return VLC_ENOTSUP;
+    }
+
+    d3d11_dec_sys *p_sys = new (std::nothrow) d3d11_dec_sys();
+    if (unlikely(!p_sys))
+    {
+        vlc_decoder_device_Release(dec_dev);
+        return VLC_ENOMEM;
+    }
+    p_sys->dec_dev = dec_dev;
+
+    if( !p_dec->fmt_in.video.i_visible_width )
+        p_dec->fmt_in.video.i_visible_width = p_dec->fmt_in.video.i_width;
+    if( !p_dec->fmt_in.video.i_visible_height )
+        p_dec->fmt_in.video.i_visible_height = p_dec->fmt_in.video.i_height;
+
+    es_format_Copy( &p_dec->fmt_out, &p_dec->fmt_in );
+
+    if( p_dec->fmt_out.video.i_frame_rate == 0 ||
+        p_dec->fmt_out.video.i_frame_rate_base == 0)
+    {
+        msg_Warn( p_dec, "invalid frame rate %d/%d, using 25 fps instead",
+                  p_dec->fmt_out.video.i_frame_rate,
+                  p_dec->fmt_out.video.i_frame_rate_base);
+        date_Init( &p_sys->pts, 25, 1 );
+    }
+    else
+        date_Init( &p_sys->pts, p_dec->fmt_out.video.i_frame_rate,
+                    p_dec->fmt_out.video.i_frame_rate_base );
+
+    if (p_dec->fmt_in.video.i_chroma == VLC_CODEC_D3D11_OPAQUE_BGRA)
+    {
+        // there's only one possible value so we don't have to wait for the
+        // DXGI_FORMAT
+        for (p_sys->output_format = DxgiGetRenderFormatList();
+            p_sys->output_format->name != nullptr; ++p_sys->output_format)
+        {
+            if (p_sys->output_format->fourcc == p_dec->fmt_in.video.i_chroma &&
+                is_d3d11_opaque(p_sys->output_format->fourcc))
+                break;
+        }
+
+        p_sys->vctx =
+            D3D11CreateVideoContext(p_sys->dec_dev, p_sys->output_format->formatTexture);
+        if (!p_sys->vctx)
+        {
+            vlc_decoder_device_Release(dec_dev);
+            return VLC_EGENERIC;
+        }
+
+        if( decoder_UpdateVideoOutput( p_dec, p_sys->vctx ) != VLC_SUCCESS )
+        {
+            vlc_video_context_Release(p_sys->vctx);
+            vlc_decoder_device_Release(dec_dev);
+            return VLC_EGENERIC;
+        }
+    }
+    else
+    {
+        // we can't do a decoder_UpdateVideoOutput() here as we don't have the video context
+        // we assume the output will handle the D3D11 output
+    }
+
+    p_dec->pf_decode = DecodeFrame;
+    p_dec->pf_flush  = Flush;
+    p_dec->p_sys = p_sys;
+
+    return VLC_SUCCESS;
+}


=====================================
modules/hw/d3d11/d3d11_deinterlace.c
=====================================
@@ -193,7 +193,7 @@ picture_t *AllocPicture( filter_t *p_filter )
     filter_sys_t *p_sys = p_filter->p_sys;
 
     picture_t *pic = D3D11_AllocPicture(VLC_OBJECT(p_filter), &p_filter->fmt_out.video,
-                                        p_filter->vctx_out, p_sys->output_format);
+                                        p_filter->vctx_out, false, p_sys->output_format);
     if (pic == NULL)
         return NULL;
 


=====================================
modules/hw/d3d11/d3d11_filters.c
=====================================
@@ -202,7 +202,9 @@ static picture_t *AllocPicture( filter_t *p_filter )
     if (unlikely(cfg == NULL))
         return NULL;
 
-    return D3D11_AllocPicture(VLC_OBJECT(p_filter), &p_filter->fmt_out.video, p_filter->vctx_out, cfg);
+    return D3D11_AllocPicture(VLC_OBJECT(p_filter),
+                              &p_filter->fmt_out.video, p_filter->vctx_out,
+                              false, cfg);
 }
 
 static picture_t *Filter(filter_t *p_filter, picture_t *p_pic)
@@ -596,4 +598,9 @@ vlc_module_begin()
 #endif /* VLC_WINSTORE_APP */
     add_shortcut ("d3d11")
 
+    add_submodule()
+    set_subcategory( SUBCAT_INPUT_VCODEC )
+    set_callbacks( D3D11OpenBlockDecoder, D3D11CloseBlockDecoder )
+    set_capability( "video decoder", 90 )
+
 vlc_module_end()


=====================================
modules/hw/d3d11/d3d11_filters.h
=====================================
@@ -28,11 +28,21 @@
 
 #include "../../video_chroma/d3d11_fmt.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 int  D3D11OpenDeinterlace(filter_t *);
 int  D3D11OpenConverter(filter_t *);
 int  D3D11OpenCPUConverter(filter_t *);
+int  D3D11OpenBlockDecoder(vlc_object_t *);
+void D3D11CloseBlockDecoder(vlc_object_t *);
 
 int  D3D11OpenDecoderDeviceW8(vlc_decoder_device *, vout_window_t *);
 int  D3D11OpenDecoderDeviceAny(vlc_decoder_device *, vout_window_t *);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* VLC_D3D11_FILTERS_H */


=====================================
modules/hw/d3d11/d3d11_surface.c
=====================================
@@ -643,7 +643,7 @@ static picture_t *AllocateCPUtoGPUTexture(filter_t *p_filter, filter_sys_t *p_sy
     }
 
     if (AllocateTextures(p_filter, p_sys->d3d_dev, cfg,
-                         &p_dst->format, pic_ctx->picsys.texture, p_dst->p) != VLC_SUCCESS)
+                         &p_dst->format, false, pic_ctx->picsys.texture, p_dst->p) != VLC_SUCCESS)
         goto done;
 
     if (unlikely(D3D11_AllocateResourceView(p_filter, p_sys->d3d_dev->d3ddevice, cfg,


=====================================
modules/video_chroma/d3d11_fmt.c
=====================================
@@ -38,6 +38,7 @@
 #include <d3d11.h>
 #include <assert.h>
 #include <initguid.h>
+#include <dxgi1_2.h>
 #if !defined(NDEBUG) && defined(HAVE_DXGIDEBUG_H)
 # include <dxgidebug.h>
 #endif
@@ -802,7 +803,7 @@ const d3d_format_t *(FindD3D11Format)(vlc_object_t *o,
 
 #undef AllocateTextures
 int AllocateTextures( vlc_object_t *obj, d3d11_device_t *d3d_dev,
-                      const d3d_format_t *cfg, const video_format_t *fmt,
+                      const d3d_format_t *cfg, const video_format_t *fmt, bool shared,
                       ID3D11Texture2D *textures[],
                       plane_t out_planes[] )
 {
@@ -814,7 +815,8 @@ int AllocateTextures( vlc_object_t *obj, d3d11_device_t *d3d_dev,
     ZeroMemory(&texDesc, sizeof(texDesc));
     texDesc.MipLevels = 1;
     texDesc.SampleDesc.Count = 1;
-    texDesc.MiscFlags = 0; //D3D11_RESOURCE_MISC_SHARED;
+    if (shared)
+        texDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED | D3D11_RESOURCE_MISC_SHARED_NTHANDLE;
     texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
     texDesc.ArraySize = 1;
     if (is_d3d11_opaque(fmt->i_chroma)) {
@@ -945,6 +947,8 @@ void d3d11_pic_context_destroy(picture_context_t *ctx)
 {
     struct d3d11_pic_context *pic_ctx = D3D11_PICCONTEXT_FROM_PICCTX(ctx);
     ReleaseD3D11PictureSys(&pic_ctx->picsys);
+    if (pic_ctx->picsys.sharedHandle != INVALID_HANDLE_VALUE)
+        CloseHandle(pic_ctx->picsys.sharedHandle);
     free(pic_ctx);
 }
 
@@ -960,7 +964,8 @@ picture_context_t *d3d11_pic_context_copy(picture_context_t *ctx)
 }
 
 picture_t *D3D11_AllocPicture(vlc_object_t *obj,
-                              const video_format_t *fmt, vlc_video_context *vctx_out, const d3d_format_t *cfg)
+                              const video_format_t *fmt, vlc_video_context *vctx_out,
+                              bool shared, const d3d_format_t *cfg)
 {
     if (unlikely(cfg == NULL))
         return NULL;
@@ -968,6 +973,7 @@ picture_t *D3D11_AllocPicture(vlc_object_t *obj,
     struct d3d11_pic_context *pic_ctx = calloc(1, sizeof(*pic_ctx));
     if (unlikely(pic_ctx == NULL))
         return NULL;
+    pic_ctx->picsys.sharedHandle = INVALID_HANDLE_VALUE;
 
     picture_t *pic = picture_NewFromFormat( fmt );
     if (unlikely(pic == NULL))
@@ -978,7 +984,7 @@ picture_t *D3D11_AllocPicture(vlc_object_t *obj,
 
     d3d11_decoder_device_t *dev_sys = GetD3D11OpaqueContext(vctx_out);
     if (AllocateTextures(obj, &dev_sys->d3d_dev, cfg,
-                         fmt, pic_ctx->picsys.texture, NULL) != VLC_SUCCESS)
+                         fmt, shared, pic_ctx->picsys.texture, NULL) != VLC_SUCCESS)
     {
         picture_Release(pic);
         free(pic_ctx);
@@ -987,6 +993,22 @@ picture_t *D3D11_AllocPicture(vlc_object_t *obj,
 
     D3D11_AllocateResourceView(obj, dev_sys->d3d_dev.d3ddevice, cfg, pic_ctx->picsys.texture, 0, pic_ctx->picsys.renderSrc);
 
+    if (shared)
+    {
+        HRESULT hr;
+        void *pv;
+        IDXGIResource1 *sharedResource;
+        hr = ID3D11Texture2D_QueryInterface(pic_ctx->picsys.texture[0], &IID_IDXGIResource1,&pv);
+        if (likely(SUCCEEDED(hr)))
+        {
+            sharedResource = pv;
+            IDXGIResource1_CreateSharedHandle(sharedResource, NULL,
+                                              DXGI_SHARED_RESOURCE_READ/*|DXGI_SHARED_RESOURCE_WRITE*/,
+                                              NULL, &pic_ctx->picsys.sharedHandle);
+            IDXGIResource1_Release(sharedResource);
+        }
+    }
+
     pic_ctx->s = (picture_context_t) {
         d3d11_pic_context_destroy, d3d11_pic_context_copy,
         vlc_video_context_Hold(vctx_out),


=====================================
modules/video_chroma/d3d11_fmt.h
=====================================
@@ -75,6 +75,7 @@ typedef struct
     ID3D11VideoProcessorInputView  *processorInput;  /* when used as processor input */
     ID3D11VideoProcessorOutputView *processorOutput; /* when used as processor output */
     ID3D11ShaderResourceView      *renderSrc[DXGI_MAX_SHADER_VIEW];
+    HANDLE                        sharedHandle;
 } picture_sys_d3d11_t;
 
 struct d3d11_pic_context
@@ -83,6 +84,15 @@ struct d3d11_pic_context
     picture_sys_d3d11_t       picsys;
 };
 
+struct block_sys_d3d11_t
+{
+    block_t       self;
+    picture_t     *d3d11_pic;
+};
+
+#define D3D11BLOCK_FROM_BLOCK(block)  \
+    container_of((block), struct block_sys_d3d11_t, self)
+
 typedef struct
 {
     d3d11_device_t      d3d_dev;
@@ -177,9 +187,9 @@ const d3d_format_t *FindD3D11Format(vlc_object_t *,
     FindD3D11Format(VLC_OBJECT(a),b,c,d,e,f,g,h,i)
 
 int AllocateTextures(vlc_object_t *, d3d11_device_t *, const d3d_format_t *,
-                     const video_format_t *, ID3D11Texture2D *textures[],
-                     plane_t planes[]);
-#define AllocateTextures(a,b,c,d,e,f)  AllocateTextures(VLC_OBJECT(a),b,c,d,e,f)
+                     const video_format_t *, bool, ID3D11Texture2D *textures[],
+                     plane_t planes[]) VLC_USED;
+#define AllocateTextures(a,b,c,d,e,f,g)  AllocateTextures(VLC_OBJECT(a),b,c,d,e,f,g)
 
 static inline void d3d11_device_lock(d3d11_device_t *d3d_dev)
 {
@@ -197,7 +207,8 @@ void d3d11_pic_context_destroy(picture_context_t *);
 picture_context_t *d3d11_pic_context_copy(picture_context_t *);
 
 picture_t *D3D11_AllocPicture(vlc_object_t *,
-                              const video_format_t *, vlc_video_context *, const d3d_format_t *);
+                              const video_format_t *, vlc_video_context *,
+                              bool, const d3d_format_t *);
 
 #ifdef __cplusplus
 }


=====================================
modules/video_output/win32/direct3d11.cpp
=====================================
@@ -318,7 +318,8 @@ static int UpdateStaging(vout_display_t *vd, const video_format_t *fmt)
         if (!is_d3d11_opaque(fmt->i_chroma))
             texture_fmt.i_chroma = sys->picQuad.generic.textureFormat->fourcc;
 
-        if (AllocateTextures(vd, sys->d3d_dev, sys->picQuad.generic.textureFormat, &texture_fmt, textures, sys->stagingPlanes))
+        if (AllocateTextures(vd, sys->d3d_dev, sys->picQuad.generic.textureFormat, &texture_fmt,
+                             false, textures, sys->stagingPlanes))
         {
             msg_Err(vd, "Failed to allocate the staging texture");
             return VLC_EGENERIC;
@@ -1321,7 +1322,8 @@ static int Direct3D11MapSubpicture(vout_display_t *vd, int *subpicture_region_co
                 continue;
             }
             quad = d3dquad;
-            if (AllocateTextures(vd, sys->d3d_dev, sys->regionQuad.generic.textureFormat, &r->p_picture->format, d3dquad->picSys.texture, NULL)) {
+            if (AllocateTextures(vd, sys->d3d_dev, sys->regionQuad.generic.textureFormat, &r->p_picture->format,
+                                 false, d3dquad->picSys.texture, NULL)) {
                 msg_Err(vd, "Failed to allocate %dx%d texture for OSD",
                         r->fmt.i_visible_width, r->fmt.i_visible_height);
                 for (int j=0; j<DXGI_MAX_SHADER_VIEW; j++)



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/5f74392dcbac45ab762adbae6c6e49cd02fa5029...a84e2e720cfda5df56e8e95fcffb90edba82114e

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/5f74392dcbac45ab762adbae6c6e49cd02fa5029...a84e2e720cfda5df56e8e95fcffb90edba82114e
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list