ext/ogg/gstoggdemux.c: Parse seeking events better.

Original commit message from CVS:
* ext/ogg/gstoggdemux.c: (gst_ogg_pad_src_query),
(gst_ogg_pad_event), (gst_ogg_demux_factory_filter),
(gst_ogg_pad_submit_packet), (gst_ogg_chain_new),
(gst_ogg_demux_init), (gst_ogg_demux_perform_seek),
(gst_ogg_demux_collect_chain_info), (gst_ogg_demux_collect_info),
(gst_ogg_demux_chain), (gst_ogg_demux_loop), (gst_ogg_print):
Parse seeking events better.
Unref static caps.
Generate correct newsegment events, fixes seeking in live oggs.

* ext/theora/theoradec.c: (theora_dec_src_query),
(theora_dec_src_event), (theora_dec_src_getcaps),
(theora_dec_sink_event), (theora_dec_push), (theora_dec_chain):
Use newsegment values to report correct play time.

* ext/vorbis/vorbisdec.c: (vorbis_dec_src_query),
(vorbis_dec_src_event), (vorbis_dec_sink_event):
* ext/vorbis/vorbisdec.h:
Parse and use newsegment values to report correct play time.

* gst-libs/gst/audio/gstbaseaudiosink.c:
(gst_base_audio_sink_event), (gst_base_audio_sink_render):
Clear ringbuffer on flush.
Use newsegment values to calculate playback time.

* sys/ximage/ximagesink.c: (gst_ximagesink_get_times):
* sys/xvimage/xvimagesink.c: (gst_xvimagesink_get_times):
Basesink does newsegment calculations for us now.
This commit is contained in:
Wim Taymans 2005-08-24 18:04:45 +00:00
parent 2136419a0a
commit 7824216cef
8 changed files with 240 additions and 75 deletions

View file

@ -1,3 +1,34 @@
2005-08-24 Wim Taymans <wim@fluendo.com>
* ext/ogg/gstoggdemux.c: (gst_ogg_pad_src_query),
(gst_ogg_pad_event), (gst_ogg_demux_factory_filter),
(gst_ogg_pad_submit_packet), (gst_ogg_chain_new),
(gst_ogg_demux_init), (gst_ogg_demux_perform_seek),
(gst_ogg_demux_collect_chain_info), (gst_ogg_demux_collect_info),
(gst_ogg_demux_chain), (gst_ogg_demux_loop), (gst_ogg_print):
Parse seeking events better.
Unref static caps.
Generate correct newsegment events, fixes seeking in live oggs.
* ext/theora/theoradec.c: (theora_dec_src_query),
(theora_dec_src_event), (theora_dec_src_getcaps),
(theora_dec_sink_event), (theora_dec_push), (theora_dec_chain):
Use newsegment values to report correct play time.
* ext/vorbis/vorbisdec.c: (vorbis_dec_src_query),
(vorbis_dec_src_event), (vorbis_dec_sink_event):
* ext/vorbis/vorbisdec.h:
Parse and use newsegment values to report correct play time.
* gst-libs/gst/audio/gstbaseaudiosink.c:
(gst_base_audio_sink_event), (gst_base_audio_sink_render):
Clear ringbuffer on flush.
Use newsegment values to calculate playback time.
* sys/ximage/ximagesink.c: (gst_ximagesink_get_times):
* sys/xvimage/xvimagesink.c: (gst_xvimagesink_get_times):
Basesink does newsegment calculations for us now.
2005-08-24 Thomas Vander Stichele <thomas at apestaart dot org> 2005-08-24 Thomas Vander Stichele <thomas at apestaart dot org>
* check/Makefile.am: * check/Makefile.am:

View file

@ -75,11 +75,12 @@ typedef struct _GstOggChain
GstClockTime total_time; /* the total time of this chain, this is the MAX of GstClockTime total_time; /* the total time of this chain, this is the MAX of
the totals of all streams */ the totals of all streams */
GstClockTime start_time; /* the timestamp of the first sample, this is the MIN of
the start times of all streams. */
GstClockTime last_time; /* the timestamp of the last page, this is the MAX of the
streams. */
GstClockTime begin_time; /* when this chain starts in the stream */ GstClockTime begin_time; /* when this chain starts in the stream */
GstClockTime segment_start; /* the timestamp of the first sample, this is the MIN of
the start times of all streams. */
GstClockTime segment_stop; /* the timestamp of the last page, this is the MAX of the
streams. */
} GstOggChain; } GstOggChain;
/* different modes for the pad */ /* different modes for the pad */
@ -151,7 +152,6 @@ struct _GstOggDemux
/* state */ /* state */
GMutex *chain_lock; /* we need the lock to protect the chains */ GMutex *chain_lock; /* we need the lock to protect the chains */
GArray *chains; /* list of chains we know */ GArray *chains; /* list of chains we know */
GstClockTime start_time; /* the start time of the first chain */
GstClockTime total_time; /* the total time of this ogg, this is the sum of GstClockTime total_time; /* the total time of this ogg, this is the sum of
the totals of all chains */ the totals of all chains */
GstOggChain *current_chain; GstOggChain *current_chain;
@ -161,6 +161,7 @@ struct _GstOggDemux
GstClockTime segment_start; GstClockTime segment_start;
GstClockTime segment_stop; GstClockTime segment_stop;
gboolean segment_play; gboolean segment_play;
gdouble segment_rate;
gint64 current_granule; gint64 current_granule;
GstClockTime current_time; GstClockTime current_time;
@ -185,7 +186,8 @@ static gboolean gst_ogg_demux_collect_chain_info (GstOggDemux * ogg,
static gboolean gst_ogg_demux_activate_chain (GstOggDemux * ogg, static gboolean gst_ogg_demux_activate_chain (GstOggDemux * ogg,
GstOggChain * chain, GstEvent * event); GstOggChain * chain, GstEvent * event);
static gboolean gst_ogg_demux_perform_seek (GstOggDemux * ogg, gboolean flush); static gboolean gst_ogg_demux_perform_seek (GstOggDemux * ogg,
gboolean accurate, gboolean flush);
static void gst_ogg_pad_class_init (GstOggPadClass * klass); static void gst_ogg_pad_class_init (GstOggPadClass * klass);
static void gst_ogg_pad_init (GstOggPad * pad); static void gst_ogg_pad_init (GstOggPad * pad);
@ -360,8 +362,20 @@ gst_ogg_pad_src_query (GstPad * pad, GstQuery * query)
switch (GST_QUERY_TYPE (query)) { switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_POSITION: case GST_QUERY_POSITION:
{
GstFormat format;
gst_query_parse_position (query, &format, NULL, NULL);
/* can only get position in time */
if (format != GST_FORMAT_TIME) {
GST_DEBUG ("only query position on TIME is supported");
res = FALSE;
goto done;
}
/* can only return the total time position */
gst_query_set_position (query, GST_FORMAT_TIME, -1, ogg->total_time); gst_query_set_position (query, GST_FORMAT_TIME, -1, ogg->total_time);
break; break;
}
case GST_QUERY_CONVERT: case GST_QUERY_CONVERT:
/* hmm .. */ /* hmm .. */
res = FALSE; res = FALSE;
@ -370,7 +384,7 @@ gst_ogg_pad_src_query (GstPad * pad, GstQuery * query)
res = FALSE; res = FALSE;
break; break;
} }
done:
return res; return res;
} }
@ -388,8 +402,9 @@ gst_ogg_pad_event (GstPad * pad, GstEvent * event)
case GST_EVENT_SEEK: case GST_EVENT_SEEK:
{ {
gboolean running; gboolean running;
gboolean flush; gboolean flush, accurate;
GstFormat format; GstFormat format;
gdouble rate;
GstSeekFlags flags; GstSeekFlags flags;
GstSeekType cur_type, stop_type; GstSeekType cur_type, stop_type;
gint64 cur, stop; gint64 cur, stop;
@ -398,23 +413,40 @@ gst_ogg_pad_event (GstPad * pad, GstEvent * event)
* seek query upstream after converting it to bytes using * seek query upstream after converting it to bytes using
* the average bitrate of the stream. */ * the average bitrate of the stream. */
if (!ogg->seekable) { if (!ogg->seekable) {
res = FALSE;
GST_DEBUG ("seek on non seekable stream"); GST_DEBUG ("seek on non seekable stream");
goto done_unref; goto error;
} }
gst_event_parse_seek (event, NULL, &format, &flags,
gst_event_parse_seek (event, &rate, &format, &flags,
&cur_type, &cur, &stop_type, &stop); &cur_type, &cur, &stop_type, &stop);
/* we can only seek on time */ /* we can only seek on time */
if (format != GST_FORMAT_TIME) { if (format != GST_FORMAT_TIME) {
res = FALSE;
GST_DEBUG ("can only seek on TIME"); GST_DEBUG ("can only seek on TIME");
goto done_unref; goto error;
} }
ogg->segment_start = cur; /* cannot yet do backwards playback */
ogg->segment_stop = stop; if (rate <= 0.0) {
GST_DEBUG ("can only seek with positive rate");
goto error;
}
/* store start and stop values */
GST_LOCK (ogg);
if (cur_type == GST_SEEK_TYPE_SET)
ogg->segment_start = cur;
else if (cur_type == GST_SEEK_TYPE_CUR)
ogg->segment_start += cur;
if (stop_type != GST_SEEK_TYPE_NONE)
ogg->segment_stop = stop;
else if (stop_type == GST_SEEK_TYPE_CUR)
ogg->segment_stop += cur;
ogg->segment_rate = rate;
ogg->segment_play = !!(flags & GST_SEEK_FLAG_SEGMENT); ogg->segment_play = !!(flags & GST_SEEK_FLAG_SEGMENT);
flush = !!(flags & GST_SEEK_FLAG_FLUSH); flush = (flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH;
accurate = (flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE;
gst_event_unref (event); gst_event_unref (event);
GST_DEBUG ("segment positions set to %" GST_TIME_FORMAT "-%" GST_DEBUG ("segment positions set to %" GST_TIME_FORMAT "-%"
@ -422,13 +454,12 @@ gst_ogg_pad_event (GstPad * pad, GstEvent * event)
GST_TIME_ARGS (ogg->segment_stop)); GST_TIME_ARGS (ogg->segment_stop));
/* check if we can do the seek now */ /* check if we can do the seek now */
GST_LOCK (ogg);
running = ogg->running; running = ogg->running;
GST_UNLOCK (ogg); GST_UNLOCK (ogg);
/* now do the seek */ /* now do the seek */
if (running) { if (running) {
res = gst_ogg_demux_perform_seek (ogg, flush); res = gst_ogg_demux_perform_seek (ogg, accurate, flush);
} else } else
res = TRUE; res = TRUE;
break; break;
@ -437,13 +468,12 @@ gst_ogg_pad_event (GstPad * pad, GstEvent * event)
res = gst_pad_event_default (pad, event); res = gst_pad_event_default (pad, event);
break; break;
} }
return res; return res;
done_unref: error:
GST_DEBUG ("error handling event"); GST_DEBUG ("error handling event");
gst_event_unref (event); gst_event_unref (event);
return res; return FALSE;
} }
static void static void
@ -454,7 +484,7 @@ gst_ogg_pad_reset (GstOggPad * pad)
} }
/* the filter function for selecting the elements we can use in /* the filter function for selecting the elements we can use in
* * autoplugging */ * autoplugging */
static gboolean static gboolean
gst_ogg_demux_factory_filter (GstPluginFeature * feature, GstCaps * caps) gst_ogg_demux_factory_filter (GstPluginFeature * feature, GstCaps * caps)
{ {
@ -493,18 +523,22 @@ gst_ogg_demux_factory_filter (GstPluginFeature * feature, GstCaps * caps)
/* we only care about the sink templates */ /* we only care about the sink templates */
if (templ->direction == GST_PAD_SINK) { if (templ->direction == GST_PAD_SINK) {
GstCaps *intersect; GstCaps *intersect;
GstCaps *scaps;
gboolean empty;
/* try to intersect the caps with the caps of the template */ /* try to intersect the caps with the caps of the template */
intersect = gst_caps_intersect (caps, scaps = gst_static_caps_get (&templ->static_caps);
gst_static_caps_get (&templ->static_caps)); intersect = gst_caps_intersect (caps, scaps);
gst_caps_unref (scaps);
empty = gst_caps_is_empty (intersect);
gst_caps_unref (intersect);
/* check if the intersection is empty */ /* check if the intersection is empty */
if (!gst_caps_is_empty (intersect)) { if (!empty) {
/* non empty intersection, we can use this element */ /* non empty intersection, we can use this element */
gst_caps_unref (intersect);
goto found; goto found;
} }
gst_caps_unref (intersect);
} }
} }
} }
@ -527,6 +561,9 @@ compare_ranks (GstPluginFeature * f1, GstPluginFeature * f2)
gst_plugin_feature_get_name (f1)); gst_plugin_feature_get_name (f1));
} }
/* function called by the internal decoder elements when it outputs
* a buffer. We use it to get the first timestamp of the stream
*/
static GstFlowReturn static GstFlowReturn
gst_ogg_pad_internal_chain (GstPad * pad, GstBuffer * buffer) gst_ogg_pad_internal_chain (GstPad * pad, GstBuffer * buffer)
{ {
@ -780,9 +817,10 @@ gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet)
GstEvent *event; GstEvent *event;
/* create the discont event we are going to send out */ /* create the discont event we are going to send out */
event = gst_event_new_newsegment (1.0, event = gst_event_new_newsegment (ogg->segment_rate,
GST_FORMAT_TIME, (gint64) chain->start_time - chain->begin_time, GST_FORMAT_TIME,
(gint64) chain->last_time - chain->begin_time, (gint64) 0); chain->segment_start - chain->begin_time,
chain->segment_stop - chain->begin_time, 0);
gst_ogg_demux_activate_chain (ogg, chain, event); gst_ogg_demux_activate_chain (ogg, chain, event);
@ -876,7 +914,7 @@ gst_ogg_chain_new (GstOggDemux * ogg)
chain->have_bos = FALSE; chain->have_bos = FALSE;
chain->streams = g_array_new (FALSE, TRUE, sizeof (GstOggPad *)); chain->streams = g_array_new (FALSE, TRUE, sizeof (GstOggPad *));
chain->begin_time = GST_CLOCK_TIME_NONE; chain->begin_time = GST_CLOCK_TIME_NONE;
chain->start_time = GST_CLOCK_TIME_NONE; chain->segment_start = GST_CLOCK_TIME_NONE;
chain->total_time = GST_CLOCK_TIME_NONE; chain->total_time = GST_CLOCK_TIME_NONE;
return chain; return chain;
@ -1062,6 +1100,7 @@ gst_ogg_demux_init (GstOggDemux * ogg)
ogg->current_granule = -1; ogg->current_granule = -1;
ogg->current_time = 0; ogg->current_time = 0;
ogg->segment_rate = 1.0;
ogg->segment_start = GST_CLOCK_TIME_NONE; ogg->segment_start = GST_CLOCK_TIME_NONE;
ogg->segment_stop = GST_CLOCK_TIME_NONE; ogg->segment_stop = GST_CLOCK_TIME_NONE;
ogg->segment_play = FALSE; ogg->segment_play = FALSE;
@ -1339,7 +1378,8 @@ gst_ogg_demux_activate_chain (GstOggDemux * ogg, GstOggChain * chain,
} }
static gboolean static gboolean
gst_ogg_demux_perform_seek (GstOggDemux * ogg, gboolean flush) gst_ogg_demux_perform_seek (GstOggDemux * ogg, gboolean accurate,
gboolean flush)
{ {
GstOggChain *chain = NULL; GstOggChain *chain = NULL;
gint64 begin, end; gint64 begin, end;
@ -1348,19 +1388,9 @@ gst_ogg_demux_perform_seek (GstOggDemux * ogg, gboolean flush)
gint64 best; gint64 best;
gint64 total; gint64 total;
gint64 result = 0; gint64 result = 0;
gint64 start, stop;
gint i; gint i;
/* nothing configured, play complete file */
if (ogg->segment_start == GST_CLOCK_TIME_NONE)
ogg->segment_start = ogg->start_time;
if (ogg->segment_stop == GST_CLOCK_TIME_NONE)
ogg->segment_stop = ogg->total_time;
ogg->segment_start =
CLAMP (ogg->segment_start, ogg->start_time, ogg->total_time);
ogg->segment_stop =
CLAMP (ogg->segment_stop, ogg->start_time, ogg->total_time);
/* first step is to unlock the streaming thread if it is /* first step is to unlock the streaming thread if it is
* blocked in a chain call, we do this by starting the flush. because * blocked in a chain call, we do this by starting the flush. because
* we cannot yet hold any streaming lock, we have to protect the chains * we cannot yet hold any streaming lock, we have to protect the chains
@ -1391,6 +1421,20 @@ gst_ogg_demux_perform_seek (GstOggDemux * ogg, gboolean flush)
* forever. */ * forever. */
GST_STREAM_LOCK (ogg->sinkpad); GST_STREAM_LOCK (ogg->sinkpad);
GST_LOCK (ogg);
/* nothing configured, play complete file */
if (ogg->segment_start == GST_CLOCK_TIME_NONE)
ogg->segment_start = 0;
if (ogg->segment_stop == GST_CLOCK_TIME_NONE)
ogg->segment_stop = ogg->total_time;
ogg->segment_start = CLAMP (ogg->segment_start, 0, ogg->total_time);
ogg->segment_stop = CLAMP (ogg->segment_stop, 0, ogg->total_time);
start = ogg->segment_start;
stop = ogg->segment_stop;
GST_UNLOCK (ogg);
/* we need to stop flushing on the srcpad as we're going to use it /* we need to stop flushing on the srcpad as we're going to use it
* next. We can do this as we have the STREAM lock now. */ * next. We can do this as we have the STREAM lock now. */
gst_pad_push_event (ogg->sinkpad, gst_event_new_flush_stop ()); gst_pad_push_event (ogg->sinkpad, gst_event_new_flush_stop ());
@ -1417,7 +1461,7 @@ gst_ogg_demux_perform_seek (GstOggDemux * ogg, gboolean flush)
for (i = ogg->chains->len - 1; i >= 0; i--) { for (i = ogg->chains->len - 1; i >= 0; i--) {
chain = g_array_index (ogg->chains, GstOggChain *, i); chain = g_array_index (ogg->chains, GstOggChain *, i);
total -= chain->total_time; total -= chain->total_time;
if (ogg->segment_start >= total) if (start >= total)
break; break;
} }
@ -1425,13 +1469,18 @@ gst_ogg_demux_perform_seek (GstOggDemux * ogg, gboolean flush)
end = chain->end_offset; end = chain->end_offset;
begintime = chain->begin_time; begintime = chain->begin_time;
endtime = chain->begin_time + chain->total_time; endtime = chain->begin_time + chain->total_time;
target = ogg->segment_start - total + begintime; target = start - total + begintime;
if (accurate) {
/* FIXME, seek 4 seconds early to catch keyframes, better implement
* keyframe detection. */
target = target - (gint64) 4 *GST_SECOND;
}
target = MAX (target, 0);
best = begin; best = begin;
GST_DEBUG_OBJECT (ogg, GST_DEBUG_OBJECT (ogg,
"seeking to %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT " in chain %p", "seeking to %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT " in chain %p",
GST_TIME_ARGS (ogg->segment_start), GST_TIME_ARGS (ogg->segment_stop), GST_TIME_ARGS (start), GST_TIME_ARGS (stop), chain);
chain);
GST_DEBUG_OBJECT (ogg, GST_DEBUG_OBJECT (ogg,
"chain offset %" G_GINT64_FORMAT ", end offset %" G_GINT64_FORMAT, begin, "chain offset %" G_GINT64_FORMAT ", end offset %" G_GINT64_FORMAT, begin,
end); end);
@ -1502,6 +1551,8 @@ gst_ogg_demux_perform_seek (GstOggDemux * ogg, gboolean flush)
(gint64 *) & granuletime)) { (gint64 *) & granuletime)) {
g_warning ("could not convert granulepos to time"); g_warning ("could not convert granulepos to time");
granuletime = target; granuletime = target;
} else {
granuletime -= pad->first_time;
} }
GST_DEBUG_OBJECT (ogg, GST_DEBUG_OBJECT (ogg,
@ -1554,8 +1605,8 @@ gst_ogg_demux_perform_seek (GstOggDemux * ogg, gboolean flush)
/* create the discont event we are going to send out */ /* create the discont event we are going to send out */
event = gst_event_new_newsegment (1.0, event = gst_event_new_newsegment (1.0,
GST_FORMAT_TIME, (gint64) ogg->segment_start, GST_FORMAT_TIME,
(gint64) ogg->segment_stop, 0); start + chain->segment_start, stop + chain->segment_start, start);
if (chain != ogg->current_chain) { if (chain != ogg->current_chain) {
/* switch to different chain, send discont on new chain */ /* switch to different chain, send discont on new chain */
@ -1869,8 +1920,8 @@ gst_ogg_demux_collect_chain_info (GstOggDemux * ogg, GstOggChain * chain)
gint i; gint i;
chain->total_time = 0; chain->total_time = 0;
chain->start_time = G_MAXINT64; chain->segment_start = G_MAXINT64;
chain->last_time = 0; chain->segment_stop = 0;
for (i = 0; i < chain->streams->len; i++) { for (i = 0; i < chain->streams->len; i++) {
GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i); GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
@ -1882,13 +1933,13 @@ gst_ogg_demux_collect_chain_info (GstOggDemux * ogg, GstOggChain * chain)
if (pad->last_time != GST_CLOCK_TIME_NONE) { if (pad->last_time != GST_CLOCK_TIME_NONE) {
pad->total_time = pad->last_time - pad->start_time; pad->total_time = pad->last_time - pad->start_time;
chain->total_time = MAX (chain->total_time, pad->total_time); chain->total_time = MAX (chain->total_time, pad->total_time);
chain->last_time = MAX (chain->last_time, pad->last_time); chain->segment_stop = MAX (chain->segment_stop, pad->last_time);
} else { } else {
pad->total_time = GST_CLOCK_TIME_NONE; pad->total_time = GST_CLOCK_TIME_NONE;
chain->total_time = GST_CLOCK_TIME_NONE; chain->total_time = GST_CLOCK_TIME_NONE;
chain->last_time = GST_CLOCK_TIME_NONE; chain->segment_stop = GST_CLOCK_TIME_NONE;
} }
chain->start_time = MIN (chain->start_time, pad->start_time); chain->segment_start = MIN (chain->segment_start, pad->start_time);
} }
return TRUE; return TRUE;
@ -1896,8 +1947,8 @@ gst_ogg_demux_collect_chain_info (GstOggDemux * ogg, GstOggChain * chain)
no_start_time: no_start_time:
{ {
chain->total_time = GST_CLOCK_TIME_NONE; chain->total_time = GST_CLOCK_TIME_NONE;
chain->start_time = GST_CLOCK_TIME_NONE; chain->segment_start = GST_CLOCK_TIME_NONE;
chain->last_time = GST_CLOCK_TIME_NONE; chain->segment_stop = GST_CLOCK_TIME_NONE;
chain->begin_time = GST_CLOCK_TIME_NONE; chain->begin_time = GST_CLOCK_TIME_NONE;
return FALSE; return FALSE;
} }
@ -1909,7 +1960,6 @@ gst_ogg_demux_collect_info (GstOggDemux * ogg)
gint i; gint i;
/* collect all info */ /* collect all info */
ogg->start_time = G_MAXINT64;
ogg->total_time = 0; ogg->total_time = 0;
for (i = 0; i < ogg->chains->len; i++) { for (i = 0; i < ogg->chains->len; i++) {
@ -1919,7 +1969,6 @@ gst_ogg_demux_collect_info (GstOggDemux * ogg)
gst_ogg_demux_collect_chain_info (ogg, chain); gst_ogg_demux_collect_chain_info (ogg, chain);
ogg->start_time = MIN (ogg->start_time, chain->start_time);
ogg->total_time += chain->total_time; ogg->total_time += chain->total_time;
} }
} }
@ -2059,7 +2108,7 @@ gst_ogg_demux_chain (GstPad * pad, GstBuffer * buffer)
GstClockTime duration; GstClockTime duration;
/* this was the duration of the previous chain */ /* this was the duration of the previous chain */
duration = ogg->current_time - current_chain->start_time; duration = ogg->current_time - current_chain->segment_start;
/* the new chain time starts at duration + begin_time */ /* the new chain time starts at duration + begin_time */
chain_time = duration + current_chain->begin_time; chain_time = duration + current_chain->begin_time;
@ -2168,7 +2217,7 @@ gst_ogg_demux_loop (GstOggPad * pad)
GST_UNLOCK (ogg); GST_UNLOCK (ogg);
/* and seek to configured positions without FLUSH */ /* and seek to configured positions without FLUSH */
gst_ogg_demux_perform_seek (ogg, FALSE); gst_ogg_demux_perform_seek (ogg, TRUE, FALSE);
} }
GST_LOG_OBJECT (ogg, "pull data %lld", ogg->offset); GST_LOG_OBJECT (ogg, "pull data %lld", ogg->offset);
@ -2422,10 +2471,9 @@ gst_ogg_print (GstOggDemux * ogg)
{ {
guint j, i; guint j, i;
GST_INFO_OBJECT (ogg, "%u chains, start time: %" GST_TIME_FORMAT, GST_INFO_OBJECT (ogg, "%u chains", ogg->chains->len);
ogg->chains->len, GST_TIME_ARGS (ogg->start_time));
GST_INFO_OBJECT (ogg, " total time: %" GST_TIME_FORMAT, GST_INFO_OBJECT (ogg, " total time: %" GST_TIME_FORMAT,
ogg->chains->len, GST_TIME_ARGS (ogg->total_time)); GST_TIME_ARGS (ogg->total_time));
for (i = 0; i < ogg->chains->len; i++) { for (i = 0; i < ogg->chains->len; i++) {
GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i); GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i);
@ -2433,12 +2481,14 @@ gst_ogg_print (GstOggDemux * ogg)
GST_INFO_OBJECT (ogg, " chain %d (%u streams):", i, chain->streams->len); GST_INFO_OBJECT (ogg, " chain %d (%u streams):", i, chain->streams->len);
GST_INFO_OBJECT (ogg, " offset: %" G_GINT64_FORMAT " - %" G_GINT64_FORMAT, GST_INFO_OBJECT (ogg, " offset: %" G_GINT64_FORMAT " - %" G_GINT64_FORMAT,
chain->offset, chain->end_offset); chain->offset, chain->end_offset);
GST_INFO_OBJECT (ogg, " start time: %" GST_TIME_FORMAT,
GST_TIME_ARGS (chain->start_time));
GST_INFO_OBJECT (ogg, " total time: %" GST_TIME_FORMAT,
GST_TIME_ARGS (chain->total_time));
GST_INFO_OBJECT (ogg, " begin time: %" GST_TIME_FORMAT, GST_INFO_OBJECT (ogg, " begin time: %" GST_TIME_FORMAT,
GST_TIME_ARGS (chain->begin_time)); GST_TIME_ARGS (chain->begin_time));
GST_INFO_OBJECT (ogg, " total time: %" GST_TIME_FORMAT,
GST_TIME_ARGS (chain->total_time));
GST_INFO_OBJECT (ogg, " segment start: %" GST_TIME_FORMAT,
GST_TIME_ARGS (chain->segment_start));
GST_INFO_OBJECT (ogg, " segment stop: %" GST_TIME_FORMAT,
GST_TIME_ARGS (chain->segment_stop));
for (j = 0; j < chain->streams->len; j++) { for (j = 0; j < chain->streams->len; j++) {
GstOggPad *stream = g_array_index (chain->streams, GstOggPad *, j); GstOggPad *stream = g_array_index (chain->streams, GstOggPad *, j);

View file

@ -66,6 +66,11 @@ struct _GstTheoraDec
gboolean crop; gboolean crop;
GList *queued; GList *queued;
gdouble segment_rate;
gint64 segment_start;
gint64 segment_stop;
gint64 segment_base;
}; };
struct _GstTheoraDecClass struct _GstTheoraDecClass
@ -449,6 +454,8 @@ theora_dec_src_query (GstPad * pad, GstQuery * query)
granulepos, &my_format, &time))) granulepos, &my_format, &time)))
goto error; goto error;
time = (time - dec->segment_start) + dec->segment_base;
GST_LOG_OBJECT (dec, GST_LOG_OBJECT (dec,
"query %p: our time: %" GST_TIME_FORMAT, query, GST_TIME_ARGS (time)); "query %p: our time: %" GST_TIME_FORMAT, query, GST_TIME_ARGS (time));
@ -589,7 +596,7 @@ theora_dec_src_getcaps (GstPad * pad)
static gboolean static gboolean
theora_dec_sink_event (GstPad * pad, GstEvent * event) theora_dec_sink_event (GstPad * pad, GstEvent * event)
{ {
gboolean ret = TRUE; gboolean ret = FALSE;
GstTheoraDec *dec; GstTheoraDec *dec;
dec = GST_THEORA_DEC (gst_pad_get_parent (pad)); dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
@ -602,20 +609,56 @@ theora_dec_sink_event (GstPad * pad, GstEvent * event)
GST_STREAM_UNLOCK (pad); GST_STREAM_UNLOCK (pad);
break; break;
case GST_EVENT_NEWSEGMENT: case GST_EVENT_NEWSEGMENT:
{
GstFormat format;
gdouble rate;
gint64 start, stop, base;
GST_STREAM_LOCK (pad); GST_STREAM_LOCK (pad);
gst_event_parse_newsegment (event, &rate, &format, &start, &stop, &base);
/* we need TIME and a positive rate */
if (format != GST_FORMAT_TIME)
goto newseg_wrong_format;
if (rate <= 0.0)
goto newseg_wrong_rate;
/* now copy over the values */
dec->segment_rate = rate;
dec->segment_start = start;
dec->segment_stop = stop;
dec->segment_base = base;
dec->need_keyframe = TRUE; dec->need_keyframe = TRUE;
dec->granulepos = -1; dec->granulepos = -1;
dec->last_timestamp = -1; dec->last_timestamp = -1;
ret = gst_pad_push_event (dec->srcpad, event); ret = gst_pad_push_event (dec->srcpad, event);
GST_STREAM_UNLOCK (pad); GST_STREAM_UNLOCK (pad);
break; break;
}
default: default:
ret = gst_pad_push_event (dec->srcpad, event); ret = gst_pad_push_event (dec->srcpad, event);
break; break;
} }
done:
gst_object_unref (dec); gst_object_unref (dec);
return ret; return ret;
/* ERRORS */
newseg_wrong_format:
{
GST_STREAM_UNLOCK (pad);
GST_DEBUG ("received non TIME newsegment");
goto done;
}
newseg_wrong_rate:
{
GST_STREAM_UNLOCK (pad);
GST_DEBUG ("negative rates not supported yet");
goto done;
}
} }
#define ROUND_UP_2(x) (((x) + 1) & ~1) #define ROUND_UP_2(x) (((x) + 1) & ~1)

View file

@ -271,6 +271,8 @@ vorbis_dec_src_query (GstPad * pad, GstQuery * query)
&value))) &value)))
goto error; goto error;
value = (value - dec->segment_start) + dec->segment_base;
gst_query_set_position (query, format, value, total); gst_query_set_position (query, format, value, total);
GST_LOG_OBJECT (dec, GST_LOG_OBJECT (dec,
@ -368,7 +370,7 @@ vorbis_dec_src_event (GstPad * pad, GstEvent * event)
real_seek = gst_event_new_seek (rate, GST_FORMAT_TIME, real_seek = gst_event_new_seek (rate, GST_FORMAT_TIME,
flags, cur_type, tcur, stop_type, tstop); flags, cur_type, tcur, stop_type, tstop);
res = gst_pad_send_event (GST_PAD_PEER (dec->sinkpad), real_seek); res = gst_pad_push_event (dec->sinkpad, real_seek);
gst_event_unref (event); gst_event_unref (event);
break; break;
@ -388,7 +390,7 @@ error:
static gboolean static gboolean
vorbis_dec_sink_event (GstPad * pad, GstEvent * event) vorbis_dec_sink_event (GstPad * pad, GstEvent * event)
{ {
gboolean ret = TRUE; gboolean ret = FALSE;
GstVorbisDec *dec; GstVorbisDec *dec;
dec = GST_VORBIS_DEC (gst_pad_get_parent (pad)); dec = GST_VORBIS_DEC (gst_pad_get_parent (pad));
@ -401,7 +403,26 @@ vorbis_dec_sink_event (GstPad * pad, GstEvent * event)
GST_STREAM_UNLOCK (pad); GST_STREAM_UNLOCK (pad);
break; break;
case GST_EVENT_NEWSEGMENT: case GST_EVENT_NEWSEGMENT:
{
GstFormat format;
gdouble rate;
gint64 start, stop, base;
GST_STREAM_LOCK (pad); GST_STREAM_LOCK (pad);
gst_event_parse_newsegment (event, &rate, &format, &start, &stop, &base);
if (format != GST_FORMAT_TIME)
goto newseg_wrong_format;
if (rate <= 0.0)
goto newseg_wrong_rate;
/* now copy over the values */
dec->segment_rate = rate;
dec->segment_start = start;
dec->segment_stop = stop;
dec->segment_base = base;
dec->granulepos = -1; dec->granulepos = -1;
#ifdef HAVE_VORBIS_SYNTHESIS_RESTART #ifdef HAVE_VORBIS_SYNTHESIS_RESTART
vorbis_synthesis_restart (&dec->vd); vorbis_synthesis_restart (&dec->vd);
@ -409,13 +430,29 @@ vorbis_dec_sink_event (GstPad * pad, GstEvent * event)
ret = gst_pad_push_event (dec->srcpad, event); ret = gst_pad_push_event (dec->srcpad, event);
GST_STREAM_UNLOCK (pad); GST_STREAM_UNLOCK (pad);
break; break;
}
default: default:
ret = gst_pad_push_event (dec->srcpad, event); ret = gst_pad_push_event (dec->srcpad, event);
break; break;
} }
done:
gst_object_unref (dec); gst_object_unref (dec);
return ret; return ret;
/* ERRORS */
newseg_wrong_format:
{
GST_STREAM_UNLOCK (pad);
GST_DEBUG ("received non TIME newsegment");
goto done;
}
newseg_wrong_rate:
{
GST_STREAM_UNLOCK (pad);
GST_DEBUG ("negative rates not supported yet");
goto done;
}
} }
static GstFlowReturn static GstFlowReturn

View file

@ -58,6 +58,11 @@ struct _GstVorbisDec {
gboolean initialized; gboolean initialized;
GList *queued; GList *queued;
gdouble segment_rate;
gint64 segment_start;
gint64 segment_stop;
gint64 segment_base;
}; };
struct _GstVorbisDecClass { struct _GstVorbisDecClass {

View file

@ -292,6 +292,7 @@ gst_base_audio_sink_event (GstBaseSink * bsink, GstEvent * event)
switch (GST_EVENT_TYPE (event)) { switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_FLUSH_START: case GST_EVENT_FLUSH_START:
gst_ring_buffer_pause (sink->ringbuffer); gst_ring_buffer_pause (sink->ringbuffer);
gst_ring_buffer_clear_all (sink->ringbuffer);
break; break;
case GST_EVENT_FLUSH_STOP: case GST_EVENT_FLUSH_STOP:
break; break;
@ -342,11 +343,11 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
time = GST_BUFFER_TIMESTAMP (buf); time = GST_BUFFER_TIMESTAMP (buf);
GST_DEBUG ("time %" GST_TIME_FORMAT ", offset %llu, start %" GST_TIME_FORMAT, GST_DEBUG ("time %" GST_TIME_FORMAT ", offset %llu, start %" GST_TIME_FORMAT,
GST_TIME_ARGS (time), in_offset, GST_TIME_ARGS (bsink->discont_start)); GST_TIME_ARGS (time), in_offset, GST_TIME_ARGS (bsink->segment_start));
render_diff = time - bsink->discont_start; render_diff = time - bsink->segment_start;
/* samples should be rendered based on their timestamp. All samples /* samples should be rendered based on their timestamp. All samples
* arriving before the discont_start are to be thrown away */ * arriving before the segment_start are to be thrown away */
/* FIXME, for now we drop the sample completely, we should /* FIXME, for now we drop the sample completely, we should
* in fact clip the sample. Same for the segment_stop, actually. */ * in fact clip the sample. Same for the segment_stop, actually. */
if (render_diff < 0) if (render_diff < 0)

View file

@ -1195,7 +1195,6 @@ gst_ximagesink_get_times (GstBaseSink * bsink, GstBuffer * buf,
if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
*start = GST_BUFFER_TIMESTAMP (buf); *start = GST_BUFFER_TIMESTAMP (buf);
*start -= bsink->discont_start;
if (GST_BUFFER_DURATION_IS_VALID (buf)) { if (GST_BUFFER_DURATION_IS_VALID (buf)) {
*end = *start + GST_BUFFER_DURATION (buf); *end = *start + GST_BUFFER_DURATION (buf);
} else { } else {

View file

@ -1496,7 +1496,6 @@ gst_xvimagesink_get_times (GstBaseSink * bsink, GstBuffer * buf,
if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
*start = GST_BUFFER_TIMESTAMP (buf); *start = GST_BUFFER_TIMESTAMP (buf);
*start -= bsink->discont_start;
if (GST_BUFFER_DURATION_IS_VALID (buf)) { if (GST_BUFFER_DURATION_IS_VALID (buf)) {
*end = *start + GST_BUFFER_DURATION (buf); *end = *start + GST_BUFFER_DURATION (buf);
} else { } else {