1 /***************************************************************************
2     copyright            : (C) 2006 by mean
3     email                : fixounet@free.fr
4  ***************************************************************************/
5 
6 /***************************************************************************
7  *                                                                         *
8  *   This program is free software; you can redistribute it and/or modify  *
9  *   it under the terms of the GNU General Public License as published by  *
10  *   the Free Software Foundation; either version 2 of the License, or     *
11  *   (at your option) any later version.                                   *
12  *                                                                         *
13  ***************************************************************************/
14 #include "ADM_cpp.h"
15 #include "ADM_default.h"
16 #include "math.h"
17 #include "ADM_Video.h"
18 
19 #include "ADM_mkv.h"
20 #include "ADM_a52info.h"
21 #include "ADM_eac3info.h"
22 #include "ADM_dcainfo.h"
23 
24 #include "ADM_vidMisc.h"
25 #if 0
26 #define vprintf printf
27 #else
28 #define vprintf(...) {}
29 #endif
30 
31 /**
32     \fn mkvAccess
33     \brief constructor
34 
35 */
mkvAccess(const char * name,mkvTrak * track)36 mkvAccess::mkvAccess(const char *name,mkvTrak *track)
37 {
38     uint8_t ac3Buffer[20000];
39     uint32_t len,sample;
40     uint64_t timecode;
41 
42    _parser=new ADM_ebml_file();
43    ADM_assert(_parser->open(name));
44   _track=track;
45   ADM_assert(_track);
46   _currentBlock=0;
47   _currentLace=_maxLace=0;
48   goToBlock(0);
49 
50   if(track->duration && !track->wavHeader.byterate)
51     track->wavHeader.byterate=(uint32_t)(track->_sizeInBytes*1000000LL/track->duration);
52 
53   /* Check that it is really EAC3 */
54   if(_track->wavHeader.encoding==WAV_EAC3)
55   {
56      if(getPacket(ac3Buffer, &len, 20000, &timecode))
57      {
58         uint32_t syncoff;
59         ADM_EAC3_INFO efo;
60         if(ADM_EAC3GetInfo(ac3Buffer, len, &syncoff, &efo, false))
61         {
62             track->wavHeader.channels=efo.channels;
63             track->wavHeader.frequency=efo.frequency;
64             track->wavHeader.byterate=efo.byterate;
65         }else
66         {
67             track->wavHeader.encoding=WAV_AC3;
68         }
69      }
70      goToBlock(0);
71   }
72 
73   /* In case of AC3, do not trust the header...*/
74   if(_track->wavHeader.encoding==WAV_AC3)
75   {
76      if( getPacket(ac3Buffer, &len, 20000,&timecode))
77      {
78        uint32_t fq,br,chan,syncoff;
79         if( ADM_AC3GetInfo(ac3Buffer, len, &fq, &br, &chan,&syncoff) )
80         {
81             track->wavHeader.channels=chan;
82             track->wavHeader.frequency=fq;
83             track->wavHeader.byterate=br;
84         }
85      }
86      goToBlock(0);
87   }
88 
89   if(_track->wavHeader.encoding==WAV_DTS)
90   {
91      if( getPacket(ac3Buffer, &len, 20000,&timecode))
92      {
93        uint32_t syncoff,flags,nbsample;
94        ADM_DCA_INFO info;
95         if( true==ADM_DCAGetInfo(ac3Buffer, len,&info,&syncoff) )
96         {
97             track->wavHeader.channels=info.channels;
98             track->wavHeader.frequency=info.frequency;
99             track->wavHeader.byterate=info.bitrate/8;
100         }
101      }
102      goToBlock(0);
103   }
104 
105 
106 }
107 /**
108     \fn getExtraData
109 */
getExtraData(uint32_t * l,uint8_t ** d)110 bool      mkvAccess::getExtraData(uint32_t *l, uint8_t **d)
111 {
112     *l=_track->extraDataLen;
113     *d=_track->extraData;
114     return true;
115 }
116 /**
117     \fn getDurationInUs
118 */
getDurationInUs(void)119 uint64_t  mkvAccess::getDurationInUs(void)
120 {
121 
122     uint32_t limit=_track->index.size();
123     if(!limit) return 0;
124     return _track->index[limit-1].Dts;
125 }
126 /**
127     \fn mkvAccess
128     \brief destructor
129 */
~mkvAccess()130 mkvAccess::~mkvAccess()
131 {
132       if(_parser) delete _parser;
133       _parser=NULL;
134 }
135 /**
136     \fn goToCluster
137     \brief Change the cluster parser...
138 */
goToBlock(uint32_t x)139 uint8_t mkvAccess::goToBlock(uint32_t x)
140 {
141   uint32_t limit=_track->index.size();
142   if(x>=limit)
143   {
144     ADM_warning("Exceeding max cluster : asked: %u max :%u\n",x,limit);
145     return 0;  // FIXME
146   }
147 
148   _parser->seek(_track->index[x].pos);
149   _currentLace=_maxLace=0;
150   _currentBlock=x;
151   return 1;
152 }
153 /**
154     \fn goToTime
155 */
goToTime(uint64_t timeUs)156 bool      mkvAccess::goToTime(uint64_t timeUs)
157 {
158 uint64_t targetUs=timeUs;
159 int      clus=-1;
160     uint32_t limit=_track->index.size();
161     if(!limit)
162     {
163         ADM_warning("No audio index, cannot seek\n");
164         return false;
165     }
166     mkvListOfIndex *dex=&(_track->index);
167       // First identify the cluster...
168 
169             if(timeUs<(*dex)[0].Dts)
170             {
171                 clus=0;
172             }else
173             {
174                 for(int i=0;i<limit-1;i++)
175                 {
176                   if(targetUs>=(*dex)[i].Dts && targetUs<(*dex)[i+1].Dts)
177                   {
178                     clus=i;
179                     break;
180                   }
181                 }
182             }
183             if(clus==-1) clus=limit-1; // Hopefully in the last one
184             ADM_info("[MKVAUDIO] Asked for %s , go to block %d\n",ADM_us2plain(timeUs),clus);
185             ADM_info("[MKVAUDIO] This block starts at %s\n",ADM_us2plain((*dex)[clus].Dts));
186             targetUs-=(*dex)[clus].Dts; // now the time is relative
187             ADM_info("[MKVAUDIO] Offset=%" PRId64" us\n",(int64_t)targetUs);
188             goToBlock(clus);
189 
190 
191             // Now seek more finely
192             // will be off by one frame
193 #if 0
194 #define MAX_SEEK_BUFFER 20000
195             uint8_t buffer[MAX_SEEK_BUFFER];
196             uint32_t len,samples;
197             uint64_t timecode;
198             while(getPacket(buffer, &len, MAX_SEEK_BUFFER,&timecode))
199             {
200               uint64_t curTime=_clusters[_currentCluster].Dts;
201               vprintf("Wanted: %lu us clusTime : %lu Timecode:%lu us\n",timeUs,_curTimeCodeUs,timecode);
202               ADM_assert(len<MAX_SEEK_BUFFER);
203 
204               if(timecode>=(timeUs))
205               {
206                 printf("[MKV audio] fine seek to %u \n",timecode);
207                 return 1;
208               }
209             }
210             printf("Failed to seek to %u mstime\n");
211             return 0;
212 #else
213             return 1;
214 #endif
215             return 1;
216 
217 }
218 /**
219     \fn initLaces
220     \brief start a bunch of lace, compute the missing DTSs
221 */
initLaces(uint32_t nbLaces,uint64_t time)222 bool mkvAccess::initLaces(uint32_t nbLaces,uint64_t time)
223 {
224                 _maxLace=nbLaces;
225                 _currentLace=1;
226                 _lastDtsBase=time;
227                 _currentBlock++;
228                 if(_currentBlock<_track->index.size()) // is it not the last block
229                 {
230                     uint64_t deltaTime=_track->index[_currentBlock].Dts;
231                     deltaTime-=time;
232                     _laceIncrementUs=deltaTime/nbLaces;
233                     vprintf("***************DeltaTime : %" PRIu64" inc:%" PRIu64"\n",deltaTime,_laceIncrementUs);
234                 } // else keep lastIncrement, which is as good as a random value
235                 return true;
236 }
237 /**
238     \fn getPacket
239 */
getPacket(uint8_t * dest,uint32_t * packlen,uint32_t maxSize,uint64_t * timecode)240 bool    mkvAccess::getPacket(uint8_t *dest, uint32_t *packlen, uint32_t maxSize,uint64_t *timecode)
241 {
242   uint64_t fileSize,len,bsize,pos;
243   uint32_t alen,vlen;
244   uint64_t id;
245   ADM_MKV_TYPE type;
246   const char *ss;
247 
248 //  vprintf("Enter: Currently at :%llx\n",_clusterParser->tell());
249 
250     // Have we still lace to go ?
251     if(_currentLace<_maxLace)
252     {
253       *packlen= readAndRepeat(dest, _Laces[_currentLace],maxSize);
254       ADM_assert(*packlen<maxSize);
255       vprintf("Continuing lacing : %u bytes, lacing %u/%u\n",*packlen,_currentLace,_maxLace);
256       *timecode=_lastDtsBase+_laceIncrementUs*_currentLace;
257        vprintf(">>>>>>>>> %" PRIu64" \n",*timecode);
258       _currentLace++;
259       return true;
260     }
261     if(_currentBlock>=_track->index.size()) return false;
262     // Else we start a new lace (or no lacing at all)
263     goToBlock(_currentBlock);
264     mkvIndex *dex=&(_track->index[_currentBlock]);
265     uint64_t size=dex->size-3;
266     uint64_t time=dex->Dts;
267     if(!time && _currentBlock) time=ADM_AUDIO_NO_DTS;
268     vprintf("[MKV] Time :%lu block:%u\n",time,_currentBlock);
269     // Read headers & flags
270      int16_t dummyTime=_parser->readSignedInt(2);
271      //if(!track) printf("TC: %d\n",timecode);
272      uint8_t flags=_parser->readu8();
273      int     lacing=((flags>>1)&3);
274         vprintf("[MKV] Lacing : %u\n",lacing);
275      *timecode=time;
276      switch(lacing)
277             {
278               case 0 : // no lacing
279 
280                       vprintf("No lacing :%d bytes\n",(int)size);
281                       *packlen= readAndRepeat(dest,size,maxSize);
282                       _currentLace=_maxLace=0;
283                       _currentBlock++;
284                       return 1;
285               case 1: //Xiph lacing
286                 {
287                         int nbLaces=_parser->readu8()+1;
288                         size--;
289                         ADM_assert(nbLaces<MKV_MAX_LACES);
290                         for(int i=0;i<nbLaces-1;i++)
291                         {
292                           int v=0;
293                           int lce=0;
294                           while(  (v=_parser->readu8())==0xff)
295                           {
296                                 lce+=v;
297                                 size-=(1+0xff);
298                           }
299                           lce+=v;
300                           size--;
301                           size-=v;
302                           _Laces[i]=lce;
303                         }
304 
305                         // The first one has Dts
306                         *packlen= readAndRepeat(dest, _Laces[0],maxSize);
307                         _Laces[nbLaces-1]=size;
308 
309                         initLaces(nbLaces,time);
310                         return 1;
311                       }
312 
313                       break;
314               case 2 : // constant size lacing
315                       {
316                         int nbLaces=_parser->readu8()+1;
317                         size--;
318                         int bsize=size/nbLaces;
319                         vprintf("NbLaces :%u lacesize:%u\n",nbLaces,bsize);
320                         ADM_assert(nbLaces<MKV_MAX_LACES);
321                         for(int i=0;i<nbLaces;i++)
322                         {
323                           _Laces[i]=bsize;
324                         }
325                         *packlen= readAndRepeat(dest, bsize,maxSize);
326                         // The first one has Dts
327                         initLaces(nbLaces,time);
328 
329                         return 1;
330                       }
331                       break;
332 
333               case 3: // Ebml lacing
334                 {
335                         uint64_t head=_parser->tell();
336                         int nbLaces=_parser->readu8()+1;
337                         int32_t curSize=_parser->readEBMCode();
338                         int32_t delta;
339                         uint32_t sum;
340 
341 
342                         vprintf("Ebml nbLaces :%u lacesize(0):%u\n",nbLaces,curSize);
343 
344                         _Laces[0]=curSize;
345                         sum=curSize;
346                         ADM_assert(nbLaces<MKV_MAX_LACES);
347                         for(int i=1;i<nbLaces-1;i++)
348                         {
349                           delta=_parser->readEBMCode_Signed();
350                           vprintf("Ebml delta :%d lacesize[%d]->:%d\n",delta,i,curSize+delta);
351                           curSize+=delta;
352                           ADM_assert(curSize>0);
353                           _Laces[i]=curSize;
354                           sum+=curSize;
355 
356                         }
357                         uint64_t tail=_parser->tell();
358                         uint64_t consumed=head+size-tail;
359 
360                         _Laces[nbLaces-1]=consumed-sum;
361 
362                           // Take the 1st laces, it has timestamp
363                           *packlen= readAndRepeat(dest, _Laces[0],maxSize);
364                           ADM_assert(*packlen<maxSize);
365                           vprintf("Continuing lacing : dts : %lu %u bytes, lacing %u/%u\n",time,*packlen,_currentLace,_maxLace);
366                           initLaces(nbLaces,time);
367                           return 1;
368                 }
369                       break;
370               default:
371                     printf("Unsupported lacing %u\n",lacing);
372                     goToBlock(0);
373             }
374 
375   return false;
376 }
377 //EOF
378