From 1d833b718845b97a5b1d90f33b547b1772bc0708 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Sun, 7 Jan 2018 08:49:29 +0100 Subject: Add new flowgraph path for metadata --- src/OutputFile.h | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'src/OutputFile.h') diff --git a/src/OutputFile.h b/src/OutputFile.h index 7121ef3..2b92369 100644 --- a/src/OutputFile.h +++ b/src/OutputFile.h @@ -2,7 +2,7 @@ Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Her Majesty the Queen in Right of Canada (Communications Research Center Canada) - Copyright (C) 2016 + Copyright (C) 2018 Matthias P. Braendli, matthias.braendli@mpb.li http://opendigitalradio.org @@ -36,19 +36,29 @@ #include #include #include +#include +struct FILEDeleter { + void operator()(FILE* fd) { + if (fd) { + fclose(fd); + } + } +}; -class OutputFile : public ModOutput +class OutputFile : public ModOutput, public ModMetadata { public: OutputFile(std::string filename); - virtual ~OutputFile(); - virtual int process(Buffer* dataIn); - const char* name() { return "OutputFile"; } + virtual int process(Buffer* dataIn) override; + const char* name() override { return "OutputFile"; } + + virtual meta_vec_t process_metadata( + const meta_vec_t& metadataIn) override; protected: std::string myFilename; - FILE* myFile; + std::unique_ptr myFile; }; -- cgit v1.2.3 From 23b369e1145c5652778345827b7df9c33e09d0e8 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Sun, 7 Jan 2018 09:21:25 +0100 Subject: Add metadata latency for all PipelinedModCodec --- src/DabMod.cpp | 6 ++++++ src/ModPlugin.cpp | 19 ++++++++++++++++--- src/ModPlugin.h | 52 +++++++++++++++++++++++++++++++--------------------- src/OutputFile.cpp | 22 +++++++++++++--------- src/OutputFile.h | 6 ++++++ 5 files changed, 72 insertions(+), 33 deletions(-) (limited to 'src/OutputFile.h') diff --git a/src/DabMod.cpp b/src/DabMod.cpp index 25a93bf..4a4ea82 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -426,6 +426,12 @@ int launch_modulator(int argc, char* argv[]) } #endif + // TODO remove + auto output_as_file = dynamic_pointer_cast(output); + if (output_as_file) { + output_as_file->setETISource(modulator->getEtiSource()); + } + inputReader->PrintInfo(); run_modulator_state_t st = run_modulator(m); diff --git a/src/ModPlugin.cpp b/src/ModPlugin.cpp index c39d883..f86bfb2 100644 --- a/src/ModPlugin.cpp +++ b/src/ModPlugin.cpp @@ -74,9 +74,9 @@ int ModOutput::process( PipelinedModCodec::PipelinedModCodec() : ModCodec(), - m_number_of_runs(0), m_input_queue(), m_output_queue(), + m_metadata_fifo(), m_running(false), m_thread() { @@ -107,7 +107,7 @@ int PipelinedModCodec::process(Buffer* dataIn, Buffer* dataOut) m_input_queue.push(inbuffer); - if (m_number_of_runs > 0) { + if (m_ready_to_output_data) { std::shared_ptr outbuffer; m_output_queue.wait_and_pop(outbuffer); @@ -116,13 +116,26 @@ int PipelinedModCodec::process(Buffer* dataIn, Buffer* dataOut) else { dataOut->setLength(dataIn->getLength()); memset(dataOut->getData(), 0, dataOut->getLength()); - m_number_of_runs++; + m_ready_to_output_data = true; } return dataOut->getLength(); } +meta_vec_t PipelinedModCodec::process_metadata(const meta_vec_t& metadataIn) +{ + m_metadata_fifo.push_back(metadataIn); + if (m_metadata_fifo.size() == 2) { + auto r = std::move(m_metadata_fifo.front()); + m_metadata_fifo.pop_front(); + return r; + } + else { + return {}; + } +} + void PipelinedModCodec::process_thread() { set_thread_name(name()); diff --git a/src/ModPlugin.h b/src/ModPlugin.h index 3c3e8b3..c0f1c1a 100644 --- a/src/ModPlugin.h +++ b/src/ModPlugin.h @@ -30,16 +30,34 @@ # include #endif - #include "Buffer.h" #include "ThreadsafeQueue.h" - -#include +#include #include #include #include #include +// All flowgraph elements derive from ModPlugin, or a variant of it. +// Some ModPlugins also support handling metadata. + +struct frame_timestamp; +struct flowgraph_metadata { + std::shared_ptr ts; +}; + +using meta_vec_t = std::vector; + +/* ModPlugins that support metadata derive from ModMetadata */ +class ModMetadata { + public: + // Receives metadata from all inputs, and process them, and output + // a sequence of metadata. + virtual meta_vec_t process_metadata(const meta_vec_t& metadataIn) = 0; +}; + + +/* Abstract base class for all flowgraph elements */ class ModPlugin { public: @@ -69,7 +87,11 @@ public: virtual int process(Buffer* const dataIn, Buffer* dataOut) = 0; }; -class PipelinedModCodec : public ModCodec +/* Pipelined ModCodecs run their processing in a separate thread, and + * have a one-call-to-process() latency. Because of this latency, they + * must also handle the metadata + */ +class PipelinedModCodec : public ModCodec, public ModMetadata { public: PipelinedModCodec(); @@ -82,6 +104,8 @@ public: virtual int process(Buffer* const dataIn, Buffer* dataOut) final; virtual const char* name() = 0; + virtual meta_vec_t process_metadata(const meta_vec_t& metadataIn) final; + protected: // Once the instance implementing PipelinedModCodec has been constructed, // it must call start_pipeline_thread() @@ -89,11 +113,13 @@ protected: virtual int internal_process(Buffer* const dataIn, Buffer* dataOut) = 0; private: - size_t m_number_of_runs; + bool m_ready_to_output_data = false; ThreadsafeQueue > m_input_queue; ThreadsafeQueue > m_output_queue; + std::deque m_metadata_fifo; + std::atomic m_running; std::thread m_thread; void process_thread(void); @@ -120,19 +146,3 @@ public: virtual int process(Buffer* dataIn) = 0; }; -struct frame_timestamp; -struct flowgraph_metadata { - std::shared_ptr ts; -}; - - -using meta_vec_t = std::vector; - -/* Some ModPlugins also support metadata */ -class ModMetadata { - public: - // Receives metadata from all inputs, and process them, and output - // a sequence of metadata. - virtual meta_vec_t process_metadata(const meta_vec_t& metadataIn) = 0; -}; - diff --git a/src/OutputFile.cpp b/src/OutputFile.cpp index 3bb45c4..481e858 100644 --- a/src/OutputFile.cpp +++ b/src/OutputFile.cpp @@ -77,22 +77,26 @@ meta_vec_t OutputFile::process_metadata(const meta_vec_t& metadataIn) for (const auto& md : metadataIn) { if (md.ts) { - ss << "FCT=" << md.ts->fct << + ss << " FCT=" << md.ts->fct << " FP=" << (int)md.ts->fp; - if (md.ts->timestamp_valid) { - ss << " ts=" << md.ts->timestamp_sec << - "+" << md.ts->timestamp_pps << ", "; - } - else { - ss << " no ts"; - } } else { - ss << "void, "; + ss << " void, "; } } + if (myEtiSource) { + frame_timestamp ts; + myEtiSource->calculateTimestamp(ts); + ss << " ETI FCT=" << ts.fct; + } + etiLog.level(debug) << "Output File got metadata: " << ss.str(); return {}; } + +void OutputFile::setETISource(EtiSource *etiSource) +{ + myEtiSource = etiSource; +} diff --git a/src/OutputFile.h b/src/OutputFile.h index 2b92369..97fdcb7 100644 --- a/src/OutputFile.h +++ b/src/OutputFile.h @@ -32,6 +32,7 @@ #include "ModPlugin.h" +#include "EtiReader.h" #include #include @@ -57,7 +58,12 @@ public: virtual meta_vec_t process_metadata( const meta_vec_t& metadataIn) override; + void setETISource(EtiSource *etiSource); + protected: + // TODO remove + EtiSource *myEtiSource = nullptr; + std::string myFilename; std::unique_ptr myFile; }; -- cgit v1.2.3 From 0315433aef00644085d2278af405eaedbc184c5c Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Sun, 7 Jan 2018 09:40:06 +0100 Subject: use unique_ptr to handle FILE* in Log --- src/Log.cpp | 39 ++++++++++++++++++++++++++------------- src/Log.h | 41 ++++++++++++----------------------------- src/OutputFile.h | 10 ++-------- 3 files changed, 40 insertions(+), 50 deletions(-) (limited to 'src/OutputFile.h') diff --git a/src/Log.cpp b/src/Log.cpp index 0792fcf..f2219eb 100644 --- a/src/Log.cpp +++ b/src/Log.cpp @@ -109,6 +109,17 @@ LogLine Logger::level(log_level_t level) return LogLine(this, level); } +LogToFile::LogToFile(const std::string& filename) : name("FILE") +{ + FILE* fd = fopen(filename.c_str(), "a"); + if (fd == nullptr) { + fprintf(stderr, "Cannot open log file !"); + throw std::runtime_error("Cannot open log file !"); + } + + log_file.reset(fd); +} + void LogToFile::log(log_level_t level, const std::string& message) { if (level != log_level_t::trace) { @@ -116,9 +127,9 @@ void LogToFile::log(log_level_t level, const std::string& message) "DEBUG", "INFO", "WARN", "ERROR", "ALERT", "EMERG"}; // fprintf is thread-safe - fprintf(log_file, SYSLOG_IDENT ": %s: %s\n", + fprintf(log_file.get(), SYSLOG_IDENT ": %s: %s\n", log_level_text[(size_t)level], message.c_str()); - fflush(log_file); + fflush(log_file.get()); } } @@ -142,31 +153,33 @@ void LogToSyslog::log(log_level_t level, const std::string& message) } } -LogTracer::LogTracer(const string& trace_filename) +LogTracer::LogTracer(const string& trace_filename) : name("TRACE") { - name = "TRACE"; etiLog.level(info) << "Setting up TRACE to " << trace_filename; - m_trace_file = fopen(trace_filename.c_str(), "a"); - if (m_trace_file == NULL) { + FILE* fd = fopen(trace_filename.c_str(), "a"); + if (fd == nullptr) { fprintf(stderr, "Cannot open trace file !"); throw std::runtime_error("Cannot open trace file !"); } + m_trace_file.reset(fd); - auto now = chrono::steady_clock::now().time_since_epoch(); - m_trace_micros_startup = - chrono::duration_cast(now).count(); + using namespace std::chrono; + auto now = steady_clock::now().time_since_epoch(); + m_trace_micros_startup = duration_cast(now).count(); - fprintf(m_trace_file, "0,TRACER,startup at %ld\n", m_trace_micros_startup); + fprintf(m_trace_file.get(), + "0,TRACER,startup at %ld\n", m_trace_micros_startup); } void LogTracer::log(log_level_t level, const std::string& message) { if (level == log_level_t::trace) { - const auto now = chrono::steady_clock::now().time_since_epoch(); - const auto micros = chrono::duration_cast(now).count(); + using namespace std::chrono; + const auto now = steady_clock::now().time_since_epoch(); + const auto micros = duration_cast(now).count(); - fprintf(m_trace_file, "%ld,%s\n", + fprintf(m_trace_file.get(), "%ld,%s\n", micros - m_trace_micros_startup, message.c_str()); } diff --git a/src/Log.h b/src/Log.h index ae252a6..0e09bc9 100644 --- a/src/Log.h +++ b/src/Log.h @@ -57,7 +57,7 @@ static const std::string levels_as_str[] = class LogBackend { public: virtual void log(log_level_t level, const std::string& message) = 0; - virtual std::string get_name() = 0; + virtual std::string get_name() const = 0; }; /** A Logging backend for Syslog */ @@ -73,7 +73,7 @@ class LogToSyslog : public LogBackend { void log(log_level_t level, const std::string& message); - std::string get_name() { return name; } + std::string get_name() const { return name; } private: const std::string name; @@ -84,27 +84,15 @@ class LogToSyslog : public LogBackend { class LogToFile : public LogBackend { public: - LogToFile(const std::string& filename) : name("FILE") { - log_file = fopen(filename.c_str(), "a"); - if (log_file == NULL) { - fprintf(stderr, "Cannot open log file !"); - throw std::runtime_error("Cannot open log file !"); - } - } - - ~LogToFile() { - if (log_file != NULL) { - fclose(log_file); - } - } - + LogToFile(const std::string& filename); void log(log_level_t level, const std::string& message); - - std::string get_name() { return name; } + std::string get_name() const { return name; } private: const std::string name; - FILE* log_file; + + struct FILEDeleter{ void operator()(FILE* fd){ if(fd) fclose(fd);}}; + std::unique_ptr log_file; LogToFile(const LogToFile& other) = delete; const LogToFile& operator=(const LogToFile& other) = delete; @@ -113,19 +101,14 @@ class LogToFile : public LogBackend { class LogTracer : public LogBackend { public: LogTracer(const std::string& filename); - - ~LogTracer() { - if (m_trace_file != NULL) { - fclose(m_trace_file); - } - } - void log(log_level_t level, const std::string& message); - std::string get_name() { return name; } + std::string get_name() const { return name; } private: std::string name; - uint64_t m_trace_micros_startup; - FILE* m_trace_file; + uint64_t m_trace_micros_startup = 0; + + struct FILEDeleter{ void operator()(FILE* fd){ if(fd) fclose(fd);}}; + std::unique_ptr m_trace_file; LogTracer(const LogTracer& other) = delete; const LogTracer& operator=(const LogTracer& other) = delete; diff --git a/src/OutputFile.h b/src/OutputFile.h index 97fdcb7..a586921 100644 --- a/src/OutputFile.h +++ b/src/OutputFile.h @@ -39,14 +39,6 @@ #include #include -struct FILEDeleter { - void operator()(FILE* fd) { - if (fd) { - fclose(fd); - } - } -}; - class OutputFile : public ModOutput, public ModMetadata { public: @@ -65,6 +57,8 @@ protected: EtiSource *myEtiSource = nullptr; std::string myFilename; + + struct FILEDeleter{ void operator()(FILE* fd){ if (fd) fclose(fd); }}; std::unique_ptr myFile; }; -- cgit v1.2.3