aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorStefan Pöschel <github@basicmaster.de>2017-02-11 10:24:37 +0100
committerStefan Pöschel <github@basicmaster.de>2017-02-11 10:24:37 +0100
commit07be2a291ec5a235c881bac43fae80de6903d35d (patch)
tree8965d5f5b45f3cad54486691e3d3c9978929b607 /src
parent209df35b899c2e6453a510940137b4bf0f31235b (diff)
downloadODR-PadEnc-07be2a291ec5a235c881bac43fae80de6903d35d.tar.gz
ODR-PadEnc-07be2a291ec5a235c881bac43fae80de6903d35d.tar.bz2
ODR-PadEnc-07be2a291ec5a235c881bac43fae80de6903d35d.zip
Move DLS stuff to new DLSManager
Diffstat (limited to 'src')
-rw-r--r--src/dls.cpp350
-rw-r--r--src/dls.h155
-rw-r--r--src/odr-padenc.cpp430
3 files changed, 512 insertions, 423 deletions
diff --git a/src/dls.cpp b/src/dls.cpp
new file mode 100644
index 0000000..f41c9ff
--- /dev/null
+++ b/src/dls.cpp
@@ -0,0 +1,350 @@
+/*
+ Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://rd.csp.it/)
+
+ Copyright (C) 2014, 2015 Matthias P. Braendli (http://opendigitalradio.org)
+
+ Copyright (C) 2015, 2016, 2017 Stefan Pöschel (http://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/>.
+*/
+/*!
+ \file dls.cpp
+ \brief Dynamic Label (DL) related code
+
+ \author Sergio Sagliocco <sergio.sagliocco@csp.it>
+ \author Matthias P. Braendli <matthias@mpb.li>
+ \author Stefan Pöschel <odr@basicmaster.de>
+*/
+
+#include "dls.h"
+
+
+// --- DLSManager -----------------------------------------------------------------
+const size_t DLSManager::MAXDLS = 128; // chars
+const size_t DLSManager::DLS_SEG_LEN_PREFIX = 2;
+const size_t DLSManager::DLS_SEG_LEN_CHAR_MAX = 16;
+const int DLSManager::DLS_REPETITION_WHILE_SLS = 50;
+const std::string DLSManager::DL_PARAMS_OPEN = "##### parameters { #####";
+const std::string DLSManager::DL_PARAMS_CLOSE = "##### parameters } #####";
+
+
+DATA_GROUP* DLSManager::createDynamicLabelCommand(uint8_t command) {
+ DATA_GROUP* dg = new DATA_GROUP(2, 2, 3);
+ uint8_vector_t &seg_data = dg->data;
+
+ // prefix: toggle? + first seg + last seg + command flag + command
+ seg_data[0] =
+ (dls_toggle ? (1 << 7) : 0) +
+ (1 << 6) +
+ (1 << 5) +
+ (1 << 4) +
+ command;
+
+ // prefix: charset (though irrelevant here)
+ seg_data[1] = CHARSET_COMPLETE_EBU_LATIN;
+
+ // CRC
+ dg->AppendCRC();
+
+ return dg;
+}
+
+DATA_GROUP* DLSManager::createDynamicLabelPlus(const DL_STATE& dl_state) {
+ size_t tags_size = dl_state.dl_plus_tags.size();
+ size_t len_dl_plus_cmd_field = 1 + 3 * tags_size;
+ DATA_GROUP* dg = new DATA_GROUP(2 + len_dl_plus_cmd_field, 2, 3);
+ uint8_vector_t &seg_data = dg->data;
+
+ // prefix: toggle? + first seg + last seg + command flag + command
+ seg_data[0] =
+ (dls_toggle ? (1 << 7) : 0) +
+ (1 << 6) +
+ (1 << 5) +
+ (1 << 4) +
+ DLS_CMD_DL_PLUS;
+
+ // prefix: link bit + length
+ seg_data[1] =
+ (dls_toggle ? (1 << 7) : 0) +
+ (len_dl_plus_cmd_field - 1); // -1 !
+
+ // DL Plus tags command: CId + IT + IR + NT
+ seg_data[2] =
+ (DL_PLUS_CMD_TAGS << 4) +
+ (dl_state.dl_plus_item_toggle ? (1 << 3) : 0) +
+ (dl_state.dl_plus_item_running ? (1 << 2) : 0) +
+ (tags_size - 1); // -1 !
+
+ for (size_t i = 0; i < tags_size; i++) {
+ // DL Plus tags command: Content Type + Start Marker + Length Marker
+ seg_data[3 + 3 * i] = dl_state.dl_plus_tags[i].content_type & 0x7F;
+ seg_data[4 + 3 * i] = dl_state.dl_plus_tags[i].start_marker & 0x7F;
+ seg_data[5 + 3 * i] = dl_state.dl_plus_tags[i].length_marker & 0x7F;
+ }
+
+ // CRC
+ dg->AppendCRC();
+
+ return dg;
+}
+
+
+bool DLSManager::parse_dl_param_bool(const std::string &key, const std::string &value, bool &target) {
+ if (value == "0") {
+ target = 0;
+ return true;
+ }
+ if (value == "1") {
+ target = 1;
+ return true;
+ }
+ fprintf(stderr, "ODR-PadEnc Warning: DL parameter '%s' has unsupported value '%s' - ignored\n", key.c_str(), value.c_str());
+ return false;
+}
+
+bool DLSManager::parse_dl_param_int_dl_plus_tag(const std::string &key, const std::string &value, int &target) {
+ int value_int = atoi(value.c_str());
+ if (value_int >= 0x00 && value_int <= 0x7F) {
+ target = value_int;
+ return true;
+ }
+ fprintf(stderr, "ODR-PadEnc Warning: DL Plus tag parameter '%s' %d out of range - ignored\n", key.c_str(), value_int);
+ return false;
+}
+
+void DLSManager::parse_dl_params(std::ifstream &dls_fstream, DL_STATE &dl_state) {
+ std::string line;
+ while (std::getline(dls_fstream, line)) {
+ // return on params close
+ if (line == DL_PARAMS_CLOSE)
+ return;
+
+ // ignore empty lines and comments
+ if (line.empty() || line[0] == '#')
+ continue;
+
+ // parse key/value pair
+ size_t separator_pos = line.find('=');
+ if (separator_pos == std::string::npos) {
+ fprintf(stderr, "ODR-PadEnc Warning: DL parameter line '%s' without separator - ignored\n", line.c_str());
+ continue;
+ }
+ std::string key = line.substr(0, separator_pos);
+ std::string value = line.substr(separator_pos + 1);
+#ifdef DEBUG
+ fprintf(stderr, "parse_dl_params: key: '%s', value: '%s'\n", key.c_str(), value.c_str());
+#endif
+
+ if (key == "DL_PLUS") {
+ parse_dl_param_bool(key, value, dl_state.dl_plus_enabled);
+ continue;
+ }
+ if (key == "DL_PLUS_ITEM_TOGGLE") {
+ parse_dl_param_bool(key, value, dl_state.dl_plus_item_toggle);
+ continue;
+ }
+ if (key == "DL_PLUS_ITEM_RUNNING") {
+ parse_dl_param_bool(key, value, dl_state.dl_plus_item_running);
+ continue;
+ }
+ if (key == "DL_PLUS_TAG") {
+ if (dl_state.dl_plus_tags.size() == 4) {
+ fprintf(stderr, "ODR-PadEnc Warning: DL Plus tag ignored, as already four tags present\n");
+ continue;
+ }
+
+ // split value
+ std::vector<std::string> params = split_string(value, ' ');
+ if (params.size() != 3) {
+ fprintf(stderr, "ODR-PadEnc Warning: DL Plus tag value '%s' does not have three parts - ignored\n", value.c_str());
+ continue;
+ }
+
+ int content_type, start_marker, length_marker;
+ if (parse_dl_param_int_dl_plus_tag("content_type", params[0], content_type) &
+ parse_dl_param_int_dl_plus_tag("start_marker", params[1], start_marker) &
+ parse_dl_param_int_dl_plus_tag("length_marker", params[2], length_marker))
+ dl_state.dl_plus_tags.push_back(DL_PLUS_TAG(content_type, start_marker, length_marker));
+ continue;
+ }
+
+ fprintf(stderr, "ODR-PadEnc Warning: DL parameter '%s' unknown - ignored\n", key.c_str());
+ }
+
+ fprintf(stderr, "ODR-PadEnc Warning: no param closing tag, so the DLS text will be empty\n");
+}
+
+
+void DLSManager::writeDLS(PADPacketizer& pad_packetizer, const std::string& dls_file, uint8_t charset, bool raw_dls, bool remove_dls) {
+ std::ifstream dls_fstream(dls_file);
+ if (!dls_fstream.is_open()) {
+ std::cerr << "Could not open " << dls_file << std::endl;
+ return;
+ }
+
+ DL_STATE dl_state;
+
+ std::vector<std::string> dls_lines;
+
+ std::string line;
+ // Read and convert lines one by one because the converter doesn't understand
+ // line endings
+ while (std::getline(dls_fstream, line)) {
+ if (line.empty())
+ continue;
+ if (line == DL_PARAMS_OPEN) {
+ parse_dl_params(dls_fstream, dl_state);
+ } else {
+ if (not raw_dls && charset == CHARSET_UTF8) {
+ dls_lines.push_back(charset_converter.convert(line));
+ }
+ else {
+ dls_lines.push_back(line);
+ }
+ // TODO handle the other charsets accordingly
+ }
+ }
+
+ std::stringstream ss;
+ for (size_t i = 0; i < dls_lines.size(); i++) {
+ if (i != 0) {
+ if (charset == CHARSET_UCS2_BE)
+ ss << '\0' << '\n';
+ else
+ ss << '\n';
+ }
+
+ // UCS-2 BE: if from file the first byte of \0\n remains, remove it
+ if (charset == CHARSET_UCS2_BE && dls_lines[i].size() % 2) {
+ dls_lines[i].resize(dls_lines[i].size() - 1);
+ }
+
+ ss << dls_lines[i];
+ }
+
+ dl_state.dl_text = ss.str();
+ if (dl_state.dl_text.size() > MAXDLS)
+ dl_state.dl_text.resize(MAXDLS);
+
+
+ // if DL Plus enabled, but no DL Plus tags were added, add the required DUMMY tag
+ if (dl_state.dl_plus_enabled && dl_state.dl_plus_tags.empty())
+ dl_state.dl_plus_tags.push_back(DL_PLUS_TAG());
+
+ if (not raw_dls)
+ charset = CHARSET_COMPLETE_EBU_LATIN;
+
+
+ // toggle the toggle bit only on new DL state
+ bool dl_state_is_new = dl_state != dl_state_prev;
+ if (verbose) {
+ fprintf(stderr, "ODR-PadEnc writing %s DLS text \"%s\"\n", dl_state_is_new ? "new" : "old", dl_state.dl_text.c_str());
+ if (dl_state.dl_plus_enabled) {
+ fprintf(
+ stderr, "ODR-PadEnc writing %s DL Plus tags (IT/IR: %d/%d): ",
+ dl_state_is_new ? "new" : "old",
+ dl_state.dl_plus_item_toggle ? 1 : 0,
+ dl_state.dl_plus_item_running ? 1 : 0);
+ for (dl_plus_tags_t::const_iterator it = dl_state.dl_plus_tags.begin(); it != dl_state.dl_plus_tags.end(); it++) {
+ if (it != dl_state.dl_plus_tags.begin())
+ fprintf(stderr, ", ");
+ fprintf(stderr, "%d (S/L: %d/%d)", it->content_type, it->start_marker, it->length_marker);
+ }
+ fprintf(stderr, "\n");
+ }
+ }
+
+ DATA_GROUP *remove_label_dg = NULL;
+ if (dl_state_is_new) {
+ if (remove_dls)
+ remove_label_dg = createDynamicLabelCommand(DLS_CMD_REMOVE_LABEL);
+
+ dls_toggle = !dls_toggle; // indicate changed text
+
+ dl_state_prev = dl_state;
+ }
+
+ prepend_dl_dgs(pad_packetizer, dl_state, charset);
+ if (remove_label_dg)
+ pad_packetizer.AddDG(remove_label_dg, true);
+}
+
+
+int DLSManager::dls_count(const std::string& text) {
+ size_t text_len = text.size();
+ return text_len / DLS_SEG_LEN_CHAR_MAX + (text_len % DLS_SEG_LEN_CHAR_MAX ? 1 : 0);
+}
+
+
+DATA_GROUP* DLSManager::dls_get(const std::string& text, uint8_t charset, int seg_index) {
+ bool first_seg = seg_index == 0;
+ bool last_seg = seg_index == dls_count(text) - 1;
+
+ int seg_text_offset = seg_index * DLS_SEG_LEN_CHAR_MAX;
+ const char *seg_text_start = text.c_str() + seg_text_offset;
+ size_t seg_text_len = std::min(text.size() - seg_text_offset, DLS_SEG_LEN_CHAR_MAX);
+
+ DATA_GROUP* dg = new DATA_GROUP(DLS_SEG_LEN_PREFIX + seg_text_len, 2, 3);
+ uint8_vector_t &seg_data = dg->data;
+
+ // prefix: toggle? + first seg? + last seg? + (seg len - 1)
+ seg_data[0] =
+ (dls_toggle ? (1 << 7) : 0) +
+ (first_seg ? (1 << 6) : 0) +
+ (last_seg ? (1 << 5) : 0) +
+ (seg_text_len - 1);
+
+ // prefix: charset / seg index
+ seg_data[1] = (first_seg ? charset : seg_index) << 4;
+
+ // character field
+ memcpy(&seg_data[DLS_SEG_LEN_PREFIX], seg_text_start, seg_text_len);
+
+ // CRC
+ dg->AppendCRC();
+
+#ifdef DEBUG
+ fprintf(stderr, "DL segment:");
+ for (int i = 0; i < seg_data.size(); i++)
+ fprintf(stderr, " %02x", seg_data[i]);
+ fprintf(stderr, "\n");
+#endif
+ return dg;
+}
+
+
+void DLSManager::prepend_dl_dgs(PADPacketizer& pad_packetizer, const DL_STATE& dl_state, uint8_t charset) {
+ // process all DL segments
+ int seg_count = dls_count(dl_state.dl_text);
+ std::vector<DATA_GROUP*> segs;
+ for (int seg_index = 0; seg_index < seg_count; seg_index++) {
+#ifdef DEBUG
+ fprintf(stderr, "Segment number %d\n", seg_index + 1);
+#endif
+ segs.push_back(dls_get(dl_state.dl_text, charset, seg_index));
+ }
+
+ // if enabled, add DL Plus data group
+ if (dl_state.dl_plus_enabled)
+ segs.push_back(createDynamicLabelPlus(dl_state));
+
+ // prepend to packetizer
+ pad_packetizer.AddDGs(segs, true);
+
+#ifdef DEBUG
+ fprintf(stderr, "PAD length: %d\n", padlen);
+ fprintf(stderr, "DLS text: %s\n", text.c_str());
+ fprintf(stderr, "Number of DL segments: %d\n", seg_count);
+#endif
+}
diff --git a/src/dls.h b/src/dls.h
new file mode 100644
index 0000000..f9e5c57
--- /dev/null
+++ b/src/dls.h
@@ -0,0 +1,155 @@
+/*
+ Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://rd.csp.it/)
+
+ Copyright (C) 2014, 2015 Matthias P. Braendli (http://opendigitalradio.org)
+
+ Copyright (C) 2015, 2016, 2017 Stefan Pöschel (http://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/>.
+*/
+/*!
+ \file dls.h
+ \brief Dynamic Label (DL) related code
+
+ \author Sergio Sagliocco <sergio.sagliocco@csp.it>
+ \author Matthias P. Braendli <matthias@mpb.li>
+ \author Stefan Pöschel <odr@basicmaster.de>
+*/
+
+#ifndef DLS_H_
+#define DLS_H_
+
+#include <fstream>
+#include <iostream>
+
+#include "pad_common.h"
+#include "charset.h"
+
+
+// Charsets from TS 101 756
+enum {
+ CHARSET_COMPLETE_EBU_LATIN = 0, //!< Complete EBU Latin based repertoire
+ CHARSET_EBU_LATIN_CY_GR = 1, //!< EBU Latin based common core, Cyrillic, Greek
+ CHARSET_EBU_LATIN_AR_HE_CY_GR = 2, //!< EBU Latin based core, Arabic, Hebrew, Cyrillic and Greek
+ CHARSET_ISO_LATIN_ALPHABET_2 = 3, //!< ISO Latin Alphabet No 2
+ CHARSET_UCS2_BE = 6, //!< ISO/IEC 10646 using UCS-2 transformation format, big endian byte order
+ CHARSET_UTF8 = 15 //!< ISO Latin Alphabet No 2
+};
+
+// DL/DL+ commands
+enum {
+ DLS_CMD_REMOVE_LABEL = 0b0001,
+ DLS_CMD_DL_PLUS = 0b0010
+};
+enum {
+ DL_PLUS_CMD_TAGS = 0b0000
+};
+
+
+// --- DL_PLUS_TAG -----------------------------------------------------------------
+struct DL_PLUS_TAG {
+ int content_type;
+ int start_marker;
+ int length_marker;
+
+ DL_PLUS_TAG() :
+ content_type(0), // = DUMMY
+ start_marker(0),
+ length_marker(0)
+ {}
+
+ DL_PLUS_TAG(int content_type, int start_marker, int length_marker) :
+ content_type(content_type),
+ start_marker(start_marker),
+ length_marker(length_marker)
+ {}
+
+ bool operator==(const DL_PLUS_TAG& other) const {
+ return
+ content_type == other.content_type &&
+ start_marker == other.start_marker &&
+ length_marker == other.length_marker;
+ }
+ bool operator!=(const DL_PLUS_TAG& other) const {
+ return !(*this == other);
+ }
+};
+
+typedef std::vector<DL_PLUS_TAG> dl_plus_tags_t;
+
+
+// --- DL_STATE -----------------------------------------------------------------
+struct DL_STATE {
+ std::string dl_text;
+
+ bool dl_plus_enabled;
+ bool dl_plus_item_toggle;
+ bool dl_plus_item_running;
+ dl_plus_tags_t dl_plus_tags;
+
+ DL_STATE() :
+ dl_plus_enabled(false),
+ dl_plus_item_toggle(false),
+ dl_plus_item_running(false)
+ {}
+
+ bool operator==(const DL_STATE& other) const {
+ if (dl_text != other.dl_text)
+ return false;
+ if (dl_plus_enabled != other.dl_plus_enabled)
+ return false;
+ if (dl_plus_enabled) {
+ if (dl_plus_item_toggle != other.dl_plus_item_toggle)
+ return false;
+ if (dl_plus_item_running != other.dl_plus_item_running)
+ return false;
+ if (dl_plus_tags != other.dl_plus_tags)
+ return false;
+ }
+ return true;
+ }
+ bool operator!=(const DL_STATE& other) const {
+ return !(*this == other);
+ }
+};
+
+
+// --- DLSManager -----------------------------------------------------------------
+class DLSManager {
+private:
+ DATA_GROUP* createDynamicLabelCommand(uint8_t command);
+ DATA_GROUP* createDynamicLabelPlus(const DL_STATE& dl_state);
+ bool parse_dl_param_bool(const std::string &key, const std::string &value, bool &target);
+ bool parse_dl_param_int_dl_plus_tag(const std::string &key, const std::string &value, int &target);
+ void parse_dl_params(std::ifstream &dls_fstream, DL_STATE &dl_state);
+ int dls_count(const std::string& text);
+ DATA_GROUP* dls_get(const std::string& text, uint8_t charset, int seg_index);
+ void prepend_dl_dgs(PADPacketizer& pad_packetizer, const DL_STATE& dl_state, uint8_t charset);
+
+ CharsetConverter charset_converter;
+ bool dls_toggle;
+ DL_STATE dl_state_prev;
+public:
+ static const size_t MAXDLS;
+ static const size_t DLS_SEG_LEN_PREFIX;
+ static const size_t DLS_SEG_LEN_CHAR_MAX;
+ static const int DLS_REPETITION_WHILE_SLS;
+ static const std::string DL_PARAMS_OPEN;
+ static const std::string DL_PARAMS_CLOSE;
+
+ DLSManager() : dls_toggle(false) {}
+ void writeDLS(PADPacketizer& pad_packetizer, const std::string& dls_file, uint8_t charset, bool raw_dls, bool remove_dls);
+};
+
+#endif /* DLS_H_ */
diff --git a/src/odr-padenc.cpp b/src/odr-padenc.cpp
index ccc18f1..c2a7c33 100644
--- a/src/odr-padenc.cpp
+++ b/src/odr-padenc.cpp
@@ -42,8 +42,8 @@
#include <dirent.h>
#include <getopt.h>
-#include "charset.h"
#include "pad_common.h"
+#include "dls.h"
#if HAVE_MAGICKWAND
# include <wand/magick_wand.h>
@@ -56,7 +56,6 @@
#define XSTR(x) #x
#define STR(x) XSTR(x)
-static const size_t MAXDLS = 128; // chars
static const size_t MAXSEGLEN = 8189; // Bytes (EN 301 234 v2.1.1, ch. 5.1.1)
static const size_t MAXSLIDESIZE = 51200; // Bytes (TS 101 499 v3.1.1, ch. 9.1.2)
@@ -64,15 +63,6 @@ static const int MAXSLIDEID = 9999; // Roll-over value for fidx
static const size_t MAXHISTORYLEN = 50; // How many slides to keep in history
static const int MINQUALITY = 40; // Do not allow the image compressor to go below JPEG quality 40
-// Charsets from TS 101 756
-enum {
- CHARSET_COMPLETE_EBU_LATIN = 0, //!< Complete EBU Latin based repertoire
- CHARSET_EBU_LATIN_CY_GR = 1, //!< EBU Latin based common core, Cyrillic, Greek
- CHARSET_EBU_LATIN_AR_HE_CY_GR = 2, //!< EBU Latin based core, Arabic, Hebrew, Cyrillic and Greek
- CHARSET_ISO_LATIN_ALPHABET_2 = 3, //!< ISO Latin Alphabet No 2
- CHARSET_UCS2_BE = 6, //!< ISO/IEC 10646 using UCS-2 transformation format, big endian byte order
- CHARSET_UTF8 = 15 //!< ISO Latin Alphabet No 2
-};
struct MSCDG {
// MSC Data Group Header (extension field not supported)
@@ -212,10 +202,6 @@ void createMscDG(MSCDG* msc, unsigned short int dgtype, int *cindex, unsigned sh
DATA_GROUP* packMscDG(MSCDG* msc);
-struct DL_STATE;
-void prepend_dl_dgs(PADPacketizer& pad_packetizer, const DL_STATE& dl_state, uint8_t charset);
-void writeDLS(PADPacketizer& pad_packetizer, const std::string& dls_file, uint8_t charset, bool raw_dls, bool remove_dls);
-
// MOT Slideshow related
static int cindex_header = 0;
@@ -327,98 +313,6 @@ void MOTHeader::AddExtension(int param_id, const uint8_t* data_field, size_t dat
-// DLS related
-static const size_t DLS_SEG_LEN_PREFIX = 2;
-static const size_t DLS_SEG_LEN_CHAR_MAX = 16;
-static const int DLS_REPETITION_WHILE_SLS = 50;
-enum {
- DLS_CMD_REMOVE_LABEL = 0b0001,
- DLS_CMD_DL_PLUS = 0b0010
-};
-static const int DL_PLUS_CMD_TAGS = 0b0000;
-
-#define DL_PARAMS_OPEN "##### parameters { #####"
-#define DL_PARAMS_CLOSE "##### parameters } #####"
-
-static CharsetConverter charset_converter;
-
-struct DL_PLUS_TAG {
- int content_type;
- int start_marker;
- int length_marker;
-
- DL_PLUS_TAG() :
- content_type(0), // = DUMMY
- start_marker(0),
- length_marker(0)
- {}
-
- DL_PLUS_TAG(int content_type, int start_marker, int length_marker) :
- content_type(content_type),
- start_marker(start_marker),
- length_marker(length_marker)
- {}
-
- bool operator==(const DL_PLUS_TAG& other) const {
- return
- content_type == other.content_type &&
- start_marker == other.start_marker &&
- length_marker == other.length_marker;
- }
- bool operator!=(const DL_PLUS_TAG& other) const {
- return !(*this == other);
- }
-};
-
-typedef std::vector<DL_PLUS_TAG> dl_plus_tags_t;
-
-struct DL_STATE {
- std::string dl_text;
-
- bool dl_plus_enabled;
- bool dl_plus_item_toggle;
- bool dl_plus_item_running;
- dl_plus_tags_t dl_plus_tags;
-
- DL_STATE() :
- dl_plus_enabled(false),
- dl_plus_item_toggle(false),
- dl_plus_item_running(false)
- {}
-
- bool operator==(const DL_STATE& other) const {
- if (dl_text != other.dl_text)
- return false;
- if (dl_plus_enabled != other.dl_plus_enabled)
- return false;
- if (dl_plus_enabled) {
- if (dl_plus_item_toggle != other.dl_plus_item_toggle)
- return false;
- if (dl_plus_item_running != other.dl_plus_item_running)
- return false;
- if (dl_plus_tags != other.dl_plus_tags)
- return false;
- }
- return true;
- }
- bool operator!=(const DL_STATE& other) const {
- return !(*this == other);
- }
-};
-
-
-static bool dls_toggle = false;
-static DL_STATE dl_state_prev;
-
-
-
-
-
-
-
-
-
-
void usage(char* name)
{
fprintf(stderr, "DAB PAD encoder %s for MOT Slideshow and DLS\n\n"
@@ -626,6 +520,7 @@ int main(int argc, char *argv[])
#endif
PADPacketizer pad_packetizer(padlen);
+ DLSManager dls_manager;
std::list<slide_metadata_t> slides_to_transmit;
History slides_history(MAXHISTORYLEN);
@@ -674,7 +569,7 @@ int main(int argc, char *argv[])
// if ATM no slides, transmit at least DLS
if (slides_to_transmit.empty()) {
if (not dls_file.empty()) {
- writeDLS(pad_packetizer, dls_file, charset, raw_dls, remove_dls);
+ dls_manager.writeDLS(pad_packetizer, dls_file, charset, raw_dls, remove_dls);
pad_packetizer.WriteAllPADs(output_fd);
}
@@ -702,14 +597,14 @@ int main(int argc, char *argv[])
// while flushing, insert DLS after a certain PAD amout
while (pad_packetizer.QueueFilled()) {
if (not dls_file.empty())
- writeDLS(pad_packetizer, dls_file, charset, raw_dls, remove_dls);
+ dls_manager.writeDLS(pad_packetizer, dls_file, charset, raw_dls, remove_dls);
- pad_packetizer.WriteAllPADs(output_fd, DLS_REPETITION_WHILE_SLS);
+ pad_packetizer.WriteAllPADs(output_fd, DLSManager::DLS_REPETITION_WHILE_SLS);
}
// after the slide, output a last DLS
if (not dls_file.empty())
- writeDLS(pad_packetizer, dls_file, charset, raw_dls, remove_dls);
+ dls_manager.writeDLS(pad_packetizer, dls_file, charset, raw_dls, remove_dls);
pad_packetizer.WriteAllPADs(output_fd);
sleep(sleepdelay);
@@ -719,7 +614,7 @@ int main(int argc, char *argv[])
}
} else { // only DLS
// Always retransmit DLS, we want it to be updated frequently
- writeDLS(pad_packetizer, dls_file, charset, raw_dls, remove_dls);
+ dls_manager.writeDLS(pad_packetizer, dls_file, charset, raw_dls, remove_dls);
pad_packetizer.WriteAllPADs(output_fd);
sleep(sleepdelay);
@@ -1247,317 +1142,6 @@ DATA_GROUP* packMscDG(MSCDG* msc)
}
-DATA_GROUP* createDynamicLabelCommand(uint8_t command) {
- DATA_GROUP* dg = new DATA_GROUP(2, 2, 3);
- uint8_vector_t &seg_data = dg->data;
-
- // prefix: toggle? + first seg + last seg + command flag + command
- seg_data[0] =
- (dls_toggle ? (1 << 7) : 0) +
- (1 << 6) +
- (1 << 5) +
- (1 << 4) +
- command;
-
- // prefix: charset (though irrelevant here)
- seg_data[1] = CHARSET_COMPLETE_EBU_LATIN;
-
- // CRC
- dg->AppendCRC();
-
- return dg;
-}
-
-DATA_GROUP* createDynamicLabelPlus(const DL_STATE& dl_state) {
- size_t tags_size = dl_state.dl_plus_tags.size();
- size_t len_dl_plus_cmd_field = 1 + 3 * tags_size;
- DATA_GROUP* dg = new DATA_GROUP(2 + len_dl_plus_cmd_field, 2, 3);
- uint8_vector_t &seg_data = dg->data;
-
- // prefix: toggle? + first seg + last seg + command flag + command
- seg_data[0] =
- (dls_toggle ? (1 << 7) : 0) +
- (1 << 6) +
- (1 << 5) +
- (1 << 4) +
- DLS_CMD_DL_PLUS;
-
- // prefix: link bit + length
- seg_data[1] =
- (dls_toggle ? (1 << 7) : 0) +
- (len_dl_plus_cmd_field - 1); // -1 !
-
- // DL Plus tags command: CId + IT + IR + NT
- seg_data[2] =
- (DL_PLUS_CMD_TAGS << 4) +
- (dl_state.dl_plus_item_toggle ? (1 << 3) : 0) +
- (dl_state.dl_plus_item_running ? (1 << 2) : 0) +
- (tags_size - 1); // -1 !
-
- for (size_t i = 0; i < tags_size; i++) {
- // DL Plus tags command: Content Type + Start Marker + Length Marker
- seg_data[3 + 3 * i] = dl_state.dl_plus_tags[i].content_type & 0x7F;
- seg_data[4 + 3 * i] = dl_state.dl_plus_tags[i].start_marker & 0x7F;
- seg_data[5 + 3 * i] = dl_state.dl_plus_tags[i].length_marker & 0x7F;
- }
-
- // CRC
- dg->AppendCRC();
-
- return dg;
-}
-
-
-bool parse_dl_param_bool(const std::string &key, const std::string &value, bool &target) {
- if (value == "0") {
- target = 0;
- return true;
- }
- if (value == "1") {
- target = 1;
- return true;
- }
- fprintf(stderr, "ODR-PadEnc Warning: DL parameter '%s' has unsupported value '%s' - ignored\n", key.c_str(), value.c_str());
- return false;
-}
-
-bool parse_dl_param_int_dl_plus_tag(const std::string &key, const std::string &value, int &target) {
- int value_int = atoi(value.c_str());
- if (value_int >= 0x00 && value_int <= 0x7F) {
- target = value_int;
- return true;
- }
- fprintf(stderr, "ODR-PadEnc Warning: DL Plus tag parameter '%s' %d out of range - ignored\n", key.c_str(), value_int);
- return false;
-}
-
-void parse_dl_params(std::ifstream &dls_fstream, DL_STATE &dl_state) {
- std::string line;
- while (std::getline(dls_fstream, line)) {
- // return on params close
- if (line == DL_PARAMS_CLOSE)
- return;
-
- // ignore empty lines and comments
- if (line.empty() || line[0] == '#')
- continue;
-
- // parse key/value pair
- size_t separator_pos = line.find('=');
- if (separator_pos == std::string::npos) {
- fprintf(stderr, "ODR-PadEnc Warning: DL parameter line '%s' without separator - ignored\n", line.c_str());
- continue;
- }
- std::string key = line.substr(0, separator_pos);
- std::string value = line.substr(separator_pos + 1);
-#ifdef DEBUG
- fprintf(stderr, "parse_dl_params: key: '%s', value: '%s'\n", key.c_str(), value.c_str());
-#endif
-
- if (key == "DL_PLUS") {
- parse_dl_param_bool(key, value, dl_state.dl_plus_enabled);
- continue;
- }
- if (key == "DL_PLUS_ITEM_TOGGLE") {
- parse_dl_param_bool(key, value, dl_state.dl_plus_item_toggle);
- continue;
- }
- if (key == "DL_PLUS_ITEM_RUNNING") {
- parse_dl_param_bool(key, value, dl_state.dl_plus_item_running);
- continue;
- }
- if (key == "DL_PLUS_TAG") {
- if (dl_state.dl_plus_tags.size() == 4) {
- fprintf(stderr, "ODR-PadEnc Warning: DL Plus tag ignored, as already four tags present\n");
- continue;
- }
-
- // split value
- std::vector<std::string> params = split_string(value, ' ');
- if (params.size() != 3) {
- fprintf(stderr, "ODR-PadEnc Warning: DL Plus tag value '%s' does not have three parts - ignored\n", value.c_str());
- continue;
- }
-
- int content_type, start_marker, length_marker;
- if (parse_dl_param_int_dl_plus_tag("content_type", params[0], content_type) &
- parse_dl_param_int_dl_plus_tag("start_marker", params[1], start_marker) &
- parse_dl_param_int_dl_plus_tag("length_marker", params[2], length_marker))
- dl_state.dl_plus_tags.push_back(DL_PLUS_TAG(content_type, start_marker, length_marker));
- continue;
- }
-
- fprintf(stderr, "ODR-PadEnc Warning: DL parameter '%s' unknown - ignored\n", key.c_str());
- }
-
- fprintf(stderr, "ODR-PadEnc Warning: no param closing tag, so the DLS text will be empty\n");
-}
-
-
-void writeDLS(PADPacketizer& pad_packetizer, const std::string& dls_file, uint8_t charset, bool raw_dls, bool remove_dls)
-{
- std::ifstream dls_fstream(dls_file);
- if (!dls_fstream.is_open()) {
- std::cerr << "Could not open " << dls_file << std::endl;
- return;
- }
-
- DL_STATE dl_state;
-
- std::vector<std::string> dls_lines;
-
- std::string line;
- // Read and convert lines one by one because the converter doesn't understand
- // line endings
- while (std::getline(dls_fstream, line)) {
- if (line.empty())
- continue;
- if (line == DL_PARAMS_OPEN) {
- parse_dl_params(dls_fstream, dl_state);
- } else {
- if (not raw_dls && charset == CHARSET_UTF8) {
- dls_lines.push_back(charset_converter.convert(line));
- }
- else {
- dls_lines.push_back(line);
- }
- // TODO handle the other charsets accordingly
- }
- }
-
- std::stringstream ss;
- for (size_t i = 0; i < dls_lines.size(); i++) {
- if (i != 0) {
- if (charset == CHARSET_UCS2_BE)
- ss << '\0' << '\n';
- else
- ss << '\n';
- }
-
- // UCS-2 BE: if from file the first byte of \0\n remains, remove it
- if (charset == CHARSET_UCS2_BE && dls_lines[i].size() % 2) {
- dls_lines[i].resize(dls_lines[i].size() - 1);
- }
-
- ss << dls_lines[i];
- }
-
- dl_state.dl_text = ss.str();
- if (dl_state.dl_text.size() > MAXDLS)
- dl_state.dl_text.resize(MAXDLS);
-
-
- // if DL Plus enabled, but no DL Plus tags were added, add the required DUMMY tag
- if (dl_state.dl_plus_enabled && dl_state.dl_plus_tags.empty())
- dl_state.dl_plus_tags.push_back(DL_PLUS_TAG());
-
- if (not raw_dls)
- charset = CHARSET_COMPLETE_EBU_LATIN;
-
-
- // toggle the toggle bit only on new DL state
- bool dl_state_is_new = dl_state != dl_state_prev;
- if (verbose) {
- fprintf(stderr, "ODR-PadEnc writing %s DLS text \"%s\"\n", dl_state_is_new ? "new" : "old", dl_state.dl_text.c_str());
- if (dl_state.dl_plus_enabled) {
- fprintf(
- stderr, "ODR-PadEnc writing %s DL Plus tags (IT/IR: %d/%d): ",
- dl_state_is_new ? "new" : "old",
- dl_state.dl_plus_item_toggle ? 1 : 0,
- dl_state.dl_plus_item_running ? 1 : 0);
- for (dl_plus_tags_t::const_iterator it = dl_state.dl_plus_tags.begin(); it != dl_state.dl_plus_tags.end(); it++) {
- if (it != dl_state.dl_plus_tags.begin())
- fprintf(stderr, ", ");
- fprintf(stderr, "%d (S/L: %d/%d)", it->content_type, it->start_marker, it->length_marker);
- }
- fprintf(stderr, "\n");
- }
- }
-
- DATA_GROUP *remove_label_dg = NULL;
- if (dl_state_is_new) {
- if (remove_dls)
- remove_label_dg = createDynamicLabelCommand(DLS_CMD_REMOVE_LABEL);
-
- dls_toggle = !dls_toggle; // indicate changed text
-
- dl_state_prev = dl_state;
- }
-
- prepend_dl_dgs(pad_packetizer, dl_state, charset);
- if (remove_label_dg)
- pad_packetizer.AddDG(remove_label_dg, true);
-}
-
-
-int dls_count(const std::string& text) {
- size_t text_len = text.size();
- return text_len / DLS_SEG_LEN_CHAR_MAX + (text_len % DLS_SEG_LEN_CHAR_MAX ? 1 : 0);
-}
-
-
-DATA_GROUP* dls_get(const std::string& text, uint8_t charset, int seg_index) {
- bool first_seg = seg_index == 0;
- bool last_seg = seg_index == dls_count(text) - 1;
-
- int seg_text_offset = seg_index * DLS_SEG_LEN_CHAR_MAX;
- const char *seg_text_start = text.c_str() + seg_text_offset;
- size_t seg_text_len = std::min(text.size() - seg_text_offset, DLS_SEG_LEN_CHAR_MAX);
-
- DATA_GROUP* dg = new DATA_GROUP(DLS_SEG_LEN_PREFIX + seg_text_len, 2, 3);
- uint8_vector_t &seg_data = dg->data;
-
- // prefix: toggle? + first seg? + last seg? + (seg len - 1)
- seg_data[0] =
- (dls_toggle ? (1 << 7) : 0) +
- (first_seg ? (1 << 6) : 0) +
- (last_seg ? (1 << 5) : 0) +
- (seg_text_len - 1);
-
- // prefix: charset / seg index
- seg_data[1] = (first_seg ? charset : seg_index) << 4;
-
- // character field
- memcpy(&seg_data[DLS_SEG_LEN_PREFIX], seg_text_start, seg_text_len);
-
- // CRC
- dg->AppendCRC();
-
-#ifdef DEBUG
- fprintf(stderr, "DL segment:");
- for (int i = 0; i < seg_data.size(); i++)
- fprintf(stderr, " %02x", seg_data[i]);
- fprintf(stderr, "\n");
-#endif
- return dg;
-}
-
-
-void prepend_dl_dgs(PADPacketizer& pad_packetizer, const DL_STATE& dl_state, uint8_t charset) {
- // process all DL segments
- int seg_count = dls_count(dl_state.dl_text);
- std::vector<DATA_GROUP*> segs;
- for (int seg_index = 0; seg_index < seg_count; seg_index++) {
-#ifdef DEBUG
- fprintf(stderr, "Segment number %d\n", seg_index + 1);
-#endif
- segs.push_back(dls_get(dl_state.dl_text, charset, seg_index));
- }
-
- // if enabled, add DL Plus data group
- if (dl_state.dl_plus_enabled)
- segs.push_back(createDynamicLabelPlus(dl_state));
-
- // prepend to packetizer
- pad_packetizer.AddDGs(segs, true);
-
-#ifdef DEBUG
- fprintf(stderr, "PAD length: %d\n", padlen);
- fprintf(stderr, "DLS text: %s\n", text.c_str());
- fprintf(stderr, "Number of DL segments: %d\n", seg_count);
-#endif
-}
-
int History::find(const fingerprint_t& fp) const
{
size_t i;