[vlc-commits] [Git][videolan/vlc][master] 7 commits: fourcc: add GStreamer Memory opaque chroma
François Cartegnie (@fcartegnie)
gitlab at videolan.org
Tue Dec 20 15:12:35 UTC 2022
François Cartegnie pushed to branch master at VideoLAN / VLC
Commits:
5d6ce992 by Yann Lochet at 2022-12-20T15:00:25+00:00
fourcc: add GStreamer Memory opaque chroma
- - - - -
5d153322 by Yann Lochet at 2022-12-20T15:00:25+00:00
gstdecode: add format negotiation
This guarantees that the video sink gets a video chroma type supported
by VLC.
- - - - -
855ddd5c by Yann Lochet at 2022-12-20T15:00:25+00:00
gstdecode: fix potential memory leak
- - - - -
ecbf3940 by Yann Lochet at 2022-12-20T15:00:25+00:00
gstdecode: add support for DMABUF
- - - - -
c45a25e5 by Yann Lochet at 2022-12-20T15:00:25+00:00
opengl: add interop_gst_mem
This interop renders DMABUF-enabled GstBuffers via EGL,
EXT_image_dma_buf_import and GL_OES_EGL_image_external.
NV12 buffers are imported as a single EGLImage as there is no
guarantee that the alignements will be correct for a chrominance
EGLImage which dimensions are twice smaller.
- - - - -
30dd6d4c by Yann Lochet at 2022-12-20T15:00:25+00:00
gstdecode: add dummy video context and dummy decoder device
- - - - -
09f99896 by Yann Lochet at 2022-12-20T15:00:25+00:00
video_chroma: add converter for opaque format VLC_CODEC_GST_MEM_OPAQUE
- - - - -
18 changed files:
- configure.ac
- include/vlc_codec.h
- include/vlc_fourcc.h
- include/vlc_picture.h
- modules/codec/Makefile.am
- + modules/codec/gstreamer/gst_mem.h
- + modules/codec/gstreamer/gstcopypicture.c
- + modules/codec/gstreamer/gstcopypicture.h
- modules/codec/gstreamer/gstdecode.c
- modules/codec/gstreamer/gstvlcpictureplaneallocator.c
- modules/codec/gstreamer/gstvlcpictureplaneallocator.h
- modules/codec/gstreamer/gstvlcvideosink.c
- modules/codec/gstreamer/gstvlcvideosink.h
- modules/video_chroma/Makefile.am
- + modules/video_chroma/gst_mem.c
- modules/video_output/Makefile.am
- + modules/video_output/opengl/interop_gst_mem.c
- src/misc/fourcc.c
Changes:
=====================================
configure.ac
=====================================
@@ -2484,7 +2484,7 @@ AC_ARG_ENABLE([gst-decode],
have_gst_decode="no"
AS_IF([test "${enable_gst_decode}" != "no"], [
PKG_CHECK_MODULES([GST_APP], [gstreamer-app-1.0], [
- PKG_CHECK_MODULES([GST_VIDEO], [gstreamer-video-1.0], [
+ PKG_CHECK_MODULES([GST_VIDEO], [gstreamer-video-1.0 gstreamer-allocators-1.0], [
have_gst_decode="yes"
], [
AC_MSG_WARN([${GST_VIDEO_PKG_ERRORS}. GStreamer decoder module will not be built.])
=====================================
include/vlc_codec.h
=====================================
@@ -588,6 +588,7 @@ enum vlc_decoder_device_type
VLC_DECODER_DEVICE_AWINDOW,
VLC_DECODER_DEVICE_NVDEC,
VLC_DECODER_DEVICE_MMAL,
+ VLC_DECODER_DEVICE_GSTDECODE,
};
struct vlc_decoder_device_operations
=====================================
include/vlc_fourcc.h
=====================================
@@ -439,6 +439,9 @@
#define VLC_CODEC_CVPX_BGRA VLC_FOURCC('C','V','P','B')
#define VLC_CODEC_CVPX_P010 VLC_FOURCC('C','V','P','P')
+/* GStreamer Memory opaque buffer type */
+#define VLC_CODEC_GST_MEM_OPAQUE VLC_FOURCC('G','S','T','M')
+
/* Image codec (video) */
#define VLC_CODEC_PNG VLC_FOURCC('p','n','g',' ')
#define VLC_CODEC_PPM VLC_FOURCC('p','p','m',' ')
=====================================
include/vlc_picture.h
=====================================
@@ -98,6 +98,7 @@ enum vlc_video_context_type
VLC_VIDEO_CONTEXT_NVDEC, //!< empty
VLC_VIDEO_CONTEXT_CVPX, //!< private: cvpx_video_context*
VLC_VIDEO_CONTEXT_MMAL, //!< empty
+ VLC_VIDEO_CONTEXT_GSTDECODE, //!< empty
};
VLC_API vlc_video_context * vlc_video_context_Create(vlc_decoder_device *,
=====================================
modules/codec/Makefile.am
=====================================
@@ -614,6 +614,9 @@ libgstdecode_plugin_la_SOURCES = codec/gstreamer/gstdecode.c \
codec/gstreamer/gstvlcvideopool.h \
codec/gstreamer/gstvlcvideosink.c \
codec/gstreamer/gstvlcvideosink.h \
+ codec/gstreamer/gstcopypicture.c \
+ codec/gstreamer/gstcopypicture.h \
+ codec/gstreamer/gst_mem.h \
codec/gstreamer/fourcc.c
libgstdecode_plugin_la_CFLAGS = $(AM_CFLAGS) $(GST_VIDEO_CFLAGS) $(GST_APP_CFLAGS)
libgstdecode_plugin_la_LIBADD = $(GST_VIDEO_LIBS) $(GST_APP_LIBS)
=====================================
modules/codec/gstreamer/gst_mem.h
=====================================
@@ -0,0 +1,38 @@
+/*****************************************************************************
+ * gst_mem.h: GStreamer Memory picture context for VLC
+ *****************************************************************************
+ * Copyright (C) 2022 VLC authors and VideoLAN
+ *
+ * Author: Yann Lochet <yann at l0chet.fr>
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifndef VLC_GST_MEM_H
+#define VLC_GST_MEM_H
+
+#include <vlc_picture.h>
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+
+struct gst_mem_pic_context
+{
+ picture_context_t s;
+ GstBuffer *p_buf;
+ GstVideoInfo *p_vinfo;
+};
+
+#endif
=====================================
modules/codec/gstreamer/gstcopypicture.c
=====================================
@@ -0,0 +1,61 @@
+/*****************************************************************************
+ * gstcopypicture.h: copy GStreamer frames into pictures
+ *****************************************************************************
+ * Copyright (C) 2022 VLC authors and VideoLAN
+ *
+ * Author: Yann Lochet <yann at l0chet.fr>
+ *
+ * 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.
+ *****************************************************************************/
+
+#include <vlc_picture.h>
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+
+#include "gstcopypicture.h"
+
+/* Copy the frame data from the GstBuffer (from decoder)
+ * to the picture obtained from downstream in VLC.
+ * This function should be avoided as much
+ * as possible, since it involves a complete frame copy. */
+void gst_CopyPicture( picture_t *p_pic, GstVideoFrame *p_frame )
+{
+ int i_plane, i_planes, i_line, i_dst_stride, i_src_stride;
+ uint8_t *p_dst, *p_src;
+ int i_w, i_h;
+
+ i_planes = p_pic->i_planes;
+ for( i_plane = 0; i_plane < i_planes; i_plane++ )
+ {
+ p_dst = p_pic->p[i_plane].p_pixels;
+ p_src = GST_VIDEO_FRAME_PLANE_DATA( p_frame, i_plane );
+ i_dst_stride = p_pic->p[i_plane].i_pitch;
+ i_src_stride = GST_VIDEO_FRAME_PLANE_STRIDE( p_frame, i_plane );
+
+ i_w = GST_VIDEO_FRAME_COMP_WIDTH( p_frame,
+ i_plane ) * GST_VIDEO_FRAME_COMP_PSTRIDE( p_frame, i_plane );
+ i_h = GST_VIDEO_FRAME_COMP_HEIGHT( p_frame, i_plane );
+
+ for( i_line = 0;
+ i_line < __MIN( p_pic->p[i_plane].i_lines, i_h );
+ i_line++ )
+ {
+ memcpy( p_dst, p_src, i_w );
+ p_src += i_src_stride;
+ p_dst += i_dst_stride;
+ }
+ }
+}
=====================================
modules/codec/gstreamer/gstcopypicture.h
=====================================
@@ -0,0 +1,31 @@
+/*****************************************************************************
+ * gstcopypicture.h: copy GStreamer frames into pictures
+ *****************************************************************************
+ * Copyright (C) 2022 VLC authors and VideoLAN
+ *
+ * Author: Yann Lochet <yann at l0chet.fr>
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifndef VLC_GSTCOPYPICTURE_H
+#define VLC_GSTCOPYPICTURE_H
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+
+void gst_CopyPicture( picture_t *p_pic, GstVideoFrame *p_frame );
+
+#endif
=====================================
modules/codec/gstreamer/gstdecode.c
=====================================
@@ -34,12 +34,15 @@
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/video/gstvideometa.h>
+#include <gst/allocators/gstdmabuf.h>
#include <gst/app/gstappsrc.h>
#include <gst/gstatomicqueue.h>
#include "gstvlcpictureplaneallocator.h"
#include "gstvlcvideosink.h"
+#include "gstcopypicture.h"
+#include "gst_mem.h"
typedef struct
{
@@ -56,6 +59,8 @@ typedef struct
GstAtomicQueue *p_que;
bool b_prerolled;
bool b_running;
+
+ vlc_video_context *vctx;
} decoder_sys_t;
typedef struct
@@ -71,6 +76,7 @@ static int OpenDecoder( vlc_object_t* );
static void CloseDecoder( vlc_object_t* );
static int DecodeBlock( decoder_t*, block_t* );
static void Flush( decoder_t * );
+static int OpenDecoderDevice( vlc_decoder_device*, vlc_window_t* );
#define MODULE_DESCRIPTION N_( "Uses GStreamer framework's plugins " \
"to decode the media codecs" )
@@ -104,8 +110,37 @@ vlc_module_begin( )
USEDECODEBIN_LONGTEXT )
add_bool( "use-vlcpool", false, USEVLCPOOL_TEXT,
USEVLCPOOL_LONGTEXT )
+ add_submodule( )
+ set_callback_dec_device( OpenDecoderDevice, 100 )
+ add_shortcut( "gstdecode" )
vlc_module_end( )
+static void gst_mem_pic_context_Destroy( struct picture_context_t *ctx )
+{
+ struct gst_mem_pic_context *gst_mem_ctx = container_of( ctx,
+ struct gst_mem_pic_context, s );
+
+ gst_buffer_unref( gst_mem_ctx->p_buf );
+ free( gst_mem_ctx );
+}
+
+static picture_context_t *gst_mem_pic_context_Copy(
+ struct picture_context_t *ctx )
+{
+ struct gst_mem_pic_context *gst_mem_ctx = container_of( ctx,
+ struct gst_mem_pic_context, s );
+ struct gst_mem_pic_context *gst_mem_ctx_copy = calloc( 1,
+ sizeof( *gst_mem_ctx_copy ) );
+ if( unlikely( gst_mem_ctx_copy == NULL ) )
+ return NULL;
+
+ *gst_mem_ctx_copy = *gst_mem_ctx;
+ vlc_video_context_Hold( gst_mem_ctx_copy->s.vctx );
+ gst_buffer_ref( gst_mem_ctx_copy->p_buf );
+
+ return &gst_mem_ctx_copy->s;
+}
+
void gst_vlc_dec_ensure_empty_queue( decoder_t *p_dec )
{
decoder_sys_t *p_sys = p_dec->p_sys;
@@ -148,6 +183,35 @@ static gboolean seek_data_cb( GstAppSrc *p_src, guint64 l_offset,
return TRUE;
}
+/* Emitted by decodebin when an autoplugged element not yet
+ * downstream-linked does a query.
+ * Used here for format and allocator negotiation. */
+static gboolean autoplug_query_cb( GstElement *p_bin, GstPad *p_pad,
+ GstElement *p_element, GstQuery *p_query,
+ gpointer p_data )
+{
+ VLC_UNUSED( p_bin );
+ decoder_t *p_dec = p_data;
+ decoder_sys_t *p_sys = p_dec->p_sys;
+
+ if( ( p_pad->direction == GST_PAD_SRC ) &&
+ GST_IS_VIDEO_DECODER( p_element ) )
+ {
+ switch( GST_QUERY_TYPE ( p_query ) ){
+ case GST_QUERY_CAPS:
+ return gst_vlc_video_sink_query_caps( p_query );
+ case GST_QUERY_ALLOCATION:
+ GstBaseSink *p_bsink = GST_BASE_SINK_CAST( p_sys->p_decode_out );
+ GstBaseSinkClass *p_bclass = GST_BASE_SINK_GET_CLASS( p_bsink );
+ return p_bclass->propose_allocation( p_bsink, p_query );
+ default:
+ return FALSE;
+ }
+ }
+
+ return FALSE;
+}
+
/* Emitted by decodebin and links decodebin to vlcvideosink.
* Since only one elementary codec stream is fed to decodebin,
* this signal cannot be emitted more than once. */
@@ -215,39 +279,6 @@ static void frame_handoff_cb( GstElement *p_ele, GstBuffer *p_buf,
gst_atomic_queue_push( p_sys->p_que, gst_buffer_ref( p_buf ) );
}
-/* Copy the frame data from the GstBuffer (from decoder)
- * to the picture obtained from downstream in VLC.
- * This function should be avoided as much
- * as possible, since it involves a complete frame copy. */
-static void gst_CopyPicture( picture_t *p_pic, GstVideoFrame *p_frame )
-{
- int i_plane, i_planes, i_line, i_dst_stride, i_src_stride;
- uint8_t *p_dst, *p_src;
- int i_w, i_h;
-
- i_planes = p_pic->i_planes;
- for( i_plane = 0; i_plane < i_planes; i_plane++ )
- {
- p_dst = p_pic->p[i_plane].p_pixels;
- p_src = GST_VIDEO_FRAME_PLANE_DATA( p_frame, i_plane );
- i_dst_stride = p_pic->p[i_plane].i_pitch;
- i_src_stride = GST_VIDEO_FRAME_PLANE_STRIDE( p_frame, i_plane );
-
- i_w = GST_VIDEO_FRAME_COMP_WIDTH( p_frame,
- i_plane ) * GST_VIDEO_FRAME_COMP_PSTRIDE( p_frame, i_plane );
- i_h = GST_VIDEO_FRAME_COMP_HEIGHT( p_frame, i_plane );
-
- for( i_line = 0;
- i_line < __MIN( p_pic->p[i_plane].i_lines, i_h );
- i_line++ )
- {
- memcpy( p_dst, p_src, i_w );
- p_src += i_src_stride;
- p_dst += i_dst_stride;
- }
- }
-}
-
/* Check if the element can use this caps */
static gint find_decoder_func( gconstpointer p_p1, gconstpointer p_p2 )
{
@@ -564,6 +595,8 @@ static int OpenDecoder( vlc_object_t *p_this )
g_signal_connect( G_OBJECT( p_sys->p_decode_in ), "pad-added",
G_CALLBACK( pad_added_cb ), p_dec );
+ g_signal_connect( G_OBJECT( p_sys->p_decode_in ), "autoplug-query",
+ G_CALLBACK( autoplug_query_cb ), p_dec );
}
/* videosink: will emit signal for every available buffer */
@@ -623,6 +656,20 @@ static int OpenDecoder( vlc_object_t *p_this )
p_dec->pf_decode = DecodeBlock;
p_dec->pf_flush = Flush;
+ vlc_decoder_device *dec_device = decoder_GetDecoderDevice( p_dec );
+ if( dec_device == NULL )
+ {
+ msg_Err( p_dec, "failed to get a decoder device" );
+ goto fail;
+ }
+ p_sys->vctx = vlc_video_context_Create( dec_device, VLC_VIDEO_CONTEXT_GSTDECODE, 0, NULL );
+ vlc_decoder_device_Release( dec_device );
+ if( unlikely( p_sys->vctx == NULL ) )
+ {
+ msg_Err( p_dec, "failed to create a video context" );
+ goto fail;
+ }
+
return VLC_SUCCESS;
fail:
@@ -775,22 +822,84 @@ static int DecodeBlock( decoder_t *p_dec, block_t *p_block )
GstBuffer *p_buf = GST_BUFFER_CAST(
gst_atomic_queue_pop( p_sys->p_que ));
GstMemory *p_mem;
+ p_mem = gst_buffer_peek_memory( p_buf, 0 );
- if(( p_mem = gst_buffer_peek_memory( p_buf, 0 )) &&
+ bool b_copy_picture = true;
+
+ if( p_mem &&
GST_IS_VLC_PICTURE_PLANE_ALLOCATOR( p_mem->allocator ))
{
+ b_copy_picture = false;
p_pic = picture_Hold(( (GstVlcPicturePlane*) p_mem )->p_pic );
}
- else
+ else if( p_mem && gst_is_dmabuf_memory(p_mem) )
+ {
+ b_copy_picture = false;
+
+ switch( p_dec->fmt_out.video.i_chroma ) {
+ case VLC_CODEC_NV12:
+ p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec =
+ VLC_CODEC_GST_MEM_OPAQUE;
+ break;
+ case VLC_CODEC_GST_MEM_OPAQUE:
+ break;
+ /* fallback */
+ default:
+ b_copy_picture = true;
+ }
+
+ if( !b_copy_picture )
+ {
+ /* Get a new picture */
+ if( decoder_UpdateVideoOutput( p_dec, p_sys->vctx ) )
+ {
+ gst_buffer_unref( p_buf );
+ goto done;
+ }
+ p_pic = decoder_NewPicture( p_dec );
+ if( !p_pic )
+ {
+ gst_buffer_unref( p_buf );
+ goto done;
+ }
+
+ struct gst_mem_pic_context *pctx = calloc( 1, sizeof( *pctx ) );
+ if( unlikely( pctx == NULL ) )
+ {
+ gst_buffer_unref( p_buf );
+ return VLCDEC_ECRITICAL;
+ }
+
+ pctx->s = ( picture_context_t ) {
+ gst_mem_pic_context_Destroy, gst_mem_pic_context_Copy,
+ p_sys->vctx,
+ };
+ vlc_video_context_Hold( pctx->s.vctx );
+
+ pctx->p_buf = p_buf;
+ gst_buffer_ref( p_buf );
+
+ pctx->p_vinfo = &p_sys->vinfo;
+ p_pic->context = &pctx->s;
+ }
+ }
+
+ if( b_copy_picture )
{
GstVideoFrame frame;
/* Get a new picture */
if( decoder_UpdateVideoFormat( p_dec ) )
+ {
+ gst_buffer_unref( p_buf );
goto done;
+ }
p_pic = decoder_NewPicture( p_dec );
if( !p_pic )
+ {
+ gst_buffer_unref( p_buf );
goto done;
+ }
if( unlikely( !gst_video_frame_map( &frame,
&p_sys->vinfo, p_buf, GST_MAP_READ ) ) )
@@ -804,6 +913,10 @@ static int DecodeBlock( decoder_t *p_dec, block_t *p_block )
gst_video_frame_unmap( &frame );
}
+ if( p_pic != NULL )
+ p_pic->b_progressive = ( p_sys->vinfo.interlace_mode ==
+ GST_VIDEO_INTERLACE_MODE_PROGRESSIVE );
+
if( likely( GST_BUFFER_PTS_IS_VALID( p_buf ) ) )
p_pic->date = gst_util_uint64_scale(
GST_BUFFER_PTS( p_buf ), GST_MSECOND, GST_SECOND );
@@ -892,5 +1005,22 @@ static void CloseDecoder( vlc_object_t *p_this )
if( p_sys->p_decoder )
gst_object_unref( p_sys->p_decoder );
+ if( p_sys->vctx )
+ vlc_video_context_Release( p_sys->vctx );
+
free( p_sys );
}
+
+static const struct vlc_decoder_device_operations gstdecode_device_ops = {
+ .close = NULL,
+};
+
+static int OpenDecoderDevice(vlc_decoder_device *device, vlc_window_t *window)
+{
+ VLC_UNUSED(window);
+
+ device->ops = &gstdecode_device_ops;
+ device->type = VLC_DECODER_DEVICE_GSTDECODE;
+
+ return VLC_SUCCESS;
+}
=====================================
modules/codec/gstreamer/gstvlcpictureplaneallocator.c
=====================================
@@ -132,7 +132,7 @@ static GstMemory* gst_vlc_picture_plane_copy(
return NULL;
}
-static vlc_fourcc_t gst_vlc_to_map_format( const char* psz_fourcc )
+vlc_fourcc_t gst_vlc_to_map_format( const char* psz_fourcc )
{
if( !psz_fourcc )
return VLC_CODEC_UNKNOWN;
=====================================
modules/codec/gstreamer/gstvlcpictureplaneallocator.h
=====================================
@@ -79,6 +79,7 @@ bool gst_vlc_picture_plane_allocator_query_format(
GstVideoAlignment *p_align, GstCaps *p_caps );
bool gst_vlc_set_vout_fmt( GstVideoInfo *p_info, GstVideoAlignment *p_align,
GstCaps *p_caps, decoder_t *p_dec );
+vlc_fourcc_t gst_vlc_to_map_format( const char* psz_fourcc );
void gst_vlc_dec_ensure_empty_queue( decoder_t* p_dec );
bool gst_vlc_picture_plane_allocator_hold( GstVlcPicturePlaneAllocator
*p_allocator, GstBuffer *p_buffer );
=====================================
modules/codec/gstreamer/gstvlcvideosink.c
=====================================
@@ -25,6 +25,7 @@
*****************************************************************************/
#include "gstvlcvideopool.h"
#include "gstvlcvideosink.h"
+#include "gstvlcpictureplaneallocator.h"
#include <vlc_common.h>
@@ -57,7 +58,9 @@ static GstStaticPadTemplate sink_template =
static gboolean gst_vlc_video_sink_setcaps( GstBaseSink *p_bsink,
GstCaps *p_caps );
static gboolean gst_vlc_video_sink_propose_allocation( GstBaseSink *p_bsink,
- GstQuery *p_query);
+ GstQuery *p_query );
+static gboolean gst_vlc_video_sink_query( GstBaseSink *p_bsink,
+ GstQuery *p_query );
static GstFlowReturn gst_vlc_video_sink_chain( GstBaseSink *p_vsink,
GstBuffer *p_buffer );
@@ -127,6 +130,8 @@ static void gst_vlc_video_sink_class_init( GstVlcVideoSinkClass *p_klass )
p_gstbasesink_class->propose_allocation =
gst_vlc_video_sink_propose_allocation;
+ p_gstbasesink_class->query = gst_vlc_video_sink_query;
+
p_gstbasesink_class->render = gst_vlc_video_sink_chain;
}
@@ -262,6 +267,52 @@ invalid_caps:
}
}
+gboolean gst_vlc_video_sink_query_caps( GstQuery *p_query )
+{
+ GstCaps *p_query_caps;
+ gst_query_parse_caps( p_query, &p_query_caps );
+
+ if( p_query_caps == NULL )
+ return FALSE;
+
+ /* gst_caps_normalize takes ownership of the cap */
+ gst_caps_ref( p_query_caps );
+ GstCaps *p_normalized = gst_caps_normalize( p_query_caps );
+ p_normalized = gst_caps_make_writable( p_normalized );
+
+ guint i = 0;
+ while( i < gst_caps_get_size( p_normalized ) )
+ {
+ GstStructure *p_str = gst_caps_get_structure( p_normalized, i );
+ const char* psz_fourcc = gst_structure_get_string( p_str, "format" );
+
+ if( ( psz_fourcc != NULL ) && gst_vlc_to_map_format( psz_fourcc ) ==
+ VLC_CODEC_UNKNOWN )
+ {
+ gst_caps_remove_structure( p_normalized, i );
+ }
+ else
+ {
+ i++;
+ }
+ }
+
+ gst_query_set_caps_result( p_query, p_normalized );
+
+ return TRUE;
+}
+
+static gboolean gst_vlc_video_sink_query( GstBaseSink *p_bsink,
+ GstQuery *p_query )
+{
+ if( GST_QUERY_TYPE( p_query ) == GST_QUERY_CAPS )
+ {
+ return gst_vlc_video_sink_query_caps( p_query );
+ }
+
+ return GST_BASE_SINK_CLASS( parent_class )->query( p_bsink, p_query );
+}
+
static GstFlowReturn gst_vlc_video_sink_chain( GstBaseSink *p_bsink,
GstBuffer *p_buffer )
{
=====================================
modules/codec/gstreamer/gstvlcvideosink.h
=====================================
@@ -81,4 +81,6 @@ struct _GstVlcVideoSinkClass
GType gst_vlc_video_sink_get_type (void);
+gboolean gst_vlc_video_sink_query_caps( GstQuery *p_query );
+
#endif /* __GST_VLC_VIDEO_SINK_H__ */
=====================================
modules/video_chroma/Makefile.am
=====================================
@@ -89,6 +89,15 @@ if HAVE_DARWIN
chroma_LTLIBRARIES += libcvpx_plugin.la
endif
+libgst_mem_plugin_la_SOURCES = video_chroma/gst_mem.c \
+ codec/gstreamer/gstcopypicture.c codec/gstreamer/gstcopypicture.h codec/gstreamer/gst_mem.h
+libgst_mem_plugin_la_CFLAGS = $(AM_CFLAGS) $(GST_VIDEO_CFLAGS) $(GST_APP_CFLAGS)
+libgst_mem_plugin_la_LIBADD = $(GST_VIDEO_LIBS) $(GST_APP_LIBS)
+
+if HAVE_GST_DECODE
+chroma_LTLIBRARIES += libgst_mem_plugin.la
+endif
+
# Tests
chroma_copy_sse_test_SOURCES = $(libchroma_copy_la_SOURCES)
chroma_copy_sse_test_CFLAGS = -DCOPY_TEST
=====================================
modules/video_chroma/gst_mem.c
=====================================
@@ -0,0 +1,118 @@
+/*****************************************************************************
+ * gst_mem.c: GStreamer Memory to picture converter
+ *****************************************************************************
+ * Copyright (C) 2022 VLC authors and VideoLAN
+ *
+ * Author: Yann Lochet <yann at l0chet.fr>
+ *
+ * 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 <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/video/video-format.h>
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_filter.h>
+#include <vlc_picture.h>
+
+#include "../codec/gstreamer/gstcopypicture.h"
+#include "../codec/gstreamer/gst_mem.h"
+
+static picture_t * Filter(filter_t *p_filter, picture_t *src)
+{
+ struct gst_mem_pic_context *pctx = container_of(src->context,
+ struct gst_mem_pic_context, s);
+ GstBuffer *p_buf = pctx->p_buf;
+
+ picture_t *dst = filter_NewPicture(p_filter);
+ if (!dst)
+ return NULL;
+ picture_CopyProperties(dst, src);
+
+ GstVideoFrame frame;
+ if (unlikely(!gst_video_frame_map(&frame, pctx->p_vinfo, p_buf, GST_MAP_READ)))
+ {
+ msg_Err(p_filter, "failed to map gst video frame");
+ return NULL;
+ }
+
+ gst_CopyPicture(dst, &frame);
+ gst_video_frame_unmap(&frame);
+
+ picture_Release(src);
+ return dst;
+}
+
+static picture_t * Filter_chain( filter_t *p_filter, picture_t *src )
+{
+ filter_chain_t *p_chain = p_filter->p_sys;
+ return filter_chain_VideoFilter(p_chain, src);
+}
+
+static const struct vlc_filter_operations filter_ops = {
+ .filter_video = Filter,
+};
+
+static const struct vlc_filter_operations chain_ops = {
+ .filter_video = Filter_chain,
+};
+
+static int Open(filter_t *p_filter)
+{
+ if(p_filter->fmt_in.video.i_chroma != VLC_CODEC_GST_MEM_OPAQUE)
+ return VLC_EGENERIC;
+
+ if(p_filter->fmt_out.video.i_chroma == VLC_CODEC_NV12)
+ {
+ p_filter->ops = &filter_ops;
+ return VLC_SUCCESS;
+ }
+
+ es_format_t fmt_intermediate;
+ es_format_Copy(&fmt_intermediate, &p_filter->fmt_out);
+ fmt_intermediate.video.i_chroma = fmt_intermediate.i_codec = VLC_CODEC_NV12;
+
+ filter_chain_t *p_chain = filter_chain_NewVideo(p_filter, false, &p_filter->owner);
+ if (p_chain == NULL)
+ return VLC_ENOMEM;
+ filter_chain_Reset(p_chain, &p_filter->fmt_in, p_filter->vctx_in, &p_filter->fmt_out);
+
+ int ret;
+ ret = filter_chain_AppendConverter(p_chain, &fmt_intermediate);
+ if (ret != 0)
+ return VLC_EGENERIC;
+
+ ret = filter_chain_AppendConverter(p_chain, NULL);
+ if (ret != 0)
+ return VLC_EGENERIC;
+
+ p_filter->p_sys = p_chain;
+ p_filter->ops = &chain_ops;
+
+ return VLC_SUCCESS;
+}
+
+vlc_module_begin()
+ set_shortname(N_("GST_MEM converter"))
+ set_description(N_("GST_MEM Chroma Converter filter"))
+ set_subcategory(SUBCAT_VIDEO_VFILTER)
+ set_callback_video_converter(Open, 10)
+vlc_module_end()
=====================================
modules/video_output/Makefile.am
=====================================
@@ -119,6 +119,12 @@ vout_LTLIBRARIES += \
libcaeagl_ios_plugin.la
endif
+libglinterop_gst_mem_plugin_la_SOURCES = video_output/opengl/interop_gst_mem.c \
+ video_output/opengl/interop.h codec/gstreamer/gst_mem.h
+libglinterop_gst_mem_plugin_la_CFLAGS = $(AM_CFLAGS) $(GL_CFLAGS) $(GST_VIDEO_CFLAGS) \
+ $(GST_APP_CFLAGS)
+libglinterop_gst_mem_plugin_la_LIBADD = $(GST_VIDEO_LIBS) $(GST_APP_LIBS)
+
libglinterop_vaapi_plugin_la_SOURCES = video_output/opengl/interop_vaapi.c \
video_output/opengl/interop.h \
hw/vaapi/vlc_vaapi.c hw/vaapi/vlc_vaapi.h
@@ -135,6 +141,10 @@ if HAVE_EGL
if HAVE_VAAPI
vout_LTLIBRARIES += libglinterop_vaapi_plugin.la
endif
+
+if HAVE_GST_DECODE
+vout_LTLIBRARIES += libglinterop_gst_mem_plugin.la
+endif
endif # HAVE_EGL
if HAVE_VDPAU
=====================================
modules/video_output/opengl/interop_gst_mem.c
=====================================
@@ -0,0 +1,276 @@
+/*****************************************************************************
+ * interop_gst_mem.c: OpenGL GStreamer Memory opaque converter
+ *****************************************************************************
+ * Copyright (C) 2022 VLC authors and VideoLAN
+ *
+ * Author: Yann Lochet <yann at l0chet.fr>
+ * Heavily inspired by interop_vaapi.c
+ *
+ * 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 <assert.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/video/video-format.h>
+#include <gst/allocators/gstdmabuf.h>
+
+#include <vlc_common.h>
+#include <vlc_window.h>
+#include <vlc_codec.h>
+#include <vlc_plugin.h>
+
+#include "gl_util.h"
+#include "interop.h"
+
+#include "../../codec/gstreamer/gst_mem.h"
+
+#define DRM_FORMAT_MOD_LINEAR 0ULL
+
+struct priv
+{
+ PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
+
+ struct
+ {
+ EGLDisplay display;
+ EGLDisplay (*getCurrentDisplay)();
+ const char *(*queryString)(EGLDisplay, EGLint);
+ EGLImage (*createImageKHR)(EGLDisplay, EGLContext, EGLenum target, EGLClientBuffer buffer,
+ const EGLint *attrib_list);
+ void (*destroyImageKHR)(EGLDisplay, EGLImage image);
+ } egl;
+
+ struct
+ {
+ PFNGLBINDTEXTUREPROC BindTexture;
+ } gl;
+
+ EGLint drm_fourccs[3];
+};
+
+static void
+egl_image_destroy(const struct vlc_gl_interop *interop, EGLImageKHR image)
+{
+ struct priv *priv = interop->priv;
+ priv->egl.destroyImageKHR(priv->egl.display, image);
+}
+
+static int
+egl_update(const struct vlc_gl_interop *interop, uint32_t textures[],
+ const int32_t tex_width[], const int32_t tex_height[],
+ picture_t *pic, const size_t *plane_offset)
+{
+ (void) plane_offset;
+ struct priv *priv = interop->priv;
+
+ struct gst_mem_pic_context *pctx = container_of( pic->context,
+ struct gst_mem_pic_context, s );
+ GstBuffer *p_buf = pctx->p_buf;
+ GstVideoMeta *p_meta = gst_buffer_get_video_meta(p_buf);
+ GstMemory *p_mem = gst_buffer_peek_memory(p_buf, 0);
+ int dmabuf_fd = gst_dmabuf_memory_get_fd(p_mem);
+
+ int egl_color_space;
+ switch (interop->fmt_in.space)
+ {
+ case COLOR_SPACE_BT601:
+ egl_color_space = EGL_ITU_REC601_EXT;
+ break;
+ case COLOR_SPACE_BT709:
+ egl_color_space = EGL_ITU_REC709_EXT;
+ break;
+ case COLOR_SPACE_BT2020:
+ egl_color_space = EGL_ITU_REC2020_EXT;
+ break;
+ default:
+ goto error;
+ }
+
+ int egl_color_range;
+ switch (interop->fmt_in.color_range)
+ {
+ case COLOR_RANGE_FULL:
+ egl_color_range = EGL_YUV_FULL_RANGE_EXT;
+ break;
+ case COLOR_RANGE_LIMITED:
+ egl_color_range = EGL_YUV_NARROW_RANGE_EXT;
+ break;
+ default:
+ vlc_assert_unreachable();
+ }
+
+ const EGLint attribs[] = {
+ EGL_WIDTH, tex_width[0],
+ EGL_HEIGHT, tex_height[0],
+ EGL_LINUX_DRM_FOURCC_EXT, priv->drm_fourccs[0],
+ EGL_DMA_BUF_PLANE0_FD_EXT, dmabuf_fd,
+ EGL_DMA_BUF_PLANE0_OFFSET_EXT, p_meta->offset[0],
+ EGL_DMA_BUF_PLANE0_PITCH_EXT, p_meta->stride[0],
+ EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, DRM_FORMAT_MOD_LINEAR & 0xffffffff,
+ EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, (DRM_FORMAT_MOD_LINEAR >> 32) & 0xffffffff,
+ EGL_DMA_BUF_PLANE1_FD_EXT, dmabuf_fd,
+ EGL_DMA_BUF_PLANE1_OFFSET_EXT, p_meta->offset[1],
+ EGL_DMA_BUF_PLANE1_PITCH_EXT, p_meta->stride[1],
+ EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT, DRM_FORMAT_MOD_LINEAR & 0xffffffff,
+ EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT, (DRM_FORMAT_MOD_LINEAR >> 32) & 0xffffffff,
+ EGL_YUV_COLOR_SPACE_HINT_EXT, egl_color_space,
+ EGL_SAMPLE_RANGE_HINT_EXT, egl_color_range,
+ EGL_NONE
+ };
+
+ EGLImageKHR egl_image = priv->egl.createImageKHR(priv->egl.display, EGL_NO_CONTEXT,
+ EGL_LINUX_DMA_BUF_EXT, NULL,
+ attribs);
+
+ if( egl_image == NULL )
+ goto error;
+
+ priv->gl.BindTexture(interop->tex_target, textures[0]);
+
+ priv->glEGLImageTargetTexture2DOES(interop->tex_target, egl_image);
+
+ egl_image_destroy(interop, egl_image);
+
+ return VLC_SUCCESS;
+
+error:
+ return VLC_EGENERIC;
+}
+
+static void
+Close(struct vlc_gl_interop *interop)
+{
+ struct priv *priv = interop->priv;
+
+ free(priv);
+}
+
+static int
+Open(vlc_object_t *obj)
+{
+ struct vlc_gl_interop *interop = (void *) obj;
+ struct priv *priv = NULL;
+
+ if (interop->vctx == NULL)
+ return VLC_EGENERIC;
+ vlc_decoder_device *dec_device = vlc_video_context_HoldDevice(interop->vctx);
+ if (dec_device->type != VLC_DECODER_DEVICE_GSTDECODE)
+ goto error;
+
+ priv = interop->priv = calloc(1, sizeof(struct priv));
+ if (unlikely(priv == NULL))
+ goto error;
+
+ switch (interop->fmt_in.i_chroma)
+ {
+ case VLC_CODEC_GST_MEM_OPAQUE:
+ interop->tex_count = 1;
+ interop->texs[0] = (struct vlc_gl_tex_cfg) {
+ .w = {1, 1},
+ .h = {1, 1},
+ .internal = GL_RGBA,
+ .format = GL_RGBA,
+ .type = GL_UNSIGNED_BYTE,
+ };
+
+ priv->drm_fourccs[0] = VLC_FOURCC('N', 'V', '1', '2');
+ break;
+ default:
+ goto error;
+ }
+
+ struct vlc_gl_extension_vt extension_vt;
+ vlc_gl_LoadExtensionFunctions(interop->gl, &extension_vt);
+
+ /* GL_OES_EGL_image_external is required for GL_TEXTURE_EXTERNAL_OES */
+ if (!vlc_gl_HasExtension(&extension_vt, "GL_OES_EGL_image_external"))
+ goto error;
+
+ priv->egl.getCurrentDisplay = vlc_gl_GetProcAddress(interop->gl, "eglGetCurrentDisplay");
+ if (priv->egl.getCurrentDisplay == EGL_NO_DISPLAY)
+ goto error;
+
+ priv->egl.display = priv->egl.getCurrentDisplay();
+ if (priv->egl.display == EGL_NO_DISPLAY)
+ goto error;
+
+ priv->egl.queryString = vlc_gl_GetProcAddress(interop->gl, "eglQueryString");
+ if (priv->egl.queryString == NULL)
+ goto error;
+
+ /* EGL_EXT_image_dma_buf_import implies EGL_KHR_image_base */
+ const char *eglexts = priv->egl.queryString(priv->egl.display, EGL_EXTENSIONS);
+ if (eglexts == NULL || !vlc_gl_StrHasToken(eglexts, "EGL_EXT_image_dma_buf_import"))
+ goto error;
+
+ priv->egl.createImageKHR =
+ vlc_gl_GetProcAddress(interop->gl, "eglCreateImageKHR");
+ if (priv->egl.createImageKHR == NULL)
+ goto error;
+
+ priv->egl.destroyImageKHR =
+ vlc_gl_GetProcAddress(interop->gl, "eglDestroyImageKHR");
+ if (priv->egl.destroyImageKHR == NULL)
+ goto error;
+
+ priv->glEGLImageTargetTexture2DOES =
+ vlc_gl_GetProcAddress(interop->gl, "glEGLImageTargetTexture2DOES");
+ if (priv->glEGLImageTargetTexture2DOES == NULL)
+ goto error;
+
+ priv->gl.BindTexture =
+ vlc_gl_GetProcAddress(interop->gl, "glBindTexture");
+ if (priv->gl.BindTexture == NULL)
+ goto error;
+
+ /* The pictures are uploaded upside-down */
+ video_format_TransformBy(&interop->fmt_out, TRANSFORM_VFLIP);
+
+ interop->tex_target = GL_TEXTURE_EXTERNAL_OES;
+ interop->fmt_out.i_chroma = VLC_CODEC_RGB32;
+ interop->fmt_out.space = COLOR_SPACE_UNDEF;
+
+ static const struct vlc_gl_interop_ops ops = {
+ .update_textures = egl_update,
+ .close = Close,
+ };
+ interop->ops = &ops;
+
+ vlc_decoder_device_Release(dec_device);
+
+ return VLC_SUCCESS;
+
+error:
+ vlc_decoder_device_Release(dec_device);
+ free(priv);
+ return VLC_EGENERIC;
+}
+
+vlc_module_begin ()
+ set_description("GST_MEM OpenGL surface converter")
+ set_capability("glinterop", 1)
+ set_callback(Open)
+ set_subcategory(SUBCAT_VIDEO_VOUT)
+ add_shortcut("gst_mem")
+vlc_module_end ()
=====================================
src/misc/fourcc.c
=====================================
@@ -835,6 +835,8 @@ static const struct
{ { VLC_CODEC_CVPX_P010, 0 }, FAKE_FMT() },
+ { { VLC_CODEC_GST_MEM_OPAQUE, 0 }, FAKE_FMT() },
+
{ { VLC_CODEC_VAAPI_420, VLC_CODEC_VAAPI_420_10BPP },
FAKE_FMT() },
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/1d312f1dd7d5199a934d715a919f704edd44aa20...09f99896cd1eef0b93123e5d8249dc044fbec233
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/1d312f1dd7d5199a934d715a919f704edd44aa20...09f99896cd1eef0b93123e5d8249dc044fbec233
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