* 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"
+#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
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;
* 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_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},
/* 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
int channels,
bitdepth,
+ internal_samplerate,
samplerate;
//..
} MatroskaAudioTrack;
/* 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). */
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;
}
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;
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;
}
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)
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)
}
}
- 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;
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[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_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;
+ }
/* 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)) {
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))
- 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;
+ }
+
+ 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;
+ }
+ }
+
+ 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 */
-
- st->codec.codec_id = codec_id;
+ 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, 1000000000, 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;
+ 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)
- 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);
} 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;
+ 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)
{
int res = 0;
uint32_t id;
- AVPacket *pkt;
+ AVPacket *pkt = NULL;
int is_keyframe = PKT_FLAG_KEY, last_num_packets = matroska->num_packets;
+ uint64_t duration = AV_NOPTS_VALUE;
+ int track = -1;
av_log(matroska->ctx, AV_LOG_DEBUG, "parsing blockgroup...\n");
case MATROSKA_ID_BLOCK: {
uint8_t *data, *origdata;
int size;
- uint64_t time;
+ int16_t block_time;
uint32_t *lace_size = NULL;
- int n, track, flags, laces = 0;
+ int n, 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 */
+ /* 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);
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;
+ /* block_time (relative to cluster time) */
+ block_time = (data[0] << 8) | data[1];
data += 2;
size -= 2;
flags = *data;
}
if (res == 0) {
+ int real_v = matroska->tracks[track]->flags & MATROSKA_TRACK_REAL_V;
for (n = 0; n < laces; n++) {
- uint64_t timecode = 0;
+ uint64_t timecode = AV_NOPTS_VALUE;
+ int slice, slices = 1;
- pkt = av_mallocz(sizeof(AVPacket));
- /* XXX: prevent data copy... */
- if (av_new_packet(pkt,lace_size[n]) < 0) {
- res = AVERROR_NOMEM;
- break;
+ if (real_v) {
+ slices = *data++ + 1;
+ lace_size[n]--;
}
- if (cluster_time != (uint64_t)-1) {
- if (time < 0 && (-time) > cluster_time)
- timecode = cluster_time;
- else
- timecode = cluster_time + time;
+ if (cluster_time != (uint64_t)-1 && n == 0) {
+ if (cluster_time + block_time >= 0)
+ timecode = (cluster_time + block_time) * matroska->time_scale;
}
/* FIXME: duration */
- memcpy(pkt->data, data, lace_size[n]);
- data += lace_size[n];
- if (n == 0)
- pkt->flags = is_keyframe;
- pkt->stream_index =
- matroska->tracks[track]->stream_index;
+ 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);
- pkt->pts = timecode / 1000000; /* ns to ms */
+ if (n == 0)
+ pkt->flags = is_keyframe;
+ pkt->stream_index =
+ matroska->tracks[track]->stream_index;
- matroska_queue_packet(matroska, pkt);
+ pkt->pts = timecode;
+ pkt->pos = pos;
+
+ matroska_queue_packet(matroska, pkt);
+ }
+ data += lace_size[n];
}
}
}
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");
break;
}
}
}
+ if (pkt)
+ {
+ if (duration != AV_NOPTS_VALUE)
+ pkt->duration = duration;
+ else if (track >= 0 && track < matroska->num_tracks)
+ pkt->duration = matroska->tracks[track]->default_duration / matroska->time_scale;
+ }
+
return res;
}
uint64_t cluster_time = 0;
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;
}
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++) {
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);
}
- 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;
-}