diff options
| -rw-r--r-- | ChangeLog | 5 | ||||
| -rw-r--r-- | README.md | 90 | ||||
| -rw-r--r-- | configure.ac | 3 | ||||
| -rw-r--r-- | src/odr-padenc.cpp | 28 | ||||
| -rw-r--r-- | src/odr-padenc.h | 1 | ||||
| -rw-r--r-- | src/pad_common.cpp | 12 | ||||
| -rw-r--r-- | src/pad_interface.cpp | 24 | ||||
| -rw-r--r-- | src/pad_interface.h | 6 |
8 files changed, 113 insertions, 56 deletions
@@ -1,3 +1,8 @@ +2025-09-10: Matthias P. Braendli <matthias@mpb.li> + (v3.1.0): + Add ability to specify full path for -o. + Don't delay DLS transmission on overlap. + 2020-09-23: Matthias P. Braendli <matthias@mpb.li> (v3.0.0): Replacement of PAD fifo with a socket, offering bidirectional @@ -1,4 +1,5 @@ # ODR-PadEnc + ODR-PadEnc is an encoder for Programme Associated Data (PAD) and includes support for: @@ -14,42 +15,29 @@ For detailed usage, see the usage screen of the tool with the `-h` option. More information is available on the [Opendigitalradio wiki](http://wiki.opendigitalradio.org/ODR-PadEnc) -# Installation +## Installation + You have 3 ways to install odr-padenc on your host: -## Using binary debian packages -If your host is running a debian-based OS on amd64, arm64 or arm/v7, then you can install this tool using the standard debian packaging system: -1. Update the debian apt repository list: - ``` - # Replace bullseye (debian-11) with bookworm (debian-12) if applicable +### Installing binary packages on some linux distributions - curl -fsSL http://debian.opendigitalradio.org/opendigitalradio-bullseye.sources > /etc/apt/sources.list.d/opendigitalradio-bullseye.sources +[](https://repology.org/project/odr-padenc/versions) - curl -fsSL http://debian.opendigitalradio.org/opendigitalradio.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/opendigitalradio.gpg - ``` -1. Refresh the debian packages list: - ``` - apt update - ``` -1. Install the debian package: - ``` - apt install --yes odr-padenc - ``` +### Using installation scripts -## Using the dab-scripts -You can compile odr-padenc as well as the other main components of the mmbTools set with an installation script: -1. Clone the dab-scripts repository: - ``` - git clone https://github.com/opendigitalradio/dab-scripts.git - ``` -1. Follow the [instructions](https://github.com/Opendigitalradio/dab-scripts/tree/master/install) +If your linux distribution is debian-based, you can install odr-padenc +as well as the other main components of the mmbTools set with the +[Opendigitalradio dab-scripts](https://github.com/opendigitalradio/dab-scripts.git) + +### Compiling manually -## Compiling manually Unlike the 2 previous options, this one allows you to compile odr-padenc with the features you really need. -### Requirements +#### Requirements + For Debian Bullseye-based OS, run the following commands: -``` + +```sh # Required packages ## C++11 compiler sudo apt-get install --yes build-essential automake libtool @@ -59,39 +47,49 @@ sudo apt-get install --yes build-essential automake libtool sudo apt-get install libmagickwand-dev ``` -### Compilation +#### Compilation + 1. Clone this repository: - ``` + + ```sh # stable version: git clone https://github.com/Opendigitalradio/ODR-PadEnc.git # or development version (at your own risk): git clone https://github.com/Opendigitalradio/ODR-PadEnc.git -b next ``` + 1. Configure the project - ``` + + ```sh cd ODR-PadEnc ./bootstrap ./configure ``` + 1. Compile and install: - ``` + + ```sh make sudo make install ``` ### ImageMagick and Debian Jessie/Ubuntu 16.04 + Please note that Debian Jessie and Ubuntu 16.04 shipped a version of ImageMagick that was affected by two memory leaks (see #2, and also Ubuntu's [#1671630](https://bugs.launchpad.net/ubuntu/+source/imagemagick/+bug/1671630) and [#1680543](https://bugs.launchpad.net/debian/+source/imagemagick/+bug/1680543)). Hence ODR-PadEnc increasingly consumed memory until it crashed. This has been fixed with the following package versions: + - Debian Jessie: 8:6.8.9.9-5+deb8u9 - Ubuntu 16.04: 8:6.8.9.9-7ubuntu5.7 -# Usage of MOT Slideshow and DLS -## Basic example +## Usage of MOT Slideshow and DLS + +### Basic example + `odr-padenc` reads images from the specified folder, and generates the PAD data for the encoder. This is communicated through a socket to the encoder. It also reads DLS from a file, and includes this information in the PAD. @@ -102,19 +100,27 @@ Basic example with both DLS taken from the file *dls.txt* and MOT Slideshow caro This assumes the common identifier between audio encoder and ODR-PadEnc is defined in the *IDENTIFIER* environment variable. - odr-padenc -o $IDENTIFIER -t dls.txt -d ./slides +```sh +odr-padenc -o $IDENTIFIER -t dls.txt -d ./slides +``` + +The `-o` parameter accepts either: +- An identifier (e.g., `station1`): Creates sockets at `/tmp/station1.padenc` and `/tmp/station1.audioenc` +- A full path (e.g., `/var/run/radio/station1`): Creates sockets at `/var/run/radio/station1.padenc` and `/var/run/radio/station1.audioenc` If you generate slides on-the-fly (e.g. content-related slides with album covers), set the `--erase` flag to ensure a slide is only transmitted once, and set `--sleep=0` to start slide transmission as soon as the file is created. -## If ImageMagick is available +### If ImageMagick is available + It can read all file formats supported by ImageMagick, and by default resizes them to 320x240 pixels, and compresses them as JPEG. If the input file is already a JPEG file of the correct size, and smaller than 50kB, it is sent without further compression. If the input file is a PNG that satisfies the same criteria, it is transmitted as PNG without any recompression. -## RAW Format +### RAW Format + If ImageMagick is not compiled in, or when enabled with the `-R` option, the images are not modified, and are transmitted as-is. Use this if you can guarantee that the generated files are smaller than 50kB and not larger than 320x240 pixels. @@ -122,7 +128,8 @@ Files whose name end in `_PadEncRawMode.png` or `_PadEncRawMode.jpg` will always be transmitted in RAW mode. It may be useful to apply [`optipng`](http://optipng.sourceforge.net) to any PNG file prior to transmission. -## Supported Encoders +### Supported Encoders + `odr-audioenc` and `odr-sourcecompanion` can insert the PAD data from `odr-padenc` into the bitstream. This is an ongoing development. Only some PAD lengths are supported, please see `odr-padenc`'s help. @@ -132,7 +139,8 @@ the tools. ODR-PadEnc v3 replaced the fifo with a socket and is compatible with ODR-AudioEnc v3 and ODR-SourceCompanion v1. -## Character Sets +### Character Sets + When `odr-padenc` is launched with the default character set options, it assumes that the DLS text in the file is encoded in UTF-8, and will convert it according to the DAB standard to the *Complete EBU Latin based repertoire* character set encoding. @@ -147,10 +155,12 @@ case, it is your responsibility to ensure the encoding is valid. For instance, if your data is already encoded in *Complete EBU Latin based repertoire*, you must specify both `--charset=0` and `--raw-dls`. -# Known Limitations +## Known Limitations + Some receivers are unable to decode slides larger than some size, even within the allowed size limit given in the specification. -# Thanks +## Thanks + This encoder was initially called `mot-encoder` and has been contributed by [CSP](http://rd.csp.it). diff --git a/configure.ac b/configure.ac index 3d70686..57c0f65 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,6 @@ dnl -*- Autoconf -*- dnl Process this file with autoconf to produce a configure script. - -AC_INIT([ODR-PadEnc], [3.0.0], [http://opendigitalradio.org/]) +AC_INIT([ODR-PadEnc], [3.1.0], [http://opendigitalradio.org/]) AC_CONFIG_AUX_DIR(.) AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE([tar-ustar foreign]) diff --git a/src/odr-padenc.cpp b/src/odr-padenc.cpp index 3d610bd..5862d17 100644 --- a/src/odr-padenc.cpp +++ b/src/odr-padenc.cpp @@ -61,7 +61,9 @@ static void usage(const char* name) { " -s, --sleep=DUR Wait DUR seconds between each slide. If set to 0, the next slide is inserted just after the previous one\n" " has been transmitted. This is useful e.g. for stations that transmit just a logo slide.\n" " Default: %d\n" - " -o, --output=IDENTIFIER Socket to communicate with audio encoder\n" + " -o, --output=IDENTIFIER Socket to communicate with audio encoder.\n" + " If IDENTIFIER contains '/', it's used as a full path.\n" + " Otherwise, /tmp/ is prepended for backward compatibility\n" " --dump-current-slide=F1 Write the slide currently being transmitted to the file F1\n" " --dump-completed-slide=F2 Once the slide is transmitted, move the file from F1 to F2\n" " -t, --dls=FILENAME FIFO or file to read DLS text from.\n" @@ -455,15 +457,22 @@ int PadEncoder::EncodeSlide() { } int PadEncoder::EncodeLabel() { - // skip insertion, if previous one not yet finished + // delay insertion, if previous one not yet finished if (pad_packetizer.QueueContainsDG(DLSEncoder::APPTYPE_START)) { - fprintf(stderr, "ODR-PadEnc Warning: skipping label insertion, as previous one still in transmission!\n"); + if(!label_warn_shown) { + fprintf(stderr, "ODR-PadEnc Warning: there is a label already in transmission, delaying until the previous one ends.\n"); + label_warn_shown = true; + } + return 0; } else { + if(label_warn_shown) { + fprintf(stderr, "ODR-PadEnc Previous label ended transmission, sending the new one.\n"); + label_warn_shown = false; + } dls_encoder.encodeLabel(options.dls_files[curr_dls_file], options.item_state_file, options.dl_params); + return 1; } - - return 0; } @@ -534,12 +543,13 @@ int PadEncoder::Encode(PadInterface& intf) { if (pad_timeline >= next_label_insertion) { // encode label - result = EncodeLabel(); - next_label_insertion += std::chrono::milliseconds(options.label_insertion); + int label_encode_result = 0; + label_encode_result = EncodeLabel(); + if(label_encode_result > 0) { + next_label_insertion += std::chrono::milliseconds(options.label_insertion); + } } } - if (result) - return result; // flush one PAD (considering X-PAD output interval) auto pad = pad_packetizer.GetNextPAD(xpad_interval_counter == 0); diff --git a/src/odr-padenc.h b/src/odr-padenc.h index c493d95..6a48516 100644 --- a/src/odr-padenc.h +++ b/src/odr-padenc.h @@ -82,6 +82,7 @@ protected: SLSEncoder sls_encoder; SlideStore slides; bool slides_success; + bool label_warn_shown; int curr_dls_file; steady_clock::time_point next_slide; steady_clock::time_point next_label; diff --git a/src/pad_common.cpp b/src/pad_common.cpp index 8ee2cd8..f8e769a 100644 --- a/src/pad_common.cpp +++ b/src/pad_common.cpp @@ -143,7 +143,9 @@ std::vector<uint8_t> PADPacketizer::GetNextPAD(bool output_xpad) { pad_t* pad = output_xpad ? GetPAD() : FlushPAD(); if (verbose >= 2) { - fprintf(stderr, "ODR-PadEnc writing PAD (%zu bytes):", pad->size()); + fprintf(stderr, "ODR-PadEnc writing %cPAD (%zu bytes):", + output_xpad ? 'X' : 'F', + pad->size()); for (size_t j = 0; j < pad->size(); j++) { const char sep = (j == (pad->size() - 1) || j == (pad->size() - 1 - FPAD_LEN)) ? '|' : ' '; fprintf(stderr, "%c%02X", sep , (*pad)[j]); @@ -227,6 +229,14 @@ bool PADPacketizer::AppendDG(DATA_GROUP* dg) { } else { AppendDGWithCI(dg); + /* + fprintf(stderr, "flush? %d %zu == %zu or %d: %zu + %zu > (%zu - %zu)\n", + used_cis == max_cis, + used_cis, max_cis, + SUBFIELD_LENS[0] + AddCINeededBytes() > (xpad_size_max - xpad_size), + SUBFIELD_LENS[0], AddCINeededBytes(), xpad_size_max, xpad_size); + */ + // if no further sub-fields could be added, PAD must be flushed if (used_cis == max_cis || SUBFIELD_LENS[0] + AddCINeededBytes() > (xpad_size_max - xpad_size)) return true; diff --git a/src/pad_interface.cpp b/src/pad_interface.cpp index 3db5308..26a04ab 100644 --- a/src/pad_interface.cpp +++ b/src/pad_interface.cpp @@ -47,7 +47,17 @@ void PadInterface::open(const std::string &pad_ident) struct sockaddr_un claddr; memset(&claddr, 0, sizeof(struct sockaddr_un)); claddr.sun_family = AF_UNIX; - snprintf(claddr.sun_path, sizeof(claddr.sun_path), "/tmp/%s.padenc", m_pad_ident.c_str()); + + size_t last_slash = m_pad_ident.find_last_of('/'); + if (last_slash != std::string::npos) { + // Full path provided, use as-is with .padenc suffix + std::string socket_dir = m_pad_ident.substr(0, last_slash); + std::string socket_base = m_pad_ident.substr(last_slash + 1); + snprintf(claddr.sun_path, sizeof(claddr.sun_path), "%s/%s.padenc", socket_dir.c_str(), socket_base.c_str()); + } else { + // Identifier only, use /tmp/ for backward compatibility + snprintf(claddr.sun_path, sizeof(claddr.sun_path), "/tmp/%s.padenc", m_pad_ident.c_str()); + } if (unlink(claddr.sun_path) == -1 and errno != ENOENT) { fprintf(stderr, "Unlinking of socket %s failed: %s\n", claddr.sun_path, strerror(errno)); } @@ -110,7 +120,17 @@ void PadInterface::send_pad_data(const uint8_t *data, size_t len) struct sockaddr_un claddr; memset(&claddr, 0, sizeof(struct sockaddr_un)); claddr.sun_family = AF_UNIX; - snprintf(claddr.sun_path, sizeof(claddr.sun_path), "/tmp/%s.audioenc", m_pad_ident.c_str()); + + size_t last_slash = m_pad_ident.find_last_of('/'); + if (last_slash != std::string::npos) { + // Full path provided, use as-is with .audioenc suffix + std::string socket_dir = m_pad_ident.substr(0, last_slash); + std::string socket_base = m_pad_ident.substr(last_slash + 1); + snprintf(claddr.sun_path, sizeof(claddr.sun_path), "%s/%s.audioenc", socket_dir.c_str(), socket_base.c_str()); + } else { + // Identifier only, use /tmp/ for backward compatibility + snprintf(claddr.sun_path, sizeof(claddr.sun_path), "/tmp/%s.audioenc", m_pad_ident.c_str()); + } vector<uint8_t> message(len + 1); message[0] = MESSAGE_PAD_DATA; diff --git a/src/pad_interface.h b/src/pad_interface.h index f0307bd..2803b5e 100644 --- a/src/pad_interface.h +++ b/src/pad_interface.h @@ -33,8 +33,10 @@ class PadInterface { public: - /*! Create a new PAD data interface that binds to /tmp/pad_ident.padenc and - * communicates with ODR-AudioEnc at /tmp/pad_ident.audioenc + /*! Create a new PAD data interface that binds to a socket and + * communicates with ODR-AudioEnc. If pad_ident contains '/', it's used as a full path. + * Otherwise, /tmp/ is prepended for backward compatibility. + * Sockets: pad_ident.padenc (this) and pad_ident.audioenc (ODR-AudioEnc) */ void open(const std::string &pad_ident); |
