1 #include <stdlib.h>
2 #include <util/threading.h>
3 #include <util/platform.h>
4 #include <graphics/graphics.h>
5 #include <obs.h>
6 
7 struct sync_pair_vid {
8 	obs_source_t *source;
9 	gs_texture_t *tex;
10 	gs_texture_t *white;
11 	gs_texture_t *black;
12 };
13 
14 uint64_t starting_time = 0;
15 uint64_t last_frame = 0;
16 
sync_pair_vid_getname(void * unused)17 static const char *sync_pair_vid_getname(void *unused)
18 {
19 	UNUSED_PARAMETER(unused);
20 	return "Sync Test Pair (Video)";
21 }
22 
sync_pair_vid_destroy(void * data)23 static void sync_pair_vid_destroy(void *data)
24 {
25 	struct sync_pair_vid *spv = data;
26 
27 	obs_enter_graphics();
28 	gs_texture_destroy(spv->tex);
29 	gs_texture_destroy(spv->white);
30 	gs_texture_destroy(spv->black);
31 	obs_leave_graphics();
32 
33 	bfree(spv);
34 }
35 
fill_texture(uint32_t * pixels,uint32_t pixel)36 static inline void fill_texture(uint32_t *pixels, uint32_t pixel)
37 {
38 	size_t x, y;
39 
40 	for (y = 0; y < 32; y++) {
41 		for (x = 0; x < 32; x++) {
42 			pixels[y * 32 + x] = pixel;
43 		}
44 	}
45 }
46 
sync_pair_vid_create(obs_data_t * settings,obs_source_t * source)47 static void *sync_pair_vid_create(obs_data_t *settings, obs_source_t *source)
48 {
49 	struct sync_pair_vid *spv = bzalloc(sizeof(struct sync_pair_vid));
50 	spv->source = source;
51 
52 	obs_enter_graphics();
53 	spv->tex = gs_texture_create(32, 32, GS_RGBA, 1, NULL, GS_DYNAMIC);
54 	spv->white = gs_texture_create(32, 32, GS_RGBA, 1, NULL, GS_DYNAMIC);
55 	spv->black = gs_texture_create(32, 32, GS_RGBA, 1, NULL, GS_DYNAMIC);
56 
57 	uint8_t *ptr;
58 	uint32_t linesize;
59 	if (gs_texture_map(spv->white, &ptr, &linesize)) {
60 		fill_texture((uint32_t *)ptr, 0xFFFFFFFF);
61 		gs_texture_unmap(spv->white);
62 	}
63 	if (gs_texture_map(spv->black, &ptr, &linesize)) {
64 		fill_texture((uint32_t *)ptr, 0xFF000000);
65 		gs_texture_unmap(spv->black);
66 	}
67 
68 	obs_leave_graphics();
69 
70 	return spv;
71 }
72 
whitelist_time(uint64_t ts,uint64_t interval,uint64_t fps_num,uint64_t fps_den)73 static inline bool whitelist_time(uint64_t ts, uint64_t interval,
74 				  uint64_t fps_num, uint64_t fps_den)
75 {
76 	if (!starting_time)
77 		return false;
78 
79 	uint64_t count = (ts - starting_time) / interval;
80 	uint64_t sec = count * fps_den / fps_num;
81 	return sec % 2 == 1;
82 }
83 
sync_pair_vid_render(void * data,gs_effect_t * effect)84 static void sync_pair_vid_render(void *data, gs_effect_t *effect)
85 {
86 	struct sync_pair_vid *spv = data;
87 
88 	uint64_t ts = obs_get_video_frame_time();
89 	if (!starting_time)
90 		starting_time = ts;
91 
92 	uint64_t interval = video_output_get_frame_time(obs_get_video());
93 	const struct video_output_info *voi =
94 		video_output_get_info(obs_get_video());
95 	uint64_t fps_num = voi->fps_num;
96 	uint64_t fps_den = voi->fps_den;
97 
98 	bool whitelist = whitelist_time(ts, interval, fps_num, fps_den);
99 
100 #if 0
101 	if (last_frame != ts) {
102 		uint8_t *ptr;
103 		uint32_t linesize;
104 		if (gs_texture_map(spv->tex, &ptr, &linesize)) {
105 			fill_texture((uint32_t*)ptr, whitelist ? 0xFFFFFFFF : 0xFF000000);
106 			gs_texture_unmap(spv->tex);
107 		}
108 		last_frame = ts;
109 	}
110 
111 	obs_source_draw(spv->tex, 0, 0, 0, 0, 0);
112 #else
113 	obs_source_draw(whitelist ? spv->white : spv->black, 0, 0, 0, 0, 0);
114 #endif
115 }
116 
sync_pair_vid_size(void * data)117 static uint32_t sync_pair_vid_size(void *data)
118 {
119 	return 32;
120 }
121 
122 struct obs_source_info sync_video = {
123 	.id = "sync_video",
124 	.type = OBS_SOURCE_TYPE_INPUT,
125 	.output_flags = OBS_SOURCE_VIDEO,
126 	.get_name = sync_pair_vid_getname,
127 	.create = sync_pair_vid_create,
128 	.destroy = sync_pair_vid_destroy,
129 	.video_render = sync_pair_vid_render,
130 	.get_width = sync_pair_vid_size,
131 	.get_height = sync_pair_vid_size,
132 };
133