📄 matroskaparser.c
字号:
errorjmp(mf,"SegmentUID size is not %d bytes",mf->Seg.UID);
readbytes(mf,mf->Seg.UID,sizeof(mf->Seg.UID));
break;
case 0x7384: // SegmentFilename
STRGETM(mf,mf->Seg.Filename,len);
break;
case 0x3cb923: // PrevUID
if (len!=sizeof(mf->Seg.PrevUID))
errorjmp(mf,"PrevUID size is not %d bytes",mf->Seg.PrevUID);
readbytes(mf,mf->Seg.PrevUID,sizeof(mf->Seg.PrevUID));
break;
case 0x3c83ab: // PrevFilename
STRGETM(mf,mf->Seg.PrevFilename,len);
break;
case 0x3eb923: // NextUID
if (len!=sizeof(mf->Seg.NextUID))
errorjmp(mf,"NextUID size is not %d bytes",mf->Seg.NextUID);
readbytes(mf,mf->Seg.NextUID,sizeof(mf->Seg.NextUID));
break;
case 0x3e83bb: // NextFilename
STRGETM(mf,mf->Seg.NextFilename,len);
break;
case 0x2ad7b1: // TimecodeScale
mf->Seg.TimecodeScale = readUInt(mf,(unsigned)len);
if (mf->Seg.TimecodeScale == 0)
errorjmp(mf,"Segment timecode scale is zero");
break;
case 0x4489: // Duration
duration = readFloat(mf,(unsigned)len);
break;
case 0x4461: // DateUTC
mf->Seg.DateUTC = readUInt(mf,(unsigned)len);
break;
case 0x7ba9: // Title
STRGETM(mf,mf->Seg.Title,len);
break;
case 0x4d80: // MuxingApp
STRGETM(mf,mf->Seg.MuxingApp,len);
break;
case 0x5741: // WritingApp
STRGETM(mf,mf->Seg.WritingApp,len);
break;
ENDFOR(mf);
mf->Seg.Duration = mul3(duration,mf->Seg.TimecodeScale);
}
static void parseFirstCluster(MatroskaFile *mf,ulonglong toplen) {
mf->seen.Cluster = 1;
mf->firstTimecode = 0;
FOREACH(mf,toplen)
case 0xe7: // Timecode
mf->firstTimecode += readUInt(mf,(unsigned)len);
break;
case 0xa0: // BlockGroup
FOREACH(mf,len)
case 0xa1: // Block
readVLUInt(mf); // track number
mf->firstTimecode += readSInt(mf,2);
skipbytes(mf,start + toplen - filepos(mf));
return;
ENDFOR(mf);
break;
ENDFOR(mf);
}
static void parseVideoInfo(MatroskaFile *mf,ulonglong toplen,struct TrackInfo *ti) {
ulonglong v;
char dW = 0, dH = 0;
FOREACH(mf,toplen)
case 0x9a: // FlagInterlaced
ti->Video.Interlaced = readUInt(mf,(unsigned)len)!=0;
break;
case 0x53b8: // StereoMode
v = readUInt(mf,(unsigned)len);
if (v>3)
errorjmp(mf,"Invalid stereo mode");
ti->Video.StereoMode = (unsigned char)v;
break;
case 0xb0: // PixelWidth
v = readUInt(mf,(unsigned)len);
if (v>0xffffffff)
errorjmp(mf,"PixelWidth is too large");
ti->Video.PixelWidth = (unsigned)v;
if (!dW)
ti->Video.DisplayWidth = ti->Video.PixelWidth;
break;
case 0xba: // PixelHeight
v = readUInt(mf,(unsigned)len);
if (v>0xffffffff)
errorjmp(mf,"PixelHeight is too large");
ti->Video.PixelHeight = (unsigned)v;
if (!dH)
ti->Video.DisplayHeight = ti->Video.PixelHeight;
break;
case 0x54b0: // DisplayWidth
v = readUInt(mf,(unsigned)len);
if (v>0xffffffff)
errorjmp(mf,"DisplayWidth is too large");
ti->Video.DisplayWidth = (unsigned)v;
dW = 1;
break;
case 0x54ba: // DisplayHeight
v = readUInt(mf,(unsigned)len);
if (v>0xffffffff)
errorjmp(mf,"DisplayHeight is too large");
ti->Video.DisplayHeight = (unsigned)v;
dH = 1;
break;
case 0x54b2: // DisplayUnit
v = readUInt(mf,(unsigned)len);
if (v>2)
errorjmp(mf,"Invalid DisplayUnit: %d",(int)v);
ti->Video.DisplayUnit = (unsigned char)v;
break;
case 0x54b3: // AspectRatioType
v = readUInt(mf,(unsigned)len);
if (v>2)
errorjmp(mf,"Invalid AspectRatioType: %d",(int)v);
ti->Video.AspectRatioType = (unsigned char)v;
break;
case 0x54aa: // PixelCropBottom
v = readUInt(mf,(unsigned)len);
if (v>0xffffffff)
errorjmp(mf,"PixelCropBottom is too large");
ti->Video.CropB = (unsigned)v;
break;
case 0x54bb: // PixelCropTop
v = readUInt(mf,(unsigned)len);
if (v>0xffffffff)
errorjmp(mf,"PixelCropTop is too large");
ti->Video.CropT = (unsigned)v;
break;
case 0x54cc: // PixelCropLeft
v = readUInt(mf,(unsigned)len);
if (v>0xffffffff)
errorjmp(mf,"PixelCropLeft is too large");
ti->Video.CropL = (unsigned)v;
break;
case 0x54dd: // PixelCropRight
v = readUInt(mf,(unsigned)len);
if (v>0xffffffff)
errorjmp(mf,"PixelCropRight is too large");
ti->Video.CropR = (unsigned)v;
break;
case 0x2eb524: // ColourSpace
ti->Video.ColourSpace = (unsigned)readUInt(mf,4);
break;
case 0x2fb523: // GammaValue
ti->Video.GammaValue = readFloat(mf,(unsigned)len);
break;
ENDFOR(mf);
}
static void parseAudioInfo(MatroskaFile *mf,ulonglong toplen,struct TrackInfo *ti) {
ulonglong v;
FOREACH(mf,toplen)
case 0xb5: // SamplingFrequency
ti->Audio.SamplingFreq = readFloat(mf,(unsigned)len);
break;
case 0x78b5: // OutputSamplingFrequency
ti->Audio.OutputSamplingFreq = readFloat(mf,(unsigned)len);
break;
case 0x9f: // Channels
v = readUInt(mf,(unsigned)len);
if (v<1 || v>255)
errorjmp(mf,"Invalid Channels value");
ti->Audio.Channels = (unsigned char)v;
break;
case 0x7d7b: // ChannelPositions
skipbytes(mf,len);
break;
case 0x6264: // BitDepth
v = readUInt(mf,(unsigned)len);
#if 0
if ((v<1 || v>255) && !IsWritingApp(mf,"AVI-Mux GUI"))
errorjmp(mf,"Invalid BitDepth: %d",(int)v);
#endif
ti->Audio.BitDepth = (unsigned char)v;
break;
ENDFOR(mf);
if (ti->Audio.Channels == 0)
ti->Audio.Channels = 1;
if (mkv_TruncFloat(ti->Audio.SamplingFreq) == 0)
ti->Audio.SamplingFreq = mkfi(8000);
if (mkv_TruncFloat(ti->Audio.OutputSamplingFreq)==0)
ti->Audio.OutputSamplingFreq = ti->Audio.SamplingFreq;
}
static void CopyStr(char **src,char **dst) {
size_t l;
if (!*src)
return;
l = strlen(*src)+1;
memcpy(*dst,*src,l);
*src = *dst;
*dst += l;
}
static void parseTrackEntry(MatroskaFile *mf,ulonglong toplen) {
struct TrackInfo t,*tp,**tpp;
ulonglong v;
char *cp = NULL;
size_t cplen = 0, cpadd = 0;
unsigned CompScope = 1;
if (mf->nTracks >= MAX_TRACKS)
errorjmp(mf,"Too many tracks.");
// clear track info
memset(&t,0,sizeof(t));
// fill default values
t.Enabled = 1;
t.Default = 1;
t.Lacing = 1;
t.TimecodeScale = mkfi(1);
t.DecodeAll = 1;
FOREACH(mf,toplen)
case 0xd7: // TrackNumber
v = readUInt(mf,(unsigned)len);
if (v>255)
errorjmp(mf,"Track number is >255 (%d)",(int)v);
t.Number = (unsigned char)v;
break;
case 0x73c5: // TrackUID
t.UID = readUInt(mf,(unsigned)len);
break;
case 0x83: // TrackType
v = readUInt(mf,(unsigned)len);
if (v<1 || v>254)
errorjmp(mf,"Invalid track type: %d",(int)v);
t.Type = (unsigned char)v;
break;
case 0xb9: // Enabled
t.Enabled = readUInt(mf,(unsigned)len)!=0;
break;
case 0x88: // Default
t.Default = readUInt(mf,(unsigned)len)!=0;
break;
case 0x9c: // Lacing
t.Lacing = readUInt(mf,(unsigned)len)!=0;
break;
case 0x6de7: // MinCache
v = readUInt(mf,(unsigned)len);
if (v > 0xffffffff)
errorjmp(mf,"MinCache is too large");
t.MinCache = (unsigned)v;
break;
case 0x6df8: // MaxCache
v = readUInt(mf,(unsigned)len);
if (v > 0xffffffff)
errorjmp(mf,"MaxCache is too large");
t.MaxCache = (unsigned)v;
break;
case 0x23e383: // DefaultDuration
t.DefaultDuration = readUInt(mf,(unsigned)len);
break;
case 0x23314f: // TrackTimecodeScale
t.TimecodeScale = readFloat(mf,(unsigned)len);
break;
case 0x55ee: // MaxBlockAdditionID
t.MaxBlockAdditionID = (unsigned)readUInt(mf,(unsigned)len);
break;
case 0x536e: // Name
if (t.Name)
errorjmp(mf,"Duplicate Track Name");
STRGETA(mf,t.Name,len);
break;
case 0x22b59c: // Language
if (t.Language)
errorjmp(mf,"Duplicate Track Language");
STRGETA(mf,t.Language,len);
break;
case 0x86: // CodecID
if (t.CodecID)
errorjmp(mf,"Duplicate CodecID");
STRGETA(mf,t.CodecID,len);
break;
case 0x63a2: // CodecPrivate
if (cp)
errorjmp(mf,"Duplicate CodecPrivate");
if (len>262144) // 256KB
errorjmp(mf,"CodecPrivate is too large: %d",(int)len);
cplen = (unsigned)len;
cp = alloca(cplen);
readbytes(mf,cp,(int)cplen);
break;
case 0x258688: // CodecName
skipbytes(mf,len);
break;
case 0x3a9697: // CodecSettings
skipbytes(mf,len);
break;
case 0x3b4040: // CodecInfoURL
skipbytes(mf,len);
break;
case 0x26b240: // CodecDownloadURL
skipbytes(mf,len);
break;
case 0xaa: // CodecDecodeAll
t.DecodeAll = readUInt(mf,(unsigned)len)!=0;
break;
case 0x6fab: // TrackOverlay
v = readUInt(mf,(unsigned)len);
if (v>255)
errorjmp(mf,"Track number in TrackOverlay is too large: %d",(int)v);
t.TrackOverlay = (unsigned char)v;
break;
case 0xe0: // VideoInfo
parseVideoInfo(mf,len,&t);
break;
case 0xe1: // AudioInfo
parseAudioInfo(mf,len,&t);
break;
case 0x6d80: // ContentEncodings
FOREACH(mf,len)
case 0x6240: // ContentEncoding
FOREACH(mf,len)
case 0x5031: // ContentEncodingOrder
readUInt(mf,(unsigned)len);
break;
case 0x5032: // ContentEncodingScope
CompScope = (unsigned)readUInt(mf,(unsigned)len);
break;
case 0x5033: // ContentEncodingType
readUInt(mf,(unsigned)len);
break;
case 0x5034: // ContentCompression
// fill in defaults
t.CompEnabled = 1;
t.CompMethod = COMP_ZLIB;
FOREACH(mf,len)
case 0x4254: // ContentCompAlgo
v = readUInt(mf,(unsigned)len);
if (v != 0)
errorjmp(mf,"Unsupported compression algorithm: %d",(int)v);
t.CompEnabled = 1;
t.CompMethod = COMP_ZLIB;
break;
case 0x4255: // ContentCompSettings
skipbytes(mf,len);
break;
ENDFOR(mf);
break;
// TODO Implement Encryption/Signatures
ENDFOR(mf);
break;
ENDFOR(mf);
break;
ENDFOR(mf);
// validate track info
if (!t.CodecID)
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 && (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 (!(CompScope & 1))
t.CompEnabled = 0;
// allocate new track
tpp = AGET(mf,Tracks);
// copy strings
if (t.Name)
cpadd += strlen(t.Name)+1;
if (t.Language)
cpadd += strlen(t.Language)+1;
if (t.CodecID)
cpadd += strlen(t.CodecID)+1;
tp = mf->cache->memalloc(mf->cache,sizeof(*tp) + cplen + cpadd);
if (tp == NULL)
errorjmp(mf,"Out of memory");
memcpy(tp,&t,sizeof(*tp));
memcpy(tp+1,cp,cplen);
if (cplen) {
tp->CodecPrivate = tp+1;
tp->CodecPrivateSize = (unsigned)cplen;
}
cp = (char*)(tp+1) + cplen;
CopyStr(&tp->Name,&cp);
CopyStr(&tp->Language,&cp);
CopyStr(&tp->CodecID,&cp);
// set default language
if (!tp->Language)
tp->Language="eng";
*tpp = tp;
}
static void parseTracks(MatroskaFile *mf,ulonglong toplen) {
mf->seen.Tracks = 1;
FOREACH(mf,toplen)
case 0xae: // TrackEntry
parseTrackEntry(mf,len);
break;
ENDFOR(mf);
}
static void addCue(MatroskaFile *mf,ulonglong pos,ulonglong timecode) {
struct Cue *cc = AGET(mf,Cues);
cc->Time = timecode;
cc->Position = pos;
cc->Track = 0;
cc->Block = 0;
}
static void fixupCues(MatroskaFile *mf) {
// adjust cues, shift cues if file does not start at 0
unsigned i;
longlong adjust = mf->firstTimecode * mf->Seg.TimecodeScale;
for (i=0;i<mf->nCues;++i) {
mf->Cues[i].Time *= mf->Seg.TimecodeScale;
mf->Cues[i].Time -= adjust;
}
}
static void parseCues(MatroskaFile *mf,ulonglong toplen) {
jmp_buf jb;
ulonglong v;
struct Cue cc;
unsigned i,j,k;
mf->seen.Cues = 1;
mf->nCues = 0;
cc.Block = 0;
memcpy(&jb,&mf->jb,sizeof(jb));
if (setjmp(mf->jb)) {
memcpy(&mf->jb,&jb,sizeof(jb));
mf->nCues = 0;
mf->seen.Cues = 0;
return;
}
FOREACH(mf,toplen)
case 0xbb: // CuePoint
FOREACH(mf,len)
case 0xb3: // CueTime
cc.Time = readUInt(mf,(unsigned)len);
break;
case 0xb7: // CueTrackPositions
FOREACH(mf,len)
case 0xf7: // CueTrack
v = readUInt(mf,(unsigned)len);
if (v>255)
errorjmp(mf,"CueTrack points to an invalid track: %d",(int)v);
cc.Track = (unsigned char)v;
break;
case 0xf1: // CueClusterPosition
cc.Position = readUInt(mf,(unsigned)len);
break;
case 0x5378: // CueBlockNumber
cc.Block = readUInt(mf,(unsigned)len);
break;
case 0xea: // CodecState
readUInt(mf,(unsigned)len);
break;
case 0xdb: // CueReference
FOREACH(mf,len)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -