Skip to content

Commit 437e4b8

Browse files
committed
add samples and user_owned
Signed-off-by: Kasiewicz, Marek <marek.kasiewicz@intel.com>
1 parent da2087d commit 437e4b8

12 files changed

+1931
-40
lines changed

app/meson.build

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,35 @@ executable('RxSt20CombinedRedundantSample', redundant_rx_st20_combined_sample_so
441441
dependencies: [asan_dep, mtl, libpthread, ws2_32_dep, mman_dep]
442442
)
443443

444+
# New unified API samples
445+
executable('NewApiTxVideoLibOwned', new_api_tx_video_lib_owned_sources,
446+
c_args : app_c_args,
447+
link_args: app_ld_args,
448+
# asan should be always the first dep
449+
dependencies: [asan_dep, mtl, libpthread, ws2_32_dep, mman_dep]
450+
)
451+
452+
executable('NewApiRxVideoLibOwned', new_api_rx_video_lib_owned_sources,
453+
c_args : app_c_args,
454+
link_args: app_ld_args,
455+
# asan should be always the first dep
456+
dependencies: [asan_dep, mtl, libpthread, ws2_32_dep, mman_dep]
457+
)
458+
459+
executable('NewApiTxVideoUserOwned', new_api_tx_video_user_owned_sources,
460+
c_args : app_c_args,
461+
link_args: app_ld_args,
462+
# asan should be always the first dep
463+
dependencies: [asan_dep, mtl, libpthread, ws2_32_dep, mman_dep]
464+
)
465+
466+
executable('NewApiRxVideoUserOwned', new_api_rx_video_user_owned_sources,
467+
c_args : app_c_args,
468+
link_args: app_ld_args,
469+
# asan should be always the first dep
470+
dependencies: [asan_dep, mtl, libpthread, ws2_32_dep, mman_dep]
471+
)
472+
444473
# Dma sample app
445474
executable('DmaSample', dma_sample_sources,
446475
c_args : app_c_args,

app/sample/meson.build

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ dma_sample_sources = files('dma/dma_sample.c', 'sample_util.c')
5050
redundant_rx_st20_combined_sample_sources = files('experimental/rx_st20_redundant_combined_sample.c',
5151
'sample_util.c')
5252

53+
# new unified API
54+
new_api_tx_video_lib_owned_sources = files('new_api/tx_video_lib_owned_sample.c', 'sample_util.c')
55+
new_api_rx_video_lib_owned_sources = files('new_api/rx_video_lib_owned_sample.c', 'sample_util.c')
56+
new_api_tx_video_user_owned_sources = files('new_api/tx_video_user_owned_sample.c', 'sample_util.c')
57+
new_api_rx_video_user_owned_sources = files('new_api/rx_video_user_owned_sample.c', 'sample_util.c')
58+
5359
# gpu direct
5460
gpu_direct_tx_sample_sources = files('gpu_direct/tx_st20_pipeline_gpu_direct.c', 'sample_util.c')
5561
gpu_direct_rx_sample_sources = files('gpu_direct/rx_st20_pipeline_gpu_direct.c', 'sample_util.c')
Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
/* SPDX-License-Identifier: BSD-3-Clause
2+
* Copyright(c) 2024 Intel Corporation
3+
*/
4+
5+
/**
6+
* @file rx_video_lib_owned_sample.c
7+
*
8+
* New unified API sample: RX video with library-owned buffers.
9+
* Library manages buffer allocation. App uses buffer_get/put loop.
10+
*
11+
* Usage:
12+
* ./NewApiRxVideoLibOwned --p_port 0000:4b:01.1 --p_sip 192.168.96.3 \
13+
* --p_rx_ip 239.168.85.20 --udp_port 20000
14+
*/
15+
16+
#include "../sample_util.h"
17+
18+
#include <mtl/mtl_session_api.h>
19+
20+
struct rx_sample_ctx {
21+
int idx;
22+
mtl_session_t* session;
23+
24+
bool stop;
25+
pthread_t frame_thread;
26+
27+
int fb_recv;
28+
size_t frame_size;
29+
30+
/* Optional: dump received frames to file */
31+
int dst_fd;
32+
uint8_t* dst_begin;
33+
uint8_t* dst_end;
34+
uint8_t* dst_cursor;
35+
int fb_cnt;
36+
};
37+
38+
static int rx_open_dest(struct rx_sample_ctx* s, const char* file) {
39+
int fd, ret, idx = s->idx;
40+
off_t f_size;
41+
int fb_cnt = 3;
42+
43+
fd = st_open_mode(file, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
44+
if (fd < 0) {
45+
err("%s(%d), open %s fail\n", __func__, idx, file);
46+
return -EIO;
47+
}
48+
49+
f_size = fb_cnt * s->frame_size;
50+
ret = ftruncate(fd, f_size);
51+
if (ret < 0) {
52+
err("%s(%d), ftruncate %s fail\n", __func__, idx, file);
53+
close(fd);
54+
return -EIO;
55+
}
56+
57+
uint8_t* m = mmap(NULL, f_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
58+
if (MAP_FAILED == m) {
59+
err("%s(%d), mmap %s fail\n", __func__, idx, file);
60+
close(fd);
61+
return -EIO;
62+
}
63+
64+
s->dst_begin = m;
65+
s->dst_cursor = m;
66+
s->dst_end = m + f_size;
67+
s->dst_fd = fd;
68+
info("%s(%d), save %d framebuffers to file %s(%p,%" PRIu64 ")\n", __func__, idx,
69+
fb_cnt, file, m, f_size);
70+
return 0;
71+
}
72+
73+
static void rx_close_dest(struct rx_sample_ctx* s) {
74+
if (s->dst_begin) {
75+
munmap(s->dst_begin, s->dst_end - s->dst_begin);
76+
s->dst_begin = NULL;
77+
}
78+
if (s->dst_fd >= 0) {
79+
close(s->dst_fd);
80+
s->dst_fd = -1;
81+
}
82+
}
83+
84+
static void rx_consume_frame(struct rx_sample_ctx* s, mtl_buffer_t* buf) {
85+
s->fb_recv++;
86+
if (s->dst_fd < 0) return; /* no dump */
87+
88+
if (s->dst_cursor + s->frame_size > s->dst_end) s->dst_cursor = s->dst_begin;
89+
mtl_memcpy(s->dst_cursor, buf->data, s->frame_size);
90+
s->dst_cursor += s->frame_size;
91+
}
92+
93+
static void* rx_frame_thread(void* arg) {
94+
struct rx_sample_ctx* s = arg;
95+
mtl_session_t* session = s->session;
96+
mtl_buffer_t* buf = NULL;
97+
int ret;
98+
99+
info("%s(%d), start\n", __func__, s->idx);
100+
while (!s->stop) {
101+
ret = mtl_session_buffer_get(session, &buf, 1000);
102+
if (ret == -EAGAIN) {
103+
info("%s(%d), session stopped\n", __func__, s->idx);
104+
break;
105+
}
106+
if (ret == -ETIMEDOUT) {
107+
continue;
108+
}
109+
if (ret < 0) {
110+
err("%s(%d), buffer_get error: %d\n", __func__, s->idx, ret);
111+
break;
112+
}
113+
114+
if (buf->flags & MTL_BUF_FLAG_INCOMPLETE) {
115+
dbg("%s(%d), incomplete frame\n", __func__, s->idx);
116+
}
117+
118+
rx_consume_frame(s, buf);
119+
120+
ret = mtl_session_buffer_put(session, buf);
121+
if (ret < 0) {
122+
err("%s(%d), buffer_put error: %d\n", __func__, s->idx, ret);
123+
break;
124+
}
125+
126+
if (s->fb_recv % 100 == 0)
127+
info("%s(%d), received %d frames\n", __func__, s->idx, s->fb_recv);
128+
}
129+
info("%s(%d), stop, received %d frames\n", __func__, s->idx, s->fb_recv);
130+
131+
return NULL;
132+
}
133+
134+
int main(int argc, char** argv) {
135+
struct st_sample_context ctx;
136+
int ret;
137+
138+
memset(&ctx, 0, sizeof(ctx));
139+
ret = rx_sample_parse_args(&ctx, argc, argv);
140+
if (ret < 0) return ret;
141+
142+
ctx.param.flags |= MTL_FLAG_DEV_AUTO_START_STOP;
143+
ctx.st = mtl_init(&ctx.param);
144+
if (!ctx.st) {
145+
err("%s, mtl_init fail\n", __func__);
146+
return -EIO;
147+
}
148+
149+
uint32_t session_num = ctx.sessions;
150+
struct rx_sample_ctx* app[session_num];
151+
152+
for (int i = 0; i < session_num; i++) {
153+
app[i] = malloc(sizeof(struct rx_sample_ctx));
154+
if (!app[i]) {
155+
err("%s(%d), app context malloc fail\n", __func__, i);
156+
ret = -ENOMEM;
157+
goto error;
158+
}
159+
memset(app[i], 0, sizeof(struct rx_sample_ctx));
160+
app[i]->idx = i;
161+
app[i]->stop = false;
162+
app[i]->dst_fd = -1;
163+
app[i]->fb_cnt = ctx.framebuff_cnt;
164+
165+
/* Configure unified session */
166+
mtl_video_config_t config;
167+
memset(&config, 0, sizeof(config));
168+
config.base.direction = MTL_SESSION_RX;
169+
config.base.ownership = MTL_BUFFER_LIBRARY_OWNED;
170+
config.base.num_buffers = ctx.framebuff_cnt;
171+
config.base.name = "new_api_rx_lib";
172+
config.base.flags = MTL_SESSION_FLAG_BLOCK_GET;
173+
174+
/* Port config */
175+
config.rx_port.num_port = ctx.param.num_ports;
176+
memcpy(config.rx_port.ip_addr[MTL_SESSION_PORT_P], ctx.rx_ip_addr[MTL_PORT_P],
177+
MTL_IP_ADDR_LEN);
178+
snprintf(config.rx_port.port[MTL_SESSION_PORT_P], MTL_PORT_MAX_LEN, "%s",
179+
ctx.param.port[MTL_PORT_P]);
180+
config.rx_port.udp_port[MTL_SESSION_PORT_P] = ctx.udp_port + i * 2;
181+
if (config.rx_port.num_port > 1) {
182+
memcpy(config.rx_port.ip_addr[MTL_SESSION_PORT_R], ctx.rx_ip_addr[MTL_PORT_R],
183+
MTL_IP_ADDR_LEN);
184+
snprintf(config.rx_port.port[MTL_SESSION_PORT_R], MTL_PORT_MAX_LEN, "%s",
185+
ctx.param.port[MTL_PORT_R]);
186+
config.rx_port.udp_port[MTL_SESSION_PORT_R] = ctx.udp_port + i * 2;
187+
}
188+
if (ctx.multi_inc_addr) {
189+
config.rx_port.udp_port[MTL_SESSION_PORT_P] = ctx.udp_port;
190+
config.rx_port.ip_addr[MTL_SESSION_PORT_P][3] += i;
191+
}
192+
config.rx_port.payload_type = ctx.payload_type;
193+
194+
/* Video format */
195+
config.width = ctx.width;
196+
config.height = ctx.height;
197+
config.fps = ctx.fps;
198+
config.interlaced = ctx.interlaced;
199+
config.frame_fmt = ctx.output_fmt;
200+
config.transport_fmt = ctx.fmt;
201+
202+
ret = mtl_video_session_create(ctx.st, &config, &app[i]->session);
203+
if (ret < 0) {
204+
err("%s(%d), session create fail: %d\n", __func__, i, ret);
205+
goto error;
206+
}
207+
208+
app[i]->frame_size = mtl_session_get_frame_size(app[i]->session);
209+
info("%s(%d), frame_size %" PRId64 "\n", __func__, i, app[i]->frame_size);
210+
211+
if (ctx.rx_dump) {
212+
ret = rx_open_dest(app[i], ctx.rx_url);
213+
if (ret < 0) goto error;
214+
}
215+
216+
ret = mtl_session_start(app[i]->session);
217+
if (ret < 0) {
218+
err("%s(%d), session start fail: %d\n", __func__, i, ret);
219+
goto error;
220+
}
221+
222+
ret = pthread_create(&app[i]->frame_thread, NULL, rx_frame_thread, app[i]);
223+
if (ret < 0) {
224+
err("%s(%d), thread create fail: %d\n", __func__, i, ret);
225+
ret = -EIO;
226+
goto error;
227+
}
228+
}
229+
230+
while (!ctx.exit) {
231+
sleep(1);
232+
}
233+
234+
/* Stop */
235+
for (int i = 0; i < session_num; i++) {
236+
app[i]->stop = true;
237+
if (app[i]->session) mtl_session_stop(app[i]->session);
238+
pthread_join(app[i]->frame_thread, NULL);
239+
info("%s(%d), received frames %d\n", __func__, i, app[i]->fb_recv);
240+
rx_close_dest(app[i]);
241+
}
242+
243+
/* Check result */
244+
for (int i = 0; i < session_num; i++) {
245+
if (app[i]->fb_recv <= 0) {
246+
err("%s(%d), error, no received frames %d\n", __func__, i, app[i]->fb_recv);
247+
ret = -EIO;
248+
}
249+
}
250+
251+
error:
252+
for (int i = 0; i < session_num; i++) {
253+
if (app[i]) {
254+
if (app[i]->session) mtl_session_destroy(app[i]->session);
255+
free(app[i]);
256+
}
257+
}
258+
259+
if (ctx.st) {
260+
mtl_uninit(ctx.st);
261+
ctx.st = NULL;
262+
}
263+
return ret;
264+
}

0 commit comments

Comments
 (0)