Add clock and sync handling to the base sink class.

Original commit message from CVS:
* docs/design/part-states.txt:
* gst/base/gstbasesink.c: (gst_basesink_get_template),
(gst_basesink_base_init), (gst_basesink_class_init),
(gst_basesink_init), (gst_base_sink_get_template),
(gst_base_sink_get_caps), (gst_base_sink_set_caps),
(gst_base_sink_alloc_buffer), (gst_basesink_finish_preroll),
(gst_basesink_event), (gst_basesink_get_times),
(gst_basesink_do_sync), (gst_basesink_chain_unlocked),
(gst_basesink_activate), (gst_basesink_change_state):
* gst/base/gstbasesink.h:
* gst/elements/gstfakesink.c: (gst_fakesink_class_init),
(gst_fakesink_get_times), (gst_fakesink_event),
(gst_fakesink_preroll), (gst_fakesink_render):
Add clock and sync handling to the base sink class.
Make fakesink extend the base sink class.
Fix some typos.
This commit is contained in:
Wim Taymans 2005-02-23 14:47:08 +00:00
parent 5b676004db
commit b152bc1c9c
8 changed files with 316 additions and 31 deletions

View file

@ -1,3 +1,22 @@
2005-02-23 Wim Taymans <wim@fluendo.com>
* docs/design/part-states.txt:
* gst/base/gstbasesink.c: (gst_basesink_get_template),
(gst_basesink_base_init), (gst_basesink_class_init),
(gst_basesink_init), (gst_base_sink_get_template),
(gst_base_sink_get_caps), (gst_base_sink_set_caps),
(gst_base_sink_alloc_buffer), (gst_basesink_finish_preroll),
(gst_basesink_event), (gst_basesink_get_times),
(gst_basesink_do_sync), (gst_basesink_chain_unlocked),
(gst_basesink_activate), (gst_basesink_change_state):
* gst/base/gstbasesink.h:
* gst/elements/gstfakesink.c: (gst_fakesink_class_init),
(gst_fakesink_get_times), (gst_fakesink_event),
(gst_fakesink_preroll), (gst_fakesink_render):
Add clock and sync handling to the base sink class.
Make fakesink extend the base sink class.
Fix some typos.
2005-02-23 Andy Wingo <wingo@pobox.com>
* check/Makefile.am (TESTS): Add pipelines/simple_launch_lines.

View file

@ -1,7 +1,7 @@
States
======
Both elements an pads can be in different states. The states of the pads are
Both elements and pads can be in different states. The states of the pads are
linked to the state of the element so the design of the states is mainly
focused around the element states.

View file

@ -71,6 +71,8 @@ static GstCaps *gst_base_sink_get_caps (GstBaseSink * sink);
static gboolean gst_base_sink_set_caps (GstBaseSink * sink, GstCaps * caps);
static GstBuffer *gst_base_sink_alloc_buffer (GstBaseSink * sink,
guint64 offset, guint size, GstCaps * caps);
static void gst_basesink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
GstClockTime * start, GstClockTime * end);
static GstElementStateReturn gst_basesink_change_state (GstElement * element);
@ -138,6 +140,7 @@ gst_basesink_class_init (GstBaseSinkClass * klass)
klass->set_caps = GST_DEBUG_FUNCPTR (gst_base_sink_set_caps);
klass->get_template = GST_DEBUG_FUNCPTR (gst_base_sink_get_template);
klass->alloc_buffer = GST_DEBUG_FUNCPTR (gst_base_sink_alloc_buffer);
klass->get_times = GST_DEBUG_FUNCPTR (gst_basesink_get_times);
}
static void
@ -331,8 +334,6 @@ gst_basesink_event (GstPad * pad, GstEvent * event)
basesink = GST_BASESINK (GST_OBJECT_PARENT (pad));
GST_STREAM_LOCK (pad);
bclass = GST_BASESINK_GET_CLASS (basesink);
if (bclass->event)
@ -343,28 +344,126 @@ gst_basesink_event (GstPad * pad, GstEvent * event)
{
GstFlowReturn ret;
GST_STREAM_LOCK (pad);
ret = gst_basesink_finish_preroll (basesink, pad, NULL);
if (ret == GST_FLOW_OK) {
basesink->eos = TRUE;
/* ok, we can post the message */
gst_element_post_message (GST_ELEMENT (basesink),
gst_message_new_eos (GST_OBJECT (basesink)));
gboolean need_eos;
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_clock_id_wait (basesink->clock_id, NULL);
GST_LOCK (basesink);
if (basesink->clock_id) {
gst_clock_id_unref (basesink->clock_id);
basesink->clock_id = NULL;
}
basesink->end_time = GST_CLOCK_TIME_NONE;
need_eos = basesink->eos;
}
}
GST_UNLOCK (basesink);
/* if we are still EOS, we can post the EOS message */
if (need_eos) {
/* ok, now we can post the message */
gst_element_post_message (GST_ELEMENT (basesink),
gst_message_new_eos (GST_OBJECT (basesink)));
}
}
GST_STREAM_UNLOCK (pad);
break;
}
case GST_EVENT_DISCONTINUOUS:
if (basesink->sync && basesink->clock) {
GST_STREAM_LOCK (pad);
if (basesink->clock) {
//gint64 value = GST_EVENT_DISCONT_OFFSET (event, 0).value;
}
GST_STREAM_UNLOCK (pad);
case GST_EVENT_FLUSH:
/* make sure we are not blocked on the clock also clear any pending
* eos state. */
GST_LOCK (basesink);
basesink->eos = FALSE;
if (basesink->clock_id) {
gst_clock_id_unschedule (basesink->clock_id);
}
GST_UNLOCK (basesink);
/* unlock from a possible state change/preroll */
GST_PREROLL_LOCK (pad);
GST_PREROLL_SIGNAL (pad);
GST_PREROLL_UNLOCK (pad);
/* now we are completely unblocked and the _chain method
* will return */
break;
default:
result = gst_pad_event_default (pad, event);
break;
}
GST_STREAM_UNLOCK (pad);
return result;
}
static void
gst_basesink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
GstClockTime * start, GstClockTime * end)
{
GstClockTime timestamp, duration;
timestamp = GST_BUFFER_TIMESTAMP (buffer);
if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
duration = GST_BUFFER_DURATION (buffer);
if (GST_CLOCK_TIME_IS_VALID (duration)) {
*end = timestamp + duration;
}
*start = timestamp;
}
}
static void
gst_basesink_do_sync (GstBaseSink * basesink, GstBuffer * buffer)
{
if (basesink->clock) {
GstClockReturn ret;
GstClockTime start, end;
GstBaseSinkClass *bclass;
bclass = GST_BASESINK_GET_CLASS (basesink);
start = end = -1;
if (bclass->get_times)
bclass->get_times (basesink, buffer, &start, &end);
if (GST_CLOCK_TIME_IS_VALID (start)) {
/* save clock id so that we can unlock it if needed */
GST_LOCK (basesink);
basesink->clock_id = gst_clock_new_single_shot_id (basesink->clock,
start + GST_ELEMENT (basesink)->base_time);
basesink->end_time = end;
GST_UNLOCK (basesink);
ret = gst_clock_id_wait (basesink->clock_id, NULL);
GST_LOCK (basesink);
if (basesink->clock_id) {
gst_clock_id_unref (basesink->clock_id);
basesink->clock_id = NULL;
}
basesink->end_time = GST_CLOCK_TIME_NONE;
GST_UNLOCK (basesink);
GST_LOG_OBJECT (basesink, "clock entry done: %d", ret);
}
}
}
static GstFlowReturn
gst_basesink_chain_unlocked (GstPad * pad, GstBuffer * buf)
{
@ -378,11 +477,7 @@ gst_basesink_chain_unlocked (GstPad * pad, GstBuffer * buf)
if (result != GST_FLOW_OK)
goto exit;
/* doClock
if (basesink->sync && basesink->clock) {
gst_element_wait (GST_ELEMENT (basesink), GST_BUFFER_TIMESTAMP (buf));
}
*/
gst_basesink_do_sync (basesink, buf);
bclass = GST_BASESINK_GET_CLASS (basesink);
if (bclass->render)
@ -470,6 +565,11 @@ gst_basesink_activate (GstPad * pad, GstActivateMode mode)
break;
case GST_ACTIVATE_NONE:
/* step 1, unblock clock sync (if any) or any other blocking thing */
GST_LOCK (basesink);
if (basesink->clock_id) {
gst_clock_id_unschedule (basesink->clock_id);
}
GST_UNLOCK (basesink);
/* unlock preroll */
GST_PREROLL_LOCK (pad);
@ -528,15 +628,27 @@ gst_basesink_change_state (GstElement * element)
GST_PREROLL_UNLOCK (basesink->sinkpad);
break;
case GST_STATE_PLAYING_TO_PAUSED:
{
gboolean eos;
/* unlock clock wait if any */
GST_LOCK (basesink);
if (basesink->clock_id) {
gst_clock_id_unschedule (basesink->clock_id);
}
eos = basesink->eos;
GST_UNLOCK (basesink);
GST_PREROLL_LOCK (basesink->sinkpad);
basesink->need_preroll = TRUE;
/* if we don't have a preroll buffer and we have not received EOS,
* we need to wait for a preroll */
if (!basesink->have_preroll && !basesink->eos) {
if (!basesink->have_preroll && !eos) {
ret = GST_STATE_ASYNC;
}
GST_PREROLL_UNLOCK (basesink->sinkpad);
break;
}
case GST_STATE_PAUSED_TO_READY:
break;
case GST_STATE_READY_TO_NULL:

View file

@ -35,6 +35,9 @@ G_BEGIN_DECLS
#define GST_IS_BASESINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASESINK))
#define GST_IS_BASESINK_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASESINK))
#define GST_BASESINK_CLOCK(obj) (GST_BASESINK (obj)->clock)
#define GST_BASESINK_PAD(obj) (GST_BASESINK (obj)->sinkpad)
typedef struct _GstBaseSink GstBaseSink;
typedef struct _GstBaseSinkClass GstBaseSinkClass;
@ -48,8 +51,9 @@ struct _GstBaseSink {
gboolean has_loop;
gboolean has_chain;
gboolean sync;
GstClock *clock;
GstClockID clock_id;
GstClockTime end_time;
gboolean eos;
gboolean need_preroll;
@ -67,6 +71,9 @@ struct _GstBaseSinkClass {
GstBuffer* (*alloc_buffer) (GstBaseSink *sink, guint64 offset, guint size,
GstCaps *caps);
void (*get_times) (GstBaseSink *sink, GstBuffer *buffer,
GstClockTime *start, GstClockTime *end);
void (*event) (GstBaseSink *sink, GstEvent *event);
GstFlowReturn (*preroll) (GstBaseSink *sink, GstBuffer *buffer);
GstFlowReturn (*render) (GstBaseSink *sink, GstBuffer *buffer);

View file

@ -117,6 +117,8 @@ static GstFlowReturn gst_fakesink_preroll (GstBaseSink * bsink,
static GstFlowReturn gst_fakesink_render (GstBaseSink * bsink,
GstBuffer * buffer);
static void gst_fakesink_event (GstBaseSink * bsink, GstEvent * event);
static void gst_fakesink_get_times (GstBaseSink * bsink, GstBuffer * buffer,
GstClockTime * start, GstClockTime * end);
static guint gst_fakesink_signals[LAST_SIGNAL] = { 0 };
@ -179,6 +181,7 @@ gst_fakesink_class_init (GstFakeSinkClass * klass)
gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_fakesink_event);
gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_fakesink_preroll);
gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_fakesink_render);
gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_fakesink_get_times);
}
static void
@ -255,6 +258,17 @@ gst_fakesink_get_property (GObject * object, guint prop_id, GValue * value,
}
}
static void
gst_fakesink_get_times (GstBaseSink * bsink, GstBuffer * buffer,
GstClockTime * start, GstClockTime * end)
{
GstFakeSink *sink = GST_FAKESINK (bsink);
if (sink->sync) {
GST_BASESINK_CLASS (parent_class)->get_times (bsink, buffer, start, end);
}
}
static void
gst_fakesink_event (GstBaseSink * bsink, GstEvent * event)
{

View file

@ -71,6 +71,8 @@ static GstCaps *gst_base_sink_get_caps (GstBaseSink * sink);
static gboolean gst_base_sink_set_caps (GstBaseSink * sink, GstCaps * caps);
static GstBuffer *gst_base_sink_alloc_buffer (GstBaseSink * sink,
guint64 offset, guint size, GstCaps * caps);
static void gst_basesink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
GstClockTime * start, GstClockTime * end);
static GstElementStateReturn gst_basesink_change_state (GstElement * element);
@ -138,6 +140,7 @@ gst_basesink_class_init (GstBaseSinkClass * klass)
klass->set_caps = GST_DEBUG_FUNCPTR (gst_base_sink_set_caps);
klass->get_template = GST_DEBUG_FUNCPTR (gst_base_sink_get_template);
klass->alloc_buffer = GST_DEBUG_FUNCPTR (gst_base_sink_alloc_buffer);
klass->get_times = GST_DEBUG_FUNCPTR (gst_basesink_get_times);
}
static void
@ -331,8 +334,6 @@ gst_basesink_event (GstPad * pad, GstEvent * event)
basesink = GST_BASESINK (GST_OBJECT_PARENT (pad));
GST_STREAM_LOCK (pad);
bclass = GST_BASESINK_GET_CLASS (basesink);
if (bclass->event)
@ -343,28 +344,126 @@ gst_basesink_event (GstPad * pad, GstEvent * event)
{
GstFlowReturn ret;
GST_STREAM_LOCK (pad);
ret = gst_basesink_finish_preroll (basesink, pad, NULL);
if (ret == GST_FLOW_OK) {
basesink->eos = TRUE;
/* ok, we can post the message */
gst_element_post_message (GST_ELEMENT (basesink),
gst_message_new_eos (GST_OBJECT (basesink)));
gboolean need_eos;
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_clock_id_wait (basesink->clock_id, NULL);
GST_LOCK (basesink);
if (basesink->clock_id) {
gst_clock_id_unref (basesink->clock_id);
basesink->clock_id = NULL;
}
basesink->end_time = GST_CLOCK_TIME_NONE;
need_eos = basesink->eos;
}
}
GST_UNLOCK (basesink);
/* if we are still EOS, we can post the EOS message */
if (need_eos) {
/* ok, now we can post the message */
gst_element_post_message (GST_ELEMENT (basesink),
gst_message_new_eos (GST_OBJECT (basesink)));
}
}
GST_STREAM_UNLOCK (pad);
break;
}
case GST_EVENT_DISCONTINUOUS:
if (basesink->sync && basesink->clock) {
GST_STREAM_LOCK (pad);
if (basesink->clock) {
//gint64 value = GST_EVENT_DISCONT_OFFSET (event, 0).value;
}
GST_STREAM_UNLOCK (pad);
case GST_EVENT_FLUSH:
/* make sure we are not blocked on the clock also clear any pending
* eos state. */
GST_LOCK (basesink);
basesink->eos = FALSE;
if (basesink->clock_id) {
gst_clock_id_unschedule (basesink->clock_id);
}
GST_UNLOCK (basesink);
/* unlock from a possible state change/preroll */
GST_PREROLL_LOCK (pad);
GST_PREROLL_SIGNAL (pad);
GST_PREROLL_UNLOCK (pad);
/* now we are completely unblocked and the _chain method
* will return */
break;
default:
result = gst_pad_event_default (pad, event);
break;
}
GST_STREAM_UNLOCK (pad);
return result;
}
static void
gst_basesink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
GstClockTime * start, GstClockTime * end)
{
GstClockTime timestamp, duration;
timestamp = GST_BUFFER_TIMESTAMP (buffer);
if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
duration = GST_BUFFER_DURATION (buffer);
if (GST_CLOCK_TIME_IS_VALID (duration)) {
*end = timestamp + duration;
}
*start = timestamp;
}
}
static void
gst_basesink_do_sync (GstBaseSink * basesink, GstBuffer * buffer)
{
if (basesink->clock) {
GstClockReturn ret;
GstClockTime start, end;
GstBaseSinkClass *bclass;
bclass = GST_BASESINK_GET_CLASS (basesink);
start = end = -1;
if (bclass->get_times)
bclass->get_times (basesink, buffer, &start, &end);
if (GST_CLOCK_TIME_IS_VALID (start)) {
/* save clock id so that we can unlock it if needed */
GST_LOCK (basesink);
basesink->clock_id = gst_clock_new_single_shot_id (basesink->clock,
start + GST_ELEMENT (basesink)->base_time);
basesink->end_time = end;
GST_UNLOCK (basesink);
ret = gst_clock_id_wait (basesink->clock_id, NULL);
GST_LOCK (basesink);
if (basesink->clock_id) {
gst_clock_id_unref (basesink->clock_id);
basesink->clock_id = NULL;
}
basesink->end_time = GST_CLOCK_TIME_NONE;
GST_UNLOCK (basesink);
GST_LOG_OBJECT (basesink, "clock entry done: %d", ret);
}
}
}
static GstFlowReturn
gst_basesink_chain_unlocked (GstPad * pad, GstBuffer * buf)
{
@ -378,11 +477,7 @@ gst_basesink_chain_unlocked (GstPad * pad, GstBuffer * buf)
if (result != GST_FLOW_OK)
goto exit;
/* doClock
if (basesink->sync && basesink->clock) {
gst_element_wait (GST_ELEMENT (basesink), GST_BUFFER_TIMESTAMP (buf));
}
*/
gst_basesink_do_sync (basesink, buf);
bclass = GST_BASESINK_GET_CLASS (basesink);
if (bclass->render)
@ -470,6 +565,11 @@ gst_basesink_activate (GstPad * pad, GstActivateMode mode)
break;
case GST_ACTIVATE_NONE:
/* step 1, unblock clock sync (if any) or any other blocking thing */
GST_LOCK (basesink);
if (basesink->clock_id) {
gst_clock_id_unschedule (basesink->clock_id);
}
GST_UNLOCK (basesink);
/* unlock preroll */
GST_PREROLL_LOCK (pad);
@ -528,15 +628,27 @@ gst_basesink_change_state (GstElement * element)
GST_PREROLL_UNLOCK (basesink->sinkpad);
break;
case GST_STATE_PLAYING_TO_PAUSED:
{
gboolean eos;
/* unlock clock wait if any */
GST_LOCK (basesink);
if (basesink->clock_id) {
gst_clock_id_unschedule (basesink->clock_id);
}
eos = basesink->eos;
GST_UNLOCK (basesink);
GST_PREROLL_LOCK (basesink->sinkpad);
basesink->need_preroll = TRUE;
/* if we don't have a preroll buffer and we have not received EOS,
* we need to wait for a preroll */
if (!basesink->have_preroll && !basesink->eos) {
if (!basesink->have_preroll && !eos) {
ret = GST_STATE_ASYNC;
}
GST_PREROLL_UNLOCK (basesink->sinkpad);
break;
}
case GST_STATE_PAUSED_TO_READY:
break;
case GST_STATE_READY_TO_NULL:

View file

@ -35,6 +35,9 @@ G_BEGIN_DECLS
#define GST_IS_BASESINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASESINK))
#define GST_IS_BASESINK_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASESINK))
#define GST_BASESINK_CLOCK(obj) (GST_BASESINK (obj)->clock)
#define GST_BASESINK_PAD(obj) (GST_BASESINK (obj)->sinkpad)
typedef struct _GstBaseSink GstBaseSink;
typedef struct _GstBaseSinkClass GstBaseSinkClass;
@ -48,8 +51,9 @@ struct _GstBaseSink {
gboolean has_loop;
gboolean has_chain;
gboolean sync;
GstClock *clock;
GstClockID clock_id;
GstClockTime end_time;
gboolean eos;
gboolean need_preroll;
@ -67,6 +71,9 @@ struct _GstBaseSinkClass {
GstBuffer* (*alloc_buffer) (GstBaseSink *sink, guint64 offset, guint size,
GstCaps *caps);
void (*get_times) (GstBaseSink *sink, GstBuffer *buffer,
GstClockTime *start, GstClockTime *end);
void (*event) (GstBaseSink *sink, GstEvent *event);
GstFlowReturn (*preroll) (GstBaseSink *sink, GstBuffer *buffer);
GstFlowReturn (*render) (GstBaseSink *sink, GstBuffer *buffer);

View file

@ -117,6 +117,8 @@ static GstFlowReturn gst_fakesink_preroll (GstBaseSink * bsink,
static GstFlowReturn gst_fakesink_render (GstBaseSink * bsink,
GstBuffer * buffer);
static void gst_fakesink_event (GstBaseSink * bsink, GstEvent * event);
static void gst_fakesink_get_times (GstBaseSink * bsink, GstBuffer * buffer,
GstClockTime * start, GstClockTime * end);
static guint gst_fakesink_signals[LAST_SIGNAL] = { 0 };
@ -179,6 +181,7 @@ gst_fakesink_class_init (GstFakeSinkClass * klass)
gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_fakesink_event);
gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_fakesink_preroll);
gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_fakesink_render);
gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_fakesink_get_times);
}
static void
@ -255,6 +258,17 @@ gst_fakesink_get_property (GObject * object, guint prop_id, GValue * value,
}
}
static void
gst_fakesink_get_times (GstBaseSink * bsink, GstBuffer * buffer,
GstClockTime * start, GstClockTime * end)
{
GstFakeSink *sink = GST_FAKESINK (bsink);
if (sink->sync) {
GST_BASESINK_CLASS (parent_class)->get_times (bsink, buffer, start, end);
}
}
static void
gst_fakesink_event (GstBaseSink * bsink, GstEvent * event)
{