67#define DEFAULT_AUDIO_LEVEL 0
68#define MOD_NAME "[NDI disp.] "
92 *available_cards = calloc(1,
sizeof(
struct device_info));
93 strncpy((*available_cards)[0].dev,
"",
sizeof (*available_cards)[0].dev - 1);
94 strncpy((*available_cards)[0].
name,
"NDI",
sizeof (*available_cards)[0].
name - 1);
95 strncpy((*available_cards)[0].extra,
"\"embeddedAudioAvailable\":\"t\"",
sizeof (*available_cards)[0].extra - 1);
96 (*available_cards)[0].repeatable =
true;
105 {
RGBA, NDIlib_FourCC_type_RGBA, NULL },
106 {
UYVY, NDIlib_FourCC_type_UYVY, NULL },
107 {
I420, NDIlib_FourCC_video_type_I420, NULL },
157 int eotf = strtol(
param + 1, NULL, 16);
158 const char *space = NULL;
161 case 1: space =
"Default";
break;
162 case 2: space =
"HLG";
break;
163 case 3: space =
"PQ";
break;
168 size_t metadata_len = 128;
169 char *out = malloc(metadata_len);
170 snprintf(out, metadata_len,
"<HDR_PROFILE>%s</HDR_PROFILE>", space);
174#define BEGIN_TRY int ret = 0; do
175#define END_TRY while(0);
176#define THROW(x) ret = (x); break;
178#define CATCH(x) if (ret == (x))
187 char *fmt_copy = NULL;
192 fmt_copy = strdup(
fmt);
193 assert(fmt_copy != NULL);
195 const char *ndi_name = NULL;
196 char *tmp = fmt_copy, *
item, *save_ptr;
197 while ((
item = strtok_r(tmp,
":", &save_ptr)) != NULL) {
198 if (strcmp(
item,
"help") == 0) {
202 if (strstr(
item,
"audio_level=") != NULL) {
203 char *
val =
item + strlen(
"audio_level=");
204 if (strcasecmp(
val,
"mic") == 0) {
206 }
else if (strcasecmp(
val,
"line") == 0) {
210 long val_num = strtol(
val, &endptr, 0);
211 if (val_num < 0 || val_num >= INT_MAX || *
val ==
'\0' || *endptr !=
'\0') {
217 }
else if (strstr(
item,
"name=") != NULL) {
218 ndi_name =
item + strlen(
"name=");
232 printf(
"%s\n", s->
NDIlib->version());
234 if (!s->
NDIlib->initialize()) {
239 NDIlib_send_create_t NDI_send_create_desc = { .p_ndi_name = ndi_name, .p_groups = NULL, .clock_video =
false, .clock_audio =
false };
284 assert((uintptr_t) out % 2 == 0);
286 uint16_t *in = (uint16_t *)(
void *) f->
tiles[0].
data;
287 uint16_t *out_y = (uint16_t *)(
void *) out;
290 for (
unsigned int i = 0; i < f->
tiles[0].
height; ++i) {
292 OPTIMIZED_FOR (
unsigned int j = 0; j < (width + 1) / 2; j += 1) {
294 *out_cb_cr++ = *in++;
296 *out_cb_cr++ = *in++;
303 assert((uintptr_t) out % 2 == 0);
305 uint16_t *in = (uint16_t *)(
void *) f->
tiles[0].
data;
306 uint16_t *out_y = (uint16_t *)(
void *) out;
310 for (
unsigned int i = 0; i < f->
tiles[0].
height; ++i) {
312 OPTIMIZED_FOR (
unsigned int j = 0; j < (width + 1) / 2; j += 1) {
315 *out_cb_cr++ = (in[2] + in[6]) / 2;
318 *out_cb_cr++ = (in[3] + in[7]) / 2;
362 int rgb_shift[] = {0, 8, 16};
379 if (
sizeof rgb_shift > *
len) {
382 memcpy(
val, rgb_shift,
sizeof rgb_shift);
383 *
len =
sizeof rgb_shift;
394 if (
sizeof(supported_il_modes) <= *
len) {
395 memcpy(
val, supported_il_modes,
sizeof(supported_il_modes));
399 *
len =
sizeof(supported_il_modes);
415#define NDI_SEND_AUDIO(frame, bit_depth) do { \
416 assert((frame)->bps * 8 == (bit_depth)); \
417 NDIlib_audio_frame_interleaved_ ## bit_depth ## s_t NDI_audio_frame = { 0 }; \
418 NDI_audio_frame.sample_rate = (frame)->sample_rate; \
419 NDI_audio_frame.no_channels = (frame)->ch_count; \
420 NDI_audio_frame.reference_level = s->audio_level; \
421 NDI_audio_frame.timecode = NDIlib_send_timecode_synthesize; \
422 NDI_audio_frame.p_data = (int ## bit_depth ## _t *)(void *) (frame)->data; \
423 NDI_audio_frame.no_samples = (frame)->data_len / (frame)->ch_count / ((bit_depth) / 8); \
425 s->NDIlib->util_send_send_audio_interleaved_ ## bit_depth ## s(s->pNDI_send, &NDI_audio_frame); \
431 switch (
frame->bps * 8) {
432#define HANDLE_CASE(b) case b: NDI_SEND_AUDIO(frame, b); break;
struct video_frame * frame
const char unsigned int flags
int void(** deleter)(void *))
void vf_free(struct video_frame *buf)
Frees video_frame structure.
struct video_frame * vf_alloc_desc_data(struct video_desc desc)
This file contains definition of some common audio types.
int color_printf(const char *format,...)
void log_msg(int level, const char *format,...)
#define LOG_LEVEL_ERROR
general errors
#define PITCH_DEFAULT
default pitch, i. e. respective linesize
#define VIDEO_DISPLAY_ABI_VERSION
@ DISPLAY_PROPERTY_BUF_PITCH
requested framebuffer pitch - int (bytes), may be PITCH_DEFAULT
@ DISPLAY_PROPERTY_RGB_SHIFT
red,green,blue shift - int[3] (bits)
@ DISPLAY_PROPERTY_SUPPORTED_IL_MODES
display supported interlacing modes - enum interlacing_t[]
@ DISPLAY_PROPERTY_VIDEO_MODE
requested video mode - int (one of display_prop_vid_mode)
@ DISPLAY_PROPERTY_CODECS
list of natively supported codecs - codec_t[]
@ DISPLAY_PROPERTY_AUDIO_FORMAT
@ DISPLAY_PROPERTY_VIDEO_MERGED
monolithic framebuffer
const char * get_commandline_param(const char *key)
@ LIBRARY_CLASS_VIDEO_DISPLAY
#define REGISTER_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
int get_framerate_d(double fps)
int get_framerate_n(double fps)
static struct video_frame * display_ndi_getf(void *state)
#define DEFAULT_AUDIO_LEVEL
static bool display_ndi_reconfigure_audio(void *state, int quant_samples, int channels, int sample_rate)
static void display_ndi_put_audio_frame(void *state, const struct audio_frame *frame)
static char * ndi_disp_format_video_metadata(void)
static void * display_ndi_init(struct module *parent, const char *fmt, unsigned int flags)
void ndi_disp_convert_t(const struct video_frame *f, char *out)
static bool display_ndi_get_property(void *state, int property, void *val, size_t *len)
static void ndi_disp_convert_Y416_to_PA16(const struct video_frame *f, char *out)
static void display_ndi_done(void *state)
static bool display_ndi_reconfigure(void *state, struct video_desc desc)
static bool display_ndi_putf(void *state, struct video_frame *frame, long long flag)
static void ndi_disp_convert_Y216_to_P216(const struct video_frame *f, char *out)
static void display_ndi_probe(struct device_info **available_cards, int *count, void(**deleter)(void *))
static const struct @90 codec_mapping[]
NDIlib_FourCC_video_type_e ndi_fourcc
static const struct video_display_info display_ndi_info
#define NDI_PRINT_COPYRIGHT
static void close_ndi_library(LIB_HANDLE hNDILib)
static const NDIlib_t * NDIlib_load(LIB_HANDLE *lib)
struct used to comunicate with audio capture/playback device
char * convert_buffer
for codecs that need conversion (eg. Y216->P216)
struct video_frame * send_frame
frame that is just being asynchronously sent
int audio_level
audio reference level - usually 0 or 20
NDIlib_video_frame_v2_t NDI_video_frame
struct audio_desc audio_desc
NDIlib_send_instance_t pNDI_send
ndi_disp_convert_t * convert
char * data
Raw tile data. Pointer must be at least 4B aligned.
enum interlacing_t interlacing
unsigned int width
width of every tile (!)
unsigned int height
height of every tile (!)
Struct video_frame represents a video frame and contains video description.
struct tile tiles[FLEXIBLE_ARRAY_MEMBER]
This file contains some common data types.
@ PROGRESSIVE
progressive frame
@ INTERLACED_MERGED
Columngs of both fields are interlaced together.
@ UYVY
YCbCr 422 8-bit - Cb Y0 Cr Y1.
@ Y416
interleaved little-endian YCbCr 4444 16-bit - UYVA
@ Y216
YCbCr 422 16-bit little-endian - Y0 Cb Y1 Cr.
@ RGBA
RGBA 8-bit, big-endian.
This is an umbrella header for video functions.
#define MAX_BPS
maximal (average) number of pixels per know pixel formats (up-round if needed)