mp3parse: conserve stop time for non-accurate seek
authorThiago Santos <thiago.sousa.santos@collabora.co.uk>
Tue, 8 Dec 2009 22:55:04 +0000 (19:55 -0300)
committerThiago Santos <thiago.sousa.santos@collabora.co.uk>
Mon, 4 Jan 2010 13:01:44 +0000 (10:01 -0300)
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

gst/mpegaudioparse/gstmpegaudioparse.c
gst/mpegaudioparse/gstmpegaudioparse.h

index b5602f1..8f5996e 100644 (file)
@@ -388,13 +388,18 @@ gst_mp3parse_reset (GstMPEGAudioParse * mp3parse)
     mp3parse->seek_table = NULL;
   }
 
-  g_mutex_lock (mp3parse->pending_accurate_seeks_lock);
+  g_mutex_lock (mp3parse->pending_seeks_lock);
   if (mp3parse->pending_accurate_seeks) {
     g_slist_foreach (mp3parse->pending_accurate_seeks, (GFunc) g_free, NULL);
     g_slist_free (mp3parse->pending_accurate_seeks);
     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) {
     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);
 
   mp3parse->adapter = gst_adapter_new ();
-  mp3parse->pending_accurate_seeks_lock = g_mutex_new ();
+  mp3parse->pending_seeks_lock = g_mutex_new ();
 
   gst_mp3parse_reset (mp3parse);
 }
@@ -440,8 +445,8 @@ gst_mp3parse_dispose (GObject * object)
     g_object_unref (mp3parse->adapter);
     mp3parse->adapter = NULL;
   }
-  g_mutex_free (mp3parse->pending_accurate_seeks_lock);
-  mp3parse->pending_accurate_seeks_lock = NULL;
+  g_mutex_free (mp3parse->pending_seeks_lock);
+  mp3parse->pending_seeks_lock = NULL;
 
   g_list_foreach (mp3parse->pending_events, (GFunc) gst_mini_object_unref,
       NULL);
@@ -467,14 +472,14 @@ gst_mp3parse_sink_event (GstPad * pad, GstEvent * event)
       GstFormat format;
       gint64 start, stop, pos;
       gboolean update;
+      MPEGAudioPendingAccurateSeek *seek = NULL;
+      GSList *node;
 
       gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
           &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) {
-        MPEGAudioPendingAccurateSeek *seek = NULL;
-        GSList *node;
 
         for (node = mp3parse->pending_accurate_seeks; node; node = node->next) {
           MPEGAudioPendingAccurateSeek *tmp = node->data;
@@ -513,7 +518,7 @@ gst_mp3parse_sink_event (GstPad * pad, GstEvent * event)
           mp3parse->pending_accurate_seeks =
               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);
 
           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");
         }
       }
-      g_mutex_unlock (mp3parse->pending_accurate_seeks_lock);
+      g_mutex_unlock (mp3parse->pending_seeks_lock);
 
       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) &&
             mp3parse_bytepos_to_time (mp3parse, pos, &seg_pos, FALSE)) {
           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,
               GST_FORMAT_TIME, seg_start, seg_stop, seg_pos);
           format = GST_FORMAT_TIME;
@@ -1869,6 +1900,8 @@ mp3parse_handle_seek (GstMPEGAudioParse * mp3parse, GstEvent * event)
   GstSeekType cur_type, stop_type;
   gint64 cur, stop;
   gint64 byte_cur, byte_stop;
+  MPEGAudioPendingAccurateSeek *seek;
+  GstClockTime start;
 
   gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
       &stop_type, &stop);
@@ -1888,6 +1921,13 @@ mp3parse_handle_seek (GstMPEGAudioParse * mp3parse, GstEvent * event)
       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 */
 
   /* 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) {
-    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) {
       byte_cur = 0;
       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,
         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->timestamp_start = start;
     mp3parse->pending_accurate_seeks =
         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)) {
       mp3parse->exact_position = TRUE;
       return TRUE;
     } else {
       mp3parse->exact_position = TRUE;
-      g_mutex_lock (mp3parse->pending_accurate_seeks_lock);
+      g_mutex_lock (mp3parse->pending_seeks_lock);
       mp3parse->pending_accurate_seeks =
           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);
       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,
       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:
   GST_DEBUG_OBJECT (mp3parse,
       "Could not determine byte position for desired time");
index c5e48cd..abadf72 100644 (file)
@@ -118,10 +118,12 @@ struct _GstMPEGAudioParse {
 
   /* Accurate seeking */
   GList *seek_table;
-  GMutex *pending_accurate_seeks_lock;
+  GMutex *pending_seeks_lock;
   GSList *pending_accurate_seeks;
   gboolean exact_position;
 
+  GSList *pending_nonaccurate_seeks;
+
   /* Track whether we're seekable (in BYTES format, if upstream operates in
    * 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