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
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ dvledtx uses a JSON config file with three sections:
| **video** | `width` | Frame width in pixels |
| | `height` | Frame height in pixels |
| | `fps` | Frames per second (25, 30, 50, 60) |
| | `fmt` | Pixel format (`yuv422p10le`, `yuv420`, `yuv444p10le`, `gbrp10le`) |
| | `fmt` | Pixel format (see [Supported Formats](#supported-formats)) |
| | `tx_url` | Path to the source video file |
| **tx_sessions[]** | `udp_port` | UDP port for the session |
| | `payload_type` | RTP payload type (typically 96) |
Expand Down Expand Up @@ -209,10 +209,16 @@ When `log_file` is set, log output is written to that file in addition to the co
## Supported Formats

### Video Formats
- **yuv422p10le**: YUV 4:2:2 10-bit little endian (default)
- **yuv420**: YUV 4:2:0 8-bit
- **yuv444p10le**: YUV 4:4:4 10-bit little endian
- **gbrp10le**: RGB (GBR planar) 10-bit little endian

| Format | Chroma | Bit Depth | Color Space |
|--------|--------|-----------|-------------|
| `yuv422p10le` | 4:2:2 | 10-bit | YUV |
| `yuv420` | 4:2:0 | 8-bit | YUV |
| `yuv444p10le` | 4:4:4 | 10-bit | YUV |
Comment thread
roshan-ku marked this conversation as resolved.
| `gbrp10le` | 4:4:4 | 10-bit | RGB |
| `yuv422p12le` | 4:2:2 | 12-bit | YUV |
| `yuv444p12le` | 4:4:4 | 12-bit | YUV |
| `gbrp12le` | 4:4:4 | 12-bit | RGB |

### Frame Rates
- 25 fps
Expand Down
4 changes: 2 additions & 2 deletions include/mtl/mtl_tx.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ enum st_fps get_st_fps(int fps);
* Handles all planar YUV formats (4:2:0, 4:2:2, 4:4:4) and GBRP at any
* supported bit depth.
*/
void mtl_copy_crop_to_frame(struct st_frame* dst, AVFrame* src,
void mtl_copy_crop_to_frame(struct st_frame* dst, const AVFrame* src,
int crop_x, int crop_y,
int crop_w, int crop_h,
enum AVPixelFormat fmt);
Expand Down Expand Up @@ -121,7 +121,7 @@ void mtl_tx_session_free(struct st20p_tx_ctx* ctx);
*
* Returns 0 on success, -1 on error.
*/
int mtl_tx_send_yuv_frame(struct st20p_tx_ctx* ctx, AVFrame* src,
int mtl_tx_send_yuv_frame(struct st20p_tx_ctx* ctx, const AVFrame* src,
int crop_x, int crop_y, int crop_w, int crop_h);

/*
Expand Down
2 changes: 1 addition & 1 deletion src/core/session_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ static void* st20p_tx_thread(void* arg) {
int crop_h = ctx->crop_height > 0 ? ctx->crop_height : (int)ctx->app->height;

while (ctx->app->exit == false && session_manager_should_exit() == false) {
AVFrame* frame = tx_fetch_next_frame(ctx);
const AVFrame* frame = tx_fetch_next_frame(ctx);
if (frame == NULL) {
if (ctx->app->exit == false && session_manager_should_exit() == false)
LOG_ERROR("ST20P TX(%d): tx_fetch_next_frame failed", ctx->idx);
Expand Down
2 changes: 1 addition & 1 deletion src/ffmpeg/ffmpeg_decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ static void close_ffmpeg_decoder(
* Open/close shared FFmpeg decoder (multi-session input path)
* ========================================================================= */
int open_shared_ffmpeg(struct shared_decode_ctx* dec, const char* filename) {
struct dvledtx_context* app = dec->app;
const struct dvledtx_context* app = dec->app;
return open_ffmpeg_decoder(
filename, "Shared decode",
app->fmt, (int)app->width, (int)app->height,
Expand Down
10 changes: 8 additions & 2 deletions src/mtl/mtl_tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ enum st_frame_fmt get_input_format(enum AVPixelFormat fmt) {
case AV_PIX_FMT_YUV420P: return ST_FRAME_FMT_YUV420CUSTOM8;
case AV_PIX_FMT_YUV444P10LE: return ST_FRAME_FMT_YUV444PLANAR10LE;
case AV_PIX_FMT_GBRP10LE: return ST_FRAME_FMT_GBRPLANAR10LE;
case AV_PIX_FMT_YUV422P12LE: return ST_FRAME_FMT_YUV422PLANAR12LE;
case AV_PIX_FMT_YUV444P12LE: return ST_FRAME_FMT_YUV444PLANAR12LE;
case AV_PIX_FMT_GBRP12LE: return ST_FRAME_FMT_GBRPLANAR12LE;
default:
LOG_ERROR("get_input_format: unsupported AVPixelFormat %d", fmt);
return (enum st_frame_fmt)-1;
Expand All @@ -62,6 +65,9 @@ enum st20_fmt get_transport_format(enum AVPixelFormat fmt) {
case AV_PIX_FMT_YUV420P: return ST20_FMT_YUV_420_8BIT;
case AV_PIX_FMT_YUV444P10LE: return ST20_FMT_YUV_444_10BIT;
case AV_PIX_FMT_GBRP10LE: return ST20_FMT_RGB_10BIT;
case AV_PIX_FMT_YUV422P12LE: return ST20_FMT_YUV_422_12BIT;
case AV_PIX_FMT_YUV444P12LE: return ST20_FMT_YUV_444_12BIT;
case AV_PIX_FMT_GBRP12LE: return ST20_FMT_RGB_12BIT;
default:
LOG_ERROR("get_transport_format: unsupported AVPixelFormat %d", fmt);
return (enum st20_fmt)-1;
Expand Down Expand Up @@ -107,7 +113,7 @@ enum st_fps get_st_fps(int fps) {
* crop_x/y — top-left corner in the full-width shared yuv_frame (luma coords)
* crop_w/h — crop rectangle dimensions in luma pixels
*/
void mtl_copy_crop_to_frame(struct st_frame* dst, AVFrame* src,
void mtl_copy_crop_to_frame(struct st_frame* dst, const AVFrame* src,
int crop_x, int crop_y,
int crop_w, int crop_h,
enum AVPixelFormat fmt) {
Expand Down Expand Up @@ -296,7 +302,7 @@ void mtl_tx_session_free(struct st20p_tx_ctx* ctx) {
* Returns 0 on success, -1 on error (e.g. get_frame returned NULL after
* timeout, or copy failed).
*/
int mtl_tx_send_yuv_frame(struct st20p_tx_ctx* ctx, AVFrame* src,
int mtl_tx_send_yuv_frame(struct st20p_tx_ctx* ctx, const AVFrame* src,
int crop_x, int crop_y, int crop_w, int crop_h) {
if (!ctx->handle || !src) return -1;

Expand Down
11 changes: 9 additions & 2 deletions src/util/config_reader.c
Original file line number Diff line number Diff line change
Expand Up @@ -439,9 +439,13 @@ int validate_tx_config(const struct dvledtx_config* config) {
strcmp(config->fmt, "yuv422p10le") != 0 &&
strcmp(config->fmt, "yuv420") != 0 &&
strcmp(config->fmt, "yuv444p10le") != 0 &&
strcmp(config->fmt, "gbrp10le") != 0) {
strcmp(config->fmt, "gbrp10le") != 0 &&
strcmp(config->fmt, "yuv422p12le") != 0 &&
strcmp(config->fmt, "yuv444p12le") != 0 &&
strcmp(config->fmt, "gbrp12le") != 0) {
LOG_ERROR("unsupported pixel format '%s'", config->fmt);
LOG_ERROR(" Supported: yuv422p10le, yuv420, yuv444p10le, gbrp10le");
LOG_ERROR(" Supported: yuv422p10le, yuv420, yuv444p10le, gbrp10le, "
"yuv422p12le, yuv444p12le, gbrp12le");
return -1;
}

Expand Down Expand Up @@ -591,6 +595,9 @@ int load_and_apply_config(struct dvledtx_context* app, const char* config_file)
else if (strcmp(config.fmt, "yuv420") == 0) app->fmt = AV_PIX_FMT_YUV420P;
else if (strcmp(config.fmt, "yuv444p10le") == 0) app->fmt = AV_PIX_FMT_YUV444P10LE;
else if (strcmp(config.fmt, "gbrp10le") == 0) app->fmt = AV_PIX_FMT_GBRP10LE;
else if (strcmp(config.fmt, "yuv422p12le") == 0) app->fmt = AV_PIX_FMT_YUV422P12LE;
else if (strcmp(config.fmt, "yuv444p12le") == 0) app->fmt = AV_PIX_FMT_YUV444P12LE;
else if (strcmp(config.fmt, "gbrp12le") == 0) app->fmt = AV_PIX_FMT_GBRP12LE;
else {
LOG_ERROR("Unsupported pixel format '%s'", config.fmt);
return -1;
Expand Down
3 changes: 2 additions & 1 deletion tests/test_config_reader.c
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,8 @@ static void test_validate_unsupported_fmt_fails(void **state)
static void test_validate_all_supported_fmts_pass(void **state)
{
(void)state;
const char *fmts[] = {"yuv422p10le", "yuv420", "yuv444p10le", "gbrp10le"};
const char *fmts[] = {"yuv422p10le", "yuv420", "yuv444p10le", "gbrp10le",
"yuv422p12le", "yuv444p12le", "gbrp12le"};
for (size_t i = 0; i < sizeof(fmts) / sizeof(fmts[0]); i++) {
struct dvledtx_config cfg;
fill_valid_config(&cfg);
Expand Down
54 changes: 54 additions & 0 deletions tests/test_mtl_tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,59 @@ static void test_get_transport_format_gbrp10le(void **state)
ST20_FMT_RGB_10BIT);
}

static void test_get_transport_format_yuv422p12le(void **state)
{
(void)state;
assert_int_equal(get_transport_format(AV_PIX_FMT_YUV422P12LE),
ST20_FMT_YUV_422_12BIT);
}

static void test_get_transport_format_yuv444p12le(void **state)
{
(void)state;
assert_int_equal(get_transport_format(AV_PIX_FMT_YUV444P12LE),
ST20_FMT_YUV_444_12BIT);
}

static void test_get_transport_format_gbrp12le(void **state)
{
(void)state;
assert_int_equal(get_transport_format(AV_PIX_FMT_GBRP12LE),
ST20_FMT_RGB_12BIT);
}

static void test_get_transport_format_unknown_returns_error(void **state)
{
(void)state;
/* AV_PIX_FMT_NONE hits the default branch → error (-1) */
assert_int_equal((int)get_transport_format(AV_PIX_FMT_NONE), -1);
}

/* =========================================================================
* get_input_format — 12-bit formats
* ========================================================================= */

static void test_get_input_format_yuv422p12le(void **state)
{
(void)state;
assert_int_equal(get_input_format(AV_PIX_FMT_YUV422P12LE),
ST_FRAME_FMT_YUV422PLANAR12LE);
}

static void test_get_input_format_yuv444p12le(void **state)
{
(void)state;
assert_int_equal(get_input_format(AV_PIX_FMT_YUV444P12LE),
ST_FRAME_FMT_YUV444PLANAR12LE);
}

static void test_get_input_format_gbrp12le(void **state)
{
(void)state;
assert_int_equal(get_input_format(AV_PIX_FMT_GBRP12LE),
ST_FRAME_FMT_GBRPLANAR12LE);
}

/* =========================================================================
* get_st_fps
* ========================================================================= */
Expand Down Expand Up @@ -370,8 +416,16 @@ int main(void)
cmocka_unit_test(test_get_transport_format_yuv420p),
cmocka_unit_test(test_get_transport_format_yuv444p10le),
cmocka_unit_test(test_get_transport_format_gbrp10le),
cmocka_unit_test(test_get_transport_format_yuv422p12le),
cmocka_unit_test(test_get_transport_format_yuv444p12le),
cmocka_unit_test(test_get_transport_format_gbrp12le),
cmocka_unit_test(test_get_transport_format_unknown_returns_error),
Comment thread
roshan-ku marked this conversation as resolved.

/* get_input_format — 12-bit */
cmocka_unit_test(test_get_input_format_yuv422p12le),
cmocka_unit_test(test_get_input_format_yuv444p12le),
cmocka_unit_test(test_get_input_format_gbrp12le),

/* get_st_fps */
cmocka_unit_test(test_get_st_fps_25),
cmocka_unit_test(test_get_st_fps_30),
Expand Down
Loading