summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Colwell <acolwell@chromium.org>2011-07-09 07:48:43 +0200
committerAnton Khirnov <anton@khirnov.net>2011-07-10 18:51:30 +0200
commit31ad14c21e0735387ba8082c6e3436241f7ccfc8 (patch)
tree88905450075213ac97c7f68f78f9c184b131509f
parent84626b364babc27c5a3db454ebf6a02aeaa186fe (diff)
downloadffmpeg-31ad14c21e0735387ba8082c6e3436241f7ccfc8.tar.gz
matroskadec: defer parsing of cues element until we seek.
This decreases startup latency. Signed-off-by: Ronald S. Bultje <rsbultje@gmail.com> Signed-off-by: Anton Khirnov <anton@khirnov.net>
-rw-r--r--libavformat/matroskadec.c131
1 files changed, 86 insertions, 45 deletions
diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
index a1e827f093..37ce3342b1 100644
--- a/libavformat/matroskadec.c
+++ b/libavformat/matroskadec.c
@@ -244,6 +244,9 @@ typedef struct {
/* What to skip before effectively reading a packet. */
int skip_to_keyframe;
uint64_t skip_to_timecode;
+
+ /* File has a CUES element, but we defer parsing until it is needed. */
+ int cues_parsing_deferred;
} MatroskaDemuxContext;
typedef struct {
@@ -1110,7 +1113,7 @@ static void matroska_convert_tags(AVFormatContext *s)
}
}
-static void matroska_execute_seekhead(MatroskaDemuxContext *matroska)
+static int matroska_parse_seekhead_entry(MatroskaDemuxContext *matroska, int idx)
{
EbmlList *seekhead_list = &matroska->seekhead;
MatroskaSeekhead *seekhead = seekhead_list->elem;
@@ -1118,34 +1121,25 @@ static void matroska_execute_seekhead(MatroskaDemuxContext *matroska)
int64_t before_pos = avio_tell(matroska->ctx->pb);
uint32_t saved_id = matroska->current_id;
MatroskaLevel level;
- int i;
-
- // we should not do any seeking in the streaming case
- if (!matroska->ctx->pb->seekable ||
- (matroska->ctx->flags & AVFMT_FLAG_IGNIDX))
- return;
-
- for (i=0; i<seekhead_list->nb_elem; i++) {
- int64_t offset = seekhead[i].pos + matroska->segment_start;
+ int64_t offset;
+ int ret = 0;
- if (seekhead[i].pos <= before_pos
- || seekhead[i].id == MATROSKA_ID_SEEKHEAD
- || seekhead[i].id == MATROSKA_ID_CLUSTER)
- continue;
+ if (idx >= seekhead_list->nb_elem
+ || seekhead[idx].id == MATROSKA_ID_SEEKHEAD
+ || seekhead[idx].id == MATROSKA_ID_CLUSTER)
+ return 0;
/* seek */
- if (avio_seek(matroska->ctx->pb, offset, SEEK_SET) != offset)
- continue;
-
+ offset = seekhead[idx].pos + matroska->segment_start;
+ if (avio_seek(matroska->ctx->pb, offset, SEEK_SET) == offset) {
/* We don't want to lose our seekhead level, so we add
* a dummy. This is a crude hack. */
if (matroska->num_levels == EBML_MAX_DEPTH) {
av_log(matroska->ctx, AV_LOG_INFO,
"Max EBML element depth (%d) reached, "
"cannot parse further.\n", EBML_MAX_DEPTH);
- break;
- }
-
+ ret = AVERROR_INVALIDDATA;
+ } else {
level.start = 0;
level.length = (uint64_t)-1;
matroska->levels[matroska->num_levels] = level;
@@ -1161,11 +1155,76 @@ static void matroska_execute_seekhead(MatroskaDemuxContext *matroska)
break;
}
}
-
+ }
/* seek back */
avio_seek(matroska->ctx->pb, before_pos, SEEK_SET);
matroska->level_up = level_up;
matroska->current_id = saved_id;
+
+ return ret;
+}
+
+static void matroska_execute_seekhead(MatroskaDemuxContext *matroska)
+{
+ EbmlList *seekhead_list = &matroska->seekhead;
+ MatroskaSeekhead *seekhead = seekhead_list->elem;
+ int64_t before_pos = avio_tell(matroska->ctx->pb);
+ int i;
+
+ // we should not do any seeking in the streaming case
+ if (!matroska->ctx->pb->seekable ||
+ (matroska->ctx->flags & AVFMT_FLAG_IGNIDX))
+ return;
+
+ for (i = 0; i < seekhead_list->nb_elem; i++) {
+ if (seekhead[i].pos <= before_pos)
+ continue;
+
+ // defer cues parsing until we actually need cue data.
+ if (seekhead[i].id == MATROSKA_ID_CUES) {
+ matroska->cues_parsing_deferred = 1;
+ continue;
+ }
+
+ if (matroska_parse_seekhead_entry(matroska, i) < 0)
+ break;
+ }
+}
+
+static void matroska_parse_cues(MatroskaDemuxContext *matroska) {
+ EbmlList *seekhead_list = &matroska->seekhead;
+ MatroskaSeekhead *seekhead = seekhead_list->elem;
+ EbmlList *index_list;
+ MatroskaIndex *index;
+ int index_scale = 1;
+ int i, j;
+
+ for (i = 0; i < seekhead_list->nb_elem; i++)
+ if (seekhead[i].id != MATROSKA_ID_CUES)
+ break;
+ assert(i <= seekhead_list->nb_elem);
+
+ matroska_parse_seekhead_entry(matroska, i);
+
+ index_list = &matroska->index;
+ index = index_list->elem;
+ if (index_list->nb_elem
+ && index[0].time > 1E14/matroska->time_scale) {
+ av_log(matroska->ctx, AV_LOG_WARNING, "Working around broken index.\n");
+ index_scale = matroska->time_scale;
+ }
+ for (i = 0; i < index_list->nb_elem; i++) {
+ EbmlList *pos_list = &index[i].pos;
+ MatroskaIndexPos *pos = pos_list->elem;
+ for (j = 0; j < pos_list->nb_elem; j++) {
+ MatroskaTrack *track = matroska_find_track_by_num(matroska, pos[j].track);
+ if (track && track->stream)
+ av_add_index_entry(track->stream,
+ pos[j].pos + matroska->segment_start,
+ index[i].time/index_scale, 0, 0,
+ AVINDEX_KEYFRAME);
+ }
+ }
}
static int matroska_aac_profile(char *codec_id)
@@ -1197,9 +1256,6 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap)
EbmlList *chapters_list = &matroska->chapters;
MatroskaChapter *chapters;
MatroskaTrack *tracks;
- EbmlList *index_list;
- MatroskaIndex *index;
- int index_scale = 1;
uint64_t max_start = 0;
Ebml ebml = { 0 };
AVStream *st;
@@ -1529,27 +1585,6 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap)
max_start = chapters[i].start;
}
- index_list = &matroska->index;
- index = index_list->elem;
- if (index_list->nb_elem
- && index[0].time > 100000000000000/matroska->time_scale) {
- av_log(matroska->ctx, AV_LOG_WARNING, "Working around broken index.\n");
- index_scale = matroska->time_scale;
- }
- for (i=0; i<index_list->nb_elem; i++) {
- EbmlList *pos_list = &index[i].pos;
- MatroskaIndexPos *pos = pos_list->elem;
- for (j=0; j<pos_list->nb_elem; j++) {
- MatroskaTrack *track = matroska_find_track_by_num(matroska,
- pos[j].track);
- if (track && track->stream)
- av_add_index_entry(track->stream,
- pos[j].pos + matroska->segment_start,
- index[i].time/index_scale, 0, 0,
- AVINDEX_KEYFRAME);
- }
- }
-
matroska_convert_tags(s);
return 0;
@@ -1898,6 +1933,12 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index,
AVStream *st = s->streams[stream_index];
int i, index, index_sub, index_min;
+ /* Parse the CUES now since we need the index data to seek. */
+ if (matroska->cues_parsing_deferred) {
+ matroska_parse_cues(matroska);
+ matroska->cues_parsing_deferred = 0;
+ }
+
if (!st->nb_index_entries)
return 0;
timestamp = FFMAX(timestamp, st->index_entries[0].timestamp);