📄 matroskaparser.c
字号:
case 0x96: // CueRefTime
readUInt(mf,(unsigned)len);
break;
case 0x97: // CueRefCluster
readUInt(mf,(unsigned)len);
break;
case 0x535f: // CueRefNumber
readUInt(mf,(unsigned)len);
break;
case 0xeb: // CueRefCodecState
readUInt(mf,(unsigned)len);
break;
ENDFOR(mf);
break;
ENDFOR(mf);
break;
ENDFOR(mf);
if (mf->nCues == 0 && mf->pCluster - mf->pSegment != cc.Position)
addCue(mf,mf->pCluster - mf->pSegment,mf->firstTimecode);
memcpy(AGET(mf,Cues),&cc,sizeof(cc));
break;
ENDFOR(mf);
memcpy(&mf->jb,&jb,sizeof(jb));
ARELEASE(mf,mf,Cues);
// bubble sort the cues and fuck the losers that write unordered cues
if (mf->nCues > 0)
for (i = mf->nCues - 1, k = 1; i > 0 && k > 0; --i)
for (j = k = 0; j < i; ++j)
if (mf->Cues[j].Time > mf->Cues[j+1].Time) {
struct Cue tmp = mf->Cues[j+1];
mf->Cues[j+1] = mf->Cues[j];
mf->Cues[j] = tmp;
++k;
}
fixupCues(mf);
}
static void parseAttachment(MatroskaFile *mf,ulonglong toplen) {
struct Attachment a,*pa;
memset(&a,0,sizeof(a));
FOREACH(mf,toplen)
case 0x467e: // Description
STRGETA(mf,a.Description,len);
break;
case 0x466e: // Name
STRGETA(mf,a.Name,len);
break;
case 0x4660: // MimeType
STRGETA(mf,a.MimeType,len);
break;
case 0x46ae: // UID
a.UID = readUInt(mf,(unsigned)len);
break;
case 0x465c: // Data
a.Position = filepos(mf);
a.Length = len;
skipbytes(mf,len);
break;
ENDFOR(mf);
if (!a.Position)
return;
pa = AGET(mf,Attachments);
memcpy(pa,&a,sizeof(a));
if (a.Description)
pa->Description = mystrdup(mf->cache,a.Description);
if (a.Name)
pa->Name = mystrdup(mf->cache,a.Name);
if (a.MimeType)
pa->MimeType = mystrdup(mf->cache,a.MimeType);
}
static void parseAttachments(MatroskaFile *mf,ulonglong toplen) {
mf->seen.Attachments = 1;
FOREACH(mf,toplen)
case 0x61a7: // AttachedFile
parseAttachment(mf,len);
break;
ENDFOR(mf);
}
static void parseChapter(MatroskaFile *mf,ulonglong toplen,struct Chapter *parent) {
struct ChapterDisplay *disp;
struct ChapterProcess *proc;
struct ChapterCommand *cmd;
struct Chapter *ch = ASGET(mf,parent,Children);
memset(ch,0,sizeof(*ch));
ch->Enabled = 1;
FOREACH(mf,toplen)
case 0x73c4: // ChapterUID
ch->UID = readUInt(mf,(unsigned)len);
break;
case 0x6e67: // ChapterSegmentUID
if (len != sizeof(ch->SegmentUID))
skipbytes(mf, len);
else
readbytes(mf, ch->SegmentUID, sizeof(ch->SegmentUID));
break;
case 0x91: // ChapterTimeStart
ch->Start = readUInt(mf,(unsigned)len);
break;
case 0x92: // ChapterTimeEnd
ch->End = readUInt(mf,(unsigned)len);
break;
case 0x98: // ChapterFlagHidden
ch->Hidden = readUInt(mf,(unsigned)len)!=0;
break;
case 0x4598: // ChapterFlagEnabled
ch->Enabled = readUInt(mf,(unsigned)len)!=0;
break;
case 0x8f: // ChapterTrack
FOREACH(mf,len)
case 0x89: // ChapterTrackNumber
*(ulonglong*)(ASGET(mf,ch,Tracks)) = readUInt(mf,(unsigned)len);
break;
ENDFOR(mf);
break;
case 0x80: // ChapterDisplay
disp = NULL;
FOREACH(mf,len)
case 0x85: // ChapterString
if (disp==NULL) {
disp = ASGET(mf,ch,Display);
memset(disp, 0, sizeof(*disp));
}
if (disp->String)
skipbytes(mf,len); // Ignore duplicate string
else
STRGETM(mf,disp->String,len);
break;
case 0x437c: // ChapterLanguage
if (disp==NULL) {
disp = ASGET(mf,ch,Display);
memset(disp, 0, sizeof(*disp));
}
if (disp->Language)
skipbytes(mf,len);
else
STRGETM(mf,disp->Language,len);
break;
case 0x437e: // ChapterCountry
if (disp==NULL) {
disp = ASGET(mf,ch,Display);
memset(disp, 0, sizeof(*disp));
}
if (disp->Country)
skipbytes(mf,len);
else
STRGETM(mf,disp->Country,len);
break;
ENDFOR(mf);
if (disp && !disp->String) {
mf->cache->memfree(mf->cache,disp->Language);
mf->cache->memfree(mf->cache,disp->Country);
--ch->nDisplay;
}
break;
case 0x6944: // ChapProcess
proc = NULL;
FOREACH(mf,len)
case 0x6955: // ChapProcessCodecID
if (proc == NULL) {
proc = ASGET(mf, ch, Process);
memset(proc, 0, sizeof(*proc));
}
proc->CodecID = (unsigned)readUInt(mf,(unsigned)len);
break;
case 0x450d: // ChapProcessPrivate
if (proc == NULL) {
proc = ASGET(mf, ch, Process);
memset(proc, 0, sizeof(*proc));
}
if (proc->CodecPrivate)
skipbytes(mf, len);
else {
proc->CodecPrivateLength = (unsigned)len;
STRGETM(mf,proc->CodecPrivate,len);
}
break;
case 0x6911: // ChapProcessCommand
if (proc == NULL) {
proc = ASGET(mf, ch, Process);
memset(proc, 0, sizeof(*proc));
}
cmd = NULL;
FOREACH(mf,len)
case 0x6922: // ChapterCommandTime
if (cmd == NULL) {
cmd = ASGET(mf,proc,Commands);
memset(cmd, 0, sizeof(*cmd));
}
cmd->Time = (unsigned)readUInt(mf,(unsigned)len);
break;
case 0x6933: // ChapterCommandString
if (cmd == NULL) {
cmd = ASGET(mf,proc,Commands);
memset(cmd, 0, sizeof(*cmd));
}
if (cmd->Command)
skipbytes(mf,len);
else {
cmd->CommandLength = (unsigned)len;
STRGETM(mf,cmd->Command,len);
}
break;
ENDFOR(mf);
if (cmd && !cmd->Command)
--proc->nCommands;
break;
ENDFOR(mf);
if (proc && !proc->nCommands)
--ch->nProcess;
break;
case 0xb6: // Nested ChapterAtom
parseChapter(mf,len,ch);
break;
ENDFOR(mf);
ARELEASE(mf,ch,Tracks);
ARELEASE(mf,ch,Display);
ARELEASE(mf,ch,Children);
}
static void parseChapters(MatroskaFile *mf,ulonglong toplen) {
struct Chapter *ch;
mf->seen.Chapters = 1;
FOREACH(mf,toplen)
case 0x45b9: // EditionEntry
ch = AGET(mf,Chapters);
memset(ch, 0, sizeof(*ch));
FOREACH(mf,len)
case 0x45bc: // EditionUID
ch->UID = readUInt(mf,(unsigned)len);
break;
case 0x45bd: // EditionFlagHidden
ch->Hidden = readUInt(mf,(unsigned)len)!=0;
break;
case 0x45db: // EditionFlagDefault
ch->Default = readUInt(mf,(unsigned)len)!=0;
break;
case 0x45dd: // EditionFlagOrdered
ch->Ordered = readUInt(mf,(unsigned)len)!=0;
break;
case 0xb6: // ChapterAtom
parseChapter(mf,len,ch);
break;
ENDFOR(mf);
break;
ENDFOR(mf);
}
static void parseTags(MatroskaFile *mf,ulonglong toplen) {
struct Tag *tag;
struct Target *target;
struct SimpleTag *st;
mf->seen.Tags = 1;
FOREACH(mf,toplen)
case 0x7373: // Tag
tag = AGET(mf,Tags);
memset(tag,0,sizeof(*tag));
FOREACH(mf,len)
case 0x63c0: // Targets
FOREACH(mf,len)
case 0x63c5: // TrackUID
target = ASGET(mf,tag,Targets);
target->UID = readUInt(mf,(unsigned)len);
target->Type = TARGET_TRACK;
break;
case 0x63c4: // ChapterUID
target = ASGET(mf,tag,Targets);
target->UID = readUInt(mf,(unsigned)len);
target->Type = TARGET_CHAPTER;
break;
case 0x63c6: // AttachmentUID
target = ASGET(mf,tag,Targets);
target->UID = readUInt(mf,(unsigned)len);
target->Type = TARGET_ATTACHMENT;
break;
case 0x63c9: // EditionUID
target = ASGET(mf,tag,Targets);
target->UID = readUInt(mf,(unsigned)len);
target->Type = TARGET_EDITION;
break;
ENDFOR(mf);
break;
case 0x67c8: // SimpleTag
st = ASGET(mf,tag,SimpleTags);
memset(st,0,sizeof(*st));
FOREACH(mf,len)
case 0x45a3: // TagName
if (st->Name)
skipbytes(mf,len);
else
STRGETM(mf,st->Name,len);
break;
case 0x4487: // TagString
if (st->Value)
skipbytes(mf,len);
else
STRGETM(mf,st->Value,len);
break;
case 0x447a: // TagLanguage
if (st->Language)
skipbytes(mf,len);
else
STRGETM(mf,st->Language,len);
break;
case 0x4484: // TagDefault
st->Default = readUInt(mf,(unsigned)len)!=0;
break;
ENDFOR(mf);
if (!st->Name || !st->Value) {
mf->cache->memfree(mf->cache,st->Name);
mf->cache->memfree(mf->cache,st->Value);
mf->cache->memfree(mf->cache,st->Language); //Picard
--tag->nSimpleTags;
}
break;
ENDFOR(mf);
break;
ENDFOR(mf);
}
static void parseContainer(MatroskaFile *mf) {
ulonglong len;
int id = readID(mf);
if (id==EOF)
errorjmp(mf,"Unexpected EOF in parseContainer");
len = readSize(mf);
switch (id) {
case 0x1549a966: // SegmentInfo
parseSegmentInfo(mf,len);
break;
case 0x1f43b675: // Cluster
parseFirstCluster(mf,len);
break;
case 0x1654ae6b: // Tracks
parseTracks(mf,len);
break;
case 0x1c53bb6b: // Cues
parseCues(mf,len);
break;
case 0x1941a469: // Attachments
parseAttachments(mf,len);
break;
case 0x1043a770: // Chapters
parseChapters(mf,len);
break;
case 0x1254c367: // Tags
parseTags(mf,len);
break;
}
}
static void parseContainerPos(MatroskaFile *mf,ulonglong pos) {
seek(mf,pos);
parseContainer(mf);
}
static void parsePointers(MatroskaFile *mf) {
jmp_buf jb;
if (mf->pSegmentInfo && !mf->seen.SegmentInfo)
parseContainerPos(mf,mf->pSegmentInfo);
if (mf->pCluster && !mf->seen.Cluster)
parseContainerPos(mf,mf->pCluster);
if (mf->pTracks && !mf->seen.Tracks)
parseContainerPos(mf,mf->pTracks);
memcpy(&jb,&mf->jb,sizeof(jb));
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)
parseContainerPos(mf,mf->pAttachments);
if (mf->pChapters && !mf->seen.Chapters)
parseContainerPos(mf,mf->pChapters);
if (mf->pTags && !mf->seen.Tags)
parseContainerPos(mf,mf->pTags);
}
memcpy(&mf->jb,&jb,sizeof(jb));
}
static void parseSegment(MatroskaFile *mf,ulonglong toplen) {
ulonglong nextpos;
unsigned nSeekHeads = 0, dontstop = 0;
// we want to read data until we find a seekhead or a trackinfo
FOREACH(mf,toplen)
case 0x114d9b74: // SeekHead
if (mf->flags & MKVF_AVOID_SEEKS) {
skipbytes(mf,len);
break;
}
nextpos = filepos(mf) + len;
do {
mf->pSeekHead = 0;
parseSeekHead(mf,len);
++nSeekHeads;
if (mf->pSeekHead) { // this is possibly a chained SeekHead
seek(mf,mf->pSeekHead);
id = readID(mf);
if (id==EOF) // chained SeekHead points to EOF?
break;
if (id != 0x114d9b74) // chained SeekHead doesnt point to a SeekHead?
break;
len = readSize(mf);
} else if (mf->pSegmentInfo && mf->pTracks && mf->pCues && mf->pCluster) { // we have pointers to all key elements
// XXX EVIL HACK
// Some software doesnt index tags via SeekHead, so we continue
// reading the segment after the second SeekHead
if (mf->pTags || nSeekHeads<2 || filepos(mf)>=start+toplen) {
parsePointers(mf);
return;
}
// reset nextpos pointer to current position
nextpos = filepos(mf);
dontstop = 1;
}
} while (mf->pSeekHead);
seek(mf,nextpos); // resume reading segment
break;
case 0x1549a966: // SegmentInfo
mf->pSegmentInfo = cur;
parseSegmentInfo(mf,len);
break;
case 0x1f43b675: // Cluster
if (!mf->pCluster)
mf->pCluster = cur;
if (mf->seen.Cluster)
skipbytes(mf,len);
else
parseFirstCluster(mf,len);
break;
case 0x1654ae6b: // Tracks
mf->pTracks = cur;
parseTracks(mf,len);
break;
case 0x1c53bb6b: // Cues
mf->pCues = cur;
parseCues(mf,len);
break;
case 0x1941a469: // Attachments
mf->pAttachments = cur;
parseAttachments(mf,len);
break;
case 0x1043a770: // Chapters
mf->pChapters = cur;
parseChapters(mf,len);
break;
case 0x1254c367: // Tags
mf->pTags = cur;
parseTags(mf,len);
break;
ENDFOR1(mf);
// if we have pointers to all key elements
if (!dontstop && mf->pSegmentInfo && mf->pTracks && mf->pCluster)
break;
ENDFOR2();
parsePointers(mf);
}
static void parseBlockAdditions(MatroskaFile *mf, ulonglong toplen, ulonglong timecode, unsigned track) {
ulonglong add_id = 1, add_pos=0, add_len=0; //Picard
unsigned char have_add;
void* add_ref = NULL;
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;
if (!have_add) add_ref = mf->cache->makeref(mf->cache,(int)len); else //Picard
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->Ref = add_ref; //Picard
add_ref = NULL;
qe->flags = FRAME_UNKNOWN_START | FRAME_UNKNOWN_END |
(((unsigned)add_id << FRAME_STREAM_SHIFT) & FRAME_STREAM_MASK);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -