From b798cb803497cb9d60918fe1d6153696b364b07d Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 7 Jul 2017 16:32:55 +0200 Subject: Write statistics to yaml file, add option to stop after N frames --- src/etianalyse.cpp | 111 ++++++++++++++++++++++++++++++++++++++++++++--------- src/etianalyse.hpp | 26 +++++-------- src/etisnoop.cpp | 31 +++++++++------ src/utils.cpp | 13 +++++++ src/utils.hpp | 3 ++ 5 files changed, 136 insertions(+), 48 deletions(-) (limited to 'src') 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 +#include #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 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 streams_to_decode; std::list > 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 \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 +#include #include #include #include @@ -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); -- cgit v1.2.3