[vlc-devel] [PATCH 2/8] libvlc: add rendering callbacks for D3D11 and D3D9

Thomas Guillem thomas at gllm.fr
Mon May 6 16:39:51 CEST 2019



On Mon, May 6, 2019, at 15:02, Steve Lhomme wrote:
> ---
>  include/vlc/libvlc_media_player.h | 144 ++++++++++++++++++++++++++++++
>  include/vlc_vout_display.h        |   8 +-
>  lib/libvlc.sym                    |   1 +
>  lib/media_player.c                |  54 +++++++++++
>  4 files changed, 203 insertions(+), 4 deletions(-)
> 
> diff --git a/include/vlc/libvlc_media_player.h 
> b/include/vlc/libvlc_media_player.h
> index ca72a550d3..72b4648019 100644
> --- a/include/vlc/libvlc_media_player.h
> +++ b/include/vlc/libvlc_media_player.h
> @@ -557,6 +557,150 @@ int libvlc_video_set_output_callbacks( 
> libvlc_media_player_t *mp,
>                                          libvlc_video_getProcAddress_cb 
> getProcAddress_cb,
>                                          void* opaque );
>  
> +
> +/**
> + * Enumeration of the Video engine to be used on output.
> + * can be passed to @a libvlc_video_surface_set_callbacks
> + */
> +typedef enum libvlc_video_rendering_t {
> +    /** Direct3D11 rendering engine */
> +    libvlc_video_rendering_direct3d11,
> +    /** Direct3D9 rendering engine */
> +    libvlc_video_rendering_direct3d9,
> +} libvlc_video_rendering_t;
> +
> +typedef struct
> +{
> +    bool hardware_decoding; /** set if 
> D3D11_CREATE_DEVICE_VIDEO_SUPPORT is needed for D3D11 */
> +} libvlc_video_surface_device_cfg_t;
> +
> +typedef struct
> +{
> +    void *device_context; /** ID3D11DeviceContext* for D3D11, 
> IDirect3DDevice9 * for D3D9 */
> +} libvlc_video_surface_device_setup_t;
> +
> +/** Setup the rendering environment.
> + *
> + * \param opaque private pointer passed to the @a 
> libvlc_video_surface_set_callbacks() [IN]
> + * \param cfg requested configuration of the video device
> + * \param out libvlc_video_surface_device_setup_t* to fill
> + * \return true on success
> + * \version LibVLC 4.0.0 or later
> + *
> + * For \ref libvlc_video_rendering_direct3d9 the output must be a 
> IDirect3DDevice9*.
> + * A reference to this object is held until the \ref 
> LIBVLC_VIDEO_DEVICE_CLEANUP is called.
> + * the device must be created with D3DPRESENT_PARAMETERS.hDeviceWindow 
> set to 0.
> + *
> + * For \ref libvlc_video_rendering_direct3d11 the output must be a 
> ID3D11DeviceContext*.
> + * A reference to this object is held until the \ref 
> LIBVLC_VIDEO_DEVICE_CLEANUP is called.
> + * The ID3D11Device used to create ID3D11DeviceContext must have 
> multithreading enabled.
> + */
> +typedef bool( *libvlc_video_surface_device_setup_cb )( void *opaque, 
> const libvlc_video_surface_device_cfg_t *cfg, 
> libvlc_video_surface_device_setup_t *out );
> +
> +/** Cleanup the rendering environment initialized during \ref 
> libvlc_video_surface_device_setup_cb.
> + *
> + * \param opaque private pointer passed to the @a 
> libvlc_video_surface_set_callbacks() [IN]
> + * \version LibVLC 4.0.0 or later
> + */
> +typedef void( *libvlc_video_surface_device_cleanup_cb )( void *opaque 
> );
> +
> +typedef struct
> +{
> +    unsigned width;                        /** rendering video width 
> in pixel */
> +    unsigned height;                      /** rendering video height 
> in pixel */
> +} libvlc_video_surface_cfg_t;
> +
> +typedef struct
> +{
> +    intptr_t surface_format;  /** the rendering DXGI_FORMAT for \ref 
> libvlc_video_rendering_direct3d11,
> +                                  D3DFORMAT for \ref 
> libvlc_video_rendering_direct3d9 */
> +} libvlc_video_output_cfg_t;
> +
> +/** Update the rendering output setup.
> + *
> + * \param opaque private pointer passed to the @a 
> libvlc_video_surface_set_callbacks() [IN]
> + * \param cfg configuration of the video that will be rendered
> + * \param output configuration describing with how the rendering is 
> setup
> + * \version LibVLC 4.0.0 or later
> + *
> + * Tone mapping, range and color conversion will be done depending on 
> the values
> + * set in the output structure.
> + */
> +typedef bool( *libvlc_video_surface_update_output_cb )( void *opaque, 
> const libvlc_video_surface_cfg_t *cfg, libvlc_video_output_cfg_t 
> *output );
> +
> +/** Tell the host the rendering is about to start/has finished.
> + *
> + * \param opaque private pointer passed to the @a 
> libvlc_video_surface_set_callbacks() [IN]
> + * \param enter true if the rendering is about to start, false if it's 
> finished
> + * \return true on success
> + * \version LibVLC 4.0.0 or later
> + *
> + * On Direct3D9 the following may change on the provided 
> IDirect3DDevice9*
> + * between \ref enter being true and \ref enter being false:
> + * - D3DSAMP_ADDRESSU
> + * - D3DSAMP_ADDRESSV
> + * - D3DSAMP_MINFILTER
> + * - D3DSAMP_MAGFILTER
> + * - D3DRS_AMBIENT
> + * - D3DRS_CULLMODE
> + * - D3DRS_ZENABLE
> + * - D3DRS_LIGHTING
> + * - D3DRS_DITHERENABLE
> + * - D3DRS_STENCILENABLE
> + * - D3DRS_ALPHABLENDENABLE
> + * - D3DRS_SRCBLEND,D3DBLEND_SRCALPHA
> + * - D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA
> + * - D3DPCMPCAPS_GREATER
> + * - D3DRS_ALPHATESTENABLE
> + * - D3DRS_ALPHAREF
> + * - D3DRS_ALPHAFUNC
> + * - D3DTSS_COLOROP
> + * - D3DTSS_COLORARG1
> + * - D3DTSS_ALPHAOP
> + * - D3DTSS_ALPHAARG1
> + * - D3DTSS_ALPHAARG2
> + *
> + * On Direct3D11 the following may change on the provided 
> ID3D11DeviceContext*
> + * between \ref enter being true and \ref enter being false:
> + * - IASetPrimitiveTopology()
> + * - IASetInputLayout()
> + * - IASetVertexBuffers()
> + * - IASetIndexBuffer()
> + * - VSSetConstantBuffers()
> + * - VSSetShader()
> + * - PSSetSamplers()
> + * - PSSetConstantBuffers()
> + * - PSSetShaderResources()
> + * - PSSetShader()
> + * - RSSetViewports()
> + * - DrawIndexed()
> + */
> +typedef bool( *libvlc_video_surface_start_rendering_cb )( void 
> *opaque, bool enter );
> +
> +
> +/**
> + * Set callbacks and data to render decoded video to a custom Direct3D 
> output
> + *
> + * \warning VLC will perform video rendering in its own thread and at 
> its own rate,
> + * You need to provide your own synchronisation mechanism.
> + *
> + * \param mp the media player
> + * \param engine the GPU engine to use
> + * \param control_cb callback that receives all the \ref 
> libvlc_video_callback_control_t
> + * \param opaque private pointer passed to the control callback
> + * \libvlc_return_bool
> + * \version LibVLC 4.0.0 or later
> + */
> +LIBVLC_API
> +int libvlc_video_surface_set_callbacks( libvlc_media_player_t *mp,
> +                                        libvlc_video_rendering_t 
> engine,
> +                                        
> libvlc_video_surface_device_setup_cb setup_cb,
> +                                        
> libvlc_video_surface_device_cleanup_cb cleanup_cb,
> +                                        
> libvlc_video_surface_update_output_cb update_output_cb,
> +                                        libvlc_video_swap_cb swap_cb,
> +                                        
> libvlc_video_surface_start_rendering_cb makeCurrent_cb,
> +                                        void* opaque );
> +
>  /**
>   * Set the NSView handler where the media player should render its 
> video output.
>   *
> diff --git a/include/vlc_vout_display.h b/include/vlc_vout_display.h
> index 7b2c9cf0d3..23657d21f5 100644
> --- a/include/vlc_vout_display.h
> +++ b/include/vlc_vout_display.h
> @@ -459,22 +459,22 @@ void 
> vout_display_TranslateMouseState(vout_display_t *vd, vlc_mouse_t *video,
>  typedef struct
>  {
>      bool hardware_decoding; /** set if 
> D3D11_CREATE_DEVICE_VIDEO_SUPPORT is needed */
> -} vlc_video_surface_device_cfg_t;
> +} vlc_video_surface_device_cfg_t; /* must match 
> libvlc_video_surface_device_cfg_t */
>  
>  typedef struct
>  {
>      void *device_context; /** ID3D11DeviceContext* for D3D11, 
> IDirect3DDevice9* for D3D9 */
> -} vlc_video_surface_device_setup_t;
> +} vlc_video_surface_device_setup_t; /* must match 
> libvlc_video_surface_device_setup_t */
>  
>  typedef struct
>  {
>      unsigned width, height;
> -} vlc_video_surface_cfg_t;
> +} vlc_video_surface_cfg_t; /* must match libvlc_video_surface_cfg_t */
>  
>  typedef struct
>  {
>      intptr_t          surface_format; /* DXGI_FORMAT for D3D11, 
> D3DFORMAT for D3D9 */
> -} video_surface_output_cfg_t;
> +} video_surface_output_cfg_t; /* must match libvlc_video_output_cfg_t 
> */
>  
>  typedef bool( *vlc_video_surface_device_setup_cb )( void *opaque, 
> const vlc_video_surface_device_cfg_t *cfg, 
> vlc_video_surface_device_setup_t *out );
>  typedef void( *vlc_video_surface_device_cleanup_cb )( void *opaque );
> diff --git a/lib/libvlc.sym b/lib/libvlc.sym
> index ef132c37e4..2a6bba09c2 100644
> --- a/lib/libvlc.sym
> +++ b/lib/libvlc.sym
> @@ -244,6 +244,7 @@ libvlc_video_set_deinterlace
>  libvlc_video_set_format
>  libvlc_video_set_format_callbacks
>  libvlc_video_set_output_callbacks
> +libvlc_video_surface_set_callbacks
>  libvlc_video_set_key_input
>  libvlc_video_set_logo_int
>  libvlc_video_set_logo_string
> diff --git a/lib/media_player.c b/lib/media_player.c
> index 106e7d26b0..e87c43b5ba 100644
> --- a/lib/media_player.c
> +++ b/lib/media_player.c
> @@ -1202,6 +1202,39 @@ int libvlc_video_set_output_callbacks( 
> libvlc_media_player_t *mp,
>  }
>  
>  
> +int libvlc_video_surface_set_callbacks( libvlc_media_player_t *mp,
> +                                        libvlc_video_rendering_t 
> engine,
> +                                        
> libvlc_video_surface_device_setup_cb setup_cb,
> +                                        
> libvlc_video_surface_device_cleanup_cb cleanup_cb,
> +                                        
> libvlc_video_surface_update_output_cb update_output_cb,
> +                                        libvlc_video_swap_cb swap_cb,
> +                                        
> libvlc_video_surface_start_rendering_cb makeCurrent_cb,
> +                                        void* opaque )
> +{
> +    var_SetString( mp, "window", "wdummy");
> +
> +    if ( engine == libvlc_video_rendering_direct3d11 )
> +    {
> +        var_SetString ( mp, "vout", "direct3d11" );
> +        var_SetString ( mp, "avcodec-hw", "d3d11va");
> +    }
> +    else if ( engine == libvlc_video_rendering_direct3d9 )
> +    {
> +        var_SetString ( mp, "vout", "direct3d9" );
> +        var_SetString ( mp, "avcodec-hw", "dxva2");
> +    }
> +    else
> +        return 0;
> +
> +    var_SetAddress( mp, "vout-cb-opaque", opaque );
> +    var_SetAddress( mp, "vout-cb-setup", setup_cb );
> +    var_SetAddress( mp, "vout-cb-cleanup", cleanup_cb );
> +    var_SetAddress( mp, "vout-cb-update-output", update_output_cb );
> +    var_SetAddress( mp, "vout-cb-swap", swap_cb );
> +    var_SetAddress( mp, "vout-cb-make-current", makeCurrent_cb );

Are we sure we can do that without doing a transformation from the libvlc struct to the vlc one ?

Also, you will break ABI if you add/remove members of these VLC structs, no ? Maybe you should add a magic that contains the struct version also.

> +    return 1;
> +}
> +
>  
> /**************************************************************************
>   * set_nsobject
>   
> **************************************************************************/
> @@ -2049,3 +2082,24 @@ int 
> libvlc_media_player_get_role(libvlc_media_player_t *mp)
>      free(str);
>      return ret;
>  }
> +
> +#include <vlc_vout_display.h>
> +
> +/* make sure surface structures from libvlc can be passed as such to 
> vlc
> +   otherwise we will need wrappers between what libvlc understands and 
> what vlc uses */
> +static_assert( sizeof( vlc_video_surface_device_cfg_t ) == sizeof( 
> libvlc_video_surface_device_cfg_t ) &&
> +               offsetof( vlc_video_surface_device_cfg_t, 
> hardware_decoding ) == offsetof( libvlc_video_surface_device_cfg_t, 
> hardware_decoding )
> +               , "video surface device configuration mismatch" );
> +
> +static_assert(sizeof(vlc_video_surface_device_setup_t) == 
> sizeof(libvlc_video_surface_device_setup_t) &&
> +              offsetof(vlc_video_surface_device_setup_t, 
> device_context) == offsetof(libvlc_video_surface_device_setup_t, 
> device_context)
> +              , "video surface device setup mismatch");
> +
> +static_assert(sizeof(vlc_video_surface_cfg_t) == 
> sizeof(libvlc_video_surface_cfg_t) &&
> +              offsetof(vlc_video_surface_cfg_t, width)     == 
> offsetof(libvlc_video_surface_cfg_t, width) &&
> +              offsetof(vlc_video_surface_cfg_t, height)    == 
> offsetof(libvlc_video_surface_cfg_t, height)
> +              , "video surface setup mismatch");
> +
> +static_assert(sizeof(video_surface_output_cfg_t) == 
> sizeof(libvlc_video_output_cfg_t) &&
> +              offsetof(video_surface_output_cfg_t, surface_format) == 
> offsetof(libvlc_video_output_cfg_t, surface_format)
> +              , "video surface configuration mismatch");
> -- 
> 2.17.1
> 
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel


More information about the vlc-devel mailing list