From e78d31d0ef6d4b2a649a14028f8dd86f8772eb86 Mon Sep 17 00:00:00 2001 From: sunilnom Date: Mon, 8 Jun 2026 11:02:32 +0530 Subject: [PATCH 1/3] Raise max video resolution limit from 1920x1080 to 3840x2160 - Update validation in config_reader to allow 2K and 4K resolutions - Update test to reflect new 3840x2160 maximum --- src/util/config_reader.c | 4 ++-- tests/test_config_reader.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/util/config_reader.c b/src/util/config_reader.c index 09b6841..1c8ec79 100644 --- a/src/util/config_reader.c +++ b/src/util/config_reader.c @@ -417,8 +417,8 @@ int validate_tx_config(const struct dvledtx_config* config) { LOG_ERROR("video width/height must be non-zero"); return -1; } - if (config->width > 1920 || config->height > 1080) { - LOG_ERROR("video resolution %dx%d exceeds maximum 1920x1080", + if (config->width > 3840 || config->height > 2160) { + LOG_ERROR("video resolution %dx%d exceeds maximum 3840x2160", config->width, config->height); return -1; } diff --git a/tests/test_config_reader.c b/tests/test_config_reader.c index 8bea230..901d612 100644 --- a/tests/test_config_reader.c +++ b/tests/test_config_reader.c @@ -602,7 +602,7 @@ static void test_validate_resolution_exceeds_max_fails(void **state) (void)state; struct dvledtx_config cfg; fill_valid_config(&cfg); - cfg.width = 2000; /* > 1920 limit */ + cfg.width = 4000; /* > 3840 limit */ assert_int_equal(validate_tx_config(&cfg), -1); } From b030986b8f37c98f83ca5f86a5dec6a20fa7fe0f Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 11 Jun 2026 09:11:50 +0530 Subject: [PATCH 2/3] feat: add 2K/4K resolution support and rename config files - Fix format specifiers: use %u for uint32_t width/height (UB fix) - Rename tx_1session.json -> tx_fullhd_single_session.json - Rename tx_3sessions.json -> tx_fullhd_multi_session.json - Add tx_2k_single_session.json and tx_2k_multi_session.json - Add tx_4k_single_session.json and tx_4k_multi_session.json - Add unit tests for 2K and 4K resolution validation - Update README with supported resolutions table (1080p, 2K, 4K) --- README.md | 15 +++++-- config/tx_2k_multi_session.json | 34 +++++++++++++++ ...session.json => tx_2k_single_session.json} | 12 +++--- config/tx_4k_multi_session.json | 34 +++++++++++++++ config/tx_4k_single_session.json | 24 +++++++++++ ...ions.json => tx_fullhd_multi_session.json} | 0 config/tx_fullhd_single_session.json | 24 +++++++++++ src/util/config_reader.c | 6 +-- tests/test_config_reader.c | 43 +++++++++++++++++-- 9 files changed, 176 insertions(+), 16 deletions(-) create mode 100644 config/tx_2k_multi_session.json rename config/{tx_1session.json => tx_2k_single_session.json} (58%) create mode 100644 config/tx_4k_multi_session.json create mode 100644 config/tx_4k_single_session.json rename config/{tx_3sessions.json => tx_fullhd_multi_session.json} (100%) create mode 100644 config/tx_fullhd_single_session.json diff --git a/README.md b/README.md index a62771f..7798477 100644 --- a/README.md +++ b/README.md @@ -138,7 +138,7 @@ dvledtx uses a JSON config file with three sections: | | `payload_type` | RTP payload type (typically 96) | | | `crop` | Region to transmit: `x`, `y`, `w`, `h` in pixels | -Example (`config/tx_1session.json`): +Example (`config/tx_fullhd_single_session.json`): ```json { "log_file": "dvledtx.log", @@ -156,7 +156,7 @@ Example (`config/tx_1session.json`): } ``` -Multiple sessions can be defined in `tx_sessions` to transmit different crop regions of the same video simultaneously (see `config/tx_3sessions.json`). +Multiple sessions can be defined in `tx_sessions` to transmit different crop regions of the same video simultaneously (see `config/tx_fullhd_multi_session.json`). ## Logging @@ -188,7 +188,7 @@ When `log_file` is set, log output is written to that file in addition to the co #### Using JSON Configuration (recommended) ```bash -./build/dvledtx --config config/tx_1session.json +./build/dvledtx --config config/tx_fullhd_single_session.json ``` ## Command-Line Options @@ -227,7 +227,14 @@ When `log_file` is set, log output is written to that file in addition to the co - 60 fps ### Resolutions -- Tested with 1920x1080 + +| Resolution | Dimensions | Description | +|------------|------------|-------------| +| **1080p** (Full HD) | 1920x1080 | Standard HD resolution | +| **2K** (QHD) | 2560x1440 | Quad HD / 2K resolution | +| **4K** (UHD) | 3840x2160 | Ultra HD / 4K resolution | + +> **Note:** Maximum supported resolution is 3840x2160. Width must be even for YUV format alignment. ## Performance Considerations diff --git a/config/tx_2k_multi_session.json b/config/tx_2k_multi_session.json new file mode 100644 index 0000000..4eb35fb --- /dev/null +++ b/config/tx_2k_multi_session.json @@ -0,0 +1,34 @@ +{ + "log_file": "dvledtx.log", + "interfaces": [ + { + "name": "0000:03:00.1", + "sip": "192.168.50.29", + "dip": "239.168.85.20" + } + ], + "video": { + "width": 2560, + "height": 1440, + "fps": 30, + "fmt": "yuv422p10le", + "tx_url": "/home/intel/workspace/sample/ball_2k_yuv420p_30fps_5min.mp4" + }, + "tx_sessions": [ + { + "udp_port": 20000, + "payload_type": 96, + "crop": { "x": 0, "y": 0, "w": 854, "h": 1440 } + }, + { + "udp_port": 20002, + "payload_type": 96, + "crop": { "x": 854, "y": 0, "w": 854, "h": 1440 } + }, + { + "udp_port": 20004, + "payload_type": 96, + "crop": { "x": 1708, "y": 0, "w": 852, "h": 1440 } + } + ] +} diff --git a/config/tx_1session.json b/config/tx_2k_single_session.json similarity index 58% rename from config/tx_1session.json rename to config/tx_2k_single_session.json index ef34df0..865267f 100644 --- a/config/tx_1session.json +++ b/config/tx_2k_single_session.json @@ -1,24 +1,24 @@ -{ +{ "log_file": "dvledtx.log", "interfaces": [ { - "name": "0000:06:00.0", + "name": "0000:03:00.1", "sip": "192.168.50.29", "dip": "239.168.85.20" } ], "video": { - "width": 1920, - "height": 1080, + "width": 2560, + "height": 1440, "fps": 30, "fmt": "yuv422p10le", - "tx_url": "bbb_sunflower_1080p_30fps_normal.mp4" + "tx_url": "/home/intel/workspace/sample/ball_2k_yuv420p_30fps_5min.mp4" }, "tx_sessions": [ { "udp_port": 20000, "payload_type": 96, - "crop": { "x": 0, "y": 0, "w": 1920, "h": 1080 } + "crop": { "x": 0, "y": 0, "w": 2560, "h": 1440 } } ] } diff --git a/config/tx_4k_multi_session.json b/config/tx_4k_multi_session.json new file mode 100644 index 0000000..5692724 --- /dev/null +++ b/config/tx_4k_multi_session.json @@ -0,0 +1,34 @@ +{ + "log_file": "dvledtx.log", + "interfaces": [ + { + "name": "0000:03:00.1", + "sip": "192.168.50.29", + "dip": "239.168.85.20" + } + ], + "video": { + "width": 3840, + "height": 2160, + "fps": 30, + "fmt": "yuv422p10le", + "tx_url": "/home/intel/workspace/sample/ball_4k_yuv420p_30fps_5min.mp4" + }, + "tx_sessions": [ + { + "udp_port": 20000, + "payload_type": 96, + "crop": { "x": 0, "y": 0, "w": 1280, "h": 2160 } + }, + { + "udp_port": 20002, + "payload_type": 96, + "crop": { "x": 1280, "y": 0, "w": 1280, "h": 2160 } + }, + { + "udp_port": 20004, + "payload_type": 96, + "crop": { "x": 2560, "y": 0, "w": 1280, "h": 2160 } + } + ] +} diff --git a/config/tx_4k_single_session.json b/config/tx_4k_single_session.json new file mode 100644 index 0000000..0a23755 --- /dev/null +++ b/config/tx_4k_single_session.json @@ -0,0 +1,24 @@ +{ + "log_file": "dvledtx.log", + "interfaces": [ + { + "name": "0000:03:00.1", + "sip": "192.168.50.29", + "dip": "239.168.85.20" + } + ], + "video": { + "width": 3840, + "height": 2160, + "fps": 30, + "fmt": "yuv422p10le", + "tx_url": "/home/intel/workspace/sample/ball_4k_yuv420p_30fps_5min.mp4" + }, + "tx_sessions": [ + { + "udp_port": 20000, + "payload_type": 96, + "crop": { "x": 0, "y": 0, "w": 3840, "h": 2160 } + } + ] +} diff --git a/config/tx_3sessions.json b/config/tx_fullhd_multi_session.json similarity index 100% rename from config/tx_3sessions.json rename to config/tx_fullhd_multi_session.json diff --git a/config/tx_fullhd_single_session.json b/config/tx_fullhd_single_session.json new file mode 100644 index 0000000..43c7ea0 --- /dev/null +++ b/config/tx_fullhd_single_session.json @@ -0,0 +1,24 @@ +{ + "log_file": "dvledtx.log", + "interfaces": [ + { + "name": "0000:03:00.1", + "sip": "192.168.50.29", + "dip": "239.168.85.20" + } + ], + "video": { + "width": 3840, + "height": 2160, + "fps": 60, + "fmt": "gbrp10le", + "tx_url": "/home/intel/workspace/sample/ball_4k_gbrp10le_30fps_5min.mp4" + }, + "tx_sessions": [ + { + "udp_port": 20000, + "payload_type": 96, + "crop": { "x": 0, "y": 0, "w": 3840, "h": 2160 } + } + ] +} diff --git a/src/util/config_reader.c b/src/util/config_reader.c index 1c8ec79..c475e07 100644 --- a/src/util/config_reader.c +++ b/src/util/config_reader.c @@ -418,12 +418,12 @@ int validate_tx_config(const struct dvledtx_config* config) { return -1; } if (config->width > 3840 || config->height > 2160) { - LOG_ERROR("video resolution %dx%d exceeds maximum 3840x2160", - config->width, config->height); + LOG_ERROR("video resolution %ux%u exceeds maximum 3840x2160", + (unsigned)config->width, (unsigned)config->height); return -1; } if (config->width % 2 != 0) { - LOG_ERROR("video width %d must be even for YUV formats", config->width); + LOG_ERROR("video width %u must be even for YUV formats", (unsigned)config->width); return -1; } diff --git a/tests/test_config_reader.c b/tests/test_config_reader.c index 901d612..241536b 100644 --- a/tests/test_config_reader.c +++ b/tests/test_config_reader.c @@ -32,8 +32,8 @@ # error "FIXTURE_DIR must be defined by the build system (-DFIXTURE_DIR=...)" #endif -#define FIXTURE_3SESSIONS FIXTURE_DIR "/tx_3sessions.json" -#define FIXTURE_1SESSION FIXTURE_DIR "/tx_1session.json" +#define FIXTURE_3SESSIONS FIXTURE_DIR "/tx_fullhd_multi_session.json" +#define FIXTURE_1SESSION FIXTURE_DIR "/tx_fullhd_single_session.json" /* -------------------------------------------------------------------------- * Helper: write content to a new temp file, return heap-allocated path. @@ -449,7 +449,7 @@ static void test_validate_zero_session_count_fails(void **state) static void test_validate_3sessions_tiled_layout_passes(void **state) { (void)state; - /* Mirrors tx_3sessions.json: three 640-wide horizontal tiles */ + /* Mirrors tx_fullhd_multi_session.json: three 640-wide horizontal tiles */ struct dvledtx_config cfg; memset(&cfg, 0, sizeof(cfg)); strncpy(cfg.interface_name, "0000:06:00.0", sizeof(cfg.interface_name) - 1); @@ -606,6 +606,40 @@ static void test_validate_resolution_exceeds_max_fails(void **state) assert_int_equal(validate_tx_config(&cfg), -1); } +static void test_validate_2k_resolution_passes(void **state) +{ + (void)state; + struct dvledtx_config cfg; + fill_valid_config(&cfg); + cfg.width = 2560; + cfg.height = 1440; + cfg.sessions[0].crop_w = 2560; + cfg.sessions[0].crop_h = 1440; + assert_int_equal(validate_tx_config(&cfg), 0); +} + +static void test_validate_4k_resolution_passes(void **state) +{ + (void)state; + struct dvledtx_config cfg; + fill_valid_config(&cfg); + cfg.width = 3840; + cfg.height = 2160; + cfg.sessions[0].crop_w = 3840; + cfg.sessions[0].crop_h = 2160; + assert_int_equal(validate_tx_config(&cfg), 0); +} + +static void test_validate_4k_height_exceeds_max_fails(void **state) +{ + (void)state; + struct dvledtx_config cfg; + fill_valid_config(&cfg); + cfg.width = 3840; + cfg.height = 2162; /* > 2160 limit */ + assert_int_equal(validate_tx_config(&cfg), -1); +} + static void test_validate_duplicate_udp_ports_fails(void **state) { (void)state; @@ -1141,6 +1175,9 @@ int main(void) cmocka_unit_test(test_validate_zero_session_count_fails), cmocka_unit_test(test_validate_3sessions_tiled_layout_passes), cmocka_unit_test(test_validate_resolution_exceeds_max_fails), + cmocka_unit_test(test_validate_2k_resolution_passes), + cmocka_unit_test(test_validate_4k_resolution_passes), + cmocka_unit_test(test_validate_4k_height_exceeds_max_fails), cmocka_unit_test(test_validate_duplicate_udp_ports_fails), cmocka_unit_test(test_validate_crop_x_misaligned_for_yuv422_fails), cmocka_unit_test(test_validate_tx_url_nonexistent_file_fails), From 5af10f71438bf082fa5f36d1bfbd982db4a1f4a4 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 11 Jun 2026 09:14:06 +0530 Subject: [PATCH 3/3] fix: use relative filenames in tx_url config fields --- config/tx_2k_multi_session.json | 2 +- config/tx_2k_single_session.json | 2 +- config/tx_4k_multi_session.json | 2 +- config/tx_4k_single_session.json | 2 +- config/tx_fullhd_single_session.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/config/tx_2k_multi_session.json b/config/tx_2k_multi_session.json index 4eb35fb..2b4c9f3 100644 --- a/config/tx_2k_multi_session.json +++ b/config/tx_2k_multi_session.json @@ -12,7 +12,7 @@ "height": 1440, "fps": 30, "fmt": "yuv422p10le", - "tx_url": "/home/intel/workspace/sample/ball_2k_yuv420p_30fps_5min.mp4" + "tx_url": "ball_2k_yuv420p_30fps_5min.mp4" }, "tx_sessions": [ { diff --git a/config/tx_2k_single_session.json b/config/tx_2k_single_session.json index 865267f..a2a5c86 100644 --- a/config/tx_2k_single_session.json +++ b/config/tx_2k_single_session.json @@ -12,7 +12,7 @@ "height": 1440, "fps": 30, "fmt": "yuv422p10le", - "tx_url": "/home/intel/workspace/sample/ball_2k_yuv420p_30fps_5min.mp4" + "tx_url": "ball_2k_yuv420p_30fps_5min.mp4" }, "tx_sessions": [ { diff --git a/config/tx_4k_multi_session.json b/config/tx_4k_multi_session.json index 5692724..bb83a02 100644 --- a/config/tx_4k_multi_session.json +++ b/config/tx_4k_multi_session.json @@ -12,7 +12,7 @@ "height": 2160, "fps": 30, "fmt": "yuv422p10le", - "tx_url": "/home/intel/workspace/sample/ball_4k_yuv420p_30fps_5min.mp4" + "tx_url": "ball_4k_yuv420p_30fps_5min.mp4" }, "tx_sessions": [ { diff --git a/config/tx_4k_single_session.json b/config/tx_4k_single_session.json index 0a23755..df69353 100644 --- a/config/tx_4k_single_session.json +++ b/config/tx_4k_single_session.json @@ -12,7 +12,7 @@ "height": 2160, "fps": 30, "fmt": "yuv422p10le", - "tx_url": "/home/intel/workspace/sample/ball_4k_yuv420p_30fps_5min.mp4" + "tx_url": "ball_4k_yuv420p_30fps_5min.mp4" }, "tx_sessions": [ { diff --git a/config/tx_fullhd_single_session.json b/config/tx_fullhd_single_session.json index 43c7ea0..82bcdff 100644 --- a/config/tx_fullhd_single_session.json +++ b/config/tx_fullhd_single_session.json @@ -12,7 +12,7 @@ "height": 2160, "fps": 60, "fmt": "gbrp10le", - "tx_url": "/home/intel/workspace/sample/ball_4k_gbrp10le_30fps_5min.mp4" + "tx_url": "ball_4k_gbrp10le_30fps_5min.mp4" }, "tx_sessions": [ {