1 /***************************************************************************
2 
3     copyright            : (C) 2007/2015 by mean
4     email                : fixounet@free.fr
5  * https://arashafiei.wordpress.com/2012/11/13/quick-dash/
6  ***************************************************************************/
7 
8 /***************************************************************************
9  *                                                                         *
10  *   This program is free software; you can redistribute it and/or modify  *
11  *   it under the terms of the GNU General Public License as published by  *
12  *   the Free Software Foundation; either version 2 of the License, or     *
13  *   (at your option) any later version.                                   *
14  *                                                                         *
15  ***************************************************************************/
16 
17 
18 #include <math.h>
19 
20 #include "ADM_default.h"
21 #include "ADM_Video.h"
22 
23 #include "fourcc.h"
24 #include "ADM_mp4.h"
25 #include "DIA_coreToolkit.h"
26 #include "ADM_getbits.h"
27 #include "ADM_coreUtils.h"
28 #include "ADM_mp4Tree.h"
29 #include "ADM_vidMisc.h"
30 
31 #if 1
32 #define aprintf(...) {}
33 #else
34 #define aprintf printf
35 #endif
36 /**
37       \fn parseDash
38       \brief Parse sidx header
39 */
parseMoof(adm_atom & tom)40 bool MP4Header::parseMoof(adm_atom &tom)
41 {
42         ADMAtoms id;
43         uint32_t container;
44         aprintf("---\n");
45         while(!tom.isDone())
46         {
47             adm_atom son(&tom);
48             if(!ADM_mp4SearchAtomName(son.getFCC(), &id,&container))
49             {
50               aprintf("[MOOF]Found atom %s unknown\n",fourCC::tostringBE(son.getFCC()));
51               son.skipAtom();
52               continue;
53             }
54             switch(id)
55             {
56                 case ADM_MP4_MFHD: son.skipAtom();break;
57                 case ADM_MP4_TRAF: parseTraf(son,tom.getStartPos());break;
58                 default:break;
59             }
60             aprintf("[MOOF]Found atom %s \n",fourCC::tostringBE(son.getFCC()));
61             son.skipAtom();
62         }
63         tom.skipAtom();
64         aprintf("---\n");
65         return false;
66 }
67 /**
68  *
69  * @param desc
70  * @return
71  */
lookupIndex(int desc)72 int  MP4Header::lookupIndex(int desc)
73 {
74     for(int i=0;i<=this->nbAudioTrack;i++)
75         if(_tracks[i].id==desc)
76             return i;
77     return -1;
78 }
79 /**
80  *
81  * @param tom
82  * @return
83  */
parseTraf(adm_atom & tom,uint64_t moofStart)84 bool MP4Header::parseTraf(adm_atom &tom,uint64_t moofStart)
85 {
86         ADMAtoms id;
87         uint32_t container;
88         aprintf("[TRAF] Starting at 0x%" PRIx64"\n",moofStart);
89         uint32_t trafFlags=0;
90         mp4TrafInfo info;
91         int trackIndex=-1;
92         while(!tom.isDone())
93         {
94             adm_atom son(&tom);
95             if(!ADM_mp4SearchAtomName(son.getFCC(), &id,&container))
96             {
97               aprintf("[MOOF]Found atom %s unknown\n",fourCC::tostringBE(son.getFCC()));
98               son.skipAtom();
99               continue;
100             }
101             switch(id)
102             {
103                 case ADM_MP4_TRUN:
104                     if(trackIndex==-1)
105                         break;
106                     else
107                         parseTrun(trackIndex,son,info);
108                     break;
109                 case ADM_MP4_TFHD:
110                 {
111                     trafFlags=son.read32()&0xfffff;
112 
113                     info.trackID=son.read32();
114                     mp4TrexInfo *trx=NULL;
115                     for(int i=0;i<nbTrex;i++)
116                     {
117                         if(_trexData[i]->trackID==info.trackID)
118                             trx=_trexData[i];
119                     }
120                     aprintf("[TFHD] Track=%d flags =0x%x\n",info.trackID,trafFlags);
121 #define TRAF_INFO(a,b,s)   if(trafFlags&a)  {info.b=son.read##s();aprintf("TFHD:"#b"=%d\n",(int)info.b);}
122 
123                     TRAF_INFO(1,baseOffset,64);
124                     TRAF_INFO(2,sampleDesc,32);
125                     TRAF_INFO(8,defaultDuration,32);
126                     TRAF_INFO(0x10,defaultSize,32);
127                     TRAF_INFO(0x20,defaultFlags,32);
128 
129                     if(trafFlags&0x10000) {aprintf("Empty duration\n");info.emptyDuration=true;}
130                     if(trx)
131                     {
132 #define CPY_TREX(a) if(!info.a) { info.a=trx->a; aprintf("[TFHD] Using "#a" from trex = %u\n",trx->a); }
133                         CPY_TREX(sampleDesc)
134                         CPY_TREX(defaultDuration)
135                         CPY_TREX(defaultSize)
136                         CPY_TREX(defaultFlags)
137                     }
138                     if(trafFlags&0x20000)
139                     {
140 
141                             info.baseIsMoof=true;
142                             info.baseOffset=moofStart;
143                             aprintf("base is moof at %llx\n",(long long int)info.baseOffset);
144                     }
145                     trackIndex=lookupIndex(info.trackID);
146                     if(-1==trackIndex)
147                     {
148                         ADM_warning("Cannot find track with id %d\n",info.trackID);
149                     }
150                     break;
151                 }
152                 case ADM_MP4_TFDT:
153                 {
154                     uint32_t version=son.read();
155                     aprintf("[TRAF]Found atom %s version=%d\n",fourCC::tostringBE(son.getFCC()),version);
156                     son.read();son.read();son.read();
157                     if(version==1)
158                         info.baseDts=son.read64();
159                     else
160                         info.baseDts=son.read32();
161                     aprintf("[TFDT] Base DTS=%ld\n",(long int)info.baseDts);
162                 }
163                     break;
164                 default:break;
165             }
166             son.skipAtom();
167         }
168         tom.skipAtom();
169         aprintf("[/TRAF]\n");
170         return false;
171 }
172 /**
173  * \fn parseTrun
174  * @param tom
175  * @return
176  */
parseTrun(int trackNo,adm_atom & tom,const mp4TrafInfo & info)177 bool MP4Header::parseTrun(int trackNo,adm_atom &tom,const mp4TrafInfo &info)
178 {
179     uint32_t flags=tom.read32()& 0xfffffff;
180     aprintf("[TRUN] Flags=%x\n",flags);
181     uint32_t count=tom.read32();
182     int64_t  firstOffset=info.baseOffset;
183     uint32_t  firstSampleFlags=0;
184     std::vector <mp4Fragment>   &fragList=_tracks[trackNo].fragments;
185     if(flags & 0x1)
186     {
187             firstOffset+=tom.read32(); // Signed!
188     }
189     if(flags & 0x4)
190             firstSampleFlags=tom.read32(); // Signed!
191     else
192             firstSampleFlags=info.defaultFlags;
193 
194     aprintf("[TRUN] count=%d, offset=0x%" PRIx64", base=0x%" PRIx64", flags=%x\n",count,firstOffset,info.baseOffset,firstSampleFlags);
195     for(int i=0;i<count;i++)
196     {
197        mp4Fragment frag;
198 
199 #define FLAGS(a,b,c) {if(flags & a)         frag.b=tom.read32(); else frag.b=c;}
200         FLAGS(0x100,duration,info.defaultDuration);
201         FLAGS(0x200,size,info.defaultSize);
202         if(!i)
203             FLAGS(0x400,flags,firstSampleFlags)
204         else
205             FLAGS(0x400,flags,info.defaultFlags)
206 
207         frag.offset=firstOffset;
208         firstOffset+=frag.size;
209         FLAGS(0x800,composition,0);
210         aprintf("[TRUN] duration=%d, size=%d,flags=%x,composition=%d\n",frag.duration,frag.size,frag.flags,frag.composition);
211         fragList.push_back(frag);
212 
213     }
214     tom.skipAtom();
215     return true;
216 }
217 /**
218  *
219  * @return
220  */
indexVideoFragments(int trackNo)221 bool MP4Header::indexVideoFragments(int trackNo)
222 {
223      MP4Track *trk=&_tracks[trackNo];
224      std::vector <mp4Fragment>   &fragList=_tracks[trackNo].fragments;
225     trk->nbIndex=fragList.size();
226     trk->index=new MP4Index[trk->nbIndex];
227     uint64_t sum=0;
228     int intra=0;
229     bool constantFps=true;
230     uint32_t thisone,step=1;
231     uint32_t previous=0;
232     for(uint32_t i=0;i<trk->nbIndex;i++)
233     {
234         MP4Index *dex=trk->index+i;
235         dex->offset=fragList[i].offset;
236         dex->size=fragList[i].size;
237         trk->totalDataSize+=fragList[i].size;
238         thisone=fragList[i].duration;
239         if(i+1<trk->nbIndex)
240         {
241             if(!i) step=thisone;
242             if(i && step>1 && thisone!=previous && thisone && previous)
243             {
244                 constantFps=false;
245                 if(thisone>previous)
246                 {
247                     if(thisone%previous)
248                         step=1;
249                 }else
250                 {
251                     if(previous%thisone)
252                         step=1;
253                     else if(step>thisone)
254                         step=thisone;
255                 }
256             }
257             previous=thisone;
258         }
259 
260         double dts=sum;
261         double ctts=fragList[i].composition;
262 
263         dts=dts/_videoScale;
264         dts*=1000000.;
265         dts+=0.49;
266         ctts=ctts/_videoScale;
267         ctts*=1000000.;
268         ctts+=0.49;
269         dex->dts=dts;
270         dex->pts=dex->dts+ctts;
271         if(!(fragList[i].flags &(0x00010000|0x01000000)))
272         {
273             dex->intra=AVI_KEY_FRAME;
274             intra++;
275         }
276         else
277             dex->intra=0;
278         sum+=thisone;
279         aprintf("[FRAG] Video entry %u offset=0x%llx size=%d dts=%s ",i,dex->offset,(int)dex->size,ADM_us2plain(dex->dts));
280         aprintf("pts=%s\n",ADM_us2plain(dex->pts));
281     }
282     printf("Found %d intra\n",intra);
283     MP4Index *ff=trk->index;
284     ff->intra=AVI_KEY_FRAME;
285     _videostream.dwLength= _mainaviheader.dwTotalFrames=_tracks[0].nbIndex;
286     _videostream.dwScale=step;
287     _videostream.dwRate=_videoScale;
288     ADM_info("Setting video timebase to %u / %u\n",step,_videoScale);
289     fragList.clear();
290     if(constantFps)
291     {
292         _mainaviheader.dwMicroSecPerFrame=0; // force usage of fraction for fps
293         return true;
294     }
295     double total=sum;
296     total/=_videostream.dwLength;
297     total*=1000.*1000.;
298     total/=_videoScale;
299     total+=0.49;
300     _mainaviheader.dwMicroSecPerFrame=(int32_t)total;
301 
302     return true;
303 }
304 
305 /**
306  *
307  * @return
308  */
indexAudioFragments(int trackNo)309 bool MP4Header::indexAudioFragments(int trackNo)
310 {
311      MP4Track *trk=&_tracks[trackNo];
312      std::vector <mp4Fragment>   &fragList=_tracks[trackNo].fragments;
313     trk->nbIndex=fragList.size();
314     trk->index=new MP4Index[trk->nbIndex];
315     uint64_t sum=0;
316     for(uint32_t i=0;i<trk->nbIndex;i++)
317     {
318         MP4Index *dex=trk->index+i;
319         dex->offset=fragList[i].offset;
320         dex->size=fragList[i].size;
321         trk->totalDataSize+=fragList[i].size;
322 
323         double dts=sum;
324         dts/=trk->scale;
325         dts*=1000000.;
326         dex->dts=dts;
327         dex->pts=dex->dts;
328         if(fragList[i].composition)
329         {
330             dts=fragList[i].composition;
331             dts/=trk->scale;
332             dts*=1000000.;
333             dex->pts+=dts;
334         }
335         dex->intra=0;
336         sum+=fragList[i].duration;
337         aprintf("[FRAG] Audio entry %d offset=0x%llx size=%d dts=%s ",i,dex->offset,(int)dex->size,ADM_us2plain(dex->dts));
338         aprintf("pts=%s\n",ADM_us2plain(dex->pts));
339     }
340     fragList.clear();
341     return true;
342 }
343 // EOF
344 
345 
346