/* GStreamer * Copyright (C) 2007 David Schleef * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include "gstappsink.h" GST_DEBUG_CATEGORY (app_sink_debug); #define GST_CAT_DEFAULT app_sink_debug static const GstElementDetails app_sink_details = GST_ELEMENT_DETAILS ("AppSink", "FIXME", "FIXME", "autogenerated by makefilter"); enum { PROP_0 }; static GstStaticPadTemplate gst_app_sink_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY); static void gst_app_sink_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_app_sink_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); static void gst_app_sink_dispose (GObject * object); static gboolean gst_app_sink_start (GstBaseSink * psink); static gboolean gst_app_sink_stop (GstBaseSink * psink); static gboolean gst_app_sink_event (GstBaseSink * sink, GstEvent * event); static GstFlowReturn gst_app_sink_render (GstBaseSink * psink, GstBuffer * buffer); GST_BOILERPLATE (GstAppSink, gst_app_sink, GstBaseSink, GST_TYPE_BASE_SINK); static void gst_app_sink_base_init (gpointer g_class) { GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); //GObjectClass *gobject_class = G_OBJECT_CLASS (g_class); GST_DEBUG_CATEGORY_INIT (app_sink_debug, "appsink", 0, "appsink element"); gst_element_class_set_details (element_class, &app_sink_details); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&gst_app_sink_template)); } static void gst_app_sink_class_init (GstAppSinkClass * klass) { GObjectClass *gobject_class = (GObjectClass *) klass; GstBaseSinkClass *basesink_class = (GstBaseSinkClass *) klass; gobject_class->set_property = gst_app_sink_set_property; gobject_class->get_property = gst_app_sink_get_property; gobject_class->dispose = gst_app_sink_dispose; basesink_class->start = gst_app_sink_start; basesink_class->stop = gst_app_sink_stop; basesink_class->event = gst_app_sink_event; basesink_class->render = gst_app_sink_render; } static void gst_app_sink_dispose (GObject * obj) { GstAppSink *appsink = GST_APP_SINK (obj); if (appsink->caps) { gst_caps_unref (appsink->caps); appsink->caps = NULL; } if (appsink->mutex) { g_mutex_free (appsink->mutex); appsink->mutex = NULL; } if (appsink->cond) { g_cond_free (appsink->cond); appsink->cond = NULL; } if (appsink->queue) { g_queue_free (appsink->queue); appsink->queue = NULL; } G_OBJECT_CLASS (parent_class)->dispose (obj); } static void gst_app_sink_init (GstAppSink * appsink, GstAppSinkClass * klass) { appsink->mutex = g_mutex_new (); appsink->cond = g_cond_new (); appsink->queue = g_queue_new (); } static void gst_app_sink_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstAppSink *appsink = GST_APP_SINK (object); GST_OBJECT_LOCK (appsink); switch (prop_id) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } GST_OBJECT_UNLOCK (appsink); } static void gst_app_sink_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstAppSink *appsink = GST_APP_SINK (object); GST_OBJECT_LOCK (appsink); switch (prop_id) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } GST_OBJECT_UNLOCK (appsink); } static gboolean gst_app_sink_start (GstBaseSink * psink) { GstAppSink *appsink = GST_APP_SINK (psink); appsink->end_of_stream = FALSE; return TRUE; } static gboolean gst_app_sink_stop (GstBaseSink * psink) { //GstAppSink *appsink = GST_APP_SINK(psink); return TRUE; } static gboolean gst_app_sink_event (GstBaseSink * sink, GstEvent * event) { GstAppSink *appsink = GST_APP_SINK (sink); switch (event->type) { case GST_EVENT_EOS: appsink->end_of_stream = TRUE; break; default: break; } gst_object_unref (sink); return FALSE; } static GstFlowReturn gst_app_sink_render (GstBaseSink * psink, GstBuffer * buffer) { GstAppSink *appsink = GST_APP_SINK (psink); g_mutex_lock (appsink->mutex); g_queue_push_tail (appsink->queue, gst_buffer_ref (buffer)); g_cond_signal (appsink->cond); g_mutex_unlock (appsink->mutex); return GST_FLOW_OK; } /* external API */ /** * gst_app_sink_set_caps: * @appsink: * @caps: * * Set the capabilities on the appsink element. This function takes * ownership of the caps structure. */ void gst_app_sink_set_caps (GstAppSink * appsink, GstCaps * caps) { g_return_if_fail (appsink != NULL); g_return_if_fail (GST_IS_APP_SINK (appsink)); gst_caps_replace (&appsink->caps, caps); } gboolean gst_app_sink_end_of_stream (GstAppSink * appsink) { gboolean ret; g_return_val_if_fail (appsink != NULL, FALSE); g_return_val_if_fail (GST_IS_APP_SINK (appsink), FALSE); g_mutex_lock (appsink->mutex); if (appsink->end_of_stream && g_queue_is_empty (appsink->queue)) { ret = TRUE; } else { ret = FALSE; } g_mutex_unlock (appsink->mutex); return ret; } GstBuffer * gst_app_sink_pull_buffer (GstAppSink * appsink) { GstBuffer *buf = NULL; g_return_val_if_fail (appsink != NULL, NULL); g_return_val_if_fail (GST_IS_APP_SINK (appsink), NULL); g_mutex_lock (appsink->mutex); while (g_queue_is_empty (appsink->queue)) { if (appsink->end_of_stream) goto out; g_cond_wait (appsink->cond, appsink->mutex); } buf = g_queue_pop_head (appsink->queue); out: g_mutex_unlock (appsink->mutex); return buf; }