Mercurial > libavformat.hg
changeset 2142:3aa1f0f698de libavformat
split some common code from the mkv demuxer that will be useful to the muxer
patch by David Conrad umovimus _at_ gmail.com
author | aurel |
---|---|
date | Mon, 04 Jun 2007 22:10:54 +0000 |
parents | 7062131d854f |
children | a3d59411106f |
files | Makefile matroska.c matroska.h matroskadec.c |
diffstat | 4 files changed, 2842 insertions(+), 2790 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile Mon Jun 04 21:05:58 2007 +0000 +++ b/Makefile Mon Jun 04 22:10:54 2007 +0000 @@ -71,7 +71,7 @@ OBJS-$(CONFIG_IPMOVIE_DEMUXER) += ipmovie.o OBJS-$(CONFIG_M4V_DEMUXER) += raw.o OBJS-$(CONFIG_M4V_MUXER) += raw.o -OBJS-$(CONFIG_MATROSKA_DEMUXER) += matroska.o riff.o +OBJS-$(CONFIG_MATROSKA_DEMUXER) += matroskadec.o matroska.o riff.o OBJS-$(CONFIG_MJPEG_DEMUXER) += raw.o OBJS-$(CONFIG_MJPEG_MUXER) += raw.o OBJS-$(CONFIG_MM_DEMUXER) += mm.o
--- a/matroska.c Mon Jun 04 21:05:58 2007 +0000 +++ b/matroska.c Mon Jun 04 22:10:54 2007 +0000 @@ -1,5 +1,5 @@ /* - * Matroska file demuxer (no muxer yet) + * Matroska common data * Copyright (c) 2003-2004 The ffmpeg Project * * This file is part of FFmpeg. @@ -19,185 +19,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/** - * @file matroska.c - * Matroska file demuxer - * by Ronald Bultje <rbultje@ronald.bitfreak.net> - * with a little help from Moritz Bunkus <moritz@bunkus.org> - * Specs available on the matroska project page: - * http://www.matroska.org/. - */ - -#include "avformat.h" -/* For codec_get_id(). */ -#include "riff.h" -#include "intfloat_readwrite.h" - -/* EBML version supported */ -#define EBML_VERSION 1 - -/* top-level master-IDs */ -#define EBML_ID_HEADER 0x1A45DFA3 - -/* IDs in the HEADER master */ -#define EBML_ID_EBMLVERSION 0x4286 -#define EBML_ID_EBMLREADVERSION 0x42F7 -#define EBML_ID_EBMLMAXIDLENGTH 0x42F2 -#define EBML_ID_EBMLMAXSIZELENGTH 0x42F3 -#define EBML_ID_DOCTYPE 0x4282 -#define EBML_ID_DOCTYPEVERSION 0x4287 -#define EBML_ID_DOCTYPEREADVERSION 0x4285 - -/* general EBML types */ -#define EBML_ID_VOID 0xEC - -/* - * Matroska element IDs. max. 32-bit. - */ - -/* toplevel segment */ -#define MATROSKA_ID_SEGMENT 0x18538067 - -/* matroska top-level master IDs */ -#define MATROSKA_ID_INFO 0x1549A966 -#define MATROSKA_ID_TRACKS 0x1654AE6B -#define MATROSKA_ID_CUES 0x1C53BB6B -#define MATROSKA_ID_TAGS 0x1254C367 -#define MATROSKA_ID_SEEKHEAD 0x114D9B74 -#define MATROSKA_ID_CLUSTER 0x1F43B675 - -/* 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 - -/* ID in the tracks master */ -#define MATROSKA_ID_TRACKENTRY 0xAE - -/* IDs in the trackentry master */ -#define MATROSKA_ID_TRACKNUMBER 0xD7 -#define MATROSKA_ID_TRACKUID 0x73C5 -#define MATROSKA_ID_TRACKTYPE 0x83 -#define MATROSKA_ID_TRACKAUDIO 0xE1 -#define MATROSKA_ID_TRACKVIDEO 0xE0 -#define MATROSKA_ID_CODECID 0x86 -#define MATROSKA_ID_CODECPRIVATE 0x63A2 -#define MATROSKA_ID_CODECNAME 0x258688 -#define MATROSKA_ID_CODECINFOURL 0x3B4040 -#define MATROSKA_ID_CODECDOWNLOADURL 0x26B240 -#define MATROSKA_ID_TRACKNAME 0x536E -#define MATROSKA_ID_TRACKLANGUAGE 0x22B59C -#define MATROSKA_ID_TRACKFLAGENABLED 0xB9 -#define MATROSKA_ID_TRACKFLAGDEFAULT 0x88 -#define MATROSKA_ID_TRACKFLAGLACING 0x9C -#define MATROSKA_ID_TRACKMINCACHE 0x6DE7 -#define MATROSKA_ID_TRACKMAXCACHE 0x6DF8 -#define MATROSKA_ID_TRACKDEFAULTDURATION 0x23E383 - -/* IDs in the trackvideo master */ -#define MATROSKA_ID_VIDEOFRAMERATE 0x2383E3 -#define MATROSKA_ID_VIDEODISPLAYWIDTH 0x54B0 -#define MATROSKA_ID_VIDEODISPLAYHEIGHT 0x54BA -#define MATROSKA_ID_VIDEOPIXELWIDTH 0xB0 -#define MATROSKA_ID_VIDEOPIXELHEIGHT 0xBA -#define MATROSKA_ID_VIDEOFLAGINTERLACED 0x9A -#define MATROSKA_ID_VIDEOSTEREOMODE 0x53B9 -#define MATROSKA_ID_VIDEOASPECTRATIO 0x54B3 -#define MATROSKA_ID_VIDEOCOLOURSPACE 0x2EB524 +#include "matroska.h" -/* 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 - -/* ID in the cues master */ -#define MATROSKA_ID_POINTENTRY 0xBB - -/* IDs in the pointentry master */ -#define MATROSKA_ID_CUETIME 0xB3 -#define MATROSKA_ID_CUETRACKPOSITION 0xB7 - -/* IDs in the cuetrackposition master */ -#define MATROSKA_ID_CUETRACK 0xF7 -#define MATROSKA_ID_CUECLUSTERPOSITION 0xF1 - -/* IDs in the tags master */ -/* TODO */ - -/* IDs in the seekhead master */ -#define MATROSKA_ID_SEEKENTRY 0x4DBB - -/* IDs in the seekpoint master */ -#define MATROSKA_ID_SEEKID 0x53AB -#define MATROSKA_ID_SEEKPOSITION 0x53AC - -/* 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 -#define MATROSKA_ID_BLOCKDURATION 0x9B -#define MATROSKA_ID_BLOCKREFERENCE 0xFB - -typedef enum { - MATROSKA_TRACK_TYPE_VIDEO = 0x1, - MATROSKA_TRACK_TYPE_AUDIO = 0x2, - MATROSKA_TRACK_TYPE_COMPLEX = 0x3, - MATROSKA_TRACK_TYPE_LOGO = 0x10, - MATROSKA_TRACK_TYPE_SUBTITLE = 0x11, - MATROSKA_TRACK_TYPE_CONTROL = 0x20, -} MatroskaTrackType; - -typedef enum { - MATROSKA_EYE_MODE_MONO = 0x0, - MATROSKA_EYE_MODE_RIGHT = 0x1, - MATROSKA_EYE_MODE_LEFT = 0x2, - MATROSKA_EYE_MODE_BOTH = 0x3, -} MatroskaEyeMode; - -typedef enum { - MATROSKA_ASPECT_RATIO_MODE_FREE = 0x0, - MATROSKA_ASPECT_RATIO_MODE_KEEP = 0x1, - MATROSKA_ASPECT_RATIO_MODE_FIXED = 0x2, -} MatroskaAspectRatioMode; - -/* - * These aren't in any way "matroska-form" things, - * it's just something I use in the muxer/demuxer. - */ - -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; - -typedef enum { - MATROSKA_VIDEOTRACK_INTERLACED = (MATROSKA_TRACK_SHIFT<<0) -} MatroskaVideoTrackFlags; - -/* - * Matroska Codec IDs. Strings. - */ - -typedef struct CodecTags{ - 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" - -static CodecTags codec_tags[]={ +CodecTags ff_mkv_codec_tags[]={ // {"V_MS/VFW/FOURCC" , CODEC_ID_NONE}, {"V_UNCOMPRESSED" , CODEC_ID_RAWVIDEO}, {"V_MPEG4/ISO/SP" , CODEC_ID_MPEG4}, @@ -232,2613 +56,3 @@ {NULL , CODEC_ID_NONE} /* TODO: AC3-9/10 (?), Real, Musepack, Quicktime */ }; - -/* max. depth in the EBML tree structure */ -#define EBML_MAX_DEPTH 16 - -typedef struct Track { - MatroskaTrackType type; - - /* Unique track number and track ID. stream_index is the index that - * the calling app uses for this track. */ - uint32_t num, - uid, - stream_index; - - char *name, - *language; - - char *codec_id, - *codec_name; - - unsigned char *codec_priv; - int codec_priv_size; - - uint64_t default_duration; - MatroskaTrackFlags flags; -} MatroskaTrack; - -typedef struct MatroskaVideoTrack { - MatroskaTrack track; - - int pixel_width, - pixel_height, - display_width, - display_height; - - uint32_t fourcc; - - MatroskaAspectRatioMode ar_mode; - MatroskaEyeMode eye_mode; - - //.. -} MatroskaVideoTrack; - -typedef struct MatroskaAudioTrack { - MatroskaTrack track; - - int channels, - bitdepth, - internal_samplerate, - samplerate; - //.. -} MatroskaAudioTrack; - -typedef struct MatroskaSubtitleTrack { - MatroskaTrack track; - - //.. -} MatroskaSubtitleTrack; - -#define MAX_TRACK_SIZE (FFMAX(FFMAX(sizeof(MatroskaVideoTrack), \ - sizeof(MatroskaAudioTrack)), \ - sizeof(MatroskaSubtitleTrack))) - -typedef struct MatroskaLevel { - uint64_t start, length; -} MatroskaLevel; - -typedef struct MatroskaDemuxIndex { - uint64_t pos; /* of the corresponding *cluster*! */ - uint16_t track; /* reference to 'num' */ - uint64_t time; /* in nanoseconds */ -} MatroskaDemuxIndex; - -typedef struct MatroskaDemuxContext { - AVFormatContext *ctx; - - /* ebml stuff */ - int num_levels; - MatroskaLevel levels[EBML_MAX_DEPTH]; - int level_up; - - /* matroska stuff */ - char *writing_app, - *muxing_app; - int64_t created; - - /* timescale in the file */ - int64_t time_scale; - - /* 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; - MatroskaTrack *tracks[MAX_STREAMS]; - - /* cache for ID peeking */ - uint32_t peek_id; - - /* byte position of the segment inside the stream */ - offset_t segment_start; - - /* The packet queue. */ - AVPacket **packets; - int num_packets; - - /* have we already parse metadata/cues/clusters? */ - int metadata_parsed, - index_parsed, - done; - - /* 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; - -/* - * The first few functions handle EBML file parsing. The rest - * is the document interpretation. Matroska really just is a - * EBML file. - */ - -/* - * Return: the amount of levels in the hierarchy that the - * current element lies higher than the previous one. - * The opposite isn't done - that's auto-done using master - * element reading. - */ - -static int -ebml_read_element_level_up (MatroskaDemuxContext *matroska) -{ - ByteIOContext *pb = &matroska->ctx->pb; - offset_t pos = url_ftell(pb); - int num = 0; - - while (matroska->num_levels > 0) { - MatroskaLevel *level = &matroska->levels[matroska->num_levels - 1]; - - if (pos >= level->start + level->length) { - matroska->num_levels--; - num++; - } else { - break; - } - } - - return num; -} - -/* - * Read: an "EBML number", which is defined as a variable-length - * array of bytes. The first byte indicates the length by giving a - * number of 0-bits followed by a one. The position of the first - * "one" bit inside the first byte indicates the length of this - * number. - * Returns: num. of bytes read. < 0 on error. - */ - -static int -ebml_read_num (MatroskaDemuxContext *matroska, - int max_size, - uint64_t *number) -{ - ByteIOContext *pb = &matroska->ctx->pb; - int len_mask = 0x80, read = 1, n = 1; - int64_t total = 0; - - /* the first byte tells us the length in bytes - get_byte() can normally - * return 0, but since that's not a valid first ebmlID byte, we can - * use it safely here to catch EOS. */ - if (!(total = get_byte(pb))) { - /* we might encounter EOS here */ - if (!url_feof(pb)) { - offset_t pos = url_ftell(pb); - av_log(matroska->ctx, AV_LOG_ERROR, - "Read error at pos. %"PRIu64" (0x%"PRIx64")\n", - pos, pos); - } - return AVERROR_IO; /* EOS or actual I/O error */ - } - - /* get the length of the EBML number */ - while (read <= max_size && !(total & len_mask)) { - read++; - len_mask >>= 1; - } - if (read > max_size) { - offset_t pos = url_ftell(pb) - 1; - av_log(matroska->ctx, AV_LOG_ERROR, - "Invalid EBML number size tag 0x%02x at pos %"PRIu64" (0x%"PRIx64")\n", - (uint8_t) total, pos, pos); - return AVERROR_INVALIDDATA; - } - - /* read out length */ - total &= ~len_mask; - while (n++ < read) - total = (total << 8) | get_byte(pb); - - *number = total; - - return read; -} - -/* - * Read: the element content data ID. - * Return: the number of bytes read or < 0 on error. - */ - -static int -ebml_read_element_id (MatroskaDemuxContext *matroska, - uint32_t *id, - int *level_up) -{ - int read; - uint64_t total; - - /* if we re-call this, use our cached ID */ - if (matroska->peek_id != 0) { - if (level_up) - *level_up = 0; - *id = matroska->peek_id; - return 0; - } - - /* read out the "EBML number", include tag in ID */ - if ((read = ebml_read_num(matroska, 4, &total)) < 0) - return read; - *id = matroska->peek_id = total | (1 << (read * 7)); - - /* level tracking */ - if (level_up) - *level_up = ebml_read_element_level_up(matroska); - - return read; -} - -/* - * Read: element content length. - * Return: the number of bytes read or < 0 on error. - */ - -static int -ebml_read_element_length (MatroskaDemuxContext *matroska, - uint64_t *length) -{ - /* clear cache since we're now beyond that data point */ - matroska->peek_id = 0; - - /* read out the "EBML number", include tag in ID */ - return ebml_read_num(matroska, 8, length); -} - -/* - * Return: the ID of the next element, or 0 on error. - * Level_up contains the amount of levels that this - * next element lies higher than the previous one. - */ - -static uint32_t -ebml_peek_id (MatroskaDemuxContext *matroska, - int *level_up) -{ - uint32_t id; - - assert(level_up != NULL); - - if (ebml_read_element_id(matroska, &id, level_up) < 0) - return 0; - - return id; -} - -/* - * Seek to a given offset. - * 0 is success, -1 is failure. - */ - -static int -ebml_read_seek (MatroskaDemuxContext *matroska, - offset_t offset) -{ - ByteIOContext *pb = &matroska->ctx->pb; - - /* clear ID cache, if any */ - matroska->peek_id = 0; - - return (url_fseek(pb, offset, SEEK_SET) == offset) ? 0 : -1; -} - -/* - * Skip the next element. - * 0 is success, -1 is failure. - */ - -static int -ebml_read_skip (MatroskaDemuxContext *matroska) -{ - ByteIOContext *pb = &matroska->ctx->pb; - uint32_t id; - uint64_t length; - int res; - - if ((res = ebml_read_element_id(matroska, &id, NULL)) < 0 || - (res = ebml_read_element_length(matroska, &length)) < 0) - return res; - - url_fskip(pb, length); - - return 0; -} - -/* - * Read the next element as an unsigned int. - * 0 is success, < 0 is failure. - */ - -static int -ebml_read_uint (MatroskaDemuxContext *matroska, - uint32_t *id, - uint64_t *num) -{ - ByteIOContext *pb = &matroska->ctx->pb; - int n = 0, size, res; - uint64_t rlength; - - if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 || - (res = ebml_read_element_length(matroska, &rlength)) < 0) - return res; - size = rlength; - if (size < 1 || size > 8) { - offset_t pos = url_ftell(pb); - av_log(matroska->ctx, AV_LOG_ERROR, - "Invalid uint element size %d at position %"PRId64" (0x%"PRIx64")\n", - size, pos, pos); - return AVERROR_INVALIDDATA; - } - - /* big-endian ordening; build up number */ - *num = 0; - while (n++ < size) - *num = (*num << 8) | get_byte(pb); - - return 0; -} - -/* - * Read the next element as a signed int. - * 0 is success, < 0 is failure. - */ - -static int -ebml_read_sint (MatroskaDemuxContext *matroska, - uint32_t *id, - int64_t *num) -{ - ByteIOContext *pb = &matroska->ctx->pb; - int size, n = 1, negative = 0, res; - uint64_t rlength; - - if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 || - (res = ebml_read_element_length(matroska, &rlength)) < 0) - return res; - size = rlength; - if (size < 1 || size > 8) { - offset_t pos = url_ftell(pb); - av_log(matroska->ctx, AV_LOG_ERROR, - "Invalid sint element size %d at position %"PRId64" (0x%"PRIx64")\n", - size, pos, pos); - return AVERROR_INVALIDDATA; - } - if ((*num = get_byte(pb)) & 0x80) { - negative = 1; - *num &= ~0x80; - } - while (n++ < size) - *num = (*num << 8) | get_byte(pb); - - /* make signed */ - if (negative) - *num = *num - (1LL << ((8 * size) - 1)); - - return 0; -} - -/* - * Read the next element as a float. - * 0 is success, < 0 is failure. - */ - -static int -ebml_read_float (MatroskaDemuxContext *matroska, - uint32_t *id, - double *num) -{ - ByteIOContext *pb = &matroska->ctx->pb; - int size, res; - uint64_t rlength; - - if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 || - (res = ebml_read_element_length(matroska, &rlength)) < 0) - return res; - size = rlength; - - if (size == 4) { - *num= av_int2flt(get_be32(pb)); - } else if(size==8){ - *num= av_int2dbl(get_be64(pb)); - } else{ - offset_t pos = url_ftell(pb); - av_log(matroska->ctx, AV_LOG_ERROR, - "Invalid float element size %d at position %"PRIu64" (0x%"PRIx64")\n", - size, pos, pos); - return AVERROR_INVALIDDATA; - } - - return 0; -} - -/* - * Read the next element as an ASCII string. - * 0 is success, < 0 is failure. - */ - -static int -ebml_read_ascii (MatroskaDemuxContext *matroska, - uint32_t *id, - char **str) -{ - ByteIOContext *pb = &matroska->ctx->pb; - int size, res; - uint64_t rlength; - - if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 || - (res = ebml_read_element_length(matroska, &rlength)) < 0) - return res; - size = rlength; - - /* ebml strings are usually not 0-terminated, so we allocate one - * byte more, read the string and NULL-terminate it ourselves. */ - if (size < 0 || !(*str = av_malloc(size + 1))) { - av_log(matroska->ctx, AV_LOG_ERROR, "Memory allocation failed\n"); - return AVERROR_NOMEM; - } - if (get_buffer(pb, (uint8_t *) *str, size) != size) { - offset_t pos = url_ftell(pb); - av_log(matroska->ctx, AV_LOG_ERROR, - "Read error at pos. %"PRIu64" (0x%"PRIx64")\n", pos, pos); - return AVERROR_IO; - } - (*str)[size] = '\0'; - - return 0; -} - -/* - * Read the next element as a UTF-8 string. - * 0 is success, < 0 is failure. - */ - -static int -ebml_read_utf8 (MatroskaDemuxContext *matroska, - uint32_t *id, - char **str) -{ - return ebml_read_ascii(matroska, id, str); -} - -/* - * Read the next element as a date (nanoseconds since 1/1/2000). - * 0 is success, < 0 is failure. - */ - -static int -ebml_read_date (MatroskaDemuxContext *matroska, - uint32_t *id, - int64_t *date) -{ - return ebml_read_sint(matroska, id, date); -} - -/* - * Read the next element, but only the header. The contents - * are supposed to be sub-elements which can be read separately. - * 0 is success, < 0 is failure. - */ - -static int -ebml_read_master (MatroskaDemuxContext *matroska, - uint32_t *id) -{ - ByteIOContext *pb = &matroska->ctx->pb; - uint64_t length; - MatroskaLevel *level; - int res; - - if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 || - (res = ebml_read_element_length(matroska, &length)) < 0) - return res; - - /* protect... (Heaven forbids that the '>' is true) */ - if (matroska->num_levels >= EBML_MAX_DEPTH) { - av_log(matroska->ctx, AV_LOG_ERROR, - "File moves beyond max. allowed depth (%d)\n", EBML_MAX_DEPTH); - return AVERROR_NOTSUPP; - } - - /* remember level */ - level = &matroska->levels[matroska->num_levels++]; - level->start = url_ftell(pb); - level->length = length; - - return 0; -} - -/* - * Read the next element as binary data. - * 0 is success, < 0 is failure. - */ - -static int -ebml_read_binary (MatroskaDemuxContext *matroska, - uint32_t *id, - uint8_t **binary, - int *size) -{ - ByteIOContext *pb = &matroska->ctx->pb; - uint64_t rlength; - int res; - - if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 || - (res = ebml_read_element_length(matroska, &rlength)) < 0) - return res; - *size = rlength; - - if (!(*binary = av_malloc(*size))) { - av_log(matroska->ctx, AV_LOG_ERROR, - "Memory allocation error\n"); - return AVERROR_NOMEM; - } - - if (get_buffer(pb, *binary, *size) != *size) { - offset_t pos = url_ftell(pb); - av_log(matroska->ctx, AV_LOG_ERROR, - "Read error at pos. %"PRIu64" (0x%"PRIx64")\n", pos, pos); - return AVERROR_IO; - } - - return 0; -} - -/* - * Read signed/unsigned "EBML" numbers. - * Return: number of bytes processed, < 0 on error. - * XXX: use ebml_read_num(). - */ - -static int -matroska_ebmlnum_uint (uint8_t *data, - uint32_t size, - uint64_t *num) -{ - int len_mask = 0x80, read = 1, n = 1, num_ffs = 0; - uint64_t total; - - if (size <= 0) - return AVERROR_INVALIDDATA; - - total = data[0]; - while (read <= 8 && !(total & len_mask)) { - read++; - len_mask >>= 1; - } - if (read > 8) - return AVERROR_INVALIDDATA; - - if ((total &= (len_mask - 1)) == len_mask - 1) - num_ffs++; - if (size < read) - return AVERROR_INVALIDDATA; - while (n < read) { - if (data[n] == 0xff) - num_ffs++; - total = (total << 8) | data[n]; - n++; - } - - if (read == num_ffs) - *num = (uint64_t)-1; - else - *num = total; - - return read; -} - -/* - * Same as above, but signed. - */ - -static int -matroska_ebmlnum_sint (uint8_t *data, - uint32_t size, - int64_t *num) -{ - uint64_t unum; - int res; - - /* read as unsigned number first */ - if ((res = matroska_ebmlnum_uint(data, size, &unum)) < 0) - return res; - - /* make signed (weird way) */ - if (unum == (uint64_t)-1) - *num = INT64_MAX; - else - *num = unum - ((1LL << ((7 * res) - 1)) - 1); - - return res; -} - -/* - * Read an EBML header. - * 0 is success, < 0 is failure. - */ - -static int -ebml_read_header (MatroskaDemuxContext *matroska, - char **doctype, - int *version) -{ - uint32_t id; - int level_up, res = 0; - - /* default init */ - if (doctype) - *doctype = NULL; - if (version) - *version = 1; - - if (!(id = ebml_peek_id(matroska, &level_up)) || - level_up != 0 || id != EBML_ID_HEADER) { - av_log(matroska->ctx, AV_LOG_ERROR, - "This is not an EBML file (id=0x%x/0x%x)\n", id, EBML_ID_HEADER); - return AVERROR_INVALIDDATA; - } - if ((res = ebml_read_master(matroska, &id)) < 0) - return res; - - while (res == 0) { - if (!(id = ebml_peek_id(matroska, &level_up))) - return AVERROR_IO; - - /* end-of-header */ - if (level_up) - break; - - switch (id) { - /* is our read version uptodate? */ - case EBML_ID_EBMLREADVERSION: { - uint64_t num; - - if ((res = ebml_read_uint(matroska, &id, &num)) < 0) - return res; - if (num > EBML_VERSION) { - av_log(matroska->ctx, AV_LOG_ERROR, - "EBML version %"PRIu64" (> %d) is not supported\n", - num, EBML_VERSION); - return AVERROR_INVALIDDATA; - } - break; - } - - /* we only handle 8 byte lengths at max */ - case EBML_ID_EBMLMAXSIZELENGTH: { - uint64_t num; - - if ((res = ebml_read_uint(matroska, &id, &num)) < 0) - return res; - if (num > sizeof(uint64_t)) { - av_log(matroska->ctx, AV_LOG_ERROR, - "Integers of size %"PRIu64" (> %zd) not supported\n", - num, sizeof(uint64_t)); - return AVERROR_INVALIDDATA; - } - break; - } - - /* we handle 4 byte IDs at max */ - case EBML_ID_EBMLMAXIDLENGTH: { - uint64_t num; - - if ((res = ebml_read_uint(matroska, &id, &num)) < 0) - return res; - if (num > sizeof(uint32_t)) { - av_log(matroska->ctx, AV_LOG_ERROR, - "IDs of size %"PRIu64" (> %zu) not supported\n", - num, sizeof(uint32_t)); - return AVERROR_INVALIDDATA; - } - break; - } - - case EBML_ID_DOCTYPE: { - char *text; - - if ((res = ebml_read_ascii(matroska, &id, &text)) < 0) - return res; - if (doctype) { - if (*doctype) - av_free(*doctype); - *doctype = text; - } else - av_free(text); - break; - } - - case EBML_ID_DOCTYPEREADVERSION: { - uint64_t num; - - if ((res = ebml_read_uint(matroska, &id, &num)) < 0) - return res; - if (version) - *version = num; - break; - } - - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown data type 0x%x in EBML header", id); - /* pass-through */ - - case EBML_ID_VOID: - /* we ignore these two, as they don't tell us anything we - * care about */ - case EBML_ID_EBMLVERSION: - case EBML_ID_DOCTYPEVERSION: - res = ebml_read_skip (matroska); - break; - } - } - - 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. - */ - -static int -matroska_deliver_packet (MatroskaDemuxContext *matroska, - AVPacket *pkt) -{ - if (matroska->num_packets > 0) { - memcpy(pkt, matroska->packets[0], sizeof(AVPacket)); - av_free(matroska->packets[0]); - if (matroska->num_packets > 1) { - memmove(&matroska->packets[0], &matroska->packets[1], - (matroska->num_packets - 1) * sizeof(AVPacket *)); - matroska->packets = - av_realloc(matroska->packets, (matroska->num_packets - 1) * - sizeof(AVPacket *)); - } else { - av_freep(&matroska->packets); - } - matroska->num_packets--; - return 0; - } - - return -1; -} - -/* - * Put a packet into our internal queue. Will be delivered to the - * user/application during the next get_packet() call. - */ - -static void -matroska_queue_packet (MatroskaDemuxContext *matroska, - AVPacket *pkt) -{ - matroska->packets = - av_realloc(matroska->packets, (matroska->num_packets + 1) * - sizeof(AVPacket *)); - matroska->packets[matroska->num_packets] = pkt; - matroska->num_packets++; -} - - -/* - * Autodetecting... - */ - -static int -matroska_probe (AVProbeData *p) -{ - uint64_t total = 0; - int len_mask = 0x80, size = 1, n = 1; - uint8_t probe_data[] = { 'm', 'a', 't', 'r', 'o', 's', 'k', 'a' }; - - /* ebml header? */ - if ((p->buf[0] << 24 | p->buf[1] << 16 | - p->buf[2] << 8 | p->buf[3]) != EBML_ID_HEADER) - return 0; - - /* length of header */ - total = p->buf[4]; - while (size <= 8 && !(total & len_mask)) { - size++; - len_mask >>= 1; - } - if (size > 8) - return 0; - total &= (len_mask - 1); - 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; - - /* the header must contain the document type 'matroska'. For now, - * we don't parse the whole header but simply check for the - * availability of that array of characters inside the header. - * Not fully fool-proof, but good enough. */ - 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; - - return 0; -} - -/* - * From here on, it's all XML-style DTD stuff... Needs no comments. - */ - -static int -matroska_parse_info (MatroskaDemuxContext *matroska) -{ - int res = 0; - uint32_t id; - - av_log(matroska->ctx, AV_LOG_DEBUG, "Parsing info...\n"); - - 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; - } - - switch (id) { - /* cluster timecode */ - case MATROSKA_ID_TIMECODESCALE: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, &num)) < 0) - break; - matroska->time_scale = num; - break; - } - - case MATROSKA_ID_DURATION: { - double num; - if ((res = ebml_read_float(matroska, &id, &num)) < 0) - break; - matroska->ctx->duration = num * matroska->time_scale * 1000 / AV_TIME_BASE; - 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) - break; - matroska->writing_app = text; - break; - } - - case MATROSKA_ID_MUXINGAPP: { - char *text; - if ((res = ebml_read_utf8(matroska, &id, &text)) < 0) - break; - matroska->muxing_app = text; - break; - } - - case MATROSKA_ID_DATEUTC: { - int64_t time; - if ((res = ebml_read_date(matroska, &id, &time)) < 0) - break; - matroska->created = time; - break; - } - - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown entry 0x%x in info header\n", id); - /* fall-through */ - - case EBML_ID_VOID: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - - return res; -} - -static int -matroska_add_stream (MatroskaDemuxContext *matroska) -{ - int res = 0; - uint32_t id; - MatroskaTrack *track; - - 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(MAX_TRACK_SIZE); - matroska->num_tracks++; - - /* start with the master */ - if ((res = ebml_read_master(matroska, &id)) < 0) - return res; - - /* try reading the trackentry headers */ - while (res == 0) { - if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { - res = AVERROR_IO; - break; - } else if (matroska->level_up > 0) { - matroska->level_up--; - break; - } - - switch (id) { - /* track number (unique stream ID) */ - case MATROSKA_ID_TRACKNUMBER: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, &num)) < 0) - break; - track->num = num; - break; - } - - /* track UID (unique identifier) */ - case MATROSKA_ID_TRACKUID: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, &num)) < 0) - break; - track->uid = num; - break; - } - - /* track type (video, audio, combined, subtitle, etc.) */ - case MATROSKA_ID_TRACKTYPE: { - uint64_t num; - 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; - } - track->type = num; - - switch (track->type) { - case MATROSKA_TRACK_TYPE_VIDEO: - case MATROSKA_TRACK_TYPE_AUDIO: - case MATROSKA_TRACK_TYPE_SUBTITLE: - break; - case MATROSKA_TRACK_TYPE_COMPLEX: - case MATROSKA_TRACK_TYPE_LOGO: - case MATROSKA_TRACK_TYPE_CONTROL: - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown or unsupported track type 0x%x\n", - track->type); - track->type = 0; - break; - } - matroska->tracks[matroska->num_tracks - 1] = track; - break; - } - - /* 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"); - res = AVERROR_INVALIDDATA; - break; - } else if ((res = ebml_read_master(matroska, &id)) < 0) - break; - videotrack = (MatroskaVideoTrack *)track; - - while (res == 0) { - if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { - res = AVERROR_IO; - break; - } else if (matroska->level_up > 0) { - matroska->level_up--; - break; - } - - switch (id) { - /* fixme, this should be one-up, but I get it here */ - case MATROSKA_ID_TRACKDEFAULTDURATION: { - uint64_t num; - if ((res = ebml_read_uint (matroska, &id, - &num)) < 0) - break; - track->default_duration = num/matroska->time_scale; - break; - } - - /* video framerate */ - case MATROSKA_ID_VIDEOFRAMERATE: { - double num; - if ((res = ebml_read_float(matroska, &id, - &num)) < 0) - break; - track->default_duration = 1000000000/(matroska->time_scale*num); - break; - } - - /* width of the size to display the video at */ - case MATROSKA_ID_VIDEODISPLAYWIDTH: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, - &num)) < 0) - break; - videotrack->display_width = num; - break; - } - - /* height of the size to display the video at */ - case MATROSKA_ID_VIDEODISPLAYHEIGHT: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, - &num)) < 0) - break; - videotrack->display_height = num; - break; - } - - /* width of the video in the file */ - case MATROSKA_ID_VIDEOPIXELWIDTH: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, - &num)) < 0) - break; - videotrack->pixel_width = num; - break; - } - - /* height of the video in the file */ - case MATROSKA_ID_VIDEOPIXELHEIGHT: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, - &num)) < 0) - break; - videotrack->pixel_height = num; - break; - } - - /* whether the video is interlaced */ - case MATROSKA_ID_VIDEOFLAGINTERLACED: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, - &num)) < 0) - break; - if (num) - track->flags |= - MATROSKA_VIDEOTRACK_INTERLACED; - else - track->flags &= - ~MATROSKA_VIDEOTRACK_INTERLACED; - break; - } - - /* stereo mode (whether the video has two streams, - * where one is for the left eye and the other for - * the right eye, which creates a 3D-like - * effect) */ - case MATROSKA_ID_VIDEOSTEREOMODE: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, - &num)) < 0) - break; - if (num != MATROSKA_EYE_MODE_MONO && - num != MATROSKA_EYE_MODE_LEFT && - num != MATROSKA_EYE_MODE_RIGHT && - num != MATROSKA_EYE_MODE_BOTH) { - av_log(matroska->ctx, AV_LOG_INFO, - "Ignoring unknown eye mode 0x%x\n", - (uint32_t) num); - break; - } - videotrack->eye_mode = num; - break; - } - - /* aspect ratio behaviour */ - case MATROSKA_ID_VIDEOASPECTRATIO: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, - &num)) < 0) - break; - if (num != MATROSKA_ASPECT_RATIO_MODE_FREE && - num != MATROSKA_ASPECT_RATIO_MODE_KEEP && - num != MATROSKA_ASPECT_RATIO_MODE_FIXED) { - av_log(matroska->ctx, AV_LOG_INFO, - "Ignoring unknown aspect ratio 0x%x\n", - (uint32_t) num); - break; - } - videotrack->ar_mode = num; - break; - } - - /* colourspace (only matters for raw video) - * fourcc */ - case MATROSKA_ID_VIDEOCOLOURSPACE: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, - &num)) < 0) - break; - videotrack->fourcc = num; - break; - } - - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown video track header entry " - "0x%x - ignoring\n", id); - /* pass-through */ - - case EBML_ID_VOID: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - break; - } - - /* 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"); - res = AVERROR_INVALIDDATA; - break; - } 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))) { - res = AVERROR_IO; - break; - } else if (matroska->level_up > 0) { - matroska->level_up--; - break; - } - - 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) - break; - audiotrack->samplerate = num; - break; - } - - /* bitdepth */ - case MATROSKA_ID_AUDIOBITDEPTH: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, - &num)) < 0) - break; - audiotrack->bitdepth = num; - break; - } - - /* channels */ - case MATROSKA_ID_AUDIOCHANNELS: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, - &num)) < 0) - break; - audiotrack->channels = num; - break; - } - - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown audio track header entry " - "0x%x - ignoring\n", id); - /* pass-through */ - - case EBML_ID_VOID: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - break; - } - - /* codec identifier */ - case MATROSKA_ID_CODECID: { - char *text; - if ((res = ebml_read_ascii(matroska, &id, &text)) < 0) - break; - track->codec_id = text; - break; - } - - /* codec private data */ - case MATROSKA_ID_CODECPRIVATE: { - uint8_t *data; - int size; - if ((res = ebml_read_binary(matroska, &id, &data, &size) < 0)) - break; - track->codec_priv = data; - track->codec_priv_size = size; - break; - } - - /* name of the codec */ - case MATROSKA_ID_CODECNAME: { - char *text; - if ((res = ebml_read_utf8(matroska, &id, &text)) < 0) - break; - track->codec_name = text; - break; - } - - /* name of this track */ - case MATROSKA_ID_TRACKNAME: { - char *text; - if ((res = ebml_read_utf8(matroska, &id, &text)) < 0) - break; - track->name = text; - break; - } - - /* language (matters for audio/subtitles, mostly) */ - case MATROSKA_ID_TRACKLANGUAGE: { - char *text; - if ((res = ebml_read_utf8(matroska, &id, &text)) < 0) - break; - track->language = text; - break; - } - - /* whether this is actually used */ - case MATROSKA_ID_TRACKFLAGENABLED: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, &num)) < 0) - break; - if (num) - track->flags |= MATROSKA_TRACK_ENABLED; - else - track->flags &= ~MATROSKA_TRACK_ENABLED; - break; - } - - /* whether it's the default for this track type */ - case MATROSKA_ID_TRACKFLAGDEFAULT: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, &num)) < 0) - break; - if (num) - track->flags |= MATROSKA_TRACK_DEFAULT; - else - track->flags &= ~MATROSKA_TRACK_DEFAULT; - break; - } - - /* lacing (like MPEG, where blocks don't end/start on frame - * boundaries) */ - case MATROSKA_ID_TRACKFLAGLACING: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, &num)) < 0) - break; - if (num) - track->flags |= MATROSKA_TRACK_LACING; - else - track->flags &= ~MATROSKA_TRACK_LACING; - break; - } - - /* default length (in time) of one data block in this track */ - case MATROSKA_ID_TRACKDEFAULTDURATION: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, &num)) < 0) - break; - track->default_duration = num / matroska->time_scale; - break; - } - - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown track header entry 0x%x - ignoring\n", id); - /* pass-through */ - - case EBML_ID_VOID: - /* we ignore these because they're nothing useful. */ - case MATROSKA_ID_CODECINFOURL: - case MATROSKA_ID_CODECDOWNLOADURL: - case MATROSKA_ID_TRACKMINCACHE: - case MATROSKA_ID_TRACKMAXCACHE: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - - return res; -} - -static int -matroska_parse_tracks (MatroskaDemuxContext *matroska) -{ - int res = 0; - uint32_t id; - - av_log(matroska->ctx, AV_LOG_DEBUG, "parsing tracks...\n"); - - 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; - } - - switch (id) { - /* one track within the "all-tracks" header */ - case MATROSKA_ID_TRACKENTRY: - res = matroska_add_stream(matroska); - break; - - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown entry 0x%x in track header\n", id); - /* fall-through */ - - case EBML_ID_VOID: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - - return res; -} - -static int -matroska_parse_index (MatroskaDemuxContext *matroska) -{ - int res = 0; - uint32_t id; - MatroskaDemuxIndex idx; - - av_log(matroska->ctx, AV_LOG_DEBUG, "parsing index...\n"); - - 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; - } - - switch (id) { - /* one single index entry ('point') */ - case MATROSKA_ID_POINTENTRY: - if ((res = ebml_read_master(matroska, &id)) < 0) - break; - - /* in the end, we hope to fill one entry with a - * timestamp, a file position and a tracknum */ - idx.pos = (uint64_t) -1; - idx.time = (uint64_t) -1; - idx.track = (uint16_t) -1; - - 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; - } - - switch (id) { - /* one single index entry ('point') */ - case MATROSKA_ID_CUETIME: { - uint64_t time; - if ((res = ebml_read_uint(matroska, &id, - &time)) < 0) - break; - idx.time = time * matroska->time_scale; - break; - } - - /* position in the file + track to which it - * belongs */ - case MATROSKA_ID_CUETRACKPOSITION: - if ((res = ebml_read_master(matroska, &id)) < 0) - break; - - 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; - } - - switch (id) { - /* track number */ - case MATROSKA_ID_CUETRACK: { - uint64_t num; - if ((res = ebml_read_uint(matroska, - &id, &num)) < 0) - break; - idx.track = num; - break; - } - - /* position in file */ - case MATROSKA_ID_CUECLUSTERPOSITION: { - uint64_t num; - if ((res = ebml_read_uint(matroska, - &id, &num)) < 0) - break; - idx.pos = num+matroska->segment_start; - break; - } - - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown entry 0x%x in " - "CuesTrackPositions\n", id); - /* fall-through */ - - case EBML_ID_VOID: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - - break; - - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown entry 0x%x in cuespoint " - "index\n", id); - /* fall-through */ - - case EBML_ID_VOID: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - - /* so let's see if we got what we wanted */ - if (idx.pos != (uint64_t) -1 && - idx.time != (uint64_t) -1 && - idx.track != (uint16_t) -1) { - if (matroska->num_indexes % 32 == 0) { - /* re-allocate bigger index */ - matroska->index = - av_realloc(matroska->index, - (matroska->num_indexes + 32) * - sizeof(MatroskaDemuxIndex)); - } - matroska->index[matroska->num_indexes] = idx; - matroska->num_indexes++; - } - break; - - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown entry 0x%x in cues header\n", id); - /* fall-through */ - - case EBML_ID_VOID: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - - return res; -} - -static int -matroska_parse_metadata (MatroskaDemuxContext *matroska) -{ - int res = 0; - uint32_t id; - - 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; - } - - switch (id) { - /* Hm, this is unsupported... */ - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown entry 0x%x in metadata header\n", id); - /* fall-through */ - - case EBML_ID_VOID: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - - return res; -} - -static int -matroska_parse_seekhead (MatroskaDemuxContext *matroska) -{ - int res = 0; - uint32_t id; - - av_log(matroska->ctx, AV_LOG_DEBUG, "parsing seekhead...\n"); - - 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; - } - - switch (id) { - case MATROSKA_ID_SEEKENTRY: { - uint32_t seek_id = 0, peek_id_cache = 0; - uint64_t seek_pos = (uint64_t) -1, t; - - if ((res = ebml_read_master(matroska, &id)) < 0) - break; - - 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; - } - - switch (id) { - case MATROSKA_ID_SEEKID: - res = ebml_read_uint(matroska, &id, &t); - seek_id = t; - break; - - case MATROSKA_ID_SEEKPOSITION: - res = ebml_read_uint(matroska, &id, &seek_pos); - break; - - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown seekhead ID 0x%x\n", id); - /* fall-through */ - - case EBML_ID_VOID: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - - if (!seek_id || seek_pos == (uint64_t) -1) { - av_log(matroska->ctx, AV_LOG_INFO, - "Incomplete seekhead entry (0x%x/%"PRIu64")\n", - seek_id, seek_pos); - break; - } - - switch (seek_id) { - case MATROSKA_ID_CUES: - case MATROSKA_ID_TAGS: { - uint32_t level_up = matroska->level_up; - offset_t before_pos; - uint64_t length; - MatroskaLevel level; - - /* remember the peeked ID and the current position */ - peek_id_cache = matroska->peek_id; - before_pos = url_ftell(&matroska->ctx->pb); - - /* seek */ - if ((res = ebml_read_seek(matroska, seek_pos + - matroska->segment_start)) < 0) - return res; - - /* we don't want to lose our seekhead level, so we add - * a dummy. This is a crude hack. */ - if (matroska->num_levels == EBML_MAX_DEPTH) { - av_log(matroska->ctx, AV_LOG_INFO, - "Max EBML element depth (%d) reached, " - "cannot parse further.\n", EBML_MAX_DEPTH); - return AVERROR_UNKNOWN; - } - - level.start = 0; - level.length = (uint64_t)-1; - matroska->levels[matroska->num_levels] = level; - matroska->num_levels++; - - /* check ID */ - if (!(id = ebml_peek_id (matroska, - &matroska->level_up))) - goto finish; - if (id != seek_id) { - av_log(matroska->ctx, AV_LOG_INFO, - "We looked for ID=0x%x but got " - "ID=0x%x (pos=%"PRIu64")", - seek_id, id, seek_pos + - matroska->segment_start); - goto finish; - } - - /* read master + parse */ - if ((res = ebml_read_master(matroska, &id)) < 0) - goto finish; - switch (id) { - case MATROSKA_ID_CUES: - if (!(res = matroska_parse_index(matroska)) || - url_feof(&matroska->ctx->pb)) { - matroska->index_parsed = 1; - res = 0; - } - break; - case MATROSKA_ID_TAGS: - if (!(res = matroska_parse_metadata(matroska)) || - url_feof(&matroska->ctx->pb)) { - matroska->metadata_parsed = 1; - res = 0; - } - break; - } - - finish: - /* remove dummy level */ - while (matroska->num_levels) { - matroska->num_levels--; - length = - matroska->levels[matroska->num_levels].length; - if (length == (uint64_t)-1) - break; - } - - /* seek back */ - if ((res = ebml_read_seek(matroska, before_pos)) < 0) - return res; - matroska->peek_id = peek_id_cache; - matroska->level_up = level_up; - break; - } - - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Ignoring seekhead entry for ID=0x%x\n", - seek_id); - break; - } - - break; - } - - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown seekhead ID 0x%x\n", id); - /* fall-through */ - - case EBML_ID_VOID: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - - 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<ARRAY_SIZE(aac_profiles); profile++) - if (strstr(codec_id, aac_profiles[profile])) - break; - return profile + 1; -} - -static int -matroska_aac_sri (int samplerate) -{ - static const int aac_sample_rates[] = { - 96000, 88200, 64000, 48000, 44100, 32000, - 24000, 22050, 16000, 12000, 11025, 8000, - }; - int sri; - - for (sri=0; sri<ARRAY_SIZE(aac_sample_rates); sri++) - if (aac_sample_rates[sri] == samplerate) - break; - return sri; -} - -static int -matroska_read_header (AVFormatContext *s, - AVFormatParameters *ap) -{ - MatroskaDemuxContext *matroska = s->priv_data; - char *doctype; - int version, last_level, res = 0; - uint32_t id; - - matroska->ctx = s; - - /* First read the EBML header. */ - doctype = NULL; - if ((res = ebml_read_header(matroska, &doctype, &version)) < 0) - return res; - if ((doctype == NULL) || strcmp(doctype, "matroska")) { - av_log(matroska->ctx, AV_LOG_ERROR, - "Wrong EBML doctype ('%s' != 'matroska').\n", - doctype ? doctype : "(none)"); - if (doctype) - av_free(doctype); - return AVERROR_NOFMT; - } - av_free(doctype); - if (version > 2) { - av_log(matroska->ctx, AV_LOG_ERROR, - "Matroska demuxer version 2 too old for file version %d\n", - version); - return AVERROR_NOFMT; - } - - /* The next thing is a segment. */ - while (1) { - if (!(id = ebml_peek_id(matroska, &last_level))) - return AVERROR_IO; - if (id == MATROSKA_ID_SEGMENT) - break; - - /* oi! */ - av_log(matroska->ctx, AV_LOG_INFO, - "Expected a Segment ID (0x%x), but received 0x%x!\n", - MATROSKA_ID_SEGMENT, id); - if ((res = ebml_read_skip(matroska)) < 0) - return res; - } - - /* We now have a Matroska segment. - * Seeks are from the beginning of the segment, - * after the segment ID/length. */ - if ((res = ebml_read_master(matroska, &id)) < 0) - return res; - matroska->segment_start = url_ftell(&s->pb); - - matroska->time_scale = 1000000; - /* we've found our segment, start reading the different contents in here */ - 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; - } - - switch (id) { - /* stream info */ - case MATROSKA_ID_INFO: { - if ((res = ebml_read_master(matroska, &id)) < 0) - break; - res = matroska_parse_info(matroska); - break; - } - - /* track info headers */ - case MATROSKA_ID_TRACKS: { - if ((res = ebml_read_master(matroska, &id)) < 0) - break; - res = matroska_parse_tracks(matroska); - break; - } - - /* stream index */ - case MATROSKA_ID_CUES: { - if (!matroska->index_parsed) { - if ((res = ebml_read_master(matroska, &id)) < 0) - break; - res = matroska_parse_index(matroska); - } else - res = ebml_read_skip(matroska); - break; - } - - /* metadata */ - case MATROSKA_ID_TAGS: { - if (!matroska->metadata_parsed) { - if ((res = ebml_read_master(matroska, &id)) < 0) - break; - res = matroska_parse_metadata(matroska); - } else - res = ebml_read_skip(matroska); - break; - } - - /* file index (if seekable, seek to Cues/Tags to parse it) */ - case MATROSKA_ID_SEEKHEAD: { - if ((res = ebml_read_master(matroska, &id)) < 0) - break; - res = matroska_parse_seekhead(matroska); - break; - } - - case MATROSKA_ID_CLUSTER: { - /* Do not read the master - this will be done in the next - * call to matroska_read_packet. */ - res = 1; - break; - } - - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown matroska file header ID 0x%x\n", id); - /* fall-through */ - - case EBML_ID_VOID: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - - /* Have we found a cluster? */ - if (ebml_peek_id(matroska, NULL) == MATROSKA_ID_CLUSTER) { - int i, j; - MatroskaTrack *track; - AVStream *st; - - for (i = 0; i < matroska->num_tracks; i++) { - 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. - * Also apply some sanity checks. */ - if ((track->type == MATROSKA_TRACK_TYPE_SUBTITLE) || - (track->codec_id == NULL)) - continue; - - for(j=0; codec_tags[j].str; j++){ - if(!strncmp(codec_tags[j].str, track->codec_id, - strlen(codec_tags[j].str))){ - codec_id= codec_tags[j].id; - break; - } - } - - /* Set the FourCC from the CodecID. */ - /* This is the MS compatibility mode which stores a - * BITMAPINFOHEADER in the CodecPrivate. */ - if (!strcmp(track->codec_id, - MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC) && - (track->codec_priv_size >= 40) && - (track->codec_priv != NULL)) { - unsigned char *p; - - /* Offset of biCompression. Stored in LE. */ - 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_id(codec_bmp_tags, ((MatroskaVideoTrack *)track)->fourcc); - - } - - /* This is the MS compatibility mode which stores a - * WAVEFORMATEX in the CodecPrivate. */ - else if (!strcmp(track->codec_id, - MATROSKA_CODEC_ID_AUDIO_ACM) && - (track->codec_priv_size >= 18) && - (track->codec_priv != NULL)) { - unsigned char *p; - uint16_t tag; - - /* Offset of wFormatTag. Stored in LE. */ - p = (unsigned char *)track->codec_priv; - tag = (p[1] << 8) | p[0]; - 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) { - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown/unsupported CodecID %s.\n", - track->codec_id); - } - - track->stream_index = matroska->num_streams; - - matroska->num_streams++; - st = av_new_stream(s, track->stream_index); - if (st == NULL) - return AVERROR_NOMEM; - 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; - st->codec->extradata_size = extradata_size; - } else if(track->codec_priv && track->codec_priv_size > 0){ - st->codec->extradata = av_malloc(track->codec_priv_size); - if(st->codec->extradata == NULL) - return AVERROR_NOMEM; - st->codec->extradata_size = track->codec_priv_size; - memcpy(st->codec->extradata,track->codec_priv+extradata_offset, - track->codec_priv_size); - } - - if (track->type == MATROSKA_TRACK_TYPE_VIDEO) { - MatroskaVideoTrack *videotrack = (MatroskaVideoTrack *)track; - - st->codec->codec_type = CODEC_TYPE_VIDEO; - st->codec->codec_tag = videotrack->fourcc; - st->codec->width = videotrack->pixel_width; - st->codec->height = videotrack->pixel_height; - if (videotrack->display_width == 0) - videotrack->display_width= videotrack->pixel_width; - if (videotrack->display_height == 0) - videotrack->display_height= videotrack->pixel_height; - av_reduce(&st->codec->sample_aspect_ratio.num, - &st->codec->sample_aspect_ratio.den, - 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; - - st->codec->codec_type = CODEC_TYPE_AUDIO; - st->codec->sample_rate = audiotrack->samplerate; - st->codec->channels = audiotrack->channels; - } else if (track->type == MATROSKA_TRACK_TYPE_SUBTITLE) { - st->codec->codec_type = CODEC_TYPE_SUBTITLE; - } - - /* What do we do with private data? E.g. for Vorbis. */ - } - res = 0; - } - - if (matroska->index_parsed) { - int i, track, stream; - for (i=0; i<matroska->num_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_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 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; - - /* 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; - } - - 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; slice<slices; slice++) { - int slice_size, slice_offset = 0; - if (real_v) - slice_offset = rv_offset(data, slice, slices); - if (slice+1 == slices) - slice_size = lace_size[n] - slice_offset; - else - slice_size = rv_offset(data, slice+1, slices) - slice_offset; - pkt = av_mallocz(sizeof(AVPacket)); - /* XXX: prevent data copy... */ - if (av_new_packet(pkt, slice_size) < 0) { - res = AVERROR_NOMEM; - n = laces-1; - break; - } - memcpy (pkt->data, 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 -matroska_parse_blockgroup (MatroskaDemuxContext *matroska, - uint64_t cluster_time) -{ - int res = 0; - uint32_t id; - 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"); - - 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; - } - - switch (id) { - /* one block inside the group. Note, block parsing is one - * of the harder things, so this code is a bit complicated. - * See http://www.matroska.org/ for documentation. */ - case MATROSKA_ID_BLOCK: { - pos = url_ftell(&matroska->ctx->pb); - res = ebml_read_binary(matroska, &id, &data, &size); - break; - } - - case MATROSKA_ID_BLOCKDURATION: { - if ((res = ebml_read_uint(matroska, &id, &duration)) < 0) - break; - duration /= matroska->time_scale; - break; - } - - 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; - 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, - "Unknown entry 0x%x in blockgroup data\n", id); - /* fall-through */ - - case EBML_ID_VOID: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - - if (res) - return res; - - if (size > 0) - res = matroska_parse_block(matroska, data, size, pos, cluster_time, - duration, is_keyframe, is_bframe); - - return res; -} - -static int -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)); - - 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; - } - - switch (id) { - /* cluster timecode */ - case MATROSKA_ID_CLUSTERTIMECODE: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, &num)) < 0) - break; - cluster_time = num; - break; - } - - /* a group of blocks inside a cluster */ - case MATROSKA_ID_BLOCKGROUP: - if ((res = ebml_read_master(matroska, &id)) < 0) - break; - 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); - /* fall-through */ - - case EBML_ID_VOID: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - - return res; -} - -static int -matroska_read_packet (AVFormatContext *s, - AVPacket *pkt) -{ - MatroskaDemuxContext *matroska = s->priv_data; - int res = 0; - uint32_t id; - - /* 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; - - 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) - 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); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - - 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; - - /* 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 -matroska_read_close (AVFormatContext *s) -{ - MatroskaDemuxContext *matroska = s->priv_data; - int n = 0; - - 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++) { - av_free_packet(matroska->packets[n]); - av_free(matroska->packets[n]); - } - av_free(matroska->packets); - } - - for (n = 0; n < matroska->num_tracks; n++) { - MatroskaTrack *track = matroska->tracks[n]; - 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); - } - - return 0; -} - -AVInputFormat matroska_demuxer = { - "matroska", - "Matroska file format", - sizeof(MatroskaDemuxContext), - matroska_probe, - matroska_read_header, - matroska_read_packet, - matroska_read_close, - matroska_read_seek, -};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/matroska.h Mon Jun 04 22:10:54 2007 +0000 @@ -0,0 +1,196 @@ +/* + * Matroska constants + * Copyright (c) 2003-2004 The ffmpeg Project + * + * 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.1 of the License, or (at your option) any later version. + * + * 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef MATROSKA_H +#define MATROSKA_H + +#include "avcodec.h" + +/* EBML version supported */ +#define EBML_VERSION 1 + +/* top-level master-IDs */ +#define EBML_ID_HEADER 0x1A45DFA3 + +/* IDs in the HEADER master */ +#define EBML_ID_EBMLVERSION 0x4286 +#define EBML_ID_EBMLREADVERSION 0x42F7 +#define EBML_ID_EBMLMAXIDLENGTH 0x42F2 +#define EBML_ID_EBMLMAXSIZELENGTH 0x42F3 +#define EBML_ID_DOCTYPE 0x4282 +#define EBML_ID_DOCTYPEVERSION 0x4287 +#define EBML_ID_DOCTYPEREADVERSION 0x4285 + +/* general EBML types */ +#define EBML_ID_VOID 0xEC + +/* + * Matroska element IDs. max. 32-bit. + */ + +/* toplevel segment */ +#define MATROSKA_ID_SEGMENT 0x18538067 + +/* matroska top-level master IDs */ +#define MATROSKA_ID_INFO 0x1549A966 +#define MATROSKA_ID_TRACKS 0x1654AE6B +#define MATROSKA_ID_CUES 0x1C53BB6B +#define MATROSKA_ID_TAGS 0x1254C367 +#define MATROSKA_ID_SEEKHEAD 0x114D9B74 +#define MATROSKA_ID_CLUSTER 0x1F43B675 + +/* 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 + +/* ID in the tracks master */ +#define MATROSKA_ID_TRACKENTRY 0xAE + +/* IDs in the trackentry master */ +#define MATROSKA_ID_TRACKNUMBER 0xD7 +#define MATROSKA_ID_TRACKUID 0x73C5 +#define MATROSKA_ID_TRACKTYPE 0x83 +#define MATROSKA_ID_TRACKAUDIO 0xE1 +#define MATROSKA_ID_TRACKVIDEO 0xE0 +#define MATROSKA_ID_CODECID 0x86 +#define MATROSKA_ID_CODECPRIVATE 0x63A2 +#define MATROSKA_ID_CODECNAME 0x258688 +#define MATROSKA_ID_CODECINFOURL 0x3B4040 +#define MATROSKA_ID_CODECDOWNLOADURL 0x26B240 +#define MATROSKA_ID_TRACKNAME 0x536E +#define MATROSKA_ID_TRACKLANGUAGE 0x22B59C +#define MATROSKA_ID_TRACKFLAGENABLED 0xB9 +#define MATROSKA_ID_TRACKFLAGDEFAULT 0x88 +#define MATROSKA_ID_TRACKFLAGLACING 0x9C +#define MATROSKA_ID_TRACKMINCACHE 0x6DE7 +#define MATROSKA_ID_TRACKMAXCACHE 0x6DF8 +#define MATROSKA_ID_TRACKDEFAULTDURATION 0x23E383 + +/* IDs in the trackvideo master */ +#define MATROSKA_ID_VIDEOFRAMERATE 0x2383E3 +#define MATROSKA_ID_VIDEODISPLAYWIDTH 0x54B0 +#define MATROSKA_ID_VIDEODISPLAYHEIGHT 0x54BA +#define MATROSKA_ID_VIDEOPIXELWIDTH 0xB0 +#define MATROSKA_ID_VIDEOPIXELHEIGHT 0xBA +#define MATROSKA_ID_VIDEOFLAGINTERLACED 0x9A +#define MATROSKA_ID_VIDEOSTEREOMODE 0x53B9 +#define MATROSKA_ID_VIDEOASPECTRATIO 0x54B3 +#define MATROSKA_ID_VIDEOCOLOURSPACE 0x2EB524 + +/* 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 + +/* ID in the cues master */ +#define MATROSKA_ID_POINTENTRY 0xBB + +/* IDs in the pointentry master */ +#define MATROSKA_ID_CUETIME 0xB3 +#define MATROSKA_ID_CUETRACKPOSITION 0xB7 + +/* IDs in the cuetrackposition master */ +#define MATROSKA_ID_CUETRACK 0xF7 +#define MATROSKA_ID_CUECLUSTERPOSITION 0xF1 + +/* IDs in the tags master */ +/* TODO */ + +/* IDs in the seekhead master */ +#define MATROSKA_ID_SEEKENTRY 0x4DBB + +/* IDs in the seekpoint master */ +#define MATROSKA_ID_SEEKID 0x53AB +#define MATROSKA_ID_SEEKPOSITION 0x53AC + +/* 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 +#define MATROSKA_ID_BLOCKDURATION 0x9B +#define MATROSKA_ID_BLOCKREFERENCE 0xFB + +typedef enum { + MATROSKA_TRACK_TYPE_VIDEO = 0x1, + MATROSKA_TRACK_TYPE_AUDIO = 0x2, + MATROSKA_TRACK_TYPE_COMPLEX = 0x3, + MATROSKA_TRACK_TYPE_LOGO = 0x10, + MATROSKA_TRACK_TYPE_SUBTITLE = 0x11, + MATROSKA_TRACK_TYPE_CONTROL = 0x20, +} MatroskaTrackType; + +typedef enum { + MATROSKA_EYE_MODE_MONO = 0x0, + MATROSKA_EYE_MODE_RIGHT = 0x1, + MATROSKA_EYE_MODE_LEFT = 0x2, + MATROSKA_EYE_MODE_BOTH = 0x3, +} MatroskaEyeMode; + +typedef enum { + MATROSKA_ASPECT_RATIO_MODE_FREE = 0x0, + MATROSKA_ASPECT_RATIO_MODE_KEEP = 0x1, + MATROSKA_ASPECT_RATIO_MODE_FIXED = 0x2, +} MatroskaAspectRatioMode; + +/* + * These aren't in any way "matroska-form" things, + * it's just something I use in the muxer/demuxer. + */ + +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; + +typedef enum { + MATROSKA_VIDEOTRACK_INTERLACED = (MATROSKA_TRACK_SHIFT<<0) +} MatroskaVideoTrackFlags; + +/* + * Matroska Codec IDs. Strings. + */ + +typedef struct CodecTags{ + 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" + +/* max. depth in the EBML tree structure */ +#define EBML_MAX_DEPTH 16 + +extern CodecTags ff_mkv_codec_tags[]; + +#endif /* MATROSKA_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/matroskadec.c Mon Jun 04 22:10:54 2007 +0000 @@ -0,0 +1,2642 @@ +/* + * Matroska file demuxer (no muxer yet) + * Copyright (c) 2003-2004 The ffmpeg Project + * + * 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.1 of the License, or (at your option) any later version. + * + * 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file matroska.c + * Matroska file demuxer + * by Ronald Bultje <rbultje@ronald.bitfreak.net> + * with a little help from Moritz Bunkus <moritz@bunkus.org> + * Specs available on the matroska project page: + * http://www.matroska.org/. + */ + +#include "avformat.h" +/* For codec_get_id(). */ +#include "riff.h" +#include "intfloat_readwrite.h" +#include "matroska.h" + +typedef struct Track { + MatroskaTrackType type; + + /* Unique track number and track ID. stream_index is the index that + * the calling app uses for this track. */ + uint32_t num, + uid, + stream_index; + + char *name, + *language; + + char *codec_id, + *codec_name; + + unsigned char *codec_priv; + int codec_priv_size; + + uint64_t default_duration; + MatroskaTrackFlags flags; +} MatroskaTrack; + +typedef struct MatroskaVideoTrack { + MatroskaTrack track; + + int pixel_width, + pixel_height, + display_width, + display_height; + + uint32_t fourcc; + + MatroskaAspectRatioMode ar_mode; + MatroskaEyeMode eye_mode; + + //.. +} MatroskaVideoTrack; + +typedef struct MatroskaAudioTrack { + MatroskaTrack track; + + int channels, + bitdepth, + internal_samplerate, + samplerate; + //.. +} MatroskaAudioTrack; + +typedef struct MatroskaSubtitleTrack { + MatroskaTrack track; + + //.. +} MatroskaSubtitleTrack; + +#define MAX_TRACK_SIZE (FFMAX(FFMAX(sizeof(MatroskaVideoTrack), \ + sizeof(MatroskaAudioTrack)), \ + sizeof(MatroskaSubtitleTrack))) + +typedef struct MatroskaLevel { + uint64_t start, length; +} MatroskaLevel; + +typedef struct MatroskaDemuxIndex { + uint64_t pos; /* of the corresponding *cluster*! */ + uint16_t track; /* reference to 'num' */ + uint64_t time; /* in nanoseconds */ +} MatroskaDemuxIndex; + +typedef struct MatroskaDemuxContext { + AVFormatContext *ctx; + + /* ebml stuff */ + int num_levels; + MatroskaLevel levels[EBML_MAX_DEPTH]; + int level_up; + + /* matroska stuff */ + char *writing_app, + *muxing_app; + int64_t created; + + /* timescale in the file */ + int64_t time_scale; + + /* 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; + MatroskaTrack *tracks[MAX_STREAMS]; + + /* cache for ID peeking */ + uint32_t peek_id; + + /* byte position of the segment inside the stream */ + offset_t segment_start; + + /* The packet queue. */ + AVPacket **packets; + int num_packets; + + /* have we already parse metadata/cues/clusters? */ + int metadata_parsed, + index_parsed, + done; + + /* 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; + +/* + * The first few functions handle EBML file parsing. The rest + * is the document interpretation. Matroska really just is a + * EBML file. + */ + +/* + * Return: the amount of levels in the hierarchy that the + * current element lies higher than the previous one. + * The opposite isn't done - that's auto-done using master + * element reading. + */ + +static int +ebml_read_element_level_up (MatroskaDemuxContext *matroska) +{ + ByteIOContext *pb = &matroska->ctx->pb; + offset_t pos = url_ftell(pb); + int num = 0; + + while (matroska->num_levels > 0) { + MatroskaLevel *level = &matroska->levels[matroska->num_levels - 1]; + + if (pos >= level->start + level->length) { + matroska->num_levels--; + num++; + } else { + break; + } + } + + return num; +} + +/* + * Read: an "EBML number", which is defined as a variable-length + * array of bytes. The first byte indicates the length by giving a + * number of 0-bits followed by a one. The position of the first + * "one" bit inside the first byte indicates the length of this + * number. + * Returns: num. of bytes read. < 0 on error. + */ + +static int +ebml_read_num (MatroskaDemuxContext *matroska, + int max_size, + uint64_t *number) +{ + ByteIOContext *pb = &matroska->ctx->pb; + int len_mask = 0x80, read = 1, n = 1; + int64_t total = 0; + + /* the first byte tells us the length in bytes - get_byte() can normally + * return 0, but since that's not a valid first ebmlID byte, we can + * use it safely here to catch EOS. */ + if (!(total = get_byte(pb))) { + /* we might encounter EOS here */ + if (!url_feof(pb)) { + offset_t pos = url_ftell(pb); + av_log(matroska->ctx, AV_LOG_ERROR, + "Read error at pos. %"PRIu64" (0x%"PRIx64")\n", + pos, pos); + } + return AVERROR_IO; /* EOS or actual I/O error */ + } + + /* get the length of the EBML number */ + while (read <= max_size && !(total & len_mask)) { + read++; + len_mask >>= 1; + } + if (read > max_size) { + offset_t pos = url_ftell(pb) - 1; + av_log(matroska->ctx, AV_LOG_ERROR, + "Invalid EBML number size tag 0x%02x at pos %"PRIu64" (0x%"PRIx64")\n", + (uint8_t) total, pos, pos); + return AVERROR_INVALIDDATA; + } + + /* read out length */ + total &= ~len_mask; + while (n++ < read) + total = (total << 8) | get_byte(pb); + + *number = total; + + return read; +} + +/* + * Read: the element content data ID. + * Return: the number of bytes read or < 0 on error. + */ + +static int +ebml_read_element_id (MatroskaDemuxContext *matroska, + uint32_t *id, + int *level_up) +{ + int read; + uint64_t total; + + /* if we re-call this, use our cached ID */ + if (matroska->peek_id != 0) { + if (level_up) + *level_up = 0; + *id = matroska->peek_id; + return 0; + } + + /* read out the "EBML number", include tag in ID */ + if ((read = ebml_read_num(matroska, 4, &total)) < 0) + return read; + *id = matroska->peek_id = total | (1 << (read * 7)); + + /* level tracking */ + if (level_up) + *level_up = ebml_read_element_level_up(matroska); + + return read; +} + +/* + * Read: element content length. + * Return: the number of bytes read or < 0 on error. + */ + +static int +ebml_read_element_length (MatroskaDemuxContext *matroska, + uint64_t *length) +{ + /* clear cache since we're now beyond that data point */ + matroska->peek_id = 0; + + /* read out the "EBML number", include tag in ID */ + return ebml_read_num(matroska, 8, length); +} + +/* + * Return: the ID of the next element, or 0 on error. + * Level_up contains the amount of levels that this + * next element lies higher than the previous one. + */ + +static uint32_t +ebml_peek_id (MatroskaDemuxContext *matroska, + int *level_up) +{ + uint32_t id; + + assert(level_up != NULL); + + if (ebml_read_element_id(matroska, &id, level_up) < 0) + return 0; + + return id; +} + +/* + * Seek to a given offset. + * 0 is success, -1 is failure. + */ + +static int +ebml_read_seek (MatroskaDemuxContext *matroska, + offset_t offset) +{ + ByteIOContext *pb = &matroska->ctx->pb; + + /* clear ID cache, if any */ + matroska->peek_id = 0; + + return (url_fseek(pb, offset, SEEK_SET) == offset) ? 0 : -1; +} + +/* + * Skip the next element. + * 0 is success, -1 is failure. + */ + +static int +ebml_read_skip (MatroskaDemuxContext *matroska) +{ + ByteIOContext *pb = &matroska->ctx->pb; + uint32_t id; + uint64_t length; + int res; + + if ((res = ebml_read_element_id(matroska, &id, NULL)) < 0 || + (res = ebml_read_element_length(matroska, &length)) < 0) + return res; + + url_fskip(pb, length); + + return 0; +} + +/* + * Read the next element as an unsigned int. + * 0 is success, < 0 is failure. + */ + +static int +ebml_read_uint (MatroskaDemuxContext *matroska, + uint32_t *id, + uint64_t *num) +{ + ByteIOContext *pb = &matroska->ctx->pb; + int n = 0, size, res; + uint64_t rlength; + + if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 || + (res = ebml_read_element_length(matroska, &rlength)) < 0) + return res; + size = rlength; + if (size < 1 || size > 8) { + offset_t pos = url_ftell(pb); + av_log(matroska->ctx, AV_LOG_ERROR, + "Invalid uint element size %d at position %"PRId64" (0x%"PRIx64")\n", + size, pos, pos); + return AVERROR_INVALIDDATA; + } + + /* big-endian ordening; build up number */ + *num = 0; + while (n++ < size) + *num = (*num << 8) | get_byte(pb); + + return 0; +} + +/* + * Read the next element as a signed int. + * 0 is success, < 0 is failure. + */ + +static int +ebml_read_sint (MatroskaDemuxContext *matroska, + uint32_t *id, + int64_t *num) +{ + ByteIOContext *pb = &matroska->ctx->pb; + int size, n = 1, negative = 0, res; + uint64_t rlength; + + if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 || + (res = ebml_read_element_length(matroska, &rlength)) < 0) + return res; + size = rlength; + if (size < 1 || size > 8) { + offset_t pos = url_ftell(pb); + av_log(matroska->ctx, AV_LOG_ERROR, + "Invalid sint element size %d at position %"PRId64" (0x%"PRIx64")\n", + size, pos, pos); + return AVERROR_INVALIDDATA; + } + if ((*num = get_byte(pb)) & 0x80) { + negative = 1; + *num &= ~0x80; + } + while (n++ < size) + *num = (*num << 8) | get_byte(pb); + + /* make signed */ + if (negative) + *num = *num - (1LL << ((8 * size) - 1)); + + return 0; +} + +/* + * Read the next element as a float. + * 0 is success, < 0 is failure. + */ + +static int +ebml_read_float (MatroskaDemuxContext *matroska, + uint32_t *id, + double *num) +{ + ByteIOContext *pb = &matroska->ctx->pb; + int size, res; + uint64_t rlength; + + if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 || + (res = ebml_read_element_length(matroska, &rlength)) < 0) + return res; + size = rlength; + + if (size == 4) { + *num= av_int2flt(get_be32(pb)); + } else if(size==8){ + *num= av_int2dbl(get_be64(pb)); + } else{ + offset_t pos = url_ftell(pb); + av_log(matroska->ctx, AV_LOG_ERROR, + "Invalid float element size %d at position %"PRIu64" (0x%"PRIx64")\n", + size, pos, pos); + return AVERROR_INVALIDDATA; + } + + return 0; +} + +/* + * Read the next element as an ASCII string. + * 0 is success, < 0 is failure. + */ + +static int +ebml_read_ascii (MatroskaDemuxContext *matroska, + uint32_t *id, + char **str) +{ + ByteIOContext *pb = &matroska->ctx->pb; + int size, res; + uint64_t rlength; + + if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 || + (res = ebml_read_element_length(matroska, &rlength)) < 0) + return res; + size = rlength; + + /* ebml strings are usually not 0-terminated, so we allocate one + * byte more, read the string and NULL-terminate it ourselves. */ + if (size < 0 || !(*str = av_malloc(size + 1))) { + av_log(matroska->ctx, AV_LOG_ERROR, "Memory allocation failed\n"); + return AVERROR_NOMEM; + } + if (get_buffer(pb, (uint8_t *) *str, size) != size) { + offset_t pos = url_ftell(pb); + av_log(matroska->ctx, AV_LOG_ERROR, + "Read error at pos. %"PRIu64" (0x%"PRIx64")\n", pos, pos); + return AVERROR_IO; + } + (*str)[size] = '\0'; + + return 0; +} + +/* + * Read the next element as a UTF-8 string. + * 0 is success, < 0 is failure. + */ + +static int +ebml_read_utf8 (MatroskaDemuxContext *matroska, + uint32_t *id, + char **str) +{ + return ebml_read_ascii(matroska, id, str); +} + +/* + * Read the next element as a date (nanoseconds since 1/1/2000). + * 0 is success, < 0 is failure. + */ + +static int +ebml_read_date (MatroskaDemuxContext *matroska, + uint32_t *id, + int64_t *date) +{ + return ebml_read_sint(matroska, id, date); +} + +/* + * Read the next element, but only the header. The contents + * are supposed to be sub-elements which can be read separately. + * 0 is success, < 0 is failure. + */ + +static int +ebml_read_master (MatroskaDemuxContext *matroska, + uint32_t *id) +{ + ByteIOContext *pb = &matroska->ctx->pb; + uint64_t length; + MatroskaLevel *level; + int res; + + if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 || + (res = ebml_read_element_length(matroska, &length)) < 0) + return res; + + /* protect... (Heaven forbids that the '>' is true) */ + if (matroska->num_levels >= EBML_MAX_DEPTH) { + av_log(matroska->ctx, AV_LOG_ERROR, + "File moves beyond max. allowed depth (%d)\n", EBML_MAX_DEPTH); + return AVERROR_NOTSUPP; + } + + /* remember level */ + level = &matroska->levels[matroska->num_levels++]; + level->start = url_ftell(pb); + level->length = length; + + return 0; +} + +/* + * Read the next element as binary data. + * 0 is success, < 0 is failure. + */ + +static int +ebml_read_binary (MatroskaDemuxContext *matroska, + uint32_t *id, + uint8_t **binary, + int *size) +{ + ByteIOContext *pb = &matroska->ctx->pb; + uint64_t rlength; + int res; + + if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 || + (res = ebml_read_element_length(matroska, &rlength)) < 0) + return res; + *size = rlength; + + if (!(*binary = av_malloc(*size))) { + av_log(matroska->ctx, AV_LOG_ERROR, + "Memory allocation error\n"); + return AVERROR_NOMEM; + } + + if (get_buffer(pb, *binary, *size) != *size) { + offset_t pos = url_ftell(pb); + av_log(matroska->ctx, AV_LOG_ERROR, + "Read error at pos. %"PRIu64" (0x%"PRIx64")\n", pos, pos); + return AVERROR_IO; + } + + return 0; +} + +/* + * Read signed/unsigned "EBML" numbers. + * Return: number of bytes processed, < 0 on error. + * XXX: use ebml_read_num(). + */ + +static int +matroska_ebmlnum_uint (uint8_t *data, + uint32_t size, + uint64_t *num) +{ + int len_mask = 0x80, read = 1, n = 1, num_ffs = 0; + uint64_t total; + + if (size <= 0) + return AVERROR_INVALIDDATA; + + total = data[0]; + while (read <= 8 && !(total & len_mask)) { + read++; + len_mask >>= 1; + } + if (read > 8) + return AVERROR_INVALIDDATA; + + if ((total &= (len_mask - 1)) == len_mask - 1) + num_ffs++; + if (size < read) + return AVERROR_INVALIDDATA; + while (n < read) { + if (data[n] == 0xff) + num_ffs++; + total = (total << 8) | data[n]; + n++; + } + + if (read == num_ffs) + *num = (uint64_t)-1; + else + *num = total; + + return read; +} + +/* + * Same as above, but signed. + */ + +static int +matroska_ebmlnum_sint (uint8_t *data, + uint32_t size, + int64_t *num) +{ + uint64_t unum; + int res; + + /* read as unsigned number first */ + if ((res = matroska_ebmlnum_uint(data, size, &unum)) < 0) + return res; + + /* make signed (weird way) */ + if (unum == (uint64_t)-1) + *num = INT64_MAX; + else + *num = unum - ((1LL << ((7 * res) - 1)) - 1); + + return res; +} + +/* + * Read an EBML header. + * 0 is success, < 0 is failure. + */ + +static int +ebml_read_header (MatroskaDemuxContext *matroska, + char **doctype, + int *version) +{ + uint32_t id; + int level_up, res = 0; + + /* default init */ + if (doctype) + *doctype = NULL; + if (version) + *version = 1; + + if (!(id = ebml_peek_id(matroska, &level_up)) || + level_up != 0 || id != EBML_ID_HEADER) { + av_log(matroska->ctx, AV_LOG_ERROR, + "This is not an EBML file (id=0x%x/0x%x)\n", id, EBML_ID_HEADER); + return AVERROR_INVALIDDATA; + } + if ((res = ebml_read_master(matroska, &id)) < 0) + return res; + + while (res == 0) { + if (!(id = ebml_peek_id(matroska, &level_up))) + return AVERROR_IO; + + /* end-of-header */ + if (level_up) + break; + + switch (id) { + /* is our read version uptodate? */ + case EBML_ID_EBMLREADVERSION: { + uint64_t num; + + if ((res = ebml_read_uint(matroska, &id, &num)) < 0) + return res; + if (num > EBML_VERSION) { + av_log(matroska->ctx, AV_LOG_ERROR, + "EBML version %"PRIu64" (> %d) is not supported\n", + num, EBML_VERSION); + return AVERROR_INVALIDDATA; + } + break; + } + + /* we only handle 8 byte lengths at max */ + case EBML_ID_EBMLMAXSIZELENGTH: { + uint64_t num; + + if ((res = ebml_read_uint(matroska, &id, &num)) < 0) + return res; + if (num > sizeof(uint64_t)) { + av_log(matroska->ctx, AV_LOG_ERROR, + "Integers of size %"PRIu64" (> %zd) not supported\n", + num, sizeof(uint64_t)); + return AVERROR_INVALIDDATA; + } + break; + } + + /* we handle 4 byte IDs at max */ + case EBML_ID_EBMLMAXIDLENGTH: { + uint64_t num; + + if ((res = ebml_read_uint(matroska, &id, &num)) < 0) + return res; + if (num > sizeof(uint32_t)) { + av_log(matroska->ctx, AV_LOG_ERROR, + "IDs of size %"PRIu64" (> %zu) not supported\n", + num, sizeof(uint32_t)); + return AVERROR_INVALIDDATA; + } + break; + } + + case EBML_ID_DOCTYPE: { + char *text; + + if ((res = ebml_read_ascii(matroska, &id, &text)) < 0) + return res; + if (doctype) { + if (*doctype) + av_free(*doctype); + *doctype = text; + } else + av_free(text); + break; + } + + case EBML_ID_DOCTYPEREADVERSION: { + uint64_t num; + + if ((res = ebml_read_uint(matroska, &id, &num)) < 0) + return res; + if (version) + *version = num; + break; + } + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown data type 0x%x in EBML header", id); + /* pass-through */ + + case EBML_ID_VOID: + /* we ignore these two, as they don't tell us anything we + * care about */ + case EBML_ID_EBMLVERSION: + case EBML_ID_DOCTYPEVERSION: + res = ebml_read_skip (matroska); + break; + } + } + + 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. + */ + +static int +matroska_deliver_packet (MatroskaDemuxContext *matroska, + AVPacket *pkt) +{ + if (matroska->num_packets > 0) { + memcpy(pkt, matroska->packets[0], sizeof(AVPacket)); + av_free(matroska->packets[0]); + if (matroska->num_packets > 1) { + memmove(&matroska->packets[0], &matroska->packets[1], + (matroska->num_packets - 1) * sizeof(AVPacket *)); + matroska->packets = + av_realloc(matroska->packets, (matroska->num_packets - 1) * + sizeof(AVPacket *)); + } else { + av_freep(&matroska->packets); + } + matroska->num_packets--; + return 0; + } + + return -1; +} + +/* + * Put a packet into our internal queue. Will be delivered to the + * user/application during the next get_packet() call. + */ + +static void +matroska_queue_packet (MatroskaDemuxContext *matroska, + AVPacket *pkt) +{ + matroska->packets = + av_realloc(matroska->packets, (matroska->num_packets + 1) * + sizeof(AVPacket *)); + matroska->packets[matroska->num_packets] = pkt; + matroska->num_packets++; +} + + +/* + * Autodetecting... + */ + +static int +matroska_probe (AVProbeData *p) +{ + uint64_t total = 0; + int len_mask = 0x80, size = 1, n = 1; + uint8_t probe_data[] = { 'm', 'a', 't', 'r', 'o', 's', 'k', 'a' }; + + /* ebml header? */ + if ((p->buf[0] << 24 | p->buf[1] << 16 | + p->buf[2] << 8 | p->buf[3]) != EBML_ID_HEADER) + return 0; + + /* length of header */ + total = p->buf[4]; + while (size <= 8 && !(total & len_mask)) { + size++; + len_mask >>= 1; + } + if (size > 8) + return 0; + total &= (len_mask - 1); + 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; + + /* the header must contain the document type 'matroska'. For now, + * we don't parse the whole header but simply check for the + * availability of that array of characters inside the header. + * Not fully fool-proof, but good enough. */ + 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; + + return 0; +} + +/* + * From here on, it's all XML-style DTD stuff... Needs no comments. + */ + +static int +matroska_parse_info (MatroskaDemuxContext *matroska) +{ + int res = 0; + uint32_t id; + + av_log(matroska->ctx, AV_LOG_DEBUG, "Parsing info...\n"); + + 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; + } + + switch (id) { + /* cluster timecode */ + case MATROSKA_ID_TIMECODESCALE: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, &num)) < 0) + break; + matroska->time_scale = num; + break; + } + + case MATROSKA_ID_DURATION: { + double num; + if ((res = ebml_read_float(matroska, &id, &num)) < 0) + break; + matroska->ctx->duration = num * matroska->time_scale * 1000 / AV_TIME_BASE; + 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) + break; + matroska->writing_app = text; + break; + } + + case MATROSKA_ID_MUXINGAPP: { + char *text; + if ((res = ebml_read_utf8(matroska, &id, &text)) < 0) + break; + matroska->muxing_app = text; + break; + } + + case MATROSKA_ID_DATEUTC: { + int64_t time; + if ((res = ebml_read_date(matroska, &id, &time)) < 0) + break; + matroska->created = time; + break; + } + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown entry 0x%x in info header\n", id); + /* fall-through */ + + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + return res; +} + +static int +matroska_add_stream (MatroskaDemuxContext *matroska) +{ + int res = 0; + uint32_t id; + MatroskaTrack *track; + + 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(MAX_TRACK_SIZE); + matroska->num_tracks++; + + /* start with the master */ + if ((res = ebml_read_master(matroska, &id)) < 0) + return res; + + /* try reading the trackentry headers */ + while (res == 0) { + if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { + res = AVERROR_IO; + break; + } else if (matroska->level_up > 0) { + matroska->level_up--; + break; + } + + switch (id) { + /* track number (unique stream ID) */ + case MATROSKA_ID_TRACKNUMBER: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, &num)) < 0) + break; + track->num = num; + break; + } + + /* track UID (unique identifier) */ + case MATROSKA_ID_TRACKUID: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, &num)) < 0) + break; + track->uid = num; + break; + } + + /* track type (video, audio, combined, subtitle, etc.) */ + case MATROSKA_ID_TRACKTYPE: { + uint64_t num; + 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; + } + track->type = num; + + switch (track->type) { + case MATROSKA_TRACK_TYPE_VIDEO: + case MATROSKA_TRACK_TYPE_AUDIO: + case MATROSKA_TRACK_TYPE_SUBTITLE: + break; + case MATROSKA_TRACK_TYPE_COMPLEX: + case MATROSKA_TRACK_TYPE_LOGO: + case MATROSKA_TRACK_TYPE_CONTROL: + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown or unsupported track type 0x%x\n", + track->type); + track->type = 0; + break; + } + matroska->tracks[matroska->num_tracks - 1] = track; + break; + } + + /* 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"); + res = AVERROR_INVALIDDATA; + break; + } else if ((res = ebml_read_master(matroska, &id)) < 0) + break; + videotrack = (MatroskaVideoTrack *)track; + + while (res == 0) { + if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { + res = AVERROR_IO; + break; + } else if (matroska->level_up > 0) { + matroska->level_up--; + break; + } + + switch (id) { + /* fixme, this should be one-up, but I get it here */ + case MATROSKA_ID_TRACKDEFAULTDURATION: { + uint64_t num; + if ((res = ebml_read_uint (matroska, &id, + &num)) < 0) + break; + track->default_duration = num/matroska->time_scale; + break; + } + + /* video framerate */ + case MATROSKA_ID_VIDEOFRAMERATE: { + double num; + if ((res = ebml_read_float(matroska, &id, + &num)) < 0) + break; + track->default_duration = 1000000000/(matroska->time_scale*num); + break; + } + + /* width of the size to display the video at */ + case MATROSKA_ID_VIDEODISPLAYWIDTH: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, + &num)) < 0) + break; + videotrack->display_width = num; + break; + } + + /* height of the size to display the video at */ + case MATROSKA_ID_VIDEODISPLAYHEIGHT: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, + &num)) < 0) + break; + videotrack->display_height = num; + break; + } + + /* width of the video in the file */ + case MATROSKA_ID_VIDEOPIXELWIDTH: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, + &num)) < 0) + break; + videotrack->pixel_width = num; + break; + } + + /* height of the video in the file */ + case MATROSKA_ID_VIDEOPIXELHEIGHT: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, + &num)) < 0) + break; + videotrack->pixel_height = num; + break; + } + + /* whether the video is interlaced */ + case MATROSKA_ID_VIDEOFLAGINTERLACED: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, + &num)) < 0) + break; + if (num) + track->flags |= + MATROSKA_VIDEOTRACK_INTERLACED; + else + track->flags &= + ~MATROSKA_VIDEOTRACK_INTERLACED; + break; + } + + /* stereo mode (whether the video has two streams, + * where one is for the left eye and the other for + * the right eye, which creates a 3D-like + * effect) */ + case MATROSKA_ID_VIDEOSTEREOMODE: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, + &num)) < 0) + break; + if (num != MATROSKA_EYE_MODE_MONO && + num != MATROSKA_EYE_MODE_LEFT && + num != MATROSKA_EYE_MODE_RIGHT && + num != MATROSKA_EYE_MODE_BOTH) { + av_log(matroska->ctx, AV_LOG_INFO, + "Ignoring unknown eye mode 0x%x\n", + (uint32_t) num); + break; + } + videotrack->eye_mode = num; + break; + } + + /* aspect ratio behaviour */ + case MATROSKA_ID_VIDEOASPECTRATIO: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, + &num)) < 0) + break; + if (num != MATROSKA_ASPECT_RATIO_MODE_FREE && + num != MATROSKA_ASPECT_RATIO_MODE_KEEP && + num != MATROSKA_ASPECT_RATIO_MODE_FIXED) { + av_log(matroska->ctx, AV_LOG_INFO, + "Ignoring unknown aspect ratio 0x%x\n", + (uint32_t) num); + break; + } + videotrack->ar_mode = num; + break; + } + + /* colourspace (only matters for raw video) + * fourcc */ + case MATROSKA_ID_VIDEOCOLOURSPACE: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, + &num)) < 0) + break; + videotrack->fourcc = num; + break; + } + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown video track header entry " + "0x%x - ignoring\n", id); + /* pass-through */ + + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + break; + } + + /* 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"); + res = AVERROR_INVALIDDATA; + break; + } 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))) { + res = AVERROR_IO; + break; + } else if (matroska->level_up > 0) { + matroska->level_up--; + break; + } + + 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) + break; + audiotrack->samplerate = num; + break; + } + + /* bitdepth */ + case MATROSKA_ID_AUDIOBITDEPTH: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, + &num)) < 0) + break; + audiotrack->bitdepth = num; + break; + } + + /* channels */ + case MATROSKA_ID_AUDIOCHANNELS: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, + &num)) < 0) + break; + audiotrack->channels = num; + break; + } + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown audio track header entry " + "0x%x - ignoring\n", id); + /* pass-through */ + + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + break; + } + + /* codec identifier */ + case MATROSKA_ID_CODECID: { + char *text; + if ((res = ebml_read_ascii(matroska, &id, &text)) < 0) + break; + track->codec_id = text; + break; + } + + /* codec private data */ + case MATROSKA_ID_CODECPRIVATE: { + uint8_t *data; + int size; + if ((res = ebml_read_binary(matroska, &id, &data, &size) < 0)) + break; + track->codec_priv = data; + track->codec_priv_size = size; + break; + } + + /* name of the codec */ + case MATROSKA_ID_CODECNAME: { + char *text; + if ((res = ebml_read_utf8(matroska, &id, &text)) < 0) + break; + track->codec_name = text; + break; + } + + /* name of this track */ + case MATROSKA_ID_TRACKNAME: { + char *text; + if ((res = ebml_read_utf8(matroska, &id, &text)) < 0) + break; + track->name = text; + break; + } + + /* language (matters for audio/subtitles, mostly) */ + case MATROSKA_ID_TRACKLANGUAGE: { + char *text; + if ((res = ebml_read_utf8(matroska, &id, &text)) < 0) + break; + track->language = text; + break; + } + + /* whether this is actually used */ + case MATROSKA_ID_TRACKFLAGENABLED: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, &num)) < 0) + break; + if (num) + track->flags |= MATROSKA_TRACK_ENABLED; + else + track->flags &= ~MATROSKA_TRACK_ENABLED; + break; + } + + /* whether it's the default for this track type */ + case MATROSKA_ID_TRACKFLAGDEFAULT: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, &num)) < 0) + break; + if (num) + track->flags |= MATROSKA_TRACK_DEFAULT; + else + track->flags &= ~MATROSKA_TRACK_DEFAULT; + break; + } + + /* lacing (like MPEG, where blocks don't end/start on frame + * boundaries) */ + case MATROSKA_ID_TRACKFLAGLACING: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, &num)) < 0) + break; + if (num) + track->flags |= MATROSKA_TRACK_LACING; + else + track->flags &= ~MATROSKA_TRACK_LACING; + break; + } + + /* default length (in time) of one data block in this track */ + case MATROSKA_ID_TRACKDEFAULTDURATION: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, &num)) < 0) + break; + track->default_duration = num / matroska->time_scale; + break; + } + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown track header entry 0x%x - ignoring\n", id); + /* pass-through */ + + case EBML_ID_VOID: + /* we ignore these because they're nothing useful. */ + case MATROSKA_ID_CODECINFOURL: + case MATROSKA_ID_CODECDOWNLOADURL: + case MATROSKA_ID_TRACKMINCACHE: + case MATROSKA_ID_TRACKMAXCACHE: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + return res; +} + +static int +matroska_parse_tracks (MatroskaDemuxContext *matroska) +{ + int res = 0; + uint32_t id; + + av_log(matroska->ctx, AV_LOG_DEBUG, "parsing tracks...\n"); + + 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; + } + + switch (id) { + /* one track within the "all-tracks" header */ + case MATROSKA_ID_TRACKENTRY: + res = matroska_add_stream(matroska); + break; + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown entry 0x%x in track header\n", id); + /* fall-through */ + + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + return res; +} + +static int +matroska_parse_index (MatroskaDemuxContext *matroska) +{ + int res = 0; + uint32_t id; + MatroskaDemuxIndex idx; + + av_log(matroska->ctx, AV_LOG_DEBUG, "parsing index...\n"); + + 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; + } + + switch (id) { + /* one single index entry ('point') */ + case MATROSKA_ID_POINTENTRY: + if ((res = ebml_read_master(matroska, &id)) < 0) + break; + + /* in the end, we hope to fill one entry with a + * timestamp, a file position and a tracknum */ + idx.pos = (uint64_t) -1; + idx.time = (uint64_t) -1; + idx.track = (uint16_t) -1; + + 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; + } + + switch (id) { + /* one single index entry ('point') */ + case MATROSKA_ID_CUETIME: { + uint64_t time; + if ((res = ebml_read_uint(matroska, &id, + &time)) < 0) + break; + idx.time = time * matroska->time_scale; + break; + } + + /* position in the file + track to which it + * belongs */ + case MATROSKA_ID_CUETRACKPOSITION: + if ((res = ebml_read_master(matroska, &id)) < 0) + break; + + 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; + } + + switch (id) { + /* track number */ + case MATROSKA_ID_CUETRACK: { + uint64_t num; + if ((res = ebml_read_uint(matroska, + &id, &num)) < 0) + break; + idx.track = num; + break; + } + + /* position in file */ + case MATROSKA_ID_CUECLUSTERPOSITION: { + uint64_t num; + if ((res = ebml_read_uint(matroska, + &id, &num)) < 0) + break; + idx.pos = num+matroska->segment_start; + break; + } + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown entry 0x%x in " + "CuesTrackPositions\n", id); + /* fall-through */ + + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + break; + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown entry 0x%x in cuespoint " + "index\n", id); + /* fall-through */ + + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + /* so let's see if we got what we wanted */ + if (idx.pos != (uint64_t) -1 && + idx.time != (uint64_t) -1 && + idx.track != (uint16_t) -1) { + if (matroska->num_indexes % 32 == 0) { + /* re-allocate bigger index */ + matroska->index = + av_realloc(matroska->index, + (matroska->num_indexes + 32) * + sizeof(MatroskaDemuxIndex)); + } + matroska->index[matroska->num_indexes] = idx; + matroska->num_indexes++; + } + break; + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown entry 0x%x in cues header\n", id); + /* fall-through */ + + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + return res; +} + +static int +matroska_parse_metadata (MatroskaDemuxContext *matroska) +{ + int res = 0; + uint32_t id; + + 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; + } + + switch (id) { + /* Hm, this is unsupported... */ + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown entry 0x%x in metadata header\n", id); + /* fall-through */ + + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + return res; +} + +static int +matroska_parse_seekhead (MatroskaDemuxContext *matroska) +{ + int res = 0; + uint32_t id; + + av_log(matroska->ctx, AV_LOG_DEBUG, "parsing seekhead...\n"); + + 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; + } + + switch (id) { + case MATROSKA_ID_SEEKENTRY: { + uint32_t seek_id = 0, peek_id_cache = 0; + uint64_t seek_pos = (uint64_t) -1, t; + + if ((res = ebml_read_master(matroska, &id)) < 0) + break; + + 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; + } + + switch (id) { + case MATROSKA_ID_SEEKID: + res = ebml_read_uint(matroska, &id, &t); + seek_id = t; + break; + + case MATROSKA_ID_SEEKPOSITION: + res = ebml_read_uint(matroska, &id, &seek_pos); + break; + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown seekhead ID 0x%x\n", id); + /* fall-through */ + + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + if (!seek_id || seek_pos == (uint64_t) -1) { + av_log(matroska->ctx, AV_LOG_INFO, + "Incomplete seekhead entry (0x%x/%"PRIu64")\n", + seek_id, seek_pos); + break; + } + + switch (seek_id) { + case MATROSKA_ID_CUES: + case MATROSKA_ID_TAGS: { + uint32_t level_up = matroska->level_up; + offset_t before_pos; + uint64_t length; + MatroskaLevel level; + + /* remember the peeked ID and the current position */ + peek_id_cache = matroska->peek_id; + before_pos = url_ftell(&matroska->ctx->pb); + + /* seek */ + if ((res = ebml_read_seek(matroska, seek_pos + + matroska->segment_start)) < 0) + return res; + + /* we don't want to lose our seekhead level, so we add + * a dummy. This is a crude hack. */ + if (matroska->num_levels == EBML_MAX_DEPTH) { + av_log(matroska->ctx, AV_LOG_INFO, + "Max EBML element depth (%d) reached, " + "cannot parse further.\n", EBML_MAX_DEPTH); + return AVERROR_UNKNOWN; + } + + level.start = 0; + level.length = (uint64_t)-1; + matroska->levels[matroska->num_levels] = level; + matroska->num_levels++; + + /* check ID */ + if (!(id = ebml_peek_id (matroska, + &matroska->level_up))) + goto finish; + if (id != seek_id) { + av_log(matroska->ctx, AV_LOG_INFO, + "We looked for ID=0x%x but got " + "ID=0x%x (pos=%"PRIu64")", + seek_id, id, seek_pos + + matroska->segment_start); + goto finish; + } + + /* read master + parse */ + if ((res = ebml_read_master(matroska, &id)) < 0) + goto finish; + switch (id) { + case MATROSKA_ID_CUES: + if (!(res = matroska_parse_index(matroska)) || + url_feof(&matroska->ctx->pb)) { + matroska->index_parsed = 1; + res = 0; + } + break; + case MATROSKA_ID_TAGS: + if (!(res = matroska_parse_metadata(matroska)) || + url_feof(&matroska->ctx->pb)) { + matroska->metadata_parsed = 1; + res = 0; + } + break; + } + + finish: + /* remove dummy level */ + while (matroska->num_levels) { + matroska->num_levels--; + length = + matroska->levels[matroska->num_levels].length; + if (length == (uint64_t)-1) + break; + } + + /* seek back */ + if ((res = ebml_read_seek(matroska, before_pos)) < 0) + return res; + matroska->peek_id = peek_id_cache; + matroska->level_up = level_up; + break; + } + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Ignoring seekhead entry for ID=0x%x\n", + seek_id); + break; + } + + break; + } + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown seekhead ID 0x%x\n", id); + /* fall-through */ + + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + 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<ARRAY_SIZE(aac_profiles); profile++) + if (strstr(codec_id, aac_profiles[profile])) + break; + return profile + 1; +} + +static int +matroska_aac_sri (int samplerate) +{ + static const int aac_sample_rates[] = { + 96000, 88200, 64000, 48000, 44100, 32000, + 24000, 22050, 16000, 12000, 11025, 8000, + }; + int sri; + + for (sri=0; sri<ARRAY_SIZE(aac_sample_rates); sri++) + if (aac_sample_rates[sri] == samplerate) + break; + return sri; +} + +static int +matroska_read_header (AVFormatContext *s, + AVFormatParameters *ap) +{ + MatroskaDemuxContext *matroska = s->priv_data; + char *doctype; + int version, last_level, res = 0; + uint32_t id; + + matroska->ctx = s; + + /* First read the EBML header. */ + doctype = NULL; + if ((res = ebml_read_header(matroska, &doctype, &version)) < 0) + return res; + if ((doctype == NULL) || strcmp(doctype, "matroska")) { + av_log(matroska->ctx, AV_LOG_ERROR, + "Wrong EBML doctype ('%s' != 'matroska').\n", + doctype ? doctype : "(none)"); + if (doctype) + av_free(doctype); + return AVERROR_NOFMT; + } + av_free(doctype); + if (version > 2) { + av_log(matroska->ctx, AV_LOG_ERROR, + "Matroska demuxer version 2 too old for file version %d\n", + version); + return AVERROR_NOFMT; + } + + /* The next thing is a segment. */ + while (1) { + if (!(id = ebml_peek_id(matroska, &last_level))) + return AVERROR_IO; + if (id == MATROSKA_ID_SEGMENT) + break; + + /* oi! */ + av_log(matroska->ctx, AV_LOG_INFO, + "Expected a Segment ID (0x%x), but received 0x%x!\n", + MATROSKA_ID_SEGMENT, id); + if ((res = ebml_read_skip(matroska)) < 0) + return res; + } + + /* We now have a Matroska segment. + * Seeks are from the beginning of the segment, + * after the segment ID/length. */ + if ((res = ebml_read_master(matroska, &id)) < 0) + return res; + matroska->segment_start = url_ftell(&s->pb); + + matroska->time_scale = 1000000; + /* we've found our segment, start reading the different contents in here */ + 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; + } + + switch (id) { + /* stream info */ + case MATROSKA_ID_INFO: { + if ((res = ebml_read_master(matroska, &id)) < 0) + break; + res = matroska_parse_info(matroska); + break; + } + + /* track info headers */ + case MATROSKA_ID_TRACKS: { + if ((res = ebml_read_master(matroska, &id)) < 0) + break; + res = matroska_parse_tracks(matroska); + break; + } + + /* stream index */ + case MATROSKA_ID_CUES: { + if (!matroska->index_parsed) { + if ((res = ebml_read_master(matroska, &id)) < 0) + break; + res = matroska_parse_index(matroska); + } else + res = ebml_read_skip(matroska); + break; + } + + /* metadata */ + case MATROSKA_ID_TAGS: { + if (!matroska->metadata_parsed) { + if ((res = ebml_read_master(matroska, &id)) < 0) + break; + res = matroska_parse_metadata(matroska); + } else + res = ebml_read_skip(matroska); + break; + } + + /* file index (if seekable, seek to Cues/Tags to parse it) */ + case MATROSKA_ID_SEEKHEAD: { + if ((res = ebml_read_master(matroska, &id)) < 0) + break; + res = matroska_parse_seekhead(matroska); + break; + } + + case MATROSKA_ID_CLUSTER: { + /* Do not read the master - this will be done in the next + * call to matroska_read_packet. */ + res = 1; + break; + } + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown matroska file header ID 0x%x\n", id); + /* fall-through */ + + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + /* Have we found a cluster? */ + if (ebml_peek_id(matroska, NULL) == MATROSKA_ID_CLUSTER) { + int i, j; + MatroskaTrack *track; + AVStream *st; + + for (i = 0; i < matroska->num_tracks; i++) { + 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. + * Also apply some sanity checks. */ + if ((track->type == MATROSKA_TRACK_TYPE_SUBTITLE) || + (track->codec_id == NULL)) + continue; + + for(j=0; ff_mkv_codec_tags[j].str; j++){ + if(!strncmp(ff_mkv_codec_tags[j].str, track->codec_id, + strlen(ff_mkv_codec_tags[j].str))){ + codec_id= ff_mkv_codec_tags[j].id; + break; + } + } + + /* Set the FourCC from the CodecID. */ + /* This is the MS compatibility mode which stores a + * BITMAPINFOHEADER in the CodecPrivate. */ + if (!strcmp(track->codec_id, + MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC) && + (track->codec_priv_size >= 40) && + (track->codec_priv != NULL)) { + unsigned char *p; + + /* Offset of biCompression. Stored in LE. */ + 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_id(codec_bmp_tags, ((MatroskaVideoTrack *)track)->fourcc); + + } + + /* This is the MS compatibility mode which stores a + * WAVEFORMATEX in the CodecPrivate. */ + else if (!strcmp(track->codec_id, + MATROSKA_CODEC_ID_AUDIO_ACM) && + (track->codec_priv_size >= 18) && + (track->codec_priv != NULL)) { + unsigned char *p; + uint16_t tag; + + /* Offset of wFormatTag. Stored in LE. */ + p = (unsigned char *)track->codec_priv; + tag = (p[1] << 8) | p[0]; + 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) { + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown/unsupported CodecID %s.\n", + track->codec_id); + } + + track->stream_index = matroska->num_streams; + + matroska->num_streams++; + st = av_new_stream(s, track->stream_index); + if (st == NULL) + return AVERROR_NOMEM; + 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; + st->codec->extradata_size = extradata_size; + } else if(track->codec_priv && track->codec_priv_size > 0){ + st->codec->extradata = av_malloc(track->codec_priv_size); + if(st->codec->extradata == NULL) + return AVERROR_NOMEM; + st->codec->extradata_size = track->codec_priv_size; + memcpy(st->codec->extradata,track->codec_priv+extradata_offset, + track->codec_priv_size); + } + + if (track->type == MATROSKA_TRACK_TYPE_VIDEO) { + MatroskaVideoTrack *videotrack = (MatroskaVideoTrack *)track; + + st->codec->codec_type = CODEC_TYPE_VIDEO; + st->codec->codec_tag = videotrack->fourcc; + st->codec->width = videotrack->pixel_width; + st->codec->height = videotrack->pixel_height; + if (videotrack->display_width == 0) + videotrack->display_width= videotrack->pixel_width; + if (videotrack->display_height == 0) + videotrack->display_height= videotrack->pixel_height; + av_reduce(&st->codec->sample_aspect_ratio.num, + &st->codec->sample_aspect_ratio.den, + 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; + + st->codec->codec_type = CODEC_TYPE_AUDIO; + st->codec->sample_rate = audiotrack->samplerate; + st->codec->channels = audiotrack->channels; + } else if (track->type == MATROSKA_TRACK_TYPE_SUBTITLE) { + st->codec->codec_type = CODEC_TYPE_SUBTITLE; + } + + /* What do we do with private data? E.g. for Vorbis. */ + } + res = 0; + } + + if (matroska->index_parsed) { + int i, track, stream; + for (i=0; i<matroska->num_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_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 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; + + /* 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; + } + + 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; slice<slices; slice++) { + int slice_size, slice_offset = 0; + if (real_v) + slice_offset = rv_offset(data, slice, slices); + if (slice+1 == slices) + slice_size = lace_size[n] - slice_offset; + else + slice_size = rv_offset(data, slice+1, slices) - slice_offset; + pkt = av_mallocz(sizeof(AVPacket)); + /* XXX: prevent data copy... */ + if (av_new_packet(pkt, slice_size) < 0) { + res = AVERROR_NOMEM; + n = laces-1; + break; + } + memcpy (pkt->data, 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 +matroska_parse_blockgroup (MatroskaDemuxContext *matroska, + uint64_t cluster_time) +{ + int res = 0; + uint32_t id; + 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"); + + 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; + } + + switch (id) { + /* one block inside the group. Note, block parsing is one + * of the harder things, so this code is a bit complicated. + * See http://www.matroska.org/ for documentation. */ + case MATROSKA_ID_BLOCK: { + pos = url_ftell(&matroska->ctx->pb); + res = ebml_read_binary(matroska, &id, &data, &size); + break; + } + + case MATROSKA_ID_BLOCKDURATION: { + if ((res = ebml_read_uint(matroska, &id, &duration)) < 0) + break; + duration /= matroska->time_scale; + break; + } + + 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; + 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, + "Unknown entry 0x%x in blockgroup data\n", id); + /* fall-through */ + + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + if (res) + return res; + + if (size > 0) + res = matroska_parse_block(matroska, data, size, pos, cluster_time, + duration, is_keyframe, is_bframe); + + return res; +} + +static int +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)); + + 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; + } + + switch (id) { + /* cluster timecode */ + case MATROSKA_ID_CLUSTERTIMECODE: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, &num)) < 0) + break; + cluster_time = num; + break; + } + + /* a group of blocks inside a cluster */ + case MATROSKA_ID_BLOCKGROUP: + if ((res = ebml_read_master(matroska, &id)) < 0) + break; + 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); + /* fall-through */ + + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + return res; +} + +static int +matroska_read_packet (AVFormatContext *s, + AVPacket *pkt) +{ + MatroskaDemuxContext *matroska = s->priv_data; + int res = 0; + uint32_t id; + + /* 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; + + 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) + 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); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + 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; + + /* 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 +matroska_read_close (AVFormatContext *s) +{ + MatroskaDemuxContext *matroska = s->priv_data; + int n = 0; + + 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++) { + av_free_packet(matroska->packets[n]); + av_free(matroska->packets[n]); + } + av_free(matroska->packets); + } + + for (n = 0; n < matroska->num_tracks; n++) { + MatroskaTrack *track = matroska->tracks[n]; + 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); + } + + return 0; +} + +AVInputFormat matroska_demuxer = { + "matroska", + "Matroska file format", + sizeof(MatroskaDemuxContext), + matroska_probe, + matroska_read_header, + matroska_read_packet, + matroska_read_close, + matroska_read_seek, +};