2 * Copyright (C) 2007 David Schleef <ds@schleef.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
22 #include <gst/base/gstbasesink.h>
23 #include <gst/gstbuffer.h>
27 #include "gstappsink.h"
29 GST_DEBUG_CATEGORY (app_sink_debug);
30 #define GST_CAT_DEFAULT app_sink_debug
32 static const GstElementDetails app_sink_details =
33 GST_ELEMENT_DETAILS ((gchar*)"AppSink",
34 (gchar*)"Generic/Sink",
35 (gchar*)"Allow the application to get access to raw buffer",
36 (gchar*)"David Schleef <ds@schleef.org>, Wim Taymans <wim.taymans@gmail.com");
59 static GstStaticPadTemplate gst_app_sink_template =
60 GST_STATIC_PAD_TEMPLATE ("sink",
65 static void gst_app_sink_dispose (GObject * object);
66 static void gst_app_sink_finalize (GObject * object);
68 static void gst_app_sink_set_property (GObject * object, guint prop_id,
69 const GValue * value, GParamSpec * pspec);
70 static void gst_app_sink_get_property (GObject * object, guint prop_id,
71 GValue * value, GParamSpec * pspec);
73 static gboolean gst_app_sink_start (GstBaseSink * psink);
74 static gboolean gst_app_sink_stop (GstBaseSink * psink);
75 static gboolean gst_app_sink_event (GstBaseSink * sink, GstEvent * event);
76 static GstFlowReturn gst_app_sink_preroll (GstBaseSink * psink,
78 static GstFlowReturn gst_app_sink_render (GstBaseSink * psink,
80 static GstCaps *gst_app_sink_getcaps (GstBaseSink * psink);
82 static guint gst_app_sink_signals[LAST_SIGNAL] = { 0 };
84 GST_BOILERPLATE (GstAppSink, gst_app_sink, GstBaseSink, GST_TYPE_BASE_SINK);
87 appsink_plugin_init (GstPlugin * plugin)
89 GST_DEBUG_CATEGORY_INIT (app_sink_debug, "opencv-appsink", 0, "Application sink");
91 if (!gst_element_register (plugin, "opencv-appsink", GST_RANK_PRIMARY,
92 gst_app_sink_get_type ()))
99 #define PACKAGE "highgui"
100 GST_PLUGIN_DEFINE_STATIC (GST_VERSION_MAJOR, GST_VERSION_MINOR,
101 "opencv-appsink", "Element application sink",
102 appsink_plugin_init, "0.1", "LGPL", "OpenCV's internal copy of gstappsink", "OpenCV")
105 gst_app_marshal_OBJECT__VOID (GClosure * closure,
106 GValue * return_value,
107 guint n_param_values,
108 const GValue * param_values,
109 gpointer invocation_hint, gpointer marshal_data)
111 typedef GstBuffer *(*GMarshalFunc_OBJECT__VOID) (gpointer data1,
113 register GMarshalFunc_OBJECT__VOID callback;
114 register GCClosure *cc = (GCClosure *) closure;
115 register gpointer data1, data2;
118 //printf("appmarshalobject\n");
120 g_return_if_fail (return_value != NULL);
121 g_return_if_fail (n_param_values == 1);
123 if (G_CCLOSURE_SWAP_DATA (closure)) {
124 data1 = closure->data;
125 data2 = g_value_peek_pointer (param_values + 0);
127 data1 = g_value_peek_pointer (param_values + 0);
128 data2 = closure->data;
131 (GMarshalFunc_OBJECT__VOID) (marshal_data ? marshal_data : cc->callback);
133 v_return = callback (data1, data2);
135 gst_value_take_buffer (return_value, v_return);
139 gst_app_sink_base_init (gpointer g_class)
141 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
143 //printf("appsinkbaseinit\n");
145 GST_DEBUG_CATEGORY_INIT (app_sink_debug, "appsink", 0, "appsink element");
147 gst_element_class_set_details (element_class, &app_sink_details);
149 gst_element_class_add_pad_template (element_class,
150 gst_static_pad_template_get (&gst_app_sink_template));
154 gst_app_sink_class_init (GstAppSinkClass * klass)
156 GObjectClass *gobject_class = (GObjectClass *) klass;
157 GstBaseSinkClass *basesink_class = (GstBaseSinkClass *) klass;
159 //printf("appsinkclassinit\n");
161 gobject_class->dispose = gst_app_sink_dispose;
162 gobject_class->finalize = gst_app_sink_finalize;
164 gobject_class->set_property = gst_app_sink_set_property;
165 gobject_class->get_property = gst_app_sink_get_property;
167 g_object_class_install_property (gobject_class, PROP_CAPS,
168 g_param_spec_boxed ("caps", "Caps",
169 "The caps of the sink pad", GST_TYPE_CAPS, (GParamFlags)G_PARAM_READWRITE));
171 g_object_class_install_property (gobject_class, PROP_EOS,
172 g_param_spec_boolean ("eos", "EOS",
173 "Check if the sink is EOS", TRUE, G_PARAM_READABLE));
177 * @appsink: the appsink element that emitted the signal
179 * Signal that the end-of-stream has been reached.
181 gst_app_sink_signals[SIGNAL_EOS] =
182 g_signal_new ("eos", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
183 G_STRUCT_OFFSET (GstAppSinkClass, eos),
184 NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
186 * GstAppSink::new-preroll:
187 * @appsink: the appsink element that emitted the signal
188 * @buffer: the buffer that caused the preroll
190 * Signal that a new preroll buffer is available.
192 gst_app_sink_signals[SIGNAL_NEW_PREROLL] =
193 g_signal_new ("new-preroll", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
194 G_STRUCT_OFFSET (GstAppSinkClass, new_preroll),
195 NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
198 * GstAppSink::new-buffer:
199 * @appsink: the appsink element that emitted the signal
200 * @buffer: the buffer that is available
202 * Signal that a new buffer is available.
204 gst_app_sink_signals[SIGNAL_NEW_BUFFER] =
205 g_signal_new ("new-buffer", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
206 G_STRUCT_OFFSET (GstAppSinkClass, new_buffer),
207 NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1,
211 * GstAppSink::pull-preroll:
212 * @appsink: the appsink element to emit this signal on
214 * Get the last preroll buffer on @appsink.
216 gst_app_sink_signals[SIGNAL_PULL_PREROLL] =
217 g_signal_new ("pull-preroll", G_TYPE_FROM_CLASS (klass),
218 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstAppSinkClass, pull_preroll), NULL,
219 NULL, gst_app_marshal_OBJECT__VOID, GST_TYPE_BUFFER, 0, G_TYPE_NONE);
221 * GstAppSink::pull-buffer:
222 * @appsink: the appsink element to emit this signal on
224 * Get the next buffer buffer on @appsink.
226 gst_app_sink_signals[SIGNAL_PULL_PREROLL] =
227 g_signal_new ("pull-buffer", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
228 G_STRUCT_OFFSET (GstAppSinkClass, pull_buffer),
229 NULL, NULL, gst_app_marshal_OBJECT__VOID, GST_TYPE_BUFFER, 0,
232 basesink_class->start = gst_app_sink_start;
233 basesink_class->stop = gst_app_sink_stop;
234 basesink_class->event = gst_app_sink_event;
235 basesink_class->preroll = gst_app_sink_preroll;
236 basesink_class->render = gst_app_sink_render;
237 basesink_class->get_caps = gst_app_sink_getcaps;
239 klass->pull_preroll = gst_app_sink_pull_preroll;
240 klass->pull_buffer = gst_app_sink_pull_buffer;
244 gst_app_sink_init (GstAppSink * appsink, GstAppSinkClass * klass)
246 appsink->mutex = g_mutex_new ();
247 appsink->cond = g_cond_new ();
248 appsink->queue = g_queue_new ();
252 gst_app_sink_dispose (GObject * obj)
254 GstAppSink *appsink = GST_APP_SINK (obj);
257 //printf("appsinkdispose\n");
260 gst_caps_unref (appsink->caps);
261 appsink->caps = NULL;
263 if (appsink->preroll) {
264 gst_buffer_unref (appsink->preroll);
265 appsink->preroll = NULL;
267 g_mutex_lock (appsink->mutex);
268 while ((buffer = (GstBuffer*)g_queue_pop_head (appsink->queue)))
269 gst_buffer_unref (buffer);
270 g_mutex_unlock (appsink->mutex);
272 G_OBJECT_CLASS (parent_class)->dispose (obj);
276 gst_app_sink_finalize (GObject * obj)
278 GstAppSink *appsink = GST_APP_SINK (obj);
280 g_mutex_free (appsink->mutex);
281 g_cond_free (appsink->cond);
282 g_queue_free (appsink->queue);
284 G_OBJECT_CLASS (parent_class)->finalize (obj);
288 gst_app_sink_set_property (GObject * object, guint prop_id,
289 const GValue * value, GParamSpec * pspec)
291 GstAppSink *appsink = GST_APP_SINK (object);
293 //printf("appsinksetproperty\n");
297 gst_app_sink_set_caps (appsink, gst_value_get_caps (value));
300 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
306 gst_app_sink_get_property (GObject * object, guint prop_id, GValue * value,
309 GstAppSink *appsink = GST_APP_SINK (object);
311 //printf("appsinkgetproperty\n");
318 caps = gst_app_sink_get_caps (appsink);
319 gst_value_set_caps (value, caps);
321 gst_caps_unref (caps);
325 g_value_set_boolean (value, gst_app_sink_is_eos (appsink));
328 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
334 gst_app_sink_flush_unlocked (GstAppSink * appsink)
338 //printf("appsinkflushunlocked\n");
340 GST_DEBUG_OBJECT (appsink, "flushing appsink");
341 appsink->is_eos = FALSE;
342 gst_buffer_replace (&appsink->preroll, NULL);
343 while ((buffer = (GstBuffer*)g_queue_pop_head (appsink->queue)))
344 gst_buffer_unref (buffer);
345 g_cond_signal (appsink->cond);
349 gst_app_sink_start (GstBaseSink * psink)
351 GstAppSink *appsink = GST_APP_SINK (psink);
353 //printf("appsinkstart\n");
355 g_mutex_lock (appsink->mutex);
356 appsink->is_eos = FALSE;
357 appsink->started = TRUE;
358 GST_DEBUG_OBJECT (appsink, "starting");
359 g_mutex_unlock (appsink->mutex);
365 gst_app_sink_stop (GstBaseSink * psink)
367 GstAppSink *appsink = GST_APP_SINK (psink);
369 //printf("appsinkstop\n");
371 g_mutex_lock (appsink->mutex);
372 GST_DEBUG_OBJECT (appsink, "stopping");
373 appsink->started = FALSE;
374 gst_app_sink_flush_unlocked (appsink);
375 g_mutex_unlock (appsink->mutex);
381 gst_app_sink_event (GstBaseSink * sink, GstEvent * event)
383 GstAppSink *appsink = GST_APP_SINK (sink);
385 //printf("appsinkevent\n");
387 switch (event->type) {
389 g_mutex_lock (appsink->mutex);
390 GST_DEBUG_OBJECT (appsink, "receiving EOS");
391 appsink->is_eos = TRUE;
392 g_cond_signal (appsink->cond);
393 g_mutex_unlock (appsink->mutex);
395 case GST_EVENT_FLUSH_START:
397 case GST_EVENT_FLUSH_STOP:
398 g_mutex_lock (appsink->mutex);
399 GST_DEBUG_OBJECT (appsink, "received FLUSH_STOP");
400 gst_app_sink_flush_unlocked (appsink);
401 g_mutex_unlock (appsink->mutex);
410 gst_app_sink_preroll (GstBaseSink * psink, GstBuffer * buffer)
412 GstAppSink *appsink = GST_APP_SINK (psink);
414 //printf("appsinkpreroll\n");
416 g_mutex_lock (appsink->mutex);
417 GST_DEBUG_OBJECT (appsink, "setting preroll buffer %p", buffer);
418 gst_buffer_replace (&appsink->preroll, buffer);
419 g_cond_signal (appsink->cond);
420 g_mutex_unlock (appsink->mutex);
422 g_signal_emit(psink, gst_app_sink_signals[SIGNAL_NEW_PREROLL], 0, buffer);
428 gst_app_sink_render (GstBaseSink * psink, GstBuffer * buffer)
430 GstAppSink *appsink = GST_APP_SINK (psink);
432 g_mutex_lock (appsink->mutex);
433 GST_DEBUG_OBJECT (appsink, "pushing render buffer %p on queue", buffer);
434 g_queue_push_tail (appsink->queue, gst_buffer_ref (buffer));
435 g_cond_signal (appsink->cond);
436 // printf("appsinkrender, have %d buffers\n", g_queue_get_length(appsink->queue));
437 g_mutex_unlock (appsink->mutex);
438 g_signal_emit(psink, gst_app_sink_signals[SIGNAL_NEW_BUFFER], 0,
439 g_queue_get_length(appsink->queue));
445 gst_app_sink_getcaps (GstBaseSink * psink)
449 //printf("appsinkgetcaps\n");
451 GstAppSink *appsink = GST_APP_SINK (psink);
453 GST_OBJECT_LOCK (appsink);
454 if ((caps = appsink->caps))
456 GST_DEBUG_OBJECT (appsink, "got caps %" GST_PTR_FORMAT, caps);
457 GST_OBJECT_UNLOCK (appsink);
465 * gst_app_sink_set_caps:
466 * @appsink: a #GstAppSink
469 * Set the capabilities on the appsink element. This function takes
470 * a copy of the caps structure. After calling this method, the sink will only
471 * accept caps that match @caps. If @caps is non-fixed, you must check the caps
472 * on the buffers to get the actual used caps.
475 gst_app_sink_set_caps (GstAppSink * appsink, const GstCaps * caps)
479 g_return_if_fail (appsink != NULL);
480 g_return_if_fail (GST_IS_APP_SINK (appsink));
482 GST_OBJECT_LOCK (appsink);
483 GST_DEBUG_OBJECT (appsink, "setting caps to %" GST_PTR_FORMAT, caps);
486 appsink->caps = gst_caps_copy (caps);
488 appsink->caps = NULL;
490 gst_caps_unref (old);
491 GST_OBJECT_UNLOCK (appsink);
495 * gst_app_sink_get_caps:
496 * @appsink: a #GstAppSink
498 * Get the configured caps on @appsink.
500 * Returns: the #GstCaps accepted by the sink. gst_caps_unref() after usage.
503 gst_app_sink_get_caps (GstAppSink * appsink)
507 g_return_val_if_fail (appsink != NULL, NULL);
508 g_return_val_if_fail (GST_IS_APP_SINK (appsink), NULL);
510 GST_OBJECT_LOCK (appsink);
511 if ((caps = appsink->caps))
513 GST_DEBUG_OBJECT (appsink, "getting caps of %" GST_PTR_FORMAT, caps);
514 GST_OBJECT_UNLOCK (appsink);
520 * gst_app_sink_is_eos:
521 * @appsink: a #GstAppSink
523 * Check if @appsink is EOS, which is when no more buffers can be pulled because
524 * an EOS event was received.
526 * This function also returns %TRUE when the appsink is not in the PAUSED or
529 * Returns: %TRUE if no more buffers can be pulled and the appsink is EOS.
532 gst_app_sink_is_eos (GstAppSink * appsink)
536 g_return_val_if_fail (appsink != NULL, FALSE);
537 g_return_val_if_fail (GST_IS_APP_SINK (appsink), FALSE);
539 g_mutex_lock (appsink->mutex);
540 if (!appsink->started)
543 if (appsink->is_eos && g_queue_is_empty (appsink->queue)) {
544 GST_DEBUG_OBJECT (appsink, "we are EOS and the queue is empty");
547 GST_DEBUG_OBJECT (appsink, "we are not yet EOS");
550 g_mutex_unlock (appsink->mutex);
556 GST_DEBUG_OBJECT (appsink, "we are stopped, return TRUE");
557 g_mutex_unlock (appsink->mutex);
563 * gst_app_sink_pull_preroll:
564 * @appsink: a #GstAppSink
566 * Get the last preroll buffer in @appsink. This was the buffer that caused the
567 * appsink to preroll in the PAUSED state. This buffer can be pulled many times
568 * and remains available to the application even after EOS.
570 * This function is typically used when dealing with a pipeline in the PAUSED
571 * state. Calling this function after doing a seek will give the buffer right
572 * after the seek position.
574 * Note that the preroll buffer will also be returned as the first buffer
575 * when calling gst_app_sink_pull_buffer().
577 * If an EOS event was received before any buffers, this function returns
578 * %NULL. Use gst_app_sink_is_eos () to check for the EOS condition.
580 * This function blocks until a preroll buffer or EOS is received or the appsink
581 * element is set to the READY/NULL state.
583 * Returns: a #GstBuffer or NULL when the appsink is stopped or EOS.
586 gst_app_sink_pull_preroll (GstAppSink * appsink)
588 GstBuffer *buf = NULL;
590 //printf("pull_preroll\n");
592 g_return_val_if_fail (appsink != NULL, NULL);
593 g_return_val_if_fail (GST_IS_APP_SINK (appsink), NULL);
595 g_mutex_lock (appsink->mutex);
598 GST_DEBUG_OBJECT (appsink, "trying to grab a buffer");
599 if (!appsink->started)
602 if (appsink->preroll != NULL)
608 /* nothing to return, wait */
609 GST_DEBUG_OBJECT (appsink, "waiting for the preroll buffer");
610 g_cond_wait (appsink->cond, appsink->mutex);
612 buf = gst_buffer_ref (appsink->preroll);
613 GST_DEBUG_OBJECT (appsink, "we have the preroll buffer %p", buf);
614 g_mutex_unlock (appsink->mutex);
618 /* special conditions */
621 GST_DEBUG_OBJECT (appsink, "we are EOS, return NULL");
622 g_mutex_unlock (appsink->mutex);
627 GST_DEBUG_OBJECT (appsink, "we are stopped, return NULL");
628 g_mutex_unlock (appsink->mutex);
634 * gst_app_sink_pull_buffer:
635 * @appsink: a #GstAppSink
637 * This function blocks until a buffer or EOS becomes available or the appsink
638 * element is set to the READY/NULL state.
640 * This function will only return buffers when the appsink is in the PLAYING
641 * state. All rendered buffers will be put in a queue so that the application
642 * can pull buffers at its own rate. Note that when the application does not
643 * pull buffers fast enough, the queued buffers could consume a lot of memory,
644 * especially when dealing with raw video frames.
646 * If an EOS event was received before any buffers, this function returns
647 * %NULL. Use gst_app_sink_is_eos () to check for the EOS condition.
649 * Returns: a #GstBuffer or NULL when the appsink is stopped or EOS.
652 gst_app_sink_pull_buffer (GstAppSink * appsink)
654 GstBuffer *buf = NULL;
656 //printf("pull_buffer\n");
658 g_return_val_if_fail (appsink != NULL, NULL);
659 g_return_val_if_fail (GST_IS_APP_SINK (appsink), NULL);
661 g_mutex_lock (appsink->mutex);
664 GST_DEBUG_OBJECT (appsink, "trying to grab a buffer");
665 if (!appsink->started)
668 if (!g_queue_is_empty (appsink->queue))
674 /* nothing to return, wait */
675 GST_DEBUG_OBJECT (appsink, "waiting for a buffer");
676 g_cond_wait (appsink->cond, appsink->mutex);
678 buf = (GstBuffer*)g_queue_pop_head (appsink->queue);
679 GST_DEBUG_OBJECT (appsink, "we have a buffer %p", buf);
680 g_mutex_unlock (appsink->mutex);
684 /* special conditions */
687 GST_DEBUG_OBJECT (appsink, "we are EOS, return NULL");
688 g_mutex_unlock (appsink->mutex);
693 GST_DEBUG_OBJECT (appsink, "we are stopped, return NULL");
694 g_mutex_unlock (appsink->mutex);
700 * gst_app_sink_peek_buffer:
701 * @appsink: a #GstAppSink
703 * This function returns a buffer if there is one queued but does not block.
705 * This function will only return buffers when the appsink is in the PLAYING
706 * state. All rendered buffers will be put in a queue so that the application
707 * can pull buffers at its own rate. Note that when the application does not
708 * pull buffers fast enough, the queued buffers could consume a lot of memory,
709 * especially when dealing with raw video frames.
711 * If an EOS event was received before any buffers, this function returns
712 * %NULL. Use gst_app_sink_is_eos () to check for the EOS condition.
714 * Returns: a #GstBuffer or NULL when the appsink is stopped or EOS.
717 gst_app_sink_peek_buffer (GstAppSink * appsink)
719 GstBuffer *buf = NULL;
721 //printf("pull_buffer\n");
723 g_return_val_if_fail (appsink != NULL, NULL);
724 g_return_val_if_fail (GST_IS_APP_SINK (appsink), NULL);
726 g_mutex_lock (appsink->mutex);
728 GST_DEBUG_OBJECT (appsink, "trying to grab a buffer");
729 if (!appsink->started)
732 if (g_queue_is_empty (appsink->queue))
738 /* nothing to return, wait */
739 buf = (GstBuffer*)g_queue_pop_head (appsink->queue);
740 GST_DEBUG_OBJECT (appsink, "we have a buffer %p", buf);
741 g_mutex_unlock (appsink->mutex);
745 /* special conditions */
748 GST_DEBUG_OBJECT (appsink, "we are EOS, return NULL");
749 g_mutex_unlock (appsink->mutex);
754 GST_DEBUG_OBJECT (appsink, "we are stopped, return NULL");
755 g_mutex_unlock (appsink->mutex);
761 gst_app_sink_get_queue_length (GstAppSink * appsink)
763 return g_queue_get_length (appsink->queue);