mp3parse: conserve stop time for non-accurate seek

Use the same strategy as accurate seeks to store
pending non-accurate seeks to avoid overwriting non-definite
stop times. When doing non-accurate seeks our position
reporting might drift off by some secs and the stream can
end up before it should.

Fixes #603695
This commit is contained in:
Thiago Santos 2009-12-08 19:55:04 -03:00
parent 6c05222326
commit 5e3f07b6a1
2 changed files with 75 additions and 25 deletions

View file

@ -388,13 +388,18 @@ gst_mp3parse_reset (GstMPEGAudioParse * mp3parse)
mp3parse->seek_table = NULL; mp3parse->seek_table = NULL;
} }
g_mutex_lock (mp3parse->pending_accurate_seeks_lock); g_mutex_lock (mp3parse->pending_seeks_lock);
if (mp3parse->pending_accurate_seeks) { if (mp3parse->pending_accurate_seeks) {
g_slist_foreach (mp3parse->pending_accurate_seeks, (GFunc) g_free, NULL); g_slist_foreach (mp3parse->pending_accurate_seeks, (GFunc) g_free, NULL);
g_slist_free (mp3parse->pending_accurate_seeks); g_slist_free (mp3parse->pending_accurate_seeks);
mp3parse->pending_accurate_seeks = NULL; mp3parse->pending_accurate_seeks = NULL;
} }
g_mutex_unlock (mp3parse->pending_accurate_seeks_lock); if (mp3parse->pending_nonaccurate_seeks) {
g_slist_foreach (mp3parse->pending_nonaccurate_seeks, (GFunc) g_free, NULL);
g_slist_free (mp3parse->pending_nonaccurate_seeks);
mp3parse->pending_nonaccurate_seeks = NULL;
}
g_mutex_unlock (mp3parse->pending_seeks_lock);
if (mp3parse->pending_segment) { if (mp3parse->pending_segment) {
GstEvent **eventp = &mp3parse->pending_segment; GstEvent **eventp = &mp3parse->pending_segment;
@ -424,7 +429,7 @@ gst_mp3parse_init (GstMPEGAudioParse * mp3parse, GstMPEGAudioParseClass * klass)
gst_element_add_pad (GST_ELEMENT (mp3parse), mp3parse->srcpad); gst_element_add_pad (GST_ELEMENT (mp3parse), mp3parse->srcpad);
mp3parse->adapter = gst_adapter_new (); mp3parse->adapter = gst_adapter_new ();
mp3parse->pending_accurate_seeks_lock = g_mutex_new (); mp3parse->pending_seeks_lock = g_mutex_new ();
gst_mp3parse_reset (mp3parse); gst_mp3parse_reset (mp3parse);
} }
@ -440,8 +445,8 @@ gst_mp3parse_dispose (GObject * object)
g_object_unref (mp3parse->adapter); g_object_unref (mp3parse->adapter);
mp3parse->adapter = NULL; mp3parse->adapter = NULL;
} }
g_mutex_free (mp3parse->pending_accurate_seeks_lock); g_mutex_free (mp3parse->pending_seeks_lock);
mp3parse->pending_accurate_seeks_lock = NULL; mp3parse->pending_seeks_lock = NULL;
g_list_foreach (mp3parse->pending_events, (GFunc) gst_mini_object_unref, g_list_foreach (mp3parse->pending_events, (GFunc) gst_mini_object_unref,
NULL); NULL);
@ -467,14 +472,14 @@ gst_mp3parse_sink_event (GstPad * pad, GstEvent * event)
GstFormat format; GstFormat format;
gint64 start, stop, pos; gint64 start, stop, pos;
gboolean update; gboolean update;
MPEGAudioPendingAccurateSeek *seek = NULL;
GSList *node;
gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate, gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
&format, &start, &stop, &pos); &format, &start, &stop, &pos);
g_mutex_lock (mp3parse->pending_accurate_seeks_lock); g_mutex_lock (mp3parse->pending_seeks_lock);
if (format == GST_FORMAT_BYTES && mp3parse->pending_accurate_seeks) { if (format == GST_FORMAT_BYTES && mp3parse->pending_accurate_seeks) {
MPEGAudioPendingAccurateSeek *seek = NULL;
GSList *node;
for (node = mp3parse->pending_accurate_seeks; node; node = node->next) { for (node = mp3parse->pending_accurate_seeks; node; node = node->next) {
MPEGAudioPendingAccurateSeek *tmp = node->data; MPEGAudioPendingAccurateSeek *tmp = node->data;
@ -513,7 +518,7 @@ gst_mp3parse_sink_event (GstPad * pad, GstEvent * event)
mp3parse->pending_accurate_seeks = mp3parse->pending_accurate_seeks =
g_slist_delete_link (mp3parse->pending_accurate_seeks, node); g_slist_delete_link (mp3parse->pending_accurate_seeks, node);
g_mutex_unlock (mp3parse->pending_accurate_seeks_lock); g_mutex_unlock (mp3parse->pending_seeks_lock);
res = gst_pad_push_event (mp3parse->srcpad, event); res = gst_pad_push_event (mp3parse->srcpad, event);
return res; return res;
@ -522,7 +527,7 @@ gst_mp3parse_sink_event (GstPad * pad, GstEvent * event)
"Accurate seek not possible, didn't get an appropiate upstream segment"); "Accurate seek not possible, didn't get an appropiate upstream segment");
} }
} }
g_mutex_unlock (mp3parse->pending_accurate_seeks_lock); g_mutex_unlock (mp3parse->pending_seeks_lock);
mp3parse->exact_position = FALSE; mp3parse->exact_position = FALSE;
@ -535,6 +540,32 @@ gst_mp3parse_sink_event (GstPad * pad, GstEvent * event)
if (mp3parse_bytepos_to_time (mp3parse, start, &seg_start, FALSE) && if (mp3parse_bytepos_to_time (mp3parse, start, &seg_start, FALSE) &&
mp3parse_bytepos_to_time (mp3parse, pos, &seg_pos, FALSE)) { mp3parse_bytepos_to_time (mp3parse, pos, &seg_pos, FALSE)) {
gst_event_unref (event); gst_event_unref (event);
/* search the pending nonaccurate seeks */
g_mutex_lock (mp3parse->pending_seeks_lock);
seek = NULL;
for (node = mp3parse->pending_nonaccurate_seeks; node;
node = node->next) {
MPEGAudioPendingAccurateSeek *tmp = node->data;
if (tmp->upstream_start == pos) {
seek = tmp;
break;
}
}
if (seek) {
if (seek->segment.stop == -1) {
/* corrent the segment end, because non-accurate seeks might make
* our streaming end earlier (see bug #603695) */
seg_stop = -1;
}
g_free (seek);
mp3parse->pending_nonaccurate_seeks =
g_slist_delete_link (mp3parse->pending_nonaccurate_seeks, node);
}
g_mutex_unlock (mp3parse->pending_seeks_lock);
event = gst_event_new_new_segment_full (update, rate, applied_rate, event = gst_event_new_new_segment_full (update, rate, applied_rate,
GST_FORMAT_TIME, seg_start, seg_stop, seg_pos); GST_FORMAT_TIME, seg_start, seg_stop, seg_pos);
format = GST_FORMAT_TIME; format = GST_FORMAT_TIME;
@ -1869,6 +1900,8 @@ mp3parse_handle_seek (GstMPEGAudioParse * mp3parse, GstEvent * event)
GstSeekType cur_type, stop_type; GstSeekType cur_type, stop_type;
gint64 cur, stop; gint64 cur, stop;
gint64 byte_cur, byte_stop; gint64 byte_cur, byte_stop;
MPEGAudioPendingAccurateSeek *seek;
GstClockTime start;
gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur, gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
&stop_type, &stop); &stop_type, &stop);
@ -1888,6 +1921,13 @@ mp3parse_handle_seek (GstMPEGAudioParse * mp3parse, GstEvent * event)
return TRUE; return TRUE;
} }
seek = g_new0 (MPEGAudioPendingAccurateSeek, 1);
seek->segment = mp3parse->segment;
gst_segment_set_seek (&seek->segment, rate, GST_FORMAT_TIME,
flags, cur_type, cur, stop_type, stop, NULL);
/* Handle TIME based seeks by converting to a BYTE position */ /* Handle TIME based seeks by converting to a BYTE position */
/* For accurate seeking get the frame 9 (MPEG1) or 29 (MPEG2) frames /* For accurate seeking get the frame 9 (MPEG1) or 29 (MPEG2) frames
@ -1899,15 +1939,6 @@ mp3parse_handle_seek (GstMPEGAudioParse * mp3parse, GstEvent * event)
*/ */
if (flags & GST_SEEK_FLAG_ACCURATE) { if (flags & GST_SEEK_FLAG_ACCURATE) {
MPEGAudioPendingAccurateSeek *seek =
g_new0 (MPEGAudioPendingAccurateSeek, 1);
GstClockTime start;
seek->segment = mp3parse->segment;
gst_segment_set_seek (&seek->segment, rate, GST_FORMAT_TIME,
flags, cur_type, cur, stop_type, stop, NULL);
if (!mp3parse->seek_table) { if (!mp3parse->seek_table) {
byte_cur = 0; byte_cur = 0;
byte_stop = -1; byte_stop = -1;
@ -1957,21 +1988,21 @@ mp3parse_handle_seek (GstMPEGAudioParse * mp3parse, GstEvent * event)
} }
event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type,
byte_cur, stop_type, byte_stop); byte_cur, stop_type, byte_stop);
g_mutex_lock (mp3parse->pending_accurate_seeks_lock); g_mutex_lock (mp3parse->pending_seeks_lock);
seek->upstream_start = byte_cur; seek->upstream_start = byte_cur;
seek->timestamp_start = start; seek->timestamp_start = start;
mp3parse->pending_accurate_seeks = mp3parse->pending_accurate_seeks =
g_slist_prepend (mp3parse->pending_accurate_seeks, seek); g_slist_prepend (mp3parse->pending_accurate_seeks, seek);
g_mutex_unlock (mp3parse->pending_accurate_seeks_lock); g_mutex_unlock (mp3parse->pending_seeks_lock);
if (gst_pad_push_event (mp3parse->sinkpad, event)) { if (gst_pad_push_event (mp3parse->sinkpad, event)) {
mp3parse->exact_position = TRUE; mp3parse->exact_position = TRUE;
return TRUE; return TRUE;
} else { } else {
mp3parse->exact_position = TRUE; mp3parse->exact_position = TRUE;
g_mutex_lock (mp3parse->pending_accurate_seeks_lock); g_mutex_lock (mp3parse->pending_seeks_lock);
mp3parse->pending_accurate_seeks = mp3parse->pending_accurate_seeks =
g_slist_remove (mp3parse->pending_accurate_seeks, seek); g_slist_remove (mp3parse->pending_accurate_seeks, seek);
g_mutex_unlock (mp3parse->pending_accurate_seeks_lock); g_mutex_unlock (mp3parse->pending_seeks_lock);
g_free (seek); g_free (seek);
return FALSE; return FALSE;
} }
@ -1993,7 +2024,24 @@ mp3parse_handle_seek (GstMPEGAudioParse * mp3parse, GstEvent * event)
event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type,
byte_cur, stop_type, byte_stop); byte_cur, stop_type, byte_stop);
return gst_pad_push_event (mp3parse->sinkpad, event); GST_LOG_OBJECT (mp3parse, "Storing pending seek");
g_mutex_lock (mp3parse->pending_seeks_lock);
seek->upstream_start = byte_cur;
seek->timestamp_start = cur;
mp3parse->pending_nonaccurate_seeks =
g_slist_prepend (mp3parse->pending_nonaccurate_seeks, seek);
g_mutex_unlock (mp3parse->pending_seeks_lock);
if (gst_pad_push_event (mp3parse->sinkpad, event)) {
return TRUE;
} else {
g_mutex_lock (mp3parse->pending_seeks_lock);
mp3parse->pending_nonaccurate_seeks =
g_slist_remove (mp3parse->pending_nonaccurate_seeks, seek);
g_mutex_unlock (mp3parse->pending_seeks_lock);
g_free (seek);
return FALSE;
}
no_pos: no_pos:
GST_DEBUG_OBJECT (mp3parse, GST_DEBUG_OBJECT (mp3parse,
"Could not determine byte position for desired time"); "Could not determine byte position for desired time");

View file

@ -118,10 +118,12 @@ struct _GstMPEGAudioParse {
/* Accurate seeking */ /* Accurate seeking */
GList *seek_table; GList *seek_table;
GMutex *pending_accurate_seeks_lock; GMutex *pending_seeks_lock;
GSList *pending_accurate_seeks; GSList *pending_accurate_seeks;
gboolean exact_position; gboolean exact_position;
GSList *pending_nonaccurate_seeks;
/* Track whether we're seekable (in BYTES format, if upstream operates in /* Track whether we're seekable (in BYTES format, if upstream operates in
* TIME format, we don't care about seekability and assume upstream handles * TIME format, we don't care about seekability and assume upstream handles
* it). The seek table for accurate seeking is not maintained if we're not * it). The seek table for accurate seeking is not maintained if we're not