Skip to content

Commit f1b48c0

Browse files
committed
Add: ST40 pipeline samples and refresh docs/USDT hooks
- added dedicated Tx/Rx ST40 pipeline sample apps, - aligned the ST40p USDT provider/macro definitions and the RX implementation, - documented the new workflow and architecture touchpoints.
1 parent 58c022d commit f1b48c0

File tree

10 files changed

+709
-12
lines changed

10 files changed

+709
-12
lines changed

app/meson.build

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ libpthread = cc.find_library('pthread', required : true)
2525
libjson_c = dependency('json-c', required : true)
2626
libpcap = dependency('pcap', required: true)
2727

28+
app_common_includes = include_directories('..', '../include')
29+
2830
libsdl2 = dependency('sdl2', required: false)
2931
if libsdl2.found()
3032
add_global_arguments('-DAPP_HAS_SDL2', language : 'c')
@@ -63,6 +65,9 @@ if get_option('buildtype') != 'debug'
6365
endif
6466
app_c_args += ['-Wall']
6567
app_c_args += ['-Wunused-parameter']
68+
app_c_args += ['-I' + join_paths(meson.current_source_dir(), '..', 'include')]
69+
app_c_args += ['-I' + join_paths(meson.current_build_dir(), '..')]
70+
app_c_args += ['-I' + join_paths(meson.project_build_root(), 'include')]
6671

6772
if is_windows
6873
app_c_args += ['-DWINDOWSENV']
@@ -250,12 +255,25 @@ executable('TxSt30PipelineSample', pipeline_tx_st30_sample_sources,
250255
# asan should be always the first dep
251256
dependencies: [asan_dep, mtl, libpthread, ws2_32_dep, mman_dep]
252257
)
258+
executable('TxSt40PipelineSample', pipeline_tx_st40_sample_sources,
259+
c_args : app_c_args,
260+
link_args: app_ld_args,
261+
include_directories: app_common_includes,
262+
# asan should be always the first dep
263+
dependencies: [asan_dep, mtl, libpthread, ws2_32_dep, mman_dep]
264+
)
253265
executable('RxSt30PipelineSample', pipeline_rx_st30_sample_sources,
254266
c_args : app_c_args,
255267
link_args: app_ld_args,
256268
# asan should be always the first dep
257269
dependencies: [asan_dep, mtl, libpthread, ws2_32_dep, mman_dep]
258270
)
271+
executable('RxSt40PipelineSample', pipeline_rx_st40_sample_sources,
272+
c_args : app_c_args,
273+
link_args: app_ld_args,
274+
# asan should be always the first dep
275+
dependencies: [asan_dep, mtl, libpthread, ws2_32_dep, mman_dep]
276+
)
259277

260278
# Video forward samples app
261279
executable('RxSt20pTxSt22pFwd', rx_st20p_tx_st22p_fwd_sources,

app/sample/meson.build

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ pipeline_tx_st22_sample_sources = files('tx_st22_pipeline_sample.c', 'sample_uti
88
pipeline_rx_st22_sample_sources = files('rx_st22_pipeline_sample.c', 'sample_util.c')
99
pipeline_tx_st30_sample_sources = files('tx_st30_pipeline_sample.c', 'sample_util.c')
1010
pipeline_rx_st30_sample_sources = files('rx_st30_pipeline_sample.c', 'sample_util.c')
11+
pipeline_tx_st40_sample_sources = files('tx_st40_pipeline_sample.c', 'sample_util.c')
12+
pipeline_rx_st40_sample_sources = files('rx_st40_pipeline_sample.c', 'sample_util.c')
1113

1214
# fwd
1315
rx_st20p_tx_st20p_fwd_sources = files('fwd/rx_st20p_tx_st20p_fwd.c', 'sample_util.c')
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
/* SPDX-License-Identifier: BSD-3-Clause
2+
* Copyright(c) 2025 Intel Corporation
3+
*/
4+
5+
#include <mtl/experimental/st40_pipeline_api.h>
6+
7+
#include "sample_util.h"
8+
9+
#define ST40P_SAMPLE_MAX_UDW_SIZE 2048
10+
#define ST40P_SAMPLE_RTP_RING_SIZE 2048
11+
12+
struct rx_st40p_sample_ctx {
13+
int idx;
14+
st40p_rx_handle handle;
15+
16+
bool stop;
17+
pthread_t frame_thread;
18+
19+
int fb_recv;
20+
21+
int dump_fd;
22+
};
23+
24+
static void rx_st40p_close_dump(struct rx_st40p_sample_ctx* s) {
25+
if (s->dump_fd >= 0) {
26+
close(s->dump_fd);
27+
s->dump_fd = -1;
28+
}
29+
}
30+
31+
static int rx_st40p_open_dump(struct rx_st40p_sample_ctx* s, const char* file) {
32+
s->dump_fd = st_open_mode(file, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR);
33+
if (s->dump_fd < 0) {
34+
err("%s(%d), open %s fail\n", __func__, s->idx, file);
35+
return -EIO;
36+
}
37+
return 0;
38+
}
39+
40+
static void rx_st40p_dump_frame(struct rx_st40p_sample_ctx* s,
41+
const struct st40_frame_info* frame_info) {
42+
if (s->dump_fd < 0) return;
43+
44+
dprintf(s->dump_fd, "frame %d meta_num %u udw_bytes %u\n", s->idx, frame_info->meta_num,
45+
frame_info->udw_buffer_fill);
46+
for (uint32_t i = 0; i < frame_info->meta_num; i++) {
47+
const struct st40_meta* meta = &frame_info->meta[i];
48+
dprintf(
49+
s->dump_fd,
50+
" meta[%u]: line=%u offset=%u stream=%u did=0x%02x sdid=0x%02x udw_size=%u\n", i,
51+
meta->line_number, meta->hori_offset, meta->stream_num, meta->did, meta->sdid,
52+
meta->udw_size);
53+
}
54+
if (frame_info->udw_buffer_fill) {
55+
dprintf(s->dump_fd, " udw:");
56+
for (uint32_t i = 0; i < frame_info->udw_buffer_fill; i++) {
57+
if ((i % 32) == 0) dprintf(s->dump_fd, "\n ");
58+
dprintf(s->dump_fd, "%02x ", frame_info->udw_buff_addr[i]);
59+
}
60+
dprintf(s->dump_fd, "\n");
61+
}
62+
dprintf(s->dump_fd, "\n");
63+
}
64+
65+
static void rx_st40p_consume_frame(struct rx_st40p_sample_ctx* s,
66+
struct st40_frame_info* frame_info) {
67+
s->fb_recv++;
68+
info("%s(%d), frame %d meta_num %u udw_bytes %u\n", __func__, s->idx, s->fb_recv,
69+
frame_info->meta_num, frame_info->udw_buffer_fill);
70+
rx_st40p_dump_frame(s, frame_info);
71+
}
72+
73+
static void* rx_st40p_frame_thread(void* arg) {
74+
struct rx_st40p_sample_ctx* s = arg;
75+
st40p_rx_handle handle = s->handle;
76+
struct st40_frame_info* frame_info;
77+
78+
info("%s(%d), start\n", __func__, s->idx);
79+
while (!s->stop) {
80+
frame_info = st40p_rx_get_frame(handle);
81+
if (!frame_info) {
82+
warn("%s(%d), get frame time out\n", __func__, s->idx);
83+
continue;
84+
}
85+
86+
rx_st40p_consume_frame(s, frame_info);
87+
st40p_rx_put_frame(handle, frame_info);
88+
}
89+
info("%s(%d), stop\n", __func__, s->idx);
90+
91+
return NULL;
92+
}
93+
94+
int main(int argc, char** argv) {
95+
struct st_sample_context ctx;
96+
int ret = 0;
97+
98+
memset(&ctx, 0, sizeof(ctx));
99+
ret = rx_sample_parse_args(&ctx, argc, argv);
100+
if (ret < 0) return ret;
101+
102+
ctx.param.flags |= MTL_FLAG_DEV_AUTO_START_STOP;
103+
ctx.st = mtl_init(&ctx.param);
104+
if (!ctx.st) {
105+
err("%s: mtl_init fail\n", __func__);
106+
return -EIO;
107+
}
108+
109+
uint32_t session_num = ctx.sessions;
110+
struct rx_st40p_sample_ctx* app[session_num];
111+
memset(app, 0, sizeof(app));
112+
113+
for (uint32_t i = 0; i < session_num; i++) {
114+
app[i] = malloc(sizeof(*app[i]));
115+
if (!app[i]) {
116+
err("%s(%u), app context malloc fail\n", __func__, i);
117+
ret = -ENOMEM;
118+
goto error;
119+
}
120+
memset(app[i], 0, sizeof(*app[i]));
121+
app[i]->idx = i;
122+
app[i]->dump_fd = -1;
123+
124+
struct st40p_rx_ops ops_rx;
125+
memset(&ops_rx, 0, sizeof(ops_rx));
126+
ops_rx.name = "st40p_rx_sample";
127+
ops_rx.priv = app[i];
128+
ops_rx.port.num_port = ctx.param.num_ports;
129+
130+
memcpy(ops_rx.port.ip_addr[MTL_SESSION_PORT_P], ctx.rx_ip_addr[MTL_PORT_P],
131+
MTL_IP_ADDR_LEN);
132+
snprintf(ops_rx.port.port[MTL_SESSION_PORT_P], MTL_PORT_MAX_LEN, "%s",
133+
ctx.param.port[MTL_PORT_P]);
134+
ops_rx.port.udp_port[MTL_SESSION_PORT_P] = ctx.udp_port + i * 2;
135+
136+
if (ops_rx.port.num_port > 1) {
137+
memcpy(ops_rx.port.ip_addr[MTL_SESSION_PORT_R], ctx.rx_ip_addr[MTL_PORT_R],
138+
MTL_IP_ADDR_LEN);
139+
snprintf(ops_rx.port.port[MTL_SESSION_PORT_R], MTL_PORT_MAX_LEN, "%s",
140+
ctx.param.port[MTL_PORT_R]);
141+
ops_rx.port.udp_port[MTL_SESSION_PORT_R] = ctx.udp_port + i * 2;
142+
}
143+
144+
if (ctx.multi_inc_addr) {
145+
ops_rx.port.udp_port[MTL_SESSION_PORT_P] = ctx.udp_port;
146+
ops_rx.port.ip_addr[MTL_SESSION_PORT_P][3] += i;
147+
if (ops_rx.port.num_port > 1) ops_rx.port.ip_addr[MTL_SESSION_PORT_R][3] += i;
148+
}
149+
150+
ops_rx.port.payload_type = ctx.payload_type;
151+
ops_rx.interlaced = ctx.interlaced;
152+
ops_rx.framebuff_cnt = ctx.framebuff_cnt;
153+
ops_rx.max_udw_buff_size = ST40P_SAMPLE_MAX_UDW_SIZE;
154+
ops_rx.rtp_ring_size = ST40P_SAMPLE_RTP_RING_SIZE;
155+
ops_rx.flags = ST40P_RX_FLAG_BLOCK_GET;
156+
157+
st40p_rx_handle rx_handle = st40p_rx_create(ctx.st, &ops_rx);
158+
if (!rx_handle) {
159+
err("%s(%u), st40p_rx_create fail\n", __func__, i);
160+
ret = -EIO;
161+
goto error;
162+
}
163+
app[i]->handle = rx_handle;
164+
165+
if (ctx.rx_dump) {
166+
char dump_file[ST_SAMPLE_URL_MAX_LEN];
167+
if (session_num == 1) {
168+
snprintf(dump_file, sizeof(dump_file), "%s", ctx.rx_url);
169+
} else {
170+
const size_t suffix_reserve = 16;
171+
size_t copy_len =
172+
sizeof(dump_file) > suffix_reserve ? sizeof(dump_file) - suffix_reserve : 0;
173+
snprintf(dump_file, sizeof(dump_file), "%.*s_%u", (int)copy_len, ctx.rx_url, i);
174+
}
175+
ret = rx_st40p_open_dump(app[i], dump_file);
176+
if (ret < 0) goto error;
177+
}
178+
179+
ret = pthread_create(&app[i]->frame_thread, NULL, rx_st40p_frame_thread, app[i]);
180+
if (ret < 0) {
181+
err("%s(%u), thread create fail %d\n", __func__, i, ret);
182+
ret = -EIO;
183+
goto error;
184+
}
185+
}
186+
187+
while (!ctx.exit) {
188+
sleep(1);
189+
}
190+
191+
for (uint32_t i = 0; i < session_num; i++) {
192+
if (!app[i]) continue;
193+
app[i]->stop = true;
194+
if (app[i]->handle) st40p_rx_wake_block(app[i]->handle);
195+
pthread_join(app[i]->frame_thread, NULL);
196+
info("%s(%u), received frames %d\n", __func__, i, app[i]->fb_recv);
197+
rx_st40p_close_dump(app[i]);
198+
}
199+
200+
for (uint32_t i = 0; i < session_num; i++) {
201+
if (!app[i]) continue;
202+
if (app[i]->fb_recv <= 0) {
203+
err("%s(%u), error, no received frames\n", __func__, i);
204+
ret = -EIO;
205+
}
206+
}
207+
208+
error:
209+
for (uint32_t i = 0; i < session_num; i++) {
210+
if (!app[i]) continue;
211+
if (app[i]->frame_thread) {
212+
app[i]->stop = true;
213+
if (app[i]->handle) st40p_rx_wake_block(app[i]->handle);
214+
pthread_join(app[i]->frame_thread, NULL);
215+
}
216+
if (app[i]->handle) {
217+
st40p_rx_free(app[i]->handle);
218+
app[i]->handle = NULL;
219+
}
220+
rx_st40p_close_dump(app[i]);
221+
free(app[i]);
222+
app[i] = NULL;
223+
}
224+
225+
if (ctx.st) {
226+
mtl_uninit(ctx.st);
227+
ctx.st = NULL;
228+
}
229+
230+
return ret;
231+
}

0 commit comments

Comments
 (0)