1
0
mirror of https://github.com/mpv-player/mpv synced 2024-12-26 17:12:36 +00:00

Added the new C based Matroska demuxer by Aurelien Jacobs.

git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@11808 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
mosu 2004-01-19 19:16:10 +00:00
parent e482826611
commit d6fad182c2
7 changed files with 3461 additions and 17 deletions

46
configure vendored
View File

@ -203,7 +203,8 @@ Codecs:
--enable-vorbis build with OggVorbis support [autodetect]
--enable-tremor build with integer-only OggVorbis support [disabled]
--enable-theora build with OggTheora support [autodetect]
--enable-matroska build with Matroska support [autodetect]
--enable-external-matroska build with external Matroska support [autodetect]
--disable-internal-matroska disable internal Matroska support [enabled]
--enable-external-faad build with external FAAD2 (AAC) support [autodetect]
--disable-internal-faad disable internal FAAD2 (AAC) support [autodetect]
--disable-libdv disable libdv 0.9.5 en/decoding support [autodetect]
@ -1144,7 +1145,8 @@ _liblzo=auto
_mad=auto
_vorbis=auto
_theora=auto
_matroska=auto
_matroska_internal=yes
_matroska_external=auto
_tremor=no
_faad_internal=auto
_faad_external=auto
@ -1310,8 +1312,10 @@ for ac_option do
--disable-tremor) _tremor=no ;;
--enable-theora) _theora=yes ;;
--disable-theora) _theora=no ;;
--enable-matroska) _matroska=yes ;;
--disable-matroska) _matroska=no ;;
--enable-internal-matroska) _matroska_internal=yes _matroska_external=no ;;
--disable-internal-matroska) _matroska_internal=no ;;
--enable-external-matroska) _matroska_internal=no _matroska_external=yes ;;
--disable-external-matroska) _matroska_external=no ;;
--enable-internal-faad) _faad_internal=yes _faad_external=no ;;
--disable-internal-faad) _faad_internal=no ;;
--enable-external-faad) _faad_external=yes _faad_internal=no ;;
@ -4494,9 +4498,15 @@ fi
echores "$_theora"
echocheck "Matroska support (0.6.0 or later)"
if test "$_matroska" != no ; then
_matroska=no
echocheck "Matroska support (external 0.6.0 or later OR internal)"
_matroska_result="no"
if test "$_matroska_internal" = yes ; then
_matroska_external=no
_inputmodules="matroska(internal) $_inputmodules"
_matroska_result="yes, internal"
fi
if test "$_matroska_external" != no ; then
_matroska_external=no
_TMPC=$TMPC
TMPC=${TMPC}pp
cat > $TMPC << EOF
@ -4513,27 +4523,30 @@ if test "$_matroska" != no ; then
int main(void) { return 0; }
EOF
cc_check -lmatroska -lebml -lstdc++ && _matroska=yes
if test "$_matroska" = no ; then
cc_check -lmatroska -lebml -lstdc++ && _matroska_external=yes
if test "$_matroska_external" = no ; then
_saved_inc_extra=$_inc_extra
_inc_extra="$_inc_extra -I/usr/local/include"
cc_check -lmatroska -lebml -lstdc++ && _matroska=yes
if test "$_matroska" = no ; then
cc_check -lmatroska -lebml -lstdc++ && _matroska_external=yes
if test "$_matroska_external" = no ; then
_inc_extra=$_saved_inc_extra
fi
fi
rm ${TMPC} > /dev/null 2> /dev/null
TMPC=$_TMPC
if test "$_matroska_external" = yes ; then
_ld_matroska="-lmatroska -lebml -lstdc++"
_inputmodules="matroska(external) $_inputmodules"
_matroska_result="yes, external"
fi
fi
if test "$_matroska" = yes ; then
echores "$_matroska_result"
if test "$_matroska_internal" != no -o "$_matroska_external" != no ; then
_def_matroska='#define HAVE_MATROSKA 1'
_inputmodules="matroska $_inputmodules"
_ld_matroska="-lmatroska -lebml -lstdc++"
else
_def_matroska='#undef HAVE_MATROSKA'
_noinputmodules="matroska $_noinputmodules"
fi
echores "$_matroska"
@ -5831,7 +5844,8 @@ CONFIG_RISKY = yes
CONFIG_MP3LAME = $_mp3lame
LIBMENU = $_menu
I18NLIBS = $_i18n_libs
MATROSKA = $_matroska
MATROSKA_INTERNAL = $_matroska_internal
MATROSKA_EXTERNAL = $_matroska_external
MATROSKA_LIB = $_ld_matroska
OPENDIVX = $_opendivx

View File

@ -26,7 +26,10 @@ SRCS += dvbin.c
SRCS += dvb_tune.c
endif
ifeq ($(MATROSKA),yes)
ifeq ($(MATROSKA_INTERNAL),yes)
SRCS += demux_mkv.c ebml.c
endif
ifeq ($(MATROSKA_EXTERNAL),yes)
CPLUSPLUSSRCS += demux_mkv.cpp
endif

2850
libmpdemux/demux_mkv.c Normal file

File diff suppressed because it is too large Load Diff

386
libmpdemux/ebml.c Normal file
View File

@ -0,0 +1,386 @@
/*
* native ebml reader for the Matroska demuxer
* Written by Aurelien Jacobs <aurel@gnuage.org>
* Based on the one written by Ronald Bultje for gstreamer
* Licence: GPL
*/
#include "config.h"
#ifdef HAVE_MATROSKA
#include <stdlib.h>
#include "stream.h"
#include "ebml.h"
/*
* Read: the element content data ID.
* Return: the ID.
*/
uint32_t
ebml_read_id (stream_t *s, int *length)
{
int i, len_mask = 0x80;
uint32_t id;
for (i=0, id=stream_read_char (s); i<4 && !(id & len_mask); i++)
len_mask >>= 1;
if (i >= 4)
return EBML_ID_INVALID;
if (length)
*length = i + 1;
while (i--)
id = (id << 8) | stream_read_char (s);
return id;
}
/*
* Read a variable length unsigned int.
*/
uint64_t
ebml_read_vlen_uint (uint8_t *buffer, int *length)
{
int i, j, num_ffs = 0, len_mask = 0x80;
uint64_t num;
for (i=0, num=*buffer++; i<8 && !(num & len_mask); i++)
len_mask >>= 1;
if (i >= 8)
return EBML_UINT_INVALID;
j = i+1;
if (length)
*length = j;
if (((int)num &= (len_mask - 1)) == len_mask - 1)
num_ffs++;
while (i--)
{
num = (num << 8) | *buffer++;
if ((num & 0xFF) == 0xFF)
num_ffs++;
}
if (j == num_ffs)
return EBML_UINT_INVALID;
return num;
}
/*
* Read a variable length signed int.
*/
int64_t
ebml_read_vlen_int (uint8_t *buffer, int *length)
{
uint64_t unum;
int l;
/* read as unsigned number first */
unum = ebml_read_vlen_uint (buffer, &l);
if (unum == EBML_UINT_INVALID)
return EBML_INT_INVALID;
if (length)
*length = l;
return unum - ((1 << ((7 * l) - 1)) - 1);
}
/*
* Read: element content length.
*/
uint64_t
ebml_read_length (stream_t *s, int *length)
{
int i, j, num_ffs = 0, len_mask = 0x80;
uint64_t len;
for (i=0, len=stream_read_char (s); i<8 && !(len & len_mask); i++)
len_mask >>= 1;
if (i >= 8)
return EBML_UINT_INVALID;
j = i+1;
if (length)
*length = j;
if (((int)len &= (len_mask - 1)) == len_mask - 1)
num_ffs++;
while (i--)
{
len = (len << 8) | stream_read_char (s);
if ((len & 0xFF) == 0xFF)
num_ffs++;
}
if (j == num_ffs)
return EBML_UINT_INVALID;
return len;
}
/*
* Read the next element as an unsigned int.
*/
uint64_t
ebml_read_uint (stream_t *s, uint64_t *length)
{
uint64_t len, value = 0;
int l;
len = ebml_read_length (s, &l);
if (len == EBML_UINT_INVALID || len < 1 || len > 8)
return EBML_UINT_INVALID;
if (length)
*length = len + l;
while (len--)
value = (value << 8) | stream_read_char (s);
return value;
}
/*
* Read the next element as a signed int.
*/
int64_t
ebml_read_int (stream_t *s, uint64_t *length)
{
int64_t value = 0;
uint64_t len;
int l;
len = ebml_read_length (s, &l);
if (len == EBML_UINT_INVALID || len < 1 || len > 8)
return EBML_INT_INVALID;
if (length)
*length = len + l;
len--;
l = stream_read_char (s);
if (l & 0x80)
value = -1;
value = (value << 8) | l;
while (len--)
value = (value << 8) | stream_read_char (s);
return value;
}
/*
* Read the next element as a float.
*/
long double
ebml_read_float (stream_t *s, uint64_t *length)
{
long double value;
uint64_t len;
int l;
len = ebml_read_length (s, &l);
switch (len)
{
case 4:
{
uint32_t i;
float *f;
#ifndef WORDS_BIGENDIAN
i = stream_read_dword (s);
#else
i = stream_read_dword_le (s);
#endif
f = (float *) (void *) &i;
value = *f;
break;
}
case 8:
{
uint64_t i;
double *d;
#ifndef WORDS_BIGENDIAN
i = stream_read_qword (s);
#else
i = stream_read_qword_le (s);
#endif
d = (double *) (void *) &i;
value = *d;
break;
}
case 10:
{
uint8_t data[10];
#ifdef WORDS_BIGENDIAN
int i = 10;
#endif
if (stream_read (s, data, 10) != 10)
return EBML_FLOAT_INVALID;
#ifndef WORDS_BIGENDIAN
value = * (long double *) data;
#else
while (i--)
((uint8_t *) &value)[i] = data[9 - i];
#endif
break;
}
default:
return EBML_FLOAT_INVALID;
}
if (length)
*length = len + l;
return value;
}
/*
* Read the next element as an ASCII string.
*/
char *
ebml_read_ascii (stream_t *s, uint64_t *length)
{
uint64_t len;
char *str;
int l;
len = ebml_read_length (s, &l);
if (len == EBML_UINT_INVALID)
return NULL;
if (length)
*length = len + l;
str = (char *) malloc (len+1);
if (stream_read(s, str, len) != (int) len)
{
free (str);
return NULL;
}
str[len] = '\0';
return str;
}
/*
* Read the next element as a UTF-8 string.
*/
char *
ebml_read_utf8 (stream_t *s, uint64_t *length)
{
return ebml_read_ascii (s, length);
}
/*
* Skip the next element.
*/
int
ebml_read_skip (stream_t *s, uint64_t *length)
{
uint64_t len;
int l;
len = ebml_read_length (s, &l);
if (len == EBML_UINT_INVALID)
return 1;
if (length)
*length = len + l;
stream_skip(s, len);
return 0;
}
/*
* Read the next element, but only the header. The contents
* are supposed to be sub-elements which can be read separately.
*/
uint32_t
ebml_read_master (stream_t *s, uint64_t *length)
{
uint64_t len;
uint32_t id;
id = ebml_read_id (s, NULL);
if (id == EBML_ID_INVALID)
return id;
len = ebml_read_length (s, NULL);
if (len == EBML_UINT_INVALID)
return EBML_ID_INVALID;
if (length)
*length = len;
return id;
}
/*
* Read an EBML header.
*/
char *
ebml_read_header (stream_t *s, int *version)
{
uint64_t length, l, num;
uint32_t id;
char *str = NULL;
if (ebml_read_master (s, &length) != EBML_ID_HEADER)
return 0;
if (version)
*version = 1;
while (length > 0)
{
id = ebml_read_id (s, NULL);
if (id == EBML_ID_INVALID)
return NULL;
length -= 2;
switch (id)
{
/* is our read version uptodate? */
case EBML_ID_EBMLREADVERSION:
num = ebml_read_uint (s, &l);
if (num != EBML_VERSION)
return NULL;
break;
/* we only handle 8 byte lengths at max */
case EBML_ID_EBMLMAXSIZELENGTH:
num = ebml_read_uint (s, &l);
if (num != sizeof (uint64_t))
return NULL;
break;
/* we handle 4 byte IDs at max */
case EBML_ID_EBMLMAXIDLENGTH:
num = ebml_read_uint (s, &l);
if (num != sizeof (uint32_t))
return NULL;
break;
case EBML_ID_DOCTYPE:
str = ebml_read_ascii (s, &l);
if (str == NULL)
return NULL;
break;
case EBML_ID_DOCTYPEREADVERSION:
num = ebml_read_uint (s, &l);
if (num == EBML_UINT_INVALID)
return NULL;
if (version)
*version = num;
break;
/* we ignore these two, they don't tell us anything we care about */
case EBML_ID_VOID:
case EBML_ID_EBMLVERSION:
case EBML_ID_DOCTYPEVERSION:
default:
if (ebml_read_skip (s, &l))
return NULL;
break;
}
length -= l;
}
return str;
}
#endif /* HAVE_MATROSKA */

175
libmpdemux/ebml.h Normal file
View File

@ -0,0 +1,175 @@
#ifndef __EBML_H
#define __EBML_H
#include <stdint.h>
/* EBML version supported */
#define EBML_VERSION 1
/*
* EBML element IDs. max. 32-bit.
*/
/* 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
/* ID returned in error cases */
#define EBML_ID_INVALID 0xFFFFFFFF
/*
* 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_ATTACHMENTS 0x1941A469
#define MATROSKA_ID_CHAPTERS 0x1043A770
#define MATROSKA_ID_CLUSTER 0x1F43B675
/* IDs in the info master */
#define MATROSKA_ID_TIMECODESCALE 0x2AD7B1
#define MATROSKA_ID_DURATION 0x4489
#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
#define MATROSKA_ID_TRACKENCODINGS 0x6D80
/* IDs in the trackaudio master */
#define MATROSKA_ID_AUDIOSAMPLINGFREQ 0xB5
#define MATROSKA_ID_AUDIOBITDEPTH 0x6264
#define MATROSKA_ID_AUDIOCHANNELS 0x9F
/* 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_VIDEODISPLAYUNIT 0x54B2
#define MATROSKA_ID_VIDEOASPECTRATIO 0x54B3
#define MATROSKA_ID_VIDEOCOLOURSPACE 0x2EB524
#define MATROSKA_ID_VIDEOGAMMA 0x2FB523
/* IDs in the trackencodings master */
#define MATROSKA_ID_CONTENTENCODING 0x6240
#define MATROSKA_ID_CONTENTENCODINGORDER 0x5031
#define MATROSKA_ID_CONTENTENCODINGSCOPE 0x5032
#define MATROSKA_ID_CONTENTENCODINGTYPE 0x5033
#define MATROSKA_ID_CONTENTCOMPRESSION 0x5034
#define MATROSKA_ID_CONTENTCOMPALGO 0x4254
#define MATROSKA_ID_CONTENTCOMPSETTINGS 0x4255
/* 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 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 chapters master */
#define MATROSKA_ID_EDITIONENTRY 0x45B9
#define MATROSKA_ID_CHAPTERATOM 0xB6
#define MATROSKA_ID_CHAPTERTIMESTART 0x91
#define MATROSKA_ID_CHAPTERTIMEEND 0x92
/* IDs in the cluster master */
#define MATROSKA_ID_CLUSTERTIMECODE 0xE7
#define MATROSKA_ID_BLOCKGROUP 0xA0
/* IDs in the blockgroup master */
#define MATROSKA_ID_BLOCKDURATION 0x9B
#define MATROSKA_ID_BLOCK 0xA1
#define MATROSKA_ID_REFERENCEBLOCK 0xFB
/* matroska track types */
#define MATROSKA_TRACK_VIDEO 0x01 /* rectangle-shaped pictures aka video */
#define MATROSKA_TRACK_AUDIO 0x02 /* anything you can hear */
#define MATROSKA_TRACK_COMPLEX 0x03 /* audio+video in same track used by DV */
#define MATROSKA_TRACK_LOGO 0x10 /* overlay-pictures displayed over video*/
#define MATROSKA_TRACK_SUBTITLE 0x11 /* text-subtitles */
#define MATROSKA_TRACK_CONTROL 0x20 /* control-codes for menu or other stuff*/
/* matroska subtitle types */
#define MATROSKA_SUBTYPE_UNKNOWN 0
#define MATROSKA_SUBTYPE_TEXT 1
#define MATROSKA_SUBTYPE_SSA 2
#define MATROSKA_SUBTYPE_VOBSUB 3
#define EBML_UINT_INVALID UINT64_MAX
#define EBML_INT_INVALID INT64_MAX
#define EBML_FLOAT_INVALID -1000000000.0
uint32_t ebml_read_id (stream_t *s, int *length);
uint64_t ebml_read_vlen_uint (uint8_t *buffer, int *length);
int64_t ebml_read_vlen_int (uint8_t *buffer, int *length);
uint64_t ebml_read_length (stream_t *s, int *length);
uint64_t ebml_read_uint (stream_t *s, uint64_t *length);
int64_t ebml_read_int (stream_t *s, uint64_t *length);
long double ebml_read_float (stream_t *s, uint64_t *length);
char *ebml_read_ascii (stream_t *s, uint64_t *length);
char *ebml_read_utf8 (stream_t *s, uint64_t *length);
int ebml_read_skip (stream_t *s, uint64_t *length);
uint32_t ebml_read_master (stream_t *s, uint64_t *length);
char *ebml_read_header (stream_t *s, int *version);
#endif /* __EBML_H */

View File

@ -47,7 +47,10 @@
#define MKV_S_TEXTASCII "S_TEXT/ASCII"
#define MKV_S_TEXTUTF8 "S_TEXT/UTF8"
#define MKV_S_TEXTSSA "S_TEXT/SSA"
#define MKV_S_TEXTASS "S_TEXT/ASS"
#define MKV_S_VOBSUB "S_VOBSUB"
#define MKV_S_SSA "S_SSA" // Deprecated
#define MKV_S_ASS "S_ASS" // Deprecated
typedef struct {
char type; // t = text, v = VobSub

View File

@ -166,6 +166,19 @@ inline static uint64_t stream_read_qword(stream_t *s){
return y;
}
inline static uint64_t stream_read_qword_le(stream_t *s){
uint64_t y;
y = stream_read_char(s);
y|=stream_read_char(s)<<8;
y|=stream_read_char(s)<<16;
y|=stream_read_char(s)<<24;
y|=(uint64_t)stream_read_char(s)<<32;
y|=(uint64_t)stream_read_char(s)<<40;
y|=(uint64_t)stream_read_char(s)<<48;
y|=(uint64_t)stream_read_char(s)<<56;
return y;
}
inline static unsigned int stream_read_int24(stream_t *s){
unsigned int y;
y = stream_read_char(s);