Skip to content

Commit

Permalink
python/example: add tx from a encoder file
Browse files Browse the repository at this point in the history
python3 python/example/st20p_tx.py

decode YUV video from an encoded file and transmit it as a ST2110
ST_FRAME_FMT_YUV422RFC4175PG2BE10 stream across the network

Signed-off-by: Frank Du <[email protected]>
  • Loading branch information
frankdjx committed Dec 27, 2023
1 parent fa7f9f2 commit 41813f9
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 4 deletions.
16 changes: 12 additions & 4 deletions python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,21 +75,29 @@ Extracting pymtl-0.1-py3.10-linux-x86_64.egg to /usr/local/lib/python3.10/dist-p
Install `opencv-python` dependency:

```bash
# for yuv display
sudo pip3 install opencv-python
# PyAv for video decode/encode
sudo pip3 install av
```

Run example: st20p_rx.py
Execute the `st20p_rx.py` to receive a ST2110 ST_FRAME_FMT_YUV422RFC4175PG2BE10 stream and display it.

```bash
cd $imtl_source_code/
# Customize the port, IP and display option in the code before using
python3 python/example/st20p_rx.py
```

Run example: st20p_tx.py
Run the `st20p_tx.py`, which reads YUV video data from a file and transmits it over the network as a ST2110 ST_FRAME_FMT_YUV422RFC4175PG2BE10 stream.

```bash
cd $imtl_source_code/
# Customize the port, IP and display option in the code before using
python3 python/example/st20p_tx.py
```

Use `decode_st20p_tx.py` to decode YUV video from an encoded file `jellyfish-3-mbps-hd-hevc-10bit.mkv` and transmit it as a ST2110 ST_FRAME_FMT_YUV422RFC4175PG2BE10 stream across the network.

```bash
# Customize the port, IP and display option in the code before using
python3 python/example/decode_st20p_tx.py
```
130 changes: 130 additions & 0 deletions python/example/decode_st20p_tx.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# SPDX-License-Identifier: BSD-3-Clause
# Copyright 2023 Intel Corporation

import ctypes
import sys

import av
import cv2_util
import numpy as np
import pymtl as mtl


def process_frame(mtl_handle, st20p_tx, frame):
# print(f"{frame.format.name}");
# convert to yuv422p10le from yuv420p10le
yuv_frame = frame.reformat(format="yuv422p10le")
tx_frame = mtl.st20p_tx_get_frame(st20p_tx)
if not tx_frame:
print("st20p_tx_get_frame fail, skip this video frame")
pass

width = frame.width
height = frame.height
y_size = width * height
u_size = y_size // 2
v_size = u_size
yuv_array = np.empty(y_size + u_size + v_size, dtype=np.uint16)

# pyav yuv422p10le not support Conversion to numpy array, use copy mode
yuv_array[:y_size] = np.frombuffer(yuv_frame.planes[0], np.uint16)
yuv_array[y_size : y_size + u_size] = np.frombuffer(yuv_frame.planes[1], np.uint16)
yuv_array[y_size + u_size :] = np.frombuffer(yuv_frame.planes[2], np.uint16)
src_p = ctypes.c_char_p(yuv_array.ctypes.data)
src_address = ctypes.cast(src_p, ctypes.c_void_p).value
src_address_uint64 = ctypes.c_uint64(src_address).value

memcpy_ops = mtl.mtl_memcpy_ops()
memcpy_ops.dst = mtl.st_frame_addr_cpuva(tx_frame, 0)
memcpy_ops.src = src_address_uint64
memcpy_ops.sz = tx_frame.data_size
mtl.mtl_memcpy_action(memcpy_ops)

mtl.st20p_tx_put_frame(st20p_tx, tx_frame)


def main():
input_file_path = "jellyfish-3-mbps-hd-hevc-10bit.mkv"
input_fmt = mtl.ST_FRAME_FMT_YUV422PLANAR10LE

# Init para
init_para = mtl.mtl_init_params()
mtl.mtl_para_port_set(init_para, mtl.MTL_PORT_P, "0000:af:01.1")
init_para.num_ports = 1
mtl.mtl_para_sip_set(init_para, mtl.MTL_PORT_P, "192.168.108.101")
init_para.flags = (
mtl.MTL_FLAG_BIND_NUMA
| mtl.MTL_FLAG_DEV_AUTO_START_STOP
| mtl.MTL_FLAG_PTP_ENABLE
)
mtl.mtl_para_tx_queues_cnt_set(init_para, mtl.MTL_PORT_P, 1)
mtl.mtl_para_rx_queues_cnt_set(init_para, mtl.MTL_PORT_P, 0)

# Create MTL instance
mtl_handle = mtl.mtl_init(init_para)
if not mtl_handle:
print("mtl_init fail")
sys.exit(1)

# Create st20p tx session
tx_para = mtl.st20p_tx_ops()
tx_para.name = "st20p_tx_python"
tx_para.width = 1920
tx_para.height = 1080
tx_para.fps = mtl.ST_FPS_P59_94
tx_para.framebuff_cnt = 3
tx_para.transport_fmt = mtl.ST20_FMT_YUV_422_10BIT
tx_para.input_fmt = input_fmt
# tx port
tx_port = mtl.st_tx_port()
mtl.st_txp_para_port_set(
tx_port,
mtl.MTL_SESSION_PORT_P,
mtl.mtl_para_port_get(init_para, mtl.MTL_SESSION_PORT_P),
)
tx_port.num_port = 1
mtl.st_txp_para_dip_set(tx_port, mtl.MTL_SESSION_PORT_P, "239.168.85.20")
mtl.st_txp_para_udp_port_set(tx_port, mtl.MTL_SESSION_PORT_P, 20000)
tx_port.payload_type = 112
tx_para.port = tx_port
# enable block get mode
tx_para.flags = mtl.ST20P_TX_FLAG_BLOCK_GET
# create st20p_tx session
st20p_tx = mtl.st20p_tx_create(mtl_handle, tx_para)
if not st20p_tx:
print("st20p_tx_create fail")
sys.exit(1)
frame_sz = mtl.st20p_tx_frame_size(st20p_tx)
print(f"frame_sz: {hex(frame_sz)}")

# loop until ctrl-c
container = av.open(input_file_path)
try:
stream = next(s for s in container.streams if s.type == "video")
while True:
for frame in container.decode(stream):
process_frame(mtl_handle, st20p_tx, frame)

# seek to the first frame
print("Finish play, seek to first frame")
container.seek(0, stream=stream)

except KeyboardInterrupt:
print("KeyboardInterrupt")

finally:
container.close()

print("Everything fine, bye")

# Free st20p_tx session
mtl.st20p_tx_free(st20p_tx)

# Free MTL instance
mtl.mtl_uninit(mtl_handle)

print("Everything fine, bye")


if __name__ == "__main__":
main()

0 comments on commit 41813f9

Please sign in to comment.