Add finalize method to RealPad.

Original commit message from CVS:
Add finalize method to RealPad.
Add new lock to correctly do the preroll, should probably not
be put here.
Make fakesink do preroll correctly. Emit a message when the
preroll sample is queued.
Add more info in gst-launch regarding state changes.
This commit is contained in:
Wim Taymans 2005-02-21 18:49:19 +00:00
parent 6664bebb6d
commit ed1664fbaf
8 changed files with 373 additions and 112 deletions

View file

@ -1,3 +1,22 @@
2005-02-21 Wim Taymans <wim@fluendo.com>
* gst/elements/gstfakesink.c: (gst_fakesink_init),
(gst_fakesink_finish_preroll), (gst_fakesink_event),
(gst_fakesink_chain_unlocked), (gst_fakesink_activate),
(gst_fakesink_change_state):
* gst/elements/gstfakesink.h:
* gst/gstpad.c: (gst_real_pad_class_init), (gst_real_pad_init),
(gst_real_pad_dispose), (gst_real_pad_finalize):
* gst/gstpad.h:
* tools/gst-launch.c: (main):
Add finalize method to RealPad.
Add new lock to correctly do the preroll, should probably not
be put here.
Make fakesink do preroll correctly. Emit a message when the
preroll sample is queued.
Add more info in gst-launch regarding state changes.
2005-02-21 Andy Wingo <wingo@pobox.com>
* gst/elements/gstfakesink.c:

View file

@ -198,12 +198,10 @@ gst_fakesink_class_init (GstFakeSinkClass * klass)
static void
gst_fakesink_init (GstFakeSink * fakesink)
{
GstPad *pad;
pad =
fakesink->sinkpad =
gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
"sink");
gst_element_add_pad (GST_ELEMENT (fakesink), pad);
gst_element_add_pad (GST_ELEMENT (fakesink), fakesink->sinkpad);
fakesink->silent = FALSE;
fakesink->dump = FALSE;
@ -212,7 +210,7 @@ gst_fakesink_init (GstFakeSink * fakesink)
fakesink->state_error = FAKESINK_STATE_ERROR_NONE;
fakesink->signal_handoffs = FALSE;
fakesink->pad_mode = GST_ACTIVATE_NONE;
GST_RPAD_TASK (pad) = NULL;
GST_RPAD_TASK (fakesink->sinkpad) = NULL;
}
static void
@ -357,55 +355,66 @@ gst_fakesink_get_property (GObject * object, guint prop_id, GValue * value,
}
}
static gboolean
gst_fakesink_activate (GstPad * pad, GstActivateMode mode)
/* STREAM_LOCK should be held */
GstFlowReturn
gst_fakesink_finish_preroll (GstFakeSink * fakesink, GstPad * pad)
{
gboolean result = FALSE;
GstFakeSink *fakesink;
/* lock order is important */
GST_STATE_LOCK (fakesink);
GST_PREROLL_LOCK (pad);
if (!fakesink->need_preroll)
goto no_preroll;
fakesink = GST_FAKESINK (GST_OBJECT_PARENT (pad));
if (!fakesink->silent) {
g_free (fakesink->last_message);
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);
fakesink->last_message =
g_strdup_printf ("preroll ******* (%s:%s)", GST_DEBUG_PAD_NAME (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) */
/* 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;
g_object_notify (G_OBJECT (fakesink), "last_message");
}
fakesink->pad_mode = mode;
fakesink->need_preroll = FALSE;
fakesink->have_preroll = TRUE;
gst_element_commit_state (GST_ELEMENT (fakesink));
GST_STATE_UNLOCK (fakesink);
return result;
{
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)
{
@ -429,9 +438,15 @@ gst_fakesink_event (GstPad * pad, GstEvent * event)
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_EOS:
{
gst_element_finish_preroll (GST_ELEMENT (fakesink), pad);
gst_element_post_message (GST_ELEMENT (fakesink),
gst_message_new_eos (GST_OBJECT (fakesink)));
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:
@ -455,7 +470,7 @@ gst_fakesink_chain_unlocked (GstPad * pad, GstBuffer * buf)
fakesink = GST_FAKESINK (GST_OBJECT_PARENT (pad));
result = gst_element_finish_preroll (GST_ELEMENT (fakesink), pad);
result = gst_fakesink_finish_preroll (fakesink, pad);
if (result != GST_FLOW_OK)
goto exit;
@ -539,13 +554,67 @@ paused:
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;
}
static GstElementStateReturn
gst_fakesink_change_state (GstElement * element)
{
GstElementStateReturn ret = GST_STATE_SUCCESS;
GstFakeSink *fakesink = GST_FAKESINK (element);
GstElementState transition = GST_STATE_TRANSITION (element);
switch (GST_STATE_TRANSITION (element)) {
switch (transition) {
case GST_STATE_NULL_TO_READY:
if (fakesink->state_error == FAKESINK_STATE_ERROR_NULL_READY)
goto error;
@ -553,17 +622,42 @@ 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 */
/* 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)
@ -575,10 +669,11 @@ gst_fakesink_change_state (GstElement * element)
g_free (fakesink->last_message);
fakesink->last_message = NULL;
break;
default:
break;
}
if (GST_ELEMENT_CLASS (parent_class)->change_state)
GST_ELEMENT_CLASS (parent_class)->change_state (element);
GST_ELEMENT_CLASS (parent_class)->change_state (element);
return ret;

View file

@ -68,6 +68,9 @@ struct _GstFakeSink {
GstFakeSinkStateError state_error;
GstActivateMode pad_mode;
guint64 offset;
gboolean eos;
gboolean need_preroll;
gboolean have_preroll;
gchar *last_message;
};

View file

@ -159,6 +159,7 @@ enum
static void gst_real_pad_class_init (GstRealPadClass * klass);
static void gst_real_pad_init (GstRealPad * pad);
static void gst_real_pad_dispose (GObject * object);
static void gst_real_pad_finalize (GObject * object);
static void gst_real_pad_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
@ -201,6 +202,7 @@ gst_real_pad_class_init (GstRealPadClass * klass)
real_pad_parent_class = g_type_class_ref (GST_TYPE_PAD);
gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_real_pad_dispose);
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_real_pad_finalize);
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_real_pad_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_real_pad_get_property);
@ -254,6 +256,9 @@ gst_real_pad_init (GstRealPad * pad)
GST_FLAG_UNSET (pad, GST_PAD_ACTIVE);
pad->preroll_lock = g_mutex_new ();
pad->preroll_cond = g_cond_new ();
pad->stream_rec_lock = g_new (GStaticRecMutex, 1);
g_static_rec_mutex_init (pad->stream_rec_lock);
@ -2539,11 +2544,6 @@ gst_real_pad_dispose (GObject * object)
g_assert (rpad->ghostpads == NULL);
}
if (rpad->stream_rec_lock) {
g_static_rec_mutex_free (rpad->stream_rec_lock);
rpad->stream_rec_lock = NULL;
}
/* clear the caps */
gst_caps_replace (&GST_RPAD_CAPS (pad), NULL);
gst_caps_replace (&GST_RPAD_APPFILTER (pad), NULL);
@ -2558,6 +2558,31 @@ gst_real_pad_dispose (GObject * object)
G_OBJECT_CLASS (real_pad_parent_class)->dispose (object);
}
static void
gst_real_pad_finalize (GObject * object)
{
GstRealPad *rpad;
rpad = GST_REAL_PAD (object);
if (rpad->stream_rec_lock) {
g_static_rec_mutex_free (rpad->stream_rec_lock);
rpad->stream_rec_lock = NULL;
}
if (rpad->preroll_lock) {
g_mutex_free (rpad->preroll_lock);
g_cond_free (rpad->preroll_cond);
rpad->preroll_lock = NULL;
rpad->preroll_cond = NULL;
}
if (rpad->block_cond) {
g_cond_free (rpad->block_cond);
rpad->block_cond = NULL;
}
G_OBJECT_CLASS (real_pad_parent_class)->finalize (object);
}
#ifndef GST_DISABLE_LOADSAVE
/* FIXME: why isn't this on a GstElement ? */

View file

@ -207,6 +207,9 @@ struct _GstRealPad {
/* streaming rec_lock */
GStaticRecMutex *stream_rec_lock;
GstTask *task;
/*< public >*/ /* with PREROLL_LOCK */
GMutex *preroll_lock;
GCond *preroll_cond;
/*< public >*/ /* with LOCK */
/* block cond, mutex is from the object */
@ -335,6 +338,17 @@ struct _GstGhostPadClass {
#define GST_STREAM_TRYLOCK(pad) (g_static_rec_mutex_trylock(GST_STREAM_GET_LOCK(pad)))
#define GST_STREAM_UNLOCK(pad) (g_static_rec_mutex_unlock(GST_STREAM_GET_LOCK(pad)))
#define GST_PREROLL_GET_LOCK(pad) (GST_PAD_REALIZE(pad)->preroll_lock)
#define GST_PREROLL_LOCK(pad) (g_mutex_lock(GST_PREROLL_GET_LOCK(pad)))
#define GST_PREROLL_TRYLOCK(pad) (g_mutex_trylock(GST_PREROLL_GET_LOCK(pad)))
#define GST_PREROLL_UNLOCK(pad) (g_mutex_unlock(GST_PREROLL_GET_LOCK(pad)))
#define GST_PREROLL_GET_COND(pad) (GST_PAD_REALIZE(pad)->preroll_cond)
#define GST_PREROLL_WAIT(pad) g_cond_wait (GST_PREROLL_GET_COND (pad), GST_PREROLL_GET_LOCK (pad))
#define GST_PREROLL_TIMED_WAIT(pad, timeval) g_cond_timed_wait (GST_PREROLL_GET_COND (pad), GST_PREROLL_GET_LOCK (pad),\
timeval)
#define GST_PREROLL_SIGNAL(pad) g_cond_signal (GST_PREROLL_GET_COND (pad));
#define GST_PREROLL_BROADCAST(pad) g_cond_broadcast (GST_PREROLL_GET_COND (pad));
#define GST_PAD_BLOCK_GET_COND(pad) (GST_PAD_REALIZE(pad)->block_cond)
#define GST_PAD_BLOCK_WAIT(pad) (g_cond_wait(GST_PAD_BLOCK_GET_COND (pad), GST_GET_LOCK (pad)))
#define GST_PAD_BLOCK_SIGNAL(pad) (g_cond_signal(GST_PAD_BLOCK_GET_COND (pad)))

View file

@ -198,12 +198,10 @@ gst_fakesink_class_init (GstFakeSinkClass * klass)
static void
gst_fakesink_init (GstFakeSink * fakesink)
{
GstPad *pad;
pad =
fakesink->sinkpad =
gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
"sink");
gst_element_add_pad (GST_ELEMENT (fakesink), pad);
gst_element_add_pad (GST_ELEMENT (fakesink), fakesink->sinkpad);
fakesink->silent = FALSE;
fakesink->dump = FALSE;
@ -212,7 +210,7 @@ gst_fakesink_init (GstFakeSink * fakesink)
fakesink->state_error = FAKESINK_STATE_ERROR_NONE;
fakesink->signal_handoffs = FALSE;
fakesink->pad_mode = GST_ACTIVATE_NONE;
GST_RPAD_TASK (pad) = NULL;
GST_RPAD_TASK (fakesink->sinkpad) = NULL;
}
static void
@ -357,55 +355,66 @@ gst_fakesink_get_property (GObject * object, guint prop_id, GValue * value,
}
}
static gboolean
gst_fakesink_activate (GstPad * pad, GstActivateMode mode)
/* STREAM_LOCK should be held */
GstFlowReturn
gst_fakesink_finish_preroll (GstFakeSink * fakesink, GstPad * pad)
{
gboolean result = FALSE;
GstFakeSink *fakesink;
/* lock order is important */
GST_STATE_LOCK (fakesink);
GST_PREROLL_LOCK (pad);
if (!fakesink->need_preroll)
goto no_preroll;
fakesink = GST_FAKESINK (GST_OBJECT_PARENT (pad));
if (!fakesink->silent) {
g_free (fakesink->last_message);
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);
fakesink->last_message =
g_strdup_printf ("preroll ******* (%s:%s)", GST_DEBUG_PAD_NAME (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) */
/* 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;
g_object_notify (G_OBJECT (fakesink), "last_message");
}
fakesink->pad_mode = mode;
fakesink->need_preroll = FALSE;
fakesink->have_preroll = TRUE;
gst_element_commit_state (GST_ELEMENT (fakesink));
GST_STATE_UNLOCK (fakesink);
return result;
{
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)
{
@ -429,9 +438,15 @@ gst_fakesink_event (GstPad * pad, GstEvent * event)
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_EOS:
{
gst_element_finish_preroll (GST_ELEMENT (fakesink), pad);
gst_element_post_message (GST_ELEMENT (fakesink),
gst_message_new_eos (GST_OBJECT (fakesink)));
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:
@ -455,7 +470,7 @@ gst_fakesink_chain_unlocked (GstPad * pad, GstBuffer * buf)
fakesink = GST_FAKESINK (GST_OBJECT_PARENT (pad));
result = gst_element_finish_preroll (GST_ELEMENT (fakesink), pad);
result = gst_fakesink_finish_preroll (fakesink, pad);
if (result != GST_FLOW_OK)
goto exit;
@ -539,13 +554,67 @@ paused:
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;
}
static GstElementStateReturn
gst_fakesink_change_state (GstElement * element)
{
GstElementStateReturn ret = GST_STATE_SUCCESS;
GstFakeSink *fakesink = GST_FAKESINK (element);
GstElementState transition = GST_STATE_TRANSITION (element);
switch (GST_STATE_TRANSITION (element)) {
switch (transition) {
case GST_STATE_NULL_TO_READY:
if (fakesink->state_error == FAKESINK_STATE_ERROR_NULL_READY)
goto error;
@ -553,17 +622,42 @@ 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 */
/* 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)
@ -575,10 +669,11 @@ gst_fakesink_change_state (GstElement * element)
g_free (fakesink->last_message);
fakesink->last_message = NULL;
break;
default:
break;
}
if (GST_ELEMENT_CLASS (parent_class)->change_state)
GST_ELEMENT_CLASS (parent_class)->change_state (element);
GST_ELEMENT_CLASS (parent_class)->change_state (element);
return ret;

View file

@ -68,6 +68,9 @@ struct _GstFakeSink {
GstFakeSinkStateError state_error;
GstActivateMode pad_mode;
guint64 offset;
gboolean eos;
gboolean need_preroll;
gboolean have_preroll;
gchar *last_message;
};

View file

@ -567,8 +567,15 @@ main (int argc, char *argv[])
g_print (_("Execution ended after %" G_GUINT64_FORMAT " ns.\n"), diff);
}
fprintf (stderr, _("PAUSE pipeline ...\n"));
gst_element_set_state (pipeline, GST_STATE_PAUSED);
gst_element_get_state (pipeline, &state, &pending, NULL);
fprintf (stderr, _("READY pipeline ...\n"));
gst_element_set_state (pipeline, GST_STATE_READY);
gst_element_get_state (pipeline, &state, &pending, NULL);
fprintf (stderr, _("NULL pipeline ...\n"));
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_element_get_state (pipeline, &state, &pending, NULL);
}
end: