#include "libavcodec/bytestream.h"
#include "libavcodec/flac.h"
#include "libavcodec/mpeg4audio.h"
+#include "libavcodec/packet_internal.h"
#include "avformat.h"
#include "avio_internal.h"
AVStream *stream;
int64_t end_timecode;
int ms_compat;
+ int needs_decoding;
uint64_t max_block_additional_id;
uint32_t palette[AVPALETTE_COUNT];
typedef struct MatroskaAttachment {
uint64_t uid;
char *filename;
+ char *description;
char *mime;
EbmlBin bin;
{ MATROSKA_ID_CODECID, EBML_STR, 0, offsetof(MatroskaTrack, codec_id) },
{ MATROSKA_ID_CODECPRIVATE, EBML_BIN, 0, offsetof(MatroskaTrack, codec_priv) },
{ MATROSKA_ID_CODECDELAY, EBML_UINT, 0, offsetof(MatroskaTrack, codec_delay) },
- { MATROSKA_ID_TRACKLANGUAGE, EBML_UTF8, 0, offsetof(MatroskaTrack, language), { .s = "eng" } },
+ { MATROSKA_ID_TRACKLANGUAGE, EBML_STR, 0, offsetof(MatroskaTrack, language), { .s = "eng" } },
{ MATROSKA_ID_TRACKDEFAULTDURATION, EBML_UINT, 0, offsetof(MatroskaTrack, default_duration) },
{ MATROSKA_ID_TRACKTIMECODESCALE, EBML_FLOAT, 0, offsetof(MatroskaTrack, time_scale), { .f = 1.0 } },
{ MATROSKA_ID_TRACKFLAGDEFAULT, EBML_UINT, 0, offsetof(MatroskaTrack, flag_default), { .u = 1 } },
{ MATROSKA_ID_FILENAME, EBML_UTF8, 0, offsetof(MatroskaAttachment, filename) },
{ MATROSKA_ID_FILEMIMETYPE, EBML_STR, 0, offsetof(MatroskaAttachment, mime) },
{ MATROSKA_ID_FILEDATA, EBML_BIN, 0, offsetof(MatroskaAttachment, bin) },
- { MATROSKA_ID_FILEDESC, EBML_NONE },
+ { MATROSKA_ID_FILEDESC, EBML_UTF8, 0, offsetof(MatroskaAttachment, description) },
CHILD_OF(matroska_attachments)
};
};
#undef CHILD_OF
+static const CodecMime mkv_image_mime_tags[] = {
+ {"image/gif" , AV_CODEC_ID_GIF},
+ {"image/jpeg" , AV_CODEC_ID_MJPEG},
+ {"image/png" , AV_CODEC_ID_PNG},
+ {"image/tiff" , AV_CODEC_ID_TIFF},
+
+ {"" , AV_CODEC_ID_NONE}
+};
+
+static const CodecMime mkv_mime_tags[] = {
+ {"text/plain" , AV_CODEC_ID_TEXT},
+ {"application/x-truetype-font", AV_CODEC_ID_TTF},
+ {"application/x-font" , AV_CODEC_ID_TTF},
+ {"application/vnd.ms-opentype", AV_CODEC_ID_OTF},
+ {"binary" , AV_CODEC_ID_BIN_DATA},
+
+ {"" , AV_CODEC_ID_NONE}
+};
+
static const char *const matroska_doctypes[] = { "matroska", "webm" };
static int matroska_read_close(AVFormatContext *s);
}
/*
- * Read signed/unsigned "EBML" numbers.
+ * Read a signed "EBML number"
* Return: number of bytes processed, < 0 on error
*/
-static int matroska_ebmlnum_uint(MatroskaDemuxContext *matroska,
- uint8_t *data, uint32_t size, uint64_t *num)
-{
- AVIOContext pb;
- ffio_init_context(&pb, data, size, 0, NULL, NULL, NULL, NULL);
- return ebml_read_num(matroska, &pb, FFMIN(size, 8), num, 1);
-}
-
-/*
- * Same as above, but signed.
- */
static int matroska_ebmlnum_sint(MatroskaDemuxContext *matroska,
- uint8_t *data, uint32_t size, int64_t *num)
+ AVIOContext *pb, int64_t *num)
{
uint64_t unum;
int res;
/* read as unsigned number first */
- if ((res = matroska_ebmlnum_uint(matroska, data, size, &unum)) < 0)
+ if ((res = ebml_read_num(matroska, pb, 8, &unum, 1)) < 0)
return res;
/* make signed (weird way) */
* 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;
}
static MatroskaTrack *matroska_find_track_by_num(MatroskaDemuxContext *matroska,
- int num)
+ uint64_t num)
{
MatroskaTrack *tracks = matroska->tracks.elem;
int i;
if (tracks[i].num == num)
return &tracks[i];
- av_log(matroska->ctx, AV_LOG_ERROR, "Invalid track number %d\n", num);
+ av_log(matroska->ctx, AV_LOG_ERROR, "Invalid track number %"PRIu64"\n", num);
return NULL;
}
#if CONFIG_LZO
case MATROSKA_TRACK_ENCODING_COMP_LZO:
do {
+ int insize = isize;
olen = pkt_size *= 3;
newpktdata = av_realloc(pkt_data, pkt_size + AV_LZO_OUTPUT_PADDING
+ AV_INPUT_BUFFER_PADDING_SIZE);
goto failed;
}
pkt_data = newpktdata;
- result = av_lzo1x_decode(pkt_data, &olen, data, &isize);
+ result = av_lzo1x_decode(pkt_data, &olen, data, &insize);
} while (result == AV_LZO_OUTPUT_FULL && pkt_size < 10000000);
if (result) {
result = AVERROR_INVALIDDATA;
}
}
if (!found) {
- av_log(NULL, AV_LOG_WARNING,
+ av_log(s, AV_LOG_WARNING,
"The tags at index %d refer to a "
"non-existent attachment %"PRId64".\n",
i, tags[i].target.attachuid);
}
}
if (!found) {
- av_log(NULL, AV_LOG_WARNING,
+ av_log(s, AV_LOG_WARNING,
"The tags at index %d refer to a non-existent chapter "
"%"PRId64".\n",
i, tags[i].target.chapteruid);
}
}
if (!found) {
- av_log(NULL, AV_LOG_WARNING,
+ av_log(s, AV_LOG_WARNING,
"The tags at index %d refer to a non-existent track "
"%"PRId64".\n",
i, tags[i].target.trackuid);
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;
static int mkv_field_order(MatroskaDemuxContext *matroska, int64_t field_order)
{
- int major, minor, micro, bttb = 0;
+ int minor, micro, bttb = 0;
/* workaround a bug in our Matroska muxer, introduced in version 57.36 alongside
* this function, and fixed in 57.52 */
- if (matroska->muxingapp && sscanf(matroska->muxingapp, "Lavf%d.%d.%d", &major, &minor, µ) == 3)
- bttb = (major == 57 && minor >= 36 && minor <= 51 && micro >= 100);
+ if (matroska->muxingapp && sscanf(matroska->muxingapp, "Lavf57.%d.%d", &minor, µ) == 2)
+ bttb = (minor >= 36 && minor <= 51 && micro >= 100);
switch (field_order) {
case MATROSKA_VIDEO_FIELDORDER_PROGRESSIVE:
return 0;
}
-static int mkv_parse_video_projection(AVStream *st, const MatroskaTrack *track) {
+static int mkv_parse_video_projection(AVStream *st, const MatroskaTrack *track,
+ void *logctx)
+{
AVSphericalMapping *spherical;
+ const MatroskaTrackVideoProjection *mkv_projection = &track->video.projection;
+ const uint8_t *priv_data = mkv_projection->private.data;
enum AVSphericalProjection projection;
size_t spherical_size;
uint32_t l = 0, t = 0, r = 0, b = 0;
uint32_t padding = 0;
int ret;
- GetByteContext gb;
-
- bytestream2_init(&gb, track->video.projection.private.data,
- track->video.projection.private.size);
- if (bytestream2_get_byte(&gb) != 0) {
- av_log(NULL, AV_LOG_WARNING, "Unknown spherical metadata\n");
+ if (mkv_projection->private.size && priv_data[0] != 0) {
+ av_log(logctx, AV_LOG_WARNING, "Unknown spherical metadata\n");
return 0;
}
- bytestream2_skip(&gb, 3); // flags
-
switch (track->video.projection.type) {
case MATROSKA_VIDEO_PROJECTION_TYPE_EQUIRECTANGULAR:
if (track->video.projection.private.size == 20) {
- t = bytestream2_get_be32(&gb);
- b = bytestream2_get_be32(&gb);
- l = bytestream2_get_be32(&gb);
- r = bytestream2_get_be32(&gb);
+ t = AV_RB32(priv_data + 4);
+ b = AV_RB32(priv_data + 8);
+ l = AV_RB32(priv_data + 12);
+ r = AV_RB32(priv_data + 16);
if (b >= UINT_MAX - t || r >= UINT_MAX - l) {
- av_log(NULL, AV_LOG_ERROR,
+ av_log(logctx, AV_LOG_ERROR,
"Invalid bounding rectangle coordinates "
"%"PRIu32",%"PRIu32",%"PRIu32",%"PRIu32"\n",
l, t, r, b);
return AVERROR_INVALIDDATA;
}
} else if (track->video.projection.private.size != 0) {
- av_log(NULL, AV_LOG_ERROR, "Unknown spherical metadata\n");
+ av_log(logctx, AV_LOG_ERROR, "Unknown spherical metadata\n");
return AVERROR_INVALIDDATA;
}
break;
case MATROSKA_VIDEO_PROJECTION_TYPE_CUBEMAP:
if (track->video.projection.private.size < 4) {
- av_log(NULL, AV_LOG_ERROR, "Missing projection private properties\n");
+ av_log(logctx, AV_LOG_ERROR, "Missing projection private properties\n");
return AVERROR_INVALIDDATA;
} else if (track->video.projection.private.size == 12) {
- uint32_t layout = bytestream2_get_be32(&gb);
+ uint32_t layout = AV_RB32(priv_data + 4);
if (layout) {
- av_log(NULL, AV_LOG_WARNING,
+ av_log(logctx, AV_LOG_WARNING,
"Unknown spherical cubemap layout %"PRIu32"\n", layout);
return 0;
}
projection = AV_SPHERICAL_CUBEMAP;
- padding = bytestream2_get_be32(&gb);
+ padding = AV_RB32(priv_data + 8);
} else {
- av_log(NULL, AV_LOG_ERROR, "Unknown spherical metadata\n");
+ av_log(logctx, AV_LOG_ERROR, "Unknown spherical metadata\n");
return AVERROR_INVALIDDATA;
}
break;
/* No Spherical metadata */
return 0;
default:
- av_log(NULL, AV_LOG_WARNING,
+ av_log(logctx, AV_LOG_WARNING,
"Unknown spherical metadata type %"PRIu64"\n",
track->video.projection.type);
return 0;
}
}
}
+ 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,
if (key_id_base64) {
/* export encryption key id as base64 metadata tag */
- av_dict_set(&st->metadata, "enc_key_id", key_id_base64, 0);
- av_freep(&key_id_base64);
+ av_dict_set(&st->metadata, "enc_key_id", key_id_base64,
+ AV_DICT_DONT_STRDUP_VAL);
}
if (!strcmp(track->codec_id, "V_MS/VFW/FOURCC") &&
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 ||
+ if (track->audio.coded_framesize <= 0 ||
track->audio.sub_packet_h <= 0 ||
- track->audio.frame_size <= 0 ||
- track->audio.sub_packet_size <= 0 && codec_id != AV_CODEC_ID_SIPR)
+ track->audio.frame_size <= 0)
return AVERROR_INVALIDDATA;
- track->audio.buf = av_malloc_array(track->audio.sub_packet_h,
- track->audio.frame_size);
- if (!track->audio.buf)
- return AVERROR(ENOMEM);
+
if (codec_id == AV_CODEC_ID_RA_288) {
+ if (track->audio.sub_packet_h & 1 || 2 * track->audio.frame_size
+ != (int64_t)track->audio.sub_packet_h * track->audio.coded_framesize)
+ return AVERROR_INVALIDDATA;
st->codecpar->block_align = track->audio.coded_framesize;
track->codec_priv.size = 0;
} else {
- if (codec_id == AV_CODEC_ID_SIPR && flavor < 4) {
+ if (codec_id == AV_CODEC_ID_SIPR) {
static const int sipr_bit_rate[4] = { 6504, 8496, 5000, 16000 };
+ if (flavor > 3)
+ return AVERROR_INVALIDDATA;
track->audio.sub_packet_size = ff_sipr_subpk_size[flavor];
st->codecpar->bit_rate = sipr_bit_rate[flavor];
- }
+ } else if (track->audio.sub_packet_size <= 0 ||
+ track->audio.frame_size % track->audio.sub_packet_size)
+ return AVERROR_INVALIDDATA;
st->codecpar->block_align = track->audio.sub_packet_size;
extradata_offset = 78;
}
+ track->audio.buf = av_malloc_array(track->audio.sub_packet_h,
+ track->audio.frame_size);
+ if (!track->audio.buf)
+ return AVERROR(ENOMEM);
} else if (codec_id == AV_CODEC_ID_FLAC && track->codec_priv.size) {
ret = matroska_parse_flac(s, track, &extradata_offset);
if (ret < 0)
return ret;
+ } else if (codec_id == AV_CODEC_ID_WAVPACK && track->codec_priv.size < 2) {
+ av_log(matroska->ctx, AV_LOG_INFO, "Assuming WavPack version 4.10 "
+ "in absence of valid CodecPrivate.\n");
+ extradata_size = 2;
+ extradata = av_mallocz(2 + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (!extradata)
+ return AVERROR(ENOMEM);
+ AV_WL16(extradata, 0x410);
} else if (codec_id == AV_CODEC_ID_PRORES && track->codec_priv.size == 4) {
fourcc = AV_RL32(track->codec_priv.data);
} else if (codec_id == AV_CODEC_ID_VP9 && track->codec_priv.size) {
ret = mkv_parse_video_color(st, track);
if (ret < 0)
return ret;
- ret = mkv_parse_video_projection(st, track);
+ ret = mkv_parse_video_projection(st, track, matroska->ctx);
if (ret < 0)
return ret;
} else if (track->type == MATROSKA_TRACK_TYPE_AUDIO) {
break;
av_dict_set(&st->metadata, "filename", attachments[j].filename, 0);
av_dict_set(&st->metadata, "mimetype", attachments[j].mime, 0);
+ if (attachments[j].description)
+ av_dict_set(&st->metadata, "title", attachments[j].description, 0);
st->codecpar->codec_id = AV_CODEC_ID_NONE;
- for (i = 0; ff_mkv_image_mime_tags[i].id != AV_CODEC_ID_NONE; i++) {
- if (!strncmp(ff_mkv_image_mime_tags[i].str, attachments[j].mime,
- strlen(ff_mkv_image_mime_tags[i].str))) {
- st->codecpar->codec_id = ff_mkv_image_mime_tags[i].id;
+ for (i = 0; mkv_image_mime_tags[i].id != AV_CODEC_ID_NONE; i++) {
+ if (!strncmp(mkv_image_mime_tags[i].str, attachments[j].mime,
+ strlen(mkv_image_mime_tags[i].str))) {
+ st->codecpar->codec_id = mkv_image_mime_tags[i].id;
break;
}
}
st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
av_init_packet(pkt);
- pkt->buf = av_buffer_ref(attachments[j].bin.buf);
- if (!pkt->buf)
- return AVERROR(ENOMEM);
+ pkt->buf = attachments[j].bin.buf;
+ attachments[j].bin.buf = NULL;
pkt->data = attachments[j].bin.data;
pkt->size = attachments[j].bin.size;
pkt->stream_index = st->index;
memcpy(st->codecpar->extradata, attachments[j].bin.data,
attachments[j].bin.size);
- for (i = 0; ff_mkv_mime_tags[i].id != AV_CODEC_ID_NONE; i++) {
- if (!strncmp(ff_mkv_mime_tags[i].str, attachments[j].mime,
- strlen(ff_mkv_mime_tags[i].str))) {
- st->codecpar->codec_id = ff_mkv_mime_tags[i].id;
+ for (i = 0; mkv_mime_tags[i].id != AV_CODEC_ID_NONE; i++) {
+ if (!strncmp(mkv_mime_tags[i].str, attachments[j].mime,
+ strlen(mkv_mime_tags[i].str))) {
+ st->codecpar->codec_id = mkv_mime_tags[i].id;
break;
}
}
(AVRational) { 1, 1000000000 },
chapters[i].start, chapters[i].end,
chapters[i].title);
- if (chapters[i].chapter) {
- av_dict_set(&chapters[i].chapter->metadata,
- "title", chapters[i].title, 0);
- }
max_start = chapters[i].start;
}
MatroskaTrack *tracks = matroska->tracks.elem;
MatroskaTrack *track;
- ff_packet_list_get(&matroska->queue, &matroska->queue_end, pkt);
+ avpriv_packet_list_get(&matroska->queue, &matroska->queue_end, pkt);
track = &tracks[pkt->stream_index];
if (track->has_palette) {
uint8_t *pal = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE);
*/
static void matroska_clear_queue(MatroskaDemuxContext *matroska)
{
- ff_packet_list_free(&matroska->queue, &matroska->queue_end);
+ avpriv_packet_list_free(&matroska->queue, &matroska->queue_end);
}
static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf,
- int size, int type,
+ int size, int type, AVIOContext *pb,
uint32_t lace_size[256], int *laces)
{
int n;
return 0;
}
- av_assert0(size > 0);
- *laces = *data + 1;
- data += 1;
- size -= 1;
+ if (size <= 0)
+ return AVERROR_INVALIDDATA;
+
+ *laces = *data + 1;
+ data += 1;
+ size -= 1;
switch (type) {
case 0x1: /* Xiph lacing */
for (n = 0; n < *laces - 1; n++) {
lace_size[n] = 0;
- while (1) {
- if (size <= total) {
+ do {
+ if (size <= total)
return AVERROR_INVALIDDATA;
- }
temp = *data;
total += temp;
lace_size[n] += temp;
data += 1;
size -= 1;
- if (temp != 0xff)
- break;
- }
+ } while (temp == 0xff);
}
- if (size <= total) {
+ if (size < total)
return AVERROR_INVALIDDATA;
- }
lace_size[n] = size - total;
break;
}
case 0x2: /* fixed-size lacing */
- if (size % (*laces)) {
+ if (size % (*laces))
return AVERROR_INVALIDDATA;
- }
for (n = 0; n < *laces; n++)
lace_size[n] = size / *laces;
break;
{
uint64_t num;
uint64_t total;
- n = matroska_ebmlnum_uint(matroska, data, size, &num);
- if (n < 0 || num > INT_MAX) {
- av_log(matroska->ctx, AV_LOG_INFO,
- "EBML block data error\n");
- return n < 0 ? n : AVERROR_INVALIDDATA;
- }
- data += n;
- size -= n;
+ int offset;
+
+ avio_skip(pb, 4);
+
+ n = ebml_read_num(matroska, pb, 8, &num, 1);
+ if (n < 0)
+ return n;
+ if (num > INT_MAX)
+ return AVERROR_INVALIDDATA;
+
total = lace_size[0] = num;
+ offset = n;
for (n = 1; n < *laces - 1; n++) {
int64_t snum;
int r;
- r = matroska_ebmlnum_sint(matroska, data, size, &snum);
- if (r < 0 || lace_size[n - 1] + snum > (uint64_t)INT_MAX) {
- av_log(matroska->ctx, AV_LOG_INFO,
- "EBML block data error\n");
- return r < 0 ? r : AVERROR_INVALIDDATA;
- }
- data += r;
- size -= r;
+ r = matroska_ebmlnum_sint(matroska, pb, &snum);
+ if (r < 0)
+ return r;
+ if (lace_size[n - 1] + snum > (uint64_t)INT_MAX)
+ return AVERROR_INVALIDDATA;
+
lace_size[n] = lace_size[n - 1] + snum;
total += lace_size[n];
+ offset += r;
}
- if (size <= total) {
+ data += offset;
+ size -= offset;
+ if (size < total)
return AVERROR_INVALIDDATA;
- }
+
lace_size[*laces - 1] = size - total;
break;
}
}
- *buf = data;
+ *buf = data;
return 0;
}
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) {
}
memcpy(track->audio.buf + y * w, data, w);
} else {
- if (size < sps * w / sps || h<=0 || w%sps) {
+ if (size < w) {
av_log(matroska->ctx, AV_LOG_ERROR,
"Corrupt generic RM-style audio packet size\n");
return AVERROR_INVALIDDATA;
track->audio.buf_timecode = AV_NOPTS_VALUE;
pkt->pos = pos;
pkt->stream_index = st->index;
- ret = ff_packet_list_put(&matroska->queue, &matroska->queue_end, pkt, 0);
+ ret = avpriv_packet_list_put(&matroska->queue, &matroska->queue_end, pkt, NULL, 0);
if (ret < 0) {
av_packet_unref(pkt);
return AVERROR(ENOMEM);
}
/* 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;
uint16_t ver;
int ret, offset = 0;
- if (srclen < 12 || track->stream->codecpar->extradata_size < 2)
+ if (srclen < 12)
return AVERROR_INVALIDDATA;
+ av_assert1(track->stream->codecpar->extradata_size >= 2);
ver = AV_RL16(track->stream->codecpar->extradata);
samples = AV_RL32(src);
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 = src;
- int dstlen = *size;
-
- if (AV_RB32(&src[4]) != MKBETAG('i', 'c', 'p', 'f')) {
- dstlen += 8;
+ 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;
pkt->duration = duration;
pkt->pos = pos;
- err = ff_packet_list_put(&matroska->queue, &matroska->queue_end, pkt, 0);
+ err = avpriv_packet_list_put(&matroska->queue, &matroska->queue_end, pkt, NULL, 0);
if (err < 0) {
av_packet_unref(pkt);
return AVERROR(ENOMEM);
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;
+ 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) {
- uint8_t *pr_data;
- res = matroska_parse_prores(track, pkt_data, &pr_data, &pkt_size);
+ if (st->codecpar->codec_id == AV_CODEC_ID_PRORES &&
+ AV_RB32(pkt_data + 4) != MKBETAG('i', 'c', 'p', 'f')) {
+ 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
FF_ENABLE_DEPRECATION_WARNINGS
#endif
- res = ff_packet_list_put(&matroska->queue, &matroska->queue_end, pkt, 0);
+ res = avpriv_packet_list_put(&matroska->queue, &matroska->queue_end, pkt, NULL, 0);
if (res < 0) {
av_packet_unref(pkt);
return AVERROR(ENOMEM);
return 0;
+no_output:
fail:
- if (pkt_data != data)
- av_freep(&pkt_data);
+ if (!buf)
+ av_free(pkt_data);
return res;
}
{
uint64_t timecode = AV_NOPTS_VALUE;
MatroskaTrack *track;
+ AVIOContext pb;
int res = 0;
AVStream *st;
int16_t block_time;
uint64_t num;
int trust_default_duration = 1;
- if ((n = matroska_ebmlnum_uint(matroska, data, size, &num)) < 0) {
+ ffio_init_context(&pb, data, size, 0, NULL, NULL, NULL, NULL);
+
+ if ((n = ebml_read_num(matroska, &pb, 8, &num, 1)) < 0)
return n;
- }
data += n;
size -= n;
track = matroska_find_track_by_num(matroska, num);
- if (!track || !track->stream) {
- av_log(matroska->ctx, AV_LOG_INFO,
- "Invalid stream %"PRIu64"\n", num);
+ if (!track || size < 3)
return AVERROR_INVALIDDATA;
- } else if (size <= 3)
+
+ if (!(st = track->stream)) {
+ av_log(matroska->ctx, AV_LOG_VERBOSE,
+ "No stream associated to TrackNumber %"PRIu64". "
+ "Ignoring Block with this TrackNumber.\n", num);
return 0;
- st = track->stream;
+ }
+
if (st->discard >= AVDISCARD_ALL)
return res;
- av_assert1(block_duration != AV_NOPTS_VALUE);
+ if (block_duration > INT64_MAX)
+ block_duration = INT64_MAX;
block_time = sign_extend(AV_RB16(data), 16);
data += 2;
}
res = matroska_parse_laces(matroska, &data, size, (flags & 0x06) >> 1,
- lace_size, &laces);
- if (res < 0)
+ &pb, lace_size, &laces);
+ if (res < 0) {
+ av_log(matroska->ctx, AV_LOG_ERROR, "Error parsing frame sizes.\n");
return res;
+ }
if (track->audio.samplerate == 8000) {
// If this is needed for more codecs, then add them here
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 ((st->codecpar->codec_id == AV_CODEC_ID_RA_288 ||
- st->codecpar->codec_id == AV_CODEC_ID_COOK ||
- st->codecpar->codec_id == AV_CODEC_ID_SIPR ||
- st->codecpar->codec_id == AV_CODEC_ID_ATRAC3) &&
- st->codecpar->block_align && track->audio.sub_packet_size) {
- res = matroska_parse_rm_audio(matroska, track, st, data,
- lace_size[n],
+ if (track->audio.buf) {
+ 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)
}
end += ret;
}
- av_dict_set(&s->streams[0]->metadata, CUE_TIMESTAMPS, buf, 0);
- av_free(buf);
+ av_dict_set(&s->streams[0]->metadata, CUE_TIMESTAMPS,
+ buf, AV_DICT_DONT_STRDUP_VAL);
return 0;
}
av_log(s, AV_LOG_ERROR, "Failed to read file headers\n");
return -1;
}
- if (!s->nb_streams) {
- matroska_read_close(s);
- av_log(s, AV_LOG_ERROR, "No streams found\n");
- return AVERROR_INVALIDDATA;
+ if (!matroska->tracks.nb_elem || !s->nb_streams) {
+ av_log(s, AV_LOG_ERROR, "No track found\n");
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
}
if (!matroska->is_live) {
buf = av_asprintf("%g", matroska->duration);
- if (!buf) return AVERROR(ENOMEM);
- av_dict_set(&s->streams[0]->metadata, DURATION, buf, 0);
- av_free(buf);
+ if (!buf) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ av_dict_set(&s->streams[0]->metadata, DURATION,
+ buf, AV_DICT_DONT_STRDUP_VAL);
// initialization range
// 5 is the offset of Cluster ID.
ret = webm_dash_manifest_cues(s, init_range);
if (ret < 0) {
av_log(s, AV_LOG_ERROR, "Error parsing Cues\n");
- return ret;
+ goto fail;
}
}
matroska->bandwidth, 0);
}
return 0;
+fail:
+ matroska_read_close(s);
+ return ret;
}
static int webm_dash_manifest_read_packet(AVFormatContext *s, AVPacket *pkt)