summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2014-11-17 09:21:27 +0100
committerMatthias P. Braendli <matthias.braendli@mpb.li>2014-11-17 09:21:27 +0100
commit90e2e9e59dd38d075c6f95629f1087e24954a327 (patch)
treef70d99fd64f447347410905a5eaf65912cdd4eec
parent3a8c93167b5879b1811e9b609227acbfe382a126 (diff)
downloadetisnoop-90e2e9e59dd38d075c6f95629f1087e24954a327.tar.gz
etisnoop-90e2e9e59dd38d075c6f95629f1087e24954a327.tar.bz2
etisnoop-90e2e9e59dd38d075c6f95629f1087e24954a327.zip
Etisnoop add faad_decoder
-rw-r--r--Makefile11
-rw-r--r--dabplussnoop.cpp101
-rw-r--r--dabplussnoop.h34
-rw-r--r--etisnoop.cpp4
-rw-r--r--faad_decoder.cpp243
-rw-r--r--faad_decoder.h86
6 files changed, 377 insertions, 102 deletions
diff --git a/Makefile b/Makefile
index f6a68b1..2b710f3 100644
--- a/Makefile
+++ b/Makefile
@@ -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
+