UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
syphon.m
Go to the documentation of this file.
1
5/*
6 * Copyright (c) 2017-2023 CESNET, z. s. p. o.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, is permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * 3. Neither the name of CESNET nor the names of its contributors may be
21 * used to endorse or promote products derived from this software without
22 * specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
26 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
28 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
35 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
47#include <AppKit/NSApplication.h>
48#include <OpenGL/gl.h>
49#include <OpenGL/OpenGL.h> // CGL
50#include <OpenGL/glext.h>
51#include <Syphon/Syphon.h>
52#include <pthread.h>
53
54#include "debug.h"
55#include "gl_context.h"
56#include "host.h"
57#include "lib_common.h"
58#include "tv.h"
59#include "utils/color_out.h"
60#include "utils/list.h"
61#include "utils/misc.h"
62#include "video.h"
63#include "video_capture.h"
64
65#define FPS 60.0
66#define MOD_NAME "[syphon cap.] "
67#define DEFAULT_MAX_QUEUE_SIZE 1
68
69static void usage(bool full);
70
71// compat
72#ifndef __MAC_10_12
73#define NSEventTypeApplicationDefined NSApplicationDefined
74#endif
75
77"#define LEGACY 1\n"
78 "#if LEGACY\n"
79 "#define TEXCOORD gl_TexCoord[0]\n"
80 "#else\n"
81 "#define TEXCOORD TEX0\n"
82 "#define texture2D texture\n"
83 "#endif\n"
84 "\n"
85 "#if LEGACY\n"
86 "#define colorOut gl_FragColor\n"
87 "#else\n"
88 "out vec4 colorOut;\n"
89 "#endif\n"
90 "\n"
91 "#if ! LEGACY\n"
92 "in vec4 TEX0;\n"
93 "#endif\n"
94 "\n"
95 "uniform sampler2DRect image;\n"
96 "uniform float imageWidth; // is original image width, it means twice as wide as ours\n"
97 "\n"
98 "void main()\n"
99 "{\n"
100 " vec4 rgba1, rgba2;\n"
101 " vec4 yuv1, yuv2;\n"
102 " vec2 coor1, coor2;\n"
103 " float U, V;\n"
104 "\n"
105 " coor1 = TEXCOORD.xy - vec2(1.0 / (imageWidth * 2.0), 0.0);\n"
106 " coor2 = TEXCOORD.xy + vec2(1.0 / (imageWidth * 2.0), 0.0);\n"
107 "\n"
108 " rgba1 = texture2DRect(image, coor1);\n"
109 " rgba2 = texture2DRect(image, coor2);\n"
110 " \n"
111 " yuv1.x = 1.0/16.0 + (rgba1.r * 0.2126 + rgba1.g * 0.7152 + rgba1.b * 0.0722) * 0.8588; // Y\n"
112 " yuv1.y = 0.5 + (-rgba1.r * 0.1145 - rgba1.g * 0.3854 + rgba1.b * 0.5) * 0.8784;\n"
113 " yuv1.z = 0.5 + (rgba1.r * 0.5 - rgba1.g * 0.4541 - rgba1.b * 0.0458) * 0.8784;\n"
114 " \n"
115 " yuv2.x = 1.0/16.0 + (rgba2.r * 0.2126 + rgba2.g * 0.7152 + rgba2.b * 0.0722) * 0.8588; // Y\n"
116 " yuv2.y = 0.5 + (-rgba2.r * 0.1145 - rgba2.g * 0.3854 + rgba2.b * 0.5) * 0.8784;\n"
117 " yuv2.z = 0.5 + (rgba2.r * 0.5 - rgba2.g * 0.4541 - rgba2.b * 0.0458) * 0.8784;\n"
118 " \n"
119 " U = mix(yuv1.y, yuv2.y, 0.5);\n"
120 " V = mix(yuv1.z, yuv2.z, 0.5);\n"
121 " \n"
122 " colorOut = vec4(U,yuv1.x, V, yuv2.x);\n"
123 "}\n"
124;
125
131
132 CFRunLoopTimerRef timer;
133
135 SyphonClient *client;
136 pthread_mutex_t lock;
137 pthread_cond_t frame_ready_cv;
140
141 GLuint fbo_id;
142 GLuint tex_id;
143
144 NSString *appName;
145 NSString *serverName;
146
149
151
156
159
160 struct module *parent;
161};
162
163static void probe_devices_callback(struct state_vidcap_syphon *s);
164static void vidcap_syphon_done(void *state);
165
166static void reconfigure(struct state_vidcap_syphon *s, struct video_desc desc) {
167 glBindTexture(GL_TEXTURE_2D, s->tex_id);
168 if (s->use_rgb) {
169 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, desc.width, desc.height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
170 } else {
171 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, desc.width / 2, desc.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
172 }
173
174 glBindFramebufferEXT(GL_FRAMEBUFFER, s->fbo_id);
175 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, s->tex_id, 0);
176
177 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
178
179 glMatrixMode( GL_MODELVIEW );
180
181 glLoadIdentity( );
182 glMatrixMode( GL_PROJECTION );
183 glLoadIdentity( );
184 glViewport( 0, 0, ( GLint ) desc.width / (s->use_rgb ? 1 : 2), ( GLint ) desc.height );
185
186 glOrtho(0, desc.width, 0, desc.height, 10, -10);
187
188 if (!s->use_rgb) {
189 glUniform1f(glGetUniformLocation(s->program_to_yuv422, "imageWidth"),
190 (GLfloat) desc.width);
191 }
192
193}
194
195static const char *get_syphon_description(SyphonClient *client) {
196 static char ret[1024];
197 NSDictionary *dict = [client serverDescription];
198 snprintf(ret, sizeof ret, "app: %s name: %s",
199 [[dict objectForKey:@"SyphonServerDescriptionAppNameKey"] UTF8String],
200 [[dict objectForKey:@"SyphonServerDescriptionNameKey"] UTF8String]);
201 return ret;
202}
203
204static void stop_application(void) {
205 [[NSApplication sharedApplication] stop : nil];
206 NSEvent* event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined
207 location:NSMakePoint(0, 0)
208 modifierFlags:0
209 timestamp:0
210 windowNumber:0
211 context:nil
212 subtype:0
213 data1:0
214 data2:0];
215 [[NSApplication sharedApplication] postEvent:event atStart:YES];
216}
217
218static void oneshot_init(CFRunLoopTimerRef timer, void *context);
219
221 CFAbsoluteTime fireTime = CFAbsoluteTimeGetCurrent() + 0.1; // 100 ms
222 CFRunLoopTimerSetNextFireDate(s->timer, fireTime);
223 CFRunLoopAddTimer(CFRunLoopGetCurrent(), s->timer, kCFRunLoopCommonModes);
224}
225
226static void oneshot_init(CFRunLoopTimerRef timer, void *context)
227{
228 CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopCommonModes);
229 struct state_vidcap_syphon *s = context;
230
231 if (s->show_help != 0) {
232 usage(s->show_help == 2);
234 return;
235 }
236
237 if (s->probe_devices) {
240 return;
241 }
242
243 // keepalive - we need to check if s->client is still valid, otherwise
244 // no more events arrive and we won't be able to reconfigure to
245 // eventual restarted sender
247
248 if (s->client && [s->client isValid] == NO) {
249 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Server %s is no longer valid, releasing.\n", get_syphon_description(s->client));
250 [s->client release];
251 s->client = nil;
252 }
253
254 // if we are already initialized, exit
255 if (s->client)
256 return;
257
258 NSArray *descriptions;
259 if (s->appName || s->serverName) {
260 descriptions = [[SyphonServerDirectory sharedDirectory] serversMatchingName:s->serverName appName:s->appName];
261 } else {
262 descriptions = [[SyphonServerDirectory sharedDirectory] servers];
263 }
264 if ([descriptions count] == 0) {
265 log_msg(LOG_LEVEL_ERROR, MOD_NAME "No server(s) found!\n");
266 return;
267 }
268
270
271 if (!s->override_fps) {
272 log_msg(LOG_LEVEL_WARNING, MOD_NAME "FPS set to %f. Use override_fps to override if you know FPS of the server.\n", FPS);
273 }
274
275 s->client = [[SyphonClient alloc] initWithServerDescription:[descriptions lastObject] context:CGLGetCurrentContext() options:nil newFrameHandler:^(SyphonClient *client) {
276 if ([client hasNewFrame] == NO)
277 return;
278
279 SyphonImage *img = [client newFrameImage];
280 unsigned int width = [img textureSize].width;
281 unsigned int height = [img textureSize].height;
282
283 gl_context_make_current(&s->gl_context);
284
285 struct video_desc d = {width, height, s->use_rgb ? RGB : UYVY, s->override_fps ? s->override_fps : FPS, PROGRESSIVE, 1};
286 if (!video_desc_eq(s->saved_desc, d)) {
287 reconfigure(s, d);
288 s->saved_desc = d;
289 }
290
291 struct video_frame *f = vf_alloc_desc_data(d);
292
293 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, [img textureName]);
294 glBegin(GL_QUADS);
295 glTexCoord2i(0, height); glVertex2i(0, 0);
296 glTexCoord2i(0, 0); glVertex2i(0, height);
297 glTexCoord2i(width, 0); glVertex2i(width, height);
298 glTexCoord2i(width, height); glVertex2i(width, 0);
299 glEnd();
300
301 glReadPixels(0, 0, width / (s->use_rgb ? 1 : 2), height, s->use_rgb ? GL_RGB : GL_RGBA, GL_UNSIGNED_BYTE, f->tiles[0].data);
302 gl_check_error();
303
304 [img release];
305
306 pthread_mutex_lock(&s->lock);
307 bool pushed = false;
308 if (simple_linked_list_append_if_less(s->q, f, s->max_queue_size)) {
309 pushed = true;
310 } else {
311 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Skipping frame.\n");
312 vf_free(f);
313 }
314 pthread_mutex_unlock(&s->lock);
315
316 if (pushed) {
317 pthread_cond_signal(&s->frame_ready_cv);
318 debug_msg(MOD_NAME "Frame acquired.\n");
319 }
320 }];
321
322 if (!s->client) {
323 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Client could have not been created!\n");
324 } else {
326 }
327}
328
329static void should_exit_syphon(void *state) {
330 struct state_vidcap_syphon *s = (struct state_vidcap_syphon *) state;
331 pthread_mutex_lock(&s->lock);
332 s->should_exit_triggered = true;
333 if (s->mainloop_started) {
335 }
336 pthread_mutex_unlock(&s->lock);
337}
338
339static void syphon_mainloop(void *state)
340{
341 struct state_vidcap_syphon *s = (struct state_vidcap_syphon *) state;
342 pthread_mutex_lock(&s->lock);
343 if (!s->should_exit_triggered) {
344 s->mainloop_started = true;
345 pthread_mutex_unlock(&s->lock);
346 [[NSApplication sharedApplication] run];
347 } else {
348 pthread_mutex_unlock(&s->lock);
349 }
350}
351
358static void usage(bool full)
359{
360 struct key_val options[] = {
361 { "name=<name>", "Syphon server name" },
362 { "app=<appname>", "Syphon server application name" },
363 { "override_fps", "overrides FPS in metadata (but not the actual rate captured)" },
364 { "RGB", "use RGB as an output codec instead of default UYVY" },
365 { NULL, NULL }
366 };
367 struct key_val options_full[] = {
368 { "queue_size=<qlen>", "size of internal frame queue" },
369 { NULL, NULL }
370 };
371 print_module_usage("-t syphon", options, options_full, full);
372 printf("\n");
373
374 printf("Available servers:\n");
375 int i = 1;
376 NSArray *descriptions = [[SyphonServerDirectory sharedDirectory] servers];
377 for (id item in descriptions) {
378 color_printf("\t%d) " TBOLD("app:") " %s " TBOLD("name:") " %s\n", i++, [[item objectForKey:@"SyphonServerDescriptionAppNameKey"] UTF8String], [[item objectForKey:@"SyphonServerDescriptionNameKey"] UTF8String]);
379 //...do something useful with myArrayElement
380 }
381 if ([descriptions count] == 0) {
382 log_msg(LOG_LEVEL_ERROR, MOD_NAME "\tNo Syphon servers found.\n");
383 }
384 color_printf("\n");
385}
386
387static int vidcap_syphon_init_common(char *opts, struct state_vidcap_syphon **out)
388{
389 struct state_vidcap_syphon *s = calloc(1, sizeof *s);
392 pthread_mutex_init(&s->lock, NULL);
393 pthread_cond_init(&s->frame_ready_cv, NULL);
395 glEnable(GL_TEXTURE_2D);
396 glEnable(GL_TEXTURE_RECTANGLE_ARB);
397 CFRunLoopTimerContext timerCtxt = { .info = s };
398 s->timer = CFRunLoopTimerCreate(NULL, 0, 1.0, 0, 0, oneshot_init, &timerCtxt);
400
401 char *item, *save_ptr;
402 item = opts == NULL ? NULL : strtok_r(opts, ":", &save_ptr);
403 while (item) {
404 if (strcmp(item, "help") == 0 || strcmp(item, "fullhelp") == 0) {
405 s->show_help = strcmp(item, "help") == 0 ? 1 : 2;
408 return VIDCAP_INIT_NOERR;
409 } else if (strstr(item, "app=") == item) {
410 s->appName = [NSString stringWithCString: item + strlen("app=") encoding:NSASCIIStringEncoding];
411 } else if (strstr(item, "name=") == item) {
412 s->serverName = [NSString stringWithCString: item + strlen("name=") encoding:NSASCIIStringEncoding];
413 } else if (strstr(item, "override_fps=") == item) {
414 s->override_fps = atof(item + strlen("override_fps="));
415 } else if (strstr(item, "queue_size=") == item) {
416 s->max_queue_size = atoi(strchr(item, '=') + 1);
417 } else if (strcasecmp(item, "RGB") == 0) {
418 s->use_rgb = true;
419 } else {
420 log_msg(LOG_LEVEL_ERROR, "Syphon: Unknown argument - %s\n", item);
422 return VIDCAP_INIT_FAIL;
423 }
424 item = strtok_r(NULL, ":", &save_ptr);
425 }
426
427 glGenFramebuffersEXT(1, &s->fbo_id);
428 glGenTextures(1, &s->tex_id);
429
430 if (!s->use_rgb) {
432 if (s->program_to_yuv422 == 0) {
433 MSG(ERROR, "Cannot compile shader for YUV 4:2:2 conversion!\n");
435 return VIDCAP_INIT_FAIL;
436 }
437 glUseProgram(s->program_to_yuv422);
438 glUniform1i(glGetUniformLocation(s->program_to_yuv422, "image"), 0);
439 }
440
441 *out = s;
442 return VIDCAP_INIT_OK;
443}
444
445static int vidcap_syphon_init(struct vidcap_params *params, void **state)
446{
449 }
450
451 char *opts = strdup(vidcap_params_get_fmt(params));
452 struct state_vidcap_syphon *s = NULL;
453 int ret = vidcap_syphon_init_common(opts, &s);
454 free(opts);
455
456 if (ret != VIDCAP_INIT_OK) {
457 return ret;
458 }
459
463
464 *state = s;
465
466 return VIDCAP_INIT_OK;
467}
468
469static void vidcap_syphon_done(void *state)
470{
471 struct state_vidcap_syphon *s = state;
472 if (s->parent != NULL) {
474 }
475
476 if (s->timer) {
477 CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), s->timer, kCFRunLoopCommonModes);
478 }
479
480 if (s->tex_id != 0) {
481 glDeleteTextures(1, &s->tex_id);
482 }
483
484 if (s->fbo_id != 0) {
485 glDeleteFramebuffersEXT(1, &s->fbo_id);
486 }
487
488 if (s->program_to_yuv422) {
489 glDeleteProgram(s->program_to_yuv422);
490 }
491
493
494 [s->appName release];
495 [s->serverName release];
496 [s->client release];
497 CFRelease(s->timer);
498
499 struct video_frame *f = NULL;
500 while ((f = simple_linked_list_pop(s->q)) != NULL) {
501 vf_free(f);
502 }
504
505 pthread_mutex_destroy(&s->lock);
506 pthread_cond_destroy(&s->frame_ready_cv);
507 free(s);
508}
509
510static struct video_frame *vidcap_syphon_grab(void *state, struct audio_frame **audio)
511{
512 struct state_vidcap_syphon *s = state;
513
514 struct timespec ts;
516 ts_add_nsec(&ts, MS_TO_NS(100LL));
517 pthread_mutex_lock(&s->lock);
518 while (simple_linked_list_size(s->q) == 0) {
519 if (pthread_cond_timedwait(&s->frame_ready_cv, &s->lock, &ts) != 0) {
520 break;
521 }
522 }
523 struct video_frame *ret = simple_linked_list_pop(s->q);
524 pthread_mutex_unlock(&s->lock);
525 if (ret != NULL) {
527 }
528
529 *audio = NULL;
530 return ret;
531}
532
534{
535 NSArray *descriptions = [[SyphonServerDirectory sharedDirectory] servers];
536 for (id item in descriptions) {
537 s->probed_devices_count += 1;
538 s->probed_devices = (struct device_info *) realloc(s->probed_devices, s->probed_devices_count * sizeof(struct device_info));
539 memset(&s->probed_devices[s->probed_devices_count - 1], 0, sizeof(struct device_info));
540 snprintf(s->probed_devices[s->probed_devices_count - 1].dev, sizeof s->probed_devices[s->probed_devices_count - 1].dev,
541 ":app=%s", [[item objectForKey:@"SyphonServerDescriptionAppNameKey"] UTF8String]);
543 "Syphon %s", [[item objectForKey:@"SyphonServerDescriptionAppNameKey"] UTF8String]);
544 }
545}
546
547static void vidcap_syphon_probe(struct device_info **available_devices, int *count, void (**deleter)(void *))
548{
549 *deleter = free;
550 *count = 0;
551 *available_devices = NULL;
552
553 struct state_vidcap_syphon *s = NULL;
554 if (vidcap_syphon_init_common(NULL, &s) != VIDCAP_INIT_OK) {
555 return;
556 }
557 s->probe_devices = true;
560 *available_devices = s->probed_devices;
561 s->probed_devices = NULL;
563}
564
572
574
575/* vim: set expandtab sw=8: */
void ** state
struct video_desc desc
struct audio_frame ** audio
int void(** deleter)(void *))
void vf_free(struct video_frame *buf)
Frees video_frame structure.
int color_printf(const char *format,...)
#define TBOLD(x)
Definition color_out.h:70
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_NOTICE
information that may be interesting
Definition debug.h:61
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define MSG(l, fmt,...)
Definition debug.h:96
#define LOG_LEVEL_WARNING
less severe errors
Definition debug.h:60
bool init_gl_context(struct gl_context *context, int which)
initializes specified OpenGL context
Definition gl_context.c:69
void destroy_gl_context(struct gl_context *context)
Definition gl_context.c:223
void gl_context_make_current(struct gl_context *context)
Definition gl_context.c:236
GLuint glsl_compile_link(const char *vprogram, const char *fprogram)
Definition gl_context.c:147
#define GL_CONTEXT_LEGACY
Definition gl_context.h:73
#define VIDCAP_INIT_NOERR
state not initialized, other action performed (typically help)
#define VIDCAP_INIT_OK
initialization successful
#define VIDEO_CAPTURE_ABI_VERSION
#define VIDCAP_INIT_FAIL
error ocured
#define VIDCAP_INIT_AUDIO_NOT_SUPPORTED
card does not support audio
int count
Definition hd-rum.c:44
void register_should_exit_callback(struct module *mod, void(*callback)(void *), void *udata)
Definition host.cpp:1144
void unregister_should_exit_callback(struct module *mod, void(*callback)(void *), void *udata)
Definition host.cpp:1158
bool register_mainloop(mainloop_t m, void *u)
Definition host.cpp:1132
void usage()
Definition main.cpp:28
@ LIBRARY_CLASS_VIDEO_CAPTURE
Definition lib_common.h:78
#define REGISTER_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
Definition lib_common.h:144
int simple_linked_list_size(struct simple_linked_list *l)
Definition list.cpp:93
struct simple_linked_list * simple_linked_list_init(void)
Definition list.cpp:53
void simple_linked_list_destroy(struct simple_linked_list *l)
Definition list.cpp:58
void * simple_linked_list_pop(struct simple_linked_list *l)
Definition list.cpp:82
void print_module_usage(const char *module_name, const struct key_val *options, const struct key_val *options_full, bool print_full_help)
Definition misc.cpp:242
struct used to comunicate with audio capture/playback device
Definition types.h:99
char name[1024]
human readable name of the device
Definition types.h:385
char dev[1024]
Definition types.h:383
Definition hd-rum.c:27
Definition misc.h:68
Definition rtp.c:253
pthread_mutex_t lock
Definition syphon.m:136
struct gl_context gl_context
Definition syphon.m:134
int show_help
only show help and exit - 1 - standard; 2 - full
Definition syphon.m:152
double override_fps
Definition syphon.m:147
NSString * serverName
Definition syphon.m:145
bool probe_devices
devices probed
Definition syphon.m:153
struct simple_linked_list * q
Definition syphon.m:138
NSString * appName
Definition syphon.m:144
CFRunLoopTimerRef timer
Definition syphon.m:132
bool should_exit_triggered
should_exit callback called just before starting mainloop
Definition syphon.m:155
pthread_cond_t frame_ready_cv
Definition syphon.m:137
GLuint program_to_yuv422
Definition syphon.m:150
SyphonClient * client
Definition syphon.m:135
size_t max_queue_size
Definition syphon.m:139
struct device_info * probed_devices
used only if state_vidcap_syphon::probe_devices is true
Definition syphon.m:158
struct module * parent
Definition syphon.m:160
int probed_devices_count
used only if state_vidcap_syphon::probe_devices is true
Definition syphon.m:157
struct video_desc saved_desc
Definition syphon.m:130
bool mainloop_started
our mainloop is started (if display is GL/SDL, it won't be started)
Definition syphon.m:154
unsigned int width
width of every tile (!)
Definition types.h:179
unsigned int height
height of every tile (!)
Definition types.h:180
void(* dispose)(struct video_frame *)
Definition types.h:245
Struct video_frame represents a video frame and contains video description.
Definition types.h:305
struct video_frame_callbacks callbacks
Definition types.h:324
static void reconfigure(struct state_vidcap_syphon *s, struct video_desc desc)
Definition syphon.m:166
static struct video_frame * vidcap_syphon_grab(void *state, struct audio_frame **audio)
Definition syphon.m:510
static void should_exit_syphon(void *state)
Definition syphon.m:329
static int vidcap_syphon_init(struct vidcap_params *params, void **state)
Definition syphon.m:445
static void vidcap_syphon_probe(struct device_info **available_devices, int *count, void(**deleter)(void *))
Definition syphon.m:547
static const struct video_capture_info vidcap_syphon_info
Definition syphon.m:565
static void probe_devices_callback(struct state_vidcap_syphon *s)
Definition syphon.m:533
static void oneshot_init(CFRunLoopTimerRef timer, void *context)
Definition syphon.m:226
static const char fp_display_rgba_to_yuv422_legacy[]
Definition syphon.m:76
static int vidcap_syphon_init_common(char *opts, struct state_vidcap_syphon **out)
Definition syphon.m:387
static void stop_application(void)
Definition syphon.m:204
#define MOD_NAME
Definition syphon.m:66
static void vidcap_syphon_done(void *state)
Definition syphon.m:469
#define DEFAULT_MAX_QUEUE_SIZE
Definition syphon.m:67
#define FPS
Definition syphon.m:65
static void schedule_next_event(struct state_vidcap_syphon *s)
Definition syphon.m:220
static const char * get_syphon_description(SyphonClient *client)
Definition syphon.m:195
static void syphon_mainloop(void *state)
Definition syphon.m:339
uint32_t ts
Definition tfrc.c:101
void ts_add_nsec(struct timespec *ts, long long offset)
Definition tv.c:79
int timespec_get(struct timespec *ts, int base)
Definition tv.c:236
#define TIME_UTC
Definition tv.h:116
#define MS_TO_NS(val_ms)
Definition tv.h:99
This is an umbrella header for video functions.
struct module * vidcap_params_get_parent(const struct vidcap_params *params)
const char * vidcap_params_get_fmt(const struct vidcap_params *params)
unsigned int vidcap_params_get_flags(const struct vidcap_params *params)
#define VIDCAP_FLAG_AUDIO_ANY