mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 08:46:40 +00:00
gst/base/gstbasesrc.c: Move some stuff around and cleanup things.
Original commit message from CVS: * gst/base/gstbasesrc.c: (gst_base_src_class_init), (gst_base_src_init), (gst_base_src_query), (gst_base_src_default_newsegment), (gst_base_src_configure_segment), (gst_base_src_do_seek), (gst_base_src_send_event), (gst_base_src_event_handler), (gst_base_src_pad_get_range), (gst_base_src_loop), (gst_base_src_unlock), (gst_base_src_default_negotiate), (gst_base_src_start), (gst_base_src_deactivate), (gst_base_src_activate_push), (gst_base_src_change_state): Move some stuff around and cleanup things.
This commit is contained in:
parent
27918022a2
commit
2e7411e8b8
3 changed files with 521 additions and 170 deletions
13
ChangeLog
13
ChangeLog
|
@ -1,3 +1,16 @@
|
||||||
|
2005-10-27 Wim Taymans <wim@fluendo.com>
|
||||||
|
|
||||||
|
* gst/base/gstbasesrc.c: (gst_base_src_class_init),
|
||||||
|
(gst_base_src_init), (gst_base_src_query),
|
||||||
|
(gst_base_src_default_newsegment),
|
||||||
|
(gst_base_src_configure_segment), (gst_base_src_do_seek),
|
||||||
|
(gst_base_src_send_event), (gst_base_src_event_handler),
|
||||||
|
(gst_base_src_pad_get_range), (gst_base_src_loop),
|
||||||
|
(gst_base_src_unlock), (gst_base_src_default_negotiate),
|
||||||
|
(gst_base_src_start), (gst_base_src_deactivate),
|
||||||
|
(gst_base_src_activate_push), (gst_base_src_change_state):
|
||||||
|
Move some stuff around and cleanup things.
|
||||||
|
|
||||||
2005-10-27 Tim-Philipp Müller <tim at centricular dot net>
|
2005-10-27 Tim-Philipp Müller <tim at centricular dot net>
|
||||||
|
|
||||||
* gst/base/gstbasesrc.c: (gst_base_src_query):
|
* gst/base/gstbasesrc.c: (gst_base_src_query):
|
||||||
|
|
|
@ -113,6 +113,7 @@ static void gst_base_src_set_property (GObject * object, guint prop_id,
|
||||||
static void gst_base_src_get_property (GObject * object, guint prop_id,
|
static void gst_base_src_get_property (GObject * object, guint prop_id,
|
||||||
GValue * value, GParamSpec * pspec);
|
GValue * value, GParamSpec * pspec);
|
||||||
static gboolean gst_base_src_event_handler (GstPad * pad, GstEvent * event);
|
static gboolean gst_base_src_event_handler (GstPad * pad, GstEvent * event);
|
||||||
|
static gboolean gst_base_src_send_event (GstElement * elem, GstEvent * event);
|
||||||
|
|
||||||
static gboolean gst_base_src_query (GstPad * pad, GstQuery * query);
|
static gboolean gst_base_src_query (GstPad * pad, GstQuery * query);
|
||||||
|
|
||||||
|
@ -167,6 +168,7 @@ gst_base_src_class_init (GstBaseSrcClass * klass)
|
||||||
|
|
||||||
gstelement_class->change_state =
|
gstelement_class->change_state =
|
||||||
GST_DEBUG_FUNCPTR (gst_base_src_change_state);
|
GST_DEBUG_FUNCPTR (gst_base_src_change_state);
|
||||||
|
gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_base_src_send_event);
|
||||||
|
|
||||||
klass->negotiate = gst_base_src_default_negotiate;
|
klass->negotiate = gst_base_src_default_negotiate;
|
||||||
klass->newsegment = gst_base_src_default_newsegment;
|
klass->newsegment = gst_base_src_default_newsegment;
|
||||||
|
@ -214,10 +216,6 @@ gst_base_src_init (GstBaseSrc * basesrc, gpointer g_class)
|
||||||
GST_DEBUG_OBJECT (basesrc, "adding src pad");
|
GST_DEBUG_OBJECT (basesrc, "adding src pad");
|
||||||
gst_element_add_pad (GST_ELEMENT (basesrc), pad);
|
gst_element_add_pad (GST_ELEMENT (basesrc), pad);
|
||||||
|
|
||||||
basesrc->segment_loop = FALSE;
|
|
||||||
basesrc->segment_start = -1;
|
|
||||||
basesrc->segment_end = -1;
|
|
||||||
basesrc->need_newsegment = TRUE;
|
|
||||||
basesrc->blocksize = DEFAULT_BLOCKSIZE;
|
basesrc->blocksize = DEFAULT_BLOCKSIZE;
|
||||||
basesrc->clock_id = NULL;
|
basesrc->clock_id = NULL;
|
||||||
|
|
||||||
|
@ -392,10 +390,26 @@ gst_base_src_query (GstPad * pad, GstQuery * query)
|
||||||
|
|
||||||
case GST_QUERY_SEEKING:
|
case GST_QUERY_SEEKING:
|
||||||
gst_query_set_seeking (query, GST_FORMAT_BYTES,
|
gst_query_set_seeking (query, GST_FORMAT_BYTES,
|
||||||
src->seekable, src->segment_start, src->segment_end);
|
src->seekable, 0, src->size);
|
||||||
res = TRUE;
|
res = TRUE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case GST_QUERY_SEGMENT:
|
||||||
|
{
|
||||||
|
gint64 start, stop;
|
||||||
|
|
||||||
|
start = src->segment_start;
|
||||||
|
/* no end segment configured, current size then */
|
||||||
|
if ((stop = src->segment_end) == -1)
|
||||||
|
stop = src->size;
|
||||||
|
|
||||||
|
/* FIXME, we can't report our rate as we did not store it, d'oh!.
|
||||||
|
* Also, subclasses might want to support other formats. */
|
||||||
|
gst_query_set_segment (query, 1.0, GST_FORMAT_BYTES, start, stop);
|
||||||
|
res = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case GST_QUERY_FORMATS:
|
case GST_QUERY_FORMATS:
|
||||||
gst_query_set_formats (query, 3, GST_FORMAT_DEFAULT,
|
gst_query_set_formats (query, 3, GST_FORMAT_DEFAULT,
|
||||||
GST_FORMAT_BYTES, GST_FORMAT_PERCENT);
|
GST_FORMAT_BYTES, GST_FORMAT_PERCENT);
|
||||||
|
@ -421,12 +435,11 @@ gst_base_src_default_newsegment (GstBaseSrc * src)
|
||||||
GstEvent *event;
|
GstEvent *event;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (src, "Sending newsegment from %" G_GINT64_FORMAT
|
GST_DEBUG_OBJECT (src, "Sending newsegment from %" G_GINT64_FORMAT
|
||||||
" to %" G_GINT64_FORMAT, (gint64) src->segment_start,
|
" to %" G_GINT64_FORMAT, src->segment_start, src->segment_end);
|
||||||
(gint64) src->segment_end);
|
|
||||||
event = gst_event_new_newsegment (FALSE, 1.0,
|
event = gst_event_new_newsegment (FALSE, 1.0,
|
||||||
GST_FORMAT_BYTES,
|
GST_FORMAT_BYTES, src->segment_start, src->segment_end,
|
||||||
(gint64) src->segment_start, (gint64) src->segment_end,
|
src->segment_start);
|
||||||
(gint64) src->segment_start);
|
|
||||||
|
|
||||||
return gst_pad_push_event (src->srcpad, event);
|
return gst_pad_push_event (src->srcpad, event);
|
||||||
}
|
}
|
||||||
|
@ -445,45 +458,31 @@ gst_base_src_newsegment (GstBaseSrc * src)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* based on the event parameters configure the segment_start/stop
|
||||||
|
* times. Called with STREAM_LOCK.
|
||||||
|
*/
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_base_src_do_seek (GstBaseSrc * src, GstEvent * event)
|
gst_base_src_configure_segment (GstBaseSrc * src, GstEvent * event)
|
||||||
{
|
{
|
||||||
gdouble rate;
|
gdouble rate;
|
||||||
GstFormat format;
|
GstFormat format;
|
||||||
GstSeekFlags flags;
|
GstSeekFlags flags;
|
||||||
GstSeekType cur_type, stop_type;
|
GstSeekType cur_type, stop_type;
|
||||||
gint64 cur, stop;
|
gint64 cur, stop;
|
||||||
gboolean flush;
|
gboolean update_stop, update_start;
|
||||||
gboolean update_stop = TRUE, update_start = TRUE;
|
|
||||||
|
|
||||||
gst_event_parse_seek (event, &rate, &format, &flags,
|
gst_event_parse_seek (event, &rate, &format, &flags,
|
||||||
&cur_type, &cur, &stop_type, &stop);
|
&cur_type, &cur, &stop_type, &stop);
|
||||||
|
|
||||||
/* get seek format */
|
/* parse the loop flag */
|
||||||
if (format == GST_FORMAT_DEFAULT)
|
/* FIXME, need to store other flags and rate too */
|
||||||
format = GST_FORMAT_BYTES;
|
|
||||||
/* we can only seek bytes */
|
|
||||||
if (format != GST_FORMAT_BYTES)
|
|
||||||
goto unsupported_seek;
|
|
||||||
|
|
||||||
flush = flags & GST_SEEK_FLAG_FLUSH;
|
|
||||||
|
|
||||||
/* get seek positions */
|
|
||||||
src->segment_loop = (flags & GST_SEEK_FLAG_SEGMENT) != 0;
|
src->segment_loop = (flags & GST_SEEK_FLAG_SEGMENT) != 0;
|
||||||
|
|
||||||
/* send flush start */
|
/* assume we'll update both start and stop values */
|
||||||
if (flush)
|
update_start = TRUE;
|
||||||
gst_pad_push_event (src->srcpad, gst_event_new_flush_start ());
|
update_stop = TRUE;
|
||||||
else
|
|
||||||
gst_pad_pause_task (src->srcpad);
|
|
||||||
|
|
||||||
/* unblock streaming thread */
|
/* perform the seek, segment_start is never invalid */
|
||||||
gst_base_src_unlock (src);
|
|
||||||
|
|
||||||
/* grab streaming lock */
|
|
||||||
GST_STREAM_LOCK (src->srcpad);
|
|
||||||
|
|
||||||
/* perform the seek */
|
|
||||||
switch (cur_type) {
|
switch (cur_type) {
|
||||||
case GST_SEEK_TYPE_NONE:
|
case GST_SEEK_TYPE_NONE:
|
||||||
/* no update to segment */
|
/* no update to segment */
|
||||||
|
@ -491,7 +490,7 @@ gst_base_src_do_seek (GstBaseSrc * src, GstEvent * event)
|
||||||
update_start = FALSE;
|
update_start = FALSE;
|
||||||
break;
|
break;
|
||||||
case GST_SEEK_TYPE_SET:
|
case GST_SEEK_TYPE_SET:
|
||||||
/* cur hold desired position */
|
/* cur holds desired position */
|
||||||
break;
|
break;
|
||||||
case GST_SEEK_TYPE_CUR:
|
case GST_SEEK_TYPE_CUR:
|
||||||
/* add cur to currently configure segment */
|
/* add cur to currently configure segment */
|
||||||
|
@ -503,64 +502,187 @@ gst_base_src_do_seek (GstBaseSrc * src, GstEvent * event)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* bring in sane range */
|
/* bring in sane range */
|
||||||
cur = CLAMP (cur, 0, src->size);
|
if (src->size != -1)
|
||||||
|
cur = CLAMP (cur, 0, src->size);
|
||||||
|
else
|
||||||
|
cur = MAX (cur, 0);
|
||||||
|
|
||||||
|
/* segment_end can be -1 if we have not configured a stop. */
|
||||||
switch (stop_type) {
|
switch (stop_type) {
|
||||||
case GST_SEEK_TYPE_NONE:
|
case GST_SEEK_TYPE_NONE:
|
||||||
stop = src->segment_end;
|
stop = src->segment_end;
|
||||||
update_stop = FALSE;
|
update_stop = FALSE;
|
||||||
break;
|
break;
|
||||||
case GST_SEEK_TYPE_SET:
|
case GST_SEEK_TYPE_SET:
|
||||||
|
/* stop folds required value */
|
||||||
break;
|
break;
|
||||||
case GST_SEEK_TYPE_CUR:
|
case GST_SEEK_TYPE_CUR:
|
||||||
stop = src->segment_end + stop;
|
if (src->segment_end != -1)
|
||||||
|
stop = src->segment_end + stop;
|
||||||
|
else
|
||||||
|
stop = -1;
|
||||||
break;
|
break;
|
||||||
case GST_SEEK_TYPE_END:
|
case GST_SEEK_TYPE_END:
|
||||||
stop = src->size + stop;
|
if (src->size != -1)
|
||||||
|
stop = src->size + stop;
|
||||||
|
else
|
||||||
|
stop = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
stop = CLAMP (stop, 0, src->size);
|
|
||||||
|
/* if we have a valid stop time, make sure it is clipped */
|
||||||
|
if (stop != -1) {
|
||||||
|
if (src->size != -1)
|
||||||
|
stop = CLAMP (stop, 0, src->size);
|
||||||
|
else
|
||||||
|
stop = MAX (stop, 0);
|
||||||
|
}
|
||||||
|
|
||||||
src->segment_start = cur;
|
src->segment_start = cur;
|
||||||
src->segment_end = stop;
|
src->segment_end = stop;
|
||||||
|
|
||||||
/* update our offset */
|
/* update our offset if it was updated */
|
||||||
src->offset = cur;
|
if (update_start)
|
||||||
|
src->offset = cur;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (src, "seek pending for segment from %" G_GINT64_FORMAT
|
GST_DEBUG_OBJECT (src, "segment configured from %" G_GINT64_FORMAT
|
||||||
" to %" G_GINT64_FORMAT, src->segment_start, src->segment_end);
|
" to %" G_GINT64_FORMAT, src->segment_start, src->segment_end);
|
||||||
|
|
||||||
/* now make sure the newsegment will be send */
|
return TRUE;
|
||||||
src->need_newsegment = TRUE;
|
}
|
||||||
|
|
||||||
|
/* this code implements the seeking. It is a good example
|
||||||
|
* handling all cases (modulo the FIXMEs).
|
||||||
|
*
|
||||||
|
* A seek updates the currently configured segment_start
|
||||||
|
* and segment_stop values based on the SEEK_TYPE. If the
|
||||||
|
* segment_start value is updated, a seek to this new position
|
||||||
|
* should be performed.
|
||||||
|
*
|
||||||
|
* The seek can only be executed when we are not currently
|
||||||
|
* streaming any data, to make sure that this is the case, we
|
||||||
|
* acquire the STREAM_LOCK which is taken when we are in the
|
||||||
|
* _loop() function or when a getrange() is called. Normally
|
||||||
|
* we will not receive a seek if we are operating in pull mode
|
||||||
|
* though.
|
||||||
|
*
|
||||||
|
* When we are in the loop() function, we might be in the middle
|
||||||
|
* of pushing a buffer, which might block in a sink. To make sure
|
||||||
|
* that the push gets unblocked we push out a FLUSH_START event.
|
||||||
|
* Our loop function will get a WRONG_STATE return value from
|
||||||
|
* the push and will pause, effectively releasing the STREAM_LOCK.
|
||||||
|
*
|
||||||
|
* For a non-flushing seek, we pause the task, which might eventually
|
||||||
|
* release the STREAM_LOCK. We say eventually because when the sink
|
||||||
|
* blocks on the sample we might wait a very long time until the sink
|
||||||
|
* unblocks the sample. In any case we acquire the STREAM_LOCK and
|
||||||
|
* can continue the seek. A non-flushing seek is normally done in a
|
||||||
|
* running pipeline to perform seamless playback.
|
||||||
|
*
|
||||||
|
* After updating the segment_start/stop values, we prepare for
|
||||||
|
* streaming again. We push out a FLUSH_STOP to make the peer pad
|
||||||
|
* accept data again and we start our task again.
|
||||||
|
*
|
||||||
|
* A segment seek posts a message on the bus saying that the playback
|
||||||
|
* of the segment started. We store the segment flag internally because
|
||||||
|
* when we reach the segment_stop we have to post a segment_done
|
||||||
|
* instead of EOS when doing a segment seek.
|
||||||
|
*/
|
||||||
|
static gboolean
|
||||||
|
gst_base_src_do_seek (GstBaseSrc * src, GstEvent * event)
|
||||||
|
{
|
||||||
|
gdouble rate;
|
||||||
|
GstFormat format;
|
||||||
|
GstSeekFlags flags;
|
||||||
|
gboolean flush;
|
||||||
|
|
||||||
|
gst_event_parse_seek (event, &rate, &format, &flags, NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
/* FIXME subclasses should be able to provide other formats */
|
||||||
|
/* get seek format */
|
||||||
|
if (format == GST_FORMAT_DEFAULT)
|
||||||
|
format = GST_FORMAT_BYTES;
|
||||||
|
/* we can only seek bytes */
|
||||||
|
if (format != GST_FORMAT_BYTES)
|
||||||
|
goto unsupported_seek;
|
||||||
|
|
||||||
|
flush = flags & GST_SEEK_FLAG_FLUSH;
|
||||||
|
|
||||||
|
/* send flush start */
|
||||||
if (flush)
|
if (flush)
|
||||||
/* send flush stop */
|
gst_pad_push_event (src->srcpad, gst_event_new_flush_start ());
|
||||||
|
else
|
||||||
|
gst_pad_pause_task (src->srcpad);
|
||||||
|
|
||||||
|
/* unblock streaming thread */
|
||||||
|
gst_base_src_unlock (src);
|
||||||
|
|
||||||
|
/* grab streaming lock, this should eventually be possible, either
|
||||||
|
* because the task is paused or out streaming thread stopped
|
||||||
|
* because our peer is flushing. */
|
||||||
|
GST_STREAM_LOCK (src->srcpad);
|
||||||
|
|
||||||
|
/* now configure the segment */
|
||||||
|
gst_base_src_configure_segment (src, event);
|
||||||
|
|
||||||
|
/* and prepare to continue streaming */
|
||||||
|
if (flush)
|
||||||
|
/* send flush stop, peer will accept data and events again. We
|
||||||
|
* are not yet providing data as we still have the STREAM_LOCK. */
|
||||||
gst_pad_push_event (src->srcpad, gst_event_new_flush_stop ());
|
gst_pad_push_event (src->srcpad, gst_event_new_flush_stop ());
|
||||||
|
|
||||||
|
/* now make sure the newsegment will be send from the streaming
|
||||||
|
* thread. We could opt to send it here too. */
|
||||||
|
src->need_newsegment = TRUE;
|
||||||
|
|
||||||
if (src->segment_loop) {
|
if (src->segment_loop) {
|
||||||
|
/* FIXME subclasses should be able to provide other formats */
|
||||||
gst_element_post_message (GST_ELEMENT (src),
|
gst_element_post_message (GST_ELEMENT (src),
|
||||||
gst_message_new_segment_start (GST_OBJECT (src), GST_FORMAT_BYTES,
|
gst_message_new_segment_start (GST_OBJECT (src), GST_FORMAT_BYTES,
|
||||||
cur));
|
src->segment_start));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* and restart the task */
|
/* and restart the task in case it got paused explicitely or by
|
||||||
|
* the FLUSH_START event we pushed out. */
|
||||||
gst_pad_start_task (src->srcpad, (GstTaskFunction) gst_base_src_loop,
|
gst_pad_start_task (src->srcpad, (GstTaskFunction) gst_base_src_loop,
|
||||||
src->srcpad);
|
src->srcpad);
|
||||||
|
|
||||||
|
/* and release the lock again so we can continue streaming */
|
||||||
GST_STREAM_UNLOCK (src->srcpad);
|
GST_STREAM_UNLOCK (src->srcpad);
|
||||||
|
|
||||||
gst_event_unref (event);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
/* ERROR */
|
/* ERROR */
|
||||||
unsupported_seek:
|
unsupported_seek:
|
||||||
{
|
{
|
||||||
GST_DEBUG_OBJECT (src, "invalid format, seek aborted.");
|
GST_DEBUG_OBJECT (src, "invalid format, seek aborted.");
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* all events send to this element directly
|
||||||
|
*/
|
||||||
|
static gboolean
|
||||||
|
gst_base_src_send_event (GstElement * element, GstEvent * event)
|
||||||
|
{
|
||||||
|
GstBaseSrc *src;
|
||||||
|
gboolean result;
|
||||||
|
|
||||||
|
src = GST_BASE_SRC (element);
|
||||||
|
|
||||||
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
|
case GST_EVENT_SEEK:
|
||||||
|
result = gst_base_src_configure_segment (src, event);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_base_src_event_handler (GstPad * pad, GstEvent * event)
|
gst_base_src_event_handler (GstPad * pad, GstEvent * event)
|
||||||
{
|
{
|
||||||
|
@ -568,31 +690,52 @@ gst_base_src_event_handler (GstPad * pad, GstEvent * event)
|
||||||
GstBaseSrcClass *bclass;
|
GstBaseSrcClass *bclass;
|
||||||
gboolean result;
|
gboolean result;
|
||||||
|
|
||||||
src = GST_BASE_SRC (GST_PAD_PARENT (pad));
|
src = GST_BASE_SRC (gst_pad_get_parent (pad));
|
||||||
bclass = GST_BASE_SRC_GET_CLASS (src);
|
bclass = GST_BASE_SRC_GET_CLASS (src);
|
||||||
|
|
||||||
if (bclass->event)
|
if (bclass->event) {
|
||||||
result = bclass->event (src, event);
|
if (!(result = bclass->event (src, event)))
|
||||||
|
goto subclass_failed;
|
||||||
|
}
|
||||||
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
case GST_EVENT_SEEK:
|
case GST_EVENT_SEEK:
|
||||||
if (!src->seekable) {
|
/* is normally called when in push mode */
|
||||||
gst_event_unref (event);
|
if (!src->seekable)
|
||||||
return FALSE;
|
goto not_seekable;
|
||||||
}
|
|
||||||
return gst_base_src_do_seek (src, event);
|
result = gst_base_src_do_seek (src, event);
|
||||||
|
break;
|
||||||
case GST_EVENT_FLUSH_START:
|
case GST_EVENT_FLUSH_START:
|
||||||
/* cancel any blocking getrange */
|
/* cancel any blocking getrange, is normally called
|
||||||
gst_base_src_unlock (src);
|
* when in pull mode. */
|
||||||
|
result = gst_base_src_unlock (src);
|
||||||
break;
|
break;
|
||||||
case GST_EVENT_FLUSH_STOP:
|
case GST_EVENT_FLUSH_STOP:
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
|
result = TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
gst_event_unref (event);
|
gst_event_unref (event);
|
||||||
|
gst_object_unref (src);
|
||||||
|
|
||||||
return TRUE;
|
return result;
|
||||||
|
|
||||||
|
/* ERRORS */
|
||||||
|
subclass_failed:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (src, "subclass refused event");
|
||||||
|
gst_object_unref (src);
|
||||||
|
gst_event_unref (event);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
not_seekable:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (src, "is not seekable");
|
||||||
|
gst_object_unref (src);
|
||||||
|
gst_event_unref (event);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -772,6 +915,7 @@ gst_base_src_loop (GstPad * pad)
|
||||||
|
|
||||||
src = GST_BASE_SRC (gst_pad_get_parent (pad));
|
src = GST_BASE_SRC (gst_pad_get_parent (pad));
|
||||||
|
|
||||||
|
/* only send segments when operating in push mode */
|
||||||
if (G_UNLIKELY (src->need_newsegment)) {
|
if (G_UNLIKELY (src->need_newsegment)) {
|
||||||
/* now send newsegment */
|
/* now send newsegment */
|
||||||
gst_base_src_newsegment (src);
|
gst_base_src_newsegment (src);
|
||||||
|
@ -800,9 +944,10 @@ gst_base_src_loop (GstPad * pad)
|
||||||
/* special cases */
|
/* special cases */
|
||||||
eos:
|
eos:
|
||||||
{
|
{
|
||||||
GST_DEBUG_OBJECT (src, "going to EOS");
|
GST_DEBUG_OBJECT (src, "going to EOS, getrange returned UNEXPECTED");
|
||||||
gst_pad_pause_task (pad);
|
gst_pad_pause_task (pad);
|
||||||
if (src->segment_loop) {
|
if (src->segment_loop) {
|
||||||
|
/* FIXME, subclass might want to use another format */
|
||||||
gst_element_post_message (GST_ELEMENT (src),
|
gst_element_post_message (GST_ELEMENT (src),
|
||||||
gst_message_new_segment_done (GST_OBJECT (src),
|
gst_message_new_segment_done (GST_OBJECT (src),
|
||||||
GST_FORMAT_BYTES, src->segment_end));
|
GST_FORMAT_BYTES, src->segment_end));
|
||||||
|
@ -815,9 +960,7 @@ eos:
|
||||||
}
|
}
|
||||||
pause:
|
pause:
|
||||||
{
|
{
|
||||||
const gchar *reason;
|
const gchar *reason = gst_flow_get_name (ret);
|
||||||
|
|
||||||
reason = gst_flow_get_name (ret);
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (src, "pausing task, reason %s", reason);
|
GST_DEBUG_OBJECT (src, "pausing task, reason %s", reason);
|
||||||
gst_pad_pause_task (pad);
|
gst_pad_pause_task (pad);
|
||||||
|
@ -850,7 +993,7 @@ static gboolean
|
||||||
gst_base_src_unlock (GstBaseSrc * basesrc)
|
gst_base_src_unlock (GstBaseSrc * basesrc)
|
||||||
{
|
{
|
||||||
GstBaseSrcClass *bclass;
|
GstBaseSrcClass *bclass;
|
||||||
gboolean result = FALSE;
|
gboolean result = TRUE;
|
||||||
|
|
||||||
GST_DEBUG ("unlock");
|
GST_DEBUG ("unlock");
|
||||||
/* unblock whatever the subclass is doing */
|
/* unblock whatever the subclass is doing */
|
||||||
|
@ -905,6 +1048,7 @@ gst_base_src_is_seekable (GstBaseSrc * basesrc)
|
||||||
return basesrc->seekable;
|
return basesrc->seekable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* default negotiation code */
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_base_src_default_negotiate (GstBaseSrc * basesrc)
|
gst_base_src_default_negotiate (GstBaseSrc * basesrc)
|
||||||
{
|
{
|
||||||
|
@ -913,38 +1057,48 @@ gst_base_src_default_negotiate (GstBaseSrc * basesrc)
|
||||||
GstCaps *peercaps = NULL;
|
GstCaps *peercaps = NULL;
|
||||||
gboolean result = FALSE;
|
gboolean result = FALSE;
|
||||||
|
|
||||||
|
/* first see what is possible on our source pad */
|
||||||
thiscaps = gst_pad_get_caps (GST_BASE_SRC_PAD (basesrc));
|
thiscaps = gst_pad_get_caps (GST_BASE_SRC_PAD (basesrc));
|
||||||
GST_DEBUG ("caps of src: %" GST_PTR_FORMAT, thiscaps);
|
GST_DEBUG ("caps of src: %" GST_PTR_FORMAT, thiscaps);
|
||||||
|
/* nothing or anything is allowed, we're done */
|
||||||
if (thiscaps == NULL || gst_caps_is_any (thiscaps))
|
if (thiscaps == NULL || gst_caps_is_any (thiscaps))
|
||||||
goto no_nego_needed;
|
goto no_nego_needed;
|
||||||
|
|
||||||
|
/* get the peer caps */
|
||||||
peercaps = gst_pad_peer_get_caps (GST_BASE_SRC_PAD (basesrc));
|
peercaps = gst_pad_peer_get_caps (GST_BASE_SRC_PAD (basesrc));
|
||||||
GST_DEBUG ("caps of peer: %" GST_PTR_FORMAT, peercaps);
|
GST_DEBUG ("caps of peer: %" GST_PTR_FORMAT, peercaps);
|
||||||
if (peercaps) {
|
if (peercaps) {
|
||||||
GstCaps *icaps;
|
GstCaps *icaps;
|
||||||
|
|
||||||
|
/* get intersection */
|
||||||
icaps = gst_caps_intersect (thiscaps, peercaps);
|
icaps = gst_caps_intersect (thiscaps, peercaps);
|
||||||
GST_DEBUG ("intersect: %" GST_PTR_FORMAT, icaps);
|
GST_DEBUG ("intersect: %" GST_PTR_FORMAT, icaps);
|
||||||
gst_caps_unref (thiscaps);
|
gst_caps_unref (thiscaps);
|
||||||
gst_caps_unref (peercaps);
|
gst_caps_unref (peercaps);
|
||||||
if (icaps) {
|
if (icaps) {
|
||||||
|
/* take first (and best) possibility */
|
||||||
caps = gst_caps_copy_nth (icaps, 0);
|
caps = gst_caps_copy_nth (icaps, 0);
|
||||||
gst_caps_unref (icaps);
|
gst_caps_unref (icaps);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
/* no peer, work with our own caps then */
|
||||||
caps = thiscaps;
|
caps = thiscaps;
|
||||||
}
|
}
|
||||||
if (caps) {
|
if (caps) {
|
||||||
caps = gst_caps_make_writable (caps);
|
caps = gst_caps_make_writable (caps);
|
||||||
gst_caps_truncate (caps);
|
gst_caps_truncate (caps);
|
||||||
|
|
||||||
|
/* now fixate */
|
||||||
gst_pad_fixate_caps (GST_BASE_SRC_PAD (basesrc), caps);
|
gst_pad_fixate_caps (GST_BASE_SRC_PAD (basesrc), caps);
|
||||||
GST_DEBUG ("fixated to: %" GST_PTR_FORMAT, caps);
|
GST_DEBUG ("fixated to: %" GST_PTR_FORMAT, caps);
|
||||||
|
|
||||||
if (gst_caps_is_any (caps)) {
|
if (gst_caps_is_any (caps)) {
|
||||||
|
/* hmm, still anything, so element can do anything and
|
||||||
|
* nego is not needed */
|
||||||
gst_caps_unref (caps);
|
gst_caps_unref (caps);
|
||||||
result = TRUE;
|
result = TRUE;
|
||||||
} else if (gst_caps_is_fixed (caps)) {
|
} else if (gst_caps_is_fixed (caps)) {
|
||||||
|
/* yay, fixed caps, use those then */
|
||||||
gst_pad_set_caps (GST_BASE_SRC_PAD (basesrc), caps);
|
gst_pad_set_caps (GST_BASE_SRC_PAD (basesrc), caps);
|
||||||
gst_caps_unref (caps);
|
gst_caps_unref (caps);
|
||||||
result = TRUE;
|
result = TRUE;
|
||||||
|
@ -999,9 +1153,6 @@ gst_base_src_start (GstBaseSrc * basesrc)
|
||||||
|
|
||||||
GST_OBJECT_FLAG_SET (basesrc, GST_BASE_SRC_STARTED);
|
GST_OBJECT_FLAG_SET (basesrc, GST_BASE_SRC_STARTED);
|
||||||
|
|
||||||
/* start in the beginning */
|
|
||||||
basesrc->offset = 0;
|
|
||||||
|
|
||||||
/* figure out the size */
|
/* figure out the size */
|
||||||
if (bclass->get_size) {
|
if (bclass->get_size) {
|
||||||
result = bclass->get_size (basesrc, &basesrc->size);
|
result = bclass->get_size (basesrc, &basesrc->size);
|
||||||
|
@ -1014,15 +1165,11 @@ gst_base_src_start (GstBaseSrc * basesrc)
|
||||||
|
|
||||||
GST_DEBUG ("size %d %lld", result, basesrc->size);
|
GST_DEBUG ("size %d %lld", result, basesrc->size);
|
||||||
|
|
||||||
/* we always run to the end when starting */
|
|
||||||
basesrc->segment_loop = FALSE;
|
|
||||||
basesrc->segment_start = 0;
|
|
||||||
basesrc->segment_end = basesrc->size;
|
|
||||||
basesrc->need_newsegment = TRUE;
|
|
||||||
|
|
||||||
/* check if we can seek, updates ->seekable */
|
/* check if we can seek, updates ->seekable */
|
||||||
gst_base_src_is_seekable (basesrc);
|
gst_base_src_is_seekable (basesrc);
|
||||||
|
|
||||||
|
basesrc->need_newsegment = TRUE;
|
||||||
|
|
||||||
/* run typefind */
|
/* run typefind */
|
||||||
#if 0
|
#if 0
|
||||||
if (basesrc->seekable) {
|
if (basesrc->seekable) {
|
||||||
|
@ -1088,10 +1235,10 @@ gst_base_src_deactivate (GstBaseSrc * basesrc, GstPad * pad)
|
||||||
GST_LIVE_UNLOCK (basesrc);
|
GST_LIVE_UNLOCK (basesrc);
|
||||||
|
|
||||||
/* step 1, unblock clock sync (if any) */
|
/* step 1, unblock clock sync (if any) */
|
||||||
gst_base_src_unlock (basesrc);
|
result = gst_base_src_unlock (basesrc);
|
||||||
|
|
||||||
/* step 2, make sure streaming finishes */
|
/* step 2, make sure streaming finishes */
|
||||||
result = gst_pad_stop_task (pad);
|
result &= gst_pad_stop_task (pad);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -1100,6 +1247,7 @@ static gboolean
|
||||||
gst_base_src_activate_push (GstPad * pad, gboolean active)
|
gst_base_src_activate_push (GstPad * pad, gboolean active)
|
||||||
{
|
{
|
||||||
GstBaseSrc *basesrc;
|
GstBaseSrc *basesrc;
|
||||||
|
gboolean res;
|
||||||
|
|
||||||
basesrc = GST_BASE_SRC (GST_OBJECT_PARENT (pad));
|
basesrc = GST_BASE_SRC (GST_OBJECT_PARENT (pad));
|
||||||
|
|
||||||
|
@ -1113,12 +1261,14 @@ gst_base_src_activate_push (GstPad * pad, gboolean active)
|
||||||
if (!gst_base_src_start (basesrc))
|
if (!gst_base_src_start (basesrc))
|
||||||
goto error_start;
|
goto error_start;
|
||||||
|
|
||||||
return gst_pad_start_task (pad, (GstTaskFunction) gst_base_src_loop, pad);
|
res = gst_pad_start_task (pad, (GstTaskFunction) gst_base_src_loop, pad);
|
||||||
} else {
|
} else {
|
||||||
GST_DEBUG_OBJECT (basesrc, "Deactivating in push mode");
|
GST_DEBUG_OBJECT (basesrc, "Deactivating in push mode");
|
||||||
return gst_base_src_deactivate (basesrc, pad);
|
res = gst_base_src_deactivate (basesrc, pad);
|
||||||
}
|
}
|
||||||
|
return res;
|
||||||
|
|
||||||
|
/* ERRORS */
|
||||||
no_push_activation:
|
no_push_activation:
|
||||||
{
|
{
|
||||||
GST_DEBUG_OBJECT (basesrc, "Subclass disabled push-mode activation");
|
GST_DEBUG_OBJECT (basesrc, "Subclass disabled push-mode activation");
|
||||||
|
@ -1182,7 +1332,6 @@ gst_base_src_change_state (GstElement * element, GstStateChange transition)
|
||||||
|
|
||||||
basesrc = GST_BASE_SRC (element);
|
basesrc = GST_BASE_SRC (element);
|
||||||
|
|
||||||
|
|
||||||
switch (transition) {
|
switch (transition) {
|
||||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
case GST_STATE_CHANGE_NULL_TO_READY:
|
||||||
break;
|
break;
|
||||||
|
@ -1212,6 +1361,15 @@ gst_base_src_change_state (GstElement * element, GstStateChange transition)
|
||||||
goto failure;
|
goto failure;
|
||||||
|
|
||||||
switch (transition) {
|
switch (transition) {
|
||||||
|
case GST_STATE_CHANGE_NULL_TO_READY:
|
||||||
|
/* we always run from start to end when in READY, after putting
|
||||||
|
* the element to READY a seek can be done on the element to
|
||||||
|
* configure the segment when going to PAUSED. */
|
||||||
|
basesrc->segment_loop = FALSE;
|
||||||
|
basesrc->segment_start = 0;
|
||||||
|
basesrc->segment_end = -1;
|
||||||
|
basesrc->offset = 0;
|
||||||
|
break;
|
||||||
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
|
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
|
||||||
GST_LIVE_LOCK (element);
|
GST_LIVE_LOCK (element);
|
||||||
if (basesrc->is_live) {
|
if (basesrc->is_live) {
|
||||||
|
@ -1222,7 +1380,12 @@ gst_base_src_change_state (GstElement * element, GstStateChange transition)
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||||
if (!gst_base_src_stop (basesrc))
|
if (!gst_base_src_stop (basesrc))
|
||||||
result = GST_STATE_CHANGE_FAILURE;
|
goto error_stop;
|
||||||
|
/* we always run from start to end when in READY */
|
||||||
|
basesrc->segment_loop = FALSE;
|
||||||
|
basesrc->segment_start = 0;
|
||||||
|
basesrc->segment_end = -1;
|
||||||
|
basesrc->offset = 0;
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||||
break;
|
break;
|
||||||
|
@ -1231,14 +1394,20 @@ gst_base_src_change_state (GstElement * element, GstStateChange transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (no_preroll && result == GST_STATE_CHANGE_SUCCESS)
|
if (no_preroll && result == GST_STATE_CHANGE_SUCCESS)
|
||||||
return GST_STATE_CHANGE_NO_PREROLL;
|
result = GST_STATE_CHANGE_NO_PREROLL;
|
||||||
else
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
failure:
|
failure:
|
||||||
{
|
{
|
||||||
|
GST_DEBUG_OBJECT (basesrc, "parent failed state change");
|
||||||
gst_base_src_stop (basesrc);
|
gst_base_src_stop (basesrc);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
error_stop:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (basesrc, "Failed to stop");
|
||||||
|
return GST_STATE_CHANGE_FAILURE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,6 +113,7 @@ static void gst_base_src_set_property (GObject * object, guint prop_id,
|
||||||
static void gst_base_src_get_property (GObject * object, guint prop_id,
|
static void gst_base_src_get_property (GObject * object, guint prop_id,
|
||||||
GValue * value, GParamSpec * pspec);
|
GValue * value, GParamSpec * pspec);
|
||||||
static gboolean gst_base_src_event_handler (GstPad * pad, GstEvent * event);
|
static gboolean gst_base_src_event_handler (GstPad * pad, GstEvent * event);
|
||||||
|
static gboolean gst_base_src_send_event (GstElement * elem, GstEvent * event);
|
||||||
|
|
||||||
static gboolean gst_base_src_query (GstPad * pad, GstQuery * query);
|
static gboolean gst_base_src_query (GstPad * pad, GstQuery * query);
|
||||||
|
|
||||||
|
@ -167,6 +168,7 @@ gst_base_src_class_init (GstBaseSrcClass * klass)
|
||||||
|
|
||||||
gstelement_class->change_state =
|
gstelement_class->change_state =
|
||||||
GST_DEBUG_FUNCPTR (gst_base_src_change_state);
|
GST_DEBUG_FUNCPTR (gst_base_src_change_state);
|
||||||
|
gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_base_src_send_event);
|
||||||
|
|
||||||
klass->negotiate = gst_base_src_default_negotiate;
|
klass->negotiate = gst_base_src_default_negotiate;
|
||||||
klass->newsegment = gst_base_src_default_newsegment;
|
klass->newsegment = gst_base_src_default_newsegment;
|
||||||
|
@ -214,10 +216,6 @@ gst_base_src_init (GstBaseSrc * basesrc, gpointer g_class)
|
||||||
GST_DEBUG_OBJECT (basesrc, "adding src pad");
|
GST_DEBUG_OBJECT (basesrc, "adding src pad");
|
||||||
gst_element_add_pad (GST_ELEMENT (basesrc), pad);
|
gst_element_add_pad (GST_ELEMENT (basesrc), pad);
|
||||||
|
|
||||||
basesrc->segment_loop = FALSE;
|
|
||||||
basesrc->segment_start = -1;
|
|
||||||
basesrc->segment_end = -1;
|
|
||||||
basesrc->need_newsegment = TRUE;
|
|
||||||
basesrc->blocksize = DEFAULT_BLOCKSIZE;
|
basesrc->blocksize = DEFAULT_BLOCKSIZE;
|
||||||
basesrc->clock_id = NULL;
|
basesrc->clock_id = NULL;
|
||||||
|
|
||||||
|
@ -392,10 +390,26 @@ gst_base_src_query (GstPad * pad, GstQuery * query)
|
||||||
|
|
||||||
case GST_QUERY_SEEKING:
|
case GST_QUERY_SEEKING:
|
||||||
gst_query_set_seeking (query, GST_FORMAT_BYTES,
|
gst_query_set_seeking (query, GST_FORMAT_BYTES,
|
||||||
src->seekable, src->segment_start, src->segment_end);
|
src->seekable, 0, src->size);
|
||||||
res = TRUE;
|
res = TRUE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case GST_QUERY_SEGMENT:
|
||||||
|
{
|
||||||
|
gint64 start, stop;
|
||||||
|
|
||||||
|
start = src->segment_start;
|
||||||
|
/* no end segment configured, current size then */
|
||||||
|
if ((stop = src->segment_end) == -1)
|
||||||
|
stop = src->size;
|
||||||
|
|
||||||
|
/* FIXME, we can't report our rate as we did not store it, d'oh!.
|
||||||
|
* Also, subclasses might want to support other formats. */
|
||||||
|
gst_query_set_segment (query, 1.0, GST_FORMAT_BYTES, start, stop);
|
||||||
|
res = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case GST_QUERY_FORMATS:
|
case GST_QUERY_FORMATS:
|
||||||
gst_query_set_formats (query, 3, GST_FORMAT_DEFAULT,
|
gst_query_set_formats (query, 3, GST_FORMAT_DEFAULT,
|
||||||
GST_FORMAT_BYTES, GST_FORMAT_PERCENT);
|
GST_FORMAT_BYTES, GST_FORMAT_PERCENT);
|
||||||
|
@ -421,12 +435,11 @@ gst_base_src_default_newsegment (GstBaseSrc * src)
|
||||||
GstEvent *event;
|
GstEvent *event;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (src, "Sending newsegment from %" G_GINT64_FORMAT
|
GST_DEBUG_OBJECT (src, "Sending newsegment from %" G_GINT64_FORMAT
|
||||||
" to %" G_GINT64_FORMAT, (gint64) src->segment_start,
|
" to %" G_GINT64_FORMAT, src->segment_start, src->segment_end);
|
||||||
(gint64) src->segment_end);
|
|
||||||
event = gst_event_new_newsegment (FALSE, 1.0,
|
event = gst_event_new_newsegment (FALSE, 1.0,
|
||||||
GST_FORMAT_BYTES,
|
GST_FORMAT_BYTES, src->segment_start, src->segment_end,
|
||||||
(gint64) src->segment_start, (gint64) src->segment_end,
|
src->segment_start);
|
||||||
(gint64) src->segment_start);
|
|
||||||
|
|
||||||
return gst_pad_push_event (src->srcpad, event);
|
return gst_pad_push_event (src->srcpad, event);
|
||||||
}
|
}
|
||||||
|
@ -445,45 +458,31 @@ gst_base_src_newsegment (GstBaseSrc * src)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* based on the event parameters configure the segment_start/stop
|
||||||
|
* times. Called with STREAM_LOCK.
|
||||||
|
*/
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_base_src_do_seek (GstBaseSrc * src, GstEvent * event)
|
gst_base_src_configure_segment (GstBaseSrc * src, GstEvent * event)
|
||||||
{
|
{
|
||||||
gdouble rate;
|
gdouble rate;
|
||||||
GstFormat format;
|
GstFormat format;
|
||||||
GstSeekFlags flags;
|
GstSeekFlags flags;
|
||||||
GstSeekType cur_type, stop_type;
|
GstSeekType cur_type, stop_type;
|
||||||
gint64 cur, stop;
|
gint64 cur, stop;
|
||||||
gboolean flush;
|
gboolean update_stop, update_start;
|
||||||
gboolean update_stop = TRUE, update_start = TRUE;
|
|
||||||
|
|
||||||
gst_event_parse_seek (event, &rate, &format, &flags,
|
gst_event_parse_seek (event, &rate, &format, &flags,
|
||||||
&cur_type, &cur, &stop_type, &stop);
|
&cur_type, &cur, &stop_type, &stop);
|
||||||
|
|
||||||
/* get seek format */
|
/* parse the loop flag */
|
||||||
if (format == GST_FORMAT_DEFAULT)
|
/* FIXME, need to store other flags and rate too */
|
||||||
format = GST_FORMAT_BYTES;
|
|
||||||
/* we can only seek bytes */
|
|
||||||
if (format != GST_FORMAT_BYTES)
|
|
||||||
goto unsupported_seek;
|
|
||||||
|
|
||||||
flush = flags & GST_SEEK_FLAG_FLUSH;
|
|
||||||
|
|
||||||
/* get seek positions */
|
|
||||||
src->segment_loop = (flags & GST_SEEK_FLAG_SEGMENT) != 0;
|
src->segment_loop = (flags & GST_SEEK_FLAG_SEGMENT) != 0;
|
||||||
|
|
||||||
/* send flush start */
|
/* assume we'll update both start and stop values */
|
||||||
if (flush)
|
update_start = TRUE;
|
||||||
gst_pad_push_event (src->srcpad, gst_event_new_flush_start ());
|
update_stop = TRUE;
|
||||||
else
|
|
||||||
gst_pad_pause_task (src->srcpad);
|
|
||||||
|
|
||||||
/* unblock streaming thread */
|
/* perform the seek, segment_start is never invalid */
|
||||||
gst_base_src_unlock (src);
|
|
||||||
|
|
||||||
/* grab streaming lock */
|
|
||||||
GST_STREAM_LOCK (src->srcpad);
|
|
||||||
|
|
||||||
/* perform the seek */
|
|
||||||
switch (cur_type) {
|
switch (cur_type) {
|
||||||
case GST_SEEK_TYPE_NONE:
|
case GST_SEEK_TYPE_NONE:
|
||||||
/* no update to segment */
|
/* no update to segment */
|
||||||
|
@ -491,7 +490,7 @@ gst_base_src_do_seek (GstBaseSrc * src, GstEvent * event)
|
||||||
update_start = FALSE;
|
update_start = FALSE;
|
||||||
break;
|
break;
|
||||||
case GST_SEEK_TYPE_SET:
|
case GST_SEEK_TYPE_SET:
|
||||||
/* cur hold desired position */
|
/* cur holds desired position */
|
||||||
break;
|
break;
|
||||||
case GST_SEEK_TYPE_CUR:
|
case GST_SEEK_TYPE_CUR:
|
||||||
/* add cur to currently configure segment */
|
/* add cur to currently configure segment */
|
||||||
|
@ -503,64 +502,187 @@ gst_base_src_do_seek (GstBaseSrc * src, GstEvent * event)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* bring in sane range */
|
/* bring in sane range */
|
||||||
cur = CLAMP (cur, 0, src->size);
|
if (src->size != -1)
|
||||||
|
cur = CLAMP (cur, 0, src->size);
|
||||||
|
else
|
||||||
|
cur = MAX (cur, 0);
|
||||||
|
|
||||||
|
/* segment_end can be -1 if we have not configured a stop. */
|
||||||
switch (stop_type) {
|
switch (stop_type) {
|
||||||
case GST_SEEK_TYPE_NONE:
|
case GST_SEEK_TYPE_NONE:
|
||||||
stop = src->segment_end;
|
stop = src->segment_end;
|
||||||
update_stop = FALSE;
|
update_stop = FALSE;
|
||||||
break;
|
break;
|
||||||
case GST_SEEK_TYPE_SET:
|
case GST_SEEK_TYPE_SET:
|
||||||
|
/* stop folds required value */
|
||||||
break;
|
break;
|
||||||
case GST_SEEK_TYPE_CUR:
|
case GST_SEEK_TYPE_CUR:
|
||||||
stop = src->segment_end + stop;
|
if (src->segment_end != -1)
|
||||||
|
stop = src->segment_end + stop;
|
||||||
|
else
|
||||||
|
stop = -1;
|
||||||
break;
|
break;
|
||||||
case GST_SEEK_TYPE_END:
|
case GST_SEEK_TYPE_END:
|
||||||
stop = src->size + stop;
|
if (src->size != -1)
|
||||||
|
stop = src->size + stop;
|
||||||
|
else
|
||||||
|
stop = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
stop = CLAMP (stop, 0, src->size);
|
|
||||||
|
/* if we have a valid stop time, make sure it is clipped */
|
||||||
|
if (stop != -1) {
|
||||||
|
if (src->size != -1)
|
||||||
|
stop = CLAMP (stop, 0, src->size);
|
||||||
|
else
|
||||||
|
stop = MAX (stop, 0);
|
||||||
|
}
|
||||||
|
|
||||||
src->segment_start = cur;
|
src->segment_start = cur;
|
||||||
src->segment_end = stop;
|
src->segment_end = stop;
|
||||||
|
|
||||||
/* update our offset */
|
/* update our offset if it was updated */
|
||||||
src->offset = cur;
|
if (update_start)
|
||||||
|
src->offset = cur;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (src, "seek pending for segment from %" G_GINT64_FORMAT
|
GST_DEBUG_OBJECT (src, "segment configured from %" G_GINT64_FORMAT
|
||||||
" to %" G_GINT64_FORMAT, src->segment_start, src->segment_end);
|
" to %" G_GINT64_FORMAT, src->segment_start, src->segment_end);
|
||||||
|
|
||||||
/* now make sure the newsegment will be send */
|
return TRUE;
|
||||||
src->need_newsegment = TRUE;
|
}
|
||||||
|
|
||||||
|
/* this code implements the seeking. It is a good example
|
||||||
|
* handling all cases (modulo the FIXMEs).
|
||||||
|
*
|
||||||
|
* A seek updates the currently configured segment_start
|
||||||
|
* and segment_stop values based on the SEEK_TYPE. If the
|
||||||
|
* segment_start value is updated, a seek to this new position
|
||||||
|
* should be performed.
|
||||||
|
*
|
||||||
|
* The seek can only be executed when we are not currently
|
||||||
|
* streaming any data, to make sure that this is the case, we
|
||||||
|
* acquire the STREAM_LOCK which is taken when we are in the
|
||||||
|
* _loop() function or when a getrange() is called. Normally
|
||||||
|
* we will not receive a seek if we are operating in pull mode
|
||||||
|
* though.
|
||||||
|
*
|
||||||
|
* When we are in the loop() function, we might be in the middle
|
||||||
|
* of pushing a buffer, which might block in a sink. To make sure
|
||||||
|
* that the push gets unblocked we push out a FLUSH_START event.
|
||||||
|
* Our loop function will get a WRONG_STATE return value from
|
||||||
|
* the push and will pause, effectively releasing the STREAM_LOCK.
|
||||||
|
*
|
||||||
|
* For a non-flushing seek, we pause the task, which might eventually
|
||||||
|
* release the STREAM_LOCK. We say eventually because when the sink
|
||||||
|
* blocks on the sample we might wait a very long time until the sink
|
||||||
|
* unblocks the sample. In any case we acquire the STREAM_LOCK and
|
||||||
|
* can continue the seek. A non-flushing seek is normally done in a
|
||||||
|
* running pipeline to perform seamless playback.
|
||||||
|
*
|
||||||
|
* After updating the segment_start/stop values, we prepare for
|
||||||
|
* streaming again. We push out a FLUSH_STOP to make the peer pad
|
||||||
|
* accept data again and we start our task again.
|
||||||
|
*
|
||||||
|
* A segment seek posts a message on the bus saying that the playback
|
||||||
|
* of the segment started. We store the segment flag internally because
|
||||||
|
* when we reach the segment_stop we have to post a segment_done
|
||||||
|
* instead of EOS when doing a segment seek.
|
||||||
|
*/
|
||||||
|
static gboolean
|
||||||
|
gst_base_src_do_seek (GstBaseSrc * src, GstEvent * event)
|
||||||
|
{
|
||||||
|
gdouble rate;
|
||||||
|
GstFormat format;
|
||||||
|
GstSeekFlags flags;
|
||||||
|
gboolean flush;
|
||||||
|
|
||||||
|
gst_event_parse_seek (event, &rate, &format, &flags, NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
/* FIXME subclasses should be able to provide other formats */
|
||||||
|
/* get seek format */
|
||||||
|
if (format == GST_FORMAT_DEFAULT)
|
||||||
|
format = GST_FORMAT_BYTES;
|
||||||
|
/* we can only seek bytes */
|
||||||
|
if (format != GST_FORMAT_BYTES)
|
||||||
|
goto unsupported_seek;
|
||||||
|
|
||||||
|
flush = flags & GST_SEEK_FLAG_FLUSH;
|
||||||
|
|
||||||
|
/* send flush start */
|
||||||
if (flush)
|
if (flush)
|
||||||
/* send flush stop */
|
gst_pad_push_event (src->srcpad, gst_event_new_flush_start ());
|
||||||
|
else
|
||||||
|
gst_pad_pause_task (src->srcpad);
|
||||||
|
|
||||||
|
/* unblock streaming thread */
|
||||||
|
gst_base_src_unlock (src);
|
||||||
|
|
||||||
|
/* grab streaming lock, this should eventually be possible, either
|
||||||
|
* because the task is paused or out streaming thread stopped
|
||||||
|
* because our peer is flushing. */
|
||||||
|
GST_STREAM_LOCK (src->srcpad);
|
||||||
|
|
||||||
|
/* now configure the segment */
|
||||||
|
gst_base_src_configure_segment (src, event);
|
||||||
|
|
||||||
|
/* and prepare to continue streaming */
|
||||||
|
if (flush)
|
||||||
|
/* send flush stop, peer will accept data and events again. We
|
||||||
|
* are not yet providing data as we still have the STREAM_LOCK. */
|
||||||
gst_pad_push_event (src->srcpad, gst_event_new_flush_stop ());
|
gst_pad_push_event (src->srcpad, gst_event_new_flush_stop ());
|
||||||
|
|
||||||
|
/* now make sure the newsegment will be send from the streaming
|
||||||
|
* thread. We could opt to send it here too. */
|
||||||
|
src->need_newsegment = TRUE;
|
||||||
|
|
||||||
if (src->segment_loop) {
|
if (src->segment_loop) {
|
||||||
|
/* FIXME subclasses should be able to provide other formats */
|
||||||
gst_element_post_message (GST_ELEMENT (src),
|
gst_element_post_message (GST_ELEMENT (src),
|
||||||
gst_message_new_segment_start (GST_OBJECT (src), GST_FORMAT_BYTES,
|
gst_message_new_segment_start (GST_OBJECT (src), GST_FORMAT_BYTES,
|
||||||
cur));
|
src->segment_start));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* and restart the task */
|
/* and restart the task in case it got paused explicitely or by
|
||||||
|
* the FLUSH_START event we pushed out. */
|
||||||
gst_pad_start_task (src->srcpad, (GstTaskFunction) gst_base_src_loop,
|
gst_pad_start_task (src->srcpad, (GstTaskFunction) gst_base_src_loop,
|
||||||
src->srcpad);
|
src->srcpad);
|
||||||
|
|
||||||
|
/* and release the lock again so we can continue streaming */
|
||||||
GST_STREAM_UNLOCK (src->srcpad);
|
GST_STREAM_UNLOCK (src->srcpad);
|
||||||
|
|
||||||
gst_event_unref (event);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
/* ERROR */
|
/* ERROR */
|
||||||
unsupported_seek:
|
unsupported_seek:
|
||||||
{
|
{
|
||||||
GST_DEBUG_OBJECT (src, "invalid format, seek aborted.");
|
GST_DEBUG_OBJECT (src, "invalid format, seek aborted.");
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* all events send to this element directly
|
||||||
|
*/
|
||||||
|
static gboolean
|
||||||
|
gst_base_src_send_event (GstElement * element, GstEvent * event)
|
||||||
|
{
|
||||||
|
GstBaseSrc *src;
|
||||||
|
gboolean result;
|
||||||
|
|
||||||
|
src = GST_BASE_SRC (element);
|
||||||
|
|
||||||
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
|
case GST_EVENT_SEEK:
|
||||||
|
result = gst_base_src_configure_segment (src, event);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_base_src_event_handler (GstPad * pad, GstEvent * event)
|
gst_base_src_event_handler (GstPad * pad, GstEvent * event)
|
||||||
{
|
{
|
||||||
|
@ -568,31 +690,52 @@ gst_base_src_event_handler (GstPad * pad, GstEvent * event)
|
||||||
GstBaseSrcClass *bclass;
|
GstBaseSrcClass *bclass;
|
||||||
gboolean result;
|
gboolean result;
|
||||||
|
|
||||||
src = GST_BASE_SRC (GST_PAD_PARENT (pad));
|
src = GST_BASE_SRC (gst_pad_get_parent (pad));
|
||||||
bclass = GST_BASE_SRC_GET_CLASS (src);
|
bclass = GST_BASE_SRC_GET_CLASS (src);
|
||||||
|
|
||||||
if (bclass->event)
|
if (bclass->event) {
|
||||||
result = bclass->event (src, event);
|
if (!(result = bclass->event (src, event)))
|
||||||
|
goto subclass_failed;
|
||||||
|
}
|
||||||
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
case GST_EVENT_SEEK:
|
case GST_EVENT_SEEK:
|
||||||
if (!src->seekable) {
|
/* is normally called when in push mode */
|
||||||
gst_event_unref (event);
|
if (!src->seekable)
|
||||||
return FALSE;
|
goto not_seekable;
|
||||||
}
|
|
||||||
return gst_base_src_do_seek (src, event);
|
result = gst_base_src_do_seek (src, event);
|
||||||
|
break;
|
||||||
case GST_EVENT_FLUSH_START:
|
case GST_EVENT_FLUSH_START:
|
||||||
/* cancel any blocking getrange */
|
/* cancel any blocking getrange, is normally called
|
||||||
gst_base_src_unlock (src);
|
* when in pull mode. */
|
||||||
|
result = gst_base_src_unlock (src);
|
||||||
break;
|
break;
|
||||||
case GST_EVENT_FLUSH_STOP:
|
case GST_EVENT_FLUSH_STOP:
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
|
result = TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
gst_event_unref (event);
|
gst_event_unref (event);
|
||||||
|
gst_object_unref (src);
|
||||||
|
|
||||||
return TRUE;
|
return result;
|
||||||
|
|
||||||
|
/* ERRORS */
|
||||||
|
subclass_failed:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (src, "subclass refused event");
|
||||||
|
gst_object_unref (src);
|
||||||
|
gst_event_unref (event);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
not_seekable:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (src, "is not seekable");
|
||||||
|
gst_object_unref (src);
|
||||||
|
gst_event_unref (event);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -772,6 +915,7 @@ gst_base_src_loop (GstPad * pad)
|
||||||
|
|
||||||
src = GST_BASE_SRC (gst_pad_get_parent (pad));
|
src = GST_BASE_SRC (gst_pad_get_parent (pad));
|
||||||
|
|
||||||
|
/* only send segments when operating in push mode */
|
||||||
if (G_UNLIKELY (src->need_newsegment)) {
|
if (G_UNLIKELY (src->need_newsegment)) {
|
||||||
/* now send newsegment */
|
/* now send newsegment */
|
||||||
gst_base_src_newsegment (src);
|
gst_base_src_newsegment (src);
|
||||||
|
@ -800,9 +944,10 @@ gst_base_src_loop (GstPad * pad)
|
||||||
/* special cases */
|
/* special cases */
|
||||||
eos:
|
eos:
|
||||||
{
|
{
|
||||||
GST_DEBUG_OBJECT (src, "going to EOS");
|
GST_DEBUG_OBJECT (src, "going to EOS, getrange returned UNEXPECTED");
|
||||||
gst_pad_pause_task (pad);
|
gst_pad_pause_task (pad);
|
||||||
if (src->segment_loop) {
|
if (src->segment_loop) {
|
||||||
|
/* FIXME, subclass might want to use another format */
|
||||||
gst_element_post_message (GST_ELEMENT (src),
|
gst_element_post_message (GST_ELEMENT (src),
|
||||||
gst_message_new_segment_done (GST_OBJECT (src),
|
gst_message_new_segment_done (GST_OBJECT (src),
|
||||||
GST_FORMAT_BYTES, src->segment_end));
|
GST_FORMAT_BYTES, src->segment_end));
|
||||||
|
@ -815,9 +960,7 @@ eos:
|
||||||
}
|
}
|
||||||
pause:
|
pause:
|
||||||
{
|
{
|
||||||
const gchar *reason;
|
const gchar *reason = gst_flow_get_name (ret);
|
||||||
|
|
||||||
reason = gst_flow_get_name (ret);
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (src, "pausing task, reason %s", reason);
|
GST_DEBUG_OBJECT (src, "pausing task, reason %s", reason);
|
||||||
gst_pad_pause_task (pad);
|
gst_pad_pause_task (pad);
|
||||||
|
@ -850,7 +993,7 @@ static gboolean
|
||||||
gst_base_src_unlock (GstBaseSrc * basesrc)
|
gst_base_src_unlock (GstBaseSrc * basesrc)
|
||||||
{
|
{
|
||||||
GstBaseSrcClass *bclass;
|
GstBaseSrcClass *bclass;
|
||||||
gboolean result = FALSE;
|
gboolean result = TRUE;
|
||||||
|
|
||||||
GST_DEBUG ("unlock");
|
GST_DEBUG ("unlock");
|
||||||
/* unblock whatever the subclass is doing */
|
/* unblock whatever the subclass is doing */
|
||||||
|
@ -905,6 +1048,7 @@ gst_base_src_is_seekable (GstBaseSrc * basesrc)
|
||||||
return basesrc->seekable;
|
return basesrc->seekable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* default negotiation code */
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_base_src_default_negotiate (GstBaseSrc * basesrc)
|
gst_base_src_default_negotiate (GstBaseSrc * basesrc)
|
||||||
{
|
{
|
||||||
|
@ -913,38 +1057,48 @@ gst_base_src_default_negotiate (GstBaseSrc * basesrc)
|
||||||
GstCaps *peercaps = NULL;
|
GstCaps *peercaps = NULL;
|
||||||
gboolean result = FALSE;
|
gboolean result = FALSE;
|
||||||
|
|
||||||
|
/* first see what is possible on our source pad */
|
||||||
thiscaps = gst_pad_get_caps (GST_BASE_SRC_PAD (basesrc));
|
thiscaps = gst_pad_get_caps (GST_BASE_SRC_PAD (basesrc));
|
||||||
GST_DEBUG ("caps of src: %" GST_PTR_FORMAT, thiscaps);
|
GST_DEBUG ("caps of src: %" GST_PTR_FORMAT, thiscaps);
|
||||||
|
/* nothing or anything is allowed, we're done */
|
||||||
if (thiscaps == NULL || gst_caps_is_any (thiscaps))
|
if (thiscaps == NULL || gst_caps_is_any (thiscaps))
|
||||||
goto no_nego_needed;
|
goto no_nego_needed;
|
||||||
|
|
||||||
|
/* get the peer caps */
|
||||||
peercaps = gst_pad_peer_get_caps (GST_BASE_SRC_PAD (basesrc));
|
peercaps = gst_pad_peer_get_caps (GST_BASE_SRC_PAD (basesrc));
|
||||||
GST_DEBUG ("caps of peer: %" GST_PTR_FORMAT, peercaps);
|
GST_DEBUG ("caps of peer: %" GST_PTR_FORMAT, peercaps);
|
||||||
if (peercaps) {
|
if (peercaps) {
|
||||||
GstCaps *icaps;
|
GstCaps *icaps;
|
||||||
|
|
||||||
|
/* get intersection */
|
||||||
icaps = gst_caps_intersect (thiscaps, peercaps);
|
icaps = gst_caps_intersect (thiscaps, peercaps);
|
||||||
GST_DEBUG ("intersect: %" GST_PTR_FORMAT, icaps);
|
GST_DEBUG ("intersect: %" GST_PTR_FORMAT, icaps);
|
||||||
gst_caps_unref (thiscaps);
|
gst_caps_unref (thiscaps);
|
||||||
gst_caps_unref (peercaps);
|
gst_caps_unref (peercaps);
|
||||||
if (icaps) {
|
if (icaps) {
|
||||||
|
/* take first (and best) possibility */
|
||||||
caps = gst_caps_copy_nth (icaps, 0);
|
caps = gst_caps_copy_nth (icaps, 0);
|
||||||
gst_caps_unref (icaps);
|
gst_caps_unref (icaps);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
/* no peer, work with our own caps then */
|
||||||
caps = thiscaps;
|
caps = thiscaps;
|
||||||
}
|
}
|
||||||
if (caps) {
|
if (caps) {
|
||||||
caps = gst_caps_make_writable (caps);
|
caps = gst_caps_make_writable (caps);
|
||||||
gst_caps_truncate (caps);
|
gst_caps_truncate (caps);
|
||||||
|
|
||||||
|
/* now fixate */
|
||||||
gst_pad_fixate_caps (GST_BASE_SRC_PAD (basesrc), caps);
|
gst_pad_fixate_caps (GST_BASE_SRC_PAD (basesrc), caps);
|
||||||
GST_DEBUG ("fixated to: %" GST_PTR_FORMAT, caps);
|
GST_DEBUG ("fixated to: %" GST_PTR_FORMAT, caps);
|
||||||
|
|
||||||
if (gst_caps_is_any (caps)) {
|
if (gst_caps_is_any (caps)) {
|
||||||
|
/* hmm, still anything, so element can do anything and
|
||||||
|
* nego is not needed */
|
||||||
gst_caps_unref (caps);
|
gst_caps_unref (caps);
|
||||||
result = TRUE;
|
result = TRUE;
|
||||||
} else if (gst_caps_is_fixed (caps)) {
|
} else if (gst_caps_is_fixed (caps)) {
|
||||||
|
/* yay, fixed caps, use those then */
|
||||||
gst_pad_set_caps (GST_BASE_SRC_PAD (basesrc), caps);
|
gst_pad_set_caps (GST_BASE_SRC_PAD (basesrc), caps);
|
||||||
gst_caps_unref (caps);
|
gst_caps_unref (caps);
|
||||||
result = TRUE;
|
result = TRUE;
|
||||||
|
@ -999,9 +1153,6 @@ gst_base_src_start (GstBaseSrc * basesrc)
|
||||||
|
|
||||||
GST_OBJECT_FLAG_SET (basesrc, GST_BASE_SRC_STARTED);
|
GST_OBJECT_FLAG_SET (basesrc, GST_BASE_SRC_STARTED);
|
||||||
|
|
||||||
/* start in the beginning */
|
|
||||||
basesrc->offset = 0;
|
|
||||||
|
|
||||||
/* figure out the size */
|
/* figure out the size */
|
||||||
if (bclass->get_size) {
|
if (bclass->get_size) {
|
||||||
result = bclass->get_size (basesrc, &basesrc->size);
|
result = bclass->get_size (basesrc, &basesrc->size);
|
||||||
|
@ -1014,15 +1165,11 @@ gst_base_src_start (GstBaseSrc * basesrc)
|
||||||
|
|
||||||
GST_DEBUG ("size %d %lld", result, basesrc->size);
|
GST_DEBUG ("size %d %lld", result, basesrc->size);
|
||||||
|
|
||||||
/* we always run to the end when starting */
|
|
||||||
basesrc->segment_loop = FALSE;
|
|
||||||
basesrc->segment_start = 0;
|
|
||||||
basesrc->segment_end = basesrc->size;
|
|
||||||
basesrc->need_newsegment = TRUE;
|
|
||||||
|
|
||||||
/* check if we can seek, updates ->seekable */
|
/* check if we can seek, updates ->seekable */
|
||||||
gst_base_src_is_seekable (basesrc);
|
gst_base_src_is_seekable (basesrc);
|
||||||
|
|
||||||
|
basesrc->need_newsegment = TRUE;
|
||||||
|
|
||||||
/* run typefind */
|
/* run typefind */
|
||||||
#if 0
|
#if 0
|
||||||
if (basesrc->seekable) {
|
if (basesrc->seekable) {
|
||||||
|
@ -1088,10 +1235,10 @@ gst_base_src_deactivate (GstBaseSrc * basesrc, GstPad * pad)
|
||||||
GST_LIVE_UNLOCK (basesrc);
|
GST_LIVE_UNLOCK (basesrc);
|
||||||
|
|
||||||
/* step 1, unblock clock sync (if any) */
|
/* step 1, unblock clock sync (if any) */
|
||||||
gst_base_src_unlock (basesrc);
|
result = gst_base_src_unlock (basesrc);
|
||||||
|
|
||||||
/* step 2, make sure streaming finishes */
|
/* step 2, make sure streaming finishes */
|
||||||
result = gst_pad_stop_task (pad);
|
result &= gst_pad_stop_task (pad);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -1100,6 +1247,7 @@ static gboolean
|
||||||
gst_base_src_activate_push (GstPad * pad, gboolean active)
|
gst_base_src_activate_push (GstPad * pad, gboolean active)
|
||||||
{
|
{
|
||||||
GstBaseSrc *basesrc;
|
GstBaseSrc *basesrc;
|
||||||
|
gboolean res;
|
||||||
|
|
||||||
basesrc = GST_BASE_SRC (GST_OBJECT_PARENT (pad));
|
basesrc = GST_BASE_SRC (GST_OBJECT_PARENT (pad));
|
||||||
|
|
||||||
|
@ -1113,12 +1261,14 @@ gst_base_src_activate_push (GstPad * pad, gboolean active)
|
||||||
if (!gst_base_src_start (basesrc))
|
if (!gst_base_src_start (basesrc))
|
||||||
goto error_start;
|
goto error_start;
|
||||||
|
|
||||||
return gst_pad_start_task (pad, (GstTaskFunction) gst_base_src_loop, pad);
|
res = gst_pad_start_task (pad, (GstTaskFunction) gst_base_src_loop, pad);
|
||||||
} else {
|
} else {
|
||||||
GST_DEBUG_OBJECT (basesrc, "Deactivating in push mode");
|
GST_DEBUG_OBJECT (basesrc, "Deactivating in push mode");
|
||||||
return gst_base_src_deactivate (basesrc, pad);
|
res = gst_base_src_deactivate (basesrc, pad);
|
||||||
}
|
}
|
||||||
|
return res;
|
||||||
|
|
||||||
|
/* ERRORS */
|
||||||
no_push_activation:
|
no_push_activation:
|
||||||
{
|
{
|
||||||
GST_DEBUG_OBJECT (basesrc, "Subclass disabled push-mode activation");
|
GST_DEBUG_OBJECT (basesrc, "Subclass disabled push-mode activation");
|
||||||
|
@ -1182,7 +1332,6 @@ gst_base_src_change_state (GstElement * element, GstStateChange transition)
|
||||||
|
|
||||||
basesrc = GST_BASE_SRC (element);
|
basesrc = GST_BASE_SRC (element);
|
||||||
|
|
||||||
|
|
||||||
switch (transition) {
|
switch (transition) {
|
||||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
case GST_STATE_CHANGE_NULL_TO_READY:
|
||||||
break;
|
break;
|
||||||
|
@ -1212,6 +1361,15 @@ gst_base_src_change_state (GstElement * element, GstStateChange transition)
|
||||||
goto failure;
|
goto failure;
|
||||||
|
|
||||||
switch (transition) {
|
switch (transition) {
|
||||||
|
case GST_STATE_CHANGE_NULL_TO_READY:
|
||||||
|
/* we always run from start to end when in READY, after putting
|
||||||
|
* the element to READY a seek can be done on the element to
|
||||||
|
* configure the segment when going to PAUSED. */
|
||||||
|
basesrc->segment_loop = FALSE;
|
||||||
|
basesrc->segment_start = 0;
|
||||||
|
basesrc->segment_end = -1;
|
||||||
|
basesrc->offset = 0;
|
||||||
|
break;
|
||||||
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
|
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
|
||||||
GST_LIVE_LOCK (element);
|
GST_LIVE_LOCK (element);
|
||||||
if (basesrc->is_live) {
|
if (basesrc->is_live) {
|
||||||
|
@ -1222,7 +1380,12 @@ gst_base_src_change_state (GstElement * element, GstStateChange transition)
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||||
if (!gst_base_src_stop (basesrc))
|
if (!gst_base_src_stop (basesrc))
|
||||||
result = GST_STATE_CHANGE_FAILURE;
|
goto error_stop;
|
||||||
|
/* we always run from start to end when in READY */
|
||||||
|
basesrc->segment_loop = FALSE;
|
||||||
|
basesrc->segment_start = 0;
|
||||||
|
basesrc->segment_end = -1;
|
||||||
|
basesrc->offset = 0;
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||||
break;
|
break;
|
||||||
|
@ -1231,14 +1394,20 @@ gst_base_src_change_state (GstElement * element, GstStateChange transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (no_preroll && result == GST_STATE_CHANGE_SUCCESS)
|
if (no_preroll && result == GST_STATE_CHANGE_SUCCESS)
|
||||||
return GST_STATE_CHANGE_NO_PREROLL;
|
result = GST_STATE_CHANGE_NO_PREROLL;
|
||||||
else
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
failure:
|
failure:
|
||||||
{
|
{
|
||||||
|
GST_DEBUG_OBJECT (basesrc, "parent failed state change");
|
||||||
gst_base_src_stop (basesrc);
|
gst_base_src_stop (basesrc);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
error_stop:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (basesrc, "Failed to stop");
|
||||||
|
return GST_STATE_CHANGE_FAILURE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue