Metadata-Version: 2.5
Name: cyomtlib
Version: 0.1.2
Summary: Python bindings for Open Media Transport (OMT)
Project-URL: Open Media Transport, https://www.openmediatransport.org
License-Expression: MIT
License-File: LICENSE
License-File: LICENSE-OMT.txt
Keywords: broadcast,ndi,omt,open media transport,streaming,video
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Operating System :: MacOS
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Multimedia :: Video
Requires-Python: >=3.9
Requires-Dist: numpy>=1.22
Provides-Extra: examples
Requires-Dist: opencv-python; extra == 'examples'
Provides-Extra: test
Requires-Dist: pytest>=7; extra == 'test'
Description-Content-Type: text/markdown

# cyomtlib

Python bindings for [Open Media Transport](https://www.openmediatransport.org) (OMT).

cyomtlib wraps `libomt`, the C interface to OMT, with `ctypes`. Encoding and
decoding run in native code and NumPy arrays are passed to libomt without
copying, so 1080p60 is realistic from Python. Wheels bundle `libomt` and the
`libvmx` codec, so there is nothing else to install.

| Platform | Wheel | Native libraries |
| --- | --- | --- |
| macOS 10.15+ (Intel and Apple Silicon) | `macosx_10_15_universal2` | official OMT release |
| Windows x64 | `win_amd64` | official OMT release |
| Windows ARM64 | `win_arm64` | official OMT release |
| Linux x86_64 (glibc 2.28+, AVX2 CPU) | `manylinux_2_28_x86_64` | built from source |
| Linux aarch64 (glibc 2.28+) | `manylinux_2_28_aarch64` | built from source |

The package is pure Python, so one wheel per platform covers every Python 3.9+.

On Linux, discovery uses Avahi: install `libavahi-client3` (Debian/Ubuntu) or
`avahi-libs` (Fedora/RHEL) and make sure `avahi-daemon` is running. Without it,
senders and receivers still work but sources are not discovered: connect to
`omt://host:port` URLs or use a discovery server
(`omt.settings.set_discovery_server(...)`). The Linux libraries carry a small
patch for this (`patches/`); unpatched upstream libomt aborts the process when
`avahi-daemon` is not running.

## Install

```sh
pip install cyomtlib
```

## Quick start

The [example scripts](https://github.com/maybites/cyomtlib/tree/main/examples)
are not part of the package. Get them from the repository, together with
OpenCV for the video window:

```sh
git clone https://github.com/maybites/cyomtlib.git
cd cyomtlib
pip install cyomtlib opencv-python
```

In one terminal, publish a 1080p60 test pattern with a 1 kHz tone:

```sh
python examples/send_test_pattern.py "My Pattern"
```

In a second terminal, pick the source from the list and watch it:

```sh
python examples/receive.py --show
```

The receiver prints the resolution and frame rate every second. Close the
window, or press `q` or Esc, to stop. Without `--show` it only prints
statistics and does not need OpenCV. To skip discovery, pass the source name or
an `omt://host:port` URL: `python examples/receive.py "HOSTNAME (My Pattern)"`.

Both scripts also work with other OMT software, for example the OBS plugin or
OMT player from [Open Media Transport](https://www.openmediatransport.org).

## Send

```python
import numpy as np
import cyomtlib as omt

frame = np.zeros((1080, 1920, 4), dtype=np.uint8)  # BGRA
frame[..., 2] = 255                                  # red
frame[..., 3] = 255

with omt.Sender("Python Test Pattern") as sender:
    print("Publishing as", sender.address)
    while True:
        # timestamp=-1 (the default) lets OMT pace the frames to frame_rate.
        sender.send_video(frame, omt.Codec.BGRA, frame_rate=60)
```

`send_video` takes packed formats (`BGRA`, `UYVY`, `YUY2`) as arrays shaped
`(height, width, bytes_per_pixel)` and infers the size. Planar formats (`NV12`,
`YV12`, `UYVA`, `P216`, `PA16`) need `width=` and `height=`. Pass
`flags=omt.VideoFlags.ALPHA` to keep an alpha channel.

Audio is planar float32, shaped `(channels, samples_per_channel)`:

```python
sender.send_audio(np.zeros((2, 960), np.float32), sample_rate=48000)
sender.send_metadata("<scene name='intro'/>")
```

## Discover and receive

```python
import cyomtlib as omt

sources = omt.discover(wait=2.0)          # ["HOSTNAME (Python Test Pattern)", ...]

with omt.Receiver(sources[0], video_format=omt.PreferredVideoFormat.BGRA) as receiver:
    while True:
        frame = receiver.receive(timeout_ms=1000)
        if isinstance(frame, omt.VideoFrame):
            pixels = frame.packed()           # (height, width, 4) uint8 view
        elif isinstance(frame, omt.AudioFrame):
            samples = frame.data              # (channels, samples) float32
        elif isinstance(frame, omt.MetadataFrame):
            print(frame.xml)
```

`receive` copies frame data into NumPy arrays you own. Pass `copy=False` to
get views into libomt's buffers instead; they stay valid only until the next
`receive` call for that frame type. To receive video and audio on separate
threads, call `receive(omt.FrameType.VIDEO)` in one and
`receive(omt.FrameType.AUDIO)` in the other.

Also available: tally (`set_tally`, `get_tally`), sender information,
per-connection metadata, redirects, quality suggestions, video and audio
statistics, settings, and logging:

```python
omt.settings.log_to_python()          # OMT log lines go to logging.getLogger("cyomtlib.omt")
omt.settings.set_integer("NetworkPortStart", 7000)
```

Call `omt.settings.shutdown()` once before the process exits, after every
Sender and Receiver has been closed.

## Using your own libomt build

Set `CYOMTLIB_LIB_DIR` to a folder containing `libomt` and `libvmx`. This
takes precedence over the bundled libraries. The source distribution builds a
wheel without native libraries, which finds libomt this way or on the system
library path.

## License

cyomtlib is MIT licensed. The bundled OMT libraries are MIT licensed by the
Open Media Transport contributors (see `LICENSE-OMT.txt`).
