Add sami extension for auto-loading of subs
[vlc.git] / modules / codec / gstreamer / gstvlcvideosink.c
blob6988e0d0a179ae99e290f3b486a3d81d3153ca46
1 /*****************************************************************************
2 * gstvlcvideosink.c: VLC gstreamer video sink
3 *****************************************************************************
4 * Copyright (C) 2016 VLC authors and VideoLAN
5 * $Id:
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 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
27 #include "gstvlcvideopool.h"
28 #include "gstvlcvideosink.h"
30 #include <vlc_common.h>
32 enum
34 SIGNAL_NEW_CAPS,
35 SIGNAL_NEW_BUFFER,
36 LAST_SIGNAL
39 enum
41 PROP_0,
42 PROP_ALLOCATOR,
43 PROP_ID
46 static guint gst_vlc_video_sink_signals[ LAST_SIGNAL ] = { 0 };
48 static GstStaticPadTemplate sink_template =
49 GST_STATIC_PAD_TEMPLATE ("sink",
50 GST_PAD_SINK,
51 GST_PAD_ALWAYS,
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,
58 GstCaps *p_caps );
59 static gboolean gst_vlc_video_sink_propose_allocation( GstBaseSink *p_bsink,
60 GstQuery *p_query);
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.
99 #if 0
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 );
106 #endif
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,
129 GstCaps *p_caps )
131 GstVlcVideoSink *p_vsink = GST_VLC_VIDEO_SINK( p_basesink );
132 GstVideoInfo info;
133 gboolean b_ret = FALSE;
135 //FIXME caps_signal
136 #if 0
137 GValue ret = { 0 };
138 GValue args[2] = { {0}, {0} };
139 #endif
141 if( !gst_video_info_from_caps( &info, p_caps ))
142 return FALSE;
144 p_vsink->vinfo = info;
146 //FIXME caps_signal
147 #if 0
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 ],
154 0, &b_ret );
155 #else
156 b_ret = p_vsink->new_caps( GST_ELEMENT_CAST( p_vsink ), p_caps,
157 (gpointer) p_vsink->p_dec );
158 #endif
160 return b_ret;
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 ))
190 goto config_failed;
192 return p_pool;
194 config_failed:
196 gst_object_unref (p_pool);
197 return NULL;
201 static gboolean gst_vlc_video_sink_propose_allocation( GstBaseSink* p_bsink,
202 GstQuery* p_query )
204 GstVlcVideoSink *p_vsink = GST_VLC_VIDEO_SINK( p_bsink );
205 GstCaps *p_caps;
206 gboolean b_need_pool;
207 GstBufferPool* p_pool = NULL;
208 gsize i_size;
210 gst_query_parse_allocation (p_query, &p_caps, &b_need_pool);
211 if( p_caps == NULL )
212 goto no_caps;
214 if( b_need_pool )
216 GstVideoInfo info;
218 if( !gst_video_info_from_caps( &info, p_caps ))
219 goto invalid_caps;
221 p_pool = (GstBufferPool*) gst_vlc_video_sink_create_pool( p_vsink,
222 p_caps, info.size, 2 );
223 if( p_pool == NULL )
224 goto no_pool;
226 i_size = GST_VIDEO_INFO_SIZE( &GST_VLC_VIDEO_POOL_CAST( p_pool )->info);
229 if( p_pool )
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 );
239 return TRUE;
241 /* ERRORS */
242 no_pool:
244 msg_Err( p_vsink->p_dec, "failed to create the pool" );
245 return FALSE;
247 no_caps:
249 msg_Err( p_vsink->p_dec, "no caps in allocation query" );
250 return FALSE;
252 invalid_caps:
254 msg_Err( p_vsink->p_dec, "invalid caps in allocation query" );
255 return FALSE;
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 );
265 return GST_FLOW_OK;
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 );
275 switch( i_prop_id )
277 case PROP_ALLOCATOR:
279 GstAllocator *p_allocator = (GstAllocator*) g_value_get_pointer(
280 p_value );
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 );
286 } else
287 msg_Err( p_vsink->p_dec, "Invalid Allocator set");
289 break;
291 case PROP_ID:
293 p_vsink->p_dec = (decoder_t*) g_value_get_pointer( p_value );
295 break;
297 default:
298 break;
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 );
309 switch( i_prop_id )
311 case PROP_ALLOCATOR:
312 g_value_set_pointer( p_value, p_vsink->p_allocator );
313 break;
315 default:
316 break;