1 /*****************************************************************************
2 * decklink.cpp: BlackMagic DeckLink SDI output module
3 *****************************************************************************
4 * Copyright (C) 2012-2013 Rafaël Carré
5 * Copyright (C) 2009 Michael Niedermayer <michaelni@gmx.at>
6 * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
8 * Authors: Rafaël Carré <funman@videolan.org>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
26 * TODO: test non stereo audio
29 #define __STDC_FORMAT_MACROS
30 #define __STDC_CONSTANT_MACROS
38 #include <vlc_common.h>
39 #include <vlc_plugin.h>
40 #include <vlc_threads.h>
42 #include <vlc_vout_display.h>
43 #include <vlc_picture_pool.h>
45 #include <vlc_block.h>
46 #include <vlc_atomic.h>
48 #include <arpa/inet.h>
50 #include <DeckLinkAPI.h>
51 #include <DeckLinkAPIDispatch.cpp>
53 #define FRAME_SIZE 1920
54 #define CHANNELS_MAX 6
57 static const int pi_channels_maps[CHANNELS_MAX+1] =
69 #define CARD_INDEX_TEXT N_("Output card")
70 #define CARD_INDEX_LONGTEXT N_(\
71 "DeckLink output card, if multiple exist. " \
72 "The cards are numbered from 0.")
74 #define MODE_TEXT N_("Desired output mode")
75 #define MODE_LONGTEXT N_(\
76 "Desired output mode for DeckLink output. " \
77 "This value should be a FOURCC code in textual " \
78 "form, e.g. \"ntsc\".")
80 #define AUDIO_CONNECTION_TEXT N_("Audio connection")
81 #define AUDIO_CONNECTION_LONGTEXT N_(\
82 "Audio connection for DeckLink output.")
85 #define RATE_TEXT N_("Audio samplerate (Hz)")
86 #define RATE_LONGTEXT N_(\
87 "Audio sampling rate (in hertz) for DeckLink output. " \
88 "0 disables audio output.")
90 #define CHANNELS_TEXT N_("Number of audio channels")
91 #define CHANNELS_LONGTEXT N_(\
92 "Number of output channels for DeckLink output. " \
93 "Must be 2, 8 or 16. 0 disables audio output.")
95 #define VIDEO_CONNECTION_TEXT N_("Video connection")
96 #define VIDEO_CONNECTION_LONGTEXT N_(\
97 "Video connection for DeckLink output.")
99 #define VIDEO_TENBITS_TEXT N_("10 bits")
100 #define VIDEO_TENBITS_LONGTEXT N_(\
101 "Use 10 bits per pixel for video frames.")
103 #define CFG_PREFIX "decklink-output-"
104 #define VIDEO_CFG_PREFIX "decklink-vout-"
105 #define AUDIO_CFG_PREFIX "decklink-aout-"
109 static const char *const ppsz_videoconns[] = {
110 "sdi", "hdmi", "opticalsdi", "component", "composite", "svideo"
112 static const char *const ppsz_videoconns_text[] = {
113 N_("SDI"), N_("HDMI"), N_("Optical SDI"), N_("Component"), N_("Composite"), N_("S-video")
116 static const char *const ppsz_audioconns[] = {
117 "embedded", "aesebu", "analog"
119 static const char *const ppsz_audioconns_text[] = {
120 N_("Embedded"), N_("AES/EBU"), N_("Analog")
124 struct vout_display_sys_t
126 picture_pool_t *pool;
130 /* Only one audio output module and one video output module
131 * can be used per process.
132 * We use a static mutex in audio/video submodules entry points. */
133 struct decklink_sys_t
135 IDeckLinkOutput *p_output;
138 * Synchronizes aout and vout modules:
139 * vout module waits until aout has been initialized.
140 * That means video-only output is NOT supported.
145 BMDAudioConnection aconn;
153 BMDTimeScale timescale;
154 BMDTimeValue frameduration;
156 /* XXX: workaround card clock drift */
160 /*****************************************************************************
162 *****************************************************************************/
164 static int OpenVideo (vlc_object_t *);
165 static void CloseVideo (vlc_object_t *);
166 static int OpenAudio (vlc_object_t *);
167 static void CloseAudio (vlc_object_t *);
169 /*****************************************************************************
171 *****************************************************************************/
174 set_shortname(N_("DecklinkOutput"))
175 set_description(N_("output module to write to Blackmagic SDI card"))
176 set_section(N_("Decklink General Options"), NULL)
177 add_integer(CFG_PREFIX "card-index", 0,
178 CARD_INDEX_TEXT, CARD_INDEX_LONGTEXT, true)
181 set_description (N_("Decklink Video Output module"))
182 set_category(CAT_VIDEO)
183 set_subcategory(SUBCAT_VIDEO_VOUT)
184 set_capability("vout display", 0)
185 set_callbacks (OpenVideo, CloseVideo)
186 set_section(N_("Decklink Video Options"), NULL)
187 add_string(VIDEO_CFG_PREFIX "video-connection", "sdi",
188 VIDEO_CONNECTION_TEXT, VIDEO_CONNECTION_LONGTEXT, true)
189 change_string_list(ppsz_videoconns, ppsz_videoconns_text)
190 add_string(VIDEO_CFG_PREFIX "mode", "pal ",
191 MODE_TEXT, MODE_LONGTEXT, true)
192 add_bool(VIDEO_CFG_PREFIX "tenbits", false,
193 VIDEO_TENBITS_TEXT, VIDEO_TENBITS_LONGTEXT, true)
197 set_description (N_("Decklink Audio Output module"))
198 set_category(CAT_AUDIO)
199 set_subcategory(SUBCAT_AUDIO_AOUT)
200 set_capability("audio output", 0)
201 set_callbacks (OpenAudio, CloseAudio)
202 set_section(N_("Decklink Audio Options"), NULL)
203 add_string(AUDIO_CFG_PREFIX "audio-connection", "embedded",
204 AUDIO_CONNECTION_TEXT, AUDIO_CONNECTION_LONGTEXT, true)
205 change_string_list(ppsz_audioconns, ppsz_audioconns_text)
206 add_integer(AUDIO_CFG_PREFIX "audio-rate", 48000,
207 RATE_TEXT, RATE_LONGTEXT, true)
208 add_integer(AUDIO_CFG_PREFIX "audio-channels", 2,
209 CHANNELS_TEXT, CHANNELS_LONGTEXT, true)
212 /* Protects decklink_sys_t creation/deletion */
213 static vlc_mutex_t sys_lock = VLC_STATIC_MUTEX;
215 static struct decklink_sys_t *GetDLSys(vlc_object_t *obj)
217 vlc_object_t *libvlc = VLC_OBJECT(obj->p_libvlc);
218 struct decklink_sys_t *sys;
220 vlc_mutex_lock(&sys_lock);
222 if (var_Type(libvlc, "decklink-sys") == VLC_VAR_ADDRESS)
223 sys = (struct decklink_sys_t*)var_GetAddress(libvlc, "decklink-sys");
225 sys = (struct decklink_sys_t*)malloc(sizeof(*sys));
227 sys->p_output = NULL;
231 vlc_mutex_init(&sys->lock);
232 vlc_cond_init(&sys->cond);
233 var_Create(libvlc, "decklink-sys", VLC_VAR_ADDRESS);
234 var_SetAddress(libvlc, "decklink-sys", (void*)sys);
238 vlc_mutex_unlock(&sys_lock);
242 static void ReleaseDLSys(vlc_object_t *obj)
244 vlc_object_t *libvlc = VLC_OBJECT(obj->p_libvlc);
246 vlc_mutex_lock(&sys_lock);
248 struct decklink_sys_t *sys = (struct decklink_sys_t*)var_GetAddress(libvlc, "decklink-sys");
250 if (--sys->users == 0) {
251 msg_Dbg(obj, "Destroying decklink data");
252 vlc_mutex_destroy(&sys->lock);
253 vlc_cond_destroy(&sys->cond);
256 sys->p_output->StopScheduledPlayback(0, NULL, 0);
257 sys->p_output->DisableVideoOutput();
258 sys->p_output->DisableAudioOutput();
259 sys->p_output->Release();
263 var_Destroy(libvlc, "decklink-sys");
266 vlc_mutex_unlock(&sys_lock);
270 static BMDAudioConnection getAConn(audio_output_t *aout)
272 BMDAudioConnection conn = bmdAudioConnectionEmbedded;
273 char *psz = var_InheritString(aout, AUDIO_CFG_PREFIX "audio-connection");
277 if (!strcmp(psz, "embedded"))
278 conn = bmdAudioConnectionEmbedded;
279 else if (!strcmp(psz, "aesebu"))
280 conn = bmdAudioConnectionAESEBU;
281 else if (!strcmp(psz, "analog"))
282 conn = bmdAudioConnectionAnalog;
288 static BMDVideoConnection getVConn(vout_display_t *vd)
290 BMDVideoConnection conn = bmdVideoConnectionSDI;
291 char *psz = var_InheritString(vd, VIDEO_CFG_PREFIX "video-connection");
295 if (!strcmp(psz, "sdi"))
296 conn = bmdVideoConnectionSDI;
297 else if (!strcmp(psz, "hdmi"))
298 conn = bmdVideoConnectionHDMI;
299 else if (!strcmp(psz, "opticalsdi"))
300 conn = bmdVideoConnectionOpticalSDI;
301 else if (!strcmp(psz, "component"))
302 conn = bmdVideoConnectionComponent;
303 else if (!strcmp(psz, "composite"))
304 conn = bmdVideoConnectionComposite;
305 else if (!strcmp(psz, "svideo"))
306 conn = bmdVideoConnectionSVideo;
313 /*****************************************************************************
315 *****************************************************************************/
317 static struct decklink_sys_t *OpenDecklink(vout_display_t *vd)
319 vout_display_sys_t *sys = vd->sys;
320 #define CHECK(message) do { \
321 if (result != S_OK) \
323 msg_Err(vd, message ": 0x%X", result); \
329 IDeckLinkIterator *decklink_iterator = NULL;
330 IDeckLinkDisplayMode *p_display_mode = NULL;
331 IDeckLinkDisplayModeIterator *p_display_iterator = NULL;
332 IDeckLinkConfiguration *p_config = NULL;
333 IDeckLink *p_card = NULL;
335 struct decklink_sys_t *decklink_sys = GetDLSys(VLC_OBJECT(vd));
336 vlc_mutex_lock(&decklink_sys->lock);
337 decklink_sys->users++;
339 /* wait until aout is ready */
340 while (decklink_sys->aconn == 0)
341 vlc_cond_wait(&decklink_sys->cond, &decklink_sys->lock);
343 int i_card_index = var_InheritInteger(vd, CFG_PREFIX "card-index");
344 BMDVideoConnection vconn = getVConn(vd);
345 char *mode = var_InheritString(vd, VIDEO_CFG_PREFIX "mode");
346 size_t len = mode ? strlen(mode) : 0;
347 if (!mode || len > 4)
350 msg_Err(vd, "Missing or invalid mode");
354 BMDDisplayMode wanted_mode_id;
355 memset(&wanted_mode_id, ' ', 4);
356 strncpy((char*)&wanted_mode_id, mode, 4);
359 if (i_card_index < 0)
361 msg_Err(vd, "Invalid card index %d", i_card_index);
365 decklink_iterator = CreateDeckLinkIteratorInstance();
366 if (!decklink_iterator)
368 msg_Err(vd, "DeckLink drivers not found.");
372 for(int i = 0; i <= i_card_index; ++i)
376 result = decklink_iterator->Next(&p_card);
377 CHECK("Card not found");
380 const char *psz_model_name;
381 result = p_card->GetModelName(&psz_model_name);
382 CHECK("Unknown model name");
384 msg_Dbg(vd, "Opened DeckLink PCI card %s", psz_model_name);
386 result = p_card->QueryInterface(IID_IDeckLinkOutput,
387 (void**)&decklink_sys->p_output);
390 result = p_card->QueryInterface(IID_IDeckLinkConfiguration,
392 CHECK("Could not get config interface");
396 result = p_config->SetInt(
397 bmdDeckLinkConfigVideoOutputConnection, vconn);
398 CHECK("Could not set video output connection");
401 result = decklink_sys->p_output->GetDisplayModeIterator(&p_display_iterator);
402 CHECK("Could not enumerate display modes");
404 for (; ; p_display_mode->Release())
407 result = p_display_iterator->Next(&p_display_mode);
411 BMDDisplayMode mode_id = ntohl(p_display_mode->GetDisplayMode());
413 const char *psz_mode_name;
414 result = p_display_mode->GetName(&psz_mode_name);
415 CHECK("Could not get display mode name");
417 result = p_display_mode->GetFrameRate(&decklink_sys->frameduration,
418 &decklink_sys->timescale);
419 CHECK("Could not get frame rate");
421 w = p_display_mode->GetWidth();
422 h = p_display_mode->GetHeight();
423 msg_Dbg(vd, "Found mode '%4.4s': %s (%dx%d, %.3f fps)",
424 (char*)&mode_id, psz_mode_name, w, h,
425 double(decklink_sys->timescale) / decklink_sys->frameduration);
426 msg_Dbg(vd, "scale %d dur %d", (int)decklink_sys->timescale,
427 (int)decklink_sys->frameduration);
429 if (wanted_mode_id != mode_id)
432 decklink_sys->i_width = w;
433 decklink_sys->i_height = h;
435 mode_id = htonl(mode_id);
437 BMDVideoOutputFlags flags = bmdVideoOutputVANC;
438 if (mode_id == bmdModeNTSC ||
439 mode_id == bmdModeNTSC2398 ||
440 mode_id == bmdModePAL)
442 flags = bmdVideoOutputVITC;
445 BMDDisplayModeSupport support;
446 IDeckLinkDisplayMode *resultMode;
448 result = decklink_sys->p_output->DoesSupportVideoMode(mode_id,
449 sys->tenbits ? bmdFormat10BitYUV : bmdFormat8BitYUV,
450 flags, &support, &resultMode);
451 CHECK("Does not support video mode");
452 if (support == bmdDisplayModeNotSupported)
454 msg_Err(vd, "Video mode not supported");
458 result = decklink_sys->p_output->EnableVideoOutput(mode_id, flags);
459 CHECK("Could not enable video output");
464 if (decklink_sys->i_width < 0 || decklink_sys->i_width & 1)
466 msg_Err(vd, "Unknown video mode specified.");
470 result = p_config->SetInt(
471 bmdDeckLinkConfigAudioInputConnection, decklink_sys->aconn);
472 CHECK("Could not set audio connection");
474 if (/*decklink_sys->i_channels > 0 &&*/ decklink_sys->i_rate > 0)
476 result = decklink_sys->p_output->EnableAudioOutput(
477 decklink_sys->i_rate,
478 bmdAudioSampleType16bitInteger,
479 /*decklink_sys->i_channels*/ 2,
480 bmdAudioOutputStreamTimestamped);
482 CHECK("Could not start audio output");
485 result = decklink_sys->p_output->StartScheduledPlayback(
486 (mdate() * decklink_sys->timescale) / CLOCK_FREQ, decklink_sys->timescale, 1.0);
487 CHECK("Could not start playback");
490 p_display_mode->Release();
491 p_display_iterator->Release();
493 decklink_iterator->Release();
495 vlc_mutex_unlock(&decklink_sys->lock);
500 if (decklink_sys->p_output) {
501 decklink_sys->p_output->Release();
502 decklink_sys->p_output = NULL;
508 if (p_display_iterator)
509 p_display_iterator->Release();
510 if (decklink_iterator)
511 decklink_iterator->Release();
513 p_display_mode->Release();
515 vlc_mutex_unlock(&decklink_sys->lock);
516 ReleaseDLSys(VLC_OBJECT(vd));
522 /*****************************************************************************
524 *****************************************************************************/
526 static picture_pool_t *PoolVideo(vout_display_t *vd, unsigned requested_count)
528 vout_display_sys_t *sys = vd->sys;
530 sys->pool = picture_pool_NewFromFormat(&vd->fmt, requested_count);
534 static inline void put_le32(uint8_t **p, uint32_t d)
540 static inline int clip(int a)
543 else if (a > 1019) return 1019;
547 static void v210_convert(void *frame_bytes, picture_t *pic, int dst_stride)
549 int width = pic->format.i_width;
550 int height = pic->format.i_height;
551 int line_padding = dst_stride - ((width * 8 + 11) / 12) * 4;
553 uint8_t *data = (uint8_t*)frame_bytes;
555 const uint16_t *y = (const uint16_t*)pic->p[0].p_pixels;
556 const uint16_t *u = (const uint16_t*)pic->p[1].p_pixels;
557 const uint16_t *v = (const uint16_t*)pic->p[2].p_pixels;
559 #define WRITE_PIXELS(a, b, c) \
562 val |= (clip(*b++) << 10) | \
563 (clip(*c++) << 20); \
564 put_le32(&data, val); \
567 for (h = 0; h < height; h++) {
569 for (w = 0; w < width - 5; w += 6) {
570 WRITE_PIXELS(u, y, v);
571 WRITE_PIXELS(y, u, y);
572 WRITE_PIXELS(v, y, u);
573 WRITE_PIXELS(y, v, y);
576 WRITE_PIXELS(u, y, v);
580 put_le32(&data, val);
584 val |= (clip(*u++) << 10) | (clip(*y++) << 20);
585 put_le32(&data, val);
587 val = clip(*v++) | (clip(*y++) << 10);
588 put_le32(&data, val);
591 memset(data, 0, line_padding);
592 data += line_padding;
594 y += pic->p[0].i_pitch / 2 - width;
595 u += pic->p[1].i_pitch / 2 - width / 2;
596 v += pic->p[2].i_pitch / 2 - width / 2;
600 static void DisplayVideo(vout_display_t *vd, picture_t *picture, subpicture_t *)
602 vout_display_sys_t *sys = vd->sys;
603 struct decklink_sys_t *decklink_sys = GetDLSys(VLC_OBJECT(vd));
609 int w, h, stride, length;
611 w = decklink_sys->i_width;
612 h = decklink_sys->i_height;
614 IDeckLinkMutableVideoFrame *pDLVideoFrame;
615 result = decklink_sys->p_output->CreateVideoFrame(w, h, w*3,
616 sys->tenbits ? bmdFormat10BitYUV : bmdFormat8BitYUV,
617 bmdFrameFlagDefault, &pDLVideoFrame);
619 if (result != S_OK) {
620 msg_Err(vd, "Failed to create video frame: 0x%X", result);
621 pDLVideoFrame = NULL;
626 pDLVideoFrame->GetBytes((void**)&frame_bytes);
627 stride = pDLVideoFrame->GetRowBytes();
630 v210_convert(frame_bytes, picture, stride);
631 else for(int y = 0; y < h; ++y) {
632 uint8_t *dst = (uint8_t *)frame_bytes + stride * y;
633 const uint8_t *src = (const uint8_t *)picture->p[0].p_pixels +
634 picture->p[0].i_pitch * y;
635 memcpy(dst, src, w * 2 /* bpp */);
639 // compute frame duration in CLOCK_FREQ units
640 length = (decklink_sys->frameduration * CLOCK_FREQ) / decklink_sys->timescale;
642 picture->date -= decklink_sys->offset;
643 result = decklink_sys->p_output->ScheduleVideoFrame(pDLVideoFrame,
644 picture->date, length, CLOCK_FREQ);
646 if (result != S_OK) {
647 msg_Err(vd, "Dropped Video frame %"PRId64 ": 0x%x",
648 picture->date, result);
652 now = mdate() - decklink_sys->offset;
654 BMDTimeValue decklink_now;
656 decklink_sys->p_output->GetScheduledStreamTime (CLOCK_FREQ, &decklink_now, &speed);
658 if ((now - decklink_now) > 400000) {
659 /* XXX: workaround card clock drift */
660 decklink_sys->offset += 50000;
661 msg_Err(vd, "Delaying: offset now %"PRId64"", decklink_sys->offset);
666 pDLVideoFrame->Release();
667 picture_Release(picture);
670 static int ControlVideo(vout_display_t *vd, int query, va_list args)
673 const vout_display_cfg_t *cfg;
676 case VOUT_DISPLAY_CHANGE_FULLSCREEN:
677 cfg = va_arg(args, const vout_display_cfg_t *);
678 return cfg->is_fullscreen ? VLC_EGENERIC : VLC_SUCCESS;
684 static int OpenVideo(vlc_object_t *p_this)
686 vout_display_t *vd = (vout_display_t *)p_this;
687 vout_display_sys_t *sys;
688 struct decklink_sys_t *decklink_sys;
690 vd->sys = sys = (vout_display_sys_t*)malloc(sizeof(*sys));
694 sys->tenbits = var_InheritBool(p_this, VIDEO_CFG_PREFIX "tenbits");
696 decklink_sys = OpenDecklink(vd);
704 vd->fmt.i_chroma = sys->tenbits
705 ? VLC_CODEC_I422_10L /* we will convert to v210 */
707 //video_format_FixRgb(&(vd->fmt));
709 vd->fmt.i_width = decklink_sys->i_width;
710 vd->fmt.i_height = decklink_sys->i_height;
712 vd->info.has_hide_mouse = true;
713 vd->pool = PoolVideo;
715 vd->display = DisplayVideo;
716 vd->control = ControlVideo;
718 vout_display_SendEventFullscreen(vd, false);
723 static void CloseVideo(vlc_object_t *p_this)
725 vout_display_t *vd = (vout_display_t *)p_this;
726 vout_display_sys_t *sys = vd->sys;
729 picture_pool_Delete(sys->pool);
733 ReleaseDLSys(p_this);
736 /*****************************************************************************
738 *****************************************************************************/
740 static void Flush (audio_output_t *aout, bool drain)
742 struct decklink_sys_t *decklink_sys = GetDLSys(VLC_OBJECT(aout));
743 vlc_mutex_lock(&decklink_sys->lock);
744 IDeckLinkOutput *p_output = decklink_sys->p_output;
745 vlc_mutex_unlock(&decklink_sys->lock);
751 decklink_sys->p_output->GetBufferedAudioSampleFrameCount(&samples);
752 msleep(CLOCK_FREQ * samples / decklink_sys->i_rate);
753 } else if (decklink_sys->p_output->FlushBufferedAudioSamples() == E_FAIL)
754 msg_Err(aout, "Flush failed");
757 static int TimeGet(audio_output_t *, mtime_t* restrict)
759 /* synchronization is handled by the card */
763 static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
765 struct decklink_sys_t *decklink_sys = GetDLSys(VLC_OBJECT(aout));
767 if (decklink_sys->i_rate == 0)
770 fmt->i_format = VLC_CODEC_S16N;
771 fmt->i_channels = 2; //decklink_sys->i_channels;
772 fmt->i_physical_channels = AOUT_CHANS_STEREO; //pi_channels_maps[fmt->i_channels];
773 fmt->i_rate = decklink_sys->i_rate;
774 fmt->i_bitspersample = 16;
775 fmt->i_blockalign = fmt->i_channels * fmt->i_bitspersample /8 ;
776 fmt->i_frame_length = FRAME_SIZE;
781 static void PlayAudio(audio_output_t *aout, block_t *audio)
783 struct decklink_sys_t *decklink_sys = GetDLSys(VLC_OBJECT(aout));
784 vlc_mutex_lock(&decklink_sys->lock);
785 IDeckLinkOutput *p_output = decklink_sys->p_output;
786 vlc_mutex_unlock(&decklink_sys->lock);
788 block_Release(audio);
792 audio->i_pts -= decklink_sys->offset;
794 uint32_t sampleFrameCount = audio->i_buffer / (2 * 2 /*decklink_sys->i_channels*/);
796 HRESULT result = decklink_sys->p_output->ScheduleAudioSamples(
797 audio->p_buffer, sampleFrameCount, audio->i_pts, CLOCK_FREQ, &written);
800 msg_Err(aout, "Failed to schedule audio sample: 0x%X", result);
801 else if (sampleFrameCount != written)
802 msg_Err(aout, "Written only %d samples out of %d", written, sampleFrameCount);
804 block_Release(audio);
807 static int OpenAudio(vlc_object_t *p_this)
809 audio_output_t *aout = (audio_output_t *)p_this;
810 struct decklink_sys_t *decklink_sys = GetDLSys(VLC_OBJECT(aout));
812 vlc_mutex_lock(&decklink_sys->lock);
813 decklink_sys->aconn = getAConn(aout);
814 //decklink_sys->i_channels = var_InheritInteger(vd, AUDIO_CFG_PREFIX "audio-channels");
815 decklink_sys->i_rate = var_InheritInteger(aout, AUDIO_CFG_PREFIX "audio-rate");
816 decklink_sys->users++;
817 vlc_cond_signal(&decklink_sys->cond);
818 vlc_mutex_unlock(&decklink_sys->lock);
820 aout->play = PlayAudio;
823 aout->time_get = TimeGet;
827 aout->mute_set = NULL;
828 aout->volume_set= NULL;
833 static void CloseAudio(vlc_object_t *p_this)
835 struct decklink_sys_t *decklink_sys = GetDLSys(p_this);
836 vlc_mutex_lock(&decklink_sys->lock);
837 decklink_sys->aconn = 0;
838 vlc_mutex_unlock(&decklink_sys->lock);
839 ReleaseDLSys(p_this);