system: Linux mars.sprixweb.com 3.10.0-1160.119.1.el7.x86_64 #1 SMP Tue Jun 4 14:43:51 UTC 2024 x86_64
/*******************************************************************************
mp4_io.c - A library for general MPEG4 I/O.
Copyright (C) 2007-2009 CodeShop B.V.
http://www.code-shop.com
For licensing see the LICENSE file
******************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef __cplusplus
#define __STDC_FORMAT_MACROS // C++ should define this for PRIu64
#define __STDC_LIMIT_MACROS // C++ should define this for UINT32_MAX
#endif
#include "mp4_io.h"
#include "mp4_reader.h" // for moov_read
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h> // FreeBSD doesn't define off_t in stdio.h
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#ifdef WIN32
#include <io.h>
#include <windows.h>
#define DIR_SEPARATOR '\\'
#define strdup _strdup
#define open _open
#define close _close
#define write _write
#define lseek _lseeki64
#define stat _stat64
#else
#define DIR_SEPARATOR '/'
#include <unistd.h>
#include <sys/mman.h>
#endif
extern uint64_t atoi64(const char* val)
{
#ifdef WIN32
return _atoi64(val);
#else // elif defined(HAVE_STRTOLL)
return strtoll(val, NULL, 10);
#endif
}
extern const char* remove_path(const char *path)
{
const char* p = strrchr(path, DIR_SEPARATOR);
if(p != NULL && *p != '\0')
{
return p + 1;
}
return path;
}
extern void mp4_log_trace(const char* fmt, ...)
{
va_list arglist;
va_start(arglist, fmt);
vprintf(fmt, arglist);
va_end(arglist);
}
static int64_t seconds_since_1970(void)
{
// #ifdef WIN32
return time(NULL);
// #else
// struct timeval tv;
// gettimeofday(&tv, NULL);
// return 1000000 * (int64_t)tv.tv_sec + tv.tv_usec;
// #endif
}
static int64_t seconds_since_1904(void)
{
return seconds_since_1970() + 2082844800;
}
extern unsigned int read_8(unsigned char const* buffer)
{
return buffer[0];
}
extern unsigned char* write_8(unsigned char* buffer, unsigned int v)
{
buffer[0] = (uint8_t)v;
return buffer + 1;
}
extern uint16_t read_16(unsigned char const* buffer)
{
return (buffer[0] << 8) |
(buffer[1] << 0);
}
extern unsigned char* write_16(unsigned char* buffer, unsigned int v)
{
buffer[0] = (uint8_t)(v >> 8);
buffer[1] = (uint8_t)(v >> 0);
return buffer + 2;
}
extern unsigned int read_24(unsigned char const* buffer)
{
return (buffer[0] << 16) |
(buffer[1] << 8) |
(buffer[2] << 0);
}
extern unsigned char* write_24(unsigned char* buffer, unsigned int v)
{
buffer[0] = (uint8_t)(v >> 16);
buffer[1] = (uint8_t)(v >> 8);
buffer[2] = (uint8_t)(v >> 0);
return buffer + 3;
}
extern uint32_t read_32(unsigned char const* buffer)
{
return (buffer[0] << 24) |
(buffer[1] << 16) |
(buffer[2] << 8) |
(buffer[3] << 0);
}
extern unsigned char* write_32(unsigned char* buffer, uint32_t v)
{
buffer[0] = (uint8_t)(v >> 24);
buffer[1] = (uint8_t)(v >> 16);
buffer[2] = (uint8_t)(v >> 8);
buffer[3] = (uint8_t)(v >> 0);
return buffer + 4;
}
extern uint64_t read_64(unsigned char const* buffer)
{
return ((uint64_t)(read_32(buffer)) << 32) + read_32(buffer + 4);
}
extern unsigned char* write_64(unsigned char* buffer, uint64_t v)
{
write_32(buffer + 0, (uint32_t)(v >> 32));
write_32(buffer + 4, (uint32_t)(v >> 0));
return buffer + 8;
}
extern uint32_t read_n(unsigned char const* buffer, unsigned int n)
{
switch(n)
{
case 8:
return read_8(buffer);
case 16:
return read_16(buffer);
case 24:
return read_24(buffer);
case 32:
return read_32(buffer);
default:
// program error
return 0;
}
}
extern unsigned char* write_n(unsigned char* buffer, unsigned int n, uint32_t v)
{
switch(n)
{
case 8:
return write_8(buffer, v);
case 16:
return write_16(buffer, v);
case 24:
return write_24(buffer, v);
case 32:
return write_32(buffer, v);
}
return NULL;
}
static unsigned int alignment()
{
#ifdef _WIN32
SYSTEM_INFO SysInfo;
GetSystemInfo(&SysInfo);
return (unsigned int)(SysInfo.dwAllocationGranularity);
#else
return (unsigned int)(getpagesize());
#endif
}
static mem_range_t* mem_range_init(char const* filename, int read_only,
uint64_t filesize,
uint64_t offset, uint64_t len)
{
mem_range_t* mem_range = (mem_range_t*)malloc(sizeof(mem_range_t));
mem_range->read_only_ = read_only;
mem_range->filesize_ = filesize;
mem_range->fd_ = -1;
mem_range->mmap_addr_ = 0;
mem_range->mmap_offset_ = 0;
mem_range->mmap_size_ = 0;
#ifdef WIN32
mem_range->fileMapHandle_ = NULL;
#endif
mem_range->fd_ = open(filename, read_only ? O_RDONLY : (O_RDWR | O_CREAT),
#ifdef WIN32
S_IREAD | S_IWRITE
#else
0666
#endif
);
if(mem_range->fd_ == -1)
{
printf("mem_range: Error opening file %s\n", filename);
mem_range_exit(mem_range);
return 0;
}
if(!read_only)
{
// shrink the file (if necessary)
if(offset + len < filesize)
{
int result;
#ifdef WIN32
lseek(mem_range->fd_, offset + len, SEEK_SET);
result =
SetEndOfFile((HANDLE)_get_osfhandle(mem_range->fd_)) == 0 ? -1 : 0;
#else
result = truncate(filename, offset + len);
#endif
if(result < 0)
{
printf("mem_range: Error shrinking file %s\n", filename);
mem_range_exit(mem_range);
return 0;
}
}
// stretch the file (if necessary)
else if(offset + len > filesize)
{
lseek(mem_range->fd_, offset + len - 1, SEEK_SET);
if(write(mem_range->fd_, "", 1) < 0)
{
printf("mem_range: Error stretching file %s\n", filename);
mem_range_exit(mem_range);
return 0;
}
}
mem_range->filesize_ = offset + len;
}
#ifdef _WIN32
{
HANDLE hFile = (HANDLE)_get_osfhandle(mem_range->fd_);
if(!hFile)
{
printf("%s", "Cannot create file mapping\n");
mem_range_exit(mem_range);
return 0;
}
mem_range->fileMapHandle_ = CreateFileMapping(hFile, 0,
read_only ? PAGE_READONLY : PAGE_READWRITE, 0, 0, NULL);
if(!mem_range->fileMapHandle_)
{
printf("%s", "Cannot create file mapping view\n");
mem_range_exit(mem_range);
return 0;
}
}
#endif
return mem_range;
}
mem_range_t* mem_range_init_read(char const* filename)
{
int read_only = 1;
uint64_t offset = 0;
struct stat status;
// make sure regular file exists and its not empty (can't mmap 0 bytes)
if(stat(filename, &status) ||
(status.st_mode & S_IFMT) != S_IFREG ||
status.st_size == 0)
{
return 0;
}
return mem_range_init(filename, read_only, status.st_size,
offset, status.st_size);
}
mem_range_t* mem_range_init_write(char const* filename,
uint64_t offset, uint64_t len)
{
int read_only = 0;
uint64_t filesize = 0;
struct stat status;
if(!stat(filename, &status))
{
filesize = status.st_size;
}
return mem_range_init(filename, read_only, filesize, offset, len);
}
void* mem_range_map(mem_range_t* mem_range, uint64_t offset, uint32_t len)
{
// only map when necessary
if(offset < mem_range->mmap_offset_ ||
offset + len >= mem_range->mmap_offset_ + mem_range->mmap_size_)
{
// use 1MB of overlap, so a little random access is okay at the end of the
// memory mapped file.
const unsigned int overlap = 1024 * 1024;
const unsigned int window_size = 16 * 1024 * 1024;
unsigned int dwSysGran = alignment();
uint64_t mmap_offset = offset > overlap ? (offset - overlap) : 0;
len += offset > overlap ? overlap : (uint32_t)offset;
// uint64_t mmap_offset = offset;
mem_range->mmap_offset_ = (mmap_offset / dwSysGran) * dwSysGran;
mem_range->mmap_size_ = (mmap_offset % dwSysGran) + len;
if(mem_range->mmap_offset_ + mem_range->mmap_size_ > mem_range->filesize_)
{
printf("%s", "mem_range_map: invalid range for file mapping\n");
return 0;
}
if(mem_range->mmap_size_ < window_size)
{
mem_range->mmap_size_ = window_size;
}
if(mem_range->mmap_offset_ + mem_range->mmap_size_ > mem_range->filesize_)
{
mem_range->mmap_size_ = mem_range->filesize_ - mem_range->mmap_offset_;
}
// printf("mem_range(%x): offset=%"PRIu64"\n", mem_range, offset);
#ifdef WIN32
if(mem_range->mmap_addr_)
{
UnmapViewOfFile(mem_range->mmap_addr_);
}
mem_range->mmap_addr_ = MapViewOfFile(mem_range->fileMapHandle_,
mem_range->read_only_ ? FILE_MAP_READ : FILE_MAP_WRITE,
mem_range->mmap_offset_ >> 32, (uint32_t)(mem_range->mmap_offset_),
(size_t)(mem_range->mmap_size_));
if(!mem_range->mmap_addr_)
{
printf("%s", "Unable to make file mapping\n");
return 0;
}
#else
if(mem_range->mmap_addr_)
{
munmap(mem_range->mmap_addr_, mem_range->mmap_size_);
}
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_);
if(mem_range->mmap_addr_ == MAP_FAILED)
{
printf("%s", "Unable to make file mapping\n");
return 0;
}
if(mem_range->read_only_ &&
madvise(mem_range->mmap_addr_, mem_range->mmap_size_, MADV_SEQUENTIAL) < 0)
{
printf("%s", "Unable to advise file mapping\n");
// continue
}
#endif
}
return (char*)mem_range->mmap_addr_ + (offset - mem_range->mmap_offset_);
}
void mem_range_exit(mem_range_t* mem_range)
{
if(!mem_range)
{
return;
}
#ifdef WIN32
CloseHandle(mem_range->fileMapHandle_);
#endif
if(mem_range->mmap_addr_)
{
#ifdef WIN32
UnmapViewOfFile(mem_range->mmap_addr_);
#else
munmap(mem_range->mmap_addr_, mem_range->mmap_size_);
#endif
}
if(mem_range->fd_ != -1)
{
close(mem_range->fd_);
}
free(mem_range);
}
extern int mp4_atom_read_header(mp4_context_t const* mp4_context,
FILE* infile, mp4_atom_t* atom)
{
unsigned char atom_header[8];
atom->start_ = ftello(infile);
if(fread(atom_header, 8, 1, infile) != 1)
{
MP4_ERROR("%s", "Error reading atom header\n");
return 0;
}
atom->short_size_ = read_32(&atom_header[0]);
atom->type_ = read_32(&atom_header[4]);
if(atom->short_size_ == 1)
{
if(fread(atom_header, 8, 1, infile) != 1)
{
MP4_ERROR("%s", "Error reading extended atom header\n");
return 0;
}
atom->size_ = read_64(&atom_header[0]);
}
else
{
atom->size_ = atom->short_size_;
}
atom->end_ = atom->start_ + atom->size_;
MP4_INFO("Atom(%c%c%c%c,%"PRIu64")\n",
atom->type_ >> 24, atom->type_ >> 16,
atom->type_ >> 8, atom->type_,
atom->size_);
if(atom->size_ < ATOM_PREAMBLE_SIZE)
{
MP4_ERROR("%s", "Error: invalid atom size\n");
return 0;
}
return 1;
}
extern int mp4_atom_write_header(unsigned char* outbuffer,
mp4_atom_t const* atom)
{
int write_box64 = atom->short_size_ == 1 ? 1 : 0;
if(write_box64)
write_32(outbuffer, 1);
else
write_32(outbuffer, (uint32_t)atom->size_);
write_32(outbuffer + 4, atom->type_);
if(write_box64)
{
write_64(outbuffer + 8, atom->size_);
return 16;
}
else
{
return 8;
}
}
static unsigned char* read_box(struct mp4_context_t* mp4_context,
FILE* infile, struct mp4_atom_t* atom)
{
unsigned char* box_data = (unsigned char*)malloc((size_t)atom->size_);
fseeko(infile, atom->start_, SEEK_SET);
if(fread(box_data, (off_t)atom->size_, 1, infile) != 1)
{
MP4_ERROR("Error reading %c%c%c%c atom\n",
atom->type_ >> 24, atom->type_ >> 16,
atom->type_ >> 8, atom->type_);
free(box_data);
fclose(infile);
return 0;
}
return box_data;
}
static mp4_context_t* mp4_context_init(const char* filename, int verbose)
{
mp4_context_t* mp4_context = (mp4_context_t*)malloc(sizeof(mp4_context_t));
mp4_context->filename_ = strdup(filename);
mp4_context->infile = NULL;
mp4_context->verbose_ = verbose;
memset(&mp4_context->ftyp_atom, 0, sizeof(struct mp4_atom_t));
memset(&mp4_context->moov_atom, 0, sizeof(struct mp4_atom_t));
memset(&mp4_context->mdat_atom, 0, sizeof(struct mp4_atom_t));
memset(&mp4_context->mfra_atom, 0, sizeof(struct mp4_atom_t));
mp4_context->moov_data = 0;
mp4_context->mfra_data = 0;
mp4_context->moov = 0;
return mp4_context;
}
static void mp4_context_exit(struct mp4_context_t* mp4_context)
{
free(mp4_context->filename_);
if(mp4_context->infile)
{
fclose(mp4_context->infile);
}
if(mp4_context->moov_data)
{
free(mp4_context->moov_data);
}
if(mp4_context->mfra_data)
{
free(mp4_context->mfra_data);
}
if(mp4_context->moov)
{
moov_exit(mp4_context->moov);
}
free(mp4_context);
}
extern mp4_context_t* mp4_open(const char* filename, int64_t filesize,
mp4_open_flags flags, int verbose)
{
mp4_context_t* mp4_context = mp4_context_init(filename, verbose);
mp4_context->infile = fopen(filename, "rb");
if(mp4_context->infile == NULL)
{
mp4_context_exit(mp4_context);
return 0;
}
// fast-open if we're only interested in the mfra atom
if(flags == MP4_OPEN_MFRA)
{
unsigned char mfro[16];
fseeko(mp4_context->infile, -16, SEEK_END);
if(fread(mfro, 16, 1, mp4_context->infile) != 1)
{
MP4_ERROR("%s", "Error reading mfro header\n");
fseeko(mp4_context->infile, 0, SEEK_SET);
}
else
{
if(read_32(mfro + 4) != FOURCC('m', 'f', 'r', 'o'))
{
MP4_ERROR("%s", "Error parsing mfro header\n");
fseeko(mp4_context->infile, 0, SEEK_SET);
}
else
{
off_t mfra_size = read_32(mfro + 12);
fseeko(mp4_context->infile, -mfra_size, SEEK_END);
}
}
}
while(ftello(mp4_context->infile) < filesize)
{
struct mp4_atom_t leaf_atom;
if(!mp4_atom_read_header(mp4_context, mp4_context->infile, &leaf_atom))
break;
switch(leaf_atom.type_)
{
case FOURCC('f', 't', 'y', 'p'):
mp4_context->ftyp_atom = leaf_atom;
break;
case FOURCC('m', 'o', 'o', 'v'):
mp4_context->moov_atom = leaf_atom;
mp4_context->moov_data = read_box(mp4_context, mp4_context->infile, &mp4_context->moov_atom);
if(mp4_context->moov_data == NULL)
{
mp4_context_exit(mp4_context);
return 0;
}
mp4_context->moov = (moov_t*)
moov_read(mp4_context, NULL,
mp4_context->moov_data + ATOM_PREAMBLE_SIZE,
mp4_context->moov_atom.size_ - ATOM_PREAMBLE_SIZE);
if(mp4_context->moov == 0 || mp4_context->moov->mvhd_ == 0)
{
MP4_ERROR("%s", "Error parsing moov header\n");
mp4_context_exit(mp4_context);
return 0;
}
break;
case FOURCC('m', 'o', 'o', 'f'):
{
moof_t* moof;
unsigned char* moof_data =
read_box(mp4_context, mp4_context->infile, &leaf_atom);
mp4_context->moof_offset_ = leaf_atom.start_;
#if 1
// Check for Expression Encoder file (missing mandatory stco)
if(mp4_context->moov != 0 &&
mp4_context->moov->tracks_ != 0 &&
mp4_context->moov->traks_[0]->mdia_->minf_->stbl_->stco_ == 0)
{
MP4_ERROR("%s", "Fixing invalid offsets for Expression Encoder file\n");
// Expression Encoder doesn't write a base_data_offset or data_offset.
// We patch the moof_offset_ to point to the mdat following the moof.
mp4_context->moof_offset_ += leaf_atom.size_ + ATOM_PREAMBLE_SIZE;
}
#endif
moof = (moof_t*)
moof_read(mp4_context, NULL,
moof_data + ATOM_PREAMBLE_SIZE,
leaf_atom.size_ - ATOM_PREAMBLE_SIZE);
free(moof_data);
if(moof == 0)
{
MP4_ERROR("%s", "Error parsing moof header\n");
mp4_context_exit(mp4_context);
return 0;
}
moof_exit(moof);
}
break;
case FOURCC('m', 'd', 'a', 't'):
mp4_context->mdat_atom = leaf_atom;
break;
case FOURCC('m', 'f', 'r', 'a'):
mp4_context->mfra_atom = leaf_atom;
mp4_context->mfra_data = read_box(mp4_context, mp4_context->infile, &mp4_context->mfra_atom);
if(mp4_context->mfra_data == NULL)
{
mp4_context_exit(mp4_context);
return 0;
}
break;
}
if(leaf_atom.end_ > (uint64_t)filesize)
{
MP4_ERROR("%s", "Reached end of file prematurely\n");
mp4_context_exit(mp4_context);
return 0;
}
fseeko(mp4_context->infile, leaf_atom.end_, SEEK_SET);
// short-circuit for mfra. We only need the mfra atom.
if((flags == MP4_OPEN_MOOV) && mp4_context->moov_atom.size_)
{
return mp4_context;
}
// short-circuit for mfra. We only need the mfra atom.
if((flags == MP4_OPEN_MFRA) && mp4_context->mfra_atom.size_)
{
return mp4_context;
}
}
if(mp4_context->moov == 0)
{
MP4_ERROR("%s", "Error: moov atom not found\n");
mp4_context_exit(mp4_context);
return 0;
}
if(mp4_context->mdat_atom.size_ == 0)
{
// or mdat atom
MP4_ERROR("%s", "Error: mdat atom not found\n");
mp4_context_exit(mp4_context);
return 0;
}
return mp4_context;
}
extern void mp4_close(struct mp4_context_t* mp4_context)
{
mp4_context_exit(mp4_context);
}
////////////////////////////////////////////////////////////////////////////////
extern struct unknown_atom_t* unknown_atom_init()
{
unknown_atom_t* atom = (unknown_atom_t*)malloc(sizeof(unknown_atom_t));
atom->atom_ = 0;
atom->next_ = 0;
return atom;
}
extern void unknown_atom_exit(unknown_atom_t* atom)
{
while(atom)
{
unknown_atom_t* next = atom->next_;
free(atom->atom_);
free(atom);
atom = next;
}
}
extern moov_t* moov_init()
{
moov_t* moov = (moov_t*)malloc(sizeof(moov_t));
moov->unknown_atoms_ = 0;
moov->mvhd_ = 0;
moov->tracks_ = 0;
moov->mvex_ = 0;
moov->is_indexed_ = 0;
return moov;
}
extern void moov_exit(moov_t* atom)
{
unsigned int i;
if(atom->unknown_atoms_)
{
unknown_atom_exit(atom->unknown_atoms_);
}
if(atom->mvhd_)
{
mvhd_exit(atom->mvhd_);
}
for(i = 0; i != atom->tracks_; ++i)
{
trak_exit(atom->traks_[i]);
}
if(atom->mvex_)
{
mvex_exit(atom->mvex_);
}
free(atom);
}
#if 0
extern void moov_shift_offsets(moov_t* moov, int64_t offset)
{
unsigned int i;
for(i = 0; i != moov->tracks_; ++i)
{
trak_shift_offsets(moov->traks_[i], offset);
}
}
#endif
extern trak_t* trak_init()
{
trak_t* trak = (trak_t*)malloc(sizeof(trak_t));
trak->unknown_atoms_ = 0;
trak->tkhd_ = 0;
trak->mdia_ = 0;
trak->edts_ = 0;
trak->chunks_size_ = 0;
trak->chunks_ = 0;
trak->samples_size_ = 0;
trak->samples_ = 0;
// trak->fragment_pts_ = 0;
return trak;
}
extern unsigned int trak_bitrate(trak_t const* trak)
{
long trak_time_scale = trak->mdia_->mdhd_->timescale_;
uint64_t duration;
unsigned int bps;
samples_t const* first = trak->samples_;
samples_t const* last = trak->samples_ + trak->samples_size_;
uint64_t sample_size = 0;
while(first != last)
{
sample_size += first->size_;
++first;
}
duration = first->pts_;
bps = (unsigned int)(sample_size * trak_time_scale / duration * 8);
return bps;
}
#if 0
extern void trak_shift_offsets(trak_t* trak, int64_t offset)
{
stco_t* stco = trak->mdia_->minf_->stbl_->stco_;
stco_shift_offsets(stco, (int32_t)offset);
}
#endif
extern void trak_exit(trak_t* trak)
{
if(trak->unknown_atoms_)
{
unknown_atom_exit(trak->unknown_atoms_);
}
if(trak->tkhd_)
{
tkhd_exit(trak->tkhd_);
}
if(trak->mdia_)
{
mdia_exit(trak->mdia_);
}
if(trak->edts_)
{
edts_exit(trak->edts_);
}
if(trak->chunks_)
{
free(trak->chunks_);
}
if(trak->samples_)
{
free(trak->samples_);
}
free(trak);
}
extern mvhd_t* mvhd_init()
{
unsigned int i;
mvhd_t* atom = (mvhd_t*)malloc(sizeof(mvhd_t));
atom->version_ = 1;
atom->flags_ = 0;
atom->creation_time_ =
atom->modification_time_ = seconds_since_1904();
atom->timescale_ = 10000000;
atom->duration_ = 0;
atom->rate_ = (1 << 16);
atom->volume_ = (1 << 8);
atom->reserved1_ = 0;
for(i = 0; i != 2; ++i)
{
atom->reserved2_[i] = 0;
}
for(i = 0; i != 9; ++i)
{
atom->matrix_[i] = 0;
}
atom->matrix_[0] = 0x00010000;
atom->matrix_[4] = 0x00010000;
atom->matrix_[8] = 0x40000000;
for(i = 0; i != 6; ++i)
{
atom->predefined_[i] = 0;
}
atom->next_track_id_ = 1;
return atom;
}
extern mvhd_t* mvhd_copy(mvhd_t const* rhs)
{
mvhd_t* atom = (mvhd_t*)malloc(sizeof(mvhd_t));
memcpy(atom, rhs, sizeof(mvhd_t));
return atom;
}
extern void mvhd_exit(mvhd_t* atom)
{
free(atom);
}
extern tkhd_t* tkhd_init()
{
unsigned int i;
tkhd_t* tkhd = (tkhd_t*)malloc(sizeof(tkhd_t));
tkhd->version_= 1;
tkhd->flags_ = 7; // track_enabled, track_in_movie, track_in_preview
tkhd->creation_time_ =
tkhd->modification_time_ = seconds_since_1904();
tkhd->track_id_ = 0;
tkhd->reserved_ = 0;
tkhd->duration_ = 0;
for(i = 0; i != 2; ++i)
{
tkhd->reserved2_[i] = 0;
}
tkhd->layer_ = 0;
tkhd->predefined_ = 0;
tkhd->volume_ = (1 << 8) + 0;
tkhd->reserved3_ = 0;
for(i = 0; i != 9; ++i)
{
tkhd->matrix_[i] = 0;
}
tkhd->matrix_[0] = 0x00010000;
tkhd->matrix_[4] = 0x00010000;
tkhd->matrix_[8] = 0x40000000;
tkhd->width_ = 0;
tkhd->height_ = 0;
return tkhd;
}
extern struct tkhd_t* tkhd_copy(tkhd_t const* rhs)
{
tkhd_t* tkhd = (tkhd_t*)malloc(sizeof(tkhd_t));
memcpy(tkhd, rhs, sizeof(tkhd_t));
return tkhd;
}
extern void tkhd_exit(tkhd_t* tkhd)
{
free(tkhd);
}
extern struct mdia_t* mdia_init()
{
mdia_t* atom = (mdia_t*)malloc(sizeof(mdia_t));
atom->unknown_atoms_ = 0;
atom->mdhd_ = 0;
atom->hdlr_ = 0;
atom->minf_ = 0;
return atom;
}
extern void mdia_exit(mdia_t* atom)
{
if(atom->unknown_atoms_)
{
unknown_atom_exit(atom->unknown_atoms_);
}
if(atom->mdhd_)
{
mdhd_exit(atom->mdhd_);
}
if(atom->hdlr_)
{
hdlr_exit(atom->hdlr_);
}
if(atom->minf_)
{
minf_exit(atom->minf_);
}
free(atom);
}
extern elst_t* elst_init()
{
elst_t* elst = (elst_t*)malloc(sizeof(elst_t));
elst->version_ = 1;
elst->flags_ = 0;
elst->entry_count_ = 0;
elst->table_ = 0;
return elst;
}
extern void elst_exit(elst_t* elst)
{
if(elst->table_)
{
free(elst->table_);
}
free(elst);
}
extern edts_t* edts_init()
{
edts_t* edts = (edts_t*)malloc(sizeof(edts_t));
edts->unknown_atoms_ = 0;
edts->elst_ = 0;
return edts;
}
extern void edts_exit(edts_t* edts)
{
if(edts->unknown_atoms_)
{
unknown_atom_exit(edts->unknown_atoms_);
}
if(edts->elst_)
{
elst_exit(edts->elst_);
}
free(edts);
}
extern mdhd_t* mdhd_init()
{
unsigned int i;
mdhd_t* mdhd = (mdhd_t*)malloc(sizeof(mdhd_t));
mdhd->version_ = 1;
mdhd->flags_ = 0;
mdhd->creation_time_ =
mdhd->modification_time_ = seconds_since_1904();
mdhd->timescale_ = 10000000;
mdhd->duration_ = 0;
for(i = 0; i != 3; ++i)
{
mdhd->language_[i] = 0x7f;
}
mdhd->predefined_ = 0;
return mdhd;
}
extern mdhd_t* mdhd_copy(mdhd_t const* rhs)
{
struct mdhd_t* mdhd = (struct mdhd_t*)malloc(sizeof(struct mdhd_t));
memcpy(mdhd, rhs, sizeof(mdhd_t));
return mdhd;
}
extern void mdhd_exit(struct mdhd_t* mdhd)
{
free(mdhd);
}
extern hdlr_t* hdlr_init()
{
hdlr_t* atom = (hdlr_t*)malloc(sizeof(hdlr_t));
atom->version_ = 0;
atom->flags_ = 0;
atom->predefined_ = 0;
atom->handler_type_ = 0;
atom->reserved1_ = 0;
atom->reserved2_ = 0;
atom->reserved3_ = 0;
atom->name_ = 0;
return atom;
}
extern hdlr_t* hdlr_copy(hdlr_t const* rhs)
{
hdlr_t* atom = (hdlr_t*)malloc(sizeof(hdlr_t));
atom->version_ = rhs->version_;
atom->flags_ = rhs->flags_;
atom->predefined_ = rhs->predefined_;
atom->handler_type_ = rhs->handler_type_;
atom->reserved1_ = rhs->reserved1_;
atom->reserved2_ = rhs->reserved2_;
atom->reserved3_ = rhs->reserved3_;
atom->name_ = rhs->name_ == NULL ? NULL : strdup(rhs->name_);
return atom;
}
extern void hdlr_exit(struct hdlr_t* atom)
{
if(atom->name_)
{
free(atom->name_);
}
free(atom);
}
extern struct minf_t* minf_init()
{
struct minf_t* atom = (struct minf_t*)malloc(sizeof(struct minf_t));
atom->unknown_atoms_ = 0;
atom->vmhd_ = 0;
atom->smhd_ = 0;
atom->dinf_ = 0;
atom->stbl_ = 0;
return atom;
}
extern void minf_exit(struct minf_t* atom)
{
if(atom->unknown_atoms_)
{
unknown_atom_exit(atom->unknown_atoms_);
}
if(atom->vmhd_)
{
vmhd_exit(atom->vmhd_);
}
if(atom->smhd_)
{
smhd_exit(atom->smhd_);
}
if(atom->dinf_)
{
dinf_exit(atom->dinf_);
}
if(atom->stbl_)
{
stbl_exit(atom->stbl_);
}
free(atom);
}
extern vmhd_t* vmhd_init()
{
unsigned int i;
vmhd_t* atom = (vmhd_t*)malloc(sizeof(vmhd_t));
atom->version_ = 0;
atom->flags_ = 1;
atom->graphics_mode_ = 0;
for(i = 0; i != 3; ++i)
{
atom->opcolor_[i] = 0;
}
return atom;
}
extern vmhd_t* vmhd_copy(vmhd_t* rhs)
{
vmhd_t* atom = (vmhd_t*)malloc(sizeof(vmhd_t));
memcpy(atom, rhs, sizeof(vmhd_t));
return atom;
}
extern void vmhd_exit(struct vmhd_t* atom)
{
free(atom);
}
extern smhd_t* smhd_init()
{
smhd_t* atom = (smhd_t*)malloc(sizeof(smhd_t));
atom->version_ = 0;
atom->flags_ = 0;
atom->balance_ = 0;
atom->reserved_ = 0;
return atom;
}
extern smhd_t* smhd_copy(smhd_t* rhs)
{
smhd_t* atom = (smhd_t*)malloc(sizeof(smhd_t));
memcpy(atom, rhs, sizeof(smhd_t));
return atom;
}
extern void smhd_exit(struct smhd_t* atom)
{
free(atom);
}
extern dinf_t* dinf_init()
{
dinf_t* atom = (dinf_t*)malloc(sizeof(dinf_t));
atom->dref_ = 0;
return atom;
}
extern dinf_t* dinf_copy(dinf_t* rhs)
{
dinf_t* atom = (dinf_t*)malloc(sizeof(dinf_t));
atom->dref_ = dref_copy(rhs->dref_);
return atom;
}
extern void dinf_exit(dinf_t* atom)
{
if(atom->dref_)
{
dref_exit(atom->dref_);
}
free(atom);
}
extern dref_t* dref_init()
{
dref_t* atom = (dref_t*)malloc(sizeof(dref_t));
atom->version_ = 0;
atom->flags_ = 0;
atom->entry_count_ = 0;
atom->table_ = 0;
return atom;
}
extern dref_t* dref_copy(dref_t const* rhs)
{
unsigned int i;
dref_t* atom = (dref_t*)malloc(sizeof(dref_t));
atom->version_ = rhs->version_;
atom->flags_ = rhs->flags_;
atom->entry_count_ = rhs->entry_count_;
atom->table_ = atom->entry_count_ == 0 ? NULL : (dref_table_t*)malloc(atom->entry_count_ * sizeof(dref_table_t));
for(i = 0; i != atom->entry_count_; ++i)
{
dref_table_assign(&atom->table_[i], &rhs->table_[i]);
}
return atom;
}
extern void dref_exit(dref_t* atom)
{
unsigned int i;
for(i = 0; i != atom->entry_count_; ++i)
{
dref_table_exit(&atom->table_[i]);
}
if(atom->table_)
{
free(atom->table_);
}
free(atom);
}
extern void dref_table_init(dref_table_t* entry)
{
entry->flags_ = 0;
entry->name_ = 0;
entry->location_ = 0;
}
extern void dref_table_assign(dref_table_t* lhs, dref_table_t const* rhs)
{
lhs->flags_ = rhs->flags_;
lhs->name_ = rhs->name_ == NULL ? NULL : strdup(rhs->name_);
lhs->location_ = rhs->location_ == NULL ? NULL : strdup(rhs->location_);
}
extern void dref_table_exit(dref_table_t* entry)
{
if(entry->name_)
{
free(entry->name_);
}
if(entry->location_)
{
free(entry->location_);
}
}
extern struct stbl_t* stbl_init()
{
struct stbl_t* atom = (struct stbl_t*)malloc(sizeof(struct stbl_t));
atom->unknown_atoms_ = 0;
atom->stsd_ = 0;
atom->stts_ = 0;
atom->stss_ = 0;
atom->stsc_ = 0;
atom->stsz_ = 0;
atom->stco_ = 0;
atom->ctts_ = 0;
return atom;
}
extern void stbl_exit(struct stbl_t* atom)
{
if(atom->unknown_atoms_)
{
unknown_atom_exit(atom->unknown_atoms_);
}
if(atom->stsd_)
{
stsd_exit(atom->stsd_);
}
if(atom->stts_)
{
stts_exit(atom->stts_);
}
if(atom->stss_)
{
stss_exit(atom->stss_);
}
if(atom->stsc_)
{
stsc_exit(atom->stsc_);
}
if(atom->stsz_)
{
stsz_exit(atom->stsz_);
}
if(atom->stco_)
{
stco_exit(atom->stco_);
}
if(atom->ctts_)
{
ctts_exit(atom->ctts_);
}
free(atom);
}
extern unsigned int stbl_get_nearest_keyframe(struct stbl_t const* stbl,
unsigned int sample)
{
// If the sync atom is not present, all samples are implicit sync samples.
if(!stbl->stss_)
return sample;
return stss_get_nearest_keyframe(stbl->stss_, sample);
}
extern stsd_t* stsd_init()
{
stsd_t* atom = (stsd_t*)malloc(sizeof(stsd_t));
atom->version_ = 0;
atom->flags_ = 0;
atom->entries_ = 0;
atom->sample_entries_ = 0;
return atom;
}
extern stsd_t* stsd_copy(stsd_t const* rhs)
{
unsigned int i;
struct stsd_t* atom = (struct stsd_t*)malloc(sizeof(struct stsd_t));
atom->version_ = rhs->version_;
atom->flags_ = rhs->flags_;
atom->entries_ = rhs->entries_;
atom->sample_entries_ =
(sample_entry_t*)malloc(atom->entries_ * sizeof(sample_entry_t));
for(i = 0; i != atom->entries_; ++i)
{
sample_entry_assign(&atom->sample_entries_[i], &rhs->sample_entries_[i]);
}
return atom;
}
extern void stsd_exit(struct stsd_t* atom)
{
unsigned int i;
for(i = 0; i != atom->entries_; ++i)
{
sample_entry_t* sample_entry = &atom->sample_entries_[i];
sample_entry_exit(sample_entry);
}
if(atom->sample_entries_)
{
free(atom->sample_entries_);
}
free(atom);
}
extern video_sample_entry_t* video_sample_entry_init()
{
video_sample_entry_t* video_sample_entry =
(video_sample_entry_t*)malloc(sizeof(video_sample_entry_t));
video_sample_entry->version_ = 0;
video_sample_entry->revision_level_ = 0;
video_sample_entry->vendor_ = 0;
video_sample_entry->temporal_quality_ = 0;
video_sample_entry->spatial_quality_ = 0;
video_sample_entry->width_ = 0;
video_sample_entry->height_ = 0;
video_sample_entry->horiz_resolution_ = (72 << 16);
video_sample_entry->vert_resolution_ = (72 << 16);
video_sample_entry->data_size_ = 0;
video_sample_entry->frame_count_ = 1;
memset(video_sample_entry->compressor_name_, 0, 32);
video_sample_entry->depth_ = 24;
video_sample_entry->color_table_id_ = -1;
return video_sample_entry;
}
extern audio_sample_entry_t* audio_sample_entry_init()
{
audio_sample_entry_t* audio_sample_entry =
(audio_sample_entry_t*)malloc(sizeof(audio_sample_entry_t));
audio_sample_entry->version_ = 0;
audio_sample_entry->revision_ = 0;
audio_sample_entry->vendor_ = 0;
audio_sample_entry->channel_count_ = 2;
audio_sample_entry->sample_size_ = 16;
audio_sample_entry->compression_id_ = 0;
audio_sample_entry->packet_size_ = 0;
audio_sample_entry->samplerate_ = (0 << 16);
return audio_sample_entry;
}
extern void sample_entry_init(sample_entry_t* sample_entry)
{
sample_entry->len_ = 0;
sample_entry->buf_ = 0;
sample_entry->codec_private_data_length_ = 0;
sample_entry->codec_private_data_ = 0;
sample_entry->video_= 0;
sample_entry->audio_ = 0;
//sample_entry->hint_ = 0;
sample_entry->nal_unit_length_ = 0;
sample_entry->sps_length_ = 0;
sample_entry->sps_ = 0;
sample_entry->pps_length_ = 0;
sample_entry->pps_ = 0;
sample_entry->wFormatTag = 0;
sample_entry->nChannels = 2;
sample_entry->nSamplesPerSec = 44100;
sample_entry->nAvgBytesPerSec = 0;
sample_entry->nBlockAlign = 0;
sample_entry->wBitsPerSample = 16;
sample_entry->max_bitrate_ = 0;
sample_entry->avg_bitrate_ = 0;
}
extern void sample_entry_assign(sample_entry_t* lhs, sample_entry_t const* rhs)
{
memcpy(lhs, rhs, sizeof(sample_entry_t));
if(rhs->buf_ != NULL)
{
lhs->buf_ = (unsigned char*)malloc(rhs->len_);
memcpy(lhs->buf_, rhs->buf_, rhs->len_);
}
}
extern void sample_entry_exit(sample_entry_t* sample_entry)
{
if(sample_entry->buf_)
{
free(sample_entry->buf_);
}
if(sample_entry->video_)
{
free(sample_entry->video_);
}
if(sample_entry->audio_)
{
free(sample_entry->audio_);
}
}
static const uint32_t aac_samplerates[] =
{
96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
16000, 12000, 11025, 8000, 7350, 0, 0, 0
};
static const uint32_t aac_channels[] =
{
0, 1, 2, 3, 4, 5, 6, 8,
0, 0, 0, 0, 0, 0, 0, 0
};
static int mp4_samplerate_to_index(unsigned int samplerate)
{
unsigned int i;
for(i = 0; i != 13; ++i)
{
if(aac_samplerates[i] == samplerate)
return i;
}
return 4;
}
// Create an ADTS frame header
extern void sample_entry_get_adts(sample_entry_t const* sample_entry,
unsigned int sample_size, uint8_t* buf)
{
unsigned int syncword = 0xfff;
unsigned int ID = 0; // MPEG-4
unsigned int layer = 0;
unsigned int protection_absent = 1;
// 0 = Main profile AAC MAIN
// 1 = Low Complexity profile (LC) AAC LC
// 2 = Scalable Sample Rate profile (SSR) AAC SSR
// 3 = (reserved) AAC LTP
unsigned int profile = 1;
unsigned int sampling_frequency_index =
mp4_samplerate_to_index(sample_entry->nSamplesPerSec);
unsigned int private_bit = 0;
unsigned int channel_configuration = sample_entry->nChannels;
unsigned int original_copy = 0;
unsigned int home = 0;
unsigned int copyright_identification_bit = 0;
unsigned int copyright_identification_start = 0;
unsigned int aac_frame_length = 7 + sample_size;
unsigned int adts_buffer_fullness = 0x7ff;
unsigned int no_raw_data_blocks_in_frame = 0;
unsigned char buffer[8];
uint64_t adts = 0;
adts = (adts << 12) | syncword;
adts = (adts << 1) | ID;
adts = (adts << 2) | layer;
adts = (adts << 1) | protection_absent;
adts = (adts << 2) | profile;
adts = (adts << 4) | sampling_frequency_index;
adts = (adts << 1) | private_bit;
adts = (adts << 3) | channel_configuration;
adts = (adts << 1) | original_copy;
adts = (adts << 1) | home;
adts = (adts << 1) | copyright_identification_bit;
adts = (adts << 1) | copyright_identification_start;
adts = (adts << 13) | aac_frame_length;
adts = (adts << 11) | adts_buffer_fullness;
adts = (adts << 2) | no_raw_data_blocks_in_frame;
write_64(buffer, adts);
memcpy(buf, buffer + 1, 7);
}
extern stts_t* stts_init()
{
stts_t* atom = (stts_t*)malloc(sizeof(stts_t));
atom->version_ = 0;
atom->flags_ = 0;
atom->entries_ = 0;
atom->table_ = 0;
return atom;
}
extern void stts_exit(struct stts_t* atom)
{
if(atom->table_)
{
free(atom->table_);
}
free(atom);
}
extern unsigned int stts_get_sample(struct stts_t const* stts, uint64_t time)
{
unsigned int stts_index = 0;
unsigned int stts_count;
unsigned int ret = 0;
uint64_t time_count = 0;
for(; stts_index != stts->entries_; ++stts_index)
{
unsigned int sample_count = stts->table_[stts_index].sample_count_;
unsigned int sample_duration = stts->table_[stts_index].sample_duration_;
if(time_count + (uint64_t)sample_duration * (uint64_t)sample_count >= time)
{
stts_count = (unsigned int)((time - time_count + sample_duration - 1) / sample_duration);
time_count += (uint64_t)stts_count * (uint64_t)sample_duration;
ret += stts_count;
break;
}
else
{
time_count += (uint64_t)sample_duration * (uint64_t)sample_count;
ret += sample_count;
}
}
return ret;
}
extern uint64_t stts_get_time(struct stts_t const* stts, unsigned int sample)
{
uint64_t ret = 0;
unsigned int stts_index = 0;
unsigned int sample_count = 0;
for(;;)
{
unsigned int table_sample_count = stts->table_[stts_index].sample_count_;
unsigned int table_sample_duration = stts->table_[stts_index].sample_duration_;
if(sample_count + table_sample_count > sample)
{
unsigned int stts_count = (sample - sample_count);
ret += (uint64_t)stts_count * (uint64_t)table_sample_duration;
break;
}
else
{
sample_count += table_sample_count;
ret += (uint64_t)table_sample_count * (uint64_t)table_sample_duration;
stts_index++;
}
}
return ret;
}
extern uint64_t stts_get_duration(struct stts_t const* stts)
{
uint64_t duration = 0;
unsigned int i;
for(i = 0; i != stts->entries_; ++i)
{
unsigned int sample_count = stts->table_[i].sample_count_;
unsigned int sample_duration = stts->table_[i].sample_duration_;
duration += (uint64_t)sample_duration * (uint64_t)sample_count;
}
return duration;
}
extern unsigned int stts_get_samples(struct stts_t const* stts)
{
unsigned int samples = 0;
unsigned int entries = stts->entries_;
unsigned int i;
for(i = 0; i != entries; ++i)
{
unsigned int sample_count = stts->table_[i].sample_count_;
// unsigned int sample_duration = stts->table_[i].sample_duration_;
samples += sample_count;
}
return samples;
}
extern struct stss_t* stss_init()
{
stss_t* atom = (stss_t*)malloc(sizeof(stss_t));
atom->version_ = 0;
atom->flags_ = 0;
atom->entries_ = 0;
atom->sample_numbers_ = 0;
return atom;
}
extern void stss_exit(struct stss_t* atom)
{
if(atom->sample_numbers_)
{
free(atom->sample_numbers_);
}
free(atom);
}
extern unsigned int stss_get_nearest_keyframe(struct stss_t const* stss,
unsigned int sample)
{
// scan the sync samples to find the key frame that precedes the sample number
unsigned int i;
unsigned int table_sample = 0;
for(i = 0; i != stss->entries_; ++i)
{
table_sample = stss->sample_numbers_[i];
if(table_sample >= sample)
break;
}
if(table_sample == sample)
return table_sample;
else
return stss->sample_numbers_[i - 1];
}
extern stsc_t* stsc_init()
{
stsc_t* atom = (stsc_t*)malloc(sizeof(stsc_t));
atom->version_ = 0;
atom->flags_ = 0;
atom->entries_ = 0;
atom->table_ = 0;
return atom;
}
extern void stsc_exit(struct stsc_t* atom)
{
if(atom->table_)
{
free(atom->table_);
}
free(atom);
}
extern stsz_t* stsz_init()
{
stsz_t* atom = (stsz_t*)malloc(sizeof(stsz_t));
atom->version_ = 0;
atom->flags_ = 0;
atom->sample_size_ = 0;
atom->entries_ = 0;
atom->sample_sizes_ = 0;
return atom;
}
extern void stsz_exit(struct stsz_t* atom)
{
if(atom->sample_sizes_)
{
free(atom->sample_sizes_);
}
free(atom);
}
extern stco_t* stco_init()
{
stco_t* atom = (stco_t*)malloc(sizeof(stco_t));
atom->version_ = 0;
atom->flags_ = 0;
atom->entries_ = 0;
atom->chunk_offsets_ = 0;
return atom;
}
extern void stco_exit(stco_t* atom)
{
if(atom->chunk_offsets_)
{
free(atom->chunk_offsets_);
}
free(atom);
}
#if 0
extern void stco_shift_offsets(stco_t* stco, int offset)
{
unsigned int i;
for(i = 0; i != stco->entries_; ++i)
stco->chunk_offsets_[i] += offset;
}
#endif
extern struct ctts_t* ctts_init()
{
struct ctts_t* atom = (struct ctts_t*)malloc(sizeof(struct ctts_t));
atom->version_ = 0;
atom->flags_ = 0;
atom->entries_ = 0;
atom->table_ = 0;
return atom;
}
extern void ctts_exit(struct ctts_t* atom)
{
if(atom->table_)
{
free(atom->table_);
}
free(atom);
}
extern unsigned int ctts_get_samples(struct ctts_t const* ctts)
{
unsigned int samples = 0;
unsigned int entries = ctts->entries_;
unsigned int i;
for(i = 0; i != entries; ++i)
{
unsigned int sample_count = ctts->table_[i].sample_count_;
// unsigned int sample_offset = ctts->table_[i].sample_offset_;
samples += sample_count;
}
return samples;
}
extern uint64_t moov_time_to_trak_time(uint64_t t, long moov_time_scale,
long trak_time_scale)
{
return t * (uint64_t)trak_time_scale / moov_time_scale;
}
extern uint64_t trak_time_to_moov_time(uint64_t t, long moov_time_scale,
long trak_time_scale)
{
return t * (uint64_t)moov_time_scale / trak_time_scale;
}
extern mvex_t* mvex_init()
{
mvex_t* mvex = (mvex_t*)malloc(sizeof(mvex_t));
mvex->unknown_atoms_ = 0;
mvex->tracks_ = 0;
return mvex;
}
extern void mvex_exit(mvex_t* atom)
{
unsigned int i;
if(atom->unknown_atoms_)
{
unknown_atom_exit(atom->unknown_atoms_);
}
for(i = 0; i != atom->tracks_; ++i)
{
trex_exit(atom->trexs_[i]);
}
free(atom);
}
extern trex_t* trex_init()
{
trex_t* trex = (trex_t*)malloc(sizeof(trex_t));
trex->version_ = 0;
trex->flags_ = 0;
trex->track_id_ = 0;
trex->default_sample_description_index_ = 0;
trex->default_sample_duration_ = 0;
trex->default_sample_size_ = 0;
trex->default_sample_flags_ = 0;
return trex;
}
extern void trex_exit(trex_t* atom)
{
free(atom);
}
extern moof_t* moof_init()
{
struct moof_t* moof = (struct moof_t*)malloc(sizeof(struct moof_t));
moof->unknown_atoms_ = 0;
moof->mfhd_ = 0;
moof->tracks_ = 0;
return moof;
}
extern void moof_exit(struct moof_t* atom)
{
unsigned int i;
if(atom->unknown_atoms_)
{
unknown_atom_exit(atom->unknown_atoms_);
}
if(atom->mfhd_)
{
mfhd_exit(atom->mfhd_);
}
for(i = 0; i != atom->tracks_; ++i)
{
traf_exit(atom->trafs_[i]);
}
free(atom);
}
extern mfhd_t* mfhd_init()
{
mfhd_t* mfhd = (mfhd_t*)malloc(sizeof(mfhd_t));
mfhd->version_ = 0;
mfhd->flags_ = 0;
mfhd->sequence_number_ = 0;
return mfhd;
}
extern void mfhd_exit(mfhd_t* atom)
{
free(atom);
}
extern traf_t* traf_init()
{
traf_t* traf = (traf_t*)malloc(sizeof(traf_t));
traf->unknown_atoms_ = 0;
traf->tfhd_ = 0;
traf->trun_ = 0;
traf->uuid0_ = 0;
traf->uuid1_ = 0;
return traf;
}
extern void traf_exit(traf_t* atom)
{
if(atom->unknown_atoms_)
{
unknown_atom_exit(atom->unknown_atoms_);
}
if(atom->tfhd_)
{
tfhd_exit(atom->tfhd_);
}
if(atom->trun_)
{
trun_t* trun = atom->trun_;
while(trun)
{
trun_t* next = trun->next_;
trun_exit(trun);
trun = next;
}
}
if(atom->uuid0_)
{
uuid0_exit(atom->uuid0_);
}
if(atom->uuid1_)
{
uuid1_exit(atom->uuid1_);
}
free(atom);
}
extern tfhd_t* tfhd_init()
{
tfhd_t* tfhd = (tfhd_t*)malloc(sizeof(tfhd_t));
tfhd->version_ = 0;
tfhd->flags_ = 0;
return tfhd;
}
extern void tfhd_exit(tfhd_t* atom)
{
free(atom);
}
extern tfra_t* tfra_init()
{
tfra_t* tfra = (tfra_t*)malloc(sizeof(tfra_t));
tfra->table_ = 0;
return tfra;
}
extern void tfra_exit(tfra_t* tfra)
{
if(tfra->table_)
{
free(tfra->table_);
}
free(tfra);
}
extern void tfra_add(tfra_t* tfra, tfra_table_t const* table)
{
tfra_table_t* tfra_table;
// allocate one more entry
tfra->table_ = (tfra_table_t*)
realloc(tfra->table_, (tfra->number_of_entry_ + 1) * sizeof(tfra_table_t));
tfra_table = &tfra->table_[tfra->number_of_entry_];
tfra_table->time_ = table->time_;
tfra_table->moof_offset_ = table->moof_offset_;
tfra_table->traf_number_ = table->traf_number_;
tfra_table->trun_number_ = table->trun_number_;
tfra_table->sample_number_ = table->sample_number_;
++tfra->number_of_entry_;
}
extern mfra_t* mfra_init()
{
mfra_t* mfra = (mfra_t*)malloc(sizeof(mfra_t));
mfra->unknown_atoms_ = 0;
mfra->tracks_ = 0;
return mfra;
}
extern void mfra_exit(mfra_t* atom)
{
unsigned int i;
if(atom->unknown_atoms_)
{
unknown_atom_exit(atom->unknown_atoms_);
}
for(i = 0; i != atom->tracks_; ++i)
{
tfra_exit(atom->tfras_[i]);
}
free(atom);
}
extern trun_t* trun_init()
{
trun_t* trun = (trun_t*)malloc(sizeof(trun_t));
trun->version_ = 0;
trun->flags_ = 0;
trun->sample_count_ = 0;
trun->data_offset_ = 0;
trun->first_sample_flags_ = 0;
trun->table_ = 0;
trun->next_ = 0;
return trun;
}
extern void trun_exit(struct trun_t* atom)
{
if(atom->table_)
{
free(atom->table_);
}
free(atom);
}
extern uuid0_t* uuid0_init()
{
uuid0_t* uuid = (uuid0_t*)malloc(sizeof(uuid0_t));
uuid->pts_ = 0;
uuid->duration_ = 0;
return uuid;
}
extern void uuid0_exit(uuid0_t* atom)
{
free(atom);
}
extern uuid1_t* uuid1_init()
{
unsigned int i;
uuid1_t* uuid = (uuid1_t*)malloc(sizeof(uuid1_t));
uuid->entries_ = 0;
for(i = 0; i != 2; ++i)
{
uuid->pts_[i] = 0;
uuid->duration_[i] = 0;
}
return uuid;
}
extern void uuid1_exit(uuid1_t* atom)
{
free(atom);
}
// End Of File