summaryrefslogtreecommitdiff
path: root/faad2/src/plugins/mpeg4ip/faad2.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'faad2/src/plugins/mpeg4ip/faad2.cpp')
-rw-r--r--faad2/src/plugins/mpeg4ip/faad2.cpp388
1 files changed, 388 insertions, 0 deletions
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 <mpeg4_audio_config.h>
+#include <mpeg4_sdp.h>
+#include <mp4.h>
+#include <SDL/SDL.h>
+
+#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 */
+
+