Contribs: update dvbpsi to 1.3.2
[vlc.git] / modules / access / decklink.cpp
blobeb5369eea22d3031aad619e38a06b788879feb07
1 /*****************************************************************************
2 * decklink.cpp: BlackMagic DeckLink SDI input module
3 *****************************************************************************
4 * Copyright (C) 2010 Steinar H. Gunderson
5 * Copyright (C) 2012-2014 Rafaël Carré
7 * Authors: Steinar H. Gunderson <steinar+vlc@gunderson.no>
8 Rafaël Carré <funman@videolanorg>
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 *****************************************************************************/
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
29 #include <vlc_common.h>
30 #include <vlc_plugin.h>
31 #include <vlc_demux.h>
33 #ifdef HAVE_ARPA_INET_H
34 #include <arpa/inet.h>
35 #endif
37 #include <DeckLinkAPI.h>
38 #include <DeckLinkAPIDispatch.cpp>
40 #include "sdi.h"
42 #include <atomic>
44 static int Open (vlc_object_t *);
45 static void Close(vlc_object_t *);
47 #define CARD_INDEX_TEXT N_("Input card to use")
48 #define CARD_INDEX_LONGTEXT N_( \
49 "DeckLink capture card to use, if multiple exist. " \
50 "The cards are numbered from 0.")
52 #define MODE_TEXT N_("Desired input video mode. Leave empty for autodetection.")
53 #define MODE_LONGTEXT N_( \
54 "Desired input video mode for DeckLink captures. " \
55 "This value should be a FOURCC code in textual " \
56 "form, e.g. \"ntsc\".")
58 #define AUDIO_CONNECTION_TEXT N_("Audio connection")
59 #define AUDIO_CONNECTION_LONGTEXT N_( \
60 "Audio connection to use for DeckLink captures. " \
61 "Valid choices: embedded, aesebu, analog. " \
62 "Leave blank for card default.")
64 #define RATE_TEXT N_("Audio samplerate (Hz)")
65 #define RATE_LONGTEXT N_( \
66 "Audio sampling rate (in hertz) for DeckLink captures. " \
67 "0 disables audio input.")
69 #define CHANNELS_TEXT N_("Number of audio channels")
70 #define CHANNELS_LONGTEXT N_( \
71 "Number of input audio channels for DeckLink captures. " \
72 "Must be 2, 8 or 16. 0 disables audio input.")
74 #define VIDEO_CONNECTION_TEXT N_("Video connection")
75 #define VIDEO_CONNECTION_LONGTEXT N_( \
76 "Video connection to use for DeckLink captures. " \
77 "Valid choices: sdi, hdmi, opticalsdi, component, " \
78 "composite, svideo. " \
79 "Leave blank for card default.")
81 static const char *const ppsz_videoconns[] = {
82 "sdi", "hdmi", "opticalsdi", "component", "composite", "svideo"
84 static const char *const ppsz_videoconns_text[] = {
85 N_("SDI"), N_("HDMI"), N_("Optical SDI"), N_("Component"), N_("Composite"), N_("S-Video")
88 static const char *const ppsz_audioconns[] = {
89 "embedded", "aesebu", "analog"
91 static const char *const ppsz_audioconns_text[] = {
92 N_("Embedded"), N_("AES/EBU"), N_("Analog")
95 #define ASPECT_RATIO_TEXT N_("Aspect ratio")
96 #define ASPECT_RATIO_LONGTEXT N_(\
97 "Aspect ratio (4:3, 16:9). Default assumes square pixels.")
99 vlc_module_begin ()
100 set_shortname(N_("DeckLink"))
101 set_description(N_("Blackmagic DeckLink SDI input"))
102 set_category(CAT_INPUT)
103 set_subcategory(SUBCAT_INPUT_ACCESS)
105 add_integer("decklink-card-index", 0,
106 CARD_INDEX_TEXT, CARD_INDEX_LONGTEXT, true)
107 add_string("decklink-mode", NULL,
108 MODE_TEXT, MODE_LONGTEXT, true)
109 add_string("decklink-audio-connection", 0,
110 AUDIO_CONNECTION_TEXT, AUDIO_CONNECTION_LONGTEXT, true)
111 change_string_list(ppsz_audioconns, ppsz_audioconns_text)
112 add_integer("decklink-audio-rate", 48000,
113 RATE_TEXT, RATE_LONGTEXT, true)
114 add_integer("decklink-audio-channels", 2,
115 CHANNELS_TEXT, CHANNELS_LONGTEXT, true)
116 add_string("decklink-video-connection", 0,
117 VIDEO_CONNECTION_TEXT, VIDEO_CONNECTION_LONGTEXT, true)
118 change_string_list(ppsz_videoconns, ppsz_videoconns_text)
119 add_string("decklink-aspect-ratio", NULL,
120 ASPECT_RATIO_TEXT, ASPECT_RATIO_LONGTEXT, true)
121 add_bool("decklink-tenbits", false, N_("10 bits"), N_("10 bits"), true)
123 add_shortcut("decklink")
124 set_capability("access", 0)
125 set_callbacks(Open, Close)
126 vlc_module_end ()
128 static int Control(demux_t *, int, va_list);
130 class DeckLinkCaptureDelegate;
132 struct demux_sys_t
134 IDeckLink *card;
135 IDeckLinkInput *input;
136 DeckLinkCaptureDelegate *delegate;
138 /* We need to hold onto the IDeckLinkConfiguration object, or our settings will not apply.
139 See section 2.4.15 of the Blackmagic DeckLink SDK documentation. */
140 IDeckLinkConfiguration *config;
141 IDeckLinkAttributes *attributes;
143 bool autodetect;
145 es_out_id_t *video_es;
146 es_format_t video_fmt;
147 es_out_id_t *audio_es;
148 es_out_id_t *cc_es;
150 vlc_mutex_t pts_lock;
151 int last_pts; /* protected by <pts_lock> */
153 uint32_t dominance_flags;
154 int channels;
156 bool tenbits;
159 static const char *GetFieldDominance(BMDFieldDominance dom, uint32_t *flags)
161 switch(dom)
163 case bmdProgressiveFrame:
164 return "";
165 case bmdProgressiveSegmentedFrame:
166 return ", segmented";
167 case bmdLowerFieldFirst:
168 *flags = BLOCK_FLAG_BOTTOM_FIELD_FIRST;
169 return ", interlaced [BFF]";
170 case bmdUpperFieldFirst:
171 *flags = BLOCK_FLAG_TOP_FIELD_FIRST;
172 return ", interlaced [TFF]";
173 case bmdUnknownFieldDominance:
174 default:
175 return ", unknown field dominance";
179 static es_format_t GetModeSettings(demux_t *demux, IDeckLinkDisplayMode *m,
180 BMDDetectedVideoInputFormatFlags fmt_flags)
182 demux_sys_t *sys = (demux_sys_t *)demux->p_sys;
183 uint32_t flags = 0;
184 (void)GetFieldDominance(m->GetFieldDominance(), &flags);
186 BMDTimeValue frame_duration, time_scale;
187 if (m->GetFrameRate(&frame_duration, &time_scale) != S_OK) {
188 time_scale = 0;
189 frame_duration = 1;
192 es_format_t video_fmt;
193 vlc_fourcc_t chroma = 0;
194 switch (fmt_flags) {
195 case bmdDetectedVideoInputYCbCr422:
196 chroma = sys->tenbits ? VLC_CODEC_I422_10L : VLC_CODEC_UYVY;
197 break;
198 case bmdDetectedVideoInputRGB444:
199 chroma = VLC_CODEC_ARGB;
200 break;
201 default:
202 msg_Err(demux, "Unsupported input format");
203 break;
205 es_format_Init(&video_fmt, VIDEO_ES, chroma);
207 video_fmt.video.i_chroma = chroma;
208 video_fmt.video.i_width = m->GetWidth();
209 video_fmt.video.i_height = m->GetHeight();
210 video_fmt.video.i_sar_num = 1;
211 video_fmt.video.i_sar_den = 1;
212 video_fmt.video.i_frame_rate = time_scale;
213 video_fmt.video.i_frame_rate_base = frame_duration;
214 video_fmt.i_bitrate = video_fmt.video.i_width * video_fmt.video.i_height * video_fmt.video.i_frame_rate * 2 * 8;
216 unsigned aspect_num, aspect_den;
217 if (!var_InheritURational(demux, &aspect_num, &aspect_den, "decklink-aspect-ratio") &&
218 aspect_num > 0 && aspect_den > 0) {
219 video_fmt.video.i_sar_num = aspect_num * video_fmt.video.i_height;
220 video_fmt.video.i_sar_den = aspect_den * video_fmt.video.i_width;
223 sys->dominance_flags = flags;
225 return video_fmt;
228 class DeckLinkCaptureDelegate : public IDeckLinkInputCallback
230 public:
231 DeckLinkCaptureDelegate(demux_t *demux) : demux_(demux)
233 m_ref_.store(1);
236 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID *) { return E_NOINTERFACE; }
238 virtual ULONG STDMETHODCALLTYPE AddRef(void)
240 return m_ref_.fetch_add(1);
243 virtual ULONG STDMETHODCALLTYPE Release(void)
245 uintptr_t new_ref = m_ref_.fetch_sub(1);
246 if (new_ref == 0)
247 delete this;
248 return new_ref;
251 virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(BMDVideoInputFormatChangedEvents events, IDeckLinkDisplayMode *mode, BMDDetectedVideoInputFormatFlags flags)
253 demux_sys_t *sys = static_cast<demux_sys_t *>(demux_->p_sys);
255 if( !(events & bmdVideoInputDisplayModeChanged ))
256 return S_OK;
258 const char *mode_name;
259 if (mode->GetName(&mode_name) != S_OK)
260 mode_name = "unknown";
262 msg_Dbg(demux_, "Video input format changed to %s", mode_name);
263 if (!sys->autodetect) {
264 msg_Err(demux_, "Video format detection disabled");
265 return S_OK;
268 BMDPixelFormat fmt = 0;
269 switch (flags) {
270 case bmdDetectedVideoInputYCbCr422:
271 fmt = sys->tenbits ? bmdFormat10BitYUV : bmdFormat8BitYUV;
272 break;
273 case bmdDetectedVideoInputRGB444:
274 fmt = bmdFormat8BitARGB;
275 break;
276 default:
277 msg_Err(demux_, "Unsupported input format");
278 return S_OK;
281 es_out_Del(demux_->out, sys->video_es);
282 sys->video_fmt = GetModeSettings(demux_, mode, flags);
283 sys->video_es = es_out_Add(demux_->out, &sys->video_fmt);
285 sys->input->PauseStreams();
286 sys->input->EnableVideoInput( mode->GetDisplayMode(), fmt, bmdVideoInputEnableFormatDetection );
287 sys->input->FlushStreams();
288 sys->input->StartStreams();
290 return S_OK;
293 virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame*, IDeckLinkAudioInputPacket*);
295 private:
296 std::atomic_uint m_ref_;
297 demux_t *demux_;
300 HRESULT DeckLinkCaptureDelegate::VideoInputFrameArrived(IDeckLinkVideoInputFrame* videoFrame, IDeckLinkAudioInputPacket* audioFrame)
302 demux_sys_t *sys = static_cast<demux_sys_t *>(demux_->p_sys);
304 if (videoFrame) {
305 if (videoFrame->GetFlags() & bmdFrameHasNoInputSource) {
306 msg_Warn(demux_, "No input signal detected (%dx%d)",
307 videoFrame->GetWidth(), videoFrame->GetHeight());
308 return S_OK;
311 const int width = videoFrame->GetWidth();
312 const int height = videoFrame->GetHeight();
313 const int stride = videoFrame->GetRowBytes();
315 int bpp = 0;
316 switch (sys->video_fmt.i_codec) {
317 case VLC_CODEC_I422_10L:
318 case VLC_CODEC_ARGB:
319 bpp = 4;
320 break;
321 case VLC_CODEC_UYVY:
322 bpp = 2;
323 break;
325 block_t *video_frame = block_Alloc(width * height * bpp);
326 if (!video_frame)
327 return S_OK;
329 const uint32_t *frame_bytes;
330 videoFrame->GetBytes((void**)&frame_bytes);
332 BMDTimeValue stream_time, frame_duration;
333 videoFrame->GetStreamTime(&stream_time, &frame_duration, CLOCK_FREQ);
334 video_frame->i_flags = BLOCK_FLAG_TYPE_I | sys->dominance_flags;
335 video_frame->i_pts = video_frame->i_dts = VLC_TS_0 + stream_time;
337 if (sys->video_fmt.i_codec == VLC_CODEC_I422_10L) {
338 v210_convert((uint16_t*)video_frame->p_buffer, frame_bytes, width, height);
339 IDeckLinkVideoFrameAncillary *vanc;
340 if (videoFrame->GetAncillaryData(&vanc) == S_OK) {
341 for (int i = 1; i < 21; i++) {
342 uint32_t *buf;
343 if (vanc->GetBufferForVerticalBlankingLine(i, (void**)&buf) != S_OK)
344 break;
345 uint16_t dec[width * 2];
346 v210_convert(&dec[0], buf, width, 1);
347 block_t *cc = vanc_to_cc(demux_, dec, width * 2);
348 if (!cc)
349 continue;
350 cc->i_pts = cc->i_dts = VLC_TS_0 + stream_time;
352 if (!sys->cc_es) {
353 es_format_t fmt;
355 es_format_Init( &fmt, SPU_ES, VLC_CODEC_CEA608 );
356 fmt.psz_description = strdup(N_("Closed captions 1"));
357 if (fmt.psz_description) {
358 sys->cc_es = es_out_Add(demux_->out, &fmt);
359 msg_Dbg(demux_, "Adding Closed captions stream");
362 if (sys->cc_es)
363 es_out_Send(demux_->out, sys->cc_es, cc);
364 else
365 block_Release(cc);
366 break; // we found the line with Closed Caption data
368 vanc->Release();
370 } else if (sys->video_fmt.i_codec == VLC_CODEC_UYVY) {
371 for (int y = 0; y < height; ++y) {
372 const uint8_t *src = (const uint8_t *)frame_bytes + stride * y;
373 uint8_t *dst = video_frame->p_buffer + width * 2 * y;
374 memcpy(dst, src, width * 2);
376 } else {
377 memcpy(video_frame->p_buffer, frame_bytes, width * height * bpp);
380 vlc_mutex_lock(&sys->pts_lock);
381 if (video_frame->i_pts > sys->last_pts)
382 sys->last_pts = video_frame->i_pts;
383 vlc_mutex_unlock(&sys->pts_lock);
385 es_out_SetPCR(demux_->out, video_frame->i_pts);
386 es_out_Send(demux_->out, sys->video_es, video_frame);
389 if (audioFrame) {
390 const int bytes = audioFrame->GetSampleFrameCount() * sizeof(int16_t) * sys->channels;
392 block_t *audio_frame = block_Alloc(bytes);
393 if (!audio_frame)
394 return S_OK;
396 void *frame_bytes;
397 audioFrame->GetBytes(&frame_bytes);
398 memcpy(audio_frame->p_buffer, frame_bytes, bytes);
400 BMDTimeValue packet_time;
401 audioFrame->GetPacketTime(&packet_time, CLOCK_FREQ);
402 audio_frame->i_pts = audio_frame->i_dts = VLC_TS_0 + packet_time;
404 vlc_mutex_lock(&sys->pts_lock);
405 if (audio_frame->i_pts > sys->last_pts)
406 sys->last_pts = audio_frame->i_pts;
407 vlc_mutex_unlock(&sys->pts_lock);
409 es_out_SetPCR(demux_->out, audio_frame->i_pts);
410 es_out_Send(demux_->out, sys->audio_es, audio_frame);
413 return S_OK;
417 static int GetAudioConn(demux_t *demux)
419 demux_sys_t *sys = (demux_sys_t *)demux->p_sys;
421 char *opt = var_CreateGetNonEmptyString(demux, "decklink-audio-connection");
422 if (!opt)
423 return VLC_SUCCESS;
425 BMDAudioConnection c;
426 if (!strcmp(opt, "embedded"))
427 c = bmdAudioConnectionEmbedded;
428 else if (!strcmp(opt, "aesebu"))
429 c = bmdAudioConnectionAESEBU;
430 else if (!strcmp(opt, "analog"))
431 c = bmdAudioConnectionAnalog;
432 else {
433 msg_Err(demux, "Invalid audio-connection: `%s\' specified", opt);
434 free(opt);
435 return VLC_EGENERIC;
438 if (sys->config->SetInt(bmdDeckLinkConfigAudioInputConnection, c) != S_OK) {
439 msg_Err(demux, "Failed to set audio input connection");
440 return VLC_EGENERIC;
443 return VLC_SUCCESS;
446 static int GetVideoConn(demux_t *demux)
448 demux_sys_t *sys = (demux_sys_t *)demux->p_sys;
450 char *opt = var_InheritString(demux, "decklink-video-connection");
451 if (!opt)
452 return VLC_SUCCESS;
454 BMDVideoConnection c;
455 if (!strcmp(opt, "sdi"))
456 c = bmdVideoConnectionSDI;
457 else if (!strcmp(opt, "hdmi"))
458 c = bmdVideoConnectionHDMI;
459 else if (!strcmp(opt, "opticalsdi"))
460 c = bmdVideoConnectionOpticalSDI;
461 else if (!strcmp(opt, "component"))
462 c = bmdVideoConnectionComponent;
463 else if (!strcmp(opt, "composite"))
464 c = bmdVideoConnectionComposite;
465 else if (!strcmp(opt, "svideo"))
466 c = bmdVideoConnectionSVideo;
467 else {
468 msg_Err(demux, "Invalid video-connection: `%s\' specified", opt);
469 free(opt);
470 return VLC_EGENERIC;
473 free(opt);
474 if (sys->config->SetInt(bmdDeckLinkConfigVideoInputConnection, c) != S_OK) {
475 msg_Err(demux, "Failed to set video input connection");
476 return VLC_EGENERIC;
479 return VLC_SUCCESS;
482 static int Open(vlc_object_t *p_this)
484 demux_t *demux = (demux_t*)p_this;
485 demux_sys_t *sys;
486 int ret = VLC_EGENERIC;
487 int card_index;
488 int physical_channels = 0;
489 int rate;
490 BMDVideoInputFlags flags = bmdVideoInputFlagDefault;
492 if (demux->out == NULL)
493 return VLC_EGENERIC;
495 /* Set up demux */
496 demux->pf_demux = NULL;
497 demux->pf_control = Control;
498 demux->p_sys = sys = (demux_sys_t*)calloc(1, sizeof(demux_sys_t));
499 if (!sys)
500 return VLC_ENOMEM;
502 vlc_mutex_init(&sys->pts_lock);
504 sys->tenbits = var_InheritBool(p_this, "decklink-tenbits");
506 IDeckLinkIterator *decklink_iterator = CreateDeckLinkIteratorInstance();
507 if (!decklink_iterator) {
508 msg_Err(demux, "DeckLink drivers not found.");
509 goto finish;
512 card_index = var_InheritInteger(demux, "decklink-card-index");
513 if (card_index < 0) {
514 msg_Err(demux, "Invalid card index %d", card_index);
515 goto finish;
518 for (int i = 0; i <= card_index; i++) {
519 if (sys->card)
520 sys->card->Release();
521 if (decklink_iterator->Next(&sys->card) != S_OK) {
522 msg_Err(demux, "DeckLink PCI card %d not found", card_index);
523 goto finish;
527 const char *model_name;
528 if (sys->card->GetModelName(&model_name) != S_OK)
529 model_name = "unknown";
531 msg_Dbg(demux, "Opened DeckLink PCI card %d (%s)", card_index, model_name);
533 if (sys->card->QueryInterface(IID_IDeckLinkInput, (void**)&sys->input) != S_OK) {
534 msg_Err(demux, "Card has no inputs");
535 goto finish;
538 /* Set up the video and audio sources. */
539 if (sys->card->QueryInterface(IID_IDeckLinkConfiguration, (void**)&sys->config) != S_OK) {
540 msg_Err(demux, "Failed to get configuration interface");
541 goto finish;
544 if (sys->card->QueryInterface(IID_IDeckLinkAttributes, (void**)&sys->attributes) != S_OK) {
545 msg_Err(demux, "Failed to get attributes interface");
546 goto finish;
549 if (GetVideoConn(demux) || GetAudioConn(demux))
550 goto finish;
552 BMDPixelFormat fmt;
553 fmt = sys->tenbits ? bmdFormat10BitYUV : bmdFormat8BitYUV;
554 if (sys->attributes->GetFlag(BMDDeckLinkSupportsInputFormatDetection, &sys->autodetect) != S_OK) {
555 msg_Err(demux, "Failed to query card attribute");
556 goto finish;
559 /* Get the list of display modes. */
560 IDeckLinkDisplayModeIterator *mode_it;
561 if (sys->input->GetDisplayModeIterator(&mode_it) != S_OK) {
562 msg_Err(demux, "Failed to enumerate display modes");
563 goto finish;
566 union {
567 BMDDisplayMode id;
568 char str[4];
569 } u;
571 u.id = 0;
573 char *mode;
574 mode = var_CreateGetNonEmptyString(demux, "decklink-mode");
575 if (mode)
576 sys->autodetect = false; // disable autodetection if mode was set
578 if (sys->autodetect) {
579 msg_Dbg(demux, "Card supports input format detection");
580 flags |= bmdVideoInputEnableFormatDetection;
581 /* Enable a random format, we will reconfigure on format detection */
582 u.id = htonl(bmdModeHD1080p2997);
583 } else {
584 if (!mode || strlen(mode) < 3 || strlen(mode) > 4) {
585 msg_Err(demux, "Invalid mode: \'%s\'", mode ? mode : "");
586 free(mode);
587 goto finish;
590 msg_Dbg(demux, "Looking for mode \'%s\'", mode);
591 memcpy(u.str, mode, 4);
592 if (u.str[3] == '\0')
593 u.str[3] = ' '; /* 'pal'\0 -> 'pal ' */
594 free(mode);
597 sys->video_fmt.video.i_width = 0;
599 for (IDeckLinkDisplayMode *m;; m->Release()) {
600 if ((mode_it->Next(&m) != S_OK) || !m)
601 break;
603 const char *mode_name;
604 BMDTimeValue frame_duration, time_scale;
605 uint32_t field_flags;
606 const char *field = GetFieldDominance(m->GetFieldDominance(), &field_flags);
607 BMDDisplayMode id = ntohl(m->GetDisplayMode());
609 if (m->GetName(&mode_name) != S_OK)
610 mode_name = "unknown";
611 if (m->GetFrameRate(&frame_duration, &time_scale) != S_OK) {
612 time_scale = 0;
613 frame_duration = 1;
616 msg_Dbg(demux, "Found mode '%4.4s': %s (%dx%d, %.3f fps%s)",
617 (char*)&id, mode_name,
618 (int)m->GetWidth(), (int)m->GetHeight(),
619 double(time_scale) / frame_duration, field);
621 if (u.id == id) {
622 sys->video_fmt = GetModeSettings(demux, m, bmdDetectedVideoInputYCbCr422);
623 msg_Dbg(demux, "Using that mode");
627 mode_it->Release();
629 if (sys->video_fmt.video.i_width == 0) {
630 msg_Err(demux, "Unknown video mode `%4.4s\' specified.", (char*)&u.id);
631 goto finish;
634 if (sys->input->EnableVideoInput(htonl(u.id), fmt, flags) != S_OK) {
635 msg_Err(demux, "Failed to enable video input");
636 goto finish;
639 /* Set up audio. */
640 sys->channels = var_InheritInteger(demux, "decklink-audio-channels");
641 switch (sys->channels) {
642 case 0:
643 break;
644 case 2:
645 physical_channels = AOUT_CHANS_STEREO;
646 break;
647 case 8:
648 physical_channels = AOUT_CHANS_7_1;
649 break;
650 //case 16:
651 default:
652 msg_Err(demux, "Invalid number of channels (%d), disabling audio", sys->channels);
653 sys->channels = 0;
655 rate = var_InheritInteger(demux, "decklink-audio-rate");
656 if (rate > 0 && sys->channels > 0) {
657 if (sys->input->EnableAudioInput(rate, bmdAudioSampleType16bitInteger, sys->channels) != S_OK) {
658 msg_Err(demux, "Failed to enable audio input");
659 goto finish;
663 sys->delegate = new DeckLinkCaptureDelegate(demux);
664 sys->input->SetCallback(sys->delegate);
666 if (sys->input->StartStreams() != S_OK) {
667 msg_Err(demux, "Could not start streaming from SDI card. This could be caused "
668 "by invalid video mode or flags, access denied, or card already in use.");
669 goto finish;
672 msg_Dbg(demux, "added new video es %4.4s %dx%d",
673 (char*)&sys->video_fmt.i_codec, sys->video_fmt.video.i_width, sys->video_fmt.video.i_height);
674 sys->video_es = es_out_Add(demux->out, &sys->video_fmt);
676 es_format_t audio_fmt;
677 es_format_Init(&audio_fmt, AUDIO_ES, VLC_CODEC_S16N);
678 audio_fmt.audio.i_channels = sys->channels;
679 audio_fmt.audio.i_physical_channels = physical_channels;
680 audio_fmt.audio.i_rate = rate;
681 audio_fmt.audio.i_bitspersample = 16;
682 audio_fmt.audio.i_blockalign = audio_fmt.audio.i_channels * audio_fmt.audio.i_bitspersample / 8;
683 audio_fmt.i_bitrate = audio_fmt.audio.i_channels * audio_fmt.audio.i_rate * audio_fmt.audio.i_bitspersample;
685 msg_Dbg(demux, "added new audio es %4.4s %dHz %dbpp %dch",
686 (char*)&audio_fmt.i_codec, audio_fmt.audio.i_rate, audio_fmt.audio.i_bitspersample, audio_fmt.audio.i_channels);
687 sys->audio_es = es_out_Add(demux->out, &audio_fmt);
689 ret = VLC_SUCCESS;
691 finish:
692 if (decklink_iterator)
693 decklink_iterator->Release();
695 if (ret != VLC_SUCCESS)
696 Close(p_this);
698 return ret;
701 static void Close(vlc_object_t *p_this)
703 demux_t *demux = (demux_t *)p_this;
704 demux_sys_t *sys = (demux_sys_t *)demux->p_sys;
706 if (sys->attributes)
707 sys->attributes->Release();
709 if (sys->config)
710 sys->config->Release();
712 if (sys->input) {
713 sys->input->StopStreams();
714 sys->input->Release();
717 if (sys->card)
718 sys->card->Release();
720 if (sys->delegate)
721 sys->delegate->Release();
723 vlc_mutex_destroy(&sys->pts_lock);
724 free(sys);
727 static int Control(demux_t *demux, int query, va_list args)
729 demux_sys_t *sys = (demux_sys_t *)demux->p_sys;
730 bool *pb;
731 int64_t *pi64;
733 switch(query)
735 /* Special for access_demux */
736 case DEMUX_CAN_PAUSE:
737 case DEMUX_CAN_SEEK:
738 case DEMUX_CAN_CONTROL_PACE:
739 pb = va_arg(args, bool *);
740 *pb = false;
741 return VLC_SUCCESS;
743 case DEMUX_GET_PTS_DELAY:
744 pi64 = va_arg(args, int64_t *);
745 *pi64 = INT64_C(1000) * var_InheritInteger(demux, "live-caching");
746 return VLC_SUCCESS;
748 case DEMUX_GET_TIME:
749 pi64 = va_arg(args, int64_t *);
750 vlc_mutex_lock(&sys->pts_lock);
751 *pi64 = sys->last_pts;
752 vlc_mutex_unlock(&sys->pts_lock);
753 return VLC_SUCCESS;
755 default:
756 return VLC_EGENERIC;