1 /*******************************************************************************
2  mp4_reader.c - A library for reading MPEG4.
3 
4  Copyright (C) 2007-2009 CodeShop B.V.
5  http://www.code-shop.com
6 
7  For licensing see the LICENSE file
8 ******************************************************************************/
9 
10 #ifdef HAVE_CONFIG_H
11 #include "config.h"
12 #endif
13 
14 #ifdef __cplusplus
15 #define __STDC_FORMAT_MACROS // C++ should define this for PRIu64
16 #define __STDC_LIMIT_MACROS  // C++ should define this for UINT64_MAX
17 #endif
18 
19 #include "mp4_reader.h"
20 #include "mp4_io.h"
21 #include <stdlib.h>
22 #include <string.h>
23 
24 struct atom_t
25 {
26  uint32_t type_;
27  uint32_t short_size_;
28  uint64_t size_;
29  unsigned char* start_;
30  unsigned char* end_;
31 };
32 typedef struct atom_t atom_t;
33 
atom_print(mp4_context_t const * mp4_context,atom_t const * atom)34 static void atom_print(mp4_context_t const* mp4_context, atom_t const* atom)
35 {
36   MP4_INFO("Atom(%c%c%c%c,%"PRIu64")\n",
37            atom->type_ >> 24,
38            atom->type_ >> 16,
39            atom->type_ >> 8,
40            atom->type_,
41            atom->size_);
42 }
43 
44 static unsigned char*
atom_read_header(mp4_context_t const * mp4_context,unsigned char * buffer,atom_t * atom)45 atom_read_header(mp4_context_t const* mp4_context, unsigned char* buffer,
46                  atom_t* atom)
47 {
48   atom->start_ = buffer;
49   atom->short_size_ = read_32(buffer);
50   atom->type_ = read_32(buffer + 4);
51 
52   if(atom->short_size_ == 1)
53     atom->size_ = read_64(buffer + 8);
54   else
55     atom->size_ = atom->short_size_;
56 
57   atom->end_ = atom->start_ + atom->size_;
58 
59   atom_print(mp4_context, atom);
60 
61   if(atom->size_ < ATOM_PREAMBLE_SIZE)
62   {
63     MP4_ERROR("%s", "Error: invalid atom size\n");
64     return 0;
65   }
66 
67   return buffer + ATOM_PREAMBLE_SIZE + (atom->short_size_ == 1 ? 8 : 0);
68 }
69 
unknown_atom_add_atom(struct unknown_atom_t * parent,void * atom)70 static struct unknown_atom_t* unknown_atom_add_atom(struct unknown_atom_t* parent, void* atom)
71 {
72   size_t size = read_32((const unsigned char*)atom);
73   unknown_atom_t* unknown = unknown_atom_init();
74   unknown->atom_ = malloc(size);
75   memcpy(unknown->atom_, atom, size);
76 
77   {
78     unknown_atom_t** adder = &parent;
79     while(*adder != NULL)
80     {
81       adder = &(*adder)->next_;
82     }
83     *adder = unknown;
84   }
85 
86   return parent;
87 }
88 
atom_reader(struct mp4_context_t const * mp4_context,struct atom_read_list_t * atom_read_list,unsigned int atom_read_list_size,void * parent,unsigned char * buffer,uint64_t size)89 extern int atom_reader(struct mp4_context_t const* mp4_context,
90                        struct atom_read_list_t* atom_read_list,
91                        unsigned int atom_read_list_size,
92                        void* parent,
93                        unsigned char* buffer, uint64_t size)
94 {
95   atom_t leaf_atom;
96   unsigned char* buffer_start = buffer;
97 
98   while(buffer < buffer_start + size)
99   {
100     unsigned int i;
101     buffer = atom_read_header(mp4_context, buffer, &leaf_atom);
102 
103     if(buffer == NULL)
104     {
105       return 0;
106     }
107 
108     for(i = 0; i != atom_read_list_size; ++i)
109     {
110       if(leaf_atom.type_ == atom_read_list[i].type_)
111       {
112         break;
113       }
114     }
115 
116     if(i == atom_read_list_size)
117     {
118       // add to unkown chunks
119       (*(unknown_atom_t**)parent) =
120         unknown_atom_add_atom(*(unknown_atom_t**)(parent), buffer - ATOM_PREAMBLE_SIZE);
121     }
122     else
123     {
124       void* child =
125         atom_read_list[i].reader_(mp4_context, parent, buffer,
126           leaf_atom.size_ - ATOM_PREAMBLE_SIZE);
127       if(!child)
128         break;
129       if(!atom_read_list[i].destination_(mp4_context, parent, child))
130         break;
131     }
132     buffer = leaf_atom.end_;
133   }
134 
135   if(buffer < buffer_start + size)
136   {
137     return 0;
138   }
139 
140   return 1;
141 }
142 
ctts_read(mp4_context_t const * UNUSED (mp4_context),void * UNUSED (parent),unsigned char * buffer,uint64_t size)143 static void* ctts_read(mp4_context_t const* UNUSED(mp4_context),
144                        void* UNUSED(parent),
145                        unsigned char* buffer, uint64_t size)
146 {
147   unsigned int i;
148 
149   ctts_t* atom;
150 
151   if(size < 8)
152     return 0;
153 
154   atom = ctts_init();
155   atom->version_ = read_8(buffer + 0);
156   atom->flags_ = read_24(buffer + 1);
157   atom->entries_ = read_32(buffer + 4);
158 
159   if(size < 8 + atom->entries_ * sizeof(ctts_table_t))
160     return 0;
161 
162   buffer += 8;
163 
164   atom->table_ = (ctts_table_t*)(malloc(atom->entries_ * sizeof(ctts_table_t)));
165 
166   for(i = 0; i != atom->entries_; ++i)
167   {
168     atom->table_[i].sample_count_ = read_32(buffer + 0);
169     atom->table_[i].sample_offset_ = read_32(buffer + 4);
170     buffer += 8;
171   }
172 
173   return atom;
174 }
175 
stco_read(mp4_context_t const * UNUSED (mp4_context),void * UNUSED (parent),unsigned char * buffer,uint64_t size)176 static void* stco_read(mp4_context_t const* UNUSED(mp4_context),
177                        void* UNUSED(parent),
178                        unsigned char* buffer, uint64_t size)
179 {
180   unsigned int i;
181 
182   stco_t* atom;
183 
184   if(size < 8)
185     return 0;
186 
187   atom = stco_init();
188   atom->version_ = read_8(buffer + 0);
189   atom->flags_ = read_24(buffer + 1);
190   atom->entries_ = read_32(buffer + 4);
191   buffer += 8;
192 
193   if(size < 8 + atom->entries_ * sizeof(uint32_t))
194     return 0;
195 
196   atom->chunk_offsets_ = (uint64_t*)malloc(atom->entries_ * sizeof(uint64_t));
197   for(i = 0; i != atom->entries_; ++i)
198   {
199     atom->chunk_offsets_[i] = read_32(buffer);
200     buffer += 4;
201   }
202 
203   return atom;
204 }
205 
co64_read(mp4_context_t const * UNUSED (mp4_context),void * UNUSED (parent),unsigned char * buffer,uint64_t size)206 static void* co64_read(mp4_context_t const* UNUSED(mp4_context),
207                        void* UNUSED(parent),
208                        unsigned char* buffer, uint64_t size)
209 {
210   unsigned int i;
211 
212   stco_t* atom;
213 
214   if(size < 8)
215     return 0;
216 
217   atom = stco_init();
218   atom->version_ = read_8(buffer + 0);
219   atom->flags_ = read_24(buffer + 1);
220   atom->entries_ = read_32(buffer + 4);
221   buffer += 8;
222 
223   if(size < 8 + atom->entries_ * sizeof(uint64_t))
224     return 0;
225 
226   atom->chunk_offsets_ = (uint64_t*)malloc(atom->entries_ * sizeof(uint64_t));
227   for(i = 0; i != atom->entries_; ++i)
228   {
229     atom->chunk_offsets_[i] = read_64(buffer);
230     buffer += 8;
231   }
232 
233   return atom;
234 }
235 
stsz_read(mp4_context_t const * mp4_context,void * UNUSED (parent),unsigned char * buffer,uint64_t size)236 static void* stsz_read(mp4_context_t const* mp4_context,
237                        void* UNUSED(parent),
238                        unsigned char* buffer, uint64_t size)
239 {
240   unsigned int i;
241 
242   stsz_t* atom;
243 
244   if(size < 12)
245   {
246     MP4_ERROR("%s", "Error: not enough bytes for stsz atom\n");
247     return 0;
248   }
249 
250   atom = stsz_init();
251   atom->version_ = read_8(buffer + 0);
252   atom->flags_ = read_24(buffer + 1);
253   atom->sample_size_ = read_32(buffer + 4);
254   atom->entries_ = read_32(buffer + 8);
255   buffer += 12;
256 
257   // fix for clayton.mp4, it mistakenly says there is 1 entry
258 //  if(atom->sample_size_ && atom->entries_)
259 //    atom->entries_ = 0;
260 
261   if(!atom->sample_size_)
262   {
263     if(size < 12 + atom->entries_ * sizeof(uint32_t))
264     {
265       MP4_ERROR("%s", "Error: stsz.entries don't match with size\n");
266       stsz_exit(atom);
267       return 0;
268     }
269 
270     atom->sample_sizes_ = (uint32_t*)malloc(atom->entries_ * sizeof(uint32_t));
271     for(i = 0; i != atom->entries_; ++i)
272     {
273       atom->sample_sizes_[i] = read_32(buffer);
274       buffer += 4;
275     }
276   }
277 
278   return atom;
279 }
280 
stsc_read(mp4_context_t const * UNUSED (mp4_context),void * UNUSED (parent),unsigned char * buffer,uint64_t size)281 static void* stsc_read(mp4_context_t const* UNUSED(mp4_context),
282                        void* UNUSED(parent),
283                        unsigned char* buffer, uint64_t size)
284 {
285   unsigned int i;
286 
287   stsc_t* atom;
288 
289   if(size < 8)
290     return 0;
291 
292   atom = stsc_init();
293   atom->version_ = read_8(buffer + 0);
294   atom->flags_ = read_24(buffer + 1);
295   atom->entries_ = read_32(buffer + 4);
296 
297   if(size < 8 + atom->entries_ * sizeof(stsc_table_t))
298     return 0;
299 
300   buffer += 8;
301 
302   // reserve space for one extra entry as when splitting the video we may have to
303   // split the first entry
304   atom->table_ = (stsc_table_t*)(malloc((atom->entries_ + 1) * sizeof(stsc_table_t)));
305 
306   for(i = 0; i != atom->entries_; ++i)
307   {
308     atom->table_[i].chunk_ = read_32(buffer + 0) - 1; // Note: we use zero based
309     atom->table_[i].samples_ = read_32(buffer + 4);
310     atom->table_[i].id_ = read_32(buffer + 8);
311     buffer += 12;
312   }
313 
314   return atom;
315 }
316 
stss_read(mp4_context_t const * UNUSED (mp4_context),void * UNUSED (parent),unsigned char * buffer,uint64_t size)317 static void* stss_read(mp4_context_t const* UNUSED(mp4_context),
318                        void* UNUSED(parent),
319                        unsigned char* buffer, uint64_t size)
320 {
321   unsigned int i;
322 
323   stss_t* atom;
324 
325   if(size < 8)
326     return 0;
327 
328   atom = stss_init();
329   atom->version_ = read_8(buffer + 0);
330   atom->flags_ = read_24(buffer + 1);
331   atom->entries_ = read_32(buffer + 4);
332 
333   if(size < 8 + atom->entries_ * sizeof(uint32_t))
334     return 0;
335 
336   buffer += 8;
337 
338   atom->sample_numbers_ = (uint32_t*)malloc(atom->entries_ * sizeof(uint32_t));
339 
340   for(i = 0; i != atom->entries_; ++i)
341   {
342     atom->sample_numbers_[i] = read_32(buffer);
343     buffer += 4;
344   }
345 
346   return atom;
347 }
348 
mp4_read_desc_len(unsigned char ** buffer)349 static int mp4_read_desc_len(unsigned char** buffer)
350 {
351   uint32_t len = 0;
352   unsigned int bytes = 0;
353   for(;;)
354   {
355     unsigned int c = read_8(*buffer + bytes);
356     len <<= 7;
357     len |= (c & 0x7f);
358     if(++bytes == 4)
359       break;
360     if(!(c & 0x80))
361       break;
362   }
363 
364   *buffer += bytes;
365 
366   return len;
367 }
368 
esds_read(mp4_context_t const * mp4_context,sample_entry_t * sample_entry,unsigned char * buffer,uint64_t size)369 static int esds_read(mp4_context_t const* mp4_context,
370                      sample_entry_t* sample_entry,
371                      unsigned char* buffer, uint64_t size)
372 {
373   unsigned int tag;
374   unsigned int len;
375 
376   uint16_t stream_id;
377   unsigned int stream_priority;
378   unsigned int object_type_id;
379   unsigned int stream_type;
380   unsigned int buffer_size_db;
381 
382   if(size < 9)
383     return 0;
384 
385   /* unsigned char version = */ read_8(buffer);
386   /* unsigned int flags = */ read_24(buffer + 1);
387 
388   buffer += 4;
389 
390   // ES_DescrTag
391   tag = read_8(buffer);
392   buffer += 1;
393   if(tag == MP4_ELEMENTARY_STREAM_DESCRIPTOR_TAG)
394   {
395     len = mp4_read_desc_len(&buffer);
396     MP4_INFO("Elementary Stream Descriptor: len=%u\n", len);
397     stream_id = read_16(buffer + 0);
398     stream_priority = read_8(buffer + 2);
399     buffer += 3;
400   }
401   else
402   {
403     MP4_INFO("Elementary Stream Descriptor: len=%u\n", 2);
404     stream_id = read_16(buffer + 0);
405     buffer += 2;
406   }
407 
408   tag = read_8(buffer);
409   buffer += 1;
410   len = mp4_read_desc_len(&buffer);
411   MP4_INFO("MPEG: tag=%u len=%u\n", tag, len);
412 
413   // Decoder config descr Tag
414   if(tag != MP4_DECODER_CONFIG_DESCRIPTOR_TAG)
415   {
416     MP4_INFO("Decoder Config Descriptor: len=%u\n", len);
417     return 0;
418   }
419 
420   object_type_id = read_8(buffer);
421   buffer += 1; // object_type_id
422 
423   stream_type = read_8(buffer);
424   buffer += 1; // stream_type
425 
426   buffer_size_db = read_24(buffer);
427   buffer += 3; // buffer_size_db
428 
429   sample_entry->max_bitrate_ = read_32(buffer);
430   buffer += 4;
431 
432   sample_entry->avg_bitrate_ = read_32(buffer);
433   buffer += 4; // avg_bitrate
434 
435   MP4_INFO("%s", "Decoder Configuration Descriptor:\n");
436   MP4_INFO("  object_type_id=$%02x\n", object_type_id);
437   MP4_INFO("  stream_type=%u\n", stream_type);
438   MP4_INFO("  buffer_size_db=%u\n", buffer_size_db);
439   MP4_INFO("  max_bitrate=%u\n", sample_entry->max_bitrate_);
440   MP4_INFO("  avg_bitrate=%u\n", sample_entry->avg_bitrate_);
441 
442   switch(object_type_id)
443   {
444   case MP4_MPEG2AudioMain:
445   case MP4_MPEG2AudioLowComplexity:
446   case MP4_MPEG2AudioScaleableSamplingRate:
447   case MP4_MPEG4Audio:
448     sample_entry->wFormatTag = 0x00ff;  // WAVE_FORMAT_RAW_AAC1
449     break;
450   case MP4_MPEG1Audio:
451   case MP4_MPEG2AudioPart3:
452     sample_entry->wFormatTag = 0x0055;  // WAVE_FORMAT_MP3
453     break;
454   default:
455     break;
456   }
457 
458   if(!sample_entry->nAvgBytesPerSec)
459   {
460     unsigned int bitrate = sample_entry->avg_bitrate_;
461     if(!bitrate)
462       bitrate = sample_entry->max_bitrate_;
463     sample_entry->nAvgBytesPerSec = bitrate / 8;
464   }
465 
466   tag = read_8(buffer);
467   buffer += 1;
468   len = mp4_read_desc_len(&buffer);
469   MP4_INFO("MPEG: tag=%u len=%u\n", tag, len);
470   // Decoder specific descr Tag
471   if(tag == MP4_DECODER_SPECIFIC_DESCRIPTOR_TAG)
472   {
473     MP4_INFO("Decoder Specific Info Descriptor: len=%u\n", len);
474     sample_entry->codec_private_data_length_ = len;
475     sample_entry->codec_private_data_ = buffer;
476   }
477 
478   return 1;
479 }
480 
481 static int
stsd_parse_vide(mp4_context_t const * mp4_context,trak_t * UNUSED (trak),sample_entry_t * sample_entry)482 stsd_parse_vide(mp4_context_t const* mp4_context,
483                 trak_t* UNUSED(trak),
484                 sample_entry_t* sample_entry)
485 {
486   unsigned char* buffer = sample_entry->buf_;
487   unsigned char* buffer_start = buffer;
488   uint64_t size = sample_entry->len_;
489   unsigned int i;
490 
491   if(size < 78)
492   {
493     MP4_ERROR("%s", "invalid stsd video size\n");
494     return 0;
495   }
496 
497   // 'ovc1' is immediately followed by additional data and ends with the codec
498   // private data, *not* by additional atoms.
499   if(sample_entry->fourcc_ == FOURCC('o', 'v', 'c', '1'))
500   {
501     // TODO: get start of ovc1 codec private data (25 00 00 01 0F CB 6C 1A ..)
502     sample_entry->codec_private_data_ = buffer + 190;
503     sample_entry->codec_private_data_length_ = (unsigned int)(size - 190);
504     return 1;
505   }
506 
507   if(size >= 78 + ATOM_PREAMBLE_SIZE)
508   {
509     atom_t atom;
510     buffer += 78;
511     while(buffer < buffer_start + size - ATOM_PREAMBLE_SIZE)
512     {
513       buffer = atom_read_header(mp4_context, buffer, &atom);
514 
515       if(buffer == NULL)
516       {
517         return 0;
518       }
519 
520       switch(atom.type_)
521       {
522       case FOURCC('a', 'v', 'c', 'C'):
523       {
524         unsigned int sequence_parameter_sets;
525         unsigned int picture_parameter_sets;
526         unsigned int configuration_version;
527         unsigned int profile_indication;
528         unsigned int profile_compatibility;
529         unsigned int level_indication;
530 
531         sample_entry->codec_private_data_ = buffer;
532 
533         configuration_version = read_8(buffer + 0);
534         profile_indication = read_8(buffer + 1);
535         profile_compatibility = read_8(buffer + 2);
536         level_indication = read_8(buffer + 3);
537 
538         sample_entry->nal_unit_length_ = (read_8(buffer + 4) & 3) + 1;
539         sequence_parameter_sets = read_8(buffer + 5) & 0x1f;
540         buffer += 6;
541         for(i = 0; i != sequence_parameter_sets; ++i)
542         {
543           unsigned int sps_length = read_16(buffer);
544           buffer += 2;
545           sample_entry->sps_ = buffer;
546           sample_entry->sps_length_ = sps_length;
547           buffer +=  sps_length;
548         }
549 
550         picture_parameter_sets = read_8(buffer);
551         buffer += 1;
552         for(i = 0; i != picture_parameter_sets; ++i)
553         {
554           unsigned int pps_length = read_16(buffer);
555           buffer += 2;
556           sample_entry->pps_ = buffer;
557           sample_entry->pps_length_ = pps_length;
558           buffer += pps_length;
559         }
560         sample_entry->codec_private_data_length_ =
561           (unsigned int)(buffer - sample_entry->codec_private_data_);
562       }
563         break;
564       case FOURCC('e', 's', 'd', 's'):
565         if(!esds_read(mp4_context, sample_entry, buffer, atom.size_ - ATOM_PREAMBLE_SIZE))
566         {
567           return 0;
568         }
569         break;
570       default:
571         break;
572       }
573       buffer = atom.end_;
574     }
575   }
576 
577   return 1;
578 }
579 
wave_read(mp4_context_t const * mp4_context,sample_entry_t * sample_entry,unsigned char * buffer,uint64_t size)580 static int wave_read(mp4_context_t const* mp4_context,
581                      sample_entry_t* sample_entry,
582                      unsigned char* buffer, uint64_t size)
583 {
584   unsigned char* end = buffer + size;
585   while(buffer < end)
586   {
587     atom_t atom;
588     buffer = atom_read_header(mp4_context, buffer, &atom);
589 
590     if(buffer == NULL)
591     {
592       return 0;
593     }
594 
595     switch(atom.type_)
596     {
597     case FOURCC('e', 's', 'd', 's'):
598       if(!esds_read(mp4_context, sample_entry, buffer, atom.size_ - ATOM_PREAMBLE_SIZE))
599       {
600         return 0;
601       }
602       break;
603     }
604 
605     buffer = atom.end_;
606   }
607 
608   return 1;
609 }
610 
611 static int
stsd_parse_soun(mp4_context_t const * mp4_context,trak_t * UNUSED (trak),sample_entry_t * sample_entry)612 stsd_parse_soun(mp4_context_t const* mp4_context,
613                 trak_t* UNUSED(trak),
614                 sample_entry_t* sample_entry)
615 {
616   unsigned char* buffer = sample_entry->buf_;
617   unsigned char* buffer_start = buffer;
618   uint64_t size = sample_entry->len_;
619 
620   unsigned int data_reference_index;
621   unsigned int version;
622   unsigned int revision;
623   unsigned int vendor;
624   unsigned int compression_id;
625   unsigned int packet_size;
626 
627   if(sample_entry->len_ < 28)
628     return 0;
629 
630   data_reference_index = read_16(buffer + 6);
631 
632   version = read_16(buffer + 8);
633   revision = read_16(buffer + 10);
634   vendor = read_32(buffer + 12);
635 
636   sample_entry->nChannels = read_16(buffer + 16);
637 
638   if(sample_entry->nChannels == 3)
639     sample_entry->nChannels = 6;
640 
641   sample_entry->wBitsPerSample = read_16(buffer + 18);
642 
643   compression_id = read_16(buffer + 20);
644   packet_size = read_16(buffer + 22);
645 
646   // samplerate = {timescale of media} << 16
647   sample_entry->samplerate_hi_ = read_16(buffer + 24);
648   sample_entry->samplerate_lo_ = read_16(buffer + 26);
649 
650   sample_entry->nSamplesPerSec = sample_entry->samplerate_hi_;
651 
652   MP4_INFO("%s", "Sample Entry:\n");
653   MP4_INFO("  data_reference_index=%u\n", data_reference_index);
654   MP4_INFO("  version=%u\n", version);
655   MP4_INFO("  revision=%u\n", revision);
656   MP4_INFO("  vendor=%08x\n", vendor);
657   MP4_INFO("  channel_count=%u\n", sample_entry->nChannels);
658   MP4_INFO("  sample_size=%u\n", sample_entry->wBitsPerSample);
659   MP4_INFO("  compression_id=%u\n", compression_id);
660   MP4_INFO("  packet_size=%u\n", packet_size);
661   MP4_INFO("  samplerate_hi=%u\n", sample_entry->samplerate_hi_);
662   MP4_INFO("  samplerate_lo=%u\n", sample_entry->samplerate_lo_);
663 
664   buffer += 28;
665 
666   // 'owma' is immediately followed by the codec private data, *not* by
667   // additional atoms.
668   if(sample_entry->fourcc_ == FOURCC('o', 'w', 'm', 'a'))
669   {
670     sample_entry->codec_private_data_ = buffer;
671     sample_entry->codec_private_data_length_ = (unsigned int)(size - 28);
672 //    sample_entry->wFormatTag = read_16(buffer + 0);
673 //    ...
674 
675     return 1;
676   }
677 
678   if(version >= 1)
679   {
680     unsigned int samples_per_packet;
681     unsigned int bytes_per_packet;
682     unsigned int bytes_per_frame;
683     unsigned int bytes_per_sample;
684 
685     if(version == 1 && size < 28 + 16)
686     {
687       return 0;
688     }
689     if(version == 2 && size < 28 + 36)
690     {
691       return 0;
692     }
693     if(version > 2)
694     {
695       return 0;
696     }
697 
698     samples_per_packet = read_32(buffer + 0);
699     bytes_per_packet = read_32(buffer + 4);
700     bytes_per_frame = read_32(buffer + 8);
701     bytes_per_sample = read_32(buffer + 12);
702 
703     MP4_INFO("  samples_per_packet=%u\n", samples_per_packet);
704     MP4_INFO("  bytes_per_packet=%u\n", bytes_per_packet);
705     MP4_INFO("  bytes_per_frame=%u\n", bytes_per_frame);
706     MP4_INFO("  bytes_per_sample=%u\n", bytes_per_sample);
707 
708     if(samples_per_packet > 0)
709     {
710       sample_entry->nAvgBytesPerSec =
711         (sample_entry->nChannels * sample_entry->nSamplesPerSec *
712          bytes_per_packet + samples_per_packet / 2) / samples_per_packet;
713       sample_entry->nBlockAlign = (uint16_t)bytes_per_frame;
714     }
715     else
716     {
717       sample_entry->nAvgBytesPerSec =
718         sample_entry->nChannels * sample_entry->nSamplesPerSec *
719         sample_entry->wBitsPerSample / 8;
720     }
721 
722     buffer += version == 1 ? 16 : 36;
723   }
724 
725   if(buffer - buffer_start >= ATOM_PREAMBLE_SIZE)
726   {
727     atom_t atom;
728     while(buffer < buffer_start + size - ATOM_PREAMBLE_SIZE)
729     {
730       buffer = atom_read_header(mp4_context, buffer, &atom);
731 
732       if(buffer == NULL)
733       {
734         return 0;
735       }
736 
737       switch(atom.type_)
738       {
739       case FOURCC('w', 'a', 'v', 'e'):
740         if(!wave_read(mp4_context, sample_entry, buffer, atom.size_ - ATOM_PREAMBLE_SIZE))
741         {
742           return 0;
743         }
744         break;
745       case FOURCC('f', 'r', 'm', 'a'):
746         break;
747       case FOURCC('e', 's', 'd', 's'):
748         if(!esds_read(mp4_context, sample_entry, buffer, atom.size_ - ATOM_PREAMBLE_SIZE))
749         {
750           return 0;
751         }
752         break;
753       default:
754         break;
755       }
756 
757       buffer = atom.end_;
758     }
759   }
760 
761   return 1;
762 }
763 
stsd_parse(mp4_context_t const * mp4_context,trak_t * trak,stsd_t * stsd)764 static int stsd_parse(mp4_context_t const* mp4_context,
765                       trak_t* trak, stsd_t* stsd)
766 {
767   unsigned int i;
768   for(i = 0; i != stsd->entries_; ++i)
769   {
770     sample_entry_t* sample_entry = &stsd->sample_entries_[i];
771     switch(trak->mdia_->hdlr_->handler_type_)
772     {
773       case FOURCC('v', 'i', 'd', 'e'):
774         if(!stsd_parse_vide(mp4_context, trak, sample_entry))
775         {
776           return 0;
777         }
778         break;
779       case FOURCC('s', 'o', 'u', 'n'):
780         if(!stsd_parse_soun(mp4_context, trak, sample_entry))
781         {
782           return 0;
783         }
784         break;
785       case FOURCC('h', 'i', 'n', 't'):
786       default:
787         return 1;
788     }
789   }
790 
791   return 1;
792 }
793 
stts_read(mp4_context_t const * UNUSED (mp4_context),void * UNUSED (parent),unsigned char * buffer,uint64_t size)794 static void* stts_read(mp4_context_t const* UNUSED(mp4_context),
795                        void* UNUSED(parent),
796                        unsigned char* buffer, uint64_t size)
797 {
798   unsigned int i;
799 
800   stts_t* atom;
801 
802   if(size < 8)
803     return 0;
804 
805   atom = stts_init();
806   atom->version_ = read_8(buffer + 0);
807   atom->flags_ = read_24(buffer + 1);
808   atom->entries_ = read_32(buffer + 4);
809 
810   if(size < 8 + atom->entries_ * sizeof(stts_table_t))
811     return 0;
812 
813   buffer += 8;
814 
815   atom->table_ = (stts_table_t*)(malloc(atom->entries_ * sizeof(stts_table_t)));
816 
817   for(i = 0; i != atom->entries_; ++i)
818   {
819     atom->table_[i].sample_count_ = read_32(buffer + 0);
820     atom->table_[i].sample_duration_ = read_32(buffer + 4);
821     buffer += 8;
822   }
823 
824   return atom;
825 }
826 
stsd_read(mp4_context_t const * UNUSED (mp4_context),void * UNUSED (parent),unsigned char * buffer,uint64_t size)827 static void* stsd_read(mp4_context_t const* UNUSED(mp4_context),
828                        void* UNUSED(parent),
829                        unsigned char* buffer, uint64_t size)
830 {
831   unsigned int i;
832 
833   stsd_t* atom;
834 
835   if(size < 8)
836     return 0;
837 
838   atom = stsd_init();
839   atom->version_ = read_8(buffer + 0);
840   atom->flags_ = read_24(buffer + 1);
841   atom->entries_ = read_32(buffer + 4);
842 
843   buffer += 8;
844 
845   atom->sample_entries_ = (sample_entry_t*)(malloc(atom->entries_ * sizeof(sample_entry_t)));
846 
847   for(i = 0; i != atom->entries_; ++i)
848   {
849     unsigned int j;
850     sample_entry_t* sample_entry = &atom->sample_entries_[i];
851     sample_entry_init(sample_entry);
852     sample_entry->len_ = read_32(buffer) - 8;
853     sample_entry->fourcc_ = read_32(buffer + 4);
854     sample_entry->buf_ = (unsigned char*)malloc(sample_entry->len_);
855     buffer += 8;
856     for(j = 0; j != sample_entry->len_; ++j)
857     {
858       sample_entry->buf_[j] = (unsigned char)read_8(buffer + j);
859     }
860     buffer += j;
861   }
862 
863   return atom;
864 }
865 
stbl_add_stsd(mp4_context_t const * UNUSED (mp4_context),void * parent,void * child)866 static int stbl_add_stsd(mp4_context_t const* UNUSED(mp4_context),
867                          void* parent, void* child)
868 {
869   stbl_t* stbl = (stbl_t*)parent;
870   stbl->stsd_ = (stsd_t*)child;
871 
872   return 1;
873 }
874 
stbl_add_stts(mp4_context_t const * UNUSED (mp4_context),void * parent,void * child)875 static int stbl_add_stts(mp4_context_t const* UNUSED(mp4_context),
876                          void* parent, void* child)
877 {
878   stbl_t* stbl = (stbl_t*)parent;
879   stbl->stts_ = (stts_t*)child;
880 
881   return 1;
882 }
883 
stbl_add_stss(mp4_context_t const * UNUSED (mp4_context),void * parent,void * child)884 static int stbl_add_stss(mp4_context_t const* UNUSED(mp4_context),
885                          void* parent, void* child)
886 {
887   stbl_t* stbl = (stbl_t*)parent;
888   stbl->stss_ = (stss_t*)child;
889 
890   return 1;
891 }
892 
stbl_add_stsc(mp4_context_t const * UNUSED (mp4_context),void * parent,void * child)893 static int stbl_add_stsc(mp4_context_t const* UNUSED(mp4_context),
894                          void* parent, void* child)
895 {
896   stbl_t* stbl = (stbl_t*)parent;
897   stbl->stsc_ = (stsc_t*)child;
898 
899   return 1;
900 }
901 
stbl_add_stsz(mp4_context_t const * UNUSED (mp4_context),void * parent,void * child)902 static int stbl_add_stsz(mp4_context_t const* UNUSED(mp4_context),
903                          void* parent, void* child)
904 {
905   stbl_t* stbl = (stbl_t*)parent;
906   stbl->stsz_ = (stsz_t*)child;
907 
908   return 1;
909 }
910 
stbl_add_stco(mp4_context_t const * UNUSED (mp4_context),void * parent,void * child)911 static int stbl_add_stco(mp4_context_t const* UNUSED(mp4_context),
912                          void* parent, void* child)
913 {
914   stbl_t* stbl = (stbl_t*)parent;
915   stbl->stco_ = (stco_t*)child;
916 
917   return 1;
918 }
919 
stbl_add_ctts(mp4_context_t const * UNUSED (mp4_context),void * parent,void * child)920 static int stbl_add_ctts(mp4_context_t const* UNUSED(mp4_context),
921                          void* parent, void* child)
922 {
923   stbl_t* stbl = (stbl_t*)parent;
924   stbl->ctts_ = (ctts_t*)child;
925 
926   return 1;
927 }
928 
929 
stbl_read(mp4_context_t const * mp4_context,void * UNUSED (parent),unsigned char * buffer,uint64_t size)930 static void* stbl_read(mp4_context_t const* mp4_context,
931                        void* UNUSED(parent),
932                        unsigned char* buffer, uint64_t size)
933 {
934   stbl_t* atom = stbl_init();
935 
936   atom_read_list_t atom_read_list[] = {
937     { FOURCC('s', 't', 's', 'd'), &stbl_add_stsd, &stsd_read },
938     { FOURCC('s', 't', 't', 's'), &stbl_add_stts, &stts_read },
939     { FOURCC('s', 't', 's', 's'), &stbl_add_stss, &stss_read },
940     { FOURCC('s', 't', 's', 'c'), &stbl_add_stsc, &stsc_read },
941     { FOURCC('s', 't', 's', 'z'), &stbl_add_stsz, &stsz_read },
942     { FOURCC('s', 't', 'c', 'o'), &stbl_add_stco, &stco_read },
943     { FOURCC('c', 'o', '6', '4'), &stbl_add_stco, &co64_read },
944     { FOURCC('c', 't', 't', 's'), &stbl_add_ctts, &ctts_read },
945   };
946 
947   int result = atom_reader(mp4_context,
948                   atom_read_list,
949                   sizeof(atom_read_list) / sizeof(atom_read_list[0]),
950                   atom,
951                   buffer, size);
952 
953   // check for mandatory atoms
954   if(!atom->stsd_)
955   {
956     MP4_ERROR("%s", "stbl: missing mandatory stsd\n");
957     result = 0;
958   }
959 
960   if(!atom->stts_)
961   {
962     MP4_ERROR("%s", "stbl: missing mandatory stts\n");
963     result = 0;
964   }
965 
966   // Expression Encoder doesn't write mandatory stsz atom
967   if(!atom->stsc_)
968   {
969     MP4_ERROR("%s", "stbl: missing mandatory stsc\n");
970 //    result = 0;
971   }
972 
973   // Expression Encoder doesn't write mandatory stsz atom
974   if(!atom->stsz_)
975   {
976     MP4_ERROR("%s", "stbl: missing mandatory stsz\n");
977 //    result = 0;
978   }
979 
980   // Expression Encoder doesn't write mandatory stco atom
981   if(!atom->stco_)
982   {
983     MP4_ERROR("%s", "stbl: missing mandatory stco\n");
984 //    result = 0;
985   }
986 
987   if(!result)
988   {
989     stbl_exit(atom);
990     return 0;
991   }
992 
993   return atom;
994 }
995 
hdlr_read(mp4_context_t const * UNUSED (mp4_context),void * UNUSED (parent),unsigned char * buffer,uint64_t size)996 static void* hdlr_read(mp4_context_t const* UNUSED(mp4_context),
997                        void* UNUSED(parent),
998                        unsigned char* buffer, uint64_t size)
999 {
1000   hdlr_t* atom;
1001 
1002   if(size < 8)
1003     return 0;
1004 
1005   atom = hdlr_init();
1006   atom->version_ = read_8(buffer + 0);
1007   atom->flags_ = read_24(buffer + 1);
1008   atom->predefined_ = read_32(buffer + 4);
1009   atom->handler_type_ = read_32(buffer + 8);
1010   atom->reserved1_ = read_32(buffer + 12);
1011   atom->reserved2_ = read_32(buffer + 16);
1012   atom->reserved3_ = read_32(buffer + 20);
1013   buffer += 24;
1014   size -= 24;
1015   if(size > 0)
1016   {
1017     size_t length = (size_t)size;
1018     atom->name_ = (char*)malloc(length + 1);
1019     if(atom->predefined_ == FOURCC('m', 'h', 'l', 'r'))
1020     {
1021       length = read_8(buffer);
1022       buffer += 1;
1023       if(size < length)
1024         length = (size_t)size;
1025     }
1026     memcpy(atom->name_, buffer, length);
1027     atom->name_[length] = '\0';
1028   }
1029 
1030   return atom;
1031 }
1032 
vmhd_read(mp4_context_t const * UNUSED (mp4_context),void * UNUSED (parent),unsigned char * buffer,uint64_t size)1033 static void* vmhd_read(mp4_context_t const* UNUSED(mp4_context),
1034                        void* UNUSED(parent),
1035                        unsigned char* buffer, uint64_t size)
1036 {
1037   unsigned int i;
1038 
1039   vmhd_t* atom;
1040 
1041   if(size < 12)
1042     return 0;
1043 
1044   atom = vmhd_init();
1045   atom->version_ = read_8(buffer + 0);
1046   atom->flags_ = read_24(buffer + 1);
1047 
1048   atom->graphics_mode_ = read_16(buffer + 4);
1049   buffer += 6;
1050   for(i = 0; i != 3; ++i)
1051   {
1052     atom->opcolor_[i] = read_16(buffer);
1053     buffer += 2;
1054   }
1055 
1056   return atom;
1057 }
1058 
smhd_read(mp4_context_t const * UNUSED (mp4_context),void * UNUSED (parent),unsigned char * buffer,uint64_t size)1059 static void* smhd_read(mp4_context_t const* UNUSED(mp4_context),
1060                        void* UNUSED(parent),
1061                        unsigned char* buffer, uint64_t size)
1062 {
1063   smhd_t* atom;
1064 
1065   if(size < 8)
1066     return 0;
1067 
1068   atom = smhd_init();
1069   atom->version_ = read_8(buffer + 0);
1070   atom->flags_ = read_24(buffer + 1);
1071 
1072   atom->balance_ = read_16(buffer + 4);
1073   atom->reserved_ = read_16(buffer + 6);
1074 
1075   return atom;
1076 }
1077 
dinf_add_dref(mp4_context_t const * UNUSED (mp4_context),void * parent,void * child)1078 static int dinf_add_dref(mp4_context_t const* UNUSED(mp4_context),
1079                          void* parent, void* child)
1080 {
1081   dinf_t* dinf = (dinf_t*)parent;
1082   dinf->dref_ = (dref_t*)child;
1083 
1084   return 1;
1085 }
1086 
dref_read(mp4_context_t const * UNUSED (mp4_context),void * UNUSED (parent),unsigned char * buffer,uint64_t size)1087 static void* dref_read(mp4_context_t const* UNUSED(mp4_context),
1088                        void* UNUSED(parent),
1089                        unsigned char* buffer, uint64_t size)
1090 {
1091   unsigned int i;
1092 
1093   dref_t* atom;
1094 
1095   if(size < 20)
1096     return 0;
1097 
1098   atom = dref_init();
1099   atom->version_ = read_8(buffer + 0);
1100   atom->flags_ = read_24(buffer + 1);
1101 
1102   atom->entry_count_ = read_32(buffer + 4);
1103   atom->table_ = atom->entry_count_ == 0 ? NULL : (dref_table_t*)malloc(atom->entry_count_ * sizeof(dref_table_t));
1104   buffer += 8;
1105 
1106   for(i = 0; i != atom->entry_count_; ++i)
1107   {
1108     dref_table_t* entry = &atom->table_[i];
1109     uint32_t entry_size = read_32(buffer + 0);
1110     uint32_t type = read_32(buffer + 4);
1111     uint32_t flags = read_32(buffer + 8);
1112     dref_table_init(entry);
1113     entry->flags_ = flags;
1114     if(flags != 0x000001)
1115     {
1116       switch(type)
1117       {
1118         case FOURCC('u', 'r', 'n', ' '):
1119           // read name and location (optional) as UTF8 zero-terminated string
1120           break;
1121         case FOURCC('u', 'r', 'l', ' '):
1122           // read location as UTF8 zero-terminated string
1123           break;
1124       }
1125     }
1126     buffer += entry_size;
1127   }
1128 
1129   return atom;
1130 }
1131 
1132 
dinf_read(mp4_context_t const * mp4_context,void * UNUSED (parent),unsigned char * buffer,uint64_t size)1133 static void* dinf_read(mp4_context_t const* mp4_context,
1134                        void* UNUSED(parent),
1135                        unsigned char* buffer, uint64_t size)
1136 {
1137   dinf_t* atom = dinf_init();
1138 
1139   atom_read_list_t atom_read_list[] = {
1140     { FOURCC('d', 'r', 'e', 'f'), &dinf_add_dref, &dref_read },
1141   };
1142 
1143   int result = atom_reader(mp4_context,
1144                   atom_read_list,
1145                   sizeof(atom_read_list) / sizeof(atom_read_list[0]),
1146                   atom,
1147                   buffer, size);
1148 
1149   // check for mandatory atoms
1150   if(!atom->dref_)
1151   {
1152     MP4_ERROR("%s", "dinf: missing dref\n");
1153     result = 0;
1154   }
1155 
1156   if(!result)
1157   {
1158     dinf_exit(atom);
1159     return 0;
1160   }
1161 
1162   return atom;
1163 }
1164 
minf_add_vmhd(mp4_context_t const * UNUSED (mp4_context),void * parent,void * child)1165 static int minf_add_vmhd(mp4_context_t const* UNUSED(mp4_context),
1166                          void* parent, void* child)
1167 {
1168   minf_t* minf = (minf_t*)parent;
1169   minf->vmhd_ = (vmhd_t*)child;
1170 
1171   return 1;
1172 }
1173 
minf_add_smhd(mp4_context_t const * UNUSED (mp4_context),void * parent,void * child)1174 static int minf_add_smhd(mp4_context_t const* UNUSED(mp4_context),
1175                          void* parent, void* child)
1176 {
1177   minf_t* minf = (minf_t*)parent;
1178   minf->smhd_ = (smhd_t*)child;
1179 
1180   return 1;
1181 }
1182 
minf_add_dinf(mp4_context_t const * UNUSED (mp4_context),void * parent,void * child)1183 static int minf_add_dinf(mp4_context_t const* UNUSED(mp4_context),
1184                          void* parent, void* child)
1185 {
1186   minf_t* minf = (minf_t*)parent;
1187   minf->dinf_ = (dinf_t*)child;
1188 
1189   return 1;
1190 }
1191 
minf_add_stbl(mp4_context_t const * UNUSED (mp4_context),void * parent,void * child)1192 static int minf_add_stbl(mp4_context_t const* UNUSED(mp4_context),
1193                          void* parent, void* child)
1194 {
1195   minf_t* minf = (minf_t*)parent;
1196   minf->stbl_ = (stbl_t*)child;
1197 
1198   return 1;
1199 }
1200 
minf_read(mp4_context_t const * mp4_context,void * UNUSED (parent),unsigned char * buffer,uint64_t size)1201 static void* minf_read(mp4_context_t const* mp4_context,
1202                        void* UNUSED(parent),
1203                        unsigned char* buffer, uint64_t size)
1204 {
1205   minf_t* atom = minf_init();
1206 
1207   atom_read_list_t atom_read_list[] = {
1208     { FOURCC('v', 'm', 'h', 'd'), &minf_add_vmhd, &vmhd_read },
1209     { FOURCC('s', 'm', 'h', 'd'), &minf_add_smhd, &smhd_read },
1210     { FOURCC('d', 'i', 'n', 'f'), &minf_add_dinf, &dinf_read },
1211     { FOURCC('s', 't', 'b', 'l'), &minf_add_stbl, &stbl_read }
1212   };
1213 
1214   int result = atom_reader(mp4_context,
1215                   atom_read_list,
1216                   sizeof(atom_read_list) / sizeof(atom_read_list[0]),
1217                   atom,
1218                   buffer, size);
1219 
1220   // check for mandatory atoms
1221   if(!atom->stbl_)
1222   {
1223     MP4_ERROR("%s", "minf: missing stbl\n");
1224     result = 0;
1225   }
1226 
1227   if(!result)
1228   {
1229     minf_exit(atom);
1230     return 0;
1231   }
1232 
1233   return atom;
1234 }
1235 
1236 
mdhd_read(mp4_context_t const * UNUSED (mp4_context),void * UNUSED (parent),unsigned char * buffer,uint64_t UNUSED (size))1237 static void* mdhd_read(mp4_context_t const* UNUSED(mp4_context),
1238                        void* UNUSED(parent),
1239                        unsigned char* buffer, uint64_t UNUSED(size))
1240 {
1241   uint16_t language;
1242   unsigned int i;
1243 
1244   mdhd_t* mdhd = mdhd_init();
1245   mdhd->version_ = read_8(buffer + 0);
1246   mdhd->flags_ = read_24(buffer + 1);
1247   if(mdhd->version_ == 0)
1248   {
1249     mdhd->creation_time_ = read_32(buffer + 4);
1250     mdhd->modification_time_ = read_32(buffer + 8);
1251     mdhd->timescale_ = read_32(buffer + 12);
1252     mdhd->duration_ = read_32(buffer + 16);
1253     buffer += 20;
1254   }
1255   else
1256   {
1257     mdhd->creation_time_ = read_64(buffer + 4);
1258     mdhd->modification_time_ = read_64(buffer + 12);
1259     mdhd->timescale_ = read_32(buffer + 20);
1260     mdhd->duration_ = read_64(buffer + 24);
1261     buffer += 32;
1262   }
1263 
1264   language = read_16(buffer + 0);
1265   for(i = 0; i != 3; ++i)
1266   {
1267     mdhd->language_[i] = ((language >> ((2 - i) * 5)) & 0x1f) + 0x60;
1268   }
1269 
1270   mdhd->predefined_ = read_16(buffer + 2);
1271 
1272   return mdhd;
1273 }
1274 
1275 
tkhd_read(mp4_context_t const * UNUSED (mp4_context),void * UNUSED (parent),unsigned char * buffer,uint64_t size)1276 static void* tkhd_read(mp4_context_t const* UNUSED(mp4_context),
1277                        void* UNUSED(parent),
1278                        unsigned char* buffer, uint64_t size)
1279 {
1280   unsigned int i;
1281 
1282   tkhd_t* tkhd = tkhd_init();
1283 
1284   tkhd->version_ = read_8(buffer + 0);
1285   tkhd->flags_ = read_24(buffer + 1);
1286   if(tkhd->version_ == 0)
1287   {
1288     if(size < 92-8)
1289       return 0;
1290 
1291     tkhd->creation_time_ = read_32(buffer + 4);
1292     tkhd->modification_time_ = read_32(buffer + 8);
1293     tkhd->track_id_ = read_32(buffer + 12);
1294     tkhd->reserved_ = read_32(buffer + 16);
1295     tkhd->duration_ = read_32(buffer + 20);
1296     buffer += 24;
1297   }
1298   else
1299   {
1300     if(size < 104-8)
1301       return 0;
1302 
1303     tkhd->creation_time_ = read_64(buffer + 4);
1304     tkhd->modification_time_ = read_64(buffer + 12);
1305     tkhd->track_id_ = read_32(buffer + 20);
1306     tkhd->reserved_ = read_32(buffer + 24);
1307     tkhd->duration_ = read_64(buffer + 28);
1308     buffer += 36;
1309   }
1310 
1311   tkhd->reserved2_[0] = read_32(buffer + 0);
1312   tkhd->reserved2_[1] = read_32(buffer + 4);
1313   tkhd->layer_ = read_16(buffer + 8);
1314   tkhd->predefined_ = read_16(buffer + 10);
1315   tkhd->volume_ = read_16(buffer + 12);
1316   tkhd->reserved3_ = read_16(buffer + 14);
1317   buffer += 16;
1318 
1319   for(i = 0; i != 9; ++i)
1320   {
1321     tkhd->matrix_[i] = read_32(buffer);
1322     buffer += 4;
1323   }
1324 
1325   tkhd->width_ = read_32(buffer + 0);
1326   tkhd->height_ = read_32(buffer + 4);
1327 
1328   return tkhd;
1329 }
1330 
mdia_add_mdhd(mp4_context_t const * UNUSED (mp4_context),void * parent,void * child)1331 static int mdia_add_mdhd(mp4_context_t const* UNUSED(mp4_context),
1332                          void* parent, void* child)
1333 {
1334   mdia_t* mdia = (mdia_t*)parent;
1335   mdia->mdhd_ = (mdhd_t*)child;
1336 
1337   return 1;
1338 }
1339 
mdia_add_hdlr(mp4_context_t const * UNUSED (mp4_context),void * parent,void * child)1340 static int mdia_add_hdlr(mp4_context_t const* UNUSED(mp4_context),
1341                          void* parent, void* child)
1342 {
1343   mdia_t* mdia = (mdia_t*)parent;
1344   mdia->hdlr_ = (hdlr_t*)child;
1345 
1346   return 1;
1347 }
1348 
mdia_add_minf(mp4_context_t const * UNUSED (mp4_context),void * parent,void * child)1349 static int mdia_add_minf(mp4_context_t const* UNUSED(mp4_context),
1350                          void* parent, void* child)
1351 {
1352   mdia_t* mdia = (mdia_t*)parent;
1353   mdia->minf_ = (minf_t*)child;
1354 
1355   return 1;
1356 }
1357 
mdia_read(mp4_context_t const * mp4_context,void * UNUSED (parent),unsigned char * buffer,uint64_t size)1358 static void* mdia_read(mp4_context_t const* mp4_context,
1359                        void* UNUSED(parent),
1360                        unsigned char* buffer, uint64_t size)
1361 {
1362   mdia_t* atom = mdia_init();
1363 
1364   atom_read_list_t atom_read_list[] = {
1365     { FOURCC('m', 'd', 'h', 'd'), &mdia_add_mdhd, &mdhd_read },
1366     { FOURCC('h', 'd', 'l', 'r'), &mdia_add_hdlr, &hdlr_read },
1367     { FOURCC('m', 'i', 'n', 'f'), &mdia_add_minf, &minf_read }
1368   };
1369 
1370   int result = atom_reader(mp4_context,
1371                   atom_read_list,
1372                   sizeof(atom_read_list) / sizeof(atom_read_list[0]),
1373                   atom,
1374                   buffer, size);
1375 
1376   // check for mandatory atoms
1377   if(!atom->mdhd_)
1378   {
1379     MP4_ERROR("%s", "mdia: missing mdhd\n");
1380     result = 0;
1381   }
1382 
1383   if(!atom->hdlr_)
1384   {
1385     MP4_ERROR("%s", "mdia: missing hdlr\n");
1386     result = 0;
1387   }
1388 
1389   if(!atom->minf_)
1390   {
1391     MP4_ERROR("%s", "mdia: missing minf\n");
1392     result = 0;
1393   }
1394 
1395   if(!result)
1396   {
1397     mdia_exit(atom);
1398     return 0;
1399   }
1400 
1401   return atom;
1402 }
1403 
elst_read(mp4_context_t const * UNUSED (mp4_context),void * UNUSED (parent),unsigned char * buffer,uint64_t size)1404 static void* elst_read(mp4_context_t const* UNUSED(mp4_context),
1405                        void* UNUSED(parent),
1406                        unsigned char* buffer, uint64_t size)
1407 {
1408   unsigned int i;
1409 
1410   elst_t* atom;
1411 
1412   if(size < 8)
1413     return 0;
1414 
1415   atom = elst_init();
1416   atom->version_ = read_8(buffer + 0);
1417   atom->flags_ = read_24(buffer + 1);
1418   atom->entry_count_ = read_32(buffer + 4);
1419 
1420   buffer += 8;
1421 
1422   atom->table_ = (elst_table_t*)(malloc(atom->entry_count_ * sizeof(elst_table_t)));
1423 
1424   for(i = 0; i != atom->entry_count_; ++i)
1425   {
1426     elst_table_t* elst_table = &atom->table_[i];
1427     if(atom->version_ == 0)
1428     {
1429       elst_table->segment_duration_ = read_32(buffer);
1430       elst_table->media_time_ = (int32_t)read_32(buffer + 4);
1431       buffer += 8;
1432     }
1433     else
1434     {
1435       elst_table->segment_duration_ = read_64(buffer);
1436       elst_table->media_time_ = read_64(buffer + 8);
1437       buffer += 16;
1438     }
1439 
1440     elst_table->media_rate_integer_ = read_16(buffer);
1441     elst_table->media_rate_fraction_ = read_16(buffer + 2);
1442     buffer += 4;
1443   }
1444 
1445   return atom;
1446 }
1447 
edts_add_elst(mp4_context_t const * UNUSED (mp4_context),void * parent,void * elst)1448 static int edts_add_elst(mp4_context_t const* UNUSED(mp4_context),
1449                          void* parent, void* elst)
1450 {
1451   edts_t* edts = (edts_t*)parent;
1452   edts->elst_ = (elst_t*)elst;
1453 
1454   return 1;
1455 }
1456 
edts_read(mp4_context_t const * mp4_context,void * UNUSED (parent),unsigned char * buffer,uint64_t size)1457 static void* edts_read(mp4_context_t const* mp4_context,
1458                        void* UNUSED(parent),
1459                        unsigned char* buffer, uint64_t size)
1460 {
1461   edts_t* atom = edts_init();
1462 
1463   atom_read_list_t atom_read_list[] = {
1464     { FOURCC('e', 'l', 's', 't'), &edts_add_elst, &elst_read }
1465   };
1466 
1467   int result = atom_reader(mp4_context,
1468                   atom_read_list,
1469                   sizeof(atom_read_list) / sizeof(atom_read_list[0]),
1470                   atom,
1471                   buffer, size);
1472 
1473   if(!result)
1474   {
1475     edts_exit(atom);
1476     return 0;
1477   }
1478 
1479   return atom;
1480 }
1481 
trak_add_tkhd(mp4_context_t const * UNUSED (mp4_context),void * parent,void * tkhd)1482 static int trak_add_tkhd(mp4_context_t const* UNUSED(mp4_context),
1483                          void* parent, void* tkhd)
1484 {
1485   trak_t* trak = (trak_t*)parent;
1486   trak->tkhd_ = (tkhd_t*)tkhd;
1487 
1488   return 1;
1489 }
1490 
trak_add_mdia(mp4_context_t const * UNUSED (mp4_context),void * parent,void * mdia)1491 static int trak_add_mdia(mp4_context_t const* UNUSED(mp4_context),
1492                          void* parent, void* mdia)
1493 {
1494   trak_t* trak = (trak_t*)parent;
1495   trak->mdia_ = (mdia_t*)mdia;
1496 
1497   return 1;
1498 }
1499 
trak_add_edts(mp4_context_t const * UNUSED (mp4_context),void * parent,void * edts)1500 static int trak_add_edts(mp4_context_t const* UNUSED(mp4_context),
1501                          void* parent, void* edts)
1502 {
1503   trak_t* trak = (trak_t*)parent;
1504   trak->edts_ = (edts_t*)edts;
1505 
1506   return 1;
1507 }
1508 
trak_read(mp4_context_t const * mp4_context,void * UNUSED (parent),unsigned char * buffer,uint64_t size)1509 static void* trak_read(mp4_context_t const* mp4_context,
1510                        void* UNUSED(parent),
1511                        unsigned char* buffer, uint64_t size)
1512 {
1513   trak_t* atom = trak_init();
1514 
1515   atom_read_list_t atom_read_list[] = {
1516     { FOURCC('t', 'k', 'h', 'd'), &trak_add_tkhd, &tkhd_read },
1517     { FOURCC('m', 'd', 'i', 'a'), &trak_add_mdia, &mdia_read },
1518     { FOURCC('e', 'd', 't', 's'), &trak_add_edts, &edts_read }
1519   };
1520 
1521   int result = atom_reader(mp4_context,
1522                   atom_read_list,
1523                   sizeof(atom_read_list) / sizeof(atom_read_list[0]),
1524                   atom,
1525                   buffer, size);
1526 
1527   // check for mandatory atoms
1528   if(!atom->tkhd_)
1529   {
1530     MP4_ERROR("%s", "trak: missing tkhd\n");
1531     result = 0;
1532   }
1533 
1534   if(!atom->mdia_)
1535   {
1536     MP4_ERROR("%s", "trak: missing mdia\n");
1537     result = 0;
1538   }
1539 
1540   if(result && !stsd_parse(mp4_context, atom, atom->mdia_->minf_->stbl_->stsd_))
1541   {
1542     MP4_ERROR("%s", "trak: error parsing stsd\n");
1543     result = 0;
1544   }
1545 
1546   if(!result)
1547   {
1548     trak_exit(atom);
1549     return 0;
1550   }
1551 
1552   return atom;
1553 }
1554 
mvhd_read(mp4_context_t const * UNUSED (mp4_context),void * UNUSED (parent),unsigned char * buffer,uint64_t size)1555 static void* mvhd_read(mp4_context_t const* UNUSED(mp4_context),
1556                        void* UNUSED(parent),
1557                        unsigned char* buffer, uint64_t size)
1558 {
1559   unsigned int i;
1560 
1561   mvhd_t* atom = mvhd_init();
1562   atom->version_ = read_8(buffer + 0);
1563   atom->flags_ = read_24(buffer + 1);
1564   if(atom->version_ == 0)
1565   {
1566     if(size < 108-8)
1567       return 0;
1568 
1569     atom->creation_time_ = read_32(buffer + 4);
1570     atom->modification_time_ = read_32(buffer + 8);
1571     atom->timescale_ = read_32(buffer + 12);
1572     atom->duration_ = read_32(buffer + 16);
1573     buffer += 20;
1574   }
1575   else
1576   {
1577     if(size < 120-8)
1578       return 0;
1579 
1580     atom->creation_time_ = read_64(buffer + 4);
1581     atom->modification_time_ = read_64(buffer + 12);
1582     atom->timescale_ = read_32(buffer + 20);
1583     atom->duration_ = read_64(buffer + 24);
1584     buffer += 32;
1585   }
1586   atom->rate_ = read_32(buffer + 0);
1587   atom->volume_ = read_16(buffer + 4);
1588   atom->reserved1_ = read_16(buffer + 6);
1589   atom->reserved2_[0] = read_32(buffer + 8);
1590   atom->reserved2_[1] = read_32(buffer + 12);
1591   buffer += 16;
1592 
1593   for(i = 0; i != 9; ++i)
1594   {
1595     atom->matrix_[i] = read_32(buffer);
1596     buffer += 4;
1597   }
1598 
1599   for(i = 0; i != 6; ++i)
1600   {
1601     atom->predefined_[i] = read_32(buffer);
1602     buffer += 4;
1603   }
1604 
1605   atom->next_track_id_ = read_32(buffer + 0);
1606 
1607   return atom;
1608 }
1609 
1610 
moov_add_mvhd(mp4_context_t const * UNUSED (mp4_context),void * parent,void * mvhd)1611 static int moov_add_mvhd(mp4_context_t const* UNUSED(mp4_context),
1612                          void* parent, void* mvhd)
1613 {
1614   moov_t* moov = (moov_t*)parent;
1615   moov->mvhd_ = (mvhd_t*)mvhd;
1616 
1617   return 1;
1618 }
1619 
moov_add_trak(mp4_context_t const * mp4_context,void * parent,void * child)1620 static int moov_add_trak(mp4_context_t const* mp4_context,
1621                          void* parent, void* child)
1622 {
1623   moov_t* moov = (moov_t*)parent;
1624   trak_t* trak = (trak_t*)child;
1625   if(moov->tracks_ == MAX_TRACKS)
1626   {
1627     trak_exit(trak);
1628     return 0;
1629   }
1630 
1631   if(trak->mdia_->hdlr_->handler_type_ != FOURCC('v', 'i', 'd', 'e') &&
1632      trak->mdia_->hdlr_->handler_type_ != FOURCC('s', 'o', 'u', 'n'))
1633   {
1634     MP4_INFO("Trak ignored (handler_type=%c%c%c%c, name=%s)\n",
1635       trak->mdia_->hdlr_->handler_type_ >> 24,
1636       trak->mdia_->hdlr_->handler_type_ >> 16,
1637       trak->mdia_->hdlr_->handler_type_ >> 8,
1638       trak->mdia_->hdlr_->handler_type_,
1639       trak->mdia_->hdlr_->name_);
1640     trak_exit(trak);
1641     return 1; // continue
1642   }
1643 
1644   // check for tracks that have a duration, but no samples. This happens with
1645   // Expression Encoder fragmented movie files.
1646   if(trak->mdia_->minf_->stbl_->stco_ == 0 ||
1647     (trak->mdia_->minf_->stbl_->stco_->entries_ == 0 &&
1648      trak->mdia_->mdhd_->duration_))
1649   {
1650     trak->mdia_->mdhd_->duration_ = 0;
1651   }
1652 
1653 #if 0  // we can't ignore empty tracks, as the fragments may come later
1654   // ignore empty track (unless LIVE)
1655   if(trak->mdia_->mdhd_->duration_ == 0 && !moov->mvex_)
1656   {
1657     trak_exit(trak);
1658     return 1; // continue
1659   }
1660 #endif
1661 
1662   moov->traks_[moov->tracks_] = trak;
1663   ++moov->tracks_;
1664 
1665   return 1;
1666 }
1667 
trex_read(mp4_context_t const * UNUSED (mp4_context),void * UNUSED (parent),unsigned char * buffer,uint64_t size)1668 static void* trex_read(mp4_context_t const* UNUSED(mp4_context),
1669                        void* UNUSED(parent),
1670                        unsigned char* buffer, uint64_t size)
1671 {
1672   trex_t* atom = trex_init();
1673 
1674   if(size < 24)
1675     return 0;
1676 
1677   atom->version_ = read_8(buffer + 0);
1678   atom->flags_ = read_24(buffer + 1);
1679 
1680   atom->track_id_ = read_32(buffer + 4);
1681   atom->default_sample_description_index_ = read_32(buffer + 8);
1682   atom->default_sample_duration_ = read_32(buffer + 12);
1683   atom->default_sample_size_ = read_32(buffer + 16);
1684   atom->default_sample_flags_ = read_32(buffer + 20);
1685 
1686   return atom;
1687 }
1688 
moov_add_mvex(mp4_context_t const * UNUSED (mp4_context),void * parent,void * mvex)1689 static int moov_add_mvex(mp4_context_t const* UNUSED(mp4_context),
1690                          void* parent, void* mvex)
1691 {
1692   moov_t* moov = (moov_t*)parent;
1693   moov->mvex_ = (mvex_t*)mvex;
1694 
1695   return 1;
1696 }
1697 
mvex_add_trex(mp4_context_t const * UNUSED (mp4_context),void * parent,void * child)1698 static int mvex_add_trex(mp4_context_t const* UNUSED(mp4_context),
1699                          void* parent, void* child)
1700 {
1701   mvex_t* mvex = (mvex_t*)parent;
1702   trex_t* trex = (trex_t*)child;
1703   if(mvex->tracks_ == MAX_TRACKS)
1704   {
1705     trex_exit(trex);
1706     return 0;
1707   }
1708 
1709   mvex->trexs_[mvex->tracks_] = trex;
1710   ++mvex->tracks_;
1711 
1712   return 1;
1713 }
1714 
mvex_read(mp4_context_t const * mp4_context,void * UNUSED (parent),unsigned char * buffer,uint64_t size)1715 static void* mvex_read(mp4_context_t const* mp4_context,
1716                        void* UNUSED(parent),
1717                        unsigned char* buffer, uint64_t size)
1718 {
1719   mvex_t* atom = mvex_init();
1720 
1721   atom_read_list_t atom_read_list[] = {
1722     { FOURCC('t', 'r', 'e', 'x'), &mvex_add_trex, &trex_read }
1723   };
1724 
1725   int result = atom_reader(mp4_context,
1726                   atom_read_list,
1727                   sizeof(atom_read_list) / sizeof(atom_read_list[0]),
1728                   atom,
1729                   buffer, size);
1730 
1731   // check for mandatory atoms
1732   if(!atom->tracks_)
1733   {
1734     MP4_ERROR("%s", "mvex: missing trex\n");
1735     result = 0;
1736   }
1737 
1738   if(!result)
1739   {
1740     mvex_exit(atom);
1741     return 0;
1742   }
1743 
1744   return atom;
1745 }
1746 
moov_read(mp4_context_t const * mp4_context,void * UNUSED (parent),unsigned char * buffer,uint64_t size)1747 extern void* moov_read(mp4_context_t const* mp4_context,
1748                        void* UNUSED(parent),
1749                        unsigned char* buffer, uint64_t size)
1750 {
1751   moov_t* atom = moov_init();
1752 
1753   atom_read_list_t atom_read_list[] = {
1754     { FOURCC('m', 'v', 'h', 'd'), &moov_add_mvhd, &mvhd_read },
1755     { FOURCC('t', 'r', 'a', 'k'), &moov_add_trak, &trak_read },
1756     { FOURCC('m', 'v', 'e', 'x'), &moov_add_mvex, &mvex_read }
1757   };
1758 
1759   int result = atom_reader(mp4_context,
1760                   atom_read_list,
1761                   sizeof(atom_read_list) / sizeof(atom_read_list[0]),
1762                   atom,
1763                   buffer, size);
1764 
1765   // check for mandatory atoms
1766   if(!atom->mvhd_)
1767   {
1768     MP4_ERROR("%s", "moov: missing mvhd\n");
1769     result = 0;
1770   }
1771 
1772   if(!atom->tracks_)
1773   {
1774     MP4_ERROR("%s", "moov: missing trak\n");
1775     result = 0;
1776   }
1777 
1778   if(!result)
1779   {
1780     moov_exit(atom);
1781     return 0;
1782   }
1783 
1784   return atom;
1785 }
1786 
add_fragmented_samples(mp4_context_t const * mp4_context,traf_t const * traf)1787 static int add_fragmented_samples(mp4_context_t const* mp4_context,
1788                                   traf_t const* traf)
1789 {
1790   unsigned int track;
1791   moov_t* moov = mp4_context->moov;
1792   trak_t* trak = NULL;
1793   trun_t* trun;
1794   for(track = 0; track != moov->tracks_; ++track)
1795   {
1796     trak = moov->traks_[track];
1797     if(trak->tkhd_->track_id_ == traf->tfhd_->track_id_)
1798       break;
1799   }
1800   if(track == moov->tracks_)
1801   {
1802     MP4_ERROR("%s", "add_fragmented_samples: trak not found\n");
1803     return 0;
1804   }
1805 
1806   trun = traf->trun_;
1807   for(; trun != NULL; trun = trun->next_)
1808   {
1809     tfhd_t const* tfhd = traf->tfhd_;
1810 //    trun_t const* trun = traf->trun_;
1811 
1812     unsigned int i;
1813     unsigned int s = trak->samples_size_;
1814 
1815     uint64_t data_offset = tfhd->base_data_offset_ + trun->data_offset_;
1816 //    int64_t pts = trak->fragment_pts_;  // trak->mdia_->mdhd_->duration_;
1817     int64_t pts = trak->mdia_->mdhd_->duration_;
1818     unsigned int cto = 0;
1819 
1820     //
1821     if(pts == 0 && trak->edts_)
1822     {
1823       elst_t const* elst = trak->edts_->elst_;
1824       if(elst && elst->entry_count_ > 0)
1825       {
1826         elst_table_t* elst_table = &elst->table_[0];
1827         if(elst_table->media_time_ >= -1)
1828         {
1829           pts = elst_table->media_time_ != -1 ? elst_table->media_time_
1830                                               : (int64_t)elst_table->segment_duration_;
1831           trak->mdia_->mdhd_->duration_ = pts;
1832 //            trak->fragment_pts_ = pts;
1833         }
1834       }
1835     }
1836 
1837     trak->samples_size_ += trun->sample_count_;
1838 
1839     // reserve one extra for the end information (like pts and cto).
1840     trak->samples_ = (samples_t*)realloc(trak->samples_,
1841       (trak->samples_size_ + 1) * sizeof(samples_t));
1842 
1843     for(i = 0; i != trun->sample_count_; ++i)
1844     {
1845       samples_t* sample = &trak->samples_[s + i];
1846       trun_table_t const* trun_table = &trun->table_[i];
1847       unsigned int is_difference_sample = (trun_table->sample_flags_ >> 16) & 1;
1848 
1849       cto = trun_table->sample_composition_time_offset_;
1850 
1851       sample->pts_ = pts;
1852       sample->size_ = trun_table->sample_size_;
1853       sample->pos_ = data_offset;
1854       sample->cto_ = trun_table->sample_composition_time_offset_;
1855 //      sample->is_ss_ = i == 0 ? 1 : 0;
1856       sample->is_smooth_ss_ = i == 0 ? 1 : 0;
1857       sample->is_ss_ = is_difference_sample ? 0 : 1;
1858 
1859 #if 0
1860       {
1861         unsigned int depends_on = (trun_table->sample_flags_ >> 24) & 3;
1862         unsigned int is_depended_on = (trun_table->sample_flags_ >> 22) & 3;
1863         unsigned int has_redundancy = (trun_table->sample_flags_ >> 20) & 3;
1864         unsigned int padding_value = (trun_table->sample_flags_ >> 17) & 7;
1865         unsigned int is_difference_sample = (trun_table->sample_flags_ >> 16) & 1;
1866         unsigned int degradation_priority = (trun_table->sample_flags_ >> 0) & 0xffff;
1867         MP4_INFO("sample_flags: depends_on=%u is_depended_on=%u has_redundancy=%u padding=%u is_difference_sample=%u degradation_priority=%u\n",
1868                 depends_on, is_depended_on, has_redundancy, padding_value, is_difference_sample, degradation_priority);
1869       }
1870 #endif
1871 
1872       pts += trun_table->sample_duration_;
1873       data_offset += sample->size_;
1874 
1875       // add fragment duration to track duration
1876       trak->mdia_->mdhd_->duration_ += trun_table->sample_duration_;
1877 //      trak->fragment_pts_ += trun_table->sample_duration_;
1878     }
1879 
1880     // write end pts
1881     trak->samples_[s + i].pts_ = pts;
1882     trak->samples_[s + i].size_ = 0;
1883     trak->samples_[s + i].pos_ = data_offset;
1884     trak->samples_[s + i].cto_ = cto;
1885     trak->samples_[s + i].is_ss_ = 1;
1886     trak->samples_[s + i].is_smooth_ss_ = 1;
1887   }
1888 
1889   return 1;
1890 }
1891 
trun_read(mp4_context_t const * UNUSED (mp4_context),void * parent,unsigned char * buffer,uint64_t size)1892 static void* trun_read(mp4_context_t const* UNUSED(mp4_context),
1893                        void* parent,
1894                        unsigned char* buffer, uint64_t size)
1895 {
1896   unsigned int i;
1897 
1898   trun_t* atom = trun_init();
1899   traf_t* traf = (traf_t*)parent;
1900   tfhd_t* tfhd = traf->tfhd_;
1901 
1902   if(size < 8)
1903     return 0;
1904 
1905   atom->version_ = read_8(buffer + 0);
1906   atom->flags_ = read_24(buffer + 1);
1907 
1908   atom->sample_count_ = read_32(buffer + 4);
1909   buffer += 8;
1910 
1911   if(atom->flags_ & 0x0001)
1912   {
1913     atom->data_offset_ = read_32(buffer);
1914     buffer += 4;
1915   }
1916   if(atom->flags_ & 0x0004)
1917   {
1918     atom->first_sample_flags_ = read_32(buffer);
1919     buffer += 4;
1920   }
1921 
1922   atom->table_ = (trun_table_t*)malloc(atom->sample_count_ * sizeof(trun_table_t));
1923   for(i = 0; i != atom->sample_count_; ++i)
1924   {
1925     uint32_t sample_duration = tfhd->default_sample_duration_;
1926     uint32_t sample_size = tfhd->default_sample_size_;
1927     uint32_t sample_flags = tfhd->default_sample_flags_;
1928     uint32_t sample_composition_time_offset = 0;
1929 
1930     if(atom->flags_ & 0x0100)
1931     {
1932       sample_duration = read_32(buffer);
1933       buffer += 4;
1934     }
1935 
1936     if(atom->flags_ & 0x0200)
1937     {
1938       sample_size = read_32(buffer);
1939       buffer += 4;
1940     }
1941 
1942     if(atom->flags_ & 0x0400)
1943     {
1944       sample_flags = read_32(buffer);
1945       buffer += 4;
1946     }
1947     else
1948     if(i == 0 && (atom->flags_ & 0x0004))
1949     {
1950       sample_flags = atom->first_sample_flags_;
1951     }
1952 
1953     if(atom->flags_ & 0x0800)
1954     {
1955       sample_composition_time_offset = read_32(buffer);
1956       buffer += 4;
1957     }
1958 
1959     atom->table_[i].sample_duration_ = sample_duration;
1960     atom->table_[i].sample_size_ = sample_size;
1961     atom->table_[i].sample_flags_ = sample_flags;
1962     atom->table_[i].sample_composition_time_offset_ =
1963       sample_composition_time_offset;
1964   }
1965 
1966   return atom;
1967 }
1968 
tfhd_read(mp4_context_t const * mp4_context,void * UNUSED (parent),unsigned char * buffer,uint64_t size)1969 static void* tfhd_read(mp4_context_t const* mp4_context,
1970                        void* UNUSED(parent),
1971                        unsigned char* buffer, uint64_t size)
1972 {
1973   unsigned int i;
1974 
1975   tfhd_t* atom = tfhd_init();
1976 
1977   moov_t const* moov = mp4_context->moov;
1978   mvex_t const* mvex = moov->mvex_;
1979   trex_t* trex = NULL;
1980 
1981   if(size < 8)
1982     return 0;
1983 
1984   if(mvex == NULL)
1985   {
1986     MP4_ERROR("%s", "tfhd: mvex not found\n");
1987     return 0;
1988   }
1989 
1990   atom->version_ = read_8(buffer + 0);
1991   atom->flags_ = read_24(buffer + 1);
1992 
1993   atom->track_id_ = read_32(buffer + 4);
1994   buffer += 8;
1995 
1996 //  trex_t trex_default;
1997 //  trex_default.default_sample_description_index_ = 1;
1998 //  trex_default.default_sample_duration_ = 0;
1999 //  trex_default.default_sample_size_ = 0;
2000 //  trex_default.default_sample_flags_ = 0;
2001 
2002 //  if(mvex == NULL)
2003 //  {
2004 //    trex = &trex_default;
2005   //}
2006 //  else
2007 //  {
2008     for(i = 0; i != mvex->tracks_; ++i)
2009     {
2010       if(mvex->trexs_[i]->track_id_ == atom->track_id_)
2011       {
2012         trex = mvex->trexs_[i];
2013         break;
2014       }
2015     }
2016 //  }
2017 
2018   if(trex == NULL)
2019   {
2020     MP4_ERROR("tfhd: trex not found (track_id=%u)\n", atom->track_id_);
2021     return 0;
2022   }
2023 
2024   if(atom->flags_ & 0x000001)
2025   {
2026     atom->base_data_offset_ = read_64(buffer);
2027     buffer += 8;
2028   }
2029   else
2030   {
2031     atom->base_data_offset_ = mp4_context->moof_offset_;
2032   }
2033   if(atom->flags_ & 0x000002)
2034   {
2035     atom->sample_description_index_ = read_32(buffer);
2036     buffer += 4;
2037   }
2038   else
2039   {
2040     atom->sample_description_index_ = trex->default_sample_description_index_;
2041   }
2042   if(atom->flags_ & 0x000008)
2043   {
2044     atom->default_sample_duration_ = read_32(buffer);
2045     buffer += 4;
2046   }
2047   else
2048   {
2049     atom->default_sample_duration_ = trex->default_sample_duration_;
2050   }
2051   if(atom->flags_ & 0x000010)
2052   {
2053     atom->default_sample_size_ = read_32(buffer);
2054     buffer += 4;
2055   }
2056   else
2057   {
2058     atom->default_sample_size_ = trex->default_sample_size_;
2059   }
2060   if(atom->flags_ & 0x000020)
2061   {
2062     atom->default_sample_flags_ = read_32(buffer);
2063     buffer += 4;
2064   }
2065   else
2066   {
2067     atom->default_sample_flags_ = trex->default_sample_flags_;
2068   }
2069 
2070   return atom;
2071 }
2072 
traf_add_tfhd(mp4_context_t const * UNUSED (mp4_context),void * parent,void * tfhd)2073 static int traf_add_tfhd(mp4_context_t const* UNUSED(mp4_context),
2074                          void* parent, void* tfhd)
2075 {
2076   traf_t* traf = (traf_t*)parent;
2077   traf->tfhd_ = (tfhd_t*)tfhd;
2078 
2079   return 1;
2080 }
2081 
traf_add_trun(mp4_context_t const * UNUSED (mp4_context),void * parent,void * child)2082 static int traf_add_trun(mp4_context_t const* UNUSED(mp4_context),
2083                          void* parent, void* child)
2084 {
2085   traf_t* traf = (traf_t*)parent;
2086   trun_t* trun = (trun_t*)child;
2087 
2088   trun_t** adder = &traf->trun_;
2089   while(*adder != NULL)
2090   {
2091     adder = &(*adder)->next_;
2092   }
2093   *adder = trun;
2094 
2095   return 1;
2096 }
2097 
traf_read(mp4_context_t const * mp4_context,void * UNUSED (parent),unsigned char * buffer,uint64_t size)2098 static void* traf_read(mp4_context_t const* mp4_context,
2099                        void* UNUSED(parent),
2100                        unsigned char* buffer, uint64_t size)
2101 {
2102   traf_t* atom = traf_init();
2103 
2104   atom_read_list_t atom_read_list[] = {
2105     { FOURCC('t', 'f', 'h', 'd'), &traf_add_tfhd, &tfhd_read },
2106     { FOURCC('t', 'r', 'u', 'n'), &traf_add_trun, &trun_read }
2107   };
2108 
2109   int result = atom_reader(mp4_context,
2110                   atom_read_list,
2111                   sizeof(atom_read_list) / sizeof(atom_read_list[0]),
2112                   atom,
2113                   buffer, size);
2114 
2115   // check for mandatory atoms
2116   if(!atom->tfhd_)
2117   {
2118     MP4_ERROR("%s", "traf: missing tfhd\n");
2119     traf_exit(atom);
2120     return 0;
2121   }
2122 
2123   if(!result)
2124   {
2125     traf_exit(atom);
2126     return 0;
2127   }
2128 
2129   if(!add_fragmented_samples(mp4_context, atom))
2130   {
2131     traf_exit(atom);
2132     return 0;
2133   }
2134 
2135   return atom;
2136 }
2137 
mfhd_read(mp4_context_t const * UNUSED (mp4_context),void * UNUSED (parent),unsigned char * buffer,uint64_t size)2138 static void* mfhd_read(mp4_context_t const* UNUSED(mp4_context),
2139                        void* UNUSED(parent),
2140                        unsigned char* buffer, uint64_t size)
2141 {
2142   mfhd_t* atom = mfhd_init();
2143 
2144   if(size < 8)
2145     return 0;
2146 
2147   atom->version_ = read_8(buffer + 0);
2148   atom->flags_ = read_24(buffer + 1);
2149 
2150   atom->sequence_number_ = read_32(buffer + 4);
2151 
2152   return atom;
2153 }
2154 
moof_add_mfhd(mp4_context_t const * UNUSED (mp4_context),void * parent,void * mfhd)2155 static int moof_add_mfhd(mp4_context_t const* UNUSED(mp4_context),
2156                          void* parent, void* mfhd)
2157 {
2158   moof_t* moof = (moof_t*)parent;
2159   moof->mfhd_ = (mfhd_t*)mfhd;
2160 
2161   return 1;
2162 }
2163 
moof_add_traf(mp4_context_t const * UNUSED (mp4_context),void * parent,void * child)2164 static int moof_add_traf(mp4_context_t const* UNUSED(mp4_context),
2165                          void* parent, void* child)
2166 {
2167   moof_t* moof = (moof_t*)parent;
2168   traf_t* traf = (traf_t*)child;
2169   if(moof->tracks_ == MAX_TRACKS)
2170   {
2171     traf_exit(traf);
2172     return 0;
2173   }
2174 
2175   moof->trafs_[moof->tracks_] = traf;
2176   ++moof->tracks_;
2177 
2178   return 1;
2179 }
2180 
moof_read(struct mp4_context_t const * mp4_context,void * UNUSED (parent),unsigned char * buffer,uint64_t size)2181 extern void* moof_read(struct mp4_context_t const* mp4_context,
2182                        void* UNUSED(parent),
2183                        unsigned char* buffer, uint64_t size)
2184 {
2185   moof_t* atom = moof_init();
2186 
2187   atom_read_list_t atom_read_list[] = {
2188     { FOURCC('m', 'f', 'h', 'd'), &moof_add_mfhd, &mfhd_read },
2189     { FOURCC('t', 'r', 'a', 'f'), &moof_add_traf, &traf_read },
2190   };
2191 
2192   int result = atom_reader(mp4_context,
2193                   atom_read_list,
2194                   sizeof(atom_read_list) / sizeof(atom_read_list[0]),
2195                   atom,
2196                   buffer, size);
2197 
2198   // check for mandatory atoms
2199   if(!atom->mfhd_)
2200   {
2201     MP4_ERROR("%s", "moof: missing mfhd\n");
2202     result = 0;
2203   }
2204 
2205   if(!atom->tracks_)
2206   {
2207     MP4_ERROR("%s", "moof: missing traf\n");
2208     result = 0;
2209   }
2210 
2211   if(!result)
2212   {
2213     moof_exit(atom);
2214     return 0;
2215   }
2216 
2217   return atom;
2218 }
2219 
trak_build_index(mp4_context_t const * mp4_context,trak_t * trak)2220 static int trak_build_index(mp4_context_t const* mp4_context, trak_t* trak)
2221 {
2222   stco_t const* stco = trak->mdia_->minf_->stbl_->stco_;
2223   int have_samples = 1;
2224   unsigned int stco_samples = 0;
2225 
2226   if(stco == NULL || stco->entries_ == 0)
2227   {
2228     have_samples = 0;
2229   }
2230 
2231   if(have_samples)
2232   {
2233     trak->chunks_size_ = stco->entries_;
2234     trak->chunks_ = (chunks_t*)malloc(trak->chunks_size_ * sizeof(chunks_t));
2235 
2236     {
2237       unsigned int i;
2238       for(i = 0; i != trak->chunks_size_; ++i)
2239       {
2240         trak->chunks_[i].pos_ = stco->chunk_offsets_[i];
2241       }
2242     }
2243   }
2244 
2245   // process chunkmap:
2246   if(have_samples)
2247   {
2248     stsc_t const* stsc = trak->mdia_->minf_->stbl_->stsc_;
2249     unsigned int last = trak->chunks_size_;
2250     unsigned int i = stsc->entries_;
2251     while(i > 0)
2252     {
2253       unsigned int j;
2254 
2255       --i;
2256 
2257       for(j = stsc->table_[i].chunk_; j < last; j++)
2258       {
2259         trak->chunks_[j].id_ = stsc->table_[i].id_;
2260         trak->chunks_[j].size_ = stsc->table_[i].samples_;
2261       }
2262       last = stsc->table_[i].chunk_;
2263     }
2264   }
2265 
2266   // calc pts of chunks:
2267   if(have_samples)
2268   {
2269     stsz_t const* stsz = trak->mdia_->minf_->stbl_->stsz_;
2270     unsigned int sample_size = stsz->sample_size_;
2271     unsigned int s = 0;
2272     {
2273       unsigned int j;
2274       for(j = 0; j < trak->chunks_size_; j++)
2275       {
2276         trak->chunks_[j].sample_ = s;
2277         s += trak->chunks_[j].size_;
2278       }
2279     }
2280     stco_samples = s;
2281 
2282     if(sample_size == 0)
2283     {
2284       trak->samples_size_ = stsz->entries_;
2285     }
2286     else
2287     {
2288       trak->samples_size_ = s;
2289     }
2290 
2291     // reserve one extra for the end information (like pts and cto).
2292     trak->samples_ = (samples_t*)calloc(trak->samples_size_ + 1, sizeof(samples_t));
2293 
2294     if(sample_size == 0)
2295     {
2296       unsigned int i;
2297       for(i = 0; i != trak->samples_size_ ; ++i)
2298         trak->samples_[i].size_ = stsz->sample_sizes_[i];
2299     }
2300     else
2301     {
2302       unsigned int i;
2303       for(i = 0; i != trak->samples_size_ ; ++i)
2304         trak->samples_[i].size_ = sample_size;
2305     }
2306   }
2307 
2308   // calc pts:
2309   if(have_samples)
2310   {
2311     stts_t const* stts = trak->mdia_->minf_->stbl_->stts_;
2312     unsigned int s = 0;
2313     uint64_t pts = 0;
2314     unsigned int entries = stts->entries_;
2315     unsigned int j;
2316     for(j = 0; j < entries; j++)
2317     {
2318       unsigned int i;
2319       unsigned int sample_count = stts->table_[j].sample_count_;
2320       unsigned int sample_duration = stts->table_[j].sample_duration_;
2321       for(i = 0; i < sample_count; i++)
2322       {
2323         trak->samples_[s].pts_ = pts;
2324         ++s;
2325         pts += sample_duration;
2326       }
2327     }
2328     // write end pts
2329     trak->samples_[s].pts_ = pts;
2330   }
2331 
2332   // calc composition times:
2333   if(have_samples)
2334   {
2335     ctts_t const* ctts = trak->mdia_->minf_->stbl_->ctts_;
2336     if(ctts)
2337     {
2338       unsigned int s = 0;
2339       unsigned int entries = ctts->entries_;
2340       unsigned int j;
2341       unsigned int sample_offset = 0;
2342 
2343       for(j = 0; j != entries; j++)
2344       {
2345         unsigned int i;
2346         unsigned int sample_count = ctts->table_[j].sample_count_;
2347         sample_offset = ctts->table_[j].sample_offset_;
2348         for(i = 0; i < sample_count; i++)
2349         {
2350           if(s == trak->samples_size_)
2351           {
2352             MP4_WARNING("Warning: ctts_get_samples=%u, should be %u\n",
2353                    ctts_get_samples(ctts), trak->samples_size_);
2354             break;
2355           }
2356 
2357           trak->samples_[s].cto_ = sample_offset;
2358           ++s;
2359         }
2360       }
2361       // write end cto
2362       trak->samples_[s].cto_ = sample_offset;
2363     }
2364   }
2365 
2366   // calc sample offsets
2367   if(have_samples)
2368   {
2369     unsigned int s = 0;
2370     unsigned int j;
2371     for(j = 0; j != trak->chunks_size_; j++)
2372     {
2373       uint64_t pos = trak->chunks_[j].pos_;
2374       unsigned int i;
2375       for(i = 0; i != trak->chunks_[j].size_; i++)
2376       {
2377         if(s == trak->samples_size_)
2378         {
2379           MP4_WARNING("Warning: stco_get_samples=%u, should be %u\n",
2380                  stco_samples, trak->samples_size_);
2381           break;
2382         }
2383         trak->samples_[s].pos_ = pos;
2384         pos += trak->samples_[s].size_;
2385         ++s;
2386       }
2387     }
2388   }
2389 
2390   if(have_samples)
2391   {
2392     stss_t const* stss = trak->mdia_->minf_->stbl_->stss_;
2393     unsigned int i;
2394     if(stss)
2395     {
2396       // TODO: The chunks for smooth streaming are now aligned to the keyframes.
2397       // We may want to consider skipping some keyframes and use a
2398       // minimal_increment_between_keyframes (say 2 seconds) as some chunks
2399       // can be very small.
2400       for(i = 0; i != stss->entries_; ++i)
2401       {
2402         uint32_t s = stss->sample_numbers_[i] - 1;
2403         trak->samples_[s].is_ss_ = 1;
2404         trak->samples_[s].is_smooth_ss_ = 1;
2405       }
2406     }
2407     else
2408     {
2409       for(i = 0; i != trak->samples_size_; ++i)
2410       {
2411         trak->samples_[i].is_ss_ = 1;
2412       }
2413     }
2414     // write end ss
2415     trak->samples_[trak->samples_size_].is_ss_ = 1;
2416     trak->samples_[trak->samples_size_].is_smooth_ss_ = 1;
2417   }
2418 
2419   return 1;
2420 }
2421 
copy_sync_samples_to_audio_track(trak_t * video,trak_t * audio)2422 static void copy_sync_samples_to_audio_track(trak_t* video, trak_t* audio)
2423 {
2424   if(video)
2425   {
2426     samples_t* first = video->samples_;
2427     samples_t* last = video->samples_ + video->samples_size_;
2428     samples_t* audio_first = audio->samples_;
2429     samples_t* audio_last = audio->samples_ + audio->samples_size_;
2430     while(first != last)
2431     {
2432       if(first->is_smooth_ss_)
2433       {
2434         uint64_t pts = trak_time_to_moov_time(first->pts_,
2435           audio->mdia_->mdhd_->timescale_, video->mdia_->mdhd_->timescale_);
2436         while(audio_first != audio_last)
2437         {
2438           if(audio_first->pts_ >= pts)
2439           {
2440             audio_first->is_smooth_ss_ = 1;
2441             break;
2442           }
2443           ++audio_first;
2444         }
2445       }
2446       ++first;
2447     }
2448   }
2449   else
2450   {
2451     // if there is no video track and we don't have sync samples, then insert
2452     // smooth sync samples every 2 seconds
2453     samples_t* f = audio->samples_;
2454     samples_t* l = audio->samples_ + audio->samples_size_;
2455     uint64_t pts = 0;
2456     uint64_t increment = 2 * audio->mdia_->mdhd_->timescale_;
2457     while(f != l)
2458     {
2459       if(f->pts_ >= pts)
2460       {
2461         f->is_smooth_ss_ = 1;
2462         pts += increment;
2463       }
2464       ++f;
2465     }
2466   }
2467 }
2468 
moov_build_index(struct mp4_context_t const * mp4_context,struct moov_t * moov)2469 extern int moov_build_index(struct mp4_context_t const* mp4_context,
2470                             struct moov_t* moov)
2471 {
2472   // Build the track index
2473   trak_t* audio_trak = NULL;
2474   trak_t* video_trak = NULL;
2475   unsigned int track;
2476 
2477   // already indexed?
2478   if(moov->is_indexed_)
2479   {
2480     return 1;
2481   }
2482   moov->is_indexed_ = 1;
2483 
2484   for(track = 0; track != moov->tracks_; ++track)
2485   {
2486     trak_t* trak = moov->traks_[track];
2487     switch(trak->mdia_->hdlr_->handler_type_)
2488     {
2489     case FOURCC('s', 'o', 'u', 'n'):
2490       audio_trak = trak;
2491       break;
2492     case FOURCC('v', 'i', 'd', 'e'):
2493       video_trak = trak;
2494       break;
2495     }
2496     if(!trak_build_index(mp4_context, trak))
2497     {
2498       return 0;
2499     }
2500   }
2501 
2502   // Copy the sync sample markers for smooth streaming from the video trak
2503   // to the audio trak in case the audio track doesn't have an 'stss'.
2504   if(!moov->mvex_ && audio_trak && !audio_trak->mdia_->minf_->stbl_->stss_)
2505   {
2506     copy_sync_samples_to_audio_track(video_trak, audio_trak);
2507   }
2508 
2509   return 1;
2510 }
2511 
tfra_read(struct mp4_context_t const * UNUSED (mp4_context),void * UNUSED (parent),unsigned char * buffer,uint64_t UNUSED (size))2512 static void* tfra_read(struct mp4_context_t const* UNUSED(mp4_context),
2513                        void* UNUSED(parent),
2514                        unsigned char* buffer, uint64_t UNUSED(size))
2515 {
2516   unsigned int i;
2517   unsigned int length_fields;
2518 
2519   tfra_t* tfra = tfra_init();
2520 
2521   tfra->version_ = read_8(buffer + 0);
2522   tfra->flags_ = read_24(buffer + 1);
2523 
2524   tfra->track_id_ = read_32(buffer + 4);
2525   length_fields = read_32(buffer + 8);
2526   tfra->length_size_of_traf_num_ = (((length_fields >> 4) & 3) + 1);
2527   tfra->length_size_of_trun_num_ = (((length_fields >> 2) & 3) + 1);
2528   tfra->length_size_of_sample_num_ = (((length_fields >> 0) & 3) + 1);
2529   tfra->number_of_entry_ = read_32(buffer + 12);
2530   tfra->table_ = (tfra_table_t*)malloc(tfra->number_of_entry_ * sizeof(tfra_table_t));
2531   buffer += 16;
2532   for(i = 0; i != tfra->number_of_entry_; ++i)
2533   {
2534     if(tfra->version_ == 0)
2535     {
2536       tfra->table_[i].time_ = read_32(buffer + 0);
2537       tfra->table_[i].moof_offset_ = read_32(buffer + 4);
2538       buffer += 8;
2539     }
2540     else
2541     {
2542       tfra->table_[i].time_ = read_64(buffer + 0);
2543       tfra->table_[i].moof_offset_ = read_64(buffer + 8);
2544       buffer += 16;
2545     }
2546     tfra->table_[i].traf_number_ =
2547       read_n(buffer, tfra->length_size_of_traf_num_ * 8) - 1;
2548     buffer += tfra->length_size_of_traf_num_;
2549 
2550     tfra->table_[i].trun_number_ =
2551       read_n(buffer, tfra->length_size_of_trun_num_ * 8) - 1;
2552     buffer += tfra->length_size_of_trun_num_;
2553 
2554     tfra->table_[i].sample_number_ =
2555       read_n(buffer, tfra->length_size_of_sample_num_ * 8) - 1;
2556     buffer += tfra->length_size_of_sample_num_ ;
2557   }
2558 
2559   return tfra;
2560 }
2561 
mfra_add_tfra(struct mp4_context_t const * UNUSED (mp4_context),void * parent,void * child)2562 static int mfra_add_tfra(struct mp4_context_t const* UNUSED(mp4_context),
2563                          void* parent, void* child)
2564 {
2565   mfra_t* mfra = (mfra_t*)parent;
2566   tfra_t* tfra = (tfra_t*)child;
2567   if(mfra->tracks_ == MAX_TRACKS)
2568   {
2569     mfra_exit(mfra);
2570     return 0;
2571   }
2572 
2573   mfra->tfras_[mfra->tracks_] = tfra;
2574   ++mfra->tracks_;
2575 
2576   return 1;
2577 }
2578 
mfra_read(struct mp4_context_t const * mp4_context,void * UNUSED (parent),unsigned char * buffer,uint64_t size)2579 extern void* mfra_read(struct mp4_context_t const* mp4_context,
2580                        void* UNUSED(parent),
2581                        unsigned char* buffer, uint64_t size)
2582 {
2583   mfra_t* atom = mfra_init();
2584 
2585   struct atom_read_list_t atom_read_list[] = {
2586     { FOURCC('t', 'f', 'r', 'a'), &mfra_add_tfra, &tfra_read },
2587   };
2588 
2589   int result = atom_reader(mp4_context,
2590                   atom_read_list,
2591                   sizeof(atom_read_list) / sizeof(atom_read_list[0]),
2592                   atom,
2593                   buffer, size);
2594 
2595   if(!result)
2596   {
2597     mfra_exit(atom);
2598     return 0;
2599   }
2600 
2601   return atom;
2602 }
2603 
2604 // End Of File
2605 
2606