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/plugins/mpeg4ip/Makefile.am | 22 ++ faad2/src/plugins/mpeg4ip/README_WIN32.txt | 11 + faad2/src/plugins/mpeg4ip/aa_file.cpp | 130 ++++++++++ faad2/src/plugins/mpeg4ip/aa_file.h | 26 ++ faad2/src/plugins/mpeg4ip/faad2.cpp | 388 +++++++++++++++++++++++++++++ faad2/src/plugins/mpeg4ip/faad2.h | 92 +++++++ 6 files changed, 669 insertions(+) create mode 100644 faad2/src/plugins/mpeg4ip/Makefile.am create mode 100644 faad2/src/plugins/mpeg4ip/README_WIN32.txt create mode 100644 faad2/src/plugins/mpeg4ip/aa_file.cpp create mode 100644 faad2/src/plugins/mpeg4ip/aa_file.h create mode 100644 faad2/src/plugins/mpeg4ip/faad2.cpp create mode 100644 faad2/src/plugins/mpeg4ip/faad2.h (limited to 'faad2/src/plugins/mpeg4ip') diff --git a/faad2/src/plugins/mpeg4ip/Makefile.am b/faad2/src/plugins/mpeg4ip/Makefile.am new file mode 100644 index 0000000..8024d2a --- /dev/null +++ b/faad2/src/plugins/mpeg4ip/Makefile.am @@ -0,0 +1,22 @@ +libdir = @MPEG4IP_PLAYER_PLUGIN_DIR@ + +lib_LTLIBRARIES = faad2_plugin.la +faad2_plugin_la_LDFLAGS = -module +faad2_plugin_la_SOURCES = \ + faad2.cpp \ + faad2.h \ + aa_file.cpp \ + aa_file.h + +faad2_plugin_la_LIBADD = \ + $(top_builddir)/libfaad/libfaad.la \ + -lm + + +INCLUDES = -I$(top_srcdir)/include + +AM_CFLAGS = -D_REENTRANT -fexceptions + +AM_CXXFLAGS = -D_REENTRANT -DNOCONTROLS -fexceptions + + diff --git a/faad2/src/plugins/mpeg4ip/README_WIN32.txt b/faad2/src/plugins/mpeg4ip/README_WIN32.txt new file mode 100644 index 0000000..7fc864a --- /dev/null +++ b/faad2/src/plugins/mpeg4ip/README_WIN32.txt @@ -0,0 +1,11 @@ +Creating mpeg4ip plugin for Windows. + +You will need to have mpeg4ip installed. If you install it on the same drive, with the top level directory +name of /mpeg4ip, you will have to do nothing other than move the faad2_plugin.dll from the Release or +Debug directory to the same directory as the other mpeg4ip plugins. + +If you install it somewhere else, you will have to change the include paths and link paths in the project +settings for faad2_plugin to the proper directory. Look for /mpeg4ip (or \mpeg4ip) and change all occurances +of these in the file. + +It might be best to hand-edit the faad_plugin.sdp file with wordpad and use the search and replace function. \ No newline at end of file diff --git a/faad2/src/plugins/mpeg4ip/aa_file.cpp b/faad2/src/plugins/mpeg4ip/aa_file.cpp new file mode 100644 index 0000000..a0cccb9 --- /dev/null +++ b/faad2/src/plugins/mpeg4ip/aa_file.cpp @@ -0,0 +1,130 @@ +/* +** MPEG4IP plugin for FAAD2 +** Copyright (C) 2003 Bill May wmay@cisco.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. +** +** $Id: aa_file.cpp,v 1.2 2004/01/05 14:05:12 menno Exp $ +**/ +/* + * aa_file.cpp - create media structure for aac files + */ + +#include "faad2.h" +codec_data_t *aac_file_check (lib_message_func_t message, + const char *name, + double *max, + char *desc[4] +#ifdef HAVE_PLUGIN_VERSION_0_8 + , CConfigSet *pConfig +#endif +) +{ + aac_codec_t *aac; + int len = strlen(name); + if (strcasecmp(name + len - 4, ".aac") != 0) { + return (NULL); + } + + aac = MALLOC_STRUCTURE(aac_codec_t); + memset(aac, 0, sizeof(*aac)); + *max = 0; + + aac->m_buffer = (uint8_t *)malloc(MAX_READ_BUFFER); + aac->m_buffer_size_max = MAX_READ_BUFFER; + aac->m_ifile = fopen(name, FOPEN_READ_BINARY); + if (aac->m_ifile == NULL) { + free(aac); + return NULL; + } + aac->m_output_frame_size = 1024; + aac->m_info = faacDecOpen(); // use defaults here... + aac->m_buffer_size = fread(aac->m_buffer, + 1, + aac->m_buffer_size_max, + aac->m_ifile); + + unsigned long freq; + unsigned char chans; + + faacDecInit(aac->m_info, (unsigned char *)aac->m_buffer, + aac->m_buffer_size, &freq, &chans); + // may want to actually decode the first frame... + if (freq == 0) { + message(LOG_ERR, aaclib, "Couldn't determine AAC frame rate"); + aac_close((codec_data_t *)aac); + return (NULL); + } + aac->m_freq = freq; + aac->m_chans = chans; + aac->m_faad_inited = 1; + aac->m_framecount = 0; + return ((codec_data_t *)aac); +} + + +int aac_file_next_frame (codec_data_t *your, + uint8_t **buffer, + uint64_t *ts) +{ + aac_codec_t *aac = (aac_codec_t *)your; + + if (aac->m_buffer_on > 0) { + memmove(aac->m_buffer, + &aac->m_buffer[aac->m_buffer_on], + aac->m_buffer_size - aac->m_buffer_on); + } + aac->m_buffer_size -= aac->m_buffer_on; + aac->m_buffer_size += fread(aac->m_buffer + aac->m_buffer_size, + 1, + aac->m_buffer_size_max - aac->m_buffer_size, + aac->m_ifile); + aac->m_buffer_on = 0; + if (aac->m_buffer_size == 0) return 0; + + + uint64_t calc; + calc = aac->m_framecount * 1024 * M_LLU; + calc /= aac->m_freq; + *ts = calc; + *buffer = aac->m_buffer; + aac->m_framecount++; + return (aac->m_buffer_size); +} + +void aac_file_used_for_frame (codec_data_t *ifptr, + uint32_t bytes) +{ + aac_codec_t *aac = (aac_codec_t *)ifptr; + aac->m_buffer_on += bytes; + if (aac->m_buffer_on > aac->m_buffer_size) aac->m_buffer_on = aac->m_buffer_size; +} + +int aac_file_eof (codec_data_t *ifptr) +{ + aac_codec_t *aac = (aac_codec_t *)ifptr; + return aac->m_buffer_on == aac->m_buffer_size && feof(aac->m_ifile); +} + +int aac_raw_file_seek_to (codec_data_t *ifptr, uint64_t ts) +{ + if (ts != 0) return -1; + + aac_codec_t *aac = (aac_codec_t *)ifptr; + rewind(aac->m_ifile); + aac->m_buffer_size = aac->m_buffer_on = 0; + aac->m_framecount = 0; + return 0; +} diff --git a/faad2/src/plugins/mpeg4ip/aa_file.h b/faad2/src/plugins/mpeg4ip/aa_file.h new file mode 100644 index 0000000..dfed15d --- /dev/null +++ b/faad2/src/plugins/mpeg4ip/aa_file.h @@ -0,0 +1,26 @@ +/* +** MPEG4IP plugin for FAAD2 +** Copyright (C) 2003 Bill May wmay@cisco.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. +** +** $Id: aa_file.h,v 1.1 2003/08/07 17:21:21 menno Exp $ +**/ +/* + * aa_file.h - prototypes for aac files + */ +int create_media_for_aac_file (CPlayerSession *pspstr, + const char *name, + const char **errmsg); diff --git a/faad2/src/plugins/mpeg4ip/faad2.cpp b/faad2/src/plugins/mpeg4ip/faad2.cpp new file mode 100644 index 0000000..72ff0c8 --- /dev/null +++ b/faad2/src/plugins/mpeg4ip/faad2.cpp @@ -0,0 +1,388 @@ +/* +** MPEG4IP plugin for FAAD2 +** Copyright (C) 2003 Bill May wmay@cisco.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. +** +** $Id: faad2.cpp,v 1.3 2004/08/20 08:30:53 menno Exp $ +**/ +#include "faad2.h" +#include +#include +#include +#include + +#define DEBUG_SYNC 2 + +#ifndef M_LLU +#define M_LLU M_64 +#define LLU U64 +#endif +const char *aaclib="faad2"; + +/* + * Create CAACodec class + */ +static codec_data_t *aac_codec_create (const char *compressor, + int type, + int profile, + format_list_t *media_fmt, + audio_info_t *audio, + const uint8_t *userdata, + uint32_t userdata_size, + audio_vft_t *vft, + void *ifptr) + +{ + aac_codec_t *aac; + + aac = (aac_codec_t *)malloc(sizeof(aac_codec_t)); + memset(aac, 0, sizeof(aac_codec_t)); + + aac->m_vft = vft; + aac->m_ifptr = ifptr; + fmtp_parse_t *fmtp = NULL; + // Start setting up FAAC stuff... + + aac->m_resync_with_header = 1; + aac->m_record_sync_time = 1; + + aac->m_audio_inited = 0; + + // Use media_fmt to indicate that we're streaming. + if (media_fmt != NULL) { + // haven't checked for null buffer + // This is not necessarilly right - it is, for the most part, but + // we should be reading the fmtp statement, and looking at the config. + // (like we do below in the userdata section... + aac->m_freq = media_fmt->rtpmap->clock_rate; + fmtp = parse_fmtp_for_mpeg4(media_fmt->fmt_param, vft->log_msg); + if (fmtp != NULL) { + userdata = fmtp->config_binary; + userdata_size = fmtp->config_binary_len; + } + } + + aac->m_info = faacDecOpen(); + unsigned long srate; + unsigned char chan; + if ((userdata == NULL && fmtp == NULL) || + (faacDecInit2(aac->m_info, + (uint8_t *)userdata, + userdata_size, + &srate, + &chan) < 0)) { + if (fmtp != NULL) free_fmtp_parse(fmtp); + return NULL; + } + + mp4AudioSpecificConfig mp4ASC; + aac->m_output_frame_size = 1024; + if (AudioSpecificConfig((unsigned char *)userdata, + userdata_size, + &mp4ASC)) { + if (mp4ASC.frameLengthFlag) { + aac->m_output_frame_size = 960; + } + } + aac->m_freq = srate; + aac->m_chans = chan; + aac->m_faad_inited = 1; + aac->m_msec_per_frame = aac->m_output_frame_size; + aac->m_msec_per_frame *= M_LLU; + aac->m_msec_per_frame /= aac->m_freq; + + // faad_init_bytestream(&m_info->ld, c_read_byte, c_bookmark, m_bytestream); + + aa_message(LOG_INFO, aaclib, "Setting freq to %d", aac->m_freq); +#if DUMP_OUTPUT_TO_FILE + aac->m_outfile = fopen("temp.raw", "w"); +#endif + if (fmtp != NULL) { + free_fmtp_parse(fmtp); + } + return (codec_data_t *)aac; +} + +void aac_close (codec_data_t *ptr) +{ + if (ptr == NULL) { + return; + } + aac_codec_t *aac = (aac_codec_t *)ptr; + faacDecClose(aac->m_info); + aac->m_info = NULL; + +#if DUMP_OUTPUT_TO_FILE + fclose(aac->m_outfile); +#endif + free(aac); +} + +/* + * Handle pause - basically re-init the codec + */ +static void aac_do_pause (codec_data_t *ifptr) +{ + aac_codec_t *aac = (aac_codec_t *)ifptr; + aac->m_resync_with_header = 1; + aac->m_record_sync_time = 1; + aac->m_audio_inited = 0; + aac->m_ignore_first_sample = 0; + faacDecPostSeekReset(aac->m_info, 0); +} + +/* + * Decode task call for FAAC + */ +static int aac_decode (codec_data_t *ptr, + uint64_t ts, + int from_rtp, + int *sync_frame, + uint8_t *buffer, + uint32_t buflen, + void *userdata) +{ + aac_codec_t *aac = (aac_codec_t *)ptr; + unsigned long bytes_consummed; + int bits = -1; + // struct timezone tz; + + if (aac->m_record_sync_time) { + aac->m_current_frame = 0; + aac->m_record_sync_time = 0; + aac->m_current_time = ts; + aac->m_last_rtp_ts = ts; + } else { + if (aac->m_last_rtp_ts == ts) { + aac->m_current_time += aac->m_msec_per_frame; + aac->m_current_frame++; + } else { + aac->m_last_rtp_ts = ts; + aac->m_current_time = ts; + aac->m_current_frame = 0; + } + + // Note - here m_current_time should pretty much always be >= rtpts. + // If we're not, we most likely want to stop and resync. We don't + // need to keep decoding - just decode this frame and indicate we + // need a resync... That should handle fast forwards... We need + // someway to handle reverses - perhaps if we're more than .5 seconds + // later... + } + + if (aac->m_faad_inited == 0) { + /* + * If not initialized, do so. + */ + abort(); + unsigned long freq; + unsigned char chans; + + faacDecInit(aac->m_info, + (unsigned char *)buffer, + buflen, + &freq, + &chans); + aac->m_freq = freq; + aac->m_chans = chans; + aac->m_faad_inited = 1; + } + + uint8_t *buff; + unsigned long samples; + bytes_consummed = buflen; + //aa_message(LOG_DEBUG, aaclib, "decoding %d bits", buflen * 8); + faacDecFrameInfo frame_info; + buff = (uint8_t *)faacDecDecode(aac->m_info, + &frame_info, + buffer, + buflen); + if (buff != NULL) { + bytes_consummed = frame_info.bytesconsumed; +#if 0 + aa_message(LOG_DEBUG, aaclib, LLU" bytes %d samples %d", + ts, bytes_consummed, frame_info.samples); +#endif + if (aac->m_audio_inited != 0) { + int tempchans = frame_info.channels; + if (tempchans != aac->m_chans) { + aa_message(LOG_NOTICE, aaclib, "chupdate - chans from data is %d", + tempchans); + } + } else { + int tempchans = frame_info.channels; + + if (tempchans == 0) { + aa_message(LOG_ERR, aaclib, "initializing aac, returned channels are 0"); + aac->m_resync_with_header = 1; + aac->m_record_sync_time = 1; + return bytes_consummed; + } + aac->m_chans = tempchans; + aac->m_freq = frame_info.samplerate; + + aac->m_vft->audio_configure(aac->m_ifptr, + aac->m_freq, + aac->m_chans, + (audio_format_t)AUDIO_S16SYS, + aac->m_output_frame_size); + uint8_t *now = aac->m_vft->audio_get_buffer(aac->m_ifptr); + aac->m_audio_inited = 1; + } + /* + * good result - give it to audio sync class + */ +#if DUMP_OUTPUT_TO_FILE + fwrite(buff, aac->m_output_frame_size * 4, 1, aac->m_outfile); +#endif + if (frame_info.samples != 0) { + aac->m_vft->audio_load_buffer(aac->m_ifptr, + buff, + frame_info.samples * 2, + aac->m_last_ts, + aac->m_resync_with_header); + if (aac->m_resync_with_header == 1) { + aac->m_resync_with_header = 0; +#ifdef DEBUG_SYNC + aa_message(LOG_DEBUG, aaclib, "Back to good at "LLU, aac->m_current_time); +#endif + } + } + } else { + aa_message(LOG_ERR, aaclib, "error return is %d", frame_info.error); + aac->m_resync_with_header = 1; +#ifdef DEBUG_SYNC + aa_message(LOG_ERR, aaclib, "Audio decode problem - at "LLU, + aac->m_current_time); +#endif + } + aac->m_last_ts = aac->m_current_time; + return (bytes_consummed); +} + +static const char *aac_compressors[] = { + "aac ", + "mp4a", + "enca", + NULL +}; + +static int aac_codec_check (lib_message_func_t message, + const char *compressor, + int type, + int profile, + format_list_t *fptr, + const uint8_t *userdata, + uint32_t userdata_size +#ifdef HAVE_PLUGIN_VERSION_0_8 + ,CConfigSet *pConfig +#endif + ) +{ + fmtp_parse_t *fmtp = NULL; + if (compressor != NULL && + strcasecmp(compressor, "MP4 FILE") == 0 && + type != -1) { + switch (type) { + case MP4_MPEG2_AAC_MAIN_AUDIO_TYPE: + case MP4_MPEG2_AAC_LC_AUDIO_TYPE: + case MP4_MPEG2_AAC_SSR_AUDIO_TYPE: + case MP4_MPEG4_AUDIO_TYPE: + break; + default: + return -1; + } + } + if (fptr != NULL && + fptr->rtpmap != NULL && + fptr->rtpmap->encode_name != NULL) { + if (strcasecmp(fptr->rtpmap->encode_name, "mpeg4-generic") != 0) { + return -1; + } + if (userdata == NULL) { + fmtp = parse_fmtp_for_mpeg4(fptr->fmt_param, message); + if (fmtp != NULL) { + userdata = fmtp->config_binary; + userdata_size = fmtp->config_binary_len; + } + } + } + if (userdata != NULL) { + mpeg4_audio_config_t audio_config; + decode_mpeg4_audio_config(userdata, userdata_size, &audio_config); + message(LOG_DEBUG, "aac", "audio type is %d", audio_config.audio_object_type); + if (fmtp != NULL) free_fmtp_parse(fmtp); + + if (audio_object_type_is_aac(&audio_config) == 0) { + return -1; + } +#if 0 + if (audio_config.audio_object_type == 17) { + message(LOG_INFO, "aac", "audio type is legal ISMA, but not supported"); + return -1; + } +#endif + return 2; + } +#if 0 + // I'm not sure I want to be here if we don't have an audio config + if (compressor != NULL) { + const char **lptr = aac_compressors; + while (*lptr != NULL) { + if (strcasecmp(*lptr, compressor) == 0) { + return 2; + } + lptr++; + } + } +#endif + return -1; +} + +#ifndef HAVE_PLUGIN_VERSION_0_8 +AUDIO_CODEC_WITH_RAW_FILE_PLUGIN("faad2", + aac_codec_create, + aac_do_pause, + aac_decode, + NULL, + aac_close, + aac_codec_check, + aac_file_check, + aac_file_next_frame, + aac_file_used_for_frame, + aac_raw_file_seek_to, + aac_file_eof + ); +#else +AUDIO_CODEC_WITH_RAW_FILE_PLUGIN("faad2", + aac_codec_create, + aac_do_pause, + aac_decode, + NULL, + aac_close, + aac_codec_check, + aac_file_check, + aac_file_next_frame, + aac_file_used_for_frame, + aac_raw_file_seek_to, + aac_file_eof, + NULL, + 0 + ); +#endif +/* end file aa.cpp */ + + diff --git a/faad2/src/plugins/mpeg4ip/faad2.h b/faad2/src/plugins/mpeg4ip/faad2.h new file mode 100644 index 0000000..b74cdff --- /dev/null +++ b/faad2/src/plugins/mpeg4ip/faad2.h @@ -0,0 +1,92 @@ +/* +** MPEG4IP plugin for FAAD2 +** Copyright (C) 2003 Bill May wmay@cisco.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. +** +** $Id: faad2.h,v 1.2 2004/01/05 14:05:12 menno Exp $ +**/ +/* + * aa.h - class definition for AAC codec. + */ + +#ifndef __AA_H__ +#define __AA_H__ 1 +#include "faad.h" +#include "codec_plugin.h" + +#ifndef M_LLU +#define M_LLU M_64 +#define LLU U64 +#endif + +typedef struct aac_codec_t { + codec_data_t c; + audio_vft_t *m_vft; + void *m_ifptr; + faacDecHandle m_info; + int m_object_type; + int m_resync_with_header; + int m_record_sync_time; + uint64_t m_current_time; + uint64_t m_last_rtp_ts; + uint64_t m_msec_per_frame; + uint32_t m_current_frame; + int m_audio_inited; + int m_faad_inited; + int m_freq; // frequency + int m_chans; // channels + int m_output_frame_size; +#if DUMP_OUTPUT_TO_FILE + FILE *m_outfile; +#endif + FILE *m_ifile; + uint8_t *m_buffer; + uint32_t m_buffer_size_max; + uint32_t m_buffer_size; + uint32_t m_buffer_on; + uint64_t m_framecount; + int m_ignore_first_sample; + uint64_t m_last_ts; +} aac_codec_t; + +#define m_vft c.v.audio_vft +#define m_ifptr c.ifptr +#define MAX_READ_BUFFER (768 * 8) + +#define aa_message aac->m_vft->log_msg +void aac_close(codec_data_t *ptr); +extern const char *aaclib; + +codec_data_t *aac_file_check(lib_message_func_t message, + const char *name, + double *max, + char *desc[4] +#ifdef HAVE_PLUGIN_VERSION_0_8 + , CConfigSet *pConfig +#endif +); + +int aac_file_next_frame(codec_data_t *ifptr, + uint8_t **buffer, + uint64_t *ts); +int aac_file_eof(codec_data_t *ifptr); + +void aac_file_used_for_frame(codec_data_t *ifptr, + uint32_t bytes); + +int aac_raw_file_seek_to(codec_data_t *ifptr, + uint64_t ts); +#endif -- cgit v1.2.3