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