mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
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.
This commit is contained in:
parent
6e2a117eb2
commit
99d9b34385
2 changed files with 54 additions and 22 deletions
|
@ -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,17 +1371,32 @@ 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;
|
||||
|
||||
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);
|
||||
|
||||
++demux->packet;
|
||||
|
||||
}
|
||||
|
||||
/* reset speed pull */
|
||||
if (G_UNLIKELY (demux->speed_packets != 1))
|
||||
demux->speed_packets = 1;
|
||||
|
||||
gst_buffer_unref (buf);
|
||||
|
||||
flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
|
||||
|
||||
++demux->packet;
|
||||
|
||||
if (demux->num_packets > 0 && demux->packet >= demux->num_packets) {
|
||||
GST_LOG_OBJECT (demux, "reached EOS");
|
||||
goto 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");
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue