mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-09-27 06:20:12 +00:00
check/gst/gstobject.c (test_fake_object_name): The object *does* have a name after g_object_new.
Original commit message from CVS: 2005-03-07 Andy Wingo <wingo@pobox.com> * check/gst/gstobject.c (test_fake_object_name): The object *does* have a name after g_object_new. * gst/base/gstbasesink.c: Change "arguments" to "properties" in the code. Die GtkObject die! (GstBaseSink::preroll-queue-len): New object property, the number of buffers to queue in preroll. By default, does not queue any buffers. Set to a higher number if you have a one-threaded demuxer. (gst_basesink_preroll_queue_push) (gst_basesink_preroll_queue_empty) (gst_basesink_preroll_queue_flush): Implement a queue of buffers for preroll. All must be called with PREROLL_LOCK. (gst_basesink_finish_preroll): Instead of always blocking, push the buffer onto the queue. preroll_queue_push will block if the queue is full. (gst_basesink_event): Make sure the preroll queue is emptied on eos and flushed on flush. (gst_basesink_handle_buffer): Does the work of chain_unlocked, but without going into finish_preroll. (gst_basesink_change_state): Handle setting up the queue and flushing it in READY<->PAUSED transitions.
This commit is contained in:
parent
6a480f3c7c
commit
eb6c9dd801
8 changed files with 451 additions and 138 deletions
25
ChangeLog
25
ChangeLog
|
@ -1,3 +1,28 @@
|
||||||
|
2005-03-07 Andy Wingo <wingo@pobox.com>
|
||||||
|
|
||||||
|
* check/gst/gstobject.c (test_fake_object_name): The object *does*
|
||||||
|
have a name after g_object_new.
|
||||||
|
|
||||||
|
* gst/base/gstbasesink.c: Change "arguments" to "properties" in
|
||||||
|
the code. Die GtkObject die!
|
||||||
|
(GstBaseSink::preroll-queue-len): New object property, the number
|
||||||
|
of buffers to queue in preroll. By default, does not queue any
|
||||||
|
buffers. Set to a higher number if you have a one-threaded
|
||||||
|
demuxer.
|
||||||
|
(gst_basesink_preroll_queue_push)
|
||||||
|
(gst_basesink_preroll_queue_empty)
|
||||||
|
(gst_basesink_preroll_queue_flush): Implement a queue of buffers
|
||||||
|
for preroll. All must be called with PREROLL_LOCK.
|
||||||
|
(gst_basesink_finish_preroll): Instead of always blocking, push
|
||||||
|
the buffer onto the queue. preroll_queue_push will block if the
|
||||||
|
queue is full.
|
||||||
|
(gst_basesink_event): Make sure the preroll queue is emptied on
|
||||||
|
eos and flushed on flush.
|
||||||
|
(gst_basesink_handle_buffer): Does the work of chain_unlocked, but
|
||||||
|
without going into finish_preroll.
|
||||||
|
(gst_basesink_change_state): Handle setting up the queue and
|
||||||
|
flushing it in READY<->PAUSED transitions.
|
||||||
|
|
||||||
2005-03-03 Wim Taymans <wim@fluendo.com>
|
2005-03-03 Wim Taymans <wim@fluendo.com>
|
||||||
|
|
||||||
* docs/design/part-MT-refcounting.txt:
|
* docs/design/part-MT-refcounting.txt:
|
||||||
|
|
|
@ -98,7 +98,9 @@ START_TEST (test_fake_object_name)
|
||||||
object = g_object_new (gst_fake_object_get_type (), NULL);
|
object = g_object_new (gst_fake_object_get_type (), NULL);
|
||||||
|
|
||||||
name = gst_object_get_name (object);
|
name = gst_object_get_name (object);
|
||||||
fail_if (name != NULL, "Newly created object has a name");
|
fail_if (name == NULL, "Newly created object has no name");
|
||||||
|
fail_if (strncmp (name, "fakeobject", 10) != 0,
|
||||||
|
"Random name %s does not start with Gst", name);
|
||||||
|
|
||||||
/* give a random name by setting with NULL;
|
/* give a random name by setting with NULL;
|
||||||
* GstFakeObject class -> fakeobject%d */
|
* GstFakeObject class -> fakeobject%d */
|
||||||
|
|
|
@ -221,10 +221,10 @@ Acquire a reference to the mutex of this object.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
@object:
|
@object:
|
||||||
@name_prefix:
|
@name:
|
||||||
@Returns:
|
@Returns:
|
||||||
<!-- # Unused Parameters # -->
|
<!-- # Unused Parameters # -->
|
||||||
@name:
|
@name_prefix:
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION gst_object_get_name ##### -->
|
<!-- ##### FUNCTION gst_object_get_name ##### -->
|
||||||
|
|
|
@ -34,7 +34,14 @@ static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_DEBUG_CATEGORY_STATIC (gst_basesink_debug);
|
GST_DEBUG_CATEGORY_STATIC (gst_basesink_debug);
|
||||||
#define GST_CAT_DEFAULT gst_basesink_debug
|
#define GST_CAT_DEFAULT gst_basesink_debug
|
||||||
|
|
||||||
/* BaseSink signals and args */
|
/* #define DEBUGGING */
|
||||||
|
#ifdef DEBUGGING
|
||||||
|
#define DEBUG(str,args...) g_print (str,##args)
|
||||||
|
#else
|
||||||
|
#define DEBUG(str,args...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* BaseSink signals and properties */
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
/* FILL ME */
|
/* FILL ME */
|
||||||
|
@ -48,9 +55,10 @@ enum
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
ARG_0,
|
PROP_0,
|
||||||
ARG_HAS_LOOP,
|
PROP_HAS_LOOP,
|
||||||
ARG_HAS_CHAIN
|
PROP_HAS_CHAIN,
|
||||||
|
PROP_PREROLL_QUEUE_LEN
|
||||||
};
|
};
|
||||||
|
|
||||||
#define _do_init(bla) \
|
#define _do_init(bla) \
|
||||||
|
@ -82,6 +90,8 @@ static void gst_basesink_loop (GstPad * pad);
|
||||||
static GstFlowReturn gst_basesink_chain (GstPad * pad, GstBuffer * buffer);
|
static GstFlowReturn gst_basesink_chain (GstPad * pad, GstBuffer * buffer);
|
||||||
static gboolean gst_basesink_activate (GstPad * pad, GstActivateMode mode);
|
static gboolean gst_basesink_activate (GstPad * pad, GstActivateMode mode);
|
||||||
static gboolean gst_basesink_event (GstPad * pad, GstEvent * event);
|
static gboolean gst_basesink_event (GstPad * pad, GstEvent * event);
|
||||||
|
static inline void gst_basesink_handle_buffer (GstBaseSink * basesink,
|
||||||
|
GstBuffer * buf);
|
||||||
|
|
||||||
static GstStaticPadTemplate *
|
static GstStaticPadTemplate *
|
||||||
gst_basesink_get_template (GstBaseSink * bsink)
|
gst_basesink_get_template (GstBaseSink * bsink)
|
||||||
|
@ -123,14 +133,19 @@ gst_basesink_class_init (GstBaseSinkClass * klass)
|
||||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_basesink_set_property);
|
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_basesink_set_property);
|
||||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_basesink_get_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_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_LOOP,
|
||||||
g_param_spec_boolean ("has-loop", "has-loop",
|
g_param_spec_boolean ("has-loop", "has-loop",
|
||||||
"Enable loop-based operation", DEFAULT_HAS_LOOP,
|
"Enable loop-based operation", DEFAULT_HAS_LOOP,
|
||||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HAS_CHAIN,
|
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_CHAIN,
|
||||||
g_param_spec_boolean ("has-chain", "has-chain",
|
g_param_spec_boolean ("has-chain", "has-chain",
|
||||||
"Enable chain-based operation", DEFAULT_HAS_CHAIN,
|
"Enable chain-based operation", DEFAULT_HAS_CHAIN,
|
||||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||||
|
g_object_class_install_property (G_OBJECT_CLASS (klass),
|
||||||
|
PROP_PREROLL_QUEUE_LEN,
|
||||||
|
g_param_spec_uint ("preroll-queue-len", "preroll-queue-len",
|
||||||
|
"Number of buffers to queue during preroll", 0, G_MAXUINT, 0,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||||
|
|
||||||
gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_basesink_set_clock);
|
gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_basesink_set_clock);
|
||||||
gstelement_class->change_state =
|
gstelement_class->change_state =
|
||||||
|
@ -262,22 +277,29 @@ gst_basesink_set_property (GObject * object, guint prop_id,
|
||||||
{
|
{
|
||||||
GstBaseSink *sink;
|
GstBaseSink *sink;
|
||||||
|
|
||||||
/* it's not null if we got it, but it might not be ours */
|
|
||||||
sink = GST_BASESINK (object);
|
sink = GST_BASESINK (object);
|
||||||
|
|
||||||
|
GST_LOCK (sink);
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case ARG_HAS_LOOP:
|
case PROP_HAS_LOOP:
|
||||||
sink->has_loop = g_value_get_boolean (value);
|
sink->has_loop = g_value_get_boolean (value);
|
||||||
gst_basesink_set_all_pad_functions (sink);
|
gst_basesink_set_all_pad_functions (sink);
|
||||||
break;
|
break;
|
||||||
case ARG_HAS_CHAIN:
|
case PROP_HAS_CHAIN:
|
||||||
sink->has_chain = g_value_get_boolean (value);
|
sink->has_chain = g_value_get_boolean (value);
|
||||||
gst_basesink_set_all_pad_functions (sink);
|
gst_basesink_set_all_pad_functions (sink);
|
||||||
break;
|
break;
|
||||||
|
case PROP_PREROLL_QUEUE_LEN:
|
||||||
|
/* preroll lock necessary to serialize with finish_preroll */
|
||||||
|
GST_PREROLL_LOCK (sink->sinkpad);
|
||||||
|
sink->preroll_queue_max_len = g_value_get_uint (value);
|
||||||
|
GST_PREROLL_UNLOCK (sink->sinkpad);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
GST_UNLOCK (sink);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -286,22 +308,24 @@ gst_basesink_get_property (GObject * object, guint prop_id, GValue * value,
|
||||||
{
|
{
|
||||||
GstBaseSink *sink;
|
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);
|
sink = GST_BASESINK (object);
|
||||||
|
|
||||||
|
GST_LOCK (sink);
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case ARG_HAS_LOOP:
|
case PROP_HAS_LOOP:
|
||||||
g_value_set_boolean (value, sink->has_loop);
|
g_value_set_boolean (value, sink->has_loop);
|
||||||
break;
|
break;
|
||||||
case ARG_HAS_CHAIN:
|
case PROP_HAS_CHAIN:
|
||||||
g_value_set_boolean (value, sink->has_chain);
|
g_value_set_boolean (value, sink->has_chain);
|
||||||
break;
|
break;
|
||||||
|
case PROP_PREROLL_QUEUE_LEN:
|
||||||
|
g_value_set_uint (value, sink->preroll_queue_max_len);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
GST_UNLOCK (sink);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstStaticPadTemplate *
|
static GstStaticPadTemplate *
|
||||||
|
@ -329,35 +353,94 @@ gst_base_sink_buffer_alloc (GstBaseSink * sink, guint64 offset, guint size,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* STREAM_LOCK should be held */
|
/* with PREROLL_LOCK */
|
||||||
GstFlowReturn
|
static void
|
||||||
|
gst_basesink_preroll_queue_push (GstBaseSink * basesink, GstPad * pad,
|
||||||
|
GstBuffer * buffer)
|
||||||
|
{
|
||||||
|
if (basesink->preroll_queue->length == 0) {
|
||||||
|
GstBaseSinkClass *bclass = GST_BASESINK_GET_CLASS (basesink);
|
||||||
|
|
||||||
|
if (bclass->preroll)
|
||||||
|
bclass->preroll (basesink, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (basesink->preroll_queue->length < basesink->preroll_queue_max_len) {
|
||||||
|
DEBUG ("push %p %p\n", basesink, buffer);
|
||||||
|
g_queue_push_tail (basesink->preroll_queue, buffer);
|
||||||
|
} else {
|
||||||
|
/* block until the state changes, or we get a flush, or something */
|
||||||
|
DEBUG ("block %p %p\n", basesink, buffer);
|
||||||
|
GST_DEBUG ("element %s waiting to finish preroll",
|
||||||
|
GST_ELEMENT_NAME (basesink));
|
||||||
|
basesink->need_preroll = FALSE;
|
||||||
|
basesink->have_preroll = TRUE;
|
||||||
|
GST_PREROLL_WAIT (pad);
|
||||||
|
GST_DEBUG ("done preroll");
|
||||||
|
basesink->have_preroll = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* with PREROLL_LOCK */
|
||||||
|
static void
|
||||||
|
gst_basesink_preroll_queue_empty (GstBaseSink * basesink, GstPad * pad)
|
||||||
|
{
|
||||||
|
GstBuffer *buf;
|
||||||
|
GQueue *q = basesink->preroll_queue;
|
||||||
|
|
||||||
|
if (q) {
|
||||||
|
DEBUG ("empty queue\n");
|
||||||
|
while ((buf = g_queue_pop_head (q))) {
|
||||||
|
DEBUG ("pop %p\n", buf);
|
||||||
|
gst_basesink_handle_buffer (basesink, buf);
|
||||||
|
}
|
||||||
|
DEBUG ("queue len %p %d\n", basesink, q->length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* with PREROLL_LOCK */
|
||||||
|
static void
|
||||||
|
gst_basesink_preroll_queue_flush (GstBaseSink * basesink)
|
||||||
|
{
|
||||||
|
GstBuffer *buf;
|
||||||
|
GQueue *q = basesink->preroll_queue;
|
||||||
|
|
||||||
|
DEBUG ("flush %p\n", basesink);
|
||||||
|
if (q) {
|
||||||
|
while ((buf = g_queue_pop_head (q))) {
|
||||||
|
DEBUG ("pop %p\n", buf);
|
||||||
|
gst_buffer_unref (buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
PREROLL_QUEUEING,
|
||||||
|
PREROLL_PLAYING,
|
||||||
|
PREROLL_FLUSHING,
|
||||||
|
PREROLL_ERROR
|
||||||
|
} PrerollReturn;
|
||||||
|
|
||||||
|
/* with STREAM_LOCK */
|
||||||
|
PrerollReturn
|
||||||
gst_basesink_finish_preroll (GstBaseSink * basesink, GstPad * pad,
|
gst_basesink_finish_preroll (GstBaseSink * basesink, GstPad * pad,
|
||||||
GstBuffer * buffer)
|
GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
gboolean usable;
|
gboolean usable;
|
||||||
GstBaseSinkClass *bclass;
|
|
||||||
|
|
||||||
|
DEBUG ("finish preroll %p <\n", basesink);
|
||||||
/* lock order is important */
|
/* lock order is important */
|
||||||
GST_STATE_LOCK (basesink);
|
GST_STATE_LOCK (basesink);
|
||||||
GST_PREROLL_LOCK (pad);
|
GST_PREROLL_LOCK (pad);
|
||||||
|
DEBUG ("finish preroll %p >\n", basesink);
|
||||||
if (!basesink->need_preroll)
|
if (!basesink->need_preroll)
|
||||||
goto no_preroll;
|
goto no_preroll;
|
||||||
|
|
||||||
bclass = GST_BASESINK_GET_CLASS (basesink);
|
|
||||||
|
|
||||||
if (bclass->preroll)
|
|
||||||
bclass->preroll (basesink, buffer);
|
|
||||||
|
|
||||||
gst_element_commit_state (GST_ELEMENT (basesink));
|
gst_element_commit_state (GST_ELEMENT (basesink));
|
||||||
GST_STATE_UNLOCK (basesink);
|
GST_STATE_UNLOCK (basesink);
|
||||||
|
|
||||||
GST_DEBUG ("element %s waiting to finish preroll",
|
gst_basesink_preroll_queue_push (basesink, pad, buffer);
|
||||||
GST_ELEMENT_NAME (basesink));
|
|
||||||
basesink->need_preroll = FALSE;
|
|
||||||
basesink->have_preroll = TRUE;
|
|
||||||
GST_PREROLL_WAIT (pad);
|
|
||||||
GST_DEBUG ("done preroll");
|
|
||||||
basesink->have_preroll = FALSE;
|
|
||||||
|
|
||||||
GST_LOCK (pad);
|
GST_LOCK (pad);
|
||||||
usable = !GST_RPAD_IS_FLUSHING (pad) && GST_RPAD_IS_ACTIVE (pad);
|
usable = !GST_RPAD_IS_FLUSHING (pad) && GST_RPAD_IS_ACTIVE (pad);
|
||||||
|
@ -365,26 +448,40 @@ gst_basesink_finish_preroll (GstBaseSink * basesink, GstPad * pad,
|
||||||
if (!usable)
|
if (!usable)
|
||||||
goto unusable;
|
goto unusable;
|
||||||
|
|
||||||
|
if (basesink->need_preroll)
|
||||||
|
goto still_queueing;
|
||||||
|
|
||||||
GST_DEBUG ("done preroll");
|
GST_DEBUG ("done preroll");
|
||||||
|
|
||||||
|
gst_basesink_preroll_queue_empty (basesink, pad);
|
||||||
|
|
||||||
GST_PREROLL_UNLOCK (pad);
|
GST_PREROLL_UNLOCK (pad);
|
||||||
return GST_FLOW_OK;
|
|
||||||
|
return PREROLL_PLAYING;
|
||||||
|
|
||||||
no_preroll:
|
no_preroll:
|
||||||
{
|
{
|
||||||
|
/* maybe it was another sink that blocked in preroll, need to check for
|
||||||
|
buffers to drain */
|
||||||
|
if (basesink->preroll_queue->length)
|
||||||
|
gst_basesink_preroll_queue_empty (basesink, pad);
|
||||||
GST_PREROLL_UNLOCK (pad);
|
GST_PREROLL_UNLOCK (pad);
|
||||||
GST_STATE_UNLOCK (basesink);
|
GST_STATE_UNLOCK (basesink);
|
||||||
return GST_FLOW_OK;
|
return PREROLL_PLAYING;
|
||||||
}
|
}
|
||||||
unusable:
|
unusable:
|
||||||
{
|
{
|
||||||
GST_DEBUG ("pad is flushing");
|
GST_DEBUG ("pad is flushing");
|
||||||
GST_PREROLL_UNLOCK (pad);
|
GST_PREROLL_UNLOCK (pad);
|
||||||
return GST_FLOW_UNEXPECTED;
|
return PREROLL_FLUSHING;
|
||||||
|
}
|
||||||
|
still_queueing:
|
||||||
|
{
|
||||||
|
GST_PREROLL_UNLOCK (pad);
|
||||||
|
return PREROLL_QUEUEING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_basesink_event (GstPad * pad, GstEvent * event)
|
gst_basesink_event (GstPad * pad, GstEvent * event)
|
||||||
{
|
{
|
||||||
|
@ -396,38 +493,40 @@ gst_basesink_event (GstPad * pad, GstEvent * event)
|
||||||
|
|
||||||
bclass = GST_BASESINK_GET_CLASS (basesink);
|
bclass = GST_BASESINK_GET_CLASS (basesink);
|
||||||
|
|
||||||
|
DEBUG ("event %p\n", basesink);
|
||||||
|
|
||||||
if (bclass->event)
|
if (bclass->event)
|
||||||
bclass->event (basesink, event);
|
bclass->event (basesink, event);
|
||||||
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
case GST_EVENT_EOS:
|
case GST_EVENT_EOS:
|
||||||
{
|
{
|
||||||
GstFlowReturn ret;
|
gboolean need_eos;
|
||||||
|
|
||||||
GST_STREAM_LOCK (pad);
|
GST_STREAM_LOCK (pad);
|
||||||
ret = gst_basesink_finish_preroll (basesink, pad, NULL);
|
|
||||||
if (ret == GST_FLOW_OK) {
|
|
||||||
gboolean need_eos;
|
|
||||||
|
|
||||||
GST_LOCK (basesink);
|
GST_PREROLL_LOCK (pad);
|
||||||
need_eos = basesink->eos = TRUE;
|
gst_basesink_preroll_queue_empty (basesink, pad);
|
||||||
if (basesink->clock) {
|
GST_PREROLL_UNLOCK (pad);
|
||||||
/* wait for last buffer to finish if we have a valid end time */
|
|
||||||
if (GST_CLOCK_TIME_IS_VALID (basesink->end_time)) {
|
|
||||||
basesink->clock_id = gst_clock_new_single_shot_id (basesink->clock,
|
|
||||||
basesink->end_time + GST_ELEMENT (basesink)->base_time);
|
|
||||||
GST_UNLOCK (basesink);
|
|
||||||
|
|
||||||
gst_clock_id_wait (basesink->clock_id, NULL);
|
GST_LOCK (basesink);
|
||||||
|
need_eos = basesink->eos = TRUE;
|
||||||
|
if (basesink->clock) {
|
||||||
|
/* wait for last buffer to finish if we have a valid end time */
|
||||||
|
if (GST_CLOCK_TIME_IS_VALID (basesink->end_time)) {
|
||||||
|
basesink->clock_id = gst_clock_new_single_shot_id (basesink->clock,
|
||||||
|
basesink->end_time + GST_ELEMENT (basesink)->base_time);
|
||||||
|
GST_UNLOCK (basesink);
|
||||||
|
|
||||||
GST_LOCK (basesink);
|
gst_clock_id_wait (basesink->clock_id, NULL);
|
||||||
if (basesink->clock_id) {
|
|
||||||
gst_clock_id_unref (basesink->clock_id);
|
GST_LOCK (basesink);
|
||||||
basesink->clock_id = NULL;
|
if (basesink->clock_id) {
|
||||||
}
|
gst_clock_id_unref (basesink->clock_id);
|
||||||
basesink->end_time = GST_CLOCK_TIME_NONE;
|
basesink->clock_id = NULL;
|
||||||
need_eos = basesink->eos;
|
|
||||||
}
|
}
|
||||||
|
basesink->end_time = GST_CLOCK_TIME_NONE;
|
||||||
|
need_eos = basesink->eos;
|
||||||
}
|
}
|
||||||
GST_UNLOCK (basesink);
|
GST_UNLOCK (basesink);
|
||||||
|
|
||||||
|
@ -462,6 +561,7 @@ gst_basesink_event (GstPad * pad, GstEvent * event)
|
||||||
/* unlock from a possible state change/preroll */
|
/* unlock from a possible state change/preroll */
|
||||||
GST_PREROLL_LOCK (pad);
|
GST_PREROLL_LOCK (pad);
|
||||||
basesink->need_preroll = TRUE;
|
basesink->need_preroll = TRUE;
|
||||||
|
gst_basesink_preroll_queue_flush (basesink);
|
||||||
GST_PREROLL_SIGNAL (pad);
|
GST_PREROLL_SIGNAL (pad);
|
||||||
GST_PREROLL_UNLOCK (pad);
|
GST_PREROLL_UNLOCK (pad);
|
||||||
}
|
}
|
||||||
|
@ -528,29 +628,47 @@ gst_basesink_do_sync (GstBaseSink * basesink, GstBuffer * buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static inline void
|
||||||
gst_basesink_chain_unlocked (GstPad * pad, GstBuffer * buf)
|
gst_basesink_handle_buffer (GstBaseSink * basesink, GstBuffer * buf)
|
||||||
{
|
{
|
||||||
GstBaseSink *basesink;
|
|
||||||
GstFlowReturn result = GST_FLOW_OK;
|
|
||||||
GstBaseSinkClass *bclass;
|
GstBaseSinkClass *bclass;
|
||||||
|
|
||||||
basesink = GST_BASESINK (GST_OBJECT_PARENT (pad));
|
|
||||||
|
|
||||||
result = gst_basesink_finish_preroll (basesink, pad, buf);
|
|
||||||
if (result != GST_FLOW_OK)
|
|
||||||
goto exit;
|
|
||||||
|
|
||||||
gst_basesink_do_sync (basesink, buf);
|
gst_basesink_do_sync (basesink, buf);
|
||||||
|
|
||||||
bclass = GST_BASESINK_GET_CLASS (basesink);
|
bclass = GST_BASESINK_GET_CLASS (basesink);
|
||||||
if (bclass->render)
|
if (bclass->render)
|
||||||
bclass->render (basesink, buf);
|
bclass->render (basesink, buf);
|
||||||
|
|
||||||
exit:
|
DEBUG ("unref %p %p\n", basesink, buf);
|
||||||
gst_buffer_unref (buf);
|
gst_buffer_unref (buf);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
static GstFlowReturn
|
||||||
|
gst_basesink_chain_unlocked (GstPad * pad, GstBuffer * buf)
|
||||||
|
{
|
||||||
|
GstBaseSink *basesink;
|
||||||
|
PrerollReturn result;
|
||||||
|
|
||||||
|
basesink = GST_BASESINK (GST_OBJECT_PARENT (pad));
|
||||||
|
|
||||||
|
DEBUG ("chain_unlocked %p\n", basesink);
|
||||||
|
|
||||||
|
result = gst_basesink_finish_preroll (basesink, pad, buf);
|
||||||
|
|
||||||
|
DEBUG ("chain_unlocked %p after\n", basesink);
|
||||||
|
|
||||||
|
switch (result) {
|
||||||
|
case PREROLL_QUEUEING:
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
case PREROLL_PLAYING:
|
||||||
|
gst_basesink_handle_buffer (basesink, buf);
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
case PREROLL_FLUSHING:
|
||||||
|
return GST_FLOW_UNEXPECTED;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
return GST_FLOW_UNEXPECTED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
|
@ -591,13 +709,14 @@ gst_basesink_loop (GstPad * pad)
|
||||||
if (result != GST_FLOW_OK)
|
if (result != GST_FLOW_OK)
|
||||||
goto paused;
|
goto paused;
|
||||||
|
|
||||||
exit:
|
/* default */
|
||||||
GST_STREAM_UNLOCK (pad);
|
GST_STREAM_UNLOCK (pad);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
paused:
|
paused:
|
||||||
gst_task_pause (GST_RPAD_TASK (pad));
|
gst_task_pause (GST_RPAD_TASK (pad));
|
||||||
goto exit;
|
GST_STREAM_UNLOCK (pad);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -665,6 +784,8 @@ gst_basesink_change_state (GstElement * element)
|
||||||
GstBaseSink *basesink = GST_BASESINK (element);
|
GstBaseSink *basesink = GST_BASESINK (element);
|
||||||
GstElementState transition = GST_STATE_TRANSITION (element);
|
GstElementState transition = GST_STATE_TRANSITION (element);
|
||||||
|
|
||||||
|
DEBUG ("state change > %p %x\n", basesink, transition);
|
||||||
|
|
||||||
switch (transition) {
|
switch (transition) {
|
||||||
case GST_STATE_NULL_TO_READY:
|
case GST_STATE_NULL_TO_READY:
|
||||||
break;
|
break;
|
||||||
|
@ -673,6 +794,7 @@ gst_basesink_change_state (GstElement * element)
|
||||||
* is no data flow in READY so we cqn safely assume we need to preroll. */
|
* is no data flow in READY so we cqn safely assume we need to preroll. */
|
||||||
basesink->offset = 0;
|
basesink->offset = 0;
|
||||||
GST_PREROLL_LOCK (basesink->sinkpad);
|
GST_PREROLL_LOCK (basesink->sinkpad);
|
||||||
|
basesink->preroll_queue = g_queue_new ();
|
||||||
basesink->need_preroll = TRUE;
|
basesink->need_preroll = TRUE;
|
||||||
basesink->have_preroll = FALSE;
|
basesink->have_preroll = FALSE;
|
||||||
GST_PREROLL_UNLOCK (basesink->sinkpad);
|
GST_PREROLL_UNLOCK (basesink->sinkpad);
|
||||||
|
@ -715,6 +837,22 @@ gst_basesink_change_state (GstElement * element)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GST_STATE_PAUSED_TO_READY:
|
case GST_STATE_PAUSED_TO_READY:
|
||||||
|
/* flush out the data thread if it's locked in finish_preroll */
|
||||||
|
GST_PREROLL_LOCK (basesink->sinkpad);
|
||||||
|
|
||||||
|
gst_basesink_preroll_queue_flush (basesink);
|
||||||
|
g_queue_free (basesink->preroll_queue);
|
||||||
|
basesink->preroll_queue = NULL;
|
||||||
|
|
||||||
|
if (basesink->have_preroll)
|
||||||
|
GST_PREROLL_SIGNAL (basesink->sinkpad);
|
||||||
|
|
||||||
|
basesink->need_preroll = FALSE;
|
||||||
|
basesink->have_preroll = FALSE;
|
||||||
|
GST_PREROLL_UNLOCK (basesink->sinkpad);
|
||||||
|
/* make sure the element is finished processing */
|
||||||
|
GST_STREAM_LOCK (basesink->sinkpad);
|
||||||
|
GST_STREAM_UNLOCK (basesink->sinkpad);
|
||||||
break;
|
break;
|
||||||
case GST_STATE_READY_TO_NULL:
|
case GST_STATE_READY_TO_NULL:
|
||||||
break;
|
break;
|
||||||
|
@ -723,5 +861,6 @@ gst_basesink_change_state (GstElement * element)
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||||
|
DEBUG ("state change < %p %x\n", basesink, transition);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,9 @@ struct _GstBaseSink {
|
||||||
GstPad *sinkpad;
|
GstPad *sinkpad;
|
||||||
GstActivateMode pad_mode;
|
GstActivateMode pad_mode;
|
||||||
|
|
||||||
|
GQueue *preroll_queue; /* with PREROLL_LOCK */
|
||||||
|
gint preroll_queue_max_len; /* with PREROLL_LOCK */
|
||||||
|
|
||||||
guint64 offset;
|
guint64 offset;
|
||||||
gboolean has_loop;
|
gboolean has_loop;
|
||||||
gboolean has_chain;
|
gboolean has_chain;
|
||||||
|
|
|
@ -34,7 +34,14 @@ static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_DEBUG_CATEGORY_STATIC (gst_basesink_debug);
|
GST_DEBUG_CATEGORY_STATIC (gst_basesink_debug);
|
||||||
#define GST_CAT_DEFAULT gst_basesink_debug
|
#define GST_CAT_DEFAULT gst_basesink_debug
|
||||||
|
|
||||||
/* BaseSink signals and args */
|
/* #define DEBUGGING */
|
||||||
|
#ifdef DEBUGGING
|
||||||
|
#define DEBUG(str,args...) g_print (str,##args)
|
||||||
|
#else
|
||||||
|
#define DEBUG(str,args...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* BaseSink signals and properties */
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
/* FILL ME */
|
/* FILL ME */
|
||||||
|
@ -48,9 +55,10 @@ enum
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
ARG_0,
|
PROP_0,
|
||||||
ARG_HAS_LOOP,
|
PROP_HAS_LOOP,
|
||||||
ARG_HAS_CHAIN
|
PROP_HAS_CHAIN,
|
||||||
|
PROP_PREROLL_QUEUE_LEN
|
||||||
};
|
};
|
||||||
|
|
||||||
#define _do_init(bla) \
|
#define _do_init(bla) \
|
||||||
|
@ -82,6 +90,8 @@ static void gst_basesink_loop (GstPad * pad);
|
||||||
static GstFlowReturn gst_basesink_chain (GstPad * pad, GstBuffer * buffer);
|
static GstFlowReturn gst_basesink_chain (GstPad * pad, GstBuffer * buffer);
|
||||||
static gboolean gst_basesink_activate (GstPad * pad, GstActivateMode mode);
|
static gboolean gst_basesink_activate (GstPad * pad, GstActivateMode mode);
|
||||||
static gboolean gst_basesink_event (GstPad * pad, GstEvent * event);
|
static gboolean gst_basesink_event (GstPad * pad, GstEvent * event);
|
||||||
|
static inline void gst_basesink_handle_buffer (GstBaseSink * basesink,
|
||||||
|
GstBuffer * buf);
|
||||||
|
|
||||||
static GstStaticPadTemplate *
|
static GstStaticPadTemplate *
|
||||||
gst_basesink_get_template (GstBaseSink * bsink)
|
gst_basesink_get_template (GstBaseSink * bsink)
|
||||||
|
@ -123,14 +133,19 @@ gst_basesink_class_init (GstBaseSinkClass * klass)
|
||||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_basesink_set_property);
|
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_basesink_set_property);
|
||||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_basesink_get_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_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_LOOP,
|
||||||
g_param_spec_boolean ("has-loop", "has-loop",
|
g_param_spec_boolean ("has-loop", "has-loop",
|
||||||
"Enable loop-based operation", DEFAULT_HAS_LOOP,
|
"Enable loop-based operation", DEFAULT_HAS_LOOP,
|
||||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HAS_CHAIN,
|
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_CHAIN,
|
||||||
g_param_spec_boolean ("has-chain", "has-chain",
|
g_param_spec_boolean ("has-chain", "has-chain",
|
||||||
"Enable chain-based operation", DEFAULT_HAS_CHAIN,
|
"Enable chain-based operation", DEFAULT_HAS_CHAIN,
|
||||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||||
|
g_object_class_install_property (G_OBJECT_CLASS (klass),
|
||||||
|
PROP_PREROLL_QUEUE_LEN,
|
||||||
|
g_param_spec_uint ("preroll-queue-len", "preroll-queue-len",
|
||||||
|
"Number of buffers to queue during preroll", 0, G_MAXUINT, 0,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||||
|
|
||||||
gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_basesink_set_clock);
|
gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_basesink_set_clock);
|
||||||
gstelement_class->change_state =
|
gstelement_class->change_state =
|
||||||
|
@ -262,22 +277,29 @@ gst_basesink_set_property (GObject * object, guint prop_id,
|
||||||
{
|
{
|
||||||
GstBaseSink *sink;
|
GstBaseSink *sink;
|
||||||
|
|
||||||
/* it's not null if we got it, but it might not be ours */
|
|
||||||
sink = GST_BASESINK (object);
|
sink = GST_BASESINK (object);
|
||||||
|
|
||||||
|
GST_LOCK (sink);
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case ARG_HAS_LOOP:
|
case PROP_HAS_LOOP:
|
||||||
sink->has_loop = g_value_get_boolean (value);
|
sink->has_loop = g_value_get_boolean (value);
|
||||||
gst_basesink_set_all_pad_functions (sink);
|
gst_basesink_set_all_pad_functions (sink);
|
||||||
break;
|
break;
|
||||||
case ARG_HAS_CHAIN:
|
case PROP_HAS_CHAIN:
|
||||||
sink->has_chain = g_value_get_boolean (value);
|
sink->has_chain = g_value_get_boolean (value);
|
||||||
gst_basesink_set_all_pad_functions (sink);
|
gst_basesink_set_all_pad_functions (sink);
|
||||||
break;
|
break;
|
||||||
|
case PROP_PREROLL_QUEUE_LEN:
|
||||||
|
/* preroll lock necessary to serialize with finish_preroll */
|
||||||
|
GST_PREROLL_LOCK (sink->sinkpad);
|
||||||
|
sink->preroll_queue_max_len = g_value_get_uint (value);
|
||||||
|
GST_PREROLL_UNLOCK (sink->sinkpad);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
GST_UNLOCK (sink);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -286,22 +308,24 @@ gst_basesink_get_property (GObject * object, guint prop_id, GValue * value,
|
||||||
{
|
{
|
||||||
GstBaseSink *sink;
|
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);
|
sink = GST_BASESINK (object);
|
||||||
|
|
||||||
|
GST_LOCK (sink);
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case ARG_HAS_LOOP:
|
case PROP_HAS_LOOP:
|
||||||
g_value_set_boolean (value, sink->has_loop);
|
g_value_set_boolean (value, sink->has_loop);
|
||||||
break;
|
break;
|
||||||
case ARG_HAS_CHAIN:
|
case PROP_HAS_CHAIN:
|
||||||
g_value_set_boolean (value, sink->has_chain);
|
g_value_set_boolean (value, sink->has_chain);
|
||||||
break;
|
break;
|
||||||
|
case PROP_PREROLL_QUEUE_LEN:
|
||||||
|
g_value_set_uint (value, sink->preroll_queue_max_len);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
GST_UNLOCK (sink);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstStaticPadTemplate *
|
static GstStaticPadTemplate *
|
||||||
|
@ -329,35 +353,94 @@ gst_base_sink_buffer_alloc (GstBaseSink * sink, guint64 offset, guint size,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* STREAM_LOCK should be held */
|
/* with PREROLL_LOCK */
|
||||||
GstFlowReturn
|
static void
|
||||||
|
gst_basesink_preroll_queue_push (GstBaseSink * basesink, GstPad * pad,
|
||||||
|
GstBuffer * buffer)
|
||||||
|
{
|
||||||
|
if (basesink->preroll_queue->length == 0) {
|
||||||
|
GstBaseSinkClass *bclass = GST_BASESINK_GET_CLASS (basesink);
|
||||||
|
|
||||||
|
if (bclass->preroll)
|
||||||
|
bclass->preroll (basesink, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (basesink->preroll_queue->length < basesink->preroll_queue_max_len) {
|
||||||
|
DEBUG ("push %p %p\n", basesink, buffer);
|
||||||
|
g_queue_push_tail (basesink->preroll_queue, buffer);
|
||||||
|
} else {
|
||||||
|
/* block until the state changes, or we get a flush, or something */
|
||||||
|
DEBUG ("block %p %p\n", basesink, buffer);
|
||||||
|
GST_DEBUG ("element %s waiting to finish preroll",
|
||||||
|
GST_ELEMENT_NAME (basesink));
|
||||||
|
basesink->need_preroll = FALSE;
|
||||||
|
basesink->have_preroll = TRUE;
|
||||||
|
GST_PREROLL_WAIT (pad);
|
||||||
|
GST_DEBUG ("done preroll");
|
||||||
|
basesink->have_preroll = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* with PREROLL_LOCK */
|
||||||
|
static void
|
||||||
|
gst_basesink_preroll_queue_empty (GstBaseSink * basesink, GstPad * pad)
|
||||||
|
{
|
||||||
|
GstBuffer *buf;
|
||||||
|
GQueue *q = basesink->preroll_queue;
|
||||||
|
|
||||||
|
if (q) {
|
||||||
|
DEBUG ("empty queue\n");
|
||||||
|
while ((buf = g_queue_pop_head (q))) {
|
||||||
|
DEBUG ("pop %p\n", buf);
|
||||||
|
gst_basesink_handle_buffer (basesink, buf);
|
||||||
|
}
|
||||||
|
DEBUG ("queue len %p %d\n", basesink, q->length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* with PREROLL_LOCK */
|
||||||
|
static void
|
||||||
|
gst_basesink_preroll_queue_flush (GstBaseSink * basesink)
|
||||||
|
{
|
||||||
|
GstBuffer *buf;
|
||||||
|
GQueue *q = basesink->preroll_queue;
|
||||||
|
|
||||||
|
DEBUG ("flush %p\n", basesink);
|
||||||
|
if (q) {
|
||||||
|
while ((buf = g_queue_pop_head (q))) {
|
||||||
|
DEBUG ("pop %p\n", buf);
|
||||||
|
gst_buffer_unref (buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
PREROLL_QUEUEING,
|
||||||
|
PREROLL_PLAYING,
|
||||||
|
PREROLL_FLUSHING,
|
||||||
|
PREROLL_ERROR
|
||||||
|
} PrerollReturn;
|
||||||
|
|
||||||
|
/* with STREAM_LOCK */
|
||||||
|
PrerollReturn
|
||||||
gst_basesink_finish_preroll (GstBaseSink * basesink, GstPad * pad,
|
gst_basesink_finish_preroll (GstBaseSink * basesink, GstPad * pad,
|
||||||
GstBuffer * buffer)
|
GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
gboolean usable;
|
gboolean usable;
|
||||||
GstBaseSinkClass *bclass;
|
|
||||||
|
|
||||||
|
DEBUG ("finish preroll %p <\n", basesink);
|
||||||
/* lock order is important */
|
/* lock order is important */
|
||||||
GST_STATE_LOCK (basesink);
|
GST_STATE_LOCK (basesink);
|
||||||
GST_PREROLL_LOCK (pad);
|
GST_PREROLL_LOCK (pad);
|
||||||
|
DEBUG ("finish preroll %p >\n", basesink);
|
||||||
if (!basesink->need_preroll)
|
if (!basesink->need_preroll)
|
||||||
goto no_preroll;
|
goto no_preroll;
|
||||||
|
|
||||||
bclass = GST_BASESINK_GET_CLASS (basesink);
|
|
||||||
|
|
||||||
if (bclass->preroll)
|
|
||||||
bclass->preroll (basesink, buffer);
|
|
||||||
|
|
||||||
gst_element_commit_state (GST_ELEMENT (basesink));
|
gst_element_commit_state (GST_ELEMENT (basesink));
|
||||||
GST_STATE_UNLOCK (basesink);
|
GST_STATE_UNLOCK (basesink);
|
||||||
|
|
||||||
GST_DEBUG ("element %s waiting to finish preroll",
|
gst_basesink_preroll_queue_push (basesink, pad, buffer);
|
||||||
GST_ELEMENT_NAME (basesink));
|
|
||||||
basesink->need_preroll = FALSE;
|
|
||||||
basesink->have_preroll = TRUE;
|
|
||||||
GST_PREROLL_WAIT (pad);
|
|
||||||
GST_DEBUG ("done preroll");
|
|
||||||
basesink->have_preroll = FALSE;
|
|
||||||
|
|
||||||
GST_LOCK (pad);
|
GST_LOCK (pad);
|
||||||
usable = !GST_RPAD_IS_FLUSHING (pad) && GST_RPAD_IS_ACTIVE (pad);
|
usable = !GST_RPAD_IS_FLUSHING (pad) && GST_RPAD_IS_ACTIVE (pad);
|
||||||
|
@ -365,26 +448,40 @@ gst_basesink_finish_preroll (GstBaseSink * basesink, GstPad * pad,
|
||||||
if (!usable)
|
if (!usable)
|
||||||
goto unusable;
|
goto unusable;
|
||||||
|
|
||||||
|
if (basesink->need_preroll)
|
||||||
|
goto still_queueing;
|
||||||
|
|
||||||
GST_DEBUG ("done preroll");
|
GST_DEBUG ("done preroll");
|
||||||
|
|
||||||
|
gst_basesink_preroll_queue_empty (basesink, pad);
|
||||||
|
|
||||||
GST_PREROLL_UNLOCK (pad);
|
GST_PREROLL_UNLOCK (pad);
|
||||||
return GST_FLOW_OK;
|
|
||||||
|
return PREROLL_PLAYING;
|
||||||
|
|
||||||
no_preroll:
|
no_preroll:
|
||||||
{
|
{
|
||||||
|
/* maybe it was another sink that blocked in preroll, need to check for
|
||||||
|
buffers to drain */
|
||||||
|
if (basesink->preroll_queue->length)
|
||||||
|
gst_basesink_preroll_queue_empty (basesink, pad);
|
||||||
GST_PREROLL_UNLOCK (pad);
|
GST_PREROLL_UNLOCK (pad);
|
||||||
GST_STATE_UNLOCK (basesink);
|
GST_STATE_UNLOCK (basesink);
|
||||||
return GST_FLOW_OK;
|
return PREROLL_PLAYING;
|
||||||
}
|
}
|
||||||
unusable:
|
unusable:
|
||||||
{
|
{
|
||||||
GST_DEBUG ("pad is flushing");
|
GST_DEBUG ("pad is flushing");
|
||||||
GST_PREROLL_UNLOCK (pad);
|
GST_PREROLL_UNLOCK (pad);
|
||||||
return GST_FLOW_UNEXPECTED;
|
return PREROLL_FLUSHING;
|
||||||
|
}
|
||||||
|
still_queueing:
|
||||||
|
{
|
||||||
|
GST_PREROLL_UNLOCK (pad);
|
||||||
|
return PREROLL_QUEUEING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_basesink_event (GstPad * pad, GstEvent * event)
|
gst_basesink_event (GstPad * pad, GstEvent * event)
|
||||||
{
|
{
|
||||||
|
@ -396,38 +493,40 @@ gst_basesink_event (GstPad * pad, GstEvent * event)
|
||||||
|
|
||||||
bclass = GST_BASESINK_GET_CLASS (basesink);
|
bclass = GST_BASESINK_GET_CLASS (basesink);
|
||||||
|
|
||||||
|
DEBUG ("event %p\n", basesink);
|
||||||
|
|
||||||
if (bclass->event)
|
if (bclass->event)
|
||||||
bclass->event (basesink, event);
|
bclass->event (basesink, event);
|
||||||
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
case GST_EVENT_EOS:
|
case GST_EVENT_EOS:
|
||||||
{
|
{
|
||||||
GstFlowReturn ret;
|
gboolean need_eos;
|
||||||
|
|
||||||
GST_STREAM_LOCK (pad);
|
GST_STREAM_LOCK (pad);
|
||||||
ret = gst_basesink_finish_preroll (basesink, pad, NULL);
|
|
||||||
if (ret == GST_FLOW_OK) {
|
|
||||||
gboolean need_eos;
|
|
||||||
|
|
||||||
GST_LOCK (basesink);
|
GST_PREROLL_LOCK (pad);
|
||||||
need_eos = basesink->eos = TRUE;
|
gst_basesink_preroll_queue_empty (basesink, pad);
|
||||||
if (basesink->clock) {
|
GST_PREROLL_UNLOCK (pad);
|
||||||
/* wait for last buffer to finish if we have a valid end time */
|
|
||||||
if (GST_CLOCK_TIME_IS_VALID (basesink->end_time)) {
|
|
||||||
basesink->clock_id = gst_clock_new_single_shot_id (basesink->clock,
|
|
||||||
basesink->end_time + GST_ELEMENT (basesink)->base_time);
|
|
||||||
GST_UNLOCK (basesink);
|
|
||||||
|
|
||||||
gst_clock_id_wait (basesink->clock_id, NULL);
|
GST_LOCK (basesink);
|
||||||
|
need_eos = basesink->eos = TRUE;
|
||||||
|
if (basesink->clock) {
|
||||||
|
/* wait for last buffer to finish if we have a valid end time */
|
||||||
|
if (GST_CLOCK_TIME_IS_VALID (basesink->end_time)) {
|
||||||
|
basesink->clock_id = gst_clock_new_single_shot_id (basesink->clock,
|
||||||
|
basesink->end_time + GST_ELEMENT (basesink)->base_time);
|
||||||
|
GST_UNLOCK (basesink);
|
||||||
|
|
||||||
GST_LOCK (basesink);
|
gst_clock_id_wait (basesink->clock_id, NULL);
|
||||||
if (basesink->clock_id) {
|
|
||||||
gst_clock_id_unref (basesink->clock_id);
|
GST_LOCK (basesink);
|
||||||
basesink->clock_id = NULL;
|
if (basesink->clock_id) {
|
||||||
}
|
gst_clock_id_unref (basesink->clock_id);
|
||||||
basesink->end_time = GST_CLOCK_TIME_NONE;
|
basesink->clock_id = NULL;
|
||||||
need_eos = basesink->eos;
|
|
||||||
}
|
}
|
||||||
|
basesink->end_time = GST_CLOCK_TIME_NONE;
|
||||||
|
need_eos = basesink->eos;
|
||||||
}
|
}
|
||||||
GST_UNLOCK (basesink);
|
GST_UNLOCK (basesink);
|
||||||
|
|
||||||
|
@ -462,6 +561,7 @@ gst_basesink_event (GstPad * pad, GstEvent * event)
|
||||||
/* unlock from a possible state change/preroll */
|
/* unlock from a possible state change/preroll */
|
||||||
GST_PREROLL_LOCK (pad);
|
GST_PREROLL_LOCK (pad);
|
||||||
basesink->need_preroll = TRUE;
|
basesink->need_preroll = TRUE;
|
||||||
|
gst_basesink_preroll_queue_flush (basesink);
|
||||||
GST_PREROLL_SIGNAL (pad);
|
GST_PREROLL_SIGNAL (pad);
|
||||||
GST_PREROLL_UNLOCK (pad);
|
GST_PREROLL_UNLOCK (pad);
|
||||||
}
|
}
|
||||||
|
@ -528,29 +628,47 @@ gst_basesink_do_sync (GstBaseSink * basesink, GstBuffer * buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static inline void
|
||||||
gst_basesink_chain_unlocked (GstPad * pad, GstBuffer * buf)
|
gst_basesink_handle_buffer (GstBaseSink * basesink, GstBuffer * buf)
|
||||||
{
|
{
|
||||||
GstBaseSink *basesink;
|
|
||||||
GstFlowReturn result = GST_FLOW_OK;
|
|
||||||
GstBaseSinkClass *bclass;
|
GstBaseSinkClass *bclass;
|
||||||
|
|
||||||
basesink = GST_BASESINK (GST_OBJECT_PARENT (pad));
|
|
||||||
|
|
||||||
result = gst_basesink_finish_preroll (basesink, pad, buf);
|
|
||||||
if (result != GST_FLOW_OK)
|
|
||||||
goto exit;
|
|
||||||
|
|
||||||
gst_basesink_do_sync (basesink, buf);
|
gst_basesink_do_sync (basesink, buf);
|
||||||
|
|
||||||
bclass = GST_BASESINK_GET_CLASS (basesink);
|
bclass = GST_BASESINK_GET_CLASS (basesink);
|
||||||
if (bclass->render)
|
if (bclass->render)
|
||||||
bclass->render (basesink, buf);
|
bclass->render (basesink, buf);
|
||||||
|
|
||||||
exit:
|
DEBUG ("unref %p %p\n", basesink, buf);
|
||||||
gst_buffer_unref (buf);
|
gst_buffer_unref (buf);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
static GstFlowReturn
|
||||||
|
gst_basesink_chain_unlocked (GstPad * pad, GstBuffer * buf)
|
||||||
|
{
|
||||||
|
GstBaseSink *basesink;
|
||||||
|
PrerollReturn result;
|
||||||
|
|
||||||
|
basesink = GST_BASESINK (GST_OBJECT_PARENT (pad));
|
||||||
|
|
||||||
|
DEBUG ("chain_unlocked %p\n", basesink);
|
||||||
|
|
||||||
|
result = gst_basesink_finish_preroll (basesink, pad, buf);
|
||||||
|
|
||||||
|
DEBUG ("chain_unlocked %p after\n", basesink);
|
||||||
|
|
||||||
|
switch (result) {
|
||||||
|
case PREROLL_QUEUEING:
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
case PREROLL_PLAYING:
|
||||||
|
gst_basesink_handle_buffer (basesink, buf);
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
case PREROLL_FLUSHING:
|
||||||
|
return GST_FLOW_UNEXPECTED;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
return GST_FLOW_UNEXPECTED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
|
@ -591,13 +709,14 @@ gst_basesink_loop (GstPad * pad)
|
||||||
if (result != GST_FLOW_OK)
|
if (result != GST_FLOW_OK)
|
||||||
goto paused;
|
goto paused;
|
||||||
|
|
||||||
exit:
|
/* default */
|
||||||
GST_STREAM_UNLOCK (pad);
|
GST_STREAM_UNLOCK (pad);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
paused:
|
paused:
|
||||||
gst_task_pause (GST_RPAD_TASK (pad));
|
gst_task_pause (GST_RPAD_TASK (pad));
|
||||||
goto exit;
|
GST_STREAM_UNLOCK (pad);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -665,6 +784,8 @@ gst_basesink_change_state (GstElement * element)
|
||||||
GstBaseSink *basesink = GST_BASESINK (element);
|
GstBaseSink *basesink = GST_BASESINK (element);
|
||||||
GstElementState transition = GST_STATE_TRANSITION (element);
|
GstElementState transition = GST_STATE_TRANSITION (element);
|
||||||
|
|
||||||
|
DEBUG ("state change > %p %x\n", basesink, transition);
|
||||||
|
|
||||||
switch (transition) {
|
switch (transition) {
|
||||||
case GST_STATE_NULL_TO_READY:
|
case GST_STATE_NULL_TO_READY:
|
||||||
break;
|
break;
|
||||||
|
@ -673,6 +794,7 @@ gst_basesink_change_state (GstElement * element)
|
||||||
* is no data flow in READY so we cqn safely assume we need to preroll. */
|
* is no data flow in READY so we cqn safely assume we need to preroll. */
|
||||||
basesink->offset = 0;
|
basesink->offset = 0;
|
||||||
GST_PREROLL_LOCK (basesink->sinkpad);
|
GST_PREROLL_LOCK (basesink->sinkpad);
|
||||||
|
basesink->preroll_queue = g_queue_new ();
|
||||||
basesink->need_preroll = TRUE;
|
basesink->need_preroll = TRUE;
|
||||||
basesink->have_preroll = FALSE;
|
basesink->have_preroll = FALSE;
|
||||||
GST_PREROLL_UNLOCK (basesink->sinkpad);
|
GST_PREROLL_UNLOCK (basesink->sinkpad);
|
||||||
|
@ -715,6 +837,22 @@ gst_basesink_change_state (GstElement * element)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GST_STATE_PAUSED_TO_READY:
|
case GST_STATE_PAUSED_TO_READY:
|
||||||
|
/* flush out the data thread if it's locked in finish_preroll */
|
||||||
|
GST_PREROLL_LOCK (basesink->sinkpad);
|
||||||
|
|
||||||
|
gst_basesink_preroll_queue_flush (basesink);
|
||||||
|
g_queue_free (basesink->preroll_queue);
|
||||||
|
basesink->preroll_queue = NULL;
|
||||||
|
|
||||||
|
if (basesink->have_preroll)
|
||||||
|
GST_PREROLL_SIGNAL (basesink->sinkpad);
|
||||||
|
|
||||||
|
basesink->need_preroll = FALSE;
|
||||||
|
basesink->have_preroll = FALSE;
|
||||||
|
GST_PREROLL_UNLOCK (basesink->sinkpad);
|
||||||
|
/* make sure the element is finished processing */
|
||||||
|
GST_STREAM_LOCK (basesink->sinkpad);
|
||||||
|
GST_STREAM_UNLOCK (basesink->sinkpad);
|
||||||
break;
|
break;
|
||||||
case GST_STATE_READY_TO_NULL:
|
case GST_STATE_READY_TO_NULL:
|
||||||
break;
|
break;
|
||||||
|
@ -723,5 +861,6 @@ gst_basesink_change_state (GstElement * element)
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||||
|
DEBUG ("state change < %p %x\n", basesink, transition);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,9 @@ struct _GstBaseSink {
|
||||||
GstPad *sinkpad;
|
GstPad *sinkpad;
|
||||||
GstActivateMode pad_mode;
|
GstActivateMode pad_mode;
|
||||||
|
|
||||||
|
GQueue *preroll_queue; /* with PREROLL_LOCK */
|
||||||
|
gint preroll_queue_max_len; /* with PREROLL_LOCK */
|
||||||
|
|
||||||
guint64 offset;
|
guint64 offset;
|
||||||
gboolean has_loop;
|
gboolean has_loop;
|
||||||
gboolean has_chain;
|
gboolean has_chain;
|
||||||
|
|
|
@ -98,7 +98,9 @@ START_TEST (test_fake_object_name)
|
||||||
object = g_object_new (gst_fake_object_get_type (), NULL);
|
object = g_object_new (gst_fake_object_get_type (), NULL);
|
||||||
|
|
||||||
name = gst_object_get_name (object);
|
name = gst_object_get_name (object);
|
||||||
fail_if (name != NULL, "Newly created object has a name");
|
fail_if (name == NULL, "Newly created object has no name");
|
||||||
|
fail_if (strncmp (name, "fakeobject", 10) != 0,
|
||||||
|
"Random name %s does not start with Gst", name);
|
||||||
|
|
||||||
/* give a random name by setting with NULL;
|
/* give a random name by setting with NULL;
|
||||||
* GstFakeObject class -> fakeobject%d */
|
* GstFakeObject class -> fakeobject%d */
|
||||||
|
|
Loading…
Reference in a new issue