Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
34 changes: 34 additions & 0 deletions config/tx_2k_multi_session.json
Original file line number Diff line number Diff line change
@@ -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": "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 }
}
]
}
12 changes: 6 additions & 6 deletions config/tx_1session.json → config/tx_2k_single_session.json
Original file line number Diff line number Diff line change
@@ -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": "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 }
}
]
}
34 changes: 34 additions & 0 deletions config/tx_4k_multi_session.json
Original file line number Diff line number Diff line change
@@ -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": "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 }
}
]
}
24 changes: 24 additions & 0 deletions config/tx_4k_single_session.json
Original file line number Diff line number Diff line change
@@ -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": "ball_4k_yuv420p_30fps_5min.mp4"
},
"tx_sessions": [
{
"udp_port": 20000,
"payload_type": 96,
"crop": { "x": 0, "y": 0, "w": 3840, "h": 2160 }
}
]
}
File renamed without changes.
24 changes: 24 additions & 0 deletions config/tx_fullhd_single_session.json
Original file line number Diff line number Diff line change
@@ -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": "ball_4k_gbrp10le_30fps_5min.mp4"
},
"tx_sessions": [
{
"udp_port": 20000,
"payload_type": 96,
"crop": { "x": 0, "y": 0, "w": 3840, "h": 2160 }
}
]
}
8 changes: 4 additions & 4 deletions src/util/config_reader.c
Original file line number Diff line number Diff line change
Expand Up @@ -417,13 +417,13 @@ 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",
config->width, config->height);
if (config->width > 3840 || config->height > 2160) {
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;
}

Expand Down
45 changes: 41 additions & 4 deletions tests/test_config_reader.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -602,7 +602,41 @@ 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 */
Comment thread
sunilnom marked this conversation as resolved.
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);
}

Expand Down Expand Up @@ -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),
Expand Down
Loading