X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fmatroskadec.c;h=3a2209f31863c036b3504abd4e64c2d983905e76;hb=be62f5569e40a578ffed8662c4f98182c0a15fe3;hp=d90162b404cb827d73c73633f8c91e9f72abf9b1;hpb=cc8be506379ae89eeac987b1f612fcd7f946babb;p=ffmpeg diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index d90162b404c..3a2209f3186 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -1,6 +1,6 @@ /* * Matroska file demuxer - * Copyright (c) 2003-2008 The ffmpeg Project + * Copyright (c) 2003-2008 The FFmpeg Project * * This file is part of FFmpeg. * @@ -20,14 +20,15 @@ */ /** - * @file matroskadec.c + * @file libavformat/matroskadec.c * Matroska file demuxer * by Ronald Bultje * with a little help from Moritz Bunkus * totally reworked by Aurelien Jacobs - * Specs available on the matroska project page: http://www.matroska.org/. + * Specs available on the Matroska project page: http://www.matroska.org/. */ +#include #include "avformat.h" /* For codec_get_id(). */ #include "riff.h" @@ -35,12 +36,13 @@ #include "matroska.h" #include "libavcodec/mpeg4audio.h" #include "libavutil/intfloat_readwrite.h" +#include "libavutil/intreadwrite.h" #include "libavutil/avstring.h" #include "libavutil/lzo.h" -#ifdef CONFIG_ZLIB +#if CONFIG_ZLIB #include #endif -#ifdef CONFIG_BZLIB +#if CONFIG_BZLIB #include #endif @@ -138,6 +140,7 @@ typedef struct { EbmlList encodings; AVStream *stream; + int64_t end_timecode; } MatroskaTrack; typedef struct { @@ -163,6 +166,12 @@ typedef struct { EbmlList pos; } MatroskaIndex; +typedef struct { + char *name; + char *string; + EbmlList sub; +} MatroskaTag; + typedef struct { uint64_t id; uint64_t pos; @@ -176,7 +185,7 @@ typedef struct { typedef struct { AVFormatContext *ctx; - /* ebml stuff */ + /* EBML stuff */ int num_levels; MatroskaLevel levels[EBML_MAX_DEPTH]; int level_up; @@ -188,25 +197,23 @@ typedef struct { EbmlList attachments; EbmlList chapters; EbmlList index; + EbmlList tags; EbmlList seekhead; - /* num_streams is the number of streams that av_new_stream() was called - * for ( = that are available to the calling program). */ - int num_streams; - /* byte position of the segment inside the stream */ - offset_t segment_start; + int64_t segment_start; - /* The packet queue. */ + /* the packet queue */ AVPacket **packets; int num_packets; + AVPacket *prev_pkt; int done; int has_cluster_id; /* What to skip before effectively reading a packet. */ int skip_to_keyframe; - AVStream *skip_to_stream; + uint64_t skip_to_timecode; } MatroskaDemuxContext; typedef struct { @@ -220,8 +227,6 @@ typedef struct { EbmlList blocks; } MatroskaCluster; -#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x)) - static EbmlSyntax ebml_header[] = { { EBML_ID_EBMLREADVERSION, EBML_UINT, 0, offsetof(Ebml,version), {.u=EBML_VERSION} }, { EBML_ID_EBMLMAXSIZELENGTH, EBML_UINT, 0, offsetof(Ebml,max_size), {.u=8} }, @@ -230,7 +235,6 @@ static EbmlSyntax ebml_header[] = { { EBML_ID_DOCTYPEREADVERSION, EBML_UINT, 0, offsetof(Ebml,doctype_version), {.u=1} }, { EBML_ID_EBMLVERSION, EBML_NONE }, { EBML_ID_DOCTYPEVERSION, EBML_NONE }, - { EBML_ID_VOID, EBML_NONE }, { 0 } }; @@ -247,7 +251,6 @@ static EbmlSyntax matroska_info[] = { { MATROSKA_ID_MUXINGAPP, EBML_NONE }, { MATROSKA_ID_DATEUTC, EBML_NONE }, { MATROSKA_ID_SEGMENTUID, EBML_NONE }, - { EBML_ID_VOID, EBML_NONE }, { 0 } }; @@ -258,10 +261,14 @@ static EbmlSyntax matroska_track_video[] = { { MATROSKA_ID_VIDEOPIXELWIDTH, EBML_UINT, 0, offsetof(MatroskaTrackVideo,pixel_width) }, { MATROSKA_ID_VIDEOPIXELHEIGHT, EBML_UINT, 0, offsetof(MatroskaTrackVideo,pixel_height) }, { MATROSKA_ID_VIDEOCOLORSPACE, EBML_UINT, 0, offsetof(MatroskaTrackVideo,fourcc) }, + { MATROSKA_ID_VIDEOPIXELCROPB, EBML_NONE }, + { MATROSKA_ID_VIDEOPIXELCROPT, EBML_NONE }, + { 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_VIDEOASPECTRATIO, EBML_NONE }, - { EBML_ID_VOID, EBML_NONE }, { 0 } }; @@ -270,14 +277,12 @@ static EbmlSyntax matroska_track_audio[] = { { MATROSKA_ID_AUDIOOUTSAMPLINGFREQ,EBML_FLOAT,0,offsetof(MatroskaTrackAudio,out_samplerate) }, { MATROSKA_ID_AUDIOBITDEPTH, EBML_UINT, 0, offsetof(MatroskaTrackAudio,bitdepth) }, { MATROSKA_ID_AUDIOCHANNELS, EBML_UINT, 0, offsetof(MatroskaTrackAudio,channels), {.u=1} }, - { EBML_ID_VOID, EBML_NONE }, { 0 } }; static EbmlSyntax matroska_track_encoding_compression[] = { { MATROSKA_ID_ENCODINGCOMPALGO, EBML_UINT, 0, offsetof(MatroskaTrackCompression,algo), {.u=0} }, { MATROSKA_ID_ENCODINGCOMPSETTINGS,EBML_BIN, 0, offsetof(MatroskaTrackCompression,settings) }, - { EBML_ID_VOID, EBML_NONE }, { 0 } }; @@ -285,13 +290,12 @@ static EbmlSyntax matroska_track_encoding[] = { { MATROSKA_ID_ENCODINGSCOPE, EBML_UINT, 0, offsetof(MatroskaTrackEncoding,scope), {.u=1} }, { MATROSKA_ID_ENCODINGTYPE, EBML_UINT, 0, offsetof(MatroskaTrackEncoding,type), {.u=0} }, { MATROSKA_ID_ENCODINGCOMPRESSION,EBML_NEST, 0, offsetof(MatroskaTrackEncoding,compression), {.n=matroska_track_encoding_compression} }, - { EBML_ID_VOID, EBML_NONE }, + { MATROSKA_ID_ENCODINGORDER, EBML_NONE }, { 0 } }; static EbmlSyntax matroska_track_encodings[] = { { MATROSKA_ID_TRACKCONTENTENCODING, EBML_NEST, sizeof(MatroskaTrackEncoding), offsetof(MatroskaTrack,encodings), {.n=matroska_track_encoding} }, - { EBML_ID_VOID, EBML_NONE }, { 0 } }; @@ -318,13 +322,12 @@ static EbmlSyntax matroska_track[] = { { MATROSKA_ID_CODECDOWNLOADURL, EBML_NONE }, { MATROSKA_ID_TRACKMINCACHE, EBML_NONE }, { MATROSKA_ID_TRACKMAXCACHE, EBML_NONE }, - { EBML_ID_VOID, EBML_NONE }, + { MATROSKA_ID_TRACKMAXBLKADDID, EBML_NONE }, { 0 } }; static EbmlSyntax matroska_tracks[] = { { MATROSKA_ID_TRACKENTRY, EBML_NEST, sizeof(MatroskaTrack), offsetof(MatroskaDemuxContext,tracks), {.n=matroska_track} }, - { EBML_ID_VOID, EBML_NONE }, { 0 } }; @@ -332,20 +335,19 @@ static EbmlSyntax matroska_attachment[] = { { 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_FILEDESC, EBML_NONE }, { MATROSKA_ID_FILEUID, EBML_NONE }, - { EBML_ID_VOID, EBML_NONE }, { 0 } }; static EbmlSyntax matroska_attachments[] = { { MATROSKA_ID_ATTACHEDFILE, EBML_NEST, sizeof(MatroskaAttachement), offsetof(MatroskaDemuxContext,attachments), {.n=matroska_attachment} }, - { EBML_ID_VOID, EBML_NONE }, { 0 } }; static EbmlSyntax matroska_chapter_display[] = { { MATROSKA_ID_CHAPSTRING, EBML_UTF8, 0, offsetof(MatroskaChapter,title) }, - { EBML_ID_VOID, EBML_NONE }, + { MATROSKA_ID_CHAPLANG, EBML_NONE }, { 0 } }; @@ -355,7 +357,9 @@ static EbmlSyntax matroska_chapter_entry[] = { { MATROSKA_ID_CHAPTERUID, EBML_UINT, 0, offsetof(MatroskaChapter,uid) }, { MATROSKA_ID_CHAPTERDISPLAY, EBML_NEST, 0, 0, {.n=matroska_chapter_display} }, { MATROSKA_ID_CHAPTERFLAGHIDDEN, EBML_NONE }, - { EBML_ID_VOID, EBML_NONE }, + { MATROSKA_ID_CHAPTERFLAGENABLED, EBML_NONE }, + { MATROSKA_ID_CHAPTERPHYSEQUIV, EBML_NONE }, + { MATROSKA_ID_CHAPTERATOM, EBML_NONE }, { 0 } }; @@ -364,51 +368,61 @@ static EbmlSyntax matroska_chapter[] = { { MATROSKA_ID_EDITIONUID, EBML_NONE }, { MATROSKA_ID_EDITIONFLAGHIDDEN, EBML_NONE }, { MATROSKA_ID_EDITIONFLAGDEFAULT, EBML_NONE }, - { EBML_ID_VOID, EBML_NONE }, + { MATROSKA_ID_EDITIONFLAGORDERED, EBML_NONE }, { 0 } }; static EbmlSyntax matroska_chapters[] = { { MATROSKA_ID_EDITIONENTRY, EBML_NEST, 0, 0, {.n=matroska_chapter} }, - { EBML_ID_VOID, EBML_NONE }, { 0 } }; static EbmlSyntax matroska_index_pos[] = { { MATROSKA_ID_CUETRACK, EBML_UINT, 0, offsetof(MatroskaIndexPos,track) }, { MATROSKA_ID_CUECLUSTERPOSITION, EBML_UINT, 0, offsetof(MatroskaIndexPos,pos) }, - { EBML_ID_VOID, EBML_NONE }, + { MATROSKA_ID_CUEBLOCKNUMBER, EBML_NONE }, { 0 } }; static EbmlSyntax matroska_index_entry[] = { { MATROSKA_ID_CUETIME, EBML_UINT, 0, offsetof(MatroskaIndex,time) }, { MATROSKA_ID_CUETRACKPOSITION, EBML_NEST, sizeof(MatroskaIndexPos), offsetof(MatroskaIndex,pos), {.n=matroska_index_pos} }, - { EBML_ID_VOID, EBML_NONE }, { 0 } }; static EbmlSyntax matroska_index[] = { { MATROSKA_ID_POINTENTRY, EBML_NEST, sizeof(MatroskaIndex), offsetof(MatroskaDemuxContext,index), {.n=matroska_index_entry} }, - { EBML_ID_VOID, EBML_NONE }, + { 0 } +}; + +static EbmlSyntax matroska_simpletag[] = { + { MATROSKA_ID_TAGNAME, EBML_UTF8, 0, offsetof(MatroskaTag,name) }, + { MATROSKA_ID_TAGSTRING, EBML_UTF8, 0, offsetof(MatroskaTag,string) }, + { MATROSKA_ID_SIMPLETAG, EBML_NEST, sizeof(MatroskaTag), offsetof(MatroskaTag,sub), {.n=matroska_simpletag} }, + { MATROSKA_ID_TAGLANG, EBML_NONE }, + { MATROSKA_ID_TAGDEFAULT, EBML_NONE }, + { 0 } +}; + +static EbmlSyntax matroska_tag[] = { + { MATROSKA_ID_SIMPLETAG, EBML_NEST, sizeof(MatroskaTag), 0, {.n=matroska_simpletag} }, + { MATROSKA_ID_TAGTARGETS, EBML_NONE }, { 0 } }; static EbmlSyntax matroska_tags[] = { - { EBML_ID_VOID, EBML_NONE }, + { MATROSKA_ID_TAG, EBML_NEST, 0, offsetof(MatroskaDemuxContext,tags), {.n=matroska_tag} }, { 0 } }; static EbmlSyntax matroska_seekhead_entry[] = { { MATROSKA_ID_SEEKID, EBML_UINT, 0, offsetof(MatroskaSeekhead,id) }, { MATROSKA_ID_SEEKPOSITION, EBML_UINT, 0, offsetof(MatroskaSeekhead,pos), {.u=-1} }, - { EBML_ID_VOID, EBML_NONE }, { 0 } }; static EbmlSyntax matroska_seekhead[] = { { MATROSKA_ID_SEEKENTRY, EBML_NEST, sizeof(MatroskaSeekhead), offsetof(MatroskaDemuxContext,seekhead), {.n=matroska_seekhead_entry} }, - { EBML_ID_VOID, EBML_NONE }, { 0 } }; @@ -421,7 +435,6 @@ static EbmlSyntax matroska_segment[] = { { MATROSKA_ID_TAGS, EBML_NEST, 0, 0, {.n=matroska_tags } }, { MATROSKA_ID_SEEKHEAD, EBML_NEST, 0, 0, {.n=matroska_seekhead } }, { MATROSKA_ID_CLUSTER, EBML_STOP, 0, offsetof(MatroskaDemuxContext,has_cluster_id) }, - { EBML_ID_VOID, EBML_NONE }, { 0 } }; @@ -435,7 +448,6 @@ static EbmlSyntax matroska_blockgroup[] = { { 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) }, - { EBML_ID_VOID, EBML_NONE }, { 0 } }; @@ -443,22 +455,46 @@ static EbmlSyntax matroska_cluster[] = { { MATROSKA_ID_CLUSTERTIMECODE,EBML_UINT,0, offsetof(MatroskaCluster,timecode) }, { MATROSKA_ID_BLOCKGROUP, EBML_NEST, sizeof(MatroskaBlock), offsetof(MatroskaCluster,blocks), {.n=matroska_blockgroup} }, { MATROSKA_ID_SIMPLEBLOCK, EBML_PASS, sizeof(MatroskaBlock), offsetof(MatroskaCluster,blocks), {.n=matroska_blockgroup} }, - { EBML_ID_VOID, EBML_NONE }, + { MATROSKA_ID_CLUSTERPOSITION,EBML_NONE }, + { MATROSKA_ID_CLUSTERPREVSIZE,EBML_NONE }, { 0 } }; static EbmlSyntax matroska_clusters[] = { { MATROSKA_ID_CLUSTER, EBML_NEST, 0, 0, {.n=matroska_cluster} }, + { MATROSKA_ID_INFO, EBML_NONE }, + { MATROSKA_ID_CUES, EBML_NONE }, + { MATROSKA_ID_TAGS, EBML_NONE }, + { MATROSKA_ID_SEEKHEAD, EBML_NONE }, { 0 } }; +#define SIZE_OFF(x) sizeof(((AVFormatContext*)0)->x),offsetof(AVFormatContext,x) +const struct { + const char name[16]; + int size; + int offset; +} metadata[] = { + { "TITLE", SIZE_OFF(title) }, + { "ARTIST", SIZE_OFF(author) }, + { "WRITTEN_BY", SIZE_OFF(author) }, + { "LEAD_PERFORMER", SIZE_OFF(author) }, + { "COPYRIGHT", SIZE_OFF(copyright) }, + { "COMMENT", SIZE_OFF(comment) }, + { "ALBUM", SIZE_OFF(album) }, + { "DATE_WRITTEN", SIZE_OFF(year) }, + { "DATE_RELEASED", SIZE_OFF(year) }, + { "PART_NUMBER", SIZE_OFF(track) }, + { "GENRE", SIZE_OFF(genre) }, +}; + /* - * Return: whether we reached the end of a level in the hierarchy or not + * Return: Whether we reached the end of a level in the hierarchy or not. */ static int ebml_level_end(MatroskaDemuxContext *matroska) { ByteIOContext *pb = matroska->ctx->pb; - offset_t pos = url_ftell(pb); + int64_t pos = url_ftell(pb); if (matroska->num_levels > 0) { MatroskaLevel *level = &matroska->levels[matroska->num_levels - 1]; @@ -476,22 +512,21 @@ static int ebml_level_end(MatroskaDemuxContext *matroska) * number of 0-bits followed by a one. The position of the first * "one" bit inside the first byte indicates the length of this * number. - * Returns: num. of bytes read. < 0 on error. + * Returns: number of bytes read, < 0 on error */ -static int ebml_read_num(MatroskaDemuxContext *matroska, +static int ebml_read_num(MatroskaDemuxContext *matroska, ByteIOContext *pb, int max_size, uint64_t *number) { - ByteIOContext *pb = matroska->ctx->pb; int len_mask = 0x80, read = 1, n = 1; int64_t total = 0; - /* the first byte tells us the length in bytes - get_byte() can normally + /* The first byte tells us the length in bytes - get_byte() can normally * return 0, but since that's not a valid first ebmlID byte, we can * use it safely here to catch EOS. */ if (!(total = get_byte(pb))) { /* we might encounter EOS here */ if (!url_feof(pb)) { - offset_t pos = url_ftell(pb); + int64_t pos = url_ftell(pb); av_log(matroska->ctx, AV_LOG_ERROR, "Read error at pos. %"PRIu64" (0x%"PRIx64")\n", pos, pos); @@ -505,7 +540,7 @@ static int ebml_read_num(MatroskaDemuxContext *matroska, len_mask >>= 1; } if (read > max_size) { - offset_t pos = url_ftell(pb) - 1; + int64_t pos = url_ftell(pb) - 1; av_log(matroska->ctx, AV_LOG_ERROR, "Invalid EBML number size tag 0x%02x at pos %"PRIu64" (0x%"PRIx64")\n", (uint8_t) total, pos, pos); @@ -522,23 +557,6 @@ static int ebml_read_num(MatroskaDemuxContext *matroska, return read; } -/* - * Read: the element content data ID. - * 0 is success, < 0 is failure. - */ -static int ebml_read_element_id(MatroskaDemuxContext *matroska, uint32_t *id) -{ - int read; - uint64_t total; - - /* read out the "EBML number", include tag in ID */ - if ((read = ebml_read_num(matroska, 4, &total)) < 0) - return read; - *id = total | (1 << (read * 7)); - - return 0; -} - /* * Read the next element as an unsigned int. * 0 is success, < 0 is failure. @@ -550,7 +568,7 @@ static int ebml_read_uint(ByteIOContext *pb, int size, uint64_t *num) if (size < 1 || size > 8) return AVERROR_INVALIDDATA; - /* big-endian ordening; build up number */ + /* big-endian ordering; build up number */ *num = 0; while (n++ < size) *num = (*num << 8) | get_byte(pb); @@ -581,7 +599,7 @@ static int ebml_read_float(ByteIOContext *pb, int size, double *num) static int ebml_read_ascii(ByteIOContext *pb, int size, char **str) { av_free(*str); - /* ebml strings are usually not 0-terminated, so we allocate one + /* EBML strings are usually not 0-terminated, so we allocate one * byte more, read the string and NULL-terminate it ourselves. */ if (!(*str = av_malloc(size + 1))) return AVERROR(ENOMEM); @@ -637,61 +655,31 @@ static int ebml_read_master(MatroskaDemuxContext *matroska, int length) /* * Read signed/unsigned "EBML" numbers. - * Return: number of bytes processed, < 0 on error. - * XXX: use ebml_read_num(). + * Return: number of bytes processed, < 0 on error */ -static int matroska_ebmlnum_uint(uint8_t *data, uint32_t size, uint64_t *num) +static int matroska_ebmlnum_uint(MatroskaDemuxContext *matroska, + uint8_t *data, uint32_t size, uint64_t *num) { - int len_mask = 0x80, read = 1, n = 1, num_ffs = 0; - uint64_t total; - - if (size <= 0) - return AVERROR_INVALIDDATA; - - total = data[0]; - while (read <= 8 && !(total & len_mask)) { - read++; - len_mask >>= 1; - } - if (read > 8) - return AVERROR_INVALIDDATA; - - if ((total &= (len_mask - 1)) == len_mask - 1) - num_ffs++; - if (size < read) - return AVERROR_INVALIDDATA; - while (n < read) { - if (data[n] == 0xff) - num_ffs++; - total = (total << 8) | data[n]; - n++; - } - - if (read == num_ffs) - *num = (uint64_t)-1; - else - *num = total; - - return read; + ByteIOContext pb; + init_put_byte(&pb, data, size, 0, NULL, NULL, NULL, NULL); + return ebml_read_num(matroska, &pb, 8, num); } /* * Same as above, but signed. */ -static int matroska_ebmlnum_sint(uint8_t *data, uint32_t size, int64_t *num) +static int matroska_ebmlnum_sint(MatroskaDemuxContext *matroska, + uint8_t *data, uint32_t size, int64_t *num) { uint64_t unum; int res; /* read as unsigned number first */ - if ((res = matroska_ebmlnum_uint(data, size, &unum)) < 0) + if ((res = matroska_ebmlnum_uint(matroska, data, size, &unum)) < 0) return res; /* make signed (weird way) */ - if (unum == (uint64_t)-1) - *num = INT64_MAX; - else - *num = unum - ((1LL << ((7 * res) - 1)) - 1); + *num = unum - ((1LL << (7*res - 1)) - 1); return res; } @@ -706,7 +694,7 @@ static int ebml_parse_id(MatroskaDemuxContext *matroska, EbmlSyntax *syntax, for (i=0; syntax[i].id; i++) if (id == syntax[i].id) break; - if (!syntax[i].id) + 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); return ebml_parse_elem(matroska, &syntax[i], data); } @@ -714,8 +702,9 @@ static int ebml_parse_id(MatroskaDemuxContext *matroska, EbmlSyntax *syntax, static int ebml_parse(MatroskaDemuxContext *matroska, EbmlSyntax *syntax, void *data) { - uint32_t id; - int res = ebml_read_element_id(matroska, &id); + uint64_t id; + int res = ebml_read_num(matroska, matroska->ctx->pb, 4, &id); + id |= 1 << 7*res; return res < 0 ? res : ebml_parse_id(matroska, syntax, id, data); } @@ -762,7 +751,7 @@ static int ebml_parse_elem(MatroskaDemuxContext *matroska, } if (syntax->type != EBML_PASS && syntax->type != EBML_STOP) - if ((res = ebml_read_num(matroska, 8, &length)) < 0) + if ((res = ebml_read_num(matroska, pb, 8, &length)) < 0) return res; switch (syntax->type) { @@ -778,7 +767,7 @@ static int ebml_parse_elem(MatroskaDemuxContext *matroska, return ebml_parse_nest(matroska, syntax->def.n, data); case EBML_PASS: return ebml_parse_id(matroska, syntax->def.n, id, data); case EBML_STOP: *(int *)data = 1; return 1; - default: url_fskip(pb, length); return 0; + default: return url_fseek(pb,length,SEEK_CUR)<0 ? AVERROR(EIO) : 0; } if (res == AVERROR_INVALIDDATA) av_log(matroska->ctx, AV_LOG_ERROR, "Invalid element\n"); @@ -818,9 +807,9 @@ static int matroska_probe(AVProbeData *p) { uint64_t total = 0; int len_mask = 0x80, size = 1, n = 1; - char probe_data[] = "matroska"; + static const char probe_data[] = "matroska"; - /* ebml header? */ + /* EBML header? */ if (AV_RB32(p->buf) != EBML_ID_HEADER) return 0; @@ -836,11 +825,11 @@ static int matroska_probe(AVProbeData *p) while (n < size) total = (total << 8) | p->buf[4 + n++]; - /* does the probe data contain the whole header? */ + /* Does the probe data contain the whole header? */ if (p->buf_size < 4 + size + total) return 0; - /* the header must contain the document type 'matroska'. For now, + /* The header must contain the document type 'matroska'. For now, * we don't parse the whole header but simply check for the * availability of that array of characters inside the header. * Not fully fool-proof, but good enough. */ @@ -882,15 +871,14 @@ static int matroska_decode_buffer(uint8_t** buf, int* buf_size, case MATROSKA_TRACK_ENCODING_COMP_LZO: do { olen = pkt_size *= 3; - pkt_data = av_realloc(pkt_data, - pkt_size+LZO_OUTPUT_PADDING); - result = lzo1x_decode(pkt_data, &olen, data, &isize); - } while (result==LZO_OUTPUT_FULL && pkt_size<10000000); + pkt_data = av_realloc(pkt_data, pkt_size+AV_LZO_OUTPUT_PADDING); + result = av_lzo1x_decode(pkt_data, &olen, data, &isize); + } while (result==AV_LZO_OUTPUT_FULL && pkt_size<10000000); if (result) goto failed; pkt_size -= olen; break; -#ifdef CONFIG_ZLIB +#if CONFIG_ZLIB case MATROSKA_TRACK_ENCODING_COMP_ZLIB: { z_stream zstream = {0}; if (inflateInit(&zstream) != Z_OK) @@ -911,7 +899,7 @@ static int matroska_decode_buffer(uint8_t** buf, int* buf_size, break; } #endif -#ifdef CONFIG_BZLIB +#if CONFIG_BZLIB case MATROSKA_TRACK_ENCODING_COMP_BZLIB: { bz_stream bzstream = {0}; if (BZ2_bzDecompressInit(&bzstream, 0, 0) != BZ_OK) @@ -932,6 +920,8 @@ static int matroska_decode_buffer(uint8_t** buf, int* buf_size, break; } #endif + default: + return -1; } *buf = pkt_data; @@ -942,17 +932,78 @@ static int matroska_decode_buffer(uint8_t** buf, int* buf_size, return -1; } +static void matroska_fix_ass_packet(MatroskaDemuxContext *matroska, + AVPacket *pkt, uint64_t display_duration) +{ + char *line, *layer, *ptr = pkt->data, *end = ptr+pkt->size; + for (; *ptr!=',' && ptrpts + display_duration; + int sc = matroska->time_scale * pkt->pts / 10000000; + int ec = matroska->time_scale * end_pts / 10000000; + int sh, sm, ss, eh, em, es, len; + sh = sc/360000; sc -= 360000*sh; + sm = sc/ 6000; sc -= 6000*sm; + ss = sc/ 100; sc -= 100*ss; + eh = ec/360000; ec -= 360000*eh; + em = ec/ 6000; ec -= 6000*em; + es = ec/ 100; ec -= 100*es; + *ptr++ = '\0'; + len = 50 + end-ptr + FF_INPUT_BUFFER_PADDING_SIZE; + if (!(line = av_malloc(len))) + return; + snprintf(line,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); + } +} + +static void matroska_merge_packets(AVPacket *out, AVPacket *in) +{ + out->data = av_realloc(out->data, out->size+in->size); + memcpy(out->data+out->size, in->data, in->size); + out->size += in->size; + av_destruct_packet(in); + av_free(in); +} + +static void matroska_convert_tags(AVFormatContext *s, EbmlList *list) +{ + MatroskaTag *tags = list->elem; + int i, j; + + for (i=0; i < list->nb_elem; i++) { + for (j=0; j < FF_ARRAY_ELEMS(metadata); j++){ + if (!strcmp(tags[i].name, metadata[j].name)) { + int *ptr = (int *)((char *)s + metadata[j].offset); + if (*ptr) continue; + if (metadata[j].size > sizeof(int)) + av_strlcpy((char *)ptr, tags[i].string, metadata[j].size); + else + *ptr = atoi(tags[i].string); + } + } + if (tags[i].sub.nb_elem) + matroska_convert_tags(s, &tags[i].sub); + } +} + static void matroska_execute_seekhead(MatroskaDemuxContext *matroska) { EbmlList *seekhead_list = &matroska->seekhead; MatroskaSeekhead *seekhead = seekhead_list->elem; uint32_t level_up = matroska->level_up; - offset_t before_pos = url_ftell(matroska->ctx->pb); + int64_t before_pos = url_ftell(matroska->ctx->pb); MatroskaLevel level; int i; for (i=0; inb_elem; i++) { - offset_t offset = seekhead[i].pos + matroska->segment_start; + int64_t offset = seekhead[i].pos + matroska->segment_start; if (seekhead[i].pos <= before_pos || seekhead[i].id == MATROSKA_ID_SEEKHEAD @@ -963,7 +1014,7 @@ static void matroska_execute_seekhead(MatroskaDemuxContext *matroska) if (url_fseek(matroska->ctx->pb, offset, SEEK_SET) != offset) continue; - /* we don't want to lose our seekhead level, so we add + /* 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, @@ -994,10 +1045,10 @@ static void matroska_execute_seekhead(MatroskaDemuxContext *matroska) static int matroska_aac_profile(char *codec_id) { - static const char *aac_profiles[] = { "MAIN", "LC", "SSR" }; + static const char * const aac_profiles[] = { "MAIN", "LC", "SSR" }; int profile; - for (profile=0; profiletitle) strncpy(matroska->ctx->title, matroska->title, sizeof(matroska->ctx->title)-1); + matroska_convert_tags(s, &matroska->tags); tracks = matroska->tracks.elem; for (i=0; i < matroska->tracks.nb_elem; i++) { @@ -1063,6 +1117,7 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap) uint8_t *extradata = NULL; int extradata_size = 0; int extradata_offset = 0; + ByteIOContext b; /* Apply some sanity checks. */ if (track->type != MATROSKA_TRACK_TYPE_VIDEO && @@ -1093,10 +1148,10 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap) } else if (encodings_list->nb_elem == 1) { if (encodings[0].type || (encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP && -#ifdef CONFIG_ZLIB +#if CONFIG_ZLIB encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_ZLIB && #endif -#ifdef CONFIG_BZLIB +#if CONFIG_BZLIB encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_BZLIB && #endif encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_LZO)) { @@ -1134,7 +1189,7 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap) } } - st = track->stream = av_new_stream(s, matroska->num_streams++); + st = track->stream = av_new_stream(s, 0); if (st == NULL) return AVERROR(ENOMEM); @@ -1146,13 +1201,31 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap) } else if (!strcmp(track->codec_id, "A_MS/ACM") && track->codec_priv.size >= 18 && track->codec_priv.data != NULL) { - uint16_t tag = AV_RL16(track->codec_priv.data); - codec_id = codec_get_id(codec_wav_tags, tag); + init_put_byte(&b, track->codec_priv.data, track->codec_priv.size, + URL_RDONLY, NULL, NULL, NULL, NULL); + get_wav_header(&b, st->codec, track->codec_priv.size); + codec_id = st->codec->codec_id; + extradata_offset = 18; + track->codec_priv.size -= extradata_offset; } 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=codec_get_id(codec_movvideo_tags, track->video.fourcc); + } else if (codec_id == CODEC_ID_PCM_S16BE) { + switch (track->audio.bitdepth) { + case 8: codec_id = CODEC_ID_PCM_U8; break; + case 24: codec_id = CODEC_ID_PCM_S24BE; break; + case 32: codec_id = CODEC_ID_PCM_S32BE; break; + } + } else if (codec_id == CODEC_ID_PCM_S16LE) { + switch (track->audio.bitdepth) { + case 8: codec_id = CODEC_ID_PCM_U8; break; + case 24: codec_id = CODEC_ID_PCM_S24LE; break; + case 32: codec_id = CODEC_ID_PCM_S32LE; break; + } + } else if (codec_id==CODEC_ID_PCM_F32LE && track->audio.bitdepth==64) { + codec_id = CODEC_ID_PCM_F64LE; } else if (codec_id == CODEC_ID_AAC && !track->codec_priv.size) { int profile = matroska_aac_profile(track->codec_id); int sri = matroska_aac_sri(track->audio.samplerate); @@ -1170,7 +1243,6 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap) } else extradata_size = 2; } else if (codec_id == CODEC_ID_TTA) { - ByteIOContext b; extradata_size = 30; extradata = av_mallocz(extradata_size); if (extradata == NULL) @@ -1192,8 +1264,6 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap) track->audio.channels = 1; } else if (codec_id == CODEC_ID_RA_288 || codec_id == CODEC_ID_COOK || codec_id == CODEC_ID_ATRAC3) { - ByteIOContext b; - init_put_byte(&b, track->codec_priv.data,track->codec_priv.size, 0, NULL, NULL, NULL, NULL); url_fskip(&b, 24); @@ -1217,6 +1287,8 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap) av_log(matroska->ctx, AV_LOG_INFO, "Unknown/unsupported CodecID %s.\n", track->codec_id); + if (track->time_scale < 0.01) + track->time_scale = 1.0; av_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; @@ -1235,7 +1307,8 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap) st->codec->extradata = extradata; st->codec->extradata_size = extradata_size; } else if(track->codec_priv.data && track->codec_priv.size > 0){ - st->codec->extradata = av_malloc(track->codec_priv.size); + st->codec->extradata = av_mallocz(track->codec_priv.size + + FF_INPUT_BUFFER_PADDING_SIZE); if(st->codec->extradata == NULL) return AVERROR(ENOMEM); st->codec->extradata_size = track->codec_priv.size; @@ -1249,8 +1322,8 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap) st->codec->codec_tag = track->video.fourcc; st->codec->width = track->video.pixel_width; st->codec->height = track->video.pixel_height; - av_reduce(&st->codec->sample_aspect_ratio.num, - &st->codec->sample_aspect_ratio.den, + 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, 255); @@ -1270,7 +1343,7 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap) attachements[j].bin.data && attachements[j].bin.size > 0)) { av_log(matroska->ctx, AV_LOG_ERROR, "incomplete attachment\n"); } else { - AVStream *st = av_new_stream(s, matroska->num_streams++); + AVStream *st = av_new_stream(s, 0); if (st == NULL) break; st->filename = av_strdup(attachements[j].filename); @@ -1294,13 +1367,21 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap) chapters = chapters_list->elem; for (i=0; inb_elem; i++) - if (chapters[i].start != AV_NOPTS_VALUE && chapters[i].uid) + if (chapters[i].start != AV_NOPTS_VALUE && chapters[i].uid + && (max_start==0 || chapters[i].start > max_start)) { ff_new_chapter(s, chapters[i].uid, (AVRational){1, 1000000000}, chapters[i].start, chapters[i].end, chapters[i].title); + 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; inb_elem; i++) { EbmlList *pos_list = &index[i].pos; MatroskaIndexPos *pos = pos_list->elem; @@ -1310,27 +1391,14 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap) if (track && track->stream) av_add_index_entry(track->stream, pos[j].pos + matroska->segment_start, - index[i].time*matroska->time_scale/AV_TIME_BASE, - 0, 0, AVINDEX_KEYFRAME); + index[i].time/index_scale, 0, 0, + AVINDEX_KEYFRAME); } } return 0; } -/* - * Put a packet into our internal queue. Will be delivered to the - * user/application during the next get_packet() call. - */ -static void matroska_queue_packet(MatroskaDemuxContext *matroska, AVPacket *pkt) -{ - matroska->packets = - av_realloc(matroska->packets, (matroska->num_packets + 1) * - sizeof(AVPacket *)); - matroska->packets[matroska->num_packets] = pkt; - matroska->num_packets++; -} - /* * Put one packet in an application-supplied AVPacket struct. * Returns 0 on success or -1 on failure. @@ -1368,16 +1436,17 @@ static void matroska_clear_queue(MatroskaDemuxContext *matroska) av_free_packet(matroska->packets[n]); av_free(matroska->packets[n]); } - av_free(matroska->packets); - matroska->packets = NULL; + av_freep(&matroska->packets); matroska->num_packets = 0; } } 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 duration, int is_keyframe, + int64_t cluster_pos) { + uint64_t timecode = AV_NOPTS_VALUE; MatroskaTrack *track; int res = 0; AVStream *st; @@ -1387,7 +1456,7 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int n, flags, laces = 0; uint64_t num; - if ((n = matroska_ebmlnum_uint(data, size, &num)) < 0) { + if ((n = matroska_ebmlnum_uint(matroska, data, size, &num)) < 0) { av_log(matroska->ctx, AV_LOG_ERROR, "EBML block data error\n"); return res; } @@ -1413,8 +1482,19 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, if (is_keyframe == -1) is_keyframe = flags & 0x80 ? PKT_FLAG_KEY : 0; - if (matroska->skip_to_keyframe) { - if (!is_keyframe || st != matroska->skip_to_stream) + if (cluster_time != (uint64_t)-1 + && (block_time >= 0 || cluster_time >= -block_time)) { + timecode = cluster_time + block_time; + if (track->type == MATROSKA_TRACK_TYPE_SUBTITLE + && timecode < track->end_timecode) + 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) { + if (!is_keyframe || timecode < matroska->skip_to_timecode) return res; matroska->skip_to_keyframe = 0; } @@ -1426,7 +1506,7 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, lace_size[0] = size; break; - case 0x1: /* xiph lacing */ + case 0x1: /* Xiph lacing */ case 0x2: /* fixed-size lacing */ case 0x3: /* EBML lacing */ assert(size>0); // size <=3 is checked before size-=3 above @@ -1436,7 +1516,7 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, lace_size = av_mallocz(laces * sizeof(int)); switch ((flags & 0x06) >> 1) { - case 0x1: /* xiph lacing */ { + case 0x1: /* Xiph lacing */ { uint8_t temp; uint32_t total = 0; for (n = 0; res == 0 && n < laces - 1; n++) { @@ -1465,7 +1545,7 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, case 0x3: /* EBML lacing */ { uint32_t total; - n = matroska_ebmlnum_uint(data, size, &num); + n = matroska_ebmlnum_uint(matroska, data, size, &num); if (n < 0) { av_log(matroska->ctx, AV_LOG_INFO, "EBML block data error\n"); @@ -1477,7 +1557,7 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, for (n = 1; res == 0 && n < laces - 1; n++) { int64_t snum; int r; - r = matroska_ebmlnum_sint (data, size, &snum); + r = matroska_ebmlnum_sint(matroska, data, size, &snum); if (r < 0) { av_log(matroska->ctx, AV_LOG_INFO, "EBML block data error\n"); @@ -1496,12 +1576,6 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, } if (res == 0) { - uint64_t timecode = AV_NOPTS_VALUE; - - if (cluster_time != (uint64_t)-1 - && (block_time >= 0 || cluster_time >= -block_time)) - timecode = cluster_time + block_time; - for (n = 0; n < laces; n++) { if (st->codec->codec_id == CODEC_ID_RA_288 || st->codec->codec_id == CODEC_ID_COOK || @@ -1535,7 +1609,7 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, + a * (h*w / a - track->audio.pkt_cnt--), a); pkt->pos = pos; pkt->stream_index = st->index; - matroska_queue_packet(matroska, pkt); + dynarray_add(&matroska->packets,&matroska->num_packets,pkt); } } else { MatroskaTrackEncoding *encodings = track->encodings.elem; @@ -1569,9 +1643,23 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, pkt->pts = timecode; pkt->pos = pos; - pkt->duration = duration; - - matroska_queue_packet(matroska, pkt); + if (st->codec->codec_id == CODEC_ID_TEXT) + pkt->convergence_duration = duration; + else if (track->type != MATROSKA_TRACK_TYPE_SUBTITLE) + pkt->duration = duration; + + if (st->codec->codec_id == 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) + 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) @@ -1590,23 +1678,28 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska) EbmlList *blocks_list; MatroskaBlock *blocks; int i, res; + int64_t pos = url_ftell(matroska->ctx->pb); + matroska->prev_pkt = NULL; if (matroska->has_cluster_id){ - /* For the first cluster we parse, it's ID was already read as + /* For the first cluster we parse, its ID was already read as part of matroska_read_header(), so don't read it again */ res = ebml_parse_id(matroska, matroska_clusters, MATROSKA_ID_CLUSTER, &cluster); + pos -= 4; /* sizeof the ID which was already read */ matroska->has_cluster_id = 0; } else res = ebml_parse(matroska, matroska_clusters, &cluster); blocks_list = &cluster.blocks; blocks = blocks_list->elem; - for (i=0; !res && inb_elem; i++) + for (i=0; inb_elem; i++) if (blocks[i].bin.size > 0) res=matroska_parse_block(matroska, blocks[i].bin.data, blocks[i].bin.size, blocks[i].bin.pos, cluster.timecode, - blocks[i].duration, !blocks[i].reference); + blocks[i].duration, !blocks[i].reference, + pos); ebml_free(matroska_cluster, &cluster); + if (res < 0) matroska->done = 1; return res; } @@ -1617,8 +1710,7 @@ static int matroska_read_packet(AVFormatContext *s, AVPacket *pkt) while (matroska_deliver_packet(matroska, pkt)) { if (matroska->done) return AVERROR(EIO); - if (matroska_parse_cluster(matroska) < 0) - matroska->done = 1; + matroska_parse_cluster(matroska); } return 0; @@ -1628,18 +1720,44 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) { MatroskaDemuxContext *matroska = s->priv_data; + MatroskaTrack *tracks = matroska->tracks.elem; AVStream *st = s->streams[stream_index]; - int index; + int i, index, index_sub, index_min; - index = av_index_search_timestamp(st, timestamp, flags); - if (index < 0) + if (!st->nb_index_entries) return 0; + timestamp = FFMAX(timestamp, st->index_entries[0].timestamp); + + if ((index = av_index_search_timestamp(st, timestamp, flags)) < 0) { + url_fseek(s->pb, st->index_entries[st->nb_index_entries-1].pos, SEEK_SET); + while ((index = av_index_search_timestamp(st, timestamp, flags)) < 0) { + matroska_clear_queue(matroska); + if (matroska_parse_cluster(matroska) < 0) + break; + } + } matroska_clear_queue(matroska); + if (index < 0) + return 0; + + index_min = index; + for (i=0; i < matroska->tracks.nb_elem; i++) { + tracks[i].end_timecode = 0; + if (tracks[i].type == MATROSKA_TRACK_TYPE_SUBTITLE + && !tracks[i].stream->discard != AVDISCARD_ALL) { + index_sub = av_index_search_timestamp(tracks[i].stream, st->index_entries[index].timestamp, AVSEEK_FLAG_BACKWARD); + if (index_sub >= 0 + && st->index_entries[index_sub].pos < st->index_entries[index_min].pos + && st->index_entries[index].timestamp - st->index_entries[index_sub].timestamp < 30000000000/matroska->time_scale) + index_min = index_sub; + } + } - url_fseek(s->pb, st->index_entries[index].pos, SEEK_SET); + url_fseek(s->pb, st->index_entries[index_min].pos, SEEK_SET); matroska->skip_to_keyframe = !(flags & AVSEEK_FLAG_ANY); - matroska->skip_to_stream = st; + matroska->skip_to_timecode = st->index_entries[index].timestamp; + matroska->done = 0; av_update_cur_dts(s, st, st->index_entries[index].timestamp); return 0; }