mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-17 22:06:41 +00:00
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:
parent
6c05222326
commit
5e3f07b6a1
2 changed files with 75 additions and 25 deletions
|
@ -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");
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue