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
19 changes: 12 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ dvledtx uses a JSON config file with three sections:
| Section | Field | Description |
|---------|-------|-------------|
| **log_file** | `log_file` | (Optional) Path/name of the log output file (e.g. `dvledtx.log`). If omitted, logging goes to console only. |
| **interfaces** | `name` | PCI BDF address of the NIC (e.g. `0000:06:00.0`) |
| **interfaces[]** | `name` | PCI BDF address of the NIC (e.g. `0000:06:00.0`) |
| | `sip` | Source IP address |
| | `dip` | Destination multicast IP address |
| **video** | `width` | Source frame width in pixels |
Expand All @@ -137,26 +137,31 @@ dvledtx uses a JSON config file with three sections:
| | `scale_height` | (Optional) Output height after scaling |
| | `fps` | Frames per second (25, 30, 50, 60) |
Comment thread
sunilnom marked this conversation as resolved.
| | `fmt` | Pixel format (see [Supported Formats](#supported-formats)) |
| **tx_sessions[]** | `udp_port` | UDP port for the session |
| **tx_sessions[]** | `nic_index` | (Optional) Index into `interfaces[]` selecting which NIC this session uses (default: `0`) |
| | `udp_port` | UDP port for the session |
| | `payload_type` | (Optional) RTP payload type — defaults to `96` if not present |
| | `crop` | Region to transmit: `x`, `y`, `w`, `h` in pixels |

Example (`config/tx_fullhd_single_session.json`):
Example (`config/tx_fullhd_multi_nic.json`):
```json
{
"log_file": "dvledtx.log",
"interfaces": [
{ "name": "0000:06:00.0", "sip": "192.168.50.29", "dip": "239.168.85.20" }
{ "name": "0000:03:10.0", "sip": "192.168.50.30", "dip": "239.168.85.20" },
{ "name": "0000:03:10.2", "sip": "192.168.50.29", "dip": "239.168.85.21" }
],
"video": {
"width": 1920, "height": 1080,
"tx_url": "bbb_sunflower_1080p_30fps_normal.mp4"
},
"tx_video": {
"fps": 30, "fmt": "yuv422p10le"
"scale_width": 1920, "scale_height": 1080,
"fps": 30,
"fmt": "yuv422p10le"
},
"tx_sessions": [
{ "udp_port": 20000, "crop": { "x": 0, "y": 0, "w": 1920, "h": 1080 } }
{ "nic_index": 0, "udp_port": 20000, "payload_type": 96, "crop": { "x": 0, "y": 0, "w": 960, "h": 1080 } },
{ "nic_index": 1, "udp_port": 20002, "payload_type": 96, "crop": { "x": 960, "y": 0, "w": 960, "h": 1080 } }
]
}
```
Expand Down Expand Up @@ -265,7 +270,7 @@ Example — upscale 1080p source to 4K output:
"fps": 30, "fmt": "yuv422p10le"
},
"tx_sessions": [
{ "udp_port": 20000, "crop": { "x": 0, "y": 0, "w": 3840, "h": 2160 } }
{ "udp_port": 20000, "payload_type": 96, "crop": { "x": 0, "y": 0, "w": 3840, "h": 2160 } }
]
}
```
Expand Down
7 changes: 5 additions & 2 deletions config/tx_2k_multi_session.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
"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": 2560,
"height": 1440,
"tx_url": "bbb_sunflower_1080p_30fps_normal.mp4"
"tx_url": "ball_2k_yuv420p_30fps_5min.mp4"
},
"tx_video": {
"scale_width": 2560,
Expand All @@ -21,14 +21,17 @@
"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 }
}
]
Expand Down
2 changes: 1 addition & 1 deletion config/tx_2k_single_session.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"video": {
"width": 2560,
"height": 1440,
"tx_url": "ball_2k_yuv420p_30fps_5min.mp4"
"tx_url": "ball_2k_yuv422p10_30fps_5min.mp4"
},
"tx_video": {
"scale_width": 2560,
Expand Down
5 changes: 4 additions & 1 deletion config/tx_4k_multi_session.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"video": {
"width": 3840,
"height": 2160,
"tx_url": "ball_4k_gbrp10le_60fps_5min.mp4"
"tx_url": "ball_4k_yuv422p10_60fps_5min.mp4"
},
"tx_video": {
"scale_width": 1920,
Expand All @@ -21,14 +21,17 @@
"tx_sessions": [
{
"udp_port": 20000,
"payload_type": 96,
"crop": { "x": 0, "y": 0, "w": 640, "h": 1080 }
},
{
"udp_port": 20002,
"payload_type": 96,
"crop": { "x": 640, "y": 0, "w": 640, "h": 1080 }
},
{
"udp_port": 20004,
"payload_type": 96,
"crop": { "x": 1280, "y": 0, "w": 640, "h": 1080 }
}
]
Expand Down
5 changes: 3 additions & 2 deletions config/tx_4k_single_session.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,18 @@
"video": {
"width": 3840,
"height": 2160,
"tx_url": "ball_4k_gbrp10le_60fps_5min.mp4"
"tx_url": "ball_4k_yuv422p10_60fps_5min.mp4"
},
"tx_video": {
"scale_width": 900,
"scale_height": 600,
"fps": 30,
"fps": 60,
"fmt": "yuv422p10le"
},
"tx_sessions": [
{
"udp_port": 20000,
"payload_type": 96,
"crop": { "x": 0, "y": 0, "w": 900, "h": 600 }
}
]
Expand Down
67 changes: 67 additions & 0 deletions config/tx_fullhd_multi_nic.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
{
"log_file": "dvledtx.log",
"interfaces": [
{
"name": "0000:03:10.0",
"sip": "192.168.50.30",
"dip": "239.168.85.20"
},
{
"name": "0000:03:10.2",
"sip": "192.168.50.31",
"dip": "239.168.85.21"
},
{
"name": "0000:03:10.4",
"sip": "192.168.50.32",
"dip": "239.168.85.22"
},
{
"name": "0000:03:10.6",
"sip": "192.168.50.33",
"dip": "239.168.85.23"
},
{
"name": "0000:03:11.0",
"sip": "192.168.50.34",
"dip": "239.168.85.24"
},
{
"name": "0000:03:11.2",
"sip": "192.168.50.35",
"dip": "239.168.85.25"
}
],
"video": {
"width": 1920,
"height": 1080,
"tx_url": "ball_fullhd_yuv422p10_30fps_5min.mp4"
},
"tx_video": {
"scale_width": 1920,
"scale_height": 1080,
"fps": 30,
"fmt": "yuv422p10le"
},
"tx_sessions": [
{
"nic_index": 0,
"udp_port": 20000,
"payload_type": 96,
"crop": { "x": 0, "y": 0, "w": 640, "h": 1080 }
},
{
"nic_index": 1,
"udp_port": 20002,
"payload_type": 96,
"crop": { "x": 640, "y": 0, "w": 640, "h": 1080 }
},
{
"nic_index": 2,
"udp_port": 20004,
"payload_type": 96,
"crop": { "x": 1280, "y": 0, "w": 640, "h": 1080 }
}
]
}

9 changes: 6 additions & 3 deletions config/tx_fullhd_multi_session.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
"log_file": "dvledtx.log",
"interfaces": [
{
"name": "0000:06:00.0",
"name": "0000:03:10.1",
"sip": "192.168.50.29",
"dip": "239.168.85.20"
"dip": "239.168.85.21"
}
],
"video": {
"width": 1920,
"height": 1080,
"tx_url": "bbb_sunflower_1080p_30fps_normal.mp4"
"tx_url": "ball_fullhd_yuv422p10_30fps_5min.mp4"
},
"tx_video": {
"scale_width": 1920,
Expand All @@ -21,14 +21,17 @@
"tx_sessions": [
{
"udp_port": 20000,
"payload_type": 96,
"crop": { "x": 0, "y": 0, "w": 640, "h": 1080 }
},
{
"udp_port": 20002,
"payload_type": 96,
"crop": { "x": 640, "y": 0, "w": 640, "h": 1080 }
},
{
"udp_port": 20004,
"payload_type": 96,
"crop": { "x": 1280, "y": 0, "w": 640, "h": 1080 }
}
]
Expand Down
3 changes: 2 additions & 1 deletion config/tx_fullhd_single_session.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"video": {
"width": 3840,
"height": 2160,
"tx_url": "bbb_sunflower_1080p_30fps_normal.mp4"
"tx_url": "ball_fullhd_yuv422p10_30fps_5min.mp4"
},
"tx_video": {
"scale_width": 3840,
Expand All @@ -21,6 +21,7 @@
"tx_sessions": [
{
"udp_port": 20000,
"payload_type": 96,
"crop": { "x": 0, "y": 0, "w": 1920, "h": 1080 }
}
]
Expand Down
68 changes: 59 additions & 9 deletions include/app_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,24 @@

#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <libavutil/pixfmt.h>

#define MAX_TX_SESSIONS (8)
/* Fixed field-width constants (not array size limits) */
#define PORT_NAME_LEN 64
#define IP_STR_LEN INET_ADDRSTRLEN
#define IP_ADDR_BYTES 4

/* Per-NIC configuration (one element per interface) */
struct nic_config {
char port[PORT_NAME_LEN]; /* DPDK NIC PCI BDF */
char sip_addr_str[IP_STR_LEN]; /* source IP string */
uint8_t sip_addr[IP_ADDR_BYTES]; /* source IP binary */
char dip_addr_str[IP_STR_LEN]; /* destination IP string */
uint8_t dip_addr[IP_ADDR_BYTES]; /* destination IP binary */
};

/* Per-session network and crop parameters (populated from JSON tx_sessions[]) */
struct tx_session_net {
Expand All @@ -19,18 +33,17 @@ struct tx_session_net {
int crop_y;
int crop_w;
int crop_h;
int nic_index; /* which NIC this session uses (index into nics[]) */
};

/* Application context for TX sessions */
struct dvledtx_context {
/* Configuration */
char port[64]; /* DPDK NIC PCI BDF/address for MTL output (e.g. 0000:af:00.0), not a Linux interface name */
/* NIC configuration — dynamically allocated array [0..nic_count-1] */
int nic_count; /* number of active NICs */
struct nic_config* nics; /* heap-allocated, nic_count elements */

char tx_url[256];
char config_file[256];
char sip_addr_str[INET_ADDRSTRLEN];
uint8_t sip_addr[4];
char dip_addr_str[INET_ADDRSTRLEN];
uint8_t dip_addr[4];
uint16_t udp_port;
uint8_t payload_type; /* RTP dynamic payload type (default: 96) */

Expand All @@ -48,10 +61,47 @@ struct dvledtx_context {
bool force_dhcp;
int test_time_s;

/* Per-session network + crop config (from JSON tx_sessions[]) */
struct tx_session_net session_net[MAX_TX_SESSIONS];
/* Per-session network + crop config — dynamically allocated, st20p_sessions elements */
struct tx_session_net* session_net;

/* Optional log file path from config (empty = console logging only) */
char log_file[256];

};

/* Free dynamically allocated members of dvledtx_context (nics, session_net).
* Does NOT free the struct itself (it may be stack-allocated). */
static inline void dvledtx_context_free(struct dvledtx_context* ctx) {
if (ctx == NULL) return;
free(ctx->nics); ctx->nics = NULL;
free(ctx->session_net); ctx->session_net = NULL;
ctx->nic_count = 0;
ctx->st20p_sessions = 0;
}

/* Allocate NIC and session arrays inside an already zeroed context.
* calloc(0, ...) is permitted by the C standard to return NULL, which is
* not an allocation failure, so a zero count is treated as "nothing to
* allocate" rather than an error (avoids spurious failures, e.g. in tests
* that call dvledtx_context_alloc(ctx, 1, 0)). On failure, ctx is left
* fully zeroed (no dangling nics pointer with a stale nic_count) so it
* remains safe to pass to dvledtx_context_free().
* Returns 0 on success, -1 on allocation failure. */
static inline int dvledtx_context_alloc(struct dvledtx_context* ctx,
int nic_count, int session_count) {
if (nic_count > 0) {
ctx->nics = calloc((size_t)nic_count, sizeof(struct nic_config));
if (ctx->nics == NULL) return -1;
}
ctx->nic_count = nic_count;

if (session_count > 0) {
ctx->session_net = calloc((size_t)session_count, sizeof(struct tx_session_net));
if (ctx->session_net == NULL) {
free(ctx->nics); ctx->nics = NULL; ctx->nic_count = 0;
return -1;
}
}
ctx->st20p_sessions = session_count;
return 0;
}
8 changes: 4 additions & 4 deletions include/core/session_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>

/* MTL pipeline API headers — only when building the direct MTL TX path */
#ifdef ENABLE_MTL_TX
/* MTL API headers — always included; mtl_tx_init/uninit are always compiled
* to allow pre-initialising all NIC ports regardless of TX path. */
#include "mtl_api.h"

#ifdef ENABLE_MTL_TX
#include "st_pipeline_api.h"
#endif

Expand Down Expand Up @@ -120,9 +122,7 @@ typedef struct session_manager_s {

struct shared_decode_ctx* shared_dec;

#ifdef ENABLE_MTL_TX
mtl_handle mtl; /* MTL library instance — owns all st20p_tx sessions */
#endif

bool running;
} session_manager_t;
Expand Down
Loading
Loading