1 /* GStreamer
2 * Copyright (C) 2011 David Schleef <ds@schleef.org>
3 * Copyright (C) 2014 Sebastian Dröge <sebastian@centricular.com>
4 * Copyright (C) 2015 Florian Langlois <florian.langlois@fr.thalesgroup.com>
5 * Copyright (C) 2020 Sohonet <dev@sohonet.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
20 * Boston, MA 02110-1335, USA.
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <gst/gst.h>
28 #include "gstdecklink.h"
29 #include "gstdecklinkaudiosink.h"
30 #include "gstdecklinkvideosink.h"
31 #include "gstdecklinkaudiosrc.h"
32 #include "gstdecklinkvideosrc.h"
33 #include "gstdecklinkdeviceprovider.h"
34
35 GST_DEBUG_CATEGORY_STATIC (gst_decklink_debug);
36 #define GST_CAT_DEFAULT gst_decklink_debug
37
38 GType
gst_decklink_mode_get_type(void)39 gst_decklink_mode_get_type (void)
40 {
41 static gsize id = 0;
42 static const GEnumValue modes[] = {
43 {GST_DECKLINK_MODE_AUTO, "Automatic detection", "auto"},
44
45 {GST_DECKLINK_MODE_NTSC, "NTSC SD 60i", "ntsc"},
46 {GST_DECKLINK_MODE_NTSC2398, "NTSC SD 60i (24 fps)", "ntsc2398"},
47 {GST_DECKLINK_MODE_PAL, "PAL SD 50i", "pal"},
48 {GST_DECKLINK_MODE_NTSC_P, "NTSC SD 60p", "ntsc-p"},
49 {GST_DECKLINK_MODE_PAL_P, "PAL SD 50p", "pal-p"},
50
51 {GST_DECKLINK_MODE_1080p2398, "HD1080 23.98p", "1080p2398"},
52 {GST_DECKLINK_MODE_1080p24, "HD1080 24p", "1080p24"},
53 {GST_DECKLINK_MODE_1080p25, "HD1080 25p", "1080p25"},
54 {GST_DECKLINK_MODE_1080p2997, "HD1080 29.97p", "1080p2997"},
55 {GST_DECKLINK_MODE_1080p30, "HD1080 30p", "1080p30"},
56
57 {GST_DECKLINK_MODE_1080i50, "HD1080 50i", "1080i50"},
58 {GST_DECKLINK_MODE_1080i5994, "HD1080 59.94i", "1080i5994"},
59 {GST_DECKLINK_MODE_1080i60, "HD1080 60i", "1080i60"},
60
61 {GST_DECKLINK_MODE_1080p50, "HD1080 50p", "1080p50"},
62 {GST_DECKLINK_MODE_1080p5994, "HD1080 59.94p", "1080p5994"},
63 {GST_DECKLINK_MODE_1080p60, "HD1080 60p", "1080p60"},
64
65 {GST_DECKLINK_MODE_720p50, "HD720 50p", "720p50"},
66 {GST_DECKLINK_MODE_720p5994, "HD720 59.94p", "720p5994"},
67 {GST_DECKLINK_MODE_720p60, "HD720 60p", "720p60"},
68
69 {GST_DECKLINK_MODE_1556p2398, "2k 23.98p", "1556p2398"},
70 {GST_DECKLINK_MODE_1556p24, "2k 24p", "1556p24"},
71 {GST_DECKLINK_MODE_1556p25, "2k 25p", "1556p25"},
72
73 {GST_DECKLINK_MODE_2KDCI2398, "2k dci 23.98p", "2kdcip2398"},
74 {GST_DECKLINK_MODE_2KDCI24, "2k dci 24p", "2kdcip24"},
75 {GST_DECKLINK_MODE_2KDCI25, "2k dci 25p", "2kdcip25"},
76 {GST_DECKLINK_MODE_2KDCI2997, "2k dci 29.97p", "2kdcip2997"},
77 {GST_DECKLINK_MODE_2KDCI30, "2k dci 30p", "2kdcip30"},
78 {GST_DECKLINK_MODE_2KDCI50, "2k dci 50p", "2kdcip50"},
79 {GST_DECKLINK_MODE_2KDCI5994, "2k dci 59.94p", "2kdcip5994"},
80 {GST_DECKLINK_MODE_2KDCI60, "2k dci 60p", "2kdcip60"},
81
82 {GST_DECKLINK_MODE_2160p2398, "4k 23.98p", "2160p2398"},
83 {GST_DECKLINK_MODE_2160p24, "4k 24p", "2160p24"},
84 {GST_DECKLINK_MODE_2160p25, "4k 25p", "2160p25"},
85 {GST_DECKLINK_MODE_2160p2997, "4k 29.97p", "2160p2997"},
86 {GST_DECKLINK_MODE_2160p30, "4k 30p", "2160p30"},
87 {GST_DECKLINK_MODE_2160p50, "4k 50p", "2160p50"},
88 {GST_DECKLINK_MODE_2160p5994, "4k 59.94p", "2160p5994"},
89 {GST_DECKLINK_MODE_2160p60, "4k 60p", "2160p60"},
90
91 {GST_DECKLINK_MODE_NTSC_WIDESCREEN, "NTSC SD 60i Widescreen",
92 "ntsc-widescreen"},
93 {GST_DECKLINK_MODE_NTSC2398_WIDESCREEN, "NTSC SD 60i Widescreen (24 fps)",
94 "ntsc2398-widescreen"},
95 {GST_DECKLINK_MODE_PAL_WIDESCREEN, "PAL SD 50i Widescreen",
96 "pal-widescreen"},
97 {GST_DECKLINK_MODE_NTSC_P_WIDESCREEN, "NTSC SD 60p Widescreen",
98 "ntsc-p-widescreen"},
99 {GST_DECKLINK_MODE_PAL_P_WIDESCREEN, "PAL SD 50p Widescreen",
100 "pal-p-widescreen"},
101
102 {0, NULL, NULL}
103 };
104
105 if (g_once_init_enter (&id)) {
106 GType tmp = g_enum_register_static ("GstDecklinkModes", modes);
107 g_once_init_leave (&id, tmp);
108 }
109
110 return (GType) id;
111 }
112
113 GType
gst_decklink_connection_get_type(void)114 gst_decklink_connection_get_type (void)
115 {
116 static gsize id = 0;
117 static const GEnumValue connections[] = {
118 {GST_DECKLINK_CONNECTION_AUTO, "Auto", "auto"},
119 {GST_DECKLINK_CONNECTION_SDI, "SDI", "sdi"},
120 {GST_DECKLINK_CONNECTION_HDMI, "HDMI", "hdmi"},
121 {GST_DECKLINK_CONNECTION_OPTICAL_SDI, "Optical SDI", "optical-sdi"},
122 {GST_DECKLINK_CONNECTION_COMPONENT, "Component", "component"},
123 {GST_DECKLINK_CONNECTION_COMPOSITE, "Composite", "composite"},
124 {GST_DECKLINK_CONNECTION_SVIDEO, "S-Video", "svideo"},
125 {0, NULL, NULL}
126 };
127
128 if (g_once_init_enter (&id)) {
129 GType tmp = g_enum_register_static ("GstDecklinkConnection", connections);
130 g_once_init_leave (&id, tmp);
131 }
132
133 return (GType) id;
134 }
135
136 GType
gst_decklink_video_format_get_type(void)137 gst_decklink_video_format_get_type (void)
138 {
139 static gsize id = 0;
140 static const GEnumValue types[] = {
141 {GST_DECKLINK_VIDEO_FORMAT_AUTO, "Auto", "auto"},
142 {GST_DECKLINK_VIDEO_FORMAT_8BIT_YUV, "bmdFormat8BitYUV", "8bit-yuv"},
143 {GST_DECKLINK_VIDEO_FORMAT_10BIT_YUV, "bmdFormat10BitYUV", "10bit-yuv"},
144 {GST_DECKLINK_VIDEO_FORMAT_8BIT_ARGB, "bmdFormat8BitARGB", "8bit-argb"},
145 {GST_DECKLINK_VIDEO_FORMAT_8BIT_BGRA, "bmdFormat8BitBGRA", "8bit-bgra"},
146 /* Not yet supported:
147 {GST_DECKLINK_VIDEO_FORMAT_10BIT_RGB, "bmdFormat10BitRGB", "10bit-rgb"},
148 {GST_DECKLINK_VIDEO_FORMAT_12BIT_RGB, "bmdFormat12BitRGB", "12bit-rgb"},
149 {GST_DECKLINK_VIDEO_FORMAT_12BIT_RGBLE, "bmdFormat12BitRGBLE", "12bit-rgble"},
150 {GST_DECKLINK_VIDEO_FORMAT_10BIT_RGBXLE, "bmdFormat10BitRGBXLE", "10bit-rgbxle"},
151 {GST_DECKLINK_VIDEO_FORMAT_10BIT_RGBX, "bmdFormat10BitRGBX", "10bit-rgbx"},
152 */
153 {0, NULL, NULL}
154 };
155
156 if (g_once_init_enter (&id)) {
157 GType tmp = g_enum_register_static ("GstDecklinkVideoFormat", types);
158 g_once_init_leave (&id, tmp);
159 }
160
161 return (GType) id;
162 }
163
164 /**
165 * GstDecklinkProfileId:
166 * @GST_DECKLINK_PROFILE_ID_DEFAULT: Don't change the profile
167 * @GST_DECKLINK_PROFILE_ID_ONE_SUB_DEVICE_FULL_DUPLEX: Equivalent to bmdProfileOneSubDeviceFullDuplex
168 * @GST_DECKLINK_PROFILE_ID_ONE_SUB_DEVICE_HALF_DUPLEX: Equivalent to bmdProfileOneSubDeviceHalfDuplex
169 * @GST_DECKLINK_PROFILE_ID_TWO_SUB_DEVICES_FULL_DUPLEX: Equivalent to bmdProfileTwoSubDevicesFullDuplex
170 * @GST_DECKLINK_PROFILE_ID_TWO_SUB_DEVICES_HALF_DUPLEX: Equivalent to bmdProfileTwoSubDevicesHalfDuplex
171 * @GST_DECKLINK_PROFILE_ID_FOUR_SUB_DEVICES_HALF_DUPLEX: Equivalent to bmdProfileFourSubDevicesHalfDuplex
172 *
173 * Decklink Profile ID
174 *
175 * Since: 1.20
176 */
177 GType
gst_decklink_profile_id_get_type(void)178 gst_decklink_profile_id_get_type (void)
179 {
180 static gsize id = 0;
181 static const GEnumValue types[] = {
182 {GST_DECKLINK_PROFILE_ID_DEFAULT, "Default, don't change profile",
183 "default"},
184 {GST_DECKLINK_PROFILE_ID_ONE_SUB_DEVICE_FULL_DUPLEX,
185 "One sub-device, Full-Duplex", "one-sub-device-full"},
186 {GST_DECKLINK_PROFILE_ID_ONE_SUB_DEVICE_HALF_DUPLEX,
187 "One sub-device, Half-Duplex", "one-sub-device-half"},
188 {GST_DECKLINK_PROFILE_ID_TWO_SUB_DEVICES_FULL_DUPLEX,
189 "Two sub-devices, Full-Duplex", "two-sub-devices-full"},
190 {GST_DECKLINK_PROFILE_ID_TWO_SUB_DEVICES_HALF_DUPLEX,
191 "Two sub-devices, Half-Duplex", "two-sub-devices-half"},
192 {GST_DECKLINK_PROFILE_ID_FOUR_SUB_DEVICES_HALF_DUPLEX,
193 "Four sub-devices, Half-Duplex", "four-sub-devices-half"},
194 {0, NULL, NULL}
195 };
196
197 if (g_once_init_enter (&id)) {
198 GType tmp = g_enum_register_static ("GstDecklinkProfileId", types);
199 g_once_init_leave (&id, tmp);
200 }
201
202 return (GType) id;
203 }
204
205 GType
gst_decklink_timecode_format_get_type(void)206 gst_decklink_timecode_format_get_type (void)
207 {
208 static gsize id = 0;
209 static const GEnumValue timecodeformats[] = {
210 {GST_DECKLINK_TIMECODE_FORMAT_RP188VITC1, "bmdTimecodeRP188VITC1",
211 "rp188vitc1"},
212 {GST_DECKLINK_TIMECODE_FORMAT_RP188VITC2, "bmdTimecodeRP188VITC2",
213 "rp188vitc2"},
214 {GST_DECKLINK_TIMECODE_FORMAT_RP188LTC, "bmdTimecodeRP188LTC", "rp188ltc"},
215 {GST_DECKLINK_TIMECODE_FORMAT_RP188ANY, "bmdTimecodeRP188Any", "rp188any"},
216 {GST_DECKLINK_TIMECODE_FORMAT_VITC, "bmdTimecodeVITC", "vitc"},
217 {GST_DECKLINK_TIMECODE_FORMAT_VITCFIELD2, "bmdTimecodeVITCField2",
218 "vitcfield2"},
219 {GST_DECKLINK_TIMECODE_FORMAT_SERIAL, "bmdTimecodeSerial", "serial"},
220 {0, NULL, NULL}
221 };
222
223 if (g_once_init_enter (&id)) {
224 GType tmp =
225 g_enum_register_static ("GstDecklinkTimecodeFormat", timecodeformats);
226 g_once_init_leave (&id, tmp);
227 }
228
229 return (GType) id;
230 }
231
232 GType
gst_decklink_keyer_mode_get_type(void)233 gst_decklink_keyer_mode_get_type (void)
234 {
235 static gsize id = 0;
236 static const GEnumValue keyermodes[] = {
237 {GST_DECKLINK_KEYER_MODE_OFF, "Off", "off"},
238 {GST_DECKLINK_KEYER_MODE_INTERNAL, "Internal", "internal"},
239 {GST_DECKLINK_KEYER_MODE_EXTERNAL, "External", "external"},
240 {0, NULL, NULL}
241 };
242
243 if (g_once_init_enter (&id)) {
244 GType tmp = g_enum_register_static ("GstDecklinkKeyerMode", keyermodes);
245 g_once_init_leave (&id, tmp);
246 }
247
248 return (GType) id;
249 }
250
251 GType
gst_decklink_audio_connection_get_type(void)252 gst_decklink_audio_connection_get_type (void)
253 {
254 static gsize id = 0;
255 static const GEnumValue connections[] = {
256 {GST_DECKLINK_AUDIO_CONNECTION_AUTO, "Automatic", "auto"},
257 {GST_DECKLINK_AUDIO_CONNECTION_EMBEDDED, "SDI/HDMI embedded audio",
258 "embedded"},
259 {GST_DECKLINK_AUDIO_CONNECTION_AES_EBU, "AES/EBU input", "aes"},
260 {GST_DECKLINK_AUDIO_CONNECTION_ANALOG, "Analog input", "analog"},
261 {GST_DECKLINK_AUDIO_CONNECTION_ANALOG_XLR, "Analog input (XLR)",
262 "analog-xlr"},
263 {GST_DECKLINK_AUDIO_CONNECTION_ANALOG_RCA, "Analog input (RCA)",
264 "analog-rca"},
265 {0, NULL, NULL}
266 };
267
268 if (g_once_init_enter (&id)) {
269 GType tmp =
270 g_enum_register_static ("GstDecklinkAudioConnection", connections);
271 g_once_init_leave (&id, tmp);
272 }
273
274 return (GType) id;
275 }
276
277 GType
gst_decklink_audio_channels_get_type(void)278 gst_decklink_audio_channels_get_type (void)
279 {
280 static gsize id = 0;
281 static const GEnumValue connections[] = {
282 {GST_DECKLINK_AUDIO_CHANNELS_2, "2 Channels", "2"},
283 {GST_DECKLINK_AUDIO_CHANNELS_8, "8 Channels", "8"},
284 {GST_DECKLINK_AUDIO_CHANNELS_16, "16 Channels", "16"},
285 {GST_DECKLINK_AUDIO_CHANNELS_MAX, "Maximum channels supported", "max"},
286 {0, NULL, NULL}
287 };
288
289 if (g_once_init_enter (&id)) {
290 GType tmp =
291 g_enum_register_static ("GstDecklinkAudioChannels", connections);
292 g_once_init_leave (&id, tmp);
293 }
294
295 return (GType) id;
296 }
297
298 #define NTSC 10, 11, false, "bt601"
299 #define PAL 12, 11, true, "bt601"
300 #define NTSC_WS 40, 33, false, "bt601"
301 #define PAL_WS 16, 11, true, "bt601"
302 #define HD 1, 1, true, "bt709"
303 #define UHD 1, 1, true, "bt2020"
304
305 static const GstDecklinkMode modes[] = {
306 {bmdModeNTSC, 720, 486, 30000, 1001, true, NTSC}, // default is ntsc
307
308 {bmdModeNTSC, 720, 486, 30000, 1001, true, NTSC},
309 {bmdModeNTSC2398, 720, 486, 24000, 1001, true, NTSC},
310 {bmdModePAL, 720, 576, 25, 1, true, PAL},
311 {bmdModeNTSCp, 720, 486, 30000, 1001, false, NTSC},
312 {bmdModePALp, 720, 576, 25, 1, false, PAL},
313
314 {bmdModeHD1080p2398, 1920, 1080, 24000, 1001, false, HD},
315 {bmdModeHD1080p24, 1920, 1080, 24, 1, false, HD},
316 {bmdModeHD1080p25, 1920, 1080, 25, 1, false, HD},
317 {bmdModeHD1080p2997, 1920, 1080, 30000, 1001, false, HD},
318 {bmdModeHD1080p30, 1920, 1080, 30, 1, false, HD},
319
320 {bmdModeHD1080i50, 1920, 1080, 25, 1, true, HD},
321 {bmdModeHD1080i5994, 1920, 1080, 30000, 1001, true, HD},
322 {bmdModeHD1080i6000, 1920, 1080, 30, 1, true, HD},
323
324 {bmdModeHD1080p50, 1920, 1080, 50, 1, false, HD},
325 {bmdModeHD1080p5994, 1920, 1080, 60000, 1001, false, HD},
326 {bmdModeHD1080p6000, 1920, 1080, 60, 1, false, HD},
327
328 {bmdModeHD720p50, 1280, 720, 50, 1, false, HD},
329 {bmdModeHD720p5994, 1280, 720, 60000, 1001, false, HD},
330 {bmdModeHD720p60, 1280, 720, 60, 1, false, HD},
331
332 {bmdMode2k2398, 2048, 1556, 24000, 1001, false, HD},
333 {bmdMode2k24, 2048, 1556, 24, 1, false, HD},
334 {bmdMode2k25, 2048, 1556, 25, 1, false, HD},
335
336 {bmdMode2kDCI2398, 2048, 1080, 24000, 1001, false, HD},
337 {bmdMode2kDCI24, 2048, 1080, 24, 1, false, HD},
338 {bmdMode2kDCI25, 2048, 1080, 25, 1, false, HD},
339 {bmdMode2kDCI2997, 2048, 1080, 30000, 1001, false, HD},
340 {bmdMode2kDCI30, 2048, 1080, 30, 1, false, HD},
341 {bmdMode2kDCI50, 2048, 1080, 50, 1, false, HD},
342 {bmdMode2kDCI5994, 2048, 1080, 60000, 1001, false, HD},
343 {bmdMode2kDCI60, 2048, 1080, 60, 1, false, HD},
344
345 {bmdMode4K2160p2398, 3840, 2160, 24000, 1001, false, UHD},
346 {bmdMode4K2160p24, 3840, 2160, 24, 1, false, UHD},
347 {bmdMode4K2160p25, 3840, 2160, 25, 1, false, UHD},
348 {bmdMode4K2160p2997, 3840, 2160, 30000, 1001, false, UHD},
349 {bmdMode4K2160p30, 3840, 2160, 30, 1, false, UHD},
350 {bmdMode4K2160p50, 3840, 2160, 50, 1, false, UHD},
351 {bmdMode4K2160p5994, 3840, 2160, 60000, 1001, false, UHD},
352 {bmdMode4K2160p60, 3840, 2160, 60, 1, false, UHD},
353
354 {bmdModeNTSC, 720, 486, 30000, 1001, true, NTSC_WS},
355 {bmdModeNTSC2398, 720, 486, 24000, 1001, true, NTSC_WS},
356 {bmdModePAL, 720, 576, 25, 1, true, PAL_WS},
357 {bmdModeNTSCp, 720, 486, 30000, 1001, false, NTSC_WS},
358 {bmdModePALp, 720, 576, 25, 1, false, PAL_WS}
359 };
360
361 static const struct
362 {
363 BMDPixelFormat format;
364 gint bpp;
365 GstVideoFormat vformat;
366 } formats[] = {
367 /* *INDENT-OFF* */
368 {bmdFormat8BitYUV, 2, GST_VIDEO_FORMAT_UYVY}, /* auto */
369 {bmdFormat8BitYUV, 2, GST_VIDEO_FORMAT_UYVY},
370 {bmdFormat10BitYUV, 4, GST_VIDEO_FORMAT_v210},
371 {bmdFormat8BitARGB, 4, GST_VIDEO_FORMAT_ARGB},
372 {bmdFormat8BitBGRA, 4, GST_VIDEO_FORMAT_BGRA},
373 /* Not yet supported
374 {bmdFormat10BitRGB, FIXME, FIXME},
375 {bmdFormat12BitRGB, FIXME, FIXME},
376 {bmdFormat12BitRGBLE, FIXME, FIXME},
377 {bmdFormat10BitRGBXLE, FIXME, FIXME},
378 {bmdFormat10BitRGBX, FIXME, FIXME} */
379 /* *INDENT-ON* */
380 };
381
382 enum ProfileSetOperationResult
383 {
384 PROFILE_SET_UNSUPPORTED,
385 PROFILE_SET_SUCCESS,
386 PROFILE_SET_FAILURE
387 };
388
389 enum DuplexModeSetOperationResult
390 {
391 DUPLEX_MODE_SET_UNSUPPORTED,
392 DUPLEX_MODE_SET_SUCCESS,
393 DUPLEX_MODE_SET_FAILURE
394 };
395
396 static const struct
397 {
398 BMDTimecodeFormat format;
399 GstDecklinkTimecodeFormat gstformat;
400 } tcformats[] = {
401 /* *INDENT-OFF* */
402 {bmdTimecodeRP188VITC1, GST_DECKLINK_TIMECODE_FORMAT_RP188VITC1},
403 {bmdTimecodeRP188VITC2, GST_DECKLINK_TIMECODE_FORMAT_RP188VITC2},
404 {bmdTimecodeRP188LTC, GST_DECKLINK_TIMECODE_FORMAT_RP188LTC},
405 {bmdTimecodeRP188Any, GST_DECKLINK_TIMECODE_FORMAT_RP188ANY},
406 {bmdTimecodeVITC, GST_DECKLINK_TIMECODE_FORMAT_VITC},
407 {bmdTimecodeVITCField2, GST_DECKLINK_TIMECODE_FORMAT_VITCFIELD2},
408 {bmdTimecodeSerial, GST_DECKLINK_TIMECODE_FORMAT_SERIAL}
409 /* *INDENT-ON* */
410 };
411
412 static const struct
413 {
414 BMDKeyerMode keymode;
415 GstDecklinkKeyerMode gstkeymode;
416 } kmodes[] = {
417 /* *INDENT-OFF* */
418 {bmdKeyerModeOff, GST_DECKLINK_KEYER_MODE_OFF},
419 {bmdKeyerModeInternal, GST_DECKLINK_KEYER_MODE_INTERNAL},
420 {bmdKeyerModeExternal, GST_DECKLINK_KEYER_MODE_EXTERNAL}
421 /* *INDENT-ON* */
422 };
423
424 const GstDecklinkMode *
gst_decklink_get_mode(GstDecklinkModeEnum e)425 gst_decklink_get_mode (GstDecklinkModeEnum e)
426 {
427 if (e < GST_DECKLINK_MODE_AUTO || e > GST_DECKLINK_MODE_PAL_P_WIDESCREEN)
428 return NULL;
429 return &modes[e];
430 }
431
432 const GstDecklinkModeEnum
gst_decklink_get_mode_enum_from_bmd(BMDDisplayMode mode)433 gst_decklink_get_mode_enum_from_bmd (BMDDisplayMode mode)
434 {
435 GstDecklinkModeEnum displayMode = GST_DECKLINK_MODE_NTSC;
436 switch (mode) {
437 case bmdModeNTSC:
438 displayMode = GST_DECKLINK_MODE_NTSC;
439 break;
440 case bmdModeNTSC2398:
441 displayMode = GST_DECKLINK_MODE_NTSC2398;
442 break;
443 case bmdModePAL:
444 displayMode = GST_DECKLINK_MODE_PAL;
445 break;
446 case bmdModeNTSCp:
447 displayMode = GST_DECKLINK_MODE_NTSC_P;
448 break;
449 case bmdModePALp:
450 displayMode = GST_DECKLINK_MODE_PAL_P;
451 break;
452 case bmdModeHD1080p2398:
453 displayMode = GST_DECKLINK_MODE_1080p2398;
454 break;
455 case bmdModeHD1080p24:
456 displayMode = GST_DECKLINK_MODE_1080p24;
457 break;
458 case bmdModeHD1080p25:
459 displayMode = GST_DECKLINK_MODE_1080p25;
460 break;
461 case bmdModeHD1080p2997:
462 displayMode = GST_DECKLINK_MODE_1080p2997;
463 break;
464 case bmdModeHD1080p30:
465 displayMode = GST_DECKLINK_MODE_1080p30;
466 break;
467 case bmdModeHD1080i50:
468 displayMode = GST_DECKLINK_MODE_1080i50;
469 break;
470 case bmdModeHD1080i5994:
471 displayMode = GST_DECKLINK_MODE_1080i5994;
472 break;
473 case bmdModeHD1080i6000:
474 displayMode = GST_DECKLINK_MODE_1080i60;
475 break;
476 case bmdModeHD1080p50:
477 displayMode = GST_DECKLINK_MODE_1080p50;
478 break;
479 case bmdModeHD1080p5994:
480 displayMode = GST_DECKLINK_MODE_1080p5994;
481 break;
482 case bmdModeHD1080p6000:
483 displayMode = GST_DECKLINK_MODE_1080p60;
484 break;
485 case bmdModeHD720p50:
486 displayMode = GST_DECKLINK_MODE_720p50;
487 break;
488 case bmdModeHD720p5994:
489 displayMode = GST_DECKLINK_MODE_720p5994;
490 break;
491 case bmdModeHD720p60:
492 displayMode = GST_DECKLINK_MODE_720p60;
493 break;
494 case bmdMode2k2398:
495 displayMode = GST_DECKLINK_MODE_1556p2398;
496 break;
497 case bmdMode2k24:
498 displayMode = GST_DECKLINK_MODE_1556p24;
499 break;
500 case bmdMode2k25:
501 displayMode = GST_DECKLINK_MODE_1556p25;
502 break;
503 case bmdMode2kDCI2398:
504 displayMode = GST_DECKLINK_MODE_2KDCI2398;
505 break;
506 case bmdMode2kDCI24:
507 displayMode = GST_DECKLINK_MODE_2KDCI24;
508 break;
509 case bmdMode2kDCI25:
510 displayMode = GST_DECKLINK_MODE_2KDCI25;
511 break;
512 case bmdMode2kDCI2997:
513 displayMode = GST_DECKLINK_MODE_2KDCI2997;
514 break;
515 case bmdMode2kDCI30:
516 displayMode = GST_DECKLINK_MODE_2KDCI30;
517 break;
518 case bmdMode2kDCI50:
519 displayMode = GST_DECKLINK_MODE_2KDCI50;
520 break;
521 case bmdMode2kDCI5994:
522 displayMode = GST_DECKLINK_MODE_2KDCI5994;
523 break;
524 case bmdMode2kDCI60:
525 displayMode = GST_DECKLINK_MODE_2KDCI60;
526 break;
527 case bmdMode4K2160p2398:
528 displayMode = GST_DECKLINK_MODE_2160p2398;
529 break;
530 case bmdMode4K2160p24:
531 displayMode = GST_DECKLINK_MODE_2160p24;
532 break;
533 case bmdMode4K2160p25:
534 displayMode = GST_DECKLINK_MODE_2160p25;
535 break;
536 case bmdMode4K2160p2997:
537 displayMode = GST_DECKLINK_MODE_2160p2997;
538 break;
539 case bmdMode4K2160p30:
540 displayMode = GST_DECKLINK_MODE_2160p30;
541 break;
542 case bmdMode4K2160p50:
543 displayMode = GST_DECKLINK_MODE_2160p50;
544 break;
545 case bmdMode4K2160p5994:
546 displayMode = GST_DECKLINK_MODE_2160p5994;
547 break;
548 case bmdMode4K2160p60:
549 displayMode = GST_DECKLINK_MODE_2160p60;
550 break;
551 default:
552 displayMode = (GstDecklinkModeEnum) - 1;
553 break;
554 }
555 return displayMode;
556 }
557
558 const BMDPixelFormat
gst_decklink_pixel_format_from_type(GstDecklinkVideoFormat t)559 gst_decklink_pixel_format_from_type (GstDecklinkVideoFormat t)
560 {
561 return formats[t].format;
562 }
563
564 const gint
gst_decklink_bpp_from_type(GstDecklinkVideoFormat t)565 gst_decklink_bpp_from_type (GstDecklinkVideoFormat t)
566 {
567 return formats[t].bpp;
568 }
569
570 const GstDecklinkVideoFormat
gst_decklink_type_from_video_format(GstVideoFormat f)571 gst_decklink_type_from_video_format (GstVideoFormat f)
572 {
573 guint i;
574
575 for (i = 1; i < G_N_ELEMENTS (formats); i++) {
576 if (formats[i].vformat == f)
577 return (GstDecklinkVideoFormat) i;
578 }
579 g_assert_not_reached ();
580 return GST_DECKLINK_VIDEO_FORMAT_AUTO;
581 }
582
583 GstVideoFormat
gst_decklink_video_format_from_type(BMDPixelFormat pf)584 gst_decklink_video_format_from_type (BMDPixelFormat pf)
585 {
586 guint i;
587
588 for (i = 1; i < G_N_ELEMENTS (formats); i++) {
589 if (formats[i].format == pf)
590 return formats[i].vformat;
591 }
592 GST_WARNING ("Unknown pixel format 0x%x", pf);
593 return GST_VIDEO_FORMAT_UNKNOWN;
594 }
595
596
597 const BMDTimecodeFormat
gst_decklink_timecode_format_from_enum(GstDecklinkTimecodeFormat f)598 gst_decklink_timecode_format_from_enum (GstDecklinkTimecodeFormat f)
599 {
600 return tcformats[f].format;
601 }
602
603 const GstDecklinkTimecodeFormat
gst_decklink_timecode_format_to_enum(BMDTimecodeFormat f)604 gst_decklink_timecode_format_to_enum (BMDTimecodeFormat f)
605 {
606 guint i;
607
608 for (i = 0; i < G_N_ELEMENTS (tcformats); i++) {
609 if (tcformats[i].format == f)
610 return (GstDecklinkTimecodeFormat) i;
611 }
612 g_assert_not_reached ();
613 return GST_DECKLINK_TIMECODE_FORMAT_RP188ANY;
614 }
615
616 const BMDKeyerMode
gst_decklink_keyer_mode_from_enum(GstDecklinkKeyerMode m)617 gst_decklink_keyer_mode_from_enum (GstDecklinkKeyerMode m)
618 {
619 return kmodes[m].keymode;
620 }
621
622 const GstDecklinkKeyerMode
gst_decklink_keyer_mode_to_enum(BMDKeyerMode m)623 gst_decklink_keyer_mode_to_enum (BMDKeyerMode m)
624 {
625 guint i;
626
627 for (i = 0; i < G_N_ELEMENTS (kmodes); i++) {
628 if (kmodes[i].keymode == m)
629 return (GstDecklinkKeyerMode) i;
630 }
631 g_assert_not_reached ();
632 return GST_DECKLINK_KEYER_MODE_OFF;
633 }
634
635 static const BMDVideoConnection connections[] = {
636 (BMDVideoConnection) 0, /* auto */
637 bmdVideoConnectionSDI,
638 bmdVideoConnectionHDMI,
639 bmdVideoConnectionOpticalSDI,
640 bmdVideoConnectionComponent,
641 bmdVideoConnectionComposite,
642 bmdVideoConnectionSVideo
643 };
644
645 const BMDVideoConnection
gst_decklink_get_connection(GstDecklinkConnectionEnum e)646 gst_decklink_get_connection (GstDecklinkConnectionEnum e)
647 {
648 g_return_val_if_fail (e != GST_DECKLINK_CONNECTION_AUTO,
649 bmdVideoConnectionSDI);
650
651 if (e <= GST_DECKLINK_CONNECTION_AUTO || e > GST_DECKLINK_CONNECTION_SVIDEO)
652 e = GST_DECKLINK_CONNECTION_SDI;
653
654 return connections[e];
655 }
656
657 static gboolean
gst_decklink_caps_get_pixel_format(GstCaps * caps,BMDPixelFormat * format)658 gst_decklink_caps_get_pixel_format (GstCaps * caps, BMDPixelFormat * format)
659 {
660 GstVideoInfo vinfo;
661 GstVideoFormat f;
662
663 if (gst_video_info_from_caps (&vinfo, caps) == FALSE) {
664 GST_ERROR ("Could not get video info from caps: %" GST_PTR_FORMAT, caps);
665 return FALSE;
666 }
667
668 f = vinfo.finfo->format;
669 *format = gst_decklink_pixel_format_from_type(gst_decklink_type_from_video_format (f));
670 return TRUE;
671 }
672
673 static GstStructure *
gst_decklink_mode_get_generic_structure(GstDecklinkModeEnum e)674 gst_decklink_mode_get_generic_structure (GstDecklinkModeEnum e)
675 {
676 const GstDecklinkMode *mode = &modes[e];
677 GstStructure *s = gst_structure_new ("video/x-raw",
678 "width", G_TYPE_INT, mode->width,
679 "height", G_TYPE_INT, mode->height,
680 "pixel-aspect-ratio", GST_TYPE_FRACTION, mode->par_n, mode->par_d,
681 "interlace-mode", G_TYPE_STRING,
682 mode->interlaced ? "interleaved" : "progressive",
683 "framerate", GST_TYPE_FRACTION, mode->fps_n, mode->fps_d, NULL);
684
685 return s;
686 }
687
688 static GstStructure *
gst_decklink_mode_get_structure(GstDecklinkModeEnum e,BMDPixelFormat f,gboolean input)689 gst_decklink_mode_get_structure (GstDecklinkModeEnum e, BMDPixelFormat f,
690 gboolean input)
691 {
692 const GstDecklinkMode *mode = &modes[e];
693 GstStructure *s = gst_decklink_mode_get_generic_structure (e);
694
695 if (input && mode->interlaced) {
696 if (mode->tff)
697 gst_structure_set (s, "field-order", G_TYPE_STRING, "top-field-first",
698 NULL);
699 else
700 gst_structure_set (s, "field-order", G_TYPE_STRING, "bottom-field-first",
701 NULL);
702 }
703
704 switch (f) {
705 case bmdFormat8BitYUV: /* '2vuy' */
706 gst_structure_set (s, "format", G_TYPE_STRING, "UYVY",
707 "colorimetry", G_TYPE_STRING, mode->colorimetry,
708 "chroma-site", G_TYPE_STRING, "mpeg2", NULL);
709 break;
710 case bmdFormat10BitYUV: /* 'v210' */
711 gst_structure_set (s, "format", G_TYPE_STRING, "v210", NULL);
712 break;
713 case bmdFormat8BitARGB: /* 'ARGB' */
714 gst_structure_set (s, "format", G_TYPE_STRING, "ARGB", NULL);
715 break;
716 case bmdFormat8BitBGRA: /* 'BGRA' */
717 gst_structure_set (s, "format", G_TYPE_STRING, "BGRA", NULL);
718 break;
719 case bmdFormat10BitRGB: /* 'r210' Big-endian RGB 10-bit per component with SMPTE video levels (64-960). Packed as 2:10:10:10 */
720 case bmdFormat12BitRGB: /* 'R12B' Big-endian RGB 12-bit per component with full range (0-4095). Packed as 12-bit per component */
721 case bmdFormat12BitRGBLE: /* 'R12L' Little-endian RGB 12-bit per component with full range (0-4095). Packed as 12-bit per component */
722 case bmdFormat10BitRGBXLE: /* 'R10l' Little-endian 10-bit RGB with SMPTE video levels (64-940) */
723 case bmdFormat10BitRGBX: /* 'R10b' Big-endian 10-bit RGB with SMPTE video levels (64-940) */
724 default:
725 GST_WARNING ("format not supported %d", f);
726 gst_structure_free (s);
727 s = NULL;
728 break;
729 }
730
731 return s;
732 }
733
734 GstCaps *
gst_decklink_mode_get_caps(GstDecklinkModeEnum e,BMDPixelFormat f,gboolean input)735 gst_decklink_mode_get_caps (GstDecklinkModeEnum e, BMDPixelFormat f,
736 gboolean input)
737 {
738 GstCaps *caps;
739
740 caps = gst_caps_new_empty ();
741 caps =
742 gst_caps_merge_structure (caps, gst_decklink_mode_get_structure (e, f,
743 input));
744
745 return caps;
746 }
747
748 GstCaps *
gst_decklink_mode_get_caps_all_formats(GstDecklinkModeEnum e,gboolean input)749 gst_decklink_mode_get_caps_all_formats (GstDecklinkModeEnum e, gboolean input)
750 {
751 GstCaps *caps;
752 guint i;
753
754 caps = gst_caps_new_empty ();
755 for (i = 1; i < G_N_ELEMENTS (formats); i++)
756 caps =
757 gst_caps_merge_structure (caps, gst_decklink_mode_get_structure (e,
758 formats[i].format, input));
759
760 return caps;
761 }
762
763 GstCaps *
gst_decklink_pixel_format_get_caps(BMDPixelFormat f,gboolean input)764 gst_decklink_pixel_format_get_caps (BMDPixelFormat f, gboolean input)
765 {
766 int i;
767 GstCaps *caps;
768 GstStructure *s;
769
770 caps = gst_caps_new_empty ();
771 for (i = 1; i < (int) G_N_ELEMENTS (modes); i++) {
772 s = gst_decklink_mode_get_structure ((GstDecklinkModeEnum) i, f, input);
773 caps = gst_caps_merge_structure (caps, s);
774 }
775
776 return caps;
777 }
778
779 GstCaps *
gst_decklink_mode_get_template_caps(gboolean input)780 gst_decklink_mode_get_template_caps (gboolean input)
781 {
782 int i;
783 GstCaps *caps;
784
785 caps = gst_caps_new_empty ();
786 for (i = 1; i < (int) G_N_ELEMENTS (modes); i++)
787 caps =
788 gst_caps_merge (caps,
789 gst_decklink_mode_get_caps_all_formats ((GstDecklinkModeEnum) i,
790 input));
791
792 return caps;
793 }
794
795 const GstDecklinkMode *
gst_decklink_find_mode_and_format_for_caps(GstCaps * caps,BMDPixelFormat * format)796 gst_decklink_find_mode_and_format_for_caps (GstCaps * caps,
797 BMDPixelFormat * format)
798 {
799 int i;
800 GstCaps *mode_caps;
801
802 g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
803 if (!gst_decklink_caps_get_pixel_format (caps, format))
804 return NULL;
805
806 for (i = 1; i < (int) G_N_ELEMENTS (modes); i++) {
807 mode_caps =
808 gst_decklink_mode_get_caps ((GstDecklinkModeEnum) i, *format, FALSE);
809 if (gst_caps_can_intersect (caps, mode_caps)) {
810 gst_caps_unref (mode_caps);
811 return gst_decklink_get_mode ((GstDecklinkModeEnum) i);
812 }
813 gst_caps_unref (mode_caps);
814 }
815
816 return NULL;
817 }
818
819 const GstDecklinkMode *
gst_decklink_find_mode_for_caps(GstCaps * caps)820 gst_decklink_find_mode_for_caps (GstCaps * caps)
821 {
822 BMDPixelFormat format;
823
824 return gst_decklink_find_mode_and_format_for_caps (caps, &format);
825 }
826
827 #define GST_TYPE_DECKLINK_CLOCK \
828 (gst_decklink_clock_get_type())
829 #define GST_DECKLINK_CLOCK(obj) \
830 (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DECKLINK_CLOCK,GstDecklinkClock))
831 #define GST_DECKLINK_CLOCK_CLASS(klass) \
832 (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DECKLINK_CLOCK,GstDecklinkClockClass))
833 #define GST_IS_Decklink_CLOCK(obj) \
834 (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DECKLINK_CLOCK))
835 #define GST_IS_Decklink_CLOCK_CLASS(klass) \
836 (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DECKLINK_CLOCK))
837 #define GST_DECKLINK_CLOCK_CAST(obj) \
838 ((GstDecklinkClock*)(obj))
839
840 typedef struct _GstDecklinkClock GstDecklinkClock;
841 typedef struct _GstDecklinkClockClass GstDecklinkClockClass;
842
843 struct _GstDecklinkClock
844 {
845 GstSystemClock clock;
846
847 GstDecklinkOutput *output;
848 };
849
850 struct _GstDecklinkClockClass
851 {
852 GstSystemClockClass parent_class;
853 };
854
855 GType gst_decklink_clock_get_type (void);
856 static GstClock *gst_decklink_clock_new (const gchar * name);
857
858 typedef struct _Device Device;
859 struct _Device
860 {
861 GstDecklinkOutput output;
862 GstDecklinkInput input;
863
864 /* Audio/video output, Audio/video input */
865 GstDecklinkDevice *devices[4];
866 };
867
868 static ProfileSetOperationResult gst_decklink_configure_profile (Device *
869 device, GstDecklinkProfileId profile_id);
870
871 class GStreamerDecklinkInputCallback:public IDeckLinkInputCallback
872 {
873 private:
874 GstDecklinkInput * m_input;
875 GMutex m_mutex;
876 gint m_refcount;
877 public:
GStreamerDecklinkInputCallback(GstDecklinkInput * input)878 GStreamerDecklinkInputCallback (GstDecklinkInput * input)
879 : IDeckLinkInputCallback (), m_refcount (1)
880 {
881 m_input = input;
882 g_mutex_init (&m_mutex);
883 }
884
~GStreamerDecklinkInputCallback()885 virtual ~ GStreamerDecklinkInputCallback ()
886 {
887 g_mutex_clear (&m_mutex);
888 }
889
QueryInterface(REFIID,LPVOID *)890 virtual HRESULT STDMETHODCALLTYPE QueryInterface (REFIID, LPVOID *)
891 {
892 return E_NOINTERFACE;
893 }
894
AddRef(void)895 virtual ULONG STDMETHODCALLTYPE AddRef (void)
896 {
897 ULONG ret;
898
899 g_mutex_lock (&m_mutex);
900 m_refcount++;
901 ret = m_refcount;
902 g_mutex_unlock (&m_mutex);
903
904 return ret;
905 }
906
Release(void)907 virtual ULONG STDMETHODCALLTYPE Release (void)
908 {
909 ULONG ret;
910
911 g_mutex_lock (&m_mutex);
912 m_refcount--;
913 ret = m_refcount;
914 g_mutex_unlock (&m_mutex);
915
916
917 if (ret == 0) {
918 delete this;
919 }
920
921 return ret;
922 }
923
924 virtual HRESULT STDMETHODCALLTYPE
VideoInputFormatChanged(BMDVideoInputFormatChangedEvents,IDeckLinkDisplayMode * mode,BMDDetectedVideoInputFormatFlags formatFlags)925 VideoInputFormatChanged (BMDVideoInputFormatChangedEvents,
926 IDeckLinkDisplayMode * mode, BMDDetectedVideoInputFormatFlags formatFlags)
927 {
928 BMDPixelFormat pixelFormat;
929
930 GST_INFO ("Video input format changed");
931
932 if ((formatFlags & bmdDetectedVideoInputRGB444)
933 && m_input->format == bmdFormat8BitYUV) {
934 /* user-set format was auto or 8BitYUV, change to RGB */
935 pixelFormat = bmdFormat8BitARGB;
936 } else {
937 /* use the user-set format, defaulting to 8BitYUV */
938 pixelFormat = m_input->format;
939 }
940
941 g_mutex_lock (&m_input->lock);
942 m_input->input->PauseStreams ();
943 m_input->input->EnableVideoInput (mode->GetDisplayMode (),
944 pixelFormat, bmdVideoInputEnableFormatDetection);
945 m_input->input->FlushStreams ();
946
947 /* Reset any timestamp observations we might've made */
948 if (m_input->videosrc) {
949 GstDecklinkVideoSrc *videosrc =
950 GST_DECKLINK_VIDEO_SRC (m_input->videosrc);
951
952 g_mutex_lock (&videosrc->lock);
953 videosrc->window_fill = 0;
954 videosrc->window_filled = FALSE;
955 videosrc->window_skip = 1;
956 videosrc->window_skip_count = 0;
957 videosrc->current_time_mapping.xbase = 0;
958 videosrc->current_time_mapping.b = 0;
959 videosrc->current_time_mapping.num = 1;
960 videosrc->current_time_mapping.den = 1;
961 videosrc->next_time_mapping.xbase = 0;
962 videosrc->next_time_mapping.b = 0;
963 videosrc->next_time_mapping.num = 1;
964 videosrc->next_time_mapping.den = 1;
965 g_mutex_unlock (&videosrc->lock);
966 }
967
968 m_input->input->StartStreams ();
969 m_input->mode =
970 gst_decklink_get_mode (gst_decklink_get_mode_enum_from_bmd
971 (mode->GetDisplayMode ()));
972 m_input->format = pixelFormat;
973 g_mutex_unlock (&m_input->lock);
974
975 return S_OK;
976 }
977
978 virtual HRESULT STDMETHODCALLTYPE
VideoInputFrameArrived(IDeckLinkVideoInputFrame * video_frame,IDeckLinkAudioInputPacket * audio_packet)979 VideoInputFrameArrived (IDeckLinkVideoInputFrame * video_frame,
980 IDeckLinkAudioInputPacket * audio_packet)
981 {
982 GstElement *videosrc = NULL, *audiosrc = NULL;
983 void (*got_video_frame) (GstElement * videosrc,
984 IDeckLinkVideoInputFrame * frame, GstDecklinkModeEnum mode,
985 GstClockTime capture_time, GstClockTime stream_time,
986 GstClockTime stream_duration, GstClockTime hardware_time,
987 GstClockTime hardware_duration, IDeckLinkTimecode * dtc,
988 gboolean no_signal) = NULL;
989 void (*got_audio_packet) (GstElement * videosrc,
990 IDeckLinkAudioInputPacket * packet, GstClockTime capture_time,
991 GstClockTime stream_time, GstClockTime stream_duration,
992 GstClockTime hardware_time, GstClockTime hardware_duration,
993 gboolean no_signal) = NULL;
994 GstDecklinkModeEnum mode = GST_DECKLINK_MODE_AUTO;
995 GstClockTime capture_time = GST_CLOCK_TIME_NONE;
996 GstClockTime base_time = 0;
997 gboolean no_signal = FALSE;
998 GstClock *clock = NULL;
999 HRESULT res;
1000 BMDTimeValue stream_time = GST_CLOCK_TIME_NONE;
1001 BMDTimeValue stream_duration = GST_CLOCK_TIME_NONE;
1002 BMDTimeValue hardware_time = GST_CLOCK_TIME_NONE;
1003 BMDTimeValue hardware_duration = GST_CLOCK_TIME_NONE;
1004
1005 g_mutex_lock (&m_input->lock);
1006 if (m_input->videosrc) {
1007 videosrc = GST_ELEMENT_CAST (gst_object_ref (m_input->videosrc));
1008 clock = gst_element_get_clock (videosrc);
1009 base_time = gst_element_get_base_time (videosrc);
1010 got_video_frame = m_input->got_video_frame;
1011 }
1012
1013 if (m_input->mode)
1014 mode = gst_decklink_get_mode_enum_from_bmd (m_input->mode->mode);
1015
1016 if (m_input->audiosrc) {
1017 audiosrc = GST_ELEMENT_CAST (gst_object_ref (m_input->audiosrc));
1018 if (!clock) {
1019 clock = gst_element_get_clock (GST_ELEMENT_CAST (audiosrc));
1020 base_time = gst_element_get_base_time (audiosrc);
1021 }
1022 got_audio_packet = m_input->got_audio_packet;
1023 }
1024 g_mutex_unlock (&m_input->lock);
1025
1026 if (clock) {
1027 capture_time = gst_clock_get_time (clock);
1028 if (video_frame) {
1029 // If we have the actual capture time for the frame, compensate the
1030 // capture time accordingly.
1031 //
1032 // We do this by subtracting the belay between "now" in hardware
1033 // reference clock and the time when the frame was finished being
1034 // capture based on the same hardware reference clock.
1035 //
1036 // We then subtract that difference from the "now" on the gst clock.
1037 //
1038 // *Technically* we should be compensating that difference for the
1039 // difference in clock rate between the "hardware reference clock" and
1040 // the GStreamer clock. But since the values are quite small this has
1041 // very little impact.
1042 BMDTimeValue hardware_now;
1043 res = m_input->input->GetHardwareReferenceClock (GST_SECOND, &hardware_now, NULL, NULL);
1044 if (res == S_OK) {
1045 res =
1046 video_frame->GetHardwareReferenceTimestamp (GST_SECOND,
1047 &hardware_time, &hardware_duration);
1048 if (res != S_OK) {
1049 GST_ERROR ("Failed to get hardware time: 0x%08lx", (unsigned long) res);
1050 hardware_time = GST_CLOCK_TIME_NONE;
1051 hardware_duration = GST_CLOCK_TIME_NONE;
1052 } else {
1053 GstClockTime hardware_diff = hardware_now - hardware_time;
1054 GST_LOG ("Compensating capture time by %" GST_TIME_FORMAT,
1055 GST_TIME_ARGS (hardware_diff));
1056 if (capture_time > hardware_diff)
1057 capture_time -= hardware_diff;
1058 else
1059 capture_time = 0;
1060 }
1061 }
1062 }
1063 if (capture_time > base_time)
1064 capture_time -= base_time;
1065 else
1066 capture_time = 0;
1067 }
1068
1069 if (video_frame) {
1070 BMDFrameFlags flags;
1071
1072 flags = video_frame->GetFlags ();
1073 if (flags & bmdFrameHasNoInputSource) {
1074 no_signal = TRUE;
1075 }
1076 }
1077
1078 if (got_video_frame && videosrc && video_frame) {
1079 IDeckLinkTimecode *dtc = 0;
1080
1081 res =
1082 video_frame->GetStreamTime (&stream_time, &stream_duration,
1083 GST_SECOND);
1084 if (res != S_OK) {
1085 GST_ERROR ("Failed to get stream time: 0x%08lx", (unsigned long) res);
1086 stream_time = GST_CLOCK_TIME_NONE;
1087 stream_duration = GST_CLOCK_TIME_NONE;
1088 }
1089
1090 res =
1091 video_frame->GetHardwareReferenceTimestamp (GST_SECOND,
1092 &hardware_time, &hardware_duration);
1093 if (res != S_OK) {
1094 GST_ERROR ("Failed to get hardware time: 0x%08lx", (unsigned long) res);
1095 hardware_time = GST_CLOCK_TIME_NONE;
1096 hardware_duration = GST_CLOCK_TIME_NONE;
1097 }
1098
1099 if (m_input->videosrc) {
1100 /* FIXME: Avoid circularity between gstdecklink.cpp and
1101 * gstdecklinkvideosrc.cpp */
1102 res =
1103 video_frame->
1104 GetTimecode (GST_DECKLINK_VIDEO_SRC (videosrc)->timecode_format,
1105 &dtc);
1106
1107 if (res != S_OK) {
1108 GST_DEBUG_OBJECT (videosrc, "Failed to get timecode: 0x%08lx",
1109 (unsigned long) res);
1110 dtc = NULL;
1111 }
1112 }
1113
1114 /* passing dtc reference */
1115 got_video_frame (videosrc, video_frame, mode, capture_time,
1116 stream_time, stream_duration, hardware_time, hardware_duration, dtc,
1117 no_signal);
1118 }
1119
1120 if (got_audio_packet && audiosrc && audio_packet) {
1121 m_input->got_audio_packet (audiosrc, audio_packet, capture_time,
1122 stream_time, stream_duration, hardware_time, hardware_duration,
1123 no_signal);
1124 } else {
1125 if (!audio_packet)
1126 GST_DEBUG ("Received no audio packet at %" GST_TIME_FORMAT,
1127 GST_TIME_ARGS (capture_time));
1128 }
1129
1130 gst_object_replace ((GstObject **) & videosrc, NULL);
1131 gst_object_replace ((GstObject **) & audiosrc, NULL);
1132 gst_object_replace ((GstObject **) & clock, NULL);
1133
1134 return S_OK;
1135 }
1136 };
1137
1138 class GStreamerDecklinkMemoryAllocator:public IDeckLinkMemoryAllocator
1139 {
1140 private:
1141 GMutex m_mutex;
1142 uint32_t m_lastBufferSize;
1143 uint32_t m_nonEmptyCalls;
1144 GstQueueArray *m_buffers;
1145 gint m_refcount;
1146
_clearBufferPool()1147 void _clearBufferPool ()
1148 {
1149 uint8_t *buf;
1150
1151 if (!m_buffers)
1152 return;
1153
1154 while ((buf = (uint8_t *) gst_queue_array_pop_head (m_buffers))) {
1155 uint8_t offset = *(buf - 1);
1156 void *alloc_buf = buf - 128 + offset;
1157 g_free (alloc_buf);
1158 }
1159 }
1160
1161 public:
GStreamerDecklinkMemoryAllocator()1162 GStreamerDecklinkMemoryAllocator ()
1163 : IDeckLinkMemoryAllocator (),
1164 m_lastBufferSize (0),
1165 m_nonEmptyCalls (0), m_buffers (NULL), m_refcount (1)
1166 {
1167 g_mutex_init (&m_mutex);
1168
1169 m_buffers = gst_queue_array_new (60);
1170 }
1171
~GStreamerDecklinkMemoryAllocator()1172 virtual ~ GStreamerDecklinkMemoryAllocator () {
1173 Decommit ();
1174
1175 gst_queue_array_free (m_buffers);
1176
1177 g_mutex_clear (&m_mutex);
1178 }
1179
QueryInterface(REFIID,LPVOID *)1180 virtual HRESULT STDMETHODCALLTYPE QueryInterface (REFIID, LPVOID *)
1181 {
1182 return E_NOINTERFACE;
1183 }
1184
AddRef(void)1185 virtual ULONG STDMETHODCALLTYPE AddRef (void)
1186 {
1187 ULONG ret;
1188
1189 g_mutex_lock (&m_mutex);
1190 m_refcount++;
1191 ret = m_refcount;
1192 g_mutex_unlock (&m_mutex);
1193
1194 return ret;
1195 }
1196
Release(void)1197 virtual ULONG STDMETHODCALLTYPE Release (void)
1198 {
1199 ULONG ret;
1200
1201 g_mutex_lock (&m_mutex);
1202 m_refcount--;
1203 ret = m_refcount;
1204 g_mutex_unlock (&m_mutex);
1205
1206
1207 if (ret == 0) {
1208 delete this;
1209 }
1210
1211 return ret;
1212 }
1213
1214 virtual HRESULT STDMETHODCALLTYPE
AllocateBuffer(uint32_t bufferSize,void ** allocatedBuffer)1215 AllocateBuffer (uint32_t bufferSize, void **allocatedBuffer)
1216 {
1217 uint8_t *buf;
1218 uint8_t offset = 0;
1219
1220 g_mutex_lock (&m_mutex);
1221
1222 /* If buffer size changed since last call, empty buffer pool */
1223 if (bufferSize != m_lastBufferSize) {
1224 _clearBufferPool ();
1225 m_lastBufferSize = bufferSize;
1226 }
1227
1228 /* Look if there is a free buffer in the pool */
1229 if (!(buf = (uint8_t *) gst_queue_array_pop_head (m_buffers))) {
1230 /* If not, alloc a new one */
1231 buf = (uint8_t *) g_malloc (bufferSize + 128);
1232
1233 /* The Decklink SDK requires 16 byte aligned memory at least but for us
1234 * to work nicely let's align to 64 bytes (512 bits) as this allows
1235 * aligned AVX2 operations for example */
1236 if (((guintptr) buf) % 64 != 0) {
1237 offset = ((guintptr) buf) % 64;
1238 }
1239
1240 /* Write the allocation size at the very beginning. It's guaranteed by
1241 * malloc() to be allocated aligned enough for doing this. */
1242 *((uint32_t *) buf) = bufferSize;
1243
1244 /* Align our buffer */
1245 buf += 128 - offset;
1246
1247 /* And write the alignment offset right before the buffer */
1248 *(buf - 1) = offset;
1249 }
1250 *allocatedBuffer = (void *) buf;
1251
1252 /* If there are still unused buffers in the pool
1253 * remove one of them every fifth call */
1254 if (gst_queue_array_get_length (m_buffers) > 0) {
1255 if (++m_nonEmptyCalls >= 5) {
1256 buf = (uint8_t *) gst_queue_array_pop_head (m_buffers);
1257 uint8_t offset = *(buf - 1);
1258 void *alloc_buf = buf - 128 + offset;
1259 g_free (alloc_buf);
1260 m_nonEmptyCalls = 0;
1261 }
1262 } else {
1263 m_nonEmptyCalls = 0;
1264 }
1265
1266 g_mutex_unlock (&m_mutex);
1267
1268 return S_OK;
1269 }
1270
ReleaseBuffer(void * buffer)1271 virtual HRESULT STDMETHODCALLTYPE ReleaseBuffer (void *buffer)
1272 {
1273 g_mutex_lock (&m_mutex);
1274
1275 /* Put the buffer back to the pool if size matches with current pool */
1276 uint8_t offset = *(((uint8_t *) buffer) - 1);
1277 uint8_t *alloc_buffer = ((uint8_t *) buffer) - 128 + offset;
1278 uint32_t size = *(uint32_t *) alloc_buffer;
1279 if (size == m_lastBufferSize) {
1280 gst_queue_array_push_tail (m_buffers, buffer);
1281 } else {
1282 g_free (alloc_buffer);
1283 }
1284
1285 g_mutex_unlock (&m_mutex);
1286
1287 return S_OK;
1288 }
1289
Commit()1290 virtual HRESULT STDMETHODCALLTYPE Commit ()
1291 {
1292 return S_OK;
1293 }
1294
Decommit()1295 virtual HRESULT STDMETHODCALLTYPE Decommit ()
1296 {
1297 /* Clear all remaining pools */
1298 _clearBufferPool ();
1299
1300 return S_OK;
1301 }
1302 };
1303
1304 #ifdef G_OS_WIN32
1305 /* FIXME: We currently never deinit this */
1306
1307 static GMutex com_init_lock;
1308 static GMutex com_deinit_lock;
1309 static GCond com_init_cond;
1310 static GCond com_deinit_cond;
1311 static GCond com_deinited_cond;
1312 static gboolean com_initialized = FALSE;
1313
1314 /* COM initialization/uninitialization thread */
1315 static gpointer
gst_decklink_com_thread(gpointer data)1316 gst_decklink_com_thread (gpointer data)
1317 {
1318 HRESULT res;
1319
1320 g_mutex_lock (&com_init_lock);
1321
1322 /* Initialize COM with a MTA for this process. This thread will
1323 * be the first one to enter the apartement and the last one to leave
1324 * it, unitializing COM properly */
1325
1326 res = CoInitializeEx (0, COINIT_MULTITHREADED);
1327 if (res == S_FALSE)
1328 GST_WARNING ("COM has been already initialized in the same process");
1329 else if (res == RPC_E_CHANGED_MODE)
1330 GST_WARNING ("The concurrency model of COM has changed.");
1331 else
1332 GST_INFO ("COM initialized successfully");
1333
1334 com_initialized = TRUE;
1335
1336 /* Signal other threads waiting on this condition that COM was initialized */
1337 g_cond_signal (&com_init_cond);
1338
1339 g_mutex_unlock (&com_init_lock);
1340
1341 /* Wait until the uninitialize condition is met to leave the COM apartement */
1342 g_mutex_lock (&com_deinit_lock);
1343 g_cond_wait (&com_deinit_cond, &com_deinit_lock);
1344
1345 CoUninitialize ();
1346 GST_INFO ("COM uninitialized successfully");
1347 com_initialized = FALSE;
1348 g_cond_signal (&com_deinited_cond);
1349 g_mutex_unlock (&com_deinit_lock);
1350
1351 return NULL;
1352 }
1353 #endif /* G_OS_WIN32 */
1354
1355 static GOnce devices_once = G_ONCE_INIT;
1356 static GPtrArray *devices; /* array of Device */
1357
1358
1359 static GstDecklinkDevice *
gst_decklink_device_new(const gchar * model_name,const gchar * display_name,const gchar * serial_number,gboolean supports_format_detection,GstCaps * video_caps,guint max_channels,gboolean video,gboolean capture,guint device_number)1360 gst_decklink_device_new (const gchar * model_name, const gchar * display_name,
1361 const gchar * serial_number, gboolean supports_format_detection,
1362 GstCaps * video_caps, guint max_channels, gboolean video, gboolean capture,
1363 guint device_number)
1364 {
1365 GstDevice *ret;
1366 gchar *name;
1367 const gchar *device_class;
1368 GstCaps *caps = NULL;
1369 GstStructure *properties;
1370
1371 if (capture)
1372 device_class = video ? "Video/Source/Hardware" : "Audio/Source/Hardware";
1373 else
1374 device_class = video ? "Video/Sink/Hardware" : "Audio/Sink/Hardware";
1375
1376 name =
1377 g_strdup_printf ("%s (%s %s)", display_name,
1378 video ? "Video" : "Audio", capture ? "Capture" : "Output");
1379
1380 if (video) {
1381 caps = gst_caps_ref (video_caps);
1382 } else {
1383 static GstStaticCaps audio_caps =
1384 GST_STATIC_CAPS
1385 ("audio/x-raw, format={S16LE,S32LE}, channels={2, 8, 16}, rate=48000, "
1386 "layout=interleaved");
1387 GstCaps *max_channel_caps =
1388 gst_caps_new_simple ("audio/x-raw", "channels", GST_TYPE_INT_RANGE, 2,
1389 max_channels, NULL);
1390
1391 caps =
1392 gst_caps_intersect (gst_static_caps_get (&audio_caps),
1393 max_channel_caps);
1394 gst_caps_unref (max_channel_caps);
1395 }
1396 properties = gst_structure_new_empty ("properties");
1397
1398 gst_structure_set (properties,
1399 "device-number", G_TYPE_UINT, device_number,
1400 "model-name", G_TYPE_STRING, model_name,
1401 "display-name", G_TYPE_STRING, display_name,
1402 "max-channels", G_TYPE_UINT, max_channels, NULL);
1403
1404 if (capture)
1405 gst_structure_set (properties, "supports-format-detection", G_TYPE_BOOLEAN,
1406 supports_format_detection, NULL);
1407
1408 if (serial_number)
1409 gst_structure_set (properties, "serial-number", G_TYPE_STRING,
1410 serial_number, NULL);
1411
1412 ret = GST_DEVICE (g_object_new (GST_TYPE_DECKLINK_DEVICE,
1413 "display-name", name,
1414 "device-class", device_class, "caps", caps, "properties", properties,
1415 NULL));
1416
1417 g_free (name);
1418 gst_caps_unref (caps);
1419 gst_structure_free (properties);
1420
1421 GST_DECKLINK_DEVICE (ret)->video = video;
1422 GST_DECKLINK_DEVICE (ret)->capture = capture;
1423 GST_DECKLINK_DEVICE (ret)->device_number = device_number;
1424
1425 return GST_DECKLINK_DEVICE (ret);
1426 }
1427
1428 static gpointer
init_devices(gpointer data)1429 init_devices (gpointer data)
1430 {
1431 IDeckLinkIterator *iterator;
1432 IDeckLink *decklink = NULL;
1433 HRESULT ret;
1434 int i;
1435
1436 #ifdef G_OS_WIN32
1437 // Start COM thread for Windows
1438
1439 g_mutex_lock (&com_init_lock);
1440
1441 /* create the COM initialization thread */
1442 g_thread_new ("COM init thread", (GThreadFunc) gst_decklink_com_thread, NULL);
1443
1444 /* wait until the COM thread signals that COM has been initialized */
1445 g_cond_wait (&com_init_cond, &com_init_lock);
1446 g_mutex_unlock (&com_init_lock);
1447 #endif /* G_OS_WIN32 */
1448
1449 iterator = CreateDeckLinkIteratorInstance ();
1450 if (iterator == NULL) {
1451 GST_DEBUG ("no driver");
1452 return NULL;
1453 }
1454
1455 devices = g_ptr_array_new ();
1456
1457 i = 0;
1458 ret = iterator->Next (&decklink);
1459 while (ret == S_OK) {
1460 Device *dev;
1461 gboolean capture = FALSE;
1462 gboolean output = FALSE;
1463 gchar *model_name = NULL;
1464 gchar *display_name = NULL;
1465 gchar *serial_number = NULL;
1466 gboolean supports_format_detection = 0;
1467 gint64 max_channels = 2;
1468 GstCaps *video_input_caps = gst_caps_new_empty ();
1469 GstCaps *video_output_caps = gst_caps_new_empty ();
1470
1471 dev = g_new0 (Device, 1);
1472
1473 g_mutex_init (&dev->input.lock);
1474 g_mutex_init (&dev->output.lock);
1475 g_cond_init (&dev->output.cond);
1476
1477 ret = decklink->QueryInterface (IID_IDeckLinkInput,
1478 (void **) &dev->input.input);
1479 if (ret != S_OK) {
1480 GST_WARNING ("selected device does not have input interface: 0x%08lx",
1481 (unsigned long) ret);
1482 } else {
1483 IDeckLinkDisplayModeIterator *mode_iter;
1484
1485 dev->input.device = decklink;
1486 dev->input.input->
1487 SetCallback (new GStreamerDecklinkInputCallback (&dev->input));
1488
1489 if ((ret = dev->input.input->GetDisplayModeIterator (&mode_iter)) == S_OK) {
1490 IDeckLinkDisplayMode *mode;
1491
1492 GST_DEBUG ("Input %d supports:", i);
1493 while ((ret = mode_iter->Next (&mode)) == S_OK) {
1494 char *name;
1495 GstDecklinkModeEnum mode_enum;
1496
1497 mode_enum =
1498 gst_decklink_get_mode_enum_from_bmd (mode->GetDisplayMode ());
1499 if (mode_enum != (GstDecklinkModeEnum) - 1)
1500 video_input_caps =
1501 gst_caps_merge_structure (video_input_caps,
1502 gst_decklink_mode_get_generic_structure (mode_enum));
1503
1504 mode->GetName ((COMSTR_T *) & name);
1505 CONVERT_COM_STRING (name);
1506 GST_DEBUG (" %s mode: 0x%08x width: %ld height: %ld"
1507 " fields: 0x%08x flags: 0x%08x", name,
1508 (int) mode->GetDisplayMode (), mode->GetWidth (),
1509 mode->GetHeight (), (int) mode->GetFieldDominance (),
1510 (int) mode->GetFlags ());
1511 FREE_COM_STRING (name);
1512 mode->Release ();
1513 }
1514 mode_iter->Release ();
1515 }
1516
1517 capture = TRUE;
1518
1519 ret = S_OK;
1520 }
1521
1522 ret = decklink->QueryInterface (IID_IDeckLinkOutput,
1523 (void **) &dev->output.output);
1524 if (ret != S_OK) {
1525 GST_WARNING ("selected device does not have output interface: 0x%08lx",
1526 (unsigned long) ret);
1527 } else {
1528 IDeckLinkDisplayModeIterator *mode_iter;
1529
1530 dev->output.device = decklink;
1531 dev->output.clock = gst_decklink_clock_new ("GstDecklinkOutputClock");
1532 GST_DECKLINK_CLOCK_CAST (dev->output.clock)->output = &dev->output;
1533
1534 if ((ret =
1535 dev->output.output->GetDisplayModeIterator (&mode_iter)) ==
1536 S_OK) {
1537 IDeckLinkDisplayMode *mode;
1538
1539 GST_DEBUG ("Output %d supports:", i);
1540 while ((ret = mode_iter->Next (&mode)) == S_OK) {
1541 char *name;
1542 GstDecklinkModeEnum mode_enum;
1543
1544 mode_enum =
1545 gst_decklink_get_mode_enum_from_bmd (mode->GetDisplayMode ());
1546 if (mode_enum != (GstDecklinkModeEnum) - 1)
1547 video_output_caps =
1548 gst_caps_merge_structure (video_output_caps,
1549 gst_decklink_mode_get_generic_structure (mode_enum));
1550
1551 mode->GetName ((COMSTR_T *) & name);
1552 CONVERT_COM_STRING (name);
1553 GST_DEBUG (" %s mode: 0x%08x width: %ld height: %ld"
1554 " fields: 0x%08x flags: 0x%08x", name,
1555 (int) mode->GetDisplayMode (), mode->GetWidth (),
1556 mode->GetHeight (), (int) mode->GetFieldDominance (),
1557 (int) mode->GetFlags ());
1558 FREE_COM_STRING (name);
1559 mode->Release ();
1560 }
1561 mode_iter->Release ();
1562 }
1563
1564 output = TRUE;
1565
1566 ret = S_OK;
1567 }
1568
1569 ret = decklink->QueryInterface (IID_IDeckLinkConfiguration,
1570 (void **) &dev->input.config);
1571 if (ret != S_OK) {
1572 GST_WARNING ("selected device does not have config interface: 0x%08lx",
1573 (unsigned long) ret);
1574 } else {
1575 ret =
1576 dev->input.
1577 config->GetString (bmdDeckLinkConfigDeviceInformationSerialNumber,
1578 (COMSTR_T *) & serial_number);
1579 if (ret == S_OK) {
1580 CONVERT_COM_STRING (serial_number);
1581 dev->output.hw_serial_number = g_strdup (serial_number);
1582 dev->input.hw_serial_number = g_strdup (serial_number);
1583 GST_DEBUG ("device %d has serial number %s", i, serial_number);
1584 }
1585 }
1586
1587 ret = decklink->QueryInterface (IID_IDeckLinkProfileAttributes,
1588 (void **) &dev->input.attributes);
1589 dev->output.attributes = dev->input.attributes;
1590 if (ret != S_OK) {
1591 GST_WARNING ("selected device does not have attributes interface: "
1592 "0x%08lx", (unsigned long) ret);
1593 } else {
1594 bool tmp_bool = false;
1595 int64_t tmp_int = 2;
1596
1597 dev->input.attributes->GetInt (BMDDeckLinkMaximumAudioChannels, &tmp_int);
1598 dev->input.attributes->GetFlag (BMDDeckLinkSupportsInputFormatDetection,
1599 &tmp_bool);
1600 supports_format_detection = tmp_bool;
1601 max_channels = tmp_int;
1602 }
1603
1604 decklink->GetModelName ((COMSTR_T *) & model_name);
1605 if (model_name)
1606 CONVERT_COM_STRING (model_name);
1607 decklink->GetDisplayName ((COMSTR_T *) & display_name);
1608 if (display_name)
1609 CONVERT_COM_STRING (display_name);
1610
1611 if (capture) {
1612 dev->devices[0] =
1613 gst_decklink_device_new (model_name, display_name, serial_number,
1614 supports_format_detection, video_input_caps, max_channels, TRUE, TRUE,
1615 i);
1616 dev->devices[1] =
1617 gst_decklink_device_new (model_name, display_name, serial_number,
1618 supports_format_detection, video_input_caps, max_channels, FALSE,
1619 TRUE, i);
1620 }
1621 if (output) {
1622 dev->devices[2] =
1623 gst_decklink_device_new (model_name, display_name, serial_number,
1624 supports_format_detection, video_output_caps, max_channels, TRUE,
1625 FALSE, i);
1626 dev->devices[3] =
1627 gst_decklink_device_new (model_name, display_name, serial_number,
1628 supports_format_detection, video_output_caps, max_channels, FALSE,
1629 FALSE, i);
1630 }
1631
1632 if (model_name)
1633 FREE_COM_STRING (model_name);
1634 if (display_name)
1635 FREE_COM_STRING (display_name);
1636 if (serial_number)
1637 FREE_COM_STRING (serial_number);
1638 gst_caps_unref (video_input_caps);
1639 gst_caps_unref (video_output_caps);
1640
1641 ret = decklink->QueryInterface (IID_IDeckLinkKeyer,
1642 (void **) &dev->output.keyer);
1643
1644 g_ptr_array_add (devices, dev);
1645
1646 /* We only warn of failure to obtain the keyer interface if the keyer
1647 * is enabled by keyer_mode
1648 */
1649
1650 ret = iterator->Next (&decklink);
1651 i++;
1652 }
1653
1654 GST_INFO ("Detected %u devices", devices->len);
1655
1656 iterator->Release ();
1657
1658 return NULL;
1659 }
1660
1661 GList *
gst_decklink_get_devices(void)1662 gst_decklink_get_devices (void)
1663 {
1664 guint i;
1665 GList *l = NULL;
1666
1667 g_once (&devices_once, init_devices, NULL);
1668
1669 if (!devices) {
1670 return NULL;
1671 }
1672
1673 for (i = 0; i < devices->len; i++) {
1674 Device *device = (Device *) g_ptr_array_index (devices, i);
1675
1676 if (device->devices[0])
1677 l = g_list_prepend (l, g_object_ref (device->devices[0]));
1678
1679 if (device->devices[1])
1680 l = g_list_prepend (l, g_object_ref (device->devices[1]));
1681
1682 if (device->devices[2])
1683 l = g_list_prepend (l, g_object_ref (device->devices[2]));
1684
1685 if (device->devices[3])
1686 l = g_list_prepend (l, g_object_ref (device->devices[3]));
1687 }
1688
1689 l = g_list_reverse (l);
1690
1691 return l;
1692 }
1693
1694 GstDecklinkOutput *
gst_decklink_acquire_nth_output(gint n,GstElement * sink,gboolean is_audio)1695 gst_decklink_acquire_nth_output (gint n, GstElement * sink, gboolean is_audio)
1696 {
1697 GstDecklinkOutput *output;
1698 Device *device;
1699
1700 g_once (&devices_once, init_devices, NULL);
1701
1702 if (devices == NULL)
1703 return NULL;
1704
1705 if (n < 0 || (guint) n >= devices->len)
1706 return NULL;
1707
1708 device = (Device *) g_ptr_array_index (devices, n);
1709 output = &device->output;
1710 if (!output->output) {
1711 GST_ERROR ("Device %d has no output", n);
1712 return NULL;
1713 }
1714
1715 if (!is_audio) {
1716 GstDecklinkVideoSink *videosink = (GstDecklinkVideoSink *) (sink);
1717 if (gst_decklink_configure_profile (device,
1718 videosink->profile_id) == PROFILE_SET_FAILURE) {
1719 return NULL;
1720 }
1721 }
1722
1723 g_mutex_lock (&output->lock);
1724 if (is_audio && !output->audiosink) {
1725 output->audiosink = GST_ELEMENT_CAST (gst_object_ref (sink));
1726 g_mutex_unlock (&output->lock);
1727 return output;
1728 } else if (!output->videosink) {
1729 output->videosink = GST_ELEMENT_CAST (gst_object_ref (sink));
1730 g_mutex_unlock (&output->lock);
1731 return output;
1732 }
1733 g_mutex_unlock (&output->lock);
1734
1735 GST_ERROR ("Output device %d (audio: %d) in use already", n, is_audio);
1736 return NULL;
1737 }
1738
1739 void
gst_decklink_release_nth_output(gint n,GstElement * sink,gboolean is_audio)1740 gst_decklink_release_nth_output (gint n, GstElement * sink, gboolean is_audio)
1741 {
1742 GstDecklinkOutput *output;
1743 Device *device;
1744
1745 if (devices == NULL)
1746 return;
1747
1748 if (n < 0 || (guint) n >= devices->len)
1749 return;
1750
1751 device = (Device *) g_ptr_array_index (devices, n);
1752 output = &device->output;
1753 g_assert (output->output);
1754
1755 g_mutex_lock (&output->lock);
1756 if (is_audio) {
1757 g_assert (output->audiosink == sink);
1758 gst_object_unref (sink);
1759 output->audiosink = NULL;
1760 } else {
1761 g_assert (output->videosink == sink);
1762 gst_object_unref (sink);
1763 output->videosink = NULL;
1764 }
1765 g_mutex_unlock (&output->lock);
1766 }
1767
1768 GstDecklinkInput *
gst_decklink_acquire_nth_input(gint n,GstElement * src,gboolean is_audio)1769 gst_decklink_acquire_nth_input (gint n, GstElement * src, gboolean is_audio)
1770 {
1771 GstDecklinkInput *input;
1772 Device *device;
1773
1774 g_once (&devices_once, init_devices, NULL);
1775
1776 if (devices == NULL)
1777 return NULL;
1778
1779 if (n < 0 || (guint) n >= devices->len)
1780 return NULL;
1781
1782 device = (Device *) g_ptr_array_index (devices, n);
1783 input = &device->input;
1784 if (!input->input) {
1785 GST_ERROR ("Device %d has no input", n);
1786 return NULL;
1787 }
1788
1789 if (!is_audio) {
1790 GstDecklinkVideoSrc *videosrc = (GstDecklinkVideoSrc *) (src);
1791 if (gst_decklink_configure_profile (device,
1792 videosrc->profile_id) == PROFILE_SET_FAILURE) {
1793 return NULL;
1794 }
1795 }
1796
1797 g_mutex_lock (&input->lock);
1798 input->input->SetVideoInputFrameMemoryAllocator (new
1799 GStreamerDecklinkMemoryAllocator);
1800 if (is_audio && !input->audiosrc) {
1801 input->audiosrc = GST_ELEMENT_CAST (gst_object_ref (src));
1802 g_mutex_unlock (&input->lock);
1803 return input;
1804 } else if (!input->videosrc) {
1805 input->videosrc = GST_ELEMENT_CAST (gst_object_ref (src));
1806 g_mutex_unlock (&input->lock);
1807 return input;
1808 }
1809
1810 g_mutex_unlock (&input->lock);
1811
1812 GST_ERROR ("Input device %d (audio: %d) in use already", n, is_audio);
1813 return NULL;
1814 }
1815
1816 void
gst_decklink_release_nth_input(gint n,GstElement * src,gboolean is_audio)1817 gst_decklink_release_nth_input (gint n, GstElement * src, gboolean is_audio)
1818 {
1819 GstDecklinkInput *input;
1820 Device *device;
1821
1822 if (devices == NULL)
1823 return;
1824
1825 if (n < 0 || (guint) n >= devices->len)
1826 return;
1827
1828 device = (Device *) g_ptr_array_index (devices, n);
1829
1830 input = &device->input;
1831 g_assert (input->input);
1832
1833 g_mutex_lock (&input->lock);
1834 if (is_audio) {
1835 g_assert (input->audiosrc == src);
1836 gst_object_unref (src);
1837 input->audiosrc = NULL;
1838 } else {
1839 g_assert (input->videosrc == src);
1840 gst_object_unref (src);
1841 input->videosrc = NULL;
1842 }
1843 g_mutex_unlock (&input->lock);
1844 }
1845
1846 static ProfileSetOperationResult
gst_decklink_configure_profile(Device * device,GstDecklinkProfileId profile_id)1847 gst_decklink_configure_profile (Device * device,
1848 GstDecklinkProfileId profile_id)
1849 {
1850 HRESULT res;
1851
1852 if (profile_id == GST_DECKLINK_PROFILE_ID_DEFAULT)
1853 return PROFILE_SET_SUCCESS;
1854
1855 GstDecklinkInput *input = &device->input;
1856 IDeckLink *decklink = input->device;
1857
1858 IDeckLinkProfileManager *manager = NULL;
1859 if (decklink->QueryInterface (IID_IDeckLinkProfileManager,
1860 (void **) &manager) == S_OK) {
1861 BMDProfileID bmd_profile_id;
1862
1863 switch (profile_id) {
1864 case GST_DECKLINK_PROFILE_ID_ONE_SUB_DEVICE_FULL_DUPLEX:
1865 bmd_profile_id = bmdProfileOneSubDeviceFullDuplex;
1866 break;
1867 case GST_DECKLINK_PROFILE_ID_ONE_SUB_DEVICE_HALF_DUPLEX:
1868 bmd_profile_id = bmdProfileOneSubDeviceHalfDuplex;
1869 break;
1870 case GST_DECKLINK_PROFILE_ID_TWO_SUB_DEVICES_FULL_DUPLEX:
1871 bmd_profile_id = bmdProfileTwoSubDevicesFullDuplex;
1872 break;
1873 case GST_DECKLINK_PROFILE_ID_TWO_SUB_DEVICES_HALF_DUPLEX:
1874 bmd_profile_id = bmdProfileTwoSubDevicesHalfDuplex;
1875 break;
1876 case GST_DECKLINK_PROFILE_ID_FOUR_SUB_DEVICES_HALF_DUPLEX:
1877 bmd_profile_id = bmdProfileFourSubDevicesHalfDuplex;
1878 break;
1879 default:
1880 case GST_DECKLINK_PROFILE_ID_DEFAULT:
1881 g_assert_not_reached ();
1882 break;
1883 }
1884
1885 IDeckLinkProfile *profile = NULL;
1886 res = manager->GetProfile (bmd_profile_id, &profile);
1887
1888 if (res == S_OK && profile) {
1889 res = profile->SetActive ();
1890 profile->Release ();
1891 }
1892
1893 manager->Release ();
1894
1895 if (res == S_OK) {
1896 GST_DEBUG ("Successfully set profile");
1897 return PROFILE_SET_SUCCESS;
1898 } else {
1899 GST_ERROR ("Failed to set profile");
1900 return PROFILE_SET_FAILURE;
1901 }
1902 } else {
1903 GST_DEBUG ("Device has only one profile");
1904 return PROFILE_SET_UNSUPPORTED;
1905 }
1906 }
1907
1908 G_DEFINE_TYPE (GstDecklinkClock, gst_decklink_clock, GST_TYPE_SYSTEM_CLOCK);
1909
1910 static GstClockTime gst_decklink_clock_get_internal_time (GstClock * clock);
1911
1912 static void
gst_decklink_clock_class_init(GstDecklinkClockClass * klass)1913 gst_decklink_clock_class_init (GstDecklinkClockClass * klass)
1914 {
1915 GstClockClass *clock_class = (GstClockClass *) klass;
1916
1917 clock_class->get_internal_time = gst_decklink_clock_get_internal_time;
1918 }
1919
1920 static void
gst_decklink_clock_init(GstDecklinkClock * clock)1921 gst_decklink_clock_init (GstDecklinkClock * clock)
1922 {
1923 GST_OBJECT_FLAG_SET (clock, GST_CLOCK_FLAG_CAN_SET_MASTER);
1924 }
1925
1926 static GstClock *
gst_decklink_clock_new(const gchar * name)1927 gst_decklink_clock_new (const gchar * name)
1928 {
1929 GstDecklinkClock *self =
1930 GST_DECKLINK_CLOCK (g_object_new (GST_TYPE_DECKLINK_CLOCK, "name", name,
1931 "clock-type", GST_CLOCK_TYPE_OTHER, NULL));
1932
1933 gst_object_ref_sink (self);
1934
1935 return GST_CLOCK_CAST (self);
1936 }
1937
1938 static GstClockTime
gst_decklink_clock_get_internal_time(GstClock * clock)1939 gst_decklink_clock_get_internal_time (GstClock * clock)
1940 {
1941 GstDecklinkClock *self = GST_DECKLINK_CLOCK (clock);
1942 GstClockTime result, start_time, last_time;
1943 GstClockTimeDiff offset;
1944 BMDTimeValue time;
1945 HRESULT ret;
1946
1947 g_mutex_lock (&self->output->lock);
1948 start_time = self->output->clock_start_time;
1949 offset = self->output->clock_offset;
1950 last_time = self->output->clock_last_time;
1951 time = -1;
1952 if (!self->output->started) {
1953 result = last_time;
1954 ret = -1;
1955 } else {
1956 ret =
1957 self->output->output->GetHardwareReferenceClock (GST_SECOND, &time,
1958 NULL, NULL);
1959 if (ret == S_OK && time >= 0) {
1960 result = time;
1961
1962 if (start_time == GST_CLOCK_TIME_NONE)
1963 start_time = self->output->clock_start_time = result;
1964
1965 if (result > start_time)
1966 result -= start_time;
1967 else
1968 result = 0;
1969
1970 if (self->output->clock_restart) {
1971 self->output->clock_offset = result - last_time;
1972 offset = self->output->clock_offset;
1973 self->output->clock_restart = FALSE;
1974 }
1975 result = MAX (last_time, result);
1976 result -= offset;
1977 result = MAX (last_time, result);
1978 } else {
1979 result = last_time;
1980 }
1981
1982 self->output->clock_last_time = result;
1983 }
1984 result += self->output->clock_epoch;
1985 g_mutex_unlock (&self->output->lock);
1986
1987 GST_LOG_OBJECT (clock,
1988 "result %" GST_TIME_FORMAT " time %" GST_TIME_FORMAT " last time %"
1989 GST_TIME_FORMAT " offset %" GST_TIME_FORMAT " start time %"
1990 GST_TIME_FORMAT " (ret: 0x%08lx)", GST_TIME_ARGS (result),
1991 GST_TIME_ARGS (time), GST_TIME_ARGS (last_time), GST_TIME_ARGS (offset),
1992 GST_TIME_ARGS (start_time), (unsigned long) ret);
1993
1994 return result;
1995 }
1996
1997 void
decklink_element_init(GstPlugin * plugin)1998 decklink_element_init (GstPlugin * plugin)
1999 {
2000 static gsize res = FALSE;
2001 if (g_once_init_enter (&res)) {
2002 GST_DEBUG_CATEGORY_INIT (gst_decklink_debug, "decklink", 0,
2003 "debug category for decklink plugin");
2004 gst_type_mark_as_plugin_api (GST_TYPE_DECKLINK_AUDIO_CHANNELS, (GstPluginAPIFlags) 0);
2005 gst_type_mark_as_plugin_api (GST_TYPE_DECKLINK_AUDIO_CONNECTION, (GstPluginAPIFlags) 0);
2006 gst_type_mark_as_plugin_api (GST_TYPE_DECKLINK_PROFILE_ID, (GstPluginAPIFlags) 0);
2007 gst_type_mark_as_plugin_api (GST_TYPE_DECKLINK_KEYER_MODE, (GstPluginAPIFlags) 0);
2008 gst_type_mark_as_plugin_api (GST_TYPE_DECKLINK_MODE, (GstPluginAPIFlags) 0);
2009 gst_type_mark_as_plugin_api (GST_TYPE_DECKLINK_TIMECODE_FORMAT, (GstPluginAPIFlags) 0);
2010 gst_type_mark_as_plugin_api (GST_TYPE_DECKLINK_VIDEO_FORMAT, (GstPluginAPIFlags) 0);
2011 gst_type_mark_as_plugin_api (GST_TYPE_DECKLINK_CONNECTION, (GstPluginAPIFlags) 0);
2012
2013 g_once_init_leave (&res, TRUE);
2014 }
2015 }
2016