1 /* GStreamer
2 * Copyright (C) 2007 David Schleef <ds@schleef.org>
3 * (C) 2008 Wim Taymans <wim.taymans@gmail.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20 /**
21 * SECTION:gstappsink
22 * @title: GstAppSink
23 * @short_description: Easy way for applications to extract samples from a
24 * pipeline
25 * @see_also: #GstSample, #GstBaseSink, appsrc
26 *
27 * Appsink is a sink plugin that supports many different methods for making
28 * the application get a handle on the GStreamer data in a pipeline. Unlike
29 * most GStreamer elements, Appsink provides external API functions.
30 *
31 * appsink can be used by linking to the gstappsink.h header file to access the
32 * methods or by using the appsink action signals and properties.
33 *
34 * The normal way of retrieving samples from appsink is by using the
35 * gst_app_sink_pull_sample() and gst_app_sink_pull_preroll() methods.
36 * These methods block until a sample becomes available in the sink or when the
37 * sink is shut down or reaches EOS. There are also timed variants of these
38 * methods, gst_app_sink_try_pull_sample() and gst_app_sink_try_pull_preroll(),
39 * which accept a timeout parameter to limit the amount of time to wait.
40 *
41 * Appsink will internally use a queue to collect buffers from the streaming
42 * thread. If the application is not pulling samples fast enough, this queue
43 * will consume a lot of memory over time. The "max-buffers" property can be
44 * used to limit the queue size. The "drop" property controls whether the
45 * streaming thread blocks or if older buffers are dropped when the maximum
46 * queue size is reached. Note that blocking the streaming thread can negatively
47 * affect real-time performance and should be avoided.
48 *
49 * If a blocking behaviour is not desirable, setting the "emit-signals" property
50 * to %TRUE will make appsink emit the "new-sample" and "new-preroll" signals
51 * when a sample can be pulled without blocking.
52 *
53 * The "caps" property on appsink can be used to control the formats that
54 * appsink can receive. This property can contain non-fixed caps, the format of
55 * the pulled samples can be obtained by getting the sample caps.
56 *
57 * If one of the pull-preroll or pull-sample methods return %NULL, the appsink
58 * is stopped or in the EOS state. You can check for the EOS state with the
59 * "eos" property or with the gst_app_sink_is_eos() method.
60 *
61 * The eos signal can also be used to be informed when the EOS state is reached
62 * to avoid polling.
63 */
64
65 #ifdef HAVE_CONFIG_H
66 #include "config.h"
67 #endif
68
69 #include <gst/gst.h>
70 #include <gst/base/base.h>
71
72 #include <string.h>
73
74 #include "gstappsink.h"
75
76 typedef enum
77 {
78 NOONE_WAITING = 0,
79 STREAM_WAITING = 1 << 0, /* streaming thread is waiting for application thread */
80 APP_WAITING = 1 << 1, /* application thread is waiting for streaming thread */
81 } GstAppSinkWaitStatus;
82
83 struct _GstAppSinkPrivate
84 {
85 GstCaps *caps;
86 gboolean emit_signals;
87 guint num_buffers;
88 guint max_buffers;
89 gboolean drop;
90 gboolean wait_on_eos;
91 GstAppSinkWaitStatus wait_status;
92
93 GCond cond;
94 GMutex mutex;
95 GstQueueArray *queue;
96 GstBuffer *preroll_buffer;
97 GstCaps *preroll_caps;
98 GstCaps *last_caps;
99 GstSegment preroll_segment;
100 GstSegment last_segment;
101 gboolean flushing;
102 gboolean unlock;
103 gboolean started;
104 gboolean is_eos;
105 gboolean buffer_lists_supported;
106
107 GstAppSinkCallbacks callbacks;
108 gpointer user_data;
109 GDestroyNotify notify;
110
111 GstSample *sample;
112 };
113
114 GST_DEBUG_CATEGORY_STATIC (app_sink_debug);
115 #define GST_CAT_DEFAULT app_sink_debug
116
117 enum
118 {
119 /* signals */
120 SIGNAL_EOS,
121 SIGNAL_NEW_PREROLL,
122 SIGNAL_NEW_SAMPLE,
123
124 /* actions */
125 SIGNAL_PULL_PREROLL,
126 SIGNAL_PULL_SAMPLE,
127 SIGNAL_TRY_PULL_PREROLL,
128 SIGNAL_TRY_PULL_SAMPLE,
129
130 LAST_SIGNAL
131 };
132
133 #define DEFAULT_PROP_EOS TRUE
134 #define DEFAULT_PROP_EMIT_SIGNALS FALSE
135 #define DEFAULT_PROP_MAX_BUFFERS 0
136 #define DEFAULT_PROP_DROP FALSE
137 #define DEFAULT_PROP_WAIT_ON_EOS TRUE
138 #define DEFAULT_PROP_BUFFER_LIST FALSE
139
140 enum
141 {
142 PROP_0,
143 PROP_CAPS,
144 PROP_EOS,
145 PROP_EMIT_SIGNALS,
146 PROP_MAX_BUFFERS,
147 PROP_DROP,
148 PROP_WAIT_ON_EOS,
149 PROP_BUFFER_LIST,
150 PROP_LAST
151 };
152
153 static GstStaticPadTemplate gst_app_sink_template =
154 GST_STATIC_PAD_TEMPLATE ("sink",
155 GST_PAD_SINK,
156 GST_PAD_ALWAYS,
157 GST_STATIC_CAPS_ANY);
158
159 static void gst_app_sink_uri_handler_init (gpointer g_iface,
160 gpointer iface_data);
161
162 static void gst_app_sink_dispose (GObject * object);
163 static void gst_app_sink_finalize (GObject * object);
164
165 static void gst_app_sink_set_property (GObject * object, guint prop_id,
166 const GValue * value, GParamSpec * pspec);
167 static void gst_app_sink_get_property (GObject * object, guint prop_id,
168 GValue * value, GParamSpec * pspec);
169
170 static gboolean gst_app_sink_unlock_start (GstBaseSink * bsink);
171 static gboolean gst_app_sink_unlock_stop (GstBaseSink * bsink);
172 static gboolean gst_app_sink_start (GstBaseSink * psink);
173 static gboolean gst_app_sink_stop (GstBaseSink * psink);
174 static gboolean gst_app_sink_event (GstBaseSink * sink, GstEvent * event);
175 static gboolean gst_app_sink_query (GstBaseSink * bsink, GstQuery * query);
176 static GstFlowReturn gst_app_sink_preroll (GstBaseSink * psink,
177 GstBuffer * buffer);
178 static GstFlowReturn gst_app_sink_render_common (GstBaseSink * psink,
179 GstMiniObject * data, gboolean is_list);
180 static GstFlowReturn gst_app_sink_render (GstBaseSink * psink,
181 GstBuffer * buffer);
182 static GstFlowReturn gst_app_sink_render_list (GstBaseSink * psink,
183 GstBufferList * list);
184 static gboolean gst_app_sink_setcaps (GstBaseSink * sink, GstCaps * caps);
185 static GstCaps *gst_app_sink_getcaps (GstBaseSink * psink, GstCaps * filter);
186
187 static guint gst_app_sink_signals[LAST_SIGNAL] = { 0 };
188
189 #define gst_app_sink_parent_class parent_class
190 G_DEFINE_TYPE_WITH_CODE (GstAppSink, gst_app_sink, GST_TYPE_BASE_SINK,
191 G_ADD_PRIVATE (GstAppSink)
192 G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER,
193 gst_app_sink_uri_handler_init));
194
195 static void
gst_app_sink_class_init(GstAppSinkClass * klass)196 gst_app_sink_class_init (GstAppSinkClass * klass)
197 {
198 GObjectClass *gobject_class = (GObjectClass *) klass;
199 GstElementClass *element_class = (GstElementClass *) klass;
200 GstBaseSinkClass *basesink_class = (GstBaseSinkClass *) klass;
201
202 GST_DEBUG_CATEGORY_INIT (app_sink_debug, "appsink", 0, "appsink element");
203
204 gobject_class->dispose = gst_app_sink_dispose;
205 gobject_class->finalize = gst_app_sink_finalize;
206
207 gobject_class->set_property = gst_app_sink_set_property;
208 gobject_class->get_property = gst_app_sink_get_property;
209
210 g_object_class_install_property (gobject_class, PROP_CAPS,
211 g_param_spec_boxed ("caps", "Caps",
212 "The allowed caps for the sink pad", GST_TYPE_CAPS,
213 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
214
215 g_object_class_install_property (gobject_class, PROP_EOS,
216 g_param_spec_boolean ("eos", "EOS",
217 "Check if the sink is EOS or not started", DEFAULT_PROP_EOS,
218 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
219
220 g_object_class_install_property (gobject_class, PROP_EMIT_SIGNALS,
221 g_param_spec_boolean ("emit-signals", "Emit signals",
222 "Emit new-preroll and new-sample signals",
223 DEFAULT_PROP_EMIT_SIGNALS,
224 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
225
226 g_object_class_install_property (gobject_class, PROP_MAX_BUFFERS,
227 g_param_spec_uint ("max-buffers", "Max Buffers",
228 "The maximum number of buffers to queue internally (0 = unlimited)",
229 0, G_MAXUINT, DEFAULT_PROP_MAX_BUFFERS,
230 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
231
232 g_object_class_install_property (gobject_class, PROP_DROP,
233 g_param_spec_boolean ("drop", "Drop",
234 "Drop old buffers when the buffer queue is filled", DEFAULT_PROP_DROP,
235 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
236
237 g_object_class_install_property (gobject_class, PROP_BUFFER_LIST,
238 g_param_spec_boolean ("buffer-list", "Buffer List",
239 "Use buffer lists", DEFAULT_PROP_BUFFER_LIST,
240 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
241 /**
242 * GstAppSink::wait-on-eos:
243 *
244 * Wait for all buffers to be processed after receiving an EOS.
245 *
246 * In cases where it is uncertain if an @appsink will have a consumer for its buffers
247 * when it receives an EOS, set to %FALSE to ensure that the @appsink will not hang.
248 *
249 * Since: 1.8
250 */
251 g_object_class_install_property (gobject_class, PROP_WAIT_ON_EOS,
252 g_param_spec_boolean ("wait-on-eos", "Wait on EOS",
253 "Wait for all buffers to be processed after receiving an EOS",
254 DEFAULT_PROP_WAIT_ON_EOS,
255 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
256
257 /**
258 * GstAppSink::eos:
259 * @appsink: the appsink element that emitted the signal
260 *
261 * Signal that the end-of-stream has been reached. This signal is emitted from
262 * the streaming thread.
263 */
264 gst_app_sink_signals[SIGNAL_EOS] =
265 g_signal_new ("eos", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
266 G_STRUCT_OFFSET (GstAppSinkClass, eos),
267 NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
268 /**
269 * GstAppSink::new-preroll:
270 * @appsink: the appsink element that emitted the signal
271 *
272 * Signal that a new preroll sample is available.
273 *
274 * This signal is emitted from the streaming thread and only when the
275 * "emit-signals" property is %TRUE.
276 *
277 * The new preroll sample can be retrieved with the "pull-preroll" action
278 * signal or gst_app_sink_pull_preroll() either from this signal callback
279 * or from any other thread.
280 *
281 * Note that this signal is only emitted when the "emit-signals" property is
282 * set to %TRUE, which it is not by default for performance reasons.
283 */
284 gst_app_sink_signals[SIGNAL_NEW_PREROLL] =
285 g_signal_new ("new-preroll", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
286 G_STRUCT_OFFSET (GstAppSinkClass, new_preroll),
287 NULL, NULL, NULL, GST_TYPE_FLOW_RETURN, 0, G_TYPE_NONE);
288 /**
289 * GstAppSink::new-sample:
290 * @appsink: the appsink element that emitted the signal
291 *
292 * Signal that a new sample is available.
293 *
294 * This signal is emitted from the streaming thread and only when the
295 * "emit-signals" property is %TRUE.
296 *
297 * The new sample can be retrieved with the "pull-sample" action
298 * signal or gst_app_sink_pull_sample() either from this signal callback
299 * or from any other thread.
300 *
301 * Note that this signal is only emitted when the "emit-signals" property is
302 * set to %TRUE, which it is not by default for performance reasons.
303 */
304 gst_app_sink_signals[SIGNAL_NEW_SAMPLE] =
305 g_signal_new ("new-sample", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
306 G_STRUCT_OFFSET (GstAppSinkClass, new_sample),
307 NULL, NULL, NULL, GST_TYPE_FLOW_RETURN, 0, G_TYPE_NONE);
308
309 /**
310 * GstAppSink::pull-preroll:
311 * @appsink: the appsink element to emit this signal on
312 *
313 * Get the last preroll sample in @appsink. This was the sample that caused the
314 * appsink to preroll in the PAUSED state.
315 *
316 * This function is typically used when dealing with a pipeline in the PAUSED
317 * state. Calling this function after doing a seek will give the sample right
318 * after the seek position.
319 *
320 * Calling this function will clear the internal reference to the preroll
321 * buffer.
322 *
323 * Note that the preroll sample will also be returned as the first sample
324 * when calling gst_app_sink_pull_sample() or the "pull-sample" action signal.
325 *
326 * If an EOS event was received before any buffers, this function returns
327 * %NULL. Use gst_app_sink_is_eos () to check for the EOS condition.
328 *
329 * This function blocks until a preroll sample or EOS is received or the appsink
330 * element is set to the READY/NULL state.
331 *
332 * Returns: a #GstSample or NULL when the appsink is stopped or EOS.
333 */
334 gst_app_sink_signals[SIGNAL_PULL_PREROLL] =
335 g_signal_new ("pull-preroll", G_TYPE_FROM_CLASS (klass),
336 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstAppSinkClass,
337 pull_preroll), NULL, NULL, NULL, GST_TYPE_SAMPLE, 0, G_TYPE_NONE);
338 /**
339 * GstAppSink::pull-sample:
340 * @appsink: the appsink element to emit this signal on
341 *
342 * This function blocks until a sample or EOS becomes available or the appsink
343 * element is set to the READY/NULL state.
344 *
345 * This function will only return samples when the appsink is in the PLAYING
346 * state. All rendered samples will be put in a queue so that the application
347 * can pull samples at its own rate.
348 *
349 * Note that when the application does not pull samples fast enough, the
350 * queued samples could consume a lot of memory, especially when dealing with
351 * raw video frames. It's possible to control the behaviour of the queue with
352 * the "drop" and "max-buffers" properties.
353 *
354 * If an EOS event was received before any buffers, this function returns
355 * %NULL. Use gst_app_sink_is_eos () to check for the EOS condition.
356 *
357 * Returns: a #GstSample or NULL when the appsink is stopped or EOS.
358 */
359 gst_app_sink_signals[SIGNAL_PULL_SAMPLE] =
360 g_signal_new ("pull-sample", G_TYPE_FROM_CLASS (klass),
361 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstAppSinkClass,
362 pull_sample), NULL, NULL, NULL, GST_TYPE_SAMPLE, 0, G_TYPE_NONE);
363 /**
364 * GstAppSink::try-pull-preroll:
365 * @appsink: the appsink element to emit this signal on
366 * @timeout: the maximum amount of time to wait for the preroll sample
367 *
368 * Get the last preroll sample in @appsink. This was the sample that caused the
369 * appsink to preroll in the PAUSED state.
370 *
371 * This function is typically used when dealing with a pipeline in the PAUSED
372 * state. Calling this function after doing a seek will give the sample right
373 * after the seek position.
374 *
375 * Calling this function will clear the internal reference to the preroll
376 * buffer.
377 *
378 * Note that the preroll sample will also be returned as the first sample
379 * when calling gst_app_sink_pull_sample() or the "pull-sample" action signal.
380 *
381 * If an EOS event was received before any buffers or the timeout expires,
382 * this function returns %NULL. Use gst_app_sink_is_eos () to check for the EOS
383 * condition.
384 *
385 * This function blocks until a preroll sample or EOS is received, the appsink
386 * element is set to the READY/NULL state, or the timeout expires.
387 *
388 * Returns: a #GstSample or NULL when the appsink is stopped or EOS or the timeout expires.
389 *
390 * Since: 1.10
391 */
392 gst_app_sink_signals[SIGNAL_TRY_PULL_PREROLL] =
393 g_signal_new ("try-pull-preroll", G_TYPE_FROM_CLASS (klass),
394 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
395 G_STRUCT_OFFSET (GstAppSinkClass, try_pull_preroll), NULL, NULL, NULL,
396 GST_TYPE_SAMPLE, 1, GST_TYPE_CLOCK_TIME);
397 /**
398 * GstAppSink::try-pull-sample:
399 * @appsink: the appsink element to emit this signal on
400 * @timeout: the maximum amount of time to wait for a sample
401 *
402 * This function blocks until a sample or EOS becomes available or the appsink
403 * element is set to the READY/NULL state or the timeout expires.
404 *
405 * This function will only return samples when the appsink is in the PLAYING
406 * state. All rendered samples will be put in a queue so that the application
407 * can pull samples at its own rate.
408 *
409 * Note that when the application does not pull samples fast enough, the
410 * queued samples could consume a lot of memory, especially when dealing with
411 * raw video frames. It's possible to control the behaviour of the queue with
412 * the "drop" and "max-buffers" properties.
413 *
414 * If an EOS event was received before any buffers or the timeout expires,
415 * this function returns %NULL. Use gst_app_sink_is_eos () to check
416 * for the EOS condition.
417 *
418 * Returns: a #GstSample or NULL when the appsink is stopped or EOS or the timeout expires.
419 *
420 * Since: 1.10
421 */
422 gst_app_sink_signals[SIGNAL_TRY_PULL_SAMPLE] =
423 g_signal_new ("try-pull-sample", G_TYPE_FROM_CLASS (klass),
424 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
425 G_STRUCT_OFFSET (GstAppSinkClass, try_pull_sample), NULL, NULL, NULL,
426 GST_TYPE_SAMPLE, 1, GST_TYPE_CLOCK_TIME);
427
428 gst_element_class_set_static_metadata (element_class, "AppSink",
429 "Generic/Sink", "Allow the application to get access to raw buffer",
430 "David Schleef <ds@schleef.org>, Wim Taymans <wim.taymans@gmail.com>");
431
432 gst_element_class_add_static_pad_template (element_class,
433 &gst_app_sink_template);
434
435 basesink_class->unlock = gst_app_sink_unlock_start;
436 basesink_class->unlock_stop = gst_app_sink_unlock_stop;
437 basesink_class->start = gst_app_sink_start;
438 basesink_class->stop = gst_app_sink_stop;
439 basesink_class->event = gst_app_sink_event;
440 basesink_class->preroll = gst_app_sink_preroll;
441 basesink_class->render = gst_app_sink_render;
442 basesink_class->render_list = gst_app_sink_render_list;
443 basesink_class->get_caps = gst_app_sink_getcaps;
444 basesink_class->set_caps = gst_app_sink_setcaps;
445 basesink_class->query = gst_app_sink_query;
446
447 klass->pull_preroll = gst_app_sink_pull_preroll;
448 klass->pull_sample = gst_app_sink_pull_sample;
449 klass->try_pull_preroll = gst_app_sink_try_pull_preroll;
450 klass->try_pull_sample = gst_app_sink_try_pull_sample;
451 }
452
453 static void
gst_app_sink_init(GstAppSink * appsink)454 gst_app_sink_init (GstAppSink * appsink)
455 {
456 GstAppSinkPrivate *priv;
457
458 priv = appsink->priv = gst_app_sink_get_instance_private (appsink);
459
460 g_mutex_init (&priv->mutex);
461 g_cond_init (&priv->cond);
462 priv->queue = gst_queue_array_new (16);
463 priv->sample = gst_sample_new (NULL, NULL, NULL, NULL);
464
465 priv->emit_signals = DEFAULT_PROP_EMIT_SIGNALS;
466 priv->max_buffers = DEFAULT_PROP_MAX_BUFFERS;
467 priv->drop = DEFAULT_PROP_DROP;
468 priv->wait_on_eos = DEFAULT_PROP_WAIT_ON_EOS;
469 priv->buffer_lists_supported = DEFAULT_PROP_BUFFER_LIST;
470 priv->wait_status = NOONE_WAITING;
471 }
472
473 static void
gst_app_sink_dispose(GObject * obj)474 gst_app_sink_dispose (GObject * obj)
475 {
476 GstAppSink *appsink = GST_APP_SINK_CAST (obj);
477 GstAppSinkPrivate *priv = appsink->priv;
478 GstMiniObject *queue_obj;
479
480 GST_OBJECT_LOCK (appsink);
481 if (priv->caps) {
482 gst_caps_unref (priv->caps);
483 priv->caps = NULL;
484 }
485 if (priv->notify) {
486 priv->notify (priv->user_data);
487 }
488 priv->user_data = NULL;
489 priv->notify = NULL;
490
491 GST_OBJECT_UNLOCK (appsink);
492
493 g_mutex_lock (&priv->mutex);
494 while ((queue_obj = gst_queue_array_pop_head (priv->queue)))
495 gst_mini_object_unref (queue_obj);
496 gst_buffer_replace (&priv->preroll_buffer, NULL);
497 gst_caps_replace (&priv->preroll_caps, NULL);
498 gst_caps_replace (&priv->last_caps, NULL);
499 if (priv->sample) {
500 gst_sample_unref (priv->sample);
501 priv->sample = NULL;
502 }
503 g_mutex_unlock (&priv->mutex);
504
505 G_OBJECT_CLASS (parent_class)->dispose (obj);
506 }
507
508 static void
gst_app_sink_finalize(GObject * obj)509 gst_app_sink_finalize (GObject * obj)
510 {
511 GstAppSink *appsink = GST_APP_SINK_CAST (obj);
512 GstAppSinkPrivate *priv = appsink->priv;
513
514 g_mutex_clear (&priv->mutex);
515 g_cond_clear (&priv->cond);
516 gst_queue_array_free (priv->queue);
517
518 G_OBJECT_CLASS (parent_class)->finalize (obj);
519 }
520
521 static void
gst_app_sink_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)522 gst_app_sink_set_property (GObject * object, guint prop_id,
523 const GValue * value, GParamSpec * pspec)
524 {
525 GstAppSink *appsink = GST_APP_SINK_CAST (object);
526
527 switch (prop_id) {
528 case PROP_CAPS:
529 gst_app_sink_set_caps (appsink, gst_value_get_caps (value));
530 break;
531 case PROP_EMIT_SIGNALS:
532 gst_app_sink_set_emit_signals (appsink, g_value_get_boolean (value));
533 break;
534 case PROP_MAX_BUFFERS:
535 gst_app_sink_set_max_buffers (appsink, g_value_get_uint (value));
536 break;
537 case PROP_DROP:
538 gst_app_sink_set_drop (appsink, g_value_get_boolean (value));
539 break;
540 case PROP_BUFFER_LIST:
541 gst_app_sink_set_buffer_list_support (appsink,
542 g_value_get_boolean (value));
543 break;
544 case PROP_WAIT_ON_EOS:
545 gst_app_sink_set_wait_on_eos (appsink, g_value_get_boolean (value));
546 break;
547 default:
548 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
549 break;
550 }
551 }
552
553 static void
gst_app_sink_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)554 gst_app_sink_get_property (GObject * object, guint prop_id, GValue * value,
555 GParamSpec * pspec)
556 {
557 GstAppSink *appsink = GST_APP_SINK_CAST (object);
558
559 switch (prop_id) {
560 case PROP_CAPS:
561 {
562 GstCaps *caps;
563
564 caps = gst_app_sink_get_caps (appsink);
565 gst_value_set_caps (value, caps);
566 if (caps)
567 gst_caps_unref (caps);
568 break;
569 }
570 case PROP_EOS:
571 g_value_set_boolean (value, gst_app_sink_is_eos (appsink));
572 break;
573 case PROP_EMIT_SIGNALS:
574 g_value_set_boolean (value, gst_app_sink_get_emit_signals (appsink));
575 break;
576 case PROP_MAX_BUFFERS:
577 g_value_set_uint (value, gst_app_sink_get_max_buffers (appsink));
578 break;
579 case PROP_DROP:
580 g_value_set_boolean (value, gst_app_sink_get_drop (appsink));
581 break;
582 case PROP_BUFFER_LIST:
583 g_value_set_boolean (value,
584 gst_app_sink_get_buffer_list_support (appsink));
585 break;
586 case PROP_WAIT_ON_EOS:
587 g_value_set_boolean (value, gst_app_sink_get_wait_on_eos (appsink));
588 break;
589 default:
590 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
591 break;
592 }
593 }
594
595 static gboolean
gst_app_sink_unlock_start(GstBaseSink * bsink)596 gst_app_sink_unlock_start (GstBaseSink * bsink)
597 {
598 GstAppSink *appsink = GST_APP_SINK_CAST (bsink);
599 GstAppSinkPrivate *priv = appsink->priv;
600
601 g_mutex_lock (&priv->mutex);
602 GST_DEBUG_OBJECT (appsink, "unlock start");
603 priv->unlock = TRUE;
604 g_cond_signal (&priv->cond);
605 g_mutex_unlock (&priv->mutex);
606
607 return TRUE;
608 }
609
610 static gboolean
gst_app_sink_unlock_stop(GstBaseSink * bsink)611 gst_app_sink_unlock_stop (GstBaseSink * bsink)
612 {
613 GstAppSink *appsink = GST_APP_SINK_CAST (bsink);
614 GstAppSinkPrivate *priv = appsink->priv;
615
616 g_mutex_lock (&priv->mutex);
617 GST_DEBUG_OBJECT (appsink, "unlock stop");
618 priv->unlock = FALSE;
619 g_cond_signal (&priv->cond);
620 g_mutex_unlock (&priv->mutex);
621
622 return TRUE;
623 }
624
625 static void
gst_app_sink_flush_unlocked(GstAppSink * appsink)626 gst_app_sink_flush_unlocked (GstAppSink * appsink)
627 {
628 GstMiniObject *obj;
629 GstAppSinkPrivate *priv = appsink->priv;
630
631 GST_DEBUG_OBJECT (appsink, "flush stop appsink");
632 priv->is_eos = FALSE;
633 gst_buffer_replace (&priv->preroll_buffer, NULL);
634 while ((obj = gst_queue_array_pop_head (priv->queue)))
635 gst_mini_object_unref (obj);
636 priv->num_buffers = 0;
637 g_cond_signal (&priv->cond);
638 }
639
640 static gboolean
gst_app_sink_start(GstBaseSink * psink)641 gst_app_sink_start (GstBaseSink * psink)
642 {
643 GstAppSink *appsink = GST_APP_SINK_CAST (psink);
644 GstAppSinkPrivate *priv = appsink->priv;
645
646 g_mutex_lock (&priv->mutex);
647 GST_DEBUG_OBJECT (appsink, "starting");
648 priv->wait_status = NOONE_WAITING;
649 priv->flushing = FALSE;
650 priv->started = TRUE;
651 gst_segment_init (&priv->preroll_segment, GST_FORMAT_TIME);
652 gst_segment_init (&priv->last_segment, GST_FORMAT_TIME);
653 priv->sample = gst_sample_make_writable (priv->sample);
654 gst_sample_set_buffer (priv->sample, NULL);
655 gst_sample_set_buffer_list (priv->sample, NULL);
656 gst_sample_set_caps (priv->sample, NULL);
657 gst_sample_set_segment (priv->sample, NULL);
658 g_mutex_unlock (&priv->mutex);
659
660 return TRUE;
661 }
662
663 static gboolean
gst_app_sink_stop(GstBaseSink * psink)664 gst_app_sink_stop (GstBaseSink * psink)
665 {
666 GstAppSink *appsink = GST_APP_SINK_CAST (psink);
667 GstAppSinkPrivate *priv = appsink->priv;
668
669 g_mutex_lock (&priv->mutex);
670 GST_DEBUG_OBJECT (appsink, "stopping");
671 priv->flushing = TRUE;
672 priv->started = FALSE;
673 priv->wait_status = NOONE_WAITING;
674 gst_app_sink_flush_unlocked (appsink);
675 gst_buffer_replace (&priv->preroll_buffer, NULL);
676 gst_caps_replace (&priv->preroll_caps, NULL);
677 gst_caps_replace (&priv->last_caps, NULL);
678 gst_segment_init (&priv->preroll_segment, GST_FORMAT_UNDEFINED);
679 gst_segment_init (&priv->last_segment, GST_FORMAT_UNDEFINED);
680 g_mutex_unlock (&priv->mutex);
681
682 return TRUE;
683 }
684
685 static gboolean
gst_app_sink_setcaps(GstBaseSink * sink,GstCaps * caps)686 gst_app_sink_setcaps (GstBaseSink * sink, GstCaps * caps)
687 {
688 GstAppSink *appsink = GST_APP_SINK_CAST (sink);
689 GstAppSinkPrivate *priv = appsink->priv;
690
691 g_mutex_lock (&priv->mutex);
692 GST_DEBUG_OBJECT (appsink, "receiving CAPS");
693 gst_queue_array_push_tail (priv->queue, gst_event_new_caps (caps));
694 if (!priv->preroll_buffer)
695 gst_caps_replace (&priv->preroll_caps, caps);
696 g_mutex_unlock (&priv->mutex);
697
698 return TRUE;
699 }
700
701 static gboolean
gst_app_sink_event(GstBaseSink * sink,GstEvent * event)702 gst_app_sink_event (GstBaseSink * sink, GstEvent * event)
703 {
704 GstAppSink *appsink = GST_APP_SINK_CAST (sink);
705 GstAppSinkPrivate *priv = appsink->priv;
706
707 switch (event->type) {
708 case GST_EVENT_SEGMENT:
709 g_mutex_lock (&priv->mutex);
710 GST_DEBUG_OBJECT (appsink, "receiving SEGMENT");
711 gst_queue_array_push_tail (priv->queue, gst_event_ref (event));
712 if (!priv->preroll_buffer)
713 gst_event_copy_segment (event, &priv->preroll_segment);
714 g_mutex_unlock (&priv->mutex);
715 break;
716 case GST_EVENT_EOS:{
717 gboolean emit = TRUE;
718
719 g_mutex_lock (&priv->mutex);
720 GST_DEBUG_OBJECT (appsink, "receiving EOS");
721 priv->is_eos = TRUE;
722 g_cond_signal (&priv->cond);
723 g_mutex_unlock (&priv->mutex);
724
725 g_mutex_lock (&priv->mutex);
726 /* wait until all buffers are consumed or we're flushing.
727 * Otherwise we might signal EOS before all buffers are
728 * consumed, which is a bit confusing for the application
729 */
730 while (priv->num_buffers > 0 && !priv->flushing && priv->wait_on_eos) {
731 if (priv->unlock) {
732 /* we are asked to unlock, call the wait_preroll method */
733 g_mutex_unlock (&priv->mutex);
734 if (gst_base_sink_wait_preroll (sink) != GST_FLOW_OK) {
735 /* Directly go out of here */
736 gst_event_unref (event);
737 return FALSE;
738 }
739
740 /* we are allowed to continue now */
741 g_mutex_lock (&priv->mutex);
742 continue;
743 }
744
745 priv->wait_status |= STREAM_WAITING;
746 g_cond_wait (&priv->cond, &priv->mutex);
747 priv->wait_status &= ~STREAM_WAITING;
748 }
749 if (priv->flushing)
750 emit = FALSE;
751 g_mutex_unlock (&priv->mutex);
752
753 if (emit) {
754 /* emit EOS now */
755 if (priv->callbacks.eos)
756 priv->callbacks.eos (appsink, priv->user_data);
757 else
758 g_signal_emit (appsink, gst_app_sink_signals[SIGNAL_EOS], 0);
759 }
760
761 break;
762 }
763 case GST_EVENT_FLUSH_START:
764 /* we don't have to do anything here, the base class will call unlock
765 * which will make sure we exit the _render method */
766 GST_DEBUG_OBJECT (appsink, "received FLUSH_START");
767 break;
768 case GST_EVENT_FLUSH_STOP:
769 g_mutex_lock (&priv->mutex);
770 GST_DEBUG_OBJECT (appsink, "received FLUSH_STOP");
771 gst_app_sink_flush_unlocked (appsink);
772 g_mutex_unlock (&priv->mutex);
773 break;
774 default:
775 break;
776 }
777 return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
778 }
779
780 static GstFlowReturn
gst_app_sink_preroll(GstBaseSink * psink,GstBuffer * buffer)781 gst_app_sink_preroll (GstBaseSink * psink, GstBuffer * buffer)
782 {
783 GstFlowReturn res;
784 GstAppSink *appsink = GST_APP_SINK_CAST (psink);
785 GstAppSinkPrivate *priv = appsink->priv;
786 gboolean emit;
787
788 g_mutex_lock (&priv->mutex);
789 if (priv->flushing)
790 goto flushing;
791
792 GST_DEBUG_OBJECT (appsink, "setting preroll buffer %p", buffer);
793 gst_buffer_replace (&priv->preroll_buffer, buffer);
794
795 if ((priv->wait_status & APP_WAITING))
796 g_cond_signal (&priv->cond);
797
798 emit = priv->emit_signals;
799 g_mutex_unlock (&priv->mutex);
800
801 if (priv->callbacks.new_preroll) {
802 res = priv->callbacks.new_preroll (appsink, priv->user_data);
803 } else {
804 res = GST_FLOW_OK;
805 if (emit)
806 g_signal_emit (appsink, gst_app_sink_signals[SIGNAL_NEW_PREROLL], 0,
807 &res);
808 }
809
810 return res;
811
812 flushing:
813 {
814 GST_DEBUG_OBJECT (appsink, "we are flushing");
815 g_mutex_unlock (&priv->mutex);
816 return GST_FLOW_FLUSHING;
817 }
818 }
819
820 static GstMiniObject *
dequeue_buffer(GstAppSink * appsink)821 dequeue_buffer (GstAppSink * appsink)
822 {
823 GstAppSinkPrivate *priv = appsink->priv;
824 GstMiniObject *obj;
825
826 do {
827 obj = gst_queue_array_pop_head (priv->queue);
828
829 if (GST_IS_BUFFER (obj) || GST_IS_BUFFER_LIST (obj)) {
830 GST_DEBUG_OBJECT (appsink, "dequeued buffer/list %p", obj);
831 priv->num_buffers--;
832 break;
833 } else if (GST_IS_EVENT (obj)) {
834 GstEvent *event = GST_EVENT_CAST (obj);
835
836 switch (GST_EVENT_TYPE (obj)) {
837 case GST_EVENT_CAPS:
838 {
839 GstCaps *caps;
840
841 gst_event_parse_caps (event, &caps);
842 GST_DEBUG_OBJECT (appsink, "activating caps %" GST_PTR_FORMAT, caps);
843 gst_caps_replace (&priv->last_caps, caps);
844 priv->sample = gst_sample_make_writable (priv->sample);
845 gst_sample_set_caps (priv->sample, priv->last_caps);
846 break;
847 }
848 case GST_EVENT_SEGMENT:
849 gst_event_copy_segment (event, &priv->last_segment);
850 priv->sample = gst_sample_make_writable (priv->sample);
851 gst_sample_set_segment (priv->sample, &priv->last_segment);
852 GST_DEBUG_OBJECT (appsink, "activated segment %" GST_SEGMENT_FORMAT,
853 &priv->last_segment);
854 break;
855 default:
856 break;
857 }
858 gst_mini_object_unref (obj);
859 }
860 } while (TRUE);
861
862 return obj;
863 }
864
865 static GstFlowReturn
gst_app_sink_render_common(GstBaseSink * psink,GstMiniObject * data,gboolean is_list)866 gst_app_sink_render_common (GstBaseSink * psink, GstMiniObject * data,
867 gboolean is_list)
868 {
869 GstFlowReturn ret;
870 GstAppSink *appsink = GST_APP_SINK_CAST (psink);
871 GstAppSinkPrivate *priv = appsink->priv;
872 gboolean emit;
873
874 restart:
875 g_mutex_lock (&priv->mutex);
876 if (priv->flushing)
877 goto flushing;
878
879 /* queue holding caps event might have been FLUSHed,
880 * but caps state still present in pad caps */
881 if (G_UNLIKELY (!priv->last_caps &&
882 gst_pad_has_current_caps (GST_BASE_SINK_PAD (psink)))) {
883 priv->last_caps = gst_pad_get_current_caps (GST_BASE_SINK_PAD (psink));
884 gst_sample_set_caps (priv->sample, priv->last_caps);
885 GST_DEBUG_OBJECT (appsink, "activating pad caps %" GST_PTR_FORMAT,
886 priv->last_caps);
887 }
888
889 GST_DEBUG_OBJECT (appsink, "pushing render buffer/list %p on queue (%d)",
890 data, priv->num_buffers);
891
892 while (priv->max_buffers > 0 && priv->num_buffers >= priv->max_buffers) {
893 if (priv->drop) {
894 GstMiniObject *old;
895
896 /* we need to drop the oldest buffer/list and try again */
897 if ((old = dequeue_buffer (appsink))) {
898 GST_DEBUG_OBJECT (appsink, "dropping old buffer/list %p", old);
899 gst_mini_object_unref (old);
900 }
901 } else {
902 GST_DEBUG_OBJECT (appsink, "waiting for free space, length %d >= %d",
903 priv->num_buffers, priv->max_buffers);
904
905 if (priv->unlock) {
906 /* we are asked to unlock, call the wait_preroll method */
907 g_mutex_unlock (&priv->mutex);
908 if ((ret = gst_base_sink_wait_preroll (psink)) != GST_FLOW_OK)
909 goto stopping;
910
911 /* we are allowed to continue now */
912 goto restart;
913 }
914
915 /* wait for a buffer to be removed or flush */
916 priv->wait_status |= STREAM_WAITING;
917 g_cond_wait (&priv->cond, &priv->mutex);
918 priv->wait_status &= ~STREAM_WAITING;
919
920 if (priv->flushing)
921 goto flushing;
922 }
923 }
924 /* we need to ref the buffer/list when pushing it in the queue */
925 gst_queue_array_push_tail (priv->queue, gst_mini_object_ref (data));
926 priv->num_buffers++;
927
928 if ((priv->wait_status & APP_WAITING))
929 g_cond_signal (&priv->cond);
930
931 emit = priv->emit_signals;
932 g_mutex_unlock (&priv->mutex);
933
934 if (priv->callbacks.new_sample) {
935 ret = priv->callbacks.new_sample (appsink, priv->user_data);
936 } else {
937 ret = GST_FLOW_OK;
938 if (emit)
939 g_signal_emit (appsink, gst_app_sink_signals[SIGNAL_NEW_SAMPLE], 0, &ret);
940 }
941 return ret;
942
943 flushing:
944 {
945 GST_DEBUG_OBJECT (appsink, "we are flushing");
946 g_mutex_unlock (&priv->mutex);
947 return GST_FLOW_FLUSHING;
948 }
949 stopping:
950 {
951 GST_DEBUG_OBJECT (appsink, "we are stopping");
952 return ret;
953 }
954 }
955
956 static GstFlowReturn
gst_app_sink_render(GstBaseSink * psink,GstBuffer * buffer)957 gst_app_sink_render (GstBaseSink * psink, GstBuffer * buffer)
958 {
959 return gst_app_sink_render_common (psink, GST_MINI_OBJECT_CAST (buffer),
960 FALSE);
961 }
962
963 static GstFlowReturn
gst_app_sink_render_list(GstBaseSink * sink,GstBufferList * list)964 gst_app_sink_render_list (GstBaseSink * sink, GstBufferList * list)
965 {
966 GstFlowReturn flow;
967 GstAppSink *appsink;
968 GstBuffer *buffer;
969 guint i, len;
970
971 appsink = GST_APP_SINK_CAST (sink);
972
973 if (appsink->priv->buffer_lists_supported)
974 return gst_app_sink_render_common (sink, GST_MINI_OBJECT_CAST (list), TRUE);
975
976 /* The application doesn't support buffer lists, extract individual buffers
977 * then and push them one-by-one */
978 GST_INFO_OBJECT (sink, "chaining each group in list as a merged buffer");
979
980 len = gst_buffer_list_length (list);
981
982 flow = GST_FLOW_OK;
983 for (i = 0; i < len; i++) {
984 buffer = gst_buffer_list_get (list, i);
985 flow = gst_app_sink_render (sink, buffer);
986 if (flow != GST_FLOW_OK)
987 break;
988 }
989
990 return flow;
991 }
992
993 static GstCaps *
gst_app_sink_getcaps(GstBaseSink * psink,GstCaps * filter)994 gst_app_sink_getcaps (GstBaseSink * psink, GstCaps * filter)
995 {
996 GstCaps *caps;
997 GstAppSink *appsink = GST_APP_SINK_CAST (psink);
998 GstAppSinkPrivate *priv = appsink->priv;
999
1000 GST_OBJECT_LOCK (appsink);
1001 if ((caps = priv->caps)) {
1002 if (filter)
1003 caps = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
1004 else
1005 gst_caps_ref (caps);
1006 }
1007 GST_DEBUG_OBJECT (appsink, "got caps %" GST_PTR_FORMAT, caps);
1008 GST_OBJECT_UNLOCK (appsink);
1009
1010 return caps;
1011 }
1012
1013 static gboolean
gst_app_sink_query(GstBaseSink * bsink,GstQuery * query)1014 gst_app_sink_query (GstBaseSink * bsink, GstQuery * query)
1015 {
1016 GstAppSink *appsink = GST_APP_SINK_CAST (bsink);
1017 GstAppSinkPrivate *priv = appsink->priv;
1018 gboolean ret;
1019
1020 switch (GST_QUERY_TYPE (query)) {
1021 case GST_QUERY_DRAIN:
1022 {
1023 g_mutex_lock (&priv->mutex);
1024 GST_DEBUG_OBJECT (appsink, "waiting buffers to be consumed");
1025 while (priv->num_buffers > 0 || priv->preroll_buffer) {
1026 if (priv->unlock) {
1027 /* we are asked to unlock, call the wait_preroll method */
1028 g_mutex_unlock (&priv->mutex);
1029 if (gst_base_sink_wait_preroll (bsink) != GST_FLOW_OK) {
1030 /* Directly go out of here */
1031 return FALSE;
1032 }
1033
1034 /* we are allowed to continue now */
1035 g_mutex_lock (&priv->mutex);
1036 continue;
1037 }
1038
1039 priv->wait_status |= STREAM_WAITING;
1040 g_cond_wait (&priv->cond, &priv->mutex);
1041 priv->wait_status &= ~STREAM_WAITING;
1042
1043 if (priv->flushing)
1044 break;
1045 }
1046 g_mutex_unlock (&priv->mutex);
1047 ret = GST_BASE_SINK_CLASS (parent_class)->query (bsink, query);
1048 break;
1049 }
1050 case GST_QUERY_SEEKING:{
1051 GstFormat fmt;
1052
1053 /* we don't supporting seeking */
1054 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
1055 gst_query_set_seeking (query, fmt, FALSE, 0, -1);
1056 ret = TRUE;
1057 break;
1058 }
1059
1060 default:
1061 ret = GST_BASE_SINK_CLASS (parent_class)->query (bsink, query);
1062 break;
1063 }
1064
1065 return ret;
1066 }
1067
1068 /* external API */
1069
1070 /**
1071 * gst_app_sink_set_caps:
1072 * @appsink: a #GstAppSink
1073 * @caps: caps to set
1074 *
1075 * Set the capabilities on the appsink element. This function takes
1076 * a copy of the caps structure. After calling this method, the sink will only
1077 * accept caps that match @caps. If @caps is non-fixed, or incomplete,
1078 * you must check the caps on the samples to get the actual used caps.
1079 */
1080 void
gst_app_sink_set_caps(GstAppSink * appsink,const GstCaps * caps)1081 gst_app_sink_set_caps (GstAppSink * appsink, const GstCaps * caps)
1082 {
1083 GstCaps *old;
1084 GstAppSinkPrivate *priv;
1085
1086 g_return_if_fail (GST_IS_APP_SINK (appsink));
1087
1088 priv = appsink->priv;
1089
1090 GST_OBJECT_LOCK (appsink);
1091 GST_DEBUG_OBJECT (appsink, "setting caps to %" GST_PTR_FORMAT, caps);
1092 if ((old = priv->caps) != caps) {
1093 if (caps)
1094 priv->caps = gst_caps_copy (caps);
1095 else
1096 priv->caps = NULL;
1097 if (old)
1098 gst_caps_unref (old);
1099 }
1100 GST_OBJECT_UNLOCK (appsink);
1101 }
1102
1103 /**
1104 * gst_app_sink_get_caps:
1105 * @appsink: a #GstAppSink
1106 *
1107 * Get the configured caps on @appsink.
1108 *
1109 * Returns: the #GstCaps accepted by the sink. gst_caps_unref() after usage.
1110 */
1111 GstCaps *
gst_app_sink_get_caps(GstAppSink * appsink)1112 gst_app_sink_get_caps (GstAppSink * appsink)
1113 {
1114 GstCaps *caps;
1115 GstAppSinkPrivate *priv;
1116
1117 g_return_val_if_fail (GST_IS_APP_SINK (appsink), NULL);
1118
1119 priv = appsink->priv;
1120
1121 GST_OBJECT_LOCK (appsink);
1122 if ((caps = priv->caps))
1123 gst_caps_ref (caps);
1124 GST_DEBUG_OBJECT (appsink, "getting caps of %" GST_PTR_FORMAT, caps);
1125 GST_OBJECT_UNLOCK (appsink);
1126
1127 return caps;
1128 }
1129
1130 /**
1131 * gst_app_sink_is_eos:
1132 * @appsink: a #GstAppSink
1133 *
1134 * Check if @appsink is EOS, which is when no more samples can be pulled because
1135 * an EOS event was received.
1136 *
1137 * This function also returns %TRUE when the appsink is not in the PAUSED or
1138 * PLAYING state.
1139 *
1140 * Returns: %TRUE if no more samples can be pulled and the appsink is EOS.
1141 */
1142 gboolean
gst_app_sink_is_eos(GstAppSink * appsink)1143 gst_app_sink_is_eos (GstAppSink * appsink)
1144 {
1145 gboolean ret;
1146 GstAppSinkPrivate *priv;
1147
1148 g_return_val_if_fail (GST_IS_APP_SINK (appsink), FALSE);
1149
1150 priv = appsink->priv;
1151
1152 g_mutex_lock (&priv->mutex);
1153 if (!priv->started)
1154 goto not_started;
1155
1156 if (priv->is_eos && priv->num_buffers == 0) {
1157 GST_DEBUG_OBJECT (appsink, "we are EOS and the queue is empty");
1158 ret = TRUE;
1159 } else {
1160 GST_DEBUG_OBJECT (appsink, "we are not yet EOS");
1161 ret = FALSE;
1162 }
1163 g_mutex_unlock (&priv->mutex);
1164
1165 return ret;
1166
1167 not_started:
1168 {
1169 GST_DEBUG_OBJECT (appsink, "we are stopped, return TRUE");
1170 g_mutex_unlock (&priv->mutex);
1171 return TRUE;
1172 }
1173 }
1174
1175 /**
1176 * gst_app_sink_set_emit_signals:
1177 * @appsink: a #GstAppSink
1178 * @emit: the new state
1179 *
1180 * Make appsink emit the "new-preroll" and "new-sample" signals. This option is
1181 * by default disabled because signal emission is expensive and unneeded when
1182 * the application prefers to operate in pull mode.
1183 */
1184 void
gst_app_sink_set_emit_signals(GstAppSink * appsink,gboolean emit)1185 gst_app_sink_set_emit_signals (GstAppSink * appsink, gboolean emit)
1186 {
1187 GstAppSinkPrivate *priv;
1188
1189 g_return_if_fail (GST_IS_APP_SINK (appsink));
1190
1191 priv = appsink->priv;
1192
1193 g_mutex_lock (&priv->mutex);
1194 priv->emit_signals = emit;
1195 g_mutex_unlock (&priv->mutex);
1196 }
1197
1198 /**
1199 * gst_app_sink_get_emit_signals:
1200 * @appsink: a #GstAppSink
1201 *
1202 * Check if appsink will emit the "new-preroll" and "new-sample" signals.
1203 *
1204 * Returns: %TRUE if @appsink is emiting the "new-preroll" and "new-sample"
1205 * signals.
1206 */
1207 gboolean
gst_app_sink_get_emit_signals(GstAppSink * appsink)1208 gst_app_sink_get_emit_signals (GstAppSink * appsink)
1209 {
1210 gboolean result;
1211 GstAppSinkPrivate *priv;
1212
1213 g_return_val_if_fail (GST_IS_APP_SINK (appsink), FALSE);
1214
1215 priv = appsink->priv;
1216
1217 g_mutex_lock (&priv->mutex);
1218 result = priv->emit_signals;
1219 g_mutex_unlock (&priv->mutex);
1220
1221 return result;
1222 }
1223
1224 /**
1225 * gst_app_sink_set_max_buffers:
1226 * @appsink: a #GstAppSink
1227 * @max: the maximum number of buffers to queue
1228 *
1229 * Set the maximum amount of buffers that can be queued in @appsink. After this
1230 * amount of buffers are queued in appsink, any more buffers will block upstream
1231 * elements until a sample is pulled from @appsink.
1232 */
1233 void
gst_app_sink_set_max_buffers(GstAppSink * appsink,guint max)1234 gst_app_sink_set_max_buffers (GstAppSink * appsink, guint max)
1235 {
1236 GstAppSinkPrivate *priv;
1237
1238 g_return_if_fail (GST_IS_APP_SINK (appsink));
1239
1240 priv = appsink->priv;
1241
1242 g_mutex_lock (&priv->mutex);
1243 if (max != priv->max_buffers) {
1244 priv->max_buffers = max;
1245 /* signal the change */
1246 g_cond_signal (&priv->cond);
1247 }
1248 g_mutex_unlock (&priv->mutex);
1249 }
1250
1251 /**
1252 * gst_app_sink_get_max_buffers:
1253 * @appsink: a #GstAppSink
1254 *
1255 * Get the maximum amount of buffers that can be queued in @appsink.
1256 *
1257 * Returns: The maximum amount of buffers that can be queued.
1258 */
1259 guint
gst_app_sink_get_max_buffers(GstAppSink * appsink)1260 gst_app_sink_get_max_buffers (GstAppSink * appsink)
1261 {
1262 guint result;
1263 GstAppSinkPrivate *priv;
1264
1265 g_return_val_if_fail (GST_IS_APP_SINK (appsink), 0);
1266
1267 priv = appsink->priv;
1268
1269 g_mutex_lock (&priv->mutex);
1270 result = priv->max_buffers;
1271 g_mutex_unlock (&priv->mutex);
1272
1273 return result;
1274 }
1275
1276 /**
1277 * gst_app_sink_set_drop:
1278 * @appsink: a #GstAppSink
1279 * @drop: the new state
1280 *
1281 * Instruct @appsink to drop old buffers when the maximum amount of queued
1282 * buffers is reached.
1283 */
1284 void
gst_app_sink_set_drop(GstAppSink * appsink,gboolean drop)1285 gst_app_sink_set_drop (GstAppSink * appsink, gboolean drop)
1286 {
1287 GstAppSinkPrivate *priv;
1288
1289 g_return_if_fail (GST_IS_APP_SINK (appsink));
1290
1291 priv = appsink->priv;
1292
1293 g_mutex_lock (&priv->mutex);
1294 if (priv->drop != drop) {
1295 priv->drop = drop;
1296 /* signal the change */
1297 g_cond_signal (&priv->cond);
1298 }
1299 g_mutex_unlock (&priv->mutex);
1300 }
1301
1302 /**
1303 * gst_app_sink_get_drop:
1304 * @appsink: a #GstAppSink
1305 *
1306 * Check if @appsink will drop old buffers when the maximum amount of queued
1307 * buffers is reached.
1308 *
1309 * Returns: %TRUE if @appsink is dropping old buffers when the queue is
1310 * filled.
1311 */
1312 gboolean
gst_app_sink_get_drop(GstAppSink * appsink)1313 gst_app_sink_get_drop (GstAppSink * appsink)
1314 {
1315 gboolean result;
1316 GstAppSinkPrivate *priv;
1317
1318 g_return_val_if_fail (GST_IS_APP_SINK (appsink), FALSE);
1319
1320 priv = appsink->priv;
1321
1322 g_mutex_lock (&priv->mutex);
1323 result = priv->drop;
1324 g_mutex_unlock (&priv->mutex);
1325
1326 return result;
1327 }
1328
1329 /**
1330 * gst_app_sink_set_buffer_list_support:
1331 * @appsink: a #GstAppSink
1332 * @enable_lists: enable or disable buffer list support
1333 *
1334 * Instruct @appsink to enable or disable buffer list support.
1335 *
1336 * For backwards-compatibility reasons applications need to opt in
1337 * to indicate that they will be able to handle buffer lists.
1338 *
1339 * Since: 1.12
1340 */
1341 void
gst_app_sink_set_buffer_list_support(GstAppSink * appsink,gboolean enable_lists)1342 gst_app_sink_set_buffer_list_support (GstAppSink * appsink,
1343 gboolean enable_lists)
1344 {
1345 GstAppSinkPrivate *priv;
1346
1347 g_return_if_fail (GST_IS_APP_SINK (appsink));
1348
1349 priv = appsink->priv;
1350
1351 g_mutex_lock (&priv->mutex);
1352 if (priv->buffer_lists_supported != enable_lists) {
1353 priv->buffer_lists_supported = enable_lists;
1354 }
1355 g_mutex_unlock (&priv->mutex);
1356 }
1357
1358 /**
1359 * gst_app_sink_get_buffer_list_support:
1360 * @appsink: a #GstAppSink
1361 *
1362 * Check if @appsink supports buffer lists.
1363 *
1364 * Returns: %TRUE if @appsink supports buffer lists.
1365 *
1366 * Since: 1.12
1367 */
1368 gboolean
gst_app_sink_get_buffer_list_support(GstAppSink * appsink)1369 gst_app_sink_get_buffer_list_support (GstAppSink * appsink)
1370 {
1371 gboolean result;
1372 GstAppSinkPrivate *priv;
1373
1374 g_return_val_if_fail (GST_IS_APP_SINK (appsink), FALSE);
1375
1376 priv = appsink->priv;
1377
1378 g_mutex_lock (&priv->mutex);
1379 result = priv->buffer_lists_supported;
1380 g_mutex_unlock (&priv->mutex);
1381
1382 return result;
1383 }
1384
1385 /**
1386 * gst_app_sink_set_wait_on_eos:
1387 * @appsink: a #GstAppSink
1388 * @wait: the new state
1389 *
1390 * Instruct @appsink to wait for all buffers to be consumed when an EOS is received.
1391 *
1392 */
1393 void
gst_app_sink_set_wait_on_eos(GstAppSink * appsink,gboolean wait)1394 gst_app_sink_set_wait_on_eos (GstAppSink * appsink, gboolean wait)
1395 {
1396 GstAppSinkPrivate *priv;
1397
1398 g_return_if_fail (GST_IS_APP_SINK (appsink));
1399
1400 priv = appsink->priv;
1401
1402 g_mutex_lock (&priv->mutex);
1403 if (priv->wait_on_eos != wait) {
1404 priv->wait_on_eos = wait;
1405 /* signal the change */
1406 g_cond_signal (&priv->cond);
1407 }
1408 g_mutex_unlock (&priv->mutex);
1409 }
1410
1411 /**
1412 * gst_app_sink_get_wait_on_eos:
1413 * @appsink: a #GstAppSink
1414 *
1415 * Check if @appsink will wait for all buffers to be consumed when an EOS is
1416 * received.
1417 *
1418 * Returns: %TRUE if @appsink will wait for all buffers to be consumed when an
1419 * EOS is received.
1420 */
1421 gboolean
gst_app_sink_get_wait_on_eos(GstAppSink * appsink)1422 gst_app_sink_get_wait_on_eos (GstAppSink * appsink)
1423 {
1424 gboolean result;
1425 GstAppSinkPrivate *priv;
1426
1427 g_return_val_if_fail (GST_IS_APP_SINK (appsink), FALSE);
1428
1429 priv = appsink->priv;
1430
1431 g_mutex_lock (&priv->mutex);
1432 result = priv->wait_on_eos;
1433 g_mutex_unlock (&priv->mutex);
1434
1435 return result;
1436 }
1437
1438 /**
1439 * gst_app_sink_pull_preroll:
1440 * @appsink: a #GstAppSink
1441 *
1442 * Get the last preroll sample in @appsink. This was the sample that caused the
1443 * appsink to preroll in the PAUSED state.
1444 *
1445 * This function is typically used when dealing with a pipeline in the PAUSED
1446 * state. Calling this function after doing a seek will give the sample right
1447 * after the seek position.
1448 *
1449 * Calling this function will clear the internal reference to the preroll
1450 * buffer.
1451 *
1452 * Note that the preroll sample will also be returned as the first sample
1453 * when calling gst_app_sink_pull_sample().
1454 *
1455 * If an EOS event was received before any buffers, this function returns
1456 * %NULL. Use gst_app_sink_is_eos () to check for the EOS condition.
1457 *
1458 * This function blocks until a preroll sample or EOS is received or the appsink
1459 * element is set to the READY/NULL state.
1460 *
1461 * Returns: (transfer full): a #GstSample or NULL when the appsink is stopped or EOS.
1462 * Call gst_sample_unref() after usage.
1463 */
1464 GstSample *
gst_app_sink_pull_preroll(GstAppSink * appsink)1465 gst_app_sink_pull_preroll (GstAppSink * appsink)
1466 {
1467 return gst_app_sink_try_pull_preroll (appsink, GST_CLOCK_TIME_NONE);
1468 }
1469
1470 /**
1471 * gst_app_sink_pull_sample:
1472 * @appsink: a #GstAppSink
1473 *
1474 * This function blocks until a sample or EOS becomes available or the appsink
1475 * element is set to the READY/NULL state.
1476 *
1477 * This function will only return samples when the appsink is in the PLAYING
1478 * state. All rendered buffers will be put in a queue so that the application
1479 * can pull samples at its own rate. Note that when the application does not
1480 * pull samples fast enough, the queued buffers could consume a lot of memory,
1481 * especially when dealing with raw video frames.
1482 *
1483 * If an EOS event was received before any buffers, this function returns
1484 * %NULL. Use gst_app_sink_is_eos () to check for the EOS condition.
1485 *
1486 * Returns: (transfer full): a #GstSample or NULL when the appsink is stopped or EOS.
1487 * Call gst_sample_unref() after usage.
1488 */
1489 GstSample *
gst_app_sink_pull_sample(GstAppSink * appsink)1490 gst_app_sink_pull_sample (GstAppSink * appsink)
1491 {
1492 return gst_app_sink_try_pull_sample (appsink, GST_CLOCK_TIME_NONE);
1493 }
1494
1495 /**
1496 * gst_app_sink_try_pull_preroll:
1497 * @appsink: a #GstAppSink
1498 * @timeout: the maximum amount of time to wait for the preroll sample
1499 *
1500 * Get the last preroll sample in @appsink. This was the sample that caused the
1501 * appsink to preroll in the PAUSED state.
1502 *
1503 * This function is typically used when dealing with a pipeline in the PAUSED
1504 * state. Calling this function after doing a seek will give the sample right
1505 * after the seek position.
1506 *
1507 * Calling this function will clear the internal reference to the preroll
1508 * buffer.
1509 *
1510 * Note that the preroll sample will also be returned as the first sample
1511 * when calling gst_app_sink_pull_sample().
1512 *
1513 * If an EOS event was received before any buffers or the timeout expires,
1514 * this function returns %NULL. Use gst_app_sink_is_eos () to check for the EOS
1515 * condition.
1516 *
1517 * This function blocks until a preroll sample or EOS is received, the appsink
1518 * element is set to the READY/NULL state, or the timeout expires.
1519 *
1520 * Returns: (transfer full): a #GstSample or NULL when the appsink is stopped or EOS or the timeout expires.
1521 * Call gst_sample_unref() after usage.
1522 *
1523 * Since: 1.10
1524 */
1525 GstSample *
gst_app_sink_try_pull_preroll(GstAppSink * appsink,GstClockTime timeout)1526 gst_app_sink_try_pull_preroll (GstAppSink * appsink, GstClockTime timeout)
1527 {
1528 GstAppSinkPrivate *priv;
1529 GstSample *sample = NULL;
1530 gboolean timeout_valid;
1531 gint64 end_time;
1532
1533 g_return_val_if_fail (GST_IS_APP_SINK (appsink), NULL);
1534
1535 priv = appsink->priv;
1536
1537 timeout_valid = GST_CLOCK_TIME_IS_VALID (timeout);
1538
1539 if (timeout_valid)
1540 end_time =
1541 g_get_monotonic_time () + timeout / (GST_SECOND / G_TIME_SPAN_SECOND);
1542
1543 g_mutex_lock (&priv->mutex);
1544
1545 while (TRUE) {
1546 GST_DEBUG_OBJECT (appsink, "trying to grab a buffer");
1547 if (!priv->started)
1548 goto not_started;
1549
1550 if (priv->preroll_buffer != NULL)
1551 break;
1552
1553 if (priv->is_eos)
1554 goto eos;
1555
1556 /* nothing to return, wait */
1557 GST_DEBUG_OBJECT (appsink, "waiting for the preroll buffer");
1558 priv->wait_status |= APP_WAITING;
1559 if (timeout_valid) {
1560 if (!g_cond_wait_until (&priv->cond, &priv->mutex, end_time))
1561 goto expired;
1562 } else {
1563 g_cond_wait (&priv->cond, &priv->mutex);
1564 }
1565 priv->wait_status &= ~APP_WAITING;
1566 }
1567 sample =
1568 gst_sample_new (priv->preroll_buffer, priv->preroll_caps,
1569 &priv->preroll_segment, NULL);
1570 gst_buffer_replace (&priv->preroll_buffer, NULL);
1571 GST_DEBUG_OBJECT (appsink, "we have the preroll sample %p", sample);
1572 g_mutex_unlock (&priv->mutex);
1573
1574 return sample;
1575
1576 /* special conditions */
1577 expired:
1578 {
1579 GST_DEBUG_OBJECT (appsink, "timeout expired, return NULL");
1580 priv->wait_status &= ~APP_WAITING;
1581 g_mutex_unlock (&priv->mutex);
1582 return NULL;
1583 }
1584 eos:
1585 {
1586 GST_DEBUG_OBJECT (appsink, "we are EOS, return NULL");
1587 g_mutex_unlock (&priv->mutex);
1588 return NULL;
1589 }
1590 not_started:
1591 {
1592 GST_DEBUG_OBJECT (appsink, "we are stopped, return NULL");
1593 g_mutex_unlock (&priv->mutex);
1594 return NULL;
1595 }
1596 }
1597
1598 /**
1599 * gst_app_sink_try_pull_sample:
1600 * @appsink: a #GstAppSink
1601 * @timeout: the maximum amount of time to wait for a sample
1602 *
1603 * This function blocks until a sample or EOS becomes available or the appsink
1604 * element is set to the READY/NULL state or the timeout expires.
1605 *
1606 * This function will only return samples when the appsink is in the PLAYING
1607 * state. All rendered buffers will be put in a queue so that the application
1608 * can pull samples at its own rate. Note that when the application does not
1609 * pull samples fast enough, the queued buffers could consume a lot of memory,
1610 * especially when dealing with raw video frames.
1611 *
1612 * If an EOS event was received before any buffers or the timeout expires,
1613 * this function returns %NULL. Use gst_app_sink_is_eos () to check for the EOS
1614 * condition.
1615 *
1616 * Returns: (transfer full): a #GstSample or NULL when the appsink is stopped or EOS or the timeout expires.
1617 * Call gst_sample_unref() after usage.
1618 *
1619 * Since: 1.10
1620 */
1621 GstSample *
gst_app_sink_try_pull_sample(GstAppSink * appsink,GstClockTime timeout)1622 gst_app_sink_try_pull_sample (GstAppSink * appsink, GstClockTime timeout)
1623 {
1624 GstAppSinkPrivate *priv;
1625 GstSample *sample = NULL;
1626 GstMiniObject *obj;
1627 gboolean timeout_valid;
1628 gint64 end_time;
1629
1630 g_return_val_if_fail (GST_IS_APP_SINK (appsink), NULL);
1631
1632 timeout_valid = GST_CLOCK_TIME_IS_VALID (timeout);
1633
1634 if (timeout_valid)
1635 end_time =
1636 g_get_monotonic_time () + timeout / (GST_SECOND / G_TIME_SPAN_SECOND);
1637
1638 priv = appsink->priv;
1639
1640 g_mutex_lock (&priv->mutex);
1641 gst_buffer_replace (&priv->preroll_buffer, NULL);
1642
1643 while (TRUE) {
1644 GST_DEBUG_OBJECT (appsink, "trying to grab a buffer");
1645 if (!priv->started)
1646 goto not_started;
1647
1648 if (priv->num_buffers > 0)
1649 break;
1650
1651 if (priv->is_eos)
1652 goto eos;
1653
1654 /* nothing to return, wait */
1655 GST_DEBUG_OBJECT (appsink, "waiting for a buffer");
1656 priv->wait_status |= APP_WAITING;
1657 if (timeout_valid) {
1658 if (!g_cond_wait_until (&priv->cond, &priv->mutex, end_time))
1659 goto expired;
1660 } else {
1661 g_cond_wait (&priv->cond, &priv->mutex);
1662 }
1663 priv->wait_status &= ~APP_WAITING;
1664 }
1665
1666 obj = dequeue_buffer (appsink);
1667 if (GST_IS_BUFFER (obj)) {
1668 GST_DEBUG_OBJECT (appsink, "we have a buffer %p", obj);
1669 priv->sample = gst_sample_make_writable (priv->sample);
1670 gst_sample_set_buffer_list (priv->sample, NULL);
1671 gst_sample_set_buffer (priv->sample, GST_BUFFER_CAST (obj));
1672 sample = gst_sample_ref (priv->sample);
1673 } else {
1674 GST_DEBUG_OBJECT (appsink, "we have a list %p", obj);
1675 priv->sample = gst_sample_make_writable (priv->sample);
1676 gst_sample_set_buffer (priv->sample, NULL);
1677 gst_sample_set_buffer_list (priv->sample, GST_BUFFER_LIST_CAST (obj));
1678 sample = gst_sample_ref (priv->sample);
1679 }
1680 gst_mini_object_unref (obj);
1681
1682 if ((priv->wait_status & STREAM_WAITING))
1683 g_cond_signal (&priv->cond);
1684
1685 g_mutex_unlock (&priv->mutex);
1686
1687 return sample;
1688
1689 /* special conditions */
1690 expired:
1691 {
1692 GST_DEBUG_OBJECT (appsink, "timeout expired, return NULL");
1693 priv->wait_status &= ~APP_WAITING;
1694 g_mutex_unlock (&priv->mutex);
1695 return NULL;
1696 }
1697 eos:
1698 {
1699 GST_DEBUG_OBJECT (appsink, "we are EOS, return NULL");
1700 g_mutex_unlock (&priv->mutex);
1701 return NULL;
1702 }
1703 not_started:
1704 {
1705 GST_DEBUG_OBJECT (appsink, "we are stopped, return NULL");
1706 g_mutex_unlock (&priv->mutex);
1707 return NULL;
1708 }
1709 }
1710
1711 /**
1712 * gst_app_sink_set_callbacks: (skip)
1713 * @appsink: a #GstAppSink
1714 * @callbacks: the callbacks
1715 * @user_data: a user_data argument for the callbacks
1716 * @notify: a destroy notify function
1717 *
1718 * Set callbacks which will be executed for each new preroll, new sample and eos.
1719 * This is an alternative to using the signals, it has lower overhead and is thus
1720 * less expensive, but also less flexible.
1721 *
1722 * If callbacks are installed, no signals will be emitted for performance
1723 * reasons.
1724 */
1725 void
gst_app_sink_set_callbacks(GstAppSink * appsink,GstAppSinkCallbacks * callbacks,gpointer user_data,GDestroyNotify notify)1726 gst_app_sink_set_callbacks (GstAppSink * appsink,
1727 GstAppSinkCallbacks * callbacks, gpointer user_data, GDestroyNotify notify)
1728 {
1729 GDestroyNotify old_notify;
1730 GstAppSinkPrivate *priv;
1731
1732 g_return_if_fail (GST_IS_APP_SINK (appsink));
1733 g_return_if_fail (callbacks != NULL);
1734
1735 priv = appsink->priv;
1736
1737 GST_OBJECT_LOCK (appsink);
1738 old_notify = priv->notify;
1739
1740 if (old_notify) {
1741 gpointer old_data;
1742
1743 old_data = priv->user_data;
1744
1745 priv->user_data = NULL;
1746 priv->notify = NULL;
1747 GST_OBJECT_UNLOCK (appsink);
1748
1749 old_notify (old_data);
1750
1751 GST_OBJECT_LOCK (appsink);
1752 }
1753 priv->callbacks = *callbacks;
1754 priv->user_data = user_data;
1755 priv->notify = notify;
1756 GST_OBJECT_UNLOCK (appsink);
1757 }
1758
1759 /*** GSTURIHANDLER INTERFACE *************************************************/
1760
1761 static GstURIType
gst_app_sink_uri_get_type(GType type)1762 gst_app_sink_uri_get_type (GType type)
1763 {
1764 return GST_URI_SINK;
1765 }
1766
1767 static const gchar *const *
gst_app_sink_uri_get_protocols(GType type)1768 gst_app_sink_uri_get_protocols (GType type)
1769 {
1770 static const gchar *protocols[] = { "appsink", NULL };
1771
1772 return protocols;
1773 }
1774
1775 static gchar *
gst_app_sink_uri_get_uri(GstURIHandler * handler)1776 gst_app_sink_uri_get_uri (GstURIHandler * handler)
1777 {
1778 return g_strdup ("appsink");
1779 }
1780
1781 static gboolean
gst_app_sink_uri_set_uri(GstURIHandler * handler,const gchar * uri,GError ** error)1782 gst_app_sink_uri_set_uri (GstURIHandler * handler, const gchar * uri,
1783 GError ** error)
1784 {
1785 /* GstURIHandler checks the protocol for us */
1786 return TRUE;
1787 }
1788
1789 static void
gst_app_sink_uri_handler_init(gpointer g_iface,gpointer iface_data)1790 gst_app_sink_uri_handler_init (gpointer g_iface, gpointer iface_data)
1791 {
1792 GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
1793
1794 iface->get_type = gst_app_sink_uri_get_type;
1795 iface->get_protocols = gst_app_sink_uri_get_protocols;
1796 iface->get_uri = gst_app_sink_uri_get_uri;
1797 iface->set_uri = gst_app_sink_uri_set_uri;
1798
1799 }
1800