Update to v1.61 of MatroskaParser library
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30942 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2004-2005 Mike Matsnev. All Rights Reserved.
|
* Copyright (c) 2004-2006 Mike Matsnev. All Rights Reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $Id: MatroskaParser.c,v 1.31 2005/03/07 11:22:16 mike Exp $
|
* $Id: MatroskaParser.c,v 1.61 2006/10/28 10:39:45 mike Exp $
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -50,23 +50,20 @@
|
|||||||
#include "MatroskaParser.h"
|
#include "MatroskaParser.h"
|
||||||
|
|
||||||
#ifdef MATROSKA_COMPRESSION_SUPPORT
|
#ifdef MATROSKA_COMPRESSION_SUPPORT
|
||||||
#include <zlib.h>
|
#include "zlib.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define EBML_VERSION 1
|
#define EBML_VERSION 1
|
||||||
#define EBML_MAX_ID_LENGTH 4
|
#define EBML_MAX_ID_LENGTH 4
|
||||||
#define EBML_MAX_SIZE_LENGTH 8
|
#define EBML_MAX_SIZE_LENGTH 8
|
||||||
#define MATROSKA_VERSION 1
|
#define MATROSKA_VERSION 2
|
||||||
#define MATROSKA_DOCTYPE "matroska"
|
#define MATROSKA_DOCTYPE "matroska"
|
||||||
|
|
||||||
#define MAX_STRING_LEN 1023
|
#define MAX_STRING_LEN 1023
|
||||||
#define QSEGSIZE 512
|
#define QSEGSIZE 512
|
||||||
#define MAX_TRACKS 32
|
#define MAX_TRACKS 32
|
||||||
#define MAX_READAHEAD (512*1024)
|
#define MAX_READAHEAD (256*1024)
|
||||||
|
|
||||||
#define DEFAULT_PAGE_SIZE 65536
|
|
||||||
#define MIN_PAGE_SIZE 4096
|
|
||||||
#define MIN_PAGES 2
|
|
||||||
#define MAXCLUSTER (64*1048576)
|
#define MAXCLUSTER (64*1048576)
|
||||||
#define MAXFRAME (4*1048576)
|
#define MAXFRAME (4*1048576)
|
||||||
|
|
||||||
@@ -90,7 +87,7 @@ static char *mystrdup(struct InputStream *is,const char *src) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
len = strlen(src);
|
len = strlen(src);
|
||||||
dst = (char *)is->memalloc(is,len+1);
|
dst = is->memalloc(is,len+1);
|
||||||
if (dst==NULL)
|
if (dst==NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@@ -236,6 +233,9 @@ static void myvsnprintf_uint_impl(char **pdest,char *de,int width,int zero,
|
|||||||
char pc = zero ? '0' : ' ';
|
char pc = zero ? '0' : ' ';
|
||||||
|
|
||||||
*--np = '\0';
|
*--np = '\0';
|
||||||
|
if (val == 0)
|
||||||
|
*--np = '0';
|
||||||
|
else
|
||||||
while (val != 0) {
|
while (val != 0) {
|
||||||
int rem = (int)(val % base);
|
int rem = (int)(val % base);
|
||||||
val = val / base;
|
val = val / base;
|
||||||
@@ -290,7 +290,7 @@ static void myvsnprintf_int(char **pdest,char *de,int width,int zero,
|
|||||||
static void myvsnprintf(char *dest,unsigned dsize,const char *fmt,va_list ap) {
|
static void myvsnprintf(char *dest,unsigned dsize,const char *fmt,va_list ap) {
|
||||||
// s,d,x,u,ll
|
// s,d,x,u,ll
|
||||||
char *de = dest + dsize - 1;
|
char *de = dest + dsize - 1;
|
||||||
int state = 0, width, zero, neg, ll;
|
int state = 0, width = 0, zero = 0, neg = 0, ll = 0;
|
||||||
|
|
||||||
if (dsize <= 1) {
|
if (dsize <= 1) {
|
||||||
if (dsize > 0)
|
if (dsize > 0)
|
||||||
@@ -315,6 +315,8 @@ static void myvsnprintf(char *dest,unsigned dsize,const char *fmt,va_list ap)
|
|||||||
state = 2;
|
state = 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (*fmt == '0')
|
||||||
|
zero = 1;
|
||||||
state = 2;
|
state = 2;
|
||||||
case 2:
|
case 2:
|
||||||
if (*fmt >= '0' && *fmt <= '9') {
|
if (*fmt >= '0' && *fmt <= '9') {
|
||||||
@@ -537,7 +539,7 @@ static inline ulonglong filepos(MatroskaFile *mf) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void readbytes(MatroskaFile *mf,void *buffer,int len) {
|
static void readbytes(MatroskaFile *mf,void *buffer,int len) {
|
||||||
char *cp = (char *)buffer;
|
char *cp = buffer;
|
||||||
int nb = mf->buflen - mf->bufpos;
|
int nb = mf->buflen - mf->bufpos;
|
||||||
|
|
||||||
if (nb > len)
|
if (nb > len)
|
||||||
@@ -852,6 +854,14 @@ static void readString(MatroskaFile *mf,ulonglong len,char *buffer,int buflen) {
|
|||||||
buffer[nread] = '\0';
|
buffer[nread] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void readLangCC(MatroskaFile *mf, ulonglong len, char lcc[4]) {
|
||||||
|
unsigned todo = len > 3 ? 3 : (int)len;
|
||||||
|
|
||||||
|
lcc[0] = lcc[1] = lcc[2] = lcc[3] = 0;
|
||||||
|
readbytes(mf, lcc, todo);
|
||||||
|
skipbytes(mf, len - todo);
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// file parser
|
// file parser
|
||||||
#define FOREACH(f,tl) \
|
#define FOREACH(f,tl) \
|
||||||
@@ -888,7 +898,7 @@ static void readString(MatroskaFile *mf,ulonglong len,char *buffer,int buflen) {
|
|||||||
{ \
|
{ \
|
||||||
char *TmpVal; \
|
char *TmpVal; \
|
||||||
unsigned TmpLen = (len)>MAX_STRING_LEN ? MAX_STRING_LEN : (unsigned)(len); \
|
unsigned TmpLen = (len)>MAX_STRING_LEN ? MAX_STRING_LEN : (unsigned)(len); \
|
||||||
TmpVal = (char *)func(f->cache,TmpLen+1); \
|
TmpVal = func(f->cache,TmpLen+1); \
|
||||||
if (TmpVal == NULL) \
|
if (TmpVal == NULL) \
|
||||||
errorjmp(mf,"Out of memory"); \
|
errorjmp(mf,"Out of memory"); \
|
||||||
readString(f,len,TmpVal,TmpLen+1); \
|
readString(f,len,TmpVal,TmpLen+1); \
|
||||||
@@ -1006,7 +1016,7 @@ static void parseSeekHead(MatroskaFile *mf,ulonglong toplen) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void parseSegmentInfo(MatroskaFile *mf,ulonglong toplen) {
|
static void parseSegmentInfo(MatroskaFile *mf,ulonglong toplen) {
|
||||||
MKFLOAT duration;
|
MKFLOAT duration = mkfi(0);
|
||||||
|
|
||||||
if (mf->seen.SegmentInfo) {
|
if (mf->seen.SegmentInfo) {
|
||||||
skipbytes(mf,toplen);
|
skipbytes(mf,toplen);
|
||||||
@@ -1051,6 +1061,7 @@ static void parseSegmentInfo(MatroskaFile *mf,ulonglong toplen) {
|
|||||||
break;
|
break;
|
||||||
case 0x4461: // DateUTC
|
case 0x4461: // DateUTC
|
||||||
mf->Seg.DateUTC = readUInt(mf,(unsigned)len);
|
mf->Seg.DateUTC = readUInt(mf,(unsigned)len);
|
||||||
|
mf->Seg.DateUTCValid = 1;
|
||||||
break;
|
break;
|
||||||
case 0x7ba9: // Title
|
case 0x7ba9: // Title
|
||||||
STRGETM(mf,mf->Seg.Title,len);
|
STRGETM(mf,mf->Seg.Title,len);
|
||||||
@@ -1074,6 +1085,12 @@ static void parseFirstCluster(MatroskaFile *mf,ulonglong toplen) {
|
|||||||
case 0xe7: // Timecode
|
case 0xe7: // Timecode
|
||||||
mf->firstTimecode += readUInt(mf,(unsigned)len);
|
mf->firstTimecode += readUInt(mf,(unsigned)len);
|
||||||
break;
|
break;
|
||||||
|
case 0xa3: // BlockEx
|
||||||
|
readVLUInt(mf); // track number
|
||||||
|
mf->firstTimecode += readSInt(mf, 2);
|
||||||
|
|
||||||
|
skipbytes(mf,start + toplen - filepos(mf));
|
||||||
|
return;
|
||||||
case 0xa0: // BlockGroup
|
case 0xa0: // BlockGroup
|
||||||
FOREACH(mf,len)
|
FOREACH(mf,len)
|
||||||
case 0xa1: // Block
|
case 0xa1: // Block
|
||||||
@@ -1093,61 +1110,85 @@ static void parseVideoInfo(MatroskaFile *mf,ulonglong toplen,struct TrackInfo *t
|
|||||||
|
|
||||||
FOREACH(mf,toplen)
|
FOREACH(mf,toplen)
|
||||||
case 0x9a: // FlagInterlaced
|
case 0x9a: // FlagInterlaced
|
||||||
ti->Video.Interlaced = readUInt(mf,(unsigned)len)!=0;
|
ti->AV.Video.Interlaced = readUInt(mf,(unsigned)len)!=0;
|
||||||
break;
|
break;
|
||||||
case 0x53b8: // StereoMode
|
case 0x53b8: // StereoMode
|
||||||
v = readUInt(mf,(unsigned)len);
|
v = readUInt(mf,(unsigned)len);
|
||||||
if (v>3)
|
if (v>3)
|
||||||
errorjmp(mf,"Invalid stereo mode");
|
errorjmp(mf,"Invalid stereo mode");
|
||||||
ti->Video.StereoMode = (unsigned char)v;
|
ti->AV.Video.StereoMode = (unsigned char)v;
|
||||||
break;
|
break;
|
||||||
case 0xb0: // PixelWidth
|
case 0xb0: // PixelWidth
|
||||||
v = readUInt(mf,(unsigned)len);
|
v = readUInt(mf,(unsigned)len);
|
||||||
if (v>0xffffffff)
|
if (v>0xffffffff)
|
||||||
errorjmp(mf,"PixelWidth is too large");
|
errorjmp(mf,"PixelWidth is too large");
|
||||||
ti->Video.PixelWidth = (unsigned)v;
|
ti->AV.Video.PixelWidth = (unsigned)v;
|
||||||
if (!dW)
|
if (!dW)
|
||||||
ti->Video.DisplayWidth = ti->Video.PixelWidth;
|
ti->AV.Video.DisplayWidth = ti->AV.Video.PixelWidth;
|
||||||
break;
|
break;
|
||||||
case 0xba: // PixelHeight
|
case 0xba: // PixelHeight
|
||||||
v = readUInt(mf,(unsigned)len);
|
v = readUInt(mf,(unsigned)len);
|
||||||
if (v>0xffffffff)
|
if (v>0xffffffff)
|
||||||
errorjmp(mf,"PixelHeight is too large");
|
errorjmp(mf,"PixelHeight is too large");
|
||||||
ti->Video.PixelHeight = (unsigned)v;
|
ti->AV.Video.PixelHeight = (unsigned)v;
|
||||||
if (!dH)
|
if (!dH)
|
||||||
ti->Video.DisplayHeight = ti->Video.PixelHeight;
|
ti->AV.Video.DisplayHeight = ti->AV.Video.PixelHeight;
|
||||||
break;
|
break;
|
||||||
case 0x54b0: // DisplayWidth
|
case 0x54b0: // DisplayWidth
|
||||||
v = readUInt(mf,(unsigned)len);
|
v = readUInt(mf,(unsigned)len);
|
||||||
if (v>0xffffffff)
|
if (v>0xffffffff)
|
||||||
errorjmp(mf,"DisplayWidth is too large");
|
errorjmp(mf,"DisplayWidth is too large");
|
||||||
ti->Video.DisplayWidth = (unsigned)v;
|
ti->AV.Video.DisplayWidth = (unsigned)v;
|
||||||
dW = 1;
|
dW = 1;
|
||||||
break;
|
break;
|
||||||
case 0x54ba: // DisplayHeight
|
case 0x54ba: // DisplayHeight
|
||||||
v = readUInt(mf,(unsigned)len);
|
v = readUInt(mf,(unsigned)len);
|
||||||
if (v>0xffffffff)
|
if (v>0xffffffff)
|
||||||
errorjmp(mf,"DisplayHeight is too large");
|
errorjmp(mf,"DisplayHeight is too large");
|
||||||
ti->Video.DisplayHeight = (unsigned)v;
|
ti->AV.Video.DisplayHeight = (unsigned)v;
|
||||||
dH = 1;
|
dH = 1;
|
||||||
break;
|
break;
|
||||||
case 0x54b2: // DisplayUnit
|
case 0x54b2: // DisplayUnit
|
||||||
v = readUInt(mf,(unsigned)len);
|
v = readUInt(mf,(unsigned)len);
|
||||||
if (v>2)
|
if (v>2)
|
||||||
errorjmp(mf,"Invalid DisplayUnit: %d",(int)v);
|
errorjmp(mf,"Invalid DisplayUnit: %d",(int)v);
|
||||||
ti->Video.DisplayUnit = (unsigned char)v;
|
ti->AV.Video.DisplayUnit = (unsigned char)v;
|
||||||
break;
|
break;
|
||||||
case 0x54b3: // AspectRatioType
|
case 0x54b3: // AspectRatioType
|
||||||
v = readUInt(mf,(unsigned)len);
|
v = readUInt(mf,(unsigned)len);
|
||||||
if (v>2)
|
if (v>2)
|
||||||
errorjmp(mf,"Invalid AspectRatioType: %d",(int)v);
|
errorjmp(mf,"Invalid AspectRatioType: %d",(int)v);
|
||||||
ti->Video.AspectRatioType = (unsigned char)v;
|
ti->AV.Video.AspectRatioType = (unsigned char)v;
|
||||||
|
break;
|
||||||
|
case 0x54aa: // PixelCropBottom
|
||||||
|
v = readUInt(mf,(unsigned)len);
|
||||||
|
if (v>0xffffffff)
|
||||||
|
errorjmp(mf,"PixelCropBottom is too large");
|
||||||
|
ti->AV.Video.CropB = (unsigned)v;
|
||||||
|
break;
|
||||||
|
case 0x54bb: // PixelCropTop
|
||||||
|
v = readUInt(mf,(unsigned)len);
|
||||||
|
if (v>0xffffffff)
|
||||||
|
errorjmp(mf,"PixelCropTop is too large");
|
||||||
|
ti->AV.Video.CropT = (unsigned)v;
|
||||||
|
break;
|
||||||
|
case 0x54cc: // PixelCropLeft
|
||||||
|
v = readUInt(mf,(unsigned)len);
|
||||||
|
if (v>0xffffffff)
|
||||||
|
errorjmp(mf,"PixelCropLeft is too large");
|
||||||
|
ti->AV.Video.CropL = (unsigned)v;
|
||||||
|
break;
|
||||||
|
case 0x54dd: // PixelCropRight
|
||||||
|
v = readUInt(mf,(unsigned)len);
|
||||||
|
if (v>0xffffffff)
|
||||||
|
errorjmp(mf,"PixelCropRight is too large");
|
||||||
|
ti->AV.Video.CropR = (unsigned)v;
|
||||||
break;
|
break;
|
||||||
case 0x2eb524: // ColourSpace
|
case 0x2eb524: // ColourSpace
|
||||||
ti->Video.ColourSpace = (unsigned)readUInt(mf,4);
|
ti->AV.Video.ColourSpace = (unsigned)readUInt(mf,4);
|
||||||
break;
|
break;
|
||||||
case 0x2fb523: // GammaValue
|
case 0x2fb523: // GammaValue
|
||||||
ti->Video.GammaValue = readFloat(mf,(unsigned)len);
|
ti->AV.Video.GammaValue = readFloat(mf,(unsigned)len);
|
||||||
break;
|
break;
|
||||||
ENDFOR(mf);
|
ENDFOR(mf);
|
||||||
}
|
}
|
||||||
@@ -1157,30 +1198,36 @@ static void parseAudioInfo(MatroskaFile *mf,ulonglong toplen,struct TrackInfo *t
|
|||||||
|
|
||||||
FOREACH(mf,toplen)
|
FOREACH(mf,toplen)
|
||||||
case 0xb5: // SamplingFrequency
|
case 0xb5: // SamplingFrequency
|
||||||
ti->Audio.SamplingFreq = readFloat(mf,(unsigned)len);
|
ti->AV.Audio.SamplingFreq = readFloat(mf,(unsigned)len);
|
||||||
break;
|
break;
|
||||||
case 0x78b5: // OutputSamplingFrequency
|
case 0x78b5: // OutputSamplingFrequency
|
||||||
ti->Audio.OutputSamplingFreq = readFloat(mf,(unsigned)len);
|
ti->AV.Audio.OutputSamplingFreq = readFloat(mf,(unsigned)len);
|
||||||
break;
|
break;
|
||||||
case 0x9f: // Channels
|
case 0x9f: // Channels
|
||||||
v = readUInt(mf,(unsigned)len);
|
v = readUInt(mf,(unsigned)len);
|
||||||
if (v<1 || v>255)
|
if (v<1 || v>255)
|
||||||
errorjmp(mf,"Invalid Channels value");
|
errorjmp(mf,"Invalid Channels value");
|
||||||
ti->Audio.Channels = (unsigned char)v;
|
ti->AV.Audio.Channels = (unsigned char)v;
|
||||||
break;
|
break;
|
||||||
case 0x7d7b: // ChannelPositions
|
case 0x7d7b: // ChannelPositions
|
||||||
skipbytes(mf,len);
|
skipbytes(mf,len);
|
||||||
break;
|
break;
|
||||||
case 0x6264: // BitDepth
|
case 0x6264: // BitDepth
|
||||||
v = readUInt(mf,(unsigned)len);
|
v = readUInt(mf,(unsigned)len);
|
||||||
|
#if 0
|
||||||
if ((v<1 || v>255) && !IsWritingApp(mf,"AVI-Mux GUI"))
|
if ((v<1 || v>255) && !IsWritingApp(mf,"AVI-Mux GUI"))
|
||||||
errorjmp(mf,"Invalid BitDepth: %d",(int)v);
|
errorjmp(mf,"Invalid BitDepth: %d",(int)v);
|
||||||
ti->Audio.BitDepth = (unsigned char)v;
|
#endif
|
||||||
|
ti->AV.Audio.BitDepth = (unsigned char)v;
|
||||||
break;
|
break;
|
||||||
ENDFOR(mf);
|
ENDFOR(mf);
|
||||||
|
|
||||||
if (mkv_TruncFloat(ti->Audio.OutputSamplingFreq)==0)
|
if (ti->AV.Audio.Channels == 0)
|
||||||
ti->Audio.OutputSamplingFreq = ti->Audio.SamplingFreq;
|
ti->AV.Audio.Channels = 1;
|
||||||
|
if (mkv_TruncFloat(ti->AV.Audio.SamplingFreq) == 0)
|
||||||
|
ti->AV.Audio.SamplingFreq = mkfi(8000);
|
||||||
|
if (mkv_TruncFloat(ti->AV.Audio.OutputSamplingFreq)==0)
|
||||||
|
ti->AV.Audio.OutputSamplingFreq = ti->AV.Audio.SamplingFreq;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CopyStr(char **src,char **dst) {
|
static void CopyStr(char **src,char **dst) {
|
||||||
@@ -1198,8 +1245,9 @@ static void CopyStr(char **src,char **dst) {
|
|||||||
static void parseTrackEntry(MatroskaFile *mf,ulonglong toplen) {
|
static void parseTrackEntry(MatroskaFile *mf,ulonglong toplen) {
|
||||||
struct TrackInfo t,*tp,**tpp;
|
struct TrackInfo t,*tp,**tpp;
|
||||||
ulonglong v;
|
ulonglong v;
|
||||||
char *cp = NULL;
|
char *cp = NULL, *cs = NULL;
|
||||||
size_t cplen = 0, cpadd = 0;
|
size_t cplen = 0, cslen = 0, cpadd = 0;
|
||||||
|
unsigned CompScope = 0, num_comp = 0;
|
||||||
|
|
||||||
if (mf->nTracks >= MAX_TRACKS)
|
if (mf->nTracks >= MAX_TRACKS)
|
||||||
errorjmp(mf,"Too many tracks.");
|
errorjmp(mf,"Too many tracks.");
|
||||||
@@ -1229,10 +1277,6 @@ static void parseTrackEntry(MatroskaFile *mf,ulonglong toplen) {
|
|||||||
if (v<1 || v>254)
|
if (v<1 || v>254)
|
||||||
errorjmp(mf,"Invalid track type: %d",(int)v);
|
errorjmp(mf,"Invalid track type: %d",(int)v);
|
||||||
t.Type = (unsigned char)v;
|
t.Type = (unsigned char)v;
|
||||||
if (t.Type == 2) { // fill defaults for audio tracks
|
|
||||||
t.Audio.Channels = 1;
|
|
||||||
t.Audio.SamplingFreq = mkfi(8000);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 0xb9: // Enabled
|
case 0xb9: // Enabled
|
||||||
t.Enabled = readUInt(mf,(unsigned)len)!=0;
|
t.Enabled = readUInt(mf,(unsigned)len)!=0;
|
||||||
@@ -1261,15 +1305,16 @@ static void parseTrackEntry(MatroskaFile *mf,ulonglong toplen) {
|
|||||||
case 0x23314f: // TrackTimecodeScale
|
case 0x23314f: // TrackTimecodeScale
|
||||||
t.TimecodeScale = readFloat(mf,(unsigned)len);
|
t.TimecodeScale = readFloat(mf,(unsigned)len);
|
||||||
break;
|
break;
|
||||||
|
case 0x55ee: // MaxBlockAdditionID
|
||||||
|
t.MaxBlockAdditionID = (unsigned)readUInt(mf,(unsigned)len);
|
||||||
|
break;
|
||||||
case 0x536e: // Name
|
case 0x536e: // Name
|
||||||
if (t.Name)
|
if (t.Name)
|
||||||
errorjmp(mf,"Duplicate Track Name");
|
errorjmp(mf,"Duplicate Track Name");
|
||||||
STRGETA(mf,t.Name,len);
|
STRGETA(mf,t.Name,len);
|
||||||
break;
|
break;
|
||||||
case 0x22b59c: // Language
|
case 0x22b59c: // Language
|
||||||
if (t.Language)
|
readLangCC(mf, len, t.Language);
|
||||||
errorjmp(mf,"Duplicate Track Language");
|
|
||||||
STRGETA(mf,t.Language,len);
|
|
||||||
break;
|
break;
|
||||||
case 0x86: // CodecID
|
case 0x86: // CodecID
|
||||||
if (t.CodecID)
|
if (t.CodecID)
|
||||||
@@ -1282,7 +1327,7 @@ static void parseTrackEntry(MatroskaFile *mf,ulonglong toplen) {
|
|||||||
if (len>262144) // 256KB
|
if (len>262144) // 256KB
|
||||||
errorjmp(mf,"CodecPrivate is too large: %d",(int)len);
|
errorjmp(mf,"CodecPrivate is too large: %d",(int)len);
|
||||||
cplen = (unsigned)len;
|
cplen = (unsigned)len;
|
||||||
cp = (char *)alloca(cplen);
|
cp = alloca(cplen);
|
||||||
readbytes(mf,cp,(int)cplen);
|
readbytes(mf,cp,(int)cplen);
|
||||||
break;
|
break;
|
||||||
case 0x258688: // CodecName
|
case 0x258688: // CodecName
|
||||||
@@ -1315,30 +1360,45 @@ static void parseTrackEntry(MatroskaFile *mf,ulonglong toplen) {
|
|||||||
case 0x6d80: // ContentEncodings
|
case 0x6d80: // ContentEncodings
|
||||||
FOREACH(mf,len)
|
FOREACH(mf,len)
|
||||||
case 0x6240: // ContentEncoding
|
case 0x6240: // ContentEncoding
|
||||||
|
// fill in defaults
|
||||||
|
t.CompEnabled = 1;
|
||||||
|
t.CompMethod = COMP_ZLIB;
|
||||||
|
CompScope = 1;
|
||||||
|
if (++num_comp > 1)
|
||||||
|
return; // only one compression layer supported
|
||||||
FOREACH(mf,len)
|
FOREACH(mf,len)
|
||||||
case 0x5031: // ContentEncodingOrder
|
case 0x5031: // ContentEncodingOrder
|
||||||
readUInt(mf,(unsigned)len);
|
readUInt(mf,(unsigned)len);
|
||||||
break;
|
break;
|
||||||
case 0x5032: // ContentEncodingScope
|
case 0x5032: // ContentEncodingScope
|
||||||
readUInt(mf,(unsigned)len);
|
CompScope = (unsigned)readUInt(mf,(unsigned)len);
|
||||||
break;
|
break;
|
||||||
case 0x5033: // ContentEncodingType
|
case 0x5033: // ContentEncodingType
|
||||||
readUInt(mf,(unsigned)len);
|
if (readUInt(mf,(unsigned)len) != 0)
|
||||||
|
return; // encryption is not supported
|
||||||
break;
|
break;
|
||||||
case 0x5034: // ContentCompression
|
case 0x5034: // ContentCompression
|
||||||
// fill in defaults
|
|
||||||
t.CompEnabled = 1;
|
|
||||||
t.CompMethod = COMP_ZLIB;
|
|
||||||
FOREACH(mf,len)
|
FOREACH(mf,len)
|
||||||
case 0x4254: // ContentCompAlgo
|
case 0x4254: // ContentCompAlgo
|
||||||
v = readUInt(mf,(unsigned)len);
|
v = readUInt(mf,(unsigned)len);
|
||||||
if (v != 0)
|
|
||||||
errorjmp(mf,"Unsupported compression algorithm: %d",(int)v);
|
|
||||||
t.CompEnabled = 1;
|
t.CompEnabled = 1;
|
||||||
|
switch (v) {
|
||||||
|
case 0: // Zlib
|
||||||
t.CompMethod = COMP_ZLIB;
|
t.CompMethod = COMP_ZLIB;
|
||||||
break;
|
break;
|
||||||
|
case 3: // prepend fixed data
|
||||||
|
t.CompMethod = COMP_PREPEND;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return; // unsupported compression, skip track
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 0x4255: // ContentCompSettings
|
case 0x4255: // ContentCompSettings
|
||||||
skipbytes(mf,len);
|
if (len > 256)
|
||||||
|
return;
|
||||||
|
cslen = (unsigned)len;
|
||||||
|
cs = alloca(cslen);
|
||||||
|
readbytes(mf, cs, (int)cslen);
|
||||||
break;
|
break;
|
||||||
ENDFOR(mf);
|
ENDFOR(mf);
|
||||||
break;
|
break;
|
||||||
@@ -1353,36 +1413,95 @@ static void parseTrackEntry(MatroskaFile *mf,ulonglong toplen) {
|
|||||||
if (!t.CodecID)
|
if (!t.CodecID)
|
||||||
errorjmp(mf,"Track has no Codec ID");
|
errorjmp(mf,"Track has no Codec ID");
|
||||||
|
|
||||||
|
if (t.UID != 0) {
|
||||||
|
unsigned i;
|
||||||
|
for (i = 0; i < mf->nTracks; ++i)
|
||||||
|
if (mf->Tracks[i]->UID == t.UID) // duplicate track entry
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MATROSKA_COMPRESSION_SUPPORT
|
||||||
|
// handle compressed CodecPrivate
|
||||||
|
if (t.CompEnabled && t.CompMethod == COMP_ZLIB && (CompScope & 2) && cplen > 0) {
|
||||||
|
z_stream zs;
|
||||||
|
char tmp[64], *ncp;
|
||||||
|
int code;
|
||||||
|
uLong ncplen;
|
||||||
|
|
||||||
|
memset(&zs,0,sizeof(zs));
|
||||||
|
if (inflateInit(&zs) != Z_OK)
|
||||||
|
errorjmp(mf, "inflateInit failed");
|
||||||
|
|
||||||
|
zs.next_in = cp;
|
||||||
|
zs.avail_in = cplen;
|
||||||
|
|
||||||
|
do {
|
||||||
|
zs.next_out = tmp;
|
||||||
|
zs.avail_out = sizeof(tmp);
|
||||||
|
|
||||||
|
code = inflate(&zs, Z_NO_FLUSH);
|
||||||
|
} while (code == Z_OK);
|
||||||
|
|
||||||
|
if (code != Z_STREAM_END)
|
||||||
|
errorjmp(mf, "invalid compressed data in CodecPrivate");
|
||||||
|
|
||||||
|
ncplen = zs.total_out;
|
||||||
|
ncp = alloca(ncplen);
|
||||||
|
|
||||||
|
inflateReset(&zs);
|
||||||
|
|
||||||
|
zs.next_in = cp;
|
||||||
|
zs.avail_in = cplen;
|
||||||
|
zs.next_out = ncp;
|
||||||
|
zs.avail_out = ncplen;
|
||||||
|
|
||||||
|
if (inflate(&zs, Z_FINISH) != Z_STREAM_END)
|
||||||
|
errorjmp(mf, "inflate failed");
|
||||||
|
|
||||||
|
inflateEnd(&zs);
|
||||||
|
|
||||||
|
cp = ncp;
|
||||||
|
cplen = ncplen;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (t.CompEnabled && !(CompScope & 1)) {
|
||||||
|
t.CompEnabled = 0;
|
||||||
|
cslen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// allocate new track
|
// allocate new track
|
||||||
tpp = (TrackInfo **)AGET(mf,Tracks);
|
tpp = AGET(mf,Tracks);
|
||||||
|
|
||||||
// copy strings
|
// copy strings
|
||||||
if (t.Name)
|
if (t.Name)
|
||||||
cpadd += strlen(t.Name)+1;
|
cpadd += strlen(t.Name)+1;
|
||||||
if (t.Language)
|
|
||||||
cpadd += strlen(t.Language)+1;
|
|
||||||
if (t.CodecID)
|
if (t.CodecID)
|
||||||
cpadd += strlen(t.CodecID)+1;
|
cpadd += strlen(t.CodecID)+1;
|
||||||
|
|
||||||
tp = (TrackInfo *)mf->cache->memalloc(mf->cache,sizeof(*tp) + cplen + cpadd);
|
tp = mf->cache->memalloc(mf->cache,sizeof(*tp) + cplen + cslen + cpadd);
|
||||||
if (tp == NULL)
|
if (tp == NULL)
|
||||||
errorjmp(mf,"Out of memory");
|
errorjmp(mf,"Out of memory");
|
||||||
|
|
||||||
memcpy(tp,&t,sizeof(*tp));
|
memcpy(tp,&t,sizeof(*tp));
|
||||||
memcpy(tp+1,cp,cplen);
|
|
||||||
if (cplen) {
|
if (cplen) {
|
||||||
tp->CodecPrivate = tp+1;
|
tp->CodecPrivate = tp+1;
|
||||||
tp->CodecPrivateSize = (unsigned)cplen;
|
tp->CodecPrivateSize = (unsigned)cplen;
|
||||||
|
memcpy(tp->CodecPrivate,cp,cplen);
|
||||||
|
}
|
||||||
|
if (cslen) {
|
||||||
|
tp->CompMethodPrivate = (char *)(tp+1) + cplen;
|
||||||
|
tp->CompMethodPrivateSize = cslen;
|
||||||
|
memcpy(tp->CompMethodPrivate, cs, cslen);
|
||||||
}
|
}
|
||||||
|
|
||||||
cp = (char*)(tp+1) + cplen;
|
cp = (char*)(tp+1) + cplen + cslen;
|
||||||
CopyStr(&tp->Name,&cp);
|
CopyStr(&tp->Name,&cp);
|
||||||
CopyStr(&tp->Language,&cp);
|
|
||||||
CopyStr(&tp->CodecID,&cp);
|
CopyStr(&tp->CodecID,&cp);
|
||||||
|
|
||||||
// set default language
|
// set default language
|
||||||
if (!tp->Language)
|
if (!tp->Language[0])
|
||||||
tp->Language="eng";
|
memcpy(tp->Language, "eng", 4);
|
||||||
|
|
||||||
*tpp = tp;
|
*tpp = tp;
|
||||||
}
|
}
|
||||||
@@ -1498,8 +1617,6 @@ static void parseCues(MatroskaFile *mf,ulonglong toplen) {
|
|||||||
mf->Cues[j] = tmp;
|
mf->Cues[j] = tmp;
|
||||||
++k;
|
++k;
|
||||||
}
|
}
|
||||||
|
|
||||||
fixupCues(mf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parseAttachment(MatroskaFile *mf,ulonglong toplen) {
|
static void parseAttachment(MatroskaFile *mf,ulonglong toplen) {
|
||||||
@@ -1554,7 +1671,7 @@ static void parseChapter(MatroskaFile *mf,ulonglong toplen,struct Chapter *paren
|
|||||||
struct ChapterDisplay *disp;
|
struct ChapterDisplay *disp;
|
||||||
struct ChapterProcess *proc;
|
struct ChapterProcess *proc;
|
||||||
struct ChapterCommand *cmd;
|
struct ChapterCommand *cmd;
|
||||||
struct Chapter *ch = (Chapter *)ASGET(mf,parent,Children);
|
struct Chapter *ch = ASGET(mf,parent,Children);
|
||||||
|
|
||||||
memset(ch,0,sizeof(*ch));
|
memset(ch,0,sizeof(*ch));
|
||||||
|
|
||||||
@@ -1564,6 +1681,12 @@ static void parseChapter(MatroskaFile *mf,ulonglong toplen,struct Chapter *paren
|
|||||||
case 0x73c4: // ChapterUID
|
case 0x73c4: // ChapterUID
|
||||||
ch->UID = readUInt(mf,(unsigned)len);
|
ch->UID = readUInt(mf,(unsigned)len);
|
||||||
break;
|
break;
|
||||||
|
case 0x6e67: // ChapterSegmentUID
|
||||||
|
if (len != sizeof(ch->SegmentUID))
|
||||||
|
skipbytes(mf, len);
|
||||||
|
else
|
||||||
|
readbytes(mf, ch->SegmentUID, sizeof(ch->SegmentUID));
|
||||||
|
break;
|
||||||
case 0x91: // ChapterTimeStart
|
case 0x91: // ChapterTimeStart
|
||||||
ch->Start = readUInt(mf,(unsigned)len);
|
ch->Start = readUInt(mf,(unsigned)len);
|
||||||
break;
|
break;
|
||||||
@@ -1602,28 +1725,19 @@ static void parseChapter(MatroskaFile *mf,ulonglong toplen,struct Chapter *paren
|
|||||||
disp = ASGET(mf,ch,Display);
|
disp = ASGET(mf,ch,Display);
|
||||||
memset(disp, 0, sizeof(*disp));
|
memset(disp, 0, sizeof(*disp));
|
||||||
}
|
}
|
||||||
if (disp->Language)
|
readLangCC(mf, len, disp->Language);
|
||||||
skipbytes(mf,len);
|
|
||||||
else
|
|
||||||
STRGETM(mf,disp->Language,len);
|
|
||||||
break;
|
break;
|
||||||
case 0x437e: // ChapterCountry
|
case 0x437e: // ChapterCountry
|
||||||
if (disp==NULL) {
|
if (disp==NULL) {
|
||||||
disp = ASGET(mf,ch,Display);
|
disp = ASGET(mf,ch,Display);
|
||||||
memset(disp, 0, sizeof(*disp));
|
memset(disp, 0, sizeof(*disp));
|
||||||
}
|
}
|
||||||
if (disp->Country)
|
readLangCC(mf, len, disp->Country);
|
||||||
skipbytes(mf,len);
|
|
||||||
else
|
|
||||||
STRGETM(mf,disp->Country,len);
|
|
||||||
break;
|
break;
|
||||||
ENDFOR(mf);
|
ENDFOR(mf);
|
||||||
|
|
||||||
if (disp && !disp->String) {
|
if (disp && !disp->String)
|
||||||
mf->cache->memfree(mf->cache,disp->Language);
|
|
||||||
mf->cache->memfree(mf->cache,disp->Country);
|
|
||||||
--ch->nDisplay;
|
--ch->nDisplay;
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 0x6944: // ChapProcess
|
case 0x6944: // ChapProcess
|
||||||
proc = NULL;
|
proc = NULL;
|
||||||
@@ -1703,7 +1817,7 @@ static void parseChapters(MatroskaFile *mf,ulonglong toplen) {
|
|||||||
|
|
||||||
FOREACH(mf,toplen)
|
FOREACH(mf,toplen)
|
||||||
case 0x45b9: // EditionEntry
|
case 0x45b9: // EditionEntry
|
||||||
ch = (Chapter *)AGET(mf,Chapters);
|
ch = AGET(mf,Chapters);
|
||||||
memset(ch, 0, sizeof(*ch));
|
memset(ch, 0, sizeof(*ch));
|
||||||
FOREACH(mf,len)
|
FOREACH(mf,len)
|
||||||
case 0x45bc: // EditionUID
|
case 0x45bc: // EditionUID
|
||||||
@@ -1735,7 +1849,7 @@ static void parseTags(MatroskaFile *mf,ulonglong toplen) {
|
|||||||
|
|
||||||
FOREACH(mf,toplen)
|
FOREACH(mf,toplen)
|
||||||
case 0x7373: // Tag
|
case 0x7373: // Tag
|
||||||
tag = (Tag *)AGET(mf,Tags);
|
tag = AGET(mf,Tags);
|
||||||
memset(tag,0,sizeof(*tag));
|
memset(tag,0,sizeof(*tag));
|
||||||
|
|
||||||
FOREACH(mf,len)
|
FOREACH(mf,len)
|
||||||
@@ -1781,10 +1895,7 @@ static void parseTags(MatroskaFile *mf,ulonglong toplen) {
|
|||||||
STRGETM(mf,st->Value,len);
|
STRGETM(mf,st->Value,len);
|
||||||
break;
|
break;
|
||||||
case 0x447a: // TagLanguage
|
case 0x447a: // TagLanguage
|
||||||
if (st->Language)
|
readLangCC(mf, len, st->Language);
|
||||||
skipbytes(mf,len);
|
|
||||||
else
|
|
||||||
STRGETM(mf,st->Language,len);
|
|
||||||
break;
|
break;
|
||||||
case 0x4484: // TagDefault
|
case 0x4484: // TagDefault
|
||||||
st->Default = readUInt(mf,(unsigned)len)!=0;
|
st->Default = readUInt(mf,(unsigned)len)!=0;
|
||||||
@@ -1841,18 +1952,22 @@ static void parseContainerPos(MatroskaFile *mf,ulonglong pos) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void parsePointers(MatroskaFile *mf) {
|
static void parsePointers(MatroskaFile *mf) {
|
||||||
|
jmp_buf jb;
|
||||||
|
|
||||||
if (mf->pSegmentInfo && !mf->seen.SegmentInfo)
|
if (mf->pSegmentInfo && !mf->seen.SegmentInfo)
|
||||||
parseContainerPos(mf,mf->pSegmentInfo);
|
parseContainerPos(mf,mf->pSegmentInfo);
|
||||||
if (mf->pCluster && !mf->seen.Cluster)
|
if (mf->pCluster && !mf->seen.Cluster)
|
||||||
parseContainerPos(mf,mf->pCluster);
|
parseContainerPos(mf,mf->pCluster);
|
||||||
if (mf->pTracks && !mf->seen.Tracks)
|
if (mf->pTracks && !mf->seen.Tracks)
|
||||||
parseContainerPos(mf,mf->pTracks);
|
parseContainerPos(mf,mf->pTracks);
|
||||||
if (mf->pCues && !mf->seen.Cues) {
|
|
||||||
parseContainerPos(mf,mf->pCues);
|
|
||||||
|
|
||||||
// ignore errors
|
memcpy(&jb,&mf->jb,sizeof(jb));
|
||||||
mf->flags &= ~MPF_ERROR;
|
|
||||||
}
|
if (setjmp(mf->jb))
|
||||||
|
mf->flags &= ~MPF_ERROR; // ignore errors
|
||||||
|
else {
|
||||||
|
if (mf->pCues && !mf->seen.Cues)
|
||||||
|
parseContainerPos(mf,mf->pCues);
|
||||||
if (mf->pAttachments && !mf->seen.Attachments)
|
if (mf->pAttachments && !mf->seen.Attachments)
|
||||||
parseContainerPos(mf,mf->pAttachments);
|
parseContainerPos(mf,mf->pAttachments);
|
||||||
if (mf->pChapters && !mf->seen.Chapters)
|
if (mf->pChapters && !mf->seen.Chapters)
|
||||||
@@ -1861,6 +1976,9 @@ static void parsePointers(MatroskaFile *mf) {
|
|||||||
parseContainerPos(mf,mf->pTags);
|
parseContainerPos(mf,mf->pTags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memcpy(&mf->jb,&jb,sizeof(jb));
|
||||||
|
}
|
||||||
|
|
||||||
static void parseSegment(MatroskaFile *mf,ulonglong toplen) {
|
static void parseSegment(MatroskaFile *mf,ulonglong toplen) {
|
||||||
ulonglong nextpos;
|
ulonglong nextpos;
|
||||||
unsigned nSeekHeads = 0, dontstop = 0;
|
unsigned nSeekHeads = 0, dontstop = 0;
|
||||||
@@ -1882,9 +2000,9 @@ static void parseSegment(MatroskaFile *mf,ulonglong toplen) {
|
|||||||
seek(mf,mf->pSeekHead);
|
seek(mf,mf->pSeekHead);
|
||||||
id = readID(mf);
|
id = readID(mf);
|
||||||
if (id==EOF) // chained SeekHead points to EOF?
|
if (id==EOF) // chained SeekHead points to EOF?
|
||||||
goto resume;
|
break;
|
||||||
if (id != 0x114d9b74) // chained SeekHead doesnt point to a SeekHead?
|
if (id != 0x114d9b74) // chained SeekHead doesnt point to a SeekHead?
|
||||||
goto resume;
|
break;
|
||||||
len = readSize(mf);
|
len = readSize(mf);
|
||||||
} else if (mf->pSegmentInfo && mf->pTracks && mf->pCues && mf->pCluster) { // we have pointers to all key elements
|
} else if (mf->pSegmentInfo && mf->pTracks && mf->pCues && mf->pCluster) { // we have pointers to all key elements
|
||||||
// XXX EVIL HACK
|
// XXX EVIL HACK
|
||||||
@@ -1899,10 +2017,6 @@ static void parseSegment(MatroskaFile *mf,ulonglong toplen) {
|
|||||||
dontstop = 1;
|
dontstop = 1;
|
||||||
}
|
}
|
||||||
} while (mf->pSeekHead);
|
} while (mf->pSeekHead);
|
||||||
resume:
|
|
||||||
// XXX workaround for AVI-Mux GUI
|
|
||||||
if (mf->pSegmentInfo && !mf->seen.SegmentInfo)
|
|
||||||
parseContainerPos(mf,mf->pSegmentInfo);
|
|
||||||
seek(mf,nextpos); // resume reading segment
|
seek(mf,nextpos); // resume reading segment
|
||||||
break;
|
break;
|
||||||
case 0x1549a966: // SegmentInfo
|
case 0x1549a966: // SegmentInfo
|
||||||
@@ -1945,10 +2059,43 @@ resume:
|
|||||||
parsePointers(mf);
|
parsePointers(mf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parseBlockGroup(MatroskaFile *mf,ulonglong toplen,ulonglong timecode) {
|
static void parseBlockAdditions(MatroskaFile *mf, ulonglong toplen, ulonglong timecode, unsigned track) {
|
||||||
|
ulonglong add_id = 1, add_pos = 0, add_len = 0;
|
||||||
|
unsigned char have_add;
|
||||||
|
|
||||||
|
FOREACH(mf, toplen)
|
||||||
|
case 0xa6: // BlockMore
|
||||||
|
have_add = 0;
|
||||||
|
FOREACH(mf, len)
|
||||||
|
case 0xee: // BlockAddId
|
||||||
|
add_id = readUInt(mf, (unsigned)len);
|
||||||
|
break;
|
||||||
|
case 0xa5: // BlockAddition
|
||||||
|
add_pos = filepos(mf);
|
||||||
|
add_len = len;
|
||||||
|
skipbytes(mf, len);
|
||||||
|
++have_add;
|
||||||
|
break;
|
||||||
|
ENDFOR(mf);
|
||||||
|
if (have_add == 1 && id > 0 && id < 255) {
|
||||||
|
struct QueueEntry *qe = QAlloc(mf);
|
||||||
|
qe->Start = qe->End = timecode;
|
||||||
|
qe->Position = add_pos;
|
||||||
|
qe->Length = (unsigned)add_len;
|
||||||
|
qe->flags = FRAME_UNKNOWN_START | FRAME_UNKNOWN_END |
|
||||||
|
(((unsigned)add_id << FRAME_STREAM_SHIFT) & FRAME_STREAM_MASK);
|
||||||
|
|
||||||
|
QPut(&mf->Queues[track],qe);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
ENDFOR(mf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parseBlockGroup(MatroskaFile *mf,ulonglong toplen,ulonglong timecode, int blockex) {
|
||||||
ulonglong v;
|
ulonglong v;
|
||||||
ulonglong duration = 0;
|
ulonglong duration = 0;
|
||||||
ulonglong dpos;
|
ulonglong dpos;
|
||||||
|
// unsigned add_id = 0;
|
||||||
struct QueueEntry *qe,*qf = NULL;
|
struct QueueEntry *qe,*qf = NULL;
|
||||||
unsigned char have_duration = 0, have_block = 0;
|
unsigned char have_duration = 0, have_block = 0;
|
||||||
unsigned char gap = 0;
|
unsigned char gap = 0;
|
||||||
@@ -1961,11 +2108,17 @@ static void parseBlockGroup(MatroskaFile *mf,ulonglong toplen,ulonglong timecode
|
|||||||
unsigned *sizes;
|
unsigned *sizes;
|
||||||
signed short block_timecode;
|
signed short block_timecode;
|
||||||
|
|
||||||
|
if (blockex)
|
||||||
|
goto blockex;
|
||||||
|
|
||||||
FOREACH(mf,toplen)
|
FOREACH(mf,toplen)
|
||||||
case 0xfb: // ReferenceBlock
|
case 0xfb: // ReferenceBlock
|
||||||
readSInt(mf,(unsigned)len);
|
readSInt(mf,(unsigned)len);
|
||||||
ref = 1;
|
ref = 1;
|
||||||
break;
|
break;
|
||||||
|
blockex:
|
||||||
|
cur = start = filepos(mf);
|
||||||
|
len = tmplen = toplen;
|
||||||
case 0xa1: // Block
|
case 0xa1: // Block
|
||||||
have_block = 1;
|
have_block = 1;
|
||||||
|
|
||||||
@@ -1977,15 +2130,16 @@ static void parseBlockGroup(MatroskaFile *mf,ulonglong toplen,ulonglong timecode
|
|||||||
trackid = (unsigned char)v;
|
trackid = (unsigned char)v;
|
||||||
|
|
||||||
for (tracknum=0;tracknum<mf->nTracks;++tracknum)
|
for (tracknum=0;tracknum<mf->nTracks;++tracknum)
|
||||||
if (mf->Tracks[tracknum]->Number == trackid)
|
if (mf->Tracks[tracknum]->Number == trackid) {
|
||||||
|
if (mf->trackMask & (1<<tracknum)) // ignore this block
|
||||||
|
break;
|
||||||
goto found;
|
goto found;
|
||||||
errorjmp(mf,"Invalid track number in Block: %u",trackid);
|
}
|
||||||
found:
|
|
||||||
|
|
||||||
if (mf->trackMask & (1<<tracknum)) { // ignore this block
|
// bad trackid/unsupported track
|
||||||
skipbytes(mf,start + tmplen - filepos(mf)); // shortcut
|
skipbytes(mf,start + tmplen - filepos(mf)); // shortcut
|
||||||
return;
|
return;
|
||||||
}
|
found:
|
||||||
|
|
||||||
block_timecode = (signed short)readSInt(mf,2);
|
block_timecode = (signed short)readSInt(mf,2);
|
||||||
|
|
||||||
@@ -1997,6 +2151,9 @@ found:
|
|||||||
if (c==EOF)
|
if (c==EOF)
|
||||||
errorjmp(mf,"Unexpected EOF while reading Block flags");
|
errorjmp(mf,"Unexpected EOF while reading Block flags");
|
||||||
|
|
||||||
|
if (blockex)
|
||||||
|
ref = !(c & 0x80);
|
||||||
|
|
||||||
gap = c & 0x1;
|
gap = c & 0x1;
|
||||||
lacing = (c >> 1) & 3;
|
lacing = (c >> 1) & 3;
|
||||||
|
|
||||||
@@ -2007,7 +2164,7 @@ found:
|
|||||||
nframes = c+1;
|
nframes = c+1;
|
||||||
} else
|
} else
|
||||||
nframes = 1;
|
nframes = 1;
|
||||||
sizes = (unsigned *)alloca(nframes*sizeof(*sizes));
|
sizes = alloca(nframes*sizeof(*sizes));
|
||||||
|
|
||||||
switch (lacing) {
|
switch (lacing) {
|
||||||
case 0: // No lacing
|
case 0: // No lacing
|
||||||
@@ -2071,39 +2228,50 @@ found:
|
|||||||
mf->cache->read(mf->cache,v,NULL,0); // touch page
|
mf->cache->read(mf->cache,v,NULL,0); // touch page
|
||||||
|
|
||||||
skipbytes(mf,len - filepos(mf) + dpos);
|
skipbytes(mf,len - filepos(mf) + dpos);
|
||||||
|
|
||||||
|
if (blockex)
|
||||||
|
goto out;
|
||||||
break;
|
break;
|
||||||
case 0x9b: // BlockDuration
|
case 0x9b: // BlockDuration
|
||||||
duration = readUInt(mf,(unsigned)len);
|
duration = readUInt(mf,(unsigned)len);
|
||||||
have_duration = 1;
|
have_duration = 1;
|
||||||
break;
|
break;
|
||||||
|
case 0x75a1: // BlockAdditions
|
||||||
|
if (nframes > 0) // have some frames
|
||||||
|
parseBlockAdditions(mf, len, timecode, tracknum);
|
||||||
|
else
|
||||||
|
skipbytes(mf, len);
|
||||||
|
break;
|
||||||
ENDFOR(mf);
|
ENDFOR(mf);
|
||||||
|
|
||||||
|
out:
|
||||||
if (!have_block)
|
if (!have_block)
|
||||||
errorjmp(mf,"Found a BlockGroup without Block");
|
errorjmp(mf,"Found a BlockGroup without Block");
|
||||||
|
|
||||||
if (nframes > 1) {
|
if (nframes > 1) {
|
||||||
|
ulonglong defd = mf->Tracks[tracknum]->DefaultDuration;
|
||||||
|
v = qf->Start;
|
||||||
|
|
||||||
if (have_duration) {
|
if (have_duration) {
|
||||||
duration = mul3(mf->Tracks[tracknum]->TimecodeScale,
|
duration = mul3(mf->Tracks[tracknum]->TimecodeScale,
|
||||||
duration * mf->Seg.TimecodeScale);
|
duration * mf->Seg.TimecodeScale);
|
||||||
dpos = duration / nframes;
|
|
||||||
|
|
||||||
v = qf->Start;
|
|
||||||
for (qe = qf; nframes > 1; --nframes, qe = qe->next) {
|
for (qe = qf; nframes > 1; --nframes, qe = qe->next) {
|
||||||
qe->Start = v;
|
qe->Start = v;
|
||||||
v += dpos;
|
v += defd;
|
||||||
duration -= dpos;
|
duration -= defd;
|
||||||
qe->End = v;
|
qe->End = v;
|
||||||
|
#if 0
|
||||||
qe->flags &= ~(FRAME_UNKNOWN_START|FRAME_UNKNOWN_END);
|
qe->flags &= ~(FRAME_UNKNOWN_START|FRAME_UNKNOWN_END);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
qe->Start = v;
|
qe->Start = v;
|
||||||
qe->End = v + duration;
|
qe->End = v + duration;
|
||||||
qe->flags &= ~(FRAME_UNKNOWN_START|FRAME_UNKNOWN_END);
|
qe->flags &= ~FRAME_UNKNOWN_END;
|
||||||
} else if (mf->Tracks[tracknum]->DefaultDuration) {
|
} else if (mf->Tracks[tracknum]->DefaultDuration) {
|
||||||
dpos = mf->Tracks[tracknum]->DefaultDuration;
|
|
||||||
v = qf->Start;
|
|
||||||
for (qe = qf; nframes > 0; --nframes, qe = qe->next) {
|
for (qe = qf; nframes > 0; --nframes, qe = qe->next) {
|
||||||
qe->Start = v;
|
qe->Start = v;
|
||||||
v += dpos;
|
v += defd;
|
||||||
qe->End = v;
|
qe->End = v;
|
||||||
qe->flags &= ~(FRAME_UNKNOWN_START|FRAME_UNKNOWN_END);
|
qe->flags &= ~(FRAME_UNKNOWN_START|FRAME_UNKNOWN_END);
|
||||||
}
|
}
|
||||||
@@ -2159,16 +2327,18 @@ static int readMoreBlocks(MatroskaFile *mf) {
|
|||||||
memcpy(&jb,&mf->jb,sizeof(jb));
|
memcpy(&jb,&mf->jb,sizeof(jb));
|
||||||
|
|
||||||
if (setjmp(mf->jb)) { // something evil happened here, try to resync
|
if (setjmp(mf->jb)) { // something evil happened here, try to resync
|
||||||
|
// always advance read position no matter what so
|
||||||
|
// we don't get caught in an endless loop
|
||||||
|
mf->readPosition = filepos(mf);
|
||||||
|
|
||||||
ret = EOF;
|
ret = EOF;
|
||||||
|
|
||||||
if (++retries > 3) // don't try too hard
|
if (++retries > 3) // don't try too hard
|
||||||
goto ex;
|
goto ex;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (filepos(mf) >= mf->pSegmentTop) {
|
if (filepos(mf) >= mf->pSegmentTop)
|
||||||
mf->readPosition = filepos(mf);
|
|
||||||
goto ex;
|
goto ex;
|
||||||
}
|
|
||||||
|
|
||||||
cp = mf->cache->scan(mf->cache,filepos(mf),0x1f43b675); // cluster
|
cp = mf->cache->scan(mf->cache,filepos(mf),0x1f43b675); // cluster
|
||||||
|
|
||||||
@@ -2194,7 +2364,7 @@ static int readMoreBlocks(MatroskaFile *mf) {
|
|||||||
mf->readPosition = cp;
|
mf->readPosition = cp;
|
||||||
}
|
}
|
||||||
|
|
||||||
cstop = mf->cache->getsize(mf->cache)>>1;
|
cstop = mf->cache->getcachesize(mf->cache)>>1;
|
||||||
if (cstop > MAX_READAHEAD)
|
if (cstop > MAX_READAHEAD)
|
||||||
cstop = MAX_READAHEAD;
|
cstop = MAX_READAHEAD;
|
||||||
cstop += mf->readPosition;
|
cstop += mf->readPosition;
|
||||||
@@ -2223,10 +2393,29 @@ static int readMoreBlocks(MatroskaFile *mf) {
|
|||||||
case 0xab: // PrevSize
|
case 0xab: // PrevSize
|
||||||
readUInt(mf,(unsigned)len);
|
readUInt(mf,(unsigned)len);
|
||||||
break;
|
break;
|
||||||
|
case 0x5854: { // SilentTracks
|
||||||
|
unsigned stmask = 0, i, trk;
|
||||||
|
FOREACH(mf, len)
|
||||||
|
case 0x58d7: // SilentTrackNumber
|
||||||
|
trk = (unsigned)readUInt(mf, (unsigned)len);
|
||||||
|
for (i = 0; i < mf->nTracks; ++i)
|
||||||
|
if (mf->Tracks[i]->Number == trk) {
|
||||||
|
stmask |= 1 << i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
ENDFOR(mf);
|
||||||
|
// TODO pass stmask to reading app
|
||||||
|
break; }
|
||||||
case 0xa0: // BlockGroup
|
case 0xa0: // BlockGroup
|
||||||
if (!have_timecode)
|
if (!have_timecode)
|
||||||
errorjmp(mf,"Found BlockGroup before cluster TimeCode");
|
errorjmp(mf,"Found BlockGroup before cluster TimeCode");
|
||||||
parseBlockGroup(mf,len,mf->tcCluster);
|
parseBlockGroup(mf,len,mf->tcCluster, 0);
|
||||||
|
goto out;
|
||||||
|
case 0xa3: // BlockEx
|
||||||
|
if (!have_timecode)
|
||||||
|
errorjmp(mf,"Found BlockGroup before cluster TimeCode");
|
||||||
|
parseBlockGroup(mf, len, mf->tcCluster, 1);
|
||||||
goto out;
|
goto out;
|
||||||
ENDFOR(mf);
|
ENDFOR(mf);
|
||||||
out:;
|
out:;
|
||||||
@@ -2234,7 +2423,9 @@ out:;
|
|||||||
if (toplen > MAXFRAME)
|
if (toplen > MAXFRAME)
|
||||||
errorjmp(mf,"Element in a cluster is too large around %llu, %X [%u]",filepos(mf),cid,(unsigned)toplen);
|
errorjmp(mf,"Element in a cluster is too large around %llu, %X [%u]",filepos(mf),cid,(unsigned)toplen);
|
||||||
if (cid == 0xa0) // BlockGroup
|
if (cid == 0xa0) // BlockGroup
|
||||||
parseBlockGroup(mf,toplen,mf->tcCluster);
|
parseBlockGroup(mf,toplen,mf->tcCluster, 0);
|
||||||
|
else if (cid == 0xa3) // BlockEx
|
||||||
|
parseBlockGroup(mf, toplen, mf->tcCluster, 1);
|
||||||
else
|
else
|
||||||
skipbytes(mf,toplen);
|
skipbytes(mf,toplen);
|
||||||
}
|
}
|
||||||
@@ -2283,7 +2474,7 @@ static void reindex(MatroskaFile *mf) {
|
|||||||
jmp_buf jb;
|
jmp_buf jb;
|
||||||
ulonglong pos = mf->pCluster;
|
ulonglong pos = mf->pCluster;
|
||||||
ulonglong step = 10*1024*1024;
|
ulonglong step = 10*1024*1024;
|
||||||
ulonglong size, tc, isize;
|
ulonglong size, tc = 0, isize;
|
||||||
longlong next_cluster;
|
longlong next_cluster;
|
||||||
int id, have_tc, bad;
|
int id, have_tc, bad;
|
||||||
struct Cue *cue;
|
struct Cue *cue;
|
||||||
@@ -2412,7 +2603,7 @@ static longlong findLastTimecode(MatroskaFile *mf) {
|
|||||||
ulonglong nd = 0;
|
ulonglong nd = 0;
|
||||||
unsigned n,vtrack;
|
unsigned n,vtrack;
|
||||||
|
|
||||||
if (mf->nCues == 0 || mf->nTracks == 0)
|
if (mf->nTracks == 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
for (n=vtrack=0;n<mf->nTracks;++n)
|
for (n=vtrack=0;n<mf->nTracks;++n)
|
||||||
@@ -2424,9 +2615,16 @@ static longlong findLastTimecode(MatroskaFile *mf) {
|
|||||||
return -1;
|
return -1;
|
||||||
ok:
|
ok:
|
||||||
|
|
||||||
mf->trackMask = ~(1 << vtrack);
|
EmptyQueues(mf);
|
||||||
|
|
||||||
|
if (mf->nCues == 0) {
|
||||||
|
mf->readPosition = mf->pCluster + 13000000 > mf->pSegmentTop ? mf->pCluster : mf->pSegmentTop - 13000000;
|
||||||
|
mf->tcCluster = 0;
|
||||||
|
} else {
|
||||||
mf->readPosition = mf->Cues[mf->nCues - 1].Position + mf->pSegment;
|
mf->readPosition = mf->Cues[mf->nCues - 1].Position + mf->pSegment;
|
||||||
mf->tcCluster = mf->Cues[mf->nCues - 1].Time / mf->Seg.TimecodeScale;
|
mf->tcCluster = mf->Cues[mf->nCues - 1].Time / mf->Seg.TimecodeScale;
|
||||||
|
}
|
||||||
|
mf->trackMask = ~(1 << vtrack);
|
||||||
|
|
||||||
do
|
do
|
||||||
while (mf->Queues[vtrack].head)
|
while (mf->Queues[vtrack].head)
|
||||||
@@ -2437,10 +2635,19 @@ ok:
|
|||||||
nd = tc;
|
nd = tc;
|
||||||
QFree(mf,QGet(&mf->Queues[vtrack]));
|
QFree(mf,QGet(&mf->Queues[vtrack]));
|
||||||
}
|
}
|
||||||
while (readMoreBlocks(mf) != EOF);
|
while (fillQueues(mf,0) != EOF);
|
||||||
|
|
||||||
mf->trackMask = 0;
|
mf->trackMask = 0;
|
||||||
|
|
||||||
|
EmptyQueues(mf);
|
||||||
|
|
||||||
|
// there may have been an error, but at this point we will ignore it
|
||||||
|
if (mf->flags & MPF_ERROR) {
|
||||||
|
mf->flags &= ~MPF_ERROR;
|
||||||
|
if (nd == 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return nd;
|
return nd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2480,22 +2687,30 @@ segment:
|
|||||||
|
|
||||||
// found it
|
// found it
|
||||||
mf->pSegment = filepos(mf);
|
mf->pSegment = filepos(mf);
|
||||||
mf->pSegmentTop = len == MAXU64 ? MAXU64 : mf->pSegment + len;
|
if (len == MAXU64) {
|
||||||
|
mf->pSegmentTop = MAXU64;
|
||||||
|
if (mf->cache->getfilesize) {
|
||||||
|
longlong seglen = mf->cache->getfilesize(mf->cache);
|
||||||
|
if (seglen > 0)
|
||||||
|
mf->pSegmentTop = seglen;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
mf->pSegmentTop = mf->pSegment + len;
|
||||||
parseSegment(mf,len);
|
parseSegment(mf,len);
|
||||||
|
|
||||||
// check if we got all data
|
// check if we got all data
|
||||||
if (!mf->seen.SegmentInfo)
|
if (!mf->seen.SegmentInfo)
|
||||||
errorjmp(mf,"Couldn't find SegmentInfo");
|
errorjmp(mf,"Couldn't find SegmentInfo");
|
||||||
if (!mf->seen.Tracks)
|
|
||||||
errorjmp(mf,"Couldn't find Tracks");
|
|
||||||
if (!mf->seen.Cluster)
|
if (!mf->seen.Cluster)
|
||||||
errorjmp(mf,"Couldn't find any Clusters");
|
mf->pCluster = mf->pSegmentTop;
|
||||||
|
|
||||||
adjust = mf->firstTimecode * mf->Seg.TimecodeScale;
|
adjust = mf->firstTimecode * mf->Seg.TimecodeScale;
|
||||||
|
|
||||||
for (i=0;i<mf->nChapters;++i)
|
for (i=0;i<mf->nChapters;++i)
|
||||||
fixupChapter(adjust, &mf->Chapters[i]);
|
fixupChapter(adjust, &mf->Chapters[i]);
|
||||||
|
|
||||||
|
fixupCues(mf);
|
||||||
|
|
||||||
// release extra memory
|
// release extra memory
|
||||||
ARELEASE(mf,mf,Tracks);
|
ARELEASE(mf,mf,Tracks);
|
||||||
|
|
||||||
@@ -2520,11 +2735,8 @@ segment:
|
|||||||
static void DeleteChapter(MatroskaFile *mf,struct Chapter *ch) {
|
static void DeleteChapter(MatroskaFile *mf,struct Chapter *ch) {
|
||||||
unsigned i,j;
|
unsigned i,j;
|
||||||
|
|
||||||
for (i=0;i<ch->nDisplay;++i) {
|
for (i=0;i<ch->nDisplay;++i)
|
||||||
mf->cache->memfree(mf->cache,ch->Display[i].String);
|
mf->cache->memfree(mf->cache,ch->Display[i].String);
|
||||||
mf->cache->memfree(mf->cache,ch->Display[i].Language);
|
|
||||||
mf->cache->memfree(mf->cache,ch->Display[i].Country);
|
|
||||||
}
|
|
||||||
mf->cache->memfree(mf->cache,ch->Display);
|
mf->cache->memfree(mf->cache,ch->Display);
|
||||||
mf->cache->memfree(mf->cache,ch->Tracks);
|
mf->cache->memfree(mf->cache,ch->Tracks);
|
||||||
|
|
||||||
@@ -2548,7 +2760,7 @@ MatroskaFile *mkv_OpenEx(InputStream *io,
|
|||||||
unsigned flags,
|
unsigned flags,
|
||||||
char *err_msg,unsigned msgsize)
|
char *err_msg,unsigned msgsize)
|
||||||
{
|
{
|
||||||
MatroskaFile *mf = (MatroskaFile *)io->memalloc(io,sizeof(*mf));
|
MatroskaFile *mf = io->memalloc(io,sizeof(*mf));
|
||||||
if (mf == NULL) {
|
if (mf == NULL) {
|
||||||
strlcpy(err_msg,"Out of memory",msgsize);
|
strlcpy(err_msg,"Out of memory",msgsize);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -2744,7 +2956,7 @@ void mkv_Seek(MatroskaFile *mf,ulonglong timecode,unsigned flags) {
|
|||||||
QFree(mf,QGet(&mf->Queues[n]));
|
QFree(mf,QGet(&mf->Queues[n]));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mf->Queues[n].head)
|
if (mf->Queues[n].head && (mf->Tracks[n]->Type != TT_AUDIO || mf->Queues[n].head->Start<=timecode))
|
||||||
if (!IS_DELTA(mf->Queues[n].head))
|
if (!IS_DELTA(mf->Queues[n].head))
|
||||||
m_kftime[n] = mf->Queues[n].head->Start;
|
m_kftime[n] = mf->Queues[n].head->Start;
|
||||||
}
|
}
|
||||||
@@ -3031,6 +3243,7 @@ int mkv_ReadData(MatroskaFile *mf,ulonglong FilePos, void *Buffer,unsigned
|
|||||||
return (mf->cache->read(mf->cache, FilePos, Buffer, Count) != Count);
|
return (mf->cache->read(mf->cache, FilePos, Buffer, Count) != Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* read and decode more data from current frame, return number of bytes decoded,
|
/* read and decode more data from current frame, return number of bytes decoded,
|
||||||
* 0 on end of frame, or -1 on error */
|
* 0 on end of frame, or -1 on error */
|
||||||
int cs_ReadData(CompressedStream *cs,char *buffer,unsigned bufsize)
|
int cs_ReadData(CompressedStream *cs,char *buffer,unsigned bufsize)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2004-2005 Mike Matsnev. All Rights Reserved.
|
* Copyright (c) 2004-2006 Mike Matsnev. All Rights Reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $Id: MatroskaParser.h,v 1.10 2005/01/10 04:52:34 mike Exp $
|
* $Id: MatroskaParser.h,v 1.19 2006/03/11 10:57:13 mike Exp $
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -84,15 +84,17 @@ struct InputStream {
|
|||||||
/* scan for a four byte signature, bytes must be nonzero */
|
/* scan for a four byte signature, bytes must be nonzero */
|
||||||
longlong (*scan)(struct InputStream *cc,ulonglong start,unsigned signature);
|
longlong (*scan)(struct InputStream *cc,ulonglong start,unsigned signature);
|
||||||
/* get cache size, this is used to cap readahead */
|
/* get cache size, this is used to cap readahead */
|
||||||
unsigned (*getsize)(struct InputStream *cc);
|
unsigned (*getcachesize)(struct InputStream *cc);
|
||||||
/* fetch last error message */
|
/* fetch last error message */
|
||||||
const char *(*geterror)(struct InputStream *cc);
|
const char *(*geterror)(struct InputStream *cc);
|
||||||
/* memory allocation */
|
/* memory allocation */
|
||||||
void *(*memalloc)(struct InputStream *cc,size_t size);
|
void *(*memalloc)(struct InputStream *cc,size_t size);
|
||||||
void *(*memrealloc)(struct InputStream *cc,void *mem,size_t newsize);
|
void *(*memrealloc)(struct InputStream *cc,void *mem,size_t newsize);
|
||||||
void (*memfree)(struct InputStream *cc,void *mem);
|
void (*memfree)(struct InputStream *cc,void *mem);
|
||||||
// zero return causes parser to abort open
|
/* zero return causes parser to abort open */
|
||||||
int (*progress)(struct InputStream *cc,ulonglong cur,ulonglong max);
|
int (*progress)(struct InputStream *cc,ulonglong cur,ulonglong max);
|
||||||
|
/* get file size, optional, can be NULL or return -1 if filesize is unknown */
|
||||||
|
longlong (*getfilesize)(struct InputStream *cc);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct InputStream InputStream;
|
typedef struct InputStream InputStream;
|
||||||
@@ -103,6 +105,9 @@ struct MatroskaFile; /* opaque */
|
|||||||
typedef struct MatroskaFile MatroskaFile;
|
typedef struct MatroskaFile MatroskaFile;
|
||||||
|
|
||||||
#define COMP_ZLIB 0
|
#define COMP_ZLIB 0
|
||||||
|
#define COMP_BZIP 1
|
||||||
|
#define COMP_LZO1X 2
|
||||||
|
#define COMP_PREPEND 3
|
||||||
|
|
||||||
#define TT_VIDEO 1
|
#define TT_VIDEO 1
|
||||||
#define TT_AUDIO 2
|
#define TT_AUDIO 2
|
||||||
@@ -120,6 +125,9 @@ struct TrackInfo {
|
|||||||
void *CodecPrivate;
|
void *CodecPrivate;
|
||||||
unsigned CodecPrivateSize;
|
unsigned CodecPrivateSize;
|
||||||
unsigned CompMethod;
|
unsigned CompMethod;
|
||||||
|
void *CompMethodPrivate;
|
||||||
|
unsigned CompMethodPrivateSize;
|
||||||
|
unsigned MaxBlockAdditionID;
|
||||||
struct {
|
struct {
|
||||||
unsigned int Enabled:1;
|
unsigned int Enabled:1;
|
||||||
unsigned int Default:1;
|
unsigned int Default:1;
|
||||||
@@ -137,6 +145,7 @@ struct TrackInfo {
|
|||||||
unsigned int PixelHeight;
|
unsigned int PixelHeight;
|
||||||
unsigned int DisplayWidth;
|
unsigned int DisplayWidth;
|
||||||
unsigned int DisplayHeight;
|
unsigned int DisplayHeight;
|
||||||
|
unsigned int CropL, CropT, CropR, CropB;
|
||||||
unsigned int ColourSpace;
|
unsigned int ColourSpace;
|
||||||
MKFLOAT GammaValue;
|
MKFLOAT GammaValue;
|
||||||
struct {
|
struct {
|
||||||
@@ -149,11 +158,11 @@ struct TrackInfo {
|
|||||||
unsigned char Channels;
|
unsigned char Channels;
|
||||||
unsigned char BitDepth;
|
unsigned char BitDepth;
|
||||||
} Audio;
|
} Audio;
|
||||||
};
|
} AV;
|
||||||
|
|
||||||
/* various strings */
|
/* various strings */
|
||||||
char *Name;
|
char *Name;
|
||||||
char *Language;
|
char Language[4];
|
||||||
char *CodecID;
|
char *CodecID;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -171,7 +180,8 @@ struct SegmentInfo {
|
|||||||
char *WritingApp;
|
char *WritingApp;
|
||||||
ulonglong TimecodeScale;
|
ulonglong TimecodeScale;
|
||||||
ulonglong Duration;
|
ulonglong Duration;
|
||||||
ulonglong DateUTC;
|
longlong DateUTC;
|
||||||
|
char DateUTCValid;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct SegmentInfo SegmentInfo;
|
typedef struct SegmentInfo SegmentInfo;
|
||||||
@@ -189,20 +199,20 @@ typedef struct Attachment Attachment;
|
|||||||
|
|
||||||
struct ChapterDisplay {
|
struct ChapterDisplay {
|
||||||
char *String;
|
char *String;
|
||||||
char *Language;
|
char Language[4];
|
||||||
char *Country;
|
char Country[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ChapterCommand {
|
struct ChapterCommand {
|
||||||
unsigned Time;
|
unsigned Time;
|
||||||
unsigned CommandLength;
|
unsigned CommandLength;
|
||||||
char *Command;
|
void *Command;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ChapterProcess {
|
struct ChapterProcess {
|
||||||
unsigned CodecID;
|
unsigned CodecID;
|
||||||
unsigned CodecPrivateLength;
|
unsigned CodecPrivateLength;
|
||||||
char *CodecPrivate;
|
void *CodecPrivate;
|
||||||
unsigned nCommands,nCommandsSize;
|
unsigned nCommands,nCommandsSize;
|
||||||
struct ChapterCommand *Commands;
|
struct ChapterCommand *Commands;
|
||||||
};
|
};
|
||||||
@@ -221,6 +231,8 @@ struct Chapter {
|
|||||||
unsigned nProcess,nProcessSize;
|
unsigned nProcess,nProcessSize;
|
||||||
struct ChapterProcess *Process;
|
struct ChapterProcess *Process;
|
||||||
|
|
||||||
|
char SegmentUID[16];
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
unsigned int Hidden:1;
|
unsigned int Hidden:1;
|
||||||
unsigned int Enabled:1;
|
unsigned int Enabled:1;
|
||||||
@@ -245,7 +257,7 @@ struct Target {
|
|||||||
struct SimpleTag {
|
struct SimpleTag {
|
||||||
char *Name;
|
char *Name;
|
||||||
char *Value;
|
char *Value;
|
||||||
char *Language;
|
char Language[4];
|
||||||
unsigned Default:1;
|
unsigned Default:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -324,10 +336,12 @@ X int mkv_TruncFloat(MKFLOAT f);
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* frame flags */
|
/* frame flags */
|
||||||
#define FRAME_KF 0x00000001
|
#define FRAME_UNKNOWN_START 0x00000001
|
||||||
#define FRAME_UNKNOWN_START 0x00000002
|
#define FRAME_UNKNOWN_END 0x00000002
|
||||||
#define FRAME_UNKNOWN_END 0x00000004
|
#define FRAME_KF 0x00000004
|
||||||
#define FRAME_GAP 0x00000008
|
#define FRAME_GAP 0x00800000
|
||||||
|
#define FRAME_STREAM_MASK 0xff000000
|
||||||
|
#define FRAME_STREAM_SHIFT 24
|
||||||
|
|
||||||
/* This sets the masking flags for the parser,
|
/* This sets the masking flags for the parser,
|
||||||
* masked tracks [with 1s in their bit positions]
|
* masked tracks [with 1s in their bit positions]
|
||||||
@@ -350,14 +364,8 @@ X int mkv_ReadFrame(/* in */ MatroskaFile *mf,
|
|||||||
/* out */ unsigned int *FrameSize /* in bytes */,
|
/* out */ unsigned int *FrameSize /* in bytes */,
|
||||||
/* out */ unsigned int *FrameFlags);
|
/* out */ unsigned int *FrameFlags);
|
||||||
|
|
||||||
/* Read raw frame data, invokes underlying io methods,
|
int mkv_ReadData(MatroskaFile *mf,ulonglong FilePos, void *Buffer,unsigned int Count);
|
||||||
* but keeps track of the file pointer for internal buffering.
|
|
||||||
* Returns the -1 if error occurred, or 0 on success
|
|
||||||
*/
|
|
||||||
X int mkv_ReadData(/* in */ MatroskaFile *mf,
|
|
||||||
/* in */ ulonglong FilePos,
|
|
||||||
/* out */ void *Buffer,
|
|
||||||
/* in */ unsigned int Count);
|
|
||||||
|
|
||||||
#ifdef MATROSKA_COMPRESSION_SUPPORT
|
#ifdef MATROSKA_COMPRESSION_SUPPORT
|
||||||
/* Compressed streams support */
|
/* Compressed streams support */
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ CreateFileCache(BDataIO *dataio)
|
|||||||
io->filecache.read = &stream_read;
|
io->filecache.read = &stream_read;
|
||||||
io->filecache.scan = &stream_scan;
|
io->filecache.scan = &stream_scan;
|
||||||
// io->filecache.close = &stream_close;
|
// io->filecache.close = &stream_close;
|
||||||
io->filecache.getsize = &stream_getsize;
|
io->filecache.getcachesize = &stream_getsize;
|
||||||
io->filecache.geterror = &stream_geterror;
|
io->filecache.geterror = &stream_geterror;
|
||||||
io->filecache.memalloc = &stream_memalloc;
|
io->filecache.memalloc = &stream_memalloc;
|
||||||
io->filecache.memrealloc = &stream_memrealloc;
|
io->filecache.memrealloc = &stream_memrealloc;
|
||||||
|
|||||||
Reference in New Issue
Block a user