aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/etianalyse.cpp111
-rw-r--r--src/etianalyse.hpp26
-rw-r--r--src/etisnoop.cpp31
-rw-r--r--src/utils.cpp13
-rw-r--r--src/utils.hpp3
5 files changed, 136 insertions, 48 deletions
diff --git a/src/etianalyse.cpp b/src/etianalyse.cpp
index b79827b..af7959a 100644
--- a/src/etianalyse.cpp
+++ b/src/etianalyse.cpp
@@ -29,6 +29,7 @@
#endif
#include <algorithm>
+#include <cassert>
#include "etianalyse.hpp"
#include "etiinput.hpp"
#include "figs.hpp"
@@ -100,6 +101,7 @@ void ETI_Analyser::eti_analyse()
static int last_fct = -1;
bool running = true;
+ size_t num_frames = 0;
int stream_type = ETI_STREAM_TYPE_NONE;
if (identify_eti_format(config.etifd, &stream_type) == -1) {
@@ -123,6 +125,16 @@ void ETI_Analyser::eti_analyse()
rate_display_header(config.analyse_fig_rates_per_second);
}
+ FILE *stat_fd = nullptr;
+ if (not config.statistics_filename.empty()) {
+ stat_fd = fopen(config.statistics_filename.c_str(), "w");
+ if (stat_fd == nullptr) {
+ fprintf(stderr, "Could not open statistics file: %s\n",
+ strerror(errno));
+ return;
+ }
+ }
+
while (running) {
int ret = get_eti_frame(config.etifd, stream_type, p);
@@ -500,35 +512,96 @@ void ETI_Analyser::eti_analyse()
rate_display_analysis(false, config.analyse_fig_rates_per_second);
}
- if (config.statistics) {
- for (const auto& snoop : config.streams_to_decode) {
- printf("Statistics for %d:\n", snoop.first);
-
- for (const auto& service : ensemble.services) {
- for (const auto& component : service.components) {
- if (component.subchId == snoop.first and
- component.primary) {
- printf("Label %s\n", service.label.c_str());
- if (not component.label.empty()) {
- printf("Component label %s\n", component.label.c_str());
+ num_frames++;
+ if (config.num_frames_to_decode > 0 and
+ num_frames >= config.num_frames_to_decode) {
+ printf("Decoded %zu ETI frames\n", num_frames);
+ break;
+ }
+
+ if (quit.load()) running = false;
+ }
+
+ if (config.statistics) {
+ assert(stat_fd != nullptr);
+
+ fprintf(stat_fd, "# Statistics from ETISnoop. This file should be valid YAML\n");
+ fprintf(stat_fd, "---\n");
+ fprintf(stat_fd, "ensemble:\n");
+ fprintf(stat_fd, " id: 0x%x\n", ensemble.EId);
+ fprintf(stat_fd, " label: %s\n", ensemble.label.c_str());
+ fprintf(stat_fd, " shortlabel: %s\n",
+ flag_to_shortlabel(ensemble.label, ensemble.shortlabel_flag).c_str());
+ fprintf(stat_fd, "audio:\n");
+
+ for (const auto& snoop : config.streams_to_decode) {
+ bool corresponding_service_found = false;
+
+ for (const auto& service : ensemble.services) {
+ for (const auto& component : service.components) {
+ if (component.subchId == snoop.second.subchid and
+ component.primary) {
+ corresponding_service_found = true;
+ fprintf(stat_fd, " - service_id: 0x%x\n", service.id);
+ fprintf(stat_fd, " subchannel_id: 0x%x\n", component.subchId);
+ fprintf(stat_fd, " label: %s\n", service.label.c_str());
+ fprintf(stat_fd, " shortlabel: %s\n",
+ flag_to_shortlabel(service.label, service.shortlabel_flag).c_str());
+ if (not component.label.empty()) {
+ fprintf(stat_fd, " component_label: %s\n", component.label.c_str());
+ }
+
+ try {
+ const auto& subch = ensemble.get_subchannel(component.subchId);
+ fprintf(stat_fd, " subchannel:\n");
+ fprintf(stat_fd, " id: %d\n", subch.id);
+ fprintf(stat_fd, " SAd: %d\n", subch.start_addr);
+ switch (subch.protection_type) {
+ case ensemble_database::subchannel_t::protection_type_t::EEP:
+ if (subch.protection_option == 0) {
+ fprintf(stat_fd, " protection: EEP %d-A\n", subch.protection_level);
+ }
+ else if (subch.protection_option == 0) {
+ fprintf(stat_fd, " protection: EEP %d-B\n", subch.protection_level);
+ }
+ else {
+ fprintf(stat_fd, " protection: unknown\n");
+ }
+
+ fprintf(stat_fd, " size: %d\n", subch.size);
+ break;
+ case ensemble_database::subchannel_t::protection_type_t::UEP:
+ fprintf(stat_fd, " table_switch: %d\n", subch.table_switch);
+ fprintf(stat_fd, " table_index: %d\n", subch.table_index);
+ break;
}
}
+ catch (ensemble_database::not_found &e)
+ {
+ fprintf(stat_fd, " subchannel: not found\n");
+ }
}
}
+ }
- const auto& stat = snoop.second.get_audio_statistics();
- printf(" Avg L/R: %d %d dB ",
- absolute_to_dB(stat.average_level_left),
- absolute_to_dB(stat.average_level_right));
- printf(" Peak L/R: %d %d dB\n",
- absolute_to_dB(stat.peak_level_left),
- absolute_to_dB(stat.peak_level_right));
+ if (not corresponding_service_found) {
+ fprintf(stat_fd, " - service_id: unknown\n");
}
+
+ const auto& stat = snoop.second.get_audio_statistics();
+ fprintf(stat_fd, " audio:\n");
+ fprintf(stat_fd, " average: %d %d\n",
+ absolute_to_dB(stat.average_level_left),
+ absolute_to_dB(stat.average_level_right));
+ fprintf(stat_fd, " peak: %d %d\n",
+ absolute_to_dB(stat.peak_level_left),
+ absolute_to_dB(stat.peak_level_right));
}
- if (quit.load()) running = false;
+ fclose(stat_fd);
}
+
if (config.decode_watermark) {
std::string watermark(wm_decoder.calculate_watermark());
printf("Watermark:\n %s\n", watermark.c_str());
diff --git a/src/etianalyse.hpp b/src/etianalyse.hpp
index fb17c8f..8024063 100644
--- a/src/etianalyse.hpp
+++ b/src/etianalyse.hpp
@@ -45,25 +45,17 @@
extern std::atomic<bool> quit;
struct eti_analyse_config_t {
- eti_analyse_config_t() :
- etifd(nullptr),
- ignore_error(false),
- streams_to_decode(),
- analyse_fic_carousel(false),
- analyse_fig_rates(false),
- analyse_fig_rates_per_second(false),
- decode_watermark(false),
- statistics(false) {}
-
- FILE* etifd;
- bool ignore_error;
+ FILE* etifd = nullptr;
+ bool ignore_error = false;
std::map<int, StreamSnoop> streams_to_decode;
std::list<std::pair<int, int> > figs_to_display;
- bool analyse_fic_carousel;
- bool analyse_fig_rates;
- bool analyse_fig_rates_per_second;
- bool decode_watermark;
- bool statistics;
+ bool analyse_fic_carousel = false;
+ bool analyse_fig_rates = false;
+ bool analyse_fig_rates_per_second = false;
+ bool decode_watermark = false;
+ bool statistics = false;
+ std::string statistics_filename;
+ size_t num_frames_to_decode = 0; // 0 means forever
bool is_fig_to_be_printed(int type, int extension) const;
};
diff --git a/src/etisnoop.cpp b/src/etisnoop.cpp
index 4c0645f..b94d0d7 100644
--- a/src/etisnoop.cpp
+++ b/src/etisnoop.cpp
@@ -57,9 +57,6 @@
using namespace std;
-const char *get_programme_type_str(size_t int_table_Id, size_t pty);
-int sprintfMJD(char *dst, int mjd);
-
static void handle_signal(int)
{
quit.store(true);
@@ -70,14 +67,15 @@ static void handle_signal(int)
#define optional_argument 2
const struct option longopts[] = {
{"analyse-figs", no_argument, 0, 'f'},
+ {"decode-stream", required_argument, 0, 'd'},
+ {"filter-fig", required_argument, 0, 'F'},
{"help", no_argument, 0, 'h'},
{"ignore-error", no_argument, 0, 'e'},
+ {"input", required_argument, 0, 'i'},
{"input-file", no_argument, 0, 'i'},
- {"statistics", no_argument, 0, 's'},
+ {"num-frames", required_argument, 0, 'n'},
+ {"statistics", required_argument, 0, 's'},
{"verbose", no_argument, 0, 'v'},
- {"decode-stream", required_argument, 0, 'd'},
- {"filter-fig", required_argument, 0, 'F'},
- {"input", required_argument, 0, 'i'}
};
void usage(void)
@@ -93,7 +91,9 @@ void usage(void)
"\n"
" -v increase verbosity (can be given more than once)\n"
" -d N decode subchannel N into .msc file and if DAB+, decode to .wav file\n"
- " -s statistic mode: decode all subchannels and measure audio level\n"
+ " -s <filename.yaml>\n"
+ " statistics mode: decode all subchannels and measure audio level, write statistics to file\n"
+ " -n N stop analysing after N ETI frames\n"
" -f analyse FIC carousel\n"
" -r analyse FIG rates in FIGs per second\n"
" -R analyse FIG rates in frames per FIG\n"
@@ -125,7 +125,7 @@ int main(int argc, char *argv[])
eti_analyse_config_t config;
while(ch != -1) {
- ch = getopt_long(argc, argv, "d:efF:hrRsvwi:", longopts, &index);
+ ch = getopt_long(argc, argv, "d:efF:hi:n:rRs:vw", longopts, &index);
switch (ch) {
case 'd':
{
@@ -138,9 +138,6 @@ int main(int argc, char *argv[])
case 'e':
config.ignore_error = true;
break;
- case 'i':
- file_name = optarg;
- break;
case 'f':
config.analyse_fic_carousel = true;
break;
@@ -164,6 +161,12 @@ int main(int argc, char *argv[])
config.figs_to_display.emplace_back(type, extension);
}
break;
+ case 'i':
+ file_name = optarg;
+ break;
+ case 'n':
+ config.num_frames_to_decode = std::atoi(optarg);
+ break;
case 'r':
config.analyse_fig_rates = true;
config.analyse_fig_rates_per_second = true;
@@ -174,6 +177,7 @@ int main(int argc, char *argv[])
break;
case 's':
config.statistics = true;
+ config.statistics_filename = optarg;
break;
case 'v':
set_verbosity(get_verbosity() + 1);
@@ -181,6 +185,9 @@ int main(int argc, char *argv[])
case 'w':
config.decode_watermark = true;
break;
+ case -1:
+ break;
+ default:
case 'h':
usage();
return 1;
diff --git a/src/utils.cpp b/src/utils.cpp
index d0c1273..90231ce 100644
--- a/src/utils.cpp
+++ b/src/utils.cpp
@@ -29,6 +29,7 @@
#include "utils.hpp"
#include <cstring>
+#include <sstream>
#include <cmath>
#include <limits>
#include <stdarg.h>
@@ -237,3 +238,15 @@ int absolute_to_dB(int16_t value)
return value ? round(20*log10((double)value / int16_max)) : -90;
}
+std::string flag_to_shortlabel(const std::string& label, uint16_t flag)
+{
+ stringstream shortlabel;
+ for (size_t i = 0; i < label.size(); ++i) {
+ if (flag & 0x8000 >> i) {
+ shortlabel << label[i];
+ }
+ }
+
+ return shortlabel.str();
+}
+
diff --git a/src/utils.hpp b/src/utils.hpp
index 3ff9f13..fdb673e 100644
--- a/src/utils.hpp
+++ b/src/utils.hpp
@@ -85,3 +85,6 @@ std::string pnum_to_str(uint16_t Programme_Number);
// Convert and absolute 16-bit int value to dB. If value is zero, returns
// -90dB
int absolute_to_dB(int16_t value);
+
+// Calculate the shortlabel from the label and the flag
+std::string flag_to_shortlabel(const std::string& label, uint16_t flag);