• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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