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