From bef856ada624060d7ca6301f34cf27a4008ce97f Mon Sep 17 00:00:00 2001 From: Frank Du Date: Tue, 19 Dec 2023 14:27:15 +0800 Subject: [PATCH] python/example: add st20p_tx support Signed-off-by: Frank Du --- include/mtl_api.h | 25 ++++- include/st_pipeline_api.h | 16 ++- lib/src/st2110/pipeline/st20_pipeline_tx.c | 3 +- lib/src/st2110/st_fmt.c | 11 ++ python/example/cv2_util.py | 40 ++++++-- python/example/st20p_rx.py | 33 +++--- python/example/st20p_tx.py | 112 +++++++++++++++++++++ 7 files changed, 207 insertions(+), 33 deletions(-) create mode 100644 python/example/st20p_tx.py diff --git a/include/mtl_api.h b/include/mtl_api.h index 4898e7163..61e7b7bf7 100644 --- a/include/mtl_api.h +++ b/include/mtl_api.h @@ -755,6 +755,11 @@ static inline void mtl_para_pmd_set(struct mtl_init_params* p, enum mtl_port por p->pmd[port] = pmd; } +/** Helper to get the port from struct mtl_init_params */ +static inline char* mtl_para_port_get(struct mtl_init_params* p, enum mtl_port port) { + return p->port[port]; +} + /** * Inline function returning primary port pointer from mtl_init_params * @param p @@ -762,7 +767,9 @@ static inline void mtl_para_pmd_set(struct mtl_init_params* p, enum mtl_port por * @return * Primary port name pointer */ -static inline char* mtl_p_port(struct mtl_init_params* p) { return p->port[MTL_PORT_P]; } +static inline char* mtl_p_port(struct mtl_init_params* p) { + return mtl_para_port_get(p, MTL_PORT_P); +} /** * Inline function returning redundant port pointer from mtl_init_params @@ -771,7 +778,9 @@ static inline char* mtl_p_port(struct mtl_init_params* p) { return p->port[MTL_P * @return * Redundant port name pointer */ -static inline char* mtl_r_port(struct mtl_init_params* p) { return p->port[MTL_PORT_R]; } +static inline char* mtl_r_port(struct mtl_init_params* p) { + return mtl_para_port_get(p, MTL_PORT_R); +} /** * Inline helper function returning primary port source IP address pointer @@ -1459,6 +1468,18 @@ static inline size_t mtl_size_page_align(size_t sz, size_t pg_sz) { return sz; } +/** Helper struct to perform mtl_memcpy with mtl_cpuva_t */ +struct mtl_memcpy_ops { + mtl_cpuva_t dst; + mtl_cpuva_t src; + size_t sz; +}; +/** Helper function to perform mtl_memcpy with mtl_cpuva_t */ +static inline int mtl_memcpy_action(struct mtl_memcpy_ops* ops) { + mtl_memcpy((void*)ops->dst, (const void*)ops->src, ops->sz); + return 0; +} + #if defined(__cplusplus) } #endif diff --git a/include/st_pipeline_api.h b/include/st_pipeline_api.h index 01bacbfde..f0c49c0bc 100644 --- a/include/st_pipeline_api.h +++ b/include/st_pipeline_api.h @@ -1934,8 +1934,22 @@ static inline void st_rxp_para_udp_port_set(struct st_rx_port* p, enum mtl_port p->udp_port[port] = udp_port; } +/** Helper to set the port for struct st_tx_port */ +int st_txp_para_port_set(struct st_tx_port* p, enum mtl_session_port port, char* name); +/** Helper to set the dip for struct st_tx_port */ +int st_txp_para_dip_set(struct st_tx_port* p, enum mtl_port port, char* ip); +/** Helper to set the udp port number for struct st_tx_port */ +static inline void st_txp_para_udp_port_set(struct st_tx_port* p, enum mtl_port port, + uint16_t udp_port) { + p->udp_port[port] = udp_port; +} + /** Helper to get the frame addr from struct st_frame */ -static inline mtl_cpuva_t st_frame_addr(struct st_frame* frame, uint8_t plane) { +static inline void* st_frame_addr(struct st_frame* frame, uint8_t plane) { + return frame->addr[plane]; +} +/** Helper to get the frame addr(mtl_cpuva_t) from struct st_frame */ +static inline mtl_cpuva_t st_frame_addr_cpuva(struct st_frame* frame, uint8_t plane) { return (mtl_cpuva_t)frame->addr[plane]; } /** Helper to get the frame iova from struct st_frame */ diff --git a/lib/src/st2110/pipeline/st20_pipeline_tx.c b/lib/src/st2110/pipeline/st20_pipeline_tx.c index 0e56474b3..4abe7b3c6 100644 --- a/lib/src/st2110/pipeline/st20_pipeline_tx.c +++ b/lib/src/st2110/pipeline/st20_pipeline_tx.c @@ -636,8 +636,7 @@ st20p_tx_handle st20p_tx_create(mtl_handle mt, struct st20p_tx_ops* ops) { } if (!ops->notify_frame_available) { - err("%s, pls set notify_frame_available\n", __func__); - return NULL; + warn("%s, pls set notify_frame_available\n", __func__); } src_size = st_frame_size(ops->input_fmt, ops->width, ops->height, ops->interlaced); diff --git a/lib/src/st2110/st_fmt.c b/lib/src/st2110/st_fmt.c index 6141f9e53..b4767b3b5 100644 --- a/lib/src/st2110/st_fmt.c +++ b/lib/src/st2110/st_fmt.c @@ -1250,3 +1250,14 @@ int st_rxp_para_sip_set(struct st_rx_port* p, enum mtl_port port, char* ip) { err("%s, fail to inet_pton for %s\n", __func__, ip); return -EIO; } + +int st_txp_para_port_set(struct st_tx_port* p, enum mtl_session_port port, char* name) { + return snprintf(p->port[port], MTL_PORT_MAX_LEN, "%s", name); +} + +int st_txp_para_dip_set(struct st_tx_port* p, enum mtl_port port, char* ip) { + int ret = inet_pton(AF_INET, ip, p->dip_addr[port]); + if (ret == 1) return 0; + err("%s, fail to inet_pton for %s\n", __func__, ip); + return -EIO; +} diff --git a/python/example/cv2_util.py b/python/example/cv2_util.py index ef58e9d2e..fe4977213 100644 --- a/python/example/cv2_util.py +++ b/python/example/cv2_util.py @@ -3,6 +3,7 @@ # opencv2 utils import ctypes +import sys import cv2 import numpy as np @@ -67,7 +68,7 @@ def display_yuv422(y, u, v): yuv = cv2.merge([y, u, v]) display_img = cv2.cvtColor(yuv, cv2.COLOR_YUV2BGR) - cv2.imshow("st20p_rx_python", display_img) + cv2.imshow(sys.argv[0], display_img) cv2.waitKey(1) @@ -77,7 +78,9 @@ def destroy(): def frame_display_yuv422p8(frame, display_scale_factor): # Pack frame pointer from frame addr - ptr = (ctypes.c_ubyte * (frame.data_size)).from_address(mtl.st_frame_addr(frame, 0)) + ptr = (ctypes.c_ubyte * (frame.data_size)).from_address( + mtl.st_frame_addr_cpuva(frame, 0) + ) width = frame.width height = frame.height @@ -91,7 +94,9 @@ def frame_display_yuv422p8(frame, display_scale_factor): def frame_display_yuv422p10le(frame, display_scale_factor): # Pack frame pointer from frame addr - ptr = (ctypes.c_ubyte * (frame.data_size)).from_address(mtl.st_frame_addr(frame, 0)) + ptr = (ctypes.c_ubyte * (frame.data_size)).from_address( + mtl.st_frame_addr_cpuva(frame, 0) + ) width = frame.width height = frame.height @@ -106,7 +111,9 @@ def frame_display_yuv422p10le(frame, display_scale_factor): def frame_display_uyvy(frame, display_scale_factor): # Pack frame pointer from frame addr - ptr = (ctypes.c_ubyte * (frame.data_size)).from_address(mtl.st_frame_addr(frame, 0)) + ptr = (ctypes.c_ubyte * (frame.data_size)).from_address( + mtl.st_frame_addr_cpuva(frame, 0) + ) width = frame.width height = frame.height downscaled_width = width // display_scale_factor @@ -122,14 +129,27 @@ def frame_display_uyvy(frame, display_scale_factor): def frame_display_rfc4175be10(mtl_handle, frame, display_scale_factor): - yuv422p10le_frame = mtl.st_frame_create( + yuv422p8_frame = mtl.st_frame_create( mtl_handle, - mtl.ST_FRAME_FMT_YUV422PLANAR10LE, + mtl.ST_FRAME_FMT_YUV422PLANAR8, frame.width, frame.height, frame.interlaced, ) - if yuv422p10le_frame: - mtl.st_frame_convert(frame, yuv422p10le_frame) - frame_display_yuv422p10le(yuv422p10le_frame, display_scale_factor) - mtl.st_frame_free(yuv422p10le_frame) + if yuv422p8_frame: + mtl.st_frame_convert(frame, yuv422p8_frame) + frame_display_yuv422p8(yuv422p8_frame, display_scale_factor) + mtl.st_frame_free(yuv422p8_frame) + + +def frame_display(mtl_handle, frame, display_scale_factor): + if frame.fmt == mtl.ST_FRAME_FMT_YUV422PLANAR10LE: + frame_display_yuv422p10le(frame, display_scale_factor) + elif frame.fmt == mtl.ST_FRAME_FMT_UYVY: + frame_display_uyvy(frame, display_scale_factor) + elif frame.fmt == mtl.ST_FRAME_FMT_YUV422PLANAR8: + frame_display_yuv422p8(frame, display_scale_factor) + elif frame.fmt == mtl.ST_FRAME_FMT_YUV422RFC4175PG2BE10: + frame_display_rfc4175be10(mtl_handle, frame, display_scale_factor) + else: + print(f"Unknown fmt: {mtl.st_frame_fmt_name(frame.fmt)}") diff --git a/python/example/st20p_rx.py b/python/example/st20p_rx.py index d408406e6..12951fed3 100644 --- a/python/example/st20p_rx.py +++ b/python/example/st20p_rx.py @@ -1,14 +1,14 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright 2023 Intel Corporation -from pickle import TRUE +import sys import cv2_util import pymtl as mtl def main(): - display = TRUE + display = True display_scale_factor = 2 # ST_FRAME_FMT_YUV422PLANAR10LE, mtl.ST_FRAME_FMT_UYVY # or ST_FRAME_FMT_YUV422RFC4175PG2BE10, ST_FRAME_FMT_YUV422PLANAR8 @@ -25,6 +25,9 @@ def main(): # Create MTL instance mtl_handle = mtl.mtl_init(init_para) + if not mtl_handle: + print("mtl_init fail") + sys.exit(1) # Create st20p rx session rx_para = mtl.st20p_rx_ops() @@ -37,7 +40,11 @@ def main(): rx_para.output_fmt = output_fmt # rx port rx_port = mtl.st_rx_port() - mtl.st_rxp_para_port_set(rx_port, mtl.MTL_SESSION_PORT_P, "0000:af:01.0") + mtl.st_rxp_para_port_set( + rx_port, + mtl.MTL_SESSION_PORT_P, + mtl.mtl_para_port_get(init_para, mtl.MTL_SESSION_PORT_P), + ) rx_port.num_port = 1 mtl.st_rxp_para_sip_set(rx_port, mtl.MTL_SESSION_PORT_P, "239.168.85.20") mtl.st_rxp_para_udp_port_set(rx_port, mtl.MTL_SESSION_PORT_P, 20000) @@ -45,30 +52,20 @@ def main(): rx_para.port = rx_port # create st20p_rx session st20p_rx = mtl.st20p_rx_create(mtl_handle, rx_para) + if not st20p_rx: + print("st20p_rx_create fail") + sys.exit(1) # loop until ctrl-c try: while True: frame = mtl.st20p_rx_get_frame(st20p_rx) if frame: - # print(f"frame addr: {hex(mtl.st_frame_addr(frame, 0))}") + # print(f"frame addr: {hex(mtl.st_frame_addr_cpuva(frame, 0))}") # print(f"frame iova: {hex(mtl.st_frame_iova(frame, 0))}") # print(f"pkts_total: {frame.pkts_total}") if display: - if output_fmt == mtl.ST_FRAME_FMT_YUV422PLANAR10LE: - cv2_util.frame_display_yuv422p10le(frame, display_scale_factor) - elif output_fmt == mtl.ST_FRAME_FMT_UYVY: - cv2_util.frame_display_uyvy(frame, display_scale_factor) - elif output_fmt == mtl.ST_FRAME_FMT_YUV422PLANAR8: - cv2_util.frame_display_yuv422p8(frame, display_scale_factor) - elif output_fmt == mtl.ST_FRAME_FMT_YUV422RFC4175PG2BE10: - cv2_util.frame_display_rfc4175be10( - mtl_handle, frame, display_scale_factor - ) - else: - print( - f"Unknown output_fmt: {mtl.st_frame_fmt_name(output_fmt)}" - ) + cv2_util.frame_display(mtl_handle, frame, display_scale_factor) # return the frame mtl.st20p_rx_put_frame(st20p_rx, frame) diff --git a/python/example/st20p_tx.py b/python/example/st20p_tx.py new file mode 100644 index 000000000..84c4508c6 --- /dev/null +++ b/python/example/st20p_tx.py @@ -0,0 +1,112 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2023 Intel Corporation + +import ctypes +import sys + +import cv2_util +import pymtl as mtl + + +def main(): + display = False + display_scale_factor = 2 + # ST_FRAME_FMT_YUV422PLANAR10LE or ST_FRAME_FMT_YUV422RFC4175PG2BE10 + input_fmt = mtl.ST_FRAME_FMT_YUV422PLANAR10LE + # yuv422p10le_1080p.yuv or yuv422rfc4175be10_1080p.yuv + yuv_file_path = "yuv422p10le_1080p.yuv" + + yuv_file = open(yuv_file_path, "rb") + if not yuv_file: + print(f"Open {yuv_file_path} fail") + sys.exit(1) + + # 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_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 + # 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 + try: + while True: + frame = mtl.st20p_tx_get_frame(st20p_tx) + if frame: + # print(f"frame addr: {hex(mtl.st_frame_addr_cpuva(frame, 0))}") + # print(f"frame iova: {hex(mtl.st_frame_iova(frame, 0))}") + yuv_frame = yuv_file.read(frame_sz) + if not yuv_frame: + yuv_file.seek(0) + # print("EOF") + yuv_frame = yuv_file.read(frame_sz) + if yuv_frame: + src_p = ctypes.c_char_p(yuv_frame) + src_address = ctypes.cast(src_p, ctypes.c_void_p).value + src_address_uint64 = ctypes.c_uint64(src_address).value + # mtl_memcpy_action + memcpy_ops = mtl.mtl_memcpy_ops() + memcpy_ops.dst = mtl.st_frame_addr_cpuva(frame, 0) + memcpy_ops.src = src_address_uint64 + memcpy_ops.sz = frame_sz + mtl.mtl_memcpy_action(memcpy_ops) + if display: + cv2_util.frame_display(mtl_handle, frame, display_scale_factor) + else: + print(f"Fail to read {hex(frame_sz)} from {yuv_file_path}") + mtl.st20p_tx_put_frame(st20p_tx, frame) + + except KeyboardInterrupt: + print("KeyboardInterrupt") + + # Free st20p_tx session + mtl.st20p_tx_free(st20p_tx) + + # Close file + yuv_file.close() + + # Free MTL instance + mtl.mtl_uninit(mtl_handle) + + print("Everything fine, bye") + + +if __name__ == "__main__": + main()