diff options
author | Matthias P. Braendli <matthias.braendli@mpb.li> | 2014-11-17 09:21:27 +0100 |
---|---|---|
committer | Matthias P. Braendli <matthias.braendli@mpb.li> | 2014-11-17 09:21:27 +0100 |
commit | 90e2e9e59dd38d075c6f95629f1087e24954a327 (patch) | |
tree | f70d99fd64f447347410905a5eaf65912cdd4eec | |
parent | 3a8c93167b5879b1811e9b609227acbfe382a126 (diff) | |
download | etisnoop-90e2e9e59dd38d075c6f95629f1087e24954a327.tar.gz etisnoop-90e2e9e59dd38d075c6f95629f1087e24954a327.tar.bz2 etisnoop-90e2e9e59dd38d075c6f95629f1087e24954a327.zip |
Etisnoop add faad_decoder
-rw-r--r-- | Makefile | 11 | ||||
-rw-r--r-- | dabplussnoop.cpp | 101 | ||||
-rw-r--r-- | dabplussnoop.h | 34 | ||||
-rw-r--r-- | etisnoop.cpp | 4 | ||||
-rw-r--r-- | faad_decoder.cpp | 243 | ||||
-rw-r--r-- | faad_decoder.h | 86 |
6 files changed, 377 insertions, 102 deletions
@@ -1,13 +1,16 @@ CC=g++ -SOURCES=etisnoop.cpp dabplussnoop.cpp lib_crc.c firecode.c -HEADERS=dabplussnoop.h lib_crc.h firecode.h +SOURCES=etisnoop.cpp dabplussnoop.cpp lib_crc.c firecode.c faad_decoder.cpp +HEADERS=dabplussnoop.h lib_crc.h firecode.h faad_decoder.h all: etisnoop -etisnoop: $(SOURCES) $(HEADERS) - $(CC) -Wall -ggdb $(SOURCES) $(HEADERS) -o etisnoop +libfaad: + make -C ./faad2-2.7 + +etisnoop: libfaad $(SOURCES) $(HEADERS) + $(CC) -Wall -ggdb $(SOURCES) $(HEADERS) faad2-2.7/libfaad/.libs/libfaad.a -o etisnoop clean: rm -f etisnoop *.o diff --git a/dabplussnoop.cpp b/dabplussnoop.cpp index c0fbcca..2fc9454 100644 --- a/dabplussnoop.cpp +++ b/dabplussnoop.cpp @@ -33,6 +33,7 @@ #include "dabplussnoop.h" #include "firecode.h" #include "lib_crc.h" +#include "faad_decoder.h" #define DPS_INDENT "\t\t" #define DPS_PREFIX "DAB+ decode:" @@ -117,21 +118,21 @@ bool DabPlusSnoop::decode() // ------ Parse firecode and audio params uint16_t header_firecode = (b[0] << 8) | b[1]; uint8_t audio_params = b[2]; - int rfa = (audio_params & 0x80) ? 1 : 0; - int dac_rate = (audio_params & 0x40) ? 1 : 0; - int sbr_flag = (audio_params & 0x20) ? 1 : 0; - int aac_channel_mode = (audio_params & 0x10) ? 1 : 0; - int ps_flag = (audio_params & 0x08) ? 1 : 0; - int mpeg_surround_config = (audio_params & 0x07) ? 1 : 0; + int rfa = (audio_params & 0x80) ? true : false; + m_dac_rate = (audio_params & 0x40) ? true : false; + m_sbr_flag = (audio_params & 0x20) ? true : false; + m_aac_channel_mode = (audio_params & 0x10) ? true : false; + m_ps_flag = (audio_params & 0x08) ? true : false; + m_mpeg_surround_config = (audio_params & 0x07); int num_aus; - if ((dac_rate == 0) && (sbr_flag == 1)) num_aus = 2; + if (!m_dac_rate && m_sbr_flag) num_aus = 2; // AAC core sampling rate 16 kHz - else if ((dac_rate == 1) && (sbr_flag == 1)) num_aus = 3; + else if (m_dac_rate && m_sbr_flag) num_aus = 3; // AAC core sampling rate 24 kHz - else if ((dac_rate == 0) && (sbr_flag == 0)) num_aus = 4; + else if (m_dac_rate && !m_sbr_flag) num_aus = 4; // AAC core sampling rate 32 kHz - else if ((dac_rate == 1) && (sbr_flag == 0)) num_aus = 6; + else if (m_dac_rate && !m_sbr_flag) num_aus = 6; // AAC core sampling rate 48 kHz printf( DPS_INDENT DPS_PREFIX "\n" @@ -143,8 +144,9 @@ bool DabPlusSnoop::decode() DPS_INDENT "\tps_flag %d\n" DPS_INDENT "\tmpeg_surround_config %d\n" DPS_INDENT "\tnum_aus %d\n", - header_firecode, rfa, dac_rate, sbr_flag, aac_channel_mode, - ps_flag, mpeg_surround_config, num_aus); + header_firecode, rfa, m_dac_rate, m_sbr_flag, + m_aac_channel_mode, m_ps_flag, m_mpeg_surround_config, + num_aus); // ------ Parse au_start @@ -262,78 +264,15 @@ bool DabPlusSnoop::extract_au(vector<int> au_start) bool DabPlusSnoop::analyse_au(vector<vector<uint8_t> >& aus) { - for (size_t i_au = 0; i_au < aus.size(); i_au++) { - size_t i = 0; - - vector<uint8_t>& au = aus[i_au]; - - bool continue_au = true; - while (continue_au && i < au.size()) { - printf("R at %zu\n", i); - int id_syn_ele = (au[i] & 0xE0) >> 5; - - /* Debugging print */ - stringstream ss; - ss << DPS_INDENT << "\tID_SYN_ELE: "; - - switch (id_syn_ele) { - case ID_SCE: ss << "Single Channel Element"; break; - case ID_CPE: ss << "Channel Pair Element"; break; - case ID_CCE: ss << "Coupling Channel Element"; break; - case ID_LFE: ss << "LFE Channel Element"; break; - case ID_DSE: ss << "Data Stream Element"; break; - case ID_PCE: ss << "Program Config Element"; break; - case ID_FIL: ss << "Fill Element"; break; - case ID_END: ss << "Terminator"; break; - case ID_EXT: ss << "Extension Payload"; break; - case ID_SCAL: ss << "AAC scalable element"; break; - default: ss << "Unknown (" << id_syn_ele << ")"; break; - } - - int element_instance_tag = (au[i] & 0x78) >> 1; - ss << " [" << element_instance_tag << "]"; - - - // Keep track of index increment in bits - size_t inc = 7; // eat id_syn_ele, element_instance_tag - - if (id_syn_ele == ID_DSE) { - bool data_byte_align_flag = (au[i] & 0x01); - inc++; - - ss << "\n" DPS_INDENT "\t\t"; - if (data_byte_align_flag) { - ss << " <byte align flag>"; - } - - - uint8_t count = au[1]; - int cnt = count; - inc += 8; + stringstream ss_filename; - if (count == 255) { - uint8_t esc_count = au[2]; - inc += 8; + ss_filename << "stream-" << m_index << ".wav"; - cnt += esc_count; - } + FaadDecoder new_decoder(ss_filename.str(), m_ps_flag, m_aac_channel_mode, + m_dac_rate, m_sbr_flag, m_mpeg_surround_config); - ss << " cnt:" << cnt; - inc += 8*cnt; - - } - else - { - continue_au = false; - } - - printf("%s\n", ss.str().c_str()); - - assert (inc % 8 == 0); - i += inc / 8; - } - } + faad_decoder = new_decoder; - return true; + return faad_decoder.Decode(aus); } diff --git a/dabplussnoop.h b/dabplussnoop.h index 28f94ba..bb4d2cb 100644 --- a/dabplussnoop.h +++ b/dabplussnoop.h @@ -76,31 +76,17 @@ he_aac_super_frame(subchannel_index) #include <string> #include <sstream> #include <vector> +#include "faad_decoder.h" #ifndef __DABPLUSSNOOP_H_ #define __DABPLUSSNOOP_H_ -/** MP4 Element IDs. */ -typedef enum -{ - ID_NONE = -1, /**< Invalid Element helper ID. */ - ID_SCE = 0, /**< Single Channel Element. */ - ID_CPE = 1, /**< Channel Pair Element. */ - ID_CCE = 2, /**< Coupling Channel Element. */ - ID_LFE = 3, /**< LFE Channel Element. */ - ID_DSE = 4, /**< Currently one Data Stream Element for ancillary data is supported. */ - ID_PCE = 5, /**< Program Config Element. */ - ID_FIL = 6, /**< Fill Element. */ - ID_END = 7, /**< Arnie (End Element = Terminator). */ - ID_EXT = 8, /**< Extension Payload (ER only). */ - ID_SCAL = 9, /**< AAC scalable element (ER only). */ - ID_LAST -} MP4_ELEMENT_ID; class DabPlusSnoop { public: DabPlusSnoop() : + m_index(0), m_subchannel_index(0), m_data(0) {} @@ -109,9 +95,25 @@ class DabPlusSnoop m_subchannel_index = subchannel_index; } + void set_index(int index) + { + m_index = index; + } + void push(uint8_t* streamdata, size_t streamsize); private: + /* Data needed for FAAD */ + FaadDecoder faad_decoder; + int m_index; + + bool m_ps_flag; + bool m_aac_channel_mode; + bool m_dac_rate; + bool m_sbr_flag; + int m_mpeg_surround_config; + + /* Functions */ bool seek_valid_firecode(void); bool decode(void); bool extract_au(std::vector<int> au_start); diff --git a/etisnoop.cpp b/etisnoop.cpp index e81741e..5e3188c 100644 --- a/etisnoop.cpp +++ b/etisnoop.cpp @@ -103,8 +103,9 @@ int main(int argc, char *argv[]) switch (ch) { case 'd': { + int subchix = atoi(optarg); DabPlusSnoop dps; - streams_to_decode[atoi(optarg)] = dps; + streams_to_decode[subchix] = dps; } break; case 'e': @@ -346,6 +347,7 @@ int eti_analyse(eti_analyse_config_t& config) if (config.streams_to_decode.count(i) > 0) { config.streams_to_decode[i].set_subchannel_index(stl[i]/3); + config.streams_to_decode[i].set_index(i); } } diff --git a/faad_decoder.cpp b/faad_decoder.cpp new file mode 100644 index 0000000..6e80d4e --- /dev/null +++ b/faad_decoder.cpp @@ -0,0 +1,243 @@ +/* + Copyright (C) 2014 Matthias P. Braendli (http://www.opendigitalradio.org) + + 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 3 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, see <http://www.gnu.org/licenses/>. + + faad_decoder.cpp + Use libfaad to decode the AAC content of the DAB+ subchannel + + Authors: + Matthias P. Braendli <matthias@mpb.li> +*/ + +#include "faad_decoder.h" +#include "utils.h" +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <string> +#include <sstream> +#include <vector> + +using namespace std; + +FaadDecoder::FaadDecoder() : + m_filename(""), + m_ps_flag(0), + m_aac_channel_mode(0), + m_dac_rate(0), + m_sbr_flag(0), + m_mpeg_surround_config(0), + m_initialised(false) +{ + m_decoder = NULL; +} + +FaadDecoder::FaadDecoder(string filename, bool ps_flag, bool aac_channel_mode, + bool dac_rate, bool sbr_flag, int mpeg_surround_config) : + m_filename(filename), + m_ps_flag(ps_flag), + m_aac_channel_mode(aac_channel_mode), + m_dac_rate(dac_rate), + m_sbr_flag(sbr_flag), + m_mpeg_surround_config(mpeg_surround_config), + m_initialised(false) +{ + + m_decoder = NeAACDecOpen(); + + m_fd = fopen(m_filename.c_str(), "w"); + +#if 0 + NeAACDecConfigurationPtr config; + + config = NeAACDecGetCurrentConfiguration(m_decoder); + if (def_srate) + config->defSampleRate = def_srate; + config->defObjectType = object_type; + config->outputFormat = outputFormat; + config->downMatrix = downMatrix; + config->useOldADTSFormat = old_format; + //config->dontUpSampleImplicitSBR = 1; + NeAACDecSetConfiguration(m_decoder, config); +#endif +} + +size_t FaadDecoder::Decode(vector<vector<uint8_t> > aus) +{ + if (!m_decoder) { + return 2; + } + + /* ADTS header creation taken from SDR-J */ + adts_fixed_header fh; + adts_variable_header vh; + + fh.syncword = 0xfff; + fh.id = 0; + fh.layer = 0; + fh.protection_absent = 1; + fh.profile_objecttype = 0; // aac main - 1 + fh.private_bit = 0; // ignored when decoding + fh.original_copy = 0; + fh.home = 0; + vh.copyright_id_bit = 0; + vh.copyright_id_start = 0; + vh.adts_buffer_fullness = 1999; // ? according to OpenDab + vh.no_raw_data_blocks = 0; + + uint8_t d_header[10]; + d_header[0] = fh.syncword >> 4; + d_header[1] = (fh.syncword & 0xf) << 4; + d_header[1] |= fh.id << 3; + d_header[1] |= fh.layer << 1; + d_header[1] |= fh.protection_absent; + d_header[2] = fh.profile_objecttype << 6; + // sampling frequency index filled in dynamically + d_header[2] |= fh.private_bit << 1; + // channel configuration filled in dynamically + d_header[3] = fh.original_copy << 5; + d_header[3] |= fh.home << 4; + d_header[3] |= vh.copyright_id_bit << 3; + d_header[3] |= vh.copyright_id_start << 2; + // framelength filled in dynamically + d_header[4] = 0; + d_header[5] = vh.adts_buffer_fullness >> 6; + d_header[6] = (vh.adts_buffer_fullness & 0x3f) << 2; + d_header[6] |= vh.no_raw_data_blocks; + + if (!m_dac_rate && m_sbr_flag) fh.sampling_freq_idx = 8; + // AAC core sampling rate 16 kHz + else if (m_dac_rate && m_sbr_flag) fh.sampling_freq_idx = 6; + // AAC core sampling rate 24 kHz + else if (m_dac_rate && !m_sbr_flag) fh.sampling_freq_idx = 5; + // AAC core sampling rate 32 kHz + else if (m_dac_rate && !m_sbr_flag) fh.sampling_freq_idx = 3; + // AAC core sampling rate 48 kHz + + setBits (&d_header[2], fh.sampling_freq_idx, 2, 4); + + if (m_mpeg_surround_config == 0) { + if (m_sbr_flag && !m_aac_channel_mode && m_ps_flag) + fh.channel_conf = 2; + else + fh.channel_conf = 1 << (m_aac_channel_mode ? 1 : 0); + } + else if (m_mpeg_surround_config == 1) { + fh.channel_conf = 6; + } + else { + printf("Unrecognized mpeg surround config (ignored)\n"); + return 1; + } + + setBits (&d_header[2], fh.channel_conf, 7, 3); + + + for (size_t au_ix = 0; au_ix < aus.size(); au_ix++) { + + vector<uint8_t>& au = aus[au_ix]; + + uint8_t helpBuffer[960]; + memset(helpBuffer, 0, sizeof(helpBuffer)); + + // Set length in header + vh.aac_frame_length = au.size(); + setBits(&d_header[3], vh.aac_frame_length, 6, 13); + + memcpy(helpBuffer, d_header, 7 * sizeof(uint8_t)); + memcpy(&helpBuffer[7], + &au[0], vh.aac_frame_length * sizeof (uint8_t)); + + + + long unsigned samplerate; + unsigned char channels; + NeAACDecFrameInfo hInfo; + int16_t* outBuffer; + + if (!m_initialised) { + int len; + + if ((len = NeAACDecInit(m_decoder, helpBuffer, + vh.aac_frame_length, &samplerate, &channels)) < 0) + { + /* If some error initializing occured, skip the file */ + printf("Error initializing decoder library (%d).\n", + len); + NeAACDecClose(m_decoder); + return 1; + } + + m_initialised = true; + + outBuffer = (int16_t *)NeAACDecDecode( + m_decoder, &hInfo, + helpBuffer + len, vh.aac_frame_length - len ); + } + else { + outBuffer = (int16_t *)NeAACDecDecode( + m_decoder, &hInfo, + helpBuffer, vh.aac_frame_length ); + } + + int sample_rate = hInfo.samplerate; + size_t samples = hInfo.samples; + + printf("bytes consumed %d\n", (int)(hInfo.bytesconsumed)); + printf("samplerate = %d, samples = %zu, channels = %d," + " error = %d, sbr = %d\n", sample_rate, samples, + hInfo.channels, hInfo.error, hInfo.sbr); + printf("header = %d\n", hInfo.header_type); + + //channels = hInfo.channels; + if (hInfo.error != 0) { + printf("FAAD Warning: %s\n", + faacDecGetErrorMessage(hInfo.error)); + return 1; + } + + if (channels == 2) { + fwrite(outBuffer, 1, samples, m_fd); + } + else { + if (channels == 1) { + int16_t *buffer = (int16_t *)alloca (2 * samples); + int16_t i; + for (i = 0; i < samples; i ++) { + buffer [2 * i] = ((int16_t *)outBuffer) [i]; + buffer [2 * i + 1] = buffer [2 * i]; + } + fwrite(outBuffer, 2, samples, m_fd); + } + else { + printf("Cannot handle these channels\n"); + } + } + + } + return 0; +} + + +FaadDecoder::~FaadDecoder() +{ + if (m_decoder) { + NeAACDecClose(m_decoder); + + fclose(m_fd); + } +} + diff --git a/faad_decoder.h b/faad_decoder.h new file mode 100644 index 0000000..10e9717 --- /dev/null +++ b/faad_decoder.h @@ -0,0 +1,86 @@ +/* + Copyright (C) 2014 Matthias P. Braendli (http://www.opendigitalradio.org) + + 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 3 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, see <http://www.gnu.org/licenses/>. + + faad_decoder.h + Use libfaad to decode the AAC content of the DAB+ subchannel + + Authors: + Matthias P. Braendli <matthias@mpb.li> +*/ + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <string> +#include <sstream> +#include <vector> +#include <neaacdec.h> + +#ifndef __FAAD_DECODER_H_ +#define __FAAD_DECODER_H_ + +struct adts_fixed_header { + unsigned int syncword :12; + unsigned int id :1; + unsigned int layer :2; + unsigned int protection_absent :1; + unsigned int profile_objecttype :2; + unsigned int sampling_freq_idx :4; + unsigned int private_bit :1; + unsigned int channel_conf :3; + unsigned int original_copy :1; + unsigned int home :1; +}; + +struct adts_variable_header { + unsigned int copyright_id_bit :1; + unsigned int copyright_id_start :1; + unsigned int aac_frame_length :13; + unsigned int adts_buffer_fullness :11; + unsigned int no_raw_data_blocks :2; +}; + +class FaadDecoder +{ + public: + FaadDecoder(); + + FaadDecoder(std::string filename, bool ps_flag, bool aac_channel_mode, + bool dac_rate, bool sbr_flag, int mpeg_surround_config); + + size_t Decode(std::vector<std::vector<uint8_t> > aus); + + ~FaadDecoder(void); + + + private: + std::string m_filename; + FILE* m_fd; + + /* Data needed for FAAD */ + bool m_ps_flag; + bool m_aac_channel_mode; + bool m_dac_rate; + bool m_sbr_flag; + int m_mpeg_surround_config; + + bool m_initialised; + NeAACDecHandle m_decoder; +}; + +#endif + |