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