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