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
33 #include <vlc_fixups.h>
36 #include <vlc_common.h>
37 #include <vlc_plugin.h>
38 #include <vlc_threads.h>
40 #include <vlc_vout_display.h>
41 #include <vlc_picture_pool.h>
43 #include <vlc_block.h>
44 #include <vlc_image.h>
47 #ifdef HAVE_ARPA_INET_H
48 #include <arpa/inet.h>
51 #include "../access/vlc_decklink.h"
52 #include <DeckLinkAPIDispatch.cpp>
54 #define FRAME_SIZE 1920
55 #define CHANNELS_MAX 6
58 static const int pi_channels_maps
[CHANNELS_MAX
+1] =
70 #define NOSIGNAL_INDEX_TEXT N_("Timelength after which we assume there is no signal.")
71 #define NOSIGNAL_INDEX_LONGTEXT N_(\
72 "Timelength after which we assume there is no signal.\n"\
73 "After this delay we black out the video."\
76 #define AFD_INDEX_TEXT N_("Active Format Descriptor value")
78 #define AR_INDEX_TEXT N_("Aspect Ratio")
79 #define AR_INDEX_LONGTEXT N_("Aspect Ratio of the source picture.")
81 #define AFDLINE_INDEX_TEXT N_("Active Format Descriptor line")
82 #define AFDLINE_INDEX_LONGTEXT N_("VBI line on which to output Active Format Descriptor.")
84 #define NOSIGNAL_IMAGE_TEXT N_("Picture to display on input signal loss")
85 #define NOSIGNAL_IMAGE_LONGTEXT NOSIGNAL_IMAGE_TEXT
87 #define CARD_INDEX_TEXT N_("Output card")
88 #define CARD_INDEX_LONGTEXT N_(\
89 "DeckLink output card, if multiple exist. " \
90 "The cards are numbered from 0.")
92 #define MODE_TEXT N_("Desired output mode")
93 #define MODE_LONGTEXT N_(\
94 "Desired output mode for DeckLink output. " \
95 "This value should be a FOURCC code in textual " \
96 "form, e.g. \"ntsc\".")
98 #define AUDIO_CONNECTION_TEXT N_("Audio connection")
99 #define AUDIO_CONNECTION_LONGTEXT N_(\
100 "Audio connection for DeckLink output.")
103 #define RATE_TEXT N_("Audio samplerate (Hz)")
104 #define RATE_LONGTEXT N_(\
105 "Audio sampling rate (in hertz) for DeckLink output. " \
106 "0 disables audio output.")
108 #define CHANNELS_TEXT N_("Number of audio channels")
109 #define CHANNELS_LONGTEXT N_(\
110 "Number of output channels for DeckLink output. " \
111 "Must be 2, 8 or 16. 0 disables audio output.")
113 #define VIDEO_CONNECTION_TEXT N_("Video connection")
114 #define VIDEO_CONNECTION_LONGTEXT N_(\
115 "Video connection for DeckLink output.")
117 #define VIDEO_TENBITS_TEXT N_("10 bits")
118 #define VIDEO_TENBITS_LONGTEXT N_(\
119 "Use 10 bits per pixel for video frames.")
121 #define CFG_PREFIX "decklink-output-"
122 #define VIDEO_CFG_PREFIX "decklink-vout-"
123 #define AUDIO_CFG_PREFIX "decklink-aout-"
125 /* Video Connections */
126 static const char *const ppsz_videoconns
[] = {
134 static const char *const ppsz_videoconns_text
[] = {
142 static const BMDVideoConnection rgbmd_videoconns
[] =
144 bmdVideoConnectionSDI
,
145 bmdVideoConnectionHDMI
,
146 bmdVideoConnectionOpticalSDI
,
147 bmdVideoConnectionComponent
,
148 bmdVideoConnectionComposite
,
149 bmdVideoConnectionSVideo
,
151 static_assert(ARRAY_SIZE(rgbmd_videoconns
) == ARRAY_SIZE(ppsz_videoconns
), "videoconn arrays messed up");
152 static_assert(ARRAY_SIZE(rgbmd_videoconns
) == ARRAY_SIZE(ppsz_videoconns_text
), "videoconn arrays messed up");
154 static const int rgi_afd_values
[] = {
155 0, 2, 3, 4, 8, 9, 10, 11, 13, 14, 15,
157 static const char * const rgsz_afd_text
[] = {
159 "2: Box 16:9 (top aligned)",
160 "3: Box 14:9 (top aligned)",
161 "4: Box > 16:9 (centre aligned)",
162 "8: Same as coded frame (full frame)",
163 "9: 4:3 (centre aligned)",
164 "10: 16:9 (centre aligned)",
165 "11: 14:9 (centre aligned)",
166 "13: 4:3 (with shoot and protect 14:9 centre)",
167 "14: 16:9 (with shoot and protect 14:9 centre)",
168 "15: 16:9 (with shoot and protect 4:3 centre)",
170 static_assert(ARRAY_SIZE(rgi_afd_values
) == ARRAY_SIZE(rgsz_afd_text
), "afd arrays messed up");
172 static const int rgi_ar_values
[] = {
175 static const char * const rgsz_ar_text
[] = {
179 static_assert(ARRAY_SIZE(rgi_ar_values
) == ARRAY_SIZE(rgsz_ar_text
), "afd arrays messed up");
183 /* Only one audio output module and one video output module
184 * can be used per process.
185 * We use a static mutex in audio/video submodules entry points. */
186 struct decklink_sys_t
189 IDeckLinkOutput
*p_output
;
192 * Synchronizes aout and vout modules:
193 * vout module waits until aout has been initialized.
194 * That means video-only output is NOT supported.
205 BMDTimeScale timescale
;
206 BMDTimeValue frameduration
;
208 /* XXX: workaround card clock drift */
213 /* single video module exclusive */
216 video_format_t currentfmt
;
217 picture_pool_t
*pool
;
221 picture_t
*pic_nosignal
;
227 /*****************************************************************************
229 *****************************************************************************/
231 static int OpenVideo (vlc_object_t
*);
232 static void CloseVideo (vlc_object_t
*);
233 static int OpenAudio (vlc_object_t
*);
234 static void CloseAudio (vlc_object_t
*);
236 /*****************************************************************************
238 *****************************************************************************/
241 set_shortname(N_("DecklinkOutput"))
242 set_description(N_("Output module to write to Blackmagic SDI card"))
243 set_section(N_("DeckLink General Options"), NULL
)
244 add_integer(CFG_PREFIX
"card-index", 0,
245 CARD_INDEX_TEXT
, CARD_INDEX_LONGTEXT
, true)
248 set_description (N_("DeckLink Video Output module"))
249 set_category(CAT_VIDEO
)
250 set_subcategory(SUBCAT_VIDEO_VOUT
)
251 set_capability("vout display", 0)
252 set_callbacks (OpenVideo
, CloseVideo
)
253 set_section(N_("DeckLink Video Options"), NULL
)
254 add_string(VIDEO_CFG_PREFIX
"video-connection", "sdi",
255 VIDEO_CONNECTION_TEXT
, VIDEO_CONNECTION_LONGTEXT
, true)
256 change_string_list(ppsz_videoconns
, ppsz_videoconns_text
)
257 add_string(VIDEO_CFG_PREFIX
"mode", "",
258 MODE_TEXT
, MODE_LONGTEXT
, true)
259 add_bool(VIDEO_CFG_PREFIX
"tenbits", true,
260 VIDEO_TENBITS_TEXT
, VIDEO_TENBITS_LONGTEXT
, true)
261 add_integer(VIDEO_CFG_PREFIX
"nosignal-delay", 5,
262 NOSIGNAL_INDEX_TEXT
, NOSIGNAL_INDEX_LONGTEXT
, true)
263 add_integer(VIDEO_CFG_PREFIX
"afd-line", 16,
264 AFDLINE_INDEX_TEXT
, AFDLINE_INDEX_LONGTEXT
, true)
265 add_integer_with_range(VIDEO_CFG_PREFIX
"afd", 8, 0, 16,
266 AFD_INDEX_TEXT
, AFD_INDEX_TEXT
, true)
267 change_integer_list(rgi_afd_values
, rgsz_afd_text
)
268 add_integer_with_range(VIDEO_CFG_PREFIX
"ar", 1, 0, 1,
269 AR_INDEX_TEXT
, AR_INDEX_LONGTEXT
, true)
270 change_integer_list(rgi_ar_values
, rgsz_ar_text
)
271 add_loadfile(VIDEO_CFG_PREFIX
"nosignal-image", NULL
,
272 NOSIGNAL_IMAGE_TEXT
, NOSIGNAL_IMAGE_LONGTEXT
)
276 set_description (N_("DeckLink Audio Output module"))
277 set_category(CAT_AUDIO
)
278 set_subcategory(SUBCAT_AUDIO_AOUT
)
279 set_capability("audio output", 0)
280 set_callbacks (OpenAudio
, CloseAudio
)
281 set_section(N_("DeckLink Audio Options"), NULL
)
282 add_obsolete_string("audio-connection")
283 add_integer(AUDIO_CFG_PREFIX
"audio-rate", 48000,
284 RATE_TEXT
, RATE_LONGTEXT
, true)
285 add_integer(AUDIO_CFG_PREFIX
"audio-channels", 2,
286 CHANNELS_TEXT
, CHANNELS_LONGTEXT
, true)
289 /* Protects decklink_sys_t creation/deletion */
290 static vlc_mutex_t sys_lock
= VLC_STATIC_MUTEX
;
292 static decklink_sys_t
*HoldDLSys(vlc_object_t
*obj
, int i_cat
)
294 vlc_object_t
*libvlc
= VLC_OBJECT(obj
->obj
.libvlc
);
297 vlc_mutex_lock(&sys_lock
);
299 if (var_Type(libvlc
, "decklink-sys") == VLC_VAR_ADDRESS
)
301 sys
= (decklink_sys_t
*)var_GetAddress(libvlc
, "decklink-sys");
304 if(i_cat
== VIDEO_ES
)
306 while(sys
->b_videomodule
)
308 vlc_mutex_unlock(&sys_lock
);
309 msg_Info(obj
, "Waiting for previous vout module to exit");
310 vlc_tick_sleep(VLC_TICK_FROM_MS(100));
311 vlc_mutex_lock(&sys_lock
);
317 sys
= (decklink_sys_t
*)malloc(sizeof(*sys
));
319 sys
->p_output
= NULL
;
322 sys
->b_videomodule
= (i_cat
== VIDEO_ES
);
323 sys
->b_recycling
= false;
324 sys
->i_rate
= var_InheritInteger(obj
, AUDIO_CFG_PREFIX
"audio-rate");
327 vlc_mutex_init(&sys
->lock
);
328 vlc_cond_init(&sys
->cond
);
329 var_Create(libvlc
, "decklink-sys", VLC_VAR_ADDRESS
);
330 var_SetAddress(libvlc
, "decklink-sys", (void*)sys
);
334 vlc_mutex_unlock(&sys_lock
);
338 static void ReleaseDLSys(vlc_object_t
*obj
, int i_cat
)
340 vlc_object_t
*libvlc
= VLC_OBJECT(obj
->obj
.libvlc
);
342 vlc_mutex_lock(&sys_lock
);
344 struct decklink_sys_t
*sys
= (struct decklink_sys_t
*)var_GetAddress(libvlc
, "decklink-sys");
346 if (--sys
->users
== 0) {
347 msg_Dbg(obj
, "Destroying decklink data");
348 vlc_mutex_destroy(&sys
->lock
);
349 vlc_cond_destroy(&sys
->cond
);
352 sys
->p_output
->StopScheduledPlayback(0, NULL
, 0);
353 sys
->p_output
->DisableVideoOutput();
354 sys
->p_output
->DisableAudioOutput();
355 sys
->p_output
->Release();
358 /* Clean video specific */
360 picture_pool_Release(sys
->video
.pool
);
361 if (sys
->video
.pic_nosignal
)
362 picture_Release(sys
->video
.pic_nosignal
);
363 video_format_Clean(&sys
->video
.currentfmt
);
366 var_Destroy(libvlc
, "decklink-sys");
368 else if (i_cat
== VIDEO_ES
)
370 sys
->b_videomodule
= false;
371 sys
->b_recycling
= true;
374 vlc_mutex_unlock(&sys_lock
);
377 static BMDVideoConnection
getVConn(vout_display_t
*vd
, BMDVideoConnection mask
)
379 BMDVideoConnection conn
= 0;
380 char *psz
= var_InheritString(vd
, VIDEO_CFG_PREFIX
"video-connection");
383 for(size_t i
=0; i
<ARRAY_SIZE(rgbmd_videoconns
); i
++)
385 if (!strcmp(psz
, ppsz_videoconns
[i
]) && (mask
& rgbmd_videoconns
[i
]))
387 conn
= rgbmd_videoconns
[i
];
393 else /* Pick one as default connection */
395 conn
= vlc_ctz(mask
);
396 conn
= conn
? ( 1 << conn
) : bmdVideoConnectionSDI
;
401 /*****************************************************************************
403 *****************************************************************************/
408 const char * const psz_string
;
409 } const errors_to_string
[] = {
410 { E_UNEXPECTED
, "Unexpected error" },
411 { E_NOTIMPL
, "Not implemented" },
412 { E_OUTOFMEMORY
, "Out of memory" },
413 { E_INVALIDARG
, "Invalid argument" },
414 { E_NOINTERFACE
, "No interface" },
415 { E_POINTER
, "Invalid pointer" },
416 { E_HANDLE
, "Invalid handle" },
417 { E_ABORT
, "Aborted" },
418 { E_FAIL
, "Failed" },
419 { E_ACCESSDENIED
,"Access denied" }
422 static const char * lookup_error_string(long i_code
)
424 for(size_t i
=0; i
<ARRAY_SIZE(errors_to_string
); i
++)
426 if(errors_to_string
[i
].i_return_code
== i_code
)
427 return errors_to_string
[i
].psz_string
;
432 static picture_t
* CreateNoSignalPicture(vlc_object_t
*p_this
, const video_format_t
*fmt
,
433 const char *psz_file
)
435 picture_t
*p_pic
= NULL
;
436 image_handler_t
*img
= image_HandlerCreate(p_this
);
439 msg_Err(p_this
, "Could not create image converter");
443 video_format_t in
, dummy
;
444 video_format_Init(&dummy
, 0);
445 video_format_Init(&in
, 0);
446 video_format_Setup(&in
, 0,
447 fmt
->i_width
, fmt
->i_height
,
448 fmt
->i_width
, fmt
->i_height
, 1, 1);
450 picture_t
*png
= image_ReadUrl(img
, psz_file
, &dummy
, &in
);
453 video_format_Clean(&dummy
);
454 video_format_Copy(&dummy
, fmt
);
455 p_pic
= image_Convert(img
, png
, &in
, &dummy
);
456 if(!video_format_IsSimilar(&dummy
, fmt
))
458 picture_Release(p_pic
);
461 picture_Release(png
);
463 image_HandlerDelete(img
);
464 video_format_Clean(&in
);
465 video_format_Clean(&dummy
);
470 static IDeckLinkDisplayMode
* MatchDisplayMode(vout_display_t
*vd
,
471 IDeckLinkOutput
*output
,
472 const video_format_t
*fmt
,
473 BMDDisplayMode forcedmode
= bmdDisplayModeNotSupported
)
476 IDeckLinkDisplayMode
*p_selected
= NULL
;
477 IDeckLinkDisplayModeIterator
*p_iterator
= NULL
;
479 for(int i
=0; i
<4 && p_selected
==NULL
; i
++)
481 int i_width
= (i
% 2 == 0) ? fmt
->i_width
: fmt
->i_visible_width
;
482 int i_height
= (i
% 2 == 0) ? fmt
->i_height
: fmt
->i_visible_height
;
483 int i_div
= (i
> 2) ? 4 : 0;
485 result
= output
->GetDisplayModeIterator(&p_iterator
);
488 IDeckLinkDisplayMode
*p_mode
= NULL
;
489 while(p_iterator
->Next(&p_mode
) == S_OK
)
491 BMDDisplayMode mode_id
= p_mode
->GetDisplayMode();
492 BMDTimeValue frameduration
;
493 BMDTimeScale timescale
;
496 decklink_str_t tmp_name
;
497 if(p_mode
->GetFrameRate(&frameduration
, ×cale
) == S_OK
&&
498 p_mode
->GetName(&tmp_name
) == S_OK
)
500 BMDDisplayMode modenl
= htonl(mode_id
);
501 psz_mode_name
= DECKLINK_STRDUP(tmp_name
);
502 DECKLINK_FREE(tmp_name
);
506 BMDFieldDominance field
= htonl(p_mode
->GetFieldDominance());
507 msg_Dbg(vd
, "Found mode '%4.4s': %s (%ldx%ld, %.3f fps, %4.4s, scale %" PRId64
" dur %" PRId64
")",
508 (char*)&modenl
, psz_mode_name
,
509 p_mode
->GetWidth(), p_mode
->GetHeight(),
510 double(timescale
) / frameduration
,
512 timescale
, frameduration
);
522 if(forcedmode
!= bmdDisplayModeNotSupported
&& unlikely(!p_selected
))
524 BMDDisplayMode modenl
= htonl(forcedmode
);
525 msg_Dbg(vd
, "Forced mode '%4.4s'", (char *)&modenl
);
526 if(forcedmode
== mode_id
)
533 if(p_selected
== NULL
&& forcedmode
== bmdDisplayModeNotSupported
)
535 if(i_width
>> i_div
== p_mode
->GetWidth() >> i_div
&&
536 i_height
>> i_div
== p_mode
->GetHeight() >> i_div
)
538 unsigned int num_deck
, den_deck
;
539 unsigned int num_stream
, den_stream
;
540 vlc_ureduce(&num_deck
, &den_deck
, timescale
, frameduration
, 0);
541 vlc_ureduce(&num_stream
, &den_stream
,
542 fmt
->i_frame_rate
, fmt
->i_frame_rate_base
, 0);
544 if (num_deck
== num_stream
&& den_deck
== den_stream
)
546 msg_Info(vd
, "Matches incoming stream");
555 p_iterator
->Release();
561 static int OpenDecklink(vout_display_t
*vd
, decklink_sys_t
*sys
)
563 #define CHECK(message) do { \
564 if (result != S_OK) \
566 const char *psz_err = lookup_error_string(result); \
568 msg_Err(vd, message ": %s", psz_err); \
570 msg_Err(vd, message ": 0x%X", result); \
576 IDeckLinkIterator
*decklink_iterator
= NULL
;
577 IDeckLinkDisplayMode
*p_display_mode
= NULL
;
578 IDeckLinkConfiguration
*p_config
= NULL
;
579 IDeckLinkAttributes
*p_attributes
= NULL
;
580 IDeckLink
*p_card
= NULL
;
581 BMDDisplayMode wanted_mode_id
= bmdDisplayModeNotSupported
;
583 vlc_mutex_lock(&sys
->lock
);
585 /* wait until aout is ready */
586 msg_Info(vd
, "Waiting for DeckLink audio input module to start");
587 while (sys
->i_rate
== -1)
588 vlc_cond_wait(&sys
->cond
, &sys
->lock
);
590 int i_card_index
= var_InheritInteger(vd
, CFG_PREFIX
"card-index");
591 char *mode
= var_InheritString(vd
, VIDEO_CFG_PREFIX
"mode");
595 size_t len
= strlen(mode
);
599 msg_Err(vd
, "Invalid mode %s", mode
);
602 memset(&wanted_mode_id
, ' ', 4);
603 strncpy((char*)&wanted_mode_id
, mode
, 4);
604 wanted_mode_id
= ntohl(wanted_mode_id
);
608 if (i_card_index
< 0)
610 msg_Err(vd
, "Invalid card index %d", i_card_index
);
614 decklink_iterator
= CreateDeckLinkIteratorInstance();
615 if (!decklink_iterator
)
617 msg_Err(vd
, "DeckLink drivers not found.");
621 for(int i
= 0; i
<= i_card_index
; ++i
)
625 result
= decklink_iterator
->Next(&p_card
);
626 CHECK("Card not found");
629 decklink_str_t tmp_name
;
630 char *psz_model_name
;
631 result
= p_card
->GetModelName(&tmp_name
);
632 CHECK("Unknown model name");
633 psz_model_name
= DECKLINK_STRDUP(tmp_name
);
634 DECKLINK_FREE(tmp_name
);
636 msg_Dbg(vd
, "Opened DeckLink PCI card %s", psz_model_name
);
637 free(psz_model_name
);
639 /* Read attributes */
641 result
= p_card
->QueryInterface(IID_IDeckLinkAttributes
, (void**)&p_attributes
);
642 CHECK("Could not get IDeckLinkAttributes");
645 result
= p_attributes
->GetInt(BMDDeckLinkVideoOutputConnections
, &vconn
); /* reads mask */
646 CHECK("Could not get BMDDeckLinkVideoOutputConnections");
648 result
= p_card
->QueryInterface(IID_IDeckLinkOutput
,
649 (void**)&sys
->p_output
);
652 result
= p_card
->QueryInterface(IID_IDeckLinkConfiguration
,
654 CHECK("Could not get config interface");
656 /* Now configure card */
658 vconn
= getVConn(vd
, (BMDVideoConnection
) vconn
);
661 msg_Err(vd
, "Invalid video connection specified");
665 result
= p_config
->SetInt(bmdDeckLinkConfigVideoOutputConnection
, (BMDVideoConnection
) vconn
);
666 CHECK("Could not set video output connection");
668 p_display_mode
= MatchDisplayMode(vd
, sys
->p_output
,
669 &vd
->fmt
, wanted_mode_id
);
670 if(p_display_mode
== NULL
)
672 msg_Err(vd
, "Could not negociate a compatible display mode");
677 BMDDisplayMode mode_id
= p_display_mode
->GetDisplayMode();
678 BMDDisplayMode modenl
= htonl(mode_id
);
679 msg_Dbg(vd
, "Selected mode '%4.4s'", (char *) &modenl
);
681 BMDVideoOutputFlags flags
= bmdVideoOutputVANC
;
682 if (mode_id
== bmdModeNTSC
||
683 mode_id
== bmdModeNTSC2398
||
684 mode_id
== bmdModePAL
)
686 flags
= bmdVideoOutputVITC
;
689 BMDDisplayModeSupport support
;
690 IDeckLinkDisplayMode
*resultMode
;
692 result
= sys
->p_output
->DoesSupportVideoMode(mode_id
,
693 sys
->video
.tenbits
? bmdFormat10BitYUV
: bmdFormat8BitYUV
,
694 flags
, &support
, &resultMode
);
695 CHECK("Does not support video mode");
696 if (support
== bmdDisplayModeNotSupported
)
698 msg_Err(vd
, "Video mode not supported");
702 if (p_display_mode
->GetWidth() <= 0 || p_display_mode
->GetWidth() & 1)
704 msg_Err(vd
, "Unknown video mode specified.");
708 result
= p_display_mode
->GetFrameRate(&sys
->frameduration
,
710 CHECK("Could not read frame rate");
712 result
= sys
->p_output
->EnableVideoOutput(mode_id
, flags
);
713 CHECK("Could not enable video output");
715 video_format_t
*fmt
= &sys
->video
.currentfmt
;
716 video_format_Copy(fmt
, &vd
->fmt
);
717 fmt
->i_width
= fmt
->i_visible_width
= p_display_mode
->GetWidth();
718 fmt
->i_height
= fmt
->i_visible_height
= p_display_mode
->GetHeight();
723 fmt
->i_chroma
= !sys
->video
.tenbits
? VLC_CODEC_UYVY
: VLC_CODEC_I422_10L
; /* we will convert to v210 */
724 fmt
->i_frame_rate
= (unsigned) sys
->frameduration
;
725 fmt
->i_frame_rate_base
= (unsigned) sys
->timescale
;
728 if (/*decklink_sys->i_channels > 0 &&*/ sys
->i_rate
> 0)
730 result
= sys
->p_output
->EnableAudioOutput(
732 bmdAudioSampleType16bitInteger
,
733 /*decklink_sys->i_channels*/ 2,
734 bmdAudioOutputStreamTimestamped
);
735 CHECK("Could not start audio output");
739 result
= sys
->p_output
->StartScheduledPlayback(
740 samples_from_vlc_tick(vlc_tick_now(), sys
->timescale
), sys
->timescale
, 1.0);
741 CHECK("Could not start playback");
744 p_display_mode
->Release();
746 p_attributes
->Release();
747 decklink_iterator
->Release();
749 vlc_mutex_unlock(&sys
->lock
);
755 sys
->p_output
->Release();
756 sys
->p_output
= NULL
;
763 p_attributes
->Release();
764 if (decklink_iterator
)
765 decklink_iterator
->Release();
767 p_display_mode
->Release();
769 vlc_mutex_unlock(&sys
->lock
);
775 /*****************************************************************************
777 *****************************************************************************/
779 static picture_pool_t
*PoolVideo(vout_display_t
*vd
, unsigned requested_count
)
781 struct decklink_sys_t
*sys
= (struct decklink_sys_t
*) vd
->sys
;
782 if (!sys
->video
.pool
)
783 sys
->video
.pool
= picture_pool_NewFromFormat(&vd
->fmt
, requested_count
);
784 return sys
->video
.pool
;
787 static inline void put_le32(uint8_t **p
, uint32_t d
)
793 static inline int clip(int a
)
796 else if (a
> 1019) return 1019;
800 static void v210_convert(void *frame_bytes
, picture_t
*pic
, int dst_stride
)
802 int width
= pic
->format
.i_width
;
803 int height
= pic
->format
.i_height
;
804 int line_padding
= dst_stride
- ((width
* 8 + 11) / 12) * 4;
806 uint8_t *data
= (uint8_t*)frame_bytes
;
808 const uint16_t *y
= (const uint16_t*)pic
->p
[0].p_pixels
;
809 const uint16_t *u
= (const uint16_t*)pic
->p
[1].p_pixels
;
810 const uint16_t *v
= (const uint16_t*)pic
->p
[2].p_pixels
;
812 #define WRITE_PIXELS(a, b, c) \
815 val |= (clip(*b++) << 10) | \
816 (clip(*c++) << 20); \
817 put_le32(&data, val); \
820 for (h
= 0; h
< height
; h
++) {
822 for (w
= 0; w
< width
- 5; w
+= 6) {
823 WRITE_PIXELS(u
, y
, v
);
824 WRITE_PIXELS(y
, u
, y
);
825 WRITE_PIXELS(v
, y
, u
);
826 WRITE_PIXELS(y
, v
, y
);
829 WRITE_PIXELS(u
, y
, v
);
833 put_le32(&data
, val
);
837 val
|= (clip(*u
++) << 10) | (clip(*y
++) << 20);
838 put_le32(&data
, val
);
840 val
= clip(*v
++) | (clip(*y
++) << 10);
841 put_le32(&data
, val
);
844 memset(data
, 0, line_padding
);
845 data
+= line_padding
;
847 y
+= pic
->p
[0].i_pitch
/ 2 - width
;
848 u
+= pic
->p
[1].i_pitch
/ 2 - width
/ 2;
849 v
+= pic
->p
[2].i_pitch
/ 2 - width
/ 2;
853 static void send_AFD(uint8_t afdcode
, uint8_t ar
, uint8_t *buf
)
855 const size_t len
= 6 /* vanc header */ + 8 /* AFD data */ + 1 /* csum */;
856 const size_t s
= ((len
+ 5) / 6) * 6; // align for v210
863 afd
[3] = 0x41; // DID
864 afd
[4] = 0x05; // SDID
865 afd
[5] = 8; // Data Count
867 int bar_data_flags
= 0;
868 int bar_data_val1
= 0;
869 int bar_data_val2
= 0;
871 afd
[ 6] = ((afdcode
& 0x0F) << 3) | ((ar
& 0x01) << 2); /* SMPTE 2016-1 */
872 afd
[ 7] = 0; // reserved
873 afd
[ 8] = 0; // reserved
874 afd
[ 9] = bar_data_flags
<< 4;
875 afd
[10] = bar_data_val1
<< 8;
876 afd
[11] = bar_data_val1
& 0xff;
877 afd
[12] = bar_data_val2
<< 8;
878 afd
[13] = bar_data_val2
& 0xff;
881 for (size_t i
= 3; i
< len
- 1; i
++)
882 afd
[i
] |= vlc_parity((unsigned)afd
[i
]) ? 0x100 : 0x200;
885 uint16_t vanc_sum
= 0;
886 for (size_t i
= 3; i
< len
- 1; i
++) {
891 afd
[len
- 1] = vanc_sum
| ((~vanc_sum
& 0x100) << 1);
894 for (size_t i
= len
; i
< s
; i
++)
897 /* convert to v210 and write into VANC */
898 for (size_t w
= 0; w
< s
/ 6 ; w
++) {
899 put_le32(&buf
, afd
[w
*6+0] << 10);
900 put_le32(&buf
, afd
[w
*6+1] | (afd
[w
*6+2] << 20));
901 put_le32(&buf
, afd
[w
*6+3] << 10);
902 put_le32(&buf
, afd
[w
*6+4] | (afd
[w
*6+5] << 20));
906 static void PrepareVideo(vout_display_t
*vd
, picture_t
*picture
, subpicture_t
*,
909 decklink_sys_t
*sys
= (decklink_sys_t
*) vd
->sys
;
910 vlc_tick_t now
= vlc_tick_now();
915 if (now
- date
> vlc_tick_from_sec( sys
->video
.nosignal_delay
)) {
916 msg_Dbg(vd
, "no signal");
917 if (sys
->video
.pic_nosignal
) {
918 picture
= sys
->video
.pic_nosignal
;
920 if (sys
->video
.tenbits
) { // I422_10L
921 plane_t
*y
= &picture
->p
[0];
922 memset(y
->p_pixels
, 0x0, y
->i_lines
* y
->i_pitch
);
923 for (int i
= 1; i
< picture
->i_planes
; i
++) {
924 plane_t
*p
= &picture
->p
[i
];
925 size_t len
= p
->i_lines
* p
->i_pitch
/ 2;
926 int16_t *data
= (int16_t*)p
->p_pixels
;
927 for (size_t j
= 0; j
< len
; j
++) // XXX: SIMD
931 size_t len
= picture
->p
[0].i_lines
* picture
->p
[0].i_pitch
;
932 for (size_t i
= 0; i
< len
; i
+= 2) { // XXX: SIMD
933 picture
->p
[0].p_pixels
[i
+0] = 0x80;
934 picture
->p
[0].p_pixels
[i
+1] = 0;
942 int w
, h
, stride
, length
;
944 h
= vd
->fmt
.i_height
;
946 IDeckLinkMutableVideoFrame
*pDLVideoFrame
;
947 result
= sys
->p_output
->CreateVideoFrame(w
, h
, w
*3,
948 sys
->video
.tenbits
? bmdFormat10BitYUV
: bmdFormat8BitYUV
,
949 bmdFrameFlagDefault
, &pDLVideoFrame
);
951 if (result
!= S_OK
) {
952 msg_Err(vd
, "Failed to create video frame: 0x%X", result
);
953 pDLVideoFrame
= NULL
;
958 pDLVideoFrame
->GetBytes((void**)&frame_bytes
);
959 stride
= pDLVideoFrame
->GetRowBytes();
961 if (sys
->video
.tenbits
) {
962 IDeckLinkVideoFrameAncillary
*vanc
;
966 result
= sys
->p_output
->CreateAncillaryData(
967 sys
->video
.tenbits
? bmdFormat10BitYUV
: bmdFormat8BitYUV
, &vanc
);
968 if (result
!= S_OK
) {
969 msg_Err(vd
, "Failed to create vanc: %d", result
);
973 line
= var_InheritInteger(vd
, VIDEO_CFG_PREFIX
"afd-line");
974 result
= vanc
->GetBufferForVerticalBlankingLine(line
, &buf
);
975 if (result
!= S_OK
) {
976 msg_Err(vd
, "Failed to get VBI line %d: %d", line
, result
);
979 send_AFD(sys
->video
.afd
, sys
->video
.ar
, (uint8_t*)buf
);
981 v210_convert(frame_bytes
, picture
, stride
);
983 result
= pDLVideoFrame
->SetAncillaryData(vanc
);
985 if (result
!= S_OK
) {
986 msg_Err(vd
, "Failed to set vanc: %d", result
);
990 else for(int y
= 0; y
< h
; ++y
) {
991 uint8_t *dst
= (uint8_t *)frame_bytes
+ stride
* y
;
992 const uint8_t *src
= (const uint8_t *)picture
->p
[0].p_pixels
+
993 picture
->p
[0].i_pitch
* y
;
994 memcpy(dst
, src
, w
* 2 /* bpp */);
998 // compute frame duration in CLOCK_FREQ units
999 length
= (sys
->frameduration
* CLOCK_FREQ
) / sys
->timescale
;
1001 date
-= sys
->offset
;
1002 result
= sys
->p_output
->ScheduleVideoFrame(pDLVideoFrame
,
1003 date
, length
, CLOCK_FREQ
);
1005 if (result
!= S_OK
) {
1006 msg_Err(vd
, "Dropped Video frame %" PRId64
": 0x%x", date
, result
);
1010 now
= vlc_tick_now() - sys
->offset
;
1012 BMDTimeValue decklink_now
;
1014 sys
->p_output
->GetScheduledStreamTime (CLOCK_FREQ
, &decklink_now
, &speed
);
1016 if ((now
- decklink_now
) > 400000) {
1017 /* XXX: workaround card clock drift */
1018 sys
->offset
+= 50000;
1019 msg_Err(vd
, "Delaying: offset now %" PRId64
, sys
->offset
);
1024 pDLVideoFrame
->Release();
1027 static int ControlVideo(vout_display_t
*vd
, int query
, va_list args
)
1029 (void) vd
; (void) query
; (void) args
;
1030 return VLC_EGENERIC
;
1033 static int OpenVideo(vlc_object_t
*p_this
)
1035 vout_display_t
*vd
= (vout_display_t
*)p_this
;
1036 decklink_sys_t
*sys
= HoldDLSys(p_this
, VIDEO_ES
);
1040 vd
->sys
= (vout_display_sys_t
*) sys
;
1043 vlc_mutex_lock(&sys
->lock
);
1044 b_init
= !sys
->b_recycling
;
1045 vlc_mutex_unlock(&sys
->lock
);
1049 sys
->video
.tenbits
= var_InheritBool(p_this
, VIDEO_CFG_PREFIX
"tenbits");
1050 sys
->video
.nosignal_delay
= var_InheritInteger(p_this
, VIDEO_CFG_PREFIX
"nosignal-delay");
1051 sys
->video
.afd
= var_InheritInteger(p_this
, VIDEO_CFG_PREFIX
"afd");
1052 sys
->video
.ar
= var_InheritInteger(p_this
, VIDEO_CFG_PREFIX
"ar");
1053 sys
->video
.pic_nosignal
= NULL
;
1054 sys
->video
.pool
= NULL
;
1056 if (OpenDecklink(vd
, sys
) != VLC_SUCCESS
)
1059 return VLC_EGENERIC
;
1062 char *pic_file
= var_InheritString(p_this
, VIDEO_CFG_PREFIX
"nosignal-image");
1065 sys
->video
.pic_nosignal
= CreateNoSignalPicture(p_this
, &vd
->fmt
, pic_file
);
1066 if (!sys
->video
.pic_nosignal
)
1067 msg_Err(p_this
, "Could not create no signal picture");
1072 /* vout must adapt */
1073 video_format_Clean( &vd
->fmt
);
1074 video_format_Copy( &vd
->fmt
, &sys
->video
.currentfmt
);
1076 vd
->pool
= PoolVideo
;
1077 vd
->prepare
= PrepareVideo
;
1079 vd
->control
= ControlVideo
;
1084 static void CloseVideo(vlc_object_t
*p_this
)
1086 ReleaseDLSys(p_this
, VIDEO_ES
);
1089 /*****************************************************************************
1091 *****************************************************************************/
1093 static void Flush (audio_output_t
*aout
, bool drain
)
1095 decklink_sys_t
*sys
= (decklink_sys_t
*) aout
->sys
;
1096 vlc_mutex_lock(&sys
->lock
);
1097 IDeckLinkOutput
*p_output
= sys
->p_output
;
1098 vlc_mutex_unlock(&sys
->lock
);
1104 sys
->p_output
->GetBufferedAudioSampleFrameCount(&samples
);
1105 vlc_tick_sleep(vlc_tick_from_samples(samples
, sys
->i_rate
));
1106 } else if (sys
->p_output
->FlushBufferedAudioSamples() == E_FAIL
)
1107 msg_Err(aout
, "Flush failed");
1110 static int TimeGet(audio_output_t
*, vlc_tick_t
* restrict
)
1112 /* synchronization is handled by the card */
1116 static int Start(audio_output_t
*aout
, audio_sample_format_t
*restrict fmt
)
1118 decklink_sys_t
*sys
= (decklink_sys_t
*) aout
->sys
;
1120 if (sys
->i_rate
== 0)
1121 return VLC_EGENERIC
;
1123 fmt
->i_format
= VLC_CODEC_S16N
;
1124 fmt
->i_channels
= 2; //decklink_sys->i_channels;
1125 fmt
->i_physical_channels
= AOUT_CHANS_STEREO
; //pi_channels_maps[fmt->i_channels];
1126 fmt
->channel_type
= AUDIO_CHANNEL_TYPE_BITMAP
;
1127 fmt
->i_rate
= sys
->i_rate
;
1128 fmt
->i_bitspersample
= 16;
1129 fmt
->i_blockalign
= fmt
->i_channels
* fmt
->i_bitspersample
/8 ;
1130 fmt
->i_frame_length
= FRAME_SIZE
;
1135 static void PlayAudio(audio_output_t
*aout
, block_t
*audio
, vlc_tick_t systempts
)
1137 decklink_sys_t
*sys
= (decklink_sys_t
*) aout
->sys
;
1138 vlc_mutex_lock(&sys
->lock
);
1139 IDeckLinkOutput
*p_output
= sys
->p_output
;
1140 audio
->i_pts
-= sys
->offset
;
1141 vlc_mutex_unlock(&sys
->lock
);
1143 block_Release(audio
);
1147 uint32_t sampleFrameCount
= audio
->i_buffer
/ (2 * 2 /*decklink_sys->i_channels*/);
1149 HRESULT result
= p_output
->ScheduleAudioSamples(
1150 audio
->p_buffer
, sampleFrameCount
, systempts
, CLOCK_FREQ
, &written
);
1153 msg_Err(aout
, "Failed to schedule audio sample: 0x%X", result
);
1154 else if (sampleFrameCount
!= written
)
1155 msg_Err(aout
, "Written only %d samples out of %d", written
, sampleFrameCount
);
1157 block_Release(audio
);
1160 static int OpenAudio(vlc_object_t
*p_this
)
1162 audio_output_t
*aout
= (audio_output_t
*)p_this
;
1163 decklink_sys_t
*sys
= HoldDLSys(p_this
, AUDIO_ES
);
1169 vlc_mutex_lock(&sys
->lock
);
1170 //decklink_sys->i_channels = var_InheritInteger(vd, AUDIO_CFG_PREFIX "audio-channels");
1171 sys
->i_rate
= var_InheritInteger(aout
, AUDIO_CFG_PREFIX
"audio-rate");
1172 vlc_cond_signal(&sys
->cond
);
1173 vlc_mutex_unlock(&sys
->lock
);
1175 aout
->play
= PlayAudio
;
1176 aout
->start
= Start
;
1177 aout
->flush
= Flush
;
1178 aout
->time_get
= TimeGet
;
1180 aout
->pause
= aout_PauseDefault
;
1182 aout
->mute_set
= NULL
;
1183 aout
->volume_set
= NULL
;
1188 static void CloseAudio(vlc_object_t
*p_this
)
1190 decklink_sys_t
*sys
= (decklink_sys_t
*) ((audio_output_t
*)p_this
)->sys
;
1191 vlc_mutex_lock(&sys
->lock
);
1192 vlc_mutex_unlock(&sys
->lock
);
1193 ReleaseDLSys(p_this
, AUDIO_ES
);