Preface

TSDuck is a free and open-source toolkit to manipulate MPEG Transport Streams.

This document is the TSDuck Developer Guide. It is used by developers of third-party C++, Python, or Java applications which use the TSDuck library.

As a product, TSDuck provides many different command-line tools and plugins. Internally, the architecture of TSDuck is made of a large shareable library (tsduck.dll on Windows, libtsduck.so on Linux and BSD systems, libtsduck.dylib on macOS). Most of the valuable processing is performed by the various C++ classes from the TSDuck library. All command-line tools and plugins are usually small wrappers around this library.

The TSDuck library offers generic C++ classes as well as specialized classes for Digital TV. They can be used by any application to manipulate MPEG transport streams, the signalization, and various data which are carried in MPEG-TS. This library can be used as a general-purpose C++ library for third-party applications, outside the TSDuck tools and plugins.

A subset of high-level features is also accessible from Java and Python applications.

The following figure illustrates the TSDuck software architecture and how it interacts with third-party applications.

TSDuck software architecture
Figure 1. TSDuck software architecture

Structure of this guide:

  • The chapter 1 describes the various TSDuck libraries.

  • The chapter 2 explains how to build an application using TSDuck.

  • The chapter 3 is an overview of the main features of the TSDuck library.

  • The chapter 4 is a detailed description of the reactor pattern and event dispatching.

  • The chapter 5 is an overview of the Java and Python bindings for TSDuck.

  • The chapter 6 describes the development of TSDuck plugins.

  • The chapter 7 describes the development of TSDuck extensions.

In addition to this developer guide, a comprehensive reference programming documentation is available online. It documents all TSDuck public C++ classes, as well as the Python and Java API’s. This is a reference documentation which is automatically generated from the source files using doxygen.

License

TSDuck is released under the terms of the license which is commonly referred to as "BSD 2-Clause License" or "Simplified BSD License" or "FreeBSD License". This is a liberal license which allows TSDuck to be used in a large number of environments. See the appendix B for more details.

Documentation format

The TSDuck guides are built using asciidoctor, from a set of text files which are maintained alongside the source code, in the same git repository.

This guide is formatted for HTML. The file tsduck-dev.html is monolithic and self-sufficient, without reference to external images. Therefore, this HTML file can be downloaded, saved, and copied, as long as the license and content are not modified.

A PDF version tsduck-dev.pdf is also available. However, due to limitations in the PDF generator of asciidoctor, the rendering is sometimes not as good as the HTML document.

Documentation set

The TSDuck documentation set is made of:

  1. TSDuck User Guide, using TSDuck commands and plugins (also from tsduck.io and in PDF format)

  2. TSDuck Builder Guide, building and installing TSDuck (also from tsduck.io and in PDF format)

  3. TSDuck Developer Guide, using TSDuck from C++, Python, Java applications (also from tsduck.io and in PDF format)

  4. TSDuck Contributor Guide, contributing to TSDuck development (also from tsduck.io and in PDF format)

  5. TSDuck Programming Reference, Doxygen-generated reference of all TSDuck classes.

1. Two libraries: TSCore and TSDuck

Starting with version 3.40, the TSDuck library has been split in two parts:

  • The TSCore library contains generic C++ classes and features which are not specific to Digital TV.

  • The TSDuck library contains all Digital TV classes and features. It depends on the TSCore library for basic features.

Although it does not compete with other widely used C++ utility libraries, the TSCore library can be useful to any type of application. It include features for networking, text processing (including XML and JSON handling), advanced strings, unified logging and reporting, data serialization and deserialization, etc.

Before the split, the size of the TSDuck library became quite large. Most of it was made of C++ classes to handle Digital TV features, including nearly 400 classes to handle tables and descriptors which are defined by the various Digital TV standards. In addition to their large memory footprint, these classes self-register themselves at the initialization of the TSDuck library, slowing down the application startup on small systems.

For applications which only used the basic features of the TSDuck library, the Digital TV features became too bulky. Therefore, these basic features were extracted as a new TSCore library.

The TSCore shared library file is named libtscore.so, libtscore.dylib, or tscore.dll, depending on the operating system. The TSDuck shared library file is named libtsduck.so, libtsduck.dylib, or tsduck.dll,

Their respective header files are installed in directories include/tscore and include/tsduck (the exact location of the include parent directory depends on the operating system).

Therefore, the two development environments are separated. The next chapters explain in details how to use each of them.

Since the TSDuck library uses the TSCore library, any application which uses the former has implicit access to the latter. Specifically, applications which already used the monolythic TSDuck library before version 3.40 can be built without any change.

Starting with version 3.42, TSDuck installs a third common shared library named libtsdektec. This library contains the common code to access the Dektec devices, as well as the Dektec-provided DTAPI proprietary code. It is only designed to provide common code for the tsdektec command and the two dektec plugins, input and output. This library is not accessible to third-party applications.

This library libtsdektec was extracted from the main TSDuck library as a response to users who preferred to separate free and non-free code. Thus, when required, removing libtsdektec, as well as the tsdektec command and the tsplugin_dektec shared library, is sufficient to remove all non-free code from a TSDuck installation.

2. Building an application with the TSDuck libraries

2.1. Pre-requisites

To be able to build applications or tsp plugins with the TSDuck libraries, you must install the TSDuck development environment first.

  • On Windows systems, you must select the optional "Development" component during the installation.

  • On Fedora, Red Hat and clones, you must install the package tsduck-devel.

  • On Ubuntu and the Debian family, you must install the package tsduck-dev.

  • On macOS systems, the development environment is always installed with TSDuck using Homebrew.

  • If you build TSDuck from sources, use make install (which is equivalent to make install-tools install-devel).

2.2. Building applications on UNIX systems (Linux, macOS, BSD)

The command tsconfig generates the appropriate build options for the current operating system. See the TSDuck user guide for more details on tsconfig.

The following sample makefile illustrates the creation of a simple application named myexec using one single source file myexec.cpp.

CXXFLAGS += $(shell tsconfig --cflags)
LDLIBS += $(shell tsconfig --libs)

default: myexec

This is as simple as that.

Just run make to build the application.

$ make

As explained in the user guide, use the tsconfig option --tscore if you want to use the TSCore library only, not the full TSDuck library for Digital TV. For instance:

CXXFLAGS += $(shell tsconfig --tscore --cflags)
LDLIBS += $(shell tsconfig --tscore --libs)

C++ language level

By default, the command tsconfig --cflags forces C++20 as level of C++ language standard. If your application requires a more recent level, define the environment variable TS_NOSTDCPP to any non-empty value. This disables the C++ standard option in tsconfig. The application shall then define its own C++ standard in its command line. This user-specified C++ standard cannot be lower than C++20.

Alternatively, the command tsconfig --nostdcpp --cflags can be used to omit the C++ standard from the compilation options without defining the environment variable TS_NOSTDCPP.

2.3. Building applications on Windows

The "Development" option of the TSDuck installer provides the build environment for Visual Studio 2022, in debug and release mode, for 64-bit Intel platforms. It may be compatible with Visual Studio 2019 or earlier, but without guarantee.

The environment variable TSDUCK is defined to the root of the TSDuck installation tree. A Visual Studio property file named tsduck.props is installed here. It provides all definitions and options to use the TSDuck libraries.

Create the solution and projects for your application. Then, manually edit the project file, named for instance app.vcxproj, and insert the following line just before the final </Project> closing tag:

<Import Project="$(TSDUCK)\tsduck.props"/>

Then build your project normally.

If you want to use the TSCore library only, not the full TSDuck library for Digital TV, use the file tscore.props instead:

<Import Project="$(TSDUCK)\tscore.props"/>

C++ language level

By default, the property file tsduck.props forces C++20 as level of C++ language standard. If your application requires a more recent level, define the environment variable TS_NOSTDCPP to any non-empty value. This disables the C++ standard option in tsduck.props. The application shall then define its own C++ standard in its project files. This user-specified C++ standard cannot be lower than C++20.

3. Overview of the TSDuck libraries

The TSDuck libraries contain general-purpose C++ classes and utilities to handle MPEG transport streams.

For programming details, see the programming reference documentation online (doxygen-generated).

Roughly, the TSDuck libraries provide two categories of features:

  • Operating system abstraction layer to make the application code fully portable between heterogeneous platforms. This is similar to frameworks such as Qt, but much more lightweight.

  • Handling of MPEG transport streams and signalization, including DVB, ATSC and ISDB features.

In early versions of TSDuck, the OS abstraction layer contained many more classes. Starting with C++11 and C++20, the standard library of the language was enriched with many more system features. Some low-level TSDuck classes became obsolete. The code was migrated to use standard C++20 features and the corresponding low-level classes were removed from TSDuck.

All C++ declarations are located inside the namespace ts, either directly within ts or inside inner namespaces. All preprocessor’s macros are named with prefix TS_.

3.1. C++ features

3.1.1. Portability issues

The file tsPlatform.h contains some very low level definitions such as macros defining the environment (processor, compiler, operating system, endianness), byte and bit manipulation, etc.

3.1.2. C++ strings

C and C++ strings are made of 8-bit characters which are notoriously unable to represent international character sets. The usage of std::string with the TSDuck libraries is discouraged in favor of Unicode strings.

3.1.3. Unicode strings

The class ts::UString implements Java-like Unicode strings. Each character uses 16 bits of storage. Formally, ts::UString uses UTF-16 representation. This means that all characters from all modern languages can be represented as one single character. Characters from archaic languages may need two UTF-16 values, called a "surrogate pair".

Technically, ts::UString is a subclass of std::u16string. So any operation on standard C++ strings is also available to ts::UString. But many more operations have been added to manipulate Unicode strings.

For consistency, the type ts::UChar is an alias for char16_t. The header file tsUChar.h defines some utility functions on ts::UChar. It also defines constants for most Unicode characters like ts::COLON or more complex ones such as ts::LATIN_CAPITAL_LETTER_A_WITH_ACUTE, among hundredths of others.

Some interesting features in class ts::UString are:

  • Explicit and implicit conversions between UTF-8 and UTF-16.

  • Including automatic conversion to UTF-8 when writing to text streams.

  • Conversions with DVB and ARIB character sets.

  • Conversions with HTML encoding.

  • Management of "display width", that is to say the amount of space which is used when the string is displayed. This can be different from the string length in the presence of combining diacritical characters or surrogate pairs.

  • String padding, trimming, truncation, justification, case conversions.

  • Substring, prefix or suffix detection, removal or substitution.

  • Splitting and joining strings based on separators or line widths.

  • Reading or writing text lines from or to a text file.

  • Data formatting using format(), Format(), Decimal(), Hexa(), Dump().

  • Data scanning using scan().

Unicode strings can be converted to and from DVB or ARIB (Japan) strings. Most DVB-defined character sets are implemented (see the classes ts::Charset and ts::DVBCharset) and recognized when a string is read from a descriptor. When a string is serialized into a binary descriptor, the most appropriate DVB character set is used. In practice, a few known DVB character sets are used and, when the string cannot be encoded in any of them, UTF-8 is used (UTF-8 is always a valid DVB character set).

3.1.4. Binary data

The class ts::ByteBlock represents a raw block of bytes. It is a subclass of std::vector<uint8_t> and consequently benefits from all standard vector operations. It also adds useful methods for data serialization or deserialization in any byte order.

For data serialization or deserialization over arbitrary memory areas, the header file tsMemory.h provides low-level functions to access integer values of 8, 16, 24, 32, 40, 48 and 64 bits in any byte order.

The class ts::Buffer provides a higher-level abstraction layer over a memory area to parse or generate bitstreams. It gives access to data of any bit-size at any bit position, any endianness, either as a continuous stream or seeking at random bit positions.

The principles of the C++ class ts::Buffer were freely inspired by the Java class java.nio.ByteBuffer. There are differences between the two but the main principles are similar.

Its subclass ts::PSIBuffer provides primitives to serialize and deserialize MPEG and DVB structures such as list of descriptors, DVB, ARIB and ATSC strings or "Modified Julian Dates".

3.1.5. Singletons and static data

The singleton design pattern is simple in theory, but not so simple to implement correctly in practice. The TSCore library encapsulates the implementation difficulties using the two macros TS_SINGLETON() (in a header file) and TS_DEFINE_SINGLETON() (in the corresponding compilation unit).

In practice, the singleton design pattern is a specific case of global static data, variables which are defined outside any function. Using static data can be a nightmare because it is impossible to manage the initialization order of modules in C++.

In the past, how to properly managed singletons and static data was quite difficult, involving dangerous pointer and thread synchronization tricks. This has been abundantly documented by Scott Meyers (see [MEYERS-EFF]).

In modern C++, most of these difficulties have been solved in the language using local static data. In practice, the same tricks are used but they are now hidden inside the compiler and the run-time library.

3.1.6. Error reporting

All TSDuck classes use a consistent error reporting mechanism through the ts::Report abstract class.

This interface defines several levels of severity in the type ts::Severity, ranging from ts::Severity::Debug to ts::Severity::Fatal. Each instance of ts::Report defines which levels of message are reported to the user. This is usually triggered by command-line options such as --verbose or --debug.

Most classes or methods from the TSDuck libraries use a reference to an instance of ts::Report to report messages and errors. The actual reporting object is often built at application level and then propagated to all layers of code.

Some interesting subclasses of ts::Report are:

  • ts::CerrReport, a singleton which reports errors to std::cerr. The macro CERR can be used as a shortcut to the instance of the singleton.

  • ts::NullReport, a singleton which drops all messages. The macro NULLREP can be used as a shortcut to the instance of the singleton.

  • ts::ReportFile which logs messages in a file. It can be made thread-safe using a ts::ThreadSafety value as template argument.

  • ts::ReportBuffer which logs messages in a memory buffer. It can be made thread-safe using a ts::ThreadSafety value as template argument.

  • ts::Args (see section 3.1.9) which defines the syntax and handling of command line arguments. This is the typical instance of ts::Report which is used at application-level.

  • ts::Plugin, the superclass of all tsp plugins. A plugin reports its messages directly in its own instance. Each tsp plugin executes in a separate thread and asynchronously logs messages without slowing down the plugin’s thread.

3.1.7. Exceptions

As a general rule, TSDuck prefers the usage of error reporting interface and error status over exceptions. However, for a limited number of unrecoverable conditions which should never occur in practice, exceptions are used.

All TSDuck exceptions inherit from the superclass ts::Exception. An instance of this exception is able to embed an error message and an optional system error code.

Each specific exception should be a subclass of ts::Exception. Instead of rewriting the subclass code, applications should use the macro TS_DECLARE_EXCEPTION().

3.1.8. Pseudo-enumeration data

An instance of the class ts::Enumeration associates a list of integer or enum values with strings. It can be used to display meaningful strings instead of integer values.

It is even more useful to decode command line arguments. When an option accepts a predefined list of values, the input string can be either an integer value or a name. When it is a name, it can even be abbreviated as long as it is not ambiguous in the corresponding ts::Enumeration. This is transparent for the application which receives the corresponding integer value.

3.1.9. Command-line arguments

The class ts::Args implements a generic handling of command line arguments.

Each application typically defines its own subclass of ts::Args. A plugin is always a subclass of ts::Args, through the intermediate class ts::Plugin.

A subclass of ts::Args defines the command line syntax and the corresponding help text. The superclass ts::Args automatically parses the command line, reports errors and handle common options such as --help or --version.

The value of command line options can be free strings, integer values or enumeration values. Integer values are recognized in decimal or hexadecimal form (prefix 0x) and thousands separators (‘,’) which are present for clarity are ignored. Enumeration values are handled through ts::Enumeration.

3.1.10. XML data

The TSCore library embeds an XML parser and several classes to handle a DOM structure.

See the class ts::xml::Node, the abstract base class of the DOM hierarchy.

3.1.11. JSON data

The TSCore library embeds a JSON parser and several classes to handle JSON values.

See the class ts::json::Value, the abstract base class of the JSON hierarchy.

3.2. Cryptography

The TSDuck libraries contain a few cryptographic classes. These libraries are not cryptographic libraries and will never be. Cryptography is a serious matter which should be left to cryptographers.

Some transport stream processing operations require cryptographic operations, essentially block ciphers and hash functions. The TSCore library proposes an homogeneous API over them. Standard cryptographic primitives are implemented using the standard system libraries, OpenSSL on UNIX systems (Linux, macOS, BSD), BCrypt on Windows. Most standard chaining modes are also implemented in the standard system libraries. The TSCore library implements more exotic chaining modes only.

Specific algorithms which are defined by Digital TV standard bodies (DVB, SCTE or IDSA) are implemented in the TSDuck library. However, most of them are only specific modes over standard cryptographic primitives such as AES or DES. The TSDuck library implements the specific modes but the primitives are used from the system cryptographic libraries, except the very specific DVB-CSA2 algorithm which is directly implemented in the TSDuck library.

The abstract class ts::BlockCipher is the root of a hierarchy of symmetric cryptography classes, including chaining modes. The main block cipher classes are ts::AES128, ts::AES256, ts::TDES and ts::DES.

DES is an obsolete and insecure algorithm. TDES (a.k.a. 3-DES or Triple DES) is also deprecated. However, the two are still used in some legacy ATSC Digital TV systems.

Chaining modes are template classes which inherit from the abstract class ts::CipherChaining. The template parameter is a block cipher class. The main chaining modes are ts::ECB, ts::CBC, various flavors of ts::CTSx or more exotic modes from the DTV world such as ts::DVS042.

Additionally, ts::CipherChaining is also a subclass of ts::BlockCipher because it remains a symmetric cipher. So, ciphers like ts::AES or ts::CBC<ts::AES> can be used through the same ts::BlockCipher interface.

The class ts::Scrambling implements DVB-CSA-2, the Digital Video Broadcasting Common Scrambling Algorithm. This implementation is older than the open-source libdvbcsa library and is probably less efficient.

The abstract class ts::Hash is the root of a hierarchy of hash functions classes. The main hash functions are ts::SHA1, ts::SHA256 or ts::SHA512.

The abstract class ts::RandomGenerator is the root of pseudo-random generators.

The subclass ts::SystemRandomGenerator is a portable interface to the system-provided PRNG. Usually, this is not the best PRNG on earth, but it is fine for most usages in TSDuck applications. For more critical usages (such as encryption key generation), use ts::BetterSystemRandomGenerator. This PRNG class uses ts::SystemRandomGenerator with an additional security layer.

The class ts::Xoshiro256ss implements the Xoshiro256** PRNG. It is a fast and deterministic PRNG, with a low level of security. The same seed will always produce the same pseudo-random sequence. It can be used in cases where many random numbers are required, without strong security criteria. It is typically used in fuzzing tools.

3.3. Operating system features

3.3.1. Miscelleaneous system utilities

The header files tsSysUtils.h, tsFileUtils.h, tsEnvironment.h, declare utility functions on top of the operating system.

With the introduction of C++20, many of these functions have been removed in favor of new standard functions. However, a number of additional features manipulate:

  • File paths.

  • File attributes.

  • Creating or deleting files and directories.

  • Environment variables.

  • Process identifiers.

  • System error codes.

3.3.2. Time

The class ts::Time is a portable implementation of time (both local and UTC time).

Many operations are provided, such as:

  • Getting system time in various forms.

  • Arithmetic operations on time.

  • Analysing and building time values.

  • Formatting time values as strings.

3.3.3. Multithreading

TSDuck is heavily multi-threaded. The abstract class ts::Thread manages a thread. To define an actual thread, derive this class and implement the virtual method main().

The class ts::ThreadAttributes contains all mandatory or optional attributes of a thead. An application typically builds a ts::ThreadAttributes object and then creates threads using these attributes.

In earlier versions of TSDuck, synchronization primitives used to be implemented through specific classes (ts::Mutex, ts::Condition). They are now removed and new C++11 classes such as std::mutex and std::condition_variable are used instead.

Note that the C++11 class std::thread is not used. Its API is too limited to be useable in complex environments: it does not allow to customize the priority or the stack size before the creation of the thread. Therefore, TSDuck exclusively uses ts::Thread and ts::ThreadAttributes instead.

TSDuck relies on C++ mechanisms to track the usage of resources. Standard classes such as std::lock_guard or std::unique_lock are used to ensure that no dangling lock is lost through the guard design pattern.

In addition to multithreading, TSDuck also uses event dispatching. See chapter 4 for more details.

3.3.4. Virtual memory

The class ts::ResidentBuffer implements a buffer which is locked in physical memory, preventing paging or swapping on this buffer. This is useful for large data buffers with high performance constraints.

This is a template class. The template parameter is the type of the elementary data in the buffer.

The core data of the tsp processor is a ts::ResidentBuffer<ts::TSPacket>. The incoming packets are directly written into this buffer by the input plugin. Each packet processing plugin directly reads and writes the packets here. And the output plugin reads the packet there, at the very same place they were written by the input plugin. Given that this global buffer is locked in physical memory, the best performances are guaranteed.

Note however that most operating systems require that the application has privileges to lock physical memory.

3.3.5. Processes

To track potential memory leaks and the impact of the application on the system, the class ts::SystemMonitor creates a background thread which reports the process metrics of the application at regular intervals.

The class ts::ForkPipe is a portable and convenient way to create a process running a specific command and creates an outgoing pipe from the calling application to the standard input of the created process, or an incoming pipe from the standard output of the created process to the calling application, or both. The pipes are open in binary mode (when it makes sense for the operating system) and can be used to pass an entire transport stream when necessary.

3.3.6. Networking

The classes ts::IPAddress and ts::IPSocketAddress define an IP address and a corresponding socket address (an IP address and a port number). Host name resolution and multicast are supported.

The class ts::IPAddress can hold IPv4 and IPv6 addresses. All network operations on name resolutions and TCP or UDP sockets are transparently supported for IPv4 and IPv6 addresses.

The classes ts::TCPSocket and ts::UDPSocket implement TCP/IP and UDP/IP endpoints.

The class ts::UDPSocket can be used directly to send and receive datagrams. Multicast is supported.

The class ts::TCPSocket can be used only through two subclasses. The subclass ts::TCPConnection is a TCP/IP communication endpoint, either on client or server side. It is used to send or receive data streams. The subclass ts::TCPServer is used to implement a TCP server. It accepts incoming client connections and initiates a ts::TCPConnection for each new connection. On the client side, the class ts::TCPConnection is directly used to connect to the server.

The class ts::WebRequest performs simple Web requests using HTTP, HTTPS or FTP. Using a URL, the result can be downloaded in memory or in a file. Multiple redirections and SSL/TLS are automatically handled. This class is built on top of native system libraries, libcurl on UNIX systems (Linux, macOS, BSD), WinInet on Windows.

In addition to straightforward communication classes using blocking I/O, TSDuck also uses event dispatching on non-blocking I/O ("immediate" I/O on UNIX systems or "asynchronous" I/O on Windows). See chapter 4 for more details.

3.3.7. Shared libraries

The TSCore library contains classes to load shared libraries (.dll on Windows, .so on Linux and BSD, .dylib on macOS) and lookup symbols inside them in a portable way. These classes are typically used to load tsp plugins but can be used in any application.

The class ts::SharedLibrary manipulates any type of shared library.

The subclass ts::ApplicationSharedLibrary searches a shared library using TSDuck rules: if the file is not found "as it is", an optional prefix and a list of directories are used. This is how, on Windows for instance, searching the shared library named dektec will end up loading the file tsplugin_dektec.dll in the same directory as the application executable file.

3.3.8. Smart-card interface

Applications which interact with smart-cards shall use the PC/SC interface. PC/SC is a standard interface which was originally developped for Windows but which is also available on Linux and macOS.

The TSDuck library does not embed or hide PC/SC but it provides a few utilities like transmitting an APDU and read the response in one single function or searching a smart-card with some characteristics in the ATR from all connected smart-cards.

All these utilities are grouped in the namespace ts::pcsc.

3.3.9. Windows specificities

The class ts::COM provides a portable and reliable way to make sure that the Common Object Model (COM) is properly initialized and terminated on Windows systems. This class is defined on all platforms but does nothing on non-Windows systems. It is consequently safe to use it everywhere without tedious conditional compilation directives.

Other classes manipulate Windows-specific objects and are not available on non-Windows systems.

The template class ts::ComPtr is the equivalent of a smart pointer for COM objects. The reference count of a COM object is properly incremented and decremented when the COM object is manipulated through a ts::ComPtr. The COM object is automatically released when no more reference exists.

There is little advantage to develop an intrinsicly non-portable COM object class. However, in order to access tuner devices, TSDuck needed a few custom internal COM classes to interact with the DirectShow framework. These internal classes needed some COM support functions which are available to applications (just in case…​)

3.4. MPEG features

3.4.1. Transport streams

The class ts::TSPacket defines a transport stream packet. It is in fact a flat structure which occupies exactly 188 bytes in memory. It is safe to use arrays or vectors of ts::TSPacket. The packets are guaranteed to be contiguous in memory.

The class ts::TSPacket also adds many operations on the TS packet to read or modify properties like the PID (type ts::PID), the continuity counters or deeper structures like PCR, DTS or PTS.

The class ts::TransportStreamId contains the identification of an MPEG/DVB transport stream.

The class ts::Service contains all possible properties of a DVB service. Not all properties need to be set at the same time. Each property can be individually set, cleared or queried.

Transport stream files are implemented by classes ts::TSFileInput and ts::TSFileOutput. They respectively read and write transport stream files with specific features such as repeating the reading of a part of the file.

The subclass ts::TSFileInputBuffered provides additional, but limited, capabilities to seek forward and backward on non-seekable files such as pipes.

The subclass ts::TSFileOutputResync adds resynchronization capabilities on continuity counters and PID’s.

The class ts::TSAnalyzer consumes all TS packets from a transport stream and analyzes virtually everything from the stream. This is the class which is used by the command tsanalyze and the plugin analyze to collect the vast amount of information it reports.

The class ts::PCRAnalyzer is a useful tool to evaluate the bitrate of a transport stream. It performs the analysis of the Program Clock Reference (PCR) which are present in the transport stream in order to evaluate the bitrate of the stream. If PCR are not found, the class can also use Decoding Time Stamps (DTS) to evaluate the bitrate. This is less precise than PCR but can be used as a backup.

3.4.2. Audio, video and PES packets

The TSDuck library provides classes to manipulate PES packets and a few audio and video attributes. These features are limited to the analysis of a transport stream. There is no video or audio decoding features. Specialized libraries exist for this and are out of scope for TSDuck.

The class ts::PESPacket implements a PES packet and can manipulate its attributes, header and payload.

The class ts::PESDemux extracts PES packets from a transport stream. It can also notify the application of the changes in audio or video attributes.

The abstract class ts::AbstractAudioVideoAttributes is the root of a hierarchy of classes which contains attributes for audio or video streams. Currently, specialized classes exist for MPEG-2 video, AVC/H.264, HEVC/H.265, VVC/H.266 video, MPEG-2 audio and AC-3 audio.

The class ts::AVCParser performs the parsing of an AVC, HEVC, or VVC bitstream.

3.5. Signalization

The MPEG signalization is built from sections, tables and descriptors. All these concepts are implemented in the TSDuck library.

3.5.1. Binary, specialized and XML formats

Signalization objects, sections, tables and descriptors, can be manipulated in several formats: binary objects, specialized classes and XML.

Tables in JSON format are also supported through automatic XML-to-JSON translation.

The classes ts::Section, ts::BinaryTable and ts::Descriptor implement binary forms of the signalization objects.

A binary table are made of a collection of sections. A binary table is valid when all binary sections are present. Each section contains its section number in the table and the total expected number of sections inside the table.

All sections and descriptors can be represented by the classes ts::Section and ts::Descriptor. They simply contain the complete binary content of the object and can manipulate the various components. An instance of ts::Section stores the table_id and manipulates the various components of the section header. For long sections, the final CRC32 can be checked for consistency or recomputed after modification of the section content.

Tables can be stored in binary files. The format of these files is quite simple. They just contain raw binary sections, without any encapsulation. Tables can also be stored in XML or JSON files. The class ts::SectionFile reads and writes tables or section from files, independently of the format, either a binary section file or an XML file.

Tables and descriptors can also be manipulated using specialized classes such as ts::PAT or ts::PMT for tables and ts::ContentDescriptor or ts::ShortEventDescriptor for descriptors.

All specialized classes inherit from a common abstract root named ts::AbstractSignalization. All descriptors inherit from the intemediate class ts::AbstractDescriptor. All tables inherit from the intemediate class ts::AbstractTable. Tables with long sections inherit from ts::AbstractLongTable.

Most tables and descriptors are implemented, from MPEG, DVB, ATSC, ISDB and a few private descriptors. Unimplemented descriptors shall be manipulated in binary form (or be implemented…​)

Binary tables or descriptors are converted from or to specialized classes using serialize() and deserialize() methods. The validity of a binary or specialized object can be checked using the isValid() method.

Sample deserialization code:

void someFunction(ts::DuckContext& duck, const ts::BinaryTable& table)
{
    ts::PMT pmt;
    if (table.isValid() && table.tableId() == ts::TID_PMT) {
        pmt.deserialize(duck, table);
        if (pmt.isValid()) {
            processPMT(pmt);
        }
    }
}

The deserialization can also be done in the constructor. And the validity and table_id checking is done anyway in the deserialization. So, the previous code can be simplified as:

void someFunction(ts::DuckContext& duck, const ts::BinaryTable& table)
{
    ts::PMT pmt(duck, table);
    if (pmt.isValid()) {
        processPMT(pmt);
    }
}

Sample serialization:

ts::DuckContext duck;

ts::PMT pmt;
pmt.version = 12;
pmt.service_id = 0x1234;
// Declare one component, PID 0x345, carrying H.264/AVC video.
pmt.streams[0x345].stream_type = ts::ST_AVC_AUDIO;

ts::BinaryTable table;
pmt.serialize(duck, table);

Note that an instance of the class ts::DuckContext can store various information about the way to interpret incorrect signalization or preferences. Its default value is appropriate for a standard PSI/SI processing.

Each time the instance of ts::DuckContext is used, it accumulates information. For instance, if it is used to deserialize an ATSC MGT table, the information that the TS is an ATSC one is retained. Later, if the same instance of ts::DuckContext is used to deserialize a descriptor for which there is an ambiguity (the tag is used in two standards for instance), the ATSC version of the descriptor will be used.

It is also possible to automatically define and load command line options to preset the state of the instance of ts::DuckContext. See section 3.5.3 for more details.

Finally, specialized classes for tables and descriptors can be converted to and from XML using the methods toXML() and fromXML().

These methods are typically used by the class ts::SectionFile which represents a file containing sections and tables in binary or XML format. The class can be used to load a set of tables in XML format or to store table objects in XML format.

The class ts::SectionFile is the core of the tstabcomp utility, the tables compiler (or decompiler).

3.5.2. Demux and packetization

Signalization objects can be extracted from transport streams using the class ts::SectionDemux and inserted back into transport streams using the class ts::Packetizer. These two classes also have specialized subclasses.

An instance of ts::SectionDemux can extract sections or complete tables in binary form.

Tables with long sections are usually cycled. A given table with a given version number and a given table id extension is reported only once, after collecting all its sections. The same table will be reported again only when its version number changes.

On the contrary, short tables are all reported since they do not implement versioning.

It is also possible to use a ts::SectionDemux to be notified of all individual sections.

3.5.3. Application preferences contexts

The class ts::DuckContext carries various preferences about the standards or localizations. Typically, each application has a given context. Using tsp, each plugin has it own context.

The preferences which are carried by a context include the default standard (DVB, ATSC, ISDB), the default character sets in PSI/SI, the default private data specifier (for DVB private descriptors), the HF region (for terrestrial or satellite frequency mapping)

The ts::DuckContext class can automatically define command-line arguments to explicitly specify preferences (options --atsc or --default-charset for instance). Thus, the preferences are setup from the beginning.

But preferences are also accumulated all along the execution. For instance, as soon as an ATSC table is demuxed, the fact that the transport stream contains ATSC data is stored in the context. Later, when an MPEG table (a PMT for instance) contains an ambiguous descriptor tag which is used by DVB and ATSC, then the ATSC alternative will be used.

3.6. DVB SimulCrypt protocols

The communications inside a DVB SimulCrypt head-end is defined by the standard ETSI TS 103 197, "Head-end implementation of DVB SimulCrypt".

Most of these protocols use the same principles. They use binary TLV (Tag/Length/Value) messages, asynchronous communications, concepts of channels, streams, status and error messages.

The generic handling of these messages is implemented by classes in the namespace ts::tlv. All TLV messages inherit from ts::tlv::Message. Channel-level messages inherit from ts::tlv::ChannelMessage and stream-level messages inherit from ts::tlv::StreamMessage.

The syntax of a given protocol is defined by subclassing ts::tlv::Protocol.

Currently, the TSDuck library implements the following protocols:

  • ECMG⇔SCS in namespace ts::ecmgscs.

  • EMMG/PDG⇔MUX in namespace ts::emmgmux.

3.7. Conditional access systems

The class ts::CASMapper analyzes the signalization of a transport stream, locates ECM and EMM stream and associates each of them with a CA_System_Id.

An instance of ts::CASMapper can then be queried for ECM, EMM streams or CAS vendors.

3.8. Other forms of demux

We have already mentioned the classes ts::SectionDemux and ts::PESDemux. Other specialized forms of demux can be implemented.

The class ts::T2MIDemux demuxes T2-MI (DVB-T2 Modulator Interface) packets and extracts encapsulated transport streams. Similarly, the class ts::TeletextDemux extracts Teletext subtitles from TS packets.

Since all forms of demux share a number of properties, they all inherit from a root abstract class named ts::AbstractDemux.

3.9. Digital TV tuners

The class ts::Tuner interfaces DVB/ATSC/ISDB tuner devices in a portable way. This is quite a challenge since Linux and Windows use very different tuner frameworks. Some very-specific features are available either only on Linux or Windows.

The abstract class ts::TunerArgs is the root of a hierarchy of classes containing tuning parameters. Subclasses exist for DVB-S, DVB-T, DVB-C and ATSC. ISDB-S and ISDB-T are currently unsupported.

The class ts::TSScanner reads a TS from a ts::Tuner until all scanning information is found, typically until the PAT, NIT and SDT are received. This is the basis for scanning a DTV network.

Note that tuner devices are supported on Linux and Windows only. On macOS, the above classes are defined but return "unimplemented" errors when used.

3.10. Interface to Dektec devices

TSDuck can manipulate ASI and (de)modulator devices from Dektec. The TSDuck library includes the DTAPI library, a proprietary C++ interface which is provided by Dektec. The DTAPI is not available in source form and not part of the TSDuck source repository. However, when TSDuck is built, the DTAPI is downloaded in binary from Dektec and included in the TSDuck library.

Such a packaging is authorized by the DTAPI license (see the file OTHERS.txt in the TSDuck source repository or installation tree).

An application should not directly call the DTAPI. In practice, this works on Linux but not on Windows. So if you want portability, do not do this. The reason is that the structure of Windows DLL’s is such that exported code from a DLL must be compiled using specific attributes. But the DTAPI, as provided by Dektec, was not compiled with these attributes. So, when the DTAPI is included in tsduck.dll, the DTAPI can be called from inside tsduck.dll but is not accessible from the application.

This is why accessing the DTAPI from the application must be done through some TSDuck proxy class. The classes ts::DektecControl, ts::DektecInputPlugin and ts::DektecOutputPlugin provide the features which are required by the utility tsdektec and the plugin dektec. They can be used by third-party applications.

Note that Dektec devices are supported on Linux and Windows only. On macOS, the above classes are defined but return "unimplemented" errors when used.

4. The Reactor pattern and event dispatching

Some parts of TSDuck are based on a reactor pattern. The TSCore library provides an implementation of event dispatching based on a "Reactor" class. Because this topic is complex and not always well-understood, it deserves some specific explanations first.

4.1. Multithreading vs. event dispatching

Generally speaking, computing relies on three major types of resources: CPU, memory, and I/O. Most applications primarily need one type of resource which may become a bottleneck, a limiting factor which must be specifically addressed.

  • CPU-bound applications need more processing power than one CPU can provide. Ideally, they simultaneously use several CPU cores of the same machine, or even several machines.

  • Memory-bound applications need mode memory than the machine can provide. They need additional storage media or remotely-accessible memory, and swap between them.

  • I/O-bound applications constantly wait for input or output operations. They need to multiplex independent I/O operations at the highest possible rate.

An I/O-bound application (e.g. a server which processes simultaneous client connections) may use two possible types of implementation: multithreading and event dispatching. These are two distinct paradigms using different programming techniques. Usually, the choice of paradigm directly influences the architecture of the application.

4.1.1. Multithreading architecture

In a multithreading architecture, each sequential activity is linearly programmed in an independent thread of execution. A server typically contains one or two threads per client connection. If the client-server protocol is synchronous, with a strict request-response pattern, each client connection is implemented using one thread. It repeatedly reads a request, processes it, writes the response and waits for the next request. On the other hand, if the protocol is asynchronous, independent messages can flow in both directions at all time. In that case, a client connection is typically implemented using two threads: one thread processes incoming messages, the other thread generates outgoing messages.

The development of that architecture is simple. The processing is implemented using linear programming, reading and writing data when necessary. The core model is "blocking-I/O". Reading or writing a message suspends the execution of the thread during the I/O, until an incoming message is received or an outgoing message is fully sent.

On the other hand, for an I/O-bound application, a multithreading architecture is costly for the two other types of resources: CPU and memory. Constant context switching between threads is costly in terms of CPU and kernel resources. The impact on memory is even worse: each thread needs an independent execution stack, while spending most of the time doing nothing but waiting for the current I/O operation.

4.1.2. Event-dispatching architecture

In an event-dispatching application, there is only one thread of execution. That thread starts all I/O operations but never waits for them to complete. Instead, after starting one I/O for a client connection, for instance, it does some processing for another connection, until that client connection starts another I/O, etc. The core model is "immediate I/O" or "asynchronous I/O" (we will see the difference between the two later). The completion of each I/O is notified as an event. Processing that event means continuing the activity for the corresponding client connection, until it starts another I/O.

Because the driving principle of this architecture is "reacting" to events, the core feature of the application is named a "reactor design pattern". Object classes which are connected to the reactor and activated on reception of events are named "reactive classes".

I/O completion is one type of events but other types of events are possible: timers, used-defined events, process completions, message passing, etc.

The core reactor waits on events. Each time an event is received, an application-defined "event handler" is invoked. The event handler shall be quick. It shall not block or execute lengthy CPU-bound processing. It can only starts I/O, not wait for them to complete. Then, the event handler returns control to the reactor.

The benefit is obvious in terms of CPU and memory. There is only one thread with only one execution stack. Each client connection only requires its own contextual data. The kernel processes I/O only, not multiple threads and context switches.

However, because any benefit has a price, the programming technique is more complex. Each activity (e.g. a client connection) must be implemented as a state machine, using a specific data context and fragmented processing between I/O operations. Additionally, the sum of all CPU loads from the various activities shall not exceed the capability of one CPU.

The main practical limitation of reactors is the necessity to control absolutely all types of input/output so that no code suspends the execution of the reactor thread during an I/O. This means that third-party libraries which perform I/O under the hood cannot be used because calling a function of these libraries may block the reactor thread.

Some libraries, such as OpenSSL may have two modes: a simple one using linear programming and blocking I/O and a much more complex one where the library only performs data processing and lets the application perform the I/O. However, libraries such as libsrt and librist (which implement the SRT and RIST protocols, respectively) only have a linear API using blocking I/O. These libraries cannot be used in an application using an event dispatching architecture.

The second practical limitation of reactors is the absence of standard API and portability. The typical example of reactor-based or event-driven application is a graphical user interface (GUI). A GUI is the source of multiple events (mouse, keyboard, data sources) which can occur in any order, at any time. All GUI systems are based on the principle of event dispatching: Microsoft Windows, GTK, Qt, X-Window, etc. However, each environment defines its own API for event dispatching. They use different and incompatible APIs. To add to the confusion, other non-GUI event dispatching frameworks exist with different APIs, from the legacy Adaptive Communication Environment (ACE) to the modern libevent.

Because of the lack of a common unique, or universally accepted, standard API, it is not possible to develop portable applications. It is not possible to develop libraries which are based on a reactor API and smoothly integrate them in all event dispatching applications. As an example, libsrt proposes a "non-blocking I/O" mode but it is based on a specific libsrt API and it can be used only in applications which use libsrt as their reactor. When several libraries only accept their own specific model as event dispatcher, they cannot be used in the same application.

4.1.3. Multithreading vs. reactor comparison

The typical use cases of these two architectures are:

  • Multithreading: CPU-bound applications, with a limited number of simultaneous connections using synchronous protocols.

  • Reactor: I/O-bound applications, with a large number of simultaneous connections, or using asynchronous protocols.

Table 1. Multithreading vs. reactor comparison
Multithreading Reactor (event dispatching)

Pros

  • CPU load-balancing, take advantage of multi-core systems.

  • Natural integration with third-party libraries encapsulating blocking I/O.

  • Easier to code (linear programming).

  • Scale well with the sources of I/O (e.g. simultaneous connections).

  • Handle asynchronous protocols.

  • High reactivity.

Cons

  • Doesn’t scale with the sources of I/O (e.g. simultaneous connections).

  • Large memory footprint.

  • More difficult to code and debug (state machine programming).

  • Can’t integrate third-party libraries encapsulating blocking I/O.

  • No standard API, several incompatible implementations.

4.2. Blocking I/O vs. immediate I/O vs. asynchronous I/O

Traditional I/Os suspend the execution of the calling thread until the I/O operation completes. We call this "blocking I/O". In an event-dispatching architecture, no I/O should block the execution thread. However, there are several ways to perform I/O without blocking: immediate I/O and asynchronous I/O.

These methods are different and implemented on different operating systems: UNIX systems use immediate I/O and Windows uses asynchronous I/O. An application doesn’t have the choice between immediate I/O and asynchronous I/O. This is imposed by the operating system.

Because these two models of "non-blocking I/O" impose different data management strategies on the application, it is particularly challenging to define a portable Reactor API.

4.2.1. Immediate I/O (UNIX)

An "immediate I/O" is …​ immediate. Either it immediately completes or immediately fails but it never blocks. When an immediate I/O fails because it is not possible to immediately complete (e.g. because no incoming data is available), the process can be notified by the kernel when an I/O becomes possible. There are two main types of I/O events: "read-ready" and "write-ready", when a read or write operation becomes possible. Note that "ready" does not mean "guaranteed". On a read-ready event, for instance, the application shall retry the read operation. It will likely immediately succeed but it may also fail again (spurious read-ready event).

The documentation of UNIX systems (Linux, macOS, BSD) uses the term "non-blocking" for immediate I/O. In a pure UNIX context, this is appropriate because those I/Os don’t block. However, in a wider context, there are different types of non-blocking I/O and the UNIX immediate I/O model is only one of them. In the TSDuck documentation, to avoid confusion between all types of non-blocking I/O, we use the term "immediate I/O" to refer to the UNIX model of non-blocking I/O.

With immediate I/O, there is no specific constraint on the user data buffers. After an I/O call, whether it fails or succeeds, the user buffers are never used outside these I/O calls and the buffers can be disposed at any time. A device or socket can be closed at any time without impact on the data buffers.

To make portability more difficult, distinct flavors of UNIX systems use different incompatible system calls and kernel mechanisms to handle immediate I/O event notification.

  • Traditionally, all UNIX systems provide the select() and poll() system calls. However, they do not scale well with the number of events and they should now be completely avoided.

  • macOS, FreeBSD, and other BSD systems use a mechanism named "kqueue" (kernel queue).

  • Linux uses a mechanism named "epoll" (event poll). There is also a more recent mechanism named "io_uring". It is more complex and particularly suited for extremely large servers. Currently, TSDuck uses epoll on Linux, not io_uring.

There are some limitations to the UNIX immediate I/O model:

  • The "immediate" success of an I/O is a flawed concept. It works well on network socket: is there any data available in the incoming buffer, or is there any free space in the outgoing buffer? Specifically, immediate input works only in a push model, e.g. when a remote peer sends data and these data are pushed into our reception buffer. However, it does not apply in a pull model, when the application requests data to be read from a disk. In that case, the "immediate I/O" blocks. The blocking time is limited thanks to the speed of disks but it may have an impact on heavily loaded reactors.

  • Some operations are lengthy by design. The typical example is a TCP connect() operation. It requires to wait for a response from a remote server. This is much longer and more unpredictable than a disk I/O and it is impossible to make it blocking, pretending it is not. In practice, an immediate TCP connect() is asynchronous. It always initially fails with a "try again later" status, just like any other immediate I/O. However, unlike other failed immediate I/Os, the actual connect operation continues in the background, in the kernel. When the connection is completed, the event "write-ready" is notified by epoll or kqueue.

  • There are some cases of non-portable operations which make the development more complex. With disk I/O, we have seen that some I/O are blocking by design but sufficiently short to pretend that they are not, with limited impact when the number of events is not too high. On macOS and BSD systems, this is transparent. The same code can be used for network sockets and files, in the same reactor. On Linux, on the other hand, it fails. Regular files and a few other classes of devices cannot be set in non-blocking mode (in practice when the corresponding driver doesn’t support the "poll" operation). All I/O must be explicitly blocking. Files and sockets cannot be multiplexed in the same reactor, making the code more complex and error-prone, without any performance benefit.

4.2.2. Asynchronous I/O (Windows)

An "asynchronous I/O" always executes in the background. An I/O is first started using a classical read or write operation. In rare cases, it completes immediately (e.g. when data are already available from a kernel buffer). However, most of the time, the I/O is "pending", it runs in the background. Later, when the I/O completes, the completion event is reported to the application.

Microsoft Windows uses the name "overlapped I/O" instead of asynchronous I/O. The event synchronization mechanism is named I/O Completion Port, or IOCP in short.

Asynchronous I/O has an important impact on the data buffer management in the application. When a read operation starts, for instance, the address and size of the buffer are remembered in the kernel. This memory buffer is then written in the background, when data arrive as part of the read operation in progress. This means that the application must not reuse the memory of that buffer before the confirmation that the I/O completed, either successfully or with an error. If the application frees a data buffer during an asynchronous I/O, the following dangerous scenario becomes possible: the freed buffer is reused by some other part of the application and some precious data are stored there; then the asynchronous I/O continues and incoming data erase the reused buffer.

Therefore, an application must be very careful about data buffers. These buffers must never be freed or reused before the confirmation of the I/O completion. This can be challenging in error paths, when a device must be prematurely closed. The application shall not simply close the device and forget about it, as it would be with classical blocking I/O. The application shall explicitely cancel all pending I/Os, then wait for the cancelation to complete (i.e. the asynchronous I/O completes with a "canceled" status), then close the device, and sometimes wait for the completion of the close operation.

The Windows asynchronous I/O model has its limitations too:

  • The read and write operations on disk files are asynchronous, but not the operations which extend a file. So, when you write on a file and that operation needs additional disk space, the file management part is blocking and the data transfer part is not. Because the former is usually longer than the latter, this makes the "asynchronous" attribute is bit useless.

  • Some devices cannot be used in "overlapped" mode, such as anonymous pipes. This is a problem because an I/O on a pipe may block for hours if the peer does not read or write on the pipe. This is worse than Linux which forbids non-blocking I/O on disk files because these file I/O are always fast. They may slightly impact the performances of the application but not block it. Strangely enough, Windows named pipes can be used in overlapped mode. So, it is possible to use named pipes instead of anonyous pipes. However, it works only if the application creates the pipe. It doesn’t work if the pipe is already created, e.g. when used in standard input or standard output. This means that there is no way to guarantee that the standard input or output will always be usable for asynchronous I/O on Windows.

4.3. TSDuck hybrid architecture

So, which architecture is best-suited for TSDuck, multithreading or event dispatching? As usual, it depends…​

TSDuck is an aggregate of heterogeneous blocks: libraries, executables, plugins, third-party libraries from various origins.

Originally, TSDuck used a strict multithreading architecture. There were several reasons for this, mostly from the tsp requirements:

  • CPU load balancing between plugins. Some plugins can be CPU-intensive, such as encryption plugins. We need to leverage multi-core architectures. From the beginning, each plugin was executed in a dedicated thread.

  • Execution isolation between tsp plugins. This means avoiding that a plugin using blocking-I/O blocks other plugins. Note that this is "execution isolation" only, there is no memory or security isolation, as usual in multithreaded environments.

  • Multiple third-party libraries which encapsulate blocking-I/O and cannot be used in an event dispatcher (SRT and RIST for instance).

  • Multiple operating systems support. Windows, Linux, macOS, BSD have very different ways of handling non-blocking I/Os in an efficient way. No common event dispatcher API was available.

  • TSDuck has always been designed as a flexible framework for debug and experimentation. Flexibility and extensibility prevail over raw performances. Using a multithreading architecture is more robust. An event dispatcher would fail in case of accidental blocking I/Os, whether they come from a third-party library or a bug in a plugin.

However, there are cases where using a strictly multithreading architecture is less efficient or more difficult to write and maintain. Standalone tools such as tsecmg are pure TCP servers, using asynchronous protocols and no third-party library. Injection plugins (EMMs, MPE, SCTE-35) multiplex two sources of input: the upstream transport stream and TCP or UDP incoming data. Their original implementation included an additional thread to receive data from the network or to poll data files. They would benefit from an event dispatching architecture.

Therefore, TSDuck is moving to a hybrid architecture, which mixes multithreading and event dispatching.

At high level, there are loosely coupled blocks, typically the plugins. The high-level architecture remains multithreaded. All plugins cannot be integrated into one single reactor. First, it would be too expensive to rewrite everything. More importantly, it would be too dangerous. One single plugin could block everything when using a third-party library with blocking I/O. One single CPU-bound plugin (e.g. encryption or decryption) could slow the entire system down.

At local level, inside a specific tool or plugin, when appropriate, a reactor can be used to multiplex and dispatch events inside one single thread.

This hybrid architecture is not uncommon and is sometimes named "multi-reactor pattern". Most of the time, it is used to balance a reactive application over multiple CPU cores: a thread executes on each CPU core and manages its own reactor and event dispatcher.

For this reason, the TSCore library has been extended in two ways:

  • The I/O classes were extended to support two modes: blocking and non-blocking.

  • A Reactor class and a set of associated reactive classes were added. They implement a core event dispatching mechanism with a portable API over Linux (epoll), macOS and BSD systems (kqueue), and Windows (IOCP). These classes also hide the differences between immediate I/O (UNIX) and asynchronous I/O (Windows).

For convenience, and unless specified otherwise, we will use the term "non-blocking I/O" in a general sense of I/Os which don’t block the execution thread and are synchronized in a reactor. This indifferently includes the two principles of UNIX immediate I/O and Windows asynchronous I/O.

4.4. Reactor and reactive classes

In the TSCore library, the core of the event dispatching features is class ts::Reactor. An instance of this class is an event dispatcher. In the case of the TSDuck hybrid architecture, there is one Reactor instance per thread with an event dispatching architecture.

The typical scenario of event dispatching is the following:

  • Instantiate and open a Reactor.

  • Define and instantiate application classes which will handle events from the reactor. The event notification is done through "handler interface classes" that the application classes should implement.

  • Instantiate and initialize a few reactive objects (network, files, processes, etc). Make sure that the events will be notified to the application classes.

  • Enter the reactor method processEventLoop().

  • The reactor calls event handlers in the various application classes, depending on events. An event handler typically starts other non-blocking operations which will trigger other handlers later.

  • If an event handler decides to terminate the event dispatching, it calls the reactor method exitEventLoop(). After all event handlers return, the reactor method processEventLoop() returns control to the application thread.

The Reactor shall be used from one single thread. Unless specified otherwise, all methods shall be invoked from the thread of the reactor, where the event loop is run. All handlers are invoked in the context of the thread which invoked processEventLoop().

The Reactor and the associated reactive classes handle the following features:

  • Timers, either repeated or one-shot. A timer is identified by an id which is passed in the completion handler. The id can also be used to cancel a timer before it expires.

  • User-events. A user-event is created by the application and identified by an id. The application can trigger that event at any time. As an exception, a user-event can be triggered from an external thread. This is how synchronization can be achieved between a reactor and other threads.

  • Message queues. The class ts::MessageQueue can be used in a Reactor. An event handler is called each time a message is available from the queue. Because MessageQueue is thread-safe by design, messages can be sent from external threads.

  • Asynchronous I/O from the following types of devices:

    • UDP sockets.

    • TCP clients and servers.

    • Encrypted TLS clients and servers.

    • Binary files.

    • Pipes to and from processes which are created by ts::ForkPipe.

  • I/O cancellation. It is possible the cancel an I/O in progress. The event handler for the completion of that I/O will be called with a "canceled" status.

  • Data presentation wrappers over asynchronous I/O channels:

    • Line-based text.

    • Tag-length-value (TLV) messages.

  • Process. An event handler is called when a process which was created by ts::ForkPipe terminates.

  • Web requests (HTTP, HTTPS, FTP), based on URL.

  • Worker delegation. When an event handler needs to run some lengthy computing, or call a library with blocking I/O, it cannot sequentially do that because it would block the reactor. Instead, it should delegate that treatment to a "worker" thread. A completion event handler will be called in the reactor when the delegated task completes. There is a pool of a maximum number of worker threads. A delegated task is either executed in an idle worker thread, executed in a newly created worker thread if none were idle, or queued for later execution if the maximum number of worker threads is reached.

Timers, user-events and process terminations are directly handled in class Reactor.

The class Reactor encapsulates the various implementations of kernel event dispatchers and proposes a portable interface. However, while it is possible to unify the various types of immediate I/O (kqueue and epoll) in one single interface, it is impossible to unify immediate I/O and asynchronous I/O into the same interface. The way they shall be used, as well as the way the data buffers are managed, are too different. Therefore, the class Reactor exposes interfaces for both models. The application shall check the current I/O model using the consteval static methods UseImmediateIO() and UseAsynchronousIO() in class ReactorSupport and then adopt the correct strategy.

In practice, because of this complexity, the I/O multiplexing features of class Reactor are not used by applications. They are used in a few specialized "reactive I/O" classes such as ts::ReactiveUDPSocket or ts::ReactiveTCPConnection. These classes are implemented on top of ts::Reactor and have fully portable and homogeneous interfaces where the differences between immediate I/O and synchronous I/O are hidden.

The following UML-like class diagram summarizes the relationships between the I/O classes, the Reactor class, and the reactive classes.

reactor class diagram
Figure 2. Reactor class diagram

4.4.1. Standard I/O classes

On the left side of the diagram, the hierarchy of subclasses of ts::Device contains all standard I/O classes.

The class name Device means a device with the potential of being used in non-blocking mode. By default, instances of these classes work in blocking mode and are suitable for use in linear programming. Applications can use them directly.

The three main types of I/O classes are binary files, pipes (to or from a forked process), and network sockets.

Files and pipes have a subclass for transport streams each.

TCP sockets, server and client connection, have a TLS subclass each, for encrypted servers and connections.

Files, pipes, and TCP connections expose the interface ts::StreamInterface. This interface declares methods such as writeStream(), readStream(), and endOfStream() which can be indifferently used of files, pipes, and TCP connections.

Any class which exposes ts::StreamInterface can be used by data-presentation classes such as ts::TextStream or ts::TLVStream, to read and write text lines or TLV (tag, length, value) messages. Thus, it is possible to indifferently exchange these data formats over files, pipes, TCP or TLS connections.

Class ts::WebRequest handles all forms of Web requests, based on URL (HTTP, HTTPS, FTP). This class is implemented using high-level system-specific libraries: libcurl on UNIX systems (Linux, macOS, BSD), WinInet on Windows. Because these libraries don’t expose their I/Os, class ts::WebRequest is not a subclass of ts::Device. Therefore, unlike subclasses of ts::Device, ts::WebRequest can be used in blocking mode only and an entirely different class ts::ReactiveWebRequest is available for non-blocking I/O.

4.4.2. Reactive I/O classes

On the right side of the Reactor class diagram, the hierarchy of subclasses of ts::ReactiveBase contains all "reactive classes". Each instance of a reactive class is attached to an instance of ts::Reactor. The same instance of ts::Reactor dispatches events for all reactive classes which use it.

An instance of a reactive class does not implement I/O. It uses an associated instance of a standard I/O class. The reactive class automatically sets the standard I/O class in non-blocking mode. The reactive class starts the I/O and uses the Reactor to synchronize on the I/O completion. When an I/O is completed, the reactive class calls a handler in a reactive interface.

The Reactor class diagram shows which level of reactive class uses which level of standard I/O class. It is important to understand that there is only one instance of a standard I/O class per instance of reactive class. For instance, an instance of ts::ReactiveTCPConnection is associated to one instance of ts::TCPConnection. The superclass ts::ReactiveStream uses the superclass ts::StreamInterface and the superclass ts::ReactiveDevice uses the superclass ts::Device, but all these superclasses are implemented in the same two instances of ts::ReactiveTCPConnection and ts::TCPConnection.

The reactive handler interfaces are implemented by the application-defined classes. When an application starts a non-blocking I/O, it specifies the handler which must be called upon completion. This is the address of an instance of an application class which implements the required handler interface class.

The following diagram summarizes all reactive handler interfaces, with their methods, and which reactive class calls them.

reactive interfaces
Figure 3. Reactive interfaces

The application-defined classes need to implement the required handler interfaces, depending on which reactive class they use.

The interface ts::ReactorHandlerInterface is directly called by the Reactor. The application may use it for timers, process completions, or user events. Its methods handleReadReady(), handleWriteReady(), and handleAsynchronousIO() are used only inside the reactive I/O classes and are normally never used by an application.

Class ts::ReactiveWebRequest handles all forms of Web requests, based on URL (HTTP, HTTPS, FTP). Like class ts::WebRequest, it is based on high-level system-specific libraries: libcurl on UNIX systems (Linux, macOS, BSD), WinInet on Windows. Because these libraries don’t expose their I/Os, class ts::ReactiveWebRequest is not a subclass of ts::ReactiveDevice. It is a direct subclass of ts::ReactiveBase Similarly, ts::ReactiveWebRequest handles its own non-blocking I/Os using specific modes of libcurl and WinInet. Unlike other types of reactive I/O classes, it does not use a separate instance of ts::WebRequest.

4.4.3. Sample reactor-based application

The TSCore library contains class ts::ReactiveServer which implements a general-purpose TCP server in a Reactor environment. It is suitable to implement all kinds of servers, including SSL/TLS servers. An instance of ts::ReactiveServer automatically creates application-defined session objects when incoming clients connect and automatically deletes the session object when they disconnect. The session objects are created by an instance of ts::ReactiveServerFactoryInterface. The session object class must implement ts::ReactiveServerSessionInterface.

The TSDuck source code repository contains a sample TCP server based on ts::ReactiveServer in subdirectory sample/sample-reactor-server.

This sample application is single-threaded and uses one single instance of ts::Reactor to dispatch events in the TCP server and all client sessions.

By default, the server uses raw TCP connections. However, using the command line option --tls, it creates a TLS server and encrypted connections. This illustrates how ts::ReactiveServer can indifferently use an instance of ts::ReactiveTCPServer or ts::ReactiveTLSServer.

The global instance of ts::ReactiveTCPServer (or its TLS counterpart) uses an instance of ts::TCPServer. Similarly, each client connection uses an instance of ts::ReactiveTCPConnections (or TLS), which uses an instance of ts::TCPConnection.

The server handles text lines (it is a simplified version of an HTTP server). It illustrates how ts::ReactiveTextStream can indifferently use an instance of ts::ReactiveTCPConnection or ts::ReactiveTLSConnection.

Each client session is implemented in an instance of the application-defined class ClientConnection. Each session instance contains:

The server management is implemented in an instance of the application-defined class ServerControl. This class is used by ts::ReactiveServer for two independent purposes:

This generic application structure is illustrated in the following general diagram which applies to all server applications.

sample ReactiveServer application
Figure 4. Sample ReactiveServer application

5. Java and Python bindings

5.1. Overview

Starting with version 3.25, TSDuck includes Java and Python bindings to some high-level features.

Although subject to enhancements, these bindings will never aim at supporting the full TSDuck feature set since this would be too large. Only a small subset of TSDuck high-level features are targeted.

The Java classes are documented in the Java bindings reference section.

The Python classes are documented in the Python bindings reference section.

Sample Java and Python applications are available in the TSDuck source tree.

Currently, the TSDuck Java and Python bindings provide access to the features in the following table. Equivalences are provided between C++, Java, Python and command line tools.

The first three classes implement high-level features which have direct counterparts as command line tools. The others are support classes which are only required to use the high-level classes.

Table 2. Equivalence between commands, C++, Java, Python classes
Command C++ class Java class Python class

tsp

ts::TSProcessor

io.tsduck.TSProcessor

tsduck.TSProcessor

tsswitch

ts::InputSwitcher

io.tsduck.InputSwitcher

tsduck.InputSwitcher

tstabcomp

ts::SectionFile

io.tsduck.SectionFile

tsduck.SectionFile

n/a

ts::DuckContext

io.tsduck.DuckContext

tsduck.DuckContext

n/a

ts::Report

io.tsduck.AbstractSyncReport

tsduck.AbstractSyncReport

n/a

ts::AsyncReport

io.tsduck.AbstractAsyncReport

tsduck.AbstractAsyncReport

n/a

ts::SystemMonitor

io.tsduck.SystemMonitor

tsduck.SystemMonitor

n/a

ts::PluginEventHandlerInterface

io.tsduck.AbstractPluginEventHandler

tsduck.AbstractPluginEventHandler

n/a

ts::PluginEventContext

io.tsduck.PluginEventContext

tsduck.PluginEventContext

5.2. Support classes

5.2.1. TSDuck execution context

The DuckContext class is used to define and accumulate regional or operator preferences. In the TSDuck C++ programming guide, it is referred to as TSDuck execution context. Most of the time, using the default state of a new instance is sufficient.

The application sample Japanese tables, available in Java and Python, demonstrates how it can be necessary to override the defaults in specific cases.

5.2.2. Reporting classes

The reporting classes (ts::Report C++ class hierarchy) are used to report logs, errors and debug. They are consistently used all over TSDuck and are required to use the high level features. There is a large hierarchy of classes in the three languages which can be classified according to two sets of criteria:

  • Synchronous vs. asynchronous:

    • Synchronous report classes log messages in the same thread as the caller. They are usually not thread-safe.

    • Asynchronous report classes, on the other hand, can be used in a multi-threaded environment and the actual message logging (such as writing in a log file) is performed in a separate thread. As a consequence, an asynchronous report instance must be explicitly terminated. An asynchronous report class is required when using heavily multi-threaded classes such as TSProcessor or InputSwitcher.

  • Native vs. abstract:

    • Native classes are the C++ classes which are used in all the TSDuck command line tools. They are typically used to report to standard output, standard error, files or dropping the logs. They can be used from Java and Python directly but cannot be derived or customized. They are typically used when predefined error logging is sufficient.

    • Abstract classes are pure Java or Python base classes which are designed to be derived in applications. Such application-defined classes shall override the method logMessageHandler (Java) or log (Python) to intercept and process the message lines.

The asynchronous abstract classes can be useful to collect events, tables and sections in XML, JSON or binary / hexadecimal form in Java or Python applications when using TSProcessor or InputSwitcher. Some of the sample Java and Python applications illustrate this mechanism.

Table 3. Categories of report classes in C++, Java, Python
Category C++ class Java class Python class

Synchronous, native

ts::CerrReport

io.tsduck.ErrReport

tsduck.StdErrReport

ts::NullReport

io.tsduck.NullReport

tsduck.NullReport

Asynchronous, native

ts::AsyncReport

io.tsduck.AsyncReport

tsduck.AsyncReport

Synchronous, abstract

ts::Report

io.tsduck.AbstractSyncReport

tsduck.AbstractSyncReport

Asynchronous, abstract

ts::AsyncReport

io.tsduck.AbstractAsyncReport

tsduck.AbstractAsyncReport

5.2.3. Resource monitoring

The SystemMonitor class is available in all languages, C++, Java and Python. It can be used at the top-level of an application to implement the --monitor option as found in tsp and tsswitch. An instance of a thread-safe Report class is used to report monitoring messages.

The SystemMonitor class is very simple to use. Examples are available in Java and Python.

5.2.4. Plugin events

For developers, TSDuck plugins can signal events which can be handled by the application. Each event is signalled with a user-defined 32-bit event code. An application can register event handlers in the ts::TSProcessor instance (see the class ts::PluginEventHandlerRegistry, knowing that ts::TSProcessor is a subclass of ts::PluginEventHandlerRegistry). The event handler registration can include various selection criteria such as event code value or originating plugin (see the inner class ts::PluginEventHandlerRegistry::Criteria).

C++ developers who create their own plugins can signal any kind of event that they later handle in their application. This is illustrated in a C++ sample custom application. In this sample code, everything is customized in the application: the plugin, the event it signals, the associated event data, the application handling of the event.

Since developing a TSDuck plugin is only possible in C++, Java and Python developers have more limited options. Some standard TSDuck plugins such as tables, psi or mpe provide the option --event-code. Using this option, the plugins signal event using the specified event code for each data they handle (sections or MPE datagrams depending on the plugin).

Java and Python applications can derive from class AbstractPluginEventHandler to define and register their own event handlers. Thus, binary sections or MPE datagrams can be handled directly from the plugin to the Java or Python application.

Some plugins are even dedicated to application developers and are useless on tsp command lines. This is the case of the plugin memory (both an input and an output plugin). This plugin, when used in a TSProcessor instance, performs direct transport stream input and output from and to the application using memory buffers. The memory buffers are signalled using plugin events. The memory input plugin is an example of an application-defined event handler returning data to the plugin. See this sample code in the TSDuck source code tree.

5.3. Application/plugin communication in Java or Python

At high level, Java and Python applications can only run TSProcessor or InputSwitcher sessions, just like a shell-script would do with commands tsp and tsswitch.

The communication from the Java and Python applications to the plugins is performed using plugin options. These options may contain file names or UDP ports which can be created by the application.

More effectively, most file contents can be provided directly on the command line, avoiding the burden of creating temporary files. For instance, wherever an input XML file name is expected, it is possible to use the XML content instead. Any "XML file name" which starts with <?xml is considered as inline XML content. Similarly, if an input "JSON file name" starts with { or [, it is considered as inline JSON content.

On reverse side, there is some limited form of communication from the plugins to the Java or Python application. There are basically two ways to handle plugin information in the application: the logging system and plugin events.

Using the logging system:

Some plugins support options such as --log-xml-line, --log-json-line or --log-hexa-line. With these options, the extracted data (table, section, MPE datagram) are "displayed" as one single line in the designated format on the logging system. Using user-defined Java or Python asynchronous abstract reporting classes, the application receives all logged lines and can filter and manipulate the data which were extracted and logged by the plugins.

Using plugin events:

Some plugins support the option --event-code. With this option, the extracted data are signalled by the plugin as an event. Using and registering user-defined Java or Python plugin event handlers, the application is directly notified of the data.

Which mechanism, logging system or plugin events, should be used depends on the application.

  • Logging system:

    • Pros:

      • The log lines are asynchronously processed in the context of the low-priority logging thread. Any lengthy processing in the Java or Python application does not hurt the dynamics of the plugins.

    • Cons:

      • If the application needs to process binary data, the additional serialization process in the log line adds some useless overhead.

      • Because the logging system is non-intrusive by design, log messages may be lost if there are more messages than the logging thread can process without making plugin threads wait. This can be mitigated using the synchronous log option in the AbstractAsyncReport consttructor.

  • Plugin events:

    • Pros:

      • The binary data are directly passed from the plugin to the application without any serialization, logging or multi-threading overhead.

    • Cons:

      • The application-defined event handlers execute in the context of the plugin thread. Any lengthy processing at this stage slows down the plugin.

The following sample applications can be used as a starting point:

Table 4. Sample Java and Python communication applications
Communication type Java Python

Logging (XML)

SampleAnalyzeSDT

sample-analyze-sdt.py

Logging (JSON)

SampleAnalyzeTS

sample-analyze-ts.py

Logging (bin/hexa)

SampleFilterTablesLog

sample-filter-tables-log.py

Plugin events (sections)

SampleFilterTablesEvent

sample-filter-tables-event.py

Plugin events (MPE datagrams)

SampleMPE

sample-mpe.py

Plugin events (input/output)

SampleMemoryPlugins

sample-memory-plugins.py

5.4. Using TSDuck Java bindings

All TSDuck Java classes are defined in a package named io.tsduck.

A few examples are provided in the directory sample/sample-java in the TSDuck source code package.

5.4.1. Linux

The TSDuck Java bindings are installed with TSDuck in /usr/share/tsduck/java. All classes are in a JAR file named tsduck.jar. Simply add this JAR in the environment variable CLASSPATH to use TSDuck from any Java application:

$ export CLASSPATH="/usr/share/tsduck/java/tsduck.jar:$CLASSPATH"

5.4.2. macOS

This is similar to Linux, except that instead of /usr/share, use /usr/local/share (Intel Macs) or /opt/homebrew/share (Apple Silicon Macs).

$ export CLASSPATH="/usr/local/share/tsduck/java/tsduck.jar:$CLASSPATH"
$ export CLASSPATH="/opt/homebrew/share/tsduck/java/tsduck.jar:$CLASSPATH"

5.4.3. Windows

On Windows, Java bindings are optional components of the TSDuck installer. When they are selected for installation, they are installed in the TSDuck area and the environment variable CLASSPATH is modified at system level to include the JAR file of the TSDuck Java bindings.

Thus, any Java program can use TSDuck directly.

5.5. Using TSDuck Python bindings

All TSDuck bindings are defined in a module named tsduck. All Python programs using TSDuck shall consequently start with:

import tsduck

A few examples are provided in the directory sample/sample-python in the TSDuck source code package.

5.5.1. Linux

The Python bindings are installed with TSDuck in /usr/share/tsduck/python. Simply add this directory in the environment variable PYTHONPATH to use TSDuck from any Python application:

$ export PYTHONPATH="/usr/share/tsduck/python:$PYTHONPATH"

5.5.2. macOS

This is similar to Linux, except that instead of /usr/share, use /usr/local/share (Intel Macs) or /opt/homebrew/share (Apple Silicon Macs).

$ export PYTHONPATH="/usr/local/share/tsduck/python:$PYTHONPATH"
$ export PYTHONPATH="/opt/homebrew/share/tsduck/python:$PYTHONPATH"

5.5.3. Windows

On Windows, Python bindings are optional components of the TSDuck installer. When they are selected for installation, they are installed in the TSDuck area and the environment variable PYTHONPATH is modified at system level to include the root directory of the TSDuck Python bindings.

Thus, any Python program can use TSDuck directly.

5.5.4. Python prerequisites

The code was initially tested with Python 3.7 and higher. Python 2.x is not supported. Intermediate versions may work but without guarantee.

5.5.5. Implementation notes

There are usually two ways to call C/C++ from Python:

  • Using the predefined ctypes Python module to call C functions,

  • Implementating a full native Python module in C/C++.

The second option is usually more flexible and more generic. However, the generated binary depends on the version of Python. If such an option is used, the binary installation of TSDuck would require a specific version of Python (or a specific set of versions of it). But each system has it own requirements on Python and it is difficult for a product like TSDuck to impose a specific version of Python.

Consequently, the less flexible ctypes approach was chosen. The TSDuck binary library contains C++ wrapper functions to some features of TSDuck and these carefully crafted functions are directly called from Python code using ctypes, regardless of the version of Python. Note, however, that these C++ functions are hidden inside the Python bindings and are invisible to the C++ application developer.

6. Developing a TSDuck plugin

6.1. Plugin development workflow

When some new kind of transport stream processing is needed, several solutions are possible:

  • First, check if an existing plugin or a combination of existing plugins can do the job.

  • Check if an existing plugin can be extended (by adding new options for instance).

  • As a last resort, develop a new plugin, which is relatively easy.

New plugins can be developed either as part of the TSDuck project or as independent third-party projects.

6.1.1. Developing independent third-party plugins

If you create your own third-party plugins (ie. if you are not a TSDuck maintainer), it is recommended to develop your plugins outside the TSDuck project.

Do not modify your own copy of the TSDuck project with your private plugins. This could create useless difficulties to upgrade with new versions of the project.

Consider developing your plugins in their own projects, outside TSDuck. You do not even need to get the full source code of TSDuck. It is sufficient to install the TSDuck development environment (see chapter 2).

An example of a third party plugin project is provided in the directory sample/sample-plugin.

6.1.2. Developing plugins for the TSDuck project

To develop a new plugin named foo, follow these steps:

  • Create a source file named tsplugin_foo.cpp in the tsplugins subdirectory.

  • On UNIX systems (Linux, macOS, BSD), this new source file will be automatically recognized by the Makefile and the new plugin will be built.

  • On Windows systems, the plugin needs a "project file" for Visual Studio and MSBuild. This project file shall be referenced in the TSDuck "solution file".

The last step is automated using the Python script scripts/build-project-files.py. This script explores the source files for all commands and plugins. It automatically generates missing project files and references them in the solution file.

This script can be run on UNIX systems (Linux, macOS, BSD) or Windows systems. On Windows, it can be easier to launch the PowerShell script scripts/build-project-files.ps1, which simply calls the Python script.

6.2. Development guidelines

Don’t write a plugin from scratch. Use an existing plugin as code base (beware however of the pitfalls of careless copy / paste). The simplest code bases can be found in the plugins null (input), drop (output) , skip (basic packet processing), nitscan (reading content of PSI/SI), svrename (modifying PSI/SI on the fly).

Always create plugins which perform simple and elementary processing. If your requirements can be divided into two independent processing, create two distinct plugins. The strength of TSDuck is the flexibility, that is to say the ability to combine elementary processing independently and in any order.

6.2.1. Class hierarchy

In the source file of the plugin, create a C++ class, derived from either ts::InputPlugin, ts::OutputPlugin or ts::ProcessorPlugin. If your plugin implements two capabilities (both input and output for instance), implement the corresponding two classes in the same source file.

See the class diagram of ts::Plugin for a global view of the plugin classes.

Specialized plugins which manipulate exiting tables derive from ts::AbstractTablePlugin. Examples of such plugins are pmt, pat, nit, etc. The actual plugin subclasses focus on the modification of the target table while the superclass automatically handles demuxing, remuxing and creation of non-existing tables.

Specialized descrambling plugins derive from ts::AbstractDescrambler. This abstract class performs the generic functions of a descrambler: service location, ECM collection, descrambling of elementary streams. The concrete classes which derive from ts::AbstractDescrambler must perform CAS-specific operations: ECM streams filtering, ECM deciphering, control words extraction. Most of the time, these concrete classes must interact with a smartcard reader containing a smartcard for the specific CAS.

6.2.2. Invoking tsp from a plugin, the ts::TSP callbacks

In its constructor, each plugin receives an associated ts::TSP object to communicate with the tsp main executable. This instance of ts::TSP is a protected field named tsp which can be freely accessed by the code of the plugin.

A plugin shared library must exclusively use that tsp object for text display and must never use std::cout, printf or the like. The class ts::TSP is a subclass of ts::Report and supports all reporting methods such as info(), verbose(), error(), debug(), etc.

When called in a multi-threaded context, the supplied tsp object is thread-safe and asynchronous (the methods return to the caller without waiting for the message to be printed).

Note that the plugin instance is also a subclass of ts::Report and automatically redirects all messages to its tsp field. Therefore, the code of the plugin can transparently use its own methods info(), error(), etc. This is equivalent to calling its tsp.

6.2.3. Joint termination support

A plugin can decide to terminate tsp on its own (returning end of input, output error or ts::ProcessorPlugin::TSP_END). The termination is unconditional, regardless of the state of the other plugins. Thus, if several plugins have termination conditions, tsp stops when the first plugin decides to terminate. In other words, there is an "or" operator between the various termination conditions.

The idea behind joint termination is to terminate tsp when several plugins have jointly terminated their processing. If several plugins have a "joint termination" condition, tsp stops when the last plugin triggers the joint termination condition. In other words, there is an "and" operator between the various joint termination conditions.

First, a plugin must decide to use joint termination. This is usually done in method ts::Plugin::start(), using ts::TSP::useJointTermination(bool) when the option --joint-termination is specified on the command line.

Then, when the plugin has completed its work, it reports this using ts::TSP::jointTerminate(). After invoking this method, any packet which is processed by the plugin may be ignored by tsp.

7. Developing a TSDuck extension

Applications or tsp plugins can be developed on their own. But it is also possible to develop fully integrated extensions to TSDuck.

An extension not only adds new plugins and commands, it can also augment the features of standard TSDuck commands and plugins. An extension can also be packaged as a binary installer which can be deployed on top of an existing installation of TSDuck.

The possible features of a TSDuck extension are:

  • Handling third-party tables and descriptors. The new tables and descriptors can be manipulated in XML or JSON, analyzed and displayed with the standard TSDuck tools.

  • Handling third-party Conditional Access Systems, based on a range of CA_system_id values. The ECM’s, EMM’s and private parts of the CA_descriptor are correctly analyzed and displayed with the standard TSDuck tools.

  • Adding filtering capabilities based on specific or private conditions on sections for command tstables and plugin tables.

  • Additional plugins for tsp.

  • Additional command-line utilities.

A complete example of a TSDuck extension is provided in the TSDuck source tree. This example also provides scripts to build standard installers (.exe on Windows, .rpm and .deb on Linux). The generated packages install the extension on top of a matching version of TSDuck.

7.1. Files in an extension

A TSDuck extension typically contains the following types of files:

  • Additional utilities. They are executable files without predefined naming. They are installed in the same directory as the TSDuck commands.

  • Additional tsp plugins. They are dynamic libraries named tsplugin_XXX.so, .dylib or .dll. The plugins are loaded by tsp when invoked by their names XXX.

  • Extension shared libraries named tslibext_XXX.so, .dylib or .dll. All shareable libraries named tslibext_XXX in the same directory as the TSDuck binaries or in the path TSPLUGINS_PATH are automatically loaded when any TSDuck command is invoked (in fact any time the TSDuck library tsduck.dll or libtsduck.so or .dylib is used). Such libraries typically install hooks into the core of TSDuck to handle third-party signalization.

  • XML files describing the XML models for third-party signalization (tables and descriptors). There is no mandatory naming template for those files but tslibext_XXX.xml is recommended. These XML files must be registered by the extension dynamic library (details below).

  • Name files describing third party identifiers (table ids, descriptor tags, CA system id, stream types, etc.) These files are used by TSDuck to better identify the various entities. There is no mandatory naming template for those files but tslibext_XXX.names is recommended. These files must be registered by the extension dynamic library (details below).

7.2. The extension dynamic library

All shareable libraries named tslibext_XXX.so, .dylib or .dll are automatically loaded by any TSDuck command or plugin. The initialization of the library is responsible for registering various hooks which implement the additional features.

7.2.1. Identification of the extension

This is an optional but recommended step. One C++ module inside the tslibext_XXX library shall invoke the macro TS_REGISTER_EXTENSION as illustrated below:

TS_REGISTER_EXTENSION(u"foo",                     // extension name
                      u"Sample foo extension",    // short description
                      {u"foot", u"foobar"},       // list of provided plugins for tsp
                      {u"footool", u"foocmd"});   // list of provided command-line tools

Using this declaration, the extension is identified and listed using the command tsversion --extensions.

Without the declaration, the extension is loaded and functional but it is not identified.

7.2.2. Providing an XML model file for additional tables and descriptors

To analyze input XML files containing tables, TSDuck uses an XML model to validate the syntax of the input XML file. There is a predefined large XML file which describes all supported tables and descriptors.

An extension may provide additional smaller XML files which describe the new tables or descriptors. See the sample extension for more details. The XML files shall be installed in the same directory as the rest of the extension (and TSDuck in general).

For each additional XML file, there must be one C++ module inside the tslibext_XXX library which invokes the macro TS_REGISTER_XML_FILE as illustrated below:

TS_REGISTER_XML_FILE(u"tslibext_foo.xml");

7.2.3. Providing a names files for additional identifiers

The usage rules and conventions are identical to the XML file above. The declaration macro for each names file is TS_REGISTER_NAMES_FILE as illustrated below:

TS_REGISTER_NAMES_FILE(u"tslibext_foo.names");

Here is an example, from the sample "foo" extension, which defines additional names for a table, a descriptor and a range of CA_system_id.

[TableId]
0xF0 = FOOT

[DescriptorId]
0xE8 = Foo

[CASystemId]
0xF001-0xF008 = FooCAS

7.2.4. Providing support for additional tables

If your environment defines a third-party table which is unsupported or unknown in TSDuck, you can implement it in your extension library.

First, define the C++ class implementing the table:

class FooTable : public ts::AbstractLongTable { ... };

In the implementation of the table, register hooks for the various features you support. In this example, we register a C++ class for FooTable:

TS_REGISTER_TABLE(FooTable,                  // C++ class name
                  {0xF0},                    // table id 0xF0
                  ts::Standards::NONE,       // not defined in any standard
                  u"FOOT",                   // XML name is <FOOT>
                  FooTable::DisplaySection);

The last argument to TS_REGISTER_TABLE is a static method of the class which displays the content of a section of this table type.

The XML model for the table is included in the XML file:

<?xml version="1.0" encoding="UTF-8"?>
<tsduck>
  <_tables>
    <FOOT version="uint5, default=0" current="bool, default=true" foo_id="uint16, required" name="string, optional">
      <_any in="_descriptors"/>
    </FOOT>
  </_tables>
</tsduck>

for the following binary layout, using the same conventions as MPEG/DVB standards:

table_id                     8 bits   = 0xF0
section_syntax_indicator     1 bit    = '1'
reserved                     3 bits
section_length              12 bits
foo_id                      16 bits
reserved                     2 bits
version_number               5 bits
current_next_indicator       1 bit
section_number               8 bits
last_section_number          8 bits
name_length                  8 bits
for(i=0;i<N;i++){
    name_char                8 bits
}
reserved_future_use          4 bits
descriptors_length          12 bits
for (i=0;i<N;i++){
    descriptor()
}
CRC_32

7.2.5. Providing support for additional descriptors

Similarly, it is possible to implement a third-party descriptor as follow:

class FooDescriptor : public ts::AbstractDescriptor { ... };

In the implementation of the descriptor, we register hooks for the various features. Since this is a non-DVB descriptor with descriptor tag 0xE8, greater than 0x80, we must set the private data specifier to zero in the ts::EDID ("extended descriptor id").

TS_REGISTER_DESCRIPTOR(FooDescriptor,                 // C++ class name
                       ts::EDID::Private(0xE8, 0),    // "extended" descriptor id
                       u"foo_descriptor",             // XML name is <foo_descriptor>
                       FooDescriptor::DisplayDescriptor);

The last argument to TS_REGISTER_DESCRIPTOR is a static method of the class which displays the content of a descriptor.

The XML model for the descriptor is included in the XML file:

<?xml version="1.0" encoding="UTF-8"?>
<tsduck>
  <_descriptors>
    <foo_descriptor name="string, required"/>
  </_descriptors>
</tsduck>

for the following binary layout:

descriptor_tag           8 bits = 0xE8
descriptor_length        8 bits
for(i=0;i<N;i++) {
    name_char            8 bits
}

7.2.6. Implementing advanced section filtering capabilities

The command tstables (and its plugin counterpart tables) can process vast amounts of tables. To extract specific tables or sections, the command provides filtering options such as --pid, --tid or --tid-ext.

For specific sections, it is possible to define additional filtering options to the tstables command.

The extension library shall provide a C++ class implementing ts::TablesLoggerFilterInterface. The sample foo extension provide an option --foo-id which selects instances of FooTable containing specific values for some foo_id field.

class FooFilter: public ts::TablesLoggerFilterInterface { ... };

See the documentation of ts::TablesLoggerFilterInterface for more details.

In the implementation of the class, we register it as a section filter for tstables:

TS_REGISTER_SECTION_FILTER(FooFilter);

7.2.7. Providing support for additional Conditional Access Systems

If you work with a specific Conditional Access System, you probably manipulate confidential information that cannot be published in an open-source tool such as TSDuck. The solution is to develop a private closed-source extension.

In the extension library, you may register functions to display the structure of the ECM’s, EMM’s or private part of the CA_descriptor. The registration is based on a range of CA_system_id (here the constants CASID_FOO_MIN and CASID_FOO_MAX).

// Display a FooCAS ECM on the output stream.
// Compatible with ts::DisplaySectionFunction profile.

void DisplayFooCASECM(ts::TablesDisplay& display, const ts::Section& section, int indent);

// Display a FooCAS EMM on the output stream.
// Compatible with ts::DisplaySectionFunction profile.

void DisplayFooCASEMM(ts::TablesDisplay& display, const ts::Section& section, int indent);

// Display the payload of a FooCAS ECM on the output stream as a one-line "log" message.
// Compatible with ts::LogSectionFunction profile.

ts::UString LogFooCASECM(const ts::Section& section, size_t max_bytes);

// Display the payload of a FooCAS EMM on the output stream as a one-line "log" message.
// Compatible with ts::LogSectionFunction profile.

ts::UString LogFooCASEMM(const ts::Section& section, size_t max_bytes);

// Display the private part of a FooCAS CA_descriptor on the output stream.
// Compatible with ts::DisplayCADescriptorFunction profile.

void DisplayFooCASCADescriptor(ts::TablesDisplay& display, const uint8_t* data, size_t size, int indent, ts::TID tid);

To register the display handlers in TSDuck:

TS_REGISTER_SECTION({ts::TID_ECM_80, ts::TID_ECM_81},
                    ts::Standards::NONE,  // not defined in any standard
                    DisplayFooCASECM,     // display function
                    LogFooCASECM,         // one-line log function
                    {},                   // no predefined PID
                    CASID_FOO_MIN,        // range of CA_system_id
                    CASID_FOO_MAX);

TS_REGISTER_SECTION(ts::Range<ts::TID>(ts::TID_EMM_FIRST, ts::TID_EMM_LAST),
                    ts::Standards::NONE,  // not defined in any standard
                    DisplayFooCASEMM,     // display function
                    LogFooCASEMM,         // one-line log function
                    {},                   // no predefined PID
                    CASID_FOO_MIN,        // range of CA_system_id
                    CASID_FOO_MAX);

TS_REGISTER_CA_DESCRIPTOR(DisplayFooCASCADescriptor, CASID_FOO_MIN, CASID_FOO_MAX);

7.3. Building cross-platform binary installers for an extension

See the sample foo extension in the TSDuck source tree.

Scripts are provided to build .exe installers on Windows, .rpm and .deb packages on Linux.

To avoid unexpected issues, an extension is only compatible with the version of TSDuck it was compiled with. When you install a new version of TSDuck, make sure to rebuild your extension with the development environment of this specific version of TSDuck. Then, install the new version of the extension on top of the same new version of TSDuck.

Appendix A: PSI/SI Signalization Reference

All signalization tables and descriptors which are supported by TSDuck are documented in the TSDuck user guide, appendix D "PSI/SI XML Reference Model".

A.1. PSI/SI tables

The table below summarize all available PSI/SI tables in TSDuck and the reference of the standard which specifies them.

XML name C++ class Defining document

AEIT

AEIT

ATSC A/81, 9.9.2

AETT

AETT

ATSC A/81, 9.9.3

AIT

AIT

ETSI TS 101 812, 10.4.6

AMT

AMT

ARIB STD-B10, Part 2, 5.2.16

ATSC_EIT

ATSCEIT

ATSC A/65, 6.5

BAT

BAT

ETSI EN 300 468, 5.2.2

BIT

BIT

ARIB STD-B10, Part 2, 5.2.13

cable_emergency_alert_table

CableEmergencyAlertTable

ANSI/SCTE 18, 5

CAT

CAT

ISO/IEC 13818-1, ITU-T H.222.0, 2.4.4.6

CDT

CDT

ARIB STD-B21, 12.2.2.2

CIT

CIT

ETSI TS 102 323, 12.2

container_table

ContainerTable

ETSI TS 102 323, 7.3.1.4

CVCT

CVCT

ATSC A/65, 6.3.2

DCCSCT

DCCSCT

ATSC A/65, 6.8

DCCT

DCCT

ATSC A/65, 6.7

DCT

DCT

ARIB STD-B16, 4.3

DET

DET

ATSC A/90, 11.3.1

DFIT

DFIT

ETSI EN 303 560, 5.3.2.3

discontinuity_information_table

DiscontinuityInformationTable

ETSI EN 300 468, 7.1.1

DLT

DLT

ARIB STD-B16, 4.4

DSMCC_download_data_message

DSMCCDownloadDataMessage

ISO/IEC 13818-6, 9.2.2 and 7.2.2

DSMCC_stream_descriptors_table

DSMCCStreamDescriptorsTable

ISO/IEC 13818-6, 9.2.2 and 9.2.7

DSMCC_user_to_network_message

DSMCCUserToNetworkMessage

ISO/IEC 13818-6, 9.2.2, 7.3.2, 7.3.6

DST

DST

ATSC A/90, 12.2

EIT

EIT

ETSI EN 300 468, 5.2.4

ERT

ERT

ARIB STD-B10, Part 3, 5.1.2

ETT

ETT

ATSC A/65, 6.6

INT

INT

ETSI EN 301 192, 8.4.3

ITT

ITT

ARIB STD-B10, Part 3, 5.1.3

LDT

LDT

ARIB STD-B10, Part 2, 5.2.15

LIT

LIT

ARIB STD-B10, Part 3, 5.1.1

LTST

LTST

ATSC A/90, 11.7

MGT

MGT

ATSC A/65, 6.2

MPE_FEC

MPEFECTable

ETSI EN 301 192, 9.9

MPE_IFEC

MPEIFECTable

ETSI TS 102 772, 5.2

NBIT

NBIT

ARIB STD-B10, Part 2, 5.2.14

NIT

NIT

ETSI EN 300 468, 5.2.1

NRT

NRT

ATSC A/90, 12.3

PAT

PAT

ISO/IEC 13818-1, ITU-T H.222.0, 2.4.4.3

PCAT

PCAT

ARIB STD-B10, Part 2, 5.2.12

PMT

PMT

ISO/IEC 13818-1, ITU-T H.222.0, 2.4.4.8

RCT

RCT

ETSI TS 102 323, 10.4.2

RNT

RNT

ETSI TS 102 323, 5.2.2

RRT

RRT

ATSC A/65, 6.4

RST

RST

ETSI EN 300 468, 5.2.7

SAT

SAT

ETSI EN 300 468, 5.2.11

SDT

SDT

ETSI EN 300 468, 5.2.3

SDTT

SDTT

ARIB STD-B21, 12.2.1.1

selection_information_table

SelectionInformationTable

ETSI EN 300 468, 7.1.2

SGT

SGT

Astra LCN Technical Specification, 2.1

splice_information_table

SpliceInformationTable

ANSI/SCTE 35, 9.2

STT

STT

ATSC A/65, 6.1

SVCT

SVCT

ATSC A/81, 9.9.1

TDT

TDT

ETSI EN 300 468, 5.2.5

TOT

TOT

ETSI EN 300 468, 5.2.6

TSDT

TSDT

ISO/IEC 13818-1, ITU-T H.222.0, 2.4.4.12

TVCT

TVCT

ATSC A/65, 6.3.1

UNT

UNT

ETSI TS 102 006, 9.4.1

A.2. PSI/SI descriptors

The table below summarize all available PSI/SI desciptors in TSDuck and the reference of the standard which specifies them.

XML name C++ class Defining document

AAC_descriptor

AACDescriptor

ETSI EN 300 468, H.2.1

adaptation_field_data_descriptor

AdaptationFieldDataDescriptor

ETSI EN 300 468, 6.2.1

af_extensions_descriptor

AFExtensionsDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.99

ancillary_data_descriptor

AncillaryDataDescriptor

ETSI EN 300 468, 6.2.2

announcement_support_descriptor

AnnouncementSupportDescriptor

ETSI EN 300 468, 6.2.3

application_descriptor

ApplicationDescriptor

ETSI TS 102 809, 5.3.5.3

application_icons_descriptor

ApplicationIconsDescriptor

ETSI TS 102 809, 5.3.5.6.2

application_name_descriptor

ApplicationNameDescriptor

ETSI TS 101 812, 10.7.4.1

application_recording_descriptor

ApplicationRecordingDescriptor

ETSI TS 102 809, 5.3.5.4

application_signalling_descriptor

ApplicationSignallingDescriptor

ETSI TS 102 809, 5.3.5.1

application_storage_descriptor

ApplicationStorageDescriptor

ETSI TS 102 809, 5.3.10.1

application_usage_descriptor

ApplicationUsageDescriptor

ETSI TS 102 809, 5.3.5.5

area_broadcasting_information_descriptor

AreaBroadcastingInformationDescriptor

ARIB STD-B10, Part 2, 6.2.55

association_tag_descriptor

AssociationTagDescriptor

ISO/IEC 13818-6 (DSM-CC), 11.4.2

astra_bouquet_list_descriptor

AstraBouquetListDescriptor

Astra LCN Technical Specification, 2.3.2

astra_service_list_name_descriptor

AstraServiceListNameDescriptor

Astra LCN Technical Specification, 2.3.1

astra_virtual_service_id_descriptor

AstraVirtualServiceIdDescriptor

Astra LCN Technical Specification, 2.3.3

ATSC_AC3_audio_stream_descriptor

ATSCAC3AudioStreamDescriptor

ATSC A/52, A.4.3

ATSC_component_list_descriptor

ATSCComponentListDescriptor

ATSC A/71, 6

ATSC_CRC32_descriptor

ATSCCRC32Descriptor

ATSC A/90, 7.2.3.5.3

ATSC_data_service_descriptor

ATSCDataServiceDescriptor

ATSC A/90, 11.5

ATSC_download_descriptor

ATSCDownloadDescriptor

ATSC A/90, 12.2.3

ATSC_EAC3_audio_descriptor

ATSCEAC3AudioDescriptor

ATSC A/52, G.3.5

ATSC_group_link_descriptor

ATSCGroupLinkDescriptor

ATSC A/90, 7.2.3.5.4

ATSC_module_link_descriptor

ATSCModuleLinkDescriptor

ATSC A/90, 7.2.3.5.2

ATSC_multiprotocol_encapsulation_descriptor

ATSCMultiprotocolEncapsulationDescriptor

ATSC A/90, 12.2.4

ATSC_parameterized_service_descriptor

ATSCParameterizedServiceDescriptor

ATSC A/71, 7

ATSC_PID_count_descriptor

ATSCPIDCountDescriptor

ATSC A/90, 11.6

ATSC_private_information_descriptor

ATSCPrivateInformationDescriptor

ATSC A/53, Part 3, 5.8.2

ATSC_stuffing_descriptor

ATSCStuffingDescriptor

ATSC A/65, 6.9.8

ATSC_time_shifted_service_descriptor

ATSCTimeShiftedServiceDescriptor

ATSC A/65, 6.9.6

audio_component_descriptor

AudioComponentDescriptor

ARIB STD-B10, Part 2, 6.2.26

audio_preselection_descriptor

AudioPreselectionDescriptor

ETSI EN 300 468, 6.4.1

audio_stream_descriptor

AudioStreamDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.4

australia_logical_channel_descriptor

AustraliaLogicalChannelDescriptor

Free TV Australia Operational Practice OP-41, 2.2

auxiliary_video_stream_descriptor

AuxiliaryVideoStreamDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.74 and ISO/IEC 23002-3

AV1_video_descriptor

AV1VideoDescriptor

https://aomediacodec.github.io/av1-mpeg2-ts/

AVC_timing_and_HRD_descriptor

AVCTimingAndHRDDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.66

AVC_video_descriptor

AVCVideoDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.64

AVS2_audio_descriptor

AVS2AudioDescriptor

AVS T/AI 109.7

AVS3_audio_descriptor

AVS3AudioDescriptor

AVS T/AI 109.7

AVS3_video_descriptor

AVS3VideoDescriptor

AVS T/AI 109.6, 9.3.2

basic_local_event_descriptor

BasicLocalEventDescriptor

ARIB STD-B10, Part 3, 5.2.1

board_information_descriptor

BoardInformationDescriptor

ARIB STD-B10, Part 2, 6.2.39

bouquet_name_descriptor

BouquetNameDescriptor

ETSI EN 300 468, 6.2.4

broadcaster_name_descriptor

BroadcasterNameDescriptor

ARIB STD-B10, Part 2, 6.2.36

C2_bundle_delivery_system_descriptor

C2BundleDeliverySystemDescriptor

ETSI EN 300 468, 6.4.6.4

C2_delivery_system_descriptor

C2DeliverySystemDescriptor

ETSI EN 300 468, 6.4.6.1

CA_contract_info_descriptor

CAContractInfoDescriptor

ARIB STD-B25, Part 1, 4.7.2

CA_descriptor

CADescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.16

CA_EMM_TS_descriptor

CAEMMTSDescriptor

ARIB STD-B25, Part 1, 4.7.1

CA_identifier_descriptor

CAIdentifierDescriptor

ETSI EN 300 468, 6.2.5

CA_service_descriptor

CAServiceDescriptor

ARIB STD-B25, Part 1, 4.7.3

cable_delivery_system_descriptor

CableDeliverySystemDescriptor

ETSI EN 300 468, 6.2.13.1

caption_service_descriptor

CaptionServiceDescriptor

ATSC A/65, 6.9.2

carousel_compatible_composite_descriptor

CarouselCompatibleCompositeDescriptor

ARIB STD-B10, Part 2, 6.2.46

carousel_identifier_descriptor

CarouselIdentifierDescriptor

ISO/IEC 13818-6 (DSM-CC), 11.4.1

cell_frequency_link_descriptor

CellFrequencyLinkDescriptor

ETSI EN 300 468, 6.2.6

cell_list_descriptor

CellListDescriptor

ETSI EN 300 468, 6.2.7

CI_ancillary_data_descriptor

CIAncillaryDataDescriptor

ETSI EN 300 468, 6.4.1

component_descriptor

ComponentDescriptor

ETSI EN 300 468, 6.2.8

component_name_descriptor

ComponentNameDescriptor

ATSC A/65, 6.9.7

conditional_playback_descriptor

ConditionalPlaybackDescriptor

ARIB STD-B25, Part 2, 2.3.2.6.4

content_advisory_descriptor

ContentAdvisoryDescriptor

ATSC A/65, 6.9.3

content_availability_descriptor

ContentAvailabilityDescriptor

ARIB STD-B10, Part 2, 6.2.45

content_descriptor

ContentDescriptor

ETSI EN 300 468, 6.2.9

content_identifier_descriptor

ContentIdentifierDescriptor

ETSI TS 102 323, 12.1

content_labelling_descriptor

ContentLabellingDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.56

copyright_descriptor

CopyrightDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.24

country_availability_descriptor

CountryAvailabilityDescriptor

ETSI EN 300 468, 6.2.10

CP_descriptor

CPDescriptor

ETSI EN 300 468, 6.4.2

CP_identifier_descriptor

CPIdentifierDescriptor

ETSI EN 300 468, 6.4.3

cpcm_delivery_signalling_descriptor

CPCMDeliverySignallingDescriptor

ETSI TS 102 825-9, 4.1.5 and ETSI TS 102 825-4, 5.4.5

cue_identifier_descriptor

CueIdentifierDescriptor

ANSI/SCTE 35, 8.2

CUVV_video_stream_descriptor

UWAVideoStreamDescriptor

T/UWA 005-2.1

data_broadcast_descriptor

DataBroadcastDescriptor

ETSI EN 300 468, 6.2.11

data_broadcast_id_descriptor

DataBroadcastIdDescriptor

ETSI EN 300 468, 6.2.12

data_component_descriptor

DataComponentDescriptor

ARIB STD-B10, Part 2, 6.2.20

data_content_descriptor

DataContentDescriptor

ARIB STD-B10, Part 2, 6.2.28

data_stream_alignment_descriptor

DataStreamAlignmentDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.10

dcc_arriving_request_descriptor

DCCArrivingRequestDescriptor

ATSC A/65, 6.9.11

dcc_departing_request_descriptor

DCCDepartingRequestDescriptor

ATSC A/65, 6.9.10

default_authority_descriptor

DefaultAuthorityDescriptor

ETSI TS 102 323, 6.3.3 and, 5.2.2 for interpretation

deferred_association_tags_descriptor

DeferredAssociationTagsDescriptor

ISO/IEC 13818-6 (DSM-CC), 11.4.3

digital_copy_control_descriptor

DigitalCopyControlDescriptor

ARIB STD-B10, Part 2, 6.2.23

DII_location_descriptor

DIILocationDescriptor

ETSI TS 101 812, 10.8.3.3

download_content_descriptor

DownloadContentDescriptor

ARIB STD-B21, 12.2.1.1

dsmcc_caching_priority_descriptor

DSMCCCachingPriorityDescriptor

ETSI TS 102 809 V1.3.1 (2017-06), B.2.2.4.2

dsmcc_compressed_module_descriptor

DSMCCCompressedModuleDescriptor

ETSI EN 301 192 V1.7.1 (2021-08), 10.2.11

dsmcc_content_type_descriptor

DSMCCContentTypeDescriptor

ETSI TS 102 809, B.2.3.4

dsmcc_CRC32_descriptor

DSMCCCRC32Descriptor

ETSI EN 301 192 V1.7.1 (2021-08), 10.2.6

dsmcc_est_download_time_descriptor

DSMCCEstDownloadTimeDescriptor

ETSI EN 301 192 V1.7.1 (2021-08), 10.2.8

dsmcc_group_link_descriptor

DSMCCGroupLinkDescriptor

ETSI EN 301 192 V1.7.1 (2021-08), 10.2.9

dsmcc_info_descriptor

DSMCCInfoDescriptor

ETSI EN 301 192 V1.7.1 (2021-08), 10.2.4

dsmcc_label_descriptor

DSMCCLabelDescriptor

ETSI TS 102 727 V1.1.1 (2010-01), B.2.2.4.1

dsmcc_location_descriptor

DSMCCLocationDescriptor

ETSI EN 301 192 V1.7.1 (2021-08), 10.2.7

dsmcc_module_link_descriptor

DSMCCModuleLinkDescriptor

ETSI EN 301 192 V1.7.1 (2021-08), 10.2.5

dsmcc_name_descriptor

DSMCCNameDescriptor

ETSI EN 301 192 V1.7.1 (2021-08), 10.2.3

dsmcc_ssu_module_type_descriptor

DSMCCSSUModuleTypeDescriptor

ETSI TS 102 006 V1.4.1 (2015-06), 8.2.1

dsmcc_subgroup_association_descriptor

DSMCCSubgroupAssociationDescriptor

ETSI TS 102 006, 9.6.2.1

dsmcc_type_descriptor

DSMCCTypeDescriptor

ETSI EN 301 192 V1.7.1 (2021-08), 10.2.2

DSNG_descriptor

DSNGDescriptor

ETSI EN 300 468, 6.2.14

dtg_guidance_descriptor

DTGGuidanceDescriptor

The D-Book 7 Part A (DTG), 8.5.3.20

dtg_HD_simulcast_logical_channel_descriptor

DTGHDSimulcastLogicalChannelDescriptor

The D-Book 7 Part A (DTG), 8.5.3.23

dtg_logical_channel_descriptor

DTGLogicalChannelDescriptor

The D-Book 7 Part A (DTG), 8.5.3.6

dtg_preferred_name_identifier_descriptor

DTGPreferredNameIdentifierDescriptor

The D-Book 7 Part A (DTG), 8.5.3.8

dtg_preferred_name_list_descriptor

DTGPreferredNameListDescriptor

The D-Book 7 Part A (DTG), 8.5.3.7

dtg_service_attribute_descriptor

DTGServiceAttributeDescriptor

The D-Book 7 Part A (DTG), 8.5.3.9

dtg_short_service_name_descriptor

DTGShortServiceNameDescriptor

The D-Book 7 Part A (DTG), 8.5.3.10

DTMB_DRM_descriptor

DTMBDRMDescriptor

ITU J.1041, 7.2.1

DTS_descriptor

DTSDescriptor

ETSI EN 300 468, G.2.1

DTS_HD_descriptor

DTSHDDescriptor

ETSI EN 300 468, G.3.1

DTS_neural_descriptor

DTSNeuralDescriptor

ETSI EN 300 468, L.1

DTS_UHD_descriptor

DVBDTSUHDDescriptor

ETSI EN 300 468, annex G

DVB_AC3_descriptor

DVBAC3Descriptor

ETSI EN 300 468, D.3

DVB_AC4_descriptor

DVBAC4Descriptor

ETSI EN 300 468, D.7

DVB_enhanced_AC3_descriptor

DVBEnhancedAC3Descriptor

ETSI EN 300 468, D.5

dvb_html_application_boundary_descriptor

DVBHTMLApplicationBoundaryDescriptor

ETSI TS 101 812, 10.10.3

dvb_html_application_descriptor

DVBHTMLApplicationDescriptor

ETSI TS 101 812, 10.10.1

dvb_html_application_location_descriptor

DVBHTMLApplicationLocationDescriptor

ETSI TS 101 812, 10.10.2

dvb_j_application_descriptor

DVBJApplicationDescriptor

ETSI TS 101 812, 10.9.1

dvb_j_application_location_descriptor

DVBJApplicationLocationDescriptor

ETSI TS 101 812, 10.9.2

DVB_stuffing_descriptor

DVBStuffingDescriptor

ETSI EN 300 468, 6.2.40

DVB_time_shifted_service_descriptor

DVBTimeShiftedServiceDescriptor

ETSI EN 300 468, 6.2.45

eacem_logical_channel_number_descriptor

EacemLogicalChannelNumberDescriptor

EACEM Technical Report Number TR-030, 9.2.11.2

eacem_preferred_name_identifier_descriptor

EacemPreferredNameIdentifierDescriptor

EACEM Technical Report Number TR-030, 9.2.11.2

eacem_preferred_name_list_descriptor

EacemPreferredNameListDescriptor

EACEM Technical Report Number TR-030, 9.2.11.2

eacem_stream_identifier_descriptor

EacemStreamIdentifierDescriptor

EACEM Technical Report Number TR-030, 9.2.11.2

EAS_audio_file_descriptor

EASAudioFileDescriptor

ANSI/SCTE 18, 5.1.3

EAS_inband_details_channel_descriptor

EASInbandDetailsChannelDescriptor

ANSI/SCTE 18, 5.1.1

EAS_inband_exception_channels_descriptor

EASInbandExceptionChannelsDescriptor

ANSI/SCTE 18, 5.1.2

EAS_metadata_descriptor

EASMetadataDescriptor

ANSI/SCTE 164, 5.0

ECM_repetition_rate_descriptor

ECMRepetitionRateDescriptor

ETSI EN 301 192, 9.7

emergency_information_descriptor

EmergencyInformationDescriptor

ARIB STD-B10, Part 2, 6.2.24

EVC_timing_and_HRD_descriptor

EVCTimingAndHRDDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.135

EVC_video_descriptor

EVCVideoDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.133

event_group_descriptor

EventGroupDescriptor

ARIB STD-B10, Part 2, 6.2.34

extended_broadcaster_descriptor

ExtendedBroadcasterDescriptor

ARIB STD-B10, Part 2, 6.2.43

extended_channel_name_descriptor

ExtendedChannelNameDescriptor

ATSC A/65, 6.9.4

extended_event_descriptor

ExtendedEventDescriptor

ETSI EN 300 468, 6.2.15

external_application_authorization_descriptor

ExternalApplicationAuthorizationDescriptor

ETSI TS 102 809, 5.3.5.7

external_ES_ID_descriptor

ExternalESIdDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.46

FMC_descriptor

FMCDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.44

frequency_list_descriptor

FrequencyListDescriptor

ETSI EN 300 468, 6.2.17

FTA_content_management_descriptor

FTAContentManagementDescriptor

ETSI EN 300 468, 6.2.18

genre_descriptor

GenreDescriptor

ATSC A/65, 6.9.13

graphics_constraints_descriptor

GraphicsConstraintsDescriptor

ETSI TS 102 809, 5.3.5.8

green_extension_descriptor

GreenExtensionDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.104

HEVC_hierarchy_extension_descriptor

HEVCHierarchyExtensionDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.102

HEVC_operation_point_descriptor

HEVCOperationPointDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.100

HEVC_subregion_descriptor

HEVCSubregionDescriptor

ISO/IEC 13818-1, 2.6.138

HEVC_tile_substream_descriptor

HEVCTileSubstreamDescriptor

ISO/IEC 13818-1 clasue 2.6.122

HEVC_timing_and_HRD_descriptor

HEVCTimingAndHRDDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.97

HEVC_video_descriptor

HEVCVideoDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.95

hierarchical_transmission_descriptor

HierarchicalTransmissionDescriptor

ARIB STD-B10, Part 2, 6.2.22

hierarchy_descriptor

HierarchyDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.6

hybrid_information_descriptor

HybridInformationDescriptor

ARIB STD-B10, Part 2, 6.2.58

IBP_descriptor

IBPDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.34

image_icon_descriptor

ImageIconDescriptor

ETSI EN 300 468, 6.4.7

IOD_descriptor

IODDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.40

ip_signalling_descriptor

IPSignallingDescriptor

ETSI TS 101 812, 10.8.2

IPMAC_generic_stream_location_descriptor

IPMACGenericStreamLocationDescriptor

ETSI EN 301 192, 8.4.5.15

IPMAC_platform_name_descriptor

IPMACPlatformNameDescriptor

ETSI EN 301 192, 8.4.5.2

IPMAC_platform_provider_name_descriptor

IPMACPlatformProviderNameDescriptor

ETSI EN 301 192, 8.4.5.3

IPMAC_stream_location_descriptor

IPMACStreamLocationDescriptor

ETSI EN 301 192, 8.4.5.14

ISDB_access_control_descriptor

ISDBAccessControlDescriptor

ARIB STD-B10, Part 2, 6.2.54

ISDB_advanced_cable_delivery_system_descriptor

ISDBAdvancedCableDeliverySystemDescriptor

JCTEA STD-003, 6.2

ISDB_CA_startup_descriptor

ISDBCAStartupDescriptor

ARIB STD-B61, Volume 2, 4.6.1

ISDB_cable_TS_division_system_descriptor

ISDBCableTSDivisionSystemDescriptor

JCTEA STD-003, 6.2 J2

ISDB_character_code_descriptor

ISDBCharacterCodeDescriptor

ARIB STD-B63, 13.1.2.1

ISDB_component_group_descriptor

ISDBComponentGroupDescriptor

ARIB STD-B10, Part 2, 6.2.37

ISDB_connected_transmission_descriptor

ISDBConnectedTransmissionDescriptor

ARIB STD-B10, Part 2, 6.2.41

ISDB_download_protection_descriptor

ISDBDownloadProtectionDescriptor

ARIB STD-B61, Volume 2, 4.4.7.1

ISDB_hyperlink_descriptor

ISDBHyperlinkDescriptor

ARIB STD-B10, Part 2, 6.2.29

ISDB_LDT_linkage_descriptor

ISDBLDTLinkageDescriptor

ARIB STD-B10, Part 2, 6.2.40

ISDB_network_identifier_descriptor

ISDBNetworkIdentifierDescriptor

ARIB STD-B21, Part 2, 9.1.8.3

ISDB_scrambler_descriptor

ISDBScramblerDescriptor

ARIB STD-B10, Part 1, 6.2, Figure 6.2-68

ISDB_target_region_descriptor

ISDBTargetRegionDescriptor

ARIB STD-B10, Part 2, 6.2.27

ISDB_terrestrial_delivery_system_descriptor

ISDBTerrestrialDeliverySystemDescriptor

ARIB STD-B10, Part 2, 6.2.31

ISDB_wired_multicarrier_transmission_descriptor

ISDBWiredMultiCarrierTransmissionDescriptor

JCTEA STD-003, 6.2 J3

ISO_639_language_descriptor

ISO639LanguageDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.18

ISP_access_mode_descriptor

ISPAccessModeDescriptor

ETSI EN 301 192, 8.4.5.16

J2K_video_descriptor

J2KVideoDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.80

JPEG_XS_video_descriptor

JPEGXSVideoDescriptor

ISO/IEC 13818-1 2.6.127, ITU-T H.222.0

LCEVC_linkage_descriptor

LCEVCLinkageDescriptor

ISO/IEC 13818-1 (Amd.1) 2.6.137, ITU-T H.222.0

LCEVC_video_descriptor

LCEVCVideoDescriptor

ISO/IEC 13818-1 (Amd.1) 2.6.137, ITU-T H.222.0

linkage_descriptor

LinkageDescriptor

ETSI EN 300 468, 6.2.19

linkage_descriptor

SSULinkageDescriptor

ETSI EN 300 468, 6.2.19

local_time_offset_descriptor

LocalTimeOffsetDescriptor

ETSI EN 300 468, 6.2.20

logo_transmission_descriptor

LogoTransmissionDescriptor

ARIB STD-B10, Part 2, 6.2.44

m4mux_timing_descriptor

M4MuxTimingDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.54

M4MuxBufferSize_descriptor

M4MuxBufferSizeDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.50

material_information_descriptor

MaterialInformationDescriptor

ARIB STD-B10, Part 3, 5.2.6

maximum_bitrate_descriptor

MaximumBitrateDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.26

Media_service_kind_descriptor

MediaServiceKindDescriptor

ISO/IEC 13818-1 (Amd.1) 2.6.141

message_descriptor

MessageDescriptor

ETSI EN 300 468, 6.4.7

metadata_descriptor

MetadataDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.60

metadata_pointer_descriptor

MetadataPointerDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.58

metadata_STD_descriptor

MetadataSTDDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.62

mosaic_descriptor

MosaicDescriptor

ETSI EN 300 468, 6.2.21

MPEG2_AAC_audio_descriptor

MPEG2AACAudioDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.68

MPEG2_stereoscopic_video_format_descriptor

MPEG2StereoscopicVideoFormatDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.84

MPEG4_audio_descriptor

MPEG4AudioDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.38

MPEG4_audio_extension_descriptor

MPEG4AudioExtensionDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.72

MPEG4_text_descriptor

MPEG4TextDescriptor

ITU-T H.222.0, 2.6.70 and ISO/IEC 14496-17

MPEG4_video_descriptor

MPEG4VideoDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.36

MPEGH_3D_audio_command_descriptor

MPEGH3DAudioCommandDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.118

MPEGH_3D_audio_config_descriptor

MPEGH3DAudioConfigDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.108

MPEGH_3D_audio_descriptor

MPEGH3DAudioDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.106

MPEGH_3D_audio_drc_loudness_descriptor

MPEGH3DAudioDRCLoudnessDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.116

MPEGH_3D_audio_multi_stream_descriptor

MPEGH3DAudioMultiStreamDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.114

MPEGH_3D_audio_scene_descriptor

MPEGH3DAudioSceneDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.110

MPEGH_3D_audio_text_label_descriptor

MPEGH3DAudioTextLabelDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.112

multilingual_bouquet_name_descriptor

MultilingualBouquetNameDescriptor

ETSI EN 300 468, 6.2.22

multilingual_component_descriptor

MultilingualComponentDescriptor

ETSI EN 300 468, 6.2.23

multilingual_network_name_descriptor

MultilingualNetworkNameDescriptor

ETSI EN 300 468, 6.2.24

multilingual_service_name_descriptor

MultilingualServiceNameDescriptor

ETSI EN 300 468, 6.2.25

multiplex_buffer_descriptor

MultiplexBufferDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.52

multiplex_buffer_utilization_descriptor

MultiplexBufferUtilizationDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.22

MuxCode_descriptor

MuxcodeDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.48 and ISO/IEC 14496-1, 7.4.2.5

MVC_extension_descriptor

MVCExtensionDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.78

MVC_operation_point_descriptor

MVCOperationPointDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.82

network_change_notify_descriptor

NetworkChangeNotifyDescriptor

ETSI EN 300 468, 6.4.9

network_download_content_descriptor

NetworkDownloadContentDescriptor

ARIB STD-B21, 12.2.1.1

network_name_descriptor

NetworkNameDescriptor

ETSI EN 300 468, 6.2.27

node_relation_descriptor

NodeRelationDescriptor

ARIB STD-B10, Part 3, 5.2.3

nordig_logical_channel_descriptor_v1

NorDigLogicalChannelDescriptorV1

NorDig Unified Requirements ver. 3.1.1, 12.2.9.2

nordig_logical_channel_descriptor_v2

NorDigLogicalChannelDescriptorV2

NorDig Unified Requirements ver. 3.1.1, 12.2.9.3

NPT_endpoint_descriptor

NPTEndpointDescriptor

ISO/IEC 13818-6, 8.1.5

NPT_reference_descriptor

NPTReferenceDescriptor

ISO/IEC 13818-6, 8.1.1

NVOD_reference_descriptor

NVODReferenceDescriptor

ETSI EN 300 468, 6.2.26

parental_rating_descriptor

ParentalRatingDescriptor

ETSI EN 300 468, 6.2.28

partial_reception_descriptor

PartialReceptionDescriptor

ARIB STD-B10, Part 2, 6.2.32

partial_transport_stream_descriptor

PartialTransportStreamDescriptor

ETSI EN 300 468, 7.2.1

partialTS_time_descriptor

PartialTSTimeDescriptor

ARIB STD-B21, 9.1.8.3 (3)

PDC_descriptor

PDCDescriptor

ETSI EN 300 468, 6.2.30

prefetch_descriptor

PrefetchDescriptor

ETSI TS 101 812, 10.8.3.2

private_data_indicator_descriptor

PrivateDataIndicatorDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.28

private_data_specifier_descriptor

PrivateDataSpecifierDescriptor

ETSI EN 300 468, 6.2.31

protection_message_descriptor

ProtectionMessageDescriptor

ETSI TS 102 809, 9.3.3

quality_extension_descriptor

QualityExtensionDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.119 and ISO/ISC 23001-10

RAR_over_DVB_stream_descriptor

RARoverDVBstreamDescriptor

ETSI TS 102 323, 5.3.5

RAR_over_IP_descriptor

RARoverIPDescriptor

ETSI TS 102 323, 5.3.6

redistribution_control_descriptor

RedistributionControlDescriptor

ATSC A/65, 6.9.12

reference_descriptor

ReferenceDescriptor

ARIB STD-B10, Part 3, 5.2.2

registration_descriptor

RegistrationDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.8

related_content_descriptor

RelatedContentDescriptor

ETSI TS 102 323, 10.3

RNT_scan_descriptor

RNTScanDescriptor

ETSI TS 102 323, 5.3.7

S2_satellite_delivery_system_descriptor

S2SatelliteDeliverySystemDescriptor

ETSI EN 300 468, 6.2.13.3

S2X_satellite_delivery_system_descriptor

S2XSatelliteDeliverySystemDescriptor

ETSI EN 300 468, 6.4.6.5

S2Xv2_satellite_delivery_system_descriptor

S2Xv2SatelliteDeliverySystemDescriptor

ETSI EN 300 468, 6.4.6.5.3

satellite_delivery_system_descriptor

SatelliteDeliverySystemDescriptor

ETSI EN 300 468, 6.2.13.2

scheduling_descriptor

SchedulingDescriptor

ETSI TS 102 006, 9.5.2.9

scrambling_descriptor

ScramblingDescriptor

ETSI EN 300 468, 6.2.32

series_descriptor

SeriesDescriptor

ARIB STD-B10, Part 2, 6.2.33

service_availability_descriptor

ServiceAvailabilityDescriptor

ETSI EN 300 468, 6.2.34

service_descriptor

ServiceDescriptor

ETSI EN 300 468, 6.2.33

service_group_descriptor

ServiceGroupDescriptor

ARIB STD-B10, Part 2, 6.2.49

service_identifier_descriptor

ServiceIdentifierDescriptor

ETSI TS 102 809, 6.2.1

service_list_descriptor

ServiceListDescriptor

ETSI EN 300 468, 6.2.35

service_location_descriptor

ServiceLocationDescriptor

ATSC A/65, 6.9.5

service_move_descriptor

ServiceMoveDescriptor

ETSI EN 300 468, 6.2.34

service_prominence_descriptor

DVBServiceProminenceDescriptor

ETSI EN 300 468, 6.4.18

service_relocated_descriptor

ServiceRelocatedDescriptor

ETSI EN 300 468, 6.4.9

SH_delivery_system_descriptor

SHDeliverySystemDescriptor

ETSI EN 300 468, 6.4.6.2

short_event_descriptor

ShortEventDescriptor

ETSI EN 300 468, 6.2.37

short_node_information_descriptor

ShortNodeInformationDescriptor

ARIB STD-B10, Part 3, 5.2.4

short_smoothing_buffer_descriptor

ShortSmoothingBufferDescriptor

ETSI EN 300 468, 6.2.38

SI_parameter_descriptor

SIParameterDescriptor

ARIB STD-B10, Part 2, 6.2.35

SI_prime_TS_descriptor

SIPrimeTSDescriptor

ARIB STD-B10, Part 2, 6.2.38

simple_application_boundary_descriptor

SimpleApplicationBoundaryDescriptor

ETSI TS 102 809, 5.3.8

simple_application_location_descriptor

SimpleApplicationLocationDescriptor

ETSI TS 102 809, 5.3.7

SL_descriptor

SLDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.42

smoothing_buffer_descriptor

SmoothingBufferDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.30

smpte_anc_data_descriptor

SMPTEAncDataDescriptor

SMPTE ST 2038, 4.1.2

splice_audio_descriptor

SpliceAudioDescriptor

ANSI/SCTE 35, 10.3.5

splice_avail_descriptor

SpliceAvailDescriptor

ANSI/SCTE 35, 10.3.1

splice_DTMF_descriptor

SpliceDTMFDescriptor

ANSI/SCTE 35, 10.3.2

splice_segmentation_descriptor

SpliceSegmentationDescriptor

ANSI/SCTE 35, 10.3.3

splice_time_descriptor

SpliceTimeDescriptor

ANSI/SCTE 35, 10.3.4

SSU_enhanced_message_descriptor

SSUEnhancedMessageDescriptor

ETSI TS 102 006, 9.5.2.14

SSU_event_name_descriptor

SSUEventNameDescriptor

ETSI TS 102 006, 9.5.2.11

SSU_location_descriptor

SSULocationDescriptor

ETSI TS 102 006, 9.5.2.7

SSU_message_descriptor

SSUMessageDescriptor

ETSI TS 102 006, 9.5.2.12

SSU_subgroup_association_descriptor

SSUSubgroupAssociationDescriptor

ETSI TS 102 006, 9.5.2.8

SSU_uri_descriptor

SSUURIDescriptor

ETSI TS 102 006, 9.5.2.15

STC_reference_descriptor

STCReferenceDescriptor

ARIB STD-B10, Part 3, 5.2.5

STD_descriptor

STDDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.32

stereoscopic_program_info_descriptor

StereoscopicProgramInfoDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.86

stereoscopic_video_info_descriptor

StereoscopicVideoInfoDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.88

stream_event_descriptor

StreamEventDescriptor

ISO/IEC 13818-6, 8.3

stream_identifier_descriptor

StreamIdentifierDescriptor

ETSI EN 300 468, 6.2.39

stream_mode_descriptor

StreamModeDescriptor

ISO/IEC 13818-6, 8.2

subtitling_descriptor

SubtitlingDescriptor

ETSI EN 300 468, 6.2.41

supplementary_audio_descriptor

SupplementaryAudioDescriptor

ETSI EN 300 468, 6.4.11

SVC_extension_descriptor

SVCExtensionDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.76

system_clock_descriptor

SystemClockDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.20

system_management_descriptor

SystemManagementDescriptor

ARIB STD-B10, Part 2, 6.2.21

T2_delivery_system_descriptor

T2DeliverySystemDescriptor

ETSI EN 300 468, 6.4.6.3

T2MI_descriptor

T2MIDescriptor

ETSI EN 300 468, 6.4.14

target_background_grid_descriptor

TargetBackgroundGridDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.12

target_IP_address_descriptor

TargetIPAddressDescriptor

ETSI EN 301 192, 8.4.5.8

target_IP_slash_descriptor

TargetIPSlashDescriptor

ETSI EN 301 192, 8.4.5.9

target_IP_source_slash_descriptor

TargetIPSourceSlashDescriptor

ETSI EN 301 192, 8.4.5.10

target_IPv6_address_descriptor

TargetIPv6AddressDescriptor

ETSI EN 301 192, 8.4.5.11

target_IPv6_slash_descriptor

TargetIPv6SlashDescriptor

ETSI EN 301 192, 8.4.5.12

target_IPv6_source_slash_descriptor

TargetIPv6SourceSlashDescriptor

ETSI EN 301 192, 8.4.5.13

target_MAC_address_descriptor

TargetMACAddressDescriptor

ETSI EN 301 192, 8.4.5.6

target_MAC_address_range_descriptor

TargetMACAddressRangeDescriptor

ETSI EN 301 192, 8.4.5.7

target_region_descriptor

TargetRegionDescriptor

ETSI EN 300 468, 6.4.12

target_region_name_descriptor

TargetRegionNameDescriptor

ETSI EN 300 468, 6.4.13

target_serial_number_descriptor

TargetSerialNumberDescriptor

ETSI EN 301 192, 8.4.5.4

target_smartcard_descriptor

TargetSmartcardDescriptor

ETSI EN 301 192, 8.4.5.5

telephone_descriptor

TelephoneDescriptor

ETSI EN 300 468, 6.2.42

teletext_descriptor

TeletextDescriptor

ETSI EN 300 468, 6.2.43

terrestrial_delivery_system_descriptor

TerrestrialDeliverySystemDescriptor

ETSI EN 300 468, 6.2.13.4

time_shifted_event_descriptor

TimeShiftedEventDescriptor

ETSI EN 300 468, 6.2.44

time_slice_fec_identifier_descriptor

TimeSliceFECIdentifierDescriptor

ETSI EN 301 192, 9.5

transport_profile_descriptor

TransportProfileDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.93

transport_protocol_descriptor

TransportProtocolDescriptor

ETSI TS 101 812, 10.8.1

transport_stream_descriptor

TransportStreamDescriptor

ETSI EN 300 468, 6.2.46

TS_information_descriptor

TSInformationDescriptor

ARIB STD-B10, Part 2, 6.2.42

TTML_subtitling_descriptor

TTMLSubtitlingDescriptor

ETSI EN 303 560, 5.2.1.1

TVA_id_descriptor

TVAIdDescriptor

ETSI TS 102 323, 11.2.4

update_descriptor

UpdateDescriptor

ETSI TS 102 006, 9.5.2.6

URI_linkage_descriptor

URILinkageDescriptor

ETSI TS 101 162

VBI_data_descriptor

VBIDataDescriptor

ETSI EN 300 468, 6.2.47

VBI_teletext_descriptor

VBITeletextDescriptor

ETSI EN 300 468, 6.2.48

video_decode_control_descriptor

VideoDecodeControlDescriptor

ARIB STD-B10, Part 2, 6.2.30

video_depth_range_descriptor

VideoDepthRangeDescriptor

ETSI EN 300 468, 6.4.16

video_stream_descriptor

VideoStreamDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.2

video_window_descriptor

VideoWindowDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.14

virtual_segmentation_descriptor

VirtualSegmentationDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.120

vvc_subpictures_descriptor

VVCSubpicturesDescriptor

ETSI EN 300 468, 6.4.17

VVC_timing_and_HRD_descriptor

VVCTimingAndHRDDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.131

VVC_video_descriptor

VVCVideoDescriptor

ISO/IEC 13818-1, ITU-T H.222.0, 2.6.129

xait_location_descriptor

XAITLocationDescriptor

ETSI TS 102 727, 10.17.6

xait_pid_descriptor

XAITPIDDescriptor

ETSI TS 102 727, 10.17.3

Appendix B: Licenses

B.1. TSDuck license

TSDuck is released under the terms of the license which is commonly referred to as "BSD 2-Clause License" or "Simplified BSD License" or "FreeBSD License". See http://opensource.org/licenses/BSD-2-Clause.

Copyright © 2005-2026, Thierry Lelégard
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

B.2. Third-party libraries

TSDuck includes a few third-party libraries, either in source form, binary form or both. For more details about the licenses of these third-party libraries, see the file named OTHERS.txt in the TSDuck source code repository.

DTAPI: On Linux and Windows, the TSDuck binary distributions contain the DTAPI library in static form. This library is part of the Dektec SDK. This software is available in binary format only and is distributed under the BSD 2-Clause License. "Copyright (c) 2017 by Dektec Digital Video B.V."

LIBSRT: On Windows, the TSDuck binary distribution contains the SRT library in static form. There are two versions of the SRT library, one from Haivision, one from Robotweax. TSDuck can be built with any of them.

Haivision LIBSRT: The Haivision SRT library is open-source and distributed under the Mozilla Public License v2.0. "Copyright (c) 2018 Haivision Systems Inc."

Robotweax LIBSRT: The Robotweax SRT library is open-source and distributed under the MIT License. "Copyright (c) 2026 Robotweax GmbH and contributors"

LIBRIST: On Windows, the TSDuck binary distribution contains the RIST library in static form. This is an open-source library which is distributed under the BSD 2-Clause License. "Copyright © 2019-2020 SipRadius LLC. All right reserved."

LibVatek: On Windows and Linux, the TSDuck binary distribution contains the LibVatek library in static form. This is an open-source library which is distributed under the BSD 2-Clause License. "Copyright © 2022, Richie Chang."

Small Deflate (sdefl): On Windows, the TSDuck binary distribution contains the Small Deflate library in static form. This is an open-source library which is distributed under two licenses, MIT License and Public Domain License. "Copyright (c) 2020-2023 Micha Mettke."

Appendix C: References

Bibliography