1 /*******************************************************************************
2 *                         Goggles Audio Player Library                         *
3 ********************************************************************************
4 *           Copyright (C) 2010-2021 by Sander Jansen. All Rights Reserved      *
5 *                               ---                                            *
6 * This program is free software: you can redistribute it and/or modify         *
7 * it under the terms of the GNU General Public License as published by         *
8 * the Free Software Foundation, either version 3 of the License, or            *
9 * (at your option) any later version.                                          *
10 *                                                                              *
11 * This program is distributed in the hope that it will be useful,              *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of               *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                *
14 * GNU General Public License for more details.                                 *
15 *                                                                              *
16 * You should have received a copy of the GNU General Public License            *
17 * along with this program.  If not, see http://www.gnu.org/licenses.           *
18 ********************************************************************************/
19 #include "ap_defs.h"
20 #include "ap_event_private.h"
21 #include "ap_packet.h"
22 #include "ap_reader_plugin.h"
23 #include "ap_input_plugin.h"
24 
25 #include <cstdint>
26 
27 namespace ap {
28 
29 #ifdef HAVE_FAAD
30 extern FXbool ap_parse_aac_specific_config(const FXuchar * data, FXuint length, FXushort & samples_per_frame, FXbool & upsampled, AudioFormat & af);
31 #endif
32 
33 class Track {
34   struct stts_entry {
35     FXuint nsamples;
36     FXuint delta;
37     };
38 
39   struct stsc_entry {
40     FXint first;
41     FXint nsamples;
42     FXint index;
43     };
44 
45   struct ctts_entry {
46     FXint nsamples;
47     FXint offset;
48     };
49 
50 public:
51   AudioFormat             af;                           // Audio Format
52   FXuchar                 codec = Codec::Invalid;       // Audio Codec
53   FXuint                  fixed_sample_size = 0;        // used if all samples have the same size
54   FXushort                samples_per_frame = 0;        // number of pcm samples in a frame (used by AAC)
55   FXbool                  upsampled = false;
56   DecoderSpecificConfig * dc = nullptr;
57   FXArray<FXuint>         stsz;                         // samples size lookup table (in bytes)
58   FXArray<FXuint>         stco;                         // chunk offset table
59   FXArray<stts_entry>     stts;                         // time to sample number lookup table
60   FXArray<stsc_entry>     stsc;                         // chunk-to-sample table
61   FXArray<ctts_entry>     ctts;
62 public:
Track()63   Track() {}
~Track()64   ~Track() { delete dc; }
65 public:
getChunkOffset(FXuint chunk,FXuint chunk_nsamples,FXuint sample) const66   FXlong getChunkOffset(FXuint chunk,FXuint chunk_nsamples,FXuint sample) const {
67     FXlong offset;
68     if (stco.no())
69       offset = stco[FXMIN(chunk,stco.no()-1)];
70     else
71       offset = 8;
72 
73     if (fixed_sample_size) {
74       offset += (sample-chunk_nsamples)*fixed_sample_size;
75       }
76     else {
77       for (FXuint i=chunk_nsamples;i<sample;i++) {
78         offset+=stsz[i];
79         }
80       }
81     return offset;
82     }
83 
84   // Find the chunk that contains sample s. Also return nsamples at start of chunk
getChunk(FXuint s,FXuint & chunk,FXuint & chunk_nsamples) const85   void getChunk(FXuint s,FXuint & chunk,FXuint & chunk_nsamples) const{
86     FXuint nchunks,nsamples,ntotal=0;
87     for (FXint i=0;i<stsc.no()-1;i++) {
88       nchunks  = (stsc[i+1].first - stsc[i].first);
89       nsamples = nchunks * stsc[i].nsamples;
90       if (s<ntotal+nsamples) {
91         chunk          = stsc[i].first + ((s-ntotal)/stsc[i].nsamples) - 1;
92         chunk_nsamples = ntotal + ((chunk+1)-stsc[i].first) * stsc[i].nsamples;
93         return;
94         }
95       ntotal+=nsamples;
96       }
97 
98     chunk          = stsc.tail().first + ((s-ntotal) / stsc.tail().nsamples) - 1;
99     chunk_nsamples = ntotal + ((chunk+1) - stsc.tail().first) * stsc.tail().nsamples;
100     }
101 
102   // Sample Offset
getCompositionOffset(FXlong position) const103   FXint getCompositionOffset(FXlong position) const {
104     FXint s = 0;
105     for (int i=0;i<ctts.no();i++){
106       if (position < s + ctts[i].nsamples){
107         if (upsampled)
108           return ctts[i].offset << 1;
109         else
110           return ctts[i].offset;
111         }
112       s+=ctts[i].nsamples;
113       }
114     return 0;
115     }
116 
getSample(FXlong position) const117   FXint getSample(FXlong position) const {
118     FXlong n,ntotal = 0;
119     FXint nsamples = 0;
120 
121     if (upsampled) {
122       position>>=1;
123       }
124 
125     for (int i=0;i<stts.no();i++){
126       n = stts[i].nsamples*stts[i].delta;
127       if (position<ntotal+n) {
128         return nsamples+((position-ntotal)/stts[i].delta);
129         }
130       ntotal+=n;
131       nsamples+=stts[i].nsamples;
132       }
133     return -1;
134     }
135 
getSamplePosition(FXuint s) const136   FXlong getSamplePosition(FXuint s) const {
137     FXlong pos=0;
138     FXuint nsamples=0;
139     for (int i=0;i<stts.no();i++){
140       if (s<(stts[i].nsamples+nsamples)){
141         pos+=stts[i].delta*(s-nsamples);
142         if (upsampled)
143           return pos << 1;
144         else
145           return pos;
146         }
147       else {
148         pos+=stts[i].delta*stts[i].nsamples;
149         }
150       nsamples+=stts[i].nsamples;
151       }
152     return 0;
153     }
154 
getLength() const155   FXlong getLength() const {
156     FXlong length=0;
157     for (int i=0;i<stts.no();i++){
158       length+=static_cast<FXlong>(stts[i].delta)*static_cast<FXlong>(stts[i].nsamples);
159       }
160 
161     if (upsampled)
162       return length << 1;
163     else
164       return length;
165     }
166 
getSampleOffset(FXuint s) const167   FXlong getSampleOffset(FXuint s) const {
168     FXuint chunk,nsamples;
169     getChunk(s,chunk,nsamples);
170     return getChunkOffset(chunk,nsamples,s);
171     }
172 
getSampleSize(FXuint s) const173   FXlong getSampleSize(FXuint s) const {
174     if (fixed_sample_size)
175       return fixed_sample_size;
176     else
177       return stsz[s];
178     }
179 
getNumSamples() const180   FXuint getNumSamples() const {
181     FXint nsamples = 0;
182     for (FXint i=0;i<stts.no();i++) {
183       nsamples += stts[i].nsamples;
184       }
185     return nsamples;
186     }
187   };
188 
189 
190 
191 
192 class MP4Reader : public ReaderPlugin {
193 protected:
194   FXPtrListOf<Track> tracks;
195   Track*             track = nullptr;
196   MetaInfo*          meta = nullptr;
197   FXushort           padstart = 0;
198   FXushort           padend = 0;
199   FXlong             framesize = 0;
200 protected:
201   FXuint read_descriptor_length(FXuint&);
202   FXbool atom_parse_asc(const FXuchar*,FXuint size);
203   FXbool atom_parse_esds(FXlong size);
204   FXbool atom_parse_mp4a(FXlong size);
205   FXbool atom_parse_alac(FXlong size);
206   FXbool atom_parse_stsd(FXlong size);
207   FXbool atom_parse_stco(FXlong size);
208   FXbool atom_parse_stsc(FXlong size);
209   FXbool atom_parse_stts(FXlong size);
210   FXbool atom_parse_stsz(FXlong size);
211   FXbool atom_parse_ctts(FXlong size);
212   FXbool atom_parse_trak(FXlong size);
213   //FXbool atom_parse_freeform(FXlong size);
214   //FXbool atom_parse_text(FXlong size,FXString & value);
215   FXbool atom_parse_meta(FXlong size);
216   FXbool atom_parse_meta_text(FXlong size,FXString &);
217   FXbool atom_parse_meta_free(FXlong size);
218   FXbool atom_parse_header(FXuint & atom_type,FXlong & atom_size,FXlong & container);
219   FXbool atom_parse(FXlong size);
220 protected:
221   FXuint   sample = 0;      // current sample
222   FXuint   nsamples = 0;    // number of samples
223 protected:
224   ReadStatus parse();
225   FXbool select_track();
226   void clear_tracks();
227 public:
228   MP4Reader(InputContext*);
229 
230   // Format
format() const231   FXuchar format() const override { return Format::MP4; };
232 
233   // Init
234   FXbool init(InputPlugin*) override;
235 
236   // Seekable
237   FXbool can_seek() const override;
238 
239   // Seek
240   FXbool seek(FXlong) override;
241 
242   // Process Packet
243   ReadStatus process(Packet*) override;
244 
245   // Destroy
246   ~MP4Reader();
247   };
248 
249 
ap_mp4_reader(InputContext * ctx)250 ReaderPlugin * ap_mp4_reader(InputContext * ctx) {
251   return new MP4Reader(ctx);
252   }
253 
254 
255 
MP4Reader(InputContext * ctx)256 MP4Reader::MP4Reader(InputContext * ctx) : ReaderPlugin(ctx), track(nullptr), meta(nullptr) {
257   }
258 
~MP4Reader()259 MP4Reader::~MP4Reader(){
260   clear_tracks();
261   }
262 
init(InputPlugin * plugin)263 FXbool MP4Reader::init(InputPlugin*plugin) {
264   ReaderPlugin::init(plugin);
265   flags&=~FLAG_PARSED;
266   clear_tracks();
267   nsamples=0;
268   sample=0;
269   framesize=0;
270   if (meta) {
271     meta->unref();
272     meta=nullptr;
273     }
274   padstart=0;
275   padend=0;
276   return true;
277   }
278 
can_seek() const279 FXbool MP4Reader::can_seek() const {
280   return true;
281   }
282 
seek(FXlong offset)283 FXbool MP4Reader::seek(FXlong offset){
284   if (!input->serial()){
285     FXint s = track->getSample(offset);
286     if (s>=0) {
287       sample = s;
288       framesize = 0;
289       return true;
290       }
291     }
292   return false;
293   }
294 
process(Packet * packet)295 ReadStatus MP4Reader::process(Packet*packet) {
296   packet->stream_position=-1;
297   packet->stream_length=stream_length;
298 
299   if (!(flags&FLAG_PARSED) && parse()==ReadError) {
300     packet->unref();
301     return ReadError;
302     }
303 
304   // Remaining data from sample
305   if (framesize) {
306     FXlong n = FXMIN(framesize,packet->space());
307     if (input->read(packet->ptr(),n)!=n)
308       return ReadError;
309     packet->wroteBytes(n);
310     framesize-=n;
311     if (framesize) {
312       context->post_packet(packet);
313       packet=NULL;
314       return ReadOk;
315       }
316     sample++;
317     }
318   else {
319     packet->stream_position = track->getSamplePosition(sample);
320     }
321 
322   for (;sample<nsamples;sample++) {
323 
324     // Framesize for this sample
325     framesize = track->getSampleSize(sample);
326 
327     // Gracefully handle unknown framesizes
328     if (__unlikely(framesize<0))
329       return ReadError;
330 
331     // Check if packet is full and we should continue at the next packet
332     if (packet->space()<8){
333       framesize = 0; // no remaining data to be read next time
334       context->post_packet(packet);
335       packet=nullptr;
336       return ReadOk;
337       }
338 
339     // Locate sample
340     FXlong offset = track->getSampleOffset(sample);
341     input->position(offset,FXIO::Begin);
342 
343     // Send framesize to AAC and ALAC decoder
344     if (track->codec==Codec::ALAC || track->codec==Codec::AAC) {
345       if (__unlikely(framesize > UINT32_MAX)) return ReadError;
346       FXuint size32=framesize; // perhaps bounce check?
347       memcpy(packet->ptr(),&size32,4);
348       packet->wroteBytes(4);
349       }
350 
351     FXlong n = FXMIN(framesize,packet->space());
352     if (input->read(packet->ptr(),n)!=n){
353       packet->unref();
354       return ReadError;
355       }
356     packet->wroteBytes(n);
357     framesize-=n;
358 
359     /// If framesize remaining, assume packet is full
360     if(framesize) {
361       context->post_packet(packet);
362       packet=nullptr;
363       return ReadOk;
364       }
365     }
366 
367   if (packet) {
368     FXASSERT(sample>=nsamples-1);
369     packet->flags|=FLAG_EOS;
370     context->post_packet(packet);
371     packet=nullptr;
372     return ReadDone;
373     }
374 
375   return ReadOk;
376   }
377 
378 
clear_tracks()379 void MP4Reader::clear_tracks(){
380   for (int i=0;i<tracks.no();i++)
381     if (tracks[i]!=track)
382       delete tracks[i];
383   tracks.clear();
384   delete track;
385   track = nullptr;
386   }
387 
388 
select_track()389 FXbool MP4Reader::select_track() {
390   Track* selected = nullptr;
391   for (FXint i=0;i<tracks.no();i++) {
392     if (tracks[i]->codec!=Codec::Invalid) {
393       selected = tracks[i];
394       }
395     }
396   for (FXint i=0;i<tracks.no();i++){
397     if (tracks[i]!=selected)
398       delete tracks[i];
399     }
400   tracks.clear();
401   track = selected;
402 #ifdef DEBUG
403   if (track==nullptr)
404     GM_DEBUG_PRINT("[mp4] no suitable track found\n");
405 #endif
406   return (track!=nullptr);
407   }
408 
409 
parse()410 ReadStatus MP4Reader::parse() {
411   meta = new MetaInfo();
412 
413   if (atom_parse(input->size()) && select_track()) {
414 
415     FXASSERT(track);
416 
417     stream_length = track->getLength();
418     nsamples      = track->getNumSamples();
419     sample        = 0;
420 
421     af = track->af;
422 
423     ConfigureEvent * cfg = new ConfigureEvent(af,track->codec);
424     cfg->dc = track->dc;
425     track->dc = nullptr;
426 
427     GM_DEBUG_PRINT("[mp4] total samples %lld\n",stream_length);
428     GM_DEBUG_PRINT("[mp4] padding %hu %hu\n",padstart,padend);
429     GM_DEBUG_PRINT("[mp4] composition offset %d\n",track->getCompositionOffset(0));
430 
431     if (track->codec == Codec::AAC) {
432 
433       if (track->upsampled) {
434         padstart <<= 1;
435         padend <<= 1;
436         }
437 
438       // FAAD has a fixed decoder delay of one frame
439       if (padstart || padend) {
440           stream_length -= (track->samples_per_frame + padend);
441         }
442       else if (stream_length && track->stts.no() && track->ctts.no()) {
443         padstart = track->getCompositionOffset(0); // usually 1024
444         stream_length -= track->samples_per_frame;
445         }
446       cfg->stream_offset_start = FXMAX(0, padstart - track->samples_per_frame);
447       GM_DEBUG_PRINT("[mp4] stream_offset_start %hu\n",cfg->stream_offset_start);
448       }
449 
450     GM_DEBUG_STREAM_LENGTH("mp4",stream_length-cfg->stream_offset_start,track->af.rate);
451     GM_DEBUG_PRINT("[mp4] codec %s\n",Codec::name(track->codec));
452     context->post_configuration(cfg);
453 
454     if (meta->title.length()) {
455       context->post_meta(meta);
456       meta = nullptr;
457       }
458     else {
459       meta->unref();
460       meta = nullptr;
461       }
462 
463     flags|=FLAG_PARSED;
464     return ReadOk;
465     }
466   meta->unref();
467   meta=nullptr;
468   return ReadError;
469   }
470 
471 
472 
473 // Defined in reverse so we don't have to byteswap while reading on LE.
474 #define DEFINE_ATOM(b1,b2,b3,b4) ((b4<<24) | (b3<<16) | (b2<<8) | (b1))
475 
476 
477 enum Atom {
478 
479   ESDS = DEFINE_ATOM('e','s','d','s'),
480 
481   FREE = DEFINE_ATOM('f','r','e','e'),
482 
483   FTYP = DEFINE_ATOM('f','t','y','p'),
484 
485   ILST = DEFINE_ATOM('i','l','s','t'),
486 
487   MDAT = DEFINE_ATOM('m','d','a','t'),
488 
489   MOOV = DEFINE_ATOM('m','o','o','v'),
490 
491   MVHD = DEFINE_ATOM('m','v','h','d'),
492   MDIA = DEFINE_ATOM('m','d','i','a'),
493   MDHD = DEFINE_ATOM('m','d','h','d'),
494   MINF = DEFINE_ATOM('m','i','n','f'),
495 
496   STBL = DEFINE_ATOM('s','t','b','l'),
497   STSD = DEFINE_ATOM('s','t','s','d'),
498   STSC = DEFINE_ATOM('s','t','s','c'),
499   STSZ = DEFINE_ATOM('s','t','s','z'),
500   STCO = DEFINE_ATOM('s','t','c','o'),
501   STTS = DEFINE_ATOM('s','t','t','s'),
502   CTTS = DEFINE_ATOM('c','t','t','s'),
503 
504   TRAK = DEFINE_ATOM('t','r','a','k'),
505   UDTA = DEFINE_ATOM('u','d','t','a'),
506   MP4A = DEFINE_ATOM('m','p','4','a'),
507   ALAC = DEFINE_ATOM('a','l','a','c'),
508   META = DEFINE_ATOM('m','e','t','a'),
509 
510   CART = DEFINE_ATOM(169,'A','R','T'),
511   CALB = DEFINE_ATOM(169,'a','l','b'),
512   CNAM = DEFINE_ATOM(169,'n','a','m'),
513   CTOO = DEFINE_ATOM(169,'t','o','o'),
514   CCMT = DEFINE_ATOM(169,'c','m','t'),
515 
516   MEAN = DEFINE_ATOM('m','e','a','n'),
517   NAME = DEFINE_ATOM('n','a','m','e'),
518   DATA = DEFINE_ATOM('d','a','t','a'),
519   DDDD = DEFINE_ATOM('-','-','-','-')
520   };
521 
522 
atom_parse_trak(FXlong)523 FXbool MP4Reader::atom_parse_trak(FXlong /*size*/) {
524   track = new Track();
525   tracks.append(track);
526   return true;
527   }
528 
529 
atom_parse_alac(FXlong size)530 FXbool MP4Reader::atom_parse_alac(FXlong size) {
531   FXuchar  alac_reserved[16];
532   FXushort index;
533   FXushort version;
534   FXushort channels;
535   FXushort samplesize;
536   FXuint   samplerate;
537 
538   if (track==NULL)
539     return false;
540 
541   if (input->read(&alac_reserved,6)!=6)
542     return false;
543 
544   if (!input->read_uint16_be(index)) // data reference index
545     return false;
546 
547   if (!input->read_uint16_be(version))
548     return false;
549 
550   if (input->read(&alac_reserved,6)!=6)
551     return false;
552 
553   if (!input->read_uint16_be(channels))
554     return false;
555 
556   if (!input->read_uint16_be(samplesize))
557     return false;
558 
559   if (input->read(&alac_reserved,4)!=4)
560     return false;
561 
562   if (!input->read_uint32_be(samplerate))
563     return false;
564 
565   // samplerate comes in as a fixed point number 16.16
566   samplerate = samplerate >> 16;
567 
568   // ALAC specifc info (size + "alac" + version)
569   if (input->read(&alac_reserved,12)!=12)
570     return false;
571 
572   // Check size of AlacSpecificConfig
573   if (size-40!=24 && size-40!=48)
574     return false;
575 
576   // Check for duplicate entry
577   if (track->dc) {
578     GM_DEBUG_PRINT("[mp4] decoder_specific_info already set?");
579     return false;
580     }
581 
582   // Read AlacSpecificConfig
583   DecoderSpecificConfig * dc = new DecoderSpecificConfig();
584   dc->config_bytes = size - 40;
585   allocElms(dc->config,dc->config_bytes);
586   if (input->read(dc->config,dc->config_bytes)!=dc->config_bytes) {
587     delete dc;
588     return false;
589     }
590 
591   // As it turns out, samplesize from the AudioSampleEntry box is not always accurate
592   // 24 bit files I've gotten from bandcamp.org had it set to 16 which is the default value
593   // for audio sample entry boxes. Since decoder itself relies on the DecoderSpecificConfig,
594   // we may as well use the bitdepth information from there instead.
595   FXuchar bitdepth = *(dc->config + 5);
596 
597   // Record what we found
598   track->codec = Codec::ALAC;
599   track->af.set(Format::Signed,bitdepth,bitdepth>>3,samplerate,channels);
600   track->dc = dc;
601 
602   // Some extra debugging
603   if (samplesize!=bitdepth)
604     GM_DEBUG_PRINT("[mp4] alac samplesize %hu doesn't match bitdepth %hhu\n",samplesize,bitdepth);
605 
606   return true;
607   }
608 
609 
610 
atom_parse_mp4a(FXlong size)611 FXbool MP4Reader::atom_parse_mp4a(FXlong size) {
612   FXuchar  mp4a_reserved[16];
613   FXushort index;
614   FXushort version;
615   FXushort channels;
616   FXushort samplesize;
617   FXuint   samplerate;
618 
619   FXlong nbytes = size;
620 
621   if (track==nullptr)
622     return false;
623 
624   if (input->read(&mp4a_reserved,6)!=6)
625     return false;
626 
627   if (!input->read_uint16_be(index))
628     return false;
629 
630   if (!input->read_uint16_be(version))
631     return false;
632 
633   if (input->read(&mp4a_reserved,6)!=6)
634     return false;
635 
636   if (!input->read_uint16_be(channels))
637     return false;
638 
639   if (!input->read_uint16_be(samplesize))
640     return false;
641 
642   if (input->read(&mp4a_reserved,4)!=4)
643     return false;
644 
645   if (!input->read_uint32_be(samplerate))
646     return false;
647 
648   samplerate = samplerate >> 16;
649 
650   GM_DEBUG_PRINT("[mp4] samplerate %d\n",samplerate);
651   GM_DEBUG_PRINT("[mp4] channels %d\n",channels);
652 
653   track->af.set(AP_FORMAT_S16,samplerate,channels);
654 
655   if (version==1) {
656     if (input->read(&mp4a_reserved,16)!=16)
657       return false;
658     nbytes -= 16;
659     }
660   else if (version==2) {
661     input->position(36,FXIO::Current);
662     nbytes -= 36;
663     }
664 
665   if (nbytes-28>0) {
666     return atom_parse(nbytes-28);
667     }
668   return true;
669   }
670 
671 
read_descriptor_length(FXuint & length)672 FXuint MP4Reader::read_descriptor_length(FXuint & length) {
673   FXuchar b,nbytes=0;
674   length=0;
675   do {
676     if (input->read(&b,1)!=1)
677       return 0;
678     nbytes++;
679     length = (length<<7) | (b&0x7f);
680     }
681   while(b&0x80);
682   return nbytes;
683   }
684 
685 
686 #define ESDescriptorTag            0x3
687 #define DecoderConfigDescriptorTag 0x4
688 #define DecoderSpecificInfoTag     0x5
689 
atom_parse_esds(FXlong size)690 FXbool MP4Reader::atom_parse_esds(FXlong size) {
691   FXlong   nbytes = size;
692   FXuint   version;
693   FXushort esid;
694   FXuchar  esflags;
695   FXuint   length;
696   FXuint   l;
697 
698   FXlong start = input->position();
699 
700   if (track==nullptr)
701     return false;
702 
703   if (!input->read_uint32_be(version))
704     return false;
705 
706   FXuchar tag;
707 
708   if (input->read(&tag,1)!=1)
709     return false;
710 
711   if (tag==ESDescriptorTag) {
712 
713     length = read_descriptor_length(l);
714 
715     if (!input->read_uint16_be(esid))
716       return false;
717 
718     if (!input->read(&esflags,1))
719       return false;
720 
721     nbytes-=(length);
722     }
723   else {
724     // fixme
725     return false;
726     }
727 
728   if (input->read(&tag,1)!=1)
729     return false;
730 
731   if (tag!=DecoderConfigDescriptorTag)
732     return false;
733 
734   nbytes -= read_descriptor_length(l);
735 
736   if (input->read(&tag,1)!=1)
737     return false;
738 
739   if (tag==0x40 || tag==0x67)
740     track->codec = Codec::AAC;
741 
742   if (!input->read_uint32_be(version))
743     return false;
744 
745   FXuint avgbitrate;
746   FXuint maxbitrate;
747 
748   if (!input->read_uint32_be(maxbitrate))
749     return false;
750 
751   if (!input->read_uint32_be(avgbitrate))
752     return false;
753 
754   if (input->read(&tag,1)!=1)
755     return false;
756 
757   if (tag!=DecoderSpecificInfoTag)
758     return false;
759 
760 
761   DecoderSpecificConfig * dc = new DecoderSpecificConfig();
762 
763   nbytes -= read_descriptor_length(dc->config_bytes);
764 
765   if (dc->config_bytes) {
766 
767     allocElms(dc->config,dc->config_bytes);
768 
769     if (input->read(dc->config,dc->config_bytes)!=dc->config_bytes) {
770       delete dc;
771       return false;
772       }
773 
774     track->dc = dc;
775 
776 #ifdef HAVE_FAAD
777     if (!ap_parse_aac_specific_config(dc->config,dc->config_bytes,track->samples_per_frame,track->upsampled,track->af))
778       return false;
779 #endif
780 
781     }
782 
783   FXlong end = input->position();
784 
785   if (end-start>0)
786     input->position(size-(end-start),FXIO::Current);
787 
788   return true;
789   }
790 
791 
792 
atom_parse_meta(FXlong size)793 FXbool MP4Reader::atom_parse_meta(FXlong size) {
794   FXuint   version;
795 
796   if (track==nullptr)
797     return false;
798 
799   if (!input->read_uint32_be(version))
800     return false;
801 
802   if (!atom_parse(size-4))
803     return false;
804 
805   return true;
806   }
807 
808 
809 
atom_parse_meta_free(FXlong size)810 FXbool MP4Reader::atom_parse_meta_free(FXlong size) {
811   FXuint atom_type;
812   FXlong atom_size;
813   FXint length;
814 
815   FXint   type;
816   FXshort county;
817   FXshort language;
818 
819   FXString mean;
820   FXString name;
821   FXString data;
822 
823   while(size>=8 && atom_parse_header(atom_type,atom_size,size)){
824     switch(atom_type){
825 
826       case MEAN:
827           if (atom_size <= 4)
828             return false;
829 
830           if (!input->read_int32_be(length))
831             return false;
832 
833           mean.length(atom_size-4);
834           if (input->read(mean.text(),atom_size-4)!=atom_size-4)
835             return false;
836 
837           break;
838 
839       case NAME:
840 
841           if (atom_size <= 4)
842             return false;
843 
844           if (!input->read_int32_be(length))
845             return false;
846 
847           name.length(atom_size-4);
848           if (input->read(name.text(),atom_size-4)!=atom_size-4)
849             return false;
850 
851           break;
852 
853       case DATA:
854 
855           if (!input->read_int32_be(type))
856             return false;
857 
858           if (type==1) { // UTF-8
859 
860             if (!input->read_int16_be(county))
861               return false;
862 
863             if (!input->read_int16_be(language))
864               return false;
865 
866             data.length(atom_size-8);
867             if (input->read(data.text(),(atom_size-8))!=(atom_size-8))
868               return false;
869 
870             }
871           else {
872             input->position(atom_size-4,FXIO::Current);
873             }
874           break;
875 
876       default : input->position(atom_size,FXIO::Current);
877                 break;
878       }
879     size-=atom_size;
880     }
881 
882   GM_DEBUG_PRINT("[mp4] %s.%s = %s\n",mean.text(),name.text(),data.text());
883   if (name=="iTunSMPB") {
884     FXlong duration;
885     data.simplify().scan("%*x %hx %hx %lx",&padstart,&padend,&duration);
886     GM_DEBUG_PRINT("[mp4] parsed iTunSMPB %hu %hu %lld\n",padstart,padend,duration);
887     }
888   return true;
889   }
890 
891 
892 
atom_parse_meta_text(FXlong size,FXString & field)893 FXbool MP4Reader::atom_parse_meta_text(FXlong size,FXString & field) {
894   FXint  length;
895   FXchar id[4];
896   FXint  type;
897   FXshort  county;
898   FXshort  language;
899 
900   if (!input->read_int32_be(length))
901     return false;
902 
903   if (size!=length)
904     return false;
905 
906   if (input->read(&id,4)!=4)
907     return false;
908 
909   if (!input->read_int32_be(type))
910     return false;
911 
912   if (type==1) {
913 
914     if (!input->read_int16_be(county))
915       return false;
916 
917     if (!input->read_int16_be(language))
918       return false;
919 
920     field.length(length-16);
921     if (input->read(&field[0],(length-16))!=(length-16))
922       return false;
923 
924     GM_DEBUG_PRINT("[mp4] meta text: \"%s\"\n",field.text());
925     }
926   else {
927     input->position(length-12,FXIO::Current);
928     }
929   return true;
930   }
931 
atom_parse_stsd(FXlong size)932 FXbool MP4Reader::atom_parse_stsd(FXlong size) {
933   FXuint   version;
934   FXuint   nentries;
935 
936   if (track==nullptr)
937     return false;
938 
939   if (!input->read_uint32_be(version))
940     return false;
941 
942   if (!input->read_uint32_be(nentries))
943     return false;
944 
945   FXASSERT(nentries==1);
946 
947   if (!atom_parse(size-8))
948     return false;
949 
950   return true;
951   }
952 
953 
atom_parse_stsc(FXlong)954 FXbool MP4Reader::atom_parse_stsc(FXlong /*size*/) {
955   FXuint version;
956   FXuint nentries;
957 
958   if (track==nullptr)
959     return false;
960 
961   if (!input->read_uint32_be(version))
962     return false;
963 
964   if (!input->read_uint32_be(nentries))
965     return false;
966 
967   if (nentries) {
968     track->stsc.no(nentries);
969     for (FXuint i=0;i<nentries;i++) {
970       if (!input->read_int32_be(track->stsc[i].first))
971         return false;
972       if (!input->read_int32_be(track->stsc[i].nsamples))
973         return false;
974       if (!input->read_int32_be(track->stsc[i].index))
975         return false;
976       }
977     }
978   //FXASSERT(size==((nentries*12)+8));
979   return true;
980   }
981 
982 
983 
atom_parse_stco(FXlong)984 FXbool MP4Reader::atom_parse_stco(FXlong/*size*/) {
985   FXuint   version;
986   FXuint   nchunks;
987 
988   if (track==nullptr)
989     return false;
990 
991   if (input->read(&version,4)!=4)
992     return false;
993 
994   if (!input->read_uint32_be(nchunks))
995     return false;
996 
997   if (nchunks>0) {
998     track->stco.no(nchunks);
999     for (FXuint i=0;i<nchunks;i++) {
1000       if (!input->read_uint32_be(track->stco[i]))
1001         return false;
1002       }
1003     }
1004   //FXASSERT(size==((nchunks*4)+8));
1005   return true;
1006   }
1007 
atom_parse_stts(FXlong)1008 FXbool MP4Reader::atom_parse_stts(FXlong /*size*/) {
1009   FXuint   version;
1010   FXuint   nsize;
1011 
1012   if (track==nullptr)
1013     return false;
1014 
1015   if (input->read(&version,4)!=4)
1016     return false;
1017 
1018   if (!input->read_uint32_be(nsize))
1019     return false;
1020 
1021   if (nsize>0) {
1022     track->stts.no(nsize);
1023     for (FXuint i=0;i<nsize;i++) {
1024       if (!input->read_uint32_be(track->stts[i].nsamples)) return false;
1025       if (!input->read_uint32_be(track->stts[i].delta)) return false;
1026       //GM_DEBUG_PRINT("stts %d: %d %d\n",i,track->stts[i].nsamples,track->stts[i].delta);
1027       }
1028 
1029     }
1030   //FXASSERT(size==((nsize*8)+8));
1031   return true;
1032   }
1033 
1034 
atom_parse_ctts(FXlong)1035 FXbool MP4Reader::atom_parse_ctts(FXlong /*size*/) {
1036   FXuint version;
1037   FXuint nentries;
1038 
1039   if (track==NULL)
1040     return false;
1041 
1042   if (!input->read_uint32_be(version))
1043     return false;
1044 
1045   if (!input->read_uint32_be(nentries))
1046     return false;
1047 
1048   if (nentries) {
1049     track->ctts.no(nentries);
1050     for (FXuint i=0;i<nentries;i++) {
1051       if (!input->read_int32_be(track->ctts[i].nsamples))
1052         return false;
1053       if (!input->read_int32_be(track->ctts[i].offset))
1054         return false;
1055       //GM_DEBUG_PRINT("ctts %d: %d %d\n",i,track->ctts[i].nsamples,track->ctts[i].offset);
1056       }
1057     }
1058   //FXASSERT(size==((nentries*12)+8));
1059   return true;
1060   }
1061 
1062 
1063 
atom_parse_stsz(FXlong)1064 FXbool MP4Reader::atom_parse_stsz(FXlong /*size*/) {
1065   FXuint version;
1066   FXuint samplecount;
1067 
1068   if (track==nullptr)
1069     return false;
1070 
1071   if (input->read(&version,4)!=4)
1072     return false;
1073 
1074   if (!input->read_uint32_be(track->fixed_sample_size))
1075     return false;
1076 
1077   if (!input->read_uint32_be(samplecount))
1078     return false;
1079 
1080   if (track->fixed_sample_size==0 && samplecount>0) {
1081     track->stsz.no(samplecount);
1082     for (FXuint i=0;i<samplecount;i++) {
1083       if (!input->read_uint32_be(track->stsz[i]))
1084         return false;
1085       }
1086     }
1087   //FXASSERT(size==((nsamples*4)+12));
1088   return true;
1089   }
1090 
atom_parse_header(FXuint & type,FXlong & size,FXlong & container)1091 FXbool MP4Reader::atom_parse_header(FXuint & type,FXlong & size,FXlong & container) {
1092   FXuint sz;
1093 
1094   if (!input->read_uint32_be(sz))
1095     return false;
1096 
1097   if (input->read(&type,4)!=4)
1098     return false;
1099 
1100   if (sz==1) {
1101     if (!input->read_int64_be(size))
1102       return false;
1103     size -= 16;
1104     container -= 16;
1105     }
1106   else {
1107     size = sz - 8;
1108     container -= 8;
1109     }
1110   return true;
1111   }
1112 
1113 
1114 
atom_parse(FXlong size)1115 FXbool MP4Reader::atom_parse(FXlong size) {
1116   static int indent = 0;
1117   FXuint atom_type;
1118   FXlong atom_size;
1119   FXbool ok;
1120   indent++;
1121   while(size>=8 && atom_parse_header(atom_type,atom_size,size)){
1122     GM_DEBUG_PRINT("[mp4] %*d atom %c%c%c%c size %lld left %lld\n",indent,indent,(atom_type)&0xFF,(atom_type>>8)&0xFF,(atom_type>>16)&0xFF,(atom_type>>24),atom_size,size);
1123     switch(atom_type){
1124 
1125       // Don't go any further than the mdat atom in serial streams.
1126       case MDAT: if (input->serial())
1127                    return true;
1128                  input->position(atom_size,FXIO::Current); ok=true;
1129                  break;
1130 
1131       case TRAK: ok=atom_parse_trak(atom_size);
1132                  if(!ok) return false;
1133                  // fallthrough - intentionally no break
1134       case MDIA:
1135       case MINF:
1136       case STBL:
1137       case UDTA:
1138       case ILST:
1139       case MOOV: ok=atom_parse(atom_size);
1140                  break;
1141       case META: ok=atom_parse_meta(atom_size); break;
1142       case STSZ: ok=atom_parse_stsz(atom_size); break;
1143       case STCO: ok=atom_parse_stco(atom_size); break;
1144       case STSD: ok=atom_parse_stsd(atom_size); break;
1145       case STSC: ok=atom_parse_stsc(atom_size); break;
1146       case STTS: ok=atom_parse_stts(atom_size); break;
1147       case CTTS: ok=atom_parse_ctts(atom_size); break;
1148       case MP4A: ok=atom_parse_mp4a(atom_size); break;
1149       case ALAC: ok=atom_parse_alac(atom_size); break;
1150       case ESDS: ok=atom_parse_esds(atom_size); break;
1151       case DDDD: ok=atom_parse_meta_free(atom_size); break;
1152       case CART: ok=atom_parse_meta_text(atom_size,meta->artist); break;
1153       case CALB: ok=atom_parse_meta_text(atom_size,meta->album); break;
1154       case CNAM: ok=atom_parse_meta_text(atom_size,meta->title); break;
1155 #ifdef DEBUG
1156       case CTOO:
1157       case CCMT:
1158         {
1159           FXString comment;
1160           ok=atom_parse_meta_text(atom_size,comment);
1161           break;
1162         }
1163 #endif
1164       default  : input->position(atom_size,FXIO::Current); ok=true;
1165                  break;
1166       }
1167     if (!ok) return false;
1168     size-=atom_size;
1169     }
1170   indent--;
1171   return true;
1172   }
1173 
1174 
1175 
1176 
1177 }
1178 
1179 
1180 
1181