📄 matroskaparser.c
字号:
mf->buflen = mf->bufpos = 0;
// get the relevant page
rd = mf->cache->read(mf->cache, mf->bufbase, mf->inbuf, IBSZ);
if (rd<0)
errorjmp(mf,"I/O Error: %s",mf->cache->geterror(mf->cache));
mf->buflen = rd;
}
// fill the buffer and return next char
static int nextbuf(MatroskaFile *mf) {
fillbuf(mf);
if (mf->bufpos < mf->buflen)
return (unsigned char)(mf->inbuf[mf->bufpos++]);
return EOF;
}
*/
static inline int readch(MatroskaFile *mf) {
return mf->cache->ioreadch(mf->cache); //Picard
//return mf->bufpos < mf->buflen ? (unsigned char)(mf->inbuf[mf->bufpos++]) : nextbuf(mf);
}
static inline ulonglong filepos(MatroskaFile *mf) {
return mf->cache->iotell(mf->cache); //Picard
//return mf->bufbase + mf->bufpos;
}
static void readbytes(MatroskaFile *mf,void *buffer,int len) {
mf->cache->ioread(mf->cache,buffer,len); //Picard
/*
char *cp = buffer;
int nb = mf->buflen - mf->bufpos;
if (nb > len)
nb = len;
memcpy(cp, mf->inbuf + mf->bufpos, nb);
mf->bufpos += nb;
len -= nb;
cp += nb;
if (len>0) {
mf->bufbase += mf->buflen;
mf->bufpos = mf->buflen = 0;
nb = mf->cache->read(mf->cache, mf->bufbase, cp, len);
if (nb<0)
errorjmp(mf,"I/O Error: %s",mf->cache->geterror(mf->cache));
if (nb != len)
errorjmp(mf,"Short read: got %d bytes of %d",nb,len);
mf->bufbase += len;
}
*/
}
static void skipbytes(MatroskaFile *mf,ulonglong len) {
mf->cache->ioseek(mf->cache,len,1);//Picard
/*
int nb = mf->buflen - mf->bufpos;
if (nb > len)
nb = (int)len;
mf->bufpos += nb;
len -= nb;
if (len>0) {
mf->bufbase += mf->buflen;
mf->bufpos = mf->buflen = 0;
mf->bufbase += len;
}
*/
}
static void seek(MatroskaFile *mf,ulonglong pos) {
mf->cache->ioseek(mf->cache,pos,0);//Picard
/*
// see if pos is inside buffer
if (pos>=mf->bufbase && pos<mf->bufbase+mf->buflen)
mf->bufpos = (unsigned)(pos - mf->bufbase);
else {
// invalidate buffer and set pointer
mf->bufbase = pos;
mf->buflen = mf->bufpos = 0;
}
*/
}
///////////////////////////////////////////////////////////////////////////
// floating point
static inline MKFLOAT mkfi(int i) {
#ifdef MATROSKA_INTEGER_ONLY
MKFLOAT f;
f.v = (longlong)i << 32;
return f;
#else
return i;
#endif
}
static inline longlong mul3(MKFLOAT scale,longlong tc) {
#ifdef MATROSKA_INTEGER_ONLY
// x1 x0
// y1 y0
// --------------
// x0*y0
// x1*y0
// x0*y1
// x1*y1
// --------------
// .. r1 r0 ..
//
// r = ((x0*y0) >> 32) + (x1*y0) + (x0*y1) + ((x1*y1) << 32)
unsigned x0,x1,y0,y1;
ulonglong p;
char sign = 0;
if (scale.v < 0)
sign = !sign, scale.v = -scale.v;
if (tc < 0)
sign = !sign, tc = -tc;
x0 = (unsigned)scale.v;
x1 = (unsigned)((ulonglong)scale.v >> 32);
y0 = (unsigned)tc;
y1 = (unsigned)((ulonglong)tc >> 32);
p = (ulonglong)x0*y0 >> 32;
p += (ulonglong)x0*y1;
p += (ulonglong)x1*y0;
p += (ulonglong)(x1*y1) << 32;
return p;
#else
return (longlong)(scale * tc);
#endif
}
///////////////////////////////////////////////////////////////////////////
// EBML support
static int readID(MatroskaFile *mf) {
int c1,c2,c3,c4;
c1 = readch(mf);
if (c1 == EOF)
return EOF;
if (c1 & 0x80)
return c1;
if ((c1 & 0xf0) == 0)
errorjmp(mf,"Invalid first byte of EBML ID: %02X",c1);
c2 = readch(mf);
if (c2 == EOF)
fail:
errorjmp(mf,"Got EOF while reading EBML ID");
if ((c1 & 0xc0) == 0x40)
return (c1<<8) | c2;
c3 = readch(mf);
if (c3 == EOF)
goto fail;
if ((c1 & 0xe0) == 0x20)
return (c1<<16) | (c2<<8) | c3;
c4 = readch(mf);
if (c4 == EOF)
goto fail;
if ((c1 & 0xf0) == 0x10)
return (c1<<24) | (c2<<16) | (c3<<8) | c4;
return 0; // NOT REACHED
}
static ulonglong readVLUIntImp(MatroskaFile *mf,int *mask) {
int c,d,m;
ulonglong v = 0;
c = readch(mf);
if (c == EOF)
return EOF;
if (c == 0)
errorjmp(mf,"Invalid first byte of EBML integer: 0");
for (m=0;;++m) {
if (c & (0x80 >> m)) {
c &= 0x7f >> m;
if (mask)
*mask = m;
return v | ((ulonglong)c << m*8);
}
d = readch(mf);
if (d == EOF)
errorjmp(mf,"Got EOF while reading EBML unsigned integer");
v = (v<<8) | d;
}
// NOT REACHED
}
static inline ulonglong readVLUInt(MatroskaFile *mf) {
return readVLUIntImp(mf,NULL);
}
static ulonglong readSize(MatroskaFile *mf) {
int m;
ulonglong v = readVLUIntImp(mf,&m);
// see if it's unspecified
if (v == (MAXU64 >> (57-m*7)))
errorjmp(mf,"Unspecified element size is not supported here.");
return v;
}
static inline longlong readVLSInt(MatroskaFile *mf) {
static longlong bias[8] = { (ONE<<6)-1, (ONE<<13)-1, (ONE<<20)-1, (ONE<<27)-1,
(ONE<<34)-1, (ONE<<41)-1, (ONE<<48)-1, (ONE<<55)-1 };
int m;
longlong v = readVLUIntImp(mf,&m);
return v - bias[m];
}
static ulonglong readUInt(MatroskaFile *mf,unsigned int len) {
int c;
unsigned int m = len;
ulonglong v = 0;
if (len==0)
return v;
if (len>8)
errorjmp(mf,"Unsupported integer size in readUInt: %u",len);
do {
c = readch(mf);
if (c == EOF)
errorjmp(mf,"Got EOF while reading EBML unsigned integer");
v = (v<<8) | c;
} while (--m);
return v;
}
static inline longlong readSInt(MatroskaFile *mf,unsigned int len) {
longlong v = readUInt(mf,(unsigned)len);
int s = 64 - (len<<3);
return (v << s) >> s;
}
static MKFLOAT readFloat(MatroskaFile *mf,unsigned int len) {
#ifdef MATROSKA_INTEGER_ONLY
MKFLOAT f;
int shift;
#else
union {
unsigned int ui;
ulonglong ull;
float f;
double d;
} u;
#endif
if (len!=4 && len!=8)
errorjmp(mf,"Invalid float size in readFloat: %u",len);
#ifdef MATROSKA_INTEGER_ONLY
if (len == 4) {
unsigned ui = (unsigned)readUInt(mf,(unsigned)len);
f.v = (ui & 0x7fffff) | 0x800000;
if (ui & 0x80000000)
f.v = -f.v;
shift = (ui >> 23) & 0xff;
if (shift == 0) // assume 0
zero:
shift = 0, f.v = 0;
else if (shift == 255)
inf:
if (ui & 0x80000000)
f.v = LL(0x8000000000000000);
else
f.v = LL(0x7fffffffffffffff);
else {
shift += -127 + 9;
if (shift > 39)
goto inf;
shift:
if (shift < 0)
f.v = f.v >> -shift;
else if (shift > 0)
f.v = f.v << shift;
}
} else if (len == 8) {
ulonglong ui = readUInt(mf,(unsigned)len);
f.v = (ui & LL(0xfffffffffffff)) | LL(0x10000000000000);
if (ui & 0x80000000)
f.v = -f.v;
shift = (int)((ui >> 52) & 0x7ff);
if (shift == 0) // assume 0
goto zero;
else if (shift == 2047)
goto inf;
else {
shift += -1023 - 20;
if (shift > 10)
goto inf;
goto shift;
}
}
return f;
#else
if (len==4) {
u.ui = (unsigned int)readUInt(mf,(unsigned)len);
return u.f;
}
if (len==8) {
u.ull = readUInt(mf,(unsigned)len);
return u.d;
}
return 0;
#endif
}
static void readString(MatroskaFile *mf,ulonglong len,char *buffer,int buflen) {
int nread;
if (buflen<1)
errorjmp(mf,"Invalid buffer size in readString: %d",buflen);
nread = buflen - 1;
if (nread > len)
nread = (int)len;
readbytes(mf,buffer,nread);
len -= nread;
if (len>0)
skipbytes(mf,len);
buffer[nread] = '\0';
}
///////////////////////////////////////////////////////////////////////////
// file parser
#define FOREACH(f,tl) \
{ \
ulonglong tmplen = (tl); \
{ \
ulonglong start = filepos(f); \
ulonglong cur,len; \
int id; \
for (;;) { \
cur = filepos(mf); \
if (cur == start + tmplen) \
break; \
id = readID(f); \
if (id==EOF) \
errorjmp(mf,"Unexpected EOF while reading EBML container"); \
len = readSize(mf); \
switch (id) {
#define ENDFOR1(f) \
default: \
skipbytes(f,len); \
break; \
}
#define ENDFOR2() \
} \
} \
}
#define ENDFOR(f) ENDFOR1(f) ENDFOR2()
#define myalloca(f,c) alloca(c)
#define STRGETF(f,v,len,func) \
{ \
char *TmpVal; \
unsigned TmpLen = (len)>MAX_STRING_LEN ? MAX_STRING_LEN : (unsigned)(len); \
TmpVal = func(f->cache,TmpLen+1); \
if (TmpVal == NULL) \
errorjmp(mf,"Out of memory"); \
readString(f,len,TmpVal,TmpLen+1); \
(v) = TmpVal; \
}
#define STRGETA(f,v,len) STRGETF(f,v,len,myalloca)
#define STRGETM(f,v,len) STRGETF(f,v,len,f->cache->memalloc)
#if 0
static int IsWritingApp(MatroskaFile *mf,const char *str) {
const char *cp = mf->Seg.WritingApp;
if (!cp)
return 0;
while (*str && *str++==*cp++) ;
return !*str;
}
#endif
static void parseEBML(MatroskaFile *mf,ulonglong toplen) {
ulonglong v;
char buf[32];
FOREACH(mf,toplen)
case 0x4286: // Version
v = readUInt(mf,(unsigned)len);
break;
case 0x42f7: // ReadVersion
v = readUInt(mf,(unsigned)len);
if (v > EBML_VERSION)
errorjmp(mf,"File requires version %d EBML parser",(int)v);
break;
case 0x42f2: // MaxIDLength
v = readUInt(mf,(unsigned)len);
if (v > EBML_MAX_ID_LENGTH)
errorjmp(mf,"File has identifiers longer than %d",(int)v);
break;
case 0x42f3: // MaxSizeLength
v = readUInt(mf,(unsigned)len);
if (v > EBML_MAX_SIZE_LENGTH)
errorjmp(mf,"File has integers longer than %d",(int)v);
break;
case 0x4282: // DocType
readString(mf,len,buf,sizeof(buf));
if (strcmp(buf,MATROSKA_DOCTYPE))
errorjmp(mf,"Unsupported DocType: %s",buf);
break;
case 0x4287: // DocTypeVersion
v = readUInt(mf,(unsigned)len);
break;
case 0x4285: // DocTypeReadVersion
v = readUInt(mf,(unsigned)len);
if (v > MATROSKA_VERSION)
errorjmp(mf,"File requires version %d Matroska parser",(int)v);
break;
ENDFOR(mf);
}
static void parseSeekEntry(MatroskaFile *mf,ulonglong toplen) {
int seekid = 0;
ulonglong pos = (ulonglong)-1;
FOREACH(mf,toplen)
case 0x53ab: // SeekID
if (len>EBML_MAX_ID_LENGTH)
errorjmp(mf,"Invalid ID size in parseSeekEntry: %d\n",(int)len);
seekid = (int)readUInt(mf,(unsigned)len);
break;
case 0x53ac: // SeekPos
pos = readUInt(mf,(unsigned)len);
break;
ENDFOR(mf);
if (pos == (ulonglong)-1)
errorjmp(mf,"Invalid element position in parseSeekEntry");
pos += mf->pSegment;
switch (seekid) {
case 0x114d9b74: // next SeekHead
if (mf->pSeekHead)
errorjmp(mf,"SeekHead contains more than one SeekHead pointer");
mf->pSeekHead = pos;
break;
case 0x1549a966: // SegmentInfo
mf->pSegmentInfo = pos;
break;
case 0x1f43b675: // Cluster
if (!mf->pCluster)
mf->pCluster = pos;
break;
case 0x1654ae6b: // Tracks
mf->pTracks = pos;
break;
case 0x1c53bb6b: // Cues
mf->pCues = pos;
break;
case 0x1941a469: // Attachments
mf->pAttachments = pos;
break;
case 0x1043a770: // Chapters
mf->pChapters = pos;
break;
case 0x1254c367: // tags
mf->pTags = pos;
break;
}
}
static void parseSeekHead(MatroskaFile *mf,ulonglong toplen) {
FOREACH(mf,toplen)
case 0x4dbb:
parseSeekEntry(mf,len);
break;
ENDFOR(mf);
}
static void parseSegmentInfo(MatroskaFile *mf,ulonglong toplen) {
MKFLOAT duration = mkfi(0);
if (mf->seen.SegmentInfo) {
skipbytes(mf,toplen);
return;
}
mf->seen.SegmentInfo = 1;
mf->Seg.TimecodeScale = 1000000; // Default value
FOREACH(mf,toplen)
case 0x73a4: // SegmentUID
if (len!=sizeof(mf->Seg.UID))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -