summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Hervey <bilboed@bilboed.com>2009-06-28 17:02:17 +0200
committerEdward Hervey <bilboed@bilboed.com>2009-06-28 17:33:48 +0200
commit99d9b3438534a303e7b933ad4c755dca7bcd66d0 (patch)
tree7fd98d369f9765a98bbbffedeff0b33b74fff1a9
parent6e2a117eb2d48e408619a0a4f8c4fc08a978f4e7 (diff)
asfdemux: Use index entry packet count to optimize seeking.
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.
-rw-r--r--gst/asfdemux/gstasfdemux.c66
-rw-r--r--gst/asfdemux/gstasfdemux.h8
2 files changed, 53 insertions, 21 deletions
diff --git a/gst/asfdemux/gstasfdemux.c b/gst/asfdemux/gstasfdemux.c
index 3df6f573..3debb461 100644
--- a/gst/asfdemux/gstasfdemux.c
+++ b/gst/asfdemux/gstasfdemux.c
@@ -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");
diff --git a/gst/asfdemux/gstasfdemux.h b/gst/asfdemux/gstasfdemux.h
index ca4a2f7b..f0f6e51b 100644
--- a/gst/asfdemux/gstasfdemux.h
+++ b/gst/asfdemux/gstasfdemux.h
@@ -46,6 +46,11 @@ 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 */
guint16 len; /* save this so we can skip unknown IDs */
@@ -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 {