diff options
author | Edward Hervey <bilboed@bilboed.com> | 2009-06-28 17:02:17 +0200 |
---|---|---|
committer | Edward Hervey <bilboed@bilboed.com> | 2009-06-28 17:33:48 +0200 |
commit | 99d9b3438534a303e7b933ad4c755dca7bcd66d0 (patch) | |
tree | 7fd98d369f9765a98bbbffedeff0b33b74fff1a9 | |
parent | 6e2a117eb2d48e408619a0a4f8c4fc08a978f4e7 (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.c | 66 | ||||
-rw-r--r-- | gst/asfdemux/gstasfdemux.h | 8 |
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 { |