/* For ff_codec_get_id(). */
#include "riff.h"
#include "isom.h"
-#include "rm.h"
+#include "rmsipr.h"
#include "matroska.h"
#include "libavcodec/bytestream.h"
#include "libavcodec/mpeg4audio.h"
{ MATROSKA_ID_SIMPLEBLOCK, EBML_BIN, 0, offsetof(MatroskaBlock,bin) },
{ MATROSKA_ID_BLOCKDURATION, EBML_UINT, 0, offsetof(MatroskaBlock,duration), {.u=AV_NOPTS_VALUE} },
{ MATROSKA_ID_BLOCKREFERENCE, EBML_UINT, 0, offsetof(MatroskaBlock,reference) },
+ { MATROSKA_ID_CODECSTATE, EBML_NONE },
{ 1, EBML_UINT, 0, offsetof(MatroskaBlock,non_simple), {.u=1} },
{ 0 }
};
static const char *const matroska_doctypes[] = { "matroska", "webm" };
+static int matroska_resync(MatroskaDemuxContext *matroska, int64_t last_pos)
+{
+ AVIOContext *pb = matroska->ctx->pb;
+ uint32_t id;
+ matroska->current_id = 0;
+ matroska->num_levels = 0;
+
+ /* seek to next position to resync from */
+ if (avio_seek(pb, last_pos + 1, SEEK_SET) < 0)
+ goto eof;
+
+ id = avio_rb32(pb);
+
+ // try to find a toplevel element
+ while (!pb->eof_reached) {
+ if (id == MATROSKA_ID_INFO || id == MATROSKA_ID_TRACKS ||
+ id == MATROSKA_ID_CUES || id == MATROSKA_ID_TAGS ||
+ id == MATROSKA_ID_SEEKHEAD || id == MATROSKA_ID_ATTACHMENTS ||
+ id == MATROSKA_ID_CLUSTER || id == MATROSKA_ID_CHAPTERS) {
+ matroska->current_id = id;
+ return 0;
+ }
+ id = (id << 8) | avio_r8(pb);
+ }
+eof:
+ matroska->done = 1;
+ return AVERROR_EOF;
+}
+
/*
* Return: Whether we reached the end of a level in the hierarchy or not.
*/
break;
case EBML_STR:
case EBML_UTF8:
- *(char **)((char *)data+syntax[i].data_offset) = av_strdup(syntax[i].def.s);
+ // the default may be NULL
+ if (syntax[i].def.s) {
+ uint8_t **dst = (uint8_t**)((uint8_t*)data + syntax[i].data_offset);
+ *dst = av_strdup(syntax[i].def.s);
+ if (!*dst)
+ return AVERROR(ENOMEM);
+ }
break;
}
uint32_t id = syntax->id;
uint64_t length;
int res;
- void *newelem;
data = (char *)data + syntax->data_offset;
if (syntax->list_elem_size) {
EbmlList *list = data;
- newelem = av_realloc(list->elem, (list->nb_elem+1)*syntax->list_elem_size);
- if (!newelem)
- return AVERROR(ENOMEM);
- list->elem = newelem;
+ if ((res = av_reallocp_array(&list->elem,
+ list->nb_elem + 1,
+ syntax->list_elem_size)) < 0) {
+ list->nb_elem = 0;
+ return res;
+ }
data = (char*)list->elem + list->nb_elem*syntax->list_elem_size;
memset(data, 0, syntax->list_elem_size);
list->nb_elem++;
}
// probably valid EBML header but no recognized doctype
- return AVPROBE_SCORE_MAX/2;
+ return AVPROBE_SCORE_EXTENSION;
}
static MatroskaTrack *matroska_find_track_by_num(MatroskaDemuxContext *matroska,
memcpy(pkt_data + header_size, data, isize);
break;
}
+#if CONFIG_LZO
case MATROSKA_TRACK_ENCODING_COMP_LZO:
do {
olen = pkt_size *= 3;
}
pkt_size -= olen;
break;
+#endif
#if CONFIG_ZLIB
case MATROSKA_TRACK_ENCODING_COMP_ZLIB: {
z_stream zstream = {0};
static void matroska_fix_ass_packet(MatroskaDemuxContext *matroska,
AVPacket *pkt, uint64_t display_duration)
{
- char *line, *layer, *ptr = pkt->data, *end = ptr+pkt->size;
+ AVBufferRef *line;
+ char *layer, *ptr = pkt->data, *end = ptr+pkt->size;
for (; *ptr!=',' && ptr<end-1; ptr++);
if (*ptr == ',')
layer = ++ptr;
es = ec/ 100; ec -= 100*es;
*ptr++ = '\0';
len = 50 + end-ptr + FF_INPUT_BUFFER_PADDING_SIZE;
- if (!(line = av_malloc(len)))
+ if (!(line = av_buffer_alloc(len)))
return;
- snprintf(line,len,"Dialogue: %s,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s\r\n",
+ snprintf(line->data, len,"Dialogue: %s,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s\r\n",
layer, sh, sm, ss, sc, eh, em, es, ec, ptr);
- av_free(pkt->data);
- pkt->data = line;
- pkt->size = strlen(line);
+ av_buffer_unref(&pkt->buf);
+ pkt->buf = line;
+ pkt->data = line->data;
+ pkt->size = strlen(line->data);
}
}
static int matroska_merge_packets(AVPacket *out, AVPacket *in)
{
- void *newdata = av_realloc(out->data, out->size+in->size);
- if (!newdata)
- return AVERROR(ENOMEM);
- out->data = newdata;
- memcpy(out->data+out->size, in->data, in->size);
- out->size += in->size;
- av_destruct_packet(in);
+ int old_size = out->size;
+ int ret = av_grow_packet(out, in->size);
+ if (ret < 0)
+ return ret;
+
+ memcpy(out->data + old_size, in->data, in->size);
+
+ av_free_packet(in);
av_free(in);
return 0;
}
int i;
for (i=0; i < list->nb_elem; i++) {
- const char *lang = strcmp(tags[i].lang, "und") ? tags[i].lang : NULL;
+ const char *lang = tags[i].lang && strcmp(tags[i].lang, "und") ?
+ tags[i].lang : NULL;
if (!tags[i].name) {
av_log(s, AV_LOG_WARNING, "Skipping invalid tag with no TagName.\n");
MatroskaChapter *chapters;
MatroskaTrack *tracks;
uint64_t max_start = 0;
+ int64_t pos;
Ebml ebml = { 0 };
AVStream *st;
int i, j, res;
ebml_free(ebml_syntax, &ebml);
/* The next thing is a segment. */
- if ((res = ebml_parse(matroska, matroska_segments, matroska)) < 0)
- return res;
+ pos = avio_tell(matroska->ctx->pb);
+ res = ebml_parse(matroska, matroska_segments, matroska);
+ // try resyncing until we find a EBML_STOP type element.
+ while (res != 1) {
+ res = matroska_resync(matroska, pos);
+ if (res < 0)
+ return res;
+ pos = avio_tell(matroska->ctx->pb);
+ res = ebml_parse(matroska, matroska_segment, matroska);
+ }
matroska_execute_seekhead(matroska);
if (!matroska->time_scale)
"Multiple combined encodings not supported");
} else if (encodings_list->nb_elem == 1) {
if (encodings[0].type ||
- (encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP &&
+ (
#if CONFIG_ZLIB
encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_ZLIB &&
#endif
#if CONFIG_BZLIB
encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_BZLIB &&
#endif
- encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_LZO)) {
+#if CONFIG_LZO
+ encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_LZO &&
+#endif
+ encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP)) {
encodings[0].scope = 0;
av_log(matroska->ctx, AV_LOG_ERROR,
"Unsupported encoding type");
&& track->codec_priv.data != NULL) {
int ret;
ffio_init_context(&b, track->codec_priv.data, track->codec_priv.size,
- AVIO_FLAG_READ, NULL, NULL, NULL, NULL);
+ 0, NULL, NULL, NULL, NULL);
ret = ff_get_wav_header(&b, st->codec, track->codec_priv.size);
if (ret < 0)
return ret;
track->audio.sub_packet_h = avio_rb16(&b);
track->audio.frame_size = avio_rb16(&b);
track->audio.sub_packet_size = avio_rb16(&b);
+ if (flavor <= 0 || track->audio.coded_framesize <= 0 ||
+ track->audio.sub_packet_h <= 0 || track->audio.frame_size <= 0 ||
+ track->audio.sub_packet_size <= 0)
+ return AVERROR_INVALIDDATA;
track->audio.buf = av_malloc(track->audio.frame_size * track->audio.sub_packet_h);
if (codec_id == AV_CODEC_ID_RA_288) {
st->codec->block_align = track->audio.coded_framesize;
st->codec->height * track->video.display_width,
st->codec-> width * track->video.display_height,
255);
- if (st->codec->codec_id != AV_CODEC_ID_H264)
- st->need_parsing = AVSTREAM_PARSE_HEADERS;
+ if (st->codec->codec_id != AV_CODEC_ID_H264 &&
+ st->codec->codec_id != AV_CODEC_ID_HEVC)
+ st->need_parsing = AVSTREAM_PARSE_HEADERS;
if (track->default_duration) {
av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den,
1000000000, track->default_duration, 30000);
-#if FF_API_R_FRAME_RATE
- st->r_frame_rate = st->avg_frame_rate;
-#endif
}
} else if (track->type == MATROSKA_TRACK_TYPE_AUDIO) {
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
*/
static void matroska_clear_queue(MatroskaDemuxContext *matroska)
{
+ matroska->prev_pkt = NULL;
if (matroska->packets) {
int n;
for (n = 0; n < matroska->num_packets; n++) {
}
}
+static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf,
+ int* buf_size, int type,
+ uint32_t **lace_buf, int *laces)
+{
+ int res = 0, n, size = *buf_size;
+ uint8_t *data = *buf;
+ uint32_t *lace_size;
+
+ if (!type) {
+ *laces = 1;
+ *lace_buf = av_mallocz(sizeof(int));
+ if (!*lace_buf)
+ return AVERROR(ENOMEM);
+
+ *lace_buf[0] = size;
+ return 0;
+ }
+
+ assert(size > 0);
+ *laces = *data + 1;
+ data += 1;
+ size -= 1;
+ lace_size = av_mallocz(*laces * sizeof(int));
+ if (!lace_size)
+ return AVERROR(ENOMEM);
+
+ switch (type) {
+ case 0x1: /* Xiph lacing */ {
+ uint8_t temp;
+ uint32_t total = 0;
+ for (n = 0; res == 0 && n < *laces - 1; n++) {
+ while (1) {
+ if (size == 0) {
+ res = AVERROR_EOF;
+ break;
+ }
+ temp = *data;
+ lace_size[n] += temp;
+ data += 1;
+ size -= 1;
+ if (temp != 0xff)
+ break;
+ }
+ total += lace_size[n];
+ }
+ if (size <= total) {
+ res = AVERROR_INVALIDDATA;
+ break;
+ }
+
+ lace_size[n] = size - total;
+ break;
+ }
+
+ case 0x2: /* fixed-size lacing */
+ if (size % (*laces)) {
+ res = AVERROR_INVALIDDATA;
+ break;
+ }
+ for (n = 0; n < *laces; n++)
+ lace_size[n] = size / *laces;
+ break;
+
+ case 0x3: /* EBML lacing */ {
+ uint64_t num;
+ uint64_t total;
+ n = matroska_ebmlnum_uint(matroska, data, size, &num);
+ if (n < 0) {
+ av_log(matroska->ctx, AV_LOG_INFO,
+ "EBML block data error\n");
+ res = n;
+ break;
+ }
+ data += n;
+ size -= n;
+ total = lace_size[0] = num;
+ for (n = 1; res == 0 && n < *laces - 1; n++) {
+ int64_t snum;
+ int r;
+ r = matroska_ebmlnum_sint(matroska, data, size, &snum);
+ if (r < 0) {
+ av_log(matroska->ctx, AV_LOG_INFO,
+ "EBML block data error\n");
+ res = r;
+ break;
+ }
+ data += r;
+ size -= r;
+ lace_size[n] = lace_size[n - 1] + snum;
+ total += lace_size[n];
+ }
+ if (size <= total) {
+ res = AVERROR_INVALIDDATA;
+ break;
+ }
+ lace_size[*laces - 1] = size - total;
+ break;
+ }
+ }
+
+ *buf = data;
+ *lace_buf = lace_size;
+ *buf_size = size;
+
+ return res;
+}
+
+static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska,
+ MatroskaTrack *track,
+ AVStream *st,
+ uint8_t *data, int size,
+ uint64_t timecode, uint64_t duration,
+ int64_t pos)
+{
+ int a = st->codec->block_align;
+ int sps = track->audio.sub_packet_size;
+ int cfs = track->audio.coded_framesize;
+ int h = track->audio.sub_packet_h;
+ int y = track->audio.sub_packet_cnt;
+ int w = track->audio.frame_size;
+ int x;
+
+ if (!track->audio.pkt_cnt) {
+ if (track->audio.sub_packet_cnt == 0)
+ track->audio.buf_timecode = timecode;
+ if (st->codec->codec_id == AV_CODEC_ID_RA_288) {
+ if (size < cfs * h / 2) {
+ av_log(matroska->ctx, AV_LOG_ERROR,
+ "Corrupt int4 RM-style audio packet size\n");
+ return AVERROR_INVALIDDATA;
+ }
+ for (x=0; x<h/2; x++)
+ memcpy(track->audio.buf+x*2*w+y*cfs,
+ data+x*cfs, cfs);
+ } else if (st->codec->codec_id == AV_CODEC_ID_SIPR) {
+ if (size < w) {
+ av_log(matroska->ctx, AV_LOG_ERROR,
+ "Corrupt sipr RM-style audio packet size\n");
+ return AVERROR_INVALIDDATA;
+ }
+ memcpy(track->audio.buf + y*w, data, w);
+ } else {
+ if (size < sps * w / sps) {
+ av_log(matroska->ctx, AV_LOG_ERROR,
+ "Corrupt generic RM-style audio packet size\n");
+ return AVERROR_INVALIDDATA;
+ }
+ for (x=0; x<w/sps; x++)
+ memcpy(track->audio.buf+sps*(h*x+((h+1)/2)*(y&1)+(y>>1)), data+x*sps, sps);
+ }
+
+ if (++track->audio.sub_packet_cnt >= h) {
+ if (st->codec->codec_id == AV_CODEC_ID_SIPR)
+ ff_rm_reorder_sipr_data(track->audio.buf, h, w);
+ track->audio.sub_packet_cnt = 0;
+ track->audio.pkt_cnt = h*w / a;
+ }
+ }
+
+ while (track->audio.pkt_cnt) {
+ AVPacket *pkt = av_mallocz(sizeof(AVPacket));
+ av_new_packet(pkt, a);
+ memcpy(pkt->data, track->audio.buf
+ + a * (h*w / a - track->audio.pkt_cnt--), a);
+ pkt->pts = track->audio.buf_timecode;
+ track->audio.buf_timecode = AV_NOPTS_VALUE;
+ pkt->pos = pos;
+ pkt->stream_index = st->index;
+ dynarray_add(&matroska->packets,&matroska->num_packets,pkt);
+ }
+
+ return 0;
+}
+
+/* reconstruct full wavpack blocks from mangled matroska ones */
+static int matroska_parse_wavpack(MatroskaTrack *track, uint8_t *src,
+ uint8_t **pdst, int *size)
+{
+ uint8_t *dst = NULL;
+ int dstlen = 0;
+ int srclen = *size;
+ uint32_t samples;
+ uint16_t ver;
+ int ret, offset = 0;
+
+ if (srclen < 12 || track->stream->codec->extradata_size < 2)
+ return AVERROR_INVALIDDATA;
+
+ ver = AV_RL16(track->stream->codec->extradata);
+
+ samples = AV_RL32(src);
+ src += 4;
+ srclen -= 4;
+
+ while (srclen >= 8) {
+ int multiblock;
+ uint32_t blocksize;
+ uint8_t *tmp;
+
+ uint32_t flags = AV_RL32(src);
+ uint32_t crc = AV_RL32(src + 4);
+ src += 8;
+ srclen -= 8;
+
+ multiblock = (flags & 0x1800) != 0x1800;
+ if (multiblock) {
+ if (srclen < 4) {
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ blocksize = AV_RL32(src);
+ src += 4;
+ srclen -= 4;
+ } else
+ blocksize = srclen;
+
+ if (blocksize > srclen) {
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+
+ tmp = av_realloc(dst, dstlen + blocksize + 32);
+ if (!tmp) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ dst = tmp;
+ dstlen += blocksize + 32;
+
+ AV_WL32(dst + offset, MKTAG('w', 'v', 'p', 'k')); // tag
+ AV_WL32(dst + offset + 4, blocksize + 24); // blocksize - 8
+ AV_WL16(dst + offset + 8, ver); // version
+ AV_WL16(dst + offset + 10, 0); // track/index_no
+ AV_WL32(dst + offset + 12, 0); // total samples
+ AV_WL32(dst + offset + 16, 0); // block index
+ AV_WL32(dst + offset + 20, samples); // number of samples
+ AV_WL32(dst + offset + 24, flags); // flags
+ AV_WL32(dst + offset + 28, crc); // crc
+ memcpy (dst + offset + 32, src, blocksize); // block data
+
+ src += blocksize;
+ srclen -= blocksize;
+ offset += blocksize + 32;
+ }
+
+ *pdst = dst;
+ *size = dstlen;
+
+ return 0;
+
+fail:
+ av_freep(&dst);
+ return ret;
+}
+
+static int matroska_parse_frame(MatroskaDemuxContext *matroska,
+ MatroskaTrack *track,
+ AVStream *st,
+ uint8_t *data, int pkt_size,
+ uint64_t timecode, uint64_t duration,
+ int64_t pos, int is_keyframe)
+{
+ MatroskaTrackEncoding *encodings = track->encodings.elem;
+ uint8_t *pkt_data = data;
+ int offset = 0, res;
+ AVPacket *pkt;
+
+ if (encodings && encodings->scope & 1) {
+ res = matroska_decode_buffer(&pkt_data, &pkt_size, track);
+ if (res < 0)
+ return res;
+ }
+
+ if (st->codec->codec_id == AV_CODEC_ID_WAVPACK) {
+ uint8_t *wv_data;
+ res = matroska_parse_wavpack(track, pkt_data, &wv_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 (st->codec->codec_id == AV_CODEC_ID_PRORES)
+ offset = 8;
+
+ pkt = av_mallocz(sizeof(AVPacket));
+ /* XXX: prevent data copy... */
+ if (av_new_packet(pkt, pkt_size + offset) < 0) {
+ av_free(pkt);
+ return AVERROR(ENOMEM);
+ }
+
+ if (st->codec->codec_id == AV_CODEC_ID_PRORES) {
+ uint8_t *buf = pkt->data;
+ bytestream_put_be32(&buf, pkt_size);
+ bytestream_put_be32(&buf, MKBETAG('i', 'c', 'p', 'f'));
+ }
+
+ memcpy(pkt->data + offset, pkt_data, pkt_size);
+
+ if (pkt_data != data)
+ av_free(pkt_data);
+
+ pkt->flags = is_keyframe;
+ pkt->stream_index = st->index;
+
+ if (track->ms_compat)
+ pkt->dts = timecode;
+ else
+ pkt->pts = timecode;
+ pkt->pos = pos;
+ if (st->codec->codec_id == AV_CODEC_ID_TEXT)
+ pkt->convergence_duration = duration;
+ else if (track->type != MATROSKA_TRACK_TYPE_SUBTITLE)
+ pkt->duration = duration;
+
+ if (st->codec->codec_id == AV_CODEC_ID_SSA)
+ matroska_fix_ass_packet(matroska, pkt, duration);
+
+ if (matroska->prev_pkt &&
+ timecode != AV_NOPTS_VALUE &&
+ matroska->prev_pkt->pts == timecode &&
+ matroska->prev_pkt->stream_index == st->index &&
+ st->codec->codec_id == AV_CODEC_ID_SSA)
+ matroska_merge_packets(matroska->prev_pkt, pkt);
+ else {
+ dynarray_add(&matroska->packets,&matroska->num_packets,pkt);
+ matroska->prev_pkt = pkt;
+ }
+
+ return 0;
+fail:
+ if (pkt_data != data)
+ av_freep(&pkt_data);
+ return res;
+}
+
static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
int size, int64_t pos, uint64_t cluster_time,
- uint64_t duration, int is_keyframe,
+ uint64_t block_duration, int is_keyframe,
int64_t cluster_pos)
{
uint64_t timecode = AV_NOPTS_VALUE;
MatroskaTrack *track;
int res = 0;
AVStream *st;
- AVPacket *pkt;
int16_t block_time;
uint32_t *lace_size = NULL;
int n, flags, laces = 0;
- uint64_t num;
+ uint64_t num, duration;
if ((n = matroska_ebmlnum_uint(matroska, data, size, &num)) < 0) {
av_log(matroska->ctx, AV_LOG_ERROR, "EBML block data error\n");
st = track->stream;
if (st->discard >= AVDISCARD_ALL)
return res;
- if (duration == AV_NOPTS_VALUE)
- duration = track->default_duration / matroska->time_scale;
block_time = AV_RB16(data);
data += 2;
is_keyframe = 0; /* overlapping subtitles are not key frame */
if (is_keyframe)
av_add_index_entry(st, cluster_pos, timecode, 0,0,AVINDEX_KEYFRAME);
- track->end_timecode = FFMAX(track->end_timecode, timecode+duration);
}
if (matroska->skip_to_keyframe && track->type != MATROSKA_TRACK_TYPE_SUBTITLE) {
matroska->skip_to_keyframe = 0;
}
- switch ((flags & 0x06) >> 1) {
- case 0x0: /* no lacing */
- laces = 1;
- lace_size = av_mallocz(sizeof(int));
- lace_size[0] = size;
- break;
-
- case 0x1: /* Xiph lacing */
- case 0x2: /* fixed-size lacing */
- case 0x3: /* EBML lacing */
- assert(size>0); // size <=3 is checked before size-=3 above
- laces = (*data) + 1;
- data += 1;
- size -= 1;
- lace_size = av_mallocz(laces * sizeof(int));
-
- switch ((flags & 0x06) >> 1) {
- case 0x1: /* Xiph lacing */ {
- uint8_t temp;
- uint32_t total = 0;
- for (n = 0; res == 0 && n < laces - 1; n++) {
- while (1) {
- if (size == 0) {
- res = -1;
- break;
- }
- temp = *data;
- lace_size[n] += temp;
- data += 1;
- size -= 1;
- if (temp != 0xff)
- break;
- }
- total += lace_size[n];
- }
- if (size <= total) {
- res = AVERROR_INVALIDDATA;
- goto end;
- }
- lace_size[n] = size - total;
- break;
- }
+ res = matroska_parse_laces(matroska, &data, &size, (flags & 0x06) >> 1,
+ &lace_size, &laces);
- case 0x2: /* fixed-size lacing */
- if (size != (size / laces) * size) {
- res = AVERROR_INVALIDDATA;
- goto end;
- }
- for (n = 0; n < laces; n++)
- lace_size[n] = size / laces;
- break;
+ if (res)
+ goto end;
- case 0x3: /* EBML lacing */ {
- uint32_t total;
- n = matroska_ebmlnum_uint(matroska, data, size, &num);
- if (n < 0) {
- av_log(matroska->ctx, AV_LOG_INFO,
- "EBML block data error\n");
- res = n;
- goto end;
- }
- data += n;
- size -= n;
- total = lace_size[0] = num;
- for (n = 1; res == 0 && n < laces - 1; n++) {
- int64_t snum;
- int r;
- r = matroska_ebmlnum_sint(matroska, data, size, &snum);
- if (r < 0) {
- av_log(matroska->ctx, AV_LOG_INFO,
- "EBML block data error\n");
- res = r;
- goto end;
- }
- data += r;
- size -= r;
- lace_size[n] = lace_size[n - 1] + snum;
- total += lace_size[n];
- }
- if (size <= total) {
- res = AVERROR_INVALIDDATA;
- goto end;
- }
- lace_size[laces - 1] = size - total;
- break;
- }
- }
- break;
+ if (block_duration != AV_NOPTS_VALUE) {
+ duration = block_duration / laces;
+ if (block_duration != duration * laces) {
+ av_log(matroska->ctx, AV_LOG_WARNING,
+ "Incorrect block_duration, possibly corrupted container");
+ }
+ } else {
+ duration = track->default_duration / matroska->time_scale;
+ block_duration = duration * laces;
}
- if (res == 0) {
- for (n = 0; n < laces; n++) {
- if ((st->codec->codec_id == AV_CODEC_ID_RA_288 ||
- st->codec->codec_id == AV_CODEC_ID_COOK ||
- st->codec->codec_id == AV_CODEC_ID_SIPR ||
- st->codec->codec_id == AV_CODEC_ID_ATRAC3) &&
- st->codec->block_align && track->audio.sub_packet_size) {
- int a = st->codec->block_align;
- int sps = track->audio.sub_packet_size;
- int cfs = track->audio.coded_framesize;
- int h = track->audio.sub_packet_h;
- int y = track->audio.sub_packet_cnt;
- int w = track->audio.frame_size;
- int x;
-
- if (!track->audio.pkt_cnt) {
- if (track->audio.sub_packet_cnt == 0)
- track->audio.buf_timecode = timecode;
- if (st->codec->codec_id == AV_CODEC_ID_RA_288) {
- if (size < cfs * h / 2) {
- av_log(matroska->ctx, AV_LOG_ERROR,
- "Corrupt int4 RM-style audio packet size\n");
- res = AVERROR_INVALIDDATA;
- goto end;
- }
- for (x=0; x<h/2; x++)
- memcpy(track->audio.buf+x*2*w+y*cfs,
- data+x*cfs, cfs);
- } else if (st->codec->codec_id == AV_CODEC_ID_SIPR) {
- if (size < w) {
- av_log(matroska->ctx, AV_LOG_ERROR,
- "Corrupt sipr RM-style audio packet size\n");
- res = AVERROR_INVALIDDATA;
- goto end;
- }
- memcpy(track->audio.buf + y*w, data, w);
- } else {
- if (size < sps * w / sps) {
- av_log(matroska->ctx, AV_LOG_ERROR,
- "Corrupt generic RM-style audio packet size\n");
- res = AVERROR_INVALIDDATA;
- goto end;
- }
- for (x=0; x<w/sps; x++)
- memcpy(track->audio.buf+sps*(h*x+((h+1)/2)*(y&1)+(y>>1)), data+x*sps, sps);
- }
-
- if (++track->audio.sub_packet_cnt >= h) {
- if (st->codec->codec_id == AV_CODEC_ID_SIPR)
- ff_rm_reorder_sipr_data(track->audio.buf, h, w);
- track->audio.sub_packet_cnt = 0;
- track->audio.pkt_cnt = h*w / a;
- }
- }
- while (track->audio.pkt_cnt) {
- pkt = av_mallocz(sizeof(AVPacket));
- av_new_packet(pkt, a);
- memcpy(pkt->data, track->audio.buf
- + a * (h*w / a - track->audio.pkt_cnt--), a);
- pkt->pts = track->audio.buf_timecode;
- track->audio.buf_timecode = AV_NOPTS_VALUE;
- pkt->pos = pos;
- pkt->stream_index = st->index;
- dynarray_add(&matroska->packets,&matroska->num_packets,pkt);
- }
- } else {
- MatroskaTrackEncoding *encodings = track->encodings.elem;
- uint32_t pkt_size = lace_size[n];
- uint8_t *pkt_data = data;
- int offset = 0;
-
- if (encodings && encodings->scope & 1) {
- res = matroska_decode_buffer(&pkt_data, &pkt_size, track);
- if (res < 0)
- break;
- }
+ if (timecode != AV_NOPTS_VALUE)
+ track->end_timecode =
+ FFMAX(track->end_timecode, timecode + block_duration);
- if (st->codec->codec_id == AV_CODEC_ID_PRORES)
- offset = 8;
+ for (n = 0; n < laces; n++) {
+ if ((st->codec->codec_id == AV_CODEC_ID_RA_288 ||
+ st->codec->codec_id == AV_CODEC_ID_COOK ||
+ st->codec->codec_id == AV_CODEC_ID_SIPR ||
+ st->codec->codec_id == AV_CODEC_ID_ATRAC3) &&
+ st->codec->block_align && track->audio.sub_packet_size) {
- pkt = av_mallocz(sizeof(AVPacket));
- /* XXX: prevent data copy... */
- if (av_new_packet(pkt, pkt_size + offset) < 0) {
- av_free(pkt);
- res = AVERROR(ENOMEM);
- break;
- }
+ res = matroska_parse_rm_audio(matroska, track, st, data,
+ lace_size[n],
+ timecode, duration, pos);
+ if (res)
+ goto end;
- if (st->codec->codec_id == AV_CODEC_ID_PRORES) {
- uint8_t *buf = pkt->data;
- bytestream_put_be32(&buf, pkt_size);
- bytestream_put_be32(&buf, MKBETAG('i', 'c', 'p', 'f'));
- }
-
- memcpy(pkt->data + offset, pkt_data, pkt_size);
-
- if (pkt_data != data)
- av_free(pkt_data);
-
- if (n == 0)
- pkt->flags = is_keyframe;
- pkt->stream_index = st->index;
-
- if (track->ms_compat)
- pkt->dts = timecode;
- else
- pkt->pts = timecode;
- pkt->pos = pos;
- if (st->codec->codec_id == AV_CODEC_ID_TEXT)
- pkt->convergence_duration = duration;
- else if (track->type != MATROSKA_TRACK_TYPE_SUBTITLE)
- pkt->duration = duration;
-
- if (st->codec->codec_id == AV_CODEC_ID_SSA)
- matroska_fix_ass_packet(matroska, pkt, duration);
-
- if (matroska->prev_pkt &&
- timecode != AV_NOPTS_VALUE &&
- matroska->prev_pkt->pts == timecode &&
- matroska->prev_pkt->stream_index == st->index &&
- st->codec->codec_id == AV_CODEC_ID_SSA)
- matroska_merge_packets(matroska->prev_pkt, pkt);
- else {
- dynarray_add(&matroska->packets,&matroska->num_packets,pkt);
- matroska->prev_pkt = pkt;
- }
- }
-
- if (timecode != AV_NOPTS_VALUE)
- timecode = duration ? timecode + duration : AV_NOPTS_VALUE;
- data += lace_size[n];
- size -= lace_size[n];
+ } else {
+ res = matroska_parse_frame(matroska, track, st, data, lace_size[n],
+ timecode, duration,
+ pos, !n? is_keyframe : 0);
+ if (res)
+ goto end;
}
+
+ if (timecode != AV_NOPTS_VALUE)
+ timecode = duration ? timecode + duration : AV_NOPTS_VALUE;
+ data += lace_size[n];
}
end:
pos);
}
ebml_free(matroska_cluster, &cluster);
- if (res < 0) matroska->done = 1;
return res;
}
int ret = 0;
while (!ret && matroska_deliver_packet(matroska, pkt)) {
+ int64_t pos = avio_tell(matroska->ctx->pb);
if (matroska->done)
return AVERROR_EOF;
- ret = matroska_parse_cluster(matroska);
+ if (matroska_parse_cluster(matroska) < 0)
+ ret = matroska_resync(matroska, pos);
}
- if (ret == AVERROR_INVALIDDATA) {
+ if (ret == AVERROR_INVALIDDATA && pkt->data) {
pkt->flags |= AV_PKT_FLAG_CORRUPT;
return 0;
}
avio_seek(s->pb, st->index_entries[st->nb_index_entries-1].pos, SEEK_SET);
matroska->current_id = 0;
while ((index = av_index_search_timestamp(st, timestamp, flags)) < 0) {
- matroska->prev_pkt = NULL;
matroska_clear_queue(matroska);
if (matroska_parse_cluster(matroska) < 0)
break;