asfdemux: Use index entry packet count to optimize seeking.
authorEdward Hervey <bilboed@bilboed.com>
Sun, 28 Jun 2009 15:02:17 +0000 (17:02 +0200)
committerEdward Hervey <bilboed@bilboed.com>
Sun, 28 Jun 2009 15:33:48 +0000 (17:33 +0200)
The simple index entries also contain the number of packets one needs
to retrieve at a given position to get a full keyframe. We therefore
use that information to retrieve all those packets in one buffer when
working in pull-mode.

gst/asfdemux/gstasfdemux.c
gst/asfdemux/gstasfdemux.h

index 3df6f5734672648eb648fabf15c5201cf63502b0..3debb461020923181ab312efdfcc3f400d9f11fc 100644 (file)
@@ -222,6 +222,8 @@ gst_asf_demux_reset (GstASFDemux * demux)
   demux->sidx_num_entries = 0;
   g_free (demux->sidx_entries);
   demux->sidx_entries = NULL;
+
+  demux->speed_packets = 1;
 }
 
 static void
@@ -373,7 +375,7 @@ gst_asf_demux_sink_event (GstPad * pad, GstEvent * event)
 
 static gboolean
 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
-    GstClockTime seek_time, GstClockTime * p_idx_time)
+    GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed)
 {
   GstClockTime idx_time;
   guint idx;
@@ -388,7 +390,9 @@ gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
   if (idx >= demux->sidx_num_entries)
     return FALSE;
 
-  *packet = demux->sidx_entries[idx];
+  *packet = demux->sidx_entries[idx].packet;
+  if (speed)
+    *speed = demux->sidx_entries[idx].count;
 
   /* so we get closer to the actual time of the packet ... actually, let's not
    * do this, since we throw away superfluous payloads before the seek position
@@ -470,7 +474,7 @@ gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
   GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
 
   /* determine packet, by index or by estimation */
-  if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL)) {
+  if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL)) {
     packet = (guint) gst_util_uint64_scale (demux->num_packets,
         cur, demux->play_time);
   }
@@ -510,7 +514,7 @@ gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
   gdouble rate;
   gint64 cur, stop;
   gint64 seek_time;
-  guint packet;
+  guint packet, speed_count = 1;
 
   if (demux->seekable == FALSE || demux->packet_size == 0 ||
       demux->num_packets == 0 || demux->play_time == 0) {
@@ -602,7 +606,8 @@ gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
 
   /* FIXME: should check the KEY_UNIT flag; need to adjust last_stop to
    * real start of data and segment_start to indexed time for key unit seek*/
-  if (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time, &idx_time)) {
+  if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
+              &idx_time, &speed_count))) {
     /* First try to query our source to see if it can convert for us. This is
        the case when our source is an mms stream, notice that in this case
        gstmms will do a time based seek to get the byte offset, this is not a
@@ -643,12 +648,13 @@ gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
     }
   }
 
-  GST_DEBUG_OBJECT (demux, "seeking to packet %u", packet);
+  GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
 
   GST_OBJECT_LOCK (demux);
   demux->segment = segment;
   demux->packet = packet;
   demux->need_newsegment = TRUE;
+  demux->speed_packets = speed_count;
   gst_asf_demux_reset_stream_state_after_discont (demux);
   GST_OBJECT_UNLOCK (demux);
 
@@ -1332,6 +1338,7 @@ gst_asf_demux_loop (GstASFDemux * demux)
   GstFlowReturn flow = GST_FLOW_OK;
   GstBuffer *buf = NULL;
   guint64 off;
+  guint n;
 
   if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
     if (!gst_asf_demux_pull_headers (demux)) {
@@ -1352,7 +1359,8 @@ gst_asf_demux_loop (GstASFDemux * demux)
 
   off = demux->data_offset + (demux->packet * demux->packet_size);
 
-  if (!gst_asf_demux_pull_data (demux, off, demux->packet_size, &buf, &flow)) {
+  if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
+              demux->packet_size * demux->speed_packets, &buf, &flow))) {
     GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
     if (flow == GST_FLOW_UNEXPECTED)
       goto eos;
@@ -1363,16 +1371,31 @@ gst_asf_demux_loop (GstASFDemux * demux)
       goto read_failed;
   }
 
-  /* FIXME: maybe we should just skip broken packets and error out only
-   * after a few broken packets in a row? */
-  if (!gst_asf_demux_parse_packet (demux, buf))
-    goto parse_error;
+  for (n = 0; n < demux->speed_packets; n++) {
+    GstBuffer *tmp = NULL, *sub = buf;
 
-  gst_buffer_unref (buf);
+    if (G_UNLIKELY (n != 0))
+      tmp = sub =
+          gst_buffer_create_sub (buf, n * demux->packet_size,
+          demux->packet_size);
+    /* FIXME: maybe we should just skip broken packets and error out only
+     * after a few broken packets in a row? */
+    if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, sub)))
+      goto parse_error;
+    if (G_UNLIKELY (n != 0))
+      gst_buffer_unref (tmp);
+
+    flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
 
-  flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
+    ++demux->packet;
 
-  ++demux->packet;
+  }
+
+  /* reset speed pull */
+  if (G_UNLIKELY (demux->speed_packets != 1))
+    demux->speed_packets = 1;
+
+  gst_buffer_unref (buf);
 
   if (demux->num_packets > 0 && demux->packet >= demux->num_packets) {
     GST_LOG_OBJECT (demux, "reached EOS");
@@ -2883,13 +2906,16 @@ gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
     demux->sidx_interval = interval;
     demux->sidx_num_entries = count;
     g_free (demux->sidx_entries);
-    demux->sidx_entries = g_new0 (guint32, count);
+    demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
 
-    for (i = 0; i < count && size > (4 + 2); ++i) {
-      demux->sidx_entries[i] = gst_asf_demux_get_uint32 (&data, &size);
-      x = (guint32) gst_asf_demux_get_uint16 (&data, &size);
-      GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u",
-          GST_TIME_ARGS (i * interval), demux->sidx_entries[i]);
+    for (i = 0; i < count; ++i) {
+      if (G_UNLIKELY (size <= 6))
+        break;
+      demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
+      demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
+      GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u  count : %2d",
+          GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
+          demux->sidx_entries[i].count);
     }
   } else {
     GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
index ca4a2f7b47a0a4a5d273f22484ff71e7513c05e1..f0f6e51bed1dcb1078f724471b16f20161ca6e0c 100644 (file)
@@ -45,6 +45,11 @@ GST_DEBUG_CATEGORY_EXTERN (asfdemux_dbg);
 typedef struct _GstASFDemux GstASFDemux;
 typedef struct _GstASFDemuxClass GstASFDemuxClass;
 
+typedef struct {
+  guint32      packet;
+  guint16      count;
+} AsfSimpleIndexEntry;
+
 typedef struct {
   AsfPayloadExtensionID   id : 16;  /* extension ID; the :16 makes sure the
                                      * struct gets packed into 4 bytes       */
@@ -132,6 +137,7 @@ struct _GstASFDemux {
   guint64            data_size;    /* total size of packet data in bytes, or 0 */
   guint64            num_packets;  /* total number of data packets, or 0       */
   gint64             packet;       /* current packet                           */
+  guint              speed_packets; /* Known number of packets to get in one go*/
 
   /* bitrates are unused at the moment */
   guint32              bitrate[GST_ASF_DEMUX_NUM_STREAM_IDS];
@@ -184,7 +190,7 @@ struct _GstASFDemux {
   /* simple index, if available */
   GstClockTime         sidx_interval;    /* interval between entries in ns */
   guint                sidx_num_entries; /* number of index entries        */
-  guint32             *sidx_entries;     /* packet number for each entry   */
+  AsfSimpleIndexEntry *sidx_entries;     /* packet number for each entry   */
 };
 
 struct _GstASFDemuxClass {