flvdemux: Do not build an index if upstream is not seekable
authorJan Urbański <wulczer@wulczer.org>
Sun, 27 Mar 2011 19:39:50 +0000 (21:39 +0200)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Mon, 28 Mar 2011 17:53:59 +0000 (19:53 +0200)
An index is not useful if upstream cannot handle seeks and building it
for infinite files, for instance FLV streams, results in a memory leak.

gst/flv/gstflvdemux.c
gst/flv/gstflvdemux.h

index 87ebf0e86931ac94a63530ec704440bd0cbff1f6..79f83bc2b8b693c172c05a4d09ba382d7fdad7dd 100644 (file)
@@ -103,6 +103,10 @@ gst_flv_demux_parse_and_add_index_entry (GstFlvDemux * demux, GstClockTime ts,
       "adding key=%d association %" GST_TIME_FORMAT "-> %" G_GUINT64_FORMAT,
       keyframe, GST_TIME_ARGS (ts), pos);
 
+  /* if upstream is not seekable there is no point in building an index */
+  if (!demux->upstream_seekable)
+    return;
+
   /* entry may already have been added before, avoid adding indefinitely */
   entry = gst_index_get_assoc_entry (demux->index, demux->index_id,
       GST_INDEX_LOOKUP_EXACT, GST_ASSOCIATION_FLAG_NONE, GST_FORMAT_BYTES, pos);
@@ -186,6 +190,41 @@ gst_flv_demux_query_types (GstPad * pad)
   return query_types;
 }
 
+static void
+gst_flv_demux_check_seekability (GstFlvDemux * demux)
+{
+  GstQuery *query;
+  gint64 start = -1, stop = -1;
+
+  demux->upstream_seekable = FALSE;
+
+  query = gst_query_new_seeking (GST_FORMAT_BYTES);
+  if (!gst_pad_peer_query (demux->sinkpad, query)) {
+    GST_DEBUG_OBJECT (demux, "seeking query failed");
+    return;
+  }
+
+  gst_query_parse_seeking (query, NULL, &demux->upstream_seekable,
+      &start, &stop);
+
+  /* try harder to query upstream size if we didn't get it the first time */
+  if (demux->upstream_seekable && stop == -1) {
+    GstFormat fmt = GST_FORMAT_BYTES;
+
+    GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
+    gst_pad_query_peer_duration (demux->sinkpad, &fmt, &stop);
+  }
+
+  /* if upstream doesn't know the size, it's likely that it's not seekable in
+   * practice even if it technically may be seekable */
+  if (demux->upstream_seekable && (start != 0 || stop <= start)) {
+    GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
+    demux->upstream_seekable = FALSE;
+  }
+
+  GST_DEBUG_OBJECT (demux, "upstream seekable: %d", demux->upstream_seekable);
+}
+
 static void
 parse_flv_demux_parse_date_string (GDate * date, const gchar * s)
 {
@@ -1491,6 +1530,9 @@ gst_flv_demux_parse_header (GstFlvDemux * demux, GstBuffer * buffer)
     }
   }
 
+  /* do a one-time seekability check */
+  gst_flv_demux_check_seekability (demux);
+
   /* We don't care about the rest */
   demux->need_header = FALSE;
 
@@ -1544,6 +1586,7 @@ gst_flv_demux_cleanup (GstFlvDemux * demux)
   demux->got_par = FALSE;
 
   demux->indexed = FALSE;
+  demux->upstream_seekable = FALSE;
   demux->file_size = 0;
 
   demux->index_max_pos = 0;
index dadff9428ea12d9c9221911966380bb0f4325536..10ff306a2b83c133347f0ce0768a01eef596e980 100644 (file)
@@ -123,6 +123,7 @@ struct _GstFlvDemux
   gboolean seeking;
   gboolean building_index;
   gboolean indexed; /* TRUE if index is completely built */
+  gboolean upstream_seekable; /* TRUE if upstream is seekable */
   gint64 file_size;
   GstEvent *seek_event;
   gint64 seek_time;