AVStream *stream;
int64_t end_timecode;
int ms_compat;
+ int needs_decoding;
uint64_t max_block_additional_id;
uint32_t palette[AVPALETTE_COUNT];
* an entry already exists, return the existing entry.
*/
static MatroskaLevel1Element *matroska_find_level1_elem(MatroskaDemuxContext *matroska,
- uint32_t id)
+ uint32_t id, int64_t pos)
{
int i;
MatroskaLevel1Element *elem;
if (id == MATROSKA_ID_CLUSTER)
return NULL;
- // There can be multiple seekheads.
- if (id != MATROSKA_ID_SEEKHEAD) {
- for (i = 0; i < matroska->num_level1_elems; i++) {
- if (matroska->level1_elems[i].id == id)
+ // There can be multiple SeekHeads and Tags.
+ for (i = 0; i < matroska->num_level1_elems; i++) {
+ if (matroska->level1_elems[i].id == id) {
+ if (matroska->level1_elems[i].pos == pos ||
+ id != MATROSKA_ID_SEEKHEAD && id != MATROSKA_ID_TAGS)
return &matroska->level1_elems[i];
}
}
// Only a completely broken file would have more elements.
- // It also provides a low-effort way to escape from circular seekheads
- // (every iteration will add a level1 entry).
if (matroska->num_level1_elems >= FF_ARRAY_ELEMS(matroska->level1_elems)) {
- av_log(matroska->ctx, AV_LOG_ERROR, "Too many level1 elements or circular seekheads.\n");
+ av_log(matroska->ctx, AV_LOG_ERROR, "Too many level1 elements.\n");
return NULL;
}
if (id == MATROSKA_ID_CUES)
matroska->cues_parsing_deferred = 0;
if (syntax->type == EBML_LEVEL1 &&
- (level1_elem = matroska_find_level1_elem(matroska, syntax->id))) {
+ (level1_elem = matroska_find_level1_elem(matroska, syntax->id, pos))) {
if (!level1_elem->pos) {
// Zero is not a valid position for a level 1 element.
level1_elem->pos = pos;
MatroskaSeekhead *seekheads = seekhead_list->elem;
uint32_t id = seekheads[i].id;
int64_t pos = seekheads[i].pos + matroska->segment_start;
+ MatroskaLevel1Element *elem;
+
+ if (id != seekheads[i].id || pos < matroska->segment_start)
+ continue;
- MatroskaLevel1Element *elem = matroska_find_level1_elem(matroska, id);
+ elem = matroska_find_level1_elem(matroska, id, pos);
if (!elem || elem->parsed)
continue;
}
}
}
+ track->needs_decoding = encodings && !encodings[0].type &&
+ encodings[0].scope & 1 &&
+ (encodings[0].compression.algo !=
+ MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP ||
+ encodings[0].compression.settings.size);
for (j = 0; ff_mkv_codec_tags[j].id != AV_CODEC_ID_NONE; j++) {
if (!strncmp(ff_mkv_codec_tags[j].str, track->codec_id,
uint8_t *data, int size, uint64_t timecode,
int64_t pos)
{
- int a = st->codecpar->block_align;
- int sps = track->audio.sub_packet_size;
- int cfs = track->audio.coded_framesize;
- int h = track->audio.sub_packet_h;
+ const int a = st->codecpar->block_align;
+ const int sps = track->audio.sub_packet_size;
+ const int cfs = track->audio.coded_framesize;
+ const int h = track->audio.sub_packet_h;
+ const int w = track->audio.frame_size;
int y = track->audio.sub_packet_cnt;
- int w = track->audio.frame_size;
int x;
if (!track->audio.pkt_cnt) {
}
/* reconstruct full wavpack blocks from mangled matroska ones */
-static int matroska_parse_wavpack(MatroskaTrack *track, uint8_t *src,
- uint8_t **pdst, int *size)
+static int matroska_parse_wavpack(MatroskaTrack *track,
+ uint8_t **data, int *size)
{
uint8_t *dst = NULL;
+ uint8_t *src = *data;
int dstlen = 0;
int srclen = *size;
uint32_t samples;
memset(dst + dstlen, 0, AV_INPUT_BUFFER_PADDING_SIZE);
- *pdst = dst;
+ *data = dst;
*size = dstlen;
return 0;
return ret;
}
-static int matroska_parse_prores(MatroskaTrack *track, uint8_t *src,
- uint8_t **pdst, int *size)
+static int matroska_parse_prores(MatroskaTrack *track,
+ uint8_t **data, int *size)
{
uint8_t *dst;
int dstlen = *size + 8;
- dst = av_malloc(dstlen + AV_INPUT_BUFFER_PADDING_SIZE);
- if (!dst)
- return AVERROR(ENOMEM);
+ dst = av_malloc(dstlen + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (!dst)
+ return AVERROR(ENOMEM);
- AV_WB32(dst, dstlen);
- AV_WB32(dst + 4, MKBETAG('i', 'c', 'p', 'f'));
- memcpy(dst + 8, src, dstlen - 8);
- memset(dst + dstlen, 0, AV_INPUT_BUFFER_PADDING_SIZE);
+ AV_WB32(dst, dstlen);
+ AV_WB32(dst + 4, MKBETAG('i', 'c', 'p', 'f'));
+ memcpy(dst + 8, *data, dstlen - 8);
+ memset(dst + dstlen, 0, AV_INPUT_BUFFER_PADDING_SIZE);
- *pdst = dst;
+ *data = dst;
*size = dstlen;
return 0;
uint8_t *additional, uint64_t additional_id, int additional_size,
int64_t discard_padding)
{
- MatroskaTrackEncoding *encodings = track->encodings.elem;
uint8_t *pkt_data = data;
int res = 0;
AVPacket pktl, *pkt = &pktl;
- if (encodings && !encodings->type && encodings->scope & 1) {
- res = matroska_decode_buffer(&pkt_data, &pkt_size, track);
- if (res < 0)
- return res;
- }
-
if (st->codecpar->codec_id == AV_CODEC_ID_WAVPACK) {
- uint8_t *wv_data;
- res = matroska_parse_wavpack(track, pkt_data, &wv_data, &pkt_size);
+ res = matroska_parse_wavpack(track, &pkt_data, &pkt_size);
if (res < 0) {
av_log(matroska->ctx, AV_LOG_ERROR,
"Error parsing a wavpack block.\n");
goto fail;
}
- if (pkt_data != data)
- av_freep(&pkt_data);
- pkt_data = wv_data;
+ if (!buf)
+ av_freep(&data);
+ buf = NULL;
}
if (st->codecpar->codec_id == AV_CODEC_ID_PRORES &&
AV_RB32(pkt_data + 4) != MKBETAG('i', 'c', 'p', 'f')) {
- uint8_t *pr_data;
- res = matroska_parse_prores(track, pkt_data, &pr_data, &pkt_size);
+ res = matroska_parse_prores(track, &pkt_data, &pkt_size);
if (res < 0) {
av_log(matroska->ctx, AV_LOG_ERROR,
"Error parsing a prores block.\n");
goto fail;
}
- if (pkt_data != data)
- av_freep(&pkt_data);
- pkt_data = pr_data;
+ if (!buf)
+ av_freep(&data);
+ buf = NULL;
}
if (!pkt_size && !additional_size)
goto no_output;
av_init_packet(pkt);
- if (pkt_data != data)
+ if (!buf)
pkt->buf = av_buffer_create(pkt_data, pkt_size + AV_INPUT_BUFFER_PADDING_SIZE,
NULL, NULL, 0);
else
no_output:
fail:
- if (pkt_data != data)
- av_freep(&pkt_data);
+ if (!buf)
+ av_free(pkt_data);
return res;
}
for (n = 0; n < laces; n++) {
int64_t lace_duration = block_duration*(n+1) / laces - block_duration*n / laces;
+ uint8_t *out_data = data;
+ int out_size = lace_size[n];
+
+ if (track->needs_decoding) {
+ res = matroska_decode_buffer(&out_data, &out_size, track);
+ if (res < 0)
+ return res;
+ /* Given that we are here means that out_data is no longer
+ * owned by buf, so set it to NULL. This depends upon
+ * zero-length header removal compression being ignored. */
+ av_assert1(out_data != data);
+ buf = NULL;
+ }
if (track->audio.buf) {
- res = matroska_parse_rm_audio(matroska, track, st, data,
- lace_size[n],
+ res = matroska_parse_rm_audio(matroska, track, st,
+ out_data, out_size,
timecode, pos);
+ if (!buf)
+ av_free(out_data);
if (res)
return res;
-
} else if (st->codecpar->codec_id == AV_CODEC_ID_WEBVTT) {
res = matroska_parse_webvtt(matroska, track, st,
- data, lace_size[n],
+ out_data, out_size,
timecode, lace_duration,
pos);
+ if (!buf)
+ av_free(out_data);
if (res)
return res;
} else {
- res = matroska_parse_frame(matroska, track, st, buf, data, lace_size[n],
- timecode, lace_duration, pos,
- !n ? is_keyframe : 0,
+ res = matroska_parse_frame(matroska, track, st, buf, out_data,
+ out_size, timecode, lace_duration,
+ pos, !n ? is_keyframe : 0,
additional, additional_id, additional_size,
discard_padding);
if (res)