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 *****************************************************************************/
27 * - test non stereo audio
28 * - inherit aout/vout settings from corresponding module
29 * (allow to change settings between successive runs per instance)
30 * - allow several instances per process
31 * - get rid of process-wide destructor
34 #define __STDC_FORMAT_MACROS
35 #define __STDC_CONSTANT_MACROS
43 #include <vlc_common.h>
44 #include <vlc_plugin.h>
45 #include <vlc_threads.h>
47 #include <vlc_vout_display.h>
48 #include <vlc_picture_pool.h>
50 #include <vlc_block.h>
51 #include <vlc_atomic.h>
53 #include <arpa/inet.h>
55 #include <DeckLinkAPI.h>
56 #include <DeckLinkAPIDispatch.cpp>
58 #define FRAME_SIZE 1920
59 #define CHANNELS_MAX 6
62 static const int pi_channels_maps[CHANNELS_MAX+1] =
74 #define CARD_INDEX_TEXT N_("Output card")
75 #define CARD_INDEX_LONGTEXT N_(\
76 "DeckLink output card, if multiple exist. " \
77 "The cards are numbered from 0.")
79 #define MODE_TEXT N_("Desired output mode")
80 #define MODE_LONGTEXT N_(\
81 "Desired output mode for DeckLink output. " \
82 "This value should be a FOURCC code in textual " \
83 "form, e.g. \"ntsc\".")
85 #define AUDIO_CONNECTION_TEXT N_("Audio connection")
86 #define AUDIO_CONNECTION_LONGTEXT N_(\
87 "Audio connection for DeckLink output.")
90 #define RATE_TEXT N_("Audio sampling rate in Hz")
91 #define RATE_LONGTEXT N_(\
92 "Audio sampling rate (in hertz) for DeckLink output. " \
93 "0 disables audio output.")
95 #define CHANNELS_TEXT N_("Number of audio channels")
96 #define CHANNELS_LONGTEXT N_(\
97 "Number of output channels for DeckLink output. " \
98 "Must be 2, 8 or 16. 0 disables audio output.")
100 #define VIDEO_CONNECTION_TEXT N_("Video connection")
101 #define VIDEO_CONNECTION_LONGTEXT N_(\
102 "Video connection for DeckLink output.")
104 #define VIDEO_TENBITS_TEXT N_("10 bits")
105 #define VIDEO_TENBITS_LONGTEXT N_(\
106 "Use 10 bits per pixel for video frames.")
108 #define CFG_PREFIX "decklink-output-"
109 #define VIDEO_CFG_PREFIX "decklink-vout-"
110 #define AUDIO_CFG_PREFIX "decklink-aout-"
114 static const char *const ppsz_videoconns[] = {
115 "sdi", "hdmi", "opticalsdi", "component", "composite", "svideo"
117 static const char *const ppsz_videoconns_text[] = {
118 N_("SDI"), N_("HDMI"), N_("Optical SDI"), N_("Component"), N_("Composite"), N_("S-video")
121 static const char *const ppsz_audioconns[] = {
122 "embedded", "aesebu", "analog"
124 static const char *const ppsz_audioconns_text[] = {
125 N_("Embedded"), N_("AES/EBU"), N_("Analog")
129 struct vout_display_sys_t
131 picture_pool_t *pool;
135 /* Only one audio output module and one video output module
136 * can be used per process.
137 * We use a static mutex in audio/video submodules entry points. */
141 IDeckLinkOutput *p_output;
142 IDeckLinkConfiguration *p_config;
143 IDeckLinkDisplayModeIterator *p_display_iterator;
144 IDeckLinkIterator *decklink_iterator;
152 BMDTimeScale timescale;
153 BMDTimeValue frameduration;
155 /* XXX: workaround card clock drift */
158 NULL, NULL, NULL, NULL, NULL,
165 /*****************************************************************************
167 *****************************************************************************/
169 static int OpenVideo (vlc_object_t *);
170 static void CloseVideo (vlc_object_t *);
171 static int OpenAudio (vlc_object_t *);
172 static void CloseAudio (vlc_object_t *);
174 /*****************************************************************************
176 *****************************************************************************/
179 set_shortname(N_("DecklinkOutput"))
180 set_description(N_("output module to write to Blackmagic SDI card"))
181 set_section(N_("Decklink General Options"), NULL)
182 add_integer(CFG_PREFIX "card-index", 0,
183 CARD_INDEX_TEXT, CARD_INDEX_LONGTEXT, true)
186 set_description (N_("Decklink Video Output module"))
187 set_category(CAT_VIDEO)
188 set_subcategory(SUBCAT_VIDEO_VOUT)
189 set_capability("vout display", 0)
190 set_callbacks (OpenVideo, CloseVideo)
191 set_section(N_("Decklink Video Options"), NULL)
192 add_string(VIDEO_CFG_PREFIX "video-connection", "sdi",
193 VIDEO_CONNECTION_TEXT, VIDEO_CONNECTION_LONGTEXT, true)
194 change_string_list(ppsz_videoconns, ppsz_videoconns_text)
195 add_string(VIDEO_CFG_PREFIX "mode", "pal ",
196 MODE_TEXT, MODE_LONGTEXT, true)
197 add_bool(VIDEO_CFG_PREFIX "tenbits", false,
198 VIDEO_TENBITS_TEXT, VIDEO_TENBITS_LONGTEXT, true)
202 set_description (N_("Decklink Audio Output module"))
203 set_category(CAT_AUDIO)
204 set_subcategory(SUBCAT_AUDIO_AOUT)
205 set_capability("audio output", 0)
206 set_callbacks (OpenAudio, CloseAudio)
207 set_section(N_("Decklink Audio Options"), NULL)
208 add_string(AUDIO_CFG_PREFIX "audio-connection", "embedded",
209 AUDIO_CONNECTION_TEXT, AUDIO_CONNECTION_LONGTEXT, true)
210 change_string_list(ppsz_audioconns, ppsz_audioconns_text)
211 add_integer(AUDIO_CFG_PREFIX "audio-rate", 48000,
212 RATE_TEXT, RATE_LONGTEXT, true)
213 add_integer(AUDIO_CFG_PREFIX "audio-channels", 2,
214 CHANNELS_TEXT, CHANNELS_LONGTEXT, true)
218 static BMDAudioConnection getAConn(vlc_object_t *p_this)
220 BMDAudioConnection conn = bmdAudioConnectionEmbedded;
221 char *psz = var_InheritString(p_this, AUDIO_CFG_PREFIX "audio-connection");
225 if (!strcmp(psz, "embedded"))
226 conn = bmdAudioConnectionEmbedded;
227 else if (!strcmp(psz, "aesebu"))
228 conn = bmdAudioConnectionAESEBU;
229 else if (!strcmp(psz, "analog"))
230 conn = bmdAudioConnectionAnalog;
237 static BMDVideoConnection getVConn(vlc_object_t *p_this)
239 BMDVideoConnection conn = bmdVideoConnectionSDI;
240 char *psz = var_InheritString(p_this, VIDEO_CFG_PREFIX "video-connection");
244 if (!strcmp(psz, "sdi"))
245 conn = bmdVideoConnectionSDI;
246 else if (!strcmp(psz, "hdmi"))
247 conn = bmdVideoConnectionHDMI;
248 else if (!strcmp(psz, "opticalsdi"))
249 conn = bmdVideoConnectionOpticalSDI;
250 else if (!strcmp(psz, "component"))
251 conn = bmdVideoConnectionComponent;
252 else if (!strcmp(psz, "composite"))
253 conn = bmdVideoConnectionComposite;
254 else if (!strcmp(psz, "svideo"))
255 conn = bmdVideoConnectionSVideo;
262 /*****************************************************************************
264 *****************************************************************************/
266 static atomic_uint initialized = ATOMIC_VAR_INIT(0);
268 static void CloseDecklink(void) __attribute__((destructor));
269 static void CloseDecklink(void)
271 if (!atomic_load(&initialized))
274 decklink_sys.p_output->StopScheduledPlayback(0, NULL, 0);
275 decklink_sys.p_output->DisableVideoOutput();
276 decklink_sys.p_output->DisableAudioOutput();
278 if (decklink_sys.decklink_iterator)
279 decklink_sys.decklink_iterator->Release();
281 if (decklink_sys.p_display_iterator)
282 decklink_sys.p_display_iterator->Release();
284 if (decklink_sys.p_config)
285 decklink_sys.p_config->Release();
287 if (decklink_sys.p_output)
288 decklink_sys.p_output->Release();
290 if (decklink_sys.p_card)
291 decklink_sys.p_card->Release();
294 static int OpenDecklink(vlc_object_t *p_this)
296 vout_display_t *vd = (vout_display_t *)p_this;
297 vout_display_sys_t *sys = vd->sys;
298 #define CHECK(message) do { \
299 if (result != S_OK) \
301 msg_Err(p_this, message ": 0x%X", result); \
307 IDeckLinkDisplayMode *p_display_mode = NULL;
308 static vlc_mutex_t lock = VLC_STATIC_MUTEX;
310 vlc_mutex_lock(&lock);
312 if (atomic_load(&initialized)) {
313 /* already initialized */
314 vlc_mutex_unlock(&lock);
318 //decklink_sys.i_channels = var_InheritInteger(p_this, AUDIO_CFG_PREFIX "audio-channels");
319 decklink_sys.i_rate = var_InheritInteger(p_this, AUDIO_CFG_PREFIX "audio-rate");
320 int i_card_index = var_InheritInteger(p_this, CFG_PREFIX "card-index");
321 BMDVideoConnection vconn = getVConn(p_this);
322 BMDAudioConnection aconn = getAConn(p_this);
323 char *mode = var_InheritString(p_this, VIDEO_CFG_PREFIX "mode");
324 size_t len = mode ? strlen(mode) : 0;
325 if (!mode || len > 4)
328 msg_Err(p_this, "Missing or invalid mode");
332 BMDDisplayMode wanted_mode_id;
333 memset(&wanted_mode_id, ' ', 4);
334 strncpy((char*)&wanted_mode_id, mode, 4);
337 if (i_card_index < 0)
339 msg_Err(p_this, "Invalid card index %d", i_card_index);
343 decklink_sys.decklink_iterator = CreateDeckLinkIteratorInstance();
344 if (!decklink_sys.decklink_iterator)
346 msg_Err(p_this, "DeckLink drivers not found.");
350 for(int i = 0; i <= i_card_index; ++i)
352 if (decklink_sys.p_card)
353 decklink_sys.p_card->Release();
354 result = decklink_sys.decklink_iterator->Next(&decklink_sys.p_card);
355 CHECK("Card not found");
358 const char *psz_model_name;
359 result = decklink_sys.p_card->GetModelName(&psz_model_name);
360 CHECK("Unknown model name");
362 msg_Dbg(p_this, "Opened DeckLink PCI card %s", psz_model_name);
364 result = decklink_sys.p_card->QueryInterface(IID_IDeckLinkOutput,
365 (void**)&decklink_sys.p_output);
368 result = decklink_sys.p_card->QueryInterface(IID_IDeckLinkConfiguration,
369 (void**)&decklink_sys.p_config);
370 CHECK("Could not get config interface");
374 result = decklink_sys.p_config->SetInt(
375 bmdDeckLinkConfigVideoOutputConnection, vconn);
376 CHECK("Could not set video output connection");
381 result = decklink_sys.p_config->SetInt(
382 bmdDeckLinkConfigAudioInputConnection, aconn);
383 CHECK("Could not set audio output connection");
386 result = decklink_sys.p_output->GetDisplayModeIterator(&decklink_sys.p_display_iterator);
387 CHECK("Could not enumerate display modes");
389 for (; ; p_display_mode->Release())
392 result = decklink_sys.p_display_iterator->Next(&p_display_mode);
396 BMDDisplayMode mode_id = ntohl(p_display_mode->GetDisplayMode());
398 const char *psz_mode_name;
399 result = p_display_mode->GetName(&psz_mode_name);
400 CHECK("Could not get display mode name");
402 result = p_display_mode->GetFrameRate(&decklink_sys.frameduration,
403 &decklink_sys.timescale);
404 CHECK("Could not get frame rate");
406 w = p_display_mode->GetWidth();
407 h = p_display_mode->GetHeight();
408 msg_Dbg(p_this, "Found mode '%4.4s': %s (%dx%d, %.3f fps)",
409 (char*)&mode_id, psz_mode_name, w, h,
410 double(decklink_sys.timescale) / decklink_sys.frameduration);
411 msg_Dbg(p_this, "scale %d dur %d", (int)decklink_sys.timescale,
412 (int)decklink_sys.frameduration);
414 if (wanted_mode_id != mode_id)
417 decklink_sys.i_width = w;
418 decklink_sys.i_height = h;
420 p_display_mode->Release();
421 p_display_mode = NULL;
423 mode_id = htonl(mode_id);
425 BMDVideoOutputFlags flags = bmdVideoOutputVANC;
426 if (mode_id == bmdModeNTSC ||
427 mode_id == bmdModeNTSC2398 ||
428 mode_id == bmdModePAL)
430 flags = bmdVideoOutputVITC;
433 BMDDisplayModeSupport support;
434 IDeckLinkDisplayMode *resultMode;
436 result = decklink_sys.p_output->DoesSupportVideoMode(mode_id,
437 sys->tenbits ? bmdFormat10BitYUV : bmdFormat8BitYUV,
438 flags, &support, &resultMode);
439 CHECK("Does not support video mode");
440 if (support == bmdDisplayModeNotSupported)
442 msg_Err(p_this, "Video mode not supported");
446 result = decklink_sys.p_output->EnableVideoOutput(mode_id, flags);
447 CHECK("Could not enable video output");
452 if (decklink_sys.i_width < 0)
454 msg_Err(p_this, "Unknown video mode specified.");
459 if (/*decklink_sys.i_channels > 0 &&*/ decklink_sys.i_rate > 0)
461 result = decklink_sys.p_output->EnableAudioOutput(
463 bmdAudioSampleType16bitInteger,
464 /*decklink_sys.i_channels*/ 2,
465 bmdAudioOutputStreamTimestamped);
469 result = decklink_sys.p_output->DisableAudioOutput();
471 CHECK("Could not enable audio output");
475 result = decklink_sys.p_output->StartScheduledPlayback(
476 (mdate() * decklink_sys.timescale) / CLOCK_FREQ, decklink_sys.timescale, 1.0);
477 CHECK("Could not start playback");
479 atomic_store(&initialized, 1);
481 vlc_mutex_unlock(&lock);
486 if (decklink_sys.decklink_iterator)
487 decklink_sys.decklink_iterator->Release();
488 if (decklink_sys.p_display_iterator)
489 decklink_sys.p_display_iterator->Release();
491 p_display_mode->Release();
493 vlc_mutex_unlock(&lock);
498 /*****************************************************************************
500 *****************************************************************************/
502 static picture_pool_t *PoolVideo(vout_display_t *vd, unsigned requested_count)
504 vout_display_sys_t *sys = vd->sys;
506 sys->pool = picture_pool_NewFromFormat(&vd->fmt, requested_count);
510 static inline void put_le32(uint8_t **p, uint32_t d)
516 static inline int clip(int a)
519 else if (a > 1019) return 1019;
523 static void v210_convert(void *frame_bytes, picture_t *pic, int dst_stride)
525 int width = pic->format.i_width;
526 int height = pic->format.i_height;
527 int line_padding = dst_stride - ((width * 8 + 11) / 12) * 4;
529 uint8_t *data = (uint8_t*)frame_bytes;
531 const uint16_t *y = (const uint16_t*)pic->p[0].p_pixels;
532 const uint16_t *u = (const uint16_t*)pic->p[1].p_pixels;
533 const uint16_t *v = (const uint16_t*)pic->p[2].p_pixels;
535 #define WRITE_PIXELS(a, b, c) \
538 val |= (clip(*b++) << 10) | \
539 (clip(*c++) << 20); \
540 put_le32(&data, val); \
543 for (h = 0; h < height; h++) {
545 for (w = 0; w < width - 5; w += 6) {
546 WRITE_PIXELS(u, y, v);
547 WRITE_PIXELS(y, u, y);
548 WRITE_PIXELS(v, y, u);
549 WRITE_PIXELS(y, v, y);
552 WRITE_PIXELS(u, y, v);
556 put_le32(&data, val);
560 val |= (clip(*u++) << 10) | (clip(*y++) << 20);
561 put_le32(&data, val);
563 val = clip(*v++) | (clip(*y++) << 10);
564 put_le32(&data, val);
567 memset(data, 0, line_padding);
568 data += line_padding;
570 y += pic->p[0].i_pitch / 2 - width;
571 u += pic->p[1].i_pitch / 2 - width / 2;
572 v += pic->p[2].i_pitch / 2 - width / 2;
576 static void DisplayVideo(vout_display_t *vd, picture_t *picture, subpicture_t *)
578 vout_display_sys_t *sys = vd->sys;
584 int w, h, stride, length;
586 w = decklink_sys.i_width;
587 h = decklink_sys.i_height;
589 IDeckLinkMutableVideoFrame *pDLVideoFrame;
590 result = decklink_sys.p_output->CreateVideoFrame(w, h, w*3,
591 sys->tenbits ? bmdFormat10BitYUV : bmdFormat8BitYUV,
592 bmdFrameFlagDefault, &pDLVideoFrame);
594 if (result != S_OK) {
595 msg_Err(vd, "Failed to create video frame: 0x%X", result);
596 pDLVideoFrame = NULL;
601 pDLVideoFrame->GetBytes((void**)&frame_bytes);
602 stride = pDLVideoFrame->GetRowBytes();
605 v210_convert(frame_bytes, picture, stride);
606 else for(int y = 0; y < h; ++y) {
607 uint8_t *dst = (uint8_t *)frame_bytes + stride * y;
608 const uint8_t *src = (const uint8_t *)picture->p[0].p_pixels +
609 picture->p[0].i_pitch * y;
610 memcpy(dst, src, w * 2 /* bpp */);
614 // compute frame duration in CLOCK_FREQ units
615 length = (decklink_sys.frameduration * CLOCK_FREQ) / decklink_sys.timescale;
617 picture->date -= decklink_sys.offset;
618 result = decklink_sys.p_output->ScheduleVideoFrame(pDLVideoFrame,
619 picture->date, length, CLOCK_FREQ);
621 if (result != S_OK) {
622 msg_Err(vd, "Dropped Video frame %"PRId64 ": 0x%x",
623 picture->date, result);
627 now = mdate() - decklink_sys.offset;
629 BMDTimeValue decklink_now;
631 decklink_sys.p_output->GetScheduledStreamTime (CLOCK_FREQ, &decklink_now, &speed);
633 if ((now - decklink_now) > 400000) {
634 /* XXX: workaround card clock drift */
635 decklink_sys.offset += 50000;
636 msg_Err(vd, "Delaying: offset now %"PRId64"", decklink_sys.offset);
641 pDLVideoFrame->Release();
642 picture_Release(picture);
645 static int ControlVideo(vout_display_t *vd, int query, va_list args)
648 const vout_display_cfg_t *cfg;
651 case VOUT_DISPLAY_CHANGE_FULLSCREEN:
652 cfg = va_arg(args, const vout_display_cfg_t *);
653 return cfg->is_fullscreen ? VLC_EGENERIC : VLC_SUCCESS;
659 static atomic_uint video_lock = ATOMIC_VAR_INIT(0);
660 static int OpenVideo(vlc_object_t *p_this)
662 vout_display_t *vd = (vout_display_t *)p_this;
663 vout_display_sys_t *sys;
665 if (atomic_exchange(&video_lock, 1)) {
666 msg_Err(vd, "Decklink video module already busy");
670 vd->sys = sys = (vout_display_sys_t*)malloc(sizeof(*sys));
674 if (OpenDecklink(p_this) != VLC_SUCCESS)
677 if (decklink_sys.i_width & 1) {
678 msg_Err(vd, "Invalid width %d", decklink_sys.i_width);
684 sys->tenbits = var_InheritBool(p_this, VIDEO_CFG_PREFIX "tenbits");
685 vd->fmt.i_chroma = sys->tenbits
686 ? VLC_CODEC_I422_10L /* we will convert to v210 */
688 //video_format_FixRgb(&(vd->fmt));
690 vd->fmt.i_width = decklink_sys.i_width;
691 vd->fmt.i_height = decklink_sys.i_height;
693 vd->info.has_hide_mouse = true;
694 vd->pool = PoolVideo;
696 vd->display = DisplayVideo;
697 vd->control = ControlVideo;
699 vout_display_SendEventFullscreen(vd, false);
708 static void CloseVideo(vlc_object_t *p_this)
710 vout_display_t *vd = (vout_display_t *)p_this;
711 vout_display_sys_t *sys = vd->sys;
714 picture_pool_Delete(sys->pool);
718 atomic_fetch_sub(&video_lock, 1);
721 /*****************************************************************************
723 *****************************************************************************/
725 static void Flush (audio_output_t *aout, bool drain)
727 if (!atomic_load(&initialized))
732 decklink_sys.p_output->GetBufferedAudioSampleFrameCount(&samples);
733 msleep(CLOCK_FREQ * samples / decklink_sys.i_rate);
734 } else if (decklink_sys.p_output->FlushBufferedAudioSamples() == E_FAIL)
735 msg_Err(aout, "Flush failed");
738 static int TimeGet(audio_output_t *, mtime_t* restrict)
740 /* synchronization is handled by the card */
744 static int Start(audio_output_t *, audio_sample_format_t *restrict fmt)
746 fmt->i_format = VLC_CODEC_S16N;
747 fmt->i_channels = 2; //decklink_sys.i_channels;
748 fmt->i_physical_channels = AOUT_CHANS_STEREO; //pi_channels_maps[fmt->i_channels];
749 fmt->i_rate = decklink_sys.i_rate;
750 fmt->i_bitspersample = 16;
751 fmt->i_blockalign = fmt->i_channels * fmt->i_bitspersample /8 ;
752 fmt->i_frame_length = FRAME_SIZE;
757 static void PlayAudio(audio_output_t *aout, block_t *audio)
759 if (!atomic_load(&initialized))
762 audio->i_pts -= decklink_sys.offset;
764 uint32_t sampleFrameCount = audio->i_buffer / (2 * 2 /*decklink_sys.i_channels*/);
766 HRESULT result = decklink_sys.p_output->ScheduleAudioSamples(
767 audio->p_buffer, sampleFrameCount, audio->i_pts, CLOCK_FREQ, &written);
770 msg_Err(aout, "Failed to schedule audio sample: 0x%X", result);
771 else if (sampleFrameCount != written)
772 msg_Err(aout, "Written only %d samples out of %d", written, sampleFrameCount);
774 block_Release(audio);
777 static atomic_uint audio_lock = ATOMIC_VAR_INIT(0);
778 static int OpenAudio(vlc_object_t *p_this)
780 audio_output_t *aout = (audio_output_t *)p_this;
782 if (atomic_exchange(&audio_lock, 1)) {
783 msg_Err(aout, "Decklink audio module already busy");
787 aout->play = PlayAudio;
790 aout->time_get = TimeGet;
794 aout->mute_set = NULL;
795 aout->volume_set= NULL;
800 static void CloseAudio(vlc_object_t *)
802 atomic_fetch_sub(&audio_lock, 1);