diff options
Diffstat (limited to 'libavformat/matroskadec.c')
-rw-r--r-- | libavformat/matroskadec.c | 487 |
1 files changed, 362 insertions, 125 deletions
diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index 9b116b0100..a1aa0ebd10 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -1,21 +1,21 @@ /* * Matroska file demuxer - * Copyright (c) 2003-2008 The Libav Project + * Copyright (c) 2003-2008 The FFmpeg Project * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -39,6 +39,7 @@ #include "matroska.h" #include "libavcodec/bytestream.h" #include "libavcodec/mpeg4audio.h" +#include "libavutil/base64.h" #include "libavutil/intfloat.h" #include "libavutil/intreadwrite.h" #include "libavutil/avstring.h" @@ -102,9 +103,15 @@ typedef struct { } MatroskaTrackCompression; typedef struct { + uint64_t algo; + EbmlBin key_id; +} MatroskaTrackEncryption; + +typedef struct { uint64_t scope; uint64_t type; MatroskaTrackCompression compression; + MatroskaTrackEncryption encryption; } MatroskaTrackEncoding; typedef struct { @@ -113,7 +120,9 @@ typedef struct { uint64_t display_height; uint64_t pixel_width; uint64_t pixel_height; - uint64_t fourcc; + EbmlBin color_space; + uint64_t stereo_mode; + uint64_t alpha_mode; } MatroskaTrackVideo; typedef struct { @@ -134,6 +143,15 @@ typedef struct { } MatroskaTrackAudio; typedef struct { + uint64_t uid; + uint64_t type; +} MatroskaTrackPlane; + +typedef struct { + EbmlList combine_planes; +} MatroskaTrackOperation; + +typedef struct { uint64_t num; uint64_t uid; uint64_t type; @@ -147,11 +165,13 @@ typedef struct { uint64_t flag_forced; MatroskaTrackVideo video; MatroskaTrackAudio audio; + MatroskaTrackOperation operation; EbmlList encodings; AVStream *stream; int64_t end_timecode; int ms_compat; + uint64_t max_block_additional_id; } MatroskaTrack; typedef struct { @@ -230,6 +250,7 @@ typedef struct { uint64_t time_scale; double duration; char *title; + EbmlBin date_utc; EbmlList tracks; EbmlList attachments; EbmlList chapters; @@ -267,6 +288,8 @@ typedef struct { int64_t reference; uint64_t non_simple; EbmlBin bin; + uint64_t additional_id; + EbmlBin additional; } MatroskaBlock; static EbmlSyntax ebml_header[] = { @@ -291,25 +314,26 @@ static EbmlSyntax matroska_info[] = { { MATROSKA_ID_TITLE, EBML_UTF8, 0, offsetof(MatroskaDemuxContext,title) }, { MATROSKA_ID_WRITINGAPP, EBML_NONE }, { MATROSKA_ID_MUXINGAPP, EBML_NONE }, - { MATROSKA_ID_DATEUTC, EBML_NONE }, + { MATROSKA_ID_DATEUTC, EBML_BIN, 0, offsetof(MatroskaDemuxContext,date_utc) }, { MATROSKA_ID_SEGMENTUID, EBML_NONE }, { 0 } }; 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) }, - { MATROSKA_ID_VIDEODISPLAYHEIGHT, EBML_UINT, 0, offsetof(MatroskaTrackVideo,display_height) }, + { MATROSKA_ID_VIDEODISPLAYWIDTH, EBML_UINT, 0, offsetof(MatroskaTrackVideo,display_width), {.u=-1} }, + { MATROSKA_ID_VIDEODISPLAYHEIGHT, EBML_UINT, 0, offsetof(MatroskaTrackVideo,display_height), {.u=-1} }, { 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_VIDEOCOLORSPACE, EBML_BIN, 0, offsetof(MatroskaTrackVideo,color_space) }, + { MATROSKA_ID_VIDEOSTEREOMODE, EBML_UINT, 0, offsetof(MatroskaTrackVideo,stereo_mode) }, + { MATROSKA_ID_VIDEOALPHAMODE, EBML_UINT, 0, offsetof(MatroskaTrackVideo,alpha_mode) }, { 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 }, { 0 } }; @@ -328,10 +352,21 @@ static EbmlSyntax matroska_track_encoding_compression[] = { { 0 } }; +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 }, + { MATROSKA_ID_ENCODINGSIGALGO, EBML_NONE }, + { MATROSKA_ID_ENCODINGSIGHASHALGO, EBML_NONE }, + { MATROSKA_ID_ENCODINGSIGKEYID, EBML_NONE }, + { MATROSKA_ID_ENCODINGSIGNATURE, EBML_NONE }, + { 0 } +}; 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} }, + { MATROSKA_ID_ENCODINGENCRYPTION, EBML_NEST, 0, offsetof(MatroskaTrackEncoding,encryption), {.n=matroska_track_encoding_encryption} }, { MATROSKA_ID_ENCODINGORDER, EBML_NONE }, { 0 } }; @@ -341,6 +376,22 @@ static EbmlSyntax matroska_track_encodings[] = { { 0 } }; +static EbmlSyntax matroska_track_plane[] = { + { MATROSKA_ID_TRACKPLANEUID, EBML_UINT, 0, offsetof(MatroskaTrackPlane,uid) }, + { MATROSKA_ID_TRACKPLANETYPE, EBML_UINT, 0, offsetof(MatroskaTrackPlane,type) }, + { 0 } +}; + +static EbmlSyntax matroska_track_combine_planes[] = { + { MATROSKA_ID_TRACKPLANE, EBML_NEST, sizeof(MatroskaTrackPlane), offsetof(MatroskaTrackOperation,combine_planes), {.n=matroska_track_plane} }, + { 0 } +}; + +static EbmlSyntax matroska_track_operation[] = { + { MATROSKA_ID_TRACKCOMBINEPLANES, EBML_NEST, 0, 0, {.n=matroska_track_combine_planes} }, + { 0 } +}; + static EbmlSyntax matroska_track[] = { { MATROSKA_ID_TRACKNUMBER, EBML_UINT, 0, offsetof(MatroskaTrack,num) }, { MATROSKA_ID_TRACKNAME, EBML_UTF8, 0, offsetof(MatroskaTrack,name) }, @@ -355,7 +406,9 @@ static EbmlSyntax matroska_track[] = { { MATROSKA_ID_TRACKFLAGFORCED, EBML_UINT, 0, offsetof(MatroskaTrack,flag_forced), {.u=0} }, { MATROSKA_ID_TRACKVIDEO, EBML_NEST, 0, offsetof(MatroskaTrack,video), {.n=matroska_track_video} }, { MATROSKA_ID_TRACKAUDIO, EBML_NEST, 0, offsetof(MatroskaTrack,audio), {.n=matroska_track_audio} }, + { MATROSKA_ID_TRACKOPERATION, EBML_NEST, 0, offsetof(MatroskaTrack,operation), {.n=matroska_track_operation} }, { MATROSKA_ID_TRACKCONTENTENCODINGS,EBML_NEST, 0, 0, {.n=matroska_track_encodings} }, + { MATROSKA_ID_TRACKMAXBLKADDID, EBML_UINT, 0, offsetof(MatroskaTrack,max_block_additional_id) }, { MATROSKA_ID_TRACKFLAGENABLED, EBML_NONE }, { MATROSKA_ID_TRACKFLAGLACING, EBML_NONE }, { MATROSKA_ID_CODECNAME, EBML_NONE }, @@ -364,7 +417,6 @@ static EbmlSyntax matroska_track[] = { { MATROSKA_ID_CODECDOWNLOADURL, EBML_NONE }, { MATROSKA_ID_TRACKMINCACHE, EBML_NONE }, { MATROSKA_ID_TRACKMAXCACHE, EBML_NONE }, - { MATROSKA_ID_TRACKMAXBLKADDID, EBML_NONE }, { 0 } }; @@ -495,10 +547,22 @@ static EbmlSyntax matroska_segments[] = { { 0 } }; +static EbmlSyntax matroska_blockmore[] = { + { MATROSKA_ID_BLOCKADDID, EBML_UINT, 0, offsetof(MatroskaBlock,additional_id) }, + { MATROSKA_ID_BLOCKADDITIONAL, EBML_BIN, 0, offsetof(MatroskaBlock,additional) }, + { 0 } +}; + +static EbmlSyntax matroska_blockadditions[] = { + { MATROSKA_ID_BLOCKMORE, EBML_NEST, 0, 0, {.n=matroska_blockmore} }, + { 0 } +}; + 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_SIMPLEBLOCK, EBML_BIN, 0, offsetof(MatroskaBlock,bin) }, - { MATROSKA_ID_BLOCKDURATION, EBML_UINT, 0, offsetof(MatroskaBlock,duration), {.u=AV_NOPTS_VALUE} }, + { MATROSKA_ID_BLOCKDURATION, EBML_UINT, 0, offsetof(MatroskaBlock,duration) }, { MATROSKA_ID_BLOCKREFERENCE, EBML_UINT, 0, offsetof(MatroskaBlock,reference) }, { MATROSKA_ID_CODECSTATE, EBML_NONE }, { 1, EBML_UINT, 0, offsetof(MatroskaBlock,non_simple), {.u=1} }, @@ -571,7 +635,7 @@ static int matroska_resync(MatroskaDemuxContext *matroska, int64_t last_pos) id = avio_rb32(pb); // try to find a toplevel element - while (!pb->eof_reached) { + while (!url_feof(pb)) { if (id == MATROSKA_ID_INFO || id == MATROSKA_ID_TRACKS || id == MATROSKA_ID_CUES || id == MATROSKA_ID_TAGS || id == MATROSKA_ID_SEEKHEAD || id == MATROSKA_ID_ATTACHMENTS || @@ -623,7 +687,7 @@ static int ebml_read_num(MatroskaDemuxContext *matroska, AVIOContext *pb, * use it safely here to catch EOS. */ if (!(total = avio_r8(pb))) { /* we might encounter EOS here */ - if (!pb->eof_reached) { + if (!url_feof(pb)) { int64_t pos = avio_tell(pb); av_log(matroska->ctx, AV_LOG_ERROR, "Read error at pos. %"PRIu64" (0x%"PRIx64")\n", @@ -733,14 +797,15 @@ static int ebml_read_ascii(AVIOContext *pb, int size, char **str) */ static int ebml_read_binary(AVIOContext *pb, int length, EbmlBin *bin) { - av_free(bin->data); - if (!(bin->data = av_malloc(length))) + av_fast_padded_malloc(&bin->data, &bin->size, length); + if (!bin->data) return AVERROR(ENOMEM); bin->size = length; bin->pos = avio_tell(pb); if (avio_read(pb, bin->data, length) != length) { av_freep(&bin->data); + bin->size = 0; return AVERROR(EIO); } @@ -917,7 +982,10 @@ 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: return 1; - default: return avio_skip(pb,length)<0 ? AVERROR(EIO) : 0; + default: + if(ffio_limit(pb, length) != length) + return AVERROR(EIO); + return avio_skip(pb,length)<0 ? AVERROR(EIO) : 0; } if (res == AVERROR_INVALIDDATA) av_log(matroska->ctx, AV_LOG_ERROR, "Invalid element\n"); @@ -1021,7 +1089,7 @@ static int matroska_decode_buffer(uint8_t** buf, int* buf_size, int result = 0; int olen; - if (pkt_size >= 10000000) + if (pkt_size >= 10000000U) return AVERROR_INVALIDDATA; switch (encodings[0].compression.algo) { @@ -1029,6 +1097,11 @@ static int matroska_decode_buffer(uint8_t** buf, int* buf_size, int header_size = encodings[0].compression.settings.size; uint8_t *header = encodings[0].compression.settings.data; + if (header_size && !header) { + av_log(NULL, AV_LOG_ERROR, "Compression size but no data in headerstrip\n"); + return -1; + } + if (!header_size) return 0; @@ -1077,7 +1150,10 @@ static int matroska_decode_buffer(uint8_t** buf, int* buf_size, pkt_data = newpktdata; zstream.avail_out = pkt_size - zstream.total_out; zstream.next_out = pkt_data + zstream.total_out; - result = inflate(&zstream, Z_NO_FLUSH); + if (pkt_data) { + result = inflate(&zstream, Z_NO_FLUSH); + } else + result = Z_MEM_ERROR; } while (result==Z_OK && pkt_size<10000000); pkt_size = zstream.total_out; inflateEnd(&zstream); @@ -1108,7 +1184,10 @@ static int matroska_decode_buffer(uint8_t** buf, int* buf_size, pkt_data = newpktdata; bzstream.avail_out = pkt_size - bzstream.total_out_lo32; bzstream.next_out = pkt_data + bzstream.total_out_lo32; - result = BZ2_bzDecompress(&bzstream); + if (pkt_data) { + result = BZ2_bzDecompress(&bzstream); + } else + result = BZ_MEM_ERROR; } while (result==BZ_OK && pkt_size<10000000); pkt_size = bzstream.total_out_lo32; BZ2_bzDecompressEnd(&bzstream); @@ -1134,6 +1213,7 @@ static int matroska_decode_buffer(uint8_t** buf, int* buf_size, return result; } +#if FF_API_ASS_SSA static void matroska_fix_ass_packet(MatroskaDemuxContext *matroska, AVPacket *pkt, uint64_t display_duration) { @@ -1141,7 +1221,8 @@ static void matroska_fix_ass_packet(MatroskaDemuxContext *matroska, char *layer, *ptr = pkt->data, *end = ptr+pkt->size; for (; *ptr!=',' && ptr<end-1; ptr++); if (*ptr == ',') - layer = ++ptr; + ptr++; + layer = ptr; for (; *ptr!=',' && ptr<end-1; ptr++); if (*ptr == ',') { int64_t end_pts = pkt->pts + display_duration; @@ -1169,17 +1250,17 @@ static void matroska_fix_ass_packet(MatroskaDemuxContext *matroska, static int matroska_merge_packets(AVPacket *out, AVPacket *in) { - int old_size = out->size; int ret = av_grow_packet(out, in->size); if (ret < 0) return ret; - memcpy(out->data + old_size, in->data, in->size); + memcpy(out->data + out->size - in->size, in->data, in->size); av_free_packet(in); av_free(in); return 0; } +#endif static void matroska_convert_tag(AVFormatContext *s, EbmlList *list, AVDictionary **metadata, char *prefix) @@ -1189,7 +1270,7 @@ static void matroska_convert_tag(AVFormatContext *s, EbmlList *list, int i; for (i=0; i < list->nb_elem; i++) { - const char *lang = strcmp(tags[i].lang, "und") ? tags[i].lang : NULL; + const char *lang= (tags[i].lang && strcmp(tags[i].lang, "und")) ? tags[i].lang : NULL; if (!tags[i].name) { av_log(s, AV_LOG_WARNING, "Skipping invalid tag with no TagName.\n"); @@ -1320,26 +1401,20 @@ static void matroska_execute_seekhead(MatroskaDemuxContext *matroska) continue; } - if (matroska_parse_seekhead_entry(matroska, i) < 0) + if (matroska_parse_seekhead_entry(matroska, i) < 0) { + // mark index as broken + matroska->cues_parsing_deferred = -1; break; + } } } -static void matroska_parse_cues(MatroskaDemuxContext *matroska) { - EbmlList *seekhead_list = &matroska->seekhead; - MatroskaSeekhead *seekhead = seekhead_list->elem; +static void matroska_add_index_entries(MatroskaDemuxContext *matroska) { EbmlList *index_list; MatroskaIndex *index; int index_scale = 1; int i, j; - for (i = 0; i < seekhead_list->nb_elem; i++) - if (seekhead[i].id == MATROSKA_ID_CUES) - break; - assert(i <= seekhead_list->nb_elem); - - matroska_parse_seekhead_entry(matroska, i); - index_list = &matroska->index; index = index_list->elem; if (index_list->nb_elem @@ -1361,6 +1436,21 @@ static void matroska_parse_cues(MatroskaDemuxContext *matroska) { } } +static void matroska_parse_cues(MatroskaDemuxContext *matroska) { + EbmlList *seekhead_list = &matroska->seekhead; + MatroskaSeekhead *seekhead = seekhead_list->elem; + int i; + + for (i = 0; i < seekhead_list->nb_elem; i++) + if (seekhead[i].id == MATROSKA_ID_CUES) + break; + av_assert1(i <= seekhead_list->nb_elem); + + if (matroska_parse_seekhead_entry(matroska, i) < 0) + matroska->cues_parsing_deferred = -1; + matroska_add_index_entries(matroska); +} + static int matroska_aac_profile(char *codec_id) { static const char * const aac_profiles[] = { "MAIN", "LC", "SSR" }; @@ -1382,6 +1472,17 @@ static int matroska_aac_sri(int samplerate) return sri; } +static void matroska_metadata_creation_time(AVDictionary **metadata, int64_t date_utc) +{ + char buffer[32]; + /* Convert to seconds and adjust by number of seconds between 2001-01-01 and Epoch */ + time_t creation_time = date_utc / 1000000000 + 978307200; + struct tm *ptm = gmtime(&creation_time); + if (!ptm) return; + strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", ptm); + av_dict_set(metadata, "creation_time", buffer, 0); +} + static int matroska_read_header(AVFormatContext *s) { MatroskaDemuxContext *matroska = s->priv_data; @@ -1394,20 +1495,25 @@ static int matroska_read_header(AVFormatContext *s) int64_t pos; Ebml ebml = { 0 }; AVStream *st; - int i, j, res; + int i, j, k, res; matroska->ctx = s; /* First read the EBML header. */ if (ebml_parse(matroska, ebml_syntax, &ebml) || ebml.version > EBML_VERSION || ebml.max_size > sizeof(uint64_t) - || ebml.id_length > sizeof(uint32_t) || ebml.doctype_version > 2) { + || ebml.id_length > sizeof(uint32_t) || ebml.doctype_version > 3 || !ebml.doctype) { av_log(matroska->ctx, AV_LOG_ERROR, "EBML header using unsupported features\n" "(EBML version %"PRIu64", doctype %s, doc version %"PRIu64")\n", ebml.version, ebml.doctype, ebml.doctype_version); ebml_free(ebml_syntax, &ebml); return AVERROR_PATCHWELCOME; + } else if (ebml.doctype_version == 3) { + av_log(matroska->ctx, AV_LOG_WARNING, + "EBML header using unsupported features\n" + "(EBML version %"PRIu64", doctype %s, doc version %"PRIu64")\n", + ebml.version, ebml.doctype, ebml.doctype_version); } for (i = 0; i < FF_ARRAY_ELEMS(matroska_doctypes); i++) if (!strcmp(ebml.doctype, matroska_doctypes[i])) @@ -1441,16 +1547,21 @@ static int matroska_read_header(AVFormatContext *s) * 1000 / AV_TIME_BASE; av_dict_set(&s->metadata, "title", matroska->title, 0); + if (matroska->date_utc.size == 8) + matroska_metadata_creation_time(&s->metadata, AV_RB64(matroska->date_utc.data)); + tracks = matroska->tracks.elem; for (i=0; i < matroska->tracks.nb_elem; i++) { MatroskaTrack *track = &tracks[i]; enum AVCodecID codec_id = AV_CODEC_ID_NONE; - EbmlList *encodings_list = &tracks->encodings; + EbmlList *encodings_list = &track->encodings; MatroskaTrackEncoding *encodings = encodings_list->elem; uint8_t *extradata = NULL; int extradata_size = 0; int extradata_offset = 0; + uint32_t fourcc = 0; AVIOContext b; + char* key_id_base64 = NULL; /* Apply some sanity checks. */ if (track->type != MATROSKA_TRACK_TYPE_VIDEO && @@ -1467,10 +1578,12 @@ static int matroska_read_header(AVFormatContext *s) if (track->type == MATROSKA_TRACK_TYPE_VIDEO) { if (!track->default_duration && track->video.frame_rate > 0) track->default_duration = 1000000000/track->video.frame_rate; - if (!track->video.display_width) + if (track->video.display_width == -1) track->video.display_width = track->video.pixel_width; - if (!track->video.display_height) + if (track->video.display_height == -1) track->video.display_height = track->video.pixel_height; + if (track->video.color_space.size == 4) + fourcc = AV_RL32(track->video.color_space.data); } else if (track->type == MATROSKA_TRACK_TYPE_AUDIO) { if (!track->audio.out_samplerate) track->audio.out_samplerate = track->audio.samplerate; @@ -1479,8 +1592,24 @@ static int matroska_read_header(AVFormatContext *s) av_log(matroska->ctx, AV_LOG_ERROR, "Multiple combined encodings not supported"); } else if (encodings_list->nb_elem == 1) { - if (encodings[0].type || - ( + if (encodings[0].type) { + if (encodings[0].encryption.key_id.size > 0) { + /* Save the encryption key id to be stored later as a + metadata tag. */ + const int b64_size = AV_BASE64_SIZE(encodings[0].encryption.key_id.size); + key_id_base64 = av_malloc(b64_size); + if (key_id_base64 == NULL) + return AVERROR(ENOMEM); + + av_base64_encode(key_id_base64, b64_size, + encodings[0].encryption.key_id.data, + encodings[0].encryption.key_id.size); + } else { + encodings[0].scope = 0; + av_log(matroska->ctx, AV_LOG_ERROR, + "Unsupported encoding type"); + } + } else if ( #if CONFIG_ZLIB encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_ZLIB && #endif @@ -1490,7 +1619,7 @@ static int matroska_read_header(AVFormatContext *s) #if CONFIG_LZO encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_LZO && #endif - encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP)) { + encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP) { encodings[0].scope = 0; av_log(matroska->ctx, AV_LOG_ERROR, "Unsupported encoding type"); @@ -1520,15 +1649,23 @@ static int matroska_read_header(AVFormatContext *s) } st = track->stream = avformat_new_stream(s, NULL); - if (st == NULL) + if (st == NULL) { + av_free(key_id_base64); return AVERROR(ENOMEM); + } + + 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); + } if (!strcmp(track->codec_id, "V_MS/VFW/FOURCC") && track->codec_priv.size >= 40 && track->codec_priv.data != NULL) { track->ms_compat = 1; - track->video.fourcc = AV_RL32(track->codec_priv.data + 16); - codec_id = ff_codec_get_id(ff_codec_bmp_tags, track->video.fourcc); + fourcc = AV_RL32(track->codec_priv.data + 16); + codec_id = ff_codec_get_id(ff_codec_bmp_tags, fourcc); extradata_offset = 40; } else if (!strcmp(track->codec_id, "A_MS/ACM") && track->codec_priv.size >= 14 @@ -1544,8 +1681,8 @@ static int matroska_read_header(AVFormatContext *s) } else if (!strcmp(track->codec_id, "V_QUICKTIME") && (track->codec_priv.size >= 86) && (track->codec_priv.data != NULL)) { - track->video.fourcc = AV_RL32(track->codec_priv.data); - codec_id=ff_codec_get_id(ff_codec_movvideo_tags, track->video.fourcc); + fourcc = AV_RL32(track->codec_priv.data); + codec_id = ff_codec_get_id(ff_codec_movvideo_tags, fourcc); } else if (codec_id == AV_CODEC_ID_PCM_S16BE) { switch (track->audio.bitdepth) { case 8: codec_id = AV_CODEC_ID_PCM_U8; break; @@ -1576,7 +1713,7 @@ static int matroska_read_header(AVFormatContext *s) extradata_size = 5; } else extradata_size = 2; - } else if (codec_id == AV_CODEC_ID_ALAC && track->codec_priv.size) { + } else if (codec_id == AV_CODEC_ID_ALAC && track->codec_priv.size && track->codec_priv.size < INT_MAX - 12 - FF_INPUT_BUFFER_PADDING_SIZE) { /* Only ALAC's magic cookie is stored in Matroska's track headers. Create the "atom size", "tag", and "tag version" fields the decoder expects manually. */ @@ -1591,7 +1728,7 @@ static int matroska_read_header(AVFormatContext *s) track->codec_priv.size); } else if (codec_id == AV_CODEC_ID_TTA) { extradata_size = 30; - extradata = av_mallocz(extradata_size); + extradata = av_mallocz(extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); if (extradata == NULL) return AVERROR(ENOMEM); ffio_init_context(&b, extradata, extradata_size, 1, @@ -1608,9 +1745,11 @@ static int matroska_read_header(AVFormatContext *s) } else if (codec_id == AV_CODEC_ID_RA_144) { track->audio.out_samplerate = 8000; track->audio.channels = 1; - } else if (codec_id == AV_CODEC_ID_RA_288 || codec_id == AV_CODEC_ID_COOK || - codec_id == AV_CODEC_ID_ATRAC3 || codec_id == AV_CODEC_ID_SIPR) { + } else if ((codec_id == AV_CODEC_ID_RA_288 || codec_id == AV_CODEC_ID_COOK || + codec_id == AV_CODEC_ID_ATRAC3 || codec_id == AV_CODEC_ID_SIPR) + && track->codec_priv.data) { int flavor; + ffio_init_context(&b, track->codec_priv.data,track->codec_priv.size, 0, NULL, NULL, NULL, NULL); avio_skip(&b, 22); @@ -1672,8 +1811,10 @@ static int matroska_read_header(AVFormatContext *s) } if (track->type == MATROSKA_TRACK_TYPE_VIDEO) { + MatroskaTrackPlane *planes = track->operation.combine_planes.elem; + st->codec->codec_type = AVMEDIA_TYPE_VIDEO; - st->codec->codec_tag = track->video.fourcc; + st->codec->codec_tag = fourcc; st->codec->width = track->video.pixel_width; st->codec->height = track->video.pixel_height; av_reduce(&st->sample_aspect_ratio.num, @@ -1681,21 +1822,52 @@ static int matroska_read_header(AVFormatContext *s) st->codec->height * track->video.display_width, st->codec-> width * track->video.display_height, 255); - if (st->codec->codec_id != AV_CODEC_ID_H264) st->need_parsing = AVSTREAM_PARSE_HEADERS; if (track->default_duration) { av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den, 1000000000, track->default_duration, 30000); +#if FF_API_R_FRAME_RATE + st->r_frame_rate = st->avg_frame_rate; +#endif + } + + /* export stereo mode flag as metadata tag */ + if (track->video.stereo_mode && track->video.stereo_mode < MATROSKA_VIDEO_STEREO_MODE_COUNT) + av_dict_set(&st->metadata, "stereo_mode", ff_matroska_video_stereo_mode[track->video.stereo_mode], 0); + + /* export alpha mode flag as metadata tag */ + if (track->video.alpha_mode) + av_dict_set(&st->metadata, "alpha_mode", "1", 0); + + /* if we have virtual track, mark the real tracks */ + for (j=0; j < track->operation.combine_planes.nb_elem; j++) { + char buf[32]; + if (planes[j].type >= MATROSKA_VIDEO_STEREO_PLANE_COUNT) + continue; + snprintf(buf, sizeof(buf), "%s_%d", + ff_matroska_video_stereo_plane[planes[j].type], i); + for (k=0; k < matroska->tracks.nb_elem; k++) + if (planes[j].uid == tracks[k].uid) { + av_dict_set(&s->streams[k]->metadata, + "stereo_mode", buf, 0); + break; + } } } else if (track->type == MATROSKA_TRACK_TYPE_AUDIO) { st->codec->codec_type = AVMEDIA_TYPE_AUDIO; st->codec->sample_rate = track->audio.out_samplerate; st->codec->channels = track->audio.channels; + st->codec->bits_per_coded_sample = track->audio.bitdepth; if (st->codec->codec_id != AV_CODEC_ID_AAC) st->need_parsing = AVSTREAM_PARSE_HEADERS; } else if (track->type == MATROSKA_TRACK_TYPE_SUBTITLE) { st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; - if (st->codec->codec_id == AV_CODEC_ID_SSA) +#if FF_API_ASS_SSA + if (st->codec->codec_id == AV_CODEC_ID_SSA || + st->codec->codec_id == AV_CODEC_ID_ASS) +#else + if (st->codec->codec_id == AV_CODEC_ID_ASS) +#endif matroska->contains_ssa = 1; } } @@ -1713,7 +1885,7 @@ static int matroska_read_header(AVFormatContext *s) av_dict_set(&st->metadata, "mimetype", attachements[j].mime, 0); st->codec->codec_id = AV_CODEC_ID_NONE; st->codec->codec_type = AVMEDIA_TYPE_ATTACHMENT; - st->codec->extradata = av_malloc(attachements[j].bin.size); + st->codec->extradata = av_malloc(attachements[j].bin.size + FF_INPUT_BUFFER_PADDING_SIZE); if(st->codec->extradata == NULL) break; st->codec->extradata_size = attachements[j].bin.size; @@ -1743,6 +1915,8 @@ static int matroska_read_header(AVFormatContext *s) max_start = chapters[i].start; } + matroska_add_index_entries(matroska); + matroska_convert_tags(s); return 0; @@ -1812,7 +1986,7 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf, return 0; } - assert(size > 0); + av_assert0(size > 0); *laces = *data + 1; data += 1; size -= 1; @@ -1826,18 +2000,18 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf, uint32_t total = 0; for (n = 0; res == 0 && n < *laces - 1; n++) { while (1) { - if (size == 0) { - res = AVERROR_EOF; + if (size <= total) { + res = AVERROR_INVALIDDATA; break; } temp = *data; + total += temp; lace_size[n] += temp; data += 1; size -= 1; if (temp != 0xff) break; } - total += lace_size[n]; } if (size <= total) { res = AVERROR_INVALIDDATA; @@ -1861,10 +2035,10 @@ 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) { + if (n < 0 || num > INT_MAX) { av_log(matroska->ctx, AV_LOG_INFO, "EBML block data error\n"); - res = n; + res = n<0 ? n : AVERROR_INVALIDDATA; break; } data += n; @@ -1874,10 +2048,10 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf, int64_t snum; int r; r = matroska_ebmlnum_sint(matroska, data, size, &snum); - if (r < 0) { + 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; + res = r<0 ? r : AVERROR_INVALIDDATA; break; } data += r; @@ -1905,7 +2079,7 @@ static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska, MatroskaTrack *track, AVStream *st, uint8_t *data, int size, - uint64_t timecode, uint64_t duration, + uint64_t timecode, int64_t pos) { int a = st->codec->block_align; @@ -1936,7 +2110,7 @@ static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska, } memcpy(track->audio.buf + y*w, data, w); } else { - if (size < sps * w / sps) { + if (size < sps * w / sps || h<=0) { av_log(matroska->ctx, AV_LOG_ERROR, "Corrupt generic RM-style audio packet size\n"); return AVERROR_INVALIDDATA; @@ -1954,8 +2128,11 @@ static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska, } while (track->audio.pkt_cnt) { - AVPacket *pkt = av_mallocz(sizeof(AVPacket)); - av_new_packet(pkt, a); + AVPacket *pkt = NULL; + if (!(pkt = av_mallocz(sizeof(AVPacket))) || av_new_packet(pkt, a) < 0){ + av_free(pkt); + return AVERROR(ENOMEM); + } memcpy(pkt->data, track->audio.buf + a * (h*w / a - track->audio.pkt_cnt--), a); pkt->pts = track->audio.buf_timecode; @@ -2053,15 +2230,16 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska, MatroskaTrack *track, AVStream *st, uint8_t *data, int pkt_size, - uint64_t timecode, uint64_t duration, - int64_t pos, int is_keyframe) + uint64_t timecode, uint64_t lace_duration, + int64_t pos, int is_keyframe, + uint8_t *additional, uint64_t additional_id, int additional_size) { MatroskaTrackEncoding *encodings = track->encodings.elem; uint8_t *pkt_data = data; int offset = 0, res; AVPacket *pkt; - if (encodings && encodings->scope & 1) { + if (encodings && !encodings->type && encodings->scope & 1) { res = matroska_decode_buffer(&pkt_data, &pkt_size, track); if (res < 0) return res; @@ -2086,7 +2264,8 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska, /* XXX: prevent data copy... */ if (av_new_packet(pkt, pkt_size + offset) < 0) { av_free(pkt); - return AVERROR(ENOMEM); + res = AVERROR(ENOMEM); + goto fail; } if (st->codec->codec_id == AV_CODEC_ID_PRORES) { @@ -2098,23 +2277,56 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska, memcpy(pkt->data + offset, pkt_data, pkt_size); if (pkt_data != data) - av_free(pkt_data); + av_freep(&pkt_data); pkt->flags = is_keyframe; pkt->stream_index = st->index; + if (additional_size > 0) { + uint8_t *side_data = av_packet_new_side_data(pkt, + AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL, + additional_size + 8); + if(side_data == NULL) { + av_free_packet(pkt); + av_free(pkt); + return AVERROR(ENOMEM); + } + AV_WB64(side_data, additional_id); + memcpy(side_data + 8, additional, additional_size); + } + if (track->ms_compat) pkt->dts = timecode; else pkt->pts = timecode; pkt->pos = pos; - if (st->codec->codec_id == AV_CODEC_ID_TEXT) - pkt->convergence_duration = duration; - else if (track->type != MATROSKA_TRACK_TYPE_SUBTITLE) - pkt->duration = duration; + if (st->codec->codec_id == AV_CODEC_ID_SUBRIP) { + /* + * For backward compatibility. + * Historically, we have put subtitle duration + * in convergence_duration, on the off chance + * that the time_scale is less than 1us, which + * could result in a 32bit overflow on the + * normal duration field. + */ + pkt->convergence_duration = lace_duration; + } + if (track->type != MATROSKA_TRACK_TYPE_SUBTITLE || + lace_duration <= INT_MAX) { + /* + * For non subtitle tracks, just store the duration + * as normal. + * + * If it's a subtitle track and duration value does + * not overflow a uint32, then also store it normally. + */ + pkt->duration = lace_duration; + } + +#if FF_API_ASS_SSA if (st->codec->codec_id == AV_CODEC_ID_SSA) - matroska_fix_ass_packet(matroska, pkt, duration); + matroska_fix_ass_packet(matroska, pkt, lace_duration); if (matroska->prev_pkt && timecode != AV_NOPTS_VALUE && @@ -2126,6 +2338,10 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska, dynarray_add(&matroska->packets,&matroska->num_packets,pkt); matroska->prev_pkt = pkt; } +#else + dynarray_add(&matroska->packets, &matroska->num_packets, pkt); + matroska->prev_pkt = pkt; +#endif return 0; fail: @@ -2137,6 +2353,7 @@ fail: static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int size, int64_t pos, uint64_t cluster_time, uint64_t block_duration, int is_keyframe, + uint8_t *additional, uint64_t additional_id, int additional_size, int64_t cluster_pos) { uint64_t timecode = AV_NOPTS_VALUE; @@ -2146,7 +2363,7 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int16_t block_time; uint32_t *lace_size = NULL; int n, flags, laces = 0; - uint64_t num, duration; + uint64_t num; if ((n = matroska_ebmlnum_uint(matroska, data, size, &num)) < 0) { av_log(matroska->ctx, AV_LOG_ERROR, "EBML block data error\n"); @@ -2165,8 +2382,9 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, st = track->stream; if (st->discard >= AVDISCARD_ALL) return res; + av_assert1(block_duration != AV_NOPTS_VALUE); - block_time = AV_RB16(data); + block_time = sign_extend(AV_RB16(data), 16); data += 2; flags = *data++; size -= 3; @@ -2184,9 +2402,14 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, } if (matroska->skip_to_keyframe && track->type != MATROSKA_TRACK_TYPE_SUBTITLE) { - if (!is_keyframe || timecode < matroska->skip_to_timecode) + if (timecode < matroska->skip_to_timecode) return res; - matroska->skip_to_keyframe = 0; + if (!st->skip_to_keyframe) { + av_log(matroska->ctx, AV_LOG_ERROR, "File is broken, keyframes not correctly marked!\n"); + matroska->skip_to_keyframe = 0; + } + if (is_keyframe) + matroska->skip_to_keyframe = 0; } res = matroska_parse_laces(matroska, &data, &size, (flags & 0x06) >> 1, @@ -2195,22 +2418,21 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, if (res) goto end; - if (block_duration != AV_NOPTS_VALUE) { - duration = block_duration / laces; - if (block_duration != duration * laces) { - av_log(matroska->ctx, AV_LOG_WARNING, - "Incorrect block_duration, possibly corrupted container"); - } - } else { - duration = track->default_duration / matroska->time_scale; - block_duration = duration * laces; - } + if (!block_duration) + block_duration = track->default_duration * laces / matroska->time_scale; - if (timecode != AV_NOPTS_VALUE) + if (cluster_time != (uint64_t)-1 && (block_time >= 0 || cluster_time >= -block_time)) track->end_timecode = FFMAX(track->end_timecode, timecode + block_duration); for (n = 0; n < laces; n++) { + int64_t lace_duration = block_duration*(n+1) / laces - block_duration*n / laces; + + if (lace_size[n] > size) { + av_log(matroska->ctx, AV_LOG_ERROR, "Invalid packet size\n"); + break; + } + if ((st->codec->codec_id == AV_CODEC_ID_RA_288 || st->codec->codec_id == AV_CODEC_ID_COOK || st->codec->codec_id == AV_CODEC_ID_SIPR || @@ -2219,21 +2441,23 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, res = matroska_parse_rm_audio(matroska, track, st, data, lace_size[n], - timecode, duration, pos); + timecode, pos); if (res) goto end; } else { res = matroska_parse_frame(matroska, track, st, data, lace_size[n], - timecode, duration, - pos, !n? is_keyframe : 0); + timecode, lace_duration, + pos, !n? is_keyframe : 0, + additional, additional_id, additional_size); if (res) goto end; } if (timecode != AV_NOPTS_VALUE) - timecode = duration ? timecode + duration : AV_NOPTS_VALUE; + timecode = lace_duration ? timecode + lace_duration : AV_NOPTS_VALUE; data += lace_size[n]; + size -= lace_size[n]; } end: @@ -2281,18 +2505,21 @@ static int matroska_parse_cluster_incremental(MatroskaDemuxContext *matroska) i = blocks_list->nb_elem - 1; if (blocks[i].bin.size > 0 && blocks[i].bin.data) { int is_keyframe = blocks[i].non_simple ? !blocks[i].reference : -1; + uint8_t* additional = blocks[i].additional.size > 0 ? + blocks[i].additional.data : NULL; if (!blocks[i].non_simple) - blocks[i].duration = AV_NOPTS_VALUE; + blocks[i].duration = 0; res = matroska_parse_block(matroska, blocks[i].bin.data, blocks[i].bin.size, blocks[i].bin.pos, matroska->current_cluster.timecode, blocks[i].duration, is_keyframe, + additional, blocks[i].additional_id, + blocks[i].additional.size, matroska->current_cluster_pos); } } - if (res < 0) matroska->done = 1; return res; } @@ -2312,15 +2539,13 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska) res = ebml_parse(matroska, matroska_clusters, &cluster); blocks_list = &cluster.blocks; blocks = blocks_list->elem; - for (i=0; i<blocks_list->nb_elem && !res; i++) + for (i=0; i<blocks_list->nb_elem; i++) if (blocks[i].bin.size > 0 && blocks[i].bin.data) { int is_keyframe = blocks[i].non_simple ? !blocks[i].reference : -1; - if (!blocks[i].non_simple) - blocks[i].duration = AV_NOPTS_VALUE; res=matroska_parse_block(matroska, blocks[i].bin.data, blocks[i].bin.size, blocks[i].bin.pos, cluster.timecode, - blocks[i].duration, is_keyframe, + blocks[i].duration, is_keyframe, NULL, 0, 0, pos); } ebml_free(matroska_cluster, &cluster); @@ -2330,22 +2555,16 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska) static int matroska_read_packet(AVFormatContext *s, AVPacket *pkt) { MatroskaDemuxContext *matroska = s->priv_data; - int ret = 0; - while (!ret && matroska_deliver_packet(matroska, pkt)) { + while (matroska_deliver_packet(matroska, pkt)) { int64_t pos = avio_tell(matroska->ctx->pb); if (matroska->done) return AVERROR_EOF; if (matroska_parse_cluster(matroska) < 0) - ret = matroska_resync(matroska, pos); - } - - if (ret == AVERROR_INVALIDDATA && pkt->data) { - pkt->flags |= AV_PKT_FLAG_CORRUPT; - return 0; + matroska_resync(matroska, pos); } - return ret; + return 0; } static int matroska_read_seek(AVFormatContext *s, int stream_index, @@ -2357,13 +2576,13 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index, int i, index, index_sub, index_min; /* Parse the CUES now since we need the index data to seek. */ - if (matroska->cues_parsing_deferred) { - matroska_parse_cues(matroska); + if (matroska->cues_parsing_deferred > 0) { matroska->cues_parsing_deferred = 0; + matroska_parse_cues(matroska); } if (!st->nb_index_entries) - return 0; + goto err; timestamp = FFMAX(timestamp, st->index_entries[0].timestamp); if ((index = av_index_search_timestamp(st, timestamp, flags)) < 0) { @@ -2377,8 +2596,8 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index, } matroska_clear_queue(matroska); - if (index < 0) - return 0; + if (index < 0 || (matroska->cues_parsing_deferred < 0 && index == st->nb_index_entries - 1)) + goto err; index_min = index; for (i=0; i < matroska->tracks.nb_elem; i++) { @@ -2387,22 +2606,40 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index, tracks[i].audio.buf_timecode = AV_NOPTS_VALUE; tracks[i].end_timecode = 0; if (tracks[i].type == MATROSKA_TRACK_TYPE_SUBTITLE - && !tracks[i].stream->discard != AVDISCARD_ALL) { + && tracks[i].stream->discard != AVDISCARD_ALL) { index_sub = av_index_search_timestamp(tracks[i].stream, st->index_entries[index].timestamp, AVSEEK_FLAG_BACKWARD); - 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; + while(index_sub >= 0 + && index_min >= 0 + && tracks[i].stream->index_entries[index_sub].pos < st->index_entries[index_min].pos + && st->index_entries[index].timestamp - tracks[i].stream->index_entries[index_sub].timestamp < 30000000000/matroska->time_scale) + index_min--; } } avio_seek(s->pb, st->index_entries[index_min].pos, SEEK_SET); matroska->current_id = 0; - matroska->skip_to_keyframe = !(flags & AVSEEK_FLAG_ANY); - matroska->skip_to_timecode = st->index_entries[index].timestamp; + if (flags & AVSEEK_FLAG_ANY) { + st->skip_to_keyframe = 0; + matroska->skip_to_timecode = timestamp; + } else { + st->skip_to_keyframe = 1; + matroska->skip_to_timecode = st->index_entries[index].timestamp; + } + matroska->skip_to_keyframe = 1; matroska->done = 0; + matroska->num_levels = 0; ff_update_cur_dts(s, st, st->index_entries[index].timestamp); return 0; +err: + // slightly hackish but allows proper fallback to + // the generic seeking code. + matroska_clear_queue(matroska); + matroska->current_id = 0; + st->skip_to_keyframe = + matroska->skip_to_keyframe = 0; + matroska->done = 0; + matroska->num_levels = 0; + return -1; } static int matroska_read_close(AVFormatContext *s) |