ext/ogg/gstoggdemux.c: Use GstSegment infrastructure to remove duplicated code and handle more seek cases correctly.

Original commit message from CVS:
* ext/ogg/gstoggdemux.c: (gst_ogg_demux_receive_event),
(gst_ogg_pad_event), (gst_ogg_pad_internal_chain),
(gst_ogg_demux_chain_peer), (gst_ogg_pad_submit_packet),
(gst_ogg_demux_deactivate_current_chain),
(gst_ogg_demux_activate_chain), (gst_ogg_demux_do_seek),
(gst_ogg_demux_perform_seek), (gst_ogg_demux_collect_info),
(gst_ogg_demux_find_chains), (gst_ogg_demux_chain),
(gst_ogg_demux_loop), (gst_ogg_demux_change_state):
Use GstSegment infrastructure to remove duplicated code
and handle more seek cases correctly.
This commit is contained in:
Wim Taymans 2006-02-28 11:04:47 +00:00
parent b4f055fe0f
commit 833af598fc
2 changed files with 209 additions and 271 deletions

View file

@ -1,3 +1,16 @@
2006-02-28 Wim Taymans <wim@fluendo.com>
* ext/ogg/gstoggdemux.c: (gst_ogg_demux_receive_event),
(gst_ogg_pad_event), (gst_ogg_pad_internal_chain),
(gst_ogg_demux_chain_peer), (gst_ogg_pad_submit_packet),
(gst_ogg_demux_deactivate_current_chain),
(gst_ogg_demux_activate_chain), (gst_ogg_demux_do_seek),
(gst_ogg_demux_perform_seek), (gst_ogg_demux_collect_info),
(gst_ogg_demux_find_chains), (gst_ogg_demux_chain),
(gst_ogg_demux_loop), (gst_ogg_demux_change_state):
Use GstSegment infrastructure to remove duplicated code
and handle more seek cases correctly.
2006-02-28 Wim Taymans <wim@fluendo.com> 2006-02-28 Wim Taymans <wim@fluendo.com>
* gst/ffmpegcolorspace/gstffmpegcolorspace.c: * gst/ffmpegcolorspace/gstffmpegcolorspace.c:

View file

@ -160,19 +160,18 @@ 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 total_time; /* the total time of this ogg, this is the sum of GstClockTime total_time;
the totals of all chains */
GstOggChain *current_chain; GstOggChain *current_chain;
GstOggChain *building_chain; GstOggChain *building_chain;
/* playback start/stop positions */ /* playback start/stop positions */
gdouble segment_rate; GstSegment segment;
GstSeekFlags segment_flags; gboolean segment_running;
GstClockTime segment_start;
GstClockTime segment_stop; GstEvent *event;
gint64 current_granule; gint64 current_granule;
GstClockTime current_time;
/* annodex stuff */ /* annodex stuff */
gboolean have_fishead; gboolean have_fishead;
@ -198,9 +197,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_configure_segment (GstOggDemux * ogg, static gboolean gst_ogg_demux_perform_seek (GstOggDemux * ogg,
GstEvent * event, gboolean * running); GstEvent * event);
static gboolean gst_ogg_demux_perform_seek (GstOggDemux * ogg);
static gboolean gst_ogg_demux_receive_event (GstElement * element, static gboolean gst_ogg_demux_receive_event (GstElement * element,
GstEvent * event); GstEvent * event);
@ -419,8 +417,6 @@ gst_ogg_demux_receive_event (GstElement * element, GstEvent * event)
switch (GST_EVENT_TYPE (event)) { switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEEK: case GST_EVENT_SEEK:
{ {
gboolean running;
/* can't seek if we are not seekable, FIXME could pass the /* can't seek if we are not seekable, FIXME could pass the
* 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. */
@ -429,16 +425,8 @@ gst_ogg_demux_receive_event (GstElement * element, GstEvent * event)
goto error; goto error;
} }
if (!gst_ogg_demux_configure_segment (ogg, event, &running)) {
GST_DEBUG ("configure segment failed");
goto error;
}
/* now do the seek */ /* now do the seek */
if (running) { res = gst_ogg_demux_perform_seek (ogg, event);
res = gst_ogg_demux_perform_seek (ogg);
} else
res = TRUE;
break; break;
} }
@ -469,8 +457,6 @@ gst_ogg_pad_event (GstPad * pad, GstEvent * event)
switch (GST_EVENT_TYPE (event)) { switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEEK: case GST_EVENT_SEEK:
{ {
gboolean running;
/* can't seek if we are not seekable, FIXME could pass the /* can't seek if we are not seekable, FIXME could pass the
* 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. */
@ -479,16 +465,8 @@ gst_ogg_pad_event (GstPad * pad, GstEvent * event)
goto error; goto error;
} }
if (!gst_ogg_demux_configure_segment (ogg, event, &running)) {
GST_DEBUG ("configure segment failed");
goto error;
}
/* now do the seek */ /* now do the seek */
if (running) { res = gst_ogg_demux_perform_seek (ogg, event);
res = gst_ogg_demux_perform_seek (ogg);
} else
res = TRUE;
break; break;
} }
default: default:
@ -497,10 +475,13 @@ gst_ogg_pad_event (GstPad * pad, GstEvent * event)
} }
return res; return res;
/* ERRORS */
error: error:
GST_DEBUG ("error handling event"); {
gst_event_unref (event); GST_DEBUG ("error handling event");
return FALSE; gst_event_unref (event);
return FALSE;
}
} }
static void static void
@ -744,7 +725,6 @@ gst_ogg_pad_internal_chain (GstPad * pad, GstBuffer * buffer)
if (oggpad->start_time == GST_CLOCK_TIME_NONE) { if (oggpad->start_time == GST_CLOCK_TIME_NONE) {
oggpad->start_time = timestamp; oggpad->start_time = timestamp;
ogg->current_time = timestamp;
} }
gst_buffer_unref (buffer); gst_buffer_unref (buffer);
@ -945,17 +925,20 @@ gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet)
if (packet->granulepos >= 0) { if (packet->granulepos >= 0) {
GstFormat format; GstFormat format;
gint64 current_time;
ogg->current_granule = packet->granulepos; ogg->current_granule = packet->granulepos;
format = GST_FORMAT_TIME; format = GST_FORMAT_TIME;
if (!pad->is_skeleton) { if (!pad->is_skeleton) {
if (!gst_ogg_pad_query_convert (pad, if (!gst_ogg_pad_query_convert (pad,
GST_FORMAT_DEFAULT, packet->granulepos, &format, GST_FORMAT_DEFAULT, packet->granulepos, &format,
(gint64 *) & ogg->current_time)) { (gint64 *) & current_time)) {
GST_WARNING_OBJECT (ogg, "could not convert granulepos to time"); GST_WARNING_OBJECT (ogg, "could not convert granulepos to time");
} else { } else {
gst_segment_set_last_stop (&ogg->segment, GST_FORMAT_TIME,
current_time);
GST_DEBUG ("ogg current time %" GST_TIME_FORMAT, GST_DEBUG ("ogg current time %" GST_TIME_FORMAT,
GST_TIME_ARGS (ogg->current_time)); GST_TIME_ARGS (current_time));
} }
} }
} }
@ -1050,8 +1033,8 @@ gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet)
GST_DEBUG ("segment_stop: %" GST_TIME_FORMAT, GST_DEBUG ("segment_stop: %" GST_TIME_FORMAT,
GST_TIME_ARGS (segment_stop)); GST_TIME_ARGS (segment_stop));
/* create the discont event we are going to send out */ /* create the newsegment event we are going to send out */
event = gst_event_new_new_segment (FALSE, ogg->segment_rate, event = gst_event_new_new_segment (FALSE, ogg->segment.rate,
GST_FORMAT_TIME, segment_start, segment_stop, 0); GST_FORMAT_TIME, segment_start, segment_stop, 0);
gst_ogg_demux_activate_chain (ogg, chain, event); gst_ogg_demux_activate_chain (ogg, chain, event);
@ -1541,10 +1524,14 @@ gst_ogg_demux_deactivate_current_chain (GstOggDemux * ogg)
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);
gst_pad_push_event (GST_PAD (pad), gst_event_new_eos ()); gst_pad_push_event (GST_PAD_CAST (pad), gst_event_new_eos ());
GST_DEBUG_OBJECT (ogg, "removing pad %" GST_PTR_FORMAT, pad); GST_DEBUG_OBJECT (ogg, "removing pad %" GST_PTR_FORMAT, pad);
gst_element_remove_pad (GST_ELEMENT (ogg), GST_PAD (pad));
/* deactivate first */
gst_pad_set_active (GST_PAD_CAST (pad), FALSE);
gst_element_remove_pad (GST_ELEMENT (ogg), GST_PAD_CAST (pad));
} }
/* if we cannot seek back to the chain, we can destroy the chain /* if we cannot seek back to the chain, we can destroy the chain
* completely */ * completely */
@ -1579,7 +1566,10 @@ gst_ogg_demux_activate_chain (GstOggDemux * ogg, GstOggChain * chain,
pad = g_array_index (chain->streams, GstOggPad *, i); pad = g_array_index (chain->streams, GstOggPad *, i);
GST_DEBUG_OBJECT (ogg, "adding pad %" GST_PTR_FORMAT, pad); GST_DEBUG_OBJECT (ogg, "adding pad %" GST_PTR_FORMAT, pad);
gst_element_add_pad (GST_ELEMENT (ogg), GST_PAD (pad)); /* activate first */
gst_pad_set_active (GST_PAD_CAST (pad), TRUE);
gst_element_add_pad (GST_ELEMENT (ogg), GST_PAD_CAST (pad));
} }
gst_element_no_more_pads (GST_ELEMENT (ogg)); gst_element_no_more_pads (GST_ELEMENT (ogg));
@ -1610,197 +1600,22 @@ gst_ogg_demux_activate_chain (GstOggDemux * ogg, GstOggChain * chain,
return TRUE; return TRUE;
} }
/*
* do seek to time @position, return FALSE or chain and TRUE
*/
static gboolean static gboolean
gst_ogg_demux_configure_segment (GstOggDemux * ogg, GstEvent * event, gst_ogg_demux_do_seek (GstOggDemux * ogg, gint64 position, gboolean accurate,
gboolean * running) GstOggChain ** rchain)
{
GstFormat format;
gdouble rate;
GstSeekFlags flags;
GstSeekType cur_type, stop_type;
gint64 cur, stop;
gboolean update_start, update_stop;
gst_event_parse_seek (event, &rate, &format, &flags,
&cur_type, &cur, &stop_type, &stop);
/* we can only seek on time */
if (format != GST_FORMAT_TIME) {
GST_DEBUG ("can only seek on TIME");
goto error;
}
/* cannot yet do backwards playback */
if (rate <= 0.0) {
GST_DEBUG ("can only seek with positive rate, not %lf", rate);
goto error;
}
/* 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 = ogg->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 = ogg->segment_start + cur;
break;
case GST_SEEK_TYPE_END:
/* add cur to total length */
cur = ogg->total_time + cur;
break;
}
/* bring in sane range */
if (ogg->total_time != -1)
cur = CLAMP (cur, 0, ogg->total_time);
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 = ogg->segment_stop;
update_stop = FALSE;
break;
case GST_SEEK_TYPE_SET:
/* stop folds required value */
break;
case GST_SEEK_TYPE_CUR:
if (ogg->segment_stop != -1)
stop = ogg->segment_stop + stop;
else
stop = -1;
break;
case GST_SEEK_TYPE_END:
if (ogg->total_time != -1)
stop = ogg->total_time + stop;
else
stop = -1;
break;
}
/* if we have a valid stop time, make sure it is clipped */
if (stop != -1) {
if (ogg->total_time != -1)
stop = CLAMP (stop, 0, ogg->total_time);
else
stop = MAX (stop, 0);
}
/* store start and stop values */
GST_OBJECT_LOCK (ogg);
ogg->segment_rate = rate;
ogg->segment_flags = flags;
ogg->segment_start = cur;
ogg->segment_stop = stop;
GST_DEBUG ("segment positions set to %" GST_TIME_FORMAT "-%"
GST_TIME_FORMAT, GST_TIME_ARGS (ogg->segment_start),
GST_TIME_ARGS (ogg->segment_stop));
/* check if we can do the seek now */
if (running)
*running = ogg->running;
GST_OBJECT_UNLOCK (ogg);
return TRUE;
/* ERRORS */
error:
{
return FALSE;
}
}
static gboolean
gst_ogg_demux_perform_seek (GstOggDemux * ogg)
{ {
GstOggChain *chain = NULL; GstOggChain *chain = NULL;
gboolean flush, accurate;
gint64 begin, end; gint64 begin, end;
gint64 begintime, endtime; gint64 begintime, endtime;
gint64 target; gint64 target;
gint64 best; gint64 best;
gint64 total; gint64 total;
gint64 result = 0; gint64 result = 0;
gint64 start, stop;
gint i; gint i;
flush = ogg->segment_flags & GST_SEEK_FLAG_FLUSH;
accurate = ogg->segment_flags & GST_SEEK_FLAG_ACCURATE;
/* first step is to unlock the streaming thread if it is
* 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
* with their own lock. */
if (flush) {
gint i;
gst_pad_push_event (ogg->sinkpad, gst_event_new_flush_start ());
GST_CHAIN_LOCK (ogg);
for (i = 0; i < ogg->chains->len; i++) {
GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i);
gint j;
for (j = 0; j < chain->streams->len; j++) {
GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, j);
gst_pad_push_event (GST_PAD (pad), gst_event_new_flush_start ());
}
}
GST_CHAIN_UNLOCK (ogg);
} else {
gst_pad_pause_task (ogg->sinkpad);
}
/* now grab the stream lock so that streaming cannot continue, for
* non flushing seeks when the element is in PAUSED this could block
* forever. */
GST_PAD_STREAM_LOCK (ogg->sinkpad);
GST_OBJECT_LOCK (ogg);
/* nothing configured, play complete file */
if (ogg->segment_start == GST_CLOCK_TIME_NONE)
start = 0;
else
start = CLAMP (ogg->segment_start, 0, ogg->total_time);
if (ogg->segment_stop == GST_CLOCK_TIME_NONE)
stop = ogg->total_time;
else
stop = CLAMP (ogg->segment_stop, 0, ogg->total_time);
GST_OBJECT_UNLOCK (ogg);
/* 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. */
gst_pad_push_event (ogg->sinkpad, gst_event_new_flush_stop ());
{
gint i;
/* reset all ogg streams now, need to do this from within the lock to
* make sure the streaming thread is not messing with the stream */
for (i = 0; i < ogg->chains->len; i++) {
GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i);
gint j;
for (j = 0; j < chain->streams->len; j++) {
GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, j);
ogg_stream_reset (&pad->stream);
}
}
}
/* first find the chain to search in */ /* first find the chain to search in */
total = ogg->total_time; total = ogg->total_time;
if (ogg->chains->len == 0) if (ogg->chains->len == 0)
@ -1809,7 +1624,7 @@ gst_ogg_demux_perform_seek (GstOggDemux * ogg)
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 (start >= total) if (position >= total)
break; break;
} }
@ -1817,7 +1632,7 @@ gst_ogg_demux_perform_seek (GstOggDemux * ogg)
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 = start - total + begintime; target = position - total + begintime;
if (accurate) { if (accurate) {
/* FIXME, seek 4 seconds early to catch keyframes, better implement /* FIXME, seek 4 seconds early to catch keyframes, better implement
* keyframe detection. */ * keyframe detection. */
@ -1827,8 +1642,8 @@ gst_ogg_demux_perform_seek (GstOggDemux * ogg)
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 " in chain %p",
GST_TIME_ARGS (start), GST_TIME_ARGS (stop), chain); GST_TIME_ARGS (position), 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);
@ -1941,31 +1756,147 @@ gst_ogg_demux_perform_seek (GstOggDemux * ogg)
} }
ogg->offset = best; ogg->offset = best;
*rchain = chain;
/* current time starts from 0 again after a flush */ return TRUE;
if (flush)
ogg->current_time = 0; no_chains:
{
GST_DEBUG_OBJECT (ogg, "no chains");
return FALSE;
}
seek_error:
{
GST_DEBUG_OBJECT (ogg, "got a seek error");
return FALSE;
}
}
static gboolean
gst_ogg_demux_perform_seek (GstOggDemux * ogg, GstEvent * event)
{
GstOggChain *chain = NULL;
gboolean res;
gboolean flush, accurate;
GstFormat format;
gdouble rate;
GstSeekFlags flags;
GstSeekType cur_type, stop_type;
gint64 cur, stop;
gboolean update;
if (event) {
gst_event_parse_seek (event, &rate, &format, &flags,
&cur_type, &cur, &stop_type, &stop);
/* we can only seek on time */
if (format != GST_FORMAT_TIME) {
GST_DEBUG_OBJECT (ogg, "can only seek on TIME");
goto error;
}
/* cannot yet do backwards playback */
if (rate <= 0.0) {
GST_DEBUG_OBJECT (ogg, "can only seek with positive rate, not %lf", rate);
goto error;
}
} else {
flags = 0;
}
GST_DEBUG_OBJECT (ogg, "seek, rate %g", rate);
flush = flags & GST_SEEK_FLAG_FLUSH;
accurate = flags & GST_SEEK_FLAG_ACCURATE;
/* first step is to unlock the streaming thread if it is
* 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
* with their own lock. */
if (flush) {
gint i;
gst_pad_push_event (ogg->sinkpad, gst_event_new_flush_start ());
GST_CHAIN_LOCK (ogg);
for (i = 0; i < ogg->chains->len; i++) {
GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i);
gint j;
for (j = 0; j < chain->streams->len; j++) {
GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, j);
gst_pad_push_event (GST_PAD (pad), gst_event_new_flush_start ());
}
}
GST_CHAIN_UNLOCK (ogg);
} else {
gst_pad_pause_task (ogg->sinkpad);
}
/* now grab the stream lock so that streaming cannot continue, for
* non flushing seeks when the element is in PAUSED this could block
* forever. */
GST_PAD_STREAM_LOCK (ogg->sinkpad);
if (ogg->segment_running && !flush) {
GstEvent *newseg;
/* create the discont event to close the current segment */
newseg = gst_event_new_new_segment (TRUE, ogg->segment.rate,
GST_FORMAT_TIME, ogg->segment.start, ogg->segment.last_stop,
ogg->segment.start);
/* send discont on old chain */
gst_ogg_demux_send_event (ogg, newseg);
}
if (event) {
gst_segment_set_seek (&ogg->segment, rate, format, flags,
cur_type, cur, stop_type, stop, &update);
}
GST_DEBUG ("segment positions set to %" GST_TIME_FORMAT "-%"
GST_TIME_FORMAT, GST_TIME_ARGS (ogg->segment.start),
GST_TIME_ARGS (ogg->segment.stop));
/* 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. */
gst_pad_push_event (ogg->sinkpad, gst_event_new_flush_stop ());
{
gint i;
/* reset all ogg streams now, need to do this from within the lock to
* make sure the streaming thread is not messing with the stream */
for (i = 0; i < ogg->chains->len; i++) {
GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i);
gint j;
for (j = 0; j < chain->streams->len; j++) {
GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, j);
ogg_stream_reset (&pad->stream);
}
}
}
res = gst_ogg_demux_do_seek (ogg, ogg->segment.last_stop, accurate, &chain);
/* now we have a new position, prepare for streaming again */ /* now we have a new position, prepare for streaming again */
{ {
GstEvent *event; GstEvent *event;
gint64 start_value = start + chain->segment_start; gint64 stop;
gint64 stop_value;
if (start_value == GST_CLOCK_TIME_NONE)
start_value = 0;
if (chain->segment_start == GST_CLOCK_TIME_NONE)
stop_value = GST_CLOCK_TIME_NONE;
else
stop_value = stop + chain->segment_start;
/* we have to send the flush to the old chain, not the new one */ /* we have to send the flush to the old chain, not the new one */
if (flush) if (flush)
gst_ogg_demux_send_event (ogg, gst_event_new_flush_stop ()); gst_ogg_demux_send_event (ogg, gst_event_new_flush_stop ());
if ((stop = ogg->segment.stop) == -1)
stop = ogg->segment.duration;
/* create the discont event we are going to send out */ /* create the discont event we are going to send out */
event = gst_event_new_new_segment (FALSE, 1.0, event = gst_event_new_new_segment (FALSE, ogg->segment.rate,
GST_FORMAT_TIME, start_value, stop_value, start); ogg->segment.format, ogg->segment.last_stop, stop, ogg->segment.time);
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 */
@ -1976,11 +1907,13 @@ gst_ogg_demux_perform_seek (GstOggDemux * ogg)
} }
/* notify start of new segment */ /* notify start of new segment */
if (ogg->segment_flags & GST_SEEK_FLAG_SEGMENT) { if (ogg->segment.flags & GST_SEEK_FLAG_SEGMENT) {
gst_element_post_message (GST_ELEMENT (ogg), gst_element_post_message (GST_ELEMENT (ogg),
gst_message_new_segment_start (GST_OBJECT (ogg), GST_FORMAT_TIME, gst_message_new_segment_start (GST_OBJECT (ogg),
start)); GST_FORMAT_TIME, ogg->segment.last_stop));
} }
ogg->segment_running = TRUE;
/* restart our task since it might have been stopped when we did the /* restart our task since it might have been stopped when we did the
* flush. */ * flush. */
gst_pad_start_task (ogg->sinkpad, (GstTaskFunction) gst_ogg_demux_loop, gst_pad_start_task (ogg->sinkpad, (GstTaskFunction) gst_ogg_demux_loop,
@ -1992,18 +1925,9 @@ gst_ogg_demux_perform_seek (GstOggDemux * ogg)
return TRUE; return TRUE;
no_chains: error:
{ {
GST_DEBUG_OBJECT (ogg, "no chains"); GST_DEBUG_OBJECT (ogg, "seek failed");
GST_PAD_STREAM_UNLOCK (ogg->sinkpad);
return FALSE;
}
seek_error:
{
GST_DEBUG_OBJECT (ogg, "got a seek error");
GST_PAD_STREAM_UNLOCK (ogg->sinkpad);
return FALSE; return FALSE;
} }
} }
@ -2370,6 +2294,7 @@ gst_ogg_demux_collect_info (GstOggDemux * ogg)
ogg->total_time += chain->total_time; ogg->total_time += chain->total_time;
} }
gst_segment_set_duration (&ogg->segment, GST_FORMAT_TIME, ogg->total_time);
} }
/* find all the chains in the ogg file, this reads the first and /* find all the chains in the ogg file, this reads the first and
@ -2394,7 +2319,7 @@ gst_ogg_demux_find_chains (GstOggDemux * ogg)
format = GST_FORMAT_BYTES; format = GST_FORMAT_BYTES;
res = gst_pad_query_duration (peer, &format, &ogg->length); res = gst_pad_query_duration (peer, &format, &ogg->length);
gst_object_unref (peer); gst_object_unref (peer);
if (!res) if (!res || ogg->length <= 0)
goto no_length; goto no_length;
GST_DEBUG ("file length %lld", ogg->length); GST_DEBUG ("file length %lld", ogg->length);
@ -2497,17 +2422,20 @@ gst_ogg_demux_chain (GstPad * pad, GstBuffer * buffer)
} else { } else {
GstClockTime chain_time; GstClockTime chain_time;
GstOggChain *current_chain; GstOggChain *current_chain;
gint64 current_time;
/* this can only happen in non-seekabe mode */ /* this can only happen in non-seekabe mode */
if (ogg->seekable) if (ogg->seekable)
goto unknown_chain; goto unknown_chain;
current_chain = ogg->current_chain; current_chain = ogg->current_chain;
current_time = ogg->segment.last_stop;
if (current_chain) { if (current_chain) {
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->segment_start; duration = 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;
@ -2515,7 +2443,7 @@ gst_ogg_demux_chain (GstPad * pad, GstBuffer * buffer)
gst_ogg_demux_deactivate_current_chain (ogg); gst_ogg_demux_deactivate_current_chain (ogg);
} else { } else {
/* non previous chain, start at configured current time */ /* non previous chain, start at configured current time */
chain_time = ogg->current_time; chain_time = current_time;
} }
if (ogg->building_chain == NULL) { if (ogg->building_chain == NULL) {
GstOggChain *newchain; GstOggChain *newchain;
@ -2597,6 +2525,7 @@ gst_ogg_demux_loop (GstOggPad * pad)
GstOggDemux *ogg; GstOggDemux *ogg;
GstFlowReturn ret; GstFlowReturn ret;
GstBuffer *buffer; GstBuffer *buffer;
GstEvent *event;
ogg = GST_OGG_DEMUX (GST_OBJECT_PARENT (pad)); ogg = GST_OGG_DEMUX (GST_OBJECT_PARENT (pad));
@ -2614,10 +2543,12 @@ gst_ogg_demux_loop (GstOggPad * pad)
GST_OBJECT_LOCK (ogg); GST_OBJECT_LOCK (ogg);
ogg->running = TRUE; ogg->running = TRUE;
event = ogg->event;
ogg->event = NULL;
GST_OBJECT_UNLOCK (ogg); GST_OBJECT_UNLOCK (ogg);
/* and seek to configured positions without FLUSH */ /* and seek to configured positions without FLUSH */
gst_ogg_demux_perform_seek (ogg); gst_ogg_demux_perform_seek (ogg, event);
} }
GST_LOG_OBJECT (ogg, "pull data %lld", ogg->offset); GST_LOG_OBJECT (ogg, "pull data %lld", ogg->offset);
@ -2627,7 +2558,8 @@ gst_ogg_demux_loop (GstOggPad * pad)
* pushing out EOS. */ * pushing out EOS. */
/* FIXME, need to be done somewhere else where we /* FIXME, need to be done somewhere else where we
* can check against segment_stop time. */ * can check against segment_stop time. */
if (ogg->segment_flags & GST_SEEK_FLAG_SEGMENT) { ogg->segment_running = FALSE;
if (ogg->segment.flags & GST_SEEK_FLAG_SEGMENT) {
GST_LOG_OBJECT (ogg, "Sending segment done, at end of segment"); GST_LOG_OBJECT (ogg, "Sending segment done, at end of segment");
gst_element_post_message (GST_ELEMENT (ogg), gst_element_post_message (GST_ELEMENT (ogg),
gst_message_new_segment_done (GST_OBJECT (ogg), GST_FORMAT_TIME, gst_message_new_segment_done (GST_OBJECT (ogg), GST_FORMAT_TIME,
@ -2754,20 +2686,16 @@ gst_ogg_demux_change_state (GstElement * element, GstStateChange transition)
switch (transition) { switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY: case GST_STATE_CHANGE_NULL_TO_READY:
ogg->segment_rate = 1.0;
ogg->segment_flags = GST_SEEK_FLAG_NONE;
ogg->segment_start = GST_CLOCK_TIME_NONE;
ogg->segment_stop = GST_CLOCK_TIME_NONE;
ogg->total_time = GST_CLOCK_TIME_NONE;
ogg->basetime = 0; ogg->basetime = 0;
ogg->have_fishead = FALSE; ogg->have_fishead = FALSE;
ogg->running = FALSE;
ogg_sync_init (&ogg->sync); ogg_sync_init (&ogg->sync);
break; break;
case GST_STATE_CHANGE_READY_TO_PAUSED: case GST_STATE_CHANGE_READY_TO_PAUSED:
ogg_sync_reset (&ogg->sync); ogg_sync_reset (&ogg->sync);
ogg->current_granule = -1; ogg->current_granule = -1;
ogg->current_time = 0; ogg->running = FALSE;
ogg->segment_running = FALSE;
gst_segment_init (&ogg->segment, GST_FORMAT_TIME);
break; break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING: case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
break; break;
@ -2784,11 +2712,8 @@ gst_ogg_demux_change_state (GstElement * element, GstStateChange transition)
gst_ogg_demux_clear_chains (ogg); gst_ogg_demux_clear_chains (ogg);
GST_OBJECT_LOCK (ogg); GST_OBJECT_LOCK (ogg);
ogg->running = FALSE; ogg->running = FALSE;
ogg->segment_running = FALSE;
ogg->have_fishead = FALSE; ogg->have_fishead = FALSE;
ogg->segment_rate = 1.0;
ogg->segment_flags = GST_SEEK_FLAG_NONE;
ogg->segment_start = GST_CLOCK_TIME_NONE;
ogg->segment_stop = GST_CLOCK_TIME_NONE;
GST_OBJECT_UNLOCK (ogg); GST_OBJECT_UNLOCK (ogg);
break; break;
case GST_STATE_CHANGE_READY_TO_NULL: case GST_STATE_CHANGE_READY_TO_NULL: