Skip to main content

Interface to the Zapping VBI decoder library

Project description

The Python “ZVBI” module provides an object-oriented interface to the ZVBI library. The ZVBI library allows accessing television broadcast data services such as teletext or closed captions via analog or DVB video capture devices.

Official ZVBI library description:

The ZVBI library provides routines to access raw VBI sampling devices (currently the Linux DVB & V4L2 API and the FreeBSD, OpenBSD, NetBSD and BSDi bktr driver API are supported), a versatile raw VBI bit slicer, decoders for various data services and basic search, render and export functions for text pages. The library was written for the Zapping TV viewer and Zapzilla Teletext browser.

The Python ZVBI module covers all exported libzvbi functions.

The Python interface module is largely based on objects which encapsulate the native C structures of libzvbi. Only when a Python script actually wants to manipulate captured or decoded data directly (i.e. not via library functions), the structures’ data is converted into Python data types. Even then, Python methods such as the “buffer protocol” are used to avoid unnecessary copying. This approach allows for a pretty snappy performance despite the additional interface layer.

Best starting point to get familiar with the module is having a look at the Class Hierarchy, description of the main classes, and the example scripts provided in the “examples/” sub-directory, which demonstrate use of all the main classes. (The examples are a more or less direct C to Python ports of the respective programs in the test/ sub-directory of the libzvbi source tree, plus a few additions, such as a teletext level 2.5 browser implemented in apx. 300 lines of TkInter.) A description of all example scripts can be found below in section Examples. Additionally you can look at the ZVBI library home and the ZVBI library documentation (unfortunately not available online; built via doxygen when compiling the library).

Finally note there is an equivalent Video::ZVBI module for Perl (also at CPAN)

Installation

The Python module works on all platforms supported by the ZVBI library, which are:

  • Linux
  • FreeBSD
  • NetBSD
  • OpenBSD

Pre-requisite to installation is a C compiler and (obviously) the ZVBI library (oldest supported version is 0.2.26) which in turn requires the pthreads and PNG libraries. Note there are no dependencies on other Python modules by the module itself. Some of the provided example scripts however depend on Tkinter.

The following is a copy of the API documentation in file doc/ZVBI.rst

SYNOPSIS

import Zvbi

cap = Zvbi.Capture("/dev/dvb/adapter0/demux0", dvb_pid=104)

vtdec = Zvbi.ServiceDec()
vtdec.event_handler_register(Zvbi.VBI_EVENT_TTX_PAGE, pg_handler)

while True:
    sliced_buffer = cap.pull_sliced(2000)
    vtdec.decode(sliced_buffer)

def pg_handler(pgtype, ev, user_data=None):
    with vtdec.fetch_vt_page(ev.pgno) as pg:
        pg.get_page_text()
        #...

DESCRIPTION

This module provides a Python interface to libzvbi. The ZVBI library allows accessing television broadcast data services such as teletext or closed captions via analog or DVB video capture devices.

Official library description: “The ZVBI library provides routines to access raw VBI sampling devices (currently the Linux DVB & V4L2 APIs and the FreeBSD, OpenBSD, NetBSD and BSDi bktr driver API are supported), a versatile raw VBI bit slicer, decoders for various data services and basic search, render and export functions for text pages. The library was written for the Zapping TV viewer and Zapzilla Teletext browser.”

The Zvbi Python module covers all exported libzvbi functions. Most of the libary functions and parameters are exposed equivalently, with adaptions to render the interface Pythonic.

Note: This manual page does not reproduce the full documentation provided by libzvbi by means of doxygen: While method and parameter descriptions are fully included, some data structures may not be not fully documented here. Hence when additional details are needed, it’s recommended to look at libzvbi documentation, or directly at its source code.

Class Hierarchy

The following is an overview how functionality provided by libzvbi is structured into classes, and how the classes are connected:

Zvbi.Capture
This class allows receiving data through a video device. For digital television transmissions (DVB) this mostly involves demultiplexing of the data service sub-stream from the overall transmission stream. For analog television transmission this involves capturing selected lines within the Vertical Blanking Interval (VBI) and “demodulating” the digitized wave form to raw data.
Zvbi.CaptureRawBuf and Zvbi.CaptureSlicedBuf
These are container classes, used for efficiently transferring data generated by the read and pull methods of the Capture class, usually to decode methods of classes RawDec or ServiceDec respectively. Alternatively one can extract data from the buffers for direct processing within a Python script.
Zvbi.RawDec
This class can optionally be used for manually processing raw data (i.e. direct output of the analog-to-digital conversion of the video signal) optionally returned by the Capture class via pull_raw() methods et.al. For most use-cases the processing (so-called “slicing”) done under control of the Capture class using pull_sliced() should be sufficient, so this class is usually not needed. This class is not applicable for DVB.
Zvbi.Proxy
This class allows accessing VBI devices via a proxy daemon. An instance of this class would be provided to the Capture class constructor. Using the proxy instead of capturing directly from a VBI device allows multiple applications to capture concurrently (e.g. for decoding multiple data services). Not applicable to DVB, as the proxy does not support DVB. (Also at least the Linux DVB driver allows multiple applications reading the same stream concurrently.)
Zvbi.ServiceDec
Class performing high level decoding of all supported services and storing the data in an internal cache. The class takes input (“sliced data”) from the Capture class. The class supports callback functions for notifications about received data; various interfaces allow extracting the data in form of instances of the Page class, or as an image in PPM or XPM formats.
Zvbi.Search
This class allows searching the cache maintained by ServiceDec for pages with text matching a pattern. The search returns instances of class Page.
Zvbi.Page
Instances of this class are produced by the ServiceDec query functions or Search. Each instance represents a teletext (sub-)page or Closed Caption page. The class has various interfaces for extracting the text and properties of the page content.
Zvbi.Export
This class allows rendering an instance of Page in specific formats, for example as plain-text or image in various formats such as PNG or PPM. The result can be returned within a Python string or a bytes object respectively, or written directly to a file.

In summary: For receiving live data, you’ll need at least an instance of the Capture class. Your application is responsible for calling the capture interface at 25 or 30 Hz intervals (ideally using a separate thread that blocks on the capture function, or else using async I/O via select/poll or polling via a timer). For standard services such as Teletext, Closed Caption, WSS or network identification you’ll need to feed the captured data into an instance of the ServiceDec class, which then drives further processing via callback notifications. For other services you may use the de-multiplexers listed below, or process the data within your application directly. After that it depends on your application which interfaces/classes you want to use for further processing of decoded data.

Special-purpose classes for DVB:

Zvbi.DvbDemux
Class performing de-multiplexing of a transport stream received from a DVB driver, i.e. separating “VBI” data from a DVB PES stream (EN 301 472, EN 301 775). Note this class is used internally by the Zvbi.Capture class for de-multiplexing. You should only use this class directly when the data does not originate from a local device.
Zvbi.DvbMux
This class converts sliced and optionally raw VBI data to a DVB Packetized Elementary Stream or Transport Stream as defined in EN 300 472 “Digital Video Broadcasting (DVB); Specification for conveying ITU-R System B Teletext in DVB bit-streams” and EN 301 775 “Digital Video Broadcasting (DVB); Specification for the carriage of Vertical Blanking Information (VBI) data in DVB bit-streams”.

The following classes are for de-multiplexing data services transmitted within teletext packets. For PFC and IDL, libzvbi only supports the protocol, but the application has to decode and store payload data. XDS is supported by Zvbi.ServiceDec (decoding and event notifications). Most likely none of these protocols are used anymore, as they were intended for use via analog television broadcast:

Zvbi.IdlDemux
This class allows decoding data transmissions within a Teletext packet stream using Independent Data Line protocol (EN 300 708 section 6), i.e. data transmissions based on packet 8/30.
Zvbi.PfcDemux
Class for separating data transmitted in Page Function Clear teletext packets (ETS 300 708 section 4), i.e. using regular packets on a dedicated teletext page. Historically this protocol was used for Nextview EPG, (i.e. an Electronic Programming Guide for analog television).
Zvbi.XdsDemux
Class for separating Extended Data Service from a Closed Caption stream (EIA 608). This service allows to transmit “now & next” EPG data in addition to sub-titles.

Class Zvbi.Capture

This class is used for opening a DVB or analog “VBI” device and start receiving data from it. The class does not support tuning of a channel.

Since parameters for capturing from DVB have little overlap with tose for analog devices, there isn’t a single constructor. Instead there are two static methods which construct an instance. The class cannot be instantiated directly. Nevertheless, the capture instances created by the factory functions can be used equivalently for all other class methods.

After creating an instance, one of the read or pull methods (see below for hints which one to use) have to be called periodically for retrieving the data. Usually this is done within a quasi-infinite “while” loop (possibly in a separate thread), but most devices will support “select()” and thus allow asynchronous I/O via event handlers. If everything else fails, you can also use polling in fixed intervals slightly lower than the (interlaced) video frame rate (e.g. 2*30 Hz for NTSC, 2*25 Hz for PAL)

Upon failure, the constructor and all member functions raise exception Zvbi.CaptureError, containing a string describing the cause. (Additional exception types may be used for specific error cases.)

The capture device is automatically closed when the Zvbi.Capture object is destroyed.

There are two different types of capture functions: The functions named read copy captured data into a bytes object (where the copying is usually done at device driver level). In contrast the functions named pull leave the data in internal buffers inside the capture context and just return a reference to this buffer. Usually this allows the device driver to avoid any copying, however not all devices support this (e.g. the Linux DVB driver does not support, i.e. there is no difference in performance between read and pull). Therefore you generally should prefer use of the pull functions; only when capturing raw data for processing by Python directly, prefer read_raw() as the data needs to be copied into a permanent buffer anyway.

If you do not need “raw” data (i.e. if you do not use the Zvbi.RawDec class, you should use pull_sliced() or read_sliced() instead of pull() or read() to avoid the overhead of returning raw data (which has high bandwidth). DVB devices will not return raw data regardless of the chosen interface.

Multithreading: The Zvbi.Capture, Zvbi.RawDec, Zvbi.ServiceDec and Zvbi.Search classes are thread-safe insofar as they allow running the capture loop (including raw decoder) and service decoder in one thread, and further event processing or a user-interface in another thread. The latter may interact with the capture/decoder thread via configuration and query interfaces. See examples/search-ttx.py for an example using multi-threading.

Zvbi.Capture.Dvb()

This static method creates and returns an instance of Zvbi.Capture for DVB devices.

cap = Zvbi.Capture.Dvb(dev, dvb_pid=0, trace=False)

Input parameters:

dev:Path of the device to open (for Linux usually /dev/dvb/adapter0/demux0)
dvb_pid:Specifies the number (PID) of a stream which contains VBI data, when the device is a DVB capture card. Else the parameter has no effect. If you omit this value, you need to configure it afterwards using Zvbi.Capture.dvb_filter(), otherwise there will be no reception.
trace:If this option is present and True, output of progress messages on sys.stderr is enabled.

Note the VBI PID value can often be derived from the PID for video in channels.conf by adding offsets in range 3 to 30. Alternatively you can look up the PID via Internet services such as <https://www.satindex.de/>.

Zvbi.Capture.Analog()

This static method creates and returns an instance of Zvbi.Capture for analog VBI devices (i.e. non-DVB devices). The method “auto-detects” the type of the given device by sequentially trying to access the device as “V4l2” (i.e. analog Linux video capture device) and “bktr” (i.e. FreeBSD analog BSD video capture device), in this order.

cap = Zvbi.Capture.Analog(dev, services, proxy=None,
                          strict=0, buffers=5, scanning=0, trace=False)

The device and service parameters are mandatory, all others are optional and keyword-only. The parameters have the following meaning:

dev:Path of the device to open (for Linux usually /dev/vbi0)
services:Is a bit-wise OR of VBI_SLICED_* symbols describing the data services to be decoded. See Zvbi.RawDec.add_services() for details. If you want to capture raw data only, set to VBI_SLICED_VBI_525, VBI_SLICED_VBI_625 or both. If this parameter is omitted, no services will be installed (this is not supported for BSD “bktr” drivers). You can do so later with Zvbi.Capture.update_services() (Note in this case the reset parameter to that function will have to be set to True.).
proxy:When present, this has to be a reference to an instance of class Zvbi.Proxy. The constructor will request start of capturing via the VBI proxy daemon instead of accessing the device directly. The following parameters are still applicable, but are passed to the daemon. The proxy does not support DVB devices. If the connection fails, the constructor will not attempt direct device access; this means the call shuld be repeated without the proxy parameter.
buffers:Number of device buffers for raw VBI data if the driver supports streaming. Use higher values if you cannot guarantee there is no latency on reading capture data (e.g. if your GUI runs in the same thread). Otherwise one bounce buffer is allocated for Zvbi.Capture.pull().
scanning:Indicates the current norm: 625 for PAL and 525 for NTSC; set to 0 if you don’t know (you should not attempt to query the device for the norm, as this parameter is only used for the ancient BSD “bktr” driver which don’t support video standard query ioctls.)
strict:The value can be 0, 1, or 2 for determining which services to allow for raw decoding. For details see Zvbi.RawDec.add_services().
trace:If True, enables output of progress messages on sys.stderr.

Whenever possible, the proxy should be used instead of opening analog devices directly, since it allows the user to start multiple VBI clients concurrently. When this function fails (usually because the user hasn’t started the proxy daemon) applications should automatically fall back to opening the device directly.

Example for using an analog source with auto-detection of a proxy:

opt_device = "/dev/vbi0"
opt_services = Zvbi.VBI_SLICED_TELETEXT_B
opt_strict = 0
opt_buf_count = 5
opt_verbose = False
try:
    proxy = Zvbi.Proxy(opt_device, appname="...", appflags=0, trace=opt_verbose)

    cap = Zvbi.Capture.Analog(opt_device, proxy=proxy,
                              services=opt_services, strict=opt_strict,
                              buffers=opt_buf_count, trace=opt_verbose)
except Zvbi.ProxyError, Zvbi.CaptureError:
    # try again without proxy
    cap = Zvbi.Capture.Analog(opt_device,
                              services=opt_services, strict=opt_strict,
                              buffers=opt_buf_count, trace=opt_verbose)

The first call of Zvbi.Capture() in the example establishes a new connection to a VBI proxy to open a VBI or DVB device for capturing. On side of the proxy daemon, the given device is opened and initialized, equivalently as it would be done locally. If the creation succeeds, and any of the requested services are available, capturing is started and all captured data is forwarded transparently to the client. See Zvbi.Proxy for details.

The second call of Zvbi.Capture.Analog() in the example creates a local capture context.

Zvbi.Capture.read_raw()

raw_buffer = cap.read_raw(timeout_ms)

Read a raw VBI frame from the capture device and return it within an object of type Zvbi.CaptureRawBuf. Please refer to the descripion of that class for details.

Parameter timeout_ms gives the limit for waiting for data in milliseconds; if no data arrives within the given time, the function raises exception Zvbi.CaptureTimeout. Exception Zvbi.CaptureError is raised upon error indications from the device. Note the function may fail if the device does not support reading data in raw format.

Note: it’s generally more efficient to use pull_raw() instead, as that may avoid having copying data into the new buffer allocated for each call of read_raw(). See also the description of read() below.

Zvbi.Capture.read_sliced()

sliced_buffer = cap.read_sliced(timeout_ms)

Captures VBI data from one video frame, “slices” the captured data samples for VBI lines of previously configured services, and returns the sliced data within an object of type Zvbi.CaptureSlicedBuf. Please refer to the descripion of that class for details.

Parameter timeout_ms gives the limit for waiting for data in milliseconds; if no data arrives within the given time, the function raises exception Zvbi.CaptureTimeout. Exception Zvbi.CaptureError is raised upon error indications from the device.

Zvbi.Capture.read()

raw_buffer, sliced_buffer = cap.read(timeout_ms)

This function is a combination of read_raw() and read_sliced(), i.e. reads a VBI frame from the capture context and returns both the raw data and the results of “slicing” the raw data. The results are returned in form of a tuple which contains firstly Zvbi.CaptureRawBuf and secondly an object of type Zvbi.CaptureSlicedBuf. Please refer to the descripion of these classes for details.

Some devices, such as DVB, may not support capturing raw VBI data. In such a case the first element of the result tuple is set to None.

Parameter timeout_ms gives the limit for waiting for data in milliseconds; if no data arrives within the given time, the function raises exception Zvbi.CaptureTimeout. Exception Zvbi.CaptureError is raised upon error indications from the device.

Note: Depending on the driver, captured raw data may have to be copied from the capture buffer into the given buffer (e.g. for V4L2 streams which use memory-mapped buffers.) It’s generally more efficient using one of the following pull interfaces. Also, unless you require raw data, it is even more efficient using pull_sliced() or read_sliced().

Zvbi.Capture.pull_raw()

raw_buffer = cap.pull_raw(timeout_ms)

Read a raw VBI frame from the capture context and return it within an object of type Zvbi.CaptureRawBuf. Please refer to the descripion of that class for details. Note: The content of the returned object remains valid only until the next call to this or any other pull function. Access to an invalidated buffer will raise exception ValueError

The returned raw_buffer can be passed to Zvbi.RawDec.decode(). If you need to process the data by Python code, use Zvbi.Capture.read_raw() instead.

Parameter timeout_ms gives the limit for waiting for data in milliseconds; if no data arrives within the given time, the function raises exception Zvbi.CaptureTimeout. Exception Zvbi.CaptureError is raised upon error indications from the device. Note the function may fail if the device does not support reading data in raw format.

Zvbi.Capture.pull_sliced()

sliced_buffer = cap.pull_sliced(timeout_ms)

Captures VBI data from one video frame, “slices” the captured data samples for VBI lines of previously configured services, and returns the sliced data within an object of type Zvbi.CaptureSlicedBuf. Please refer to the descripion of that class for details. Note: The content of the returned object remains valid only until the next call to this or any other capture function. Access to an invalidated buffer will raise exception ValueError

Usually the returned sliced_buffer is passed immediately Zvbi.ServiceDec.decode().

Parameter timeout_ms gives the limit for waiting for data in milliseconds; if no data arrives within the given time, the function raises exception Zvbi.CaptureTimeout. Exception Zvbi.CaptureError is raised upon error indications from the device.

Zvbi.Capture.pull()

raw_buffer, sliced_buffer = cap.pull(timeout_ms)

This function is a combination of pull_raw() and pull_sliced(), i.e. reads a VBI frame from the capture context and returns both the raw data and the results of “slicing” the raw data. The results are returned in form of a tuple which contains firstly Zvbi.CaptureRawBuf and secondly an object of type Zvbi.CaptureSlicedBuf. Please refer to the descripion of these classes for details.

Some devices, such as DVB, may not support capturing raw VBI data. In such a case the first element of the result tuple is set to None.

Note: The content of the returned objects remains valid only until the next call to this or any other pull function. Access to an invalidated buffer will raise exception ValueError

Parameter timeout_ms gives the limit for waiting for data in milliseconds; if no data arrives within the given time, the function raises exception Zvbi.CaptureTimeout. Exception Zvbi.CaptureError is raised upon error indications from the device.

Zvbi.Capture.parameters()

params = cap.parameters()

Returns an instance of class Zvbi.RawParams describing the physical parameters of the VBI source. See the description of that class for a description of attributes.

Modifying the attributes of the returned object has no effect on the Zvbi.Capture instance. To control raw decoding, pass the returned (and possibly modified) parameters when instantiating class Zvbi.RawDec and then use that class for decoding instead of the sliced_buffer output of the Zvbi.Capture member functions.

Note: For DVB devices this function only returns dummy parameters, as no “raw decoding” is performed in this case. In particular the sampling format will be zero, which is an invalid value, so this can be used for detecting this case.

Zvbi.Capture.update_services()

services = cap.update_services(services, reset=True, commit=True, strict=0)

Not applicable to DVB: Adds and/or removes one or more services to an already initialized capture context. Can be used to dynamically change the set of active services.

Internally the function will restart parameter negotiation with the VBI device driver and then call add_services() on the internal raw decoder context. You may set reset to rebuild your service mask from scratch. Note that the number of VBI lines may change with this call even if the function fails and raises an exception.

Result: The function returns a bit-mask of supported services among those requested (not including previously added services), 0 upon errors.

services:An integer consisting of a bit-wise OR of one or more VBI_SLICED_* constants describing the data services to be decoded.
reset:When this optional parameter is set True, the method clears all previous services before adding new ones (by invoking Zvbi.RawDec.reset() at the appropriate time.) When False, new services are in addition to previously configured services.
commit:When this optional parameter is set True, the method applies all previously added services to the device. Set this to False when doing multiple consecutive calls of this function; then commit should be set only for the last call. Reading data cannot continue before changes were committed (because capturing has to be suspended to allow resizing the VBI image.) Note this flag is ignored when using the VBI proxy.
strict:The meaning of this optional parameter is as described for Zvbi.RawDec.add_services(), as that function is used internally by libzvbi. The parameter defaults to 0.

The function returns an integer value with bit-wise OR of VBI_SLICED_* services actually decodable.

Zvbi.Capture.fd()

cap.fd()

This function returns the file descriptor used to read from the capture context’s device. Note when using the proxy this will not be the actual device, but a socket instead. Some devices may also return -1 if they don’t have anything similar, or upon internal errors.

This function is equivalent to fileno() for Pythone file objects.

The descriptor is intended be used in a select(2) syscall. The application especially must not read or write from it and must never close the handle (instead destroy the capture context to free the device.) In other words, the file handle is intended to allow capturing asynchronously in the background; The handle will become readable when new data is available.

Zvbi.Capture.get_scanning()

scanning = cap.get_scanning()

This function is intended to allow the application to check for asynchronous norm changes, i.e. by a different application using the same device. The function queries the capture device for the current norm and returns value 625 for PAL/SECAM norms, 525 for NTSC; 0 if unknown, -1 on error.

Zvbi.Capture.flush()

cap.flush()

After a channel change this function should be used to discard all VBI data in intermediate buffers which may still originate from the previous TV channel. The function returns None.

Zvbi.Capture.get_fd_flags()

flags = cap.get_fd_flags()

Returns properties of the capture context’s device. The result is an integer value containing a bit-wise OR of one or more of the following constants:

VBI_FD_HAS_SELECT:
Is set when select(2) can be used on the file handle returned by cap.fd() to wait for new data on the capture device file handle.
VBI_FD_HAS_MMAP:
Is set when the capture device supports “user-space DMA”. In this case it’s more efficient to use one of the “pull” functions to read raw data because otherwise the data has to be copied once more into the passed buffer.
VBI_FD_IS_DEVICE:
Is not set when the capture device file handle is not the actual device. In this case it can only be used for select(2) and not for ioctl(2)

Zvbi.Capture.dvb_filter()

cap.dvb_filter(pid)

Programs the DVB device transport stream demultiplexer to filter out PES packets with the given pid. The meaning of the parameter is equivalent to the pid parameter to the constructor.

Zvbi.Capture.dvb_last_pts()

cap.dvb_last_pts()

Returns the presentation time stamp (33 bits) associated with the data last read from the capture context. The PTS refers to the first sliced VBI line, not the last packet containing data of that frame.

Note timestamps returned by VBI capture read functions contain the sampling time of the data, that is the time at which the packet containing the first sliced line arrived.

Class Zvbi.CaptureRawBuf

For reasons of efficiency, captured data is not immediately converted into Python structures. Instead class Zvbi.Capture returns an instance of this class for raw data, which encapsulates both the data and related attributes.

Usually this object is simply forwarded to Zvbi.RawDec.decode(); in this case there is very little overhead for managing the object by Python. If you want to process the data directly within Python, you can access it in the following ways:

  1. Subscripting the object allows retrieving the data byte-by-byte. The standard len operator indicates the number of bytes in the buffer. Example:

    raw_buf = cap.read_raw(2000)
    for x in range(0, par.bytes_per_line):
        y = raw_buf[x]
    
  2. In any context that expects a bytes-like object, the data content is accessed efficiently via direct access at C level. Example:

    raw_buf = cap.read_raw(2000)
    arr = bytes(raw_buf)
    
  3. The timestamp can be retrieved via attribute timestamp. The value indicates when the data was captured in form of the number of seconds and fractions since 1970-01-01 00:00; the value is of type float.

Note the raw buffer contains all captured VBI lines consecutively in a one-dimensional array. Length of a line can be queried from the capture context using Zvbi.Capture.parameters(): attribute bytes_per_line.

Note class Zvbi.CaptureRawBuf internally uses different memory management depending on use of read or pull capturing methods. This difference is not visible at the interface. However data retrieved by pull interfaces is valid only until the next call of a capture function on the same object.

Class Zvbi.CaptureSlicedBuf

For reasons of efficiency, captured data is not immediately converted into Python structures. Instead class Zvbi.Capture returns an instance of this class for sliced data, which encapsulates data of all sliced lines and related attributes.

Usually this object is simply forwarded to Zvbi.ServiceDec.decode(); in this case there is very little overhead for managing the object by Python. If you want to process the data directly within Python, you can access it in the following ways:

  1. Subscripting the object allows retrieving sliced lines one-by-one. The standard len operator indicates the number of bytes in the buffer.
  2. In any context that expects an iterator, the function delivered sliced lines consecutively.
  3. The timestamp can be retrieved via attribute timestamp. The value indicates when the data was captured in form of the number of seconds and fractions since 1970-01-01 00:00; the value is of type float.

Example:

sliced_buffer = cap.pull(2000)
for data, ident, line_no in sliced_buffer:
    ...

Iteration returns for each sliced line a named tuple of type Zvbi.CaptureSlicedLine, holding the following three elements:

  1. data: Sliced data from the respective line in the sliced buffer. The structure of the contained data depends on the kind of data in the VBI line as identified by the following attribute. (For example, for VBI_SLICED_TELETEXT_B 42 bytes are used; first two bytes contain Hamming-8/4 encoded magazine and packet number, which determine the encoding and semantics of the rest of the data.)
  2. ident: One or more ‘VBI_SLICED_*’ symbols (bit-wise OR), identifying the type of data service. Multiple identifiers may occur e.g. for VBI_SLICED_TELETEXT_B.
  3. line_no: Source line number according to the ITU-R line numbering scheme, or 0 if the exact line number is unknown. This number is required by the service decoder.

Note class Zvbi.CaptureSlicedBuf internally uses different memory management depending on use of read or pull capturing methods. This difference is not visible at the interface. However data retrieved by pull interfaces is valid only until the next call of a capture function on the same object.

Class Zvbi.RawDec

The functions in this section allow converting raw VBI samples (i.e. a digitized image of the transmitted analog waveform) to payload data bytes. This class is not applicable to DVB.

These functions are used internally by libzvbi if you use the slicer functions of the capture object (e.g. pull_sliced()). This class is useful only when capturing raw data only (e.g. pull_raw()), allowing your application to take full control of slicing raw data.

After instantiating and configuring the class, the actual work is done by Zvbi.RawDec.decode(), which you’d call on the data of each captured VBI frame.

Example control flow:

cap = Zvbi.Capture("/dev/vbi0", services=VBI_SLICED_CAPTION_525)

vtdec = Zvbi.ServiceDec()
vtdec.event_handler_register(Zvbi.VBI_EVENT_TTX_PAGE, pg_handler)

raw_dec = Zvbi.RawDec(cap)
raw_dec.add_services(opt_services, opt_strict)

while True:
    raw_buffer = cap.pull_raw(opt_timeout)

    sliced_buffer = raw_dec.decode(raw_buffer)

    vtdec.decode(sliced_buffer)

Constructor Zvbi.RawDec()

raw_dec = Zvbi.RawDec(ref)

Creates and initializes a new raw decoder context. Parameter ref specifies the physical parameters of the raw VBI image, such as the sampling rate, number of VBI lines etc. The parameter can be either a reference to a capture context (Zvbi.Capture) or raw capture parameters of type Zvbi.RawParams.

A properly initialized instance of Zvbi.RawParams can be obtained either via method Zvbi.Capture.parameters() or Zvbi.RawDec.parameters(). In case an instance of Zvbi.Capture is used as parameter to the constructor, decoder parameters are retrieved internally using Zvbi.Capture.parameters() for convenience.

See description of class Zvbi.RawParams for a list of sampling parameters.

Zvbi.RawDec.parameters()

services, max_rate, par = Zvbi.RawDec.parameters(services, scanning)

This is a static member function. The function calculates the sampling parameters required to receive and decode the requested data services. This function can be used to initialize hardware parameters prior to calling Zvbi.RawDec.add_services(). The returned sampling format is fixed to VBI_PIXFMT_YUV420, and attribute bytes_per_line is set to a reasonable minimum.

Input parameters:

services:This integer value contains a bit-wise OR of VBI_SLICED_* constants. Here (and only here) you can add VBI_SLICED_VBI_625 or VBI_SLICED_VBI_525 to include all VBI scan lines in the calculated sampling parameters.
scanning:If scanning is set to 525 only NTSC services are accepted; if set to 625 only PAL/SECAM services are accepted. When scanning is 0, the norm is determined from the requested services; an ambiguous set will result in undefined behavior.

The function returns a tuple containing the following three results:

  1. An integer value containing a bit-wise OR of a sub-set of VBI_SLICED_* constants describing the data services covered by the calculated sampling parameters returned in href. This excludes services the libzvbi raw decoder cannot decode assuming the specified physical parameters.
  2. Calculated maximum rate, which is to the highest data bit rate in Hz of all services requested (The sampling rate should be at least twice as high; attribute sampling_rate will be set by libzvbi to a more reasonable value of 27 MHz derived from ITU-R Rec. 601.)
  3. An instance of class Zvbi.RawParams which contains the calculated sampling parameters. The content is described as for function Zvbi.Capture.parameters()

Zvbi.RawDec.reset()

raw_dec.reset()

Resets the raw decoder context. This removes all previously added services to be decoded (if any) but does not touch the sampling parameters. You are free to change the sampling parameters after calling this.

Zvbi.RawDec.add_services()

services = raw_dec.add_services(services, strict)

After you initialized the sampling parameters in raw decoder context (according to the abilities of your VBI device), this function adds one or more data services to be decoded. The libzvbi raw VBI decoder can decode up to eight data services in parallel. You can call this function while already decoding, it does not change sampling parameters and you must not change them either after calling this.

Input parameters:

services:This integer value contains a bit-wise OR of VBI_SLICED_* constants. (see also description of the parameters function above.)
strict:The parameter can be set to 0, 1 or 2 for requesting requests loose, reliable or strict matching of sampling parameters respectively. For example if the data service requires knowledge of line numbers while they are not known, value 0 will accept the service (which may work if the scan lines are populated in a non-confusing way) but values 1 or 2 will not. If the data service may use more lines than are sampled, value 1 will still accept but value 2 will not. If unsure, set to 1.

The function returns an integer value containing a bit-wise OR of VBI_SLICED_* constants describing the data services that actually can be decoded. This excludes those services not decodable given sampling parameters of the raw decoder context.

Zvbi.RawDec.check_services()

services = raw_dec.check_services(services, strict=0)

Check and return which of the given services can be decoded with current physical parameters at a given strictness level.

See Zvbi.RawDec.add_services() for details on parameter semantics.

Zvbi.RawDec.remove_services()

services = raw_dec.remove_services(services)

Removes one or more data services given in input parameter services to be decoded from the raw decoder context. This function can be called at any time and does not touch sampling parameters stored in the context.

Returns a set of VBI_SLICED_* constants describing the remaining data services that will be decoded.

Zvbi.RawDec.resize()

raw_dec.resize(start_a, count_a, start_b, count_b)

Grows or shrinks the internal state arrays for VBI geometry changes. Returns None.

Zvbi.RawDec.decode()

sliced_buffer = raw_dec.decode(raw_buffer)

This is the main service offered by the raw decoder: Decodes a raw VBI image given in raw_buffer, consisting of several scan lines of raw VBI data. The output is sorted by line number.

The input parameter raw_buffer can by any bytes-like object that contains at least the number of bytes required by the capture geometry (which is par.bytes_per_line * (par.count_a + par.count_b), where par is the used instance of Zvbi.RawParams). Usually the parameter is an object of type Zvbi.CaptureRawBuf as returned by the pull kind of Zvbi.Capture methods (e.g. Zvbi.Capture.pull_raw()).

Return value is a buffer of type Zvbi.CaptureSlicedBuf, containing the sliced output data. (Please refer to the descripion of that class for details.) Upon errors the function raises exception Zvbi.RawDecError.

Usually the sliced buffer result is forwarded to Zvbi.ServiceDec.decode(). (See general description Zvbi.RawDec for an example control flow.) Note in that case the buffer needs to be forwarded even if zero lines were sliced; refer to description of the method for details.

Note this function attempts to learn which lines carry which data service, or none, to speed up decoding. Hence you must use different raw decoder contexts for different devices.

Class Zvbi.RawParams

This is a simple parameter container, encapsulating parameters of raw captured data (i.e. raw_buffer result produced by methods Zvbi.Capture.read_raw() et.al.), or for instantiating a raw decoder of class Zvbi.RawDec.

The class has the following attributes:

scanning:
Either 525 (M/NTSC, M/PAL) or 625 (PAL, SECAM), describing the scan line system all line numbers refer to.
sampling_format:
Format of the raw VBI data (one of the VBI_PIXFMT_* constants, e.g. VBI_PIXFMT_YUV420; see enum vbi_pixfmt)
sampling_rate:
Sampling rate in Hz (i.e. the number of samples or pixels captured per second.)
bytes_per_line:
Number of samples or pixels captured per scan line, in bytes. This determines the raw VBI image width and you want it large enough to cover all data transmitted in the line (with headroom).
offset:
The distance from 0H (leading edge hsync, half amplitude point) to the first sample (pixel) captured, in samples (pixels). You want an offset small enough not to miss the start of the data transmitted.
start_a, start_b:
First scan line to be captured in the first and second half-frame respectively. Numbering is according to the ITU-R line numbering scheme (see vbi_sliced). Set to zero if the exact line number isn’t known.
count_a, count_b:
Number of scan lines captured in the first and second half-frame respectively. This can be zero if only data from one field is required. The sum count_a + count_b determines the raw VBI image height.
interlaced:
In the raw vbi image, normally all lines of the second field are supposed to follow all lines of the first field. When this flag is set, the scan lines of first and second field will be interleaved in memory. This implies count_a and count_b are equal.
synchronous:
Fields must be stored in temporal order, i. e. as the lines have been captured. It is assumed that the first field is also stored first in memory, however if the hardware cannot reliable distinguish fields this flag shall be cleared, which disables decoding of data services depending on the field number.

Class Zvbi.Proxy

This class is used for receiving sliced or raw data from a VBI proxy daemon. Using the daemon instead of capturing directly from a VBI device allows multiple applications to capture concurrently, e.g. to decode multiple data services.

Note the proxy is only useful if all VBI applications use it. For applications that do not support the proxy directly, there is a library that can overload calls to C library, so that access to the VBI device is redirected transparently through the daemon. Details are described in the manual zvbi-chains(1). In principle it’s as easy as as prepending zvbi-chains -dev /dev/vbi0 to the application command line.

See examples/proxy-test.py for examples how to use these functions.

Constructor Zvbi.Proxy

proxy = Zvbi.Proxy(dev, appname, appflags=0, trace=False)

cap = Zvbi.Capture( ..., proxy=proxy )

Creates and returns a new proxy context, or raises exception Zvbi.ProxyError upon error. (Note in reality this call will always succeed, since a connection to the proxy daemon isn’t established until you actually open a capture context when instantiating Zvbi.Capture with a reference to Zvbi.Proxy.)

Parameters:

dev:Specifies the name of the device to open, usually one of /dev/vbi0 and up. The device name has to match that used by the deamon, else the daemon will refuse the connection, so that Zvbi.Capture calls back to direct access to the device.
client_name:Names the client application, typically identical to sys.argv[0] (without the path though). Can be used by the proxy daemon for fine-tuning scheduling, or for presenting the user with a list of currently connected applications.
flags:Contains zero or a bit-wise OR of VBI_PROXY_CLIENT_* flags.
trace:If True, enables output of progress messages on sys.stderr.

Proxy.set_callback()

proxy.set_callback(callback=None, user_data=None)

Installs or removes a callback function for asynchronous messages (e.g. channel change notifications.) Input parameters are a callable object callback and an optional object user_data which is passed through to the callback function unchanged. Call without any arguments to remove the callback again.

The callback function will receive the event mask (i.e. one of the constants VBI_PROXY_EV_* in the following list) and, if provided, user_data as parameters.

  • VBI_PROXY_EV_CHN_GRANTED: The channel control token was granted, so that the client may now change the channel. Note: the client should return the token after the channel change was completed (the channel will still remain reserved for the requested time.)
  • VBI_PROXY_EV_CHN_CHANGED: The channel (e.g. TV tuner frequency) was changed by another proxy client.
  • VBI_PROXY_EV_NORM_CHANGED: The TV norm was changed by another client (in a way which affects VBI, e.g. changes between PAL/SECAM are ignored.) The client must update its services, else no data will be forwarded by the proxy until the norm is changed back.
  • VBI_PROXY_EV_CHN_RECLAIMED: The proxy daemon requests to return the channel control token. The client is no longer allowed to switch the channel and must immediately reply with a channel notification with flag VBI_PROXY_CHN_TOKEN
  • VBI_PROXY_EV_NONE: No news.

Since the proxy client has no “life” on it’s own (i.e. it’s not using an internal thread or process) callbacks will only occur from inside other proxy client or capture function calls. The client’s capture device file descriptor will become readable when an asynchronous message has arrived from the daemon. Typically the application then will call read to obtain sliced data and the callback will be invoked from inside the read function. Usually in this case the read call will return zero, i.e. indicate an timeout since no actual sliced data has arrived.

Note for channel requests the callback to grant channel control may be invoked before the request function returns. Note you can call any interface function from inside the callback, including the destroy operator.

Proxy.get_driver_api()

api = proxy.get_driver_api()

This method can be used for querying which driver is behind the device which is currently opened by the VBI proxy daemon. Applications which only use libzvbi’s capture API need not care about this. The information is relevant to applications which need to switch TV channels or norms.

Returns an identifier describing which API is used on server side, i.e. one of the symbols VBI_API_V4L1, VBI_API_V4L2, VBI_API_BKTR or VBI_API_UNKNOWN upon error. The function will fail if the client is currently not connected to the proxy daemon, i.e. VBI capture has to be started first.

Proxy.channel_request()

Proxy.channel_request(chn_prio, request_chn=False, allow_suspend=FALSE,
                      sub_prio=-1, min_duration=-1, exp_duration=-1)

This method is used to request permission to switch channels or norm. Since the VBI device can be shared with other proxy clients, clients should wait for permission, so that the proxy daemon can fairly schedule channel requests.

Scheduling differs at the 3 priority levels. For available priority levels for chn_prio see constants VBI_CHN_PRIO_*. At background level channel changes are coordinated by introduction of a virtual token: only the one client which holds the token is allowed to switch channels. The daemon will wait for the token to be returned before it’s granted to another client. This way conflicting channel changes are avoided. At the upper levels the latest request always wins. To avoid interference, the application still might wait until it gets indicated that the token has been returned to the daemon.

The token may be granted right away or at a later time, e.g. when it has to be reclaimed from another client first, or if there are other clients with higher priority. If a callback has been registered, the respective function will be invoked when the token arrives; otherwise proxy.has_channel_control() can be used to poll for it.

Input parameters:

chn_prio:

This mandatory parameter sets the priority. The priority should always be set if default VBI_CHN_PRIO_INTERACTIVE is not needed, to avoid blocking other applications.

request_chn:

Set this parameter to True if your application needs to switch channels. Inversely, for only setting the chn_prio level to VBI_CHN_PRIO_BACKGROUND without requesting a channel, set this parameter to False.

Note the following parameters have no effect when this parameter is set to False. Inversely, when this parameter is set, the following parameters are mandatory.

allow_suspend:

Set to FALSE if your capture client needs an atomic time slice (i.e. would need to restart capturing from the beginning it it was interrupted.)

sub_prio:

Sub-priority for channel scheduling at “background” priority. You can use aribtrary values in the range 0 … 256, but as this value is only meaningful in relation to priorities used by other clients, you should stick to the scale defined by VBI_CHN_SUBPRIO.

min_duration:

Minimum time slice your capture client requires. This value is used when multiple clients have the same sub-priority to give all clients channel control in a round-robin manner.

exp_duration:

Expected duration of use of that channel.

Zvbi.Proxy.channel_notify()

proxy.channel_notify(notify_flags [, scanning])

Sends channel control request to proxy daemon. Parameter notify_flags is an OR of one or more of the following constants:

  • VBI_PROXY_CHN_RELEASE: Revoke a previous channel request and return the channel switch token to the daemon.
  • VBI_PROXY_CHN_TOKEN: Return the channel token to the daemon without releasing the channel; This should always be done when the channel switch has been completed to allow faster scheduling in the daemon (i.e. the daemon can grant the token to a different client without having to reclaim it first.)
  • VBI_PROXY_CHN_FLUSH: Indicate that the channel was changed and VBI buffer queue must be flushed; Should be called as fast as possible after the channel and/or norm was changed. Note this affects other clients’ capturing too, so use with care. Other clients will be informed about this change by a channel change indication.
  • VBI_PROXY_CHN_NORM: Indicate a norm change. The new norm should be supplied in the scanning parameter in case the daemon is not able to determine it from the device directly.
  • VBI_PROXY_CHN_FAIL: Indicate that the client failed to switch the channel because the device was busy. Used to notify the channel scheduler that the current time slice cannot be used by the client. If the client isn’t able to schedule periodic re-attempts it should also return the token.

Proxy.channel_suspend()

proxy.channel_suspend(cmd)

Request to temporarily suspend capturing (if cmd is VBI_PROXY_SUSPEND_START) or revoke a suspension (if cmd equals VBI_PROXY_SUSPEND_STOP.)

Zvbi.Proxy.device_ioctl()

proxy.device_ioctl(request, arg)

This method allows manipulating parameters of the underlying VBI device. Not all ioctls are allowed here. It’s mainly intended to be used for channel enumeration and channel/norm changes. The request codes and parameters are the same as for the actual device. The caller has to query the driver API via proxy.get_driver_api() first and use the respective ioctl codes, same as if the device would be used directly.

Parameters and results are as documented for the ioctl(2) system interface (see the respective UNIX manual page for details). Therefore parameter request is the first parameter to ioctl() and the arg byte buffer contains the data structure that the second parameter to ioctl points to. Use struct.pack to build the argument buffer. Example:

# get current config of the selected channel
vchan = struct.pack("=i32xiLhh", channel, 0, 0, 0, norm);
vchan_result = proxy.device_ioctl(VIDIOCGCHAN, vchan);

After the call, the data passed in arg may be modified by ioctl operations which return data. Therefore the the proxy returns an updated copy of the input buffer, which is returned by the function in form of a bytes object.

Upon failure of the I/O operation, the function raises exception OSError and includes the errno error code and string as usual. The same exception is also used for non-device related failures, as the proxy response currently does not allow distinguishing them. In particular error code EBUSY may indicate that the application is currently not allowed to control the device.

Proxy.get_channel_desc()

scanning, granted = proxy.get_channel_desc()

Retrieve info sent by the proxy daemon in a channel change indication. The function returns a tuple with two elements: scanning value (625 indicating PAL, or 525 indicating NTSC, or 0 if unknown) and a boolean indicator if the change request was granted.

Proxy.has_channel_control()

Returns True if client is currently allowed to switch channels, else False.

Class Zvbi.ServiceDec

This class is used for high level decoding of sliced data received from an instance of the Zvbi.Capture class or the raw decoder (Zvbi.RawDec). Decoded data is stored in caches for each service. The application can be notified via callbacks about various events. Various interfaces allow extracting decoded data from the caches.

Constructor Zvbi.ServiceDec()

vt = Zvbi.ServiceDec()
vt.event_handler_register(Zvbi.VBI_EVENT_TTX_PAGE, pg_handler)

Creates and returns a new data service decoder instance. The constructor does not take any parameters. However: The type of data services to be decoded is determined by the type of installed callbacks. Hence for the class to do any actual decoding, you must install at least one callback using Zvbi.ServiceDec.event_handler_register() after construction.

Zvbi.ServiceDec.decode()

while True:
  sliced_buffer = cap.pull_sliced(2000)

  vt.decode(sliced_buffer)

This is the main service offered by the data service decoder: The method decodes sliced VBI data from a video frame, updates the decoder state and invokes callback functions for registered events. Note this function has to be called for each received frame, even if it did not contain any sliced data, because the decoder otherwise assumes a frame was lost and may reset decoding state.

Input parameter sliced_buffer has to be an instance of class Zvbi.CaptureSlicedBuf returned by read and pull methods of the Zvbi.Capture class. The function always returns None. As a side-effect, registered callbacks are invoked.

Zvbi.ServiceDec.decode_bytes()

vt.decode_bytes(data, n_lines, timestamp)

This method is an alternate interface to decode(), allowing to insert data from external sources, such as sliced data stored in a file. Thus the discrete method parameters replace attributes otherwise stored in Zvbi.CaptureSlicedBuf:

data:

Is a bytes-like object containing concatenated sliced data lines. Each line is a binary packed format “=LL56c”, containing the service ID VBI_SLICED_*, the number of the (analog) line from where the line was captured, followed by 56 bytes slicer output data.

n_lines:

Gives the number of valid lines in the sliced data buffer. The value must be between 0 and len(data) / (2*4+56) (i.e. the maximum number of records in the given data buffer)

timestamp:

This should be a copy of the timestamp value returned by the read and pull capture functions within Zvbi.CaptureSlicedBuf and Zvbi.CaptureRawBuf class.

The timestamps are expected to advance by 1/30 to 1/25 seconds for each call to this function. Different steps will be interpreted as dropped frames, which starts a re-synchronization cycle, eventually a channel switch may be assumed which resets even more decoder state. So this function must be called even if a frame did not contain any useful data (i.e. with parameter n_lines equal 0)

Zvbi.ServiceDec.channel_switched()

vt.channel_switched( [nuid] )

Call this after switching away from the channel (RF channel, video input line, … - i.e. after switching the network) from which this context used to receive VBI data, to reset the decoding context accordingly. This includes deletion of all cached Teletext and Closed Caption pages from the cache. Optional parameter nuid is currently unused by libzvbi and defaults to zero.

The decoder attempts to detect channel switches automatically, but this does not work reliably, especially when not receiving and decoding Teletext or VPS (since only these usually transmit network identifiers frequently enough.)

Note the reset is not executed until the next frame is about to be decoded, so you may still receive “old” events after calling this. You may also receive blank events (e. g. unknown network, unknown aspect ratio) revoking a previously sent event, until new information becomes available.

Zvbi.ServiceDec.classify_page()

(type, subno, lang) = vt.classify_page(pgno)

This function queries information about the named page. The return value is a tuple consisting of three scalars: page number, sub-page number, and language Their meaning depends on the data service to which the given page belongs:

For Closed Caption pages (pgno value in range 1 … 8) subno will always be zero, language set or an empty string. type will be VBI_SUBTITLE_PAGE for page 1 … 4 (Closed Caption channel 1 … 4), VBI_NORMAL_PAGE for page 5 … 8 (Text channel 1 … 4), or VBI_NO_PAGE if no data is currently transmitted on the channel.

For Teletext pages (pgno in range hex 0x100 … 0x8FF) subno returns the highest sub-page number used. Note this number can be larger (but not smaller) than the number of sub-pages actually received and cached. Still there is no guarantee the advertised sub-pages will ever appear or stay in cache. Special value 0 means the given page is a “single page” without alternate sub-pages. (Hence value 1 will never be used.) language currently returns the language of subtitle pages, or an empty string if unknown or the page is not classified as VBI_SUBTITLE_PAGE.

Note: The information returned by this function is volatile: When more information becomes available, or when pages are modified (e. g. activation of subtitles, news updates, program related pages) sub-page numbers can increase or page types and languages can change.

Zvbi.ServiceDec.set_brightness()

vt.set_brightness(brightness)

Change brightness of text pages, this affects the color palette of pages fetched with fetch_vt_page() and fetch_cc_page(). Parameter brightness is in range 0 … 255, where 0 is darkest, 255 brightest. Brightness value 128 is default.

Zvbi.ServiceDec.set_contrast()

vt.set_contrast(contrast)

Change contrast of text pages, this affects the color palette of pages fetched with vt.fetch_vt_page() and vt.fetch_cc_page(). Parameter contrast is in range -128 to 127, where -128 is inverse, 127 maximum. Contrast value 64 is default.

Zvbi.ServiceDec.teletext_set_default_region()

vt.teletext_set_default_region(default_region)

The original Teletext specification distinguished between eight national character sets. When more countries started to broadcast Teletext the three bit character set id was locally redefined and later extended to seven bits grouping the regional variants. Since some stations still transmit only the legacy three bit id and we don’t ship regional variants of this decoder as TV manufacturers do, this function can be used to set a default for the extended bits. The “factory default” is 16.

Parameter default_region is a value between 0 … 80, index into the Teletext character set table according to ETS 300 706, Section 15 (or libzvbi source file lang.c). The three last significant bits will be replaced.

Zvbi.ServiceDec.fetch_vt_page()

with vt.fetch_vt_page(pgno, [subno],
                      max_level=Zvbi.VBI_WST_LEVEL_3p5,
                      display_rows=25,
                      navigation=True) as pg:
    # ... process page object 'pg'

Fetches a Teletext page designated by parameters pgno and optionally subno from the cache, formats and returns it as an instance of Zvbi.Page. The object can then be used to extract page content, or be passed to the various libzvbi methods working on page objects, such as the export functions.

The function raises exception ServiceDecError if the page is not cached or could not be formatted for other reasons, for instance is a data page not intended for display. Level 2.5/3.5 pages which could not be formatted e. g. due to referencing data pages not in cache are formatted at a lower level.

Input parameters:

page:Teletext page number. Not the number is hexadecimal, which means to retrieve text page “100”, pass number 0x100. Teletext also allows hexadecimal page numbers (sometimes used for transmitting hidden data), so allowed is the full range of 0x100 to 0x8FF.
subno:Defaults to VBI_ANY_SUBNO, which means the newest sub-page of the given page is returned. Else this is a sub-page number in range 0 to 0x3F7E.
max_level:Is one of the VBI_WST_LEVEL_* constants and specifies the Teletext implementation level to use for formatting.
display_rows:Limits rendering to the given number of rows (i.e. row 0 … display_rows - 1) In practice, useful values are 1 (format the page header row only) or 25 (complete page).
navigation:This boolean parameter can be used to skip parsing the page for navigation links to save formatting time.

Although safe to do, this function is not supposed to be called from an event handler since rendering may block decoding for extended periods of time.

Note: The returned object must be deleted to release resources which are locked internally in the library during the fetch. Page objects support Python’s “Context Manager” protocol to allow doing this easily using the “with” statement. See also the description of Zvbi.Page.

Zvbi.ServiceDec.fetch_cc_page()

pg = vt.fetch_cc_page(pgno, reset=False)

Fetches a Closed Caption page designated by pgno from the cache, formats and returns it and as an object of type Zvbi.Page. The function raises exception ServiceDecError upon errors.

Closed Caption pages are transmitted basically in two modes: at once and character by character (“roll-up” mode). Either way you get a snapshot of the page as it should appear on screen at the present time.

With Zvbi.ServiceDec.event_handler_register() you can request a VBI_EVENT_CAPTION event to be notified about pending changes (in case of “roll-up” mode that is with each new word received) and the “dirty” attribute provided by Zvbi.Page.get_page_dirty_range() will mark the lines actually in need of updates, for speeding-up rendering.

If the reset parameter is omitted or set to True, the page dirty flags in the cached paged are reset after fetching. Pass False only if you plan to call this function again to update other displays.

Although safe to do, this function is not supposed to be called from an event handler, since rendering may block decoding for extended periods of time.

Note: The returned object must be deleted to release resources which are locked internally in the library during the fetch. Page objects support Python’s “Context Manager” protocol to allow doing this easily using the “with” statement. See the description of Zvbi.Page for an example.

Zvbi.ServiceDec.page_title()

title = vt.page_title(pgno, [subno])

The function makes an effort to deduce a page title to be used in bookmarks or similar purposes for the page specified by parameters pgno and subno. The title is mainly derived from navigation data on the given page.

As usual, parameter subno defaults to VBI_ANY_SUBNO, which means the newest sub-page of the given page is used. The function raises exception ServiceDecError upon errors.

Event handling

Typically the transmission of VBI data elements like a Teletext or Closed Caption page spans several VBI lines or even video frames. So internally the data service decoder maintains caches accumulating data. When a page or other object is complete it calls the respective event handler to notify the application.

Clients can register any number of handlers needed, also different handlers for the same event. They will be called by the Zvbi.ServiceDec.decode() function in the order in which they were registered. Since decoding is stopped while in the callback, the handlers should return as soon as possible.

The handler function receives two parameters: First is the event type (i.e. one of the VBI_EVENT_* constants kisted below), second a named tuple describing the event. The type and contents of the second parameter depends on the event type. The following event types are defined:

VBI_EVENT_NONE:
No event. Second callback parameter is None.
VBI_EVENT_CLOSE:
The vbi decoding context is about to be closed. This event is sent when the decoder object is destroyed and can be used to clean up event handlers. Second callback parameter is None.
VBI_EVENT_TTX_PAGE:

The vbi decoder received and cached another Teletext page. For this type the second callback function parameter has type Zvbi.EventTtx with the following elements:

The received page is designated by ev.pgno and ev.subno.

ev.roll_header flags the page header as suitable for rolling page numbers, e. g. excluding pages transmitted out of order. The ev.header_update flag is set when the header, excluding the page number and real time clock, changed since the last VBI_EVENT_TTX_PAGE evemt. Note this may happen at midnight when the date string changes. The ev.clock_update flag is set when the real time clock changed since the last VBI_EVENT_TTX_PAGE (that is at most once per second). They are both set at the first VBI_EVENT_TTX_PAGE sent and unset while the received header or clock field is corrupted.

If any of the roll_header, header_update or clock_update flags are set, ev.raw_header contains the raw header data (40 bytes). ev.pn_offset will be the offset (0 … 37) of the three-digit page number in the raw or formatted header. Always call vt.fetch_vt_page() for proper translation of national characters and character attributes; the raw header is only provided here as a means to quickly detect changes.

VBI_EVENT_CAPTION:

A Closed Caption page has changed and needs visual update. For this type the second callback function parameter has type Zvbi.EventCaption with a single element ev.pgno, which indicates the “CC channel” of the received page.

When the client is monitoring this page, the expected action is to call vt.fetch_cc_page(). To speed up rendering, more detailed update information can be queried via Zvbi.Page.get_page_dirty_range(). (Note when the page is fetched afterward, the contents will be a snapshot of the status at fetch time and not event time, i.e. the “dirty” flags accumulate all changes since the last fetch.)

VBI_EVENT_NETWORK:

Some station/network identifier has been received or is no longer transmitted (in the latter case all values are zero, e.g. after a channel switch). The event will not repeat until a different identifier has been received and confirmed. (Note: VPS/TTX and XDS will not combine in real life, feeding the decoder with artificial data can confuse the logic.)

For this type the second callback function parameter has type Zvbi.EventNetwork with the following elements:

  1. nuid: Network identifier
  2. name: Name of the network from XDS or from a table lookup of CNIs in Teletext packet 8/30 or VPS
  3. call: Network call letters, from XDS (i.e. closed-caption, US only), else empty
  4. tape_delay: Tape delay in minutes, from XDS; 0 outside of US
  5. cni_vps: Network ID received from VPS, or zero if unknown
  6. cni_8301: Network ID received from teletext packet 8/30/1, or zero if unknown
  7. cni_8302: Network ID received from teletext packet 8/30/2, or zero if unknown

Minimum times for identifying a network, when data service is transmitted: VPS (DE/AT/CH only): 0.08 seconds; Teletext PDC or 8/30: 2 seconds; XDS (US only): unknown, between 0.1x to 10x seconds.

VBI_EVENT_NETWORK_ID:
Like VBI_EVENT_NETWORK, but this event will also be sent when the decoder cannot determine a network name. For this type the second callback function parameter has type Zvbi.EventNetwork with same contents as described above.
VBI_EVENT_TRIGGER:

Triggers are sent by broadcasters to start some action on the user interface of modern TVs. Until libzvbi implements all of WebTV and SuperTeletext the information available are program related (or unrelated) URLs, short messages and Teletext page links.

This event is sent when a trigger has fired. The second callback function parameter is of type Zvbi.PageLink and has the following elements:

  1. type: Link type: One of VBI_LINK* constants
  2. eacem: Link received via EACEM or ATVEF transport method
  3. name: Some descriptive text or empty
  4. url: URL
  5. script: A piece of ECMA script (Javascript), this may be used on WebTV or SuperTeletext pages to trigger some action. Usually empty.
  6. nuid: Network ID for linking to pages on other channels
  7. pgno: Teletext page number
  8. subno: Teletext sub-page number
  9. expires: The time in seconds and fractions since 1970-01-01 00:00 when the link should no longer be offered to the user, similar to a HTTP cache expiration date
  10. itv_type: One of VBI_WEBLINK_* constants; only applicable to ATVEF triggers; else UNKNOWN
  11. priority: Trigger priority (0=EMERGENCY, should never be blocked, 1..2=HIGH, 3..5=MEDIUM, 6..9=LOW) for ordering and filtering
  12. autoload: Open the target without user confirmation
VBI_EVENT_ASPECT:

The vbi decoder received new information (potentially from PAL WSS, NTSC XDS or EIA-J CPR-1204) about the program aspect ratio.

The second callback function parameter is of type Zvbi.AspectRatio and has the following elements:

  1. first_line: Describe start of active video (inclusive), i.e. without the black bars in letterbox mode
  2. last_line: Describes enf of active video (inclusive)
  3. ratio: The picture aspect ratio in anamorphic mode, 16/9 for example. Normal or letterboxed video has aspect ratio 1/1
  4. film_mode: TRUE when the source is known to be film transferred to video, as opposed to interlaced video from a video camera.
  5. open_subtitles: Describes how subtitles are inserted into the picture: None, or overlay in picture, or in letterbox bars, or unknown.
VBI_EVENT_PROG_INFO:

We have new information about the current or next program.

The second callback function parameter is of type Zvbi.ProgInfo and has the following elements:

  1. current_or_next: Indicates if entry refers to the current or next program
  2. start_month: Month of the start date
  3. start_day: Day-of-month of the start date
  4. start_hour: Hour of the start time
  5. start_min: Minute of the start time
  6. tape_delayed: Indicates if a program is routinely tape delayed for Western US time zones.
  7. length_hour: Duration in hours
  8. length_min: Duration remainder in minutes
  9. elapsed_hour: Already elapsed duration
  10. elapsed_min: Already elapsed duration
  11. elapsed_sec: Already elapsed duration
  12. title: Program title text (ASCII)
  13. type_classf: Scheme used for program type classification: One of the VBI_PROG_CLASSF constants. Use Zvbi.prog_type_string() for obtaining a string from this value and each of the following type identifiers.
  14. type_id_0: Program type classifier #1 according to scheme
  15. type_id_1: Program type classifier #2
  16. type_id_2: Program type classifier #3
  17. type_id_3: Program type classifier #4
  18. rating_auth: Scheme used for rating: One of VBI_RATING_AUTH* constants. Use Zvbi.rating_string() for obtaining a string from this value and the following rating_id.
  19. rating_id: Rating classification
  20. rating_dlsv: Additional rating for scheme in case of scheme VBI_RATING_TV_US
  21. audio_mode_a: Audio mode: One of VBI_AUDIO_MODE* constants
  22. audio_language_a: Audio language (audio channel A)
  23. audio_mode_b: Audio mode (channel B)
  24. audio_language_b: Audio language (audio channel B)
  25. caption_services: Active caption pages: bits 0-7 correspond to caption pages 1-8
  26. caption_languages: Tuple with caption language on all 8 CC pages
  27. aspect_ratio: Aspect ratio description, an instance of class Zvbi.AspectRatio
  28. description: Program content description text: Up to 8 lines of ASCII text spearated by newline character.

Multithreading: The Zvbi.Capture, Zvbi.RawDec, Zvbi.ServiceDec and Zvbi.Search classes are thread-safe insofar as they allow running the capture loop (including raw decoder) and service decoder in one thread, and further event processing or a user-interface in another thread. The latter may interact with the capture/decoder thread via configuration and query interfaces.

However note that callbacks registered with the service decoder will occur within the capture thread (i.e. where you call Zvbi.ServiceDec.decode() on captured sliced data buffers). Take care to call only thread-safe functions of the user thread in that context. Usually one will filter and then forward the notifications to the main thread using some IPC mechanism (e.g. via a queued signal when using Qt). See examples/search-ttx.py for an example using multi-threading.

Zvbi.ServiceDec.event_handler_register()

vt.event_handler_register(event_mask, function, [user_data])

Registers a new event handler. event_mask can be a but-wise ‘OR’ of VBI_EVENT_* constants. When the handler function with same user_data is already registered, its event_mask will be changed. Any number of handlers can be registered, also different handlers for the same event which will be called in registration order.

The registered handler function will be invoked from within Zvbi.ServiceDec.decode(). The function is called either with two or three parameters, depending on the presence of parameter user_data during registration:

  1. Event type (i.e. one of the VBI_EVENT_* constants).
  2. A named tuple type describing the event. The class type depends on the type of event indicated as first parameter.
  3. A copy of the user_data object specified during registration. The parameter is omitted here when omitted during registration.

See section Zvbi.ServiceDec event handling above for a detailed descripion of the callback parameters and information types.

Apart of adding handlers, this function also enables and disables decoding of data services depending on the presence of at least one handler for the respective data. A VBI_EVENT_TTX_PAGE handler for example enables Teletext decoding.

This function can be safely called at any time, even from inside of a handler. Note only 10 event callback functions can be registered in a script at the same time. Callbacks are automatically unregistered when the decoder object is destroyed.

Zvbi.ServiceDec.event_handler_unregister()

vt.event_handler_unregister(function, [user_data])

De-registers the event handler handler with optional parameter user_data, if such a handler was previously registered with the same user data parameter.

Apart from removing a handler, this function also disables decoding of associated data services when no handler is registered to consume the respective data. For example, removing the last handler for event type VBI_EVENT_TTX_PAGE disables Teletext decoding.

This function can be safely called at any time, even from inside of a handler removing itself or another handler, and regardless if the handler has been successfully registered.

Zvbi.Search.__iternext__()

After creating an instance of Zvbi.Search, iteration is used to execute the search:

search = Zvbi.Search(decoder, pattern)
for pg in search:
    # ... process pg object

As long as matching pages are found, iteration returns a reference to the next match in form of an instance of Zvbi.Page. The matching range of text is highlighted in the page.

Note: The returned page object refers to temporary memory within the C library; therefore the page content is no longer valid after continuation of the search or start of a new search. An exception of type ValueError will be raised upon access to an invalidated page.

If no matching page is found, iteration raises exception StopIteration as usual. The same exception is raised when the callback returned False. If iteration is continued after reaching its end, the search will restart from the starting point given in the constructor. After cancellation search will continue from the last visited page.

Upon other errors the function raises exception Zvbi.SearchError which contains a string describing the cause, which can be because the cache is completely empty, or internal errors.

Class Zvbi.Page

These are functions to render Teletext and Closed Caption pages directly into memory, essentially a more direct interface to the functions of some important export modules described in Zvbi.Export.

All of the functions in this section work on page objects as returned by the page cache’s “fetch” functions (see Zvbi.ServiceDec) or the page search function (see Zvbi.Search)

Page objects returned by Zvbi.ServiceDec’s “fetch” interfaces must be deleted for releasing resources which are locked internally in the library during the fetch. Zvbi.Page supports the Python’s “Context Manager” protocol (i.e. methods “__enter__” and “__exit__”) to allow doing this easily using the “with” statement:

with vtdec.fetch_vt_page(pgno, subno) as pg:
    # process object "pg"

Any access to the page after the block defined by “with” would raise exception ValueError.

Page objects returned by Zvbi.Search (or referenced as parameter to the progress callback function) have an implicitly limited life-time as they refer to internal static storage within the C library. These objects are released invalidated automatically. Any access outside of their lifetime raises exception ValueError. In particular this means you must not assign such page objects to global variables. Instead just store the page number and fetch the page again from the cache via Zvbi.ServiceDec when needed.

Zvbi.Page.draw_vt_page()

canvas = pg.draw_vt_page(column, row, width, height,
                         fmt=Zvbi.VBI_PIXFMT_RGBA32_LE,
                         reveal=False, flash_on=False,
                         img_pix_width, col_pix_off, row_pix_off)

Draws a complete Teletext page or a sub-section thereof into a raw image canvas and returns it in form of a bytes object. Each teletext character occupies 12 x 10 pixels (i.e. a character is 12 pixels wide and each line is 10 pixels high. Note that this aspect ratio is not optimal for display, so pixel lines should be doubled. This is done automatically by the PPM and XPM conversion functions.)

The image is returned in form of a bytes object. When using format Zvbi.VBI_PIXFMT_RGBA32_LE, each pixel consists of 4 subsequent bytes (RGBA). Hence the bytes array is 4 * 12 * pg_columns * 10 * pg_rows bytes long, where pg_columns and pg_rows are the page width and height in teletext characters respectively. When using format Zvbi.VBI_PIXFMT_PAL8 each pixel uses one byte. In this case each pixel value is an index into the color palette as delivered by Zvbi.Page.get_page_color_map().

Input parameters:

column:Start column in the page to render at the first pixel column, defaults to 0. Note this and the following three values are given as numbers of teletext characters (not pixels.)
row:Start row in the page to render at the first pixel column, defaults to 0.
width:Number of columns to render. The sum of parameters column plus width shall be less or equal the page width. When omitted, the value defaults to the page width minus the start row offset.
height:Number of rows to render. The sum of parameters row plus height shall be less or equal the page height. When omitted, the value defaults to the page height minus the start column offset.
fmt:Specifies the output format. Supported is Zvbi.VBI_PIXFMT_RGBA32_LE (i.e. each pixel uses 4 subsequent bytes for R,G,B,A) and Zvbi.VBI_PIXFMT_PAL8 (i.e. each pixel uses one byte, which is an index into the color palette)
img_pix_width:Is the distance between canvas pixel lines in pixels. When omitted or set to 0, the image width is automatically set to the width of the selected region (i.e. the number of columns times 12) plus col_pix_off, if present. If specified, the value has to be equal or larger than the default; extraneous pixels are left zero in the returned image.
col_pix_off:Offset to the left in pixels defining where in the canvas to draw the page section. By using this value combined with img_pix_width you can achieve a black border around the image.
row_pix_off:Offset to the top in pixels defining where in the canvas to draw the page section.
reveal:When omitted or set to False, characters flagged as “concealed” are rendered space (U+0020). When set to True the characters are rendered.
flash_on:Set to True to draw characters flagged “blink” (properties) as space (U+0020). To implement blinking you’ll have to draw the page repeatedly with this parameter alternating between 0 and 1.

Zvbi.Page.draw_cc_page()

canvas = pg.draw_cc_page(column, row, width, height,
                         fmt=Zvbi.VBI_PIXFMT_RGBA32_LE,
                         img_pix_width, col_pix_off, row_pix_off)

Draw a complete or sub-section of a Closed Caption page. Each character occupies 16 x 26 pixels (i.e. a character is 16 pixels wide and each line is 26 pixels high.)

The image is returned in a byte object. Each pixel uses 4 subsequent bytes (RGBA). Hence the bytes array is 4 * 16 * pg_columns * 26 * pg_rows bytes long, where pg_columns and pg_rows are the page width and height in Closed Caption characters respectively.

For details on parameters please see the previous function.

Zvbi.Page.canvas_to_ppm()

ppm = pg.canvas_to_ppm(canvas, fmt=Zvbi.VBI_PIXFMT_RGBA32_LE,
                       aspect=True, img_pix_width=0)

This is a helper function which converts the image given in canvas from a raw bytes object generated by draw_vt_page() or draw_cc_page() into PPM format (specifically “P6” with 256 colors per dimensions, which means there is a small ASCII header, followed by the image bitmap consisting of 3 bytes (RGB) per pixel.)

fmt:The is the format of the input canvas. If must be the same value as passed to draw_vt_page() or draw_cc_page().
aspect:This optional boolean parameter when set to False, disables the aspect ratio correction (i.e. on teletext pages all lines are doubled by default; closed caption output ration is already correct.) Default is True.
img_pix_width:The is the pixel width of the input canvas. It must be the same value as passed to draw_vt_page() or draw_cc_page(). When omitted or zero, the value is calculated in the same way as described for these methods.

Zvbi.Page.canvas_to_xpm()

xpm = pg.canvas_to_xpm(canvas, fmt=Zvbi.VBI_PIXFMT_RGBA32_LE,
                       aspect=True, img_pix_width=0)

This is a helper function which converts the image given in canvas from a raw bytes object generated by draw_vt_page() or draw_cc_page() into XPM format. Due to the way XPM is specified, the output is an ASCII text string (suitable for including in C source code), however returned within a bytes object.

fmt:The is the format of the input canvas. If must be the same value as passed to draw_vt_page() or draw_cc_page().
aspect:This optional boolean parameter when set to False, disables the aspect ratio correction (i.e. on teletext pages all lines are doubled by default; closed caption output ration is already correct.) Default is True.
img_pix_width:The is the pixel width of the input canvas. It must be the same value as passed to draw_vt_page() or draw_cc_page(). When omitted or zero, the value is calculated in the same way as described for these methods.

Zvbi.Page.print_page()

txt = pg.print_page(column, row, width, height,
                    fmt='UTF-8', table=True)

Print and return the referenced Teletext or Closed Caption page in form of a bytes object. Rows are separated by line-feed characters (“n”). All character attributes and colors will be lost. Graphics characters, DRCS and all characters not representable in UTF-8 will be replaced by spaces.

column:Start column in the page to render at the first output column. Defaults to 0.
row:Start row in the page to render at the first output row. Defaults to 0.
width:Number of columns to render. The sum of parameters column plus width shall be less or equal the page width (use pg.get_page_size() to determine the dimensions.) When omitted, the value defaults to the page width minus the start row offset.
height:Number of rows to render. The sum of parameters row plus height shall be less or equal the page height. When omitted, the value defaults to the page height minus the start column offset.
format:Encoding to be used in the output. Default is ‘UTF-8’. Use the equivalent format specification when decoding the bytes into a Python string.
table:When optional parameter table is set to 1, the page is scanned in table mode, printing all characters within the source rectangle including runs of spaces at the start and end of rows. This is the default. When set to False, sequences of spaces at the start and end of rows are collapsed into single spaces and blank lines are suppressed.

Zvbi.Page.get_page_no()

(pgno, subno) = pg.get_page_no()

This function returns a tuple containing the page and sub-page number of the page instance.

Teletext page numbers are hexadecimal numbers in the range 0x100 .. 0x8FF, Closed Caption page numbers are in the range 1 .. 8. Sub-page numbers are used for teletext only. These are hexadecimal numbers in range 0x0001 .. 0x3F7F, i.e. the 2nd and 4th digit count from 0..F, the 1st and 3rd only from 0..3 and 0..7 respectively. A sub-page number zero means the page has no sub-pages.

Zvbi.Page.get_page_size()

(rows, columns) = pg.get_page_size()

This function returns a tuple containing the dimensions (i.e. row and column count) of the page instance.

Zvbi.Page.get_page_dirty_range()

(y0, y1, roll) = pg.get_page_dirty_range()

To speed up rendering these variables mark the rows which actually changed since the page has been last fetched from cache. y0y1 are the first to last row changed, inclusive. roll indicates the page has been vertically scrolled this number of rows, negative numbers up (towards lower row numbers), positive numbers down. For example -1 means row y0 + 1 … y1 moved to y0 … y1 - 1, erasing row y1 to all spaces.

Practically this is only used in Closed Caption roll-up mode, otherwise all rows are always marked dirty. Clients are free to ignore this information.

Zvbi.Page.get_page_color_map()

map = pg.get_page_color_map()

The function returns a tuple of length 40 which contains the page’s color palette. Each entry is a 24-bit RGB value (i.e. three 8-bit values for red, green, blue, with red in the lowest bits) To convert this into the usual “#RRGGBB” syntax use:

print("#%02X%02X%02X" %
         (rgb&0xFF, (rgb>>8)&0xFF, (rgb>>16)&0xFF))

Zvbi.Page.get_page_text_properties()

av = pg.get_page_text_properties()

The function returns tuple which contains the properties of all characters on the given page, starting with those of the first row left to right, directly followed by the next row etc. (use pg.get_page_size() for unpacking). Each entry is a bit-field. The members are (in ascending order, width in bits given behind the colon):

  • foreground color:8: Index into the color map returned by Zvbi.Page.get_page_color_map()

  • background color:8: Index into the color map returned by Zvbi.Page.get_page_color_map()

  • opacity:4: Character opacity, as one of constants:

    • VBI_TRANSPARENT_SPACE (replace char with video),
    • VBI_TRANSPARENT_FULL (replace background with video),
    • VBI_SEMI_TRANSPARENT (mix video into background), or
    • VBI_OPAQUE (no transparency).

    Both foreground and background colors are valid independent of this flag.

  • size:4: One of the constants:

    • VBI_NORMAL_SIZE,
    • VBI_DOUBLE_WIDTH,
    • VBI_DOUBLE_HEIGHT,
    • VBI_DOUBLE_SIZE,
    • VBI_OVER_TOP (i.e. this is to the right of VBI_DOUBLE_WIDTH or VBI_DOUBLE_SIZE),
    • VBI_OVER_BOTTOM (i.e. this is below VBI_OVER_TOP, thus lower right of VBI_DOUBLE_SIZE),
    • VBI_DOUBLE_HEIGHT2 (i.e. this is lower half of a VBI_DOUBLE_HEIGHT character in the row above), or
    • VBI_DOUBLE_SIZE2 (i.e. this is lower half of a VBI_DOUBLE_SIZE character in the row above).

    Note characters marked VBI_DOUBLE_HEIGHT2, VBI_DOUBLE_SIZE2, VBI_OVER_TOP, VBI_OVER_BOTTOM have the same character unicode and attributes as the top/left anchor. Partial characters (like a single VBI_DOUBLE_HEIGHT2) will not appear, so characters with these attributes can be safely ignored when scanning the page content.

  • underline:1: Boolean True for underlined, else False.

  • bold:1: Boolean True for bold, else False.

  • italic:1: Boolean True for displaying the character slanted right, else False.

  • flash:1: Boolean True for characters that should flash (i.e. blink), else False. Note the GUI is responsible for rendering the page periodically with such characters present, or omitted. See Zvbi.Page.draw_vt_page().

  • conceal:1: Boolean True for characters that should be concealed (i.e. replaced by space character), else False. See also option reveal for Zvbi.Page.draw_vt_page().

  • proportional:1: Currently always False, i.e. use fixed-width fonts for rendering.

  • link:1: Boolean True if the character is part of a hyperlink, else False. Call Zvbi.Page.resolve_link() to get more information.

Zvbi.Page.get_page_text()

txt = pg.get_page_text( replace_chr='' )

The function returns the complete page text in form of a string (i.e. Unicode). This function is very similar to pg.print_page(), but does not insert or remove any characters so that it’s guaranteed that characters in the returned string correlate exactly with the array returned by Zvbi.Page.get_page_text_properties().

The optional parameter can be set to a single-character string for replacing “private-use” Unicode code points in range [0xE000, 0xF8FF] with that character. Note these code points are used for representing graphical characters. When not replacing them, there will be errors when passing the string to transcoder functions (such as Pythons’s decode().)

Zvbi.Page.resolve_home()

href = pg.resolve_home()

All Teletext pages have a built-in home link, by default page 100, but can also be the magazine intro page or another page selected by the editor.

The function returns an object of type Zvbi.PageLink. See chapter Event handling, item VBI_EVENT_TRIGGER for a description of the contents.

Class Zvbi.Export

Once libzvbi received, decoded and formatted a Teletext or Closed Caption page you will want to render it on screen, print it as text or store it in various formats. libzvbi provides export modules converting a page object into the desired format or rendering directly into an image.

Currently the following export formats are supported:

  • Text
  • HTML
  • PNG (image with lossless compression)
  • PPM (image without compression)
  • XPM (image without compression)

All the formats support boolean option “reveal”; all the image formats support boolean option “aspect”. The meaning of the options is the same as for Zvbi.Page.draw_vt_page().

Constructor Zvbi.Export()

exp = Zvbi.Export(keyword)

Creates a new object for exporting a Zvbi.Page object in the format implied by parameter keyword. As a special service you can initialize options by appending to the keyword parameter like this: keyword = “keyword; quality=75.5, comment=”example text””;

Note: A quick overview of all export formats and options can be obtained by running the demo script examples/explist.py in the ZVBI package.

Zvbi.Export.info_enum()

href = Zvbi.Export.info_enum(index)

This is a static member function. The function enumerates all available export modules. You should start with index 0, incrementing until the function raises exception StopIteration. Some modules may depend on machine features or the presence of certain libraries, thus the list can vary from session to session.

The function returns a dict with the following elements:

  • “keyword”
  • “label”
  • “tooltip”
  • “mime_type”
  • “extension”

Zvbi.Export.info_keyword(keyword)

href = Zvbi.Export.info_keyword(keyword)

This is a static member function. Similar to the above function info_enum(), this function returns info about available modules, although this one searches for an export module which matches the given keyword. If no match is found the function raises exception Zvbi.ExportError, else a dict as described above.

Zvbi.Export.info_export()

href = exp.info_export()

Returns the export module info for the export instance in form of a dict. The contents are as described for the previous two functions.

Zvbi.Export.option_info_enum()

href = exp.option_info_enum(index)

This member function enumerates the options available for the given export instance. You should start at index 0, incrementing until the function raises exception StopIteration. On success, the function returns a dict with the following elements:

  • “type”
  • “keyword”
  • “label”
  • “min”
  • “max”
  • “step”
  • “def”
  • “menu”
  • “tooltip”

The content format of min, max, step and def depends on the type, i.e. it may be an integer, double or string.

If present, the value of “menu” is a tuple. Elements in the tuple are of the same type as min, max, etc. If no label or tooltip are available for the option, these elements are undefined.

Zvbi.Export.option_info_keyword()

href = exp.option_info_keyword(keyword)

Similar to the above function exp.option_info_enum() this function returns info about available options, although this one identifies options based on the given keyword.

Zvbi.Export.option_set()

exp.option_set(keyword, opt)

Sets the value of the option named by keword to opt. Raises exception Zvbi.ExportError on failure. Example:

exp.option_set('quality', 75.5);

Note the expected type of the option value depends on the keyword. The ZVBI interface module automatically converts the option into type expected by the libzvbi library.

Mind that options of type VBI_OPTION_MENU must be set by menu entry number (integer), all other options by value. If necessary it will be replaced by the closest value possible. Use function exp.option_menu_set() to set options with menu by menu entry.

Zvbi.Export.option_get()

opt = exp.option_get(keyword)

This function queries and returns the current value of the option named by keyword.

Zvbi.Export.option_menu_set()

exp.option_menu_set(keyword, entry)

Similar to exp.option_set() this function sets the value of the option named by keyword to entry, however it does so by number of the corresponding menu entry. Naturally this must be an option with menu.

Zvbi.Export.option_menu_get()

entry = exp.option_menu_get(keyword)

Similar to exp.option_get() this function queries the current value of the option named by keyword, but returns this value as number of the corresponding menu entry. Naturally this must be an option with menu.

Zvbi.Export.to_stdio()

exp.to_stdio(pg, fd)

This function writes contents of the Zvbi.Page instance given in pg, converted to the respective export module format, to a stream created from fd using fdopen(3). This means fd has to be a value as returned by fileno() on a file-like object.

The function raises exception Zvbi.ExportError upon errors. Note this function may write incomplete files when an error occurs.

You can call this function as many times as you want, it does not change state of the export or page objects.

Zvbi.Export.to_file()

exp.to_file(pg, file_name)

This function writes contents of the Zvbi.Page instance given in pg, converted to the respective export module format, into a new file specified by file_name. When an error occurs the file will be deleted. The function raises exception Zvbi.ExportError upon errors.

You can call this function as many times as you want, it does not change state of the export or page objects.

Zvbi.Export.to_memory()

data = exp.to_memory(pg)

This function writes contents of the Zvbi.Page instance given in pg, converted to the respective export module format, into a bytes object.

The function raises exception Zvbi.ExportError upon errors.

Class Zvbi.DvbMux

These functions convert raw and/or sliced VBI data to a DVB Packetized Elementary Stream or Transport Stream as defined in EN 300 472 “Digital Video Broadcasting (DVB); Specification for conveying ITU-R System B Teletext in DVB bit-streams” and EN 301 775 “Digital Video Broadcasting (DVB); Specification for the carriage of Vertical Blanking Information (VBI) data in DVB bit-streams”.

Note EN 300 468 “Digital Video Broadcasting (DVB); Specification for Service Information (SI) in DVB systems” defines another method to transmit VPS data in DVB streams. Libzvbi does not provide functions to generate SI tables but the encode_dvb_pdc_descriptor() function is available to convert a VPS PIL to a PDC descriptor (since version 0.3.0)

Constructor Zvbi.DvbMux()

mx = Zvbi.DvbMux( {pes=True | ts_pid=pid}
                  [,callback [,user_data]]
                  [,raw_par] )

There are two separate semantics:

  • When option pes is present and True, a DVB VBI multiplexer instance is created for converting raw and/or sliced VBI data to MPEG-2 Packetized Elementary Stream (PES) packets as defined in the standards EN 300 472 and EN 301 775.
  • When option ts_pid is present and non-zero, a DVB VBI multiplexer instance is created for converting raw and/or sliced VBI data to MPEG-2 Transport Stream (TS) packets as defined in the standards EN 300 472 and EN 301 775.

The following keyword-only parameters are available:

pes:When this option is set, a PES stream will be encoded. This option must not be combined with option ts_pid.
ts_pid:When this option is present and non-zero, a TS stream will be encoded. The PID value is a program identifier that will be stored in the header of generated TS packets. The value must be in range 0x0010 to 0x1FFE inclusive. This option must not be combined with option pes.
callback:Specifies a handler function which is called by method feed() when a new TS or PES packet is available. When the callback parameter is omitted, packets have to be extracted via iteration. See method feed() for additional details.
user_data:The given object is passed through transparently as extra parameter to the specified callback when invoked from within the feed() method.
raw_par:This optional parameter of type Zvbi.RawParams describes attributes of raw data optionally provided to method Zvbi.DvbMux.feed(). The parameters have to match the capture source (i.e. usually one would obtain them via Zvbi.Capture.parameters() called on your capture instance). The parameter need not be specified when no raw data is to be encoded.

Wen raw decoder parameters are provided, they have to meet the following constraints:

  • videostd_set must contain one or more bits from the VBI_VIDEOSTD_SET_625_50.
  • scanning must be 625 (libzvbi 0.2.x only)
  • sampling_format must be VBI_PIXFMT_Y8 or VBI_PIXFMT_YUV420. Chrominance samples are ignored.
  • sampling_rate must be 13500000.
  • offset must be >= 132.
  • bytes_per_line must be >= 1.
  • offset + bytes_per_line must be <= 132 + 720.
  • synchronous must be True.

Zvbi.DvbMux.feed()

This method provides the main service of class Zvbi.DvbMux:

mx.feed(service_mask, sliced_buffer, raw_buf=None, pts=0)

This function converts raw and/or sliced VBI data to one DVB VBI PES packet or one or more TS packets as defined in EN 300 472 and EN 301 775.

Usage with a callback function:

When the DVB multiplexer was intiantiated with a callback function parameter, the feed() function invokes the callback for each generated PES or TS packet before it returns. Example for use of the callback:

# callback function, invoked out of DvbMux.feed()
def feed_cb(pkg, outfile):
    bwritten = outfile.write(pkg)
    return (bwritten == len(pkg))

outfile = open(SOME_FILE, "wb")
mx = Zvbi.DvbMux(pes=True, callback=feed_cb, user_data=outfile)

sliced_buffer = cap.pull_sliced(1000)
mx.feed(service_mask, sliced_buffer)

The packet parameter is a Bytes object containing a copy of the generated packet. Parameter user_data loops back the object passed to the constructor; it is omitted here if not present in the constructor parameters. The handler function has to return True on success and False on failure. In case of the latter, the feed() function terminates with exception Zvbi.DvbMuxError.

Usage without a callback function:

When the DVB multiplexer was intiantiated without a callback function parameter, generated packets have to be retrieved using iteration on the DvbMux object. Example usage for this mode:

outfile = open(SOME_FILE, "wb")
mx = Zvbi.DvbMux(pes=True)

sliced_buffer = cap.pull_sliced(1000)
mx.feed(service_mask, sliced_buffer)

for pes_pkg in mx:
    outfile.write(pes_pkg)

Note each iteration pre-allocates a packet buffer of size Zvbi.DvbMux.get_max_pes_packet_size(), which defaults to theoretical maximum 65504. For compatibility with decoders compliant to the Teletext buffer model defined in EN 300 472 the maximum should not exceed 1472 bytes. For this reason and for efficiency, is is recommended to limit the maximum to a value such as 2048 using Zvbi.DvbMux.set_pes_packet_size().

Input parameters:

service_mask:

Only data services in this set will be encoded. Other data services in the sliced buffer will be discarded without further checks. Create a set by ORing VBI_SLICED_* constants. Only the following data services can be encoded:

  1. VBI_SLICED_TELETEXT_B on lines 7 to 22 and 320 to 335 inclusive, or with line number 0 (undefined). All Teletext lines will be encoded with data_unit_id 0x02 (“EBU Teletext non-subtitle data”).
  2. VBI_SLICED_VPS on line 16.
  3. VBI_SLICED_CAPTION_625 on line 22.
  4. VBI_SLICED_WSS_625 on line 23.
sliced_buffer:

This mandatory parameter of type Zvbi.CaptureSlicedBuf contains the sliced VBI data to be converted. All data must belong to the same video frame.

raw_buf:

This optional parameter may pass an object of type Zvbi.CaptureRawBuf that contains raw VBI data to be converted. The object shall contain sample data of size (rdp.count_a + rdp.count_b) lines times rdp.bytes_per_line (where rdp is the raw decoder parameter set passed during instantiation). The function encodes only those lines which have been selected by sliced lines in the sliced_buffer object with id VBI_SLICED_VBI_625 The data field of these structures is ignored. When the sliced input buffer does not contain such structures, raw_buf can be omitted.

Raw VBI data with id VBI_SLICED_VBI_625 can be encoded on lines 7 to 23 and 320 to 336 inclusive. Note for compliance with the Teletext buffer model defined in EN 300 472, EN 301 775 recommends to encode at most one raw and one sliced, or two raw VBI lines per frame.

pts:

This Presentation Time Stamp will be encoded into the PES packet. Bits 33 … 63 are discarded. Resolution is 90 kHz. Note the value can be derived from the timestamp in sliced_buffer as sliced_buffer.timestamp * 90000.0.

The function may raise exception Zvbi.DvbMuxError upon failures, which may occur under the following circumstances:

  • The maximum PES packet size, or the value selected with Zvbi.DvbMux.set_pes_packet_size(), is too small to contain all the sliced and raw VBI data.
  • The sliced array is not sorted by ascending line number, except for elements with line number 0 (undefined).
  • An unsupported service was requested for encoding of sliced data.
  • A selected raw data line is not in the allowed ranges listed above.
  • A sliced line within sliced_buffer contains a physical line number outside the valid range specified above.
  • Parameter raw_dec was not specified during instantiation although the sliced_buffer contains a structure with id VBI_SLICED_VBI_625.
  • One or more members of the raw decoder parameters are invalid.
  • A sliced line within sliced_buffer with id VBI_SLICED_VBI_625 contains a physical line number outside the ranges defined by raw_dec parameters.

Zvbi.DvbMux.mux_reset()

mx.mux_reset()

This function clears the internal buffers of the DVB VBI multiplexer.

After a reset call the feed() function will encode a new PES packet, discarding any data of the previous packet which has not been consumed by the application.

Zvbi.DvbMux.get_data_identifier()

id = mx.get_data_identifier()

Returns the data_identifier the multiplexer encodes into PES packets.

Zvbi.DvbMux.set_data_identifier()

mx.set_data_identifier(data_identifier)

This function can be used to specify the data_identifier byte to be stored in PES packets.

For compatibility with decoders compliant to EN 300 472 this should be a value in the range 0x10 to 0x1F inclusive. The values 0x99 to 0x9B inclusive as defined in EN 301 775 are also permitted. The default data_identifier is 0x10.

The method raises exception Zvbi.DvbMuxError if the given identifier is outside the valid range.

Zvbi.DvbMux.get_min_pes_packet_size()

size = mx.get_min_pes_packet_size()

Returns the minimum size of PES packets the multiplexer generates.

Zvbi.DvbMux.get_max_pes_packet_size()

size = mx.get_max_pes_packet_size()

Returns the maximum size of PES packets the multiplexer generates.

Zvbi.DvbMux.set_pes_packet_size()

mx.set_pes_packet_size(min_size, max_size)

Determines the minimum and maximum total size of PES packets generated by the multiplexer, including all header bytes. When the data to be stored in a packet is smaller than the minimum size, the multiplexer will fill the packet up with stuffing bytes. When the data is larger than the maximum size the feed() function will fail.

The PES packet size must be a multiple of 184 bytes, in the range 184 to 65504 bytes inclusive, and this function will round min_size up and max_size down accordingly. If after rounding the maximum size is lower than the minimum, it will be set to the same value as the minimum size.

The default minimum size is 184, the default maximum 65504 bytes. For compatibility with decoders compliant to the Teletext buffer model defined in EN 300 472 the maximum should not exceed 1472 bytes.

The method raises exception Zvbi.DvbMuxError upon failure (out of memory).

Zvbi.DvbMux.dvb_multiplex_sliced()

This static method converts the sliced VBI data in the sliced buffer to VBI data units as defined in EN 300 472 and EN 301 775 and stores them in packet as output buffer. Thus this function provides a fraction of the functionality of the feed() method.

packet_left, sliced_left =
    Zvbi.DvbMux.dvb_multiplex_sliced(packet, packet_left,
                                     sliced, sliced_left,
                                     service_mask,
                                     data_identifier=0x10, stuffing= False)

Input parameters:

packet:

This parameter has to be a bytearray that is to be filled with the generated packet. The size of the bytearray needs to be pre-initialized to the initial value of packet_left.

packet_left:

Contains the number of bytes available in the packet object. It will be decremented by the cumulative size of the successfully stored data units.

sliced:

This has to be an object of type Zvbi.CaptureSlicedBuf. It contains the sliced VBI data to be converted.

sliced_left:

Indicates initially the number of sliced lines in the sliced buffer, or it can be zero.

service_mask:

Only data services in this set will be encoded. Other data services in the sliced buffer will be discarded without further checks. Create a set by bit-wise ORing VBI_SLICED_ values. The parameter defauls to the set of all allowed services, which are:

  • VBI_SLICED_TELETEXT_B on lines 7 to 22 and 320 to 335 inclusive
  • VBI_SLICED_VPS on line 16
  • VBI_SLICED_CAPTION_625 on line 22
  • VBI_SLICED_WSS_625 on line 23
data_identifier:
 

When the given value lies in range 0x10 to 0x1F inclusive, the encoded data units will be padded to data_unit_length 0x2C for compatibility with EN 300 472 compliant decoders. The data_identifier itself will not be stored in the output buffer.

stuffing:

If this optional parameter is specified and set True, and space remains in the output buffer after all data has been successfully converted, or sliced_left is zero, the function fills the buffer up with stuffing data units.

The function returns a tuple of two values:

  1. Returns the value of parameter packet_left, decremented by the cumulative size of the successfully stored data units.
  2. Returns the value of parameter sliced_left decremented by the number of successfully converted VBI lines in sliced

The method raises exception Zvbi.DvbMuxError upon failure. The method may fail for the following causes:

  • packet_left is less than 2 (the minimum data unit size is two bytes). The output buffer remains unchanged in this case.
  • The data_identifier is in range 0x10 to 0x1F inclusive and packet_left is not a multiple of 46. The output buffer remains unchanged in this case.
  • The lines in the sliced buffer are not sorted by ascending line number, except for elements with line number 0 (undefined).
  • The service mask contains a serive type that is not one of the allowed types listed above.
  • A sliced line selected by service_mask contains a line number outside the valid range specified above.

All errors are recoverable. Just call the function again, possibly after skipping the offending sliced line (by reducing the value of sliced_left), to continue where it left off. Note packet_left must be at least 2 (or a multiple of 46) in each call.

Simplified example without error checking:

sliced_buffer = cap.pull_sliced(1000)

pkg = bytearray(2024) # multiple of 46
pkg_left = len(pkg)
sliced_left = len(sliced_buffer)
pkg_left, sliced_left = \
    Zvbi.DvbMux.multiplex_sliced(pkg, pkg_left, sliced_buffer, sliced_left)
del pkg[pkg_left :]

Note: According to EN 301 775 all lines stored in one PES packet must belong to the same video frame (but the data of one frame may be transmitted in several successive PES packets). They must be encoded in the same order as they would be transmitted in the VBI, no line more than once. Samples may have to be split into multiple segments and they must be contiguously encoded into adjacent data units. The function cannot enforce this if multiple calls are necessary to encode all samples.

Zvbi.DvbMux.dvb_multiplex_raw()

This static method converts one line of raw VBI samples in raw to one or more “monochrome 4:2:2 samples” data units as defined in EN 301 775, and stores them in the buf output buffer. Thus this function provides a fraction of the functionality of the feed() method.

packet_left, raw_left =
    Zvbi.DvbMux.dvb_multiplex_raw(packet, packet_left,
                                  raw, raw_left,
                                  data_identifier, videostd_set, line,
                                  first_pixel_position, n_pixels_total,
                                  stuffing=False)

Input parameters:

data_identifier:
 When the given value lies in range 0x10 to 0x1F inclusive, the encoded data units will be padded to data_unit_length 0x2C for compatibility with EN 300 472 compliant decoders. The data_identifier itself will not be stored in the output buffer.
videostd_set:The line parameter will be interpreted according to this set of video standards. It must not change until all samples have been encoded. Only one of two values are permitted: Zvbi.VBI_VIDEOSTD_SET_625_50 or Zvbi.VBI_VIDEOSTD_SET_525_60.
line:The ITU-R line number to be encoded in the data units. It must not change until all samples have been encoded.
first_pixel_position:
 The horizontal offset where decoders shall insert the first sample in the VBI, counting samples from the start of the digital active line as defined in ITU-R BT.601. Usually this value is zero and n_pixels_total is 720. first_pixel_position + n_pixels_total must not be greater than 720. This parameter must not change until all samples have been encoded.
n_pixels_total:Total size of the raw input buffer in bytes, and the total number of samples to be encoded. Initially this value must be equal to raw_left, and it must not change until all samples have been encoded.
stuffing:If this optional parameter is specified and set True, and space remains in the output buffer after all data has been successfully converted, or sliced_left is zero, the function fills the buffer up with stuffing data units.

The function returns a tuple of two values:

  1. Returns the value of parameter packet_left, decremented by the cumulative size of the successfully stored data units.
  2. Returns the value of parameter raw_left decremented by the number of successfully converted samples.

The method raises exception Zvbi.DvbMuxError upon failure. The method may fail for the following causes:

  • packet_left is less than two (the minimum data unit size is two bytes).
  • raw_left is zero.
  • The data_identifier is in range 0x10 to 0x1F inclusive and packet_left is not a multiple of 46.
  • The videostd_set is ambiguous.
  • The line parameter is outside the valid range, that is 7 to 23 and 270 to 286 for 525 line standards, 7 to 23 and 320 to 336 for 625 line standards. All numbers inclusive.
  • raw_left is greater than n_pixels_total
  • first_pixel_position + n_pixels_total is greater than 720.

The output buffer remains unchanged on all errors.

Class Zvbi.DvbDemux

This class extracts sliced VBI data from a DVB Packetized Elementary Stream (PES) or Transport Stream (TS) as defined in EN 300 472 “Digital Video Broadcasting (DVB); Specification for conveying ITU-R System B Teletext in DVB bitstreams” and EN 301 775 “Digital Video Broadcasting (DVB); Specification for the carriage of Vertical Blanking Information (VBI) data in DVB bitstreams”.

Constructor Zvbi.DvbDemux

dvb = Zvbi.DvbDemux( [callback [, user_data]] [,max_sliced=64] )

Creates and returns a new DVB VBI demultiplexer context taking a PES stream as input.

The constructor takes the following optional keyword-only parameters:

callback:

When this parameter is present, it must be a function object. The function will be called from inside of method feed whenever a complete sliced data of a VBI frame is available during de-multiplexing the provided stream data.

When the callback parameter is omitted, VBI data has to be extracted via iteration. See dvb.feed() for additional details.

user_data:

If present, the passed object is appended to the callback’s parameter list. IF omitted, one parameter less is passed to the callback.

max_sliced:

This optional parameter indicates the size of the buffer to allocate for the sliced buffer to be returned by iteration (i.e. when no callback is defined). The default is 64 lines per frame.

Zvbi.DvbDemux.feed()

dvb.feed(buf)

This function takes an arbitrary number of DVB PES data bytes in buf, filters out PRIVATE_STREAM_1 packets, filters out valid VBI data units, and stores them in objects of type Zvbi.CaptureSlicedBuf function may raise exception Zvbi.DvbDemuxError if the data contained errors. When a callback is configured, the exception is also raised if the callback function returned value False.

Note the timestamp included in the generated Zvbi.CaptureSlicedBuf instantes is derived from the presentation timestamp (PTS) of the DVB stream, converted from 1/90000 Hz to a second resolution (as Float type to allow fractions). The value does not represent seconds since 1970-Jan-01, but can nevertheless be used equivalently to timestampts generated by class Zvbi.Capture.

Note: Demultiplexing of raw VBI data is not supported; any raw data present in the stream will be discarded.

Usage with a callback function:

When the de-multiplexer was intiantiated with a callback function parameter, the feed function invokes the callback for each completed VBI frame before it returns. The callback is invoked with the following signature:

ok = callback(sliced_buffer, user_data)

The handler function has to return True on success and False on failure. Parameters to the callback have the following meaning:

  • sliced_buffer is an object of type Zvbi.CaptureSlicedBuf, containing the sliced data and attributes (i.e. this is the same type as returned by Zvbi.Capture methods). The timestamp attribute is derived from the PTS value in the stream, converted from 90 kHz to one second (with fraction) resolution.

    Note: The sliced buffer instance passed here is valid only for the duration of the callback execution. (When assigned to a global variable and accessed after the callback returns, exception ValueError will be raised.)

  • user_data loops back the object passed via user_data parameter to the constructor. If not specified there, this parameter is omitted here.

Usage without a callback function:

When the de-multiplexer was intiantiated without a callback function parameter, the feed() function only stores a reference to the given input buffer. Actual de-multiplexing is done when the object is used as an iterator. The iteration has to be completed before feeding new data, else exception ZvbiDvbDemuxError is raised.

Each iteration returns an object of type Zvbi.CaptureSlicedBuf, containing the sliced data and attributes (i.e. this is the same type as returned by Zvbi.Capture methods). The timestamp attribute is derived from the PTS value in the stream, converted from 90 kHz to one second (with fraction) resolution.

Example usage for this mode:

dvb.feed(buf)
for sliced_buffer in dvb:
    # process sliced_buffer...

See also examples/dvb-mux.py for a working example.

At most the maximum number of sliced lines indicated via parameter max_sliced (or default value 64) to the constructor is returned. If the frame contains more lines, they are discarded sliently. To detect this, you can set max_sliced to plus one of the expected maximum and treat reaching this value as overflow error. (The number of sliced lines in the returned buffer can be queried via len(sliced_buffer).)

Note in contrary to callback mode, the life-time of returned sliced_buffer objects is not limited by the library, as a separate buffer, owned by the instance, is allocated for each iteration.

Zvbi.DvbDemux.set_log_fn()

dvb.set_log_fn(mask, log_fn=None, user_data=None)

The DVB demultiplexer supports the logging of errors in the PES stream and information useful to debug the demultiplexer. With this function you can redirect log messages generated by this module from general log function Zvbi.set_log_fn() to a different function or enable logging only in the DVB demultiplexer.

The callback can be removed by calling the function with a zero mask value or without a handler parameter.

Input parameters:

mask:An integer value specifying which kind of information to log. If zero, logging is disabled (and parameter log_fn is ignored). Else this is a bit-wise OR of one or more of the constants VBI_LOG_ERROR, VBI_LOG_WARNING, VBI_LOG_NOTICE, VBI_LOG_INFO, VBI_LOG_DEBUG, VBI_LOG_DRIVER, VBI_LOG_DEBUG2, VBI_LOG_DEBUG3.
log_fn:If present, has to be a callable object that is invoked for each message with the parameters listed below. If omitted, logging is disabled.
user_data:If present, this object is passed through to the handler function as last parameter.

The handler function is called with the following parameters: level, context, message and, if given, user_data. Meaning of the parameters is the same as described for Zvbi.set_log_fn().

Note: Kind and contents of log messages may change in the future.

Zvbi.DvbDemux.reset()

dvb.reset()

Resets the DVB demux to the initial state as after creation. Intended to be used after channel changes.

Class Zvbi.IdlDemux

The functions in this section decode data transmissions in Teletext Independent Data Line packets (EN 300 708 section 6), i.e. data transmissions based on teletext packet 8/30.

The decoder only supports format A.

Constructor Zvbi.IdlDemux()

idl = Zvbi.IdlDemux(channel, address, callback, [user_data] )

Creates and returns a new Independent Data Line format A (EN 300 708 section 6.5) demultiplexer.

Input parameters:

channel:Process packets of this channel.
address:Process packets with this service data address.
callback:Parameters callback and optional user_data specify a handler and passed-through parameter which is called when a new packet is available. Passing the callback is mandatory as the data is otherwise discarded.
user_data:This optional parameter is passed through to the callback function, if specified. Else the user_data parameter to the callback is omitted.

The callback function is invoked with the following parameters for each received data packet:

  1. buffer: A bytes object containing the data received in the packet (i.e. payload data after stripping teletext packet header)
  2. flags: A bit-wise OR of VBI_IDL_DATA_ constants.
  3. Optionally the user_data object specified as constructor parameter; if the parameter was specified to the constructor, it is omitted here.

Zvbi.IdlDemux.feed()

idl.feed(buf)

This function takes 42 bytes of a Teletext packet, detects packets belonging to the configured data channel and address and calls the callback function given during context creation when new payload data is available.

Parameter buf is a scalar containing a teletext packet’s data (at least 42 bytes, i. e. without clock run-in and framing code), as returned by the slicer functions.

The function returns None. Exception Zvbi.IdlDemuxError is raised if the buffer contained incorrectible errors.

Zvbi.IdlDemux.feed_frame()

This function works like idl.feed() but takes a complete sliced buffer (i.e. a full frame’s worth of sliced data as returned by Zvbi.Capture.pull_sliced()) and automatically filters out all unrelated teletext packets. This can be used to “short-circuit” the capture output with the demultiplexer. Example:

sliced_buffer = cap.pull_sliced(1000)
idl.feed_frame(sliced_buffer)

The callback function given during context creation is called when new payload data is available. The function returns None. Exception Zvbi.IdlDemuxError is raised if any of the teletext packets in the buffer contained incorrectible errors.

Zvbi.IdlDemux.reset()

idl.reset(dx)

Resets the IDL demux context, useful for example after a channel change.

Class Zvbi.PfcDemux

Separating data transmitted in Page Function Clear Teletext packets (ETS 300 708 section 4), i.e. using regular packets on a dedicated teletext page.

Constructor Zvbi.PfcDemux()

pfc = Zvbi.PfcDemux(pgno, stream, callback, [user_data] )

Creates and returns a new demultiplexer context.

Input parameters:

page:Number of the teletext page on which the data is transmitted. (Usually data is transmitted on a “non-decimal looking” page number such as 1DF.)
stream:Number of the stream to be de-multiplexed.
callback:Parameters callback and optional user_data specify a handler and passed-through parameter which is called when a new packet is available. Passing the callback is mandatory as the data is otherwise discarded.
user_data:This optional parameter is passed through to the callback function, if specified. Else the user_data parameter to the callback is omitted.

The callback function is invoked with the following parameters for each correctly assembled data block.

  1. page: Teletext page number given in constructor.
  2. stream: Stream identifier given in constructor.
  3. application_id: Application ID received in the AI block.
  4. block: A bytes object containing the data received in the block.
  5. Optionally the user_data object specified as constructor parameter; if the parameter was specified to the constructor, it is omitted here.

Note multiple small blocks may fit within a teletext packet; inversely larger blocks may span multiple teletext packets. Therefore the callback may be called 0, 1, or more times per received teletext packet.

Zvbi.PfcDemux.feed()

pfc.feed(buf)

This function takes a raw stream of Teletext packets, detects if they belong to the requested page and stream and assembles the data transmitted in this packet in an internal buffer. When a data block is complete it calls the handler given during creation.

Zvbi.PfcDemux.feed_frame()

This function works like pfc.feed() but takes a complete sliced buffer (i.e. a full frame’s worth of sliced data as returned by Zvbi.Capture.pull_sliced()) and automatically filters out all unrelated teletext packets. This can be used to “short-circuit” the capture output with the demultiplexer. Example:

sliced_buffer = cap.pull_sliced(1000)
pfc.feed_frame(sliced_buffer)

The callback function given during context creation is called when a new data block is complete. The function returns None. Exception Zvbi.PfcDemuxError is raised if any of the teletext packets in the buffer contained incorrectible errors.

Zvbi.PfcDemux.reset()

pfc.reset()

Resets the PFC demux context, useful for example after a channel change.

Class Zvbi.XdsDemux

Separating “Extended Data Service” (XDS) from a Closed Caption stream (EIA 608).

Constructor Zvbi.XdsDemux()

xds = Zvbi.XdsDemux(callback, user_data)

Creates and returns a new Extended Data Service (EIA 608) demultiplexer.

Parameters callback and optionally user_data specify a handler and passed-through parameter which is called when a new packet is available. Passing the callback is mandatory as the data is otherwise discarded.

The callback function is invoked with the following parameters:

  1. xds_class is the XDS packet class, i.e. one of the VBI_XDS_CLASS_* constants.
  2. xds_subclass holds the subclass; meaning depends on the main class.
  3. buffer is a bytes object holding the packet data (already parity decoded.)
  4. Optionally user_data, if specified as constructor parameter; else the parameter is omitted.

Zvbi.XdsDemux.feed()

xds.feed(buf)

This function takes two successive bytes of a raw Closed Caption stream, filters out XDS data and calls the handler function given during context creation when a new packet is complete.

Parameter buf is a bytes-like object holding data from NTSC line 284 (as returned by the slicer functions.) Only the first two bytes in the buffer are used.

The function returns None. Exception Zvbi.XdsDemuxError is raised if the buffer contained parity errors.

Zvbi.XdsDemux.feed_frame()

This function works like xds.feed() but takes a complete sliced buffer (i.e. a full frame’s worth of sliced data as returned by Zvbi.Capture.pull_sliced()) and automatically filters out all non-closed caption lines. This can be used to “short-circuit” the capture output with the demultiplexer. Example:

sliced_buffer = cap.pull_sliced(1000)
xds.feed_frame(sliced_buffer)

The callback function given during context creation is called when a new packet is complete. The function returns None. Exception Zvbi.XdsDemuxError is raised if any of the CC lines in the buffer contained parity errors.

Zvbi.XdsDemux.reset()

xds.reset()

Resets the XDS demux context, useful for example after a channel change.

Miscellaneous (Zvbi)

Zvbi.lib_version()

major, minor, micro = Zvbi.lib_version()

Returns the major, minor and micro versions of the ZVBI library in form of a tuple.

Zvbi.check_lib_version()

Zvbi.check_lib_version(major, minor, micro)

Returns True if the library version is at least the given version. The last two parameters are optional and default to zero. Example:

if not Zvbi.check_lib_version(0, 2, 35):
    print("Library version is outdated")

Zvbi.set_log_fn()

Zvbi.set_log_fn(mask, log_fn=None, user_data=None)

Various functions within the libzvbi library can print warnings, errors and information useful for debugging the library or application. By default such messages are disabled. This function allows enabling these messages by specifying a function for printing them. (Note: The kind and contents of messages logged by particular functions may change in the future.)

Input parameters:

mask:An integer value specifying which kind of information to log. If zero, logging is disabled (and parameter log_fn is ignored). Else this is a bit-wise OR of one or more of the constants VBI_LOG_ERROR, VBI_LOG_WARNING, VBI_LOG_NOTICE, VBI_LOG_INFO, VBI_LOG_DEBUG, VBI_LOG_DRIVER, VBI_LOG_DEBUG2, VBI_LOG_DEBUG3.
log_fn:Callable object to be called for log messages. Omit this parameter to disable logging.
user_data:If present, the parameter is passed through as last parameter to each call of the function specified by log_fn. When not specified, the callback is invoked with one less parameter.

The handler function is called with the following parameters:

  1. level: Is an integer with the value of one of the VBI_LOG_* constants enumerated above.
  2. context: Is a text string describing the module where the event occurred.
  3. message: String with the actual message text.
  4. user_data: The object passed as user_data parameter to set_log_fn(). The parameter is omitted from the call when omitted as parameter to set_log_fn().

Note if you simply want to have the messages printed to sys.stderr, you can use Zvbi.set_log_on_stderr() instead. Also note you can register only one log handler; further registrations will override the previous one.

Zvbi.set_log_on_stderr()

Zvbi.set_log_on_stderr(mask)

This function enables error logging just like Zvbi.set_log_fn(), but uses the library’s internal log function which prints all messages to stderr, i.e. on the terminal.

mask is a bit-wise OR of zero or more of the VBI_LOG_* constants. The mask specifies which kind of information to log. To disable logging, pass a zero mask value.

Zvbi.par8()

par_val = par8(val)

This function encodes the given 7-bit value with Parity. The result is an 8-bit value in the range 0..255. Exception ValueError is raised when the input is out of range.

Zvbi.unpar8()

val = Zvbi.unpar8(par_val)

This function decodes the given Parity encoded 8-bit value. The result is a 7-bit value in the range 0…127 or a negative value when a parity error is detected. (Note: to decode parity while ignoring errors, simply mask out the highest bit, i.e. val &= 0x7F) Exception ValueError is raised when the input is out of range.

Zvbi.par_str()

byte_str = Zvbi.par_str(data)

This function encodes a string in an Unicode or bytes-like object with parity and returns the result within a bytes object.

Zvbi.unpar_str()

byte_str = Zvbi.unpar_str(data)

This function decodes a Parity encoded string and returns the result within a bytes object. (Note despite the name the characters cannot by returned as Python Unicode string, as the encoding is not known.)

Zvbi.rev8()

val = Zvbi.rev8(val)

This function reverses the order of all bits of the given 8-bit integer value and returns the result. This conversion is required for decoding certain teletext elements which are transmitted MSB first instead of the usual LSB first (the teletext VBI slicer already inverts the bit order so that LSB are in bit #0)

Zvbi.rev16()

val = Zvbi.rev16(val)

This function reverses the order of all bits of the given 16-bit integer value and returns the result.

Zvbi.rev16p()

val = Zvbi.rev16p(data, offset=0)

This function reverses all bits of two consecutive bytes in the given bytes-like object starting at the given offset and returns them as a 16-bit integer value.

Zvbi.ham8()

ham_val = Zvbi.ham8(val)

This function encodes the given 4-bit integer value (i.e. range 0..15) with Hamming-8/4. The result is an 8-bit value in the range 0..255.

Zvbi.unham8()

val = Zvbi.unham8(ham_val)

This function decodes the given Hamming-8/4 encoded integer value. The result is a 4-bit value, or -1 upon incorrectable errors.

Zvbi.unham16p()

val = Zvbi.unham16p(data, offset=0)

This function decodes two Hamming-8/4 encoded bytes (taken from the bytes-like object data at the given offset). The result is an 8-bit integer value, or -1 upon incorrectable errors.

Zvbi.unham24p()

val = Zvbi.unham24p(data, offset=0)

This function decodes three Hamming-24/18 encoded bytes (taken from the bytes-like object data at the given offset). The result is a 12-bit integer value, or -1 upon incorrectable errors.

Zvbi.dec2bcd()

bcd = Zvbi.dec2bcd(dec)

Converts an integer value (i.e. a regular two’s complement encoded binary value) in range 0 … 999 into a packed BCD number (binary coded decimal) in range 0x000 … 0x999, where each hex nibble is in range 0..9. Exception ValueError is raised when the input is out of range.

Zvbi.bcd2dec()

dec = Zvbi.bcd2dec(bcd)

Converts a packed BCD number in range 0x000 … 0xFFF into a regular integer value (i.e. two’s complement binary) in range 0 … 999. Exception ValueError is raised when the input is out of range or invalid BCD.

Zvbi.add_bcd()

bcd_sum = Zvbi.add_bcd(bcd1, bcd2)

Adds two packed BCD numbers, returning a packed BCD sum. Arguments and result are in range 0xF0000000 … 0x09999999, that is -10**7 … +10**7 - 1 in decimal notation. To subtract you can add the 10’s complement, e. g. -1 = 0xF9999999.

The return value is a packed BCD number. Exception ValueError is raised when the input values are out of range or invalid BCD.

Zvbi.is_bcd()

yes_no = Zvbi.is_bcd(bcd)

Tests if bcd forms a valid BCD number. The argument must be in range 0x00000000 … 0x09999999. Return value is 0 if bcd contains hex digits 0xA … 0xF.

Zvbi.decode_vps_cni()

cni = Zvbi.decode_vps_cni(data)

This function takes a sliced VPS line in form of a bytes-like object holding at least 13 bytes. The function decodes the network identifier and returns it as a 16-bit CNI value. The function raises exception ZvbiError in case of errors.

Zvbi.encode_vps_cni()

byte_str = Zvbi.encode_vps_cni(cni)

This function receives a 16-bit CNI value and returns a VPS line, or raises exception ZvbiError in case of an invalid CNI value that cannot be encoded (e.g. out of range)

Zvbi.rating_string()

rating = Zvbi.rating_string(auth, id)

Translate a program rating code given by auth and id into a string, native language. Raises exception Zvbi.Error if this code is undefined. The input parameters will usually originate from elements ev.rating_auth and ev.rating_id, provided within an instance of type Zvbi.ProgInfo for an event of type VBI_EVENT_PROG_INFO raised by Zvbi.ServiceDec event handling.

Zvbi.prog_type_string()

prog_type = Zvbi.prog_type_string(classf, id)

Translate a vbi_program_info program type code into string, currently English only. Raises exception Zvbi.Error if this code is undefined.

The input parameters will usually originate from elements ev.type_classf and ev.type_id_0 et.al., provided within an instance of type Zvbi.ProgInfo for an event of type VBI_EVENT_PROG_INFO raised by Zvbi.ServiceDec event handling.

Zvbi.iconv_caption()

str = Zvbi.iconv_caption(src, repl_char=None)

Converts a string of EIA 608 Closed Caption characters into a Unicode string. The function ignores parity bits and the bytes 0x00 … 0x1F, except for two-byte special and extended characters (e.g. music note 0x11 0x37) See also caption_unicode().

The optional second parameter repl_char specifies an UCS-2 replacement for characters that are not representable with standard Unicode code points. The parameter is expected in form of a string containing a single character. When omitted, the function will raise exception Zvbi.Error if the source buffer contains unrepresentable characters.

Returns the converted string as an Unicode object. The function raises exception Zvbi.Error when the source buffer contains non-representable code points, or when the conversion fails, or when it runs out of memory.

Zvbi.caption_unicode()

str = Zvbi.caption_unicode(c, to_upper=False)

Converts a single Closed Caption character code into a Unicode string. Codes in range 0x1130 to 0x1B3F are special and extended characters (e.g. caption command 11 37).

Input character codes in c are in ranges:

  • 0x0020 … 0x007F
  • 0x1130 … 0x113F
  • 0x1930 … 0x193F
  • 0x1220 … 0x123F
  • 0x1A20 … 0x1A3F
  • 0x1320 … 0x133F
  • 0x1B20 … 0x1B3F

When True is passed as optional second parameter, the character is converted into upper case. (Often programs are captioned in all upper case, but except for one character the basic and special CC character sets contain only lower case accented characters.)

Examples

The examples sub-directory in the Zvbi package contains a number of scripts used to test the various interface functions. You can also use them as examples for your code.

Note: Example command lines for scripts capturing directly from a DVB/VBI device shown below do not include options required for configuring the device. Generally, you’ll need either –device /dev/dvb/adapter0/demux0 –pid PID for DVB, or –device /dev/vbi0 for analog capture devices. The VBI PID value can often be derived from the PID for video in channels.conf by adding offsets in range 3 to 30. Alternatively you can look up the PID via Internet services such as <https://www.satindex.de/>.

capture.py:

Example for the use of class Zvbi.Capture. The script captures VBI data from a device and slices it. The result can be dumped for the various data services in form of hex-string plus roughly decoded text (where applicable) for inspection of incoming data. Altnernatively, output can be written to STDOUT in binary format for further processing (decoding) by piping the data into one of the following example scripts. Call with option –help for a list of options. (This is a translation of test/capture.c in the libzvbi package.)

decode.py:

Example for the use of class Zvbi.ServiceDec. Decodes sliced VBI data on STDIN, e.g.

./capture.py --sliced | ./decode.py --ttx

Call with option –help for a list of options. (This is a direct translation of test/decode.c in the libzvbi package.)

caption.py:

Example for the use of class Zvbi.ServiceDec, type Zvbi.VBI_EVENT_CAPTION. When called without an input stream, the application opens a GUI displaying a demo messages sequente (character sets etc.) for debugging the decoder. For displaying live CC streams you can use the following:

./capture.py --sliced | ./caption.py

The buttons on top of the GUI switch between Closed Caption channels 1-4 and Text channels 1-4. (This is a translation of test/caption.c in the libzvbi package, albeit based on TkInter here.)

export.py:

Example for the use of export actions in class Zvbi.Export. The script captures from a device until the specified Teletext page (range 100-8FF) or Closed Caption page (range 1-8) is found and then exports the page content in the requested format. The format is specified as first parameter and the page number as second parameter on the command line. Alternatively, the script can be used to continuously export a single or all received pages. Examples:

./export.py text 100       # teletext page 100 as text
./export.py text all       # continuously all teletext pages
./export.py --loop text 1  # continuously closed caption
./export.py "png;reveal=1" 100 > page_100.png

Use ./explist.py for listing supported export formats (aka “modules”) and possible options. Note options are appended to the module name, separated by semicolon as shown in the second example. (This is a translation of test/export.c in the libzvbi package, plus support for Closed Caption)

explist.py:

Example for the use of export option management in class Zvbi.Export. Test of page export options and menu interfaces. The script lists all available export modules (i.e. formats) and options. (This is a direct translation of test/explist.c in the libzvbi package.)

hamm.py:

Automated test of the odd parity and Hamming encoder and decoder functions. Note this test runs for a long time. (This is a direct translation of test/hamm.c in the libzvbi package.)

network.py:

Example for the use of class Zvbi.ServiceDec, type Zvbi.VBI_EVENT_NETWORK. This script shows how to identify a network from data transmitted in XDS packets, Teletext packet 8/30 format 1 and 2, and VPS packets. The script captures directly from a device until the currently tuned channel is identified by means of VPS, PDC et.al. (This is a direct translation of examples/network.c in the libzvbi package.)

proxy-test.py:

Example for the use of class Zvbi.Proxy. The script can capture either from a proxy daemon or a local device and dumps captured data on the terminal. Also allows changing services and channels during capturing (e.g. by entering “+ttx” or “-ttx” on stdin.) Start with option -help for a list of supported command line options. (This is a direct translation of test/proxy-test.c in the libzvbi package.)

test-vps.py:

This script contains tests for encoding and decoding the VPS data service on randomly generated data. (This is a direct translation of test/test-vps.c in the libzvbi package.)

search-ttx.py:

Example for the use of class Zvbi.Search and for multi-threading. The script captures and caches teletext pages in a separate thread. The main thread displays the progress of captured pages until the RETURN key is pressed, then prompts for a search string. A search across cached teletext pages is started, and the content of matching pages is printed on the terminal.

browse-ttx.py:

Example for the use of classes Zvbi.Page and Zvbi.Export for rendering teletext pages. The script captures teletext from a given device and renders selected teletext pages in a simple GUI using TkInter.

osc.py:

Example for the use of class Zvbi.RawDec. The script continuously captures raw VBI data and displays the data as an animated gray-scale image. Below this, the analog wave line of one selected video line is plotted (i.e. essentially simulating an oscilloscope). For the selected line, the resulting data from slicing is also shown if decoding is successful. (This script is loosely based on test/osc.c in the libzvbi package.)

dvb-mux.py:

Example for the use of class Zvbi.DvbMux. This script excercises the DVB multiplexer functions: The script first opens a capture device (normally this will be an analog device, as the goal is forwarding VBI services from analog to digital domain), then continuously captures VBI data, encodes it in a DVB packet stream and wites the result to STDOUT. The output stream can be decoded equivalently to that of capture.py, which is:

./dvb-mux.py | ./decode.py –pes –all

dvb-demux.py:

Example for the use of class Zvbi.DvbDemux. This script excercises the DVB de-multiplexer functions: The script directly opens a DVB capture device, and reads the incoming packets. The de-multiplexer is used to extract VBI packets, which are then forwarded to STDOUT. The output stream can be decoded equivalently to that of capture.py, which is:

./dvb-demux.py --sliced | ./decode.py --ttx

Note: Instead of reading from the device directly (and performing device ioctl with hard-coded constants, which is prone to breakage) you should normally use the Zvbi.Capture class which does that work for you. Using the Zvbi.DvbDemux class directly only is useful when receiving a stream from other sources (e.g. via socket from proxy on a remote host).

Authors

The ZVBI Perl interface module (https://metacpan.org/pod/Video::ZVBI) was written by T. Zoerner <tomzo@sourceforge.net> starting March 2006 for the Teletext EPG grabber accompanying nxtvepg (http://nxtvepg.sourceforge.net/). The Perl module was ported to Python in April 2020. Its official home is at https://pypi.org/project/Zvbi/

The module is based on the libzvbi library, mainly written and maintained by Michael H. Schimek (2000-2007) and Inaki Garcia Etxebarria (2000-2001), which in turn is based on AleVT 1.5.1 by Edgar Toernig (1998-1999). See also http://zapping.sourceforge.net/

License

Copyright (C) 2006-2020 T. Zoerner.

Parts of the descriptions in this man page are copied from the “libzvbi” documentation, licensed under the GNU General Public License version 2 or later. The respective copyright is by the following:

  • Copyright (C) 2000-2007 Michael H. Schimek,
  • Copyright (C) 2000-2001 Inaki Garcia Etxebarria,
  • Copyright (C) 2003-2004 Tom Zoerner.

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Files for Zvbi, version 0.1.1
Filename, size File type Python version Upload date Hashes
Filename, size Zvbi-0.1.1.tar.gz (245.2 kB) File type Source Python version None Upload date Hashes View

Supported by

Pingdom Pingdom Monitoring Google Google Object Storage and Download Analytics Sentry Sentry Error logging AWS AWS Cloud computing DataDog DataDog Monitoring Fastly Fastly CDN DigiCert DigiCert EV certificate StatusPage StatusPage Status page