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