aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--README.md90
-rw-r--r--configure.ac3
-rw-r--r--src/odr-padenc.cpp28
-rw-r--r--src/odr-padenc.h1
-rw-r--r--src/pad_common.cpp12
-rw-r--r--src/pad_interface.cpp24
-rw-r--r--src/pad_interface.h6
8 files changed, 113 insertions, 56 deletions
diff --git a/ChangeLog b/ChangeLog
index 868055e..e710655 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/README.md b/README.md
index d31dd43..b2bc16f 100644
--- a/README.md
+++ b/README.md
@@ -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
+[![Packaging status](https://repology.org/badge/vertical-allrepos/odr-padenc.svg)](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);