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>
42 #include <vlc_block.h>
44 #include <vlc_cxx_helpers.hpp>
46 #ifdef HAVE_ARPA_INET_H
47 #include <arpa/inet.h>
50 #include "../access/vlc_decklink.h"
51 #include "../stream_out/sdi/V210.hpp"
52 #include "../stream_out/sdi/Ancillary.hpp"
53 #include "../stream_out/sdi/DBMHelper.hpp"
54 #include "../stream_out/sdi/SDIGenerator.hpp"
55 #include <DeckLinkAPIDispatch.cpp>
56 #include <DeckLinkAPIVersion.h>
57 #if BLACKMAGIC_DECKLINK_API_VERSION < 0x0b010000
58 #define IID_IDeckLinkProfileAttributes IID_IDeckLinkAttributes
59 #define IDeckLinkProfileAttributes IDeckLinkAttributes
62 #define FRAME_SIZE 1920
63 #define CHANNELS_MAX 6
66 static const int pi_channels_maps
[CHANNELS_MAX
+1] =
78 #define NOSIGNAL_INDEX_TEXT N_("Timelength after which we assume there is no signal.")
79 #define NOSIGNAL_INDEX_LONGTEXT N_(\
80 "Timelength after which we assume there is no signal.\n"\
81 "After this delay we black out the video."\
84 #define AFD_INDEX_TEXT N_("Active Format Descriptor value")
86 #define AR_INDEX_TEXT N_("Aspect Ratio")
87 #define AR_INDEX_LONGTEXT N_("Aspect Ratio of the source picture.")
89 #define AFDLINE_INDEX_TEXT N_("Active Format Descriptor line")
90 #define AFDLINE_INDEX_LONGTEXT N_("VBI line on which to output Active Format Descriptor.")
92 #define NOSIGNAL_IMAGE_TEXT N_("Picture to display on input signal loss")
93 #define NOSIGNAL_IMAGE_LONGTEXT NOSIGNAL_IMAGE_TEXT
95 #define CARD_INDEX_TEXT N_("Output card")
96 #define CARD_INDEX_LONGTEXT N_(\
97 "DeckLink output card, if multiple exist. " \
98 "The cards are numbered from 0.")
100 #define MODE_TEXT N_("Desired output mode")
101 #define MODE_LONGTEXT N_(\
102 "Desired output mode for DeckLink output. " \
103 "This value should be a FOURCC code in textual " \
104 "form, e.g. \"ntsc\".")
106 #define AUDIO_CONNECTION_TEXT N_("Audio connection")
107 #define AUDIO_CONNECTION_LONGTEXT N_(\
108 "Audio connection for DeckLink output.")
111 #define RATE_TEXT N_("Audio samplerate (Hz)")
112 #define RATE_LONGTEXT N_(\
113 "Audio sampling rate (in hertz) for DeckLink output. " \
114 "0 disables audio output.")
116 #define CHANNELS_TEXT N_("Number of audio channels")
117 #define CHANNELS_LONGTEXT N_(\
118 "Number of output channels for DeckLink output. " \
119 "Must be 2, 8 or 16. 0 disables audio output.")
121 #define VIDEO_CONNECTION_TEXT N_("Video connection")
122 #define VIDEO_CONNECTION_LONGTEXT N_(\
123 "Video connection for DeckLink output.")
125 #define VIDEO_TENBITS_TEXT N_("10 bits")
126 #define VIDEO_TENBITS_LONGTEXT N_(\
127 "Use 10 bits per pixel for video frames.")
129 #define CFG_PREFIX "decklink-output-"
130 #define VIDEO_CFG_PREFIX "decklink-vout-"
131 #define AUDIO_CFG_PREFIX "decklink-aout-"
133 /* Video Connections */
134 static const char *const ppsz_videoconns
[] = {
142 static const char *const ppsz_videoconns_text
[] = {
150 static const BMDVideoConnection rgbmd_videoconns
[] =
152 bmdVideoConnectionSDI
,
153 bmdVideoConnectionHDMI
,
154 bmdVideoConnectionOpticalSDI
,
155 bmdVideoConnectionComponent
,
156 bmdVideoConnectionComposite
,
157 bmdVideoConnectionSVideo
,
159 static_assert(ARRAY_SIZE(rgbmd_videoconns
) == ARRAY_SIZE(ppsz_videoconns
), "videoconn arrays messed up");
160 static_assert(ARRAY_SIZE(rgbmd_videoconns
) == ARRAY_SIZE(ppsz_videoconns_text
), "videoconn arrays messed up");
162 static const int rgi_afd_values
[] = {
163 0, 2, 3, 4, 8, 9, 10, 11, 13, 14, 15,
165 static const char * const rgsz_afd_text
[] = {
167 "2: Box 16:9 (top aligned)",
168 "3: Box 14:9 (top aligned)",
169 "4: Box > 16:9 (centre aligned)",
170 "8: Same as coded frame (full frame)",
171 "9: 4:3 (centre aligned)",
172 "10: 16:9 (centre aligned)",
173 "11: 14:9 (centre aligned)",
174 "13: 4:3 (with shoot and protect 14:9 centre)",
175 "14: 16:9 (with shoot and protect 14:9 centre)",
176 "15: 16:9 (with shoot and protect 4:3 centre)",
178 static_assert(ARRAY_SIZE(rgi_afd_values
) == ARRAY_SIZE(rgsz_afd_text
), "afd arrays messed up");
180 static const int rgi_ar_values
[] = {
183 static const char * const rgsz_ar_text
[] = {
187 static_assert(ARRAY_SIZE(rgi_ar_values
) == ARRAY_SIZE(rgsz_ar_text
), "afd arrays messed up");
191 /* Only one audio output module and one video output module
192 * can be used per process.
193 * We use a static mutex in audio/video submodules entry points. */
194 struct decklink_sys_t
197 IDeckLinkOutput
*p_output
;
200 * Synchronizes aout and vout modules:
201 * vout module waits until aout has been initialized.
202 * That means video-only output is NOT supported.
213 BMDTimeScale timescale
;
214 BMDTimeValue frameduration
;
216 /* XXX: workaround card clock drift */
221 /* single video module exclusive */
227 picture_t
*pic_nosignal
;
233 /*****************************************************************************
235 *****************************************************************************/
237 static int OpenVideo (vout_display_t
*, const vout_display_cfg_t
*,
238 video_format_t
*, vlc_video_context
*);
239 static void CloseVideo (vout_display_t
*);
240 static int OpenAudio (vlc_object_t
*);
241 static void CloseAudio (vlc_object_t
*);
243 /*****************************************************************************
245 *****************************************************************************/
248 set_shortname(N_("DecklinkOutput"))
249 set_description(N_("Output module to write to Blackmagic SDI card"))
250 set_section(N_("DeckLink General Options"), NULL
)
251 add_integer(CFG_PREFIX
"card-index", 0,
252 CARD_INDEX_TEXT
, CARD_INDEX_LONGTEXT
, true)
255 set_description (N_("DeckLink Video Output module"))
256 set_category(CAT_VIDEO
)
257 set_subcategory(SUBCAT_VIDEO_VOUT
)
258 set_callback_display(OpenVideo
, 0)
259 set_section(N_("DeckLink Video Options"), NULL
)
260 add_string(VIDEO_CFG_PREFIX
"video-connection", "sdi",
261 VIDEO_CONNECTION_TEXT
, VIDEO_CONNECTION_LONGTEXT
, true)
262 change_string_list(ppsz_videoconns
, ppsz_videoconns_text
)
263 add_string(VIDEO_CFG_PREFIX
"mode", "",
264 MODE_TEXT
, MODE_LONGTEXT
, true)
265 add_bool(VIDEO_CFG_PREFIX
"tenbits", true,
266 VIDEO_TENBITS_TEXT
, VIDEO_TENBITS_LONGTEXT
, true)
267 add_integer(VIDEO_CFG_PREFIX
"nosignal-delay", 5,
268 NOSIGNAL_INDEX_TEXT
, NOSIGNAL_INDEX_LONGTEXT
, true)
269 add_integer(VIDEO_CFG_PREFIX
"afd-line", 16,
270 AFDLINE_INDEX_TEXT
, AFDLINE_INDEX_LONGTEXT
, true)
271 add_integer_with_range(VIDEO_CFG_PREFIX
"afd", 8, 0, 16,
272 AFD_INDEX_TEXT
, AFD_INDEX_TEXT
, true)
273 change_integer_list(rgi_afd_values
, rgsz_afd_text
)
274 add_integer_with_range(VIDEO_CFG_PREFIX
"ar", 1, 0, 1,
275 AR_INDEX_TEXT
, AR_INDEX_LONGTEXT
, true)
276 change_integer_list(rgi_ar_values
, rgsz_ar_text
)
277 add_loadfile(VIDEO_CFG_PREFIX
"nosignal-image", NULL
,
278 NOSIGNAL_IMAGE_TEXT
, NOSIGNAL_IMAGE_LONGTEXT
)
282 set_description (N_("DeckLink Audio Output module"))
283 set_category(CAT_AUDIO
)
284 set_subcategory(SUBCAT_AUDIO_AOUT
)
285 set_capability("audio output", 0)
286 set_callbacks (OpenAudio
, CloseAudio
)
287 set_section(N_("DeckLink Audio Options"), NULL
)
288 add_obsolete_string("audio-connection")
289 add_integer(AUDIO_CFG_PREFIX
"audio-rate", 48000,
290 RATE_TEXT
, RATE_LONGTEXT
, true)
291 add_integer(AUDIO_CFG_PREFIX
"audio-channels", 2,
292 CHANNELS_TEXT
, CHANNELS_LONGTEXT
, true)
295 /* Protects decklink_sys_t creation/deletion */
296 static vlc::threads::mutex sys_lock
;
298 static decklink_sys_t
*HoldDLSys(vlc_object_t
*obj
, int i_cat
)
300 vlc_object_t
*libvlc
= VLC_OBJECT(vlc_object_instance(obj
));
305 if (var_Type(libvlc
, "decklink-sys") == VLC_VAR_ADDRESS
)
307 sys
= (decklink_sys_t
*)var_GetAddress(libvlc
, "decklink-sys");
310 if(i_cat
== VIDEO_ES
)
312 while(sys
->b_videomodule
)
315 msg_Info(obj
, "Waiting for previous vout module to exit");
316 vlc_tick_sleep(VLC_TICK_FROM_MS(100));
323 sys
= (decklink_sys_t
*)malloc(sizeof(*sys
));
325 sys
->p_output
= NULL
;
328 sys
->b_videomodule
= (i_cat
== VIDEO_ES
);
329 sys
->b_recycling
= false;
330 sys
->i_rate
= var_InheritInteger(obj
, AUDIO_CFG_PREFIX
"audio-rate");
333 vlc_mutex_init(&sys
->lock
);
334 vlc_cond_init(&sys
->cond
);
335 var_Create(libvlc
, "decklink-sys", VLC_VAR_ADDRESS
);
336 var_SetAddress(libvlc
, "decklink-sys", (void*)sys
);
344 static void ReleaseDLSys(vlc_object_t
*obj
, int i_cat
)
346 vlc_object_t
*libvlc
= VLC_OBJECT(vlc_object_instance(obj
));
350 struct decklink_sys_t
*sys
= (struct decklink_sys_t
*)var_GetAddress(libvlc
, "decklink-sys");
352 if (--sys
->users
== 0) {
353 msg_Dbg(obj
, "Destroying decklink data");
356 sys
->p_output
->StopScheduledPlayback(0, NULL
, 0);
357 sys
->p_output
->DisableVideoOutput();
358 sys
->p_output
->DisableAudioOutput();
359 sys
->p_output
->Release();
362 /* Clean video specific */
363 if (sys
->video
.pic_nosignal
)
364 picture_Release(sys
->video
.pic_nosignal
);
367 var_Destroy(libvlc
, "decklink-sys");
369 else if (i_cat
== VIDEO_ES
)
371 sys
->b_videomodule
= false;
372 sys
->b_recycling
= true;
378 static BMDVideoConnection
getVConn(vout_display_t
*vd
, BMDVideoConnection mask
)
380 BMDVideoConnection conn
= 0;
381 char *psz
= var_InheritString(vd
, VIDEO_CFG_PREFIX
"video-connection");
384 for(size_t i
=0; i
<ARRAY_SIZE(rgbmd_videoconns
); i
++)
386 if (!strcmp(psz
, ppsz_videoconns
[i
]) && (mask
& rgbmd_videoconns
[i
]))
388 conn
= rgbmd_videoconns
[i
];
394 else /* Pick one as default connection */
396 conn
= vlc_ctz(mask
);
397 conn
= conn
? ( 1 << conn
) : bmdVideoConnectionSDI
;
402 /*****************************************************************************
404 *****************************************************************************/
405 static int OpenDecklink(vout_display_t
*vd
, decklink_sys_t
*sys
, video_format_t
*fmt
)
407 #define CHECK(message) do { \
408 if (result != S_OK) \
410 const char *psz_err = Decklink::Helper::ErrorToString(result); \
412 msg_Err(vd, message ": %s", psz_err); \
414 msg_Err(vd, message ": 0x%X", result); \
420 IDeckLinkIterator
*decklink_iterator
= NULL
;
421 IDeckLinkDisplayMode
*p_display_mode
= NULL
;
422 IDeckLinkConfiguration
*p_config
= NULL
;
423 IDeckLinkProfileAttributes
*p_attributes
= NULL
;
424 IDeckLink
*p_card
= NULL
;
425 BMDDisplayMode wanted_mode_id
= bmdModeUnknown
;
427 vlc_mutex_lock(&sys
->lock
);
429 /* wait until aout is ready */
430 msg_Info(vd
, "Waiting for DeckLink audio input module to start");
431 while (sys
->i_rate
== -1)
432 vlc_cond_wait(&sys
->cond
, &sys
->lock
);
434 int i_card_index
= var_InheritInteger(vd
, CFG_PREFIX
"card-index");
435 char *mode
= var_InheritString(vd
, VIDEO_CFG_PREFIX
"mode");
439 size_t len
= strlen(mode
);
443 msg_Err(vd
, "Invalid mode %s", mode
);
446 memset(&wanted_mode_id
, ' ', 4);
447 strncpy((char*)&wanted_mode_id
, mode
, 4);
448 wanted_mode_id
= ntohl(wanted_mode_id
);
452 if (i_card_index
< 0)
454 msg_Err(vd
, "Invalid card index %d", i_card_index
);
458 decklink_iterator
= CreateDeckLinkIteratorInstance();
459 if (!decklink_iterator
)
461 msg_Err(vd
, "DeckLink drivers not found.");
465 for(int i
= 0; i
<= i_card_index
; ++i
)
469 result
= decklink_iterator
->Next(&p_card
);
470 CHECK("Card not found");
473 decklink_str_t tmp_name
;
474 char *psz_model_name
;
475 result
= p_card
->GetModelName(&tmp_name
);
476 CHECK("Unknown model name");
477 psz_model_name
= DECKLINK_STRDUP(tmp_name
);
478 DECKLINK_FREE(tmp_name
);
480 msg_Dbg(vd
, "Opened DeckLink PCI card %s", psz_model_name
);
481 free(psz_model_name
);
483 /* Read attributes */
485 result
= p_card
->QueryInterface(IID_IDeckLinkProfileAttributes
, (void**)&p_attributes
);
486 CHECK("Could not get IDeckLinkAttributes");
489 result
= p_attributes
->GetInt(BMDDeckLinkVideoOutputConnections
, &vconn
); /* reads mask */
490 CHECK("Could not get BMDDeckLinkVideoOutputConnections");
492 result
= p_card
->QueryInterface(IID_IDeckLinkOutput
,
493 (void**)&sys
->p_output
);
496 result
= p_card
->QueryInterface(IID_IDeckLinkConfiguration
,
498 CHECK("Could not get config interface");
500 /* Now configure card */
502 vconn
= getVConn(vd
, (BMDVideoConnection
) vconn
);
505 msg_Err(vd
, "Invalid video connection specified");
509 result
= p_config
->SetInt(bmdDeckLinkConfigVideoOutputConnection
, (BMDVideoConnection
) vconn
);
510 CHECK("Could not set video output connection");
512 p_display_mode
= Decklink::Helper::MatchDisplayMode(VLC_OBJECT(vd
), sys
->p_output
,
513 vd
->source
, wanted_mode_id
);
514 if(p_display_mode
== NULL
)
516 msg_Err(vd
, "Could not negociate a compatible display mode");
521 BMDDisplayMode mode_id
= p_display_mode
->GetDisplayMode();
522 BMDDisplayMode modenl
= htonl(mode_id
);
523 msg_Dbg(vd
, "Selected mode '%4.4s'", (char *) &modenl
);
525 BMDPixelFormat pixelFormat
= sys
->video
.tenbits
? bmdFormat10BitYUV
: bmdFormat8BitYUV
;
526 BMDVideoOutputFlags flags
= bmdVideoOutputVANC
;
527 if (mode_id
== bmdModeNTSC
||
528 mode_id
== bmdModeNTSC2398
||
529 mode_id
== bmdModePAL
)
531 flags
= bmdVideoOutputVITC
;
534 #if BLACKMAGIC_DECKLINK_API_VERSION < 0x0b010000
535 BMDDisplayModeSupport support
= bmdDisplayModeNotSupported
;
536 result
= sys
->p_output
->DoesSupportVideoMode(mode_id
,
541 supported
= (support
!= bmdDisplayModeNotSupported
);
543 result
= sys
->p_output
->DoesSupportVideoMode(vconn
,
546 bmdSupportedVideoModeDefault
,
550 CHECK("Does not support video mode");
553 msg_Err(vd
, "Video mode not supported");
557 if (p_display_mode
->GetWidth() <= 0 || p_display_mode
->GetWidth() & 1)
559 msg_Err(vd
, "Unknown video mode specified.");
563 result
= p_display_mode
->GetFrameRate(&sys
->frameduration
,
565 CHECK("Could not read frame rate");
567 result
= sys
->p_output
->EnableVideoOutput(mode_id
, flags
);
568 CHECK("Could not enable video output");
570 video_format_Copy(fmt
, vd
->source
);
571 fmt
->i_width
= fmt
->i_visible_width
= p_display_mode
->GetWidth();
572 fmt
->i_height
= fmt
->i_visible_height
= p_display_mode
->GetHeight();
577 fmt
->i_chroma
= !sys
->video
.tenbits
? VLC_CODEC_UYVY
: VLC_CODEC_I422_10L
; /* we will convert to v210 */
578 fmt
->i_frame_rate
= (unsigned) sys
->frameduration
;
579 fmt
->i_frame_rate_base
= (unsigned) sys
->timescale
;
582 if (/*decklink_sys->i_channels > 0 &&*/ sys
->i_rate
> 0)
584 result
= sys
->p_output
->EnableAudioOutput(
586 bmdAudioSampleType16bitInteger
,
587 /*decklink_sys->i_channels*/ 2,
588 bmdAudioOutputStreamTimestamped
);
589 CHECK("Could not start audio output");
593 result
= sys
->p_output
->StartScheduledPlayback(
594 samples_from_vlc_tick(vlc_tick_now(), sys
->timescale
), sys
->timescale
, 1.0);
595 CHECK("Could not start playback");
598 p_display_mode
->Release();
600 p_attributes
->Release();
601 decklink_iterator
->Release();
603 vlc_mutex_unlock(&sys
->lock
);
609 sys
->p_output
->Release();
610 sys
->p_output
= NULL
;
617 p_attributes
->Release();
618 if (decklink_iterator
)
619 decklink_iterator
->Release();
621 p_display_mode
->Release();
622 video_format_Clean(fmt
);
624 vlc_mutex_unlock(&sys
->lock
);
630 /*****************************************************************************
632 *****************************************************************************/
633 static void PrepareVideo(vout_display_t
*vd
, picture_t
*picture
, subpicture_t
*,
636 decklink_sys_t
*sys
= (decklink_sys_t
*) vd
->sys
;
637 vlc_tick_t now
= vlc_tick_now();
642 if (now
- date
> vlc_tick_from_sec( sys
->video
.nosignal_delay
)) {
643 msg_Dbg(vd
, "no signal");
644 if (sys
->video
.pic_nosignal
) {
645 picture
= sys
->video
.pic_nosignal
;
647 if (sys
->video
.tenbits
) { // I422_10L
648 plane_t
*y
= &picture
->p
[0];
649 memset(y
->p_pixels
, 0x0, y
->i_lines
* y
->i_pitch
);
650 for (int i
= 1; i
< picture
->i_planes
; i
++) {
651 plane_t
*p
= &picture
->p
[i
];
652 size_t len
= p
->i_lines
* p
->i_pitch
/ 2;
653 int16_t *data
= (int16_t*)p
->p_pixels
;
654 for (size_t j
= 0; j
< len
; j
++) // XXX: SIMD
658 size_t len
= picture
->p
[0].i_lines
* picture
->p
[0].i_pitch
;
659 for (size_t i
= 0; i
< len
; i
+= 2) { // XXX: SIMD
660 picture
->p
[0].p_pixels
[i
+0] = 0x80;
661 picture
->p
[0].p_pixels
[i
+1] = 0;
669 int w
, h
, stride
, length
;
670 w
= vd
->fmt
->i_width
;
671 h
= vd
->fmt
->i_height
;
673 IDeckLinkMutableVideoFrame
*pDLVideoFrame
;
674 result
= sys
->p_output
->CreateVideoFrame(w
, h
, w
*3,
675 sys
->video
.tenbits
? bmdFormat10BitYUV
: bmdFormat8BitYUV
,
676 bmdFrameFlagDefault
, &pDLVideoFrame
);
678 if (result
!= S_OK
) {
679 msg_Err(vd
, "Failed to create video frame: 0x%X", result
);
680 pDLVideoFrame
= NULL
;
685 pDLVideoFrame
->GetBytes((void**)&frame_bytes
);
686 stride
= pDLVideoFrame
->GetRowBytes();
688 if (sys
->video
.tenbits
) {
689 IDeckLinkVideoFrameAncillary
*vanc
;
693 result
= sys
->p_output
->CreateAncillaryData(
694 sys
->video
.tenbits
? bmdFormat10BitYUV
: bmdFormat8BitYUV
, &vanc
);
695 if (result
!= S_OK
) {
696 msg_Err(vd
, "Failed to create vanc: %d", result
);
700 line
= var_InheritInteger(vd
, VIDEO_CFG_PREFIX
"afd-line");
701 result
= vanc
->GetBufferForVerticalBlankingLine(line
, &buf
);
702 if (result
!= S_OK
) {
703 msg_Err(vd
, "Failed to get VBI line %d: %d", line
, result
);
707 sdi::AFD
afd(sys
->video
.afd
, sys
->video
.ar
);
708 afd
.FillBuffer(reinterpret_cast<uint8_t*>(buf
), stride
);
710 sdi::V210::Convert(picture
, stride
, frame_bytes
);
712 result
= pDLVideoFrame
->SetAncillaryData(vanc
);
714 if (result
!= S_OK
) {
715 msg_Err(vd
, "Failed to set vanc: %d", result
);
719 else for(int y
= 0; y
< h
; ++y
) {
720 uint8_t *dst
= (uint8_t *)frame_bytes
+ stride
* y
;
721 const uint8_t *src
= (const uint8_t *)picture
->p
[0].p_pixels
+
722 picture
->p
[0].i_pitch
* y
;
723 memcpy(dst
, src
, w
* 2 /* bpp */);
727 // compute frame duration in CLOCK_FREQ units
728 length
= (sys
->frameduration
* CLOCK_FREQ
) / sys
->timescale
;
731 result
= sys
->p_output
->ScheduleVideoFrame(pDLVideoFrame
,
732 date
, length
, CLOCK_FREQ
);
734 if (result
!= S_OK
) {
735 msg_Err(vd
, "Dropped Video frame %" PRId64
": 0x%x", date
, result
);
739 now
= vlc_tick_now() - sys
->offset
;
741 BMDTimeValue decklink_now
;
743 sys
->p_output
->GetScheduledStreamTime (CLOCK_FREQ
, &decklink_now
, &speed
);
745 if ((now
- decklink_now
) > 400000) {
746 /* XXX: workaround card clock drift */
747 sys
->offset
+= 50000;
748 msg_Err(vd
, "Delaying: offset now %" PRId64
, sys
->offset
);
753 pDLVideoFrame
->Release();
756 static int ControlVideo(vout_display_t
*vd
, int query
)
761 case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE
:
762 case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED
:
763 case VOUT_DISPLAY_CHANGE_ZOOM
:
764 case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT
:
765 case VOUT_DISPLAY_CHANGE_SOURCE_CROP
:
771 static const struct vlc_display_operations ops
= {
772 CloseVideo
, PrepareVideo
, NULL
, ControlVideo
, NULL
, NULL
,
775 static int OpenVideo(vout_display_t
*vd
, const vout_display_cfg_t
*cfg
,
776 video_format_t
*fmtp
, vlc_video_context
*context
)
778 VLC_UNUSED(cfg
); VLC_UNUSED(context
);
779 decklink_sys_t
*sys
= HoldDLSys(VLC_OBJECT(vd
), VIDEO_ES
);
784 vlc_mutex_lock(&sys
->lock
);
785 b_init
= !sys
->b_recycling
;
786 vlc_mutex_unlock(&sys
->lock
);
790 sys
->video
.tenbits
= var_InheritBool(vd
, VIDEO_CFG_PREFIX
"tenbits");
791 sys
->video
.nosignal_delay
= var_InheritInteger(vd
, VIDEO_CFG_PREFIX
"nosignal-delay");
792 sys
->video
.afd
= var_InheritInteger(vd
, VIDEO_CFG_PREFIX
"afd");
793 sys
->video
.ar
= var_InheritInteger(vd
, VIDEO_CFG_PREFIX
"ar");
794 sys
->video
.pic_nosignal
= NULL
;
796 if (OpenDecklink(vd
, sys
, fmtp
) != VLC_SUCCESS
)
802 char *pic_file
= var_InheritString(vd
, VIDEO_CFG_PREFIX
"nosignal-image");
805 sys
->video
.pic_nosignal
= sdi::Generator::Picture(VLC_OBJECT(vd
), pic_file
, fmtp
);
806 if (!sys
->video
.pic_nosignal
)
807 msg_Err(vd
, "Could not create no signal picture");
814 vd
->sys
= (vout_display_sys_t
*) sys
;
819 static void CloseVideo(vout_display_t
*vd
)
821 ReleaseDLSys(VLC_OBJECT(vd
), VIDEO_ES
);
824 /*****************************************************************************
826 *****************************************************************************/
828 static void Flush(audio_output_t
*aout
)
830 decklink_sys_t
*sys
= (decklink_sys_t
*) aout
->sys
;
831 vlc_mutex_lock(&sys
->lock
);
832 IDeckLinkOutput
*p_output
= sys
->p_output
;
833 vlc_mutex_unlock(&sys
->lock
);
837 if (sys
->p_output
->FlushBufferedAudioSamples() == E_FAIL
)
838 msg_Err(aout
, "Flush failed");
841 static void Drain(audio_output_t
*aout
)
843 decklink_sys_t
*sys
= (decklink_sys_t
*) aout
->sys
;
844 vlc_mutex_lock(&sys
->lock
);
845 IDeckLinkOutput
*p_output
= sys
->p_output
;
846 vlc_mutex_unlock(&sys
->lock
);
851 sys
->p_output
->GetBufferedAudioSampleFrameCount(&samples
);
852 vlc_tick_sleep(vlc_tick_from_samples(samples
, sys
->i_rate
));
856 static int TimeGet(audio_output_t
*, vlc_tick_t
* restrict
)
858 /* synchronization is handled by the card */
862 static int Start(audio_output_t
*aout
, audio_sample_format_t
*restrict fmt
)
864 decklink_sys_t
*sys
= (decklink_sys_t
*) aout
->sys
;
866 if (sys
->i_rate
== 0)
869 fmt
->i_format
= VLC_CODEC_S16N
;
870 fmt
->i_channels
= 2; //decklink_sys->i_channels;
871 fmt
->i_physical_channels
= AOUT_CHANS_STEREO
; //pi_channels_maps[fmt->i_channels];
872 fmt
->channel_type
= AUDIO_CHANNEL_TYPE_BITMAP
;
873 fmt
->i_rate
= sys
->i_rate
;
874 fmt
->i_bitspersample
= 16;
875 fmt
->i_blockalign
= fmt
->i_channels
* fmt
->i_bitspersample
/8 ;
876 fmt
->i_frame_length
= FRAME_SIZE
;
881 static void PlayAudio(audio_output_t
*aout
, block_t
*audio
, vlc_tick_t systempts
)
883 decklink_sys_t
*sys
= (decklink_sys_t
*) aout
->sys
;
884 vlc_mutex_lock(&sys
->lock
);
885 IDeckLinkOutput
*p_output
= sys
->p_output
;
886 audio
->i_pts
-= sys
->offset
;
887 vlc_mutex_unlock(&sys
->lock
);
889 block_Release(audio
);
893 uint32_t sampleFrameCount
= audio
->i_buffer
/ (2 * 2 /*decklink_sys->i_channels*/);
895 HRESULT result
= p_output
->ScheduleAudioSamples(
896 audio
->p_buffer
, sampleFrameCount
, systempts
, CLOCK_FREQ
, &written
);
899 msg_Err(aout
, "Failed to schedule audio sample: 0x%X", result
);
900 else if (sampleFrameCount
!= written
)
901 msg_Err(aout
, "Written only %d samples out of %d", written
, sampleFrameCount
);
903 block_Release(audio
);
906 static int OpenAudio(vlc_object_t
*p_this
)
908 audio_output_t
*aout
= (audio_output_t
*)p_this
;
909 decklink_sys_t
*sys
= HoldDLSys(p_this
, AUDIO_ES
);
915 vlc_mutex_lock(&sys
->lock
);
916 //decklink_sys->i_channels = var_InheritInteger(vd, AUDIO_CFG_PREFIX "audio-channels");
917 sys
->i_rate
= var_InheritInteger(aout
, AUDIO_CFG_PREFIX
"audio-rate");
918 vlc_cond_signal(&sys
->cond
);
919 vlc_mutex_unlock(&sys
->lock
);
921 aout
->play
= PlayAudio
;
925 aout
->time_get
= TimeGet
;
927 aout
->pause
= aout_PauseDefault
;
929 aout
->mute_set
= NULL
;
930 aout
->volume_set
= NULL
;
935 static void CloseAudio(vlc_object_t
*p_this
)
937 decklink_sys_t
*sys
= (decklink_sys_t
*) ((audio_output_t
*)p_this
)->sys
;
938 vlc_mutex_lock(&sys
->lock
);
939 vlc_mutex_unlock(&sys
->lock
);
940 ReleaseDLSys(p_this
, AUDIO_ES
);