From cc2160de5cc05dc3aa77f3a34358e66f6193c8c9 Mon Sep 17 00:00:00 2001 From: Michał Cichoń Date: Tue, 26 Jun 2012 20:35:30 +0200 Subject: Add support for AAC. --- faad2/src/common/mp4ff/mp4ff.c | 475 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 475 insertions(+) create mode 100644 faad2/src/common/mp4ff/mp4ff.c (limited to 'faad2/src/common/mp4ff/mp4ff.c') diff --git a/faad2/src/common/mp4ff/mp4ff.c b/faad2/src/common/mp4ff/mp4ff.c new file mode 100644 index 0000000..f513e86 --- /dev/null +++ b/faad2/src/common/mp4ff/mp4ff.c @@ -0,0 +1,475 @@ +/* +** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding +** Copyright (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +** +** Any non-GPL usage of this software or parts of this software is strictly +** forbidden. +** +** The "appropriate copyright message" mentioned in section 2c of the GPLv2 +** must read: "Code from FAAD2 is copyright (c) Nero AG, www.nero.com" +** +** Commercial non-GPL licensing of this software is possible. +** For more info contact Nero AG through Mpeg4AAClicense@nero.com. +** +** $Id: mp4ff.c,v 1.22 2009/01/26 23:01:40 menno Exp $ +**/ + +#include +#include +#include "mp4ffint.h" + +mp4ff_t *mp4ff_open_read(mp4ff_callback_t *f) +{ + mp4ff_t *ff = malloc(sizeof(mp4ff_t)); + + memset(ff, 0, sizeof(mp4ff_t)); + + ff->stream = f; + + parse_atoms(ff,0); + + return ff; +} + +mp4ff_t *mp4ff_open_read_metaonly(mp4ff_callback_t *f) +{ + mp4ff_t *ff = malloc(sizeof(mp4ff_t)); + + memset(ff, 0, sizeof(mp4ff_t)); + + ff->stream = f; + + parse_atoms(ff,1); + + return ff; +} + +void mp4ff_close(mp4ff_t *ff) +{ + int32_t i; + + for (i = 0; i < ff->total_tracks; i++) + { + if (ff->track[i]) + { + if (ff->track[i]->stsz_table) + free(ff->track[i]->stsz_table); + if (ff->track[i]->stts_sample_count) + free(ff->track[i]->stts_sample_count); + if (ff->track[i]->stts_sample_delta) + free(ff->track[i]->stts_sample_delta); + if (ff->track[i]->stsc_first_chunk) + free(ff->track[i]->stsc_first_chunk); + if (ff->track[i]->stsc_samples_per_chunk) + free(ff->track[i]->stsc_samples_per_chunk); + if (ff->track[i]->stsc_sample_desc_index) + free(ff->track[i]->stsc_sample_desc_index); + if (ff->track[i]->stco_chunk_offset) + free(ff->track[i]->stco_chunk_offset); + if (ff->track[i]->decoderConfig) + free(ff->track[i]->decoderConfig); + if (ff->track[i]->ctts_sample_count) + free(ff->track[i]->ctts_sample_count); + if (ff->track[i]->ctts_sample_offset) + free(ff->track[i]->ctts_sample_offset); +#ifdef ITUNES_DRM + if (ff->track[i]->p_drms) + drms_free(ff->track[i]->p_drms); +#endif + free(ff->track[i]); + } + } + +#ifdef USE_TAGGING + mp4ff_tag_delete(&(ff->tags)); +#endif + + if (ff) free(ff); +} + +void mp4ff_track_add(mp4ff_t *f) +{ + f->total_tracks++; + + f->track[f->total_tracks - 1] = malloc(sizeof(mp4ff_track_t)); + + memset(f->track[f->total_tracks - 1], 0, sizeof(mp4ff_track_t)); +} + +static int need_parse_when_meta_only(uint8_t atom_type) +{ + switch(atom_type) + { + case ATOM_EDTS: +// case ATOM_MDIA: +// case ATOM_MINF: + case ATOM_DRMS: + case ATOM_SINF: + case ATOM_SCHI: +// case ATOM_STBL: +// case ATOM_STSD: + case ATOM_STTS: + case ATOM_STSZ: + case ATOM_STZ2: + case ATOM_STCO: + case ATOM_STSC: +// case ATOM_CTTS: + case ATOM_FRMA: + case ATOM_IVIV: + case ATOM_PRIV: + return 0; + default: + return 1; + } +} + +/* parse atoms that are sub atoms of other atoms */ +int32_t parse_sub_atoms(mp4ff_t *f, const uint64_t total_size,int meta_only) +{ + uint64_t size; + uint8_t atom_type = 0; + uint64_t counted_size = 0; + uint8_t header_size = 0; + + while (counted_size < total_size) + { + size = mp4ff_atom_read_header(f, &atom_type, &header_size); + counted_size += size; + + /* check for end of file */ + if (size == 0) + break; + + /* we're starting to read a new track, update index, + * so that all data and tables get written in the right place + */ + if (atom_type == ATOM_TRAK) + { + mp4ff_track_add(f); + } + + /* parse subatoms */ + if (meta_only && !need_parse_when_meta_only(atom_type)) + { + mp4ff_set_position(f, mp4ff_position(f)+size-header_size); + } else if (atom_type < SUBATOMIC) + { + parse_sub_atoms(f, size-header_size,meta_only); + } else { + mp4ff_atom_read(f, (uint32_t)size, atom_type); + } + } + + return 0; +} + +/* parse root atoms */ +int32_t parse_atoms(mp4ff_t *f,int meta_only) +{ + uint64_t size; + uint8_t atom_type = 0; + uint8_t header_size = 0; + + f->file_size = 0; + + while ((size = mp4ff_atom_read_header(f, &atom_type, &header_size)) != 0) + { + f->file_size += size; + f->last_atom = atom_type; + + if (atom_type == ATOM_MDAT && f->moov_read) + { + /* moov atom is before mdat, we can stop reading when mdat is encountered */ + /* file position will stay at beginning of mdat data */ +// break; + } + + if (atom_type == ATOM_MOOV && size > header_size) + { + f->moov_read = 1; + f->moov_offset = mp4ff_position(f)-header_size; + f->moov_size = size; + } + + /* parse subatoms */ + if (meta_only && !need_parse_when_meta_only(atom_type)) + { + mp4ff_set_position(f, mp4ff_position(f)+size-header_size); + } else if (atom_type < SUBATOMIC) + { + parse_sub_atoms(f, size-header_size,meta_only); + } else { + /* skip this atom */ + mp4ff_set_position(f, mp4ff_position(f)+size-header_size); + } + } + + return 0; +} + +int32_t mp4ff_get_decoder_config(const mp4ff_t *f, const int32_t track, + uint8_t** ppBuf, uint32_t* pBufSize) +{ + if (track >= f->total_tracks) + { + *ppBuf = NULL; + *pBufSize = 0; + return 1; + } + + if (f->track[track]->decoderConfig == NULL || f->track[track]->decoderConfigLen == 0) + { + *ppBuf = NULL; + *pBufSize = 0; + } else { + *ppBuf = malloc(f->track[track]->decoderConfigLen); + if (*ppBuf == NULL) + { + *pBufSize = 0; + return 1; + } + memcpy(*ppBuf, f->track[track]->decoderConfig, f->track[track]->decoderConfigLen); + *pBufSize = f->track[track]->decoderConfigLen; + } + + return 0; +} + +int32_t mp4ff_get_track_type(const mp4ff_t *f, const int track) +{ + return f->track[track]->type; +} + +int32_t mp4ff_total_tracks(const mp4ff_t *f) +{ + return f->total_tracks; +} + +int32_t mp4ff_time_scale(const mp4ff_t *f, const int32_t track) +{ + return f->track[track]->timeScale; +} + +uint32_t mp4ff_get_avg_bitrate(const mp4ff_t *f, const int32_t track) +{ + return f->track[track]->avgBitrate; +} + +uint32_t mp4ff_get_max_bitrate(const mp4ff_t *f, const int32_t track) +{ + return f->track[track]->maxBitrate; +} + +int64_t mp4ff_get_track_duration(const mp4ff_t *f, const int32_t track) +{ + return f->track[track]->duration; +} + +int64_t mp4ff_get_track_duration_use_offsets(const mp4ff_t *f, const int32_t track) +{ + int64_t duration = mp4ff_get_track_duration(f,track); + if (duration!=-1) + { + int64_t offset = mp4ff_get_sample_offset(f,track,0); + if (offset > duration) duration = 0; + else duration -= offset; + } + return duration; +} + + +int32_t mp4ff_num_samples(const mp4ff_t *f, const int32_t track) +{ + int32_t i; + int32_t total = 0; + + for (i = 0; i < f->track[track]->stts_entry_count; i++) + { + total += f->track[track]->stts_sample_count[i]; + } + return total; +} + + + + +uint32_t mp4ff_get_sample_rate(const mp4ff_t *f, const int32_t track) +{ + return f->track[track]->sampleRate; +} + +uint32_t mp4ff_get_channel_count(const mp4ff_t * f,const int32_t track) +{ + return f->track[track]->channelCount; +} + +uint32_t mp4ff_get_audio_type(const mp4ff_t * f,const int32_t track) +{ + return f->track[track]->audioType; +} + +int32_t mp4ff_get_sample_duration_use_offsets(const mp4ff_t *f, const int32_t track, const int32_t sample) +{ + int32_t d,o; + d = mp4ff_get_sample_duration(f,track,sample); + if (d!=-1) + { + o = mp4ff_get_sample_offset(f,track,sample); + if (o>d) d = 0; + else d -= o; + } + return d; +} + +int32_t mp4ff_get_sample_duration(const mp4ff_t *f, const int32_t track, const int32_t sample) +{ + int32_t i, co = 0; + + for (i = 0; i < f->track[track]->stts_entry_count; i++) + { + int32_t delta = f->track[track]->stts_sample_count[i]; + if (sample < co + delta) + return f->track[track]->stts_sample_delta[i]; + co += delta; + } + return (int32_t)(-1); +} + +int64_t mp4ff_get_sample_position(const mp4ff_t *f, const int32_t track, const int32_t sample) +{ + int32_t i, co = 0; + int64_t acc = 0; + + for (i = 0; i < f->track[track]->stts_entry_count; i++) + { + int32_t delta = f->track[track]->stts_sample_count[i]; + if (sample < co + delta) + { + acc += f->track[track]->stts_sample_delta[i] * (sample - co); + return acc; + } + else + { + acc += f->track[track]->stts_sample_delta[i] * delta; + } + co += delta; + } + return (int64_t)(-1); +} + +int32_t mp4ff_get_sample_offset(const mp4ff_t *f, const int32_t track, const int32_t sample) +{ + int32_t i, co = 0; + + for (i = 0; i < f->track[track]->ctts_entry_count; i++) + { + int32_t delta = f->track[track]->ctts_sample_count[i]; + if (sample < co + delta) + return f->track[track]->ctts_sample_offset[i]; + co += delta; + } + return 0; +} + +int32_t mp4ff_find_sample(const mp4ff_t *f, const int32_t track, const int64_t offset,int32_t * toskip) +{ + int32_t i, co = 0; + int64_t offset_total = 0; + mp4ff_track_t * p_track = f->track[track]; + + for (i = 0; i < p_track->stts_entry_count; i++) + { + int32_t sample_count = p_track->stts_sample_count[i]; + int32_t sample_delta = p_track->stts_sample_delta[i]; + int64_t offset_delta = (int64_t)sample_delta * (int64_t)sample_count; + if (offset < offset_total + offset_delta) + { + int64_t offset_fromstts = offset - offset_total; + if (toskip) *toskip = (int32_t)(offset_fromstts % sample_delta); + return co + (int32_t)(offset_fromstts / sample_delta); + } + else + { + offset_total += offset_delta; + } + co += sample_count; + } + return (int32_t)(-1); +} + +int32_t mp4ff_find_sample_use_offsets(const mp4ff_t *f, const int32_t track, const int64_t offset,int32_t * toskip) +{ + return mp4ff_find_sample(f,track,offset + mp4ff_get_sample_offset(f,track,0),toskip); +} + +int32_t mp4ff_read_sample(mp4ff_t *f, const int32_t track, const int32_t sample, + uint8_t **audio_buffer, uint32_t *bytes) +{ + int32_t result = 0; + + *bytes = mp4ff_audio_frame_size(f, track, sample); + + if (*bytes==0) return 0; + + *audio_buffer = (uint8_t*)malloc(*bytes); + + mp4ff_set_sample_position(f, track, sample); + + result = mp4ff_read_data(f, *audio_buffer, *bytes); + + if (!result) + { + free(*audio_buffer); + *audio_buffer = 0; + return 0; + } + +#ifdef ITUNES_DRM + if (f->track[track]->p_drms != NULL) + { + drms_decrypt(f->track[track]->p_drms, (uint32_t*)*audio_buffer, *bytes); + } +#endif + + return *bytes; +} + + +int32_t mp4ff_read_sample_v2(mp4ff_t *f, const int track, const int sample,unsigned char *buffer) +{ + int32_t result = 0; + int32_t size = mp4ff_audio_frame_size(f,track,sample); + if (size<=0) return 0; + mp4ff_set_sample_position(f, track, sample); + result = mp4ff_read_data(f,buffer,size); + +#ifdef ITUNES_DRM + if (f->track[track]->p_drms != NULL) + { + drms_decrypt(f->track[track]->p_drms, (uint32_t*)buffer, size); + } +#endif + + return result; +} + +int32_t mp4ff_read_sample_getsize(mp4ff_t *f, const int track, const int sample) +{ + int32_t temp = mp4ff_audio_frame_size(f, track, sample); + if (temp<0) temp = 0; + return temp; +} -- cgit v1.2.3