mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-17 19:55:32 +00:00
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:
parent
6664bebb6d
commit
ed1664fbaf
8 changed files with 373 additions and 112 deletions
19
ChangeLog
19
ChangeLog
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
35
gst/gstpad.c
35
gst/gstpad.c
|
@ -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 ? */
|
||||
|
|
14
gst/gstpad.h
14
gst/gstpad.h
|
@ -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)))
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue