Decklink: remove tabs
[vlc.git] / modules / access / decklink.cpp
blob00faca5c9f0a4c3c69753c8fe9cd9744aa85bf47
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 "vlc_decklink.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 namespace {
132 class DeckLinkCaptureDelegate;
134 struct demux_sys_t
136 IDeckLink *card;
137 IDeckLinkInput *input;
138 DeckLinkCaptureDelegate *delegate;
140 /* We need to hold onto the IDeckLinkConfiguration object, or our settings will not apply.
141 See section 2.4.15 of the Blackmagic DeckLink SDK documentation. */
142 IDeckLinkConfiguration *config;
143 IDeckLinkAttributes *attributes;
145 bool autodetect;
147 es_out_id_t *video_es;
148 es_format_t video_fmt;
149 es_out_id_t *audio_es[8];
150 es_out_id_t *cc_es;
152 vlc_mutex_t pts_lock;
153 vlc_tick_t last_pts; /* protected by <pts_lock> */
155 uint32_t dominance_flags;
156 int channels;
157 int audio_streams;
159 bool tenbits;
162 } // namespace
164 static const char *GetFieldDominance(BMDFieldDominance dom, uint32_t *flags)
166 switch(dom)
168 case bmdProgressiveFrame:
169 return "";
170 case bmdProgressiveSegmentedFrame:
171 return ", segmented";
172 case bmdLowerFieldFirst:
173 *flags = BLOCK_FLAG_BOTTOM_FIELD_FIRST;
174 return ", interlaced [BFF]";
175 case bmdUpperFieldFirst:
176 *flags = BLOCK_FLAG_TOP_FIELD_FIRST;
177 return ", interlaced [TFF]";
178 case bmdUnknownFieldDominance:
179 default:
180 return ", unknown field dominance";
184 static es_format_t GetModeSettings(demux_t *demux, IDeckLinkDisplayMode *m,
185 BMDDetectedVideoInputFormatFlags fmt_flags)
187 demux_sys_t *sys = (demux_sys_t *)demux->p_sys;
188 uint32_t flags = 0;
189 (void)GetFieldDominance(m->GetFieldDominance(), &flags);
191 BMDTimeValue frame_duration, time_scale;
192 if (m->GetFrameRate(&frame_duration, &time_scale) != S_OK) {
193 time_scale = 0;
194 frame_duration = 1;
197 es_format_t video_fmt;
198 vlc_fourcc_t chroma = 0;
199 switch (fmt_flags) {
200 case bmdDetectedVideoInputYCbCr422:
201 chroma = sys->tenbits ? VLC_CODEC_I422_10L : VLC_CODEC_UYVY;
202 break;
203 case bmdDetectedVideoInputRGB444:
204 chroma = VLC_CODEC_ARGB;
205 break;
206 default:
207 msg_Err(demux, "Unsupported input format");
208 break;
210 es_format_Init(&video_fmt, VIDEO_ES, chroma);
212 video_fmt.video.i_chroma = chroma;
213 video_fmt.video.i_width = m->GetWidth();
214 video_fmt.video.i_height = m->GetHeight();
215 video_fmt.video.i_sar_num = 1;
216 video_fmt.video.i_sar_den = 1;
217 video_fmt.video.i_frame_rate = time_scale;
218 video_fmt.video.i_frame_rate_base = frame_duration;
219 video_fmt.i_bitrate = video_fmt.video.i_width * video_fmt.video.i_height * video_fmt.video.i_frame_rate * 2 * 8;
221 unsigned aspect_num, aspect_den;
222 if (!var_InheritURational(demux, &aspect_num, &aspect_den, "decklink-aspect-ratio") &&
223 aspect_num > 0 && aspect_den > 0) {
224 video_fmt.video.i_sar_num = aspect_num * video_fmt.video.i_height;
225 video_fmt.video.i_sar_den = aspect_den * video_fmt.video.i_width;
228 sys->dominance_flags = flags;
230 return video_fmt;
232 namespace {
234 class DeckLinkCaptureDelegate : public IDeckLinkInputCallback
236 public:
237 DeckLinkCaptureDelegate(demux_t *demux) : demux_(demux)
239 m_ref_.store(1);
242 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID *) { return E_NOINTERFACE; }
244 virtual ULONG STDMETHODCALLTYPE AddRef(void)
246 return m_ref_.fetch_add(1);
249 virtual ULONG STDMETHODCALLTYPE Release(void)
251 uintptr_t new_ref = m_ref_.fetch_sub(1);
252 if (new_ref == 0)
253 delete this;
254 return new_ref;
257 virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(BMDVideoInputFormatChangedEvents events, IDeckLinkDisplayMode *mode, BMDDetectedVideoInputFormatFlags flags)
259 demux_sys_t *sys = static_cast<demux_sys_t *>(demux_->p_sys);
261 if( !(events & bmdVideoInputDisplayModeChanged ))
262 return S_OK;
264 decklink_str_t tmp_name;
265 char *mode_name = NULL;
266 if (mode->GetName(&tmp_name) == S_OK) {
267 mode_name = DECKLINK_STRDUP(tmp_name);
268 DECKLINK_FREE(tmp_name);
271 msg_Dbg(demux_, "Video input format changed to %s",
272 (mode_name) ? mode_name : "unknown");
273 free(mode_name);
274 if (!sys->autodetect) {
275 msg_Err(demux_, "Video format detection disabled");
276 return S_OK;
279 BMDPixelFormat fmt = 0;
280 switch (flags) {
281 case bmdDetectedVideoInputYCbCr422:
282 fmt = sys->tenbits ? bmdFormat10BitYUV : bmdFormat8BitYUV;
283 break;
284 case bmdDetectedVideoInputRGB444:
285 fmt = bmdFormat8BitARGB;
286 break;
287 default:
288 msg_Err(demux_, "Unsupported input format");
289 return S_OK;
292 es_out_Del(demux_->out, sys->video_es);
293 sys->video_fmt = GetModeSettings(demux_, mode, flags);
294 sys->video_es = es_out_Add(demux_->out, &sys->video_fmt);
296 sys->input->PauseStreams();
297 sys->input->EnableVideoInput( mode->GetDisplayMode(), fmt, bmdVideoInputEnableFormatDetection );
298 sys->input->FlushStreams();
299 sys->input->StartStreams();
301 return S_OK;
304 virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame*, IDeckLinkAudioInputPacket*);
306 private:
307 std::atomic_uint m_ref_;
308 demux_t *demux_;
311 } // namespace
313 HRESULT DeckLinkCaptureDelegate::VideoInputFrameArrived(IDeckLinkVideoInputFrame* videoFrame, IDeckLinkAudioInputPacket* audioFrame)
315 demux_sys_t *sys = static_cast<demux_sys_t *>(demux_->p_sys);
317 if (videoFrame) {
318 if (videoFrame->GetFlags() & bmdFrameHasNoInputSource) {
319 msg_Warn(demux_, "No input signal detected (%ldx%ld)",
320 videoFrame->GetWidth(), videoFrame->GetHeight());
321 return S_OK;
324 const int width = videoFrame->GetWidth();
325 const int height = videoFrame->GetHeight();
326 const int stride = videoFrame->GetRowBytes();
328 int bpp = 0;
329 switch (sys->video_fmt.i_codec) {
330 case VLC_CODEC_I422_10L:
331 case VLC_CODEC_ARGB:
332 bpp = 4;
333 break;
334 case VLC_CODEC_UYVY:
335 bpp = 2;
336 break;
338 block_t *video_frame = block_Alloc(width * height * bpp);
339 if (!video_frame)
340 return S_OK;
342 const uint32_t *frame_bytes;
343 videoFrame->GetBytes((void**)&frame_bytes);
345 BMDTimeValue stream_time, frame_duration;
346 videoFrame->GetStreamTime(&stream_time, &frame_duration, CLOCK_FREQ);
347 video_frame->i_flags = BLOCK_FLAG_TYPE_I | sys->dominance_flags;
348 video_frame->i_pts = video_frame->i_dts = VLC_TICK_0 + stream_time;
350 if (sys->video_fmt.i_codec == VLC_CODEC_I422_10L) {
351 v210_convert((uint16_t*)video_frame->p_buffer, frame_bytes, width, height);
352 IDeckLinkVideoFrameAncillary *vanc;
353 if (videoFrame->GetAncillaryData(&vanc) == S_OK) {
354 for (int i = 1; i < 21; i++) {
355 uint32_t *buf;
356 if (vanc->GetBufferForVerticalBlankingLine(i, (void**)&buf) != S_OK)
357 break;
358 uint16_t dec[width * 2];
359 v210_convert(&dec[0], buf, width, 1);
360 block_t *cc = vanc_to_cc(demux_, dec, width * 2);
361 if (!cc)
362 continue;
363 cc->i_pts = cc->i_dts = VLC_TICK_0 + stream_time;
365 if (!sys->cc_es) {
366 es_format_t fmt;
368 es_format_Init( &fmt, SPU_ES, VLC_CODEC_CEA608 );
369 fmt.psz_description = strdup(N_("Closed captions 1"));
370 if (fmt.psz_description) {
371 sys->cc_es = es_out_Add(demux_->out, &fmt);
372 msg_Dbg(demux_, "Adding Closed captions stream");
375 if (sys->cc_es)
376 es_out_Send(demux_->out, sys->cc_es, cc);
377 else
378 block_Release(cc);
379 break; // we found the line with Closed Caption data
381 vanc->Release();
383 } else if (sys->video_fmt.i_codec == VLC_CODEC_UYVY) {
384 for (int y = 0; y < height; ++y) {
385 const uint8_t *src = (const uint8_t *)frame_bytes + stride * y;
386 uint8_t *dst = video_frame->p_buffer + width * 2 * y;
387 memcpy(dst, src, width * 2);
389 } else {
390 memcpy(video_frame->p_buffer, frame_bytes, width * height * bpp);
393 vlc_mutex_lock(&sys->pts_lock);
394 if (video_frame->i_pts > sys->last_pts)
395 sys->last_pts = video_frame->i_pts;
396 vlc_mutex_unlock(&sys->pts_lock);
398 es_out_SetPCR(demux_->out, video_frame->i_pts);
399 es_out_Send(demux_->out, sys->video_es, video_frame);
402 if (audioFrame && audioFrame->GetSampleFrameCount())
404 const int bytes = audioFrame->GetSampleFrameCount() * sizeof(int16_t) * sys->channels;
405 BMDTimeValue packet_time;
406 void *frame_bytes;
408 audioFrame->GetBytes(&frame_bytes);
409 audioFrame->GetPacketTime(&packet_time, CLOCK_FREQ);
411 if(sys->audio_streams > 1)
413 for(int i=0; i<sys->audio_streams; i++)
415 size_t i_samples = bytes / (sys->audio_streams * 4);
416 block_t *p_frame = block_Alloc(i_samples * 4);
417 if (!p_frame)
418 continue;
420 for(size_t j=0; j<i_samples; j++) /* for each pair sample */
422 memcpy(&p_frame->p_buffer[j * 4],
423 &reinterpret_cast<uint8_t *>(frame_bytes)[(j * sys->audio_streams + i) * 4],
427 p_frame->i_pts = p_frame->i_dts = VLC_TICK_0 + packet_time;
428 es_out_Send(demux_->out, sys->audio_es[i], p_frame);
431 else
433 block_t *audio_frame = block_Alloc(bytes);
434 if (!audio_frame)
435 return S_OK;
436 memcpy(audio_frame->p_buffer, frame_bytes, bytes);
437 audio_frame->i_pts = audio_frame->i_dts = VLC_TICK_0 + packet_time;
438 es_out_Send(demux_->out, sys->audio_es[0], audio_frame);
441 vlc_mutex_lock(&sys->pts_lock);
442 if (VLC_TICK_0 + packet_time > sys->last_pts)
443 sys->last_pts = VLC_TICK_0 + packet_time;
444 vlc_mutex_unlock(&sys->pts_lock);
446 es_out_SetPCR(demux_->out, VLC_TICK_0 + packet_time);
449 return S_OK;
453 static int GetAudioConn(demux_t *demux)
455 demux_sys_t *sys = (demux_sys_t *)demux->p_sys;
457 char *opt = var_CreateGetNonEmptyString(demux, "decklink-audio-connection");
458 if (!opt)
459 return VLC_SUCCESS;
461 BMDAudioConnection c;
462 if (!strcmp(opt, "embedded"))
463 c = bmdAudioConnectionEmbedded;
464 else if (!strcmp(opt, "aesebu"))
465 c = bmdAudioConnectionAESEBU;
466 else if (!strcmp(opt, "analog"))
467 c = bmdAudioConnectionAnalog;
468 else {
469 msg_Err(demux, "Invalid audio-connection: `%s\' specified", opt);
470 free(opt);
471 return VLC_EGENERIC;
474 if (sys->config->SetInt(bmdDeckLinkConfigAudioInputConnection, c) != S_OK) {
475 msg_Err(demux, "Failed to set audio input connection");
476 return VLC_EGENERIC;
479 return VLC_SUCCESS;
482 static int GetVideoConn(demux_t *demux)
484 demux_sys_t *sys = (demux_sys_t *)demux->p_sys;
486 char *opt = var_InheritString(demux, "decklink-video-connection");
487 if (!opt)
488 return VLC_SUCCESS;
490 BMDVideoConnection c;
491 if (!strcmp(opt, "sdi"))
492 c = bmdVideoConnectionSDI;
493 else if (!strcmp(opt, "hdmi"))
494 c = bmdVideoConnectionHDMI;
495 else if (!strcmp(opt, "opticalsdi"))
496 c = bmdVideoConnectionOpticalSDI;
497 else if (!strcmp(opt, "component"))
498 c = bmdVideoConnectionComponent;
499 else if (!strcmp(opt, "composite"))
500 c = bmdVideoConnectionComposite;
501 else if (!strcmp(opt, "svideo"))
502 c = bmdVideoConnectionSVideo;
503 else {
504 msg_Err(demux, "Invalid video-connection: `%s\' specified", opt);
505 free(opt);
506 return VLC_EGENERIC;
509 free(opt);
510 if (sys->config->SetInt(bmdDeckLinkConfigVideoInputConnection, c) != S_OK) {
511 msg_Err(demux, "Failed to set video input connection");
512 return VLC_EGENERIC;
515 return VLC_SUCCESS;
518 static int Open(vlc_object_t *p_this)
520 demux_t *demux = (demux_t*)p_this;
521 demux_sys_t *sys;
522 int ret = VLC_EGENERIC;
523 int card_index;
524 int physical_channels = 0;
525 int rate;
526 BMDVideoInputFlags flags = bmdVideoInputFlagDefault;
528 if (demux->out == NULL)
529 return VLC_EGENERIC;
531 /* Set up demux */
532 demux->pf_demux = NULL;
533 demux->pf_control = Control;
534 demux->p_sys = sys = (demux_sys_t*)calloc(1, sizeof(demux_sys_t));
535 if (!sys)
536 return VLC_ENOMEM;
538 vlc_mutex_init(&sys->pts_lock);
540 sys->tenbits = var_InheritBool(p_this, "decklink-tenbits");
542 IDeckLinkIterator *decklink_iterator = CreateDeckLinkIteratorInstance();
543 if (!decklink_iterator) {
544 msg_Err(demux, "DeckLink drivers not found.");
545 goto finish;
548 card_index = var_InheritInteger(demux, "decklink-card-index");
549 if (card_index < 0) {
550 msg_Err(demux, "Invalid card index %d", card_index);
551 goto finish;
554 for (int i = 0; i <= card_index; i++) {
555 if (sys->card)
556 sys->card->Release();
557 if (decklink_iterator->Next(&sys->card) != S_OK) {
558 msg_Err(demux, "DeckLink PCI card %d not found", card_index);
559 goto finish;
563 decklink_str_t tmp_name;
564 char *model_name;
565 if (sys->card->GetModelName(&tmp_name) != S_OK) {
566 model_name = strdup("unknown");
567 } else {
568 model_name = DECKLINK_STRDUP(tmp_name);
569 DECKLINK_FREE(tmp_name);
572 msg_Dbg(demux, "Opened DeckLink PCI card %d (%s)", card_index, model_name);
573 free(model_name);
575 if (sys->card->QueryInterface(IID_IDeckLinkInput, (void**)&sys->input) != S_OK) {
576 msg_Err(demux, "Card has no inputs");
577 goto finish;
580 /* Set up the video and audio sources. */
581 if (sys->card->QueryInterface(IID_IDeckLinkConfiguration, (void**)&sys->config) != S_OK) {
582 msg_Err(demux, "Failed to get configuration interface");
583 goto finish;
586 if (sys->card->QueryInterface(IID_IDeckLinkAttributes, (void**)&sys->attributes) != S_OK) {
587 msg_Err(demux, "Failed to get attributes interface");
588 goto finish;
591 if (GetVideoConn(demux) || GetAudioConn(demux))
592 goto finish;
594 BMDPixelFormat fmt;
595 fmt = sys->tenbits ? bmdFormat10BitYUV : bmdFormat8BitYUV;
596 if (sys->attributes->GetFlag(BMDDeckLinkSupportsInputFormatDetection, &sys->autodetect) != S_OK) {
597 msg_Err(demux, "Failed to query card attribute");
598 goto finish;
601 /* Get the list of display modes. */
602 IDeckLinkDisplayModeIterator *mode_it;
603 if (sys->input->GetDisplayModeIterator(&mode_it) != S_OK) {
604 msg_Err(demux, "Failed to enumerate display modes");
605 goto finish;
608 union {
609 BMDDisplayMode id;
610 char str[4];
611 } u;
613 u.id = 0;
615 char *mode;
616 mode = var_CreateGetNonEmptyString(demux, "decklink-mode");
617 if (mode)
618 sys->autodetect = false; // disable autodetection if mode was set
620 if (sys->autodetect) {
621 msg_Dbg(demux, "Card supports input format detection");
622 flags |= bmdVideoInputEnableFormatDetection;
623 /* Enable a random format, we will reconfigure on format detection */
624 u.id = htonl(bmdModeHD1080p2997);
625 } else {
626 if (!mode || strlen(mode) < 3 || strlen(mode) > 4) {
627 msg_Err(demux, "Invalid mode: \'%s\'", mode ? mode : "");
628 free(mode);
629 goto finish;
632 msg_Dbg(demux, "Looking for mode \'%s\'", mode);
633 memcpy(u.str, mode, 4);
634 if (u.str[3] == '\0')
635 u.str[3] = ' '; /* 'pal'\0 -> 'pal ' */
636 free(mode);
639 sys->video_fmt.video.i_width = 0;
641 for (IDeckLinkDisplayMode *m;; m->Release()) {
642 if ((mode_it->Next(&m) != S_OK) || !m)
643 break;
645 const char *mode_name;
646 BMDTimeValue frame_duration, time_scale;
647 uint32_t field_flags;
648 const char *field = GetFieldDominance(m->GetFieldDominance(), &field_flags);
649 BMDDisplayMode id = ntohl(m->GetDisplayMode());
650 decklink_str_t tmp_name;
652 if (m->GetName(&tmp_name) != S_OK) {
653 mode_name = "unknown";
654 } else {
655 mode_name = DECKLINK_STRDUP(tmp_name);
656 DECKLINK_FREE(tmp_name);
658 if (m->GetFrameRate(&frame_duration, &time_scale) != S_OK) {
659 time_scale = 0;
660 frame_duration = 1;
663 msg_Dbg(demux, "Found mode '%4.4s': %s (%dx%d, %.3f fps%s)",
664 (char*)&id, mode_name,
665 (int)m->GetWidth(), (int)m->GetHeight(),
666 double(time_scale) / frame_duration, field);
668 if (u.id == id) {
669 sys->video_fmt = GetModeSettings(demux, m, bmdDetectedVideoInputYCbCr422);
670 msg_Dbg(demux, "Using that mode");
674 mode_it->Release();
676 if (sys->video_fmt.video.i_width == 0) {
677 msg_Err(demux, "Unknown video mode `%4.4s\' specified.", (char*)&u.id);
678 goto finish;
681 if (sys->input->EnableVideoInput(htonl(u.id), fmt, flags) != S_OK) {
682 msg_Err(demux, "Failed to enable video input");
683 goto finish;
686 /* Set up audio. */
687 sys->channels = var_InheritInteger(demux, "decklink-audio-channels");
688 switch (sys->channels) {
689 case 0:
690 break;
691 case 2:
692 physical_channels = AOUT_CHANS_STEREO;
693 sys->audio_streams = 1;
694 break;
695 case 8:
696 physical_channels = AOUT_CHANS_7_1;
697 sys->audio_streams = 1;
698 break;
699 case 16:
700 physical_channels = AOUT_CHANS_STEREO;
701 sys->audio_streams = 8;
702 break;
703 default:
704 msg_Err(demux, "Invalid number of channels (%d), disabling audio", sys->channels);
705 sys->channels = 0;
706 sys->audio_streams = 0;
708 rate = var_InheritInteger(demux, "decklink-audio-rate");
709 if (rate > 0 && sys->channels > 0) {
710 if (sys->input->EnableAudioInput(rate, bmdAudioSampleType16bitInteger, sys->channels) != S_OK) {
711 msg_Err(demux, "Failed to enable audio input");
712 goto finish;
716 sys->delegate = new DeckLinkCaptureDelegate(demux);
717 sys->input->SetCallback(sys->delegate);
719 if (sys->input->StartStreams() != S_OK) {
720 msg_Err(demux, "Could not start streaming from SDI card. This could be caused "
721 "by invalid video mode or flags, access denied, or card already in use.");
722 goto finish;
725 msg_Dbg(demux, "added new video es %4.4s %dx%d",
726 (char*)&sys->video_fmt.i_codec, sys->video_fmt.video.i_width, sys->video_fmt.video.i_height);
727 sys->video_es = es_out_Add(demux->out, &sys->video_fmt);
729 es_format_t audio_fmt;
730 es_format_Init(&audio_fmt, AUDIO_ES, VLC_CODEC_S16N);
731 audio_fmt.audio.i_channels = sys->channels / sys->audio_streams;
732 audio_fmt.audio.i_physical_channels = physical_channels;
733 audio_fmt.audio.i_rate = rate;
734 audio_fmt.audio.i_bitspersample = 16;
735 audio_fmt.audio.i_blockalign = audio_fmt.audio.i_channels * audio_fmt.audio.i_bitspersample / 8;
736 audio_fmt.i_bitrate = audio_fmt.audio.i_channels * audio_fmt.audio.i_rate * audio_fmt.audio.i_bitspersample;
738 for(int i=0; i<sys->audio_streams; i++)
740 msg_Dbg(demux, "added new audio es [%d] %4.4s %dHz %dbpp %dch", i,
741 (char*)&audio_fmt.i_codec, audio_fmt.audio.i_rate,
742 audio_fmt.audio.i_bitspersample, audio_fmt.audio.i_channels);
743 sys->audio_es[i] = es_out_Add(demux->out, &audio_fmt);
746 ret = VLC_SUCCESS;
748 finish:
749 if (decklink_iterator)
750 decklink_iterator->Release();
752 if (ret != VLC_SUCCESS)
753 Close(p_this);
755 return ret;
758 static void Close(vlc_object_t *p_this)
760 demux_t *demux = (demux_t *)p_this;
761 demux_sys_t *sys = (demux_sys_t *)demux->p_sys;
763 if (sys->attributes)
764 sys->attributes->Release();
766 if (sys->config)
767 sys->config->Release();
769 if (sys->input) {
770 sys->input->StopStreams();
771 sys->input->Release();
774 if (sys->card)
775 sys->card->Release();
777 if (sys->delegate)
778 sys->delegate->Release();
780 vlc_mutex_destroy(&sys->pts_lock);
781 free(sys);
784 static int Control(demux_t *demux, int query, va_list args)
786 demux_sys_t *sys = (demux_sys_t *)demux->p_sys;
787 bool *pb;
789 switch(query)
791 /* Special for access_demux */
792 case DEMUX_CAN_PAUSE:
793 case DEMUX_CAN_SEEK:
794 case DEMUX_CAN_CONTROL_PACE:
795 pb = va_arg(args, bool *);
796 *pb = false;
797 return VLC_SUCCESS;
799 case DEMUX_GET_PTS_DELAY:
800 *va_arg(args, vlc_tick_t *) =
801 VLC_TICK_FROM_MS(var_InheritInteger(demux, "live-caching"));
802 return VLC_SUCCESS;
804 case DEMUX_GET_TIME:
805 vlc_mutex_lock(&sys->pts_lock);
806 *va_arg(args, vlc_tick_t *) = sys->last_pts;
807 vlc_mutex_unlock(&sys->pts_lock);
808 return VLC_SUCCESS;
810 default:
811 return VLC_EGENERIC;