Skip to content

Commit

Permalink
st20p/rx: add auto detect support for non-ext-frame mode (#857)
Browse files Browse the repository at this point in the history
test with:
./build/app/RxVideoAutoDetectSample --rx_dump
./build/app/RxVideoAutoDetectSample --rx_dump --pipeline_fmt
YUV422RFC4175PG2BE10

Signed-off-by: Frank Du <[email protected]>
  • Loading branch information
frankdjx authored May 13, 2024
1 parent 8806506 commit 587c4a8
Show file tree
Hide file tree
Showing 8 changed files with 344 additions and 17 deletions.
15 changes: 11 additions & 4 deletions app/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -299,18 +299,18 @@ executable('RxSt20pTxSt20pMergeFwd', rx_st20p_tx_st20p_merge_fwd_sources,
)

# Misc video samples app
executable('TxVideoSplitSample', video_tx_split_sample_sources,
executable('RxVideoTimingParserSample', rx_st20p_timing_parser_sample_sources,
c_args : app_c_args,
link_args: app_ld_args,
# asan should be always the first dep
dependencies: [asan_dep, mtl, ws2_32_dep, mman_dep]
dependencies: [asan_dep, mtl, libpthread, ws2_32_dep]
)

executable('RxVideoTimingParserSample', rx_st20p_timing_parser_sample_sources,
executable('RxVideoAutoDetectSample', rx_st20p_auto_detect_sample_sources,
c_args : app_c_args,
link_args: app_ld_args,
# asan should be always the first dep
dependencies: [asan_dep, mtl, libpthread, ws2_32_dep]
dependencies: [asan_dep, mtl, libpthread, ws2_32_dep, mman_dep]
)

# Legacy video samples app
Expand Down Expand Up @@ -371,6 +371,13 @@ executable('RxSt20pHdrSplitGpuDirect', pipeline_rx_st20_dyn_hdr_split_gpu_direct
dependencies: [asan_dep, mtl, libpthread, ws2_32_dep, mman_dep]
)

executable('TxVideoSplitSample', video_tx_split_sample_sources,
c_args : app_c_args,
link_args: app_ld_args,
# asan should be always the first dep
dependencies: [asan_dep, mtl, ws2_32_dep, mman_dep]
)

# Low level video samples app
executable('TxRtpVideoSample', video_tx_rtp_sample_sources,
c_args : app_c_args,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Copyright(c) 2022 Intel Corporation
*/

#include "sample_util.h"
#include "../sample_util.h"

struct tv_split_sample_ctx {
int idx;
Expand Down
3 changes: 2 additions & 1 deletion app/sample/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@ rx_st20p_tx_st20p_downsample_fwd_sources = files('fwd/rx_st20p_tx_st20p_downsamp
rx_st20p_tx_st20p_downsample_merge_fwd_sources = files('fwd/rx_st20p_tx_st20p_downsample_merge_fwd.c', 'sample_util.c')

# misc
video_tx_split_sample_sources = files('tx_video_split_sample.c', 'sample_util.c')
rx_st20p_timing_parser_sample_sources = files('rx_st20p_timing_parser_sample.c', 'sample_util.c')
rx_st20p_auto_detect_sample_sources = files('rx_st20p_auto_detect_sample.c', 'sample_util.c')

# ext frame
pipeline_tx_st20_ext_frame_sample_sources = files('ext_frame/tx_st20_pipeline_ext_frame_sample.c', 'sample_util.c')
pipeline_rx_st20_dyn_ext_frame_sample_sources = files('ext_frame/rx_st20_pipeline_dyn_ext_frame_sample.c', 'sample_util.c')
pipeline_rx_st20_dyn_hdr_split_gpu_direct_sources = files('ext_frame/rx_st20p_hdr_split_gpu_direct.c', 'sample_util.c')
video_tx_split_sample_sources = files('ext_frame/tx_video_split_sample.c', 'sample_util.c')

# legacy
video_tx_sample_sources = files('legacy/tx_video_sample.c', 'sample_util.c')
Expand Down
249 changes: 249 additions & 0 deletions app/sample/rx_st20p_auto_detect_sample.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2024 Intel Corporation
*/

#include "sample_util.h"

struct rx_st20p_auto_detect_ctx {
int idx;
st20p_rx_handle handle;

bool stop;
pthread_t frame_thread;
struct st_sample_context* ctx;

int fb_recv;

size_t frame_size;
int dst_fd;
uint8_t* dst_begin;
uint8_t* dst_end;
uint8_t* dst_cursor;

int fb_cnt;
};

static int rx_st20p_close_source(struct rx_st20p_auto_detect_ctx* s) {
if (s->dst_begin) {
munmap(s->dst_begin, s->dst_end - s->dst_begin);
s->dst_begin = NULL;
}
if (s->dst_fd >= 0) {
close(s->dst_fd);
s->dst_fd = 0;
}

return 0;
}

static int rx_st20p_open_source(struct rx_st20p_auto_detect_ctx* s, const char* file) {
int fd, ret, idx = s->idx;
off_t f_size;
int fb_cnt = 3;

fd = st_open_mode(file, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (fd < 0) {
err("%s(%d), open %s fail\n", __func__, idx, file);
return -EIO;
}

f_size = fb_cnt * s->frame_size;
ret = ftruncate(fd, f_size);
if (ret < 0) {
err("%s(%d), ftruncate %s fail\n", __func__, idx, file);
close(fd);
return -EIO;
}

uint8_t* m = mmap(NULL, f_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (MAP_FAILED == m) {
err("%s(%d), mmap %s fail\n", __func__, idx, file);
close(fd);
return -EIO;
}

s->dst_begin = m;
s->dst_cursor = m;
s->dst_end = m + f_size;
s->dst_fd = fd;
info("%s(%d), save %d framebuffers to file %s(%p,%" PRIu64 ")\n", __func__, idx, fb_cnt,
file, m, f_size);

return 0;
}

static void rx_st20p_consume_frame(struct rx_st20p_auto_detect_ctx* s,
struct st_frame* frame) {
s->fb_recv++;
if (s->dst_fd < 0) return; /* no dump */

if (s->dst_cursor + s->frame_size > s->dst_end) s->dst_cursor = s->dst_begin;
mtl_memcpy(s->dst_cursor, frame->addr[0], s->frame_size);
s->dst_cursor += s->frame_size;
}

static void* rx_st20p_frame_thread(void* arg) {
struct rx_st20p_auto_detect_ctx* s = arg;
st20p_rx_handle handle = s->handle;
struct st_frame* frame;

info("%s(%d), start\n", __func__, s->idx);
while (!s->stop) {
frame = st20p_rx_get_frame(handle);
if (!frame) { /* no frame */
warn("%s(%d), get frame time out\n", __func__, s->idx);
continue;
}
dbg("%s(%d), one new frame\n", __func__, s->idx);
if (frame->user_meta) {
const struct st_frame_user_meta* user_meta = frame->user_meta;
if (frame->user_meta_size != sizeof(*user_meta)) {
err("%s(%d), user_meta_size wrong\n", __func__, s->idx);
}
info("%s(%d), user_meta %d %s\n", __func__, s->idx, user_meta->idx,
user_meta->dummy);
}
rx_st20p_consume_frame(s, frame);
st20p_rx_put_frame(handle, frame);
}
info("%s(%d), stop\n", __func__, s->idx);

return NULL;
}

static int rx_st20p_notify_detected(void* priv, const struct st20_detect_meta* meta,
struct st20_detect_reply* reply) {
struct rx_st20p_auto_detect_ctx* s = priv;
MTL_MAY_UNUSED(meta);
MTL_MAY_UNUSED(reply);

s->frame_size = st20p_rx_frame_size(s->handle);
info("%s(%d), frame_size %" PRId64 "\n", __func__, s->idx, s->frame_size);
if (s->ctx->rx_dump) {
rx_st20p_open_source(s, s->ctx->rx_url);
}

return 0;
}

int main(int argc, char** argv) {
struct st_sample_context ctx;
int ret;

/* init sample(st) dev */
memset(&ctx, 0, sizeof(ctx));
ret = rx_sample_parse_args(&ctx, argc, argv);
if (ret < 0) return ret;

ctx.st = mtl_init(&ctx.param);
if (!ctx.st) {
err("%s: mtl_init fail\n", __func__);
return -EIO;
}

uint32_t session_num = ctx.sessions;
struct rx_st20p_auto_detect_ctx* app[session_num];

// create and register rx session
for (int i = 0; i < session_num; i++) {
app[i] = malloc(sizeof(struct rx_st20p_auto_detect_ctx));
if (!app[i]) {
err("%s(%d), app context malloc fail\n", __func__, i);
ret = -ENOMEM;
goto error;
}
memset(app[i], 0, sizeof(struct rx_st20p_auto_detect_ctx));
app[i]->idx = i;
app[i]->stop = false;
app[i]->dst_fd = -1;
app[i]->fb_cnt = ctx.framebuff_cnt;
app[i]->ctx = &ctx;

struct st20p_rx_ops ops_rx;
memset(&ops_rx, 0, sizeof(ops_rx));
ops_rx.name = "st20p_test";
ops_rx.priv = app[i]; // app handle register to lib
ops_rx.port.num_port = ctx.param.num_ports;
memcpy(ops_rx.port.ip_addr[MTL_SESSION_PORT_P], ctx.rx_ip_addr[MTL_PORT_P],
MTL_IP_ADDR_LEN);
snprintf(ops_rx.port.port[MTL_SESSION_PORT_P], MTL_PORT_MAX_LEN, "%s",
ctx.param.port[MTL_PORT_P]);
ops_rx.port.udp_port[MTL_SESSION_PORT_P] = ctx.udp_port + i * 2;
if (ops_rx.port.num_port > 1) {
memcpy(ops_rx.port.ip_addr[MTL_SESSION_PORT_R], ctx.rx_ip_addr[MTL_PORT_R],
MTL_IP_ADDR_LEN);
snprintf(ops_rx.port.port[MTL_SESSION_PORT_R], MTL_PORT_MAX_LEN, "%s",
ctx.param.port[MTL_PORT_R]);
ops_rx.port.udp_port[MTL_SESSION_PORT_R] = ctx.udp_port + i * 2;
}
ops_rx.port.payload_type = ctx.payload_type;
/* not set width, height, fps as not known now */
ops_rx.interlaced = ctx.interlaced;
ops_rx.transport_fmt = ctx.fmt;
ops_rx.output_fmt = ctx.output_fmt;
ops_rx.device = ST_PLUGIN_DEVICE_AUTO;
ops_rx.framebuff_cnt = app[i]->fb_cnt;
ops_rx.flags |= ST20P_RX_FLAG_BLOCK_GET;
/* enable auto detect */
ops_rx.flags |= ST20P_RX_FLAG_AUTO_DETECT;
ops_rx.notify_detected = rx_st20p_notify_detected;

st20p_rx_handle rx_handle = st20p_rx_create(ctx.st, &ops_rx);
if (!rx_handle) {
err("%s(%d), st20p_rx_create fail\n", __func__, i);
ret = -EIO;
goto error;
}
app[i]->handle = rx_handle;

ret = pthread_create(&app[i]->frame_thread, NULL, rx_st20p_frame_thread, app[i]);
if (ret < 0) {
err("%s(%d), thread create fail %d\n", __func__, ret, i);
ret = -EIO;
goto error;
}
}

// start rx
ret = mtl_start(ctx.st);

while (!ctx.exit) {
sleep(1);
}

// stop app thread
for (int i = 0; i < session_num; i++) {
app[i]->stop = true;
if (app[i]->handle) st20p_rx_wake_block(app[i]->handle);
pthread_join(app[i]->frame_thread, NULL);
info("%s(%d), received frames %d\n", __func__, i, app[i]->fb_recv);

rx_st20p_close_source(app[i]);
}

// stop rx
ret = mtl_stop(ctx.st);

// check result
for (int i = 0; i < session_num; i++) {
if (app[i]->fb_recv <= 0) {
err("%s(%d), error, no received frames %d\n", __func__, i, app[i]->fb_recv);
ret = -EIO;
}
}

error:
for (int i = 0; i < session_num; i++) {
if (app[i]) {
if (app[i]->handle) st20p_rx_free(app[i]->handle);
free(app[i]);
}
}

/* release sample(st) dev */
if (ctx.st) {
mtl_uninit(ctx.st);
ctx.st = NULL;
}
return ret;
}
1 change: 1 addition & 0 deletions app/sample/tx_st20_pipeline_sample.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ static int tx_st20p_open_source(struct tx_st20p_sample_ctx* s, char* file) {
}
frame_cnt = i.st_size / s->frame_size;
fbs_size = i.st_size;
info("%s, tx_url %s frame_cnt %d\n", __func__, file, frame_cnt);

init_fb:

Expand Down
Loading

0 comments on commit 587c4a8

Please sign in to comment.