/** \fn find \brief Search for the tag given and returns the corresponding atom */ uint8_t ADM_ebml_file::simplefind(MKV_ELEM_ID prim,uint64_t *len,uint32_t rewind) { uint64_t id,alen; ADM_MKV_TYPE type; const char *ss; vprintf("[MKV] Simple Searching for tag %llx\n",prim); if(rewind) seek(_begin); while(!finished()) { readElemId(&id,&alen); if(!ADM_searchMkvTag( (MKV_ELEM_ID)id,&ss,&type)) { vprintf("[MKV] Tag 0x%x not found\n",id); skip(alen); continue; } if(!alen) { printf("[MKV] WARNING ZERO SIZED ATOM %s %llu/%llu\n",ss,tell(),_fileSize); continue; } vprintf("Found Tag : %x (%s)\n",id,ss); if(id==prim) { *len=alen; return 1; }else skip(alen); } vprintf("[MKV] Failed to locate %llx\n",prim); return 0; }
/** \fn analyzeTracks \brief Read Tracks Info. */ uint8_t mkvHeader::analyzeTracks(void *head,uint32_t headlen) { uint64_t id,len; ADM_MKV_TYPE type; const char *ss; ADM_ebml_file father( (ADM_ebml_file *)head,headlen); while(!father.finished()) { father.readElemId(&id,&len); if(!ADM_searchMkvTag( (MKV_ELEM_ID)id,&ss,&type)) { printf("[MKV] Tag 0x%x not found (len %llu)\n",id,len); father.skip(len); continue; } ADM_assert(ss); if(id!=MKV_TRACK_ENTRY) { printf("[MKV] skipping %s\n",ss); father.skip(len); continue; } if(!analyzeOneTrack(&father,len)) return 0; } return 1; }
/** \fn walk \brief Walk a matroska atom and print out what is found. */ uint8_t mkvHeader::walk(void *seed) { uint64_t id,len; ADM_MKV_TYPE type; const char *ss; ADM_ebml_file *father=(ADM_ebml_file *)seed; while(!father->finished()) { father->readElemId(&id,&len); if(!ADM_searchMkvTag( (MKV_ELEM_ID)id,&ss,&type)) { printf("[MKV] Tag 0x%x not found (len %llu)\n",id,len); father->skip(len); continue; } ADM_assert(ss); switch(type) { case ADM_MKV_TYPE_CONTAINER: father->skip(len); printf("%s skipped\n",ss); break; case ADM_MKV_TYPE_UINTEGER: printf("%s:%llu\n",ss,father->readUnsignedInt(len)); break; case ADM_MKV_TYPE_INTEGER: printf("%s:%lld\n",ss,father->readSignedInt(len)); break; case ADM_MKV_TYPE_STRING: { char string[len+1]; string[0]=0; father->readString(string,len); printf("%s:<%s>\n",ss,string); break; } default: printf("%s skipped\n",ss); father->skip(len); break; } } return 1; }
int main(int argc, char *argv[]) { ADM_ebml_file *ebml=new ADM_ebml_file ; uint64_t id,len; ADM_MKV_TYPE type; const char *ss; if(!ebml->open(argv[1])) ADM_assert(0); // Read level 1 stuff while(!ebml->finished()) { ebml->readElemId(&id,&len); if(!ADM_searchMkvTag( (MKV_ELEM_ID)id,&ss,&type)) { printf("[MKV] Tag 0x%x not found\n",id); ebml->skip(len); continue; } uint64_t w=ebml->tell(); printf("Found Tag : %x (%s) at 0x%x size %d end at 0x%x\n",id,ss,w,len,w+len); if(type==ADM_MKV_TYPE_CONTAINER) { ADM_mkvWalk(ebml,len); if(ebml->tell() > w+len) { printf("*** WARNING INCORRECT CONTAINER SIZE : %d vs real size %d\n",len,ebml->tell()-w); } else { printf(">Seeking from 0x%x to 0x%x (size %d)\n",w,w+len,len); ebml->seek(w+len); } }else ebml->skip(len); } return 0; }
uint8_t mkvAudio::getPacket(uint8_t *dest, uint32_t *packlen, uint32_t *samples,uint32_t *timecode) { uint64_t fileSize,len,bsize,pos; uint32_t alen,vlen; uint64_t id; ADM_MKV_TYPE type; const char *ss; vprintf("Enter: Currently at :%llx\n",_clusterParser->tell()); // Have we still lace to go ? if(_currentLace<_maxLace) { _clusterParser->readBin(dest,_Laces[_currentLace]); *packlen= _Laces[_currentLace]; vprintf("Continuing lacing : %u bytes, lacing %u/%u\n",*packlen,_currentLace,_maxLace); _currentLace++; *samples=_frameDurationInSample; *timecode=_curTimeCode; return 1; } while(1) { vprintf("While: Currently at :%llx\n",_clusterParser->tell()); // need to switch cluster ? if(_clusterParser->finished()) { if(!goToCluster(_currentCluster+1)) { printf("[MKVAUDIO] cannot go to next cluster\n"); return 0; } _currentCluster++; } // Ok read a new block while(!_clusterParser->finished()) { _clusterParser->readElemId(&id,&len); pos=_clusterParser->tell(); if(!ADM_searchMkvTag( (MKV_ELEM_ID)id,&ss,&type)) { vprintf("[MKVAUDIO] unknown tag %x\n",id); _clusterParser->skip(len); continue; } vprintf("[MKVAudio]Found tag %x (%s) at 0x%llx len %u\n",id,ss,_clusterParser->tell(),len); switch(id) { default: case MKV_TIMECODE: _clusterParser->skip(len); break; case MKV_BLOCK_GROUP: break; case MKV_SIMPLE_BLOCK: case MKV_BLOCK: { uint32_t tid=_clusterParser->readEBMCode(); uint64_t tail=pos+len; uint64_t head=pos; // FIXME WARNING ASSUME TRACK FITS ON 1 BYTE! len--; vprintf("Tid = %u, my tid=%u\n",tid,_track->streamIndex); if(tid!=_track->streamIndex) { _clusterParser->skip(len); // skip this block break; // not our track } // Skip timecode int tc=_clusterParser->readUnsignedInt(2); // FIXME Should be signed if(tc<0) tc=0; _curTimeCode=(uint32_t )tc; len-=2; *timecode=_curTimeCode; uint8_t flags=_clusterParser->readu8(); len--; uint32_t remaining=len; uint32_t lacing=((flags>>1)&3); switch(lacing) { case 0 : // no lacing vprintf("No lacing :%d bytes\n",remaining); _clusterParser->readBin(dest,remaining); *packlen=remaining; *samples=_frameDurationInSample; _currentLace=_maxLace=0; return 1; case 1: //Xiph lacing { int nbLaces=_clusterParser->readu8()+1; ADM_assert(nbLaces<MKV_MAX_LACES); for(int i=0;i<nbLaces-1;i++) { int v=0; int lce=0; while( (v=_clusterParser->readu8())==0xff) lce+=v; lce+=v; _Laces[i]=lce; } int64_t d=_clusterParser->tell(); d=tail-d; /* We have the remaining size after laces, substract the already known lace size */ for(int i=0;i<nbLaces-1;i++) { d-=_Laces[i]; } // What is left is the sift of the last lace if(d>0) _Laces[nbLaces-1]=(uint32_t)d; else { printf("[MKVAUDIO] OOps overflow on Xiph\n"); nbLaces--; } _currentLace=0; _maxLace=nbLaces; return getPacket(dest, packlen, samples); } break; case 2 : // constant size lacing { int nbLaces=_clusterParser->readu8()+1; remaining--; int bsize=remaining/nbLaces; vprintf("NbLaces :%u lacesize:%u\n",nbLaces,bsize); ADM_assert(nbLaces<MKV_MAX_LACES); for(int i=0;i<nbLaces;i++) { _Laces[i]=bsize; } _currentLace=0; _maxLace=nbLaces; return getPacket(dest, packlen, samples); } break; case 3: // Ebml lacing { int nbLaces=_clusterParser->readu8()+1; int32_t curSize=_clusterParser->readEBMCode(); int32_t delta; vprintf("Ebml nbLaces :%u lacesize(0):%u\n",nbLaces,curSize); _Laces[0]=curSize; ADM_assert(nbLaces<MKV_MAX_LACES); for(int i=1;i<nbLaces-1;i++) { delta=_clusterParser->readEBMCode_Signed(); vprintf("Ebml delta :%d lacesize[%d]->:%d\n",delta,i,curSize+delta); curSize+=delta; ADM_assert(curSize>0); _Laces[i]=curSize; } int64_t d=_clusterParser->tell(); d=tail-d; /* We have the remaining size after laces, substract the already known lace size */ for(int i=0;i<nbLaces-1;i++) { d-=_Laces[i]; } // What is left is the sift of the last lace if(d>0) _Laces[nbLaces-1]=(uint32_t)d; else { printf("[MKVAUDIO] OOps overflow on ebml\n"); nbLaces--; } _currentLace=0; _maxLace=nbLaces; return getPacket(dest, packlen, samples); } break; default: printf("Unsupported lacing %u\n",lacing); _clusterParser->seek(pos+len); } } break; } } } return 0; }
void ADM_mkvWalk(ADM_ebml_file *working, uint32_t size) { uint64_t id,len; ADM_MKV_TYPE type; const char *ss; static int recurse=0; uint64_t pos; recurse++; ADM_ebml_file son(working,size); while(!son.finished()) { pos=son.tell(); son.readElemId(&id,&len); if(!ADM_searchMkvTag( (MKV_ELEM_ID)id,&ss,&type)) { recTab();printf("[MKV] Tag 0x%x not found\n",id); son.skip(len); continue; } recTab();printf("at 0x%llx, Found Tag : %x (%s) type %d (%s) size %d, start at 0x%x end at 0x%x\n",pos,id,ss,type,ADM_mkvTypeAsString(type),len,working->tell(),working->tell()+len); uint32_t val; switch(type) { case ADM_MKV_TYPE_CONTAINER: //if(id!=MKV_CLUSTER) if(len) ADM_mkvWalk(&son,len); else { printf("******************************* WARNING ZERO SIZE ******************\n"); } //else // son.skip(len); break; case ADM_MKV_TYPE_UINTEGER: val=son.readUnsignedInt(len); recTab();printf("\tval uint: %llu (0x%llx) \n",val,val); break; case ADM_MKV_TYPE_UTF8: { char string[len+1]; string[0]=0; son.readString(string,len); recTab();printf("\tval utf8 as string: <%s> \n",string); } break; case ADM_MKV_TYPE_FLOAT: recTab();printf("\tval float: %f \n",son.readFloat(len)); break; case ADM_MKV_TYPE_INTEGER: recTab();printf("\tval int: %lld \n",son.readSignedInt(len)); break; case ADM_MKV_TYPE_STRING: { char string[len+1]; string[0]=0; son.readString(string,len); recTab();printf("\tval string: <%s> \n",string); break; } default: if(id==MKV_BLOCK) { recTab();printf("\t\tTrack :%u",son.readu8()-128); // Assume 1 byte code //printf(" Timecode:%d",son.reads16()); son.skip(2); int lacing=son.readu8(); printf(" Lacing :%x "); if(lacing&1) printf(" keyframe "); lacing=(lacing>>1)&3; switch(lacing) { case 0:printf("No lacing\n");break; case 1:printf("Xiph lacing\n");break; case 3:printf("Ebml lacing\n");break; case 2:printf("Fixed lacing :%u remaining:%u\n",son.readu8()+1,len-5);len--;break; } son.skip(len-4); } else { recTab();printf("Skipping %s\n",ss); son.skip(len); } break; }