1 /***************************************************************************
2 ADMMP4p.cpp - description
3 -------------------
4
5 Read quicktime/mpeg4 file format found in 3gpp file.
6 They are limited to SQCIF/QCIF video size and can
7 only contains
8 video : h263 or mpeg4
9 audio : AMR or AAC
10
11
12 For the mpeg4, the VOL headers are stored in esds atom
13 and not in the first image
14 Idem for MJPG and SVQ3
15
16 The usual tree structure of a 3gp file is
17
18 - ftyp
19 - mdat
20 - moov
21 xxx
22 trak
23 tkhd (duration / ...)
24 mdia
25 hdlr (type)
26 minf
27 stsd header for audio/video
28 stbl index to datas
29
30 We ignore other chunk as they are not vital for our aim
31 and just keep moov/mdia/minf/stsd/stbl stuff
32
33 Generic
34 *********
35 http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap2/chapter_3_section_5.html#//apple_ref/doc/uid/DontLinkBookID_69-CH204-BBCJEIIA
36
37 version 2 media descriptor :
38 ****************************** http://developer.apple.com/documentation/QuickTime/Conceptual/QT7Win_Update_Guide/Chapter03/chapter_3_section_1.html#//apple_ref/doc/uid/TP40002476-CH314-BBCDGGBB
39
40
41
42 begin : Tue Jul 2003
43 copyright : (C) 2003/2006 by mean
44 email : fixounet@free.fr
45 ***************************************************************************/
46
47 /***************************************************************************
48 * *
49 * This program is free software; you can redistribute it and/or modify *
50 * it under the terms of the GNU General Public License as published by *
51 * the Free Software Foundation; either version 2 of the License, or *
52 * (at your option) any later version. *
53 * *
54 ***************************************************************************/
55
56
57 #include <string.h>
58 #include <math.h>
59
60 #include "ADM_default.h"
61 #include "ADM_Video.h"
62
63 #include "fourcc.h"
64 #include "ADM_mp4.h"
65
66 #include "ADM_vidMisc.h"
67 #include "DIA_processing.h"
68
69 #include "ADM_videoInfoExtractor.h"
70 #include "ADM_codecType.h"
71 #include "ADM_a52info.h"
72 #include "ADM_mp3info.h"
73 #include "ADM_audioXiphUtils.h"
74
75 #if 1
76 #define aprintf(...) {}
77 #else
78 #define aprintf printf
79 #endif
80
81 //#define MP4_VERBOSE
82 #define MAX_CHUNK_SIZE (3*1024)
83
84 uint32_t ADM_UsecFromFps1000(uint32_t fps1000);
85 //****************************************************
MP4Track(void)86 MP4Track::MP4Track(void)
87 {
88 extraDataSize=0;
89 extraData=NULL;
90 index=NULL;
91 nbIndex=0;
92 id=0;
93 memset(&_rdWav,0,sizeof(_rdWav));
94 delay=0;
95 totalDataSize=0;
96 }
~MP4Track()97 MP4Track::~MP4Track()
98 {
99 if(extraData) delete [] extraData;
100 if(index) delete [] index;
101
102 index=NULL;
103 extraData=NULL;
104
105 }
106 //****************************************************
setFlag(uint32_t frame,uint32_t flags)107 uint8_t MP4Header::setFlag(uint32_t frame,uint32_t flags)
108 {
109 UNUSED_ARG(frame);
110 UNUSED_ARG(flags);
111
112 VDEO.index[frame].intra=flags;
113 return 0;
114 }
115
getFlags(uint32_t frame,uint32_t * flags)116 uint32_t MP4Header::getFlags(uint32_t frame,uint32_t *flags)
117 {
118 if(frame>= (uint32_t)_videostream.dwLength) return 0;
119 *flags=VDEO.index[frame].intra;
120
121 return 1;
122 }
123 /**
124 \fn getTime
125 */
getTime(uint32_t frameNum)126 uint64_t MP4Header::getTime(uint32_t frameNum)
127 {
128 ADM_assert(frameNum<VDEO.nbIndex);
129 // Assume if not PTS, PTS=DTS (non mpeg4/non h264 streams)
130 if(VDEO.index[frameNum].pts==ADM_COMPRESSED_NO_PTS) return VDEO.index[frameNum].dts;
131 return VDEO.index[frameNum].pts;
132 }
133 /**
134 \fn getVideoDuration
135 */
getVideoDuration(void)136 uint64_t MP4Header::getVideoDuration(void)
137 {
138 return _movieDuration*1000LL; //VDEO.index[VDEO.nbIndex-1].time;
139
140 }
141
142 #ifdef DERIVE_TB_FROM_MINIMUM_DELTA
143 /**
144 * \fn compute the minimum us delta = maximum fps
145 * \brief average fps is not good enough, it might be too high
146 * @return
147 */
refineFps(void)148 bool MP4Header::refineFps(void)
149 {
150 int n=VDEO.nbIndex;
151 uint64_t minDelta=60*1000*1000;
152 for(int i=0;i<n-1;i++)
153 {
154 MP4Index *dex=&(_tracks[0].index[i]);
155 MP4Index *next=&(_tracks[0].index[i+1]);
156 if(dex->dts==ADM_NO_PTS) continue;
157 if(next->dts==ADM_NO_PTS) continue;
158 uint64_t delta=next->dts-dex->dts;
159 if(delta<minDelta) minDelta=delta;
160 }
161 if(minDelta>1000)
162 {
163 double f=1000000./(double)minDelta;
164 f*=1000.;
165 uint32_t fps1000=floor(f+0.49);
166 ADM_info("MinDelta=%d us\n",(int)minDelta);
167 ADM_info("Computed fps1000=%d\n",fps1000);
168 if(fps1000 == _videostream.dwRate)
169 {
170 ADM_info("Computed fps1000 matches the average one.\n");
171 return true;
172 }
173 int score=0;
174 uint64_t avgDelta=_mainaviheader.dwMicroSecPerFrame;
175 int64_t halfway=avgDelta-minDelta+1;
176 halfway/=2;
177 halfway+=minDelta;
178 for(int i=0;i<n-1;i++)
179 {
180 MP4Index *dex=&(_tracks[0].index[i]);
181 MP4Index *next=&(_tracks[0].index[i+1]);
182 if(dex->dts==ADM_NO_PTS) continue;
183 if(next->dts==ADM_NO_PTS) continue;
184 uint64_t delta=next->dts-dex->dts;
185 if(delta==minDelta) score++;
186 if(delta<halfway) score++;
187 }
188 float weighted=score*1000.;
189 weighted/=n;
190 ADM_info("Original fps1000 = %d, score = %d, weighted score = %d\n",_videostream.dwRate,score,(int)weighted);
191 // require that at least 10% of video better or 5% perfectly matches max fps
192 if(fps1000 > _videostream.dwRate && (int)weighted > 100)
193 {
194 ADM_info("Adjusting fps, the computed is higher than average, dropped frames ?\n");
195 _videostream.dwRate=fps1000;
196 _mainaviheader.dwMicroSecPerFrame=ADM_UsecFromFps1000(_videostream.dwRate);
197 }
198 }
199 return true;
200
201 }
202 #endif
203
getFrame(uint32_t framenum,ADMCompressedImage * img)204 uint8_t MP4Header::getFrame(uint32_t framenum,ADMCompressedImage *img)
205 {
206 aprintf("[MP4] frame %d requested (nbFrame=%d)\n",framenum,VDEO.nbIndex);
207 if(framenum>=VDEO.nbIndex)
208 {
209 return 0;
210 }
211
212 MP4Index *idx=&(VDEO.index[framenum]);
213
214 uint64_t offset=idx->offset; //+_mdatOffset;
215
216
217 if(fseeko(_fd,offset,SEEK_SET))
218 {
219 ADM_error("Seeking past the end of the file! Broken index?\n");
220 return 0;
221 }
222 if(!fread(img->data, (size_t)idx->size, 1, _fd))
223 {
224 ADM_error("Incomplete frame %" PRIu32". Broken index?\n",framenum);
225 return 0;
226 }
227 img->dataLength=idx->size;
228 img->flags = idx->intra;
229
230 img->demuxerDts=idx->dts;
231 img->demuxerPts=idx->pts;
232 aprintf("[MP4] Pts=%s\n",ADM_us2plain(idx->pts));
233 aprintf("[MP4] Dts=%s\n",ADM_us2plain(idx->dts));
234 /*
235 if(img->demuxerPts==ADM_COMPRESSED_NO_PTS)
236 img->demuxerPts=img->demuxerDts;
237 */
238 return 1;
239 }
~MP4Header()240 MP4Header::~MP4Header()
241 {
242 close();
243
244 for(int audio = 0; audio < nbAudioTrack; audio++)
245 {
246 delete audioStream[audio];
247 delete audioAccess[audio];
248 }
249 for(int i = 0; i < nbTrex; i++)
250 {
251 delete _trexData[i];
252 _trexData[i] = NULL;
253 }
254 }
close(void)255 uint8_t MP4Header::close( void )
256 {
257 if(_fd)
258 {
259 fclose(_fd);
260 }
261 _fd=NULL;
262 return 1;
263 }
264 //
265 // Set default save value
266 //
267
MP4Header(void)268 MP4Header::MP4Header(void)
269 {
270 _fd=NULL;
271 nbAudioTrack=0;
272 _currentAudioTrack=0;
273 _reordered=0;
274 _videoScale=1;
275 _videoFound=0;
276 delayRelativeToVideo=0;
277 _flavor=Mp4Regular;
278 nbTrex=0;
279 for(int i=0;i<_3GP_MAX_TRACKS;i++)
280 _trexData[i]=NULL;
281 }
282 /**
283 \fn getAudioInfo
284 \brief
285 */
getAudioInfo(uint32_t i)286 WAVHeader *MP4Header::getAudioInfo(uint32_t i )
287 {
288 if(nbAudioTrack)
289 {
290 ADM_assert(i<nbAudioTrack);
291 return &(_tracks[i+1]._rdWav);
292 }
293
294 return NULL;
295
296 }
297 /**
298 \fn getAudioStream
299 */
300
getAudioStream(uint32_t i,ADM_audioStream ** audio)301 uint8_t MP4Header::getAudioStream(uint32_t i,ADM_audioStream **audio)
302 {
303 if(nbAudioTrack)
304 {
305 ADM_assert(i<nbAudioTrack);
306 *audio=audioStream[i];
307 } else
308 *audio=NULL;
309 return 1;
310 }
311 /**
312 \fn getNbAudioStreams
313 */
getNbAudioStreams(void)314 uint8_t MP4Header::getNbAudioStreams(void)
315 {
316 return nbAudioTrack;
317
318 }
319
320
getExtraHeaderData(uint32_t * len,uint8_t ** data)321 uint8_t MP4Header::getExtraHeaderData(uint32_t *len, uint8_t **data)
322 {
323 *len=0;*data=NULL;
324 if(_tracks[0].extraDataSize)
325 {
326 *len= VDEO.extraDataSize;
327 *data=VDEO.extraData;
328 }
329 return 1;
330 }
331 //______________________________________
332 //
333 // Open and recursively read the atoms
334 // until we got the information we want
335 // i.e. :
336 // index for audio and video track
337 // esds for mpeg4
338 // size / codec used
339 //
340 // We don't care about sync atom and all
341 // other stuff which are pretty useless on
342 // 3gp file anyway.
343 //______________________________________
open(const char * name)344 uint8_t MP4Header::open(const char *name)
345 {
346 printf("** opening 3gpp files **\n");
347 _fd=ADM_fopen(name,"rb");
348 if(!_fd)
349 {
350 printf("\n cannot open %s \n",name);
351 return 0;
352 }
353 #define CLR(x) memset(& x,0,sizeof( x));
354
355 CLR( _videostream);
356 CLR( _mainaviheader);
357
358 _videostream.dwScale=1000;
359 _videostream.dwRate=10000;
360 _mainaviheader.dwMicroSecPerFrame=100000;; // 10 fps hard coded
361
362 adm_atom *atom=new adm_atom(_fd);
363 // Some mp4/mov files have the data at the end but do start properly
364 // detect and workaround...
365 // Check it is not mdat start(ADM_memcpy_0)
366 uint8_t check[4];
367 uint64_t fileSize;
368 fseeko(_fd,0,SEEK_END);
369 fileSize=ftello(_fd);
370 fseeko(_fd,4,SEEK_SET);
371 fread(check,4,1,_fd);
372 fseeko(_fd,0,SEEK_SET);
373 if(check[0]=='m' && check[1]=='d' &&check[2]=='a' && check[3]=='t')
374 {
375 uint64_t of;
376 uint64_t hi,lo;
377 printf("Data first, header later...\n");
378 of=atom->read32();
379 if(of==1)
380 {
381 atom->read32(); // size
382 atom->read32(); // fcc
383 hi=atom->read32();
384 lo=atom->read32();
385 of=(hi<<32)+lo;
386 if(of>fileSize) of=hi;
387 }
388 fseeko(_fd,of,SEEK_SET);
389 printf("Header starts at %" PRIx64"\n",of);
390 delete atom;
391 atom=new adm_atom(_fd);
392 }
393 //**************
394
395 if(!lookupMainAtoms((void*) atom))
396 {
397 printf("Cannot find needed atom\n");
398 if(!_tracks[0].fragments.size() || !indexVideoFragments(0))
399 {
400 fclose(_fd);
401 _fd=NULL;
402 delete atom;
403 return 0;
404 }else
405 { // do other tracks as well
406 for(int i=1;i<=nbAudioTrack;i++)
407 {
408 if(_tracks[i].fragments.size())
409 indexAudioFragments(i);
410 if(_tracks[i].index==NULL)
411 nbAudioTrack--;
412 }
413 }
414 }
415
416 delete atom;
417
418 _isvideopresent=1;
419 _isaudiopresent=0;
420
421 _videostream.fccType=fourCC::get((uint8_t *)"vids");
422 _video_bih.biBitCount=24;
423 _videostream.dwInitialFrames= 0;
424 _videostream.dwStart= 0;
425
426 printf("\n");
427
428
429 if(!VDEO.index)
430 {
431 printf("No index!\n");
432 return 0;
433 }
434
435 // If it is mpeg4 and we have extra data
436 // Decode vol header to get the real width/height
437 // The mpeg4/3GP/Mov header is often misleading
438
439 if(fourCC::check(_videostream.fccHandler,(uint8_t *)"DIVX"))
440 {
441 if(VDEO.extraDataSize)
442 {
443 uint32_t w,h,ti;
444 if(extractMpeg4Info(VDEO.extraData,VDEO.extraDataSize,&w,&h,&ti))
445 {
446 printf("MP4 Corrected size : %" PRIu32" x %" PRIu32"\n",w,h);
447 _video_bih.biWidth=_mainaviheader.dwWidth=w ;
448 _video_bih.biHeight=_mainaviheader.dwHeight=h;
449 }
450 }else { printf("No extradata to probe\n");}
451
452 }else if(fourCC::check(_videostream.fccHandler,(uint8_t *)"H263"))
453 { // Same story for H263 : Analyze 1st frame to get the real width/height
454 uint32_t w,h,sz;
455 uint8_t *bfer=NULL;
456 sz=VDEO.index[0].size;
457 if(sz)
458 {
459 bfer=new uint8_t[sz];
460 ADMCompressedImage img;
461 img.data=bfer;
462 if(getFrame(0,&img))
463 {
464 if(extractH263Info(bfer,sz,&w,&h))
465 {
466 printf("H263 Corrected size : %" PRIu32" x %" PRIu32"\n",w,h);
467 _video_bih.biWidth=_mainaviheader.dwWidth=w ;
468 _video_bih.biHeight=_mainaviheader.dwHeight=h;
469 }else
470 {
471 printf("H263 COULD NOT EXTRACT SIZE, using : %" PRIu32" x %" PRIu32"\n",
472 _video_bih.biWidth, _video_bih.biHeight);
473 }
474 }
475 delete [] bfer;
476 }
477 }else if(isH264Compatible(_videostream.fccHandler) && VDEO.extraDataSize)
478 { // Get frame type from H.264 slice headers, this is essential for handling of field encoded streams
479 ADM_SPSInfo info;
480 if(extractSPSInfo_mp4Header(VDEO.extraData,VDEO.extraDataSize,&info))
481 {
482 uint32_t nalSize = ADM_getNalSizeH264(VDEO.extraData,VDEO.extraDataSize);
483 uint32_t prevSpsLen=0;
484 uint8_t *prevSps=NULL, *curSps=NULL;
485 #define MAX_SPS_SIZE 1024
486 #define MAX_FRAME_LENGTH (1920*1080*3) // ~7 MiB, should be enough even for 4K
487 uint8_t *bfer=new uint8_t[MAX_FRAME_LENGTH];
488 ADMCompressedImage img;
489 img.data=bfer;
490 uint32_t i,fields=0,nb=VDEO.nbIndex;
491 uint64_t processed=0;
492 DIA_processingBase *work=createProcessing(QT_TRANSLATE_NOOP("mp4demuxer","Decoding frame type"),nb);
493 for(i=0;i<nb;i++)
494 {
495 if(work && work->update(1,processed++))
496 break; // cancelling frame type decoding is non-fatal
497 if(!getFrame(i,&img))
498 {
499 ADM_warning("Could not get frame %u while decoding H.264 frame type.\n",i);
500 continue;
501 }
502 if(img.flags & AVI_KEY_FRAME)
503 {
504 // Check for presence of SPS in the stream. If it changes on-the-fly, we are in trouble.
505 if(!curSps)
506 curSps=new uint8_t[MAX_SPS_SIZE];
507 memset(curSps,0,MAX_SPS_SIZE);
508 uint32_t curSpsLen = getRawH264SPS(img.data, img.dataLength, nalSize, curSps, MAX_SPS_SIZE);
509 bool match=true;
510 if(curSpsLen)
511 {
512 if(prevSps)
513 {
514 if(prevSpsLen)
515 match=!memcmp(prevSps,curSps,(prevSpsLen>curSpsLen)? curSpsLen : prevSpsLen);
516 }else
517 {
518 prevSps=new uint8_t[MAX_SPS_SIZE];
519 }
520 if(!match)
521 {
522 ADM_warning("Codec parameters change at frame %u.\n",i);
523 printf("\nOld SPS:\n");
524 mixDump(prevSps,prevSpsLen);
525 printf("\nNew SPS:\n");
526 mixDump(curSps,curSpsLen);
527 }
528 prevSpsLen=curSpsLen;
529 memset(prevSps,0,MAX_SPS_SIZE);
530 memcpy(prevSps,curSps,prevSpsLen);
531 }
532 if(!match && curSps)
533 {
534 ADM_info("SPS mismatch? Checking deeper...\n");
535 ADM_SPSInfo info2;
536 if(extractSPSInfoFromData(curSps,curSpsLen,&info2))
537 { // check only fields we actually use
538 #define MATCH(x) if(info.x != info2.x) { ADM_warning("%s value does not match.\n",#x); info.x = info2.x; match=false; }
539 match=true;
540 // FIXME: dimensions mismatch should be fatal
541 MATCH(CpbDpbToSkip)
542 MATCH(hasPocInfo)
543 MATCH(log2MaxFrameNum)
544 MATCH(log2MaxPocLsb)
545 MATCH(frameMbsOnlyFlag)
546 MATCH(refFrames)
547 if(!match)
548 ADM_warning("Codec parameters change on the fly, expect problems.\n");
549 }
550 }
551 }
552 uint32_t flags;
553 if(extractH264FrameType(img.data,img.dataLength,nalSize,&flags,NULL,&info))
554 {
555 if(flags & AVI_FIELD_STRUCTURE)
556 {
557 if(!fields)
558 printf("First field at frame %u\n",i);
559 fields++;
560 }else if(fields==1)
561 { // discard a single field immediately followed by a frame, probably damaged stream
562 printf("Resetting fields counter at frame %u\n",i);
563 fields=0;
564 }
565 setFlag(i,flags);
566 }
567 }
568 if(work) delete work;
569 work=NULL;
570 delete [] bfer;
571 bfer=NULL;
572 if(curSps) delete [] curSps;
573 curSps=NULL;
574 if(prevSps) delete [] prevSps;
575 prevSps=NULL;
576 if(fields)
577 ADM_info("Field encoded H.264 stream detected, # fields: %u\n",fields);
578 else
579 ADM_info("Probably a frame encoded H.264 stream.\n");
580 }
581 }
582 /*
583 * Veryfy DTS<=PTS
584 */
585 int nb=(int)_tracks[0].nbIndex;
586 uint64_t delta,maxDelta=0;
587 for(int i=0;i<nb;i++)
588 {
589 uint64_t pts,dts;
590 dts=VDEO.index[i].dts;
591 pts=VDEO.index[i].pts;
592 if(pts==ADM_COMPRESSED_NO_PTS || dts==ADM_COMPRESSED_NO_PTS) continue;
593 if(dts>=pts)
594 {
595 uint64_t delta=(uint64_t)(dts-pts);
596 if(delta>maxDelta) maxDelta=delta;
597 }
598 }
599 if(maxDelta)
600 {
601 shiftTimeBy(maxDelta);
602 _movieDuration+=(maxDelta+999)/1000;
603 }
604 /*
605 Now build audio tracks
606 */
607 if(nbAudioTrack) _isaudiopresent=1; // Still needed ?
608
609 adjustElstDelay();
610
611 //
612 for(int audio=0;audio<nbAudioTrack;audio++)
613 {
614 switch(_tracks[1+audio]._rdWav.encoding)
615 {
616
617 // Lookup if AAC is lying about # of channels
618 case WAV_AAC:
619 {
620 if(_tracks[1+audio].extraDataSize==2)
621 {
622 // Channels
623 uint32_t word=(_tracks[1+audio].extraData[0]<<8)+_tracks[1+audio].extraData[1];
624 uint32_t chan=(word>>3)&0xf;
625 uint32_t fqIndex=(word>>7)&0xf;
626 printf("0x%x word, Channel : %d, fqIndex=%d\n",word,chan,fqIndex);
627 }
628 }
629 break;
630 case WAV_AC3: // same for ac3
631 {
632 // read First chunk
633
634 MP4Index *dex=_tracks[1+audio].index;
635 int size=dex[0].size;
636 uint8_t *buffer=new uint8_t[size];
637 fseeko(_fd,dex[0].offset,SEEK_SET);
638 if(fread(buffer,1,size,_fd))
639 {
640 uint32_t fq, br, chan, syncoff;
641 if(ADM_AC3GetInfo(buffer,size, &fq, &br, &chan,&syncoff))
642 {
643 ADM_info("Updating AC3 info : Fq=%d, br=%d, chan=%d\n",fq,br,chan);
644 _tracks[1+audio]._rdWav.channels=chan;
645 _tracks[1+audio]._rdWav.byterate=br;
646 }
647 }
648 delete [] buffer;
649 break;
650 }
651 case WAV_MP3: // same for mp3
652 {
653 MP4Index *dex=_tracks[1+audio].index;
654 int size=dex[0].size;
655 uint8_t *buffer=new uint8_t[size];
656 fseeko(_fd,dex[0].offset,SEEK_SET);
657 if(fread(buffer,1,size,_fd))
658 {
659 uint32_t off;
660 MpegAudioInfo mpeg;
661 if(getMpegFrameInfo(buffer, size, &mpeg, NULL, &off) && size >= off+mpeg.size)
662 {
663 if(mpeg.mode == 3 && _tracks[1+audio]._rdWav.channels!=1)
664 {
665 uint32_t fq=mpeg.samplerate;
666 uint32_t br=(mpeg.bitrate*1000)>>3; //
667 ADM_info("Updating MP3 info : Fq=%u, br=%u, chan=%u\n",fq,br,1);
668 _tracks[1+audio]._rdWav.channels=1;
669 _tracks[1+audio]._rdWav.frequency=fq;
670 _tracks[1+audio]._rdWav.byterate=br;
671 }
672 }else
673 {
674 ADM_warning("Cannot get MP3 info from the first sample.\n");
675 }
676 }
677 delete [] buffer;
678 break;
679 }
680 case WAV_OGG_VORBIS:
681 {
682 ADM_info("[MP4] Reformatting vorbis header for track %u\n",1+audio);
683 uint8_t *newExtra=NULL;
684 int newExtraSize=0;
685 if(false==ADMXiph::xiphExtraData2Adm(_tracks[1+audio].extraData, _tracks[1+audio].extraDataSize, &newExtra, &newExtraSize))
686 {
687 ADM_warning("Cannot reformat vorbis extra data, faking audio format to avoid crash.\n");
688 _tracks[1+audio]._rdWav.encoding=WAV_UNKNOWN;
689 }
690 // Destroy old extradata
691 delete [] _tracks[1+audio].extraData;
692 _tracks[1+audio].extraData=newExtra;
693 _tracks[1+audio].extraDataSize=newExtraSize;
694 }
695 break;
696 default:
697 break;
698 }
699 audioAccess[audio]=new ADM_mp4AudioAccess(name,&(_tracks[1+audio]));
700 audioStream[audio]=ADM_audioCreateStream(&(_tracks[1+audio]._rdWav), audioAccess[audio]);
701 }
702 fseeko(_fd,0,SEEK_SET);
703 uint64_t duration1=_movieDuration*1000LL;
704 uint64_t duration2=0;
705 uint32_t lastFrame=0;
706 for(int i=nb-32;i<nb;i++)
707 {
708 if(i<0) continue;
709 if(_tracks[0].index[i].pts==ADM_NO_PTS) continue;
710 if(duration2<_tracks[0].index[i].pts)
711 {
712 duration2=_tracks[0].index[i].pts;
713 lastFrame=i;
714 }
715 }
716 int64_t increment=_mainaviheader.dwMicroSecPerFrame;
717 if(!increment) // perfectly regular stream
718 {
719 ADM_assert(_videostream.dwRate);
720 double f=_videostream.dwScale;
721 f*=1000.*1000.;
722 f/=_videostream.dwRate;
723 f+=0.49;
724 increment=(int64_t)f;
725 }
726 duration2+=increment;
727 ADM_info("3gp/mov file successfully read..\n");
728 if(duration2!=ADM_NO_PTS && duration2>=duration1)
729 { // video duration must be > max PTS, otherwise we drop the last frame
730 ADM_warning("Last PTS is at or after movie duration, increasing movie duration\n");
731 _movieDuration=(duration2+499)/1000;
732 #ifdef DERIVE_TB_FROM_MINIMUM_DELTA
733 // adjust calculated average FPS and time increment
734 double f=_movieDuration;
735 f=1000.*_tracks[0].nbIndex/f;
736 f*=1000.;
737 _videostream.dwRate=(uint32_t)floor(f+0.49);
738 _mainaviheader.dwMicroSecPerFrame=ADM_UsecFromFps1000(_videostream.dwRate);
739 ADM_info("Adjusted fps1000: %d = %" PRIu64" us per frame.\n",_videostream.dwRate,_mainaviheader.dwMicroSecPerFrame);
740 #endif
741 }
742 #ifdef DERIVE_TB_FROM_MINIMUM_DELTA
743 refineFps();
744 #endif
745 if(nb>1 && !lastFrame)
746 lastFrame=nb-1;
747 ADM_info("Nb images : %d\n",nb);
748 ADM_info("Movie duration : %s\n",ADM_us2plain(_movieDuration*1000LL));
749 ADM_info("Last video PTS : %s\n",ADM_us2plain(_tracks[0].index[lastFrame].pts));
750 ADM_info("Last video DTS : %s\n",ADM_us2plain(_tracks[0].index[nb-1].dts));
751
752 checkDuplicatedPts();
753
754 return 1;
755 }
checkDuplicatedPts(void)756 bool MP4Header::checkDuplicatedPts(void)
757 {
758 int nb=(int)_tracks[0].nbIndex;
759 for(int i=0;i<nb;i++)
760 {
761 int mn,mx;
762 mn=i-10;
763 if(mn<0) mn=0;
764 mx=i+10;
765 if(mx>=nb-1) mx=nb-1;
766 for(int j=mn;j<mx;j++)
767 {
768 if(j==i) continue;
769 if(_tracks[0].index[i].pts==_tracks[0].index[j].pts)
770 {
771 ADM_warning("Duplicate pts %s at %d and %d\n",ADM_us2plain(_tracks[0].index[i].pts),i,j);
772 _tracks[0].index[j].pts+=1000; // add 1 ms
773 }
774 }
775
776 }
777 return true;
778 }
779 /**
780 * \fn adjustElstDelay
781 * @return
782 */
adjustElstDelay(void)783 bool MP4Header::adjustElstDelay(void)
784 {
785 int xmin=10000000;
786 int xscaledDelay[_3GP_MAX_TRACKS];
787 for(int i=0;i<1+nbAudioTrack;i++)
788 {
789 double scaledDelay=_tracks[i].delay;
790 double scaledStartOffset=_tracks[i].startOffset;
791 scaledDelay/=_movieScale;
792 scaledStartOffset/=_tracks[i].scale;
793 scaledDelay*=1000000;
794 scaledStartOffset*=1000000;
795 ADM_info("Delay for track %d : raw = %d, scaled = %d with scale = %d\n",i,_tracks[i].delay,(int)scaledDelay,_movieScale);
796 ADM_info("Start offset for track %d : raw = %d, scaled = %d with scale = %d\n",i,_tracks[i].startOffset,(int)scaledStartOffset,_tracks[i].scale);
797 scaledDelay-=scaledStartOffset;
798 xscaledDelay[i]=scaledDelay;
799 if(scaledDelay<xmin)
800 xmin=scaledDelay;
801 }
802 ADM_info("Elst minimum = %d us\n",xmin);
803 for(int i=0;i<1+nbAudioTrack;i++)
804 {
805 int d=xscaledDelay[i]-xmin;
806 if(d)
807 {
808 ADM_info(" Shifting track %d by %s\n",i,ADM_us2plain(d));
809 shiftTrackByTime(i,d);
810 }
811 }
812 return true;
813 }
814
815
816
817 /**
818 * \fn shiftTimeBy
819 * \brief increase pts by shift, fix some mp4 where dts is too low
820 * @param shift
821 * @return
822 */
shiftTimeBy(uint64_t shift)823 bool MP4Header::shiftTimeBy(uint64_t shift)
824 {
825
826 ADM_warning("MP4, Must increase pts by %d us\n",(int)shift);
827 int nb=(int)_tracks[0].nbIndex;
828 for(int i=0;i<nb;i++)
829 {
830 uint64_t pts;
831 pts=VDEO.index[i].pts;
832 if(pts==ADM_COMPRESSED_NO_PTS) continue;
833 pts+=shift;
834 VDEO.index[i].pts=pts;
835 }
836 for(int i=1;i<nbAudioTrack;i++)
837 shiftTrackByTime(i,shift);
838 return true;
839 }
840 /**
841 *
842 * @param dex
843 * @param shift
844 * @return
845 */
shiftTrackByTime(int dex,uint64_t shift)846 bool MP4Header::shiftTrackByTime(int dex,uint64_t shift)
847 {
848 int nb=(int)_tracks[dex].nbIndex;
849 MP4Index *myIndex=_tracks[dex].index;
850 for(int i=0;i<nb;i++)
851 {
852 uint64_t dts,pts;
853 dts=myIndex[i].dts;
854 pts=myIndex[i].pts;
855 if(dts!=ADM_COMPRESSED_NO_PTS)
856 {
857 dts+=shift;
858 }
859 if(pts!=ADM_COMPRESSED_NO_PTS)
860 {
861 pts+=shift;
862 }
863 myIndex[i].dts=dts;
864 myIndex[i].pts=pts;
865 }
866
867 return true;
868 }
869
870 //
871 // That tag are coded like this
872 // Each 8 bits is in fact a 7 Bits part while b7=1
873 // So we concanate them while possible
readPackedLen(adm_atom * tom)874 uint32_t MP4Header::readPackedLen(adm_atom *tom )
875 {
876 uint32_t len=0;
877 uint8_t b=0;
878
879 do
880 {
881 b=tom->read();
882 len=len<<7;
883 len+=b&0x7f;
884 }while(b&0x80);
885 return len;
886 }
887
getFrameSize(uint32_t frame,uint32_t * size)888 uint8_t MP4Header::getFrameSize (uint32_t frame, uint32_t * size){
889 if(frame >= _videostream.dwLength) return 0;
890 *size = VDEO.index[frame].size;
891 return 1;
892 }
changeAudioStream(uint32_t newstream)893 uint8_t MP4Header::changeAudioStream(uint32_t newstream)
894 {
895 if(newstream>nbAudioTrack) return 0;
896 _currentAudioTrack=newstream;
897 return 1;
898 }
getCurrentAudioStreamNumber(void)899 uint32_t MP4Header::getCurrentAudioStreamNumber(void)
900 {
901 return _currentAudioTrack;
902 }
903
904 /**
905 \fn getPtsDts
906 */
getPtsDts(uint32_t frame,uint64_t * pts,uint64_t * dts)907 bool MP4Header::getPtsDts(uint32_t frame,uint64_t *pts,uint64_t *dts)
908 {
909
910 if(frame>=VDEO.nbIndex)
911 {
912 printf("[MP4] Frame %" PRIu32" exceeds # of frames %" PRIu32"\n",frame,VDEO.nbIndex);
913 return false;
914 }
915
916 MP4Index *idx=&(VDEO.index[frame]);
917
918 *dts=idx->dts; // FIXME
919 *pts=idx->pts;
920 return true;
921 }
922 /**
923 \fn setPtsDts
924 */
setPtsDts(uint32_t frame,uint64_t pts,uint64_t dts)925 bool MP4Header::setPtsDts(uint32_t frame,uint64_t pts,uint64_t dts)
926 {
927 if(frame>=VDEO.nbIndex)
928 {
929 printf("[MP4] Frame %" PRIu32" exceeds # of frames %" PRIu32"\n",frame,VDEO.nbIndex);
930 return 0;
931 }
932
933 MP4Index *idx=&(VDEO.index[frame]);
934
935 idx->dts=dts; // FIXME
936 idx->pts=pts;
937 return true;
938 }
939 /**
940 * \fn unreliableBFramePts
941 * \brief with mp4+h264, bframe PTS are unreliable
942 * @return
943 */
unreliableBFramePts(void)944 bool MP4Header::unreliableBFramePts (void)
945 {
946 if(isH264Compatible(_videostream.fccHandler))
947 return true;
948 return false;
949 }
950 //EOF
951