1 /******************************************************************************
2     Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
3 
4     This program is free software: you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation, either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 ******************************************************************************/
17 
18 /* Useful C++ classes and bindings for base obs data */
19 
20 #pragma once
21 
22 #include "obs.h"
23 
24 /* RAII wrappers */
25 
26 template<typename T, void addref(T), void release(T)> class OBSRef;
27 
28 using OBSSource = OBSRef<obs_source_t *, obs_source_addref, obs_source_release>;
29 using OBSScene = OBSRef<obs_scene_t *, obs_scene_addref, obs_scene_release>;
30 using OBSSceneItem =
31 	OBSRef<obs_sceneitem_t *, obs_sceneitem_addref, obs_sceneitem_release>;
32 using OBSData = OBSRef<obs_data_t *, obs_data_addref, obs_data_release>;
33 using OBSDataArray = OBSRef<obs_data_array_t *, obs_data_array_addref,
34 			    obs_data_array_release>;
35 using OBSOutput = OBSRef<obs_output_t *, obs_output_addref, obs_output_release>;
36 using OBSEncoder =
37 	OBSRef<obs_encoder_t *, obs_encoder_addref, obs_encoder_release>;
38 using OBSService =
39 	OBSRef<obs_service_t *, obs_service_addref, obs_service_release>;
40 
41 using OBSWeakSource = OBSRef<obs_weak_source_t *, obs_weak_source_addref,
42 			     obs_weak_source_release>;
43 using OBSWeakOutput = OBSRef<obs_weak_output_t *, obs_weak_output_addref,
44 			     obs_weak_output_release>;
45 using OBSWeakEncoder = OBSRef<obs_weak_encoder_t *, obs_weak_encoder_addref,
46 			      obs_weak_encoder_release>;
47 using OBSWeakService = OBSRef<obs_weak_service_t *, obs_weak_service_addref,
48 			      obs_weak_service_release>;
49 
50 template<typename T, void addref(T), void release(T)> class OBSRef {
51 	T val;
52 
Replace(T valIn)53 	inline OBSRef &Replace(T valIn)
54 	{
55 		addref(valIn);
56 		release(val);
57 		val = valIn;
58 		return *this;
59 	}
60 
61 	struct TakeOwnership {
62 	};
OBSRef(T val,TakeOwnership)63 	inline OBSRef(T val, TakeOwnership) : val(val) {}
64 
65 public:
OBSRef()66 	inline OBSRef() : val(nullptr) {}
OBSRef(T val_)67 	inline OBSRef(T val_) : val(val_) { addref(val); }
OBSRef(const OBSRef & ref)68 	inline OBSRef(const OBSRef &ref) : val(ref.val) { addref(val); }
OBSRef(OBSRef && ref)69 	inline OBSRef(OBSRef &&ref) : val(ref.val) { ref.val = nullptr; }
70 
~OBSRef()71 	inline ~OBSRef() { release(val); }
72 
operator =(T valIn)73 	inline OBSRef &operator=(T valIn) { return Replace(valIn); }
operator =(const OBSRef & ref)74 	inline OBSRef &operator=(const OBSRef &ref) { return Replace(ref.val); }
75 
operator =(OBSRef && ref)76 	inline OBSRef &operator=(OBSRef &&ref)
77 	{
78 		if (this != &ref) {
79 			release(val);
80 			val = ref.val;
81 			ref.val = nullptr;
82 		}
83 
84 		return *this;
85 	}
86 
operator T() const87 	inline operator T() const { return val; }
Get() const88 	inline T Get() const { return val; }
89 
operator ==(T p) const90 	inline bool operator==(T p) const { return val == p; }
operator !=(T p) const91 	inline bool operator!=(T p) const { return val != p; }
92 
93 	friend OBSSource OBSGetStrongRef(obs_weak_source_t *weak);
94 	friend OBSWeakSource OBSGetWeakRef(obs_source_t *source);
95 
96 	friend OBSOutput OBSGetStrongRef(obs_weak_output_t *weak);
97 	friend OBSWeakOutput OBSGetWeakRef(obs_output_t *output);
98 
99 	friend OBSEncoder OBSGetStrongRef(obs_weak_encoder_t *weak);
100 	friend OBSWeakEncoder OBSGetWeakRef(obs_encoder_t *encoder);
101 
102 	friend OBSService OBSGetStrongRef(obs_weak_service_t *weak);
103 	friend OBSWeakService OBSGetWeakRef(obs_service_t *service);
104 };
105 
OBSGetStrongRef(obs_weak_source_t * weak)106 inline OBSSource OBSGetStrongRef(obs_weak_source_t *weak)
107 {
108 	return {obs_weak_source_get_source(weak), OBSSource::TakeOwnership()};
109 }
110 
OBSGetWeakRef(obs_source_t * source)111 inline OBSWeakSource OBSGetWeakRef(obs_source_t *source)
112 {
113 	return {obs_source_get_weak_source(source),
114 		OBSWeakSource::TakeOwnership()};
115 }
116 
OBSGetStrongRef(obs_weak_output_t * weak)117 inline OBSOutput OBSGetStrongRef(obs_weak_output_t *weak)
118 {
119 	return {obs_weak_output_get_output(weak), OBSOutput::TakeOwnership()};
120 }
121 
OBSGetWeakRef(obs_output_t * output)122 inline OBSWeakOutput OBSGetWeakRef(obs_output_t *output)
123 {
124 	return {obs_output_get_weak_output(output),
125 		OBSWeakOutput::TakeOwnership()};
126 }
127 
OBSGetStrongRef(obs_weak_encoder_t * weak)128 inline OBSEncoder OBSGetStrongRef(obs_weak_encoder_t *weak)
129 {
130 	return {obs_weak_encoder_get_encoder(weak),
131 		OBSEncoder::TakeOwnership()};
132 }
133 
OBSGetWeakRef(obs_encoder_t * encoder)134 inline OBSWeakEncoder OBSGetWeakRef(obs_encoder_t *encoder)
135 {
136 	return {obs_encoder_get_weak_encoder(encoder),
137 		OBSWeakEncoder::TakeOwnership()};
138 }
139 
OBSGetStrongRef(obs_weak_service_t * weak)140 inline OBSService OBSGetStrongRef(obs_weak_service_t *weak)
141 {
142 	return {obs_weak_service_get_service(weak),
143 		OBSService::TakeOwnership()};
144 }
145 
OBSGetWeakRef(obs_service_t * service)146 inline OBSWeakService OBSGetWeakRef(obs_service_t *service)
147 {
148 	return {obs_service_get_weak_service(service),
149 		OBSWeakService::TakeOwnership()};
150 }
151 
152 /* objects that are not meant to be instanced */
153 template<typename T, void destroy(T)> class OBSObj {
154 	T obj;
155 
156 public:
OBSObj()157 	inline OBSObj() : obj(nullptr) {}
OBSObj(T obj_)158 	inline OBSObj(T obj_) : obj(obj_) {}
159 	inline OBSObj(const OBSObj &) = delete;
OBSObj(OBSObj && other)160 	inline OBSObj(OBSObj &&other) : obj(other.obj) { other.obj = nullptr; }
161 
~OBSObj()162 	inline ~OBSObj() { destroy(obj); }
163 
operator =(T obj_)164 	inline OBSObj &operator=(T obj_)
165 	{
166 		if (obj_ != obj)
167 			destroy(obj);
168 		obj = obj_;
169 		return *this;
170 	}
171 	inline OBSObj &operator=(const OBSObj &) = delete;
operator =(OBSObj && other)172 	inline OBSObj &operator=(OBSObj &&other)
173 	{
174 		if (obj)
175 			destroy(obj);
176 		obj = other.obj;
177 		other.obj = nullptr;
178 		return *this;
179 	}
180 
operator T() const181 	inline operator T() const { return obj; }
182 
operator ==(T p) const183 	inline bool operator==(T p) const { return obj == p; }
operator !=(T p) const184 	inline bool operator!=(T p) const { return obj != p; }
185 };
186 
187 using OBSDisplay = OBSObj<obs_display_t *, obs_display_destroy>;
188 using OBSView = OBSObj<obs_view_t *, obs_view_destroy>;
189 
190 /* signal handler connection */
191 class OBSSignal {
192 	signal_handler_t *handler;
193 	const char *signal;
194 	signal_callback_t callback;
195 	void *param;
196 
197 public:
OBSSignal()198 	inline OBSSignal()
199 		: handler(nullptr),
200 		  signal(nullptr),
201 		  callback(nullptr),
202 		  param(nullptr)
203 	{
204 	}
205 
OBSSignal(signal_handler_t * handler_,const char * signal_,signal_callback_t callback_,void * param_)206 	inline OBSSignal(signal_handler_t *handler_, const char *signal_,
207 			 signal_callback_t callback_, void *param_)
208 		: handler(handler_),
209 		  signal(signal_),
210 		  callback(callback_),
211 		  param(param_)
212 	{
213 		signal_handler_connect_ref(handler, signal, callback, param);
214 	}
215 
Disconnect()216 	inline void Disconnect()
217 	{
218 		signal_handler_disconnect(handler, signal, callback, param);
219 		handler = nullptr;
220 		signal = nullptr;
221 		callback = nullptr;
222 		param = nullptr;
223 	}
224 
~OBSSignal()225 	inline ~OBSSignal() { Disconnect(); }
226 
Connect(signal_handler_t * handler_,const char * signal_,signal_callback_t callback_,void * param_)227 	inline void Connect(signal_handler_t *handler_, const char *signal_,
228 			    signal_callback_t callback_, void *param_)
229 	{
230 		Disconnect();
231 
232 		handler = handler_;
233 		signal = signal_;
234 		callback = callback_;
235 		param = param_;
236 		signal_handler_connect_ref(handler, signal, callback, param);
237 	}
238 
239 	OBSSignal(const OBSSignal &) = delete;
OBSSignal(OBSSignal && other)240 	OBSSignal(OBSSignal &&other) noexcept
241 		: handler(other.handler),
242 		  signal(other.signal),
243 		  callback(other.callback),
244 		  param(other.param)
245 	{
246 		other.handler = nullptr;
247 		other.signal = nullptr;
248 		other.callback = nullptr;
249 		other.param = nullptr;
250 	}
251 
252 	OBSSignal &operator=(const OBSSignal &) = delete;
operator =(OBSSignal && other)253 	OBSSignal &operator=(OBSSignal &&other) noexcept
254 	{
255 		Disconnect();
256 
257 		handler = other.handler;
258 		signal = other.signal;
259 		callback = other.callback;
260 		param = other.param;
261 
262 		other.handler = nullptr;
263 		other.signal = nullptr;
264 		other.callback = nullptr;
265 		other.param = nullptr;
266 
267 		return *this;
268 	}
269 };
270