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>
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.
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.
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.
28 #include "gstdecklink.h"
29 #include "gstdecklinkaudiosink.h"
30 #include "gstdecklinkvideosink.h"
31 #include "gstdecklinkaudiosrc.h"
32 #include "gstdecklinkvideosrc.h"
33 #include "gstdecklinkdeviceprovider.h"
35 GST_DEBUG_CATEGORY_STATIC (gst_decklink_debug);
36 #define GST_CAT_DEFAULT gst_decklink_debug
39 gst_decklink_mode_get_type (void)
42 static const GEnumValue modes[] = {
43 {GST_DECKLINK_MODE_AUTO, "Automatic detection", "auto"},
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"},
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"},
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"},
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"},
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"},
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"},
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"},
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"},
91 {GST_DECKLINK_MODE_NTSC_WIDESCREEN, "NTSC SD 60i 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",
97 {GST_DECKLINK_MODE_NTSC_P_WIDESCREEN, "NTSC SD 60p Widescreen",
99 {GST_DECKLINK_MODE_PAL_P_WIDESCREEN, "PAL SD 50p Widescreen",
105 if (g_once_init_enter (&id)) {
106 GType tmp = g_enum_register_static ("GstDecklinkModes", modes);
107 g_once_init_leave (&id, tmp);
114 gst_decklink_connection_get_type (void)
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"},
128 if (g_once_init_enter (&id)) {
129 GType tmp = g_enum_register_static ("GstDecklinkConnection", connections);
130 g_once_init_leave (&id, tmp);
137 gst_decklink_video_format_get_type (void)
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"},
156 if (g_once_init_enter (&id)) {
157 GType tmp = g_enum_register_static ("GstDecklinkVideoFormat", types);
158 g_once_init_leave (&id, tmp);
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
173 * Decklink Profile ID
178 gst_decklink_profile_id_get_type (void)
181 static const GEnumValue types[] = {
182 {GST_DECKLINK_PROFILE_ID_DEFAULT, "Default, don't change profile",
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"},
197 if (g_once_init_enter (&id)) {
198 GType tmp = g_enum_register_static ("GstDecklinkProfileId", types);
199 g_once_init_leave (&id, tmp);
206 gst_decklink_timecode_format_get_type (void)
209 static const GEnumValue timecodeformats[] = {
210 {GST_DECKLINK_TIMECODE_FORMAT_RP188VITC1, "bmdTimecodeRP188VITC1",
212 {GST_DECKLINK_TIMECODE_FORMAT_RP188VITC2, "bmdTimecodeRP188VITC2",
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",
219 {GST_DECKLINK_TIMECODE_FORMAT_SERIAL, "bmdTimecodeSerial", "serial"},
223 if (g_once_init_enter (&id)) {
225 g_enum_register_static ("GstDecklinkTimecodeFormat", timecodeformats);
226 g_once_init_leave (&id, tmp);
233 gst_decklink_keyer_mode_get_type (void)
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"},
243 if (g_once_init_enter (&id)) {
244 GType tmp = g_enum_register_static ("GstDecklinkKeyerMode", keyermodes);
245 g_once_init_leave (&id, tmp);
252 gst_decklink_audio_connection_get_type (void)
255 static const GEnumValue connections[] = {
256 {GST_DECKLINK_AUDIO_CONNECTION_AUTO, "Automatic", "auto"},
257 {GST_DECKLINK_AUDIO_CONNECTION_EMBEDDED, "SDI/HDMI embedded audio",
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)",
263 {GST_DECKLINK_AUDIO_CONNECTION_ANALOG_RCA, "Analog input (RCA)",
268 if (g_once_init_enter (&id)) {
270 g_enum_register_static ("GstDecklinkAudioConnection", connections);
271 g_once_init_leave (&id, tmp);
278 gst_decklink_audio_channels_get_type (void)
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"},
289 if (g_once_init_enter (&id)) {
291 g_enum_register_static ("GstDecklinkAudioChannels", connections);
292 g_once_init_leave (&id, tmp);
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"
305 static const GstDecklinkMode modes[] = {
306 {bmdModeNTSC, 720, 486, 30000, 1001, true, NTSC}, // default is ntsc
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},
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},
320 {bmdModeHD1080i50, 1920, 1080, 25, 1, true, HD},
321 {bmdModeHD1080i5994, 1920, 1080, 30000, 1001, true, HD},
322 {bmdModeHD1080i6000, 1920, 1080, 30, 1, true, HD},
324 {bmdModeHD1080p50, 1920, 1080, 50, 1, false, HD},
325 {bmdModeHD1080p5994, 1920, 1080, 60000, 1001, false, HD},
326 {bmdModeHD1080p6000, 1920, 1080, 60, 1, false, HD},
328 {bmdModeHD720p50, 1280, 720, 50, 1, false, HD},
329 {bmdModeHD720p5994, 1280, 720, 60000, 1001, false, HD},
330 {bmdModeHD720p60, 1280, 720, 60, 1, false, HD},
332 {bmdMode2k2398, 2048, 1556, 24000, 1001, false, HD},
333 {bmdMode2k24, 2048, 1556, 24, 1, false, HD},
334 {bmdMode2k25, 2048, 1556, 25, 1, false, HD},
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},
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},
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}
363 BMDPixelFormat format;
365 GstVideoFormat vformat;
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},
374 {bmdFormat10BitRGB, FIXME, FIXME},
375 {bmdFormat12BitRGB, FIXME, FIXME},
376 {bmdFormat12BitRGBLE, FIXME, FIXME},
377 {bmdFormat10BitRGBXLE, FIXME, FIXME},
378 {bmdFormat10BitRGBX, FIXME, FIXME} */
382 enum ProfileSetOperationResult
384 PROFILE_SET_UNSUPPORTED,
389 enum DuplexModeSetOperationResult
391 DUPLEX_MODE_SET_UNSUPPORTED,
392 DUPLEX_MODE_SET_SUCCESS,
393 DUPLEX_MODE_SET_FAILURE
398 BMDTimecodeFormat format;
399 GstDecklinkTimecodeFormat gstformat;
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}
414 BMDKeyerMode keymode;
415 GstDecklinkKeyerMode gstkeymode;
418 {bmdKeyerModeOff, GST_DECKLINK_KEYER_MODE_OFF},
419 {bmdKeyerModeInternal, GST_DECKLINK_KEYER_MODE_INTERNAL},
420 {bmdKeyerModeExternal, GST_DECKLINK_KEYER_MODE_EXTERNAL}
424 const GstDecklinkMode *
425 gst_decklink_get_mode (GstDecklinkModeEnum e)
427 if (e < GST_DECKLINK_MODE_AUTO || e > GST_DECKLINK_MODE_PAL_P_WIDESCREEN)
432 const GstDecklinkModeEnum
433 gst_decklink_get_mode_enum_from_bmd (BMDDisplayMode mode)
435 GstDecklinkModeEnum displayMode = GST_DECKLINK_MODE_NTSC;
438 displayMode = GST_DECKLINK_MODE_NTSC;
440 case bmdModeNTSC2398:
441 displayMode = GST_DECKLINK_MODE_NTSC2398;
444 displayMode = GST_DECKLINK_MODE_PAL;
447 displayMode = GST_DECKLINK_MODE_NTSC_P;
450 displayMode = GST_DECKLINK_MODE_PAL_P;
452 case bmdModeHD1080p2398:
453 displayMode = GST_DECKLINK_MODE_1080p2398;
455 case bmdModeHD1080p24:
456 displayMode = GST_DECKLINK_MODE_1080p24;
458 case bmdModeHD1080p25:
459 displayMode = GST_DECKLINK_MODE_1080p25;
461 case bmdModeHD1080p2997:
462 displayMode = GST_DECKLINK_MODE_1080p2997;
464 case bmdModeHD1080p30:
465 displayMode = GST_DECKLINK_MODE_1080p30;
467 case bmdModeHD1080i50:
468 displayMode = GST_DECKLINK_MODE_1080i50;
470 case bmdModeHD1080i5994:
471 displayMode = GST_DECKLINK_MODE_1080i5994;
473 case bmdModeHD1080i6000:
474 displayMode = GST_DECKLINK_MODE_1080i60;
476 case bmdModeHD1080p50:
477 displayMode = GST_DECKLINK_MODE_1080p50;
479 case bmdModeHD1080p5994:
480 displayMode = GST_DECKLINK_MODE_1080p5994;
482 case bmdModeHD1080p6000:
483 displayMode = GST_DECKLINK_MODE_1080p60;
485 case bmdModeHD720p50:
486 displayMode = GST_DECKLINK_MODE_720p50;
488 case bmdModeHD720p5994:
489 displayMode = GST_DECKLINK_MODE_720p5994;
491 case bmdModeHD720p60:
492 displayMode = GST_DECKLINK_MODE_720p60;
495 displayMode = GST_DECKLINK_MODE_1556p2398;
498 displayMode = GST_DECKLINK_MODE_1556p24;
501 displayMode = GST_DECKLINK_MODE_1556p25;
503 case bmdMode2kDCI2398:
504 displayMode = GST_DECKLINK_MODE_2KDCI2398;
507 displayMode = GST_DECKLINK_MODE_2KDCI24;
510 displayMode = GST_DECKLINK_MODE_2KDCI25;
512 case bmdMode2kDCI2997:
513 displayMode = GST_DECKLINK_MODE_2KDCI2997;
516 displayMode = GST_DECKLINK_MODE_2KDCI30;
519 displayMode = GST_DECKLINK_MODE_2KDCI50;
521 case bmdMode2kDCI5994:
522 displayMode = GST_DECKLINK_MODE_2KDCI5994;
525 displayMode = GST_DECKLINK_MODE_2KDCI60;
527 case bmdMode4K2160p2398:
528 displayMode = GST_DECKLINK_MODE_2160p2398;
530 case bmdMode4K2160p24:
531 displayMode = GST_DECKLINK_MODE_2160p24;
533 case bmdMode4K2160p25:
534 displayMode = GST_DECKLINK_MODE_2160p25;
536 case bmdMode4K2160p2997:
537 displayMode = GST_DECKLINK_MODE_2160p2997;
539 case bmdMode4K2160p30:
540 displayMode = GST_DECKLINK_MODE_2160p30;
542 case bmdMode4K2160p50:
543 displayMode = GST_DECKLINK_MODE_2160p50;
545 case bmdMode4K2160p5994:
546 displayMode = GST_DECKLINK_MODE_2160p5994;
548 case bmdMode4K2160p60:
549 displayMode = GST_DECKLINK_MODE_2160p60;
552 displayMode = (GstDecklinkModeEnum) - 1;
559 gst_decklink_pixel_format_from_type (GstDecklinkVideoFormat t)
561 return formats[t].format;
565 gst_decklink_bpp_from_type (GstDecklinkVideoFormat t)
567 return formats[t].bpp;
570 const GstDecklinkVideoFormat
571 gst_decklink_type_from_video_format (GstVideoFormat f)
575 for (i = 1; i < G_N_ELEMENTS (formats); i++) {
576 if (formats[i].vformat == f)
577 return (GstDecklinkVideoFormat) i;
579 g_assert_not_reached ();
580 return GST_DECKLINK_VIDEO_FORMAT_AUTO;
584 gst_decklink_video_format_from_type (BMDPixelFormat pf)
588 for (i = 1; i < G_N_ELEMENTS (formats); i++) {
589 if (formats[i].format == pf)
590 return formats[i].vformat;
592 GST_WARNING ("Unknown pixel format 0x%x", pf);
593 return GST_VIDEO_FORMAT_UNKNOWN;
597 const BMDTimecodeFormat
598 gst_decklink_timecode_format_from_enum (GstDecklinkTimecodeFormat f)
600 return tcformats[f].format;
603 const GstDecklinkTimecodeFormat
604 gst_decklink_timecode_format_to_enum (BMDTimecodeFormat f)
608 for (i = 0; i < G_N_ELEMENTS (tcformats); i++) {
609 if (tcformats[i].format == f)
610 return (GstDecklinkTimecodeFormat) i;
612 g_assert_not_reached ();
613 return GST_DECKLINK_TIMECODE_FORMAT_RP188ANY;
617 gst_decklink_keyer_mode_from_enum (GstDecklinkKeyerMode m)
619 return kmodes[m].keymode;
622 const GstDecklinkKeyerMode
623 gst_decklink_keyer_mode_to_enum (BMDKeyerMode m)
627 for (i = 0; i < G_N_ELEMENTS (kmodes); i++) {
628 if (kmodes[i].keymode == m)
629 return (GstDecklinkKeyerMode) i;
631 g_assert_not_reached ();
632 return GST_DECKLINK_KEYER_MODE_OFF;
635 static const BMDVideoConnection connections[] = {
636 (BMDVideoConnection) 0, /* auto */
637 bmdVideoConnectionSDI,
638 bmdVideoConnectionHDMI,
639 bmdVideoConnectionOpticalSDI,
640 bmdVideoConnectionComponent,
641 bmdVideoConnectionComposite,
642 bmdVideoConnectionSVideo
645 const BMDVideoConnection
646 gst_decklink_get_connection (GstDecklinkConnectionEnum e)
648 g_return_val_if_fail (e != GST_DECKLINK_CONNECTION_AUTO,
649 bmdVideoConnectionSDI);
651 if (e <= GST_DECKLINK_CONNECTION_AUTO || e > GST_DECKLINK_CONNECTION_SVIDEO)
652 e = GST_DECKLINK_CONNECTION_SDI;
654 return connections[e];
658 gst_decklink_caps_get_pixel_format (GstCaps * caps, BMDPixelFormat * format)
663 if (gst_video_info_from_caps (&vinfo, caps) == FALSE) {
664 GST_ERROR ("Could not get video info from caps: %" GST_PTR_FORMAT, caps);
668 f = vinfo.finfo->format;
669 *format = gst_decklink_pixel_format_from_type(gst_decklink_type_from_video_format (f));
673 static GstStructure *
674 gst_decklink_mode_get_generic_structure (GstDecklinkModeEnum e)
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);
688 static GstStructure *
689 gst_decklink_mode_get_structure (GstDecklinkModeEnum e, BMDPixelFormat f,
692 const GstDecklinkMode *mode = &modes[e];
693 GstStructure *s = gst_decklink_mode_get_generic_structure (e);
695 if (input && mode->interlaced) {
697 gst_structure_set (s, "field-order", G_TYPE_STRING, "top-field-first",
700 gst_structure_set (s, "field-order", G_TYPE_STRING, "bottom-field-first",
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);
710 case bmdFormat10BitYUV: /* 'v210' */
711 gst_structure_set (s, "format", G_TYPE_STRING, "v210", NULL);
713 case bmdFormat8BitARGB: /* 'ARGB' */
714 gst_structure_set (s, "format", G_TYPE_STRING, "ARGB", NULL);
716 case bmdFormat8BitBGRA: /* 'BGRA' */
717 gst_structure_set (s, "format", G_TYPE_STRING, "BGRA", NULL);
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) */
725 GST_WARNING ("format not supported %d", f);
726 gst_structure_free (s);
735 gst_decklink_mode_get_caps (GstDecklinkModeEnum e, BMDPixelFormat f,
740 caps = gst_caps_new_empty ();
742 gst_caps_merge_structure (caps, gst_decklink_mode_get_structure (e, f,
749 gst_decklink_mode_get_caps_all_formats (GstDecklinkModeEnum e, gboolean input)
754 caps = gst_caps_new_empty ();
755 for (i = 1; i < G_N_ELEMENTS (formats); i++)
757 gst_caps_merge_structure (caps, gst_decklink_mode_get_structure (e,
758 formats[i].format, input));
764 gst_decklink_pixel_format_get_caps (BMDPixelFormat f, gboolean input)
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);
780 gst_decklink_mode_get_template_caps (gboolean input)
785 caps = gst_caps_new_empty ();
786 for (i = 1; i < (int) G_N_ELEMENTS (modes); i++)
788 gst_caps_merge (caps,
789 gst_decklink_mode_get_caps_all_formats ((GstDecklinkModeEnum) i,
795 const GstDecklinkMode *
796 gst_decklink_find_mode_and_format_for_caps (GstCaps * caps,
797 BMDPixelFormat * format)
802 g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
803 if (!gst_decklink_caps_get_pixel_format (caps, format))
806 for (i = 1; i < (int) G_N_ELEMENTS (modes); i++) {
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);
813 gst_caps_unref (mode_caps);
819 const GstDecklinkMode *
820 gst_decklink_find_mode_for_caps (GstCaps * caps)
822 BMDPixelFormat format;
824 return gst_decklink_find_mode_and_format_for_caps (caps, &format);
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))
840 typedef struct _GstDecklinkClock GstDecklinkClock;
841 typedef struct _GstDecklinkClockClass GstDecklinkClockClass;
843 struct _GstDecklinkClock
845 GstSystemClock clock;
847 GstDecklinkOutput *output;
850 struct _GstDecklinkClockClass
852 GstSystemClockClass parent_class;
855 GType gst_decklink_clock_get_type (void);
856 static GstClock *gst_decklink_clock_new (const gchar * name);
858 typedef struct _Device Device;
861 GstDecklinkOutput output;
862 GstDecklinkInput input;
864 /* Audio/video output, Audio/video input */
865 GstDecklinkDevice *devices[4];
868 static ProfileSetOperationResult gst_decklink_configure_profile (Device *
869 device, GstDecklinkProfileId profile_id);
871 class GStreamerDecklinkInputCallback:public IDeckLinkInputCallback
874 GstDecklinkInput * m_input;
878 GStreamerDecklinkInputCallback (GstDecklinkInput * input)
879 : IDeckLinkInputCallback (), m_refcount (1)
882 g_mutex_init (&m_mutex);
885 virtual ~ GStreamerDecklinkInputCallback ()
887 g_mutex_clear (&m_mutex);
890 virtual HRESULT STDMETHODCALLTYPE QueryInterface (REFIID, LPVOID *)
892 return E_NOINTERFACE;
895 virtual ULONG STDMETHODCALLTYPE AddRef (void)
899 g_mutex_lock (&m_mutex);
902 g_mutex_unlock (&m_mutex);
907 virtual ULONG STDMETHODCALLTYPE Release (void)
911 g_mutex_lock (&m_mutex);
914 g_mutex_unlock (&m_mutex);
924 virtual HRESULT STDMETHODCALLTYPE
925 VideoInputFormatChanged (BMDVideoInputFormatChangedEvents,
926 IDeckLinkDisplayMode * mode, BMDDetectedVideoInputFormatFlags formatFlags)
928 BMDPixelFormat pixelFormat;
930 GST_INFO ("Video input format changed");
932 if ((formatFlags & bmdDetectedVideoInputRGB444)
933 && m_input->format == bmdFormat8BitYUV) {
934 /* user-set format was auto or 8BitYUV, change to RGB */
935 pixelFormat = bmdFormat8BitARGB;
937 /* use the user-set format, defaulting to 8BitYUV */
938 pixelFormat = m_input->format;
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 ();
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);
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);
968 m_input->input->StartStreams ();
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);
978 virtual HRESULT STDMETHODCALLTYPE
979 VideoInputFrameArrived (IDeckLinkVideoInputFrame * video_frame,
980 IDeckLinkAudioInputPacket * audio_packet)
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;
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;
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;
1014 mode = gst_decklink_get_mode_enum_from_bmd (m_input->mode->mode);
1016 if (m_input->audiosrc) {
1017 audiosrc = GST_ELEMENT_CAST (gst_object_ref (m_input->audiosrc));
1019 clock = gst_element_get_clock (GST_ELEMENT_CAST (audiosrc));
1020 base_time = gst_element_get_base_time (audiosrc);
1022 got_audio_packet = m_input->got_audio_packet;
1024 g_mutex_unlock (&m_input->lock);
1027 capture_time = gst_clock_get_time (clock);
1029 // If we have the actual capture time for the frame, compensate the
1030 // capture time accordingly.
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.
1036 // We then subtract that difference from the "now" on the gst clock.
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);
1046 video_frame->GetHardwareReferenceTimestamp (GST_SECOND,
1047 &hardware_time, &hardware_duration);
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;
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;
1063 if (capture_time > base_time)
1064 capture_time -= base_time;
1070 BMDFrameFlags flags;
1072 flags = video_frame->GetFlags ();
1073 if (flags & bmdFrameHasNoInputSource) {
1078 if (got_video_frame && videosrc && video_frame) {
1079 IDeckLinkTimecode *dtc = 0;
1082 video_frame->GetStreamTime (&stream_time, &stream_duration,
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;
1091 video_frame->GetHardwareReferenceTimestamp (GST_SECOND,
1092 &hardware_time, &hardware_duration);
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;
1099 if (m_input->videosrc) {
1100 /* FIXME: Avoid circularity between gstdecklink.cpp and
1101 * gstdecklinkvideosrc.cpp */
1104 GetTimecode (GST_DECKLINK_VIDEO_SRC (videosrc)->timecode_format,
1108 GST_DEBUG_OBJECT (videosrc, "Failed to get timecode: 0x%08lx",
1109 (unsigned long) res);
1114 /* passing dtc reference */
1115 got_video_frame (videosrc, video_frame, mode, capture_time,
1116 stream_time, stream_duration, hardware_time, hardware_duration, dtc,
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,
1126 GST_DEBUG ("Received no audio packet at %" GST_TIME_FORMAT,
1127 GST_TIME_ARGS (capture_time));
1130 gst_object_replace ((GstObject **) & videosrc, NULL);
1131 gst_object_replace ((GstObject **) & audiosrc, NULL);
1132 gst_object_replace ((GstObject **) & clock, NULL);
1138 class GStreamerDecklinkMemoryAllocator:public IDeckLinkMemoryAllocator
1142 uint32_t m_lastBufferSize;
1143 uint32_t m_nonEmptyCalls;
1144 GstQueueArray *m_buffers;
1147 void _clearBufferPool ()
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;
1162 GStreamerDecklinkMemoryAllocator ()
1163 : IDeckLinkMemoryAllocator (),
1164 m_lastBufferSize (0),
1165 m_nonEmptyCalls (0), m_buffers (NULL), m_refcount (1)
1167 g_mutex_init (&m_mutex);
1169 m_buffers = gst_queue_array_new (60);
1172 virtual ~ GStreamerDecklinkMemoryAllocator () {
1175 gst_queue_array_free (m_buffers);
1177 g_mutex_clear (&m_mutex);
1180 virtual HRESULT STDMETHODCALLTYPE QueryInterface (REFIID, LPVOID *)
1182 return E_NOINTERFACE;
1185 virtual ULONG STDMETHODCALLTYPE AddRef (void)
1189 g_mutex_lock (&m_mutex);
1192 g_mutex_unlock (&m_mutex);
1197 virtual ULONG STDMETHODCALLTYPE Release (void)
1201 g_mutex_lock (&m_mutex);
1204 g_mutex_unlock (&m_mutex);
1214 virtual HRESULT STDMETHODCALLTYPE
1215 AllocateBuffer (uint32_t bufferSize, void **allocatedBuffer)
1220 g_mutex_lock (&m_mutex);
1222 /* If buffer size changed since last call, empty buffer pool */
1223 if (bufferSize != m_lastBufferSize) {
1224 _clearBufferPool ();
1225 m_lastBufferSize = bufferSize;
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);
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;
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;
1244 /* Align our buffer */
1245 buf += 128 - offset;
1247 /* And write the alignment offset right before the buffer */
1248 *(buf - 1) = offset;
1250 *allocatedBuffer = (void *) buf;
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;
1260 m_nonEmptyCalls = 0;
1263 m_nonEmptyCalls = 0;
1266 g_mutex_unlock (&m_mutex);
1271 virtual HRESULT STDMETHODCALLTYPE ReleaseBuffer (void *buffer)
1273 g_mutex_lock (&m_mutex);
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);
1282 g_free (alloc_buffer);
1285 g_mutex_unlock (&m_mutex);
1290 virtual HRESULT STDMETHODCALLTYPE Commit ()
1295 virtual HRESULT STDMETHODCALLTYPE Decommit ()
1297 /* Clear all remaining pools */
1298 _clearBufferPool ();
1305 /* FIXME: We currently never deinit this */
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;
1314 /* COM initialization/uninitialization thread */
1316 gst_decklink_com_thread (gpointer data)
1320 g_mutex_lock (&com_init_lock);
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 */
1326 res = CoInitializeEx (0, COINIT_MULTITHREADED);
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.");
1332 GST_INFO ("COM initialized successfully");
1334 com_initialized = TRUE;
1336 /* Signal other threads waiting on this condition that COM was initialized */
1337 g_cond_signal (&com_init_cond);
1339 g_mutex_unlock (&com_init_lock);
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);
1346 GST_INFO ("COM uninitialized successfully");
1347 com_initialized = FALSE;
1348 g_cond_signal (&com_deinited_cond);
1349 g_mutex_unlock (&com_deinit_lock);
1353 #endif /* G_OS_WIN32 */
1355 static GOnce devices_once = G_ONCE_INIT;
1356 static GPtrArray *devices; /* array of Device */
1359 static GstDecklinkDevice *
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)
1367 const gchar *device_class;
1368 GstCaps *caps = NULL;
1369 GstStructure *properties;
1372 device_class = video ? "Video/Source/Hardware" : "Audio/Source/Hardware";
1374 device_class = video ? "Video/Sink/Hardware" : "Audio/Sink/Hardware";
1377 g_strdup_printf ("%s (%s %s)", display_name,
1378 video ? "Video" : "Audio", capture ? "Capture" : "Output");
1381 caps = gst_caps_ref (video_caps);
1383 static GstStaticCaps audio_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);
1392 gst_caps_intersect (gst_static_caps_get (&audio_caps),
1394 gst_caps_unref (max_channel_caps);
1396 properties = gst_structure_new_empty ("properties");
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);
1405 gst_structure_set (properties, "supports-format-detection", G_TYPE_BOOLEAN,
1406 supports_format_detection, NULL);
1409 gst_structure_set (properties, "serial-number", G_TYPE_STRING,
1410 serial_number, NULL);
1412 ret = GST_DEVICE (g_object_new (GST_TYPE_DECKLINK_DEVICE,
1413 "display-name", name,
1414 "device-class", device_class, "caps", caps, "properties", properties,
1418 gst_caps_unref (caps);
1419 gst_structure_free (properties);
1421 GST_DECKLINK_DEVICE (ret)->video = video;
1422 GST_DECKLINK_DEVICE (ret)->capture = capture;
1423 GST_DECKLINK_DEVICE (ret)->device_number = device_number;
1425 return GST_DECKLINK_DEVICE (ret);
1429 init_devices (gpointer data)
1431 IDeckLinkIterator *iterator;
1432 IDeckLink *decklink = NULL;
1437 // Start COM thread for Windows
1439 g_mutex_lock (&com_init_lock);
1441 /* create the COM initialization thread */
1442 g_thread_new ("COM init thread", (GThreadFunc) gst_decklink_com_thread, NULL);
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 */
1449 iterator = CreateDeckLinkIteratorInstance ();
1450 if (iterator == NULL) {
1451 GST_DEBUG ("no driver");
1455 devices = g_ptr_array_new ();
1458 ret = iterator->Next (&decklink);
1459 while (ret == S_OK) {
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 ();
1471 dev = g_new0 (Device, 1);
1473 g_mutex_init (&dev->input.lock);
1474 g_mutex_init (&dev->output.lock);
1475 g_cond_init (&dev->output.cond);
1477 ret = decklink->QueryInterface (IID_IDeckLinkInput,
1478 (void **) &dev->input.input);
1480 GST_WARNING ("selected device does not have input interface: 0x%08lx",
1481 (unsigned long) ret);
1483 IDeckLinkDisplayModeIterator *mode_iter;
1485 dev->input.device = decklink;
1487 SetCallback (new GStreamerDecklinkInputCallback (&dev->input));
1489 if ((ret = dev->input.input->GetDisplayModeIterator (&mode_iter)) == S_OK) {
1490 IDeckLinkDisplayMode *mode;
1492 GST_DEBUG ("Input %d supports:", i);
1493 while ((ret = mode_iter->Next (&mode)) == S_OK) {
1495 GstDecklinkModeEnum mode_enum;
1498 gst_decklink_get_mode_enum_from_bmd (mode->GetDisplayMode ());
1499 if (mode_enum != (GstDecklinkModeEnum) - 1)
1501 gst_caps_merge_structure (video_input_caps,
1502 gst_decklink_mode_get_generic_structure (mode_enum));
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);
1514 mode_iter->Release ();
1522 ret = decklink->QueryInterface (IID_IDeckLinkOutput,
1523 (void **) &dev->output.output);
1525 GST_WARNING ("selected device does not have output interface: 0x%08lx",
1526 (unsigned long) ret);
1528 IDeckLinkDisplayModeIterator *mode_iter;
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;
1535 dev->output.output->GetDisplayModeIterator (&mode_iter)) ==
1537 IDeckLinkDisplayMode *mode;
1539 GST_DEBUG ("Output %d supports:", i);
1540 while ((ret = mode_iter->Next (&mode)) == S_OK) {
1542 GstDecklinkModeEnum mode_enum;
1545 gst_decklink_get_mode_enum_from_bmd (mode->GetDisplayMode ());
1546 if (mode_enum != (GstDecklinkModeEnum) - 1)
1548 gst_caps_merge_structure (video_output_caps,
1549 gst_decklink_mode_get_generic_structure (mode_enum));
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);
1561 mode_iter->Release ();
1569 ret = decklink->QueryInterface (IID_IDeckLinkConfiguration,
1570 (void **) &dev->input.config);
1572 GST_WARNING ("selected device does not have config interface: 0x%08lx",
1573 (unsigned long) ret);
1577 config->GetString (bmdDeckLinkConfigDeviceInformationSerialNumber,
1578 (COMSTR_T *) & serial_number);
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);
1587 ret = decklink->QueryInterface (IID_IDeckLinkProfileAttributes,
1588 (void **) &dev->input.attributes);
1589 dev->output.attributes = dev->input.attributes;
1591 GST_WARNING ("selected device does not have attributes interface: "
1592 "0x%08lx", (unsigned long) ret);
1594 bool tmp_bool = false;
1595 int64_t tmp_int = 2;
1597 dev->input.attributes->GetInt (BMDDeckLinkMaximumAudioChannels, &tmp_int);
1598 dev->input.attributes->GetFlag (BMDDeckLinkSupportsInputFormatDetection,
1600 supports_format_detection = tmp_bool;
1601 max_channels = tmp_int;
1604 decklink->GetModelName ((COMSTR_T *) & model_name);
1606 CONVERT_COM_STRING (model_name);
1607 decklink->GetDisplayName ((COMSTR_T *) & display_name);
1609 CONVERT_COM_STRING (display_name);
1613 gst_decklink_device_new (model_name, display_name, serial_number,
1614 supports_format_detection, video_input_caps, max_channels, TRUE, TRUE,
1617 gst_decklink_device_new (model_name, display_name, serial_number,
1618 supports_format_detection, video_input_caps, max_channels, FALSE,
1623 gst_decklink_device_new (model_name, display_name, serial_number,
1624 supports_format_detection, video_output_caps, max_channels, TRUE,
1627 gst_decklink_device_new (model_name, display_name, serial_number,
1628 supports_format_detection, video_output_caps, max_channels, FALSE,
1633 FREE_COM_STRING (model_name);
1635 FREE_COM_STRING (display_name);
1637 FREE_COM_STRING (serial_number);
1638 gst_caps_unref (video_input_caps);
1639 gst_caps_unref (video_output_caps);
1641 ret = decklink->QueryInterface (IID_IDeckLinkKeyer,
1642 (void **) &dev->output.keyer);
1644 g_ptr_array_add (devices, dev);
1646 /* We only warn of failure to obtain the keyer interface if the keyer
1647 * is enabled by keyer_mode
1650 ret = iterator->Next (&decklink);
1654 GST_INFO ("Detected %u devices", devices->len);
1656 iterator->Release ();
1662 gst_decklink_get_devices (void)
1667 g_once (&devices_once, init_devices, NULL);
1673 for (i = 0; i < devices->len; i++) {
1674 Device *device = (Device *) g_ptr_array_index (devices, i);
1676 if (device->devices[0])
1677 l = g_list_prepend (l, g_object_ref (device->devices[0]));
1679 if (device->devices[1])
1680 l = g_list_prepend (l, g_object_ref (device->devices[1]));
1682 if (device->devices[2])
1683 l = g_list_prepend (l, g_object_ref (device->devices[2]));
1685 if (device->devices[3])
1686 l = g_list_prepend (l, g_object_ref (device->devices[3]));
1689 l = g_list_reverse (l);
1695 gst_decklink_acquire_nth_output (gint n, GstElement * sink, gboolean is_audio)
1697 GstDecklinkOutput *output;
1700 g_once (&devices_once, init_devices, NULL);
1702 if (devices == NULL)
1705 if (n < 0 || (guint) n >= devices->len)
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);
1716 GstDecklinkVideoSink *videosink = (GstDecklinkVideoSink *) (sink);
1717 if (gst_decklink_configure_profile (device,
1718 videosink->profile_id) == PROFILE_SET_FAILURE) {
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);
1728 } else if (!output->videosink) {
1729 output->videosink = GST_ELEMENT_CAST (gst_object_ref (sink));
1730 g_mutex_unlock (&output->lock);
1733 g_mutex_unlock (&output->lock);
1735 GST_ERROR ("Output device %d (audio: %d) in use already", n, is_audio);
1740 gst_decklink_release_nth_output (gint n, GstElement * sink, gboolean is_audio)
1742 GstDecklinkOutput *output;
1745 if (devices == NULL)
1748 if (n < 0 || (guint) n >= devices->len)
1751 device = (Device *) g_ptr_array_index (devices, n);
1752 output = &device->output;
1753 g_assert (output->output);
1755 g_mutex_lock (&output->lock);
1757 g_assert (output->audiosink == sink);
1758 gst_object_unref (sink);
1759 output->audiosink = NULL;
1761 g_assert (output->videosink == sink);
1762 gst_object_unref (sink);
1763 output->videosink = NULL;
1765 g_mutex_unlock (&output->lock);
1769 gst_decklink_acquire_nth_input (gint n, GstElement * src, gboolean is_audio)
1771 GstDecklinkInput *input;
1774 g_once (&devices_once, init_devices, NULL);
1776 if (devices == NULL)
1779 if (n < 0 || (guint) n >= devices->len)
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);
1790 GstDecklinkVideoSrc *videosrc = (GstDecklinkVideoSrc *) (src);
1791 if (gst_decklink_configure_profile (device,
1792 videosrc->profile_id) == PROFILE_SET_FAILURE) {
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);
1804 } else if (!input->videosrc) {
1805 input->videosrc = GST_ELEMENT_CAST (gst_object_ref (src));
1806 g_mutex_unlock (&input->lock);
1810 g_mutex_unlock (&input->lock);
1812 GST_ERROR ("Input device %d (audio: %d) in use already", n, is_audio);
1817 gst_decklink_release_nth_input (gint n, GstElement * src, gboolean is_audio)
1819 GstDecklinkInput *input;
1822 if (devices == NULL)
1825 if (n < 0 || (guint) n >= devices->len)
1828 device = (Device *) g_ptr_array_index (devices, n);
1830 input = &device->input;
1831 g_assert (input->input);
1833 g_mutex_lock (&input->lock);
1835 g_assert (input->audiosrc == src);
1836 gst_object_unref (src);
1837 input->audiosrc = NULL;
1839 g_assert (input->videosrc == src);
1840 gst_object_unref (src);
1841 input->videosrc = NULL;
1843 g_mutex_unlock (&input->lock);
1846 static ProfileSetOperationResult
1847 gst_decklink_configure_profile (Device * device,
1848 GstDecklinkProfileId profile_id)
1852 if (profile_id == GST_DECKLINK_PROFILE_ID_DEFAULT)
1853 return PROFILE_SET_SUCCESS;
1855 GstDecklinkInput *input = &device->input;
1856 IDeckLink *decklink = input->device;
1858 IDeckLinkProfileManager *manager = NULL;
1859 if (decklink->QueryInterface (IID_IDeckLinkProfileManager,
1860 (void **) &manager) == S_OK) {
1861 BMDProfileID bmd_profile_id;
1863 switch (profile_id) {
1864 case GST_DECKLINK_PROFILE_ID_ONE_SUB_DEVICE_FULL_DUPLEX:
1865 bmd_profile_id = bmdProfileOneSubDeviceFullDuplex;
1867 case GST_DECKLINK_PROFILE_ID_ONE_SUB_DEVICE_HALF_DUPLEX:
1868 bmd_profile_id = bmdProfileOneSubDeviceHalfDuplex;
1870 case GST_DECKLINK_PROFILE_ID_TWO_SUB_DEVICES_FULL_DUPLEX:
1871 bmd_profile_id = bmdProfileTwoSubDevicesFullDuplex;
1873 case GST_DECKLINK_PROFILE_ID_TWO_SUB_DEVICES_HALF_DUPLEX:
1874 bmd_profile_id = bmdProfileTwoSubDevicesHalfDuplex;
1876 case GST_DECKLINK_PROFILE_ID_FOUR_SUB_DEVICES_HALF_DUPLEX:
1877 bmd_profile_id = bmdProfileFourSubDevicesHalfDuplex;
1880 case GST_DECKLINK_PROFILE_ID_DEFAULT:
1881 g_assert_not_reached ();
1885 IDeckLinkProfile *profile = NULL;
1886 res = manager->GetProfile (bmd_profile_id, &profile);
1888 if (res == S_OK && profile) {
1889 res = profile->SetActive ();
1890 profile->Release ();
1893 manager->Release ();
1896 GST_DEBUG ("Successfully set profile");
1897 return PROFILE_SET_SUCCESS;
1899 GST_ERROR ("Failed to set profile");
1900 return PROFILE_SET_FAILURE;
1903 GST_DEBUG ("Device has only one profile");
1904 return PROFILE_SET_UNSUPPORTED;
1908 G_DEFINE_TYPE (GstDecklinkClock, gst_decklink_clock, GST_TYPE_SYSTEM_CLOCK);
1910 static GstClockTime gst_decklink_clock_get_internal_time (GstClock * clock);
1913 gst_decklink_clock_class_init (GstDecklinkClockClass * klass)
1915 GstClockClass *clock_class = (GstClockClass *) klass;
1917 clock_class->get_internal_time = gst_decklink_clock_get_internal_time;
1921 gst_decklink_clock_init (GstDecklinkClock * clock)
1923 GST_OBJECT_FLAG_SET (clock, GST_CLOCK_FLAG_CAN_SET_MASTER);
1927 gst_decklink_clock_new (const gchar * name)
1929 GstDecklinkClock *self =
1930 GST_DECKLINK_CLOCK (g_object_new (GST_TYPE_DECKLINK_CLOCK, "name", name,
1931 "clock-type", GST_CLOCK_TYPE_OTHER, NULL));
1933 gst_object_ref_sink (self);
1935 return GST_CLOCK_CAST (self);
1939 gst_decklink_clock_get_internal_time (GstClock * clock)
1941 GstDecklinkClock *self = GST_DECKLINK_CLOCK (clock);
1942 GstClockTime result, start_time, last_time;
1943 GstClockTimeDiff offset;
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;
1952 if (!self->output->started) {
1957 self->output->output->GetHardwareReferenceClock (GST_SECOND, &time,
1959 if (ret == S_OK && time >= 0) {
1962 if (start_time == GST_CLOCK_TIME_NONE)
1963 start_time = self->output->clock_start_time = result;
1965 if (result > start_time)
1966 result -= start_time;
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;
1975 result = MAX (last_time, result);
1977 result = MAX (last_time, result);
1982 self->output->clock_last_time = result;
1984 result += self->output->clock_epoch;
1985 g_mutex_unlock (&self->output->lock);
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);
1998 decklink_element_init (GstPlugin * plugin)
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);
2013 g_once_init_leave (&res, TRUE);