Skip to content

Commit

Permalink
Merge branch 'main' into documentation_link
Browse files Browse the repository at this point in the history
  • Loading branch information
skolelis authored Jan 31, 2025
2 parents a99e488 + 4c4d675 commit 6df5e14
Show file tree
Hide file tree
Showing 13 changed files with 323 additions and 46 deletions.
2 changes: 2 additions & 0 deletions ecosystem/gstreamer_plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ The `mtl_st30p_tx` plugin supports the following pad capabilities:
|---------------------|--------|-------------------------------------------------------|-------------------------|---------------|
| tx-samplerate | uint | Sample rate of the audio. | [gst_mtl_supported_audio_sampling](#232-supported-audio-sampling-rates-gst_mtl_supported_audio_sampling) | 0 |
| tx-channels | uint | Number of audio channels. | 1 to 8 | 2 |
| tx-ptime | string | Packetization time for the audio stream. | `1ms`, `125us`, `250us`, `333us`, `4ms`, `80us`, `1.09ms`, `0.14ms`, `0.09ms` | `1.09ms` for 44.1kHz, `1ms` for others |

#### 4.1.2. Example GStreamer Pipeline for Transmission with s16LE format

Expand Down Expand Up @@ -310,6 +311,7 @@ The `mtl_st30p_rx` plugin supports the following pad capabilities:
| rx-channel | uint | Audio channel number. | 0 to G_MAXUINT | 2 |
| rx-sampling | uint | Audio sampling rate. | [gst_mtl_supported_audio_sampling](#232-supported-audio-sampling-rates-gst_mtl_supported_audio_sampling) | 48000 |
| rx-audio-format | string | Audio format type. | `S8`, `S16LE`, `S24LE` | `S16LE` |
| rx-ptime | string | Packetization time for the audio stream. | `1ms`, `125us`, `250us`, `333us`, `4ms`, `80us`, `1.09ms`, `0.14ms`, `0.09ms` | `1.09ms` for 44.1kHz, `1ms` for others |

#### 4.2.2. Preparing Output Path

Expand Down
32 changes: 32 additions & 0 deletions ecosystem/gstreamer_plugin/gst_mtl_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,38 @@ gboolean gst_mtl_common_parse_pixel_format(const char* format, enum st_frame_fmt
return TRUE;
}

gboolean gst_mtl_common_parse_ptime(const char* ptime_str, enum st30_ptime* ptime) {
if (!ptime_str || !ptime) {
GST_ERROR("%s, invalid input\n", __func__);
return FALSE;
}

if (strcmp(ptime_str, "1ms") == 0) {
*ptime = ST30_PTIME_1MS;
} else if (strcmp(ptime_str, "125us") == 0) {
*ptime = ST30_PTIME_125US;
} else if (strcmp(ptime_str, "250us") == 0) {
*ptime = ST30_PTIME_250US;
} else if (strcmp(ptime_str, "333us") == 0) {
*ptime = ST30_PTIME_333US;
} else if (strcmp(ptime_str, "4ms") == 0) {
*ptime = ST30_PTIME_4MS;
} else if (strcmp(ptime_str, "80us") == 0) {
*ptime = ST31_PTIME_80US;
} else if (strcmp(ptime_str, "1.09ms") == 0) {
*ptime = ST31_PTIME_1_09MS;
} else if (strcmp(ptime_str, "0.14ms") == 0) {
*ptime = ST31_PTIME_0_14MS;
} else if (strcmp(ptime_str, "0.09ms") == 0) {
*ptime = ST31_PTIME_0_09MS;
} else {
GST_ERROR("invalid packet time %s\n", ptime_str);
return FALSE;
}

return TRUE;
}

gboolean gst_mtl_common_parse_audio_format(const char* format, enum st30_fmt* audio) {
if (!audio || !format) {
GST_ERROR("%s, invalid input\n", __func__);
Expand Down
1 change: 1 addition & 0 deletions ecosystem/gstreamer_plugin/gst_mtl_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ gboolean gst_mtl_common_parse_fps_code(gint fps_code, enum st_fps* fps);
gboolean gst_mtl_common_parse_pixel_format(const char* format, enum st_frame_fmt* fmt);

gboolean gst_mtl_common_parse_audio_format(const char* format, enum st30_fmt* audio);
gboolean gst_mtl_common_parse_ptime(const char* ptime_str, enum st30_ptime* ptime);
gboolean gst_mtl_common_gst_to_st_sampling(gint sampling,
enum st30_sampling* st_sampling);
gboolean gst_mtl_common_st_to_gst_sampling(enum st30_sampling st_sampling,
Expand Down
26 changes: 25 additions & 1 deletion ecosystem/gstreamer_plugin/gst_mtl_st30p_rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ enum {
PROP_ST30P_RX_CHANNEL,
PROP_ST30P_RX_SAMPLING,
PROP_ST30P_RX_AUDIO_FORMAT,
PROP_ST30P_RX_PTIME,
PROP_MAX
};

Expand Down Expand Up @@ -180,6 +181,12 @@ static void gst_mtl_st30p_rx_class_init(Gst_Mtl_St30p_RxClass* klass) {
gobject_class, PROP_ST30P_RX_AUDIO_FORMAT,
g_param_spec_string("rx-audio-format", "Audio format", "Audio format type.", NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

g_object_class_install_property(
gobject_class, PROP_ST30P_RX_PTIME,
g_param_spec_string("rx-ptime", "Packetization time",
"Packetization time for the audio stream", NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}

static gboolean gst_mtl_st30p_rx_start(GstBaseSrc* basesrc) {
Expand All @@ -205,14 +212,25 @@ static gboolean gst_mtl_st30p_rx_start(GstBaseSrc* basesrc) {
ops_rx->name = "st30src";
ops_rx->channel = src->channel;
ops_rx->port.num_port = 1;
ops_rx->ptime = ST30_PTIME_1MS;
ops_rx->flags |= ST30P_RX_FLAG_BLOCK_GET;

if (!gst_mtl_common_gst_to_st_sampling(src->sampling, &ops_rx->sampling)) {
GST_ERROR("Failed to parse ops_rx sampling %d", src->sampling);
return FALSE;
}

if (src->ptime[0] != '\0') {
if (!gst_mtl_common_parse_ptime(src->ptime, &ops_rx->ptime)) {
GST_ERROR("Failed to parse ops_rx ptime %s", src->ptime);
return FALSE;
}
} else {
if (ops_rx->sampling == ST31_SAMPLING_44K)
ops_rx->ptime = ST31_PTIME_1_09MS;
else
ops_rx->ptime = ST30_PTIME_1MS;
}

if (!gst_mtl_common_parse_audio_format(src->audio_format, &ops_rx->fmt)) {
GST_ERROR("Failed to parse ops_rx audio format %s", src->audio_format);
return FALSE;
Expand Down Expand Up @@ -312,6 +330,9 @@ static void gst_mtl_st30p_rx_set_property(GObject* object, guint prop_id,
case PROP_ST30P_RX_AUDIO_FORMAT:
strncpy(self->audio_format, g_value_get_string(value), MTL_PORT_MAX_LEN);
break;
case PROP_ST30P_RX_PTIME:
g_strlcpy(self->ptime, g_value_get_string(value), MTL_PORT_MAX_LEN);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
Expand Down Expand Up @@ -341,6 +362,9 @@ static void gst_mtl_st30p_rx_get_property(GObject* object, guint prop_id, GValue
case PROP_ST30P_RX_AUDIO_FORMAT:
g_value_set_string(value, src->audio_format);
break;
case PROP_ST30P_RX_PTIME:
g_value_set_string(value, src->ptime);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
Expand Down
2 changes: 1 addition & 1 deletion ecosystem/gstreamer_plugin/gst_mtl_st30p_rx.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ struct _Gst_Mtl_St30p_Rx {
/* audio (st30p) specific arguments */
guint channel;
guint sampling;
gboolean ptime;
gchar ptime[MTL_PORT_MAX_LEN];
gchar audio_format[MTL_PORT_MAX_LEN];
};

Expand Down
25 changes: 24 additions & 1 deletion ecosystem/gstreamer_plugin/gst_mtl_st30p_tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ enum {
PROP_ST30P_TX_RETRY = PROP_GENERAL_MAX,
PROP_ST30P_TX_FRAMERATE,
PROP_ST30P_TX_FRAMEBUFF_NUM,
PROP_ST30P_TX_PTIME,
PROP_MAX
};

Expand Down Expand Up @@ -157,6 +158,12 @@ static void gst_mtl_st30p_tx_class_init(Gst_Mtl_St30p_TxClass* klass) {
g_param_spec_uint("tx-framebuff-num", "Number of framebuffers",
"Number of framebuffers to be used for transmission.", 0,
G_MAXUINT, 3, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

g_object_class_install_property(
gobject_class, PROP_ST30P_TX_PTIME,
g_param_spec_string("tx-ptime", "Packetization time",
"Packetization time for the audio stream", NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}

static gboolean gst_mtl_st30p_tx_start(GstBaseSink* bsink) {
Expand Down Expand Up @@ -215,6 +222,9 @@ static void gst_mtl_st30p_tx_set_property(GObject* object, guint prop_id,
case PROP_ST30P_TX_FRAMEBUFF_NUM:
self->framebuffer_num = g_value_get_uint(value);
break;
case PROP_ST30P_TX_PTIME:
g_strlcpy(self->ptime, g_value_get_string(value), MTL_PORT_MAX_LEN);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
Expand All @@ -241,6 +251,9 @@ static void gst_mtl_st30p_tx_get_property(GObject* object, guint prop_id, GValue
case PROP_ST30P_TX_FRAMEBUFF_NUM:
g_value_set_uint(value, sink->framebuffer_num);
break;
case PROP_ST30P_TX_PTIME:
g_value_set_string(value, sink->ptime);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
Expand Down Expand Up @@ -296,7 +309,17 @@ static gboolean gst_mtl_st30p_tx_session_create(Gst_Mtl_St30p_Tx* sink, GstCaps*
return FALSE;
}
gst_audio_info_free(info);
ops_tx.ptime = ST30_PTIME_1MS;
if (sink->ptime[0] != '\0') {
if (!gst_mtl_common_parse_ptime(sink->ptime, &ops_tx.ptime)) {
GST_ERROR("Failed to parse ops_tx ptime %s", sink->ptime);
return FALSE;
}
} else {
if (ops_tx.sampling == ST31_SAMPLING_44K)
ops_tx.ptime = ST31_PTIME_1_09MS;
else
ops_tx.ptime = ST30_PTIME_1MS;
}

ops_tx.port.num_port = 1;

Expand Down
1 change: 1 addition & 0 deletions ecosystem/gstreamer_plugin/gst_mtl_st30p_tx.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ struct _Gst_Mtl_St30p_Tx {
SessionPortArgs portArgs; /* imtl tx session */
guint framebuffer_num;
guint framerate;
gchar ptime[MTL_PORT_MAX_LEN];
};

G_END_DECLS
Expand Down
139 changes: 100 additions & 39 deletions tests/validation/tests/Engine/GstreamerApp.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import hashlib
import os
import time

from tests.Engine.execute import call, log_fail, log_info, wait

Expand Down Expand Up @@ -213,26 +214,103 @@ def setup_gstreamer_st30_rx_pipeline(
return pipeline_command


def setup_gstreamer_st40p_tx_pipeline(
build: str,
nic_port_list: str,
input_path: str,
tx_payload_type: int,
tx_queues: int,
tx_framebuff_cnt: int,
tx_fps: int,
tx_did: int,
tx_sdid: int,
):
connection_params = create_connection_params(
dev_port=nic_port_list, payload_type=tx_payload_type, udp_port=40000, is_tx=True
)

# st40 tx GStreamer command line
pipeline_command = [
"gst-launch-1.0",
"filesrc",
f"location={input_path}",
"!",
"mtl_st40p_tx",
f"tx-queues={tx_queues}",
f"tx-framebuff-cnt={tx_framebuff_cnt}",
f"tx-fps={tx_fps}",
f"tx-did={tx_did}",
f"tx-sdid={tx_sdid}",
]

for key, value in connection_params.items():
pipeline_command.append(f"{key}={value}")

pipeline_command.append(
f"--gst-plugin-path={build}/ecosystem/gstreamer_plugin/builddir/"
)

return pipeline_command


def setup_gstreamer_st40p_rx_pipeline(
build: str,
nic_port_list: str,
output_path: str,
rx_payload_type: int,
rx_queues: int,
timeout: int,
):
connection_params = create_connection_params(
dev_port=nic_port_list,
payload_type=rx_payload_type,
udp_port=40000,
is_tx=False,
)

# st40 rx GStreamer command line
pipeline_command = [
"gst-launch-1.0",
"-v",
"mtl_st40_rx",
f"rx-queues={rx_queues}",
f"timeout={timeout}",
]

for key, value in connection_params.items():
pipeline_command.append(f"{key}={value}")

pipeline_command.extend(["!", "filesink", f"location={output_path}"])

pipeline_command.append(
f"--gst-plugin-path={build}/ecosystem/gstreamer_plugin/builddir/"
)

return pipeline_command


def execute_test(
build: str,
tx_command: list,
rx_command: list,
input_file: str,
output_file: str,
type: str,
fps: int = None,
sleep_interval: int = 0,
tx_first: bool = True,
):

tx_process = call(" ".join(tx_command), cwd=build, timeout=120)
rx_process = call(" ".join(rx_command), cwd=build, timeout=120)
if tx_first:
tx_process = call(" ".join(tx_command), cwd=build, timeout=120)
time.sleep(sleep_interval)
rx_process = call(" ".join(rx_command), cwd=build, timeout=120)
else:
rx_process = call(" ".join(rx_command), cwd=build, timeout=120)
time.sleep(sleep_interval)
tx_process = call(" ".join(tx_command), cwd=build, timeout=120)

tx_output = wait(tx_process)
wait(tx_process)
wait(rx_process)
if type == "st20":
tx_result = check_tx_output(fps=fps, output=tx_output.splitlines())
# rx_result = check_rx_output(fps=fps, output=rx_output.splitlines())
if tx_result is False:
return False

file_compare = compare_files(input_file, output_file)

Expand All @@ -244,36 +322,6 @@ def execute_test(
return False


def check_tx_output(fps: int, output: list) -> bool:
tx_fps_result = None
for line in output:
if "TX_VIDEO_SESSION(0,0:st20sink): fps" in line:
tx_fps_result = line
if tx_fps_result is not None:
for x in range(fps, fps - 3, -1):
if f"fps {x}" in tx_fps_result:
log_info(f"FPS > {x}")
return True

log_fail("tx session failed")
return False


def check_rx_output(fps: int, output: list) -> bool:
rx_fps_result = None
for line in output:
if "RX_VIDEO_SESSION(0,0:st20src): fps" in line:
rx_fps_result = line
if rx_fps_result is not None:
for x in range(fps, fps - 2, -1):
if f"fps {x}" in line:
log_info(f"FPS > {x}")
return True

log_fail("rx session failed")
return False


def compare_files(input_file, output_file):
if os.path.exists(input_file) and os.path.exists(output_file):
input_file_size = os.path.getsize(input_file)
Expand Down Expand Up @@ -318,3 +366,16 @@ def audio_format_change(file_format, rx_side: bool = False):
return 16
else:
return 24


def fps_change(fps: int):
if fps == 23:
return 2398
if fps == 29:
return 2997
if fps == 59:
return 5994
if fps == 119:
return 11988
else:
return fps
Loading

0 comments on commit 6df5e14

Please sign in to comment.