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