#include "config.h"
+#include <inttypes.h>
#include <stdio.h>
#if CONFIG_BZLIB
#include <bzlib.h>
#include "libavutil/intfloat.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/lzo.h"
+#include "libavutil/mathematics.h"
#include "libavcodec/bytestream.h"
+#include "libavcodec/flac.h"
#include "libavcodec/mpeg4audio.h"
#include "avformat.h"
#include "internal.h"
#include "isom.h"
#include "matroska.h"
+#include "oggdec.h"
/* For ff_codec_get_id(). */
#include "riff.h"
#include "rmsipr.h"
} def;
} EbmlSyntax;
-typedef struct {
+typedef struct EbmlList {
int nb_elem;
void *elem;
} EbmlList;
-typedef struct {
+typedef struct EbmlBin {
int size;
uint8_t *data;
int64_t pos;
} EbmlBin;
-typedef struct {
+typedef struct Ebml {
uint64_t version;
uint64_t max_size;
uint64_t id_length;
uint64_t doctype_version;
} Ebml;
-typedef struct {
+typedef struct MatroskaTrackCompression {
uint64_t algo;
EbmlBin settings;
} MatroskaTrackCompression;
-typedef struct {
+typedef struct MatroskaTrackEncoding {
uint64_t scope;
uint64_t type;
MatroskaTrackCompression compression;
} MatroskaTrackEncoding;
-typedef struct {
+typedef struct MatroskaTrackVideo {
double frame_rate;
uint64_t display_width;
uint64_t display_height;
uint64_t pixel_width;
uint64_t pixel_height;
uint64_t fourcc;
+ uint64_t interlaced;
+ uint64_t field_order;
+ uint64_t stereo_mode;
} MatroskaTrackVideo;
-typedef struct {
+typedef struct MatroskaTrackAudio {
double samplerate;
double out_samplerate;
uint64_t bitdepth;
uint8_t *buf;
} MatroskaTrackAudio;
-typedef struct {
+typedef struct MatroskaTrack {
uint64_t num;
uint64_t uid;
uint64_t type;
MatroskaTrackVideo video;
MatroskaTrackAudio audio;
EbmlList encodings;
+ uint64_t codec_delay;
AVStream *stream;
int64_t end_timecode;
int ms_compat;
} MatroskaTrack;
-typedef struct {
+typedef struct MatroskaAttachment {
uint64_t uid;
char *filename;
char *mime;
EbmlBin bin;
AVStream *stream;
-} MatroskaAttachement;
+} MatroskaAttachment;
-typedef struct {
+typedef struct MatroskaChapter {
uint64_t start;
uint64_t end;
uint64_t uid;
AVChapter *chapter;
} MatroskaChapter;
-typedef struct {
+typedef struct MatroskaIndexPos {
uint64_t track;
uint64_t pos;
} MatroskaIndexPos;
-typedef struct {
+typedef struct MatroskaIndex {
uint64_t time;
EbmlList pos;
} MatroskaIndex;
-typedef struct {
+typedef struct MatroskaTag {
char *name;
char *string;
char *lang;
EbmlList sub;
} MatroskaTag;
-typedef struct {
+typedef struct MatroskaTagTarget {
char *type;
uint64_t typevalue;
uint64_t trackuid;
uint64_t attachuid;
} MatroskaTagTarget;
-typedef struct {
+typedef struct MatroskaTags {
MatroskaTagTarget target;
EbmlList tag;
} MatroskaTags;
-typedef struct {
+typedef struct MatroskaSeekhead {
uint64_t id;
uint64_t pos;
} MatroskaSeekhead;
-typedef struct {
+typedef struct MatroskaLevel {
uint64_t start;
uint64_t length;
} MatroskaLevel;
-typedef struct {
+typedef struct MatroskaCluster {
uint64_t timecode;
EbmlList blocks;
} MatroskaCluster;
-typedef struct {
+typedef struct MatroskaDemuxContext {
AVFormatContext *ctx;
/* EBML stuff */
int contains_ssa;
} MatroskaDemuxContext;
-typedef struct {
+typedef struct MatroskaBlock {
uint64_t duration;
int64_t reference;
uint64_t non_simple;
{ MATROSKA_ID_VIDEOPIXELCROPL, EBML_NONE },
{ MATROSKA_ID_VIDEOPIXELCROPR, EBML_NONE },
{ MATROSKA_ID_VIDEODISPLAYUNIT, EBML_NONE },
- { MATROSKA_ID_VIDEOFLAGINTERLACED, EBML_NONE },
- { MATROSKA_ID_VIDEOSTEREOMODE, EBML_NONE },
+ { MATROSKA_ID_VIDEOFLAGINTERLACED, EBML_UINT, 0, offsetof(MatroskaTrackVideo, interlaced), { .u = MATROSKA_VIDEO_INTERLACE_FLAG_UNDETERMINED } },
+ { MATROSKA_ID_VIDEOFIELDORDER, EBML_UINT, 0, offsetof(MatroskaTrackVideo, field_order), { .u = MATROSKA_VIDEO_FIELDORDER_UNDETERMINED } },
+ { MATROSKA_ID_VIDEOSTEREOMODE, EBML_UINT, 0, offsetof(MatroskaTrackVideo, stereo_mode), { .u = MATROSKA_VIDEO_STEREOMODE_TYPE_NB } },
{ MATROSKA_ID_VIDEOASPECTRATIO, EBML_NONE },
{ 0 }
};
{ MATROSKA_ID_TRACKTYPE, EBML_UINT, 0, offsetof(MatroskaTrack, type) },
{ 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_TRACKDEFAULTDURATION, EBML_UINT, 0, offsetof(MatroskaTrack, default_duration) },
{ MATROSKA_ID_TRACKTIMECODESCALE, EBML_FLOAT, 0, offsetof(MatroskaTrack, time_scale), { .f = 1.0 } },
};
static EbmlSyntax matroska_attachment[] = {
- { MATROSKA_ID_FILEUID, EBML_UINT, 0, offsetof(MatroskaAttachement, uid) },
- { MATROSKA_ID_FILENAME, EBML_UTF8, 0, offsetof(MatroskaAttachement, filename) },
- { MATROSKA_ID_FILEMIMETYPE, EBML_STR, 0, offsetof(MatroskaAttachement, mime) },
- { MATROSKA_ID_FILEDATA, EBML_BIN, 0, offsetof(MatroskaAttachement, bin) },
+ { MATROSKA_ID_FILEUID, EBML_UINT, 0, offsetof(MatroskaAttachment, uid) },
+ { 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 },
{ 0 }
};
static EbmlSyntax matroska_attachments[] = {
- { MATROSKA_ID_ATTACHEDFILE, EBML_NEST, sizeof(MatroskaAttachement), offsetof(MatroskaDemuxContext, attachments), { .n = matroska_attachment } },
+ { MATROSKA_ID_ATTACHEDFILE, EBML_NEST, sizeof(MatroskaAttachment), offsetof(MatroskaDemuxContext, attachments), { .n = matroska_attachment } },
{ 0 }
};
static int ebml_read_binary(AVIOContext *pb, int length, EbmlBin *bin)
{
av_free(bin->data);
- if (!(bin->data = av_malloc(length + FF_INPUT_BUFFER_PADDING_SIZE)))
+ if (!(bin->data = av_mallocz(length + AV_INPUT_BUFFER_PADDING_SIZE)))
return AVERROR(ENOMEM);
- memset(bin->data + length, 0, FF_INPUT_BUFFER_PADDING_SIZE);
-
bin->size = length;
bin->pos = avio_tell(pb);
if (avio_read(pb, bin->data, length) != length) {
matroska->levels[matroska->num_levels - 1].length == 0xffffffffffffff)
return 0; // we reached the end of an unknown size cluster
if (!syntax[i].id && id != EBML_ID_VOID && id != EBML_ID_CRC32) {
- av_log(matroska->ctx, AV_LOG_INFO, "Unknown entry 0x%X\n", id);
+ av_log(matroska->ctx, AV_LOG_INFO, "Unknown entry 0x%"PRIX32"\n", id);
if (matroska->ctx->error_recognition & AV_EF_EXPLODE)
return AVERROR_INVALIDDATA;
}
es = ec / 100;
ec -= 100 * es;
*ptr++ = '\0';
- len = 50 + end - ptr + FF_INPUT_BUFFER_PADDING_SIZE;
+ len = 50 + end - ptr + AV_INPUT_BUFFER_PADDING_SIZE;
if (!(line = av_buffer_alloc(len)))
return;
snprintf(line->data, len,
memcpy(out->data + old_size, in->data, in->size);
- av_free_packet(in);
+ av_packet_unref(in);
av_free(in);
return 0;
}
for (i = 0; i < matroska->tags.nb_elem; i++) {
if (tags[i].target.attachuid) {
- MatroskaAttachement *attachment = matroska->attachments.elem;
- for (j = 0; j < matroska->attachments.nb_elem; j++)
+ MatroskaAttachment *attachment = matroska->attachments.elem;
+ int found = 0;
+ for (j = 0; j < matroska->attachments.nb_elem; j++) {
if (attachment[j].uid == tags[i].target.attachuid &&
- attachment[j].stream)
+ attachment[j].stream) {
matroska_convert_tag(s, &tags[i].tag,
&attachment[j].stream->metadata, NULL);
+ found = 1;
+ }
+ }
+ if (!found) {
+ av_log(NULL, AV_LOG_WARNING,
+ "The tags at index %d refer to a "
+ "non-existent attachment %"PRId64".\n",
+ i, tags[i].target.attachuid);
+ }
} else if (tags[i].target.chapteruid) {
MatroskaChapter *chapter = matroska->chapters.elem;
- for (j = 0; j < matroska->chapters.nb_elem; j++)
+ int found = 0;
+ for (j = 0; j < matroska->chapters.nb_elem; j++) {
if (chapter[j].uid == tags[i].target.chapteruid &&
- chapter[j].chapter)
+ chapter[j].chapter) {
matroska_convert_tag(s, &tags[i].tag,
&chapter[j].chapter->metadata, NULL);
+ found = 1;
+ }
+ }
+ if (!found) {
+ av_log(NULL, AV_LOG_WARNING,
+ "The tags at index %d refer to a non-existent chapter "
+ "%"PRId64".\n",
+ i, tags[i].target.chapteruid);
+ }
} else if (tags[i].target.trackuid) {
MatroskaTrack *track = matroska->tracks.elem;
- for (j = 0; j < matroska->tracks.nb_elem; j++)
- if (track[j].uid == tags[i].target.trackuid && track[j].stream)
+ int found = 0;
+ for (j = 0; j < matroska->tracks.nb_elem; j++) {
+ if (track[j].uid == tags[i].target.trackuid &&
+ track[j].stream) {
matroska_convert_tag(s, &tags[i].tag,
&track[j].stream->metadata, NULL);
+ found = 1;
+ }
+ }
+ if (!found) {
+ av_log(NULL, AV_LOG_WARNING,
+ "The tags at index %d refer to a non-existent track "
+ "%"PRId64".\n",
+ i, tags[i].target.trackuid);
+ }
} else {
matroska_convert_tag(s, &tags[i].tag, &s->metadata,
tags[i].target.type);
int i;
// we should not do any seeking in the streaming case
- if (!matroska->ctx->pb->seekable ||
+ if (!(matroska->ctx->pb->seekable & AVIO_SEEKABLE_NORMAL) ||
(matroska->ctx->flags & AVFMT_FLAG_IGNIDX))
return;
return sri;
}
-static int matroska_read_header(AVFormatContext *s)
+static int matroska_parse_flac(AVFormatContext *s,
+ MatroskaTrack *track,
+ int *offset)
{
- MatroskaDemuxContext *matroska = s->priv_data;
- EbmlList *attachements_list = &matroska->attachments;
- EbmlList *chapters_list = &matroska->chapters;
- MatroskaAttachement *attachements;
- MatroskaChapter *chapters;
- MatroskaTrack *tracks;
- uint64_t max_start = 0;
- int64_t pos;
- Ebml ebml = { 0 };
- AVStream *st;
- int i, j, res;
+ AVStream *st = track->stream;
+ uint8_t *p = track->codec_priv.data;
+ int size = track->codec_priv.size;
- matroska->ctx = s;
-
- /* First read the EBML header. */
- if (ebml_parse(matroska, ebml_syntax, &ebml) ||
- ebml.version > EBML_VERSION ||
- ebml.max_size > sizeof(uint64_t) ||
- ebml.id_length > sizeof(uint32_t) ||
- ebml.doctype_version > 2) {
- av_log(matroska->ctx, AV_LOG_ERROR,
- "EBML header using unsupported features\n"
- "(EBML version %"PRIu64", doctype %s, doc version %"PRIu64")\n",
- ebml.version, ebml.doctype, ebml.doctype_version);
- ebml_free(ebml_syntax, &ebml);
- return AVERROR_PATCHWELCOME;
+ if (size < 8 + FLAC_STREAMINFO_SIZE || p[4] & 0x7f) {
+ av_log(s, AV_LOG_WARNING, "Invalid FLAC private data\n");
+ track->codec_priv.size = 0;
+ return 0;
}
- for (i = 0; i < FF_ARRAY_ELEMS(matroska_doctypes); i++)
- if (!strcmp(ebml.doctype, matroska_doctypes[i]))
- break;
- if (i >= FF_ARRAY_ELEMS(matroska_doctypes)) {
- av_log(s, AV_LOG_WARNING, "Unknown EBML doctype '%s'\n", ebml.doctype);
- if (matroska->ctx->error_recognition & AV_EF_EXPLODE) {
- ebml_free(ebml_syntax, &ebml);
- return AVERROR_INVALIDDATA;
+ *offset = 8;
+ track->codec_priv.size = 8 + FLAC_STREAMINFO_SIZE;
+
+ p += track->codec_priv.size;
+ size -= track->codec_priv.size;
+
+ /* parse the remaining metadata blocks if present */
+ while (size >= 4) {
+ int block_last, block_type, block_size;
+
+ flac_parse_block_header(p, &block_last, &block_type, &block_size);
+
+ p += 4;
+ size -= 4;
+ if (block_size > size)
+ return 0;
+
+ /* check for the channel mask */
+ if (block_type == FLAC_METADATA_TYPE_VORBIS_COMMENT) {
+ AVDictionary *dict = NULL;
+ AVDictionaryEntry *chmask;
+
+ ff_vorbis_comment(s, &dict, p, block_size, 0);
+ chmask = av_dict_get(dict, "WAVEFORMATEXTENSIBLE_CHANNEL_MASK", NULL, 0);
+ if (chmask) {
+ uint64_t mask = strtol(chmask->value, NULL, 0);
+ if (!mask || mask & ~0x3ffffULL) {
+ av_log(s, AV_LOG_WARNING,
+ "Invalid value of WAVEFORMATEXTENSIBLE_CHANNEL_MASK\n");
+ } else
+ st->codecpar->channel_layout = mask;
+ }
+ av_dict_free(&dict);
}
+
+ p += block_size;
+ size -= block_size;
}
- ebml_free(ebml_syntax, &ebml);
- /* The next thing is a segment. */
- 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);
+ return 0;
+}
+
+static int mkv_field_order(int64_t field_order)
+{
+ switch (field_order) {
+ case MATROSKA_VIDEO_FIELDORDER_PROGRESSIVE:
+ return AV_FIELD_PROGRESSIVE;
+ case MATROSKA_VIDEO_FIELDORDER_UNDETERMINED:
+ return AV_FIELD_UNKNOWN;
+ case MATROSKA_VIDEO_FIELDORDER_TT:
+ return AV_FIELD_TT;
+ case MATROSKA_VIDEO_FIELDORDER_BB:
+ return AV_FIELD_BB;
+ case MATROSKA_VIDEO_FIELDORDER_BT:
+ return AV_FIELD_BT;
+ case MATROSKA_VIDEO_FIELDORDER_TB:
+ return AV_FIELD_TB;
+ default:
+ return AV_FIELD_UNKNOWN;
}
- matroska_execute_seekhead(matroska);
+}
- if (!matroska->time_scale)
- matroska->time_scale = 1000000;
- if (matroska->duration)
- matroska->ctx->duration = matroska->duration * matroska->time_scale *
- 1000 / AV_TIME_BASE;
- av_dict_set(&s->metadata, "title", matroska->title, 0);
+static void mkv_stereo_mode_display_mul(int stereo_mode,
+ int *h_width, int *h_height)
+{
+ switch (stereo_mode) {
+ case MATROSKA_VIDEO_STEREOMODE_TYPE_MONO:
+ case MATROSKA_VIDEO_STEREOMODE_TYPE_CHECKERBOARD_RL:
+ case MATROSKA_VIDEO_STEREOMODE_TYPE_CHECKERBOARD_LR:
+ case MATROSKA_VIDEO_STEREOMODE_TYPE_BOTH_EYES_BLOCK_RL:
+ case MATROSKA_VIDEO_STEREOMODE_TYPE_BOTH_EYES_BLOCK_LR:
+ break;
+ case MATROSKA_VIDEO_STEREOMODE_TYPE_RIGHT_LEFT:
+ case MATROSKA_VIDEO_STEREOMODE_TYPE_LEFT_RIGHT:
+ case MATROSKA_VIDEO_STEREOMODE_TYPE_COL_INTERLEAVED_RL:
+ case MATROSKA_VIDEO_STEREOMODE_TYPE_COL_INTERLEAVED_LR:
+ *h_width = 2;
+ break;
+ case MATROSKA_VIDEO_STEREOMODE_TYPE_BOTTOM_TOP:
+ case MATROSKA_VIDEO_STEREOMODE_TYPE_TOP_BOTTOM:
+ case MATROSKA_VIDEO_STEREOMODE_TYPE_ROW_INTERLEAVED_RL:
+ case MATROSKA_VIDEO_STEREOMODE_TYPE_ROW_INTERLEAVED_LR:
+ *h_height = 2;
+ break;
+ }
+}
+
+static int matroska_parse_tracks(AVFormatContext *s)
+{
+ MatroskaDemuxContext *matroska = s->priv_data;
+ MatroskaTrack *tracks = matroska->tracks.elem;
+ AVStream *st;
+ int i, j, ret;
- tracks = matroska->tracks.elem;
for (i = 0; i < matroska->tracks.nb_elem; i++) {
MatroskaTrack *track = &tracks[i];
enum AVCodecID codec_id = AV_CODEC_ID_NONE;
track->type);
continue;
}
- if (track->codec_id == NULL)
+ if (!track->codec_id)
continue;
if (track->type == MATROSKA_TRACK_TYPE_VIDEO) {
}
st = track->stream = avformat_new_stream(s, NULL);
- if (st == NULL)
+ if (!st)
return AVERROR(ENOMEM);
if (!strcmp(track->codec_id, "V_MS/VFW/FOURCC") &&
track->codec_priv.size >= 40 &&
- track->codec_priv.data != NULL) {
+ track->codec_priv.data) {
track->ms_compat = 1;
track->video.fourcc = AV_RL32(track->codec_priv.data + 16);
codec_id = ff_codec_get_id(ff_codec_bmp_tags,
extradata_offset = 40;
} else if (!strcmp(track->codec_id, "A_MS/ACM") &&
track->codec_priv.size >= 14 &&
- track->codec_priv.data != NULL) {
+ track->codec_priv.data) {
int ret;
ffio_init_context(&b, track->codec_priv.data,
track->codec_priv.size,
0, NULL, NULL, NULL, NULL);
- ret = ff_get_wav_header(&b, st->codec, track->codec_priv.size);
+ ret = ff_get_wav_header(s, &b, st->codecpar, track->codec_priv.size);
if (ret < 0)
return ret;
- codec_id = st->codec->codec_id;
+ codec_id = st->codecpar->codec_id;
extradata_offset = FFMIN(track->codec_priv.size, 18);
} else if (!strcmp(track->codec_id, "V_QUICKTIME") &&
(track->codec_priv.size >= 86) &&
- (track->codec_priv.data != NULL)) {
- track->video.fourcc = AV_RL32(track->codec_priv.data);
- codec_id = ff_codec_get_id(ff_codec_movvideo_tags,
- track->video.fourcc);
+ (track->codec_priv.data)) {
+ if (track->codec_priv.size == AV_RB32(track->codec_priv.data)) {
+ track->video.fourcc = AV_RL32(track->codec_priv.data + 4);
+ codec_id = ff_codec_get_id(ff_codec_movvideo_tags,
+ track->video.fourcc);
+ }
+ if (codec_id == AV_CODEC_ID_NONE) {
+ track->video.fourcc = AV_RL32(track->codec_priv.data);
+ codec_id = ff_codec_get_id(ff_codec_movvideo_tags,
+ track->video.fourcc);
+ }
+ if (codec_id == AV_CODEC_ID_NONE) {
+ char buf[32];
+ av_get_codec_tag_string(buf, sizeof(buf), track->video.fourcc);
+ av_log(matroska->ctx, AV_LOG_ERROR,
+ "mov FourCC not found %s.\n", buf);
+ }
} else if (codec_id == AV_CODEC_ID_PCM_S16BE) {
switch (track->audio.bitdepth) {
case 8:
} else if (codec_id == AV_CODEC_ID_AAC && !track->codec_priv.size) {
int profile = matroska_aac_profile(track->codec_id);
int sri = matroska_aac_sri(track->audio.samplerate);
- extradata = av_mallocz(5 + FF_INPUT_BUFFER_PADDING_SIZE);
- if (extradata == NULL)
+ extradata = av_mallocz(5 + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (!extradata)
return AVERROR(ENOMEM);
extradata[0] = (profile << 3) | ((sri & 0x0E) >> 1);
extradata[1] = ((sri & 0x01) << 7) | (track->audio.channels << 3);
* decoder expects manually. */
extradata_size = 12 + track->codec_priv.size;
extradata = av_mallocz(extradata_size +
- FF_INPUT_BUFFER_PADDING_SIZE);
- if (extradata == NULL)
+ AV_INPUT_BUFFER_PADDING_SIZE);
+ if (!extradata)
return AVERROR(ENOMEM);
AV_WB32(extradata, extradata_size);
memcpy(&extradata[4], "alac", 4);
} else if (codec_id == AV_CODEC_ID_TTA) {
extradata_size = 30;
extradata = av_mallocz(extradata_size);
- if (extradata == NULL)
+ if (!extradata)
return AVERROR(ENOMEM);
ffio_init_context(&b, extradata, extradata_size, 1,
NULL, NULL, NULL, NULL);
return AVERROR_INVALIDDATA;
track->audio.buf = av_malloc(track->audio.frame_size *
track->audio.sub_packet_h);
+ if (!track->audio.buf)
+ return AVERROR(ENOMEM);
if (codec_id == AV_CODEC_ID_RA_288) {
- st->codec->block_align = track->audio.coded_framesize;
+ st->codecpar->block_align = track->audio.coded_framesize;
track->codec_priv.size = 0;
} else {
if (codec_id == AV_CODEC_ID_SIPR && flavor < 4) {
- const int sipr_bit_rate[4] = { 6504, 8496, 5000, 16000 };
+ static const int sipr_bit_rate[4] = { 6504, 8496, 5000, 16000 };
track->audio.sub_packet_size = ff_sipr_subpk_size[flavor];
- st->codec->bit_rate = sipr_bit_rate[flavor];
+ st->codecpar->bit_rate = sipr_bit_rate[flavor];
}
- st->codec->block_align = track->audio.sub_packet_size;
+ st->codecpar->block_align = track->audio.sub_packet_size;
extradata_offset = 78;
}
+ } 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;
}
track->codec_priv.size -= extradata_offset;
avpriv_set_pts_info(st, 64, matroska->time_scale * track->time_scale,
1000 * 1000 * 1000); /* 64 bit pts in ns */
- st->codec->codec_id = codec_id;
+ if (track->type == MATROSKA_TRACK_TYPE_AUDIO &&
+ track->audio.out_samplerate) {
+ st->codecpar->initial_padding = av_rescale_q(track->codec_delay,
+ (AVRational){ 1, 1000000000 },
+ (AVRational){ 1, track->audio.out_samplerate });
+ }
+
+ /* convert the delay from ns to the track timebase */
+ track->codec_delay = av_rescale_q(track->codec_delay,
+ (AVRational){ 1, 1000000000 },
+ st->time_base);
+
+ st->codecpar->codec_id = codec_id;
st->start_time = 0;
if (strcmp(track->language, "und"))
av_dict_set(&st->metadata, "language", track->language, 0);
if (track->flag_forced)
st->disposition |= AV_DISPOSITION_FORCED;
- if (!st->codec->extradata) {
+ if (!st->codecpar->extradata) {
if (extradata) {
- st->codec->extradata = extradata;
- st->codec->extradata_size = extradata_size;
+ st->codecpar->extradata = extradata;
+ st->codecpar->extradata_size = extradata_size;
} else if (track->codec_priv.data && track->codec_priv.size > 0) {
- st->codec->extradata = av_mallocz(track->codec_priv.size +
- FF_INPUT_BUFFER_PADDING_SIZE);
- if (st->codec->extradata == NULL)
+ st->codecpar->extradata = av_mallocz(track->codec_priv.size +
+ AV_INPUT_BUFFER_PADDING_SIZE);
+ if (!st->codecpar->extradata)
return AVERROR(ENOMEM);
- st->codec->extradata_size = track->codec_priv.size;
- memcpy(st->codec->extradata,
+ st->codecpar->extradata_size = track->codec_priv.size;
+ memcpy(st->codecpar->extradata,
track->codec_priv.data + extradata_offset,
track->codec_priv.size);
}
}
if (track->type == MATROSKA_TRACK_TYPE_VIDEO) {
- st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
- st->codec->codec_tag = track->video.fourcc;
- st->codec->width = track->video.pixel_width;
- st->codec->height = track->video.pixel_height;
+ int display_width_mul = 1;
+ int display_height_mul = 1;
+
+ st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codecpar->codec_tag = track->video.fourcc;
+ st->codecpar->width = track->video.pixel_width;
+ st->codecpar->height = track->video.pixel_height;
+
+ if (track->video.interlaced == MATROSKA_VIDEO_INTERLACE_FLAG_INTERLACED)
+ st->codecpar->field_order = mkv_field_order(track->video.field_order);
+
+ if (track->video.stereo_mode && track->video.stereo_mode < MATROSKA_VIDEO_STEREOMODE_TYPE_NB)
+ mkv_stereo_mode_display_mul(track->video.stereo_mode, &display_width_mul, &display_height_mul);
+
av_reduce(&st->sample_aspect_ratio.num,
&st->sample_aspect_ratio.den,
- st->codec->height * track->video.display_width,
- st->codec->width * track->video.display_height,
+ st->codecpar->height * track->video.display_width * display_width_mul,
+ st->codecpar->width * track->video.display_height * display_height_mul,
255);
- if (st->codec->codec_id != AV_CODEC_ID_H264 &&
- st->codec->codec_id != AV_CODEC_ID_HEVC)
+ if (st->codecpar->codec_id != AV_CODEC_ID_H264 &&
+ st->codecpar->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);
}
+ // add stream level stereo3d side data if it is a supported format
+ if (track->video.stereo_mode < MATROSKA_VIDEO_STEREOMODE_TYPE_NB &&
+ track->video.stereo_mode != 10 && track->video.stereo_mode != 12) {
+ int ret = ff_mkv_stereo3d_conv(st, track->video.stereo_mode);
+ if (ret < 0)
+ return ret;
+ }
} else if (track->type == MATROSKA_TRACK_TYPE_AUDIO) {
- st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
- st->codec->sample_rate = track->audio.out_samplerate;
- st->codec->channels = track->audio.channels;
- if (st->codec->codec_id != AV_CODEC_ID_AAC)
+ st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codecpar->sample_rate = track->audio.out_samplerate;
+ st->codecpar->channels = track->audio.channels;
+ if (st->codecpar->codec_id != AV_CODEC_ID_AAC)
st->need_parsing = AVSTREAM_PARSE_HEADERS;
+ if (st->codecpar->codec_id == AV_CODEC_ID_MP3)
+ st->need_parsing = AVSTREAM_PARSE_FULL;
} else if (track->type == MATROSKA_TRACK_TYPE_SUBTITLE) {
- st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
- if (st->codec->codec_id == AV_CODEC_ID_SSA)
+ st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE;
+ if (st->codecpar->codec_id == AV_CODEC_ID_SSA)
matroska->contains_ssa = 1;
}
}
- attachements = attachements_list->elem;
- for (j = 0; j < attachements_list->nb_elem; j++) {
- if (!(attachements[j].filename && attachements[j].mime &&
- attachements[j].bin.data && attachements[j].bin.size > 0)) {
+ return 0;
+}
+
+static int matroska_read_header(AVFormatContext *s)
+{
+ MatroskaDemuxContext *matroska = s->priv_data;
+ EbmlList *attachments_list = &matroska->attachments;
+ EbmlList *chapters_list = &matroska->chapters;
+ MatroskaAttachment *attachments;
+ MatroskaChapter *chapters;
+ uint64_t max_start = 0;
+ int64_t pos;
+ Ebml ebml = { 0 };
+ int i, j, res;
+
+ matroska->ctx = s;
+
+ /* First read the EBML header. */
+ if (ebml_parse(matroska, ebml_syntax, &ebml) || !ebml.doctype) {
+ av_log(matroska->ctx, AV_LOG_ERROR, "EBML header parsing failed\n");
+ ebml_free(ebml_syntax, &ebml);
+ return AVERROR_INVALIDDATA;
+ }
+ if (ebml.version > EBML_VERSION ||
+ ebml.max_size > sizeof(uint64_t) ||
+ ebml.id_length > sizeof(uint32_t) ||
+ ebml.doctype_version > 3) {
+ avpriv_report_missing_feature(matroska->ctx,
+ "EBML version %"PRIu64", doctype %s, doc version %"PRIu64,
+ ebml.version, ebml.doctype, ebml.doctype_version);
+ ebml_free(ebml_syntax, &ebml);
+ return AVERROR_PATCHWELCOME;
+ }
+ for (i = 0; i < FF_ARRAY_ELEMS(matroska_doctypes); i++)
+ if (!strcmp(ebml.doctype, matroska_doctypes[i]))
+ break;
+ if (i >= FF_ARRAY_ELEMS(matroska_doctypes)) {
+ av_log(s, AV_LOG_WARNING, "Unknown EBML doctype '%s'\n", ebml.doctype);
+ if (matroska->ctx->error_recognition & AV_EF_EXPLODE) {
+ ebml_free(ebml_syntax, &ebml);
+ return AVERROR_INVALIDDATA;
+ }
+ }
+ ebml_free(ebml_syntax, &ebml);
+
+ /* The next thing is a segment. */
+ 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)
+ matroska->time_scale = 1000000;
+ if (matroska->duration)
+ matroska->ctx->duration = matroska->duration * matroska->time_scale *
+ 1000 / AV_TIME_BASE;
+ av_dict_set(&s->metadata, "title", matroska->title, 0);
+
+ res = matroska_parse_tracks(s);
+ if (res < 0)
+ return res;
+
+ attachments = attachments_list->elem;
+ for (j = 0; j < attachments_list->nb_elem; j++) {
+ if (!(attachments[j].filename && attachments[j].mime &&
+ attachments[j].bin.data && attachments[j].bin.size > 0)) {
av_log(matroska->ctx, AV_LOG_ERROR, "incomplete attachment\n");
} else {
AVStream *st = avformat_new_stream(s, NULL);
- if (st == NULL)
- break;
- av_dict_set(&st->metadata, "filename", attachements[j].filename, 0);
- av_dict_set(&st->metadata, "mimetype", attachements[j].mime, 0);
- st->codec->codec_id = AV_CODEC_ID_NONE;
- st->codec->codec_type = AVMEDIA_TYPE_ATTACHMENT;
- st->codec->extradata = av_malloc(attachements[j].bin.size);
- if (st->codec->extradata == NULL)
+ if (!st)
break;
- st->codec->extradata_size = attachements[j].bin.size;
- memcpy(st->codec->extradata, attachements[j].bin.data,
- attachements[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, attachements[j].mime,
- strlen(ff_mkv_mime_tags[i].str))) {
- st->codec->codec_id = ff_mkv_mime_tags[i].id;
+ av_dict_set(&st->metadata, "filename", attachments[j].filename, 0);
+ av_dict_set(&st->metadata, "mimetype", attachments[j].mime, 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;
break;
}
}
- attachements[j].stream = st;
+
+ attachments[j].stream = st;
+
+ if (st->codecpar->codec_id != AV_CODEC_ID_NONE) {
+ st->disposition |= AV_DISPOSITION_ATTACHED_PIC;
+ st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
+
+ av_init_packet(&st->attached_pic);
+ if ((res = av_new_packet(&st->attached_pic, attachments[j].bin.size)) < 0)
+ return res;
+ memcpy(st->attached_pic.data, attachments[j].bin.data, attachments[j].bin.size);
+ st->attached_pic.stream_index = st->index;
+ st->attached_pic.flags |= AV_PKT_FLAG_KEY;
+ } else {
+ st->codecpar->codec_type = AVMEDIA_TYPE_ATTACHMENT;
+ st->codecpar->extradata = av_malloc(attachments[j].bin.size);
+ if (!st->codecpar->extradata)
+ break;
+
+ st->codecpar->extradata_size = attachments[j].bin.size;
+ 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;
+ break;
+ }
+ }
+ }
}
}
if (matroska->packets) {
int n;
for (n = 0; n < matroska->num_packets; n++) {
- av_free_packet(matroska->packets[n]);
+ av_packet_unref(matroska->packets[n]);
av_free(matroska->packets[n]);
}
av_freep(&matroska->packets);
uint8_t *data, int size, uint64_t timecode,
uint64_t duration, int64_t pos)
{
- int a = st->codec->block_align;
+ 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;
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 (st->codecpar->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");
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) {
+ } else if (st->codecpar->codec_id == AV_CODEC_ID_SIPR) {
if (size < w) {
av_log(matroska->ctx, AV_LOG_ERROR,
"Corrupt sipr RM-style audio packet size\n");
}
if (++track->audio.sub_packet_cnt >= h) {
- if (st->codec->codec_id == AV_CODEC_ID_SIPR)
+ if (st->codecpar->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) {
+ int ret;
AVPacket *pkt = av_mallocz(sizeof(AVPacket));
- av_new_packet(pkt, a);
+ if (!pkt)
+ return AVERROR(ENOMEM);
+
+ ret = av_new_packet(pkt, a);
+ if (ret < 0) {
+ av_free(pkt);
+ return ret;
+ }
memcpy(pkt->data,
track->audio.buf + a * (h * w / a - track->audio.pkt_cnt--),
a);
uint16_t ver;
int ret, offset = 0;
- if (srclen < 12 || track->stream->codec->extradata_size < 2)
+ if (srclen < 12 || track->stream->codecpar->extradata_size < 2)
return AVERROR_INVALIDDATA;
- ver = AV_RL16(track->stream->codec->extradata);
+ ver = AV_RL16(track->stream->codecpar->extradata);
samples = AV_RL32(src);
src += 4;
return res;
}
- if (st->codec->codec_id == AV_CODEC_ID_WAVPACK) {
+ if (st->codecpar->codec_id == AV_CODEC_ID_WAVPACK) {
uint8_t *wv_data;
res = matroska_parse_wavpack(track, pkt_data, &wv_data, &pkt_size);
if (res < 0) {
pkt_data = wv_data;
}
- if (st->codec->codec_id == AV_CODEC_ID_PRORES)
+ if (st->codecpar->codec_id == AV_CODEC_ID_PRORES)
offset = 8;
pkt = av_mallocz(sizeof(AVPacket));
+ if (!pkt) {
+ av_freep(&pkt_data);
+ return AVERROR(ENOMEM);
+ }
/* XXX: prevent data copy... */
if (av_new_packet(pkt, pkt_size + offset) < 0) {
av_free(pkt);
+ av_freep(&pkt_data);
return AVERROR(ENOMEM);
}
- if (st->codec->codec_id == AV_CODEC_ID_PRORES) {
+ if (st->codecpar->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'));
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)
+ if (track->type != MATROSKA_TRACK_TYPE_SUBTITLE || st->codecpar->codec_id == AV_CODEC_ID_SRT)
pkt->duration = duration;
+#if FF_API_CONVERGENCE_DURATION
+FF_DISABLE_DEPRECATION_WARNINGS
+ if (st->codecpar->codec_id == AV_CODEC_ID_SRT)
+ pkt->convergence_duration = duration;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
- if (st->codec->codec_id == AV_CODEC_ID_SSA)
+ if (st->codecpar->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)
+ st->codecpar->codec_id == AV_CODEC_ID_SSA)
matroska_merge_packets(matroska->prev_pkt, pkt);
else {
dynarray_add(&matroska->packets, &matroska->num_packets, pkt);
if (cluster_time != (uint64_t) -1 &&
(block_time >= 0 || cluster_time >= -block_time)) {
- timecode = cluster_time + block_time;
+ timecode = cluster_time + block_time - track->codec_delay;
if (track->type == MATROSKA_TRACK_TYPE_SUBTITLE &&
timecode < track->end_timecode)
is_keyframe = 0; /* overlapping subtitles are not key frame */
FFMAX(track->end_timecode, timecode + block_duration);
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) {
+ 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],
timecode, duration, pos);
int64_t timestamp, int flags)
{
MatroskaDemuxContext *matroska = s->priv_data;
- MatroskaTrack *tracks = matroska->tracks.elem;
+ MatroskaTrack *tracks = NULL;
AVStream *st = s->streams[stream_index];
int i, index, index_sub, index_min;
return 0;
index_min = index;
+ tracks = matroska->tracks.elem;
for (i = 0; i < matroska->tracks.nb_elem; i++) {
tracks[i].audio.pkt_cnt = 0;
tracks[i].audio.sub_packet_cnt = 0;
tracks[i].audio.buf_timecode = AV_NOPTS_VALUE;
tracks[i].end_timecode = 0;
if (tracks[i].type == MATROSKA_TRACK_TYPE_SUBTITLE &&
- !tracks[i].stream->discard != AVDISCARD_ALL) {
+ tracks[i].stream->discard != AVDISCARD_ALL) {
index_sub = av_index_search_timestamp(
tracks[i].stream, st->index_entries[index].timestamp,
AVSEEK_FLAG_BACKWARD);
AVInputFormat ff_matroska_demuxer = {
.name = "matroska,webm",
.long_name = NULL_IF_CONFIG_SMALL("Matroska / WebM"),
+ .extensions = "mkv,mk3d,mka,mks",
.priv_data_size = sizeof(MatroskaDemuxContext),
.read_probe = matroska_probe,
.read_header = matroska_read_header,
.read_packet = matroska_read_packet,
.read_close = matroska_read_close,
.read_seek = matroska_read_seek,
+ .mime_type = "audio/webm,audio/x-matroska,video/webm,video/x-matroska"
};