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