* Matroska file demuxer (no muxer yet)
* Copyright (c) 2003-2004 The ffmpeg Project
*
- * This library is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
- * This library is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
*/
#include "avformat.h"
-/* For codec_get_bmp_id and codec_get_wav_id. */
-#include "avi.h"
+/* For codec_get_id(). */
+#include "riff.h"
+#include "intfloat_readwrite.h"
/* EBML version supported */
#define EBML_VERSION 1
/* 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
/* 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
/* 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
MATROSKA_TRACK_ENABLED = (1<<0),
MATROSKA_TRACK_DEFAULT = (1<<1),
MATROSKA_TRACK_LACING = (1<<2),
+ MATROSKA_TRACK_REAL_V = (1<<4),
+ MATROSKA_TRACK_REORDER = (1<<8),
MATROSKA_TRACK_SHIFT = (1<<16)
} MatroskaTrackFlags;
* 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_VIDEO_UNCOMPRESSED "V_UNCOMPRESSED"
-#define MATROSKA_CODEC_ID_VIDEO_MPEG4_SP "V_MPEG4/ISO/SP"
-#define MATROSKA_CODEC_ID_VIDEO_MPEG4_ASP "V_MPEG4/ISO/ASP"
-#define MATROSKA_CODEC_ID_VIDEO_MPEG4_AP "V_MPEG4/ISO/AP"
-#define MATROSKA_CODEC_ID_VIDEO_MPEG4_AVC "V_MPEG4/ISO/AVC"
-#define MATROSKA_CODEC_ID_VIDEO_MSMPEG4V3 "V_MPEG4/MS/V3"
-#define MATROSKA_CODEC_ID_VIDEO_MPEG1 "V_MPEG1"
-#define MATROSKA_CODEC_ID_VIDEO_MPEG2 "V_MPEG2"
-#define MATROSKA_CODEC_ID_VIDEO_MJPEG "V_MJPEG"
+#define MATROSKA_CODEC_ID_AUDIO_ACM "A_MS/ACM"
+
+static CodecTags codec_tags[]={
+// {"V_MS/VFW/FOURCC" , CODEC_ID_NONE},
+ {"V_UNCOMPRESSED" , CODEC_ID_RAWVIDEO},
+ {"V_MPEG4/ISO/SP" , CODEC_ID_MPEG4},
+ {"V_MPEG4/ISO/ASP" , CODEC_ID_MPEG4},
+ {"V_MPEG4/ISO/AP" , CODEC_ID_MPEG4},
+ {"V_MPEG4/ISO/AVC" , CODEC_ID_H264},
+ {"V_MPEG4/MS/V3" , CODEC_ID_MSMPEG4V3},
+ {"V_MPEG1" , CODEC_ID_MPEG1VIDEO},
+ {"V_MPEG2" , CODEC_ID_MPEG2VIDEO},
+ {"V_MJPEG" , CODEC_ID_MJPEG},
+ {"V_REAL/RV10" , CODEC_ID_RV10},
+ {"V_REAL/RV20" , CODEC_ID_RV20},
+ {"V_REAL/RV30" , CODEC_ID_RV30},
+ {"V_REAL/RV40" , CODEC_ID_RV40},
+ {"V_THEORA" , CODEC_ID_THEORA},
/* TODO: Real/Quicktime */
-#define MATROSKA_CODEC_ID_AUDIO_ACM "A_MS/ACM"
-#define MATROSKA_CODEC_ID_AUDIO_MPEG1_L1 "A_MPEG/L1"
-#define MATROSKA_CODEC_ID_AUDIO_MPEG1_L2 "A_MPEG/L2"
-#define MATROSKA_CODEC_ID_AUDIO_MPEG1_L3 "A_MPEG/L3"
-#define MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE "A_PCM/INT/BIG"
-#define MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE "A_PCM/INT/LIT"
-#define MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT "A_PCM/FLOAT/IEEE"
-#define MATROSKA_CODEC_ID_AUDIO_AC3 "A_AC3"
-#define MATROSKA_CODEC_ID_AUDIO_DTS "A_DTS"
-#define MATROSKA_CODEC_ID_AUDIO_VORBIS "A_VORBIS"
-#define MATROSKA_CODEC_ID_AUDIO_ACM "A_MS/ACM"
-#define MATROSKA_CODEC_ID_AUDIO_MPEG2 "A_AAC/MPEG2/"
-#define MATROSKA_CODEC_ID_AUDIO_MPEG4 "A_AAC/MPEG4/"
+// {"A_MS/ACM" , CODEC_ID_NONE},
+ {"A_MPEG/L1" , CODEC_ID_MP3},
+ {"A_MPEG/L2" , CODEC_ID_MP3},
+ {"A_MPEG/L3" , CODEC_ID_MP3},
+ {"A_PCM/INT/BIG" , CODEC_ID_PCM_U16BE},
+ {"A_PCM/INT/LIT" , CODEC_ID_PCM_U16LE},
+// {"A_PCM/FLOAT/IEEE" , CODEC_ID_NONE},
+ {"A_AC3" , CODEC_ID_AC3},
+ {"A_DTS" , CODEC_ID_DTS},
+ {"A_VORBIS" , CODEC_ID_VORBIS},
+ {"A_AAC" , CODEC_ID_AAC},
+ {"A_FLAC" , CODEC_ID_FLAC},
+ {"A_WAVPACK4" , CODEC_ID_WAVPACK},
+ {"A_TTA1" , CODEC_ID_TTA},
+ {NULL , CODEC_ID_NONE}
/* TODO: AC3-9/10 (?), Real, Musepack, Quicktime */
+};
/* max. depth in the EBML tree structure */
#define EBML_MAX_DEPTH 16
unsigned char *codec_priv;
int codec_priv_size;
- int64_t default_duration;
+ uint64_t default_duration;
MatroskaTrackFlags flags;
} MatroskaTrack;
int channels,
bitdepth,
+ internal_samplerate,
samplerate;
//..
} MatroskaAudioTrack;
//..
} MatroskaSubtitleTrack;
+#define MAX_TRACK_SIZE (FFMAX(FFMAX(sizeof(MatroskaVideoTrack), \
+ sizeof(MatroskaAudioTrack)), \
+ sizeof(MatroskaSubtitleTrack)))
+
typedef struct MatroskaLevel {
uint64_t start, length;
} MatroskaLevel;
/* timescale in the file */
int64_t time_scale;
- /* length, position (time, ns) */
- int64_t duration,
- pos;
+ /* position (time, ns) */
+ int64_t pos;
/* num_streams is the number of streams that av_new_stream() was called
* for ( = that are available to the calling program). */
/* The packet queue. */
AVPacket **packets;
int num_packets;
+ /* Second packet queue used to reorder pts of some video track. */
+ AVPacket **packets_reorder;
+ int num_packets_reorder;
+ uint64_t reorder_max_pts;
/* have we already parse metadata/cues/clusters? */
int metadata_parsed,
if (!url_feof(pb)) {
offset_t pos = url_ftell(pb);
av_log(matroska->ctx, AV_LOG_ERROR,
- "Read error at pos. %llu (0x%llx)\n",
+ "Read error at pos. %"PRIu64" (0x%"PRIx64")\n",
pos, pos);
}
return AVERROR_IO; /* EOS or actual I/O error */
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 %llu (0x%llx)\n",
+ "Invalid EBML number size tag 0x%02x at pos %"PRIu64" (0x%"PRIx64")\n",
(uint8_t) total, pos, pos);
return AVERROR_INVALIDDATA;
}
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 %lld (0x%llx)\n",
+ "Invalid uint element size %d at position %"PRId64" (0x%"PRIx64")\n",
size, pos, pos);
return AVERROR_INVALIDDATA;
}
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 %lld (0x%llx)\n",
+ "Invalid sint element size %d at position %"PRId64" (0x%"PRIx64")\n",
size, pos, pos);
return AVERROR_INVALIDDATA;
}
negative = 1;
*num &= ~0x80;
}
- *num = 0;
while (n++ < size)
*num = (*num << 8) | get_byte(pb);
static int
ebml_read_float (MatroskaDemuxContext *matroska,
- uint32_t *id,
- double *num)
+ uint32_t *id,
+ double *num)
{
ByteIOContext *pb = &matroska->ctx->pb;
int size, res;
return res;
size = rlength;
- if (size != 4 && size != 8 && size != 10) {
+ 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 %llu (0x%llx)\n",
+ "Invalid float element size %d at position %"PRIu64" (0x%"PRIx64")\n",
size, pos, pos);
return AVERROR_INVALIDDATA;
}
- if (size == 10) {
- av_log(matroska->ctx, AV_LOG_ERROR,
- "FIXME! 10-byte floats unimplemented\n");
- return AVERROR_UNKNOWN;
- }
-
- if (size == 4) {
- float f;
-
- while (size-- > 0)
-#ifdef WORDS_BIGENDIAN
- ((uint8_t *) &f)[3 - size] = get_byte(pb);
-#else
- ((uint8_t *) &f)[size] = get_byte(pb);
-#endif
-
- *num = f;
- } else {
- double d;
-
- while (size-- > 0)
-#ifdef WORDS_BIGENDIAN
- ((uint8_t *) &d)[7 - size] = get_byte(pb);
-#else
- ((uint8_t *) &d)[size] = get_byte(pb);
-#endif
-
- *num = d;
- }
return 0;
}
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. %llu (0x%llx)\n", pos, pos);
+ "Read error at pos. %"PRIu64" (0x%"PRIx64")\n", pos, pos);
return AVERROR_IO;
}
(*str)[size] = '\0';
if (get_buffer(pb, *binary, *size) != *size) {
offset_t pos = url_ftell(pb);
av_log(matroska->ctx, AV_LOG_ERROR,
- "Read error at pos. %llu (0x%llx)\n", pos, pos);
+ "Read error at pos. %"PRIu64" (0x%"PRIx64")\n", pos, pos);
return AVERROR_IO;
}
n++;
}
- if (!total)
- return AVERROR_INVALIDDATA;
-
if (read == num_ffs)
*num = (uint64_t)-1;
else
return res;
if (num > EBML_VERSION) {
av_log(matroska->ctx, AV_LOG_ERROR,
- "EBML version %llu (> %d) is not supported\n",
+ "EBML version %"PRIu64" (> %d) is not supported\n",
num, EBML_VERSION);
return AVERROR_INVALIDDATA;
}
return res;
if (num > sizeof(uint64_t)) {
av_log(matroska->ctx, AV_LOG_ERROR,
- "Integers of size %llu (> %d) not supported\n",
+ "Integers of size %"PRIu64" (> %zd) not supported\n",
num, sizeof(uint64_t));
return AVERROR_INVALIDDATA;
}
return res;
if (num > sizeof(uint32_t)) {
av_log(matroska->ctx, AV_LOG_ERROR,
- "IDs of size %llu (> %u) not supported\n",
- num, sizeof(uint32_t));
+ "IDs of size %"PRIu64" (> %zu) not supported\n",
+ num, sizeof(uint32_t));
return AVERROR_INVALIDDATA;
}
break;
av_realloc(matroska->packets, (matroska->num_packets - 1) *
sizeof(AVPacket *));
} else {
- av_free(matroska->packets);
- matroska->packets = NULL;
+ av_freep(&matroska->packets);
}
matroska->num_packets--;
return 0;
matroska->num_packets++;
}
+/*
+ * Put a packet into our internal reordering queue. Will be moved to the
+ * main packet queue when enough packets are available to reorder pts.
+ */
+
+static void
+matroska_queue_packet_reordered (MatroskaDemuxContext *matroska,
+ AVPacket *pkt,
+ int is_bframe)
+{
+ if (matroska->num_packets_reorder && !is_bframe
+ && pkt->pts > matroska->reorder_max_pts) {
+ /* reorder pts */
+ int i, j, k = 1;
+ for (j=matroska->num_packets_reorder-1; j && k; j--) {
+ k = 0;
+ for (i=0; i<j; i++) {
+ if (matroska->packets_reorder[i]->pts > matroska->packets_reorder[i+1]->pts) {
+ FFSWAP(uint64_t, matroska->packets_reorder[i]->pts, matroska->packets_reorder[i+1]->pts);
+ k = 1;
+ }
+ }
+ }
+ /* then really queue the packets */
+ for (i=0; i<matroska->num_packets_reorder; i++)
+ matroska_queue_packet (matroska, matroska->packets_reorder[i]);
+ matroska->num_packets_reorder = 0;
+ }
+ matroska->packets_reorder =
+ av_realloc(matroska->packets_reorder,
+ (matroska->num_packets_reorder + 1) * sizeof(AVPacket *));
+ matroska->packets_reorder[matroska->num_packets_reorder++] = pkt;
+ if (pkt->pts > matroska->reorder_max_pts)
+ matroska->reorder_max_pts = pkt->pts;
+}
+
+
/*
* Autodetecting...
*/
* we don't parse the whole header but simply check for the
* availability of that array of characters inside the header.
* Not fully fool-proof, but good enough. */
- for (n = 4 + size; n < 4 + size + total - sizeof(probe_data); n++)
+ for (n = 4 + size; n <= 4 + size + total - sizeof(probe_data); n++)
if (!memcmp (&p->buf[n], probe_data, sizeof(probe_data)))
return AVPROBE_SCORE_MAX;
double num;
if ((res = ebml_read_float(matroska, &id, &num)) < 0)
break;
- matroska->duration = num * matroska->time_scale;
+ 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;
}
av_log(matroska->ctx, AV_LOG_DEBUG, "parsing track, adding stream..,\n");
/* Allocate a generic track. As soon as we know its type we'll realloc. */
- track = av_mallocz(sizeof(MatroskaTrack));
+ track = av_mallocz(MAX_TRACK_SIZE);
matroska->num_tracks++;
/* start with the master */
/* track type (video, audio, combined, subtitle, etc.) */
case MATROSKA_ID_TRACKTYPE: {
uint64_t num;
- if (track->type != 0) {
+ if ((res = ebml_read_uint(matroska, &id, &num)) < 0)
+ break;
+ if (track->type && track->type != num) {
av_log(matroska->ctx, AV_LOG_INFO,
"More than one tracktype in an entry - skip\n");
break;
}
- if ((res = ebml_read_uint(matroska, &id, &num)) < 0)
- break;
track->type = num;
- /* ok, so we're actually going to reallocate this thing */
switch (track->type) {
case MATROSKA_TRACK_TYPE_VIDEO:
- track = (MatroskaTrack *)
- av_realloc(track, sizeof(MatroskaVideoTrack));
- break;
case MATROSKA_TRACK_TYPE_AUDIO:
- track = (MatroskaTrack *)
- av_realloc(track, sizeof(MatroskaAudioTrack));
- ((MatroskaAudioTrack *)track)->channels = 1;
- ((MatroskaAudioTrack *)track)->samplerate = 8000;
- break;
case MATROSKA_TRACK_TYPE_SUBTITLE:
- track = (MatroskaTrack *)
- av_realloc(track, sizeof(MatroskaSubtitleTrack));
break;
case MATROSKA_TRACK_TYPE_COMPLEX:
case MATROSKA_TRACK_TYPE_LOGO:
/* 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");
if ((res = ebml_read_uint (matroska, &id,
&num)) < 0)
break;
- track->default_duration = num;
+ track->default_duration = num/matroska->time_scale;
break;
}
if ((res = ebml_read_float(matroska, &id,
&num)) < 0)
break;
- track->default_duration = 1000000000 * (1. / num);
+ track->default_duration = 1000000000/(matroska->time_scale*num);
break;
}
/* 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");
} 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))) {
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)
uint64_t num;
if ((res = ebml_read_uint(matroska, &id, &num)) < 0)
break;
- track->default_duration = num;
+ track->default_duration = num / matroska->time_scale;
break;
}
switch (id) {
/* one single index entry ('point') */
case MATROSKA_ID_CUETIME: {
- int64_t time;
+ uint64_t time;
if ((res = ebml_read_uint(matroska, &id,
&time)) < 0)
break;
break;
}
- /* position in the file + track to which it
+ /* position in the file + track to which it
* belongs */
case MATROSKA_ID_CUETRACKPOSITION:
if ((res = ebml_read_master(matroska, &id)) < 0)
if (!seek_id || seek_pos == (uint64_t) -1) {
av_log(matroska->ctx, AV_LOG_INFO,
- "Incomplete seekhead entry (0x%x/%llu)\n",
+ "Incomplete seekhead entry (0x%x/%"PRIu64")\n",
seek_id, seek_pos);
break;
}
"cannot parse further.\n", EBML_MAX_DEPTH);
return AVERROR_UNKNOWN;
}
-
+
level.start = 0;
level.length = (uint64_t)-1;
matroska->levels[matroska->num_levels] = level;
/* check ID */
if (!(id = ebml_peek_id (matroska,
&matroska->level_up)))
- break;
+ goto finish;
if (id != seek_id) {
av_log(matroska->ctx, AV_LOG_INFO,
"We looked for ID=0x%x but got "
- "ID=0x%x (pos=%llu)",
+ "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)
- break;
+ goto finish;
switch (id) {
case MATROSKA_ID_CUES:
if (!(res = matroska_parse_index(matroska)) ||
}
break;
}
- if (res < 0)
- break;
finish:
/* remove dummy level */
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)
return AVERROR_NOFMT;
}
av_free(doctype);
- if (version != 1) {
+ if (version > 2) {
av_log(matroska->ctx, AV_LOG_ERROR,
- "Matroska demuxer version 1 too old for file version %d\n",
+ "Matroska demuxer version 2 too old for file version %d\n",
version);
return AVERROR_NOFMT;
}
}
}
- if (res < 0)
- return res;
-
/* Have we found a cluster? */
- if (res == 1) {
- int i;
- enum CodecID codec_id;
+ if (ebml_peek_id(matroska, NULL) == MATROSKA_ID_CLUSTER) {
+ int i, j;
MatroskaTrack *track;
AVStream *st;
- void *extradata = NULL;
- int extradata_size = 0;
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.
(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. */
p = (unsigned char *)track->codec_priv + 16;
((MatroskaVideoTrack *)track)->fourcc = (p[3] << 24) |
(p[2] << 16) | (p[1] << 8) | p[0];
- codec_id = codec_get_bmp_id(((MatroskaVideoTrack *)track)->fourcc);
-
- } else if (!strcmp(track->codec_id,
- MATROSKA_CODEC_ID_VIDEO_MPEG4_SP) ||
- !strcmp(track->codec_id,
- MATROSKA_CODEC_ID_VIDEO_MPEG4_ASP) ||
- !strcmp(track->codec_id,
- MATROSKA_CODEC_ID_VIDEO_MPEG4_AP))
- codec_id = CODEC_ID_MPEG4;
- else if (!strcmp(track->codec_id,
- MATROSKA_CODEC_ID_VIDEO_MPEG4_AVC))
- codec_id = CODEC_ID_H264;
-/* else if (!strcmp(track->codec_id, */
-/* MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED)) */
-/* codec_id = CODEC_ID_???; */
- else if (!strcmp(track->codec_id,
- MATROSKA_CODEC_ID_VIDEO_MSMPEG4V3))
- codec_id = CODEC_ID_MSMPEG4V3;
- else if (!strcmp(track->codec_id,
- MATROSKA_CODEC_ID_VIDEO_MPEG1) ||
- !strcmp(track->codec_id,
- MATROSKA_CODEC_ID_VIDEO_MPEG2))
- codec_id = CODEC_ID_MPEG2VIDEO;
+ 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,
+ else if (!strcmp(track->codec_id,
MATROSKA_CODEC_ID_AUDIO_ACM) &&
(track->codec_priv_size >= 18) &&
(track->codec_priv != NULL)) {
/* Offset of wFormatTag. Stored in LE. */
p = (unsigned char *)track->codec_priv;
tag = (p[1] << 8) | p[0];
- codec_id = codec_get_wav_id(tag);
-
- } else if (!strcmp(track->codec_id,
- MATROSKA_CODEC_ID_AUDIO_MPEG1_L1) ||
- !strcmp(track->codec_id,
- MATROSKA_CODEC_ID_AUDIO_MPEG1_L2) ||
- !strcmp(track->codec_id,
- MATROSKA_CODEC_ID_AUDIO_MPEG1_L3))
- codec_id = CODEC_ID_MP3;
- else if (!strcmp(track->codec_id,
- MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE))
- codec_id = CODEC_ID_PCM_U16BE;
- else if (!strcmp(track->codec_id,
- MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE))
- codec_id = CODEC_ID_PCM_U16LE;
-/* else if (!strcmp(track->codec_id, */
-/* MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT)) */
-/* codec_id = CODEC_ID_PCM_???; */
- else if (!strcmp(track->codec_id,
- MATROSKA_CODEC_ID_AUDIO_AC3))
- codec_id = CODEC_ID_AC3;
- else if (!strcmp(track->codec_id,
- MATROSKA_CODEC_ID_AUDIO_DTS))
- codec_id = CODEC_ID_DTS;
- /* No such codec id so far. */
-/* else if (!strcmp(track->codec_id, */
-/* MATROSKA_CODEC_ID_AUDIO_DTS)) */
-/* codec_id = CODEC_ID_DTS; */
- else if (!strcmp(track->codec_id,
- MATROSKA_CODEC_ID_AUDIO_VORBIS)) {
- extradata_size = track->codec_priv_size;
- if(extradata_size) {
- extradata = av_malloc(extradata_size);
- if(extradata == NULL)
- return AVERROR_NOMEM;
- memcpy(extradata, track->codec_priv, extradata_size);
+ 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;
}
- codec_id = CODEC_ID_VORBIS;
- } else if (!strcmp(track->codec_id,
- MATROSKA_CODEC_ID_AUDIO_MPEG2) ||
- !strcmp(track->codec_id,
- MATROSKA_CODEC_ID_AUDIO_MPEG4))
- codec_id = CODEC_ID_AAC;
- else
- codec_id = CODEC_ID_NONE;
+ 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,
st = av_new_stream(s, track->stream_index);
if (st == NULL)
return AVERROR_NOMEM;
- av_set_pts_info(st, 24, 1, 1000); /* 24 bit pts in ms */
+ av_set_pts_info(st, 64, matroska->time_scale, 1000*1000*1000); /* 64 bit pts in ns */
st->codec->codec_id = codec_id;
+ 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;
if(st->codec->extradata == NULL)
return AVERROR_NOMEM;
st->codec->extradata_size = track->codec_priv_size;
- memcpy(st->codec->extradata, track->codec_priv,
+ memcpy(st->codec->extradata,track->codec_priv+extradata_offset,
track->codec_priv_size);
}
st->codec->width = videotrack->pixel_width;
st->codec->height = videotrack->pixel_height;
if (videotrack->display_width == 0)
- st->codec->sample_aspect_ratio.num =
- videotrack->pixel_width;
- else
- st->codec->sample_aspect_ratio.num =
- videotrack->display_width;
+ videotrack->display_width= videotrack->pixel_width;
if (videotrack->display_height == 0)
- st->codec->sample_aspect_ratio.num =
- videotrack->pixel_height;
- else
- st->codec->sample_aspect_ratio.num =
- videotrack->display_height;
-
+ 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 = 2;
} 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;
}
- return 0;
+ return res;
}
static int
return -1;
}
+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_blockgroup (MatroskaDemuxContext *matroska,
- uint64_t cluster_time)
+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;
- uint32_t id;
+ int track;
AVPacket *pkt;
- int is_keyframe = PKT_FLAG_KEY, last_num_packets = matroska->num_packets;
-
- av_log(matroska->ctx, AV_LOG_DEBUG, "parsing blockgroup...\n");
+ 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;
- while (res == 0) {
- if (!(id = ebml_peek_id(matroska, &matroska->level_up))) {
- res = AVERROR_IO;
- break;
- } else if (matroska->level_up) {
- matroska->level_up--;
+ /* 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;
+ }
+ if(matroska->ctx->streams[ matroska->tracks[track]->stream_index ]->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;
+ switch ((flags & 0x06) >> 1) {
+ case 0x0: /* no lacing */
+ laces = 1;
+ lace_size = av_mallocz(sizeof(int));
+ lace_size[0] = size;
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: {
- uint8_t *data, *origdata;
- int size;
- uint64_t time;
- uint32_t *lace_size = NULL;
- int n, track, flags, laces = 0;
- uint64_t num;
- int64_t pos= url_ftell(&matroska->ctx->pb);
- if ((res = ebml_read_binary(matroska, &id, &data, &size)) < 0)
- break;
- origdata = data;
-
- /* first byte(s): blocknum */
- if ((n = matroska_ebmlnum_uint(data, size, &num)) < 0) {
- av_log(matroska->ctx, AV_LOG_ERROR,
- "EBML block data error\n");
- av_free(origdata);
+ 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;
}
- 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);
+ case 0x2: /* fixed-size lacing */
+ for (n = 0; n < laces; n++)
+ lace_size[n] = size / laces;
break;
- }
- if(matroska->ctx->streams[ matroska->tracks[track]->stream_index ]->discard >= AVDISCARD_ALL){
- av_free(origdata);
- break;
- }
- /* time (relative to cluster time) */
- time = ((data[0] << 8) | data[1]) * matroska->time_scale;
- data += 2;
- size -= 2;
- flags = *data;
- data += 1;
- size -= 1;
- switch ((flags & 0x06) >> 1) {
- case 0x0: /* no lacing */
- laces = 1;
- lace_size = av_mallocz(sizeof(int));
- lace_size[0] = size;
+ 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;
-
- case 0x1: /* xiph lacing */
- case 0x2: /* fixed-size lacing */
- case 0x3: /* EBML lacing */
- if (size == 0) {
- res = -1;
+ }
+ 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;
}
- 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;
- }
+ data += r;
+ size -= r;
+ lace_size[n] = lace_size[n - 1] + snum;
+ total += lace_size[n];
+ }
+ lace_size[n] = size - total;
+ break;
+ }
+ }
+ break;
+ }
- case 0x2: /* fixed-size lacing */
- for (n = 0; n < laces; n++)
- lace_size[n] = size / laces;
- break;
+ if (res == 0) {
+ int real_v = matroska->tracks[track]->flags & MATROSKA_TRACK_REAL_V;
+ uint64_t timecode = AV_NOPTS_VALUE;
- 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 (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 (res == 0) {
- for (n = 0; n < laces; n++) {
- uint64_t timecode = 0;
+ if (n == 0)
+ pkt->flags = is_keyframe;
+ pkt->stream_index = matroska->tracks[track]->stream_index;
- pkt = av_mallocz(sizeof(AVPacket));
- /* XXX: prevent data copy... */
- if (av_new_packet(pkt,lace_size[n]) < 0) {
- res = AVERROR_NOMEM;
- break;
- }
- if (cluster_time != (uint64_t)-1) {
- if (time < 0 && (-time) > cluster_time)
- timecode = cluster_time;
- else
- timecode = cluster_time + time;
- }
- /* FIXME: duration */
+ pkt->pts = timecode;
+ pkt->pos = pos;
+ pkt->duration = duration;
- memcpy(pkt->data, data, lace_size[n]);
- data += lace_size[n];
- if (n == 0)
- pkt->flags = is_keyframe;
- pkt->stream_index =
- matroska->tracks[track]->stream_index;
+ if (matroska->tracks[track]->flags & MATROSKA_TRACK_REORDER)
+ matroska_queue_packet_reordered(matroska, pkt, is_bframe);
+ else
+ matroska_queue_packet(matroska, pkt);
- pkt->pts = timecode / 1000000; /* ns to ms */
- pkt->pos= pos;
+ if (timecode != AV_NOPTS_VALUE)
+ timecode = duration ? timecode + duration : AV_NOPTS_VALUE;
+ }
+ data += lace_size[n];
+ }
+ }
- matroska_queue_packet(matroska, pkt);
- }
- }
+ 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");
- av_free(lace_size);
- av_free(origdata);
+ 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: {
- uint64_t num;
- if ((res = ebml_read_uint(matroska, &id, &num)) < 0)
+ if ((res = ebml_read_uint(matroska, &id, &duration)) < 0)
break;
- av_log(matroska->ctx, AV_LOG_INFO,
- "FIXME: implement support for BlockDuration\n");
+ duration /= matroska->time_scale;
break;
}
- case MATROSKA_ID_BLOCKREFERENCE:
+ case MATROSKA_ID_BLOCKREFERENCE: {
+ int64_t num;
/* We've found a reference, so not even the first frame in
* the lace is a key frame. */
is_keyframe = 0;
if (last_num_packets != matroska->num_packets)
matroska->packets[last_num_packets]->flags = 0;
- res = ebml_read_skip(matroska);
+ if ((res = ebml_read_sint(matroska, &id, &num)) < 0)
+ break;
+ if (num > 0)
+ is_bframe = 1;
break;
+ }
default:
av_log(matroska->ctx, AV_LOG_INFO,
}
}
+ if (res)
+ return res;
+
+ if (size > 0)
+ res = matroska_parse_block(matroska, data, size, pos, cluster_time,
+ duration, is_keyframe, is_bframe);
+
return res;
}
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 %lld\n", url_ftell(&matroska->ctx->pb));
+ "parsing cluster at %"PRId64"\n", url_ftell(&matroska->ctx->pb));
while (res == 0) {
if (!(id = ebml_peek_id(matroska, &matroska->level_up))) {
uint64_t num;
if ((res = ebml_read_uint(matroska, &id, &num)) < 0)
break;
- cluster_time = num * matroska->time_scale;
+ cluster_time = num;
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);
int res = 0;
uint32_t id;
- /* Do we still have a packet queued? */
- if (matroska_deliver_packet(matroska, pkt) == 0)
- return 0;
+ /* Read stream until we have a packet queued. */
+ while (matroska_deliver_packet(matroska, pkt)) {
- /* Have we already reached the end? */
- if (matroska->done)
- return AVERROR_IO;
+ /* Have we already reached the end? */
+ if (matroska->done)
+ return AVERROR_IO;
- while (res == 0) {
- if (!(id = ebml_peek_id(matroska, &matroska->level_up))) {
- res = AVERROR_IO;
- break;
- } else if (matroska->level_up) {
- matroska->level_up--;
- break;
- }
+ while (res == 0) {
+ if (!(id = ebml_peek_id(matroska, &matroska->level_up))) {
+ return AVERROR_IO;
+ } else if (matroska->level_up) {
+ matroska->level_up--;
+ break;
+ }
- switch (id) {
- case MATROSKA_ID_CLUSTER:
- if ((res = ebml_read_master(matroska, &id)) < 0)
+ switch (id) {
+ case MATROSKA_ID_CLUSTER:
+ if ((res = ebml_read_master(matroska, &id)) < 0)
+ break;
+ if ((res = matroska_parse_cluster(matroska)) == 0)
+ res = 1; /* Parsed one cluster, let's get out. */
break;
- if ((res = matroska_parse_cluster(matroska)) == 0)
- res = 1; /* Parsed one cluster, let's get out. */
- break;
- default:
- case EBML_ID_VOID:
- res = ebml_read_skip(matroska);
+ default:
+ case EBML_ID_VOID:
+ res = ebml_read_skip(matroska);
+ break;
+ }
+
+ if (matroska->level_up) {
+ matroska->level_up--;
break;
+ }
}
- if (matroska->level_up) {
- matroska->level_up--;
- break;
- }
+ if (res == -1)
+ matroska->done = 1;
}
- if (res == -1)
- matroska->done = 1;
-
- return matroska_deliver_packet(matroska, pkt);
+ return 0;
}
static int
MatroskaDemuxContext *matroska = s->priv_data;
int n = 0;
- if (matroska->writing_app)
- av_free(matroska->writing_app);
- if (matroska->muxing_app)
- av_free(matroska->muxing_app);
- if (matroska->index)
- av_free(matroska->index);
+ av_free(matroska->writing_app);
+ av_free(matroska->muxing_app);
+ av_free(matroska->index);
if (matroska->packets != NULL) {
for (n = 0; n < matroska->num_packets; n++) {
}
av_free(matroska->packets);
}
+ if (matroska->packets_reorder) {
+ for (n = 0; n < matroska->num_packets_reorder; n++) {
+ av_free_packet(matroska->packets_reorder[n]);
+ av_free(matroska->packets_reorder[n]);
+ }
+ av_free(matroska->packets_reorder);
+ }
for (n = 0; n < matroska->num_tracks; n++) {
MatroskaTrack *track = matroska->tracks[n];
- if (track->codec_id)
- av_free(track->codec_id);
- if (track->codec_name)
- av_free(track->codec_name);
- if (track->codec_priv)
- av_free(track->codec_priv);
- if (track->name)
- av_free(track->name);
- if (track->language)
- av_free(track->language);
+ av_free(track->codec_id);
+ av_free(track->codec_name);
+ av_free(track->codec_priv);
+ av_free(track->name);
+ av_free(track->language);
av_free(track);
}
- for (n = 0; n < s->nb_streams; n++) {
- av_free(s->streams[n]->codec->extradata);
- }
-
- memset(matroska, 0, sizeof(MatroskaDemuxContext));
-
return 0;
}
-static AVInputFormat matroska_iformat = {
+AVInputFormat matroska_demuxer = {
"matroska",
"Matroska file format",
sizeof(MatroskaDemuxContext),
matroska_read_packet,
matroska_read_close,
};
-
-int
-matroska_init(void)
-{
- av_register_input_format(&matroska_iformat);
- return 0;
-}