From a35882df1f992051c5ef0b7806597765447b3cf1 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 21 Nov 2005 17:09:45 +0000 Subject: [PATCH] More segment updates, replace code in plugins with segment helper functions. Original commit message from CVS: * check/gst/gstsegment.c: (GST_START_TEST): * docs/design/part-TODO.txt: * gst/base/gstbasesink.c: (gst_base_sink_handle_object), (gst_base_sink_event), (gst_base_sink_do_sync), (gst_base_sink_activate_pull), (gst_base_sink_get_position), (gst_base_sink_query), (gst_base_sink_change_state): * gst/base/gstbasesink.h: * gst/base/gstbasesrc.c: (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_get_range), (gst_base_src_loop), (gst_base_src_change_state): * gst/base/gstbasesrc.h: * gst/base/gstbasetransform.c: (gst_base_transform_prepare_output_buf), (gst_base_transform_event), (gst_base_transform_change_state): * gst/base/gstbasetransform.h: * gst/base/gstcollectpads.c: (gst_collect_pads_add_pad), (gst_collect_pads_event): * gst/base/gstcollectpads.h: * gst/elements/gstfakesrc.c: (gst_fake_src_init), (gst_fake_src_create): * gst/elements/gstfakesrc.h: * gst/elements/gstidentity.c: (gst_identity_transform_ip): * gst/gstsegment.c: (gst_segment_init), (gst_segment_set_duration), (gst_segment_set_last_stop), (gst_segment_set_seek), (gst_segment_set_newsegment), (gst_segment_to_stream_time), (gst_segment_to_running_time), (gst_segment_clip): * gst/gstsegment.h: More segment updates, replace code in plugins with segment helper functions. --- ChangeLog | 34 +++++++ check/gst/gstsegment.c | 32 +++++-- docs/design/part-TODO.txt | 6 -- gst/base/gstbasesink.c | 202 +++++++++------------------------------ gst/base/gstbasesink.h | 10 +- gst/base/gstbasesrc.c | 129 ++++++------------------- gst/base/gstbasesrc.h | 4 +- gst/base/gstbasetransform.c | 71 +++----------- gst/base/gstbasetransform.h | 38 +++----- gst/base/gstcollectpads.c | 17 ++-- gst/base/gstcollectpads.h | 4 +- gst/elements/gstfakesrc.c | 8 -- gst/elements/gstfakesrc.h | 4 +- gst/elements/gstidentity.c | 4 +- gst/gstsegment.c | 64 ++++++++++--- gst/gstsegment.h | 3 +- libs/gst/base/gstbasesink.c | 202 +++++++++------------------------------ libs/gst/base/gstbasesink.h | 10 +- libs/gst/base/gstbasesrc.c | 129 ++++++------------------- libs/gst/base/gstbasesrc.h | 4 +- libs/gst/base/gstbasetransform.c | 71 +++----------- libs/gst/base/gstbasetransform.h | 38 +++----- libs/gst/base/gstcollectpads.c | 17 ++-- libs/gst/base/gstcollectpads.h | 4 +- plugins/elements/gstfakesrc.c | 8 -- plugins/elements/gstfakesrc.h | 4 +- plugins/elements/gstidentity.c | 4 +- tests/check/gst/gstsegment.c | 32 +++++-- 28 files changed, 363 insertions(+), 790 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2f6031c..b21421d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,37 @@ +2005-11-21 Wim Taymans + + * check/gst/gstsegment.c: (GST_START_TEST): + * docs/design/part-TODO.txt: + * gst/base/gstbasesink.c: (gst_base_sink_handle_object), + (gst_base_sink_event), (gst_base_sink_do_sync), + (gst_base_sink_activate_pull), (gst_base_sink_get_position), + (gst_base_sink_query), (gst_base_sink_change_state): + * gst/base/gstbasesink.h: + * gst/base/gstbasesrc.c: (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_get_range), (gst_base_src_loop), + (gst_base_src_change_state): + * gst/base/gstbasesrc.h: + * gst/base/gstbasetransform.c: + (gst_base_transform_prepare_output_buf), + (gst_base_transform_event), (gst_base_transform_change_state): + * gst/base/gstbasetransform.h: + * gst/base/gstcollectpads.c: (gst_collect_pads_add_pad), + (gst_collect_pads_event): + * gst/base/gstcollectpads.h: + * gst/elements/gstfakesrc.c: (gst_fake_src_init), + (gst_fake_src_create): + * gst/elements/gstfakesrc.h: + * gst/elements/gstidentity.c: (gst_identity_transform_ip): + * gst/gstsegment.c: (gst_segment_init), (gst_segment_set_duration), + (gst_segment_set_last_stop), (gst_segment_set_seek), + (gst_segment_set_newsegment), (gst_segment_to_stream_time), + (gst_segment_to_running_time), (gst_segment_clip): + * gst/gstsegment.h: + More segment updates, replace code in plugins with segment + helper functions. + 2005-11-21 Jan Schmidt * gst/elements/gstfdsrc.c: (gst_fdsrc_uri_set_uri): diff --git a/check/gst/gstsegment.c b/check/gst/gstsegment.c index b4e2f5b..e32715e 100644 --- a/check/gst/gstsegment.c +++ b/check/gst/gstsegment.c @@ -27,13 +27,15 @@ GST_START_TEST (segment_seek_nosize) GstSegment segment; gboolean res; gint64 cstart, cstop; + gboolean update; gst_segment_init (&segment, GST_FORMAT_BYTES); /* configure segment to start 100 */ gst_segment_set_seek (&segment, 1.0, GST_FORMAT_BYTES, - GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_SET, 100, GST_SEEK_TYPE_NONE, -1); + GST_SEEK_FLAG_NONE, + GST_SEEK_TYPE_SET, 100, GST_SEEK_TYPE_NONE, -1, &update); fail_unless (segment.start == 100); fail_unless (segment.stop == -1); @@ -41,7 +43,8 @@ GST_START_TEST (segment_seek_nosize) * size is unknown. */ gst_segment_set_seek (&segment, 1.0, GST_FORMAT_BYTES, - GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_NONE, 200, GST_SEEK_TYPE_CUR, -100); + GST_SEEK_FLAG_NONE, + GST_SEEK_TYPE_NONE, 200, GST_SEEK_TYPE_CUR, -100, &update); fail_unless (segment.start == 100); fail_unless (segment.stop == -1); @@ -99,7 +102,8 @@ GST_START_TEST (segment_seek_nosize) /* add 100 to start, set stop to 300 */ gst_segment_set_seek (&segment, 1.0, GST_FORMAT_BYTES, - GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_CUR, 100, GST_SEEK_TYPE_SET, 300); + GST_SEEK_FLAG_NONE, + GST_SEEK_TYPE_CUR, 100, GST_SEEK_TYPE_SET, 300, &update); fail_unless (segment.start == 200); fail_unless (segment.stop == 300); @@ -107,7 +111,8 @@ GST_START_TEST (segment_seek_nosize) * nothing should be updated in the segment. */ ASSERT_CRITICAL (gst_segment_set_seek (&segment, 1.0, GST_FORMAT_BYTES, - GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_CUR, 100, GST_SEEK_TYPE_SET, 200)); + GST_SEEK_FLAG_NONE, + GST_SEEK_TYPE_CUR, 100, GST_SEEK_TYPE_SET, 200, &update)); fail_unless (segment.start == 200); fail_unless (segment.stop == 300); @@ -115,7 +120,8 @@ GST_START_TEST (segment_seek_nosize) * unknown. */ gst_segment_set_seek (&segment, 1.0, GST_FORMAT_BYTES, - GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_END, -300, GST_SEEK_TYPE_END, -100); + GST_SEEK_FLAG_NONE, + GST_SEEK_TYPE_END, -300, GST_SEEK_TYPE_END, -100, &update); fail_unless (segment.start == 200); fail_unless (segment.stop == 300); @@ -193,6 +199,7 @@ GST_START_TEST (segment_seek_size) GstSegment segment; gboolean res; gint64 cstart, cstop; + gboolean update; gst_segment_init (&segment, GST_FORMAT_BYTES); gst_segment_set_duration (&segment, GST_FORMAT_BYTES, 200); @@ -200,7 +207,8 @@ GST_START_TEST (segment_seek_size) /* configure segment to start 100 */ gst_segment_set_seek (&segment, 1.0, GST_FORMAT_BYTES, - GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_SET, 100, GST_SEEK_TYPE_NONE, -1); + GST_SEEK_FLAG_NONE, + GST_SEEK_TYPE_SET, 100, GST_SEEK_TYPE_NONE, -1, &update); fail_unless (segment.start == 100); fail_unless (segment.stop == -1); @@ -208,7 +216,8 @@ GST_START_TEST (segment_seek_size) * since we did not set it before. */ gst_segment_set_seek (&segment, 1.0, GST_FORMAT_BYTES, - GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_NONE, 200, GST_SEEK_TYPE_CUR, -100); + GST_SEEK_FLAG_NONE, + GST_SEEK_TYPE_NONE, 200, GST_SEEK_TYPE_CUR, -100, &update); fail_unless (segment.start == 100); fail_unless (segment.stop == -1); @@ -273,7 +282,8 @@ GST_START_TEST (segment_seek_size) /* add 100 to start, set stop to 300, stop clips to 200 */ gst_segment_set_seek (&segment, 1.0, GST_FORMAT_BYTES, - GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_CUR, 100, GST_SEEK_TYPE_SET, 300); + GST_SEEK_FLAG_NONE, + GST_SEEK_TYPE_CUR, 100, GST_SEEK_TYPE_SET, 300, &update); fail_unless (segment.start == 200); fail_unless (segment.stop == 200); @@ -281,14 +291,16 @@ GST_START_TEST (segment_seek_size) * to duration */ gst_segment_set_seek (&segment, 1.0, GST_FORMAT_BYTES, - GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_CUR, 100, GST_SEEK_TYPE_SET, 200); + GST_SEEK_FLAG_NONE, + GST_SEEK_TYPE_CUR, 100, GST_SEEK_TYPE_SET, 200, &update); fail_unless (segment.start == 200); fail_unless (segment.stop == 200); /* seek relative to end */ gst_segment_set_seek (&segment, 1.0, GST_FORMAT_BYTES, - GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_END, -100, GST_SEEK_TYPE_END, -20); + GST_SEEK_FLAG_NONE, + GST_SEEK_TYPE_END, -100, GST_SEEK_TYPE_END, -20, &update); fail_unless (segment.start == 100); fail_unless (segment.stop == 180); diff --git a/docs/design/part-TODO.txt b/docs/design/part-TODO.txt index 548f874..a8da5db 100644 --- a/docs/design/part-TODO.txt +++ b/docs/design/part-TODO.txt @@ -15,8 +15,6 @@ API/ABI - unblocking while seeking. gst_element_flush_pads (GstElement, gboolean); -- make GstCapsFlags instead of the #define for GST_CAPS_FLAGS_ANY. - - query POSITION/DURATION return accuracy. Just a flag or accuracy percentage. - add some sort of time/frame stepping functionality, either with a flag on the seek @@ -26,10 +24,6 @@ API/ABI N frames/time, sending more complicated queries upstream which can ideally handle those cases more efficiently too. -- GstClockFlags should use the gstobject flags field instead of inventing its own. - -- Add gstsegment.[ch]. - IMPLEMENTATION -------------- diff --git a/gst/base/gstbasesink.c b/gst/base/gstbasesink.c index f0c948a..cd5477e 100644 --- a/gst/base/gstbasesink.c +++ b/gst/base/gstbasesink.c @@ -579,81 +579,28 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad, gboolean update; gdouble rate; GstFormat format; - gint64 segment_start; - gint64 segment_stop; - gint64 segment_time; - GstClockTime duration; + gint64 start; + gint64 stop; + gint64 time; /* the newsegment event is needed to bring the buffer timestamps to the * stream time and to drop samples outside of the playback segment. */ gst_event_parse_newsegment (event, &update, &rate, &format, - &segment_start, &segment_stop, &segment_time); + &start, &stop, &time); basesink->have_newsegment = TRUE; - /* any other format with 0 also gives time 0, the other values are - * invalid as time though. */ - if (format != GST_FORMAT_TIME && segment_start == 0) { - GST_DEBUG_OBJECT (basesink, - "non-time newsegment with start 0, coaxing into FORMAT_TIME"); - format = GST_FORMAT_TIME; - if (segment_stop != 0) - segment_stop = -1; - if (segment_time != 0) - segment_time = -1; - } - - if (format != GST_FORMAT_TIME) { - GST_DEBUG_OBJECT (basesink, - "received non time %d NEW_SEGMENT %" G_GINT64_FORMAT - " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT, - format, segment_start, segment_stop, segment_time); - - /* this means this sink will not be able to clip or drop samples - * and timestamps have to start from 0. */ - basesink->segment_start = -1; - basesink->segment_stop = -1; - basesink->segment_time = -1; - goto done_newsegment; - } - /* check if we really have a new segment or the previous one is - * closed */ - if (!update) { - /* the new segment has to be aligned with the old segment. - * We first update the accumulated time of the previous - * segment. the accumulated time is used when syncing to the - * clock. A flush event sets the accumulated time back to 0 - */ - if (GST_CLOCK_TIME_IS_VALID (basesink->segment_stop)) { - duration = basesink->segment_stop - basesink->segment_start; - } else if (GST_CLOCK_TIME_IS_VALID (basesink->current_end)) { - /* else use last seen timestamp as segment stop */ - duration = basesink->current_end - basesink->segment_start; - } else { - duration = 0; - } - } else { - duration = segment_start - basesink->segment_start; - } - - /* use previous rate to calculate duration */ - basesink->segment_accum += gst_gdouble_to_guint64 ( - (gst_guint64_to_gdouble (duration) / ABS (basesink->segment_rate))); - /* then update the current segment */ - basesink->segment_rate = rate; - basesink->segment_start = segment_start; - basesink->segment_stop = segment_stop; - basesink->segment_time = segment_time; + gst_segment_set_newsegment (&basesink->segment, update, rate, format, + start, stop, time); GST_DEBUG_OBJECT (basesink, "received NEWSEGMENT %" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT ", accum %" GST_TIME_FORMAT, - GST_TIME_ARGS (basesink->segment_start), - GST_TIME_ARGS (basesink->segment_stop), - GST_TIME_ARGS (basesink->segment_time), - GST_TIME_ARGS (basesink->segment_accum)); - done_newsegment: + GST_TIME_ARGS (basesink->segment.start), + GST_TIME_ARGS (basesink->segment.stop), + GST_TIME_ARGS (basesink->segment.time), + GST_TIME_ARGS (basesink->segment.accum)); break; } default: @@ -669,8 +616,8 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad, ("Received buffer without a new-segment. Cannot sync to clock.")); basesink->have_newsegment = TRUE; /* this means this sink will not be able to sync to the clock */ - basesink->segment_start = -1; - basesink->segment_stop = -1; + basesink->segment.start = -1; + basesink->segment.stop = -1; } /* check if the buffer needs to be dropped */ @@ -685,28 +632,10 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad, ", end: %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (end)); - /* need to drop if the timestamp is not between segment_start and - * segment_stop. we check if the complete sample is outside of the - * range since the sink might be able to clip the sample. */ - if (GST_CLOCK_TIME_IS_VALID (end) && - GST_CLOCK_TIME_IS_VALID (basesink->segment_start)) { - if (end <= basesink->segment_start) { - GST_DEBUG_OBJECT (basesink, - "buffer end %" GST_TIME_FORMAT " <= segment start %" - GST_TIME_FORMAT ", dropping buffer", GST_TIME_ARGS (end), - GST_TIME_ARGS (basesink->segment_start)); + if (GST_CLOCK_TIME_IS_VALID (start)) { + if (!gst_segment_clip (&basesink->segment, GST_FORMAT_TIME, + (gint64) start, (gint64) end, NULL, NULL)) goto dropping; - } - } - if (GST_CLOCK_TIME_IS_VALID (start) && - GST_CLOCK_TIME_IS_VALID (basesink->segment_stop)) { - if (basesink->segment_stop <= start) { - GST_DEBUG_OBJECT (basesink, - "buffer start %" GST_TIME_FORMAT " >= segment stop %" - GST_TIME_FORMAT ", dropping buffer", GST_TIME_ARGS (start), - GST_TIME_ARGS (basesink->segment_stop)); - goto dropping; - } } } basesink->preroll_queued++; @@ -917,13 +846,7 @@ gst_base_sink_event (GstPad * pad, GstEvent * event) basesink->flushing = FALSE; GST_OBJECT_UNLOCK (basesink); /* we need new segment info after the flush. */ - basesink->segment_start = -1; - basesink->segment_stop = -1; - basesink->current_start = -1; - basesink->current_end = -1; - GST_DEBUG_OBJECT (basesink, "reset accum %" GST_TIME_FORMAT, - GST_TIME_ARGS (basesink->segment_accum)); - basesink->segment_accum = 0; + gst_segment_init (&basesink->segment, GST_FORMAT_TIME); GST_STREAM_UNLOCK (pad); GST_DEBUG_OBJECT (basesink, "event unref %p %p", basesink, event); @@ -1004,9 +927,8 @@ gst_base_sink_do_sync (GstBaseSink * basesink, GstBuffer * buffer) { GstClockReturn result = GST_CLOCK_OK; GstClockTime start, end; - GstClockTimeDiff stream_start, stream_end; + gint64 cstart, cend; GstBaseSinkClass *bclass; - gboolean start_valid, end_valid; bclass = GST_BASE_SINK_GET_CLASS (basesink); @@ -1014,61 +936,27 @@ gst_base_sink_do_sync (GstBaseSink * basesink, GstBuffer * buffer) if (bclass->get_times) bclass->get_times (basesink, buffer, &start, &end); - start_valid = GST_CLOCK_TIME_IS_VALID (start); - end_valid = GST_CLOCK_TIME_IS_VALID (end); - GST_DEBUG_OBJECT (basesink, "got times start: %" GST_TIME_FORMAT ", end: %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (end)); /* if we don't have a timestamp, we don't sync */ - if (!start_valid) { + if (!GST_CLOCK_TIME_IS_VALID (start)) { GST_DEBUG_OBJECT (basesink, "start not valid"); goto done; } /* save last times seen. */ - basesink->current_start = start; - if (end_valid) - basesink->current_end = end; + if (GST_CLOCK_TIME_IS_VALID (end)) + gst_segment_set_last_stop (&basesink->segment, GST_FORMAT_TIME, + (gint64) end); else - basesink->current_end = start; + gst_segment_set_last_stop (&basesink->segment, GST_FORMAT_TIME, + (gint64) start); - if (GST_CLOCK_TIME_IS_VALID (basesink->segment_stop)) { - /* check if not outside of the segment range, start is - * always valid here. */ - if (start > basesink->segment_stop) - goto out_of_segment; - } - - /* bring timestamp to stream time using last segment offset. */ - if (GST_CLOCK_TIME_IS_VALID (basesink->segment_start)) { - /* check if not outside of the segment range */ - if (end_valid && end < basesink->segment_start) - goto out_of_segment; - - stream_start = (gint64) start - basesink->segment_start; - stream_end = (gint64) end - basesink->segment_start; - - if (stream_start < 0) { - GST_DEBUG_OBJECT (basesink, "stream_start negative, invalid"); - goto done; - } - } else { - stream_start = (gint64) start; - stream_end = (gint64) end; - } - - - /* correct for rate */ - if (basesink->segment_rate != 0.0) { - stream_start /= ABS (basesink->segment_rate); - if (end_valid) - stream_end /= ABS (basesink->segment_rate); - } - - stream_start += basesink->segment_accum; - if (end_valid) - stream_end += basesink->segment_accum; + /* clip */ + if (!gst_segment_clip (&basesink->segment, GST_FORMAT_TIME, + (gint64) start, (gint64) end, &cstart, &cend)) + goto out_of_segment; if (!basesink->sync) { GST_DEBUG_OBJECT (basesink, "no need to sync"); @@ -1078,6 +966,13 @@ gst_base_sink_do_sync (GstBaseSink * basesink, GstBuffer * buffer) /* now do clocking */ if (basesink->clock) { GstClockTime base_time; + GstClockTimeDiff stream_start, stream_end; + + stream_start = + gst_segment_to_running_time (&basesink->segment, GST_FORMAT_TIME, + cstart); + stream_end = + gst_segment_to_running_time (&basesink->segment, GST_FORMAT_TIME, cend); GST_OBJECT_LOCK (basesink); @@ -1090,7 +985,7 @@ gst_base_sink_do_sync (GstBaseSink * basesink, GstBuffer * buffer) /* also save end_time of this buffer so that we can wait * to signal EOS */ - if (end_valid) + if (GST_CLOCK_TIME_IS_VALID (stream_end)) basesink->end_time = stream_end + base_time; else basesink->end_time = GST_CLOCK_TIME_NONE; @@ -1386,7 +1281,7 @@ gst_base_sink_activate_pull (GstPad * pad, gboolean active) } else { if (gst_pad_activate_pull (peer, TRUE)) { basesink->have_newsegment = TRUE; - basesink->segment_start = basesink->segment_stop = 0; + gst_segment_init (&basesink->segment, GST_FORMAT_TIME); /* set the pad mode before starting the task so that it's in the correct state for the new thread... */ @@ -1467,7 +1362,7 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format, GST_OBJECT_LOCK (basesink); if ((clock = GST_ELEMENT_CLOCK (basesink))) { GstClockTime now; - gint64 segment_time; + gint64 time; gst_object_ref (clock); GST_OBJECT_UNLOCK (basesink); @@ -1475,18 +1370,18 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format, now = gst_clock_get_time (clock); GST_OBJECT_LOCK (basesink); - if (GST_CLOCK_TIME_IS_VALID (basesink->segment_time)) - segment_time = basesink->segment_time; + if (GST_CLOCK_TIME_IS_VALID (basesink->segment.time)) + time = basesink->segment.time; else - segment_time = 0; + time = 0; *cur = now - GST_ELEMENT_CAST (basesink)->base_time - - basesink->segment_accum + segment_time; + basesink->segment.accum + time; GST_DEBUG_OBJECT (basesink, "now %" GST_TIME_FORMAT " + segment_time %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT, GST_TIME_ARGS (now), - GST_TIME_ARGS (segment_time), GST_TIME_ARGS (*cur)); + GST_TIME_ARGS (time), GST_TIME_ARGS (*cur)); gst_object_unref (clock); @@ -1547,8 +1442,8 @@ gst_base_sink_query (GstElement * element, GstQuery * query) case GST_QUERY_SEGMENT: { /* FIXME, bring start/stop to stream time */ - gst_query_set_segment (query, basesink->segment_rate, - GST_FORMAT_TIME, basesink->segment_start, basesink->segment_stop); + gst_query_set_segment (query, basesink->segment.rate, + GST_FORMAT_TIME, basesink->segment.start, basesink->segment.stop); break; } case GST_QUERY_SEEKING: @@ -1585,15 +1480,8 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition) GST_DEBUG_OBJECT (basesink, "READY to PAUSED, need preroll to FALSE"); basesink->need_preroll = TRUE; GST_PREROLL_UNLOCK (basesink->sinkpad); + gst_segment_init (&basesink->segment, GST_FORMAT_TIME); basesink->have_newsegment = FALSE; - basesink->segment_rate = 1.0; - basesink->segment_start = 0; - basesink->segment_stop = -1; - basesink->segment_time = 0; - basesink->current_start = -1; - basesink->current_duration = -1; - basesink->current_end = -1; - basesink->segment_accum = 0; ret = GST_STATE_CHANGE_ASYNC; break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: diff --git a/gst/base/gstbasesink.h b/gst/base/gstbasesink.h index f3fb83a..bb87cb5 100644 --- a/gst/base/gstbasesink.h +++ b/gst/base/gstbasesink.h @@ -80,15 +80,7 @@ struct _GstBaseSink { /*< protected >*/ /* with STREAM_LOCK */ gboolean have_newsegment; - gdouble segment_rate; - gint64 segment_start; - gint64 segment_stop; - gint64 segment_time; - gint64 segment_accum; - - gint64 current_start; - gint64 current_duration; - gint64 current_end; + GstSegment segment; /*< private >*/ /* with LOCK */ GstClock *clock; diff --git a/gst/base/gstbasesrc.c b/gst/base/gstbasesrc.c index 9080623..d57e6c3 100644 --- a/gst/base/gstbasesrc.c +++ b/gst/base/gstbasesrc.c @@ -229,8 +229,7 @@ gst_base_src_init (GstBaseSrc * basesrc, gpointer g_class) basesrc->blocksize = DEFAULT_BLOCKSIZE; basesrc->clock_id = NULL; - basesrc->segment_start = 0; - basesrc->segment_end = -1; + gst_segment_init (&basesrc->segment, GST_FORMAT_BYTES); GST_OBJECT_FLAG_UNSET (basesrc, GST_BASE_SRC_STARTED); @@ -411,9 +410,9 @@ gst_base_src_query (GstPad * pad, GstQuery * query) { gint64 start, stop; - start = src->segment_start; + start = src->segment.start; /* no end segment configured, current size then */ - if ((stop = src->segment_end) == -1) + if ((stop = src->segment.stop) == -1) stop = src->size; /* FIXME, we can't report our rate as we did not store it, d'oh!. @@ -448,11 +447,11 @@ gst_base_src_default_newsegment (GstBaseSrc * src) GstEvent *event; GST_DEBUG_OBJECT (src, "Sending newsegment from %" G_GINT64_FORMAT - " to %" G_GINT64_FORMAT, src->segment_start, src->segment_end); + " to %" G_GINT64_FORMAT, src->segment.start, src->segment.stop); event = gst_event_new_newsegment (FALSE, 1.0, - GST_FORMAT_BYTES, src->segment_start, src->segment_end, - src->segment_start); + GST_FORMAT_BYTES, src->segment.start, src->segment.stop, + src->segment.start); return gst_pad_push_event (src->srcpad, event); } @@ -471,7 +470,7 @@ gst_base_src_newsegment (GstBaseSrc * src) return result; } -/* based on the event parameters configure the segment_start/stop +/* based on the event parameters configure the segment.start/stop * times. Called with STREAM_LOCK. */ static gboolean @@ -482,84 +481,20 @@ gst_base_src_configure_segment (GstBaseSrc * src, GstEvent * event) GstSeekFlags flags; GstSeekType cur_type, stop_type; gint64 cur, stop; - gboolean update_stop, update_start; + gboolean update; gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur, &stop_type, &stop); - /* parse the loop flag */ - /* FIXME, need to store other flags and rate too */ - src->segment_loop = (flags & GST_SEEK_FLAG_SEGMENT) != 0; - - /* assume we'll update both start and stop values */ - update_start = TRUE; - update_stop = TRUE; - - /* perform the seek, segment_start is never invalid */ - switch (cur_type) { - case GST_SEEK_TYPE_NONE: - /* no update to segment */ - cur = src->segment_start; - update_start = FALSE; - break; - case GST_SEEK_TYPE_SET: - /* cur holds desired position */ - break; - case GST_SEEK_TYPE_CUR: - /* add cur to currently configure segment */ - cur = src->segment_start + cur; - break; - case GST_SEEK_TYPE_END: - /* add cur to total length */ - cur = src->size + cur; - break; - } - /* bring in sane range */ - 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) { - case GST_SEEK_TYPE_NONE: - stop = src->segment_end; - update_stop = FALSE; - break; - case GST_SEEK_TYPE_SET: - /* stop folds required value */ - break; - case GST_SEEK_TYPE_CUR: - if (src->segment_end != -1) - stop = src->segment_end + stop; - else - stop = -1; - break; - case GST_SEEK_TYPE_END: - if (src->size != -1) - stop = src->size + stop; - else - stop = -1; - break; - } - - /* 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_end = stop; + gst_segment_set_seek (&src->segment, rate, format, flags, + cur_type, cur, stop_type, stop, &update); /* update our offset if it was updated */ - if (update_start) + if (update) src->offset = cur; 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.stop); return TRUE; } @@ -567,9 +502,9 @@ gst_base_src_configure_segment (GstBaseSrc * src, GstEvent * event) /* 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 + * 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 @@ -592,13 +527,13 @@ gst_base_src_configure_segment (GstBaseSrc * src, GstEvent * event) * 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 + * 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 + * when we reach the segment.stop we have to post a segment.done * instead of EOS when doing a segment seek. */ static gboolean @@ -648,11 +583,11 @@ gst_base_src_do_seek (GstBaseSrc * src, GstEvent * event) * thread. We could opt to send it here too. */ src->need_newsegment = TRUE; - if (src->segment_loop) { + if (src->segment.flags & GST_SEEK_FLAG_SEGMENT) { /* FIXME subclasses should be able to provide other formats */ gst_element_post_message (GST_ELEMENT (src), gst_message_new_segment_start (GST_OBJECT (src), GST_FORMAT_BYTES, - src->segment_start)); + src->segment.start)); } /* and restart the task in case it got paused explicitely or by @@ -906,16 +841,16 @@ gst_base_src_get_range (GstBaseSrc * src, guint64 offset, guint length, goto no_function; /* the max amount of bytes to read is the total size or - * up to the segment_end if present. */ - if (src->segment_end != -1) - maxsize = MIN (src->size, src->segment_end); + * up to the segment.stop if present. */ + if (src->segment.stop != -1) + maxsize = MIN (src->size, src->segment.stop); else maxsize = src->size; GST_DEBUG_OBJECT (src, "reading offset %" G_GUINT64_FORMAT ", length %u, size %" G_GINT64_FORMAT - ", segment_end %" G_GINT64_FORMAT ", maxsize %" G_GINT64_FORMAT, offset, - length, src->size, src->segment_end, maxsize); + ", segment.stop %" G_GINT64_FORMAT ", maxsize %" G_GINT64_FORMAT, offset, + length, src->size, src->segment.stop, maxsize); /* check size */ if (maxsize != -1) { @@ -927,8 +862,8 @@ gst_base_src_get_range (GstBaseSrc * src, guint64 offset, guint length, if (bclass->get_size) bclass->get_size (src, &src->size); - if (src->segment_end != -1) - maxsize = MIN (src->size, src->segment_end); + if (src->segment.stop != -1) + maxsize = MIN (src->size, src->segment.stop); else maxsize = src->size; @@ -1072,11 +1007,11 @@ eos: { GST_DEBUG_OBJECT (src, "going to EOS, getrange returned UNEXPECTED"); gst_pad_pause_task (pad); - if (src->segment_loop) { + if (src->segment.flags & GST_SEEK_FLAG_SEGMENT) { /* FIXME, subclass might want to use another format */ gst_element_post_message (GST_ELEMENT (src), gst_message_new_segment_done (GST_OBJECT (src), - GST_FORMAT_BYTES, src->segment_end)); + GST_FORMAT_BYTES, src->segment.stop)); } else { gst_pad_push_event (pad, gst_event_new_eos ()); } @@ -1493,9 +1428,7 @@ gst_base_src_change_state (GstElement * element, GstStateChange transition) /* 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; + gst_segment_init (&basesrc->segment, GST_FORMAT_BYTES); basesrc->offset = 0; break; case GST_STATE_CHANGE_PLAYING_TO_PAUSED: @@ -1510,9 +1443,7 @@ gst_base_src_change_state (GstElement * element, GstStateChange transition) if (!gst_base_src_stop (basesrc)) 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; + gst_segment_init (&basesrc->segment, GST_FORMAT_BYTES); basesrc->offset = 0; break; case GST_STATE_CHANGE_READY_TO_NULL: diff --git a/gst/base/gstbasesrc.h b/gst/base/gstbasesrc.h index f62f1c0..1d788a5 100644 --- a/gst/base/gstbasesrc.h +++ b/gst/base/gstbasesrc.h @@ -84,9 +84,7 @@ struct _GstBaseSrc { GstClockTime end_time; /* MT-protected (with STREAM_LOCK) */ - gint64 segment_start; /* start and end positions for seeking */ - gint64 segment_end; - gboolean segment_loop; + GstSegment segment; gboolean need_newsegment; guint64 offset; /* current offset in the resource */ diff --git a/gst/base/gstbasetransform.c b/gst/base/gstbasetransform.c index ba50418..e856c51 100644 --- a/gst/base/gstbasetransform.c +++ b/gst/base/gstbasetransform.c @@ -854,6 +854,7 @@ gst_base_transform_prepare_output_buf (GstBaseTransform * trans, if (G_UNLIKELY (!gst_caps_is_equal (out_caps, GST_BUFFER_CAPS (*out_buf)))) { /* FIXME, it is possible we can reconfigure the transform with new caps at this * point but for now we just create a buffer ourselves */ + gst_buffer_unref (*out_buf); *out_buf = gst_buffer_new_and_alloc (out_size); gst_buffer_set_caps (*out_buf, out_caps); } @@ -1056,13 +1057,7 @@ gst_base_transform_event (GstPad * pad, GstEvent * event) GST_STREAM_LOCK (pad); unlock = TRUE; /* we need new segment info after the flush. */ - trans->segment_rate = 1.0; - trans->segment_start = -1; - trans->segment_stop = -1; - trans->segment_base = -1; - GST_DEBUG_OBJECT (trans, "reset accum %" GST_TIME_FORMAT, - GST_TIME_ARGS (trans->segment_accum)); - trans->segment_accum = 0; + gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED); break; case GST_EVENT_EOS: GST_STREAM_LOCK (pad); @@ -1076,7 +1071,7 @@ gst_base_transform_event (GstPad * pad, GstEvent * event) { GstFormat format; gdouble rate; - gint64 start, stop, time, duration; + gint64 start, stop, time; gboolean update; GST_STREAM_LOCK (pad); @@ -1084,63 +1079,25 @@ gst_base_transform_event (GstPad * pad, GstEvent * event) gst_event_parse_newsegment (event, &update, &rate, &format, &start, &stop, &time); - /* any other format with 0 also gives time 0, the other values are - * invalid as time though. */ - if (format != GST_FORMAT_TIME) { - GST_DEBUG_OBJECT (trans, - "non-time newsegment with start 0, coaxing into FORMAT_TIME"); - format = GST_FORMAT_TIME; - if (start != 0) - start = -1; - if (stop != 0) - stop = -1; - if (time != 0) - time = -1; - } - - /* check if we really have a new segment or the previous one is - * closed */ - if (!update) { - /* the new segment has to be aligned with the old segment. - * We first update the accumulated time of the previous - * segment. the accumulated time is used when syncing to the - * clock. A flush event sets the accumulated time back to 0 - */ - if (GST_CLOCK_TIME_IS_VALID (trans->segment_stop)) { - duration = trans->segment_stop - trans->segment_start; - } else { - duration = 0; - } - } else { - if (GST_CLOCK_TIME_IS_VALID (start)) - duration = start - trans->segment_start; - else - duration = 0; - } + gst_segment_set_newsegment (&trans->segment, update, rate, format, start, + stop, time); trans->have_newsegment = TRUE; - trans->segment_accum += gst_gdouble_to_guint64 ( - (gst_guint64_to_gdouble (duration) / ABS (trans->segment_rate)));; - trans->segment_rate = rate; - trans->segment_start = start; - trans->segment_stop = stop; - trans->segment_base = time; - if (format == GST_FORMAT_TIME) { GST_DEBUG_OBJECT (trans, "received NEW_SEGMENT %" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT ", accum %" GST_TIME_FORMAT, - GST_TIME_ARGS (trans->segment_start), - GST_TIME_ARGS (trans->segment_stop), - GST_TIME_ARGS (trans->segment_base), - GST_TIME_ARGS (trans->segment_accum)); + GST_TIME_ARGS (trans->segment.start), + GST_TIME_ARGS (trans->segment.stop), + GST_TIME_ARGS (trans->segment.time), + GST_TIME_ARGS (trans->segment.accum)); } else { GST_DEBUG_OBJECT (trans, "received NEW_SEGMENT %" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT ", accum %" G_GINT64_FORMAT, - trans->segment_start, trans->segment_stop, - trans->segment_base, trans->segment_accum); + trans->segment.start, trans->segment.stop, + trans->segment.time, trans->segment.accum); } break; } @@ -1432,11 +1389,7 @@ gst_base_transform_change_state (GstElement * element, GST_DEBUG_OBJECT (trans, "have_same_caps %d", trans->have_same_caps); trans->negotiated = FALSE; trans->have_newsegment = FALSE; - trans->segment_rate = 1.0; - trans->segment_start = 0; - trans->segment_stop = -1; - trans->segment_base = 0; - trans->segment_accum = 0; + gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED); GST_OBJECT_UNLOCK (trans); break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: diff --git a/gst/base/gstbasetransform.h b/gst/base/gstbasetransform.h index 77a4268..fdd4ac1 100644 --- a/gst/base/gstbasetransform.h +++ b/gst/base/gstbasetransform.h @@ -65,6 +65,7 @@ struct _GstBaseTransform { guint cache_caps1_size; GstCaps *cache_caps2; guint cache_caps2_size; + gboolean have_same_caps; gboolean delay_configure; gboolean pending_configure; @@ -73,22 +74,12 @@ struct _GstBaseTransform { gboolean have_newsegment; /* MT-protected (with STREAM_LOCK) */ - gdouble segment_rate; - gint64 segment_start; - gint64 segment_stop; - gint64 segment_base; - - union { - /* FIXME: When adjusting the padding, move this to a nice place in the structure */ - /* Set if caps on each pad are equal */ - struct { - gboolean have_same_caps; - GMutex *transform_lock; - gint64 segment_accum; - }; - /*< private >*/ - gpointer _gst_reserved[GST_PADDING-1+1]; - }; + GstSegment segment; + + GMutex *transform_lock; + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING]; }; /** @@ -165,15 +156,16 @@ struct _GstBaseTransformClass { gpointer _gst_reserved[GST_PADDING - 2]; }; -void gst_base_transform_set_passthrough (GstBaseTransform *trans, - gboolean passthrough); -gboolean gst_base_transform_is_passthrough (GstBaseTransform *trans); +GType gst_base_transform_get_type (void); + +void gst_base_transform_set_passthrough (GstBaseTransform *trans, + gboolean passthrough); +gboolean gst_base_transform_is_passthrough (GstBaseTransform *trans); -void gst_base_transform_set_in_place (GstBaseTransform *trans, - gboolean in_place); -gboolean gst_base_transform_is_in_place (GstBaseTransform *trans); +void gst_base_transform_set_in_place (GstBaseTransform *trans, + gboolean in_place); +gboolean gst_base_transform_is_in_place (GstBaseTransform *trans); -GType gst_base_transform_get_type (void); G_END_DECLS diff --git a/gst/base/gstcollectpads.c b/gst/base/gstcollectpads.c index de08df4..d3a48fc 100644 --- a/gst/base/gstcollectpads.c +++ b/gst/base/gstcollectpads.c @@ -196,6 +196,7 @@ gst_collect_pads_add_pad (GstCollectPads * pads, GstPad * pad, guint size) data->collect = pads; data->pad = pad; data->buffer = NULL; + gst_segment_init (&data->segment, GST_FORMAT_UNDEFINED); GST_OBJECT_LOCK (pads); pads->data = g_slist_append (pads->data, data); @@ -599,20 +600,16 @@ gst_collect_pads_event (GstPad * pad, GstEvent * event) } case GST_EVENT_NEWSEGMENT: { - gint64 segment_start, segment_stop, stream_time; - gdouble segment_rate; + gint64 start, stop, time; + gdouble rate; GstFormat format; gboolean update; - gst_event_parse_newsegment (event, &update, &segment_rate, &format, - &segment_start, &segment_stop, &stream_time); - - if (format == GST_FORMAT_TIME) { - data->segment_start = segment_start; - data->segment_stop = segment_stop; - data->stream_time = stream_time; - } + gst_event_parse_newsegment (event, &update, &rate, &format, + &start, &stop, &time); + gst_segment_set_newsegment (&data->segment, update, rate, format, + start, stop, time); goto beach; } default: diff --git a/gst/base/gstcollectpads.h b/gst/base/gstcollectpads.h index 789197f..e6d7ca9 100644 --- a/gst/base/gstcollectpads.h +++ b/gst/base/gstcollectpads.h @@ -55,9 +55,7 @@ struct _GstCollectData GstPad *pad; GstBuffer *buffer; guint pos; - gint64 segment_start; - gint64 segment_stop; - gint64 stream_time; + GstSegment segment; /*< private >*/ gpointer _gst_reserved[GST_PADDING]; diff --git a/gst/elements/gstfakesrc.c b/gst/elements/gstfakesrc.c index ea8c632..0502b8f 100644 --- a/gst/elements/gstfakesrc.c +++ b/gst/elements/gstfakesrc.c @@ -324,8 +324,6 @@ static void gst_fake_src_init (GstFakeSrc * fakesrc, GstFakeSrcClass * g_class) { fakesrc->output = FAKE_SRC_FIRST_LAST_LOOP; - fakesrc->segment_start = -1; - fakesrc->segment_end = -1; fakesrc->buffer_count = 0; fakesrc->silent = DEFAULT_SILENT; fakesrc->signal_handoffs = DEFAULT_SIGNAL_HANDOFFS; @@ -687,12 +685,6 @@ gst_fake_src_create (GstBaseSrc * basesrc, guint64 offset, guint length, src = GST_FAKE_SRC (basesrc); - if (src->buffer_count == src->segment_end) { - GST_INFO ("buffer_count reaches segment_end %d %d", src->buffer_count, - src->segment_end); - return GST_FLOW_UNEXPECTED; - } - buf = gst_fake_src_create_buffer (src); GST_BUFFER_OFFSET (buf) = src->buffer_count++; diff --git a/gst/elements/gstfakesrc.h b/gst/elements/gstfakesrc.h index 0ea04c4..783db23 100644 --- a/gst/elements/gstfakesrc.h +++ b/gst/elements/gstfakesrc.h @@ -96,9 +96,7 @@ struct _GstFakeSrc { gint datarate; gboolean sync; GstClock *clock; - gint64 segment_start; - gint64 segment_end; - gboolean segment_loop; + gint num_buffers; gint rt_num_buffers; /* we are going to change this at runtime */ gint64 buffer_count; diff --git a/gst/elements/gstidentity.c b/gst/elements/gstidentity.c index 37906b9..27c7e58 100644 --- a/gst/elements/gstidentity.c +++ b/gst/elements/gstidentity.c @@ -376,8 +376,8 @@ gst_identity_transform_ip (GstBaseTransform * trans, GstBuffer * buf) GstClockReturn cret; GstClockTime timestamp; - timestamp = GST_BUFFER_TIMESTAMP (buf) - trans->segment_start; - timestamp += trans->segment_accum; + timestamp = gst_segment_to_running_time (&trans->segment, + GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buf)); timestamp += GST_ELEMENT (identity)->base_time; /* save id if we need to unlock */ diff --git a/gst/gstsegment.c b/gst/gstsegment.c index bae53c1..4a14654 100644 --- a/gst/gstsegment.c +++ b/gst/gstsegment.c @@ -77,7 +77,11 @@ gst_segment_set_duration (GstSegment * segment, GstFormat format, gint64 duration) { g_return_if_fail (segment != NULL); - g_return_if_fail (segment->format == format); + + if (segment->format == GST_FORMAT_UNDEFINED) + segment->format = format; + else + g_return_if_fail (segment->format == format); segment->duration = duration; } @@ -95,7 +99,11 @@ gst_segment_set_last_stop (GstSegment * segment, GstFormat format, gint64 position) { g_return_if_fail (segment != NULL); - g_return_if_fail (segment->format == format); + + if (segment->format == GST_FORMAT_UNDEFINED) + segment->format = format; + else + g_return_if_fail (segment->format == format); segment->last_stop = position; } @@ -110,19 +118,26 @@ gst_segment_set_last_stop (GstSegment * segment, GstFormat format, * @cur: the seek start value * @stop_type: the seek method * @stop: the seek stop value + * @update: boolean holding whether an update the current segment is + * needed. * * Update the segment structure with the field values of a seek event. */ void gst_segment_set_seek (GstSegment * segment, gdouble rate, GstFormat format, GstSeekFlags flags, - GstSeekType cur_type, gint64 cur, GstSeekType stop_type, gint64 stop) + GstSeekType cur_type, gint64 cur, + GstSeekType stop_type, gint64 stop, gboolean * update) { gboolean update_stop, update_start; g_return_if_fail (rate != 0.0); g_return_if_fail (segment != NULL); - g_return_if_fail (segment->format == format); + + if (segment->format == GST_FORMAT_UNDEFINED) + segment->format = format; + else + g_return_if_fail (segment->format == format); update_stop = update_start = TRUE; @@ -199,6 +214,9 @@ gst_segment_set_seek (GstSegment * segment, gdouble rate, segment->flags = flags; segment->start = cur; segment->stop = stop; + + if (update) + *update = update_start || update_stop; } /** @@ -222,6 +240,9 @@ gst_segment_set_newsegment (GstSegment * segment, gboolean update, gdouble rate, g_return_if_fail (rate != 0.0); g_return_if_fail (segment != NULL); + if (segment->format == GST_FORMAT_UNDEFINED) + segment->format = format; + /* any other format with 0 also gives time 0, the other values are * invalid in the format though. */ if (format != segment->format && start == 0) { @@ -283,12 +304,22 @@ gint64 gst_segment_to_stream_time (GstSegment * segment, GstFormat format, gint64 position) { - gint64 result; + gint64 result, time; g_return_val_if_fail (segment != NULL, FALSE); - g_return_val_if_fail (segment->format == format, FALSE); - result = ((position - segment->start) / segment->abs_rate) + segment->time; + if (segment->format == GST_FORMAT_UNDEFINED) + segment->format = format; + else + g_return_val_if_fail (segment->format == format, FALSE); + + if ((time = segment->time) == -1) + time = 0; + + if (position != -1) + result = ((position - segment->start) / segment->abs_rate) + time; + else + result = -1; return result; } @@ -313,10 +344,17 @@ gst_segment_to_running_time (GstSegment * segment, GstFormat format, { gint64 result; - g_return_val_if_fail (segment != NULL, FALSE); - g_return_val_if_fail (segment->format == format, FALSE); + g_return_val_if_fail (segment != NULL, -1); - result = ((position - segment->start) / segment->abs_rate) + segment->accum; + if (segment->format == GST_FORMAT_UNDEFINED) + segment->format = format; + else + g_return_val_if_fail (segment->format == format, -1); + + if (position != -1) + result = ((position - segment->start) / segment->abs_rate) + segment->accum; + else + result = -1; return result; } @@ -341,7 +379,11 @@ gst_segment_clip (GstSegment * segment, GstFormat format, gint64 start, gint64 stop, gint64 * clip_start, gint64 * clip_stop) { g_return_val_if_fail (segment != NULL, FALSE); - g_return_val_if_fail (segment->format == format, FALSE); + + if (segment->format == GST_FORMAT_UNDEFINED) + segment->format = format; + else + g_return_val_if_fail (segment->format == format, FALSE); /* we need a valid start position */ if (start == -1) diff --git a/gst/gstsegment.h b/gst/gstsegment.h index 07115bd..d5eaedc 100644 --- a/gst/gstsegment.h +++ b/gst/gstsegment.h @@ -72,7 +72,8 @@ void gst_segment_set_last_stop (GstSegment *segment, GstFormat format, gint64 p void gst_segment_set_seek (GstSegment *segment, gdouble rate, GstFormat format, GstSeekFlags flags, GstSeekType cur_type, gint64 cur, - GstSeekType stop_type, gint64 stop); + GstSeekType stop_type, gint64 stop, + gboolean *update); void gst_segment_set_newsegment (GstSegment *segment, gboolean update, gdouble rate, GstFormat format, gint64 start, gint64 stop, gint64 time); diff --git a/libs/gst/base/gstbasesink.c b/libs/gst/base/gstbasesink.c index f0c948a..cd5477e 100644 --- a/libs/gst/base/gstbasesink.c +++ b/libs/gst/base/gstbasesink.c @@ -579,81 +579,28 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad, gboolean update; gdouble rate; GstFormat format; - gint64 segment_start; - gint64 segment_stop; - gint64 segment_time; - GstClockTime duration; + gint64 start; + gint64 stop; + gint64 time; /* the newsegment event is needed to bring the buffer timestamps to the * stream time and to drop samples outside of the playback segment. */ gst_event_parse_newsegment (event, &update, &rate, &format, - &segment_start, &segment_stop, &segment_time); + &start, &stop, &time); basesink->have_newsegment = TRUE; - /* any other format with 0 also gives time 0, the other values are - * invalid as time though. */ - if (format != GST_FORMAT_TIME && segment_start == 0) { - GST_DEBUG_OBJECT (basesink, - "non-time newsegment with start 0, coaxing into FORMAT_TIME"); - format = GST_FORMAT_TIME; - if (segment_stop != 0) - segment_stop = -1; - if (segment_time != 0) - segment_time = -1; - } - - if (format != GST_FORMAT_TIME) { - GST_DEBUG_OBJECT (basesink, - "received non time %d NEW_SEGMENT %" G_GINT64_FORMAT - " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT, - format, segment_start, segment_stop, segment_time); - - /* this means this sink will not be able to clip or drop samples - * and timestamps have to start from 0. */ - basesink->segment_start = -1; - basesink->segment_stop = -1; - basesink->segment_time = -1; - goto done_newsegment; - } - /* check if we really have a new segment or the previous one is - * closed */ - if (!update) { - /* the new segment has to be aligned with the old segment. - * We first update the accumulated time of the previous - * segment. the accumulated time is used when syncing to the - * clock. A flush event sets the accumulated time back to 0 - */ - if (GST_CLOCK_TIME_IS_VALID (basesink->segment_stop)) { - duration = basesink->segment_stop - basesink->segment_start; - } else if (GST_CLOCK_TIME_IS_VALID (basesink->current_end)) { - /* else use last seen timestamp as segment stop */ - duration = basesink->current_end - basesink->segment_start; - } else { - duration = 0; - } - } else { - duration = segment_start - basesink->segment_start; - } - - /* use previous rate to calculate duration */ - basesink->segment_accum += gst_gdouble_to_guint64 ( - (gst_guint64_to_gdouble (duration) / ABS (basesink->segment_rate))); - /* then update the current segment */ - basesink->segment_rate = rate; - basesink->segment_start = segment_start; - basesink->segment_stop = segment_stop; - basesink->segment_time = segment_time; + gst_segment_set_newsegment (&basesink->segment, update, rate, format, + start, stop, time); GST_DEBUG_OBJECT (basesink, "received NEWSEGMENT %" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT ", accum %" GST_TIME_FORMAT, - GST_TIME_ARGS (basesink->segment_start), - GST_TIME_ARGS (basesink->segment_stop), - GST_TIME_ARGS (basesink->segment_time), - GST_TIME_ARGS (basesink->segment_accum)); - done_newsegment: + GST_TIME_ARGS (basesink->segment.start), + GST_TIME_ARGS (basesink->segment.stop), + GST_TIME_ARGS (basesink->segment.time), + GST_TIME_ARGS (basesink->segment.accum)); break; } default: @@ -669,8 +616,8 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad, ("Received buffer without a new-segment. Cannot sync to clock.")); basesink->have_newsegment = TRUE; /* this means this sink will not be able to sync to the clock */ - basesink->segment_start = -1; - basesink->segment_stop = -1; + basesink->segment.start = -1; + basesink->segment.stop = -1; } /* check if the buffer needs to be dropped */ @@ -685,28 +632,10 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad, ", end: %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (end)); - /* need to drop if the timestamp is not between segment_start and - * segment_stop. we check if the complete sample is outside of the - * range since the sink might be able to clip the sample. */ - if (GST_CLOCK_TIME_IS_VALID (end) && - GST_CLOCK_TIME_IS_VALID (basesink->segment_start)) { - if (end <= basesink->segment_start) { - GST_DEBUG_OBJECT (basesink, - "buffer end %" GST_TIME_FORMAT " <= segment start %" - GST_TIME_FORMAT ", dropping buffer", GST_TIME_ARGS (end), - GST_TIME_ARGS (basesink->segment_start)); + if (GST_CLOCK_TIME_IS_VALID (start)) { + if (!gst_segment_clip (&basesink->segment, GST_FORMAT_TIME, + (gint64) start, (gint64) end, NULL, NULL)) goto dropping; - } - } - if (GST_CLOCK_TIME_IS_VALID (start) && - GST_CLOCK_TIME_IS_VALID (basesink->segment_stop)) { - if (basesink->segment_stop <= start) { - GST_DEBUG_OBJECT (basesink, - "buffer start %" GST_TIME_FORMAT " >= segment stop %" - GST_TIME_FORMAT ", dropping buffer", GST_TIME_ARGS (start), - GST_TIME_ARGS (basesink->segment_stop)); - goto dropping; - } } } basesink->preroll_queued++; @@ -917,13 +846,7 @@ gst_base_sink_event (GstPad * pad, GstEvent * event) basesink->flushing = FALSE; GST_OBJECT_UNLOCK (basesink); /* we need new segment info after the flush. */ - basesink->segment_start = -1; - basesink->segment_stop = -1; - basesink->current_start = -1; - basesink->current_end = -1; - GST_DEBUG_OBJECT (basesink, "reset accum %" GST_TIME_FORMAT, - GST_TIME_ARGS (basesink->segment_accum)); - basesink->segment_accum = 0; + gst_segment_init (&basesink->segment, GST_FORMAT_TIME); GST_STREAM_UNLOCK (pad); GST_DEBUG_OBJECT (basesink, "event unref %p %p", basesink, event); @@ -1004,9 +927,8 @@ gst_base_sink_do_sync (GstBaseSink * basesink, GstBuffer * buffer) { GstClockReturn result = GST_CLOCK_OK; GstClockTime start, end; - GstClockTimeDiff stream_start, stream_end; + gint64 cstart, cend; GstBaseSinkClass *bclass; - gboolean start_valid, end_valid; bclass = GST_BASE_SINK_GET_CLASS (basesink); @@ -1014,61 +936,27 @@ gst_base_sink_do_sync (GstBaseSink * basesink, GstBuffer * buffer) if (bclass->get_times) bclass->get_times (basesink, buffer, &start, &end); - start_valid = GST_CLOCK_TIME_IS_VALID (start); - end_valid = GST_CLOCK_TIME_IS_VALID (end); - GST_DEBUG_OBJECT (basesink, "got times start: %" GST_TIME_FORMAT ", end: %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (end)); /* if we don't have a timestamp, we don't sync */ - if (!start_valid) { + if (!GST_CLOCK_TIME_IS_VALID (start)) { GST_DEBUG_OBJECT (basesink, "start not valid"); goto done; } /* save last times seen. */ - basesink->current_start = start; - if (end_valid) - basesink->current_end = end; + if (GST_CLOCK_TIME_IS_VALID (end)) + gst_segment_set_last_stop (&basesink->segment, GST_FORMAT_TIME, + (gint64) end); else - basesink->current_end = start; + gst_segment_set_last_stop (&basesink->segment, GST_FORMAT_TIME, + (gint64) start); - if (GST_CLOCK_TIME_IS_VALID (basesink->segment_stop)) { - /* check if not outside of the segment range, start is - * always valid here. */ - if (start > basesink->segment_stop) - goto out_of_segment; - } - - /* bring timestamp to stream time using last segment offset. */ - if (GST_CLOCK_TIME_IS_VALID (basesink->segment_start)) { - /* check if not outside of the segment range */ - if (end_valid && end < basesink->segment_start) - goto out_of_segment; - - stream_start = (gint64) start - basesink->segment_start; - stream_end = (gint64) end - basesink->segment_start; - - if (stream_start < 0) { - GST_DEBUG_OBJECT (basesink, "stream_start negative, invalid"); - goto done; - } - } else { - stream_start = (gint64) start; - stream_end = (gint64) end; - } - - - /* correct for rate */ - if (basesink->segment_rate != 0.0) { - stream_start /= ABS (basesink->segment_rate); - if (end_valid) - stream_end /= ABS (basesink->segment_rate); - } - - stream_start += basesink->segment_accum; - if (end_valid) - stream_end += basesink->segment_accum; + /* clip */ + if (!gst_segment_clip (&basesink->segment, GST_FORMAT_TIME, + (gint64) start, (gint64) end, &cstart, &cend)) + goto out_of_segment; if (!basesink->sync) { GST_DEBUG_OBJECT (basesink, "no need to sync"); @@ -1078,6 +966,13 @@ gst_base_sink_do_sync (GstBaseSink * basesink, GstBuffer * buffer) /* now do clocking */ if (basesink->clock) { GstClockTime base_time; + GstClockTimeDiff stream_start, stream_end; + + stream_start = + gst_segment_to_running_time (&basesink->segment, GST_FORMAT_TIME, + cstart); + stream_end = + gst_segment_to_running_time (&basesink->segment, GST_FORMAT_TIME, cend); GST_OBJECT_LOCK (basesink); @@ -1090,7 +985,7 @@ gst_base_sink_do_sync (GstBaseSink * basesink, GstBuffer * buffer) /* also save end_time of this buffer so that we can wait * to signal EOS */ - if (end_valid) + if (GST_CLOCK_TIME_IS_VALID (stream_end)) basesink->end_time = stream_end + base_time; else basesink->end_time = GST_CLOCK_TIME_NONE; @@ -1386,7 +1281,7 @@ gst_base_sink_activate_pull (GstPad * pad, gboolean active) } else { if (gst_pad_activate_pull (peer, TRUE)) { basesink->have_newsegment = TRUE; - basesink->segment_start = basesink->segment_stop = 0; + gst_segment_init (&basesink->segment, GST_FORMAT_TIME); /* set the pad mode before starting the task so that it's in the correct state for the new thread... */ @@ -1467,7 +1362,7 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format, GST_OBJECT_LOCK (basesink); if ((clock = GST_ELEMENT_CLOCK (basesink))) { GstClockTime now; - gint64 segment_time; + gint64 time; gst_object_ref (clock); GST_OBJECT_UNLOCK (basesink); @@ -1475,18 +1370,18 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format, now = gst_clock_get_time (clock); GST_OBJECT_LOCK (basesink); - if (GST_CLOCK_TIME_IS_VALID (basesink->segment_time)) - segment_time = basesink->segment_time; + if (GST_CLOCK_TIME_IS_VALID (basesink->segment.time)) + time = basesink->segment.time; else - segment_time = 0; + time = 0; *cur = now - GST_ELEMENT_CAST (basesink)->base_time - - basesink->segment_accum + segment_time; + basesink->segment.accum + time; GST_DEBUG_OBJECT (basesink, "now %" GST_TIME_FORMAT " + segment_time %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT, GST_TIME_ARGS (now), - GST_TIME_ARGS (segment_time), GST_TIME_ARGS (*cur)); + GST_TIME_ARGS (time), GST_TIME_ARGS (*cur)); gst_object_unref (clock); @@ -1547,8 +1442,8 @@ gst_base_sink_query (GstElement * element, GstQuery * query) case GST_QUERY_SEGMENT: { /* FIXME, bring start/stop to stream time */ - gst_query_set_segment (query, basesink->segment_rate, - GST_FORMAT_TIME, basesink->segment_start, basesink->segment_stop); + gst_query_set_segment (query, basesink->segment.rate, + GST_FORMAT_TIME, basesink->segment.start, basesink->segment.stop); break; } case GST_QUERY_SEEKING: @@ -1585,15 +1480,8 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition) GST_DEBUG_OBJECT (basesink, "READY to PAUSED, need preroll to FALSE"); basesink->need_preroll = TRUE; GST_PREROLL_UNLOCK (basesink->sinkpad); + gst_segment_init (&basesink->segment, GST_FORMAT_TIME); basesink->have_newsegment = FALSE; - basesink->segment_rate = 1.0; - basesink->segment_start = 0; - basesink->segment_stop = -1; - basesink->segment_time = 0; - basesink->current_start = -1; - basesink->current_duration = -1; - basesink->current_end = -1; - basesink->segment_accum = 0; ret = GST_STATE_CHANGE_ASYNC; break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: diff --git a/libs/gst/base/gstbasesink.h b/libs/gst/base/gstbasesink.h index f3fb83a..bb87cb5 100644 --- a/libs/gst/base/gstbasesink.h +++ b/libs/gst/base/gstbasesink.h @@ -80,15 +80,7 @@ struct _GstBaseSink { /*< protected >*/ /* with STREAM_LOCK */ gboolean have_newsegment; - gdouble segment_rate; - gint64 segment_start; - gint64 segment_stop; - gint64 segment_time; - gint64 segment_accum; - - gint64 current_start; - gint64 current_duration; - gint64 current_end; + GstSegment segment; /*< private >*/ /* with LOCK */ GstClock *clock; diff --git a/libs/gst/base/gstbasesrc.c b/libs/gst/base/gstbasesrc.c index 9080623..d57e6c3 100644 --- a/libs/gst/base/gstbasesrc.c +++ b/libs/gst/base/gstbasesrc.c @@ -229,8 +229,7 @@ gst_base_src_init (GstBaseSrc * basesrc, gpointer g_class) basesrc->blocksize = DEFAULT_BLOCKSIZE; basesrc->clock_id = NULL; - basesrc->segment_start = 0; - basesrc->segment_end = -1; + gst_segment_init (&basesrc->segment, GST_FORMAT_BYTES); GST_OBJECT_FLAG_UNSET (basesrc, GST_BASE_SRC_STARTED); @@ -411,9 +410,9 @@ gst_base_src_query (GstPad * pad, GstQuery * query) { gint64 start, stop; - start = src->segment_start; + start = src->segment.start; /* no end segment configured, current size then */ - if ((stop = src->segment_end) == -1) + if ((stop = src->segment.stop) == -1) stop = src->size; /* FIXME, we can't report our rate as we did not store it, d'oh!. @@ -448,11 +447,11 @@ gst_base_src_default_newsegment (GstBaseSrc * src) GstEvent *event; GST_DEBUG_OBJECT (src, "Sending newsegment from %" G_GINT64_FORMAT - " to %" G_GINT64_FORMAT, src->segment_start, src->segment_end); + " to %" G_GINT64_FORMAT, src->segment.start, src->segment.stop); event = gst_event_new_newsegment (FALSE, 1.0, - GST_FORMAT_BYTES, src->segment_start, src->segment_end, - src->segment_start); + GST_FORMAT_BYTES, src->segment.start, src->segment.stop, + src->segment.start); return gst_pad_push_event (src->srcpad, event); } @@ -471,7 +470,7 @@ gst_base_src_newsegment (GstBaseSrc * src) return result; } -/* based on the event parameters configure the segment_start/stop +/* based on the event parameters configure the segment.start/stop * times. Called with STREAM_LOCK. */ static gboolean @@ -482,84 +481,20 @@ gst_base_src_configure_segment (GstBaseSrc * src, GstEvent * event) GstSeekFlags flags; GstSeekType cur_type, stop_type; gint64 cur, stop; - gboolean update_stop, update_start; + gboolean update; gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur, &stop_type, &stop); - /* parse the loop flag */ - /* FIXME, need to store other flags and rate too */ - src->segment_loop = (flags & GST_SEEK_FLAG_SEGMENT) != 0; - - /* assume we'll update both start and stop values */ - update_start = TRUE; - update_stop = TRUE; - - /* perform the seek, segment_start is never invalid */ - switch (cur_type) { - case GST_SEEK_TYPE_NONE: - /* no update to segment */ - cur = src->segment_start; - update_start = FALSE; - break; - case GST_SEEK_TYPE_SET: - /* cur holds desired position */ - break; - case GST_SEEK_TYPE_CUR: - /* add cur to currently configure segment */ - cur = src->segment_start + cur; - break; - case GST_SEEK_TYPE_END: - /* add cur to total length */ - cur = src->size + cur; - break; - } - /* bring in sane range */ - 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) { - case GST_SEEK_TYPE_NONE: - stop = src->segment_end; - update_stop = FALSE; - break; - case GST_SEEK_TYPE_SET: - /* stop folds required value */ - break; - case GST_SEEK_TYPE_CUR: - if (src->segment_end != -1) - stop = src->segment_end + stop; - else - stop = -1; - break; - case GST_SEEK_TYPE_END: - if (src->size != -1) - stop = src->size + stop; - else - stop = -1; - break; - } - - /* 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_end = stop; + gst_segment_set_seek (&src->segment, rate, format, flags, + cur_type, cur, stop_type, stop, &update); /* update our offset if it was updated */ - if (update_start) + if (update) src->offset = cur; 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.stop); return TRUE; } @@ -567,9 +502,9 @@ gst_base_src_configure_segment (GstBaseSrc * src, GstEvent * event) /* 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 + * 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 @@ -592,13 +527,13 @@ gst_base_src_configure_segment (GstBaseSrc * src, GstEvent * event) * 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 + * 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 + * when we reach the segment.stop we have to post a segment.done * instead of EOS when doing a segment seek. */ static gboolean @@ -648,11 +583,11 @@ gst_base_src_do_seek (GstBaseSrc * src, GstEvent * event) * thread. We could opt to send it here too. */ src->need_newsegment = TRUE; - if (src->segment_loop) { + if (src->segment.flags & GST_SEEK_FLAG_SEGMENT) { /* FIXME subclasses should be able to provide other formats */ gst_element_post_message (GST_ELEMENT (src), gst_message_new_segment_start (GST_OBJECT (src), GST_FORMAT_BYTES, - src->segment_start)); + src->segment.start)); } /* and restart the task in case it got paused explicitely or by @@ -906,16 +841,16 @@ gst_base_src_get_range (GstBaseSrc * src, guint64 offset, guint length, goto no_function; /* the max amount of bytes to read is the total size or - * up to the segment_end if present. */ - if (src->segment_end != -1) - maxsize = MIN (src->size, src->segment_end); + * up to the segment.stop if present. */ + if (src->segment.stop != -1) + maxsize = MIN (src->size, src->segment.stop); else maxsize = src->size; GST_DEBUG_OBJECT (src, "reading offset %" G_GUINT64_FORMAT ", length %u, size %" G_GINT64_FORMAT - ", segment_end %" G_GINT64_FORMAT ", maxsize %" G_GINT64_FORMAT, offset, - length, src->size, src->segment_end, maxsize); + ", segment.stop %" G_GINT64_FORMAT ", maxsize %" G_GINT64_FORMAT, offset, + length, src->size, src->segment.stop, maxsize); /* check size */ if (maxsize != -1) { @@ -927,8 +862,8 @@ gst_base_src_get_range (GstBaseSrc * src, guint64 offset, guint length, if (bclass->get_size) bclass->get_size (src, &src->size); - if (src->segment_end != -1) - maxsize = MIN (src->size, src->segment_end); + if (src->segment.stop != -1) + maxsize = MIN (src->size, src->segment.stop); else maxsize = src->size; @@ -1072,11 +1007,11 @@ eos: { GST_DEBUG_OBJECT (src, "going to EOS, getrange returned UNEXPECTED"); gst_pad_pause_task (pad); - if (src->segment_loop) { + if (src->segment.flags & GST_SEEK_FLAG_SEGMENT) { /* FIXME, subclass might want to use another format */ gst_element_post_message (GST_ELEMENT (src), gst_message_new_segment_done (GST_OBJECT (src), - GST_FORMAT_BYTES, src->segment_end)); + GST_FORMAT_BYTES, src->segment.stop)); } else { gst_pad_push_event (pad, gst_event_new_eos ()); } @@ -1493,9 +1428,7 @@ gst_base_src_change_state (GstElement * element, GstStateChange transition) /* 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; + gst_segment_init (&basesrc->segment, GST_FORMAT_BYTES); basesrc->offset = 0; break; case GST_STATE_CHANGE_PLAYING_TO_PAUSED: @@ -1510,9 +1443,7 @@ gst_base_src_change_state (GstElement * element, GstStateChange transition) if (!gst_base_src_stop (basesrc)) 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; + gst_segment_init (&basesrc->segment, GST_FORMAT_BYTES); basesrc->offset = 0; break; case GST_STATE_CHANGE_READY_TO_NULL: diff --git a/libs/gst/base/gstbasesrc.h b/libs/gst/base/gstbasesrc.h index f62f1c0..1d788a5 100644 --- a/libs/gst/base/gstbasesrc.h +++ b/libs/gst/base/gstbasesrc.h @@ -84,9 +84,7 @@ struct _GstBaseSrc { GstClockTime end_time; /* MT-protected (with STREAM_LOCK) */ - gint64 segment_start; /* start and end positions for seeking */ - gint64 segment_end; - gboolean segment_loop; + GstSegment segment; gboolean need_newsegment; guint64 offset; /* current offset in the resource */ diff --git a/libs/gst/base/gstbasetransform.c b/libs/gst/base/gstbasetransform.c index ba50418..e856c51 100644 --- a/libs/gst/base/gstbasetransform.c +++ b/libs/gst/base/gstbasetransform.c @@ -854,6 +854,7 @@ gst_base_transform_prepare_output_buf (GstBaseTransform * trans, if (G_UNLIKELY (!gst_caps_is_equal (out_caps, GST_BUFFER_CAPS (*out_buf)))) { /* FIXME, it is possible we can reconfigure the transform with new caps at this * point but for now we just create a buffer ourselves */ + gst_buffer_unref (*out_buf); *out_buf = gst_buffer_new_and_alloc (out_size); gst_buffer_set_caps (*out_buf, out_caps); } @@ -1056,13 +1057,7 @@ gst_base_transform_event (GstPad * pad, GstEvent * event) GST_STREAM_LOCK (pad); unlock = TRUE; /* we need new segment info after the flush. */ - trans->segment_rate = 1.0; - trans->segment_start = -1; - trans->segment_stop = -1; - trans->segment_base = -1; - GST_DEBUG_OBJECT (trans, "reset accum %" GST_TIME_FORMAT, - GST_TIME_ARGS (trans->segment_accum)); - trans->segment_accum = 0; + gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED); break; case GST_EVENT_EOS: GST_STREAM_LOCK (pad); @@ -1076,7 +1071,7 @@ gst_base_transform_event (GstPad * pad, GstEvent * event) { GstFormat format; gdouble rate; - gint64 start, stop, time, duration; + gint64 start, stop, time; gboolean update; GST_STREAM_LOCK (pad); @@ -1084,63 +1079,25 @@ gst_base_transform_event (GstPad * pad, GstEvent * event) gst_event_parse_newsegment (event, &update, &rate, &format, &start, &stop, &time); - /* any other format with 0 also gives time 0, the other values are - * invalid as time though. */ - if (format != GST_FORMAT_TIME) { - GST_DEBUG_OBJECT (trans, - "non-time newsegment with start 0, coaxing into FORMAT_TIME"); - format = GST_FORMAT_TIME; - if (start != 0) - start = -1; - if (stop != 0) - stop = -1; - if (time != 0) - time = -1; - } - - /* check if we really have a new segment or the previous one is - * closed */ - if (!update) { - /* the new segment has to be aligned with the old segment. - * We first update the accumulated time of the previous - * segment. the accumulated time is used when syncing to the - * clock. A flush event sets the accumulated time back to 0 - */ - if (GST_CLOCK_TIME_IS_VALID (trans->segment_stop)) { - duration = trans->segment_stop - trans->segment_start; - } else { - duration = 0; - } - } else { - if (GST_CLOCK_TIME_IS_VALID (start)) - duration = start - trans->segment_start; - else - duration = 0; - } + gst_segment_set_newsegment (&trans->segment, update, rate, format, start, + stop, time); trans->have_newsegment = TRUE; - trans->segment_accum += gst_gdouble_to_guint64 ( - (gst_guint64_to_gdouble (duration) / ABS (trans->segment_rate)));; - trans->segment_rate = rate; - trans->segment_start = start; - trans->segment_stop = stop; - trans->segment_base = time; - if (format == GST_FORMAT_TIME) { GST_DEBUG_OBJECT (trans, "received NEW_SEGMENT %" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT ", accum %" GST_TIME_FORMAT, - GST_TIME_ARGS (trans->segment_start), - GST_TIME_ARGS (trans->segment_stop), - GST_TIME_ARGS (trans->segment_base), - GST_TIME_ARGS (trans->segment_accum)); + GST_TIME_ARGS (trans->segment.start), + GST_TIME_ARGS (trans->segment.stop), + GST_TIME_ARGS (trans->segment.time), + GST_TIME_ARGS (trans->segment.accum)); } else { GST_DEBUG_OBJECT (trans, "received NEW_SEGMENT %" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT ", accum %" G_GINT64_FORMAT, - trans->segment_start, trans->segment_stop, - trans->segment_base, trans->segment_accum); + trans->segment.start, trans->segment.stop, + trans->segment.time, trans->segment.accum); } break; } @@ -1432,11 +1389,7 @@ gst_base_transform_change_state (GstElement * element, GST_DEBUG_OBJECT (trans, "have_same_caps %d", trans->have_same_caps); trans->negotiated = FALSE; trans->have_newsegment = FALSE; - trans->segment_rate = 1.0; - trans->segment_start = 0; - trans->segment_stop = -1; - trans->segment_base = 0; - trans->segment_accum = 0; + gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED); GST_OBJECT_UNLOCK (trans); break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: diff --git a/libs/gst/base/gstbasetransform.h b/libs/gst/base/gstbasetransform.h index 77a4268..fdd4ac1 100644 --- a/libs/gst/base/gstbasetransform.h +++ b/libs/gst/base/gstbasetransform.h @@ -65,6 +65,7 @@ struct _GstBaseTransform { guint cache_caps1_size; GstCaps *cache_caps2; guint cache_caps2_size; + gboolean have_same_caps; gboolean delay_configure; gboolean pending_configure; @@ -73,22 +74,12 @@ struct _GstBaseTransform { gboolean have_newsegment; /* MT-protected (with STREAM_LOCK) */ - gdouble segment_rate; - gint64 segment_start; - gint64 segment_stop; - gint64 segment_base; - - union { - /* FIXME: When adjusting the padding, move this to a nice place in the structure */ - /* Set if caps on each pad are equal */ - struct { - gboolean have_same_caps; - GMutex *transform_lock; - gint64 segment_accum; - }; - /*< private >*/ - gpointer _gst_reserved[GST_PADDING-1+1]; - }; + GstSegment segment; + + GMutex *transform_lock; + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING]; }; /** @@ -165,15 +156,16 @@ struct _GstBaseTransformClass { gpointer _gst_reserved[GST_PADDING - 2]; }; -void gst_base_transform_set_passthrough (GstBaseTransform *trans, - gboolean passthrough); -gboolean gst_base_transform_is_passthrough (GstBaseTransform *trans); +GType gst_base_transform_get_type (void); + +void gst_base_transform_set_passthrough (GstBaseTransform *trans, + gboolean passthrough); +gboolean gst_base_transform_is_passthrough (GstBaseTransform *trans); -void gst_base_transform_set_in_place (GstBaseTransform *trans, - gboolean in_place); -gboolean gst_base_transform_is_in_place (GstBaseTransform *trans); +void gst_base_transform_set_in_place (GstBaseTransform *trans, + gboolean in_place); +gboolean gst_base_transform_is_in_place (GstBaseTransform *trans); -GType gst_base_transform_get_type (void); G_END_DECLS diff --git a/libs/gst/base/gstcollectpads.c b/libs/gst/base/gstcollectpads.c index de08df4..d3a48fc 100644 --- a/libs/gst/base/gstcollectpads.c +++ b/libs/gst/base/gstcollectpads.c @@ -196,6 +196,7 @@ gst_collect_pads_add_pad (GstCollectPads * pads, GstPad * pad, guint size) data->collect = pads; data->pad = pad; data->buffer = NULL; + gst_segment_init (&data->segment, GST_FORMAT_UNDEFINED); GST_OBJECT_LOCK (pads); pads->data = g_slist_append (pads->data, data); @@ -599,20 +600,16 @@ gst_collect_pads_event (GstPad * pad, GstEvent * event) } case GST_EVENT_NEWSEGMENT: { - gint64 segment_start, segment_stop, stream_time; - gdouble segment_rate; + gint64 start, stop, time; + gdouble rate; GstFormat format; gboolean update; - gst_event_parse_newsegment (event, &update, &segment_rate, &format, - &segment_start, &segment_stop, &stream_time); - - if (format == GST_FORMAT_TIME) { - data->segment_start = segment_start; - data->segment_stop = segment_stop; - data->stream_time = stream_time; - } + gst_event_parse_newsegment (event, &update, &rate, &format, + &start, &stop, &time); + gst_segment_set_newsegment (&data->segment, update, rate, format, + start, stop, time); goto beach; } default: diff --git a/libs/gst/base/gstcollectpads.h b/libs/gst/base/gstcollectpads.h index 789197f..e6d7ca9 100644 --- a/libs/gst/base/gstcollectpads.h +++ b/libs/gst/base/gstcollectpads.h @@ -55,9 +55,7 @@ struct _GstCollectData GstPad *pad; GstBuffer *buffer; guint pos; - gint64 segment_start; - gint64 segment_stop; - gint64 stream_time; + GstSegment segment; /*< private >*/ gpointer _gst_reserved[GST_PADDING]; diff --git a/plugins/elements/gstfakesrc.c b/plugins/elements/gstfakesrc.c index ea8c632..0502b8f 100644 --- a/plugins/elements/gstfakesrc.c +++ b/plugins/elements/gstfakesrc.c @@ -324,8 +324,6 @@ static void gst_fake_src_init (GstFakeSrc * fakesrc, GstFakeSrcClass * g_class) { fakesrc->output = FAKE_SRC_FIRST_LAST_LOOP; - fakesrc->segment_start = -1; - fakesrc->segment_end = -1; fakesrc->buffer_count = 0; fakesrc->silent = DEFAULT_SILENT; fakesrc->signal_handoffs = DEFAULT_SIGNAL_HANDOFFS; @@ -687,12 +685,6 @@ gst_fake_src_create (GstBaseSrc * basesrc, guint64 offset, guint length, src = GST_FAKE_SRC (basesrc); - if (src->buffer_count == src->segment_end) { - GST_INFO ("buffer_count reaches segment_end %d %d", src->buffer_count, - src->segment_end); - return GST_FLOW_UNEXPECTED; - } - buf = gst_fake_src_create_buffer (src); GST_BUFFER_OFFSET (buf) = src->buffer_count++; diff --git a/plugins/elements/gstfakesrc.h b/plugins/elements/gstfakesrc.h index 0ea04c4..783db23 100644 --- a/plugins/elements/gstfakesrc.h +++ b/plugins/elements/gstfakesrc.h @@ -96,9 +96,7 @@ struct _GstFakeSrc { gint datarate; gboolean sync; GstClock *clock; - gint64 segment_start; - gint64 segment_end; - gboolean segment_loop; + gint num_buffers; gint rt_num_buffers; /* we are going to change this at runtime */ gint64 buffer_count; diff --git a/plugins/elements/gstidentity.c b/plugins/elements/gstidentity.c index 37906b9..27c7e58 100644 --- a/plugins/elements/gstidentity.c +++ b/plugins/elements/gstidentity.c @@ -376,8 +376,8 @@ gst_identity_transform_ip (GstBaseTransform * trans, GstBuffer * buf) GstClockReturn cret; GstClockTime timestamp; - timestamp = GST_BUFFER_TIMESTAMP (buf) - trans->segment_start; - timestamp += trans->segment_accum; + timestamp = gst_segment_to_running_time (&trans->segment, + GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buf)); timestamp += GST_ELEMENT (identity)->base_time; /* save id if we need to unlock */ diff --git a/tests/check/gst/gstsegment.c b/tests/check/gst/gstsegment.c index b4e2f5b..e32715e 100644 --- a/tests/check/gst/gstsegment.c +++ b/tests/check/gst/gstsegment.c @@ -27,13 +27,15 @@ GST_START_TEST (segment_seek_nosize) GstSegment segment; gboolean res; gint64 cstart, cstop; + gboolean update; gst_segment_init (&segment, GST_FORMAT_BYTES); /* configure segment to start 100 */ gst_segment_set_seek (&segment, 1.0, GST_FORMAT_BYTES, - GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_SET, 100, GST_SEEK_TYPE_NONE, -1); + GST_SEEK_FLAG_NONE, + GST_SEEK_TYPE_SET, 100, GST_SEEK_TYPE_NONE, -1, &update); fail_unless (segment.start == 100); fail_unless (segment.stop == -1); @@ -41,7 +43,8 @@ GST_START_TEST (segment_seek_nosize) * size is unknown. */ gst_segment_set_seek (&segment, 1.0, GST_FORMAT_BYTES, - GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_NONE, 200, GST_SEEK_TYPE_CUR, -100); + GST_SEEK_FLAG_NONE, + GST_SEEK_TYPE_NONE, 200, GST_SEEK_TYPE_CUR, -100, &update); fail_unless (segment.start == 100); fail_unless (segment.stop == -1); @@ -99,7 +102,8 @@ GST_START_TEST (segment_seek_nosize) /* add 100 to start, set stop to 300 */ gst_segment_set_seek (&segment, 1.0, GST_FORMAT_BYTES, - GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_CUR, 100, GST_SEEK_TYPE_SET, 300); + GST_SEEK_FLAG_NONE, + GST_SEEK_TYPE_CUR, 100, GST_SEEK_TYPE_SET, 300, &update); fail_unless (segment.start == 200); fail_unless (segment.stop == 300); @@ -107,7 +111,8 @@ GST_START_TEST (segment_seek_nosize) * nothing should be updated in the segment. */ ASSERT_CRITICAL (gst_segment_set_seek (&segment, 1.0, GST_FORMAT_BYTES, - GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_CUR, 100, GST_SEEK_TYPE_SET, 200)); + GST_SEEK_FLAG_NONE, + GST_SEEK_TYPE_CUR, 100, GST_SEEK_TYPE_SET, 200, &update)); fail_unless (segment.start == 200); fail_unless (segment.stop == 300); @@ -115,7 +120,8 @@ GST_START_TEST (segment_seek_nosize) * unknown. */ gst_segment_set_seek (&segment, 1.0, GST_FORMAT_BYTES, - GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_END, -300, GST_SEEK_TYPE_END, -100); + GST_SEEK_FLAG_NONE, + GST_SEEK_TYPE_END, -300, GST_SEEK_TYPE_END, -100, &update); fail_unless (segment.start == 200); fail_unless (segment.stop == 300); @@ -193,6 +199,7 @@ GST_START_TEST (segment_seek_size) GstSegment segment; gboolean res; gint64 cstart, cstop; + gboolean update; gst_segment_init (&segment, GST_FORMAT_BYTES); gst_segment_set_duration (&segment, GST_FORMAT_BYTES, 200); @@ -200,7 +207,8 @@ GST_START_TEST (segment_seek_size) /* configure segment to start 100 */ gst_segment_set_seek (&segment, 1.0, GST_FORMAT_BYTES, - GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_SET, 100, GST_SEEK_TYPE_NONE, -1); + GST_SEEK_FLAG_NONE, + GST_SEEK_TYPE_SET, 100, GST_SEEK_TYPE_NONE, -1, &update); fail_unless (segment.start == 100); fail_unless (segment.stop == -1); @@ -208,7 +216,8 @@ GST_START_TEST (segment_seek_size) * since we did not set it before. */ gst_segment_set_seek (&segment, 1.0, GST_FORMAT_BYTES, - GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_NONE, 200, GST_SEEK_TYPE_CUR, -100); + GST_SEEK_FLAG_NONE, + GST_SEEK_TYPE_NONE, 200, GST_SEEK_TYPE_CUR, -100, &update); fail_unless (segment.start == 100); fail_unless (segment.stop == -1); @@ -273,7 +282,8 @@ GST_START_TEST (segment_seek_size) /* add 100 to start, set stop to 300, stop clips to 200 */ gst_segment_set_seek (&segment, 1.0, GST_FORMAT_BYTES, - GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_CUR, 100, GST_SEEK_TYPE_SET, 300); + GST_SEEK_FLAG_NONE, + GST_SEEK_TYPE_CUR, 100, GST_SEEK_TYPE_SET, 300, &update); fail_unless (segment.start == 200); fail_unless (segment.stop == 200); @@ -281,14 +291,16 @@ GST_START_TEST (segment_seek_size) * to duration */ gst_segment_set_seek (&segment, 1.0, GST_FORMAT_BYTES, - GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_CUR, 100, GST_SEEK_TYPE_SET, 200); + GST_SEEK_FLAG_NONE, + GST_SEEK_TYPE_CUR, 100, GST_SEEK_TYPE_SET, 200, &update); fail_unless (segment.start == 200); fail_unless (segment.stop == 200); /* seek relative to end */ gst_segment_set_seek (&segment, 1.0, GST_FORMAT_BYTES, - GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_END, -100, GST_SEEK_TYPE_END, -20); + GST_SEEK_FLAG_NONE, + GST_SEEK_TYPE_END, -100, GST_SEEK_TYPE_END, -20, &update); fail_unless (segment.start == 100); fail_unless (segment.stop == 180); -- 2.7.4