X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fmatroskadec.c;h=374831baa32acc10b60f943c29e974d51b70684e;hb=cae57cae1f70371591223a5f9fe3f370ce8dfd50;hp=6eab0765384280753a476bde627e18f70a827b1f;hpb=3c70b941d5d1f756cf4e141c3c7ee921478ec300;p=ffmpeg diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index 6eab0765384..374831baa32 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -48,6 +48,7 @@ #include "libavcodec/bytestream.h" #include "libavcodec/flac.h" #include "libavcodec/mpeg4audio.h" +#include "libavcodec/packet_internal.h" #include "avformat.h" #include "avio_internal.h" @@ -97,8 +98,8 @@ typedef enum { typedef const struct EbmlSyntax { uint32_t id; EbmlType type; - int list_elem_size; - int data_offset; + size_t list_elem_size; + size_t data_offset; union { int64_t i; uint64_t u; @@ -110,6 +111,7 @@ typedef const struct EbmlSyntax { typedef struct EbmlList { int nb_elem; + unsigned int alloc_elem_size; void *elem; } EbmlList; @@ -248,6 +250,7 @@ typedef struct MatroskaTrack { AVStream *stream; int64_t end_timecode; int ms_compat; + int needs_decoding; uint64_t max_block_additional_id; uint32_t palette[AVPALETTE_COUNT]; @@ -257,6 +260,7 @@ typedef struct MatroskaTrack { typedef struct MatroskaAttachment { uint64_t uid; char *filename; + char *description; char *mime; EbmlBin bin; @@ -330,7 +334,7 @@ typedef struct MatroskaCluster { } MatroskaCluster; typedef struct MatroskaLevel1Element { - uint64_t pos; + int64_t pos; uint32_t id; int parsed; } MatroskaLevel1Element; @@ -389,14 +393,18 @@ typedef struct MatroskaDemuxContext { #define CHILD_OF(parent) { .def = { .n = parent } } -static const EbmlSyntax ebml_syntax[], matroska_segment[], matroska_track_video_color[], matroska_track_video[], - matroska_track[], matroska_track_encoding[], matroska_track_encodings[], - matroska_track_combine_planes[], matroska_track_operation[], matroska_tracks[], - matroska_attachments[], matroska_chapter_entry[], matroska_chapter[], matroska_chapters[], - matroska_index_entry[], matroska_index[], matroska_tag[], matroska_tags[], matroska_seekhead[], - matroska_blockadditions[], matroska_blockgroup[], matroska_cluster_parsing[]; - -static const EbmlSyntax ebml_header[] = { +// The following forward declarations need their size because +// a tentative definition with internal linkage must not be an +// incomplete type (6.7.2 in C90, 6.9.2 in C99). +// Removing the sizes breaks MSVC. +static EbmlSyntax ebml_syntax[3], matroska_segment[9], matroska_track_video_color[15], matroska_track_video[19], + matroska_track[27], matroska_track_encoding[6], matroska_track_encodings[2], + matroska_track_combine_planes[2], matroska_track_operation[2], matroska_tracks[2], + matroska_attachments[2], matroska_chapter_entry[9], matroska_chapter[6], matroska_chapters[2], + matroska_index_entry[3], matroska_index[2], matroska_tag[3], matroska_tags[2], matroska_seekhead[2], + matroska_blockadditions[2], matroska_blockgroup[8], matroska_cluster_parsing[8]; + +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 } }, { EBML_ID_EBMLMAXIDLENGTH, EBML_UINT, 0, offsetof(Ebml, id_length), { .u = 4 } }, @@ -407,13 +415,13 @@ static const EbmlSyntax ebml_header[] = { CHILD_OF(ebml_syntax) }; -static const EbmlSyntax ebml_syntax[] = { +static EbmlSyntax ebml_syntax[] = { { EBML_ID_HEADER, EBML_NEST, 0, 0, { .n = ebml_header } }, { MATROSKA_ID_SEGMENT, EBML_STOP }, { 0 } }; -static const EbmlSyntax matroska_info[] = { +static EbmlSyntax matroska_info[] = { { MATROSKA_ID_TIMECODESCALE, EBML_UINT, 0, offsetof(MatroskaDemuxContext, time_scale), { .u = 1000000 } }, { MATROSKA_ID_DURATION, EBML_FLOAT, 0, offsetof(MatroskaDemuxContext, duration) }, { MATROSKA_ID_TITLE, EBML_UTF8, 0, offsetof(MatroskaDemuxContext, title) }, @@ -424,7 +432,7 @@ static const EbmlSyntax matroska_info[] = { CHILD_OF(matroska_segment) }; -static const EbmlSyntax matroska_mastering_meta[] = { +static EbmlSyntax matroska_mastering_meta[] = { { MATROSKA_ID_VIDEOCOLOR_RX, EBML_FLOAT, 0, offsetof(MatroskaMasteringMeta, r_x), { .f=-1 } }, { MATROSKA_ID_VIDEOCOLOR_RY, EBML_FLOAT, 0, offsetof(MatroskaMasteringMeta, r_y), { .f=-1 } }, { MATROSKA_ID_VIDEOCOLOR_GX, EBML_FLOAT, 0, offsetof(MatroskaMasteringMeta, g_x), { .f=-1 } }, @@ -438,7 +446,7 @@ static const EbmlSyntax matroska_mastering_meta[] = { CHILD_OF(matroska_track_video_color) }; -static const EbmlSyntax matroska_track_video_color[] = { +static EbmlSyntax matroska_track_video_color[] = { { MATROSKA_ID_VIDEOCOLORMATRIXCOEFF, EBML_UINT, 0, offsetof(MatroskaTrackVideoColor, matrix_coefficients), { .u = AVCOL_SPC_UNSPECIFIED } }, { MATROSKA_ID_VIDEOCOLORBITSPERCHANNEL, EBML_UINT, 0, offsetof(MatroskaTrackVideoColor, bits_per_channel), { .u=0 } }, { MATROSKA_ID_VIDEOCOLORCHROMASUBHORZ, EBML_UINT, 0, offsetof(MatroskaTrackVideoColor, chroma_sub_horz), { .u=0 } }, @@ -456,7 +464,7 @@ static const EbmlSyntax matroska_track_video_color[] = { CHILD_OF(matroska_track_video) }; -static const EbmlSyntax matroska_track_video_projection[] = { +static EbmlSyntax matroska_track_video_projection[] = { { MATROSKA_ID_VIDEOPROJECTIONTYPE, EBML_UINT, 0, offsetof(MatroskaTrackVideoProjection, type), { .u = MATROSKA_VIDEO_PROJECTION_TYPE_RECTANGULAR } }, { MATROSKA_ID_VIDEOPROJECTIONPRIVATE, EBML_BIN, 0, offsetof(MatroskaTrackVideoProjection, private) }, { MATROSKA_ID_VIDEOPROJECTIONPOSEYAW, EBML_FLOAT, 0, offsetof(MatroskaTrackVideoProjection, yaw), { .f=0.0 } }, @@ -465,7 +473,7 @@ static const EbmlSyntax matroska_track_video_projection[] = { CHILD_OF(matroska_track_video) }; -static const EbmlSyntax matroska_track_video[] = { +static EbmlSyntax matroska_track_video[] = { { MATROSKA_ID_VIDEOFRAMERATE, EBML_FLOAT, 0, offsetof(MatroskaTrackVideo, frame_rate) }, { MATROSKA_ID_VIDEODISPLAYWIDTH, EBML_UINT, 0, offsetof(MatroskaTrackVideo, display_width), { .u=-1 } }, { MATROSKA_ID_VIDEODISPLAYHEIGHT, EBML_UINT, 0, offsetof(MatroskaTrackVideo, display_height), { .u=-1 } }, @@ -487,7 +495,7 @@ static const EbmlSyntax matroska_track_video[] = { CHILD_OF(matroska_track) }; -static const EbmlSyntax matroska_track_audio[] = { +static EbmlSyntax matroska_track_audio[] = { { MATROSKA_ID_AUDIOSAMPLINGFREQ, EBML_FLOAT, 0, offsetof(MatroskaTrackAudio, samplerate), { .f = 8000.0 } }, { MATROSKA_ID_AUDIOOUTSAMPLINGFREQ, EBML_FLOAT, 0, offsetof(MatroskaTrackAudio, out_samplerate) }, { MATROSKA_ID_AUDIOBITDEPTH, EBML_UINT, 0, offsetof(MatroskaTrackAudio, bitdepth) }, @@ -495,13 +503,13 @@ static const EbmlSyntax matroska_track_audio[] = { CHILD_OF(matroska_track) }; -static const EbmlSyntax matroska_track_encoding_compression[] = { +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) }, CHILD_OF(matroska_track_encoding) }; -static const EbmlSyntax matroska_track_encoding_encryption[] = { +static EbmlSyntax matroska_track_encoding_encryption[] = { { MATROSKA_ID_ENCODINGENCALGO, EBML_UINT, 0, offsetof(MatroskaTrackEncryption,algo), {.u = 0} }, { MATROSKA_ID_ENCODINGENCKEYID, EBML_BIN, 0, offsetof(MatroskaTrackEncryption,key_id) }, { MATROSKA_ID_ENCODINGENCAESSETTINGS, EBML_NONE }, @@ -511,7 +519,7 @@ static const EbmlSyntax matroska_track_encoding_encryption[] = { { MATROSKA_ID_ENCODINGSIGNATURE, EBML_NONE }, CHILD_OF(matroska_track_encoding) }; -static const EbmlSyntax matroska_track_encoding[] = { +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 } }, @@ -520,28 +528,28 @@ static const EbmlSyntax matroska_track_encoding[] = { CHILD_OF(matroska_track_encodings) }; -static const EbmlSyntax matroska_track_encodings[] = { +static EbmlSyntax matroska_track_encodings[] = { { MATROSKA_ID_TRACKCONTENTENCODING, EBML_NEST, sizeof(MatroskaTrackEncoding), offsetof(MatroskaTrack, encodings), { .n = matroska_track_encoding } }, CHILD_OF(matroska_track) }; -static const EbmlSyntax matroska_track_plane[] = { +static EbmlSyntax matroska_track_plane[] = { { MATROSKA_ID_TRACKPLANEUID, EBML_UINT, 0, offsetof(MatroskaTrackPlane,uid) }, { MATROSKA_ID_TRACKPLANETYPE, EBML_UINT, 0, offsetof(MatroskaTrackPlane,type) }, CHILD_OF(matroska_track_combine_planes) }; -static const EbmlSyntax matroska_track_combine_planes[] = { +static EbmlSyntax matroska_track_combine_planes[] = { { MATROSKA_ID_TRACKPLANE, EBML_NEST, sizeof(MatroskaTrackPlane), offsetof(MatroskaTrackOperation,combine_planes), {.n = matroska_track_plane} }, CHILD_OF(matroska_track_operation) }; -static const EbmlSyntax matroska_track_operation[] = { +static EbmlSyntax matroska_track_operation[] = { { MATROSKA_ID_TRACKCOMBINEPLANES, EBML_NEST, 0, 0, {.n = matroska_track_combine_planes} }, CHILD_OF(matroska_track) }; -static const EbmlSyntax matroska_track[] = { +static EbmlSyntax matroska_track[] = { { MATROSKA_ID_TRACKNUMBER, EBML_UINT, 0, offsetof(MatroskaTrack, num) }, { MATROSKA_ID_TRACKNAME, EBML_UTF8, 0, offsetof(MatroskaTrack, name) }, { MATROSKA_ID_TRACKUID, EBML_UINT, 0, offsetof(MatroskaTrack, uid) }, @@ -549,7 +557,7 @@ static const EbmlSyntax matroska_track[] = { { 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 } }, @@ -571,33 +579,33 @@ static const EbmlSyntax matroska_track[] = { CHILD_OF(matroska_tracks) }; -static const EbmlSyntax matroska_tracks[] = { +static EbmlSyntax matroska_tracks[] = { { MATROSKA_ID_TRACKENTRY, EBML_NEST, sizeof(MatroskaTrack), offsetof(MatroskaDemuxContext, tracks), { .n = matroska_track } }, CHILD_OF(matroska_segment) }; -static const EbmlSyntax matroska_attachment[] = { +static EbmlSyntax matroska_attachment[] = { { 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 }, + { MATROSKA_ID_FILEDESC, EBML_UTF8, 0, offsetof(MatroskaAttachment, description) }, CHILD_OF(matroska_attachments) }; -static const EbmlSyntax matroska_attachments[] = { +static EbmlSyntax matroska_attachments[] = { { MATROSKA_ID_ATTACHEDFILE, EBML_NEST, sizeof(MatroskaAttachment), offsetof(MatroskaDemuxContext, attachments), { .n = matroska_attachment } }, CHILD_OF(matroska_segment) }; -static const EbmlSyntax matroska_chapter_display[] = { +static EbmlSyntax matroska_chapter_display[] = { { MATROSKA_ID_CHAPSTRING, EBML_UTF8, 0, offsetof(MatroskaChapter, title) }, { MATROSKA_ID_CHAPLANG, EBML_NONE }, { MATROSKA_ID_CHAPCOUNTRY, EBML_NONE }, CHILD_OF(matroska_chapter_entry) }; -static const EbmlSyntax matroska_chapter_entry[] = { +static EbmlSyntax matroska_chapter_entry[] = { { MATROSKA_ID_CHAPTERTIMESTART, EBML_UINT, 0, offsetof(MatroskaChapter, start), { .u = AV_NOPTS_VALUE } }, { MATROSKA_ID_CHAPTERTIMEEND, EBML_UINT, 0, offsetof(MatroskaChapter, end), { .u = AV_NOPTS_VALUE } }, { MATROSKA_ID_CHAPTERUID, EBML_UINT, 0, offsetof(MatroskaChapter, uid) }, @@ -609,7 +617,7 @@ static const EbmlSyntax matroska_chapter_entry[] = { CHILD_OF(matroska_chapter) }; -static const EbmlSyntax matroska_chapter[] = { +static EbmlSyntax matroska_chapter[] = { { MATROSKA_ID_CHAPTERATOM, EBML_NEST, sizeof(MatroskaChapter), offsetof(MatroskaDemuxContext, chapters), { .n = matroska_chapter_entry } }, { MATROSKA_ID_EDITIONUID, EBML_NONE }, { MATROSKA_ID_EDITIONFLAGHIDDEN, EBML_NONE }, @@ -618,12 +626,12 @@ static const EbmlSyntax matroska_chapter[] = { CHILD_OF(matroska_chapters) }; -static const EbmlSyntax matroska_chapters[] = { +static EbmlSyntax matroska_chapters[] = { { MATROSKA_ID_EDITIONENTRY, EBML_NEST, 0, 0, { .n = matroska_chapter } }, CHILD_OF(matroska_segment) }; -static const EbmlSyntax matroska_index_pos[] = { +static EbmlSyntax matroska_index_pos[] = { { MATROSKA_ID_CUETRACK, EBML_UINT, 0, offsetof(MatroskaIndexPos, track) }, { MATROSKA_ID_CUECLUSTERPOSITION, EBML_UINT, 0, offsetof(MatroskaIndexPos, pos) }, { MATROSKA_ID_CUERELATIVEPOSITION,EBML_NONE }, @@ -632,18 +640,18 @@ static const EbmlSyntax matroska_index_pos[] = { CHILD_OF(matroska_index_entry) }; -static const EbmlSyntax matroska_index_entry[] = { +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 } }, CHILD_OF(matroska_index) }; -static const EbmlSyntax matroska_index[] = { +static EbmlSyntax matroska_index[] = { { MATROSKA_ID_POINTENTRY, EBML_NEST, sizeof(MatroskaIndex), offsetof(MatroskaDemuxContext, index), { .n = matroska_index_entry } }, CHILD_OF(matroska_segment) }; -static const EbmlSyntax matroska_simpletag[] = { +static EbmlSyntax matroska_simpletag[] = { { MATROSKA_ID_TAGNAME, EBML_UTF8, 0, offsetof(MatroskaTag, name) }, { MATROSKA_ID_TAGSTRING, EBML_UTF8, 0, offsetof(MatroskaTag, string) }, { MATROSKA_ID_TAGLANG, EBML_STR, 0, offsetof(MatroskaTag, lang), { .s = "und" } }, @@ -653,7 +661,7 @@ static const EbmlSyntax matroska_simpletag[] = { CHILD_OF(matroska_tag) }; -static const EbmlSyntax matroska_tagtargets[] = { +static EbmlSyntax matroska_tagtargets[] = { { MATROSKA_ID_TAGTARGETS_TYPE, EBML_STR, 0, offsetof(MatroskaTagTarget, type) }, { MATROSKA_ID_TAGTARGETS_TYPEVALUE, EBML_UINT, 0, offsetof(MatroskaTagTarget, typevalue), { .u = 50 } }, { MATROSKA_ID_TAGTARGETS_TRACKUID, EBML_UINT, 0, offsetof(MatroskaTagTarget, trackuid) }, @@ -662,29 +670,30 @@ static const EbmlSyntax matroska_tagtargets[] = { CHILD_OF(matroska_tag) }; -static const EbmlSyntax matroska_tag[] = { +static EbmlSyntax matroska_tag[] = { { MATROSKA_ID_SIMPLETAG, EBML_NEST, sizeof(MatroskaTag), offsetof(MatroskaTags, tag), { .n = matroska_simpletag } }, { MATROSKA_ID_TAGTARGETS, EBML_NEST, 0, offsetof(MatroskaTags, target), { .n = matroska_tagtargets } }, CHILD_OF(matroska_tags) }; -static const EbmlSyntax matroska_tags[] = { +static EbmlSyntax matroska_tags[] = { { MATROSKA_ID_TAG, EBML_NEST, sizeof(MatroskaTags), offsetof(MatroskaDemuxContext, tags), { .n = matroska_tag } }, CHILD_OF(matroska_segment) }; -static const EbmlSyntax matroska_seekhead_entry[] = { +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 } }, CHILD_OF(matroska_seekhead) }; -static const EbmlSyntax matroska_seekhead[] = { +static EbmlSyntax matroska_seekhead[] = { { MATROSKA_ID_SEEKENTRY, EBML_NEST, sizeof(MatroskaSeekhead), offsetof(MatroskaDemuxContext, seekhead), { .n = matroska_seekhead_entry } }, CHILD_OF(matroska_segment) }; -static const EbmlSyntax matroska_segment[] = { +static EbmlSyntax matroska_segment[] = { + { MATROSKA_ID_CLUSTER, EBML_STOP }, { MATROSKA_ID_INFO, EBML_LEVEL1, 0, 0, { .n = matroska_info } }, { MATROSKA_ID_TRACKS, EBML_LEVEL1, 0, 0, { .n = matroska_tracks } }, { MATROSKA_ID_ATTACHMENTS, EBML_LEVEL1, 0, 0, { .n = matroska_attachments } }, @@ -692,27 +701,26 @@ static const EbmlSyntax matroska_segment[] = { { MATROSKA_ID_CUES, EBML_LEVEL1, 0, 0, { .n = matroska_index } }, { MATROSKA_ID_TAGS, EBML_LEVEL1, 0, 0, { .n = matroska_tags } }, { MATROSKA_ID_SEEKHEAD, EBML_LEVEL1, 0, 0, { .n = matroska_seekhead } }, - { MATROSKA_ID_CLUSTER, EBML_STOP }, { 0 } /* We don't want to go back to level 0, so don't add the parent. */ }; -static const EbmlSyntax matroska_segments[] = { +static EbmlSyntax matroska_segments[] = { { MATROSKA_ID_SEGMENT, EBML_NEST, 0, 0, { .n = matroska_segment } }, { 0 } }; -static const EbmlSyntax matroska_blockmore[] = { - { MATROSKA_ID_BLOCKADDID, EBML_UINT, 0, offsetof(MatroskaBlock,additional_id) }, +static EbmlSyntax matroska_blockmore[] = { + { MATROSKA_ID_BLOCKADDID, EBML_UINT, 0, offsetof(MatroskaBlock,additional_id), { .u = 1 } }, { MATROSKA_ID_BLOCKADDITIONAL, EBML_BIN, 0, offsetof(MatroskaBlock,additional) }, CHILD_OF(matroska_blockadditions) }; -static const EbmlSyntax matroska_blockadditions[] = { +static EbmlSyntax matroska_blockadditions[] = { { MATROSKA_ID_BLOCKMORE, EBML_NEST, 0, 0, {.n = matroska_blockmore} }, CHILD_OF(matroska_blockgroup) }; -static const EbmlSyntax matroska_blockgroup[] = { +static EbmlSyntax matroska_blockgroup[] = { { MATROSKA_ID_BLOCK, EBML_BIN, 0, offsetof(MatroskaBlock, bin) }, { MATROSKA_ID_BLOCKADDITIONS, EBML_NEST, 0, 0, { .n = matroska_blockadditions} }, { MATROSKA_ID_BLOCKDURATION, EBML_UINT, 0, offsetof(MatroskaBlock, duration) }, @@ -725,7 +733,7 @@ static const EbmlSyntax matroska_blockgroup[] = { // The following array contains SimpleBlock and BlockGroup twice // in order to reuse the other values for matroska_cluster_enter. -static const EbmlSyntax matroska_cluster_parsing[] = { +static EbmlSyntax matroska_cluster_parsing[] = { { MATROSKA_ID_SIMPLEBLOCK, EBML_BIN, 0, offsetof(MatroskaBlock, bin) }, { MATROSKA_ID_BLOCKGROUP, EBML_NEST, 0, 0, { .n = matroska_blockgroup } }, { MATROSKA_ID_CLUSTERTIMECODE, EBML_UINT, 0, offsetof(MatroskaCluster, timecode) }, @@ -736,23 +744,30 @@ static const EbmlSyntax matroska_cluster_parsing[] = { CHILD_OF(matroska_segment) }; -static const EbmlSyntax matroska_cluster_enter[] = { +static EbmlSyntax matroska_cluster_enter[] = { { MATROSKA_ID_CLUSTER, EBML_NEST, 0, 0, { .n = &matroska_cluster_parsing[2] } }, { 0 } }; +#undef CHILD_OF -static const EbmlSyntax matroska_clusters[] = { - { MATROSKA_ID_CLUSTER, EBML_STOP }, - { MATROSKA_ID_CUES, EBML_NONE }, - { MATROSKA_ID_TAGS, EBML_NONE }, - { MATROSKA_ID_INFO, EBML_NONE }, - { MATROSKA_ID_TRACKS, EBML_NONE }, - { MATROSKA_ID_ATTACHMENTS, EBML_NONE }, - { MATROSKA_ID_CHAPTERS, EBML_NONE }, - { MATROSKA_ID_SEEKHEAD, EBML_NONE }, - { 0 } /* We don't want to go back to level 0, so don't add the parent. */ +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} }; -#undef CHILD_OF static const char *const matroska_doctypes[] = { "matroska", "webm" }; @@ -765,7 +780,7 @@ static int matroska_reset_status(MatroskaDemuxContext *matroska, uint32_t id, int64_t position) { if (position >= 0) { - int err = avio_seek(matroska->ctx->pb, position, SEEK_SET); + int64_t err = avio_seek(matroska->ctx->pb, position, SEEK_SET); if (err < 0) return err; } @@ -805,7 +820,7 @@ static int matroska_resync(MatroskaDemuxContext *matroska, int64_t last_pos) id == MATROSKA_ID_CLUSTER || id == MATROSKA_ID_CHAPTERS) { /* Prepare the context for parsing of a level 1 element. */ matroska_reset_status(matroska, id, -1); - /* Given that we are here means that an error has occured, + /* Given that we are here means that an error has occurred, * so treat the segment as unknown length in order not to * discard valid data that happens to be beyond the designated * end of the segment. */ @@ -1031,28 +1046,17 @@ static int ebml_read_master(MatroskaDemuxContext *matroska, } /* - * 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) */ @@ -1080,34 +1084,36 @@ static EbmlSyntax *ebml_parse_id(EbmlSyntax *syntax, uint32_t id) static int ebml_parse_nest(MatroskaDemuxContext *matroska, EbmlSyntax *syntax, void *data) { - int i, res; + int res; - for (i = 0; syntax[i].id; i++) - switch (syntax[i].type) { - case EBML_UINT: - *(uint64_t *) ((char *) data + syntax[i].data_offset) = syntax[i].def.u; - break; - case EBML_SINT: - *(int64_t *) ((char *) data + syntax[i].data_offset) = syntax[i].def.i; - break; - case EBML_FLOAT: - *(double *) ((char *) data + syntax[i].data_offset) = syntax[i].def.f; - break; - case EBML_STR: - case EBML_UTF8: - // the default may be NULL - if (syntax[i].def.s) { - uint8_t **dst = (uint8_t **) ((uint8_t *) data + syntax[i].data_offset); - *dst = av_strdup(syntax[i].def.s); - if (!*dst) - return AVERROR(ENOMEM); + if (data) { + for (int i = 0; syntax[i].id; i++) + switch (syntax[i].type) { + case EBML_UINT: + *(uint64_t *) ((char *) data + syntax[i].data_offset) = syntax[i].def.u; + break; + case EBML_SINT: + *(int64_t *) ((char *) data + syntax[i].data_offset) = syntax[i].def.i; + break; + case EBML_FLOAT: + *(double *) ((char *) data + syntax[i].data_offset) = syntax[i].def.f; + break; + case EBML_STR: + case EBML_UTF8: + // the default may be NULL + if (syntax[i].def.s) { + uint8_t **dst = (uint8_t **) ((uint8_t *) data + syntax[i].data_offset); + *dst = av_strdup(syntax[i].def.s); + if (!*dst) + return AVERROR(ENOMEM); + } + break; } - break; - } - if (!matroska->levels[matroska->num_levels - 1].length) { - matroska->num_levels--; - return 0; + if (!matroska->levels[matroska->num_levels - 1].length) { + matroska->num_levels--; + return 0; + } } do { @@ -1131,7 +1137,7 @@ static int is_ebml_id_valid(uint32_t id) * 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; @@ -1143,19 +1149,18 @@ static MatroskaLevel1Element *matroska_find_level1_elem(MatroskaDemuxContext *ma 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; } @@ -1238,17 +1243,24 @@ static int ebml_parse(MatroskaDemuxContext *matroska, update_pos = 0; /* Don't update resync_pos as an error might have happened. */ } - data = (char *) data + syntax->data_offset; - if (syntax->list_elem_size) { - EbmlList *list = data; - void *newelem = av_realloc_array(list->elem, list->nb_elem + 1, - syntax->list_elem_size); - if (!newelem) - return AVERROR(ENOMEM); - list->elem = newelem; - data = (char *) list->elem + list->nb_elem * syntax->list_elem_size; - memset(data, 0, syntax->list_elem_size); - list->nb_elem++; + if (data) { + data = (char *) data + syntax->data_offset; + if (syntax->list_elem_size) { + EbmlList *list = data; + void *newelem; + + if ((unsigned)list->nb_elem + 1 >= UINT_MAX / syntax->list_elem_size) + return AVERROR(ENOMEM); + newelem = av_fast_realloc(list->elem, + &list->alloc_elem_size, + (list->nb_elem + 1) * syntax->list_elem_size); + if (!newelem) + return AVERROR(ENOMEM); + list->elem = newelem; + data = (char *) list->elem + list->nb_elem * syntax->list_elem_size; + memset(data, 0, syntax->list_elem_size); + list->nb_elem++; + } } if (syntax->type != EBML_STOP) { @@ -1329,7 +1341,7 @@ static int ebml_parse(MatroskaDemuxContext *matroska, // current element (i.e. how much would be skipped); if there were // more than a few skipped elements in a row and skipping the current // element would lead us more than SKIP_THRESHOLD away from the last - // known good position, then it is inferred that an error occured. + // known good position, then it is inferred that an error occurred. // The dependency on the number of unknown elements in a row exists // because the distance to the last known good position is // automatically big if the last parsed element was big. @@ -1366,6 +1378,9 @@ static int ebml_parse(MatroskaDemuxContext *matroska, // of the element as the "last known good" position. matroska->resync_pos = pos; } + + if (!data && length != EBML_UNKNOWN_LENGTH) + goto skip; } switch (syntax->type) { @@ -1394,8 +1409,11 @@ static int ebml_parse(MatroskaDemuxContext *matroska, if (id == MATROSKA_ID_CUES) matroska->cues_parsing_deferred = 0; if (syntax->type == EBML_LEVEL1 && - (level1_elem = matroska_find_level1_elem(matroska, syntax->id))) { - if (level1_elem->parsed) + (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; + } else if (level1_elem->pos != pos) av_log(matroska->ctx, AV_LOG_ERROR, "Duplicate element\n"); level1_elem->parsed = 1; } @@ -1404,6 +1422,7 @@ static int ebml_parse(MatroskaDemuxContext *matroska, break; case EBML_STOP: return 1; + skip: default: if (length) { int64_t res2; @@ -1487,6 +1506,7 @@ static void ebml_free(EbmlSyntax *syntax, void *data) ebml_free(syntax[i].def.n, ptr); av_freep(&list->elem); list->nb_elem = 0; + list->alloc_elem_size = 0; } else ebml_free(syntax[i].def.n, data_off); default: @@ -1519,9 +1539,14 @@ static int matroska_probe(const AVProbeData *p) while (n < size) total = (total << 8) | p->buf[4 + n++]; - /* Does the probe data contain the whole header? */ - if (p->buf_size < 4 + size + total) - return 0; + if (total + 1 == 1ULL << (7 * size)){ + /* Unknown-length header - simply parse the whole buffer. */ + total = p->buf_size - 4 - size; + } else { + /* Does the probe data contain the whole header? */ + if (p->buf_size < 4 + size + total) + return 0; + } /* The header should contain a known document type. For now, * we don't parse the whole header but simply check for the @@ -1541,7 +1566,7 @@ static int matroska_probe(const AVProbeData *p) } static MatroskaTrack *matroska_find_track_by_num(MatroskaDemuxContext *matroska, - int num) + uint64_t num) { MatroskaTrack *tracks = matroska->tracks.elem; int i; @@ -1550,7 +1575,7 @@ static MatroskaTrack *matroska_find_track_by_num(MatroskaDemuxContext *matroska, 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; } @@ -1595,6 +1620,7 @@ static int matroska_decode_buffer(uint8_t **buf, int *buf_size, #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); @@ -1603,7 +1629,7 @@ static int matroska_decode_buffer(uint8_t **buf, int *buf_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; @@ -1747,7 +1773,7 @@ static void matroska_convert_tags(AVFormatContext *s) } } 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); @@ -1764,7 +1790,7 @@ static void matroska_convert_tags(AVFormatContext *s) } } 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); @@ -1781,7 +1807,7 @@ static void matroska_convert_tags(AVFormatContext *s) } } 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); @@ -1794,16 +1820,14 @@ static void matroska_convert_tags(AVFormatContext *s) } static int matroska_parse_seekhead_entry(MatroskaDemuxContext *matroska, - uint64_t pos) + int64_t pos) { uint32_t saved_id = matroska->current_id; int64_t before_pos = avio_tell(matroska->ctx->pb); - int64_t offset; int ret = 0; /* seek */ - offset = pos + matroska->segment_start; - if (avio_seek(matroska->ctx->pb, offset, SEEK_SET) == offset) { + if (avio_seek(matroska->ctx->pb, pos, SEEK_SET) == pos) { /* 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) { @@ -1841,10 +1865,14 @@ static void matroska_execute_seekhead(MatroskaDemuxContext *matroska) for (i = 0; i < seekhead_list->nb_elem; i++) { MatroskaSeekhead *seekheads = seekhead_list->elem; - uint32_t id = seekheads[i].id; - uint64_t pos = seekheads[i].pos; + uint32_t id = seekheads[i].id; + int64_t pos = seekheads[i].pos + matroska->segment_start; + MatroskaLevel1Element *elem; - MatroskaLevel1Element *elem = matroska_find_level1_elem(matroska, id); + if (id != seekheads[i].id || pos < matroska->segment_start) + continue; + + elem = matroska_find_level1_elem(matroska, id, pos); if (!elem || elem->parsed) continue; @@ -2000,12 +2028,12 @@ static int matroska_parse_flac(AVFormatContext *s, 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: @@ -2103,9 +2131,6 @@ static int mkv_parse_video_color(AVStream *st, const MatroskaTrack *track) { } if (has_mastering_primaries || has_mastering_luminance) { - // Use similar rationals as other standards. - const int chroma_den = 50000; - const int luma_den = 10000; AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata*) av_stream_new_side_data( st, AV_PKT_DATA_MASTERING_DISPLAY_METADATA, @@ -2115,71 +2140,59 @@ static int mkv_parse_video_color(AVStream *st, const MatroskaTrack *track) { } memset(metadata, 0, sizeof(AVMasteringDisplayMetadata)); if (has_mastering_primaries) { - metadata->display_primaries[0][0] = av_make_q( - round(mastering_meta->r_x * chroma_den), chroma_den); - metadata->display_primaries[0][1] = av_make_q( - round(mastering_meta->r_y * chroma_den), chroma_den); - metadata->display_primaries[1][0] = av_make_q( - round(mastering_meta->g_x * chroma_den), chroma_den); - metadata->display_primaries[1][1] = av_make_q( - round(mastering_meta->g_y * chroma_den), chroma_den); - metadata->display_primaries[2][0] = av_make_q( - round(mastering_meta->b_x * chroma_den), chroma_den); - metadata->display_primaries[2][1] = av_make_q( - round(mastering_meta->b_y * chroma_den), chroma_den); - metadata->white_point[0] = av_make_q( - round(mastering_meta->white_x * chroma_den), chroma_den); - metadata->white_point[1] = av_make_q( - round(mastering_meta->white_y * chroma_den), chroma_den); + metadata->display_primaries[0][0] = av_d2q(mastering_meta->r_x, INT_MAX); + metadata->display_primaries[0][1] = av_d2q(mastering_meta->r_y, INT_MAX); + metadata->display_primaries[1][0] = av_d2q(mastering_meta->g_x, INT_MAX); + metadata->display_primaries[1][1] = av_d2q(mastering_meta->g_y, INT_MAX); + metadata->display_primaries[2][0] = av_d2q(mastering_meta->b_x, INT_MAX); + metadata->display_primaries[2][1] = av_d2q(mastering_meta->b_y, INT_MAX); + metadata->white_point[0] = av_d2q(mastering_meta->white_x, INT_MAX); + metadata->white_point[1] = av_d2q(mastering_meta->white_y, INT_MAX); metadata->has_primaries = 1; } if (has_mastering_luminance) { - metadata->max_luminance = av_make_q( - round(mastering_meta->max_luminance * luma_den), luma_den); - metadata->min_luminance = av_make_q( - round(mastering_meta->min_luminance * luma_den), luma_den); + metadata->max_luminance = av_d2q(mastering_meta->max_luminance, INT_MAX); + metadata->min_luminance = av_d2q(mastering_meta->min_luminance, INT_MAX); metadata->has_luminance = 1; } } 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; } @@ -2190,19 +2203,19 @@ static int mkv_parse_video_projection(AVStream *st, const MatroskaTrack *track) 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; @@ -2210,7 +2223,7 @@ static int mkv_parse_video_projection(AVStream *st, const MatroskaTrack *track) /* 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; @@ -2305,6 +2318,15 @@ static int matroska_parse_tracks(AVFormatContext *s) if (!track->codec_id) continue; + if ( track->type == MATROSKA_TRACK_TYPE_AUDIO && track->codec_id[0] != 'A' + || track->type == MATROSKA_TRACK_TYPE_VIDEO && track->codec_id[0] != 'V' + || track->type == MATROSKA_TRACK_TYPE_SUBTITLE && track->codec_id[0] != 'D' && track->codec_id[0] != 'S' + || track->type == MATROSKA_TRACK_TYPE_METADATA && track->codec_id[0] != 'D' && track->codec_id[0] != 'S' + ) { + av_log(matroska->ctx, AV_LOG_INFO, "Inconsistent track type\n"); + continue; + } + if (track->audio.samplerate < 0 || track->audio.samplerate > INT_MAX || isnan(track->audio.samplerate)) { av_log(matroska->ctx, AV_LOG_WARNING, @@ -2396,6 +2418,11 @@ static int matroska_parse_tracks(AVFormatContext *s) } } } + 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, @@ -2413,8 +2440,8 @@ static int matroska_parse_tracks(AVFormatContext *s) 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") && @@ -2545,34 +2572,33 @@ static int matroska_parse_tracks(AVFormatContext *s) memcpy(&extradata[12], track->codec_priv.data, track->codec_priv.size); } else if (codec_id == AV_CODEC_ID_TTA) { - extradata_size = 30; - extradata = av_mallocz(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); - if (!extradata) - return AVERROR(ENOMEM); - ffio_init_context(&b, extradata, extradata_size, 1, - NULL, NULL, NULL, NULL); - avio_write(&b, "TTA1", 4); - avio_wl16(&b, 1); + uint8_t *ptr; if (track->audio.channels > UINT16_MAX || track->audio.bitdepth > UINT16_MAX) { av_log(matroska->ctx, AV_LOG_WARNING, "Too large audio channel number %"PRIu64 " or bitdepth %"PRIu64". Skipping track.\n", track->audio.channels, track->audio.bitdepth); - av_freep(&extradata); if (matroska->ctx->error_recognition & AV_EF_EXPLODE) return AVERROR_INVALIDDATA; else continue; } - avio_wl16(&b, track->audio.channels); - avio_wl16(&b, track->audio.bitdepth); if (track->audio.out_samplerate < 0 || track->audio.out_samplerate > INT_MAX) return AVERROR_INVALIDDATA; - avio_wl32(&b, track->audio.out_samplerate); - avio_wl32(&b, av_rescale((matroska->duration * matroska->time_scale), - track->audio.out_samplerate, - AV_TIME_BASE * 1000)); + extradata_size = 22; + extradata = av_mallocz(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!extradata) + return AVERROR(ENOMEM); + ptr = extradata; + bytestream_put_be32(&ptr, AV_RB32("TTA1")); + bytestream_put_le16(&ptr, 1); + bytestream_put_le16(&ptr, track->audio.channels); + bytestream_put_le16(&ptr, track->audio.bitdepth); + bytestream_put_le32(&ptr, track->audio.out_samplerate); + bytestream_put_le32(&ptr, av_rescale(matroska->duration * matroska->time_scale, + track->audio.out_samplerate, + AV_TIME_BASE * 1000)); } else if (codec_id == AV_CODEC_ID_RV10 || codec_id == AV_CODEC_ID_RV20 || codec_id == AV_CODEC_ID_RV30 || @@ -2598,32 +2624,46 @@ static int matroska_parse_tracks(AVFormatContext *s) 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) { @@ -2641,8 +2681,12 @@ static int matroska_parse_tracks(AVFormatContext *s) av_log(matroska->ctx, AV_LOG_INFO, "Unknown/unsupported AVCodecID %s.\n", track->codec_id); - if (track->time_scale < 0.01) + if (track->time_scale < 0.01) { + av_log(matroska->ctx, AV_LOG_WARNING, + "Track TimestampScale too small %f, assuming 1.0.\n", + track->time_scale); track->time_scale = 1.0; + } avpriv_set_pts_info(st, 64, matroska->time_scale * track->time_scale, 1000 * 1000 * 1000); /* 64 bit pts in ns */ @@ -2748,7 +2792,7 @@ static int matroska_parse_tracks(AVFormatContext *s) 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) { @@ -2883,12 +2927,14 @@ static int matroska_read_header(AVFormatContext *s) 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; } } @@ -2902,9 +2948,8 @@ static int matroska_read_header(AVFormatContext *s) 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; @@ -2916,10 +2961,10 @@ static int matroska_read_header(AVFormatContext *s) 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; } } @@ -2936,10 +2981,6 @@ static int matroska_read_header(AVFormatContext *s) (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; } @@ -2964,7 +3005,7 @@ static int matroska_deliver_packet(MatroskaDemuxContext *matroska, 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); @@ -2986,71 +3027,57 @@ static int matroska_deliver_packet(MatroskaDemuxContext *matroska, */ 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 *buf_size, int type, - uint32_t **lace_buf, int *laces) + int size, int type, AVIOContext *pb, + uint32_t lace_size[256], int *laces) { - int res = 0, n, size = *buf_size; + int n; uint8_t *data = *buf; - uint32_t *lace_size; if (!type) { *laces = 1; - *lace_buf = av_malloc(sizeof(**lace_buf)); - if (!*lace_buf) - return AVERROR(ENOMEM); - - *lace_buf[0] = size; + lace_size[0] = size; return 0; } - av_assert0(size > 0); - *laces = *data + 1; - data += 1; - size -= 1; - lace_size = av_malloc_array(*laces, sizeof(*lace_size)); - if (!lace_size) - return AVERROR(ENOMEM); + if (size <= 0) + return AVERROR_INVALIDDATA; + + *laces = *data + 1; + data += 1; + size -= 1; switch (type) { case 0x1: /* Xiph lacing */ { uint8_t temp; uint32_t total = 0; - for (n = 0; res == 0 && n < *laces - 1; n++) { + for (n = 0; n < *laces - 1; n++) { lace_size[n] = 0; - while (1) { - if (size <= total) { - res = AVERROR_INVALIDDATA; - break; - } + do { + if (size <= total) + return AVERROR_INVALIDDATA; temp = *data; total += temp; lace_size[n] += temp; data += 1; size -= 1; - if (temp != 0xff) - break; - } - } - if (size <= total) { - res = AVERROR_INVALIDDATA; - break; + } while (temp == 0xff); } + if (size < total) + return AVERROR_INVALIDDATA; lace_size[n] = size - total; break; } case 0x2: /* fixed-size lacing */ - if (size % (*laces)) { - res = AVERROR_INVALIDDATA; - break; - } + if (size % (*laces)) + return AVERROR_INVALIDDATA; for (n = 0; n < *laces; n++) lace_size[n] = size / *laces; break; @@ -3059,45 +3086,44 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf, { 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"); - res = n<0 ? n : AVERROR_INVALIDDATA; - break; - } - 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; - for (n = 1; res == 0 && n < *laces - 1; n++) { + 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"); - res = r<0 ? r : AVERROR_INVALIDDATA; - break; - } - 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) { - res = AVERROR_INVALIDDATA; - break; - } + data += offset; + size -= offset; + if (size < total) + return AVERROR_INVALIDDATA; + lace_size[*laces - 1] = size - total; break; } } - *buf = data; - *lace_buf = lace_size; - *buf_size = size; + *buf = data; - return res; + return 0; } static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska, @@ -3105,12 +3131,12 @@ static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska, 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) { @@ -3133,7 +3159,7 @@ static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska, } 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; @@ -3167,7 +3193,7 @@ static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska, 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); @@ -3178,19 +3204,21 @@ static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska, } /* 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); @@ -3250,7 +3278,7 @@ static int matroska_parse_wavpack(MatroskaTrack *track, uint8_t *src, memset(dst + dstlen, 0, AV_INPUT_BUFFER_PADDING_SIZE); - *pdst = dst; + *data = dst; *size = dstlen; return 0; @@ -3260,25 +3288,22 @@ fail: 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; + uint8_t *dst; + int dstlen = *size + 8; - if (AV_RB32(&src[4]) != MKBETAG('i', 'c', 'p', 'f')) { - dst = av_malloc(dstlen + 8 + 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); - memset(dst + 8 + dstlen, 0, AV_INPUT_BUFFER_PADDING_SIZE); - dstlen += 8; - } + 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; @@ -3390,7 +3415,7 @@ static int matroska_parse_webvtt(MatroskaDemuxContext *matroska, 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); @@ -3407,45 +3432,40 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska, 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 @@ -3506,7 +3526,7 @@ FF_DISABLE_DEPRECATION_WARNINGS 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); @@ -3514,9 +3534,10 @@ FF_ENABLE_DEPRECATION_WARNINGS return 0; +no_output: fail: - if (pkt_data != data) - av_freep(&pkt_data); + if (!buf) + av_free(pkt_data); return res; } @@ -3528,31 +3549,37 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, AVBufferRef *buf { uint64_t timecode = AV_NOPTS_VALUE; MatroskaTrack *track; + AVIOContext pb; int res = 0; AVStream *st; int16_t block_time; - uint32_t *lace_size = NULL; + uint32_t lace_size[256]; int n, flags, laces = 0; uint64_t num; - int trust_default_duration = 1; + int trust_default_duration; - 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; @@ -3563,7 +3590,8 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, AVBufferRef *buf if (cluster_time != (uint64_t) -1 && (block_time >= 0 || cluster_time >= -block_time)) { - timecode = cluster_time + block_time - track->codec_delay_in_track_tb; + uint64_t timecode_cluster_in_track_tb = (double) cluster_time / track->time_scale; + timecode = timecode_cluster_in_track_tb + block_time - track->codec_delay_in_track_tb; if (track->type == MATROSKA_TRACK_TYPE_SUBTITLE && timecode < track->end_timecode) is_keyframe = 0; /* overlapping subtitles are not key frame */ @@ -3583,19 +3611,21 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, AVBufferRef *buf return res; if (is_keyframe) matroska->skip_to_keyframe = 0; - else if (!st->skip_to_keyframe) { + else if (!st->internal->skip_to_keyframe) { av_log(matroska->ctx, AV_LOG_ERROR, "File is broken, keyframes not correctly marked!\n"); matroska->skip_to_keyframe = 0; } } - res = matroska_parse_laces(matroska, &data, &size, (flags & 0x06) >> 1, - &lace_size, &laces); - - if (res) - goto end; + res = matroska_parse_laces(matroska, &data, size, (flags & 0x06) >> 1, + &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) { + trust_default_duration = track->default_duration != 0; + if (track->audio.samplerate == 8000 && trust_default_duration) { // If this is needed for more codecs, then add them here if (st->codecpar->codec_id == AV_CODEC_ID_AC3) { if (track->audio.samplerate != st->codecpar->sample_rate || !st->codecpar->frame_size) @@ -3612,49 +3642,53 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, AVBufferRef *buf 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 (lace_size[n] > size) { - av_log(matroska->ctx, AV_LOG_ERROR, "Invalid packet size\n"); - break; + 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) - goto end; - + 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) - goto end; + 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) - goto end; + return res; } if (timecode != AV_NOPTS_VALUE) timecode = lace_duration ? timecode + lace_duration : AV_NOPTS_VALUE; data += lace_size[n]; - size -= lace_size[n]; } -end: - av_free(lace_size); - return res; + return 0; } static int matroska_parse_cluster(MatroskaDemuxContext *matroska) @@ -3666,7 +3700,7 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska) av_assert0(matroska->num_levels <= 2); if (matroska->num_levels == 1) { - res = ebml_parse(matroska, matroska_clusters, NULL); + res = ebml_parse(matroska, matroska_segment, NULL); if (res == 1) { /* Found a cluster: subtract the size of the ID already read. */ @@ -3747,13 +3781,13 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index, matroska_parse_cues(matroska); } - if (!st->nb_index_entries) + if (!st->internal->nb_index_entries) goto err; - timestamp = FFMAX(timestamp, st->index_entries[0].timestamp); + timestamp = FFMAX(timestamp, st->internal->index_entries[0].timestamp); - if ((index = av_index_search_timestamp(st, timestamp, flags)) < 0 || index == st->nb_index_entries - 1) { - matroska_reset_status(matroska, 0, st->index_entries[st->nb_index_entries - 1].pos); - while ((index = av_index_search_timestamp(st, timestamp, flags)) < 0 || index == st->nb_index_entries - 1) { + if ((index = av_index_search_timestamp(st, timestamp, flags)) < 0 || index == st->internal->nb_index_entries - 1) { + matroska_reset_status(matroska, 0, st->internal->index_entries[st->internal->nb_index_entries - 1].pos); + while ((index = av_index_search_timestamp(st, timestamp, flags)) < 0 || index == st->internal->nb_index_entries - 1) { matroska_clear_queue(matroska); if (matroska_parse_cluster(matroska) < 0) break; @@ -3761,7 +3795,7 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index, } matroska_clear_queue(matroska); - if (index < 0 || (matroska->cues_parsing_deferred < 0 && index == st->nb_index_entries - 1)) + if (index < 0 || (matroska->cues_parsing_deferred < 0 && index == st->internal->nb_index_entries - 1)) goto err; tracks = matroska->tracks.elem; @@ -3773,17 +3807,17 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index, } /* We seek to a level 1 element, so set the appropriate status. */ - matroska_reset_status(matroska, 0, st->index_entries[index].pos); + matroska_reset_status(matroska, 0, st->internal->index_entries[index].pos); if (flags & AVSEEK_FLAG_ANY) { - st->skip_to_keyframe = 0; + st->internal->skip_to_keyframe = 0; matroska->skip_to_timecode = timestamp; } else { - st->skip_to_keyframe = 1; - matroska->skip_to_timecode = st->index_entries[index].timestamp; + st->internal->skip_to_keyframe = 1; + matroska->skip_to_timecode = st->internal->index_entries[index].timestamp; } matroska->skip_to_keyframe = 1; matroska->done = 0; - ff_update_cur_dts(s, st, st->index_entries[index].timestamp); + ff_update_cur_dts(s, st, st->internal->index_entries[index].timestamp); return 0; err: // slightly hackish but allows proper fallback to @@ -3791,7 +3825,7 @@ err: matroska_reset_status(matroska, 0, -1); matroska->resync_pos = -1; matroska_clear_queue(matroska); - st->skip_to_keyframe = + st->internal->skip_to_keyframe = matroska->skip_to_keyframe = 0; matroska->done = 0; return -1; @@ -3828,8 +3862,8 @@ static CueDesc get_cue_desc(AVFormatContext *s, int64_t ts, int64_t cues_start) MatroskaDemuxContext *matroska = s->priv_data; CueDesc cue_desc; int i; - int nb_index_entries = s->streams[0]->nb_index_entries; - AVIndexEntry *index_entries = s->streams[0]->index_entries; + int nb_index_entries = s->streams[0]->internal->nb_index_entries; + AVIndexEntry *index_entries = s->streams[0]->internal->index_entries; if (ts >= matroska->duration * matroska->time_scale) return (CueDesc) {-1, -1, -1, -1}; for (i = 1; i < nb_index_entries; i++) { if (index_entries[i - 1].timestamp * matroska->time_scale <= ts && @@ -3859,11 +3893,11 @@ static int webm_clusters_start_with_keyframe(AVFormatContext *s) uint32_t id = matroska->current_id; int64_t cluster_pos, before_pos; int index, rv = 1; - if (s->streams[0]->nb_index_entries <= 0) return 0; + if (s->streams[0]->internal->nb_index_entries <= 0) return 0; // seek to the first cluster using cues. index = av_index_search_timestamp(s->streams[0], 0, 0); if (index < 0) return 0; - cluster_pos = s->streams[0]->index_entries[index].pos; + cluster_pos = s->streams[0]->internal->index_entries[index].pos; before_pos = avio_tell(s->pb); while (1) { uint64_t cluster_id, cluster_length; @@ -3987,9 +4021,9 @@ static int64_t webm_dash_manifest_compute_bandwidth(AVFormatContext *s, int64_t double bandwidth = 0.0; int i; - for (i = 0; i < st->nb_index_entries; i++) { + for (i = 0; i < st->internal->nb_index_entries; i++) { int64_t prebuffer_ns = 1000000000; - int64_t time_ns = st->index_entries[i].timestamp * matroska->time_scale; + int64_t time_ns = st->internal->index_entries[i].timestamp * matroska->time_scale; double nano_seconds_per_second = 1000000000.0; int64_t prebuffered_ns = time_ns + prebuffer_ns; double prebuffer_bytes = 0.0; @@ -4127,22 +4161,22 @@ static int webm_dash_manifest_cues(AVFormatContext *s, int64_t init_range) // store cue point timestamps as a comma separated list for checking subsegment alignment in // the muxer. assumes that each timestamp cannot be more than 20 characters long. - buf = av_malloc_array(s->streams[0]->nb_index_entries, 20); + buf = av_malloc_array(s->streams[0]->internal->nb_index_entries, 20); if (!buf) return -1; strcpy(buf, ""); - for (i = 0; i < s->streams[0]->nb_index_entries; i++) { + for (i = 0; i < s->streams[0]->internal->nb_index_entries; i++) { int ret = snprintf(buf + end, 20, - "%" PRId64"%s", s->streams[0]->index_entries[i].timestamp, - i != s->streams[0]->nb_index_entries - 1 ? "," : ""); - if (ret <= 0 || (ret == 20 && i == s->streams[0]->nb_index_entries - 1)) { + "%" PRId64"%s", s->streams[0]->internal->index_entries[i].timestamp, + i != s->streams[0]->internal->nb_index_entries - 1 ? "," : ""); + if (ret <= 0 || (ret == 20 && i == s->streams[0]->internal->nb_index_entries - 1)) { av_log(s, AV_LOG_ERROR, "timestamp too long.\n"); av_free(buf); return AVERROR_INVALIDDATA; } 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; } @@ -4158,17 +4192,20 @@ static int webm_dash_manifest_read_header(AVFormatContext *s) 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. @@ -4189,7 +4226,7 @@ static int webm_dash_manifest_read_header(AVFormatContext *s) 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; } } @@ -4199,6 +4236,9 @@ static int webm_dash_manifest_read_header(AVFormatContext *s) matroska->bandwidth, 0); } return 0; +fail: + matroska_read_close(s); + return ret; } static int webm_dash_manifest_read_packet(AVFormatContext *s, AVPacket *pkt)