X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fmatroska.c;h=eaf4ceb953fdb17570b181a0889e39448589a442;hb=b484ec78e8c3db1d7475ec53abce752c8ea0fb1e;hp=252c47ba5ed1918dd88951d313befba4569b6ad2;hpb=78a11456a1d45cf416750322de7b2325ded4188e;p=ffmpeg diff --git a/libavformat/matroska.c b/libavformat/matroska.c index 252c47ba5ed..eaf4ceb953f 100644 --- a/libavformat/matroska.c +++ b/libavformat/matroska.c @@ -2,18 +2,20 @@ * Matroska file demuxer (no muxer yet) * Copyright (c) 2003-2004 The ffmpeg Project * - * This library is free software; you can redistribute it and/or + * This file is part of FFmpeg. + * + * 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 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * - * This library 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 this library; 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 */ @@ -27,8 +29,8 @@ */ #include "avformat.h" -/* For codec_get_bmp_id and codec_get_wav_id. */ -#include "avi.h" +/* For codec_get_id(). */ +#include "riff.h" #include "intfloat_readwrite.h" /* EBML version supported */ @@ -67,6 +69,7 @@ /* IDs in the info master */ #define MATROSKA_ID_TIMECODESCALE 0x2AD7B1 #define MATROSKA_ID_DURATION 0x4489 +#define MATROSKA_ID_TITLE 0x7BA9 #define MATROSKA_ID_WRITINGAPP 0x5741 #define MATROSKA_ID_MUXINGAPP 0x4D80 #define MATROSKA_ID_DATEUTC 0x4461 @@ -107,6 +110,8 @@ /* IDs in the trackaudio master */ #define MATROSKA_ID_AUDIOSAMPLINGFREQ 0xB5 +#define MATROSKA_ID_AUDIOOUTSAMPLINGFREQ 0x78B5 + #define MATROSKA_ID_AUDIOBITDEPTH 0x6264 #define MATROSKA_ID_AUDIOCHANNELS 0x9F @@ -134,6 +139,7 @@ /* IDs in the cluster master */ #define MATROSKA_ID_CLUSTERTIMECODE 0xE7 #define MATROSKA_ID_BLOCKGROUP 0xA0 +#define MATROSKA_ID_SIMPLEBLOCK 0xA3 /* IDs in the blockgroup master */ #define MATROSKA_ID_BLOCK 0xA1 @@ -171,6 +177,7 @@ typedef enum { MATROSKA_TRACK_ENABLED = (1<<0), MATROSKA_TRACK_DEFAULT = (1<<1), MATROSKA_TRACK_LACING = (1<<2), + MATROSKA_TRACK_REAL_V = (1<<4), MATROSKA_TRACK_SHIFT = (1<<16) } MatroskaTrackFlags; @@ -183,14 +190,14 @@ typedef enum { */ typedef struct CodecTags{ - char *str; + const char *str; enum CodecID id; }CodecTags; #define MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC "V_MS/VFW/FOURCC" #define MATROSKA_CODEC_ID_AUDIO_ACM "A_MS/ACM" -CodecTags codec_tags[]={ +static CodecTags codec_tags[]={ // {"V_MS/VFW/FOURCC" , CODEC_ID_NONE}, {"V_UNCOMPRESSED" , CODEC_ID_RAWVIDEO}, {"V_MPEG4/ISO/SP" , CODEC_ID_MPEG4}, @@ -205,6 +212,7 @@ CodecTags codec_tags[]={ {"V_REAL/RV20" , CODEC_ID_RV20}, {"V_REAL/RV30" , CODEC_ID_RV30}, {"V_REAL/RV40" , CODEC_ID_RV40}, + {"V_THEORA" , CODEC_ID_THEORA}, /* TODO: Real/Quicktime */ // {"A_MS/ACM" , CODEC_ID_NONE}, @@ -217,8 +225,10 @@ CodecTags codec_tags[]={ {"A_AC3" , CODEC_ID_AC3}, {"A_DTS" , CODEC_ID_DTS}, {"A_VORBIS" , CODEC_ID_VORBIS}, - {"A_AAC/MPEG2/" , CODEC_ID_AAC}, - {"A_AAC/MPEG4/" , CODEC_ID_AAC}, + {"A_AAC" , CODEC_ID_AAC}, + {"A_FLAC" , CODEC_ID_FLAC}, + {"A_WAVPACK4" , CODEC_ID_WAVPACK}, + {"A_TTA1" , CODEC_ID_TTA}, {NULL , CODEC_ID_NONE} /* TODO: AC3-9/10 (?), Real, Musepack, Quicktime */ }; @@ -244,7 +254,7 @@ typedef struct Track { unsigned char *codec_priv; int codec_priv_size; - int64_t default_duration; + uint64_t default_duration; MatroskaTrackFlags flags; } MatroskaTrack; @@ -269,6 +279,7 @@ typedef struct MatroskaAudioTrack { int channels, bitdepth, + internal_samplerate, samplerate; //.. } MatroskaAudioTrack; @@ -279,6 +290,10 @@ typedef struct MatroskaSubtitleTrack { //.. } MatroskaSubtitleTrack; +#define MAX_TRACK_SIZE (FFMAX(FFMAX(sizeof(MatroskaVideoTrack), \ + sizeof(MatroskaAudioTrack)), \ + sizeof(MatroskaSubtitleTrack))) + typedef struct MatroskaLevel { uint64_t start, length; } MatroskaLevel; @@ -305,9 +320,6 @@ typedef struct MatroskaDemuxContext { /* timescale in the file */ int64_t time_scale; - /* position (time, ns) */ - int64_t pos; - /* num_streams is the number of streams that av_new_stream() was called * for ( = that are available to the calling program). */ int num_tracks, num_streams; @@ -331,6 +343,10 @@ typedef struct MatroskaDemuxContext { /* The index for seeking. */ int num_indexes; MatroskaDemuxIndex *index; + + /* What to skip before effectively reading a packet. */ + int skip_to_keyframe; + AVStream *skip_to_stream; } MatroskaDemuxContext; /* @@ -593,7 +609,6 @@ ebml_read_sint (MatroskaDemuxContext *matroska, negative = 1; *num &= ~0x80; } - *num = 0; while (n++ < size) *num = (*num << 8) | get_byte(pb); @@ -627,10 +642,6 @@ ebml_read_float (MatroskaDemuxContext *matroska, *num= av_int2flt(get_be32(pb)); } else if(size==8){ *num= av_int2dbl(get_be64(pb)); - } else if(size==10){ - av_log(matroska->ctx, AV_LOG_ERROR, - "FIXME! 10-byte floats unimplemented\n"); - return AVERROR_UNKNOWN; } else{ offset_t pos = url_ftell(pb); av_log(matroska->ctx, AV_LOG_ERROR, @@ -967,6 +978,21 @@ ebml_read_header (MatroskaDemuxContext *matroska, return 0; } + +static int +matroska_find_track_by_num (MatroskaDemuxContext *matroska, + int num) +{ + int i; + + for (i = 0; i < matroska->num_tracks; i++) + if (matroska->tracks[i]->num == num) + return i; + + return -1; +} + + /* * Put one packet in an application-supplied AVPacket struct. * Returns 0 on success or -1 on failure. @@ -986,8 +1012,7 @@ matroska_deliver_packet (MatroskaDemuxContext *matroska, av_realloc(matroska->packets, (matroska->num_packets - 1) * sizeof(AVPacket *)); } else { - av_free(matroska->packets); - matroska->packets = NULL; + av_freep(&matroska->packets); } matroska->num_packets--; return 0; @@ -1012,6 +1037,7 @@ matroska_queue_packet (MatroskaDemuxContext *matroska, matroska->num_packets++; } + /* * Autodetecting... */ @@ -1023,9 +1049,6 @@ matroska_probe (AVProbeData *p) int len_mask = 0x80, size = 1, n = 1; uint8_t probe_data[] = { 'm', 'a', 't', 'r', 'o', 's', 'k', 'a' }; - if (p->buf_size < 5) - return 0; - /* ebml header? */ if ((p->buf[0] << 24 | p->buf[1] << 16 | p->buf[2] << 8 | p->buf[3]) != EBML_ID_HEADER) @@ -1051,7 +1074,7 @@ matroska_probe (AVProbeData *p) * we don't parse the whole header but simply check for the * availability of that array of characters inside the header. * Not fully fool-proof, but good enough. */ - for (n = 4 + size; n < 4 + size + total - sizeof(probe_data); n++) + for (n = 4 + size; n <= 4 + size + total - sizeof(probe_data); n++) if (!memcmp (&p->buf[n], probe_data, sizeof(probe_data))) return AVPROBE_SCORE_MAX; @@ -1097,6 +1120,16 @@ matroska_parse_info (MatroskaDemuxContext *matroska) break; } + case MATROSKA_ID_TITLE: { + char *text; + if ((res = ebml_read_utf8(matroska, &id, &text)) < 0) + break; + strncpy(matroska->ctx->title, text, + sizeof(matroska->ctx->title)-1); + av_free(text); + break; + } + case MATROSKA_ID_WRITINGAPP: { char *text; if ((res = ebml_read_utf8(matroska, &id, &text)) < 0) @@ -1150,7 +1183,7 @@ matroska_add_stream (MatroskaDemuxContext *matroska) av_log(matroska->ctx, AV_LOG_DEBUG, "parsing track, adding stream..,\n"); /* Allocate a generic track. As soon as we know its type we'll realloc. */ - track = av_mallocz(sizeof(MatroskaTrack)); + track = av_mallocz(MAX_TRACK_SIZE); matroska->num_tracks++; /* start with the master */ @@ -1189,30 +1222,19 @@ matroska_add_stream (MatroskaDemuxContext *matroska) /* track type (video, audio, combined, subtitle, etc.) */ case MATROSKA_ID_TRACKTYPE: { uint64_t num; - if (track->type != 0) { + if ((res = ebml_read_uint(matroska, &id, &num)) < 0) + break; + if (track->type && track->type != num) { av_log(matroska->ctx, AV_LOG_INFO, "More than one tracktype in an entry - skip\n"); break; } - if ((res = ebml_read_uint(matroska, &id, &num)) < 0) - break; track->type = num; - /* ok, so we're actually going to reallocate this thing */ switch (track->type) { case MATROSKA_TRACK_TYPE_VIDEO: - track = (MatroskaTrack *) - av_realloc(track, sizeof(MatroskaVideoTrack)); - break; case MATROSKA_TRACK_TYPE_AUDIO: - track = (MatroskaTrack *) - av_realloc(track, sizeof(MatroskaAudioTrack)); - ((MatroskaAudioTrack *)track)->channels = 1; - ((MatroskaAudioTrack *)track)->samplerate = 8000; - break; case MATROSKA_TRACK_TYPE_SUBTITLE: - track = (MatroskaTrack *) - av_realloc(track, sizeof(MatroskaSubtitleTrack)); break; case MATROSKA_TRACK_TYPE_COMPLEX: case MATROSKA_TRACK_TYPE_LOGO: @@ -1231,6 +1253,8 @@ matroska_add_stream (MatroskaDemuxContext *matroska) /* tracktype specific stuff for video */ case MATROSKA_ID_TRACKVIDEO: { MatroskaVideoTrack *videotrack; + if (!track->type) + track->type = MATROSKA_TRACK_TYPE_VIDEO; if (track->type != MATROSKA_TRACK_TYPE_VIDEO) { av_log(matroska->ctx, AV_LOG_INFO, "video data in non-video track - ignoring\n"); @@ -1256,7 +1280,7 @@ matroska_add_stream (MatroskaDemuxContext *matroska) if ((res = ebml_read_uint (matroska, &id, &num)) < 0) break; - track->default_duration = num; + track->default_duration = num/matroska->time_scale; break; } @@ -1266,7 +1290,7 @@ matroska_add_stream (MatroskaDemuxContext *matroska) if ((res = ebml_read_float(matroska, &id, &num)) < 0) break; - track->default_duration = 1000000000 * (1. / num); + track->default_duration = 1000000000/(matroska->time_scale*num); break; } @@ -1398,6 +1422,8 @@ matroska_add_stream (MatroskaDemuxContext *matroska) /* tracktype specific stuff for audio */ case MATROSKA_ID_TRACKAUDIO: { MatroskaAudioTrack *audiotrack; + if (!track->type) + track->type = MATROSKA_TRACK_TYPE_AUDIO; if (track->type != MATROSKA_TRACK_TYPE_AUDIO) { av_log(matroska->ctx, AV_LOG_INFO, "audio data in non-audio track - ignoring\n"); @@ -1406,6 +1432,8 @@ matroska_add_stream (MatroskaDemuxContext *matroska) } else if ((res = ebml_read_master(matroska, &id)) < 0) break; audiotrack = (MatroskaAudioTrack *)track; + audiotrack->channels = 1; + audiotrack->samplerate = 8000; while (res == 0) { if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { @@ -1419,6 +1447,16 @@ matroska_add_stream (MatroskaDemuxContext *matroska) switch (id) { /* samplerate */ case MATROSKA_ID_AUDIOSAMPLINGFREQ: { + double num; + if ((res = ebml_read_float(matroska, &id, + &num)) < 0) + break; + audiotrack->internal_samplerate = + audiotrack->samplerate = num; + break; + } + + case MATROSKA_ID_AUDIOOUTSAMPLINGFREQ: { double num; if ((res = ebml_read_float(matroska, &id, &num)) < 0) @@ -1555,7 +1593,7 @@ matroska_add_stream (MatroskaDemuxContext *matroska) uint64_t num; if ((res = ebml_read_uint(matroska, &id, &num)) < 0) break; - track->default_duration = num; + track->default_duration = num / matroska->time_scale; break; } @@ -1667,7 +1705,7 @@ matroska_parse_index (MatroskaDemuxContext *matroska) switch (id) { /* one single index entry ('point') */ case MATROSKA_ID_CUETIME: { - int64_t time; + uint64_t time; if ((res = ebml_read_uint(matroska, &id, &time)) < 0) break; @@ -1708,7 +1746,7 @@ matroska_parse_index (MatroskaDemuxContext *matroska) if ((res = ebml_read_uint(matroska, &id, &num)) < 0) break; - idx.pos = num; + idx.pos = num+matroska->segment_start; break; } @@ -1920,7 +1958,7 @@ matroska_parse_seekhead (MatroskaDemuxContext *matroska) /* check ID */ if (!(id = ebml_peek_id (matroska, &matroska->level_up))) - break; + goto finish; if (id != seek_id) { av_log(matroska->ctx, AV_LOG_INFO, "We looked for ID=0x%x but got " @@ -1932,7 +1970,7 @@ matroska_parse_seekhead (MatroskaDemuxContext *matroska) /* read master + parse */ if ((res = ebml_read_master(matroska, &id)) < 0) - break; + goto finish; switch (id) { case MATROSKA_ID_CUES: if (!(res = matroska_parse_index(matroska)) || @@ -1949,8 +1987,6 @@ matroska_parse_seekhead (MatroskaDemuxContext *matroska) } break; } - if (res < 0) - break; finish: /* remove dummy level */ @@ -1999,6 +2035,37 @@ matroska_parse_seekhead (MatroskaDemuxContext *matroska) return res; } +#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x)) + +static int +matroska_aac_profile (char *codec_id) +{ + static const char *aac_profiles[] = { + "MAIN", "LC", "SSR" + }; + int profile; + + for (profile=0; profile 2) { av_log(matroska->ctx, AV_LOG_ERROR, - "Matroska demuxer version 1 too old for file version %d\n", + "Matroska demuxer version 2 too old for file version %d\n", version); return AVERROR_NOFMT; } @@ -2133,19 +2200,17 @@ matroska_read_header (AVFormatContext *s, } } - if (res < 0) - return res; - /* Have we found a cluster? */ - if (res == 1) { + if (ebml_peek_id(matroska, NULL) == MATROSKA_ID_CLUSTER) { int i, j; - enum CodecID codec_id= CODEC_ID_NONE; MatroskaTrack *track; AVStream *st; for (i = 0; i < matroska->num_tracks; i++) { - void *extradata = NULL; + enum CodecID codec_id = CODEC_ID_NONE; + uint8_t *extradata = NULL; int extradata_size = 0; + int extradata_offset = 0; track = matroska->tracks[i]; /* libavformat does not really support subtitles. @@ -2155,7 +2220,8 @@ matroska_read_header (AVFormatContext *s, continue; for(j=0; codec_tags[j].str; j++){ - if(!strcmp(codec_tags[j].str, track->codec_id)){ + if(!strncmp(codec_tags[j].str, track->codec_id, + strlen(codec_tags[j].str))){ codec_id= codec_tags[j].id; break; } @@ -2174,7 +2240,7 @@ matroska_read_header (AVFormatContext *s, p = (unsigned char *)track->codec_priv + 16; ((MatroskaVideoTrack *)track)->fourcc = (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]; - codec_id = codec_get_bmp_id(((MatroskaVideoTrack *)track)->fourcc); + codec_id = codec_get_id(codec_bmp_tags, ((MatroskaVideoTrack *)track)->fourcc); } @@ -2190,8 +2256,53 @@ matroska_read_header (AVFormatContext *s, /* Offset of wFormatTag. Stored in LE. */ p = (unsigned char *)track->codec_priv; tag = (p[1] << 8) | p[0]; - codec_id = codec_get_wav_id(tag); + codec_id = codec_get_id(codec_wav_tags, tag); + + } + + else if (codec_id == CODEC_ID_AAC && !track->codec_priv_size) { + MatroskaAudioTrack *audiotrack = (MatroskaAudioTrack *) track; + int profile = matroska_aac_profile(track->codec_id); + int sri = matroska_aac_sri(audiotrack->internal_samplerate); + extradata = av_malloc(5); + if (extradata == NULL) + return AVERROR_NOMEM; + extradata[0] = (profile << 3) | ((sri&0x0E) >> 1); + extradata[1] = ((sri&0x01) << 7) | (audiotrack->channels<<3); + if (strstr(track->codec_id, "SBR")) { + sri = matroska_aac_sri(audiotrack->samplerate); + extradata[2] = 0x56; + extradata[3] = 0xE5; + extradata[4] = 0x80 | (sri<<3); + extradata_size = 5; + } else { + extradata_size = 2; + } + track->default_duration = 1024*1000 / audiotrack->internal_samplerate; + } + + else if (codec_id == CODEC_ID_TTA) { + MatroskaAudioTrack *audiotrack = (MatroskaAudioTrack *) track; + ByteIOContext b; + extradata_size = 30; + extradata = av_mallocz(extradata_size); + if (extradata == NULL) + return AVERROR_NOMEM; + init_put_byte(&b, extradata, extradata_size, 1, + NULL, NULL, NULL, NULL); + put_buffer(&b, (uint8_t *) "TTA1", 4); + put_le16(&b, 1); + put_le16(&b, audiotrack->channels); + put_le16(&b, audiotrack->bitdepth); + put_le32(&b, audiotrack->samplerate); + put_le32(&b, matroska->ctx->duration * audiotrack->samplerate); + } + else if (codec_id == CODEC_ID_RV10 || codec_id == CODEC_ID_RV20 || + codec_id == CODEC_ID_RV30 || codec_id == CODEC_ID_RV40) { + extradata_offset = 26; + track->codec_priv_size -= extradata_offset; + track->flags |= MATROSKA_TRACK_REAL_V; } if (codec_id == CODEC_ID_NONE) { @@ -2209,6 +2320,11 @@ matroska_read_header (AVFormatContext *s, av_set_pts_info(st, 64, matroska->time_scale, 1000*1000*1000); /* 64 bit pts in ns */ st->codec->codec_id = codec_id; + st->start_time = 0; + + if (track->default_duration) + av_reduce(&st->codec->time_base.num, &st->codec->time_base.den, + track->default_duration, 1000, 30000); if(extradata){ st->codec->extradata = extradata; @@ -2218,7 +2334,7 @@ matroska_read_header (AVFormatContext *s, if(st->codec->extradata == NULL) return AVERROR_NOMEM; st->codec->extradata_size = track->codec_priv_size; - memcpy(st->codec->extradata, track->codec_priv, + memcpy(st->codec->extradata,track->codec_priv+extradata_offset, track->codec_priv_size); } @@ -2238,6 +2354,7 @@ matroska_read_header (AVFormatContext *s, st->codec->height * videotrack->display_width, st->codec-> width * videotrack->display_height, 255); + st->need_parsing = AVSTREAM_PARSE_HEADERS; } else if (track->type == MATROSKA_TRACK_TYPE_AUDIO) { MatroskaAudioTrack *audiotrack = (MatroskaAudioTrack *)track; @@ -2250,22 +2367,217 @@ matroska_read_header (AVFormatContext *s, /* What do we do with private data? E.g. for Vorbis. */ } + res = 0; } - return 0; + if (matroska->index_parsed) { + int i, track, stream; + for (i=0; inum_indexes; i++) { + MatroskaDemuxIndex *idx = &matroska->index[i]; + track = matroska_find_track_by_num(matroska, idx->track); + stream = matroska->tracks[track]->stream_index; + av_add_index_entry(matroska->ctx->streams[stream], + idx->pos, idx->time/matroska->time_scale, + 0, 0, AVINDEX_KEYFRAME); + } + } + + return res; +} + +static inline int +rv_offset(uint8_t *data, int slice, int slices) +{ + return AV_RL32(data+8*slice+4) + 8*slices; } static int -matroska_find_track_by_num (MatroskaDemuxContext *matroska, - int num) +matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int size, + int64_t pos, uint64_t cluster_time, uint64_t duration, + int is_keyframe, int is_bframe) { - int i; + int res = 0; + int track; + AVStream *st; + AVPacket *pkt; + uint8_t *origdata = data; + int16_t block_time; + uint32_t *lace_size = NULL; + int n, flags, laces = 0; + uint64_t num; + + /* first byte(s): tracknum */ + if ((n = matroska_ebmlnum_uint(data, size, &num)) < 0) { + av_log(matroska->ctx, AV_LOG_ERROR, "EBML block data error\n"); + av_free(origdata); + return res; + } + data += n; + size -= n; - for (i = 0; i < matroska->num_tracks; i++) - if (matroska->tracks[i]->num == num) - return i; + /* fetch track from num */ + track = matroska_find_track_by_num(matroska, num); + if (size <= 3 || track < 0 || track >= matroska->num_tracks) { + av_log(matroska->ctx, AV_LOG_INFO, + "Invalid stream %d or size %u\n", track, size); + av_free(origdata); + return res; + } + st = matroska->ctx->streams[matroska->tracks[track]->stream_index]; + if (st->discard >= AVDISCARD_ALL) { + av_free(origdata); + return res; + } + if (duration == AV_NOPTS_VALUE) + duration = matroska->tracks[track]->default_duration; + + /* block_time (relative to cluster time) */ + block_time = (data[0] << 8) | data[1]; + data += 2; + size -= 2; + flags = *data; + data += 1; + size -= 1; + if (is_keyframe == -1) + is_keyframe = flags & 1 ? PKT_FLAG_KEY : 0; + + if (matroska->skip_to_keyframe) { + if (!is_keyframe || st != matroska->skip_to_stream) + return res; + matroska->skip_to_keyframe = 0; + } - return -1; + switch ((flags & 0x06) >> 1) { + case 0x0: /* no lacing */ + laces = 1; + lace_size = av_mallocz(sizeof(int)); + lace_size[0] = size; + break; + + case 0x1: /* xiph lacing */ + case 0x2: /* fixed-size lacing */ + case 0x3: /* EBML lacing */ + if (size == 0) { + res = -1; + break; + } + laces = (*data) + 1; + data += 1; + size -= 1; + lace_size = av_mallocz(laces * sizeof(int)); + + switch ((flags & 0x06) >> 1) { + case 0x1: /* xiph lacing */ { + uint8_t temp; + uint32_t total = 0; + for (n = 0; res == 0 && n < laces - 1; n++) { + while (1) { + if (size == 0) { + res = -1; + break; + } + temp = *data; + lace_size[n] += temp; + data += 1; + size -= 1; + if (temp != 0xff) + break; + } + total += lace_size[n]; + } + lace_size[n] = size - total; + break; + } + + case 0x2: /* fixed-size lacing */ + for (n = 0; n < laces; n++) + lace_size[n] = size / laces; + break; + + case 0x3: /* EBML lacing */ { + uint32_t total; + n = matroska_ebmlnum_uint(data, size, &num); + if (n < 0) { + av_log(matroska->ctx, AV_LOG_INFO, + "EBML block data error\n"); + break; + } + data += n; + size -= n; + total = lace_size[0] = num; + for (n = 1; res == 0 && n < laces - 1; n++) { + int64_t snum; + int r; + r = matroska_ebmlnum_sint (data, size, &snum); + if (r < 0) { + av_log(matroska->ctx, AV_LOG_INFO, + "EBML block data error\n"); + break; + } + data += r; + size -= r; + lace_size[n] = lace_size[n - 1] + snum; + total += lace_size[n]; + } + lace_size[n] = size - total; + break; + } + } + break; + } + + if (res == 0) { + int real_v = matroska->tracks[track]->flags & MATROSKA_TRACK_REAL_V; + uint64_t timecode = AV_NOPTS_VALUE; + + if (cluster_time != (uint64_t)-1 && cluster_time + block_time >= 0) + timecode = cluster_time + block_time; + + for (n = 0; n < laces; n++) { + int slice, slices = 1; + + if (real_v) { + slices = *data++ + 1; + lace_size[n]--; + } + + for (slice=0; slicedata, data+slice_offset, slice_size); + + if (n == 0) + pkt->flags = is_keyframe; + pkt->stream_index = matroska->tracks[track]->stream_index; + + pkt->pts = timecode; + pkt->pos = pos; + pkt->duration = duration; + + matroska_queue_packet(matroska, pkt); + + if (timecode != AV_NOPTS_VALUE) + timecode = duration ? timecode + duration : AV_NOPTS_VALUE; + } + data += lace_size[n]; + } + } + + av_free(lace_size); + av_free(origdata); + return res; } static int @@ -2274,8 +2586,12 @@ matroska_parse_blockgroup (MatroskaDemuxContext *matroska, { int res = 0; uint32_t id; - AVPacket *pkt; + int is_bframe = 0; int is_keyframe = PKT_FLAG_KEY, last_num_packets = matroska->num_packets; + uint64_t duration = AV_NOPTS_VALUE; + uint8_t *data; + int size = 0; + int64_t pos = 0; av_log(matroska->ctx, AV_LOG_DEBUG, "parsing blockgroup...\n"); @@ -2293,182 +2609,31 @@ matroska_parse_blockgroup (MatroskaDemuxContext *matroska, * of the harder things, so this code is a bit complicated. * See http://www.matroska.org/ for documentation. */ case MATROSKA_ID_BLOCK: { - uint8_t *data, *origdata; - int size; - int16_t block_time; - uint32_t *lace_size = NULL; - int n, track, flags, laces = 0; - uint64_t num; - int64_t pos= url_ftell(&matroska->ctx->pb); - - if ((res = ebml_read_binary(matroska, &id, &data, &size)) < 0) - break; - origdata = data; - - /* first byte(s): blocknum */ - if ((n = matroska_ebmlnum_uint(data, size, &num)) < 0) { - av_log(matroska->ctx, AV_LOG_ERROR, - "EBML block data error\n"); - av_free(origdata); - break; - } - data += n; - size -= n; - - /* fetch track from num */ - track = matroska_find_track_by_num(matroska, num); - if (size <= 3 || track < 0 || track >= matroska->num_tracks) { - av_log(matroska->ctx, AV_LOG_INFO, - "Invalid stream %d or size %u\n", track, size); - av_free(origdata); - break; - } - if(matroska->ctx->streams[ matroska->tracks[track]->stream_index ]->discard >= AVDISCARD_ALL){ - av_free(origdata); - break; - } - - /* block_time (relative to cluster time) */ - block_time = (data[0] << 8) | data[1]; - data += 2; - size -= 2; - flags = *data; - data += 1; - size -= 1; - switch ((flags & 0x06) >> 1) { - case 0x0: /* no lacing */ - laces = 1; - lace_size = av_mallocz(sizeof(int)); - lace_size[0] = size; - break; - - case 0x1: /* xiph lacing */ - case 0x2: /* fixed-size lacing */ - case 0x3: /* EBML lacing */ - if (size == 0) { - res = -1; - break; - } - laces = (*data) + 1; - data += 1; - size -= 1; - lace_size = av_mallocz(laces * sizeof(int)); - - switch ((flags & 0x06) >> 1) { - case 0x1: /* xiph lacing */ { - uint8_t temp; - uint32_t total = 0; - for (n = 0; res == 0 && n < laces - 1; n++) { - while (1) { - if (size == 0) { - res = -1; - break; - } - temp = *data; - lace_size[n] += temp; - data += 1; - size -= 1; - if (temp != 0xff) - break; - } - total += lace_size[n]; - } - lace_size[n] = size - total; - break; - } - - case 0x2: /* fixed-size lacing */ - for (n = 0; n < laces; n++) - lace_size[n] = size / laces; - break; - - case 0x3: /* EBML lacing */ { - uint32_t total; - n = matroska_ebmlnum_uint(data, size, &num); - if (n < 0) { - av_log(matroska->ctx, AV_LOG_INFO, - "EBML block data error\n"); - break; - } - data += n; - size -= n; - total = lace_size[0] = num; - for (n = 1; res == 0 && n < laces - 1; n++) { - int64_t snum; - int r; - r = matroska_ebmlnum_sint (data, size, - &snum); - if (r < 0) { - av_log(matroska->ctx, AV_LOG_INFO, - "EBML block data error\n"); - break; - } - data += r; - size -= r; - lace_size[n] = lace_size[n - 1] + snum; - total += lace_size[n]; - } - lace_size[n] = size - total; - break; - } - } - break; - } - - if (res == 0) { - for (n = 0; n < laces; n++) { - uint64_t timecode = 0; - - pkt = av_mallocz(sizeof(AVPacket)); - /* XXX: prevent data copy... */ - if (av_new_packet(pkt,lace_size[n]) < 0) { - res = AVERROR_NOMEM; - break; - } - if (cluster_time != (uint64_t)-1) { - if (block_time < 0 && (-block_time) > cluster_time) - timecode = cluster_time; - else - timecode = cluster_time + block_time; - } - /* FIXME: duration */ - - memcpy(pkt->data, data, lace_size[n]); - data += lace_size[n]; - if (n == 0) - pkt->flags = is_keyframe; - pkt->stream_index = - matroska->tracks[track]->stream_index; - - pkt->pts = timecode; - pkt->pos= pos; - - matroska_queue_packet(matroska, pkt); - } - } - - av_free(lace_size); - av_free(origdata); + pos = url_ftell(&matroska->ctx->pb); + res = ebml_read_binary(matroska, &id, &data, &size); break; } case MATROSKA_ID_BLOCKDURATION: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, &num)) < 0) + if ((res = ebml_read_uint(matroska, &id, &duration)) < 0) break; - av_log(matroska->ctx, AV_LOG_INFO, - "FIXME: implement support for BlockDuration\n"); + duration /= matroska->time_scale; break; } - case MATROSKA_ID_BLOCKREFERENCE: + case MATROSKA_ID_BLOCKREFERENCE: { + int64_t num; /* We've found a reference, so not even the first frame in * the lace is a key frame. */ is_keyframe = 0; if (last_num_packets != matroska->num_packets) matroska->packets[last_num_packets]->flags = 0; - res = ebml_read_skip(matroska); + if ((res = ebml_read_sint(matroska, &id, &num)) < 0) + break; + if (num > 0) + is_bframe = 1; break; + } default: av_log(matroska->ctx, AV_LOG_INFO, @@ -2486,6 +2651,13 @@ matroska_parse_blockgroup (MatroskaDemuxContext *matroska, } } + if (res) + return res; + + if (size > 0) + res = matroska_parse_block(matroska, data, size, pos, cluster_time, + duration, is_keyframe, is_bframe); + return res; } @@ -2495,6 +2667,9 @@ matroska_parse_cluster (MatroskaDemuxContext *matroska) int res = 0; uint32_t id; uint64_t cluster_time = 0; + uint8_t *data; + int64_t pos; + int size; av_log(matroska->ctx, AV_LOG_DEBUG, "parsing cluster at %"PRId64"\n", url_ftell(&matroska->ctx->pb)); @@ -2525,6 +2700,15 @@ matroska_parse_cluster (MatroskaDemuxContext *matroska) res = matroska_parse_blockgroup(matroska, cluster_time); break; + case MATROSKA_ID_SIMPLEBLOCK: + pos = url_ftell(&matroska->ctx->pb); + res = ebml_read_binary(matroska, &id, &data, &size); + if (res == 0) + res = matroska_parse_block(matroska, data, size, pos, + cluster_time, AV_NOPTS_VALUE, + -1, 0); + break; + default: av_log(matroska->ctx, AV_LOG_INFO, "Unknown entry 0x%x in cluster data\n", id); @@ -2552,47 +2736,68 @@ matroska_read_packet (AVFormatContext *s, int res = 0; uint32_t id; - /* Do we still have a packet queued? */ - if (matroska_deliver_packet(matroska, pkt) == 0) - return 0; + /* Read stream until we have a packet queued. */ + while (matroska_deliver_packet(matroska, pkt)) { - /* Have we already reached the end? */ - if (matroska->done) - return AVERROR_IO; + /* Have we already reached the end? */ + if (matroska->done) + return AVERROR_IO; - while (res == 0) { - if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { - res = AVERROR_IO; - break; - } else if (matroska->level_up) { - matroska->level_up--; - break; - } + while (res == 0) { + if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { + return AVERROR_IO; + } else if (matroska->level_up) { + matroska->level_up--; + break; + } - switch (id) { - case MATROSKA_ID_CLUSTER: - if ((res = ebml_read_master(matroska, &id)) < 0) + switch (id) { + case MATROSKA_ID_CLUSTER: + if ((res = ebml_read_master(matroska, &id)) < 0) + break; + if ((res = matroska_parse_cluster(matroska)) == 0) + res = 1; /* Parsed one cluster, let's get out. */ break; - if ((res = matroska_parse_cluster(matroska)) == 0) - res = 1; /* Parsed one cluster, let's get out. */ - break; - default: - case EBML_ID_VOID: - res = ebml_read_skip(matroska); + default: + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; break; + } } - if (matroska->level_up) { - matroska->level_up--; - break; - } + if (res == -1) + matroska->done = 1; } - if (res == -1) - matroska->done = 1; + return 0; +} + +static int +matroska_read_seek (AVFormatContext *s, int stream_index, int64_t timestamp, + int flags) +{ + MatroskaDemuxContext *matroska = s->priv_data; + AVStream *st = s->streams[stream_index]; + int index; + + /* find index entry */ + index = av_index_search_timestamp(st, timestamp, flags); + if (index < 0) + return 0; - return matroska_deliver_packet(matroska, pkt); + /* do the seek */ + url_fseek(&s->pb, st->index_entries[index].pos, SEEK_SET); + matroska->skip_to_keyframe = !(flags & AVSEEK_FLAG_ANY); + matroska->skip_to_stream = st; + matroska->num_packets = 0; + matroska->peek_id = 0; + return 0; } static int @@ -2601,12 +2806,9 @@ matroska_read_close (AVFormatContext *s) MatroskaDemuxContext *matroska = s->priv_data; int n = 0; - if (matroska->writing_app) - av_free(matroska->writing_app); - if (matroska->muxing_app) - av_free(matroska->muxing_app); - if (matroska->index) - av_free(matroska->index); + av_free(matroska->writing_app); + av_free(matroska->muxing_app); + av_free(matroska->index); if (matroska->packets != NULL) { for (n = 0; n < matroska->num_packets; n++) { @@ -2618,30 +2820,19 @@ matroska_read_close (AVFormatContext *s) for (n = 0; n < matroska->num_tracks; n++) { MatroskaTrack *track = matroska->tracks[n]; - if (track->codec_id) - av_free(track->codec_id); - if (track->codec_name) - av_free(track->codec_name); - if (track->codec_priv) - av_free(track->codec_priv); - if (track->name) - av_free(track->name); - if (track->language) - av_free(track->language); + av_free(track->codec_id); + av_free(track->codec_name); + av_free(track->codec_priv); + av_free(track->name); + av_free(track->language); av_free(track); } - for (n = 0; n < s->nb_streams; n++) { - av_free(s->streams[n]->codec->extradata); - } - - memset(matroska, 0, sizeof(MatroskaDemuxContext)); - return 0; } -static AVInputFormat matroska_iformat = { +AVInputFormat matroska_demuxer = { "matroska", "Matroska file format", sizeof(MatroskaDemuxContext), @@ -2649,11 +2840,5 @@ static AVInputFormat matroska_iformat = { matroska_read_header, matroska_read_packet, matroska_read_close, + matroska_read_seek, }; - -int -matroska_init(void) -{ - av_register_input_format(&matroska_iformat); - return 0; -}