[vlc-devel] [PATCH] Added video bridge output plugin
Rémi Denis-Courmont
remi at remlab.net
Sat Jul 1 16:04:32 CEST 2017
Le 1 juillet 2017 14:00:54 GMT+02:00, Oliver Collyer <ovcollyer at mac.com> a écrit :
>Hello
>
>A little out of left-field this one but I wrote this vout plugin for a
>project I've been working on.
>
>It's kind of similar to vmem in that an application can use this plugin
>to retrieve the decoder/filtered surfaces, but rather than receive a
>system memory copy of the surface (clean but slow) it instead allows
>these surfaces to be passed through directly to the caller. More
>importantly, it supports this for certain hardware formats too -
>currently DXVA2, VideoToolbox and VAAPI. There is no reason why
>D3D11VA, VDPAU etc couldn't be supported in future.
>
>I see this plugin as filling a small niche where an application already
>manages its own devices, contexts, textures etc and wants to embed
>video into this, but without losing the benefits of hardware
>acceleration.
>
>Im my video streaming application I take these hardware surfaces and
>use them to fill out SDL textures, thus avoiding any GPU-CPU-GPU
>copies. For DXVA2 this is done via StretchRect, for VideoToolbox I used
>the texture cache on both iOS/tvOS and macOS. For VAAPI I use the GLX
>extension. I had to add in a couple of functions to SDL to give deeper
>access to the underling devices/textures/surfaces, but it works very
>well.
>
>Initially I was hacking these changes into vmem but rather than break
>that interface or get bogged-down trying to support two different
>methods I thought it cleaner to write this as a new plugin.
>
>I understand from jb that there are possible plans in future for a
>plugin that writes to a texture, so maybe my plugin will be redundant,
>I'm not sure, but I'm offering it anyway, in case you want to include
>it, or in case someone wants to use it in their own project.
>
>Cheers
>
>Oliver
>
>---
> include/vlc/libvlc_media_player.h | 108 +++++++
> lib/libvlc.sym | 1 +
> lib/media_player.c | 32 ++
> modules/MODULES_LIST | 1 +
> modules/video_output/Makefile.am | 33 ++
>modules/video_output/vbridge.c | 615
>++++++++++++++++++++++++++++++++++++++
> po/POTFILES.in | 1 +
> 7 files changed, 791 insertions(+)
> create mode 100644 modules/video_output/vbridge.c
>
>diff --git a/include/vlc/libvlc_media_player.h
>b/include/vlc/libvlc_media_player.h
>index 160cdfbaa8..72be05bb9b 100644
>--- a/include/vlc/libvlc_media_player.h
>+++ b/include/vlc/libvlc_media_player.h
>@@ -457,6 +457,114 @@ void libvlc_video_set_format_callbacks(
>libvlc_media_player_t *mp,
> libvlc_video_cleanup_cb cleanup );
>
> /**
>+ * Callback prototype to configure format for video bridge output.
>+ *
>+ * This callback gets the format of the video as output by the video
>decoder
>+ * and the chain of video filters (if any). It can opt to change any
>parameter
>+ * as it needs. In that case, LibVLC will attempt to convert the video
>format
>+ * (rescaling and chroma conversion) but these operations can be CPU
>intensive.
>+ *
>+ * The device pointer must be set to a valid D3D9 device in the case
>of DXVA2 or
>+ * a valid VADisplay in the case of VAAPI. This is used by libVLC to
>initialize
>+ * the hardware decoder and create the hardware surfaces that are
>later passed
>+ * to the prepare and display callbacks.
>+ *
>+ * \param opaque pointer to the private pointer passed to
>+ * libvlc_media_player_set_vbridge_callbacks() [IN/OUT]
>+ * \param chroma pointer to the 4 bytes video format identifier
>[IN/OUT]
>+ * \param width pointer to the pixel width [IN/OUT]
>+ * \param height pointer to the pixel height [IN/OUT]
>+ * \param x_offset pointer to the pixel x offset [IN/OUT]
>+ * \param y_offset pointer to the pixel y offset [IN/OUT]
>+ * \param visible_width pointer to the pixel visible width [IN/OUT]
>+ * \param visible_height pointer to the pixel visible height [IN/OUT]
>+ * \param device pointer to the platform-specific device pointer [OUT]
>+ *
>+ */
>+typedef void (*libvlc_vbridge_format_cb)(void **opaque, char *chroma,
>+ unsigned *width, unsigned
>*height,
>+ unsigned *x_offset, unsigned
>*y_offset,
>+ unsigned *visible_width,
>+ unsigned *visible_height,
>+ void **device);
>+
>+/**
>+ * Callback prototype to cleanup resources for video bridge output.
>+ *
>+ * \param opaque private pointer as passed to
>+ * libvlc_media_player_set_vbridge_callbacks()
>+ * (and possibly modified by @ref
>libvlc_vbridge_format_cb) [IN]
>+ */
>+typedef void (*libvlc_vbridge_cleanup_cb)(void *opaque);
>+
>+/**
>+ * Callback prototype to prepare a picture for video bridge output.
>+ *
>+ * When the video frame decoding is complete, the prepare callback is
>invoked.
>+ * This callback might not be needed at all. It is only an indication
>that the
>+ * application can now read the pixel values if it needs to.
>+ *
>+ * If the picture is a software surface then planes[] will point to
>system
>+ * memory and pitches[] and lines[] will be valid. The number and
>layout of the
>+ * planes will depend on the chroma.
>+ *
>+ * If the picture is a hardware surface then planes[0] should be cast
>to the
>+ * appropriate type (IDirect3D9Surface, CVPixelBuffer or VASurfaceID)
>and the
>+ * pitches[0] and lines[0] entries will be zero.
>+ *
>+ * \param opaque private pointer as passed to
>+ * libvlc_media_player_set_vbridge_callbacks()
>+ * (and possibly modified by @ref
>libvlc_vbridge_format_cb) [IN]
>+ * \param planes start address of the pixel planes[IN]
>+ * \param pitches table of scanline pitches in bytes for each pixel
>plane [IN]
>+ * \param lines table of scanlines count for each plane [IN]
>+ */
>+typedef void (*libvlc_vbridge_prepare_cb)(void *opaque, void *const
>*planes,
>+ unsigned *pitches, unsigned
>*lines);
>+
>+/**
>+ * Callback prototype to display a picture for video bridge output.
>+ *
>+ * When the video frame needs to be shown, as determined by the media
>playback
>+ * clock, the display callback is invoked.
>+ *
>+ * If the picture is a software surface then planes[] will point to
>system
>+ * memory and pitches[] and lines[] will be valid. The number and
>layout of the
>+ * planes will depend on the chroma.
>+ *
>+ * If the picture is a hardware surface then planes[0] should be cast
>to the
>+ * appropriate type (IDirect3D9Surface, CVPixelBuffer or VASurfaceID)
>and the
>+ * pitches[0] and lines[0] entries will be zero.
>+ *
>+ * \param opaque private pointer as passed to
>+ * libvlc_media_player_set_vbridge_callbacks()
>+ * (and possibly modified by @ref
>libvlc_vbridge_format_cb) [IN]
>+ * \param planes start address of the pixel planes[IN]
>+ * \param pitches table of scanline pitches in bytes for each pixel
>plane [IN]
>+ * \param lines table of scanlines count for each plane [IN]
>+ */
>+typedef void (*libvlc_vbridge_display_cb)(void *opaque, void *const
>*planes,
>+ unsigned *pitches, unsigned
>*lines);
>+
>+/**
>+ * Set callbacks and private data for video bridge output.
>+ *
>+ * \param mp the media player
>+ * \param format callback to configure format
>+ * \param cleanup callback to cleanup resources
>+ * \param prepare callback to prepare a picture
>+ * \param display callback to display a picture
>+ * \param opaque private pointer
>+ */
>+LIBVLC_API
>+void libvlc_media_player_set_vbridge_callbacks(libvlc_media_player_t
>*mp,
>+
>libvlc_vbridge_format_cb format,
>+
>libvlc_vbridge_cleanup_cb cleanup,
>+
>libvlc_vbridge_prepare_cb prepare,
>+
>libvlc_vbridge_display_cb display,
>+ void *opaque);
>+
>+/**
>* Set the NSView handler where the media player should render its video
>output.
> *
> * Use the vout called "macosx".
>diff --git a/lib/libvlc.sym b/lib/libvlc.sym
>index caa55981bf..9fb3be8707 100644
>--- a/lib/libvlc.sym
>+++ b/lib/libvlc.sym
>@@ -203,6 +203,7 @@ libvlc_media_player_stop
> libvlc_media_player_will_play
> libvlc_media_player_navigate
> libvlc_media_player_set_video_title_display
>+libvlc_media_player_set_vbridge_callbacks
> libvlc_media_release
> libvlc_media_retain
> libvlc_media_save_meta
>diff --git a/lib/media_player.c b/lib/media_player.c
>index dc17f7765d..9d56402cd7 100644
>--- a/lib/media_player.c
>+++ b/lib/media_player.c
>@@ -693,6 +693,12 @@ libvlc_media_player_new( libvlc_instance_t
>*instance )
> var_Create (mp, "saturation", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
> var_Create (mp, "gamma", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
>
>+ var_Create (mp, "vbridge-format", VLC_VAR_ADDRESS);
>+ var_Create (mp, "vbridge-cleanup", VLC_VAR_ADDRESS);
>+ var_Create (mp, "vbridge-prepare", VLC_VAR_ADDRESS);
>+ var_Create (mp, "vbridge-display", VLC_VAR_ADDRESS);
>+ var_Create (mp, "vbridge-opaque", VLC_VAR_ADDRESS);
>+
> /* Audio */
> var_Create (mp, "aout", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
> var_Create (mp, "audio-device", VLC_VAR_STRING);
>@@ -1115,6 +1121,32 @@ void libvlc_video_set_format(
>libvlc_media_player_t *mp, const char *chroma,
> }
>
>/**************************************************************************
>+ * set_vbridge_callbacks
>+
>**************************************************************************/
>+void libvlc_media_player_set_vbridge_callbacks(libvlc_media_player_t
>*mp,
>+
>libvlc_vbridge_format_cb format,
>+
>libvlc_vbridge_cleanup_cb cleanup,
>+
>libvlc_vbridge_prepare_cb prepare,
>+
>libvlc_vbridge_display_cb display,
>+ void *opaque)
>+{
>+ var_SetAddress(mp, "vbridge-format", format);
>+ var_SetAddress(mp, "vbridge-cleanup", cleanup);
>+ var_SetAddress(mp, "vbridge-prepare", prepare);
>+ var_SetAddress(mp, "vbridge-display", display);
>+ var_SetAddress(mp, "vbridge-opaque", opaque);
>+#ifdef _WIN32
>+ var_SetString(mp, "avcodec-hw", "dxva2");
>+#elif defined(__linux__)
>+ var_SetString(mp, "avcodec-hw", "vaapi");
>+#else
>+ var_SetString(mp, "avcodec-hw", "none");
>+#endif
>+ var_SetString(mp, "vout", "vbridge");
>+ var_SetString(mp, "window", "none");
>+}
>+
>+/**************************************************************************
> * set_nsobject
>**************************************************************************/
> void libvlc_media_player_set_nsobject( libvlc_media_player_t *p_mi,
>diff --git a/modules/MODULES_LIST b/modules/MODULES_LIST
>index 04468e438d..0db5467123 100644
>--- a/modules/MODULES_LIST
>+++ b/modules/MODULES_LIST
>@@ -421,6 +421,7 @@ $Id$
> * vaapi_drm: VAAPI hardware-accelerated decoding with drm backend
>* vaapi_filters: VAAPI hardware-accelerated
>deinterlacing/adjust/sharpen/chroma filters
> * vaapi_x11: VAAPI hardware-accelerated decoding with x11 backend
>+ * vbridge: video bridge output
> * vc1: VC-1 Video demuxer
> * vcd: input module for accessing Video CDs
> * vdpau_adjust: VDPAU color adjust video filter
>diff --git a/modules/video_output/Makefile.am
>b/modules/video_output/Makefile.am
>index 2e7c5d8ba7..7407896569 100644
>--- a/modules/video_output/Makefile.am
>+++ b/modules/video_output/Makefile.am
>@@ -440,6 +440,39 @@ vout_LTLIBRARIES += libevas_plugin.la
> endif
>
>
>+### Video Bridge ###
>+libvbridge_plugin_la_SOURCES = video_output/vbridge.c
>+if HAVE_AVCODEC_DXVA2
>+libvbridge_plugin_la_CFLAGS = $(AM_CFLAGS) -DUSE_DXVA2
>+libvbridge_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)'
>+endif
>+if HAVE_OSX
>+libvbridge_plugin_la_SOURCES += codec/vt_utils.c codec/vt_utils.h
>+libvbridge_plugin_la_CFLAGS = $(AM_CFLAGS) -DUSE_VTBOX
>+libvbridge_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)' \
>+ -Wl,-framework,CoreFoundation,-framework,CoreVideo
>+endif
>+if HAVE_IOS
>+libvbridge_plugin_la_SOURCES += codec/vt_utils.c codec/vt_utils.h
>+libvbridge_plugin_la_CFLAGS = $(AM_CFLAGS) -DUSE_VTBOX
>+libvbridge_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)' \
>+ -Wl,-framework,CoreFoundation,-framework,CoreVideo
>+endif
>+if HAVE_TVOS
>+libvbridge_plugin_la_SOURCES += codec/vt_utils.c codec/vt_utils.h
>+libvbridge_plugin_la_CFLAGS = $(AM_CFLAGS) -DUSE_VTBOX
>+libvbridge_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)' \
>+ -Wl,-framework,CoreFoundation,-framework,CoreVideo
>+endif
>+if HAVE_AVCODEC_VAAPI
>+libvbridge_plugin_la_SOURCES += hw/vaapi/vlc_vaapi.c
>hw/vaapi/vlc_vaapi.h
>+libvbridge_plugin_la_CFLAGS = $(AM_CFLAGS) -DUSE_VAAPI
>+libvbridge_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)'
>+libvbridge_plugin_la_LIBADD = $(LIBVA_LIBS) libvlc_vaapi_instance.la
>+endif
>+vout_LTLIBRARIES += libvbridge_plugin.la
>+
>+
> ### Common ###
>
> libflaschen_plugin_la_SOURCES = video_output/flaschen.c
>diff --git a/modules/video_output/vbridge.c
>b/modules/video_output/vbridge.c
>new file mode 100644
>index 0000000000..839b51526e
>--- /dev/null
>+++ b/modules/video_output/vbridge.c
>@@ -0,0 +1,615 @@
>+/*****************************************************************************
>+ * vbridge.c: video bridge driver for vlc
>+
>*****************************************************************************
>+ * Copyright (C) 2017 VLC authors and VideoLAN
>+ *
>+ * Authors: Oliver Collyer <ovcollyer at mac.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.
>+
>*****************************************************************************/
>+
>+/*****************************************************************************
>+ * Preamble
>+
>*****************************************************************************/
>+#ifdef HAVE_CONFIG_H
>+# include "config.h"
>+#endif
>+
>+#include <assert.h>
>+
>+#include <vlc_common.h>
>+#include <vlc_plugin.h>
>+#include <vlc_vout_display.h>
>+#include <vlc_picture_pool.h>
>+
>+#ifdef USE_DXVA2
>+#include <d3d9.h>
>+#include "../video_chroma/d3d9_fmt.h"
>+#elif defined(USE_VTBOX)
>+#import <CoreVideo/CoreVideo.h>
>+#include "../codec/vt_utils.h"
>+#elif defined(USE_VAAPI)
>+#include <va/va.h>
>+#include "../hw/vaapi/vlc_vaapi.h"
>+#endif
>+
>+/*****************************************************************************
>+ * Module descriptor
>+
>*****************************************************************************/
>+static int Open (vlc_object_t *);
>+static void Close(vlc_object_t *);
>+
>+vlc_module_begin()
>+ set_shortname(N_("Video bridge"))
>+ set_description(N_("Video bridge output"))
>+ set_category(CAT_VIDEO)
>+ set_subcategory(SUBCAT_VIDEO_VOUT)
>+ set_capability("vout display", 0)
>+ set_callbacks(Open, Close)
>+vlc_module_end()
>+
>+/*****************************************************************************
>+ * Local prototypes
>+
>*****************************************************************************/
>+struct vout_display_sys_t
>+{
>+ picture_pool_t *pool;
>+ picture_t *prev_pic;
>+ bool hw_surfaces;
>+
>+#ifdef USE_VAAPI
>+ VADisplay dpy;
>+ VABufferID config_id;
>+ VABufferID context_id;
>+#endif
>+
>+ void (*cleanup)(void *);
>+ void (*prepare)(void *, void *const *, unsigned *, unsigned *);
>+ void (*display)(void *, void *const *, unsigned *, unsigned *);
>+ void *opaque;
>+ void *device;
>+};
>+
>+typedef void (*vlc_format_cb)(void **, char *,
>+ unsigned *, unsigned *,
>+ unsigned *, unsigned *,
>+ unsigned *, unsigned *,
>+ void **);
>+
>+static picture_pool_t *Pool(vout_display_t *, unsigned);
>+static void SoftwareSurfacePrepare(vout_display_t *, picture_t *,
>subpicture_t *);
>+static void SoftwareSurfaceDisplay(vout_display_t *, picture_t *,
>subpicture_t *);
>+static void HardwareSurfacePrepare(vout_display_t *, picture_t *,
>subpicture_t *);
>+static void HardwareSurfaceDisplay(vout_display_t *, picture_t *,
>subpicture_t *);
>+static int Control(vout_display_t *, int, va_list);
>+
>+/*****************************************************************************
>+ * Create the video bridge output
>+
>*****************************************************************************/
>+static int Open(vlc_object_t *object)
>+{
>+ vout_display_t *vd = (vout_display_t *)object;
>+
>+ vlc_format_cb format = var_InheritAddress(vd, "vbridge-format");
>+ if (!format)
>+ {
>+ msg_Err(vd, "Invalid vbridge-format callback");
>+ return VLC_EGENERIC;
>+ }
>+
>+ vout_display_sys_t *sys = calloc(1, sizeof(*sys));
>+ if (unlikely(!sys))
>+ return VLC_ENOMEM;
>+
>+ sys->cleanup = var_InheritAddress(vd, "vbridge-cleanup");
>+ sys->prepare = var_InheritAddress(vd, "vbridge-prepare");
>+ sys->display = var_InheritAddress(vd, "vbridge-display");
>+ sys->opaque = var_InheritAddress(vd, "vbridge-opaque");
>+
>+#ifdef USE_VAAPI
>+ sys->config_id = VA_INVALID_ID;
>+ sys->context_id = VA_INVALID_ID;
>+#endif
>+
>+ video_format_t fmt;
>+ video_format_ApplyRotation(&fmt, &vd->fmt);
>+
>+ char chroma[5];
>+ memcpy(chroma, &fmt.i_chroma, 4);
>+ chroma[4] = '\0';
>+
>+ format(&sys->opaque,
>+ chroma,
>+ &fmt.i_width, &fmt.i_height,
>+ &fmt.i_x_offset, &fmt.i_y_offset,
>+ &fmt.i_visible_width, &fmt.i_visible_height,
>+ &sys->device);
>+
>+ fmt.i_chroma = vlc_fourcc_GetCodecFromString(VIDEO_ES, chroma);
>+ if (!fmt.i_chroma)
>+ {
>+ msg_Err(vd, "Invalid chroma requested (%s)", chroma);
>+ free(sys);
>+ return VLC_EGENERIC;
>+ }
>+
>+ switch (fmt.i_chroma)
>+ {
>+ case VLC_CODEC_RGB15:
>+ fmt.i_rmask = 0x001f;
>+ fmt.i_gmask = 0x03e0;
>+ fmt.i_bmask = 0x7c00;
>+ break;
>+ case VLC_CODEC_RGB16:
>+ fmt.i_rmask = 0x001f;
>+ fmt.i_gmask = 0x07e0;
>+ fmt.i_bmask = 0xf800;
>+ break;
>+ case VLC_CODEC_RGB24:
>+ case VLC_CODEC_RGB32:
>+ fmt.i_rmask = 0xff0000;
>+ fmt.i_gmask = 0x00ff00;
>+ fmt.i_bmask = 0x0000ff;
>+ break;
>+ default:
>+ fmt.i_rmask = 0;
>+ fmt.i_gmask = 0;
>+ fmt.i_bmask = 0;
>+ break;
>+ }
>+
>+#ifdef USE_DXVA2
>+ if (vd->fmt.i_chroma == VLC_CODEC_D3D9_OPAQUE ||
>+ vd->fmt.i_chroma == VLC_CODEC_D3D9_OPAQUE_10B)
>+ sys->hw_surfaces = true;
>+#elif defined(USE_VTBOX)
>+ if (vd->fmt.i_chroma == VLC_CODEC_CVPX_UYVY ||
>+ vd->fmt.i_chroma == VLC_CODEC_CVPX_NV12 ||
>+ vd->fmt.i_chroma == VLC_CODEC_CVPX_I420 ||
>+ vd->fmt.i_chroma == VLC_CODEC_CVPX_BGRA)
>+ sys->hw_surfaces = true;
>+#elif defined(USE_VAAPI)
>+ if (vd->fmt.i_chroma == VLC_CODEC_VAAPI_420)
>+ sys->hw_surfaces = true;
>+#endif
>+ if (sys->hw_surfaces)
>+ msg_Dbg(vd, "Using hardware surfaces");
>+
>+ vout_display_info_t info = vd->info;
>+ info.has_hide_mouse = true;
>+
>+ vd->sys = sys;
>+ vd->fmt = fmt;
>+ vd->info = info;
>+ vd->pool = Pool;
>+ vd->prepare = sys->hw_surfaces ? HardwareSurfacePrepare :
>SoftwareSurfacePrepare;
>+ vd->display = sys->hw_surfaces ? HardwareSurfaceDisplay :
>SoftwareSurfaceDisplay;
>+ vd->control = Control;
>+ vd->manage = NULL;
>+
>+ vout_display_SendEventDisplaySize(vd, fmt.i_width, fmt.i_height);
>+ vout_display_DeleteWindow(vd, NULL);
>+
>+ return VLC_SUCCESS;
>+}
>+
>+/*****************************************************************************
>+ * Destroy the video bridge output
>+
>*****************************************************************************/
>+static void Close(vlc_object_t *object)
>+{
>+ vout_display_t *vd = (vout_display_t *)object;
>+ vout_display_sys_t *sys = vd->sys;
>+
>+ if (sys->prev_pic)
>+ picture_Release(sys->prev_pic);
>+
>+#ifdef USE_VAAPI
>+ if (sys->context_id != VA_INVALID_ID)
>+ vlc_vaapi_DestroyContext(object, sys->dpy, sys->context_id);
>+#endif
>+ if (sys->pool != NULL)
>+ picture_pool_Release(sys->pool);
>+#ifdef USE_VAAPI
>+ if (sys->config_id != VA_INVALID_ID)
>+ vlc_vaapi_DestroyConfig(object, sys->dpy, sys->config_id);
>+ if (sys->dpy != NULL)
>+ vlc_vaapi_ReleaseInstance(sys->dpy);
>+#endif
>+
>+ if (sys->cleanup)
>+ sys->cleanup(sys->opaque);
>+
>+ free(sys);
>+}
>+
>+#ifdef USE_DXVA2
>+
>+/*****************************************************************************
>+ * Destroy a single DXVA2 picture
>+
>*****************************************************************************/
>+static void DestroyPoolPicture(picture_t *picture)
>+{
>+ picture_sys_t *p_sys = (picture_sys_t *)picture->p_sys;
>+
>+ if (p_sys->surface)
>+ IDirect3DSurface9_Release(p_sys->surface);
>+ free(p_sys);
>+ free(picture);
>+}
>+
>+/*****************************************************************************
>+ * Create the DXVA2 picture pool
>+
>*****************************************************************************/
>+static picture_pool_t *Pool(vout_display_t *vd, unsigned count)
>+{
>+ vout_display_sys_t *sys = vd->sys;
>+
>+ if (sys->pool != NULL)
>+ return sys->pool;
>+
>+ if (!sys->hw_surfaces)
>+ {
>+ sys->pool = picture_pool_NewFromFormat(&vd->fmt, count);
>+ return sys->pool;
>+ }
>+
>+ LPDIRECT3DDEVICE9 d3ddev = (LPDIRECT3DDEVICE9)sys->device;
>+ if (!d3ddev)
>+ {
>+ msg_Err(vd, "Invalid D3D9 display device");
>+ return NULL;
>+ }
>+
>+ D3DFORMAT format;
>+ switch (vd->fmt.i_chroma)
>+ {
>+ case VLC_CODEC_D3D9_OPAQUE_10B:
>+ format = MAKEFOURCC('P','0','1','0');
>+ break;
>+ default:
>+ format = MAKEFOURCC('N','V','1','2');
>+ break;
>+ }
>+
>+ picture_t** pictures = calloc(count, sizeof(*pictures));
>+ if (unlikely(!pictures))
>+ goto error;
>+
>+ for (unsigned int i = 0; i < count; i++)
>+ {
>+ picture_sys_t *picsys = calloc(1, sizeof(*picsys));
>+ if (unlikely(!picsys))
>+ goto error;
>+
>+ HRESULT hr =
>IDirect3DDevice9_CreateOffscreenPlainSurface(d3ddev,
>+
>vd->fmt.i_width,
>+
>vd->fmt.i_height,
>+ format,
>+
>D3DPOOL_DEFAULT,
>+
>&picsys->surface,
>+ NULL);
>+ if (FAILED(hr))
>+ {
>+ msg_Err(vd, "Failed to create D3D9 surface");
>+ free(picsys);
>+ goto error;
>+ }
>+
>+ picture_resource_t picture_resource;
>+ picture_resource.p_sys = picsys;
>+ picture_resource.pf_destroy = DestroyPoolPicture;
>+
>+ picture_t *picture = picture_NewFromResource(&vd->fmt,
>&picture_resource);
>+ if (unlikely(picture == NULL))
>+ {
>+ free(picsys);
>+ goto error;
>+ }
>+
>+ pictures[i] = picture;
>+ }
>+
>+ picture_pool_configuration_t pool_config;
>+ memset(&pool_config, 0, sizeof(pool_config));
>+ pool_config.picture_count = count;
>+ pool_config.picture = pictures;
>+
>+ sys->pool = picture_pool_NewExtended(&pool_config);
>+ if (!sys->pool)
>+ {
>+ msg_Err(vd, "Failed to create picture pool");
>+ goto error;
>+ }
>+
>+ return sys->pool;
>+
>+error:
>+ if (pictures)
>+ {
>+ for (unsigned int i = 0; i < count; i++)
>+ if (pictures[i])
>+ DestroyPoolPicture(pictures[i]);
>+ free(pictures);
>+ }
>+
>+ return NULL;
>+}
>+
>+#elif defined(USE_VAAPI)
>+
>+/*****************************************************************************
>+ * Create the VAAPI picture pool
>+
>*****************************************************************************/
>+static picture_pool_t *Pool(vout_display_t *vd, unsigned count)
>+{
>+ vout_display_sys_t *sys = vd->sys;
>+ vlc_object_t *o = VLC_OBJECT(vd);
>+
>+ if (sys->pool != NULL)
>+ return sys->pool;
>+
>+ if (!sys->hw_surfaces)
>+ {
>+ sys->pool = picture_pool_NewFromFormat(&vd->fmt, count);
>+ return sys->pool;
>+ }
>+
>+ sys->dpy = (VADisplay)sys->device;
>+ if (!sys->dpy)
>+ {
>+ msg_Err(vd, "Invalid VAAPI display device");
>+ return NULL;
>+ }
>+
>+ if (vlc_vaapi_Initialize(o, sys->dpy))
>+ {
>+ msg_Err(vd, "Failed to initialize VAAPI");
>+ sys->dpy = NULL;
>+ goto error;
>+ }
>+
>+ if (vlc_vaapi_SetInstance(sys->dpy))
>+ {
>+ msg_Err(vd, "Failed to set VAAPI instance");
>+ sys->dpy = NULL;
>+ goto error;
>+ }
>+
>+ sys->config_id = vlc_vaapi_CreateConfigChecked(o, sys->dpy,
>VAProfileNone,
>+
>VAEntrypointVideoProc, 0);
>+ if (sys->config_id == VA_INVALID_ID)
>+ {
>+ msg_Err(vd, "Failed to create VAAPI config");
>+ goto error;
>+ }
>+
>+ VASurfaceID *surfaces;
>+ sys->pool = vlc_vaapi_PoolNew(o, sys->dpy, count, &surfaces,
>&vd->fmt,
>+ VA_RT_FORMAT_YUV420, 0);
>+ if (!sys->pool)
>+ {
>+ msg_Err(vd, "Failed to create VAAPI pool");
>+ goto error;
>+ }
>+
>+ sys->context_id = vlc_vaapi_CreateContext(o, sys->dpy,
>sys->config_id,
>+ vd->fmt.i_width,
>vd->fmt.i_height,
>+ VA_PROGRESSIVE,
>surfaces, count);
>+ if (sys->context_id == VA_INVALID_ID)
>+ {
>+ msg_Err(vd, "Failed to create VAAPI context");
>+ goto error;
>+ }
>+
>+ return sys->pool;
>+
>+error:
>+ if (sys->context_id != VA_INVALID_ID)
>+ vlc_vaapi_DestroyContext(o, sys->dpy, sys->context_id);
>+ if (sys->pool != NULL)
>+ picture_pool_Release(sys->pool);
>+ if (sys->config_id != VA_INVALID_ID)
>+ vlc_vaapi_DestroyConfig(o, sys->dpy, sys->config_id);
>+ if (sys->dpy != NULL)
>+ vlc_vaapi_ReleaseInstance(sys->dpy);
>+
>+ return NULL;
>+}
>+
>+#else
>+
>+/*****************************************************************************
>+ * Create the generic picture pool
>+
>*****************************************************************************/
>+static picture_pool_t *Pool(vout_display_t *vd, unsigned count)
>+{
>+ vout_display_sys_t *sys = vd->sys;
>+
>+ if (sys->pool != NULL)
>+ return sys->pool;
>+
>+ sys->pool = picture_pool_NewFromFormat(&vd->fmt, count);
>+
>+ return sys->pool;
>+}
>+
>+#endif
>+
>+/*****************************************************************************
>+ * Call the software surface prepare
>+
>*****************************************************************************/
>+static void SoftwareSurfacePrepare(vout_display_t *vd, picture_t *pic,
>subpicture_t *subpic)
>+{
>+ vout_display_sys_t *sys = vd->sys;
>+
>+ if (sys->prepare != NULL)
>+ {
>+ void *planes[PICTURE_PLANE_MAX];
>+ unsigned pitches[PICTURE_PLANE_MAX];
>+ unsigned lines[PICTURE_PLANE_MAX];
>+ for (unsigned int i = 0; i < PICTURE_PLANE_MAX; i++)
>+ {
>+ if (i < (unsigned int)pic->i_planes)
>+ {
>+ plane_t *p_src = pic->p+i;
>+ planes[i] = p_src->p_pixels;
>+ pitches[i] = p_src->i_pitch;
>+ lines[i] = p_src->i_lines;
>+ }
>+ else
>+ {
>+ planes[i] = NULL;
>+ pitches[i] = 0;
>+ lines[i] = 0;
>+ }
>+ }
>+ sys->prepare(sys->opaque, planes, pitches, lines);
>+ }
>+
>+ VLC_UNUSED(subpic);
>+}
>+
>+/*****************************************************************************
>+ * Call the software surface display
>+
>*****************************************************************************/
>+static void SoftwareSurfaceDisplay(vout_display_t *vd, picture_t *pic,
>subpicture_t *subpic)
>+{
>+ vout_display_sys_t *sys = vd->sys;
>+
>+ if (sys->display != NULL)
>+ {
>+ void *planes[PICTURE_PLANE_MAX];
>+ unsigned pitches[PICTURE_PLANE_MAX];
>+ unsigned lines[PICTURE_PLANE_MAX];
>+ for (unsigned int i = 0; i < PICTURE_PLANE_MAX; i++)
>+ {
>+ if (i < (unsigned int)pic->i_planes)
>+ {
>+ plane_t *p_src = pic->p+i;
>+ planes[i] = p_src->p_pixels;
>+ pitches[i] = p_src->i_pitch;
>+ lines[i] = p_src->i_lines;
>+ }
>+ else
>+ {
>+ planes[i] = NULL;
>+ pitches[i] = 0;
>+ lines[i] = 0;
>+ }
>+ }
>+ sys->display(sys->opaque, planes, pitches, lines);
>+ }
>+
>+ if (sys->prev_pic)
>+ picture_Release(sys->prev_pic);
>+ sys->prev_pic = pic;
>+
>+ VLC_UNUSED(subpic);
>+}
>+
>+/*****************************************************************************
>+ * Call the hardware surface prepare
>+
>*****************************************************************************/
>+static void HardwareSurfacePrepare(vout_display_t *vd, picture_t *pic,
>subpicture_t *subpic)
>+{
>+ vout_display_sys_t *sys = vd->sys;
>+
>+ if (sys->prepare)
>+ {
>+ void *planes[PICTURE_PLANE_MAX];
>+ unsigned pitches[PICTURE_PLANE_MAX];
>+ unsigned lines[PICTURE_PLANE_MAX];
>+ for (unsigned int i = 0; i < PICTURE_PLANE_MAX; i++)
>+ {
>+ if (i == 0)
>+ {
>+#ifdef USE_DXVA2
>+ if (pic->context)
>+ planes[i] = (void*)((struct
>va_pic_context*)pic->context)->picsys.surface;
>+ else
>+ planes[i] = (void*)pic->p_sys->surface;
>+#elif defined(USE_VTBOX)
>+ planes[i] = (void*)cvpxpic_get_ref(pic);
>+#elif defined(USE_VAAPI)
>+ planes[i] =
>(void*)(uintptr_t)vlc_vaapi_PicGetSurface(pic);
>+#else
>+ planes[i] = NULL;
>+#endif
>+ }
>+ else
>+ planes[i] = NULL;
>+ pitches[i] = 0;
>+ lines[i] = 0;
>+ }
>+ sys->prepare(sys->opaque, planes, pitches, lines);
>+ }
>+
>+ VLC_UNUSED(subpic);
>+}
>+
>+/*****************************************************************************
>+ * Call the hardware surface display
>+
>*****************************************************************************/
>+static void HardwareSurfaceDisplay(vout_display_t *vd, picture_t *pic,
>subpicture_t *subpic)
>+{
>+ vout_display_sys_t *sys = vd->sys;
>+
>+ if (sys->display)
>+ {
>+ void *planes[PICTURE_PLANE_MAX];
>+ unsigned pitches[PICTURE_PLANE_MAX];
>+ unsigned lines[PICTURE_PLANE_MAX];
>+ for (unsigned int i = 0; i < PICTURE_PLANE_MAX; i++)
>+ {
>+ if (i == 0)
>+ {
>+#ifdef USE_DXVA2
>+ if (pic->context)
>+ planes[i] = (void*)((struct
>va_pic_context*)pic->context)->picsys.surface;
>+ else
>+ planes[i] = (void*)pic->p_sys->surface;
>+#elif defined(USE_VTBOX)
>+ planes[i] = (void*)cvpxpic_get_ref(pic);
>+#elif defined(USE_VAAPI)
>+ planes[i] =
>(void*)(uintptr_t)vlc_vaapi_PicGetSurface(pic);
>+#else
>+ planes[i] = NULL;
>+#endif
>+ }
>+ else
>+ planes[i] = NULL;
>+ pitches[i] = 0;
>+ lines[i] = 0;
>+ }
>+ sys->display(sys->opaque, planes, pitches, lines);
>+ }
>+
>+ if (sys->prev_pic)
>+ picture_Release(sys->prev_pic);
>+ sys->prev_pic = pic;
>+
>+ VLC_UNUSED(subpic);
>+}
>+
>+/* */
>+static int Control(vout_display_t *vd, int query, va_list args)
>+{
>+ VLC_UNUSED(vd);
>+ VLC_UNUSED(query);
>+ VLC_UNUSED(args);
>+
>+ return VLC_EGENERIC;
>+}
>diff --git a/po/POTFILES.in b/po/POTFILES.in
>index 66ea2ddf6d..3197106a26 100644
>--- a/po/POTFILES.in
>+++ b/po/POTFILES.in
>@@ -1138,6 +1138,7 @@ modules/video_output/win32/events.c
> modules/video_output/win32/glwin32.c
> modules/video_output/win32/wingdi.c
> modules/video_output/sdl.c
>+modules/video_output/vbridge.c
> modules/video_output/vdummy.c
> modules/video_output/vmem.c
> modules/video_output/wayland/shell.c
>--
>2.11.0
>
>_______________________________________________
>vlc-devel mailing list
>To unsubscribe or modify your subscription options:
>https://mailman.videolan.org/listinfo/vlc-devel
No. Just no. This was discussed several times. This creates a tight coupling between the vodeo output core and LibVLC, which *will* break in future versions.
If you want tight integration with the core, you write a plugin.
--
Rémi Denis-Courmont
Typed on an inconvenient virtual keyboard
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/vlc-devel/attachments/20170701/e79adbb9/attachment-0001.html>
More information about the vlc-devel
mailing list