mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-07 16:05:47 +00:00
Add sink base class to abstract locking and preroll.
Original commit message from CVS: * configure.ac: * docs/design/part-states.txt: * gst/Makefile.am: * gst/base/Makefile.am: * gst/base/gstbasesink.c: (gst_basesink_get_template), (gst_basesink_base_init), (gst_basesink_class_init), (gst_basesink_init), (gst_basesink_set_pad_functions), (gst_basesink_set_all_pad_functions), (gst_basesink_set_clock), (gst_basesink_set_property), (gst_basesink_get_property), (gst_base_sink_get_template), (gst_base_sink_get_caps), (gst_base_sink_set_caps), (gst_base_sink_alloc_buffer), (gst_basesink_finish_preroll), (gst_basesink_event), (gst_basesink_chain_unlocked), (gst_basesink_chain), (gst_basesink_loop), (gst_basesink_activate), (gst_basesink_change_state): * gst/base/gstbasesink.h: * gst/elements/Makefile.am: * gst/elements/gstfakesink.c: (gst_fakesink_base_init), (gst_fakesink_class_init), (gst_fakesink_init), (gst_fakesink_set_property), (gst_fakesink_get_property), (gst_fakesink_event), (gst_fakesink_preroll), (gst_fakesink_render), (gst_fakesink_change_state): * gst/elements/gstfakesink.h: * gst/gstelement.c: (gst_element_get_random_pad): * gst/gstevent.h: * gst/gstiterator.c: (gst_iterator_init), (gst_iterator_new), (gst_list_iterator_next), (gst_list_iterator_free), (gst_iterator_new_list), (gst_iterator_pop), (gst_iterator_next), (gst_iterator_push), (filter_next): * gst/gstmessage.h: * gst/gsttrashstack.h: Add sink base class to abstract locking and preroll. Make fakesink use the base class. Some doc fixes. Fix missing breaks.
This commit is contained in:
parent
7ba6b8b6b7
commit
ba3534f315
21 changed files with 1550 additions and 835 deletions
40
ChangeLog
40
ChangeLog
|
@ -1,3 +1,43 @@
|
|||
2005-02-23 Wim Taymans <wim@fluendo.com>
|
||||
|
||||
* configure.ac:
|
||||
* docs/design/part-states.txt:
|
||||
* gst/Makefile.am:
|
||||
* gst/base/Makefile.am:
|
||||
* gst/base/gstbasesink.c: (gst_basesink_get_template),
|
||||
(gst_basesink_base_init), (gst_basesink_class_init),
|
||||
(gst_basesink_init), (gst_basesink_set_pad_functions),
|
||||
(gst_basesink_set_all_pad_functions), (gst_basesink_set_clock),
|
||||
(gst_basesink_set_property), (gst_basesink_get_property),
|
||||
(gst_base_sink_get_template), (gst_base_sink_get_caps),
|
||||
(gst_base_sink_set_caps), (gst_base_sink_alloc_buffer),
|
||||
(gst_basesink_finish_preroll), (gst_basesink_event),
|
||||
(gst_basesink_chain_unlocked), (gst_basesink_chain),
|
||||
(gst_basesink_loop), (gst_basesink_activate),
|
||||
(gst_basesink_change_state):
|
||||
* gst/base/gstbasesink.h:
|
||||
* gst/elements/Makefile.am:
|
||||
* gst/elements/gstfakesink.c: (gst_fakesink_base_init),
|
||||
(gst_fakesink_class_init), (gst_fakesink_init),
|
||||
(gst_fakesink_set_property), (gst_fakesink_get_property),
|
||||
(gst_fakesink_event), (gst_fakesink_preroll),
|
||||
(gst_fakesink_render), (gst_fakesink_change_state):
|
||||
* gst/elements/gstfakesink.h:
|
||||
* gst/gstelement.c: (gst_element_get_random_pad):
|
||||
* gst/gstevent.h:
|
||||
* gst/gstiterator.c: (gst_iterator_init), (gst_iterator_new),
|
||||
(gst_list_iterator_next), (gst_list_iterator_free),
|
||||
(gst_iterator_new_list), (gst_iterator_pop), (gst_iterator_next),
|
||||
(gst_iterator_push), (filter_next):
|
||||
* gst/gstmessage.h:
|
||||
* gst/gsttrashstack.h:
|
||||
Add sink base class to abstract locking and preroll.
|
||||
Make fakesink use the base class.
|
||||
Some doc fixes.
|
||||
Fix missing breaks.
|
||||
|
||||
|
||||
|
||||
2005-02-22 Andy Wingo <wingo@pobox.com>
|
||||
|
||||
* gst/elements/gstidentity.h
|
||||
|
|
|
@ -661,6 +661,7 @@ include/Makefile
|
|||
gst/Makefile
|
||||
gst/gstconfig.h
|
||||
gst/gstversion.h
|
||||
gst/base/Makefile
|
||||
gst/indexers/Makefile
|
||||
gst/elements/Makefile
|
||||
gst/parse/Makefile
|
||||
|
|
|
@ -15,7 +15,7 @@ State definitions
|
|||
- NULL: This is the initial state of an element.
|
||||
- READY: The element should be prepared to go to PAUSED.
|
||||
- PAUSED: The element should be ready to accept and process data. Sink
|
||||
elements however only accept one sample and then block.
|
||||
elements however only accept one buffer and then block.
|
||||
- PLAYING: The same as PAUSED except for sinks, who are now accepting
|
||||
and rendering data.
|
||||
|
||||
|
@ -57,7 +57,7 @@ The _set_state() function can return 3 possible values:
|
|||
|
||||
GST_STATE_ASYNC: The state change will complete later on. This can happen
|
||||
When the element needs a long time to perform the state
|
||||
change or for sinks that need to receive the first sample
|
||||
change or for sinks that need to receive the first buffer
|
||||
before they can complete the state change (preroll).
|
||||
|
||||
In the case of an async state change, it is not possible to proceed to the next
|
||||
|
|
|
@ -62,8 +62,8 @@ else
|
|||
GST_URI_SRC = gsturi.c
|
||||
endif
|
||||
|
||||
SUBDIRS = $(GST_PARSE_DIRS) $(GST_REGISTRY_DIRS) . elements schedulers $(GST_INDEX_DIRS)
|
||||
DIST_SUBDIRS = elements parse registries schedulers indexers
|
||||
SUBDIRS = $(GST_PARSE_DIRS) $(GST_REGISTRY_DIRS) . base elements schedulers $(GST_INDEX_DIRS)
|
||||
DIST_SUBDIRS = base elements parse registries schedulers indexers
|
||||
|
||||
# make variables for all generated source and header files to make the
|
||||
# distinction clear
|
||||
|
|
23
gst/base/Makefile.am
Normal file
23
gst/base/Makefile.am
Normal file
|
@ -0,0 +1,23 @@
|
|||
lib_LTLIBRARIES = libgstbase.la
|
||||
AS_LIBTOOL_LIB = libgstbase
|
||||
|
||||
EXTRA_DIST = $(as_libtool_EXTRA_DIST)
|
||||
noinst_DATA = $(as_libtool_noinst_DATA_files)
|
||||
|
||||
libgstbase_la_DEPENDENCIES = ../libgstreamer-@GST_MAJORMINOR@.la
|
||||
libgstbase_la_SOURCES = \
|
||||
gstbasesink.c
|
||||
|
||||
libgstbase_la_CFLAGS = $(GST_OBJ_CFLAGS)
|
||||
libgstbase_la_LIBADD = $(GST_OBJ_LIBS)
|
||||
libgstbase_la_LDFLAGS = $(as_libtool_LDFLAGS)
|
||||
|
||||
noinst_HEADERS =
|
||||
gstbasesink.h
|
||||
|
||||
install-data-local: as-libtool-install-data-local
|
||||
|
||||
uninstall-local: as-libtool-uninstall-local
|
||||
|
||||
include $(top_srcdir)/common/as-libtool.mak
|
||||
|
550
gst/base/gstbasesink.c
Normal file
550
gst/base/gstbasesink.c
Normal file
|
@ -0,0 +1,550 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* gstbasesink.c:
|
||||
*
|
||||
* 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 "gstbasesink.h"
|
||||
#include <gst/gstmarshal.h>
|
||||
|
||||
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_basesink_debug);
|
||||
#define GST_CAT_DEFAULT gst_basesink_debug
|
||||
|
||||
/* BaseSink signals and args */
|
||||
enum
|
||||
{
|
||||
/* FILL ME */
|
||||
SIGNAL_HANDOFF,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
#define DEFAULT_SIZE 1024
|
||||
#define DEFAULT_HAS_LOOP FALSE
|
||||
#define DEFAULT_HAS_CHAIN TRUE
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0,
|
||||
ARG_HAS_LOOP,
|
||||
ARG_HAS_CHAIN
|
||||
};
|
||||
|
||||
#define _do_init(bla) \
|
||||
GST_DEBUG_CATEGORY_INIT (gst_basesink_debug, "basesink", 0, "basesink element");
|
||||
|
||||
GST_BOILERPLATE_FULL (GstBaseSink, gst_basesink, GstElement, GST_TYPE_ELEMENT,
|
||||
_do_init);
|
||||
|
||||
static void gst_basesink_set_clock (GstElement * element, GstClock * clock);
|
||||
|
||||
static void gst_basesink_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_basesink_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
static GstStaticPadTemplate *gst_base_sink_get_template (GstBaseSink * sink);
|
||||
static GstCaps *gst_base_sink_get_caps (GstBaseSink * sink);
|
||||
static gboolean gst_base_sink_set_caps (GstBaseSink * sink, GstCaps * caps);
|
||||
static GstBuffer *gst_base_sink_alloc_buffer (GstBaseSink * sink,
|
||||
guint64 offset, guint size, GstCaps * caps);
|
||||
|
||||
static GstElementStateReturn gst_basesink_change_state (GstElement * element);
|
||||
|
||||
static GstFlowReturn gst_basesink_chain_unlocked (GstPad * pad,
|
||||
GstBuffer * buffer);
|
||||
static void gst_basesink_loop (GstPad * pad);
|
||||
static GstFlowReturn gst_basesink_chain (GstPad * pad, GstBuffer * buffer);
|
||||
static gboolean gst_basesink_activate (GstPad * pad, GstActivateMode mode);
|
||||
static gboolean gst_basesink_event (GstPad * pad, GstEvent * event);
|
||||
|
||||
static GstStaticPadTemplate *
|
||||
gst_basesink_get_template (GstBaseSink * bsink)
|
||||
{
|
||||
GstStaticPadTemplate *template = NULL;
|
||||
GstBaseSinkClass *bclass;
|
||||
|
||||
bclass = GST_BASESINK_GET_CLASS (bsink);
|
||||
|
||||
if (bclass->get_template)
|
||||
template = bclass->get_template (bsink);
|
||||
|
||||
if (template == NULL) {
|
||||
template = &sinktemplate;
|
||||
}
|
||||
return template;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_basesink_base_init (gpointer g_class)
|
||||
{
|
||||
//GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
|
||||
|
||||
/*
|
||||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&sinktemplate));
|
||||
*/
|
||||
}
|
||||
|
||||
static void
|
||||
gst_basesink_class_init (GstBaseSinkClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
|
||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_basesink_set_property);
|
||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_basesink_get_property);
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HAS_LOOP,
|
||||
g_param_spec_boolean ("has-loop", "has-loop",
|
||||
"Enable loop-based operation", DEFAULT_HAS_LOOP,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HAS_CHAIN,
|
||||
g_param_spec_boolean ("has-chain", "has-chain",
|
||||
"Enable chain-based operation", DEFAULT_HAS_CHAIN,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||
|
||||
gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_basesink_set_clock);
|
||||
gstelement_class->change_state =
|
||||
GST_DEBUG_FUNCPTR (gst_basesink_change_state);
|
||||
|
||||
klass->get_caps = GST_DEBUG_FUNCPTR (gst_base_sink_get_caps);
|
||||
klass->set_caps = GST_DEBUG_FUNCPTR (gst_base_sink_set_caps);
|
||||
klass->get_template = GST_DEBUG_FUNCPTR (gst_base_sink_get_template);
|
||||
klass->alloc_buffer = GST_DEBUG_FUNCPTR (gst_base_sink_alloc_buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_basesink_init (GstBaseSink * basesink)
|
||||
{
|
||||
GstStaticPadTemplate *template;
|
||||
|
||||
template = gst_basesink_get_template (basesink);
|
||||
|
||||
basesink->sinkpad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get (template),
|
||||
"sink");
|
||||
gst_element_add_pad (GST_ELEMENT (basesink), basesink->sinkpad);
|
||||
|
||||
basesink->pad_mode = GST_ACTIVATE_NONE;
|
||||
GST_RPAD_TASK (basesink->sinkpad) = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_basesink_set_pad_functions (GstBaseSink * this, GstPad * pad)
|
||||
{
|
||||
gst_pad_set_activate_function (pad,
|
||||
GST_DEBUG_FUNCPTR (gst_basesink_activate));
|
||||
gst_pad_set_event_function (pad, GST_DEBUG_FUNCPTR (gst_basesink_event));
|
||||
|
||||
if (this->has_chain)
|
||||
gst_pad_set_chain_function (pad, GST_DEBUG_FUNCPTR (gst_basesink_chain));
|
||||
else
|
||||
gst_pad_set_chain_function (pad, NULL);
|
||||
|
||||
if (this->has_loop)
|
||||
gst_pad_set_loop_function (pad, GST_DEBUG_FUNCPTR (gst_basesink_loop));
|
||||
else
|
||||
gst_pad_set_loop_function (pad, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_basesink_set_all_pad_functions (GstBaseSink * this)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = GST_ELEMENT_PADS (this); l; l = l->next)
|
||||
gst_basesink_set_pad_functions (this, (GstPad *) l->data);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_basesink_set_clock (GstElement * element, GstClock * clock)
|
||||
{
|
||||
GstBaseSink *sink;
|
||||
|
||||
sink = GST_BASESINK (element);
|
||||
|
||||
sink->clock = clock;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_basesink_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstBaseSink *sink;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
sink = GST_BASESINK (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_HAS_LOOP:
|
||||
sink->has_loop = g_value_get_boolean (value);
|
||||
gst_basesink_set_all_pad_functions (sink);
|
||||
break;
|
||||
case ARG_HAS_CHAIN:
|
||||
sink->has_chain = g_value_get_boolean (value);
|
||||
gst_basesink_set_all_pad_functions (sink);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_basesink_get_property (GObject * object, guint prop_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstBaseSink *sink;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_BASESINK (object));
|
||||
|
||||
sink = GST_BASESINK (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_HAS_LOOP:
|
||||
g_value_set_boolean (value, sink->has_loop);
|
||||
break;
|
||||
case ARG_HAS_CHAIN:
|
||||
g_value_set_boolean (value, sink->has_chain);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static GstStaticPadTemplate *
|
||||
gst_base_sink_get_template (GstBaseSink * sink)
|
||||
{
|
||||
return &sinktemplate;
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
gst_base_sink_get_caps (GstBaseSink * sink)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_base_sink_set_caps (GstBaseSink * sink, GstCaps * caps)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GstBuffer *
|
||||
gst_base_sink_alloc_buffer (GstBaseSink * sink, guint64 offset, guint size,
|
||||
GstCaps * caps)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* STREAM_LOCK should be held */
|
||||
GstFlowReturn
|
||||
gst_basesink_finish_preroll (GstBaseSink * basesink, GstPad * pad,
|
||||
GstBuffer * buffer)
|
||||
{
|
||||
gboolean usable;
|
||||
GstBaseSinkClass *bclass;
|
||||
|
||||
/* lock order is important */
|
||||
GST_STATE_LOCK (basesink);
|
||||
GST_PREROLL_LOCK (pad);
|
||||
if (!basesink->need_preroll)
|
||||
goto no_preroll;
|
||||
|
||||
bclass = GST_BASESINK_GET_CLASS (basesink);
|
||||
|
||||
if (bclass->preroll)
|
||||
bclass->preroll (basesink, buffer);
|
||||
|
||||
basesink->need_preroll = FALSE;
|
||||
basesink->have_preroll = TRUE;
|
||||
gst_element_commit_state (GST_ELEMENT (basesink));
|
||||
GST_STATE_UNLOCK (basesink);
|
||||
|
||||
GST_DEBUG ("element %s waiting to finish preroll",
|
||||
GST_ELEMENT_NAME (basesink));
|
||||
GST_PREROLL_WAIT (pad);
|
||||
GST_DEBUG ("done preroll");
|
||||
|
||||
GST_LOCK (pad);
|
||||
usable = !GST_RPAD_IS_FLUSHING (pad) && GST_RPAD_IS_ACTIVE (pad);
|
||||
GST_UNLOCK (pad);
|
||||
if (!usable)
|
||||
goto unusable;
|
||||
|
||||
GST_DEBUG ("done preroll");
|
||||
basesink->have_preroll = FALSE;
|
||||
|
||||
GST_PREROLL_UNLOCK (pad);
|
||||
return GST_FLOW_OK;
|
||||
|
||||
no_preroll:
|
||||
{
|
||||
GST_PREROLL_UNLOCK (pad);
|
||||
GST_STATE_UNLOCK (basesink);
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
unusable:
|
||||
{
|
||||
GST_DEBUG ("pad is flushing");
|
||||
GST_PREROLL_UNLOCK (pad);
|
||||
return GST_FLOW_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
gst_basesink_event (GstPad * pad, GstEvent * event)
|
||||
{
|
||||
GstBaseSink *basesink;
|
||||
gboolean result = TRUE;
|
||||
GstBaseSinkClass *bclass;
|
||||
|
||||
basesink = GST_BASESINK (GST_OBJECT_PARENT (pad));
|
||||
|
||||
GST_STREAM_LOCK (pad);
|
||||
|
||||
bclass = GST_BASESINK_GET_CLASS (basesink);
|
||||
|
||||
if (bclass->event)
|
||||
bclass->event (basesink, event);
|
||||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_EOS:
|
||||
{
|
||||
GstFlowReturn ret;
|
||||
|
||||
ret = gst_basesink_finish_preroll (basesink, pad, NULL);
|
||||
if (ret == GST_FLOW_OK) {
|
||||
basesink->eos = TRUE;
|
||||
/* ok, we can post the message */
|
||||
gst_element_post_message (GST_ELEMENT (basesink),
|
||||
gst_message_new_eos (GST_OBJECT (basesink)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GST_EVENT_DISCONTINUOUS:
|
||||
if (basesink->sync && basesink->clock) {
|
||||
//gint64 value = GST_EVENT_DISCONT_OFFSET (event, 0).value;
|
||||
}
|
||||
default:
|
||||
result = gst_pad_event_default (pad, event);
|
||||
break;
|
||||
}
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_basesink_chain_unlocked (GstPad * pad, GstBuffer * buf)
|
||||
{
|
||||
GstBaseSink *basesink;
|
||||
GstFlowReturn result = GST_FLOW_OK;
|
||||
GstBaseSinkClass *bclass;
|
||||
|
||||
basesink = GST_BASESINK (GST_OBJECT_PARENT (pad));
|
||||
|
||||
result = gst_basesink_finish_preroll (basesink, pad, buf);
|
||||
if (result != GST_FLOW_OK)
|
||||
goto exit;
|
||||
|
||||
/* doClock
|
||||
if (basesink->sync && basesink->clock) {
|
||||
gst_element_wait (GST_ELEMENT (basesink), GST_BUFFER_TIMESTAMP (buf));
|
||||
}
|
||||
*/
|
||||
|
||||
bclass = GST_BASESINK_GET_CLASS (basesink);
|
||||
if (bclass->render)
|
||||
bclass->render (basesink, buf);
|
||||
|
||||
exit:
|
||||
gst_buffer_unref (buf);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_basesink_chain (GstPad * pad, GstBuffer * buf)
|
||||
{
|
||||
GstFlowReturn result;
|
||||
|
||||
g_assert (GST_BASESINK (GST_OBJECT_PARENT (pad))->pad_mode ==
|
||||
GST_ACTIVATE_PUSH);
|
||||
|
||||
GST_STREAM_LOCK (pad);
|
||||
|
||||
result = gst_basesink_chain_unlocked (pad, buf);
|
||||
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_basesink_loop (GstPad * pad)
|
||||
{
|
||||
GstBaseSink *basesink;
|
||||
GstBuffer *buf = NULL;
|
||||
GstFlowReturn result;
|
||||
|
||||
basesink = GST_BASESINK (GST_OBJECT_PARENT (pad));
|
||||
|
||||
g_assert (basesink->pad_mode == GST_ACTIVATE_PULL);
|
||||
|
||||
GST_STREAM_LOCK (pad);
|
||||
|
||||
result = gst_pad_pull_range (pad, basesink->offset, DEFAULT_SIZE, &buf);
|
||||
if (result != GST_FLOW_OK)
|
||||
goto paused;
|
||||
|
||||
result = gst_basesink_chain_unlocked (pad, buf);
|
||||
if (result != GST_FLOW_OK)
|
||||
goto paused;
|
||||
|
||||
exit:
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
return;
|
||||
|
||||
paused:
|
||||
gst_task_pause (GST_RPAD_TASK (pad));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_basesink_activate (GstPad * pad, GstActivateMode mode)
|
||||
{
|
||||
gboolean result = FALSE;
|
||||
GstBaseSink *basesink;
|
||||
|
||||
basesink = GST_BASESINK (GST_OBJECT_PARENT (pad));
|
||||
|
||||
switch (mode) {
|
||||
case GST_ACTIVATE_PUSH:
|
||||
g_return_val_if_fail (basesink->has_chain, FALSE);
|
||||
result = TRUE;
|
||||
break;
|
||||
case GST_ACTIVATE_PULL:
|
||||
/* if we have a scheduler we can start the task */
|
||||
g_return_val_if_fail (basesink->has_loop, FALSE);
|
||||
if (GST_ELEMENT_SCHEDULER (basesink)) {
|
||||
GST_STREAM_LOCK (pad);
|
||||
GST_RPAD_TASK (pad) =
|
||||
gst_scheduler_create_task (GST_ELEMENT_SCHEDULER (basesink),
|
||||
(GstTaskFunction) gst_basesink_loop, pad);
|
||||
|
||||
gst_task_start (GST_RPAD_TASK (pad));
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
result = TRUE;
|
||||
}
|
||||
break;
|
||||
case GST_ACTIVATE_NONE:
|
||||
/* step 1, unblock clock sync (if any) or any other blocking thing */
|
||||
|
||||
/* unlock preroll */
|
||||
GST_PREROLL_LOCK (pad);
|
||||
GST_PREROLL_SIGNAL (pad);
|
||||
GST_PREROLL_UNLOCK (pad);
|
||||
|
||||
/* step 2, make sure streaming finishes */
|
||||
GST_STREAM_LOCK (pad);
|
||||
/* step 3, stop the task */
|
||||
if (GST_RPAD_TASK (pad)) {
|
||||
gst_task_stop (GST_RPAD_TASK (pad));
|
||||
gst_object_unref (GST_OBJECT (GST_RPAD_TASK (pad)));
|
||||
GST_RPAD_TASK (pad) = NULL;
|
||||
}
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
|
||||
result = TRUE;
|
||||
break;
|
||||
}
|
||||
basesink->pad_mode = mode;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
gst_basesink_change_state (GstElement * element)
|
||||
{
|
||||
GstElementStateReturn ret = GST_STATE_SUCCESS;
|
||||
GstBaseSink *basesink = GST_BASESINK (element);
|
||||
GstElementState transition = GST_STATE_TRANSITION (element);
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_NULL_TO_READY:
|
||||
break;
|
||||
case GST_STATE_READY_TO_PAUSED:
|
||||
/* need to complete preroll before this state change completes, there
|
||||
* is no data flow in READY so we cqn safely assume we need to preroll. */
|
||||
basesink->offset = 0;
|
||||
GST_PREROLL_LOCK (basesink->sinkpad);
|
||||
basesink->need_preroll = TRUE;
|
||||
basesink->have_preroll = FALSE;
|
||||
GST_PREROLL_UNLOCK (basesink->sinkpad);
|
||||
ret = GST_STATE_ASYNC;
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
/* the state change completes when we are blocking on a preroll
|
||||
* sample */
|
||||
GST_PREROLL_LOCK (basesink->sinkpad);
|
||||
if (!basesink->have_preroll) {
|
||||
basesink->need_preroll = TRUE;
|
||||
ret = GST_STATE_ASYNC;
|
||||
} else {
|
||||
/* now let it play */
|
||||
GST_PREROLL_SIGNAL (basesink->sinkpad);
|
||||
}
|
||||
GST_PREROLL_UNLOCK (basesink->sinkpad);
|
||||
break;
|
||||
case GST_STATE_PLAYING_TO_PAUSED:
|
||||
GST_PREROLL_LOCK (basesink->sinkpad);
|
||||
basesink->need_preroll = TRUE;
|
||||
/* if we don't have a preroll buffer and we have not received EOS,
|
||||
* we need to wait for a preroll */
|
||||
if (!basesink->have_preroll && !basesink->eos) {
|
||||
ret = GST_STATE_ASYNC;
|
||||
}
|
||||
GST_PREROLL_UNLOCK (basesink->sinkpad);
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_READY:
|
||||
break;
|
||||
case GST_STATE_READY_TO_NULL:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||
return ret;
|
||||
}
|
79
gst/base/gstbasesink.h
Normal file
79
gst/base/gstbasesink.h
Normal file
|
@ -0,0 +1,79 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstbasesink.h:
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __GST_BASESINK_H__
|
||||
#define __GST_BASESINK_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
#define GST_TYPE_BASESINK (gst_basesink_get_type())
|
||||
#define GST_BASESINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_BASESINK,GstBaseSink))
|
||||
#define GST_BASESINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_BASESINK,GstBaseSinkClass))
|
||||
#define GST_BASESINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_BASESINK, GstBaseSinkClass))
|
||||
#define GST_IS_BASESINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASESINK))
|
||||
#define GST_IS_BASESINK_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASESINK))
|
||||
|
||||
typedef struct _GstBaseSink GstBaseSink;
|
||||
typedef struct _GstBaseSinkClass GstBaseSinkClass;
|
||||
|
||||
struct _GstBaseSink {
|
||||
GstElement element;
|
||||
|
||||
GstPad *sinkpad;
|
||||
GstActivateMode pad_mode;
|
||||
|
||||
guint64 offset;
|
||||
gboolean has_loop;
|
||||
gboolean has_chain;
|
||||
|
||||
gboolean sync;
|
||||
GstClock *clock;
|
||||
|
||||
gboolean eos;
|
||||
gboolean need_preroll;
|
||||
gboolean have_preroll;
|
||||
};
|
||||
|
||||
struct _GstBaseSinkClass {
|
||||
GstElementClass parent_class;
|
||||
|
||||
GstStaticPadTemplate* (*get_template) (GstBaseSink *sink);
|
||||
|
||||
GstCaps* (*get_caps) (GstBaseSink *sink);
|
||||
gboolean (*set_caps) (GstBaseSink *sink, GstCaps *caps);
|
||||
|
||||
GstBuffer* (*alloc_buffer) (GstBaseSink *sink, guint64 offset, guint size,
|
||||
GstCaps *caps);
|
||||
|
||||
void (*event) (GstBaseSink *sink, GstEvent *event);
|
||||
GstFlowReturn (*preroll) (GstBaseSink *sink, GstBuffer *buffer);
|
||||
GstFlowReturn (*render) (GstBaseSink *sink, GstBuffer *buffer);
|
||||
};
|
||||
|
||||
GType gst_basesink_get_type(void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_BASESINK_H__ */
|
|
@ -45,7 +45,7 @@ libgstelements_la_SOURCES = \
|
|||
|
||||
libgstelements_la_CFLAGS = $(GST_OBJ_CFLAGS)
|
||||
libgstelements_la_LIBADD = $(GST_OBJ_LIBS)
|
||||
libgstelements_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(as_libtool_LDFLAGS)
|
||||
libgstelements_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(as_libtool_LDFLAGS) $(top_builddir)/gst/base/libgstbase.la
|
||||
|
||||
noinst_HEADERS = \
|
||||
gstaggregator.h \
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
* 2005 Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* gstfakesink.c:
|
||||
*
|
||||
|
@ -36,12 +36,12 @@ static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
|
|||
GST_DEBUG_CATEGORY_STATIC (gst_fakesink_debug);
|
||||
#define GST_CAT_DEFAULT gst_fakesink_debug
|
||||
|
||||
#define DEFAULT_SIZE 1024
|
||||
|
||||
GstElementDetails gst_fakesink_details = GST_ELEMENT_DETAILS ("Fake Sink",
|
||||
"Sink",
|
||||
"Black hole for data",
|
||||
"Erik Walthinsen <omega@cse.ogi.edu>, Tim Waymans <tway@fluendo.com>");
|
||||
"Erik Walthinsen <omega@cse.ogi.edu>, "
|
||||
"Wim Taymans <wim@fluendo.com>, "
|
||||
"Mr. 'frag-me-more' Vanderwingo <wingo@fluendo.com>");
|
||||
|
||||
|
||||
/* FakeSink signals and args */
|
||||
|
@ -52,25 +52,24 @@ enum
|
|||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
#define DEFAULT_STATE_ERROR FAKESINK_STATE_ERROR_NONE
|
||||
#define DEFAULT_SILENT FALSE
|
||||
#define DEFAULT_DUMP FALSE
|
||||
#define DEFAULT_SYNC FALSE
|
||||
#define DEFAULT_SIGNAL_HANDOFFS FALSE
|
||||
#define DEFAULT_LAST_MESSAGE NULL
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0,
|
||||
ARG_STATE_ERROR,
|
||||
ARG_NUM_SINKS,
|
||||
ARG_SILENT,
|
||||
ARG_DUMP,
|
||||
ARG_SYNC,
|
||||
ARG_SIGNAL_HANDOFFS,
|
||||
ARG_LAST_MESSAGE,
|
||||
ARG_HAS_LOOP,
|
||||
ARG_HAS_CHAIN
|
||||
};
|
||||
|
||||
GstStaticPadTemplate fakesink_sink_template = GST_STATIC_PAD_TEMPLATE ("sink%d",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_REQUEST,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
#define GST_TYPE_FAKESINK_STATE_ERROR (gst_fakesink_state_error_get_type())
|
||||
static GType
|
||||
gst_fakesink_state_error_get_type (void)
|
||||
|
@ -103,13 +102,9 @@ gst_fakesink_state_error_get_type (void)
|
|||
#define _do_init(bla) \
|
||||
GST_DEBUG_CATEGORY_INIT (gst_fakesink_debug, "fakesink", 0, "fakesink element");
|
||||
|
||||
GST_BOILERPLATE_FULL (GstFakeSink, gst_fakesink, GstElement, GST_TYPE_ELEMENT,
|
||||
GST_BOILERPLATE_FULL (GstFakeSink, gst_fakesink, GstBaseSink, GST_TYPE_BASESINK,
|
||||
_do_init);
|
||||
|
||||
static void gst_fakesink_set_clock (GstElement * element, GstClock * clock);
|
||||
static GstPad *gst_fakesink_request_new_pad (GstElement * element,
|
||||
GstPadTemplate * templ, const gchar * unused);
|
||||
|
||||
static void gst_fakesink_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_fakesink_get_property (GObject * object, guint prop_id,
|
||||
|
@ -117,12 +112,11 @@ static void gst_fakesink_get_property (GObject * object, guint prop_id,
|
|||
|
||||
static GstElementStateReturn gst_fakesink_change_state (GstElement * element);
|
||||
|
||||
static GstFlowReturn gst_fakesink_chain_unlocked (GstPad * pad,
|
||||
static GstFlowReturn gst_fakesink_preroll (GstBaseSink * bsink,
|
||||
GstBuffer * buffer);
|
||||
static void gst_fakesink_loop (GstPad * pad);
|
||||
static GstFlowReturn gst_fakesink_chain (GstPad * pad, GstBuffer * buffer);
|
||||
static gboolean gst_fakesink_activate (GstPad * pad, GstActivateMode mode);
|
||||
static gboolean gst_fakesink_event (GstPad * pad, GstEvent * event);
|
||||
static GstFlowReturn gst_fakesink_render (GstBaseSink * bsink,
|
||||
GstBuffer * buffer);
|
||||
static void gst_fakesink_event (GstBaseSink * bsink, GstEvent * event);
|
||||
|
||||
static guint gst_fakesink_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
|
@ -134,8 +128,6 @@ gst_fakesink_base_init (gpointer g_class)
|
|||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&sinktemplate));
|
||||
gst_element_class_set_details (gstelement_class, &gst_fakesink_details);
|
||||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&fakesink_sink_template));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -143,44 +135,37 @@ gst_fakesink_class_init (GstFakeSinkClass * klass)
|
|||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
GstBaseSinkClass *gstbasesink_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
gstbasesink_class = (GstBaseSinkClass *) klass;
|
||||
|
||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fakesink_set_property);
|
||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fakesink_get_property);
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_SINKS,
|
||||
g_param_spec_int ("num_sinks", "Number of sinks",
|
||||
"The number of sinkpads", 1, G_MAXINT, 1, G_PARAM_READABLE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_STATE_ERROR,
|
||||
g_param_spec_enum ("state_error", "State Error",
|
||||
"Generate a state change error", GST_TYPE_FAKESINK_STATE_ERROR,
|
||||
FAKESINK_STATE_ERROR_NONE, G_PARAM_READWRITE));
|
||||
DEFAULT_STATE_ERROR, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
|
||||
g_param_spec_string ("last_message", "Last Message",
|
||||
"The message describing current status", NULL, G_PARAM_READABLE));
|
||||
"The message describing current status", DEFAULT_LAST_MESSAGE,
|
||||
G_PARAM_READABLE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SYNC,
|
||||
g_param_spec_boolean ("sync", "Sync", "Sync on the clock", FALSE,
|
||||
g_param_spec_boolean ("sync", "Sync", "Sync on the clock", DEFAULT_SYNC,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIGNAL_HANDOFFS,
|
||||
g_param_spec_boolean ("signal-handoffs", "Signal handoffs",
|
||||
"Send a signal before unreffing the buffer", FALSE,
|
||||
"Send a signal before unreffing the buffer", DEFAULT_SIGNAL_HANDOFFS,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
|
||||
g_param_spec_boolean ("silent", "Silent",
|
||||
"Don't produce last_message events", FALSE, G_PARAM_READWRITE));
|
||||
"Don't produce last_message events", DEFAULT_SILENT,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DUMP,
|
||||
g_param_spec_boolean ("dump", "Dump", "Dump received bytes to stdout",
|
||||
FALSE, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HAS_LOOP,
|
||||
g_param_spec_boolean ("has-loop", "has-loop",
|
||||
"Enable loop-based operation", TRUE,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HAS_CHAIN,
|
||||
g_param_spec_boolean ("has-chain", "has-chain",
|
||||
"Enable chain-based operation", TRUE,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||
DEFAULT_DUMP, G_PARAM_READWRITE));
|
||||
|
||||
gst_fakesink_signals[SIGNAL_HANDOFF] =
|
||||
g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
|
||||
|
@ -188,93 +173,23 @@ gst_fakesink_class_init (GstFakeSinkClass * klass)
|
|||
gst_marshal_VOID__BOXED_OBJECT, G_TYPE_NONE, 2,
|
||||
GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, GST_TYPE_PAD);
|
||||
|
||||
gstelement_class->request_new_pad =
|
||||
GST_DEBUG_FUNCPTR (gst_fakesink_request_new_pad);
|
||||
gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_fakesink_set_clock);
|
||||
gstelement_class->change_state =
|
||||
GST_DEBUG_FUNCPTR (gst_fakesink_change_state);
|
||||
|
||||
gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_fakesink_event);
|
||||
gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_fakesink_preroll);
|
||||
gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_fakesink_render);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fakesink_init (GstFakeSink * fakesink)
|
||||
{
|
||||
fakesink->sinkpad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
|
||||
"sink");
|
||||
gst_element_add_pad (GST_ELEMENT (fakesink), fakesink->sinkpad);
|
||||
|
||||
fakesink->silent = FALSE;
|
||||
fakesink->dump = FALSE;
|
||||
fakesink->sync = FALSE;
|
||||
fakesink->last_message = NULL;
|
||||
fakesink->state_error = FAKESINK_STATE_ERROR_NONE;
|
||||
fakesink->signal_handoffs = FALSE;
|
||||
fakesink->pad_mode = GST_ACTIVATE_NONE;
|
||||
GST_RPAD_TASK (fakesink->sinkpad) = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fakesink_set_pad_functions (GstFakeSink * this, GstPad * pad)
|
||||
{
|
||||
gst_pad_set_activate_function (pad,
|
||||
GST_DEBUG_FUNCPTR (gst_fakesink_activate));
|
||||
gst_pad_set_event_function (pad, GST_DEBUG_FUNCPTR (gst_fakesink_event));
|
||||
|
||||
if (this->has_chain)
|
||||
gst_pad_set_chain_function (pad, GST_DEBUG_FUNCPTR (gst_fakesink_chain));
|
||||
else
|
||||
gst_pad_set_chain_function (pad, NULL);
|
||||
|
||||
if (this->has_loop)
|
||||
gst_pad_set_loop_function (pad, GST_DEBUG_FUNCPTR (gst_fakesink_loop));
|
||||
else
|
||||
gst_pad_set_loop_function (pad, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fakesink_set_all_pad_functions (GstFakeSink * this)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = GST_ELEMENT_PADS (this); l; l = l->next)
|
||||
gst_fakesink_set_pad_functions (this, (GstPad *) l->data);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fakesink_set_clock (GstElement * element, GstClock * clock)
|
||||
{
|
||||
GstFakeSink *sink;
|
||||
|
||||
sink = GST_FAKESINK (element);
|
||||
|
||||
sink->clock = clock;
|
||||
}
|
||||
|
||||
static GstPad *
|
||||
gst_fakesink_request_new_pad (GstElement * element, GstPadTemplate * templ,
|
||||
const gchar * unused)
|
||||
{
|
||||
gchar *name;
|
||||
GstPad *sinkpad;
|
||||
GstFakeSink *fakesink;
|
||||
|
||||
g_return_val_if_fail (GST_IS_FAKESINK (element), NULL);
|
||||
|
||||
if (templ->direction != GST_PAD_SINK) {
|
||||
g_warning ("gstfakesink: request new pad that is not a SINK pad\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fakesink = GST_FAKESINK (element);
|
||||
|
||||
name = g_strdup_printf ("sink%d", GST_ELEMENT (fakesink)->numsinkpads);
|
||||
|
||||
sinkpad = gst_pad_new_from_template (templ, name);
|
||||
g_free (name);
|
||||
gst_fakesink_set_pad_functions (fakesink, sinkpad);
|
||||
gst_element_add_pad (GST_ELEMENT (fakesink), sinkpad);
|
||||
|
||||
return sinkpad;
|
||||
fakesink->silent = DEFAULT_SILENT;
|
||||
fakesink->dump = DEFAULT_DUMP;
|
||||
fakesink->sync = DEFAULT_SYNC;
|
||||
fakesink->last_message = DEFAULT_LAST_MESSAGE;
|
||||
fakesink->state_error = DEFAULT_STATE_ERROR;
|
||||
fakesink->signal_handoffs = DEFAULT_SIGNAL_HANDOFFS;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -283,18 +198,9 @@ gst_fakesink_set_property (GObject * object, guint prop_id,
|
|||
{
|
||||
GstFakeSink *sink;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
sink = GST_FAKESINK (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_HAS_LOOP:
|
||||
sink->has_loop = g_value_get_boolean (value);
|
||||
gst_fakesink_set_all_pad_functions (sink);
|
||||
break;
|
||||
case ARG_HAS_CHAIN:
|
||||
sink->has_chain = g_value_get_boolean (value);
|
||||
gst_fakesink_set_all_pad_functions (sink);
|
||||
break;
|
||||
case ARG_SILENT:
|
||||
sink->silent = g_value_get_boolean (value);
|
||||
break;
|
||||
|
@ -322,24 +228,12 @@ gst_fakesink_get_property (GObject * object, guint prop_id, GValue * value,
|
|||
{
|
||||
GstFakeSink *sink;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_FAKESINK (object));
|
||||
|
||||
sink = GST_FAKESINK (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_NUM_SINKS:
|
||||
g_value_set_int (value, GST_ELEMENT (sink)->numsinkpads);
|
||||
break;
|
||||
case ARG_STATE_ERROR:
|
||||
g_value_set_enum (value, sink->state_error);
|
||||
break;
|
||||
case ARG_HAS_LOOP:
|
||||
g_value_set_boolean (value, sink->has_loop);
|
||||
break;
|
||||
case ARG_HAS_CHAIN:
|
||||
g_value_set_boolean (value, sink->has_chain);
|
||||
break;
|
||||
case ARG_SILENT:
|
||||
g_value_set_boolean (value, sink->silent);
|
||||
break;
|
||||
|
@ -361,256 +255,65 @@ gst_fakesink_get_property (GObject * object, guint prop_id, GValue * value,
|
|||
}
|
||||
}
|
||||
|
||||
/* STREAM_LOCK should be held */
|
||||
GstFlowReturn
|
||||
gst_fakesink_finish_preroll (GstFakeSink * fakesink, GstPad * pad)
|
||||
static void
|
||||
gst_fakesink_event (GstBaseSink * bsink, GstEvent * event)
|
||||
{
|
||||
/* lock order is important */
|
||||
GST_STATE_LOCK (fakesink);
|
||||
GST_PREROLL_LOCK (pad);
|
||||
if (!fakesink->need_preroll)
|
||||
goto no_preroll;
|
||||
GstFakeSink *sink = GST_FAKESINK (bsink);
|
||||
|
||||
if (!fakesink->silent) {
|
||||
g_free (fakesink->last_message);
|
||||
if (!sink->silent) {
|
||||
g_free (sink->last_message);
|
||||
|
||||
fakesink->last_message =
|
||||
g_strdup_printf ("preroll ******* (%s:%s)", GST_DEBUG_PAD_NAME (pad));
|
||||
sink->last_message =
|
||||
g_strdup_printf ("chain ******* E (type: %d) %p",
|
||||
GST_EVENT_TYPE (event), event);
|
||||
|
||||
g_object_notify (G_OBJECT (fakesink), "last_message");
|
||||
g_object_notify (G_OBJECT (sink), "last_message");
|
||||
}
|
||||
|
||||
fakesink->need_preroll = FALSE;
|
||||
fakesink->have_preroll = TRUE;
|
||||
gst_element_commit_state (GST_ELEMENT (fakesink));
|
||||
GST_STATE_UNLOCK (fakesink);
|
||||
|
||||
{
|
||||
gboolean usable;
|
||||
|
||||
GST_DEBUG ("element %s waiting to finish preroll",
|
||||
GST_ELEMENT_NAME (fakesink));
|
||||
GST_PREROLL_WAIT (pad);
|
||||
GST_DEBUG ("done preroll");
|
||||
|
||||
GST_LOCK (pad);
|
||||
usable = !GST_RPAD_IS_FLUSHING (pad) && GST_RPAD_IS_ACTIVE (pad);
|
||||
GST_UNLOCK (pad);
|
||||
if (!usable)
|
||||
goto unusable;
|
||||
|
||||
GST_DEBUG ("done preroll");
|
||||
}
|
||||
fakesink->have_preroll = FALSE;
|
||||
|
||||
GST_PREROLL_UNLOCK (pad);
|
||||
return GST_FLOW_OK;
|
||||
|
||||
no_preroll:
|
||||
{
|
||||
GST_PREROLL_UNLOCK (pad);
|
||||
GST_STATE_UNLOCK (fakesink);
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
unusable:
|
||||
{
|
||||
GST_DEBUG ("pad is flushing");
|
||||
GST_PREROLL_UNLOCK (pad);
|
||||
return GST_FLOW_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
gst_fakesink_event (GstPad * pad, GstEvent * event)
|
||||
{
|
||||
GstFakeSink *fakesink;
|
||||
gboolean result = TRUE;
|
||||
|
||||
fakesink = GST_FAKESINK (GST_OBJECT_PARENT (pad));
|
||||
|
||||
GST_STREAM_LOCK (pad);
|
||||
|
||||
if (!fakesink->silent) {
|
||||
g_free (fakesink->last_message);
|
||||
|
||||
fakesink->last_message =
|
||||
g_strdup_printf ("chain ******* (%s:%s)E (type: %d) %p",
|
||||
GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE (event), event);
|
||||
|
||||
g_object_notify (G_OBJECT (fakesink), "last_message");
|
||||
}
|
||||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_EOS:
|
||||
{
|
||||
GstFlowReturn ret;
|
||||
|
||||
ret = gst_fakesink_finish_preroll (fakesink, pad);
|
||||
if (ret == GST_FLOW_OK) {
|
||||
fakesink->eos = TRUE;
|
||||
/* ok, we can post the message */
|
||||
gst_element_post_message (GST_ELEMENT (fakesink),
|
||||
gst_message_new_eos (GST_OBJECT (fakesink)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GST_EVENT_DISCONTINUOUS:
|
||||
if (fakesink->sync && fakesink->clock) {
|
||||
//gint64 value = GST_EVENT_DISCONT_OFFSET (event, 0).value;
|
||||
}
|
||||
default:
|
||||
result = gst_pad_event_default (pad, event);
|
||||
break;
|
||||
}
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_fakesink_chain_unlocked (GstPad * pad, GstBuffer * buf)
|
||||
gst_fakesink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
|
||||
{
|
||||
GstFakeSink *fakesink;
|
||||
GstFlowReturn result = GST_FLOW_OK;
|
||||
GstFakeSink *sink = GST_FAKESINK (bsink);
|
||||
|
||||
fakesink = GST_FAKESINK (GST_OBJECT_PARENT (pad));
|
||||
if (!sink->silent) {
|
||||
g_free (sink->last_message);
|
||||
|
||||
result = gst_fakesink_finish_preroll (fakesink, pad);
|
||||
if (result != GST_FLOW_OK)
|
||||
goto exit;
|
||||
sink->last_message = g_strdup_printf ("preroll ******* ");
|
||||
|
||||
if (fakesink->sync && fakesink->clock) {
|
||||
gst_element_wait (GST_ELEMENT (fakesink), GST_BUFFER_TIMESTAMP (buf));
|
||||
g_object_notify (G_OBJECT (sink), "last_message");
|
||||
}
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
if (!fakesink->silent) {
|
||||
g_free (fakesink->last_message);
|
||||
static GstFlowReturn
|
||||
gst_fakesink_render (GstBaseSink * bsink, GstBuffer * buf)
|
||||
{
|
||||
GstFakeSink *sink = GST_FAKESINK (bsink);
|
||||
|
||||
fakesink->last_message =
|
||||
g_strdup_printf ("chain ******* (%s:%s)< (%d bytes, timestamp: %"
|
||||
if (!sink->silent) {
|
||||
g_free (sink->last_message);
|
||||
|
||||
sink->last_message =
|
||||
g_strdup_printf ("chain ******* < (%d bytes, timestamp: %"
|
||||
GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %"
|
||||
G_GINT64_FORMAT ", offset_end: %" G_GINT64_FORMAT ", flags: %d) %p",
|
||||
GST_DEBUG_PAD_NAME (pad), GST_BUFFER_SIZE (buf),
|
||||
GST_BUFFER_SIZE (buf),
|
||||
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
|
||||
GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf),
|
||||
GST_BUFFER_OFFSET_END (buf), GST_BUFFER_FLAGS (buf), buf);
|
||||
|
||||
g_object_notify (G_OBJECT (fakesink), "last_message");
|
||||
g_object_notify (G_OBJECT (sink), "last_message");
|
||||
}
|
||||
if (sink->signal_handoffs)
|
||||
g_signal_emit (G_OBJECT (sink), gst_fakesink_signals[SIGNAL_HANDOFF], 0,
|
||||
buf);
|
||||
|
||||
if (fakesink->signal_handoffs)
|
||||
g_signal_emit (G_OBJECT (fakesink), gst_fakesink_signals[SIGNAL_HANDOFF], 0,
|
||||
buf, pad);
|
||||
|
||||
if (fakesink->dump) {
|
||||
if (sink->dump) {
|
||||
gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
|
||||
}
|
||||
|
||||
exit:
|
||||
gst_buffer_unref (buf);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_fakesink_chain (GstPad * pad, GstBuffer * buf)
|
||||
{
|
||||
GstFlowReturn result;
|
||||
|
||||
g_assert (GST_FAKESINK (GST_OBJECT_PARENT (pad))->pad_mode ==
|
||||
GST_ACTIVATE_PUSH);
|
||||
|
||||
GST_STREAM_LOCK (pad);
|
||||
|
||||
result = gst_fakesink_chain_unlocked (pad, buf);
|
||||
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fakesink_loop (GstPad * pad)
|
||||
{
|
||||
GstFakeSink *fakesink;
|
||||
GstBuffer *buf = NULL;
|
||||
GstFlowReturn result;
|
||||
|
||||
fakesink = GST_FAKESINK (GST_OBJECT_PARENT (pad));
|
||||
|
||||
g_assert (fakesink->pad_mode == GST_ACTIVATE_PULL);
|
||||
|
||||
GST_STREAM_LOCK (pad);
|
||||
|
||||
result = gst_pad_pull_range (pad, fakesink->offset, DEFAULT_SIZE, &buf);
|
||||
if (result != GST_FLOW_OK)
|
||||
goto paused;
|
||||
|
||||
result = gst_fakesink_chain_unlocked (pad, buf);
|
||||
if (result != GST_FLOW_OK)
|
||||
goto paused;
|
||||
|
||||
exit:
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
return;
|
||||
|
||||
paused:
|
||||
gst_task_pause (GST_RPAD_TASK (pad));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_fakesink_activate (GstPad * pad, GstActivateMode mode)
|
||||
{
|
||||
gboolean result = FALSE;
|
||||
GstFakeSink *fakesink;
|
||||
|
||||
fakesink = GST_FAKESINK (GST_OBJECT_PARENT (pad));
|
||||
|
||||
switch (mode) {
|
||||
case GST_ACTIVATE_PUSH:
|
||||
g_return_val_if_fail (fakesink->has_chain, FALSE);
|
||||
result = TRUE;
|
||||
break;
|
||||
case GST_ACTIVATE_PULL:
|
||||
/* if we have a scheduler we can start the task */
|
||||
g_return_val_if_fail (fakesink->has_loop, FALSE);
|
||||
if (GST_ELEMENT_SCHEDULER (fakesink)) {
|
||||
GST_STREAM_LOCK (pad);
|
||||
GST_RPAD_TASK (pad) =
|
||||
gst_scheduler_create_task (GST_ELEMENT_SCHEDULER (fakesink),
|
||||
(GstTaskFunction) gst_fakesink_loop, pad);
|
||||
|
||||
gst_task_start (GST_RPAD_TASK (pad));
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
result = TRUE;
|
||||
}
|
||||
break;
|
||||
case GST_ACTIVATE_NONE:
|
||||
/* step 1, unblock clock sync (if any) or any other blocking thing */
|
||||
|
||||
/* unlock preroll */
|
||||
GST_PREROLL_LOCK (pad);
|
||||
GST_PREROLL_SIGNAL (pad);
|
||||
GST_PREROLL_UNLOCK (pad);
|
||||
|
||||
/* step 2, make sure streaming finishes */
|
||||
GST_STREAM_LOCK (pad);
|
||||
/* step 3, stop the task */
|
||||
if (GST_RPAD_TASK (pad)) {
|
||||
gst_task_stop (GST_RPAD_TASK (pad));
|
||||
gst_object_unref (GST_OBJECT (GST_RPAD_TASK (pad)));
|
||||
GST_RPAD_TASK (pad) = NULL;
|
||||
}
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
|
||||
result = TRUE;
|
||||
break;
|
||||
}
|
||||
fakesink->pad_mode = mode;
|
||||
|
||||
return result;
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
|
@ -628,42 +331,14 @@ gst_fakesink_change_state (GstElement * element)
|
|||
case GST_STATE_READY_TO_PAUSED:
|
||||
if (fakesink->state_error == FAKESINK_STATE_ERROR_READY_PAUSED)
|
||||
goto error;
|
||||
/* need to complete preroll before this state change completes, there
|
||||
* is no data flow in READY so we cqn safely assume we need to preroll. */
|
||||
fakesink->offset = 0;
|
||||
GST_PREROLL_LOCK (fakesink->sinkpad);
|
||||
fakesink->need_preroll = TRUE;
|
||||
fakesink->have_preroll = FALSE;
|
||||
GST_PREROLL_UNLOCK (fakesink->sinkpad);
|
||||
ret = GST_STATE_ASYNC;
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
if (fakesink->state_error == FAKESINK_STATE_ERROR_PAUSED_PLAYING)
|
||||
goto error;
|
||||
/* the state change completes when we are blocking on a preroll
|
||||
* sample */
|
||||
GST_PREROLL_LOCK (fakesink->sinkpad);
|
||||
if (!fakesink->have_preroll) {
|
||||
fakesink->need_preroll = TRUE;
|
||||
ret = GST_STATE_ASYNC;
|
||||
} else {
|
||||
/* now let it play */
|
||||
GST_PREROLL_SIGNAL (fakesink->sinkpad);
|
||||
}
|
||||
GST_PREROLL_UNLOCK (fakesink->sinkpad);
|
||||
break;
|
||||
case GST_STATE_PLAYING_TO_PAUSED:
|
||||
if (fakesink->state_error == FAKESINK_STATE_ERROR_PLAYING_PAUSED)
|
||||
goto error;
|
||||
|
||||
GST_PREROLL_LOCK (fakesink->sinkpad);
|
||||
fakesink->need_preroll = TRUE;
|
||||
/* if we don't have a preroll buffer and we have not received EOS,
|
||||
* we need to wait for a preroll */
|
||||
if (!fakesink->have_preroll && !fakesink->eos) {
|
||||
ret = GST_STATE_ASYNC;
|
||||
}
|
||||
GST_PREROLL_UNLOCK (fakesink->sinkpad);
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_READY:
|
||||
if (fakesink->state_error == FAKESINK_STATE_ERROR_PAUSED_READY)
|
||||
|
@ -679,7 +354,7 @@ gst_fakesink_change_state (GstElement * element)
|
|||
break;
|
||||
}
|
||||
|
||||
GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#define __GST_FAKESINK_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/base/gstbasesink.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
@ -54,29 +55,18 @@ typedef struct _GstFakeSink GstFakeSink;
|
|||
typedef struct _GstFakeSinkClass GstFakeSinkClass;
|
||||
|
||||
struct _GstFakeSink {
|
||||
GstElement element;
|
||||
|
||||
GstPad *sinkpad;
|
||||
GstBaseSink element;
|
||||
|
||||
gboolean silent;
|
||||
gboolean dump;
|
||||
gboolean has_loop;
|
||||
gboolean has_chain;
|
||||
gboolean sync;
|
||||
gboolean signal_handoffs;
|
||||
GstClock *clock;
|
||||
GstFakeSinkStateError state_error;
|
||||
GstActivateMode pad_mode;
|
||||
guint64 offset;
|
||||
gboolean eos;
|
||||
gboolean need_preroll;
|
||||
gboolean have_preroll;
|
||||
|
||||
gchar *last_message;
|
||||
};
|
||||
|
||||
struct _GstFakeSinkClass {
|
||||
GstElementClass parent_class;
|
||||
GstBaseSinkClass parent_class;
|
||||
|
||||
/* signals */
|
||||
void (*handoff) (GstElement *element, GstBuffer *buf, GstPad *pad);
|
||||
|
|
|
@ -978,8 +978,10 @@ gst_element_get_random_pad (GstElement * element, GstPadDirection dir)
|
|||
switch (dir) {
|
||||
case GST_PAD_SRC:
|
||||
pads = element->srcpads;
|
||||
break;
|
||||
case GST_PAD_SINK:
|
||||
pads = element->sinkpads;
|
||||
break;
|
||||
default:
|
||||
g_warning ("unknown pad direction");
|
||||
return NULL;
|
||||
|
|
|
@ -34,6 +34,19 @@ G_BEGIN_DECLS
|
|||
|
||||
GST_EXPORT GType _gst_event_type;
|
||||
|
||||
/**
|
||||
* GstBufferFlag:
|
||||
* @GST_EVENT_UNKNOWN:
|
||||
* @GST_EVENT_EOS:
|
||||
* @GST_EVENT_FLUSH:
|
||||
* @GST_EVENT_DISCONTINUOUS:
|
||||
* @GST_EVENT_QOS:
|
||||
* @GST_EVENT_SEEK:
|
||||
* @GST_EVENT_SIZE:
|
||||
* @GST_EVENT_RATE:
|
||||
* @GST_EVENT_NAVIGATION:
|
||||
* @GST_EVENT_TAG:
|
||||
*/
|
||||
typedef enum {
|
||||
GST_EVENT_UNKNOWN = 0,
|
||||
GST_EVENT_EOS = 1,
|
||||
|
|
|
@ -318,7 +318,7 @@ typedef struct _GstIteratorFilter
|
|||
static GstIteratorResult
|
||||
filter_next (GstIteratorFilter * it, gpointer * elem)
|
||||
{
|
||||
GstIteratorResult result;
|
||||
GstIteratorResult result = GST_ITERATOR_ERROR;
|
||||
gboolean done = FALSE;
|
||||
|
||||
*elem = NULL;
|
||||
|
|
|
@ -28,20 +28,42 @@
|
|||
#include <gst/gsttag.h>
|
||||
#include <gst/gststructure.h>
|
||||
|
||||
G_BEGIN_DECLS GST_EXPORT GType _gst_message_type;
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GST_EXPORT GType _gst_message_type;
|
||||
|
||||
/**
|
||||
* GstMessageType:
|
||||
* @GST_MESSAGE_UNKNOWN: an undefined message
|
||||
* @GST_MESSAGE_EOS: end-of-stream reached in a pipeline
|
||||
* @GST_MESSAGE_ERROR: an error occured
|
||||
* @GST_MESSAGE_WARNING: a warning occured.
|
||||
* @GST_MESSAGE_INFO: an info message occured
|
||||
* @GST_MESSAGE_TAG: a tag was found.
|
||||
* @GST_MESSAGE_BUFFERING: the pipeline is buffering
|
||||
* @GST_MESSAGE_STATE_CHANGED: a state change happened
|
||||
* @GST_MESSAGE_STEP_DONE: a framestep finished.
|
||||
* @GST_MESSAGE_NEW_CLOCK: a new clock was selected in the pipeline
|
||||
* @GST_MESSAGE_STRUCTURE_CHANGE: the structure of the pipeline changed.
|
||||
* @GST_MESSAGE_STREAM_STATUS: status about a stream, emited when it starts,
|
||||
* stops, errors, etc..
|
||||
* @GST_MESSAGE_ANY: mask for all of the above messages.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
GST_MESSAGE_UNKNOWN = 0,
|
||||
GST_MESSAGE_EOS = (1 << 0),
|
||||
GST_MESSAGE_ERROR = (1 << 1),
|
||||
GST_MESSAGE_WARNING = (1 << 2),
|
||||
GST_MESSAGE_INFO = (1 << 3),
|
||||
GST_MESSAGE_TAG = (1 << 4),
|
||||
GST_MESSAGE_BUFFERING = (1 << 5),
|
||||
GST_MESSAGE_STATE_CHANGED = (1 << 6),
|
||||
GST_MESSAGE_STEP_DONE = (1 << 7),
|
||||
GST_MESSAGE_ANY = 0xffffffff
|
||||
GST_MESSAGE_UNKNOWN = 0,
|
||||
GST_MESSAGE_EOS = (1 << 0),
|
||||
GST_MESSAGE_ERROR = (1 << 1),
|
||||
GST_MESSAGE_WARNING = (1 << 2),
|
||||
GST_MESSAGE_INFO = (1 << 3),
|
||||
GST_MESSAGE_TAG = (1 << 4),
|
||||
GST_MESSAGE_BUFFERING = (1 << 5),
|
||||
GST_MESSAGE_STATE_CHANGED = (1 << 6),
|
||||
GST_MESSAGE_STEP_DONE = (1 << 7),
|
||||
GST_MESSAGE_NEW_CLOCK = (1 << 8),
|
||||
GST_MESSAGE_STRUCTURE_CHANGE = (1 << 9),
|
||||
GST_MESSAGE_STREAM_STATUS = (1 << 10),
|
||||
GST_MESSAGE_ANY = 0xffffffff
|
||||
} GstMessageType;
|
||||
|
||||
#define GST_MESSAGE_TRACE_NAME "GstMessage"
|
||||
|
@ -50,6 +72,9 @@ typedef enum
|
|||
#define GST_MESSAGE(message) ((GstMessage*)(message))
|
||||
#define GST_IS_MESSAGE(message) (GST_DATA_TYPE(message) == GST_TYPE_MESSAGE)
|
||||
|
||||
/* the lock is used to handle the synchronous handling of messages,
|
||||
* the emiting thread is block until the handling thread processed
|
||||
* the message using this mutex/cond pair */
|
||||
#define GST_MESSAGE_GET_LOCK(message) (GST_MESSAGE(message)->lock)
|
||||
#define GST_MESSAGE_LOCK(message) g_mutex_lock(GST_MESSAGE_GET_LOCK(message))
|
||||
#define GST_MESSAGE_UNLOCK(message) g_mutex_unlock(GST_MESSAGE_GET_LOCK(message))
|
||||
|
|
|
@ -98,7 +98,7 @@ gst_trash_stack_pop (GstTrashStack *stack)
|
|||
* problem that arises when a pop and push of the same element happens
|
||||
* right between when we read head->next and try to swing the new pointer
|
||||
* into place. This is usually solved using a counter which makes it highly
|
||||
* inlikely that we manage to grab the wrong head->next value.
|
||||
* unlikely that we manage to grab the wrong head->next value.
|
||||
*/
|
||||
__asm__ __volatile__ (
|
||||
" pushl %%ebx; \n\t"
|
||||
|
|
23
libs/gst/base/Makefile.am
Normal file
23
libs/gst/base/Makefile.am
Normal file
|
@ -0,0 +1,23 @@
|
|||
lib_LTLIBRARIES = libgstbase.la
|
||||
AS_LIBTOOL_LIB = libgstbase
|
||||
|
||||
EXTRA_DIST = $(as_libtool_EXTRA_DIST)
|
||||
noinst_DATA = $(as_libtool_noinst_DATA_files)
|
||||
|
||||
libgstbase_la_DEPENDENCIES = ../libgstreamer-@GST_MAJORMINOR@.la
|
||||
libgstbase_la_SOURCES = \
|
||||
gstbasesink.c
|
||||
|
||||
libgstbase_la_CFLAGS = $(GST_OBJ_CFLAGS)
|
||||
libgstbase_la_LIBADD = $(GST_OBJ_LIBS)
|
||||
libgstbase_la_LDFLAGS = $(as_libtool_LDFLAGS)
|
||||
|
||||
noinst_HEADERS =
|
||||
gstbasesink.h
|
||||
|
||||
install-data-local: as-libtool-install-data-local
|
||||
|
||||
uninstall-local: as-libtool-uninstall-local
|
||||
|
||||
include $(top_srcdir)/common/as-libtool.mak
|
||||
|
550
libs/gst/base/gstbasesink.c
Normal file
550
libs/gst/base/gstbasesink.c
Normal file
|
@ -0,0 +1,550 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* gstbasesink.c:
|
||||
*
|
||||
* 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 "gstbasesink.h"
|
||||
#include <gst/gstmarshal.h>
|
||||
|
||||
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_basesink_debug);
|
||||
#define GST_CAT_DEFAULT gst_basesink_debug
|
||||
|
||||
/* BaseSink signals and args */
|
||||
enum
|
||||
{
|
||||
/* FILL ME */
|
||||
SIGNAL_HANDOFF,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
#define DEFAULT_SIZE 1024
|
||||
#define DEFAULT_HAS_LOOP FALSE
|
||||
#define DEFAULT_HAS_CHAIN TRUE
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0,
|
||||
ARG_HAS_LOOP,
|
||||
ARG_HAS_CHAIN
|
||||
};
|
||||
|
||||
#define _do_init(bla) \
|
||||
GST_DEBUG_CATEGORY_INIT (gst_basesink_debug, "basesink", 0, "basesink element");
|
||||
|
||||
GST_BOILERPLATE_FULL (GstBaseSink, gst_basesink, GstElement, GST_TYPE_ELEMENT,
|
||||
_do_init);
|
||||
|
||||
static void gst_basesink_set_clock (GstElement * element, GstClock * clock);
|
||||
|
||||
static void gst_basesink_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_basesink_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
static GstStaticPadTemplate *gst_base_sink_get_template (GstBaseSink * sink);
|
||||
static GstCaps *gst_base_sink_get_caps (GstBaseSink * sink);
|
||||
static gboolean gst_base_sink_set_caps (GstBaseSink * sink, GstCaps * caps);
|
||||
static GstBuffer *gst_base_sink_alloc_buffer (GstBaseSink * sink,
|
||||
guint64 offset, guint size, GstCaps * caps);
|
||||
|
||||
static GstElementStateReturn gst_basesink_change_state (GstElement * element);
|
||||
|
||||
static GstFlowReturn gst_basesink_chain_unlocked (GstPad * pad,
|
||||
GstBuffer * buffer);
|
||||
static void gst_basesink_loop (GstPad * pad);
|
||||
static GstFlowReturn gst_basesink_chain (GstPad * pad, GstBuffer * buffer);
|
||||
static gboolean gst_basesink_activate (GstPad * pad, GstActivateMode mode);
|
||||
static gboolean gst_basesink_event (GstPad * pad, GstEvent * event);
|
||||
|
||||
static GstStaticPadTemplate *
|
||||
gst_basesink_get_template (GstBaseSink * bsink)
|
||||
{
|
||||
GstStaticPadTemplate *template = NULL;
|
||||
GstBaseSinkClass *bclass;
|
||||
|
||||
bclass = GST_BASESINK_GET_CLASS (bsink);
|
||||
|
||||
if (bclass->get_template)
|
||||
template = bclass->get_template (bsink);
|
||||
|
||||
if (template == NULL) {
|
||||
template = &sinktemplate;
|
||||
}
|
||||
return template;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_basesink_base_init (gpointer g_class)
|
||||
{
|
||||
//GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
|
||||
|
||||
/*
|
||||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&sinktemplate));
|
||||
*/
|
||||
}
|
||||
|
||||
static void
|
||||
gst_basesink_class_init (GstBaseSinkClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
|
||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_basesink_set_property);
|
||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_basesink_get_property);
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HAS_LOOP,
|
||||
g_param_spec_boolean ("has-loop", "has-loop",
|
||||
"Enable loop-based operation", DEFAULT_HAS_LOOP,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HAS_CHAIN,
|
||||
g_param_spec_boolean ("has-chain", "has-chain",
|
||||
"Enable chain-based operation", DEFAULT_HAS_CHAIN,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||
|
||||
gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_basesink_set_clock);
|
||||
gstelement_class->change_state =
|
||||
GST_DEBUG_FUNCPTR (gst_basesink_change_state);
|
||||
|
||||
klass->get_caps = GST_DEBUG_FUNCPTR (gst_base_sink_get_caps);
|
||||
klass->set_caps = GST_DEBUG_FUNCPTR (gst_base_sink_set_caps);
|
||||
klass->get_template = GST_DEBUG_FUNCPTR (gst_base_sink_get_template);
|
||||
klass->alloc_buffer = GST_DEBUG_FUNCPTR (gst_base_sink_alloc_buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_basesink_init (GstBaseSink * basesink)
|
||||
{
|
||||
GstStaticPadTemplate *template;
|
||||
|
||||
template = gst_basesink_get_template (basesink);
|
||||
|
||||
basesink->sinkpad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get (template),
|
||||
"sink");
|
||||
gst_element_add_pad (GST_ELEMENT (basesink), basesink->sinkpad);
|
||||
|
||||
basesink->pad_mode = GST_ACTIVATE_NONE;
|
||||
GST_RPAD_TASK (basesink->sinkpad) = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_basesink_set_pad_functions (GstBaseSink * this, GstPad * pad)
|
||||
{
|
||||
gst_pad_set_activate_function (pad,
|
||||
GST_DEBUG_FUNCPTR (gst_basesink_activate));
|
||||
gst_pad_set_event_function (pad, GST_DEBUG_FUNCPTR (gst_basesink_event));
|
||||
|
||||
if (this->has_chain)
|
||||
gst_pad_set_chain_function (pad, GST_DEBUG_FUNCPTR (gst_basesink_chain));
|
||||
else
|
||||
gst_pad_set_chain_function (pad, NULL);
|
||||
|
||||
if (this->has_loop)
|
||||
gst_pad_set_loop_function (pad, GST_DEBUG_FUNCPTR (gst_basesink_loop));
|
||||
else
|
||||
gst_pad_set_loop_function (pad, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_basesink_set_all_pad_functions (GstBaseSink * this)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = GST_ELEMENT_PADS (this); l; l = l->next)
|
||||
gst_basesink_set_pad_functions (this, (GstPad *) l->data);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_basesink_set_clock (GstElement * element, GstClock * clock)
|
||||
{
|
||||
GstBaseSink *sink;
|
||||
|
||||
sink = GST_BASESINK (element);
|
||||
|
||||
sink->clock = clock;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_basesink_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstBaseSink *sink;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
sink = GST_BASESINK (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_HAS_LOOP:
|
||||
sink->has_loop = g_value_get_boolean (value);
|
||||
gst_basesink_set_all_pad_functions (sink);
|
||||
break;
|
||||
case ARG_HAS_CHAIN:
|
||||
sink->has_chain = g_value_get_boolean (value);
|
||||
gst_basesink_set_all_pad_functions (sink);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_basesink_get_property (GObject * object, guint prop_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstBaseSink *sink;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_BASESINK (object));
|
||||
|
||||
sink = GST_BASESINK (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_HAS_LOOP:
|
||||
g_value_set_boolean (value, sink->has_loop);
|
||||
break;
|
||||
case ARG_HAS_CHAIN:
|
||||
g_value_set_boolean (value, sink->has_chain);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static GstStaticPadTemplate *
|
||||
gst_base_sink_get_template (GstBaseSink * sink)
|
||||
{
|
||||
return &sinktemplate;
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
gst_base_sink_get_caps (GstBaseSink * sink)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_base_sink_set_caps (GstBaseSink * sink, GstCaps * caps)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GstBuffer *
|
||||
gst_base_sink_alloc_buffer (GstBaseSink * sink, guint64 offset, guint size,
|
||||
GstCaps * caps)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* STREAM_LOCK should be held */
|
||||
GstFlowReturn
|
||||
gst_basesink_finish_preroll (GstBaseSink * basesink, GstPad * pad,
|
||||
GstBuffer * buffer)
|
||||
{
|
||||
gboolean usable;
|
||||
GstBaseSinkClass *bclass;
|
||||
|
||||
/* lock order is important */
|
||||
GST_STATE_LOCK (basesink);
|
||||
GST_PREROLL_LOCK (pad);
|
||||
if (!basesink->need_preroll)
|
||||
goto no_preroll;
|
||||
|
||||
bclass = GST_BASESINK_GET_CLASS (basesink);
|
||||
|
||||
if (bclass->preroll)
|
||||
bclass->preroll (basesink, buffer);
|
||||
|
||||
basesink->need_preroll = FALSE;
|
||||
basesink->have_preroll = TRUE;
|
||||
gst_element_commit_state (GST_ELEMENT (basesink));
|
||||
GST_STATE_UNLOCK (basesink);
|
||||
|
||||
GST_DEBUG ("element %s waiting to finish preroll",
|
||||
GST_ELEMENT_NAME (basesink));
|
||||
GST_PREROLL_WAIT (pad);
|
||||
GST_DEBUG ("done preroll");
|
||||
|
||||
GST_LOCK (pad);
|
||||
usable = !GST_RPAD_IS_FLUSHING (pad) && GST_RPAD_IS_ACTIVE (pad);
|
||||
GST_UNLOCK (pad);
|
||||
if (!usable)
|
||||
goto unusable;
|
||||
|
||||
GST_DEBUG ("done preroll");
|
||||
basesink->have_preroll = FALSE;
|
||||
|
||||
GST_PREROLL_UNLOCK (pad);
|
||||
return GST_FLOW_OK;
|
||||
|
||||
no_preroll:
|
||||
{
|
||||
GST_PREROLL_UNLOCK (pad);
|
||||
GST_STATE_UNLOCK (basesink);
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
unusable:
|
||||
{
|
||||
GST_DEBUG ("pad is flushing");
|
||||
GST_PREROLL_UNLOCK (pad);
|
||||
return GST_FLOW_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
gst_basesink_event (GstPad * pad, GstEvent * event)
|
||||
{
|
||||
GstBaseSink *basesink;
|
||||
gboolean result = TRUE;
|
||||
GstBaseSinkClass *bclass;
|
||||
|
||||
basesink = GST_BASESINK (GST_OBJECT_PARENT (pad));
|
||||
|
||||
GST_STREAM_LOCK (pad);
|
||||
|
||||
bclass = GST_BASESINK_GET_CLASS (basesink);
|
||||
|
||||
if (bclass->event)
|
||||
bclass->event (basesink, event);
|
||||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_EOS:
|
||||
{
|
||||
GstFlowReturn ret;
|
||||
|
||||
ret = gst_basesink_finish_preroll (basesink, pad, NULL);
|
||||
if (ret == GST_FLOW_OK) {
|
||||
basesink->eos = TRUE;
|
||||
/* ok, we can post the message */
|
||||
gst_element_post_message (GST_ELEMENT (basesink),
|
||||
gst_message_new_eos (GST_OBJECT (basesink)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GST_EVENT_DISCONTINUOUS:
|
||||
if (basesink->sync && basesink->clock) {
|
||||
//gint64 value = GST_EVENT_DISCONT_OFFSET (event, 0).value;
|
||||
}
|
||||
default:
|
||||
result = gst_pad_event_default (pad, event);
|
||||
break;
|
||||
}
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_basesink_chain_unlocked (GstPad * pad, GstBuffer * buf)
|
||||
{
|
||||
GstBaseSink *basesink;
|
||||
GstFlowReturn result = GST_FLOW_OK;
|
||||
GstBaseSinkClass *bclass;
|
||||
|
||||
basesink = GST_BASESINK (GST_OBJECT_PARENT (pad));
|
||||
|
||||
result = gst_basesink_finish_preroll (basesink, pad, buf);
|
||||
if (result != GST_FLOW_OK)
|
||||
goto exit;
|
||||
|
||||
/* doClock
|
||||
if (basesink->sync && basesink->clock) {
|
||||
gst_element_wait (GST_ELEMENT (basesink), GST_BUFFER_TIMESTAMP (buf));
|
||||
}
|
||||
*/
|
||||
|
||||
bclass = GST_BASESINK_GET_CLASS (basesink);
|
||||
if (bclass->render)
|
||||
bclass->render (basesink, buf);
|
||||
|
||||
exit:
|
||||
gst_buffer_unref (buf);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_basesink_chain (GstPad * pad, GstBuffer * buf)
|
||||
{
|
||||
GstFlowReturn result;
|
||||
|
||||
g_assert (GST_BASESINK (GST_OBJECT_PARENT (pad))->pad_mode ==
|
||||
GST_ACTIVATE_PUSH);
|
||||
|
||||
GST_STREAM_LOCK (pad);
|
||||
|
||||
result = gst_basesink_chain_unlocked (pad, buf);
|
||||
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_basesink_loop (GstPad * pad)
|
||||
{
|
||||
GstBaseSink *basesink;
|
||||
GstBuffer *buf = NULL;
|
||||
GstFlowReturn result;
|
||||
|
||||
basesink = GST_BASESINK (GST_OBJECT_PARENT (pad));
|
||||
|
||||
g_assert (basesink->pad_mode == GST_ACTIVATE_PULL);
|
||||
|
||||
GST_STREAM_LOCK (pad);
|
||||
|
||||
result = gst_pad_pull_range (pad, basesink->offset, DEFAULT_SIZE, &buf);
|
||||
if (result != GST_FLOW_OK)
|
||||
goto paused;
|
||||
|
||||
result = gst_basesink_chain_unlocked (pad, buf);
|
||||
if (result != GST_FLOW_OK)
|
||||
goto paused;
|
||||
|
||||
exit:
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
return;
|
||||
|
||||
paused:
|
||||
gst_task_pause (GST_RPAD_TASK (pad));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_basesink_activate (GstPad * pad, GstActivateMode mode)
|
||||
{
|
||||
gboolean result = FALSE;
|
||||
GstBaseSink *basesink;
|
||||
|
||||
basesink = GST_BASESINK (GST_OBJECT_PARENT (pad));
|
||||
|
||||
switch (mode) {
|
||||
case GST_ACTIVATE_PUSH:
|
||||
g_return_val_if_fail (basesink->has_chain, FALSE);
|
||||
result = TRUE;
|
||||
break;
|
||||
case GST_ACTIVATE_PULL:
|
||||
/* if we have a scheduler we can start the task */
|
||||
g_return_val_if_fail (basesink->has_loop, FALSE);
|
||||
if (GST_ELEMENT_SCHEDULER (basesink)) {
|
||||
GST_STREAM_LOCK (pad);
|
||||
GST_RPAD_TASK (pad) =
|
||||
gst_scheduler_create_task (GST_ELEMENT_SCHEDULER (basesink),
|
||||
(GstTaskFunction) gst_basesink_loop, pad);
|
||||
|
||||
gst_task_start (GST_RPAD_TASK (pad));
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
result = TRUE;
|
||||
}
|
||||
break;
|
||||
case GST_ACTIVATE_NONE:
|
||||
/* step 1, unblock clock sync (if any) or any other blocking thing */
|
||||
|
||||
/* unlock preroll */
|
||||
GST_PREROLL_LOCK (pad);
|
||||
GST_PREROLL_SIGNAL (pad);
|
||||
GST_PREROLL_UNLOCK (pad);
|
||||
|
||||
/* step 2, make sure streaming finishes */
|
||||
GST_STREAM_LOCK (pad);
|
||||
/* step 3, stop the task */
|
||||
if (GST_RPAD_TASK (pad)) {
|
||||
gst_task_stop (GST_RPAD_TASK (pad));
|
||||
gst_object_unref (GST_OBJECT (GST_RPAD_TASK (pad)));
|
||||
GST_RPAD_TASK (pad) = NULL;
|
||||
}
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
|
||||
result = TRUE;
|
||||
break;
|
||||
}
|
||||
basesink->pad_mode = mode;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
gst_basesink_change_state (GstElement * element)
|
||||
{
|
||||
GstElementStateReturn ret = GST_STATE_SUCCESS;
|
||||
GstBaseSink *basesink = GST_BASESINK (element);
|
||||
GstElementState transition = GST_STATE_TRANSITION (element);
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_NULL_TO_READY:
|
||||
break;
|
||||
case GST_STATE_READY_TO_PAUSED:
|
||||
/* need to complete preroll before this state change completes, there
|
||||
* is no data flow in READY so we cqn safely assume we need to preroll. */
|
||||
basesink->offset = 0;
|
||||
GST_PREROLL_LOCK (basesink->sinkpad);
|
||||
basesink->need_preroll = TRUE;
|
||||
basesink->have_preroll = FALSE;
|
||||
GST_PREROLL_UNLOCK (basesink->sinkpad);
|
||||
ret = GST_STATE_ASYNC;
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
/* the state change completes when we are blocking on a preroll
|
||||
* sample */
|
||||
GST_PREROLL_LOCK (basesink->sinkpad);
|
||||
if (!basesink->have_preroll) {
|
||||
basesink->need_preroll = TRUE;
|
||||
ret = GST_STATE_ASYNC;
|
||||
} else {
|
||||
/* now let it play */
|
||||
GST_PREROLL_SIGNAL (basesink->sinkpad);
|
||||
}
|
||||
GST_PREROLL_UNLOCK (basesink->sinkpad);
|
||||
break;
|
||||
case GST_STATE_PLAYING_TO_PAUSED:
|
||||
GST_PREROLL_LOCK (basesink->sinkpad);
|
||||
basesink->need_preroll = TRUE;
|
||||
/* if we don't have a preroll buffer and we have not received EOS,
|
||||
* we need to wait for a preroll */
|
||||
if (!basesink->have_preroll && !basesink->eos) {
|
||||
ret = GST_STATE_ASYNC;
|
||||
}
|
||||
GST_PREROLL_UNLOCK (basesink->sinkpad);
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_READY:
|
||||
break;
|
||||
case GST_STATE_READY_TO_NULL:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||
return ret;
|
||||
}
|
79
libs/gst/base/gstbasesink.h
Normal file
79
libs/gst/base/gstbasesink.h
Normal file
|
@ -0,0 +1,79 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstbasesink.h:
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __GST_BASESINK_H__
|
||||
#define __GST_BASESINK_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
#define GST_TYPE_BASESINK (gst_basesink_get_type())
|
||||
#define GST_BASESINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_BASESINK,GstBaseSink))
|
||||
#define GST_BASESINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_BASESINK,GstBaseSinkClass))
|
||||
#define GST_BASESINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_BASESINK, GstBaseSinkClass))
|
||||
#define GST_IS_BASESINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASESINK))
|
||||
#define GST_IS_BASESINK_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASESINK))
|
||||
|
||||
typedef struct _GstBaseSink GstBaseSink;
|
||||
typedef struct _GstBaseSinkClass GstBaseSinkClass;
|
||||
|
||||
struct _GstBaseSink {
|
||||
GstElement element;
|
||||
|
||||
GstPad *sinkpad;
|
||||
GstActivateMode pad_mode;
|
||||
|
||||
guint64 offset;
|
||||
gboolean has_loop;
|
||||
gboolean has_chain;
|
||||
|
||||
gboolean sync;
|
||||
GstClock *clock;
|
||||
|
||||
gboolean eos;
|
||||
gboolean need_preroll;
|
||||
gboolean have_preroll;
|
||||
};
|
||||
|
||||
struct _GstBaseSinkClass {
|
||||
GstElementClass parent_class;
|
||||
|
||||
GstStaticPadTemplate* (*get_template) (GstBaseSink *sink);
|
||||
|
||||
GstCaps* (*get_caps) (GstBaseSink *sink);
|
||||
gboolean (*set_caps) (GstBaseSink *sink, GstCaps *caps);
|
||||
|
||||
GstBuffer* (*alloc_buffer) (GstBaseSink *sink, guint64 offset, guint size,
|
||||
GstCaps *caps);
|
||||
|
||||
void (*event) (GstBaseSink *sink, GstEvent *event);
|
||||
GstFlowReturn (*preroll) (GstBaseSink *sink, GstBuffer *buffer);
|
||||
GstFlowReturn (*render) (GstBaseSink *sink, GstBuffer *buffer);
|
||||
};
|
||||
|
||||
GType gst_basesink_get_type(void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_BASESINK_H__ */
|
|
@ -45,7 +45,7 @@ libgstelements_la_SOURCES = \
|
|||
|
||||
libgstelements_la_CFLAGS = $(GST_OBJ_CFLAGS)
|
||||
libgstelements_la_LIBADD = $(GST_OBJ_LIBS)
|
||||
libgstelements_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(as_libtool_LDFLAGS)
|
||||
libgstelements_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(as_libtool_LDFLAGS) $(top_builddir)/gst/base/libgstbase.la
|
||||
|
||||
noinst_HEADERS = \
|
||||
gstaggregator.h \
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
* 2005 Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* gstfakesink.c:
|
||||
*
|
||||
|
@ -36,12 +36,12 @@ static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
|
|||
GST_DEBUG_CATEGORY_STATIC (gst_fakesink_debug);
|
||||
#define GST_CAT_DEFAULT gst_fakesink_debug
|
||||
|
||||
#define DEFAULT_SIZE 1024
|
||||
|
||||
GstElementDetails gst_fakesink_details = GST_ELEMENT_DETAILS ("Fake Sink",
|
||||
"Sink",
|
||||
"Black hole for data",
|
||||
"Erik Walthinsen <omega@cse.ogi.edu>, Tim Waymans <tway@fluendo.com>");
|
||||
"Erik Walthinsen <omega@cse.ogi.edu>, "
|
||||
"Wim Taymans <wim@fluendo.com>, "
|
||||
"Mr. 'frag-me-more' Vanderwingo <wingo@fluendo.com>");
|
||||
|
||||
|
||||
/* FakeSink signals and args */
|
||||
|
@ -52,25 +52,24 @@ enum
|
|||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
#define DEFAULT_STATE_ERROR FAKESINK_STATE_ERROR_NONE
|
||||
#define DEFAULT_SILENT FALSE
|
||||
#define DEFAULT_DUMP FALSE
|
||||
#define DEFAULT_SYNC FALSE
|
||||
#define DEFAULT_SIGNAL_HANDOFFS FALSE
|
||||
#define DEFAULT_LAST_MESSAGE NULL
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0,
|
||||
ARG_STATE_ERROR,
|
||||
ARG_NUM_SINKS,
|
||||
ARG_SILENT,
|
||||
ARG_DUMP,
|
||||
ARG_SYNC,
|
||||
ARG_SIGNAL_HANDOFFS,
|
||||
ARG_LAST_MESSAGE,
|
||||
ARG_HAS_LOOP,
|
||||
ARG_HAS_CHAIN
|
||||
};
|
||||
|
||||
GstStaticPadTemplate fakesink_sink_template = GST_STATIC_PAD_TEMPLATE ("sink%d",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_REQUEST,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
#define GST_TYPE_FAKESINK_STATE_ERROR (gst_fakesink_state_error_get_type())
|
||||
static GType
|
||||
gst_fakesink_state_error_get_type (void)
|
||||
|
@ -103,13 +102,9 @@ gst_fakesink_state_error_get_type (void)
|
|||
#define _do_init(bla) \
|
||||
GST_DEBUG_CATEGORY_INIT (gst_fakesink_debug, "fakesink", 0, "fakesink element");
|
||||
|
||||
GST_BOILERPLATE_FULL (GstFakeSink, gst_fakesink, GstElement, GST_TYPE_ELEMENT,
|
||||
GST_BOILERPLATE_FULL (GstFakeSink, gst_fakesink, GstBaseSink, GST_TYPE_BASESINK,
|
||||
_do_init);
|
||||
|
||||
static void gst_fakesink_set_clock (GstElement * element, GstClock * clock);
|
||||
static GstPad *gst_fakesink_request_new_pad (GstElement * element,
|
||||
GstPadTemplate * templ, const gchar * unused);
|
||||
|
||||
static void gst_fakesink_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_fakesink_get_property (GObject * object, guint prop_id,
|
||||
|
@ -117,12 +112,11 @@ static void gst_fakesink_get_property (GObject * object, guint prop_id,
|
|||
|
||||
static GstElementStateReturn gst_fakesink_change_state (GstElement * element);
|
||||
|
||||
static GstFlowReturn gst_fakesink_chain_unlocked (GstPad * pad,
|
||||
static GstFlowReturn gst_fakesink_preroll (GstBaseSink * bsink,
|
||||
GstBuffer * buffer);
|
||||
static void gst_fakesink_loop (GstPad * pad);
|
||||
static GstFlowReturn gst_fakesink_chain (GstPad * pad, GstBuffer * buffer);
|
||||
static gboolean gst_fakesink_activate (GstPad * pad, GstActivateMode mode);
|
||||
static gboolean gst_fakesink_event (GstPad * pad, GstEvent * event);
|
||||
static GstFlowReturn gst_fakesink_render (GstBaseSink * bsink,
|
||||
GstBuffer * buffer);
|
||||
static void gst_fakesink_event (GstBaseSink * bsink, GstEvent * event);
|
||||
|
||||
static guint gst_fakesink_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
|
@ -134,8 +128,6 @@ gst_fakesink_base_init (gpointer g_class)
|
|||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&sinktemplate));
|
||||
gst_element_class_set_details (gstelement_class, &gst_fakesink_details);
|
||||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&fakesink_sink_template));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -143,44 +135,37 @@ gst_fakesink_class_init (GstFakeSinkClass * klass)
|
|||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
GstBaseSinkClass *gstbasesink_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
gstbasesink_class = (GstBaseSinkClass *) klass;
|
||||
|
||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fakesink_set_property);
|
||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fakesink_get_property);
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_SINKS,
|
||||
g_param_spec_int ("num_sinks", "Number of sinks",
|
||||
"The number of sinkpads", 1, G_MAXINT, 1, G_PARAM_READABLE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_STATE_ERROR,
|
||||
g_param_spec_enum ("state_error", "State Error",
|
||||
"Generate a state change error", GST_TYPE_FAKESINK_STATE_ERROR,
|
||||
FAKESINK_STATE_ERROR_NONE, G_PARAM_READWRITE));
|
||||
DEFAULT_STATE_ERROR, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
|
||||
g_param_spec_string ("last_message", "Last Message",
|
||||
"The message describing current status", NULL, G_PARAM_READABLE));
|
||||
"The message describing current status", DEFAULT_LAST_MESSAGE,
|
||||
G_PARAM_READABLE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SYNC,
|
||||
g_param_spec_boolean ("sync", "Sync", "Sync on the clock", FALSE,
|
||||
g_param_spec_boolean ("sync", "Sync", "Sync on the clock", DEFAULT_SYNC,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIGNAL_HANDOFFS,
|
||||
g_param_spec_boolean ("signal-handoffs", "Signal handoffs",
|
||||
"Send a signal before unreffing the buffer", FALSE,
|
||||
"Send a signal before unreffing the buffer", DEFAULT_SIGNAL_HANDOFFS,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
|
||||
g_param_spec_boolean ("silent", "Silent",
|
||||
"Don't produce last_message events", FALSE, G_PARAM_READWRITE));
|
||||
"Don't produce last_message events", DEFAULT_SILENT,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DUMP,
|
||||
g_param_spec_boolean ("dump", "Dump", "Dump received bytes to stdout",
|
||||
FALSE, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HAS_LOOP,
|
||||
g_param_spec_boolean ("has-loop", "has-loop",
|
||||
"Enable loop-based operation", TRUE,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HAS_CHAIN,
|
||||
g_param_spec_boolean ("has-chain", "has-chain",
|
||||
"Enable chain-based operation", TRUE,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||
DEFAULT_DUMP, G_PARAM_READWRITE));
|
||||
|
||||
gst_fakesink_signals[SIGNAL_HANDOFF] =
|
||||
g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
|
||||
|
@ -188,93 +173,23 @@ gst_fakesink_class_init (GstFakeSinkClass * klass)
|
|||
gst_marshal_VOID__BOXED_OBJECT, G_TYPE_NONE, 2,
|
||||
GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, GST_TYPE_PAD);
|
||||
|
||||
gstelement_class->request_new_pad =
|
||||
GST_DEBUG_FUNCPTR (gst_fakesink_request_new_pad);
|
||||
gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_fakesink_set_clock);
|
||||
gstelement_class->change_state =
|
||||
GST_DEBUG_FUNCPTR (gst_fakesink_change_state);
|
||||
|
||||
gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_fakesink_event);
|
||||
gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_fakesink_preroll);
|
||||
gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_fakesink_render);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fakesink_init (GstFakeSink * fakesink)
|
||||
{
|
||||
fakesink->sinkpad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
|
||||
"sink");
|
||||
gst_element_add_pad (GST_ELEMENT (fakesink), fakesink->sinkpad);
|
||||
|
||||
fakesink->silent = FALSE;
|
||||
fakesink->dump = FALSE;
|
||||
fakesink->sync = FALSE;
|
||||
fakesink->last_message = NULL;
|
||||
fakesink->state_error = FAKESINK_STATE_ERROR_NONE;
|
||||
fakesink->signal_handoffs = FALSE;
|
||||
fakesink->pad_mode = GST_ACTIVATE_NONE;
|
||||
GST_RPAD_TASK (fakesink->sinkpad) = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fakesink_set_pad_functions (GstFakeSink * this, GstPad * pad)
|
||||
{
|
||||
gst_pad_set_activate_function (pad,
|
||||
GST_DEBUG_FUNCPTR (gst_fakesink_activate));
|
||||
gst_pad_set_event_function (pad, GST_DEBUG_FUNCPTR (gst_fakesink_event));
|
||||
|
||||
if (this->has_chain)
|
||||
gst_pad_set_chain_function (pad, GST_DEBUG_FUNCPTR (gst_fakesink_chain));
|
||||
else
|
||||
gst_pad_set_chain_function (pad, NULL);
|
||||
|
||||
if (this->has_loop)
|
||||
gst_pad_set_loop_function (pad, GST_DEBUG_FUNCPTR (gst_fakesink_loop));
|
||||
else
|
||||
gst_pad_set_loop_function (pad, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fakesink_set_all_pad_functions (GstFakeSink * this)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = GST_ELEMENT_PADS (this); l; l = l->next)
|
||||
gst_fakesink_set_pad_functions (this, (GstPad *) l->data);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fakesink_set_clock (GstElement * element, GstClock * clock)
|
||||
{
|
||||
GstFakeSink *sink;
|
||||
|
||||
sink = GST_FAKESINK (element);
|
||||
|
||||
sink->clock = clock;
|
||||
}
|
||||
|
||||
static GstPad *
|
||||
gst_fakesink_request_new_pad (GstElement * element, GstPadTemplate * templ,
|
||||
const gchar * unused)
|
||||
{
|
||||
gchar *name;
|
||||
GstPad *sinkpad;
|
||||
GstFakeSink *fakesink;
|
||||
|
||||
g_return_val_if_fail (GST_IS_FAKESINK (element), NULL);
|
||||
|
||||
if (templ->direction != GST_PAD_SINK) {
|
||||
g_warning ("gstfakesink: request new pad that is not a SINK pad\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fakesink = GST_FAKESINK (element);
|
||||
|
||||
name = g_strdup_printf ("sink%d", GST_ELEMENT (fakesink)->numsinkpads);
|
||||
|
||||
sinkpad = gst_pad_new_from_template (templ, name);
|
||||
g_free (name);
|
||||
gst_fakesink_set_pad_functions (fakesink, sinkpad);
|
||||
gst_element_add_pad (GST_ELEMENT (fakesink), sinkpad);
|
||||
|
||||
return sinkpad;
|
||||
fakesink->silent = DEFAULT_SILENT;
|
||||
fakesink->dump = DEFAULT_DUMP;
|
||||
fakesink->sync = DEFAULT_SYNC;
|
||||
fakesink->last_message = DEFAULT_LAST_MESSAGE;
|
||||
fakesink->state_error = DEFAULT_STATE_ERROR;
|
||||
fakesink->signal_handoffs = DEFAULT_SIGNAL_HANDOFFS;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -283,18 +198,9 @@ gst_fakesink_set_property (GObject * object, guint prop_id,
|
|||
{
|
||||
GstFakeSink *sink;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
sink = GST_FAKESINK (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_HAS_LOOP:
|
||||
sink->has_loop = g_value_get_boolean (value);
|
||||
gst_fakesink_set_all_pad_functions (sink);
|
||||
break;
|
||||
case ARG_HAS_CHAIN:
|
||||
sink->has_chain = g_value_get_boolean (value);
|
||||
gst_fakesink_set_all_pad_functions (sink);
|
||||
break;
|
||||
case ARG_SILENT:
|
||||
sink->silent = g_value_get_boolean (value);
|
||||
break;
|
||||
|
@ -322,24 +228,12 @@ gst_fakesink_get_property (GObject * object, guint prop_id, GValue * value,
|
|||
{
|
||||
GstFakeSink *sink;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_FAKESINK (object));
|
||||
|
||||
sink = GST_FAKESINK (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_NUM_SINKS:
|
||||
g_value_set_int (value, GST_ELEMENT (sink)->numsinkpads);
|
||||
break;
|
||||
case ARG_STATE_ERROR:
|
||||
g_value_set_enum (value, sink->state_error);
|
||||
break;
|
||||
case ARG_HAS_LOOP:
|
||||
g_value_set_boolean (value, sink->has_loop);
|
||||
break;
|
||||
case ARG_HAS_CHAIN:
|
||||
g_value_set_boolean (value, sink->has_chain);
|
||||
break;
|
||||
case ARG_SILENT:
|
||||
g_value_set_boolean (value, sink->silent);
|
||||
break;
|
||||
|
@ -361,256 +255,65 @@ gst_fakesink_get_property (GObject * object, guint prop_id, GValue * value,
|
|||
}
|
||||
}
|
||||
|
||||
/* STREAM_LOCK should be held */
|
||||
GstFlowReturn
|
||||
gst_fakesink_finish_preroll (GstFakeSink * fakesink, GstPad * pad)
|
||||
static void
|
||||
gst_fakesink_event (GstBaseSink * bsink, GstEvent * event)
|
||||
{
|
||||
/* lock order is important */
|
||||
GST_STATE_LOCK (fakesink);
|
||||
GST_PREROLL_LOCK (pad);
|
||||
if (!fakesink->need_preroll)
|
||||
goto no_preroll;
|
||||
GstFakeSink *sink = GST_FAKESINK (bsink);
|
||||
|
||||
if (!fakesink->silent) {
|
||||
g_free (fakesink->last_message);
|
||||
if (!sink->silent) {
|
||||
g_free (sink->last_message);
|
||||
|
||||
fakesink->last_message =
|
||||
g_strdup_printf ("preroll ******* (%s:%s)", GST_DEBUG_PAD_NAME (pad));
|
||||
sink->last_message =
|
||||
g_strdup_printf ("chain ******* E (type: %d) %p",
|
||||
GST_EVENT_TYPE (event), event);
|
||||
|
||||
g_object_notify (G_OBJECT (fakesink), "last_message");
|
||||
g_object_notify (G_OBJECT (sink), "last_message");
|
||||
}
|
||||
|
||||
fakesink->need_preroll = FALSE;
|
||||
fakesink->have_preroll = TRUE;
|
||||
gst_element_commit_state (GST_ELEMENT (fakesink));
|
||||
GST_STATE_UNLOCK (fakesink);
|
||||
|
||||
{
|
||||
gboolean usable;
|
||||
|
||||
GST_DEBUG ("element %s waiting to finish preroll",
|
||||
GST_ELEMENT_NAME (fakesink));
|
||||
GST_PREROLL_WAIT (pad);
|
||||
GST_DEBUG ("done preroll");
|
||||
|
||||
GST_LOCK (pad);
|
||||
usable = !GST_RPAD_IS_FLUSHING (pad) && GST_RPAD_IS_ACTIVE (pad);
|
||||
GST_UNLOCK (pad);
|
||||
if (!usable)
|
||||
goto unusable;
|
||||
|
||||
GST_DEBUG ("done preroll");
|
||||
}
|
||||
fakesink->have_preroll = FALSE;
|
||||
|
||||
GST_PREROLL_UNLOCK (pad);
|
||||
return GST_FLOW_OK;
|
||||
|
||||
no_preroll:
|
||||
{
|
||||
GST_PREROLL_UNLOCK (pad);
|
||||
GST_STATE_UNLOCK (fakesink);
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
unusable:
|
||||
{
|
||||
GST_DEBUG ("pad is flushing");
|
||||
GST_PREROLL_UNLOCK (pad);
|
||||
return GST_FLOW_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
gst_fakesink_event (GstPad * pad, GstEvent * event)
|
||||
{
|
||||
GstFakeSink *fakesink;
|
||||
gboolean result = TRUE;
|
||||
|
||||
fakesink = GST_FAKESINK (GST_OBJECT_PARENT (pad));
|
||||
|
||||
GST_STREAM_LOCK (pad);
|
||||
|
||||
if (!fakesink->silent) {
|
||||
g_free (fakesink->last_message);
|
||||
|
||||
fakesink->last_message =
|
||||
g_strdup_printf ("chain ******* (%s:%s)E (type: %d) %p",
|
||||
GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE (event), event);
|
||||
|
||||
g_object_notify (G_OBJECT (fakesink), "last_message");
|
||||
}
|
||||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_EOS:
|
||||
{
|
||||
GstFlowReturn ret;
|
||||
|
||||
ret = gst_fakesink_finish_preroll (fakesink, pad);
|
||||
if (ret == GST_FLOW_OK) {
|
||||
fakesink->eos = TRUE;
|
||||
/* ok, we can post the message */
|
||||
gst_element_post_message (GST_ELEMENT (fakesink),
|
||||
gst_message_new_eos (GST_OBJECT (fakesink)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GST_EVENT_DISCONTINUOUS:
|
||||
if (fakesink->sync && fakesink->clock) {
|
||||
//gint64 value = GST_EVENT_DISCONT_OFFSET (event, 0).value;
|
||||
}
|
||||
default:
|
||||
result = gst_pad_event_default (pad, event);
|
||||
break;
|
||||
}
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_fakesink_chain_unlocked (GstPad * pad, GstBuffer * buf)
|
||||
gst_fakesink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
|
||||
{
|
||||
GstFakeSink *fakesink;
|
||||
GstFlowReturn result = GST_FLOW_OK;
|
||||
GstFakeSink *sink = GST_FAKESINK (bsink);
|
||||
|
||||
fakesink = GST_FAKESINK (GST_OBJECT_PARENT (pad));
|
||||
if (!sink->silent) {
|
||||
g_free (sink->last_message);
|
||||
|
||||
result = gst_fakesink_finish_preroll (fakesink, pad);
|
||||
if (result != GST_FLOW_OK)
|
||||
goto exit;
|
||||
sink->last_message = g_strdup_printf ("preroll ******* ");
|
||||
|
||||
if (fakesink->sync && fakesink->clock) {
|
||||
gst_element_wait (GST_ELEMENT (fakesink), GST_BUFFER_TIMESTAMP (buf));
|
||||
g_object_notify (G_OBJECT (sink), "last_message");
|
||||
}
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
if (!fakesink->silent) {
|
||||
g_free (fakesink->last_message);
|
||||
static GstFlowReturn
|
||||
gst_fakesink_render (GstBaseSink * bsink, GstBuffer * buf)
|
||||
{
|
||||
GstFakeSink *sink = GST_FAKESINK (bsink);
|
||||
|
||||
fakesink->last_message =
|
||||
g_strdup_printf ("chain ******* (%s:%s)< (%d bytes, timestamp: %"
|
||||
if (!sink->silent) {
|
||||
g_free (sink->last_message);
|
||||
|
||||
sink->last_message =
|
||||
g_strdup_printf ("chain ******* < (%d bytes, timestamp: %"
|
||||
GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %"
|
||||
G_GINT64_FORMAT ", offset_end: %" G_GINT64_FORMAT ", flags: %d) %p",
|
||||
GST_DEBUG_PAD_NAME (pad), GST_BUFFER_SIZE (buf),
|
||||
GST_BUFFER_SIZE (buf),
|
||||
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
|
||||
GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf),
|
||||
GST_BUFFER_OFFSET_END (buf), GST_BUFFER_FLAGS (buf), buf);
|
||||
|
||||
g_object_notify (G_OBJECT (fakesink), "last_message");
|
||||
g_object_notify (G_OBJECT (sink), "last_message");
|
||||
}
|
||||
if (sink->signal_handoffs)
|
||||
g_signal_emit (G_OBJECT (sink), gst_fakesink_signals[SIGNAL_HANDOFF], 0,
|
||||
buf);
|
||||
|
||||
if (fakesink->signal_handoffs)
|
||||
g_signal_emit (G_OBJECT (fakesink), gst_fakesink_signals[SIGNAL_HANDOFF], 0,
|
||||
buf, pad);
|
||||
|
||||
if (fakesink->dump) {
|
||||
if (sink->dump) {
|
||||
gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
|
||||
}
|
||||
|
||||
exit:
|
||||
gst_buffer_unref (buf);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_fakesink_chain (GstPad * pad, GstBuffer * buf)
|
||||
{
|
||||
GstFlowReturn result;
|
||||
|
||||
g_assert (GST_FAKESINK (GST_OBJECT_PARENT (pad))->pad_mode ==
|
||||
GST_ACTIVATE_PUSH);
|
||||
|
||||
GST_STREAM_LOCK (pad);
|
||||
|
||||
result = gst_fakesink_chain_unlocked (pad, buf);
|
||||
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fakesink_loop (GstPad * pad)
|
||||
{
|
||||
GstFakeSink *fakesink;
|
||||
GstBuffer *buf = NULL;
|
||||
GstFlowReturn result;
|
||||
|
||||
fakesink = GST_FAKESINK (GST_OBJECT_PARENT (pad));
|
||||
|
||||
g_assert (fakesink->pad_mode == GST_ACTIVATE_PULL);
|
||||
|
||||
GST_STREAM_LOCK (pad);
|
||||
|
||||
result = gst_pad_pull_range (pad, fakesink->offset, DEFAULT_SIZE, &buf);
|
||||
if (result != GST_FLOW_OK)
|
||||
goto paused;
|
||||
|
||||
result = gst_fakesink_chain_unlocked (pad, buf);
|
||||
if (result != GST_FLOW_OK)
|
||||
goto paused;
|
||||
|
||||
exit:
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
return;
|
||||
|
||||
paused:
|
||||
gst_task_pause (GST_RPAD_TASK (pad));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_fakesink_activate (GstPad * pad, GstActivateMode mode)
|
||||
{
|
||||
gboolean result = FALSE;
|
||||
GstFakeSink *fakesink;
|
||||
|
||||
fakesink = GST_FAKESINK (GST_OBJECT_PARENT (pad));
|
||||
|
||||
switch (mode) {
|
||||
case GST_ACTIVATE_PUSH:
|
||||
g_return_val_if_fail (fakesink->has_chain, FALSE);
|
||||
result = TRUE;
|
||||
break;
|
||||
case GST_ACTIVATE_PULL:
|
||||
/* if we have a scheduler we can start the task */
|
||||
g_return_val_if_fail (fakesink->has_loop, FALSE);
|
||||
if (GST_ELEMENT_SCHEDULER (fakesink)) {
|
||||
GST_STREAM_LOCK (pad);
|
||||
GST_RPAD_TASK (pad) =
|
||||
gst_scheduler_create_task (GST_ELEMENT_SCHEDULER (fakesink),
|
||||
(GstTaskFunction) gst_fakesink_loop, pad);
|
||||
|
||||
gst_task_start (GST_RPAD_TASK (pad));
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
result = TRUE;
|
||||
}
|
||||
break;
|
||||
case GST_ACTIVATE_NONE:
|
||||
/* step 1, unblock clock sync (if any) or any other blocking thing */
|
||||
|
||||
/* unlock preroll */
|
||||
GST_PREROLL_LOCK (pad);
|
||||
GST_PREROLL_SIGNAL (pad);
|
||||
GST_PREROLL_UNLOCK (pad);
|
||||
|
||||
/* step 2, make sure streaming finishes */
|
||||
GST_STREAM_LOCK (pad);
|
||||
/* step 3, stop the task */
|
||||
if (GST_RPAD_TASK (pad)) {
|
||||
gst_task_stop (GST_RPAD_TASK (pad));
|
||||
gst_object_unref (GST_OBJECT (GST_RPAD_TASK (pad)));
|
||||
GST_RPAD_TASK (pad) = NULL;
|
||||
}
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
|
||||
result = TRUE;
|
||||
break;
|
||||
}
|
||||
fakesink->pad_mode = mode;
|
||||
|
||||
return result;
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
|
@ -628,42 +331,14 @@ gst_fakesink_change_state (GstElement * element)
|
|||
case GST_STATE_READY_TO_PAUSED:
|
||||
if (fakesink->state_error == FAKESINK_STATE_ERROR_READY_PAUSED)
|
||||
goto error;
|
||||
/* need to complete preroll before this state change completes, there
|
||||
* is no data flow in READY so we cqn safely assume we need to preroll. */
|
||||
fakesink->offset = 0;
|
||||
GST_PREROLL_LOCK (fakesink->sinkpad);
|
||||
fakesink->need_preroll = TRUE;
|
||||
fakesink->have_preroll = FALSE;
|
||||
GST_PREROLL_UNLOCK (fakesink->sinkpad);
|
||||
ret = GST_STATE_ASYNC;
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
if (fakesink->state_error == FAKESINK_STATE_ERROR_PAUSED_PLAYING)
|
||||
goto error;
|
||||
/* the state change completes when we are blocking on a preroll
|
||||
* sample */
|
||||
GST_PREROLL_LOCK (fakesink->sinkpad);
|
||||
if (!fakesink->have_preroll) {
|
||||
fakesink->need_preroll = TRUE;
|
||||
ret = GST_STATE_ASYNC;
|
||||
} else {
|
||||
/* now let it play */
|
||||
GST_PREROLL_SIGNAL (fakesink->sinkpad);
|
||||
}
|
||||
GST_PREROLL_UNLOCK (fakesink->sinkpad);
|
||||
break;
|
||||
case GST_STATE_PLAYING_TO_PAUSED:
|
||||
if (fakesink->state_error == FAKESINK_STATE_ERROR_PLAYING_PAUSED)
|
||||
goto error;
|
||||
|
||||
GST_PREROLL_LOCK (fakesink->sinkpad);
|
||||
fakesink->need_preroll = TRUE;
|
||||
/* if we don't have a preroll buffer and we have not received EOS,
|
||||
* we need to wait for a preroll */
|
||||
if (!fakesink->have_preroll && !fakesink->eos) {
|
||||
ret = GST_STATE_ASYNC;
|
||||
}
|
||||
GST_PREROLL_UNLOCK (fakesink->sinkpad);
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_READY:
|
||||
if (fakesink->state_error == FAKESINK_STATE_ERROR_PAUSED_READY)
|
||||
|
@ -679,7 +354,7 @@ gst_fakesink_change_state (GstElement * element)
|
|||
break;
|
||||
}
|
||||
|
||||
GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#define __GST_FAKESINK_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/base/gstbasesink.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
@ -54,29 +55,18 @@ typedef struct _GstFakeSink GstFakeSink;
|
|||
typedef struct _GstFakeSinkClass GstFakeSinkClass;
|
||||
|
||||
struct _GstFakeSink {
|
||||
GstElement element;
|
||||
|
||||
GstPad *sinkpad;
|
||||
GstBaseSink element;
|
||||
|
||||
gboolean silent;
|
||||
gboolean dump;
|
||||
gboolean has_loop;
|
||||
gboolean has_chain;
|
||||
gboolean sync;
|
||||
gboolean signal_handoffs;
|
||||
GstClock *clock;
|
||||
GstFakeSinkStateError state_error;
|
||||
GstActivateMode pad_mode;
|
||||
guint64 offset;
|
||||
gboolean eos;
|
||||
gboolean need_preroll;
|
||||
gboolean have_preroll;
|
||||
|
||||
gchar *last_message;
|
||||
};
|
||||
|
||||
struct _GstFakeSinkClass {
|
||||
GstElementClass parent_class;
|
||||
GstBaseSinkClass parent_class;
|
||||
|
||||
/* signals */
|
||||
void (*handoff) (GstElement *element, GstBuffer *buf, GstPad *pad);
|
||||
|
|
Loading…
Reference in a new issue