1 /*****************************************************************************
2 * gstvlcvideosink.c: VLC gstreamer video sink
3 *****************************************************************************
4 * Copyright (C) 2016 VLC authors and VideoLAN
7 * Author: Vikram Fugro <vikram.fugro@gmail.com>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
27 #include "gstvlcvideopool.h"
28 #include "gstvlcvideosink.h"
30 #include <vlc_common.h>
46 static guint gst_vlc_video_sink_signals
[ LAST_SIGNAL
] = { 0 };
48 static GstStaticPadTemplate sink_template
=
49 GST_STATIC_PAD_TEMPLATE ("sink",
52 GST_STATIC_CAPS ("video/x-raw, "
53 "framerate = (fraction) [ 0, MAX ], "
54 "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
57 static gboolean
gst_vlc_video_sink_setcaps( GstBaseSink
*p_bsink
,
59 static gboolean
gst_vlc_video_sink_propose_allocation( GstBaseSink
*p_bsink
,
61 static GstFlowReturn
gst_vlc_video_sink_chain( GstBaseSink
*p_vsink
,
62 GstBuffer
*p_buffer
);
64 static void gst_vlc_video_sink_set_property( GObject
*p_object
, guint prop_id
,
65 const GValue
*p_value
, GParamSpec
*p_pspec
);
66 static void gst_vlc_video_sink_get_property( GObject
*p_object
, guint prop_id
,
67 GValue
*p_value
, GParamSpec
*p_pspec
);
68 static void gst_vlc_video_sink_finalize( GObject
*p_obj
);
70 #define gst_vlc_video_sink_parent_class parent_class
71 G_DEFINE_TYPE( GstVlcVideoSink
, gst_vlc_video_sink
, GST_TYPE_BASE_SINK
);
73 static void gst_vlc_video_sink_class_init( GstVlcVideoSinkClass
*p_klass
)
75 GObjectClass
*p_gobject_class
;
76 GstElementClass
*p_gstelement_class
;
77 GstBaseSinkClass
*p_gstbasesink_class
;
79 p_gobject_class
= (GObjectClass
*) p_klass
;
80 p_gstelement_class
= (GstElementClass
*) p_klass
;
81 p_gstbasesink_class
= (GstBaseSinkClass
*) p_klass
;
83 p_gobject_class
->set_property
= gst_vlc_video_sink_set_property
;
84 p_gobject_class
->get_property
= gst_vlc_video_sink_get_property
;
85 p_gobject_class
->finalize
= gst_vlc_video_sink_finalize
;
87 g_object_class_install_property( G_OBJECT_CLASS( p_klass
), PROP_ALLOCATOR
,
88 g_param_spec_pointer( "allocator", "Allocator", "VlcPictureAllocator",
89 G_PARAM_READWRITE
| GST_PARAM_MUTABLE_READY
|
90 G_PARAM_STATIC_STRINGS
));
92 g_object_class_install_property( G_OBJECT_CLASS( p_klass
), PROP_ID
,
93 g_param_spec_pointer( "id", "Id", "ID",
94 G_PARAM_WRITABLE
| GST_PARAM_MUTABLE_READY
|
95 G_PARAM_STATIC_STRINGS
));
97 //FIXME caps_signal: GObject signal didn't seem to work when return
98 //value is expected, so went with the native callback mechanism here.
100 gst_vlc_video_sink_signals
[ SIGNAL_NEW_CAPS
] =
101 g_signal_new( "new-caps", G_TYPE_FROM_CLASS( p_klass
),
102 G_SIGNAL_RUN_LAST
, G_STRUCT_OFFSET( GstVlcVideoSinkClass
,
103 new_caps
), g_signal_accumulator_true_handled
,
104 NULL
, g_cclosure_marshal_generic
,
105 G_TYPE_BOOLEAN
, 1, GST_TYPE_CAPS
);
107 gst_vlc_video_sink_signals
[ SIGNAL_NEW_BUFFER
] =
108 g_signal_new( "new-buffer", G_TYPE_FROM_CLASS( p_klass
),
109 G_SIGNAL_RUN_LAST
, G_STRUCT_OFFSET( GstVlcVideoSinkClass
,
110 new_buffer
), NULL
, NULL
, g_cclosure_marshal_generic
,
111 G_TYPE_NONE
, 1, GST_TYPE_BUFFER
);
113 gst_element_class_add_pad_template( p_gstelement_class
,
114 gst_static_pad_template_get( &sink_template
));
116 gst_element_class_set_static_metadata( p_gstelement_class
,
117 "VLC Video Sink", "Sink/Video",
118 "Video Sink for VLC video decoders",
119 "Vikram Fugro <vikram.fugro@gmail.com>" );
121 p_gstbasesink_class
->set_caps
= gst_vlc_video_sink_setcaps
;
122 p_gstbasesink_class
->propose_allocation
=
123 gst_vlc_video_sink_propose_allocation
;
125 p_gstbasesink_class
->render
= gst_vlc_video_sink_chain
;
128 static gboolean
gst_vlc_video_sink_setcaps( GstBaseSink
*p_basesink
,
131 GstVlcVideoSink
*p_vsink
= GST_VLC_VIDEO_SINK( p_basesink
);
133 gboolean b_ret
= FALSE
;
138 GValue args
[2] = { {0}, {0} };
141 if( !gst_video_info_from_caps( &info
, p_caps
))
144 p_vsink
->vinfo
= info
;
148 g_value_init( &args
[0], GST_TYPE_ELEMENT
);
149 g_value_set_object( &args
[0], p_vsink
);
150 g_value_init( &args
[1], GST_TYPE_CAPS
);
151 g_value_set_boxed( &args
[1], p_caps
);
153 g_signal_emitv( args
, gst_vlc_video_sink_signals
[ SIGNAL_NEW_CAPS
],
156 b_ret
= p_vsink
->new_caps( GST_ELEMENT_CAST( p_vsink
), p_caps
,
157 (gpointer
) p_vsink
->p_dec
);
163 static void gst_vlc_video_sink_init( GstVlcVideoSink
*p_vlc_video_sink
)
165 gst_base_sink_set_sync( GST_BASE_SINK( p_vlc_video_sink
), FALSE
);
168 static void gst_vlc_video_sink_finalize( GObject
*p_obj
)
170 GstVlcVideoSink
*p_vsink
= GST_VLC_VIDEO_SINK( p_obj
);
172 if( p_vsink
->p_allocator
)
173 gst_object_unref( p_vsink
->p_allocator
);
175 G_OBJECT_CLASS( parent_class
)->finalize( p_obj
);
178 static GstVlcVideoPool
* gst_vlc_video_sink_create_pool(
179 GstVlcVideoSink
*p_vsink
, GstCaps
*p_caps
, gsize i_size
, gint i_min
)
181 GstVlcVideoPool
*p_pool
;
182 GstStructure
*p_config
;
184 p_pool
= gst_vlc_video_pool_new( p_vsink
->p_allocator
, p_vsink
->p_dec
);
186 p_config
= gst_buffer_pool_get_config( GST_BUFFER_POOL_CAST( p_pool
));
187 gst_buffer_pool_config_set_params( p_config
, p_caps
, i_size
, i_min
, 0);
189 if( !gst_buffer_pool_set_config( GST_BUFFER_POOL_CAST( p_pool
), p_config
))
196 gst_object_unref (p_pool
);
201 static gboolean
gst_vlc_video_sink_propose_allocation( GstBaseSink
* p_bsink
,
204 GstVlcVideoSink
*p_vsink
= GST_VLC_VIDEO_SINK( p_bsink
);
206 gboolean b_need_pool
;
207 GstBufferPool
* p_pool
= NULL
;
210 gst_query_parse_allocation (p_query
, &p_caps
, &b_need_pool
);
218 if( !gst_video_info_from_caps( &info
, p_caps
))
221 p_pool
= (GstBufferPool
*) gst_vlc_video_sink_create_pool( p_vsink
,
222 p_caps
, info
.size
, 2 );
226 i_size
= GST_VIDEO_INFO_SIZE( &GST_VLC_VIDEO_POOL_CAST( p_pool
)->info
);
231 /* we need at least 2 buffer because we hold on to the last one */
232 gst_query_add_allocation_pool( p_query
, p_pool
, i_size
, 2, 0);
233 gst_object_unref (p_pool
);
236 /* we support various metadata */
237 gst_query_add_allocation_meta( p_query
, GST_VIDEO_META_API_TYPE
, NULL
);
244 msg_Err( p_vsink
->p_dec
, "failed to create the pool" );
249 msg_Err( p_vsink
->p_dec
, "no caps in allocation query" );
254 msg_Err( p_vsink
->p_dec
, "invalid caps in allocation query" );
259 static GstFlowReturn
gst_vlc_video_sink_chain( GstBaseSink
*p_bsink
,
260 GstBuffer
*p_buffer
)
262 g_signal_emit( p_bsink
,
263 gst_vlc_video_sink_signals
[ SIGNAL_NEW_BUFFER
], 0, p_buffer
);
268 static void gst_vlc_video_sink_set_property( GObject
*p_object
, guint i_prop_id
,
269 const GValue
*p_value
, GParamSpec
*p_pspec
)
271 VLC_UNUSED( p_pspec
);
273 GstVlcVideoSink
*p_vsink
= GST_VLC_VIDEO_SINK( p_object
);
279 GstAllocator
*p_allocator
= (GstAllocator
*) g_value_get_pointer(
281 if( GST_IS_VLC_PICTURE_PLANE_ALLOCATOR( p_allocator
))
283 if( p_vsink
->p_allocator
)
284 gst_object_unref( p_vsink
->p_allocator
);
285 p_vsink
->p_allocator
= gst_object_ref( p_allocator
);
287 msg_Err( p_vsink
->p_dec
, "Invalid Allocator set");
293 p_vsink
->p_dec
= (decoder_t
*) g_value_get_pointer( p_value
);
302 static void gst_vlc_video_sink_get_property( GObject
*p_object
, guint i_prop_id
,
303 GValue
*p_value
, GParamSpec
*p_pspec
)
305 VLC_UNUSED( p_pspec
);
307 GstVlcVideoSink
*p_vsink
= GST_VLC_VIDEO_SINK( p_object
);
312 g_value_set_pointer( p_value
, p_vsink
->p_allocator
);