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