access_out: rist: fix mem leak
[vlc.git] / modules / video_output / decklink.cpp
blobac8195f6be30a6f6de52e75aaab8394bf6003c95
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
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
33 #include <vlc_fixups.h>
34 #include <cinttypes>
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>
45 #include <vlc_aout.h>
47 #ifdef HAVE_ARPA_INET_H
48 #include <arpa/inet.h>
49 #endif
51 #include "../access/vlc_decklink.h"
52 #include <DeckLinkAPIDispatch.cpp>
54 #define FRAME_SIZE 1920
55 #define CHANNELS_MAX 6
57 #if 0
58 static const int pi_channels_maps[CHANNELS_MAX+1] =
61 AOUT_CHAN_CENTER,
62 AOUT_CHANS_STEREO,
63 AOUT_CHANS_3_0,
64 AOUT_CHANS_4_0,
65 AOUT_CHANS_5_0,
66 AOUT_CHANS_5_1,
68 #endif
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[] = {
127 "sdi",
128 "hdmi",
129 "opticalsdi",
130 "component",
131 "composite",
132 "svideo"
134 static const char *const ppsz_videoconns_text[] = {
135 "SDI",
136 "HDMI",
137 "Optical SDI",
138 "Component",
139 "Composite",
140 "S-video",
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[] = {
158 "0: Undefined",
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[] = {
173 0, 1,
175 static const char * const rgsz_ar_text[] = {
176 "0: 4:3",
177 "1: 16:9",
179 static_assert(ARRAY_SIZE(rgi_ar_values) == ARRAY_SIZE(rgsz_ar_text), "afd arrays messed up");
181 namespace {
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
188 /* With LOCK */
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.
196 vlc_mutex_t lock;
197 vlc_cond_t cond;
198 uint8_t users;
199 bool b_videomodule;
200 bool b_recycling;
202 //int i_channels;
203 int i_rate;
205 BMDTimeScale timescale;
206 BMDTimeValue frameduration;
208 /* XXX: workaround card clock drift */
209 vlc_tick_t offset;
211 /* !With LOCK */
213 /* single video module exclusive */
214 struct
216 video_format_t currentfmt;
217 picture_pool_t *pool;
218 bool tenbits;
219 uint8_t afd, ar;
220 int nosignal_delay;
221 picture_t *pic_nosignal;
222 } video;
225 } // namespace
227 /*****************************************************************************
228 * Local prototypes.
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 /*****************************************************************************
237 * Module descriptor
238 *****************************************************************************/
240 vlc_module_begin()
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)
247 add_submodule ()
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)
275 add_submodule ()
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)
287 vlc_module_end ()
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);
295 decklink_sys_t *sys;
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");
302 sys->users++;
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);
315 else
317 sys = (decklink_sys_t*)malloc(sizeof(*sys));
318 if (sys) {
319 sys->p_output = NULL;
320 sys->offset = 0;
321 sys->users = 1;
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");
325 if(sys->i_rate > 0)
326 sys->i_rate = -1;
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);
335 return sys;
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);
351 if (sys->p_output) {
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 */
359 if (sys->video.pool)
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);
365 free(sys);
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");
381 if (psz)
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];
388 break;
391 free(psz);
393 else /* Pick one as default connection */
395 conn = vlc_ctz(mask);
396 conn = conn ? ( 1 << conn ) : bmdVideoConnectionSDI;
398 return conn;
401 /*****************************************************************************
403 *****************************************************************************/
405 static struct
407 long i_return_code;
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;
429 return NULL;
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);
437 if (!img)
439 msg_Err(p_this, "Could not create image converter");
440 return NULL;
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);
451 if (png)
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);
459 p_pic = NULL;
461 picture_Release(png);
463 image_HandlerDelete(img);
464 video_format_Clean(&in);
465 video_format_Clean(&dummy);
467 return p_pic;
470 static IDeckLinkDisplayMode * MatchDisplayMode(vout_display_t *vd,
471 IDeckLinkOutput *output,
472 const video_format_t *fmt,
473 BMDDisplayMode forcedmode = bmdDisplayModeNotSupported)
475 HRESULT result;
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);
486 if(result == S_OK)
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;
494 char *psz_mode_name;
496 decklink_str_t tmp_name;
497 if(p_mode->GetFrameRate(&frameduration, &timescale) == 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);
504 if(i==0)
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,
511 (char *)&field,
512 timescale, frameduration);
514 free(psz_mode_name);
516 else
518 p_mode->Release();
519 continue;
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)
527 p_selected = p_mode;
528 else
529 p_mode->Release();
530 continue;
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");
547 p_selected = p_mode;
548 continue;
553 p_mode->Release();
555 p_iterator->Release();
558 return p_selected;
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); \
567 if(psz_err)\
568 msg_Err(vd, message ": %s", psz_err); \
569 else \
570 msg_Err(vd, message ": 0x%X", result); \
571 goto error; \
573 } while(0)
575 HRESULT 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");
593 if(mode)
595 size_t len = strlen(mode);
596 if (len > 4)
598 free(mode);
599 msg_Err(vd, "Invalid mode %s", mode);
600 goto error;
602 memset(&wanted_mode_id, ' ', 4);
603 strncpy((char*)&wanted_mode_id, mode, 4);
604 wanted_mode_id = ntohl(wanted_mode_id);
605 free(mode);
608 if (i_card_index < 0)
610 msg_Err(vd, "Invalid card index %d", i_card_index);
611 goto error;
614 decklink_iterator = CreateDeckLinkIteratorInstance();
615 if (!decklink_iterator)
617 msg_Err(vd, "DeckLink drivers not found.");
618 goto error;
621 for(int i = 0; i <= i_card_index; ++i)
623 if (p_card)
624 p_card->Release();
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");
644 int64_t vconn;
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);
650 CHECK("No outputs");
652 result = p_card->QueryInterface(IID_IDeckLinkConfiguration,
653 (void**)&p_config);
654 CHECK("Could not get config interface");
656 /* Now configure card */
658 vconn = getVConn(vd, (BMDVideoConnection) vconn);
659 if (vconn == 0)
661 msg_Err(vd, "Invalid video connection specified");
662 goto error;
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");
673 goto error;
675 else
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");
699 goto error;
702 if (p_display_mode->GetWidth() <= 0 || p_display_mode->GetWidth() & 1)
704 msg_Err(vd, "Unknown video mode specified.");
705 goto error;
708 result = p_display_mode->GetFrameRate(&sys->frameduration,
709 &sys->timescale);
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();
719 fmt->i_x_offset = 0;
720 fmt->i_y_offset = 0;
721 fmt->i_sar_num = 0;
722 fmt->i_sar_den = 0;
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(
731 sys->i_rate,
732 bmdAudioSampleType16bitInteger,
733 /*decklink_sys->i_channels*/ 2,
734 bmdAudioOutputStreamTimestamped);
735 CHECK("Could not start audio output");
738 /* start */
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");
743 p_config->Release();
744 p_display_mode->Release();
745 p_card->Release();
746 p_attributes->Release();
747 decklink_iterator->Release();
749 vlc_mutex_unlock(&sys->lock);
751 return VLC_SUCCESS;
753 error:
754 if (sys->p_output) {
755 sys->p_output->Release();
756 sys->p_output = NULL;
758 if (p_card)
759 p_card->Release();
760 if (p_config)
761 p_config->Release();
762 if (p_attributes)
763 p_attributes->Release();
764 if (decklink_iterator)
765 decklink_iterator->Release();
766 if (p_display_mode)
767 p_display_mode->Release();
769 vlc_mutex_unlock(&sys->lock);
771 return VLC_EGENERIC;
772 #undef CHECK
775 /*****************************************************************************
776 * Video
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)
789 SetDWLE(*p, d);
790 (*p) += 4;
793 static inline int clip(int a)
795 if (a < 4) return 4;
796 else if (a > 1019) return 1019;
797 else return a;
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;
805 int h, w;
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) \
813 do { \
814 val = clip(*a++); \
815 val |= (clip(*b++) << 10) | \
816 (clip(*c++) << 20); \
817 put_le32(&data, val); \
818 } while (0)
820 for (h = 0; h < height; h++) {
821 uint32_t val = 0;
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);
828 if (w < width - 1) {
829 WRITE_PIXELS(u, y, v);
831 val = clip(*y++);
832 if (w == width - 2)
833 put_le32(&data, val);
834 #undef WRITE_PIXELS
836 if (w < width - 3) {
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
858 uint16_t afd[s];
860 afd[0] = 0x000;
861 afd[1] = 0x3ff;
862 afd[2] = 0x3ff;
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;
880 /* parity bit */
881 for (size_t i = 3; i < len - 1; i++)
882 afd[i] |= vlc_parity((unsigned)afd[i]) ? 0x100 : 0x200;
884 /* vanc checksum */
885 uint16_t vanc_sum = 0;
886 for (size_t i = 3; i < len - 1; i++) {
887 vanc_sum += afd[i];
888 vanc_sum &= 0x1ff;
891 afd[len - 1] = vanc_sum | ((~vanc_sum & 0x100) << 1);
893 /* pad */
894 for (size_t i = len; i < s; i++)
895 afd[i] = 0x040;
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 *,
907 vlc_tick_t date)
909 decklink_sys_t *sys = (decklink_sys_t *) vd->sys;
910 vlc_tick_t now = vlc_tick_now();
912 if (!picture)
913 return;
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;
919 } else {
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
928 data[j] = 0x200;
930 } else { // UYVY
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;
938 date = now;
941 HRESULT result;
942 int w, h, stride, length;
943 w = vd->fmt.i_width;
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;
954 goto end;
957 void *frame_bytes;
958 pDLVideoFrame->GetBytes((void**)&frame_bytes);
959 stride = pDLVideoFrame->GetRowBytes();
961 if (sys->video.tenbits) {
962 IDeckLinkVideoFrameAncillary *vanc;
963 int line;
964 void *buf;
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);
970 goto end;
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);
977 goto end;
979 send_AFD(sys->video.afd, sys->video.ar, (uint8_t*)buf);
981 v210_convert(frame_bytes, picture, stride);
983 result = pDLVideoFrame->SetAncillaryData(vanc);
984 vanc->Release();
985 if (result != S_OK) {
986 msg_Err(vd, "Failed to set vanc: %d", result);
987 goto end;
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);
1007 goto end;
1010 now = vlc_tick_now() - sys->offset;
1012 BMDTimeValue decklink_now;
1013 double speed;
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);
1022 end:
1023 if (pDLVideoFrame)
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);
1037 if(!sys)
1038 return VLC_ENOMEM;
1040 vd->sys = (vout_display_sys_t*) sys;
1042 bool b_init;
1043 vlc_mutex_lock(&sys->lock);
1044 b_init = !sys->b_recycling;
1045 vlc_mutex_unlock(&sys->lock);
1047 if( b_init )
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)
1058 CloseVideo(p_this);
1059 return VLC_EGENERIC;
1062 char *pic_file = var_InheritString(p_this, VIDEO_CFG_PREFIX "nosignal-image");
1063 if (pic_file)
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");
1068 free(pic_file);
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;
1078 vd->display = NULL;
1079 vd->control = ControlVideo;
1081 return VLC_SUCCESS;
1084 static void CloseVideo(vlc_object_t *p_this)
1086 ReleaseDLSys(p_this, VIDEO_ES);
1089 /*****************************************************************************
1090 * Audio
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);
1099 if (!p_output)
1100 return;
1102 if (drain) {
1103 uint32_t samples;
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 */
1113 return -1;
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;
1132 return VLC_SUCCESS;
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);
1142 if (!p_output) {
1143 block_Release(audio);
1144 return;
1147 uint32_t sampleFrameCount = audio->i_buffer / (2 * 2 /*decklink_sys->i_channels*/);
1148 uint32_t written;
1149 HRESULT result = p_output->ScheduleAudioSamples(
1150 audio->p_buffer, sampleFrameCount, systempts, CLOCK_FREQ, &written);
1152 if (result != S_OK)
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);
1164 if(!sys)
1165 return VLC_ENOMEM;
1167 aout->sys = sys;
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;
1181 aout->stop = NULL;
1182 aout->mute_set = NULL;
1183 aout->volume_set= NULL;
1185 return VLC_SUCCESS;
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);