1 /*******************************************************************************
2  mp4_io.c - A library for general MPEG4 I/O.
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 UINT32_MAX
17 #endif
18 
19 #include "mp4_io.h"
20 #include "mp4_reader.h" // for moov_read
21 #include <stdio.h>
22 #include <stdarg.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <sys/types.h>  // FreeBSD doesn't define off_t in stdio.h
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <time.h>
29 
30 #ifdef WIN32
31 #include <io.h>
32 #include <windows.h>
33 #define DIR_SEPARATOR '\\'
34 #define strdup _strdup
35 #define open _open
36 #define close _close
37 #define write _write
38 #define lseek _lseeki64
39 #define stat _stat64
40 #else
41 #define DIR_SEPARATOR '/'
42 #include <unistd.h>
43 #include <sys/mman.h>
44 #endif
45 
atoi64(const char * val)46 extern uint64_t atoi64(const char* val)
47 {
48 #ifdef WIN32
49   return _atoi64(val);
50 #else // elif defined(HAVE_STRTOLL)
51   return strtoll(val, NULL, 10);
52 #endif
53 }
54 
remove_path(const char * path)55 extern const char* remove_path(const char *path)
56 {
57   const char* p = strrchr(path, DIR_SEPARATOR);
58   if(p != NULL && *p != '\0')
59   {
60     return p + 1;
61   }
62 
63   return path;
64 }
65 
mp4_log_trace(const char * fmt,...)66 extern void mp4_log_trace(const char* fmt, ...)
67 {
68   va_list arglist;
69   va_start(arglist, fmt);
70 
71   vprintf(fmt, arglist);
72 
73   va_end(arglist);
74 }
75 
seconds_since_1970(void)76 static int64_t seconds_since_1970(void)
77 {
78 // #ifdef WIN32
79   return time(NULL);
80 // #else
81 //   struct timeval tv;
82 //   gettimeofday(&tv, NULL);
83 //   return 1000000 * (int64_t)tv.tv_sec + tv.tv_usec;
84 // #endif
85 }
86 
seconds_since_1904(void)87 static int64_t seconds_since_1904(void)
88 {
89   return seconds_since_1970() + 2082844800;
90 }
91 
read_8(unsigned char const * buffer)92 extern unsigned int read_8(unsigned char const* buffer)
93 {
94   return buffer[0];
95 }
96 
write_8(unsigned char * buffer,unsigned int v)97 extern unsigned char* write_8(unsigned char* buffer, unsigned int v)
98 {
99   buffer[0] = (uint8_t)v;
100 
101   return buffer + 1;
102 }
103 
read_16(unsigned char const * buffer)104 extern uint16_t read_16(unsigned char const* buffer)
105 {
106   return (buffer[0] << 8) |
107          (buffer[1] << 0);
108 }
109 
write_16(unsigned char * buffer,unsigned int v)110 extern unsigned char* write_16(unsigned char* buffer, unsigned int v)
111 {
112   buffer[0] = (uint8_t)(v >> 8);
113   buffer[1] = (uint8_t)(v >> 0);
114 
115   return buffer + 2;
116 }
117 
read_24(unsigned char const * buffer)118 extern unsigned int read_24(unsigned char const* buffer)
119 {
120   return (buffer[0] << 16) |
121          (buffer[1] << 8) |
122          (buffer[2] << 0);
123 }
124 
write_24(unsigned char * buffer,unsigned int v)125 extern unsigned char* write_24(unsigned char* buffer, unsigned int v)
126 {
127   buffer[0] = (uint8_t)(v >> 16);
128   buffer[1] = (uint8_t)(v >> 8);
129   buffer[2] = (uint8_t)(v >> 0);
130 
131   return buffer + 3;
132 }
133 
read_32(unsigned char const * buffer)134 extern uint32_t read_32(unsigned char const* buffer)
135 {
136   return (buffer[0] << 24) |
137          (buffer[1] << 16) |
138          (buffer[2] << 8) |
139          (buffer[3] << 0);
140 }
141 
write_32(unsigned char * buffer,uint32_t v)142 extern unsigned char* write_32(unsigned char* buffer, uint32_t v)
143 {
144   buffer[0] = (uint8_t)(v >> 24);
145   buffer[1] = (uint8_t)(v >> 16);
146   buffer[2] = (uint8_t)(v >> 8);
147   buffer[3] = (uint8_t)(v >> 0);
148 
149   return buffer + 4;
150 }
151 
read_64(unsigned char const * buffer)152 extern uint64_t read_64(unsigned char const* buffer)
153 {
154   return ((uint64_t)(read_32(buffer)) << 32) + read_32(buffer + 4);
155 }
156 
write_64(unsigned char * buffer,uint64_t v)157 extern unsigned char* write_64(unsigned char* buffer, uint64_t v)
158 {
159   write_32(buffer + 0, (uint32_t)(v >> 32));
160   write_32(buffer + 4, (uint32_t)(v >> 0));
161 
162   return buffer + 8;
163 }
164 
read_n(unsigned char const * buffer,unsigned int n)165 extern uint32_t read_n(unsigned char const* buffer, unsigned int n)
166 {
167   switch(n)
168   {
169   case 8:
170     return read_8(buffer);
171   case 16:
172     return read_16(buffer);
173   case 24:
174     return read_24(buffer);
175   case 32:
176     return read_32(buffer);
177   default:
178     // program error
179     return 0;
180   }
181 }
182 
write_n(unsigned char * buffer,unsigned int n,uint32_t v)183 extern unsigned char* write_n(unsigned char* buffer, unsigned int n, uint32_t v)
184 {
185   switch(n)
186   {
187   case 8:
188     return write_8(buffer, v);
189   case 16:
190     return write_16(buffer, v);
191   case 24:
192     return write_24(buffer, v);
193   case 32:
194     return write_32(buffer, v);
195   }
196   return NULL;
197 }
198 
alignment()199 static unsigned int alignment()
200 {
201 #ifdef _WIN32
202   SYSTEM_INFO SysInfo;
203   GetSystemInfo(&SysInfo);
204   return (unsigned int)(SysInfo.dwAllocationGranularity);
205 #else
206   return (unsigned int)(getpagesize());
207 #endif
208 }
209 
mem_range_init(char const * filename,int read_only,uint64_t filesize,uint64_t offset,uint64_t len)210 static mem_range_t* mem_range_init(char const* filename, int read_only,
211                                    uint64_t filesize,
212                                    uint64_t offset, uint64_t len)
213 {
214   mem_range_t* mem_range = (mem_range_t*)malloc(sizeof(mem_range_t));
215   mem_range->read_only_ = read_only;
216   mem_range->filesize_ = filesize;
217   mem_range->fd_ = -1;
218   mem_range->mmap_addr_ = 0;
219   mem_range->mmap_offset_ = 0;
220   mem_range->mmap_size_ = 0;
221 #ifdef WIN32
222   mem_range->fileMapHandle_ = NULL;
223 #endif
224 
225   mem_range->fd_ = open(filename, read_only ? O_RDONLY : (O_RDWR | O_CREAT),
226 #ifdef WIN32
227   S_IREAD | S_IWRITE
228 #else
229   0666
230 #endif
231   );
232   if(mem_range->fd_ == -1)
233   {
234     printf("mem_range: Error opening file %s\n", filename);
235     mem_range_exit(mem_range);
236     return 0;
237   }
238 
239   if(!read_only)
240   {
241     // shrink the file (if necessary)
242     if(offset + len < filesize)
243     {
244       int result;
245 #ifdef WIN32
246       lseek(mem_range->fd_, offset + len, SEEK_SET);
247       result =
248         SetEndOfFile((HANDLE)_get_osfhandle(mem_range->fd_)) == 0 ? -1 : 0;
249 #else
250       result = truncate(filename, offset + len);
251 #endif
252       if(result < 0)
253       {
254         printf("mem_range: Error shrinking file %s\n", filename);
255         mem_range_exit(mem_range);
256         return 0;
257       }
258     }
259     // stretch the file (if necessary)
260     else if(offset + len > filesize)
261     {
262       lseek(mem_range->fd_, offset + len - 1, SEEK_SET);
263       if(write(mem_range->fd_, "", 1) < 0)
264       {
265         printf("mem_range: Error stretching file %s\n", filename);
266         mem_range_exit(mem_range);
267         return 0;
268       }
269     }
270     mem_range->filesize_ = offset + len;
271   }
272 
273 #ifdef _WIN32
274 {
275   HANDLE hFile = (HANDLE)_get_osfhandle(mem_range->fd_);
276 
277   if(!hFile)
278   {
279     printf("%s", "Cannot create file mapping\n");
280     mem_range_exit(mem_range);
281     return 0;
282   }
283 
284   mem_range->fileMapHandle_ = CreateFileMapping(hFile, 0,
285     read_only ? PAGE_READONLY : PAGE_READWRITE, 0, 0, NULL);
286 
287   if(!mem_range->fileMapHandle_)
288   {
289     printf("%s", "Cannot create file mapping view\n");
290     mem_range_exit(mem_range);
291     return 0;
292   }
293 }
294 #endif
295 
296   return mem_range;
297 }
298 
mem_range_init_read(char const * filename)299 mem_range_t* mem_range_init_read(char const* filename)
300 {
301   int read_only = 1;
302   uint64_t offset = 0;
303   struct stat status;
304   // make sure regular file exists and its not empty (can't mmap 0 bytes)
305   if(stat(filename, &status) ||
306      (status.st_mode & S_IFMT) != S_IFREG ||
307      status.st_size == 0)
308   {
309     return 0;
310   }
311 
312   return mem_range_init(filename, read_only, status.st_size,
313                         offset, status.st_size);
314 }
315 
mem_range_init_write(char const * filename,uint64_t offset,uint64_t len)316 mem_range_t* mem_range_init_write(char const* filename,
317                                   uint64_t offset, uint64_t len)
318 {
319   int read_only = 0;
320   uint64_t filesize = 0;
321   struct stat status;
322   if(!stat(filename, &status))
323   {
324     filesize = status.st_size;
325   }
326 
327   return mem_range_init(filename, read_only, filesize, offset, len);
328 }
329 
mem_range_map(mem_range_t * mem_range,uint64_t offset,uint32_t len)330 void* mem_range_map(mem_range_t* mem_range, uint64_t offset, uint32_t len)
331 {
332   // only map when necessary
333   if(offset < mem_range->mmap_offset_ ||
334      offset + len >= mem_range->mmap_offset_ + mem_range->mmap_size_)
335   {
336     // use 1MB of overlap, so a little random access is okay at the end of the
337     // memory mapped file.
338     const unsigned int overlap = 1024 * 1024;
339     const unsigned int window_size = 16 * 1024 * 1024;
340 
341     unsigned int dwSysGran = alignment();
342     uint64_t mmap_offset = offset > overlap ? (offset - overlap) : 0;
343     len += offset > overlap ? overlap : (uint32_t)offset;
344 //    uint64_t mmap_offset = offset;
345     mem_range->mmap_offset_ = (mmap_offset / dwSysGran) * dwSysGran;
346     mem_range->mmap_size_ = (mmap_offset % dwSysGran) + len;
347 
348     if(mem_range->mmap_offset_ + mem_range->mmap_size_ > mem_range->filesize_)
349     {
350       printf("%s", "mem_range_map: invalid range for file mapping\n");
351       return 0;
352     }
353 
354     if(mem_range->mmap_size_ < window_size)
355     {
356       mem_range->mmap_size_ = window_size;
357     }
358 
359     if(mem_range->mmap_offset_ + mem_range->mmap_size_ > mem_range->filesize_)
360     {
361       mem_range->mmap_size_ = mem_range->filesize_ - mem_range->mmap_offset_;
362     }
363 
364 //    printf("mem_range(%x): offset=%"PRIu64"\n", mem_range, offset);
365 
366 #ifdef WIN32
367     if(mem_range->mmap_addr_)
368     {
369       UnmapViewOfFile(mem_range->mmap_addr_);
370     }
371 
372     mem_range->mmap_addr_ = MapViewOfFile(mem_range->fileMapHandle_,
373       mem_range->read_only_ ? FILE_MAP_READ : FILE_MAP_WRITE,
374       mem_range->mmap_offset_ >> 32, (uint32_t)(mem_range->mmap_offset_),
375       (size_t)(mem_range->mmap_size_));
376 
377     if(!mem_range->mmap_addr_)
378     {
379       printf("%s", "Unable to make file mapping\n");
380       return 0;
381     }
382 #else
383     if(mem_range->mmap_addr_)
384     {
385       munmap(mem_range->mmap_addr_, mem_range->mmap_size_);
386     }
387 
388     mem_range->mmap_addr_ = mmap(0, mem_range->mmap_size_, mem_range->read_only_ ? PROT_READ : (PROT_READ | PROT_WRITE), mem_range->read_only_ ? MAP_PRIVATE : MAP_SHARED, mem_range->fd_, mem_range->mmap_offset_);
389 
390     if(mem_range->mmap_addr_ == MAP_FAILED)
391     {
392       printf("%s", "Unable to make file mapping\n");
393       return 0;
394     }
395 
396     if(mem_range->read_only_ &&
397        madvise(mem_range->mmap_addr_, mem_range->mmap_size_, MADV_SEQUENTIAL) < 0)
398     {
399       printf("%s", "Unable to advise file mapping\n");
400       // continue
401     }
402 #endif
403   }
404 
405   return (char*)mem_range->mmap_addr_ + (offset - mem_range->mmap_offset_);
406 }
407 
mem_range_exit(mem_range_t * mem_range)408 void mem_range_exit(mem_range_t* mem_range)
409 {
410   if(!mem_range)
411   {
412     return;
413   }
414 
415 #ifdef WIN32
416   CloseHandle(mem_range->fileMapHandle_);
417 #endif
418 
419   if(mem_range->mmap_addr_)
420   {
421 #ifdef WIN32
422     UnmapViewOfFile(mem_range->mmap_addr_);
423 #else
424     munmap(mem_range->mmap_addr_, mem_range->mmap_size_);
425 #endif
426   }
427 
428   if(mem_range->fd_ != -1)
429   {
430     close(mem_range->fd_);
431   }
432 
433   free(mem_range);
434 }
435 
mp4_atom_read_header(mp4_context_t const * mp4_context,FILE * infile,mp4_atom_t * atom)436 extern int mp4_atom_read_header(mp4_context_t const* mp4_context,
437                                 FILE* infile, mp4_atom_t* atom)
438 {
439   unsigned char atom_header[8];
440 
441   atom->start_ = ftello(infile);
442   if(fread(atom_header, 8, 1, infile) != 1)
443   {
444     MP4_ERROR("%s", "Error reading atom header\n");
445     return 0;
446   }
447   atom->short_size_ = read_32(&atom_header[0]);
448   atom->type_ = read_32(&atom_header[4]);
449 
450   if(atom->short_size_ == 1)
451   {
452     if(fread(atom_header, 8, 1, infile) != 1)
453     {
454       MP4_ERROR("%s", "Error reading extended atom header\n");
455       return 0;
456     }
457     atom->size_ = read_64(&atom_header[0]);
458   }
459   else
460   {
461     atom->size_ = atom->short_size_;
462   }
463 
464   atom->end_ = atom->start_ + atom->size_;
465 
466   MP4_INFO("Atom(%c%c%c%c,%"PRIu64")\n",
467            atom->type_ >> 24, atom->type_ >> 16,
468            atom->type_ >> 8, atom->type_,
469            atom->size_);
470 
471   if(atom->size_ < ATOM_PREAMBLE_SIZE)
472   {
473     MP4_ERROR("%s", "Error: invalid atom size\n");
474     return 0;
475   }
476 
477   return 1;
478 }
479 
mp4_atom_write_header(unsigned char * outbuffer,mp4_atom_t const * atom)480 extern int mp4_atom_write_header(unsigned char* outbuffer,
481                                  mp4_atom_t const* atom)
482 {
483   int write_box64 = atom->short_size_ == 1 ? 1 : 0;
484 
485   if(write_box64)
486     write_32(outbuffer, 1);
487   else
488     write_32(outbuffer, (uint32_t)atom->size_);
489 
490   write_32(outbuffer + 4, atom->type_);
491 
492   if(write_box64)
493   {
494     write_64(outbuffer + 8, atom->size_);
495     return 16;
496   }
497   else
498   {
499     return 8;
500   }
501 }
502 
503 
read_box(struct mp4_context_t * mp4_context,FILE * infile,struct mp4_atom_t * atom)504 static unsigned char* read_box(struct mp4_context_t* mp4_context,
505                                FILE* infile, struct mp4_atom_t* atom)
506 {
507   unsigned char* box_data = (unsigned char*)malloc((size_t)atom->size_);
508   fseeko(infile, atom->start_, SEEK_SET);
509   if(fread(box_data, (off_t)atom->size_, 1, infile) != 1)
510   {
511     MP4_ERROR("Error reading %c%c%c%c atom\n",
512            atom->type_ >> 24, atom->type_ >> 16,
513            atom->type_ >> 8, atom->type_);
514     free(box_data);
515     fclose(infile);
516     return 0;
517   }
518   return box_data;
519 }
520 
mp4_context_init(const char * filename,int verbose)521 static mp4_context_t* mp4_context_init(const char* filename, int verbose)
522 {
523   mp4_context_t* mp4_context = (mp4_context_t*)malloc(sizeof(mp4_context_t));
524 
525   mp4_context->filename_ = strdup(filename);
526   mp4_context->infile = NULL;
527   mp4_context->verbose_ = verbose;
528 
529   memset(&mp4_context->ftyp_atom, 0, sizeof(struct mp4_atom_t));
530   memset(&mp4_context->moov_atom, 0, sizeof(struct mp4_atom_t));
531   memset(&mp4_context->mdat_atom, 0, sizeof(struct mp4_atom_t));
532   memset(&mp4_context->mfra_atom, 0, sizeof(struct mp4_atom_t));
533 
534   mp4_context->moov_data = 0;
535   mp4_context->mfra_data = 0;
536 
537   mp4_context->moov = 0;
538 
539   return mp4_context;
540 }
541 
mp4_context_exit(struct mp4_context_t * mp4_context)542 static void mp4_context_exit(struct mp4_context_t* mp4_context)
543 {
544   free(mp4_context->filename_);
545 
546   if(mp4_context->infile)
547   {
548     fclose(mp4_context->infile);
549   }
550 
551   if(mp4_context->moov_data)
552   {
553     free(mp4_context->moov_data);
554   }
555 
556   if(mp4_context->mfra_data)
557   {
558     free(mp4_context->mfra_data);
559   }
560 
561   if(mp4_context->moov)
562   {
563     moov_exit(mp4_context->moov);
564   }
565 
566   free(mp4_context);
567 }
568 
mp4_open(const char * filename,int64_t filesize,mp4_open_flags flags,int verbose)569 extern mp4_context_t* mp4_open(const char* filename, int64_t filesize,
570                                mp4_open_flags flags, int verbose)
571 {
572   mp4_context_t* mp4_context = mp4_context_init(filename, verbose);
573 
574   mp4_context->infile = fopen(filename, "rb");
575   if(mp4_context->infile == NULL)
576   {
577     mp4_context_exit(mp4_context);
578     return 0;
579   }
580 
581   // fast-open if we're only interested in the mfra atom
582   if(flags == MP4_OPEN_MFRA)
583   {
584     unsigned char mfro[16];
585     fseeko(mp4_context->infile, -16, SEEK_END);
586     if(fread(mfro, 16, 1, mp4_context->infile) != 1)
587     {
588       MP4_ERROR("%s", "Error reading mfro header\n");
589       fseeko(mp4_context->infile, 0, SEEK_SET);
590     }
591     else
592     {
593       if(read_32(mfro + 4) != FOURCC('m', 'f', 'r', 'o'))
594       {
595         MP4_ERROR("%s", "Error parsing mfro header\n");
596         fseeko(mp4_context->infile, 0, SEEK_SET);
597       }
598       else
599       {
600         off_t mfra_size = read_32(mfro + 12);
601         fseeko(mp4_context->infile, -mfra_size, SEEK_END);
602       }
603     }
604   }
605 
606   while(ftello(mp4_context->infile) < filesize)
607   {
608     struct mp4_atom_t leaf_atom;
609 
610     if(!mp4_atom_read_header(mp4_context, mp4_context->infile, &leaf_atom))
611       break;
612 
613     switch(leaf_atom.type_)
614     {
615     case FOURCC('f', 't', 'y', 'p'):
616       mp4_context->ftyp_atom = leaf_atom;
617       break;
618     case FOURCC('m', 'o', 'o', 'v'):
619       mp4_context->moov_atom = leaf_atom;
620       mp4_context->moov_data = read_box(mp4_context, mp4_context->infile, &mp4_context->moov_atom);
621       if(mp4_context->moov_data == NULL)
622       {
623         mp4_context_exit(mp4_context);
624         return 0;
625       }
626 
627       mp4_context->moov = (moov_t*)
628         moov_read(mp4_context, NULL,
629                   mp4_context->moov_data + ATOM_PREAMBLE_SIZE,
630                   mp4_context->moov_atom.size_ - ATOM_PREAMBLE_SIZE);
631 
632       if(mp4_context->moov == 0 || mp4_context->moov->mvhd_ == 0)
633       {
634         MP4_ERROR("%s", "Error parsing moov header\n");
635         mp4_context_exit(mp4_context);
636         return 0;
637       }
638       break;
639     case FOURCC('m', 'o', 'o', 'f'):
640       {
641         moof_t* moof;
642         unsigned char* moof_data =
643           read_box(mp4_context, mp4_context->infile, &leaf_atom);
644 
645         mp4_context->moof_offset_ = leaf_atom.start_;
646 
647 #if 1
648         // Check for Expression Encoder file (missing mandatory stco)
649         if(mp4_context->moov != 0 &&
650            mp4_context->moov->tracks_ != 0 &&
651            mp4_context->moov->traks_[0]->mdia_->minf_->stbl_->stco_ == 0)
652         {
653           MP4_ERROR("%s", "Fixing invalid offsets for Expression Encoder file\n");
654           // Expression Encoder doesn't write a base_data_offset or data_offset.
655           // We patch the moof_offset_ to point to the mdat following the moof.
656           mp4_context->moof_offset_ += leaf_atom.size_ + ATOM_PREAMBLE_SIZE;
657         }
658 #endif
659 
660         moof = (moof_t*)
661           moof_read(mp4_context, NULL,
662                     moof_data + ATOM_PREAMBLE_SIZE,
663                     leaf_atom.size_ - ATOM_PREAMBLE_SIZE);
664 
665         free(moof_data);
666 
667         if(moof == 0)
668         {
669           MP4_ERROR("%s", "Error parsing moof header\n");
670           mp4_context_exit(mp4_context);
671           return 0;
672         }
673 
674         moof_exit(moof);
675       }
676       break;
677     case FOURCC('m', 'd', 'a', 't'):
678       mp4_context->mdat_atom = leaf_atom;
679       break;
680     case FOURCC('m', 'f', 'r', 'a'):
681       mp4_context->mfra_atom = leaf_atom;
682       mp4_context->mfra_data = read_box(mp4_context, mp4_context->infile, &mp4_context->mfra_atom);
683       if(mp4_context->mfra_data == NULL)
684       {
685         mp4_context_exit(mp4_context);
686         return 0;
687       }
688       break;
689     }
690 
691     if(leaf_atom.end_ > (uint64_t)filesize)
692     {
693       MP4_ERROR("%s", "Reached end of file prematurely\n");
694       mp4_context_exit(mp4_context);
695       return 0;
696     }
697 
698     fseeko(mp4_context->infile, leaf_atom.end_, SEEK_SET);
699 
700     // short-circuit for mfra. We only need the mfra atom.
701     if((flags == MP4_OPEN_MOOV) && mp4_context->moov_atom.size_)
702     {
703       return mp4_context;
704     }
705 
706     // short-circuit for mfra. We only need the mfra atom.
707     if((flags == MP4_OPEN_MFRA) && mp4_context->mfra_atom.size_)
708     {
709       return mp4_context;
710     }
711   }
712 
713   if(mp4_context->moov == 0)
714   {
715     MP4_ERROR("%s", "Error: moov atom not found\n");
716     mp4_context_exit(mp4_context);
717     return 0;
718   }
719 
720   if(mp4_context->mdat_atom.size_ == 0)
721   {
722     // or mdat atom
723     MP4_ERROR("%s", "Error: mdat atom not found\n");
724     mp4_context_exit(mp4_context);
725     return 0;
726   }
727 
728   return mp4_context;
729 }
730 
mp4_close(struct mp4_context_t * mp4_context)731 extern void mp4_close(struct mp4_context_t* mp4_context)
732 {
733   mp4_context_exit(mp4_context);
734 }
735 
736 ////////////////////////////////////////////////////////////////////////////////
737 
unknown_atom_init()738 extern struct unknown_atom_t* unknown_atom_init()
739 {
740   unknown_atom_t* atom = (unknown_atom_t*)malloc(sizeof(unknown_atom_t));
741   atom->atom_ = 0;
742   atom->next_ = 0;
743 
744   return atom;
745 }
746 
unknown_atom_exit(unknown_atom_t * atom)747 extern void unknown_atom_exit(unknown_atom_t* atom)
748 {
749   while(atom)
750   {
751     unknown_atom_t* next = atom->next_;
752     free(atom->atom_);
753     free(atom);
754     atom = next;
755   }
756 }
757 
758 
moov_init()759 extern moov_t* moov_init()
760 {
761   moov_t* moov = (moov_t*)malloc(sizeof(moov_t));
762   moov->unknown_atoms_ = 0;
763   moov->mvhd_ = 0;
764   moov->tracks_ = 0;
765   moov->mvex_ = 0;
766 
767   moov->is_indexed_ = 0;
768 
769   return moov;
770 }
771 
moov_exit(moov_t * atom)772 extern void moov_exit(moov_t* atom)
773 {
774   unsigned int i;
775   if(atom->unknown_atoms_)
776   {
777     unknown_atom_exit(atom->unknown_atoms_);
778   }
779   if(atom->mvhd_)
780   {
781     mvhd_exit(atom->mvhd_);
782   }
783   for(i = 0; i != atom->tracks_; ++i)
784   {
785     trak_exit(atom->traks_[i]);
786   }
787   if(atom->mvex_)
788   {
789     mvex_exit(atom->mvex_);
790   }
791   free(atom);
792 }
793 
794 #if 0
795 extern void moov_shift_offsets(moov_t* moov, int64_t offset)
796 {
797   unsigned int i;
798   for(i = 0; i != moov->tracks_; ++i)
799   {
800     trak_shift_offsets(moov->traks_[i], offset);
801   }
802 }
803 #endif
804 
trak_init()805 extern trak_t* trak_init()
806 {
807   trak_t* trak = (trak_t*)malloc(sizeof(trak_t));
808   trak->unknown_atoms_ = 0;
809   trak->tkhd_ = 0;
810   trak->mdia_ = 0;
811   trak->edts_ = 0;
812   trak->chunks_size_ = 0;
813   trak->chunks_ = 0;
814   trak->samples_size_ = 0;
815   trak->samples_ = 0;
816 
817 //  trak->fragment_pts_ = 0;
818 
819   return trak;
820 }
821 
trak_bitrate(trak_t const * trak)822 extern unsigned int trak_bitrate(trak_t const* trak)
823 {
824   long trak_time_scale = trak->mdia_->mdhd_->timescale_;
825   uint64_t duration;
826   unsigned int bps;
827 
828   samples_t const* first = trak->samples_;
829   samples_t const* last = trak->samples_ + trak->samples_size_;
830   uint64_t sample_size = 0;
831   while(first != last)
832   {
833     sample_size += first->size_;
834     ++first;
835   }
836   duration = first->pts_;
837 
838   bps = (unsigned int)(sample_size * trak_time_scale / duration * 8);
839 
840   return bps;
841 }
842 
843 #if 0
844 extern void trak_shift_offsets(trak_t* trak, int64_t offset)
845 {
846   stco_t* stco = trak->mdia_->minf_->stbl_->stco_;
847   stco_shift_offsets(stco, (int32_t)offset);
848 }
849 #endif
850 
trak_exit(trak_t * trak)851 extern void trak_exit(trak_t* trak)
852 {
853   if(trak->unknown_atoms_)
854   {
855     unknown_atom_exit(trak->unknown_atoms_);
856   }
857   if(trak->tkhd_)
858   {
859     tkhd_exit(trak->tkhd_);
860   }
861   if(trak->mdia_)
862   {
863     mdia_exit(trak->mdia_);
864   }
865   if(trak->edts_)
866   {
867     edts_exit(trak->edts_);
868   }
869   if(trak->chunks_)
870   {
871     free(trak->chunks_);
872   }
873   if(trak->samples_)
874   {
875     free(trak->samples_);
876   }
877   free(trak);
878 }
879 
mvhd_init()880 extern mvhd_t* mvhd_init()
881 {
882   unsigned int i;
883   mvhd_t* atom = (mvhd_t*)malloc(sizeof(mvhd_t));
884 
885   atom->version_ = 1;
886   atom->flags_ = 0;
887   atom->creation_time_ =
888   atom->modification_time_ = seconds_since_1904();
889   atom->timescale_ = 10000000;
890   atom->duration_ = 0;
891   atom->rate_ = (1 << 16);
892   atom->volume_ = (1 << 8);
893   atom->reserved1_ = 0;
894   for(i = 0; i != 2; ++i)
895   {
896     atom->reserved2_[i] = 0;
897   }
898   for(i = 0; i != 9; ++i)
899   {
900     atom->matrix_[i] = 0;
901   }
902   atom->matrix_[0] = 0x00010000;
903   atom->matrix_[4] = 0x00010000;
904   atom->matrix_[8] = 0x40000000;
905   for(i = 0; i != 6; ++i)
906   {
907     atom->predefined_[i] = 0;
908   }
909   atom->next_track_id_ = 1;
910 
911   return atom;
912 }
913 
mvhd_copy(mvhd_t const * rhs)914 extern mvhd_t* mvhd_copy(mvhd_t const* rhs)
915 {
916   mvhd_t* atom = (mvhd_t*)malloc(sizeof(mvhd_t));
917 
918   memcpy(atom, rhs, sizeof(mvhd_t));
919 
920   return atom;
921 }
922 
mvhd_exit(mvhd_t * atom)923 extern void mvhd_exit(mvhd_t* atom)
924 {
925   free(atom);
926 }
927 
tkhd_init()928 extern tkhd_t* tkhd_init()
929 {
930   unsigned int i;
931   tkhd_t* tkhd = (tkhd_t*)malloc(sizeof(tkhd_t));
932 
933   tkhd->version_= 1;
934   tkhd->flags_ = 7;           // track_enabled, track_in_movie, track_in_preview
935   tkhd->creation_time_ =
936   tkhd->modification_time_ = seconds_since_1904();
937   tkhd->track_id_ = 0;
938   tkhd->reserved_ = 0;
939   tkhd->duration_ = 0;
940   for(i = 0; i != 2; ++i)
941   {
942     tkhd->reserved2_[i] = 0;
943   }
944   tkhd->layer_ = 0;
945   tkhd->predefined_ = 0;
946   tkhd->volume_ = (1 << 8) + 0;
947   tkhd->reserved3_ = 0;
948   for(i = 0; i != 9; ++i)
949   {
950     tkhd->matrix_[i] = 0;
951   }
952   tkhd->matrix_[0] = 0x00010000;
953   tkhd->matrix_[4] = 0x00010000;
954   tkhd->matrix_[8] = 0x40000000;
955   tkhd->width_ = 0;
956   tkhd->height_ = 0;
957 
958   return tkhd;
959 }
960 
tkhd_copy(tkhd_t const * rhs)961 extern struct tkhd_t* tkhd_copy(tkhd_t const* rhs)
962 {
963   tkhd_t* tkhd = (tkhd_t*)malloc(sizeof(tkhd_t));
964 
965   memcpy(tkhd, rhs, sizeof(tkhd_t));
966 
967   return tkhd;
968 }
969 
tkhd_exit(tkhd_t * tkhd)970 extern void tkhd_exit(tkhd_t* tkhd)
971 {
972   free(tkhd);
973 }
974 
mdia_init()975 extern struct mdia_t* mdia_init()
976 {
977   mdia_t* atom = (mdia_t*)malloc(sizeof(mdia_t));
978   atom->unknown_atoms_ = 0;
979   atom->mdhd_ = 0;
980   atom->hdlr_ = 0;
981   atom->minf_ = 0;
982 
983   return atom;
984 }
985 
mdia_exit(mdia_t * atom)986 extern void mdia_exit(mdia_t* atom)
987 {
988   if(atom->unknown_atoms_)
989   {
990     unknown_atom_exit(atom->unknown_atoms_);
991   }
992   if(atom->mdhd_)
993   {
994     mdhd_exit(atom->mdhd_);
995   }
996   if(atom->hdlr_)
997   {
998     hdlr_exit(atom->hdlr_);
999   }
1000   if(atom->minf_)
1001   {
1002     minf_exit(atom->minf_);
1003   }
1004   free(atom);
1005 }
1006 
elst_init()1007 extern elst_t* elst_init()
1008 {
1009   elst_t* elst = (elst_t*)malloc(sizeof(elst_t));
1010 
1011   elst->version_ = 1;
1012   elst->flags_ = 0;
1013   elst->entry_count_ = 0;
1014   elst->table_ = 0;
1015 
1016   return elst;
1017 }
1018 
elst_exit(elst_t * elst)1019 extern void elst_exit(elst_t* elst)
1020 {
1021   if(elst->table_)
1022   {
1023     free(elst->table_);
1024   }
1025   free(elst);
1026 }
1027 
edts_init()1028 extern edts_t* edts_init()
1029 {
1030   edts_t* edts = (edts_t*)malloc(sizeof(edts_t));
1031 
1032   edts->unknown_atoms_ = 0;
1033   edts->elst_ = 0;
1034 
1035   return edts;
1036 }
1037 
edts_exit(edts_t * edts)1038 extern void edts_exit(edts_t* edts)
1039 {
1040   if(edts->unknown_atoms_)
1041   {
1042     unknown_atom_exit(edts->unknown_atoms_);
1043   }
1044   if(edts->elst_)
1045   {
1046     elst_exit(edts->elst_);
1047   }
1048   free(edts);
1049 }
1050 
mdhd_init()1051 extern mdhd_t* mdhd_init()
1052 {
1053   unsigned int i;
1054   mdhd_t* mdhd = (mdhd_t*)malloc(sizeof(mdhd_t));
1055 
1056   mdhd->version_ = 1;
1057   mdhd->flags_ = 0;
1058   mdhd->creation_time_ =
1059   mdhd->modification_time_ = seconds_since_1904();
1060   mdhd->timescale_ = 10000000;
1061   mdhd->duration_ = 0;
1062   for(i = 0; i != 3; ++i)
1063   {
1064     mdhd->language_[i] = 0x7f;
1065   }
1066   mdhd->predefined_ = 0;
1067 
1068   return mdhd;
1069 }
1070 
mdhd_copy(mdhd_t const * rhs)1071 extern mdhd_t* mdhd_copy(mdhd_t const* rhs)
1072 {
1073   struct mdhd_t* mdhd = (struct mdhd_t*)malloc(sizeof(struct mdhd_t));
1074 
1075   memcpy(mdhd, rhs, sizeof(mdhd_t));
1076 
1077   return mdhd;
1078 }
1079 
mdhd_exit(struct mdhd_t * mdhd)1080 extern void mdhd_exit(struct mdhd_t* mdhd)
1081 {
1082   free(mdhd);
1083 }
1084 
hdlr_init()1085 extern hdlr_t* hdlr_init()
1086 {
1087   hdlr_t* atom = (hdlr_t*)malloc(sizeof(hdlr_t));
1088 
1089   atom->version_ = 0;
1090   atom->flags_ = 0;
1091   atom->predefined_ = 0;
1092   atom->handler_type_ = 0;
1093   atom->reserved1_ = 0;
1094   atom->reserved2_ = 0;
1095   atom->reserved3_ = 0;
1096   atom->name_ = 0;
1097 
1098   return atom;
1099 }
1100 
hdlr_copy(hdlr_t const * rhs)1101 extern hdlr_t* hdlr_copy(hdlr_t const* rhs)
1102 {
1103   hdlr_t* atom = (hdlr_t*)malloc(sizeof(hdlr_t));
1104 
1105   atom->version_ = rhs->version_;
1106   atom->flags_ = rhs->flags_;
1107   atom->predefined_ = rhs->predefined_;
1108   atom->handler_type_ = rhs->handler_type_;
1109   atom->reserved1_ = rhs->reserved1_;
1110   atom->reserved2_ = rhs->reserved2_;
1111   atom->reserved3_ = rhs->reserved3_;
1112   atom->name_ = rhs->name_ == NULL ? NULL : strdup(rhs->name_);
1113 
1114   return atom;
1115 }
1116 
hdlr_exit(struct hdlr_t * atom)1117 extern void hdlr_exit(struct hdlr_t* atom)
1118 {
1119   if(atom->name_)
1120   {
1121     free(atom->name_);
1122   }
1123   free(atom);
1124 }
1125 
minf_init()1126 extern struct minf_t* minf_init()
1127 {
1128   struct minf_t* atom = (struct minf_t*)malloc(sizeof(struct minf_t));
1129   atom->unknown_atoms_ = 0;
1130   atom->vmhd_ = 0;
1131   atom->smhd_ = 0;
1132   atom->dinf_ = 0;
1133   atom->stbl_ = 0;
1134 
1135   return atom;
1136 }
1137 
minf_exit(struct minf_t * atom)1138 extern void minf_exit(struct minf_t* atom)
1139 {
1140   if(atom->unknown_atoms_)
1141   {
1142     unknown_atom_exit(atom->unknown_atoms_);
1143   }
1144   if(atom->vmhd_)
1145   {
1146     vmhd_exit(atom->vmhd_);
1147   }
1148   if(atom->smhd_)
1149   {
1150     smhd_exit(atom->smhd_);
1151   }
1152   if(atom->dinf_)
1153   {
1154     dinf_exit(atom->dinf_);
1155   }
1156   if(atom->stbl_)
1157   {
1158     stbl_exit(atom->stbl_);
1159   }
1160   free(atom);
1161 }
1162 
vmhd_init()1163 extern vmhd_t* vmhd_init()
1164 {
1165   unsigned int i;
1166   vmhd_t* atom = (vmhd_t*)malloc(sizeof(vmhd_t));
1167 
1168   atom->version_ = 0;
1169   atom->flags_ = 1;
1170   atom->graphics_mode_ = 0;
1171   for(i = 0; i != 3; ++i)
1172   {
1173     atom->opcolor_[i] = 0;
1174   }
1175 
1176   return atom;
1177 }
1178 
vmhd_copy(vmhd_t * rhs)1179 extern vmhd_t* vmhd_copy(vmhd_t* rhs)
1180 {
1181   vmhd_t* atom = (vmhd_t*)malloc(sizeof(vmhd_t));
1182 
1183   memcpy(atom, rhs, sizeof(vmhd_t));
1184 
1185   return atom;
1186 }
1187 
vmhd_exit(struct vmhd_t * atom)1188 extern void vmhd_exit(struct vmhd_t* atom)
1189 {
1190   free(atom);
1191 }
1192 
smhd_init()1193 extern smhd_t* smhd_init()
1194 {
1195   smhd_t* atom = (smhd_t*)malloc(sizeof(smhd_t));
1196 
1197   atom->version_ = 0;
1198   atom->flags_ = 0;
1199   atom->balance_ = 0;
1200   atom->reserved_ = 0;
1201 
1202   return atom;
1203 }
1204 
smhd_copy(smhd_t * rhs)1205 extern smhd_t* smhd_copy(smhd_t* rhs)
1206 {
1207   smhd_t* atom = (smhd_t*)malloc(sizeof(smhd_t));
1208 
1209   memcpy(atom, rhs, sizeof(smhd_t));
1210 
1211   return atom;
1212 }
1213 
smhd_exit(struct smhd_t * atom)1214 extern void smhd_exit(struct smhd_t* atom)
1215 {
1216   free(atom);
1217 }
1218 
dinf_init()1219 extern dinf_t* dinf_init()
1220 {
1221   dinf_t* atom = (dinf_t*)malloc(sizeof(dinf_t));
1222 
1223   atom->dref_ = 0;
1224 
1225   return atom;
1226 }
1227 
dinf_copy(dinf_t * rhs)1228 extern dinf_t* dinf_copy(dinf_t* rhs)
1229 {
1230   dinf_t* atom = (dinf_t*)malloc(sizeof(dinf_t));
1231 
1232   atom->dref_ = dref_copy(rhs->dref_);
1233 
1234   return atom;
1235 }
1236 
dinf_exit(dinf_t * atom)1237 extern void dinf_exit(dinf_t* atom)
1238 {
1239   if(atom->dref_)
1240   {
1241     dref_exit(atom->dref_);
1242   }
1243   free(atom);
1244 }
1245 
dref_init()1246 extern dref_t* dref_init()
1247 {
1248   dref_t* atom = (dref_t*)malloc(sizeof(dref_t));
1249 
1250   atom->version_ = 0;
1251   atom->flags_ = 0;
1252   atom->entry_count_ = 0;
1253   atom->table_ = 0;
1254 
1255   return atom;
1256 }
1257 
dref_copy(dref_t const * rhs)1258 extern dref_t* dref_copy(dref_t const* rhs)
1259 {
1260   unsigned int i;
1261   dref_t* atom = (dref_t*)malloc(sizeof(dref_t));
1262 
1263   atom->version_ = rhs->version_;
1264   atom->flags_ = rhs->flags_;
1265   atom->entry_count_ = rhs->entry_count_;
1266   atom->table_ = atom->entry_count_ == 0 ? NULL : (dref_table_t*)malloc(atom->entry_count_ * sizeof(dref_table_t));
1267   for(i = 0; i != atom->entry_count_; ++i)
1268   {
1269     dref_table_assign(&atom->table_[i], &rhs->table_[i]);
1270   }
1271 
1272   return atom;
1273 }
1274 
dref_exit(dref_t * atom)1275 extern void dref_exit(dref_t* atom)
1276 {
1277   unsigned int i;
1278   for(i = 0; i != atom->entry_count_; ++i)
1279   {
1280     dref_table_exit(&atom->table_[i]);
1281   }
1282   if(atom->table_)
1283   {
1284     free(atom->table_);
1285   }
1286   free(atom);
1287 }
1288 
dref_table_init(dref_table_t * entry)1289 extern void dref_table_init(dref_table_t* entry)
1290 {
1291   entry->flags_ = 0;
1292   entry->name_ = 0;
1293   entry->location_ = 0;
1294 }
1295 
dref_table_assign(dref_table_t * lhs,dref_table_t const * rhs)1296 extern void dref_table_assign(dref_table_t* lhs, dref_table_t const* rhs)
1297 {
1298   lhs->flags_ = rhs->flags_;
1299   lhs->name_ = rhs->name_ == NULL ? NULL : strdup(rhs->name_);
1300   lhs->location_ = rhs->location_ == NULL ? NULL : strdup(rhs->location_);
1301 }
1302 
dref_table_exit(dref_table_t * entry)1303 extern void dref_table_exit(dref_table_t* entry)
1304 {
1305   if(entry->name_)
1306   {
1307     free(entry->name_);
1308   }
1309   if(entry->location_)
1310   {
1311     free(entry->location_);
1312   }
1313 }
1314 
stbl_init()1315 extern struct stbl_t* stbl_init()
1316 {
1317   struct stbl_t* atom = (struct stbl_t*)malloc(sizeof(struct stbl_t));
1318   atom->unknown_atoms_ = 0;
1319   atom->stsd_ = 0;
1320   atom->stts_ = 0;
1321   atom->stss_ = 0;
1322   atom->stsc_ = 0;
1323   atom->stsz_ = 0;
1324   atom->stco_ = 0;
1325   atom->ctts_ = 0;
1326 
1327   return atom;
1328 }
1329 
stbl_exit(struct stbl_t * atom)1330 extern void stbl_exit(struct stbl_t* atom)
1331 {
1332   if(atom->unknown_atoms_)
1333   {
1334     unknown_atom_exit(atom->unknown_atoms_);
1335   }
1336   if(atom->stsd_)
1337   {
1338     stsd_exit(atom->stsd_);
1339   }
1340   if(atom->stts_)
1341   {
1342     stts_exit(atom->stts_);
1343   }
1344   if(atom->stss_)
1345   {
1346     stss_exit(atom->stss_);
1347   }
1348   if(atom->stsc_)
1349   {
1350     stsc_exit(atom->stsc_);
1351   }
1352   if(atom->stsz_)
1353   {
1354     stsz_exit(atom->stsz_);
1355   }
1356   if(atom->stco_)
1357   {
1358     stco_exit(atom->stco_);
1359   }
1360   if(atom->ctts_)
1361   {
1362     ctts_exit(atom->ctts_);
1363   }
1364 
1365   free(atom);
1366 }
1367 
stbl_get_nearest_keyframe(struct stbl_t const * stbl,unsigned int sample)1368 extern unsigned int stbl_get_nearest_keyframe(struct stbl_t const* stbl,
1369                                               unsigned int sample)
1370 {
1371   // If the sync atom is not present, all samples are implicit sync samples.
1372   if(!stbl->stss_)
1373     return sample;
1374 
1375   return stss_get_nearest_keyframe(stbl->stss_, sample);
1376 }
1377 
stsd_init()1378 extern stsd_t* stsd_init()
1379 {
1380   stsd_t* atom = (stsd_t*)malloc(sizeof(stsd_t));
1381   atom->version_ = 0;
1382   atom->flags_ = 0;
1383   atom->entries_ = 0;
1384   atom->sample_entries_ = 0;
1385 
1386   return atom;
1387 }
1388 
stsd_copy(stsd_t const * rhs)1389 extern stsd_t* stsd_copy(stsd_t const* rhs)
1390 {
1391   unsigned int i;
1392   struct stsd_t* atom = (struct stsd_t*)malloc(sizeof(struct stsd_t));
1393 
1394   atom->version_ = rhs->version_;
1395   atom->flags_ = rhs->flags_;
1396   atom->entries_ = rhs->entries_;
1397   atom->sample_entries_ =
1398     (sample_entry_t*)malloc(atom->entries_ * sizeof(sample_entry_t));
1399   for(i = 0; i != atom->entries_; ++i)
1400   {
1401     sample_entry_assign(&atom->sample_entries_[i], &rhs->sample_entries_[i]);
1402   }
1403 
1404   return atom;
1405 }
1406 
stsd_exit(struct stsd_t * atom)1407 extern void stsd_exit(struct stsd_t* atom)
1408 {
1409   unsigned int i;
1410   for(i = 0; i != atom->entries_; ++i)
1411   {
1412     sample_entry_t* sample_entry = &atom->sample_entries_[i];
1413     sample_entry_exit(sample_entry);
1414   }
1415   if(atom->sample_entries_)
1416   {
1417     free(atom->sample_entries_);
1418   }
1419   free(atom);
1420 }
1421 
video_sample_entry_init()1422 extern video_sample_entry_t* video_sample_entry_init()
1423 {
1424   video_sample_entry_t* video_sample_entry =
1425     (video_sample_entry_t*)malloc(sizeof(video_sample_entry_t));
1426 
1427   video_sample_entry->version_ = 0;
1428   video_sample_entry->revision_level_ = 0;
1429   video_sample_entry->vendor_ = 0;
1430   video_sample_entry->temporal_quality_ = 0;
1431   video_sample_entry->spatial_quality_ = 0;
1432   video_sample_entry->width_ = 0;
1433   video_sample_entry->height_ = 0;
1434   video_sample_entry->horiz_resolution_ = (72 << 16);
1435   video_sample_entry->vert_resolution_ = (72 << 16);
1436   video_sample_entry->data_size_ = 0;
1437   video_sample_entry->frame_count_ = 1;
1438   memset(video_sample_entry->compressor_name_, 0, 32);
1439   video_sample_entry->depth_ = 24;
1440   video_sample_entry->color_table_id_ = -1;
1441 
1442   return video_sample_entry;
1443 }
1444 
audio_sample_entry_init()1445 extern audio_sample_entry_t* audio_sample_entry_init()
1446 {
1447   audio_sample_entry_t* audio_sample_entry =
1448     (audio_sample_entry_t*)malloc(sizeof(audio_sample_entry_t));
1449 
1450   audio_sample_entry->version_ = 0;
1451   audio_sample_entry->revision_ = 0;
1452   audio_sample_entry->vendor_ = 0;
1453   audio_sample_entry->channel_count_ = 2;
1454   audio_sample_entry->sample_size_ = 16;
1455   audio_sample_entry->compression_id_ = 0;
1456   audio_sample_entry->packet_size_ = 0;
1457   audio_sample_entry->samplerate_ = (0 << 16);
1458 
1459   return audio_sample_entry;
1460 }
1461 
sample_entry_init(sample_entry_t * sample_entry)1462 extern void sample_entry_init(sample_entry_t* sample_entry)
1463 {
1464   sample_entry->len_ = 0;
1465   sample_entry->buf_ = 0;
1466   sample_entry->codec_private_data_length_ = 0;
1467   sample_entry->codec_private_data_ = 0;
1468 
1469   sample_entry->video_= 0;
1470   sample_entry->audio_ = 0;
1471 //sample_entry->hint_ = 0;
1472 
1473   sample_entry->nal_unit_length_ = 0;
1474   sample_entry->sps_length_ = 0;
1475   sample_entry->sps_ = 0;
1476   sample_entry->pps_length_ = 0;
1477   sample_entry->pps_ = 0;
1478 
1479   sample_entry->wFormatTag = 0;
1480   sample_entry->nChannels = 2;
1481   sample_entry->nSamplesPerSec = 44100;
1482   sample_entry->nAvgBytesPerSec = 0;
1483   sample_entry->nBlockAlign = 0;
1484   sample_entry->wBitsPerSample = 16;
1485 
1486   sample_entry->max_bitrate_ = 0;
1487   sample_entry->avg_bitrate_ = 0;
1488 }
1489 
sample_entry_assign(sample_entry_t * lhs,sample_entry_t const * rhs)1490 extern void sample_entry_assign(sample_entry_t* lhs, sample_entry_t const* rhs)
1491 {
1492   memcpy(lhs, rhs, sizeof(sample_entry_t));
1493   if(rhs->buf_ != NULL)
1494   {
1495     lhs->buf_ = (unsigned char*)malloc(rhs->len_);
1496     memcpy(lhs->buf_, rhs->buf_, rhs->len_);
1497   }
1498 }
1499 
sample_entry_exit(sample_entry_t * sample_entry)1500 extern void sample_entry_exit(sample_entry_t* sample_entry)
1501 {
1502   if(sample_entry->buf_)
1503   {
1504     free(sample_entry->buf_);
1505   }
1506 
1507   if(sample_entry->video_)
1508   {
1509     free(sample_entry->video_);
1510   }
1511   if(sample_entry->audio_)
1512   {
1513     free(sample_entry->audio_);
1514   }
1515 }
1516 
1517 static const uint32_t aac_samplerates[] =
1518 {
1519   96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
1520   16000, 12000, 11025,  8000,  7350,     0,     0,     0
1521 };
1522 
1523 static const uint32_t aac_channels[] =
1524 {
1525   0, 1, 2, 3, 4, 5, 6, 8,
1526   0, 0, 0, 0, 0, 0, 0, 0
1527 };
1528 
mp4_samplerate_to_index(unsigned int samplerate)1529 static int mp4_samplerate_to_index(unsigned int samplerate)
1530 {
1531   unsigned int i;
1532   for(i = 0; i != 13; ++i)
1533   {
1534     if(aac_samplerates[i] == samplerate)
1535       return i;
1536   }
1537   return 4;
1538 }
1539 
1540 // Create an ADTS frame header
sample_entry_get_adts(sample_entry_t const * sample_entry,unsigned int sample_size,uint8_t * buf)1541 extern void sample_entry_get_adts(sample_entry_t const* sample_entry,
1542                                   unsigned int sample_size, uint8_t* buf)
1543 {
1544   unsigned int syncword = 0xfff;
1545   unsigned int ID = 0; // MPEG-4
1546   unsigned int layer = 0;
1547   unsigned int protection_absent = 1;
1548   // 0 = Main profile AAC MAIN
1549   // 1 = Low Complexity profile (LC) AAC LC
1550   // 2 = Scalable Sample Rate profile (SSR) AAC SSR
1551   // 3 = (reserved) AAC LTP
1552   unsigned int profile = 1;
1553   unsigned int sampling_frequency_index =
1554     mp4_samplerate_to_index(sample_entry->nSamplesPerSec);
1555   unsigned int private_bit = 0;
1556   unsigned int channel_configuration = sample_entry->nChannels;
1557   unsigned int original_copy = 0;
1558   unsigned int home = 0;
1559   unsigned int copyright_identification_bit = 0;
1560   unsigned int copyright_identification_start = 0;
1561   unsigned int aac_frame_length = 7 + sample_size;
1562   unsigned int adts_buffer_fullness = 0x7ff;
1563   unsigned int no_raw_data_blocks_in_frame = 0;
1564   unsigned char buffer[8];
1565 
1566   uint64_t adts = 0;
1567   adts = (adts << 12) | syncword;
1568   adts = (adts << 1) | ID;
1569   adts = (adts << 2) | layer;
1570   adts = (adts << 1) | protection_absent;
1571   adts = (adts << 2) | profile;
1572   adts = (adts << 4) | sampling_frequency_index;
1573   adts = (adts << 1) | private_bit;
1574   adts = (adts << 3) | channel_configuration;
1575   adts = (adts << 1) | original_copy;
1576   adts = (adts << 1) | home;
1577   adts = (adts << 1) | copyright_identification_bit;
1578   adts = (adts << 1) | copyright_identification_start;
1579   adts = (adts << 13) | aac_frame_length;
1580   adts = (adts << 11) | adts_buffer_fullness;
1581   adts = (adts << 2) | no_raw_data_blocks_in_frame;
1582 
1583   write_64(buffer, adts);
1584 
1585   memcpy(buf, buffer + 1, 7);
1586 }
1587 
stts_init()1588 extern stts_t* stts_init()
1589 {
1590   stts_t* atom = (stts_t*)malloc(sizeof(stts_t));
1591   atom->version_ = 0;
1592   atom->flags_ = 0;
1593   atom->entries_ = 0;
1594   atom->table_ = 0;
1595 
1596   return atom;
1597 }
1598 
stts_exit(struct stts_t * atom)1599 extern void stts_exit(struct stts_t* atom)
1600 {
1601   if(atom->table_)
1602   {
1603     free(atom->table_);
1604   }
1605   free(atom);
1606 }
1607 
stts_get_sample(struct stts_t const * stts,uint64_t time)1608 extern unsigned int stts_get_sample(struct stts_t const* stts, uint64_t time)
1609 {
1610   unsigned int stts_index = 0;
1611   unsigned int stts_count;
1612 
1613   unsigned int ret = 0;
1614   uint64_t time_count = 0;
1615 
1616   for(; stts_index != stts->entries_; ++stts_index)
1617   {
1618     unsigned int sample_count = stts->table_[stts_index].sample_count_;
1619     unsigned int sample_duration = stts->table_[stts_index].sample_duration_;
1620     if(time_count + (uint64_t)sample_duration * (uint64_t)sample_count >= time)
1621     {
1622       stts_count = (unsigned int)((time - time_count + sample_duration - 1) / sample_duration);
1623       time_count += (uint64_t)stts_count * (uint64_t)sample_duration;
1624       ret += stts_count;
1625       break;
1626     }
1627     else
1628     {
1629       time_count += (uint64_t)sample_duration * (uint64_t)sample_count;
1630       ret += sample_count;
1631     }
1632   }
1633   return ret;
1634 }
1635 
stts_get_time(struct stts_t const * stts,unsigned int sample)1636 extern uint64_t stts_get_time(struct stts_t const* stts, unsigned int sample)
1637 {
1638   uint64_t ret = 0;
1639   unsigned int stts_index = 0;
1640   unsigned int sample_count = 0;
1641 
1642   for(;;)
1643   {
1644     unsigned int table_sample_count = stts->table_[stts_index].sample_count_;
1645     unsigned int table_sample_duration = stts->table_[stts_index].sample_duration_;
1646     if(sample_count + table_sample_count > sample)
1647     {
1648       unsigned int stts_count = (sample - sample_count);
1649       ret += (uint64_t)stts_count * (uint64_t)table_sample_duration;
1650       break;
1651     }
1652     else
1653     {
1654       sample_count += table_sample_count;
1655       ret += (uint64_t)table_sample_count * (uint64_t)table_sample_duration;
1656       stts_index++;
1657     }
1658   }
1659   return ret;
1660 }
1661 
stts_get_duration(struct stts_t const * stts)1662 extern uint64_t stts_get_duration(struct stts_t const* stts)
1663 {
1664   uint64_t duration = 0;
1665   unsigned int i;
1666   for(i = 0; i != stts->entries_; ++i)
1667   {
1668     unsigned int sample_count = stts->table_[i].sample_count_;
1669     unsigned int sample_duration = stts->table_[i].sample_duration_;
1670     duration += (uint64_t)sample_duration * (uint64_t)sample_count;
1671   }
1672 
1673   return duration;
1674 }
1675 
stts_get_samples(struct stts_t const * stts)1676 extern unsigned int stts_get_samples(struct stts_t const* stts)
1677 {
1678   unsigned int samples = 0;
1679   unsigned int entries = stts->entries_;
1680   unsigned int i;
1681   for(i = 0; i != entries; ++i)
1682   {
1683     unsigned int sample_count = stts->table_[i].sample_count_;
1684 //  unsigned int sample_duration = stts->table_[i].sample_duration_;
1685     samples += sample_count;
1686   }
1687 
1688   return samples;
1689 }
1690 
stss_init()1691 extern struct stss_t* stss_init()
1692 {
1693   stss_t* atom = (stss_t*)malloc(sizeof(stss_t));
1694   atom->version_ = 0;
1695   atom->flags_ = 0;
1696   atom->entries_ = 0;
1697   atom->sample_numbers_ = 0;
1698 
1699   return atom;
1700 }
1701 
stss_exit(struct stss_t * atom)1702 extern void stss_exit(struct stss_t* atom)
1703 {
1704   if(atom->sample_numbers_)
1705   {
1706     free(atom->sample_numbers_);
1707   }
1708   free(atom);
1709 }
1710 
stss_get_nearest_keyframe(struct stss_t const * stss,unsigned int sample)1711 extern unsigned int stss_get_nearest_keyframe(struct stss_t const* stss,
1712                                               unsigned int sample)
1713 {
1714   // scan the sync samples to find the key frame that precedes the sample number
1715   unsigned int i;
1716   unsigned int table_sample = 0;
1717   for(i = 0; i != stss->entries_; ++i)
1718   {
1719     table_sample = stss->sample_numbers_[i];
1720     if(table_sample >= sample)
1721       break;
1722   }
1723   if(table_sample == sample)
1724     return table_sample;
1725   else
1726     return stss->sample_numbers_[i - 1];
1727 }
1728 
stsc_init()1729 extern stsc_t* stsc_init()
1730 {
1731   stsc_t* atom = (stsc_t*)malloc(sizeof(stsc_t));
1732 
1733   atom->version_ = 0;
1734   atom->flags_ = 0;
1735   atom->entries_ = 0;
1736   atom->table_ = 0;
1737 
1738   return atom;
1739 }
1740 
stsc_exit(struct stsc_t * atom)1741 extern void stsc_exit(struct stsc_t* atom)
1742 {
1743   if(atom->table_)
1744   {
1745     free(atom->table_);
1746   }
1747   free(atom);
1748 }
1749 
stsz_init()1750 extern stsz_t* stsz_init()
1751 {
1752   stsz_t* atom = (stsz_t*)malloc(sizeof(stsz_t));
1753 
1754   atom->version_ = 0;
1755   atom->flags_ = 0;
1756   atom->sample_size_ = 0;
1757   atom->entries_ = 0;
1758   atom->sample_sizes_ = 0;
1759 
1760   return atom;
1761 }
1762 
stsz_exit(struct stsz_t * atom)1763 extern void stsz_exit(struct stsz_t* atom)
1764 {
1765   if(atom->sample_sizes_)
1766   {
1767     free(atom->sample_sizes_);
1768   }
1769   free(atom);
1770 }
1771 
stco_init()1772 extern stco_t* stco_init()
1773 {
1774   stco_t* atom = (stco_t*)malloc(sizeof(stco_t));
1775 
1776   atom->version_ = 0;
1777   atom->flags_ = 0;
1778   atom->entries_ = 0;
1779   atom->chunk_offsets_ = 0;
1780 
1781   return atom;
1782 }
1783 
stco_exit(stco_t * atom)1784 extern void stco_exit(stco_t* atom)
1785 {
1786   if(atom->chunk_offsets_)
1787   {
1788     free(atom->chunk_offsets_);
1789   }
1790   free(atom);
1791 }
1792 
1793 #if 0
1794 extern void stco_shift_offsets(stco_t* stco, int offset)
1795 {
1796   unsigned int i;
1797   for(i = 0; i != stco->entries_; ++i)
1798     stco->chunk_offsets_[i] += offset;
1799 }
1800 #endif
1801 
ctts_init()1802 extern struct ctts_t* ctts_init()
1803 {
1804   struct ctts_t* atom = (struct ctts_t*)malloc(sizeof(struct ctts_t));
1805   atom->version_ = 0;
1806   atom->flags_ = 0;
1807   atom->entries_ = 0;
1808   atom->table_ = 0;
1809 
1810   return atom;
1811 }
1812 
ctts_exit(struct ctts_t * atom)1813 extern void ctts_exit(struct ctts_t* atom)
1814 {
1815   if(atom->table_)
1816   {
1817     free(atom->table_);
1818   }
1819   free(atom);
1820 }
1821 
ctts_get_samples(struct ctts_t const * ctts)1822 extern unsigned int ctts_get_samples(struct ctts_t const* ctts)
1823 {
1824   unsigned int samples = 0;
1825   unsigned int entries = ctts->entries_;
1826   unsigned int i;
1827   for(i = 0; i != entries; ++i)
1828   {
1829     unsigned int sample_count = ctts->table_[i].sample_count_;
1830 //  unsigned int sample_offset = ctts->table_[i].sample_offset_;
1831     samples += sample_count;
1832   }
1833 
1834   return samples;
1835 }
1836 
moov_time_to_trak_time(uint64_t t,long moov_time_scale,long trak_time_scale)1837 extern uint64_t moov_time_to_trak_time(uint64_t t, long moov_time_scale,
1838                                        long trak_time_scale)
1839 {
1840   return t * (uint64_t)trak_time_scale / moov_time_scale;
1841 }
1842 
trak_time_to_moov_time(uint64_t t,long moov_time_scale,long trak_time_scale)1843 extern uint64_t trak_time_to_moov_time(uint64_t t, long moov_time_scale,
1844                                        long trak_time_scale)
1845 {
1846   return t * (uint64_t)moov_time_scale / trak_time_scale;
1847 }
1848 
mvex_init()1849 extern mvex_t* mvex_init()
1850 {
1851   mvex_t* mvex = (mvex_t*)malloc(sizeof(mvex_t));
1852   mvex->unknown_atoms_ = 0;
1853   mvex->tracks_ = 0;
1854 
1855   return mvex;
1856 }
1857 
mvex_exit(mvex_t * atom)1858 extern void mvex_exit(mvex_t* atom)
1859 {
1860   unsigned int i;
1861   if(atom->unknown_atoms_)
1862   {
1863     unknown_atom_exit(atom->unknown_atoms_);
1864   }
1865   for(i = 0; i != atom->tracks_; ++i)
1866   {
1867     trex_exit(atom->trexs_[i]);
1868   }
1869   free(atom);
1870 }
1871 
trex_init()1872 extern trex_t* trex_init()
1873 {
1874   trex_t* trex = (trex_t*)malloc(sizeof(trex_t));
1875 
1876   trex->version_ = 0;
1877   trex->flags_ = 0;
1878   trex->track_id_ = 0;
1879   trex->default_sample_description_index_ = 0;
1880   trex->default_sample_duration_ = 0;
1881   trex->default_sample_size_ = 0;
1882   trex->default_sample_flags_ = 0;
1883 
1884   return trex;
1885 }
1886 
trex_exit(trex_t * atom)1887 extern void trex_exit(trex_t* atom)
1888 {
1889   free(atom);
1890 }
1891 
moof_init()1892 extern moof_t* moof_init()
1893 {
1894   struct moof_t* moof = (struct moof_t*)malloc(sizeof(struct moof_t));
1895   moof->unknown_atoms_ = 0;
1896   moof->mfhd_ = 0;
1897   moof->tracks_ = 0;
1898 
1899   return moof;
1900 }
1901 
moof_exit(struct moof_t * atom)1902 extern void moof_exit(struct moof_t* atom)
1903 {
1904   unsigned int i;
1905   if(atom->unknown_atoms_)
1906   {
1907     unknown_atom_exit(atom->unknown_atoms_);
1908   }
1909   if(atom->mfhd_)
1910   {
1911     mfhd_exit(atom->mfhd_);
1912   }
1913   for(i = 0; i != atom->tracks_; ++i)
1914   {
1915     traf_exit(atom->trafs_[i]);
1916   }
1917   free(atom);
1918 }
1919 
mfhd_init()1920 extern mfhd_t* mfhd_init()
1921 {
1922   mfhd_t* mfhd = (mfhd_t*)malloc(sizeof(mfhd_t));
1923   mfhd->version_ = 0;
1924   mfhd->flags_ = 0;
1925   mfhd->sequence_number_ = 0;
1926 
1927   return mfhd;
1928 }
1929 
mfhd_exit(mfhd_t * atom)1930 extern void mfhd_exit(mfhd_t* atom)
1931 {
1932   free(atom);
1933 }
1934 
traf_init()1935 extern traf_t* traf_init()
1936 {
1937   traf_t* traf = (traf_t*)malloc(sizeof(traf_t));
1938   traf->unknown_atoms_ = 0;
1939   traf->tfhd_ = 0;
1940   traf->trun_ = 0;
1941   traf->uuid0_ = 0;
1942   traf->uuid1_ = 0;
1943 
1944   return traf;
1945 }
1946 
traf_exit(traf_t * atom)1947 extern void traf_exit(traf_t* atom)
1948 {
1949   if(atom->unknown_atoms_)
1950   {
1951     unknown_atom_exit(atom->unknown_atoms_);
1952   }
1953   if(atom->tfhd_)
1954   {
1955     tfhd_exit(atom->tfhd_);
1956   }
1957   if(atom->trun_)
1958   {
1959     trun_t* trun = atom->trun_;
1960     while(trun)
1961     {
1962       trun_t* next = trun->next_;
1963       trun_exit(trun);
1964       trun = next;
1965     }
1966   }
1967   if(atom->uuid0_)
1968   {
1969     uuid0_exit(atom->uuid0_);
1970   }
1971   if(atom->uuid1_)
1972   {
1973     uuid1_exit(atom->uuid1_);
1974   }
1975   free(atom);
1976 }
1977 
tfhd_init()1978 extern tfhd_t* tfhd_init()
1979 {
1980   tfhd_t* tfhd = (tfhd_t*)malloc(sizeof(tfhd_t));
1981 
1982   tfhd->version_ = 0;
1983   tfhd->flags_ = 0;
1984 
1985   return tfhd;
1986 }
1987 
tfhd_exit(tfhd_t * atom)1988 extern void tfhd_exit(tfhd_t* atom)
1989 {
1990   free(atom);
1991 }
1992 
tfra_init()1993 extern tfra_t* tfra_init()
1994 {
1995   tfra_t* tfra = (tfra_t*)malloc(sizeof(tfra_t));
1996   tfra->table_ = 0;
1997 
1998   return tfra;
1999 }
2000 
tfra_exit(tfra_t * tfra)2001 extern void tfra_exit(tfra_t* tfra)
2002 {
2003   if(tfra->table_)
2004   {
2005     free(tfra->table_);
2006   }
2007   free(tfra);
2008 }
2009 
tfra_add(tfra_t * tfra,tfra_table_t const * table)2010 extern void tfra_add(tfra_t* tfra, tfra_table_t const* table)
2011 {
2012   tfra_table_t* tfra_table;
2013 
2014   // allocate one more entry
2015   tfra->table_ = (tfra_table_t*)
2016     realloc(tfra->table_, (tfra->number_of_entry_ + 1) * sizeof(tfra_table_t));
2017 
2018   tfra_table = &tfra->table_[tfra->number_of_entry_];
2019 
2020   tfra_table->time_ = table->time_;
2021   tfra_table->moof_offset_ = table->moof_offset_;
2022   tfra_table->traf_number_ = table->traf_number_;
2023   tfra_table->trun_number_ = table->trun_number_;
2024   tfra_table->sample_number_ = table->sample_number_;
2025   ++tfra->number_of_entry_;
2026 }
2027 
mfra_init()2028 extern mfra_t* mfra_init()
2029 {
2030   mfra_t* mfra = (mfra_t*)malloc(sizeof(mfra_t));
2031   mfra->unknown_atoms_ = 0;
2032   mfra->tracks_ = 0;
2033 
2034   return mfra;
2035 }
2036 
mfra_exit(mfra_t * atom)2037 extern void mfra_exit(mfra_t* atom)
2038 {
2039   unsigned int i;
2040   if(atom->unknown_atoms_)
2041   {
2042     unknown_atom_exit(atom->unknown_atoms_);
2043   }
2044   for(i = 0; i != atom->tracks_; ++i)
2045   {
2046     tfra_exit(atom->tfras_[i]);
2047   }
2048   free(atom);
2049 }
2050 
trun_init()2051 extern trun_t* trun_init()
2052 {
2053   trun_t* trun = (trun_t*)malloc(sizeof(trun_t));
2054   trun->version_ = 0;
2055   trun->flags_ = 0;
2056   trun->sample_count_ = 0;
2057   trun->data_offset_ = 0;
2058   trun->first_sample_flags_ = 0;
2059   trun->table_ = 0;
2060   trun->next_ = 0;
2061 
2062   return trun;
2063 }
2064 
trun_exit(struct trun_t * atom)2065 extern void trun_exit(struct trun_t* atom)
2066 {
2067   if(atom->table_)
2068   {
2069     free(atom->table_);
2070   }
2071   free(atom);
2072 }
2073 
uuid0_init()2074 extern uuid0_t* uuid0_init()
2075 {
2076   uuid0_t* uuid = (uuid0_t*)malloc(sizeof(uuid0_t));
2077 
2078   uuid->pts_ = 0;
2079   uuid->duration_ = 0;
2080 
2081   return uuid;
2082 }
2083 
uuid0_exit(uuid0_t * atom)2084 extern void uuid0_exit(uuid0_t* atom)
2085 {
2086   free(atom);
2087 }
2088 
uuid1_init()2089 extern uuid1_t* uuid1_init()
2090 {
2091   unsigned int i;
2092   uuid1_t* uuid = (uuid1_t*)malloc(sizeof(uuid1_t));
2093   uuid->entries_ = 0;
2094   for(i = 0; i != 2; ++i)
2095   {
2096     uuid->pts_[i] = 0;
2097     uuid->duration_[i] = 0;
2098   }
2099 
2100   return uuid;
2101 }
2102 
uuid1_exit(uuid1_t * atom)2103 extern void uuid1_exit(uuid1_t* atom)
2104 {
2105   free(atom);
2106 }
2107 
2108 // End Of File
2109 
2110