Tizen 2.0 Release
[framework/multimedia/gst-plugins-bad0.10.git] / sys / decklink / gstdecklinksrc.cpp
1 /* GStreamer
2  * Copyright (C) 2011 David Schleef <ds@schleef.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
17  * Boston, MA 02110-1335, USA.
18  */
19 /**
20  * SECTION:element-gstdecklinksrc
21  *
22  * The decklinksrc element is a source element for Blackmagic
23  * Decklink cards.
24  *
25  * <refsect2>
26  * <title>Example launch line</title>
27  * |[
28  * gst-launch -v decklinksrc ! xvimagesink
29  * ]|
30  * 
31  * </refsect2>
32  */
33
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37
38 #include <gst/gst.h>
39 #include "gstdecklink.h"
40 #include "gstdecklinksrc.h"
41 #include "capture.h"
42 #include <string.h>
43
44 GST_DEBUG_CATEGORY (gst_decklink_src_debug_category);
45 #define GST_CAT_DEFAULT gst_decklink_src_debug_category
46
47 /* prototypes */
48
49
50 static void gst_decklink_src_set_property (GObject * object,
51     guint property_id, const GValue * value, GParamSpec * pspec);
52 static void gst_decklink_src_get_property (GObject * object,
53     guint property_id, GValue * value, GParamSpec * pspec);
54 static void gst_decklink_src_dispose (GObject * object);
55 static void gst_decklink_src_finalize (GObject * object);
56
57 static GstPad *gst_decklink_src_request_new_pad (GstElement * element,
58     GstPadTemplate * templ, const gchar * name);
59 static void gst_decklink_src_release_pad (GstElement * element, GstPad * pad);
60 static GstStateChangeReturn
61 gst_decklink_src_change_state (GstElement * element, GstStateChange transition);
62 static GstClock *gst_decklink_src_provide_clock (GstElement * element);
63 static gboolean gst_decklink_src_set_clock (GstElement * element,
64     GstClock * clock);
65 static GstIndex *gst_decklink_src_get_index (GstElement * element);
66 static void gst_decklink_src_set_index (GstElement * element, GstIndex * index);
67 static gboolean gst_decklink_src_send_event (GstElement * element,
68     GstEvent * event);
69 static gboolean gst_decklink_src_query (GstElement * element, GstQuery * query);
70
71 static GstCaps *gst_decklink_src_audio_src_getcaps (GstPad * pad);
72 static gboolean gst_decklink_src_audio_src_setcaps (GstPad * pad,
73     GstCaps * caps);
74 static gboolean gst_decklink_src_audio_src_acceptcaps (GstPad * pad,
75     GstCaps * caps);
76 static void gst_decklink_src_audio_src_fixatecaps (GstPad * pad,
77     GstCaps * caps);
78 static gboolean gst_decklink_src_audio_src_activate (GstPad * pad);
79 static gboolean gst_decklink_src_audio_src_activatepush (GstPad * pad,
80     gboolean active);
81 static gboolean gst_decklink_src_audio_src_activatepull (GstPad * pad,
82     gboolean active);
83 static GstPadLinkReturn gst_decklink_src_audio_src_link (GstPad * pad,
84     GstPad * peer);
85 static GstFlowReturn gst_decklink_src_audio_src_getrange (GstPad * pad,
86     guint64 offset, guint length, GstBuffer ** buffer);
87 static gboolean gst_decklink_src_audio_src_event (GstPad * pad,
88     GstEvent * event);
89 static gboolean gst_decklink_src_audio_src_query (GstPad * pad,
90     GstQuery * query);
91 static GstIterator *gst_decklink_src_audio_src_iterintlink (GstPad * pad);
92
93
94 static GstCaps *gst_decklink_src_video_src_getcaps (GstPad * pad);
95 static gboolean gst_decklink_src_video_src_setcaps (GstPad * pad,
96     GstCaps * caps);
97 static gboolean gst_decklink_src_video_src_acceptcaps (GstPad * pad,
98     GstCaps * caps);
99 static void gst_decklink_src_video_src_fixatecaps (GstPad * pad,
100     GstCaps * caps);
101 static gboolean gst_decklink_src_video_src_activate (GstPad * pad);
102 static gboolean gst_decklink_src_video_src_activatepush (GstPad * pad,
103     gboolean active);
104 static gboolean gst_decklink_src_video_src_activatepull (GstPad * pad,
105     gboolean active);
106 static GstPadLinkReturn gst_decklink_src_video_src_link (GstPad * pad,
107     GstPad * peer);
108 static GstFlowReturn gst_decklink_src_video_src_getrange (GstPad * pad,
109     guint64 offset, guint length, GstBuffer ** buffer);
110 static gboolean gst_decklink_src_video_src_event (GstPad * pad,
111     GstEvent * event);
112 static gboolean gst_decklink_src_video_src_query (GstPad * pad,
113     GstQuery * query);
114 static GstIterator *gst_decklink_src_video_src_iterintlink (GstPad * pad);
115
116 static void gst_decklink_src_task (void *priv);
117
118 #ifdef _MSC_VER
119 /* COM initialization/uninitialization thread */
120 static void gst_decklink_src_com_thread (GstDecklinkSrc * src);
121 #endif /* _MSC_VER */
122
123 enum
124 {
125   PROP_0,
126   PROP_MODE,
127   PROP_CONNECTION,
128   PROP_AUDIO_INPUT,
129   PROP_SUBDEVICE
130 };
131
132 /* pad templates */
133
134 static GstStaticPadTemplate gst_decklink_src_audio_src_template =
135 GST_STATIC_PAD_TEMPLATE ("audiosrc",
136     GST_PAD_SRC,
137     GST_PAD_ALWAYS,
138     GST_STATIC_CAPS ("audio/x-raw-int,width=16,depth=16,channels=2,rate=48000")
139     );
140
141 /* the video source pad template is created on the fly */
142
143 /* class initialization */
144
145 #define DEBUG_INIT(bla) \
146   GST_DEBUG_CATEGORY_INIT (gst_decklink_src_debug_category, "decklinksrc", 0, \
147       "debug category for decklinksrc element");
148
149 GST_BOILERPLATE_FULL (GstDecklinkSrc, gst_decklink_src, GstElement,
150     GST_TYPE_ELEMENT, DEBUG_INIT);
151
152 static void
153 gst_decklink_src_base_init (gpointer g_class)
154 {
155   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
156   GstPadTemplate *pad_template;
157
158   gst_element_class_add_static_pad_template (element_class,
159       &gst_decklink_src_audio_src_template);
160   pad_template =
161       gst_pad_template_new ("videosrc", GST_PAD_SRC, GST_PAD_ALWAYS,
162       gst_decklink_mode_get_template_caps ());
163   gst_element_class_add_pad_template (element_class, pad_template);
164   gst_object_unref (pad_template);
165
166   gst_element_class_set_details_simple (element_class, "Decklink source",
167       "Source/Video", "DeckLink Source", "David Schleef <ds@entropywave.com>");
168 }
169
170 static void
171 gst_decklink_src_class_init (GstDecklinkSrcClass * klass)
172 {
173   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
174   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
175
176   gobject_class->set_property = gst_decklink_src_set_property;
177   gobject_class->get_property = gst_decklink_src_get_property;
178   gobject_class->dispose = gst_decklink_src_dispose;
179   gobject_class->finalize = gst_decklink_src_finalize;
180   element_class->request_new_pad =
181       GST_DEBUG_FUNCPTR (gst_decklink_src_request_new_pad);
182   element_class->release_pad = GST_DEBUG_FUNCPTR (gst_decklink_src_release_pad);
183   element_class->change_state =
184       GST_DEBUG_FUNCPTR (gst_decklink_src_change_state);
185   element_class->provide_clock =
186       GST_DEBUG_FUNCPTR (gst_decklink_src_provide_clock);
187   element_class->set_clock = GST_DEBUG_FUNCPTR (gst_decklink_src_set_clock);
188   element_class->get_index = GST_DEBUG_FUNCPTR (gst_decklink_src_get_index);
189   element_class->set_index = GST_DEBUG_FUNCPTR (gst_decklink_src_set_index);
190   element_class->send_event = GST_DEBUG_FUNCPTR (gst_decklink_src_send_event);
191   element_class->query = GST_DEBUG_FUNCPTR (gst_decklink_src_query);
192
193   g_object_class_install_property (gobject_class, PROP_MODE,
194       g_param_spec_enum ("mode", "Mode", "Mode",
195           GST_TYPE_DECKLINK_MODE, GST_DECKLINK_MODE_NTSC,
196           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
197               G_PARAM_CONSTRUCT)));
198
199   g_object_class_install_property (gobject_class, PROP_CONNECTION,
200       g_param_spec_enum ("connection", "Connection", "Connection",
201           GST_TYPE_DECKLINK_CONNECTION, GST_DECKLINK_CONNECTION_SDI,
202           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
203               G_PARAM_CONSTRUCT)));
204
205   g_object_class_install_property (gobject_class, PROP_AUDIO_INPUT,
206       g_param_spec_enum ("audio-input", "Audio Input", "Audio Input Connection",
207           GST_TYPE_DECKLINK_AUDIO_CONNECTION,
208           GST_DECKLINK_AUDIO_CONNECTION_AUTO,
209           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
210               G_PARAM_CONSTRUCT)));
211
212   g_object_class_install_property (gobject_class, PROP_SUBDEVICE,
213       g_param_spec_int ("subdevice", "Subdevice", "Subdevice",
214           0, 3, 0,
215           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
216               G_PARAM_CONSTRUCT)));
217 }
218
219 static void
220 gst_decklink_src_init (GstDecklinkSrc * decklinksrc,
221     GstDecklinkSrcClass * decklinksrc_class)
222 {
223   g_static_rec_mutex_init (&decklinksrc->task_mutex);
224   decklinksrc->task = gst_task_create (gst_decklink_src_task, decklinksrc);
225   gst_task_set_lock (decklinksrc->task, &decklinksrc->task_mutex);
226
227   decklinksrc->audiosrcpad =
228       gst_pad_new_from_static_template (&gst_decklink_src_audio_src_template,
229       "audiosrc");
230   gst_pad_set_getcaps_function (decklinksrc->audiosrcpad,
231       GST_DEBUG_FUNCPTR (gst_decklink_src_audio_src_getcaps));
232   gst_pad_set_setcaps_function (decklinksrc->audiosrcpad,
233       GST_DEBUG_FUNCPTR (gst_decklink_src_audio_src_setcaps));
234   gst_pad_set_acceptcaps_function (decklinksrc->audiosrcpad,
235       GST_DEBUG_FUNCPTR (gst_decklink_src_audio_src_acceptcaps));
236   gst_pad_set_fixatecaps_function (decklinksrc->audiosrcpad,
237       GST_DEBUG_FUNCPTR (gst_decklink_src_audio_src_fixatecaps));
238   gst_pad_set_activate_function (decklinksrc->audiosrcpad,
239       GST_DEBUG_FUNCPTR (gst_decklink_src_audio_src_activate));
240   gst_pad_set_activatepush_function (decklinksrc->audiosrcpad,
241       GST_DEBUG_FUNCPTR (gst_decklink_src_audio_src_activatepush));
242   gst_pad_set_activatepull_function (decklinksrc->audiosrcpad,
243       GST_DEBUG_FUNCPTR (gst_decklink_src_audio_src_activatepull));
244   gst_pad_set_link_function (decklinksrc->audiosrcpad,
245       GST_DEBUG_FUNCPTR (gst_decklink_src_audio_src_link));
246   gst_pad_set_getrange_function (decklinksrc->audiosrcpad,
247       GST_DEBUG_FUNCPTR (gst_decklink_src_audio_src_getrange));
248   gst_pad_set_event_function (decklinksrc->audiosrcpad,
249       GST_DEBUG_FUNCPTR (gst_decklink_src_audio_src_event));
250   gst_pad_set_query_function (decklinksrc->audiosrcpad,
251       GST_DEBUG_FUNCPTR (gst_decklink_src_audio_src_query));
252   gst_pad_set_iterate_internal_links_function (decklinksrc->audiosrcpad,
253       GST_DEBUG_FUNCPTR (gst_decklink_src_audio_src_iterintlink));
254   gst_element_add_pad (GST_ELEMENT (decklinksrc), decklinksrc->audiosrcpad);
255
256
257
258   decklinksrc->videosrcpad =
259       gst_pad_new_from_template (gst_element_class_get_pad_template
260       (GST_ELEMENT_CLASS (decklinksrc_class), "videosrc"), "videosrc");
261   gst_pad_set_getcaps_function (decklinksrc->videosrcpad,
262       GST_DEBUG_FUNCPTR (gst_decklink_src_video_src_getcaps));
263   gst_pad_set_setcaps_function (decklinksrc->videosrcpad,
264       GST_DEBUG_FUNCPTR (gst_decklink_src_video_src_setcaps));
265   gst_pad_set_acceptcaps_function (decklinksrc->videosrcpad,
266       GST_DEBUG_FUNCPTR (gst_decklink_src_video_src_acceptcaps));
267   gst_pad_set_fixatecaps_function (decklinksrc->videosrcpad,
268       GST_DEBUG_FUNCPTR (gst_decklink_src_video_src_fixatecaps));
269   gst_pad_set_activate_function (decklinksrc->videosrcpad,
270       GST_DEBUG_FUNCPTR (gst_decklink_src_video_src_activate));
271   gst_pad_set_activatepush_function (decklinksrc->videosrcpad,
272       GST_DEBUG_FUNCPTR (gst_decklink_src_video_src_activatepush));
273   gst_pad_set_activatepull_function (decklinksrc->videosrcpad,
274       GST_DEBUG_FUNCPTR (gst_decklink_src_video_src_activatepull));
275   gst_pad_set_link_function (decklinksrc->videosrcpad,
276       GST_DEBUG_FUNCPTR (gst_decklink_src_video_src_link));
277   gst_pad_set_getrange_function (decklinksrc->videosrcpad,
278       GST_DEBUG_FUNCPTR (gst_decklink_src_video_src_getrange));
279   gst_pad_set_event_function (decklinksrc->videosrcpad,
280       GST_DEBUG_FUNCPTR (gst_decklink_src_video_src_event));
281   gst_pad_set_query_function (decklinksrc->videosrcpad,
282       GST_DEBUG_FUNCPTR (gst_decklink_src_video_src_query));
283   gst_pad_set_iterate_internal_links_function (decklinksrc->videosrcpad,
284       GST_DEBUG_FUNCPTR (gst_decklink_src_video_src_iterintlink));
285   gst_element_add_pad (GST_ELEMENT (decklinksrc), decklinksrc->videosrcpad);
286
287
288   decklinksrc->cond = g_cond_new ();
289   decklinksrc->mutex = g_mutex_new ();
290
291   decklinksrc->copy_data = TRUE;
292   decklinksrc->mode = GST_DECKLINK_MODE_NTSC;
293   decklinksrc->connection = GST_DECKLINK_CONNECTION_SDI;
294   decklinksrc->audio_connection = GST_DECKLINK_AUDIO_CONNECTION_AUTO;
295   decklinksrc->subdevice = 0;
296
297   decklinksrc->stop = FALSE;
298   decklinksrc->dropped_frames = 0;
299   decklinksrc->dropped_frames_old = 0;
300   decklinksrc->frame_num = -1; /* -1 so will be 0 after incrementing */
301
302 #ifdef _MSC_VER
303   decklinksrc->com_init_lock = g_mutex_new();
304   decklinksrc->com_deinit_lock = g_mutex_new();
305   decklinksrc->com_initialized = g_cond_new();
306   decklinksrc->com_uninitialize = g_cond_new();
307   decklinksrc->com_uninitialized = g_cond_new();
308
309   g_mutex_lock (decklinksrc->com_init_lock);
310
311   /* create the COM initialization thread */
312   g_thread_create ((GThreadFunc)gst_decklink_src_com_thread,
313     decklinksrc, FALSE, NULL);
314
315   /* wait until the COM thread signals that COM has been initialized */
316   g_cond_wait (decklinksrc->com_initialized, decklinksrc->com_init_lock);
317   g_mutex_unlock (decklinksrc->com_init_lock);
318 #endif /* _MSC_VER */
319 }
320
321 void
322 gst_decklink_src_set_property (GObject * object, guint property_id,
323     const GValue * value, GParamSpec * pspec)
324 {
325   GstDecklinkSrc *decklinksrc;
326
327   g_return_if_fail (GST_IS_DECKLINK_SRC (object));
328   decklinksrc = GST_DECKLINK_SRC (object);
329
330   switch (property_id) {
331     case PROP_MODE:
332       decklinksrc->mode = (GstDecklinkModeEnum) g_value_get_enum (value);
333       break;
334     case PROP_CONNECTION:
335       decklinksrc->connection =
336           (GstDecklinkConnectionEnum) g_value_get_enum (value);
337       break;
338     case PROP_AUDIO_INPUT:
339       decklinksrc->audio_connection =
340           (GstDecklinkAudioConnectionEnum) g_value_get_enum (value);
341       break;
342     case PROP_SUBDEVICE:
343       decklinksrc->subdevice = g_value_get_int (value);
344       break;
345     default:
346       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
347       break;
348   }
349 }
350
351 void
352 gst_decklink_src_get_property (GObject * object, guint property_id,
353     GValue * value, GParamSpec * pspec)
354 {
355   GstDecklinkSrc *decklinksrc;
356
357   g_return_if_fail (GST_IS_DECKLINK_SRC (object));
358   decklinksrc = GST_DECKLINK_SRC (object);
359
360   switch (property_id) {
361     case PROP_MODE:
362       g_value_set_enum (value, decklinksrc->mode);
363       break;
364     case PROP_CONNECTION:
365       g_value_set_enum (value, decklinksrc->connection);
366       break;
367     case PROP_AUDIO_INPUT:
368       g_value_set_enum (value, decklinksrc->audio_connection);
369       break;
370     case PROP_SUBDEVICE:
371       g_value_set_int (value, decklinksrc->subdevice);
372       break;
373     default:
374       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
375       break;
376   }
377 }
378
379 #ifdef _MSC_VER
380 static void
381 gst_decklink_src_com_thread (GstDecklinkSrc * src)
382 {
383   HRESULT res;
384
385   g_mutex_lock (src->com_init_lock);
386
387   /* Initialize COM with a MTA for this process. This thread will
388    * be the first one to enter the apartement and the last one to leave
389    * it, unitializing COM properly */
390
391   res = CoInitializeEx (0, COINIT_MULTITHREADED);
392   if (res == S_FALSE)
393     GST_WARNING_OBJECT (src, "COM has been already initialized in the same process");
394   else if (res == RPC_E_CHANGED_MODE)
395     GST_WARNING_OBJECT (src, "The concurrency model of COM has changed.");
396   else
397     GST_INFO_OBJECT (src, "COM intialized succesfully");
398
399   src->comInitialized = TRUE;
400
401   /* Signal other threads waiting on this condition that COM was initialized */
402   g_cond_signal (src->com_initialized);
403
404   g_mutex_unlock (src->com_init_lock);
405
406   /* Wait until the unitialize condition is met to leave the COM apartement */
407   g_mutex_lock (src->com_deinit_lock);
408   g_cond_wait (src->com_uninitialize, src->com_deinit_lock);
409
410   CoUninitialize ();
411   GST_INFO_OBJECT (src, "COM unintialized succesfully");
412   src->comInitialized = FALSE;
413   g_cond_signal (src->com_uninitialized);
414   g_mutex_unlock (src->com_deinit_lock);
415 }
416 #endif /* _MSC_VER */
417
418 void
419 gst_decklink_src_dispose (GObject * object)
420 {
421   g_return_if_fail (GST_IS_DECKLINK_SRC (object));
422
423   /* clean up as possible.  may be called multiple times */
424
425   G_OBJECT_CLASS (parent_class)->dispose (object);
426 }
427
428 void
429 gst_decklink_src_finalize (GObject * object)
430 {
431   GstDecklinkSrc *decklinksrc;
432
433   g_return_if_fail (GST_IS_DECKLINK_SRC (object));
434   decklinksrc = GST_DECKLINK_SRC (object);
435
436   /* clean up object here */
437
438   g_cond_free (decklinksrc->cond);
439   g_mutex_free (decklinksrc->mutex);
440   gst_task_set_lock (decklinksrc->task, NULL);
441   g_object_unref (decklinksrc->task);
442   if (decklinksrc->audio_caps) {
443     gst_caps_unref (decklinksrc->audio_caps);
444   }
445   if (decklinksrc->video_caps) {
446     gst_caps_unref (decklinksrc->video_caps);
447   }
448
449 #ifdef _MSC_VER
450   /* signal the COM thread that it should uninitialize COM */
451   if (decklinksrc->comInitialized) {
452     g_mutex_lock (decklinksrc->com_deinit_lock);
453     g_cond_signal (decklinksrc->com_uninitialize);
454     g_cond_wait (decklinksrc->com_uninitialized, decklinksrc->com_deinit_lock);
455     g_mutex_unlock (decklinksrc->com_deinit_lock);
456   }
457
458   g_mutex_free (decklinksrc->com_init_lock);
459   g_mutex_free (decklinksrc->com_deinit_lock);
460   g_cond_free (decklinksrc->com_initialized);
461   g_cond_free (decklinksrc->com_uninitialize);
462   g_cond_free (decklinksrc->com_uninitialized);
463 #endif /* _MSC_VER */
464
465   G_OBJECT_CLASS (parent_class)->finalize (object);
466 }
467
468
469
470 static GstPad *
471 gst_decklink_src_request_new_pad (GstElement * element, GstPadTemplate * templ,
472     const gchar * name)
473 {
474
475   return NULL;
476 }
477
478 static void
479 gst_decklink_src_release_pad (GstElement * element, GstPad * pad)
480 {
481
482 }
483
484 static gboolean
485 gst_decklink_src_start (GstElement * element)
486 {
487   GstDecklinkSrc *decklinksrc = GST_DECKLINK_SRC (element);
488   IDeckLinkIterator *iterator;
489   DeckLinkCaptureDelegate *delegate;
490   //IDeckLinkDisplayModeIterator *mode_iterator;
491   //IDeckLinkDisplayMode *mode;
492   BMDAudioSampleType sample_depth;
493   int channels;
494   HRESULT ret;
495   const GstDecklinkMode *mode;
496   IDeckLinkConfiguration *config;
497   BMDVideoConnection conn;
498   BMDAudioConnection aconn;
499   int i;
500
501   GST_DEBUG_OBJECT (decklinksrc, "start");
502
503   iterator = CreateDeckLinkIteratorInstance ();
504   if (iterator == NULL) {
505     GST_ERROR ("no driver");
506     return FALSE;
507   }
508
509   ret = iterator->Next (&decklinksrc->decklink);
510   if (ret != S_OK) {
511     GST_ERROR ("no card");
512     return FALSE;
513   }
514   for (i = 0; i < decklinksrc->subdevice; i++) {
515     ret = iterator->Next (&decklinksrc->decklink);
516     if (ret != S_OK) {
517       GST_ERROR ("no card");
518       return FALSE;
519     }
520   }
521
522   ret = decklinksrc->decklink->QueryInterface (IID_IDeckLinkInput,
523       (void **) &decklinksrc->input);
524   if (ret != S_OK) {
525     GST_ERROR ("query interface failed");
526     return FALSE;
527   }
528
529   delegate = new DeckLinkCaptureDelegate ();
530   delegate->priv = decklinksrc;
531   decklinksrc->input->SetCallback (delegate);
532
533   ret = decklinksrc->decklink->QueryInterface (IID_IDeckLinkConfiguration,
534       (void **) &config);
535   if (ret != S_OK) {
536     GST_ERROR ("query interface failed");
537     return FALSE;
538   }
539
540   switch (decklinksrc->connection) {
541     default:
542     case GST_DECKLINK_CONNECTION_SDI:
543       conn = bmdVideoConnectionSDI;
544       aconn = bmdAudioConnectionEmbedded;
545       break;
546     case GST_DECKLINK_CONNECTION_HDMI:
547       conn = bmdVideoConnectionHDMI;
548       aconn = bmdAudioConnectionEmbedded;
549       break;
550     case GST_DECKLINK_CONNECTION_OPTICAL_SDI:
551       conn = bmdVideoConnectionOpticalSDI;
552       aconn = bmdAudioConnectionEmbedded;
553       break;
554     case GST_DECKLINK_CONNECTION_COMPONENT:
555       conn = bmdVideoConnectionComponent;
556       aconn = bmdAudioConnectionAnalog;
557       break;
558     case GST_DECKLINK_CONNECTION_COMPOSITE:
559       conn = bmdVideoConnectionComposite;
560       aconn = bmdAudioConnectionAnalog;
561       break;
562     case GST_DECKLINK_CONNECTION_SVIDEO:
563       conn = bmdVideoConnectionSVideo;
564       aconn = bmdAudioConnectionAnalog;
565       break;
566   }
567
568   ret = config->SetInt (bmdDeckLinkConfigVideoInputConnection, conn);
569   if (ret != S_OK) {
570     GST_ERROR ("set configuration (input source)");
571     return FALSE;
572   }
573
574   if (decklinksrc->connection == GST_DECKLINK_CONNECTION_COMPOSITE) {
575     ret = config->SetInt (bmdDeckLinkConfigAnalogVideoInputFlags,
576         bmdAnalogVideoFlagCompositeSetup75);
577     if (ret != S_OK) {
578       GST_ERROR ("set configuration (composite setup)");
579       return FALSE;
580     }
581   }
582
583   switch (decklinksrc->audio_connection) {
584     default:
585     case GST_DECKLINK_AUDIO_CONNECTION_AUTO:
586       break;
587     case GST_DECKLINK_AUDIO_CONNECTION_EMBEDDED:
588       aconn = bmdAudioConnectionEmbedded;
589       break;
590     case GST_DECKLINK_AUDIO_CONNECTION_AES_EBU:
591       aconn = bmdAudioConnectionAESEBU;
592       break;
593     case GST_DECKLINK_AUDIO_CONNECTION_ANALOG:
594       aconn = bmdAudioConnectionAnalog;
595       break;
596   }
597   ret = config->SetInt (bmdDeckLinkConfigAudioInputConnection, aconn);
598   if (ret != S_OK) {
599     GST_ERROR ("set configuration (audio input connection)");
600     return FALSE;
601   }
602 #if 0
603   ret = decklinksrc->input->GetDisplayModeIterator (&mode_iterator);
604   if (ret != S_OK) {
605     GST_ERROR ("failed to get display mode iterator");
606     return FALSE;
607   }
608
609   i = 0;
610   while (mode_iterator->Next (&mode) == S_OK) {
611     const char *mode_name;
612
613     mode->GetName (&mode_name);
614
615     GST_DEBUG ("%d: mode name: %s", i, mode_name);
616
617     mode->Release ();
618     i++;
619   }
620 #endif
621
622   mode = gst_decklink_get_mode (decklinksrc->mode);
623
624   ret = decklinksrc->input->EnableVideoInput (mode->mode, bmdFormat8BitYUV, 0);
625   if (ret != S_OK) {
626     GST_ERROR ("enable video input failed");
627     return FALSE;
628   }
629
630   sample_depth = bmdAudioSampleType16bitInteger;
631   channels = 2;
632   ret = decklinksrc->input->EnableAudioInput (bmdAudioSampleRate48kHz,
633       sample_depth, channels);
634   if (ret != S_OK) {
635     GST_ERROR ("enable video input failed");
636     return FALSE;
637   }
638
639   ret = decklinksrc->input->StartStreams ();
640   if (ret != S_OK) {
641     GST_ERROR ("start streams failed");
642     return FALSE;
643   }
644
645   g_static_rec_mutex_lock (&decklinksrc->task_mutex);
646   gst_task_start (decklinksrc->task);
647   g_static_rec_mutex_unlock (&decklinksrc->task_mutex);
648
649   return TRUE;
650 }
651
652 static gboolean
653 gst_decklink_src_stop (GstElement * element)
654 {
655   GstDecklinkSrc *decklinksrc = GST_DECKLINK_SRC (element);
656
657   gst_task_stop (decklinksrc->task);
658
659   g_mutex_lock (decklinksrc->mutex);
660   decklinksrc->stop = TRUE;
661   g_cond_signal (decklinksrc->cond);
662   g_mutex_unlock (decklinksrc->mutex);
663
664   gst_task_join (decklinksrc->task);
665
666   decklinksrc->input->StopStreams ();
667   decklinksrc->input->DisableVideoInput ();
668   decklinksrc->input->DisableAudioInput ();
669
670   decklinksrc->input->Release ();
671   decklinksrc->input = NULL;
672
673   return TRUE;
674 }
675
676 static GstStateChangeReturn
677 gst_decklink_src_change_state (GstElement * element, GstStateChange transition)
678 {
679   GstStateChangeReturn ret;
680   gboolean no_preroll = FALSE;
681
682   g_return_val_if_fail (GST_IS_DECKLINK_SRC (element),
683       GST_STATE_CHANGE_FAILURE);
684
685   switch (transition) {
686     case GST_STATE_CHANGE_NULL_TO_READY:
687       if (!gst_decklink_src_start (element)) {
688         ret = GST_STATE_CHANGE_FAILURE;
689         goto out;
690       }
691       break;
692     case GST_STATE_CHANGE_READY_TO_PAUSED:
693       no_preroll = TRUE;
694       break;
695     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
696       break;
697     default:
698       break;
699   }
700
701   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
702
703   switch (transition) {
704     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
705       no_preroll = TRUE;
706       break;
707     case GST_STATE_CHANGE_PAUSED_TO_READY:
708       break;
709     case GST_STATE_CHANGE_READY_TO_NULL:
710       gst_decklink_src_stop (element);
711       break;
712     default:
713       break;
714   }
715
716   if (no_preroll && ret == GST_STATE_CHANGE_SUCCESS)
717     ret = GST_STATE_CHANGE_NO_PREROLL;
718
719 out:
720   return ret;
721 }
722
723 static GstClock *
724 gst_decklink_src_provide_clock (GstElement * element)
725 {
726
727   return NULL;
728 }
729
730 static gboolean
731 gst_decklink_src_set_clock (GstElement * element, GstClock * clock)
732 {
733
734   return TRUE;
735 }
736
737 static GstIndex *
738 gst_decklink_src_get_index (GstElement * element)
739 {
740
741   return NULL;
742 }
743
744 static void
745 gst_decklink_src_set_index (GstElement * element, GstIndex * index)
746 {
747
748 }
749
750 static gboolean
751 gst_decklink_src_send_event (GstElement * element, GstEvent * event)
752 {
753
754   return TRUE;
755 }
756
757 static gboolean
758 gst_decklink_src_query (GstElement * element, GstQuery * query)
759 {
760
761   return FALSE;
762 }
763
764 static GstCaps *
765 gst_decklink_src_audio_src_getcaps (GstPad * pad)
766 {
767   GstDecklinkSrc *decklinksrc;
768   GstCaps *caps;
769
770   decklinksrc = GST_DECKLINK_SRC (gst_pad_get_parent (pad));
771
772   GST_DEBUG_OBJECT (decklinksrc, "getcaps");
773
774   caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
775
776   gst_object_unref (decklinksrc);
777   return caps;
778 }
779
780 static gboolean
781 gst_decklink_src_audio_src_setcaps (GstPad * pad, GstCaps * caps)
782 {
783   GstDecklinkSrc *decklinksrc;
784
785   decklinksrc = GST_DECKLINK_SRC (gst_pad_get_parent (pad));
786
787   GST_DEBUG_OBJECT (decklinksrc, "setcaps");
788
789
790   gst_object_unref (decklinksrc);
791   return TRUE;
792 }
793
794 static gboolean
795 gst_decklink_src_audio_src_acceptcaps (GstPad * pad, GstCaps * caps)
796 {
797   GstDecklinkSrc *decklinksrc;
798
799   decklinksrc = GST_DECKLINK_SRC (gst_pad_get_parent (pad));
800
801   GST_DEBUG_OBJECT (decklinksrc, "acceptcaps");
802
803
804   gst_object_unref (decklinksrc);
805   return TRUE;
806 }
807
808 static void
809 gst_decklink_src_audio_src_fixatecaps (GstPad * pad, GstCaps * caps)
810 {
811   GstDecklinkSrc *decklinksrc;
812
813   decklinksrc = GST_DECKLINK_SRC (gst_pad_get_parent (pad));
814
815   GST_DEBUG_OBJECT (decklinksrc, "fixatecaps");
816
817
818   gst_object_unref (decklinksrc);
819 }
820
821 static gboolean
822 gst_decklink_src_audio_src_activate (GstPad * pad)
823 {
824   GstDecklinkSrc *decklinksrc;
825   gboolean ret;
826
827   decklinksrc = GST_DECKLINK_SRC (gst_pad_get_parent (pad));
828
829   GST_DEBUG_OBJECT (decklinksrc, "activate");
830
831   if (gst_pad_check_pull_range (pad)) {
832     GST_DEBUG_OBJECT (pad, "activating pull");
833     ret = gst_pad_activate_pull (pad, TRUE);
834   } else {
835     GST_DEBUG_OBJECT (pad, "activating push");
836     ret = gst_pad_activate_push (pad, TRUE);
837   }
838
839   gst_object_unref (decklinksrc);
840   return ret;
841 }
842
843 static gboolean
844 gst_decklink_src_audio_src_activatepush (GstPad * pad, gboolean active)
845 {
846   GstDecklinkSrc *decklinksrc;
847
848   decklinksrc = GST_DECKLINK_SRC (gst_pad_get_parent (pad));
849
850   GST_DEBUG_OBJECT (decklinksrc, "activatepush");
851
852
853   gst_object_unref (decklinksrc);
854   return TRUE;
855 }
856
857 static gboolean
858 gst_decklink_src_audio_src_activatepull (GstPad * pad, gboolean active)
859 {
860   GstDecklinkSrc *decklinksrc;
861
862   decklinksrc = GST_DECKLINK_SRC (gst_pad_get_parent (pad));
863
864   GST_DEBUG_OBJECT (decklinksrc, "activatepull");
865
866
867   gst_object_unref (decklinksrc);
868   return TRUE;
869 }
870
871 static GstPadLinkReturn
872 gst_decklink_src_audio_src_link (GstPad * pad, GstPad * peer)
873 {
874   GstDecklinkSrc *decklinksrc;
875
876   decklinksrc = GST_DECKLINK_SRC (gst_pad_get_parent (pad));
877
878   GST_DEBUG_OBJECT (decklinksrc, "link");
879
880
881   gst_object_unref (decklinksrc);
882   return GST_PAD_LINK_OK;
883 }
884
885 static GstFlowReturn
886 gst_decklink_src_audio_src_getrange (GstPad * pad, guint64 offset, guint length,
887     GstBuffer ** buffer)
888 {
889   GstDecklinkSrc *decklinksrc;
890
891   decklinksrc = GST_DECKLINK_SRC (gst_pad_get_parent (pad));
892
893   GST_DEBUG_OBJECT (decklinksrc, "getrange");
894
895
896   gst_object_unref (decklinksrc);
897   return GST_FLOW_OK;
898 }
899
900 static gboolean
901 gst_decklink_src_audio_src_event (GstPad * pad, GstEvent * event)
902 {
903   gboolean res;
904   GstDecklinkSrc *decklinksrc;
905
906   decklinksrc = GST_DECKLINK_SRC (gst_pad_get_parent (pad));
907
908   GST_DEBUG_OBJECT (decklinksrc, "event");
909
910   switch (GST_EVENT_TYPE (event)) {
911     default:
912       res = gst_pad_event_default (pad, event);
913       break;
914   }
915
916   gst_object_unref (decklinksrc);
917   return res;
918 }
919
920 static gboolean
921 gst_decklink_src_audio_src_query (GstPad * pad, GstQuery * query)
922 {
923   gboolean res;
924   GstDecklinkSrc *decklinksrc;
925
926   decklinksrc = GST_DECKLINK_SRC (gst_pad_get_parent (pad));
927
928   GST_DEBUG_OBJECT (decklinksrc, "query");
929
930   switch (GST_QUERY_TYPE (query)) {
931     default:
932       res = gst_pad_query_default (pad, query);
933       break;
934   }
935
936   gst_object_unref (decklinksrc);
937   return res;
938 }
939
940 static GstIterator *
941 gst_decklink_src_audio_src_iterintlink (GstPad * pad)
942 {
943   GstDecklinkSrc *decklinksrc;
944   GstIterator *iter;
945
946   decklinksrc = GST_DECKLINK_SRC (gst_pad_get_parent (pad));
947
948   GST_DEBUG_OBJECT (decklinksrc, "iterintlink");
949
950   iter = gst_pad_iterate_internal_links_default (pad);
951
952   gst_object_unref (decklinksrc);
953   return iter;
954 }
955
956
957 static GstCaps *
958 gst_decklink_src_video_src_getcaps (GstPad * pad)
959 {
960   GstDecklinkSrc *decklinksrc;
961   GstCaps *caps;
962
963   decklinksrc = GST_DECKLINK_SRC (gst_pad_get_parent (pad));
964
965   GST_DEBUG_OBJECT (decklinksrc, "getcaps");
966
967   caps = gst_decklink_mode_get_caps (decklinksrc->mode);
968
969   gst_object_unref (decklinksrc);
970   return caps;
971 }
972
973 static gboolean
974 gst_decklink_src_video_src_setcaps (GstPad * pad, GstCaps * caps)
975 {
976   GstDecklinkSrc *decklinksrc;
977
978   decklinksrc = GST_DECKLINK_SRC (gst_pad_get_parent (pad));
979
980   GST_DEBUG_OBJECT (decklinksrc, "setcaps");
981
982
983   gst_object_unref (decklinksrc);
984   return TRUE;
985 }
986
987 static gboolean
988 gst_decklink_src_video_src_acceptcaps (GstPad * pad, GstCaps * caps)
989 {
990   GstDecklinkSrc *decklinksrc;
991
992   decklinksrc = GST_DECKLINK_SRC (gst_pad_get_parent (pad));
993
994   GST_DEBUG_OBJECT (decklinksrc, "acceptcaps");
995
996
997   gst_object_unref (decklinksrc);
998   return TRUE;
999 }
1000
1001 static void
1002 gst_decklink_src_video_src_fixatecaps (GstPad * pad, GstCaps * caps)
1003 {
1004   GstDecklinkSrc *decklinksrc;
1005
1006   decklinksrc = GST_DECKLINK_SRC (gst_pad_get_parent (pad));
1007
1008   GST_DEBUG_OBJECT (decklinksrc, "fixatecaps");
1009
1010
1011   gst_object_unref (decklinksrc);
1012 }
1013
1014 static gboolean
1015 gst_decklink_src_video_src_activate (GstPad * pad)
1016 {
1017   GstDecklinkSrc *decklinksrc;
1018   gboolean ret;
1019
1020   decklinksrc = GST_DECKLINK_SRC (gst_pad_get_parent (pad));
1021
1022   GST_DEBUG_OBJECT (decklinksrc, "activate");
1023
1024   if (gst_pad_check_pull_range (pad)) {
1025     GST_DEBUG_OBJECT (pad, "activating pull");
1026     ret = gst_pad_activate_pull (pad, TRUE);
1027   } else {
1028     GST_DEBUG_OBJECT (pad, "activating push");
1029     ret = gst_pad_activate_push (pad, TRUE);
1030   }
1031
1032   gst_object_unref (decklinksrc);
1033   return ret;
1034 }
1035
1036 static gboolean
1037 gst_decklink_src_video_src_activatepush (GstPad * pad, gboolean active)
1038 {
1039   GstDecklinkSrc *decklinksrc;
1040
1041   decklinksrc = GST_DECKLINK_SRC (gst_pad_get_parent (pad));
1042
1043   GST_DEBUG_OBJECT (decklinksrc, "activatepush");
1044
1045
1046   gst_object_unref (decklinksrc);
1047   return TRUE;
1048 }
1049
1050 static gboolean
1051 gst_decklink_src_video_src_activatepull (GstPad * pad, gboolean active)
1052 {
1053   GstDecklinkSrc *decklinksrc;
1054
1055   decklinksrc = GST_DECKLINK_SRC (gst_pad_get_parent (pad));
1056
1057   GST_DEBUG_OBJECT (decklinksrc, "activatepull");
1058
1059
1060   gst_object_unref (decklinksrc);
1061   return TRUE;
1062 }
1063
1064 static GstPadLinkReturn
1065 gst_decklink_src_video_src_link (GstPad * pad, GstPad * peer)
1066 {
1067   GstDecklinkSrc *decklinksrc;
1068
1069   decklinksrc = GST_DECKLINK_SRC (gst_pad_get_parent (pad));
1070
1071   GST_DEBUG_OBJECT (decklinksrc, "link");
1072
1073
1074   gst_object_unref (decklinksrc);
1075   return GST_PAD_LINK_OK;
1076 }
1077
1078 static GstFlowReturn
1079 gst_decklink_src_video_src_getrange (GstPad * pad, guint64 offset, guint length,
1080     GstBuffer ** buffer)
1081 {
1082   GstDecklinkSrc *decklinksrc;
1083
1084   decklinksrc = GST_DECKLINK_SRC (gst_pad_get_parent (pad));
1085
1086   GST_DEBUG_OBJECT (decklinksrc, "getrange");
1087
1088
1089   gst_object_unref (decklinksrc);
1090   return GST_FLOW_OK;
1091 }
1092
1093 static gboolean
1094 gst_decklink_src_video_src_event (GstPad * pad, GstEvent * event)
1095 {
1096   gboolean res;
1097   GstDecklinkSrc *decklinksrc;
1098
1099   decklinksrc = GST_DECKLINK_SRC (gst_pad_get_parent (pad));
1100
1101   GST_DEBUG_OBJECT (decklinksrc, "event");
1102
1103   switch (GST_EVENT_TYPE (event)) {
1104     default:
1105       res = gst_pad_event_default (pad, event);
1106       break;
1107   }
1108
1109   gst_object_unref (decklinksrc);
1110   return res;
1111 }
1112
1113 static gboolean
1114 gst_decklink_src_video_src_query (GstPad * pad, GstQuery * query)
1115 {
1116   gboolean res;
1117   GstDecklinkSrc *decklinksrc;
1118
1119   decklinksrc = GST_DECKLINK_SRC (gst_pad_get_parent (pad));
1120
1121   GST_DEBUG_OBJECT (decklinksrc, "query");
1122
1123   switch (GST_QUERY_TYPE (query)) {
1124     default:
1125       res = gst_pad_query_default (pad, query);
1126       break;
1127   }
1128
1129   gst_object_unref (decklinksrc);
1130   return res;
1131 }
1132
1133 static GstIterator *
1134 gst_decklink_src_video_src_iterintlink (GstPad * pad)
1135 {
1136   GstDecklinkSrc *decklinksrc;
1137   GstIterator *iter;
1138
1139   decklinksrc = GST_DECKLINK_SRC (gst_pad_get_parent (pad));
1140
1141   GST_DEBUG_OBJECT (decklinksrc, "iterintlink");
1142
1143   iter = gst_pad_iterate_internal_links_default (pad);
1144
1145   gst_object_unref (decklinksrc);
1146   return iter;
1147 }
1148
1149
1150 static void
1151 video_frame_free (void *data)
1152 {
1153   IDeckLinkVideoInputFrame *video_frame = (IDeckLinkVideoInputFrame *) data;
1154
1155   video_frame->Release ();
1156 }
1157
1158 static void
1159 gst_decklink_src_task (void *priv)
1160 {
1161   GstDecklinkSrc *decklinksrc = GST_DECKLINK_SRC (priv);
1162   GstBuffer *buffer;
1163   GstBuffer *audio_buffer;
1164   IDeckLinkVideoInputFrame *video_frame;
1165   IDeckLinkAudioInputPacket *audio_frame;
1166   void *data;
1167   int n_samples;
1168   GstFlowReturn ret;
1169   const GstDecklinkMode *mode;
1170
1171   GST_DEBUG_OBJECT (decklinksrc, "task");
1172
1173   g_mutex_lock (decklinksrc->mutex);
1174   while (decklinksrc->video_frame == NULL && !decklinksrc->stop) {
1175     g_cond_wait (decklinksrc->cond, decklinksrc->mutex);
1176   }
1177   video_frame = decklinksrc->video_frame;
1178   audio_frame = decklinksrc->audio_frame;
1179   decklinksrc->video_frame = NULL;
1180   decklinksrc->audio_frame = NULL;
1181   g_mutex_unlock (decklinksrc->mutex);
1182
1183   if (decklinksrc->stop) {
1184     GST_DEBUG ("stopping task");
1185     return;
1186   }
1187
1188   /* warning on dropped frames */
1189   if (decklinksrc->dropped_frames - decklinksrc->dropped_frames_old > 0) {
1190     GST_ELEMENT_WARNING (decklinksrc, RESOURCE, READ,
1191                          ("Dropped %d frame(s), for a total of %d frame(s)",
1192                           decklinksrc->dropped_frames - decklinksrc->dropped_frames_old,
1193                           decklinksrc->dropped_frames),
1194                          (NULL));
1195     decklinksrc->dropped_frames_old = decklinksrc->dropped_frames;
1196   }
1197
1198   mode = gst_decklink_get_mode (decklinksrc->mode);
1199
1200   video_frame->GetBytes (&data);
1201   if (decklinksrc->copy_data) {
1202     buffer = gst_buffer_new_and_alloc (mode->width * mode->height * 2);
1203
1204     memcpy (GST_BUFFER_DATA (buffer), data, mode->width * mode->height * 2);
1205
1206     video_frame->Release ();
1207   } else {
1208     buffer = gst_buffer_new ();
1209     GST_BUFFER_SIZE (buffer) = mode->width * mode->height * 2;
1210
1211     GST_BUFFER_DATA (buffer) = (guint8 *) data;
1212
1213     GST_BUFFER_FREE_FUNC (buffer) = video_frame_free;
1214     GST_BUFFER_MALLOCDATA (buffer) = (guint8 *) video_frame;
1215   }
1216
1217   GST_BUFFER_TIMESTAMP (buffer) =
1218       gst_util_uint64_scale_int (decklinksrc->frame_num * GST_SECOND,
1219       mode->fps_d, mode->fps_n);
1220   GST_BUFFER_DURATION (buffer) =
1221       gst_util_uint64_scale_int ((decklinksrc->frame_num + 1) * GST_SECOND,
1222       mode->fps_d, mode->fps_n) - GST_BUFFER_TIMESTAMP (buffer);
1223   GST_BUFFER_OFFSET (buffer) = decklinksrc->frame_num;
1224   GST_BUFFER_OFFSET_END (buffer) = decklinksrc->frame_num;
1225   if (decklinksrc->frame_num == 0) {
1226     GstEvent *event;
1227     gboolean ret;
1228
1229     GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
1230
1231     event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0,
1232         GST_CLOCK_TIME_NONE, 0);
1233
1234     ret = gst_pad_push_event (decklinksrc->videosrcpad, event);
1235     if (!ret) {
1236       GST_ERROR_OBJECT (decklinksrc, "new segment event ret=%d", ret);
1237       return;
1238     }
1239   }
1240
1241   if (decklinksrc->video_caps == NULL) {
1242     decklinksrc->video_caps = gst_decklink_mode_get_caps (decklinksrc->mode);
1243   }
1244   gst_buffer_set_caps (buffer, decklinksrc->video_caps);
1245
1246   ret = gst_pad_push (decklinksrc->videosrcpad, buffer);
1247   if (ret != GST_FLOW_OK) {
1248     GST_ELEMENT_ERROR (decklinksrc, CORE, NEGOTIATION, (NULL), (NULL));
1249   }
1250
1251   if (gst_pad_is_linked (decklinksrc->audiosrcpad)) {
1252     n_samples = audio_frame->GetSampleFrameCount ();
1253     audio_frame->GetBytes (&data);
1254     audio_buffer = gst_buffer_new_and_alloc (n_samples * 2 * 2);
1255     memcpy (GST_BUFFER_DATA (audio_buffer), data, n_samples * 2 * 2);
1256
1257     GST_BUFFER_TIMESTAMP (audio_buffer) =
1258         gst_util_uint64_scale_int (decklinksrc->num_audio_samples * GST_SECOND,
1259         1, 48000);
1260     GST_BUFFER_DURATION (audio_buffer) =
1261         gst_util_uint64_scale_int ((decklinksrc->num_audio_samples +
1262             n_samples) * GST_SECOND, 1,
1263         48000) - GST_BUFFER_TIMESTAMP (audio_buffer);
1264     decklinksrc->num_audio_samples += n_samples;
1265
1266     if (decklinksrc->audio_caps == NULL) {
1267       decklinksrc->audio_caps = gst_caps_new_simple ("audio/x-raw-int",
1268           "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
1269           "signed", G_TYPE_BOOLEAN, TRUE,
1270           "depth", G_TYPE_INT, 16,
1271           "width", G_TYPE_INT, 16,
1272           "channels", G_TYPE_INT, 2, "rate", G_TYPE_INT, 48000, NULL);
1273     }
1274     gst_buffer_set_caps (audio_buffer, decklinksrc->audio_caps);
1275
1276     ret = gst_pad_push (decklinksrc->audiosrcpad, audio_buffer);
1277     if (ret != GST_FLOW_OK) {
1278       GST_ELEMENT_ERROR (decklinksrc, CORE, NEGOTIATION, (NULL), (NULL));
1279     }
1280   }
1281   audio_frame->Release ();
1282 }