1 #include <obs-module.h>
2 #include <util/platform.h>
3 #include "shared-memory-queue.h"
4 
5 struct virtualcam_data {
6 	obs_output_t *output;
7 	video_queue_t *vq;
8 };
9 
virtualcam_name(void * unused)10 static const char *virtualcam_name(void *unused)
11 {
12 	UNUSED_PARAMETER(unused);
13 	return "Virtual Camera Output";
14 }
15 
virtualcam_destroy(void * data)16 static void virtualcam_destroy(void *data)
17 {
18 	struct virtualcam_data *vcam = (struct virtualcam_data *)data;
19 	video_queue_close(vcam->vq);
20 	bfree(data);
21 }
22 
virtualcam_create(obs_data_t * settings,obs_output_t * output)23 static void *virtualcam_create(obs_data_t *settings, obs_output_t *output)
24 {
25 	struct virtualcam_data *vcam =
26 		(struct virtualcam_data *)bzalloc(sizeof(*vcam));
27 	vcam->output = output;
28 
29 	UNUSED_PARAMETER(settings);
30 	return vcam;
31 }
32 
virtualcam_start(void * data)33 static bool virtualcam_start(void *data)
34 {
35 	struct virtualcam_data *vcam = (struct virtualcam_data *)data;
36 	uint32_t width = obs_output_get_width(vcam->output);
37 	uint32_t height = obs_output_get_height(vcam->output);
38 
39 	struct obs_video_info ovi;
40 	obs_get_video_info(&ovi);
41 
42 	uint64_t interval = ovi.fps_den * 10000000ULL / ovi.fps_num;
43 
44 	char res[64];
45 	snprintf(res, sizeof(res), "%dx%dx%lld", (int)width, (int)height,
46 		 (long long)interval);
47 
48 	char *res_file = os_get_config_path_ptr("obs-virtualcam.txt");
49 	os_quick_write_utf8_file_safe(res_file, res, strlen(res), false, "tmp",
50 				      NULL);
51 	bfree(res_file);
52 
53 	vcam->vq = video_queue_create(width, height, interval);
54 	if (!vcam->vq) {
55 		blog(LOG_WARNING, "starting virtual-output failed");
56 		return false;
57 	}
58 
59 	struct video_scale_info vsi = {0};
60 	vsi.format = VIDEO_FORMAT_NV12;
61 	vsi.width = width;
62 	vsi.height = height;
63 	obs_output_set_video_conversion(vcam->output, &vsi);
64 
65 	blog(LOG_INFO, "Virtual output started");
66 	obs_output_begin_data_capture(vcam->output, 0);
67 	return true;
68 }
69 
virtualcam_stop(void * data,uint64_t ts)70 static void virtualcam_stop(void *data, uint64_t ts)
71 {
72 	struct virtualcam_data *vcam = (struct virtualcam_data *)data;
73 	obs_output_end_data_capture(vcam->output);
74 	video_queue_close(vcam->vq);
75 	vcam->vq = NULL;
76 
77 	blog(LOG_INFO, "Virtual output stopped");
78 
79 	UNUSED_PARAMETER(ts);
80 }
81 
virtual_video(void * param,struct video_data * frame)82 static void virtual_video(void *param, struct video_data *frame)
83 {
84 	struct virtualcam_data *vcam = (struct virtualcam_data *)param;
85 
86 	if (!vcam->vq)
87 		return;
88 
89 	video_queue_write(vcam->vq, frame->data, frame->linesize,
90 			  frame->timestamp);
91 }
92 
93 struct obs_output_info virtualcam_info = {
94 	.id = "virtualcam_output",
95 	.flags = OBS_OUTPUT_VIDEO,
96 	.get_name = virtualcam_name,
97 	.create = virtualcam_create,
98 	.destroy = virtualcam_destroy,
99 	.start = virtualcam_start,
100 	.stop = virtualcam_stop,
101 	.raw_video = virtual_video,
102 };
103