|
|
|
@ -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); |
|
|
|
|