-/*****************************************************************************
+/*****************************************************************************
* decklink.cpp: BlackMagic DeckLink SDI output module
*****************************************************************************
* Copyright (C) 2012-2013 Rafaël Carré
#include <vlc_picture_pool.h>
#include <vlc_block.h>
+#include <vlc_image.h>
#include <vlc_atomic.h>
#include <vlc_aout.h>
#include <arpa/inet.h>
"After this delay we black out the video."\
)
+#define NOSIGNAL_IMAGE_TEXT N_("Picture to display on input signal loss.")
+#define NOSIGNAL_IMAGE_LONGTEXT NOSIGNAL_IMAGE_TEXT
+
#define CARD_INDEX_TEXT N_("Output card")
#define CARD_INDEX_LONGTEXT N_(\
"DeckLink output card, if multiple exist. " \
N_("SDI"), N_("HDMI"), N_("Optical SDI"), N_("Component"), N_("Composite"), N_("S-video")
};
-static const char *const ppsz_audioconns[] = {
- "embedded", "aesebu", "analog"
-};
-static const char *const ppsz_audioconns_text[] = {
- N_("Embedded"), N_("AES/EBU"), N_("Analog")
-};
-
-
struct vout_display_sys_t
{
picture_pool_t *pool;
bool tenbits;
int nosignal_delay;
+ picture_t *pic_nosignal;
};
/* Only one audio output module and one video output module
vlc_mutex_t lock;
vlc_cond_t cond;
uint8_t users;
- BMDAudioConnection aconn;
//int i_channels;
int i_rate;
VIDEO_TENBITS_TEXT, VIDEO_TENBITS_LONGTEXT, true)
add_integer(VIDEO_CFG_PREFIX "nosignal-delay", 5,
NOSIGNAL_INDEX_TEXT, NOSIGNAL_INDEX_LONGTEXT, true)
+ add_loadfile(VIDEO_CFG_PREFIX "nosignal-image", NULL,
+ NOSIGNAL_IMAGE_TEXT, NOSIGNAL_IMAGE_LONGTEXT, true)
add_submodule ()
set_capability("audio output", 0)
set_callbacks (OpenAudio, CloseAudio)
set_section(N_("Decklink Audio Options"), NULL)
- add_string(AUDIO_CFG_PREFIX "audio-connection", "embedded",
- AUDIO_CONNECTION_TEXT, AUDIO_CONNECTION_LONGTEXT, true)
- change_string_list(ppsz_audioconns, ppsz_audioconns_text)
+ add_obsolete_string("audio-connection")
add_integer(AUDIO_CFG_PREFIX "audio-rate", 48000,
RATE_TEXT, RATE_LONGTEXT, true)
add_integer(AUDIO_CFG_PREFIX "audio-channels", 2,
sys->p_output = NULL;
sys->offset = 0;
sys->users = 0;
- sys->aconn = 0;
+ sys->i_rate = -1;
vlc_mutex_init(&sys->lock);
vlc_cond_init(&sys->cond);
var_Create(libvlc, "decklink-sys", VLC_VAR_ADDRESS);
vlc_mutex_unlock(&sys_lock);
}
-// Connection mode
-static BMDAudioConnection getAConn(audio_output_t *aout)
-{
- BMDAudioConnection conn = bmdAudioConnectionEmbedded;
- char *psz = var_InheritString(aout, AUDIO_CFG_PREFIX "audio-connection");
- if (!psz)
- return conn;
-
- if (!strcmp(psz, "embedded"))
- conn = bmdAudioConnectionEmbedded;
- else if (!strcmp(psz, "aesebu"))
- conn = bmdAudioConnectionAESEBU;
- else if (!strcmp(psz, "analog"))
- conn = bmdAudioConnectionAnalog;
-
- free(psz);
- return conn;
-}
-
static BMDVideoConnection getVConn(vout_display_t *vd)
{
BMDVideoConnection conn = bmdVideoConnectionSDI;
decklink_sys->users++;
/* wait until aout is ready */
- while (decklink_sys->aconn == 0)
+ while (decklink_sys->i_rate == -1)
vlc_cond_wait(&decklink_sys->cond, &decklink_sys->lock);
int i_card_index = var_InheritInteger(vd, CFG_PREFIX "card-index");
goto error;
}
- result = p_config->SetInt(
- bmdDeckLinkConfigAudioInputConnection, decklink_sys->aconn);
- CHECK("Could not set audio connection");
-
if (/*decklink_sys->i_channels > 0 &&*/ decklink_sys->i_rate > 0)
{
result = decklink_sys->p_output->EnableAudioOutput(
vlc_mutex_unlock(&decklink_sys->lock);
+ vout_display_DeleteWindow(vd, NULL);
+
return decklink_sys;
error:
if (!picture)
return;
+ picture_t *orig_picture = picture;
+
if (now - picture->date > sys->nosignal_delay * CLOCK_FREQ) {
msg_Dbg(vd, "no signal");
- if (sys->tenbits) { // I422_10L
- plane_t *y = &picture->p[0];
- memset(y->p_pixels, 0x0, y->i_lines * y->i_pitch);
- for (int i = 1; i < picture->i_planes; i++) {
- plane_t *p = &picture->p[i];
- size_t len = p->i_lines * p->i_pitch / 2;
- int16_t *data = (int16_t*)p->p_pixels;
- for (size_t j = 0; j < len; j++) // XXX: SIMD
- data[j] = 0x200;
- }
- } else { // UYVY
- size_t len = picture->p[0].i_lines * picture->p[0].i_pitch;
- for (size_t i = 0; i < len; i+= 2) { // XXX: SIMD
- picture->p[0].p_pixels[i+0] = 0x80;
- picture->p[0].p_pixels[i+1] = 0;
+ if (sys->pic_nosignal) {
+ picture = sys->pic_nosignal;
+ } else {
+ if (sys->tenbits) { // I422_10L
+ plane_t *y = &picture->p[0];
+ memset(y->p_pixels, 0x0, y->i_lines * y->i_pitch);
+ for (int i = 1; i < picture->i_planes; i++) {
+ plane_t *p = &picture->p[i];
+ size_t len = p->i_lines * p->i_pitch / 2;
+ int16_t *data = (int16_t*)p->p_pixels;
+ for (size_t j = 0; j < len; j++) // XXX: SIMD
+ data[j] = 0x200;
+ }
+ } else { // UYVY
+ size_t len = picture->p[0].i_lines * picture->p[0].i_pitch;
+ for (size_t i = 0; i < len; i+= 2) { // XXX: SIMD
+ picture->p[0].p_pixels[i+0] = 0x80;
+ picture->p[0].p_pixels[i+1] = 0;
+ }
}
}
picture->date = now;
end:
if (pDLVideoFrame)
pDLVideoFrame->Release();
- picture_Release(picture);
+ picture_Release(orig_picture);
}
static int ControlVideo(vout_display_t *vd, int query, va_list args)
{
- VLC_UNUSED(vd);
- const vout_display_cfg_t *cfg;
-
- switch (query) {
- case VOUT_DISPLAY_CHANGE_FULLSCREEN:
- cfg = va_arg(args, const vout_display_cfg_t *);
- return cfg->is_fullscreen ? VLC_EGENERIC : VLC_SUCCESS;
- default:
- return VLC_EGENERIC;
- }
+ (void) vd; (void) query; (void) args;
+ return VLC_EGENERIC;
}
static int OpenVideo(vlc_object_t *p_this)
sys->tenbits = var_InheritBool(p_this, VIDEO_CFG_PREFIX "tenbits");
sys->nosignal_delay = var_InheritInteger(p_this, VIDEO_CFG_PREFIX "nosignal-delay");
+ sys->pic_nosignal = NULL;
decklink_sys = OpenDecklink(vd);
if (!decklink_sys) {
+ if (sys->pic_nosignal)
+ picture_Release(sys->pic_nosignal);
free(sys);
return VLC_EGENERIC;
}
vd->fmt.i_width = decklink_sys->i_width;
vd->fmt.i_height = decklink_sys->i_height;
+ char *pic_file = var_InheritString(p_this, VIDEO_CFG_PREFIX "nosignal-image");
+ if (pic_file) {
+ image_handler_t *img = image_HandlerCreate(p_this);
+ if (!img) {
+ msg_Err(p_this, "Could not create image converter");
+ } else {
+ video_format_t in, dummy;
+
+ video_format_Init(&in, 0);
+ video_format_Setup(&in, 0, vd->fmt.i_width, vd->fmt.i_height,
+ vd->fmt.i_width, vd->fmt.i_height, 1, 1);
+
+ video_format_Init(&dummy, 0);
+
+ picture_t *png = image_ReadUrl(img, pic_file, &dummy, &in);
+ if (png) {
+ msg_Err(p_this, "Converting");
+ sys->pic_nosignal = image_Convert(img, png, &in, &vd->fmt);
+ picture_Release(png);
+ }
+
+ image_HandlerDelete(img);
+ }
+
+ free(pic_file);
+ if (!sys->pic_nosignal) {
+ CloseVideo(p_this);
+ msg_Err(p_this, "Could not create no signal picture");
+ return VLC_EGENERIC;
+ }
+ }
vd->info.has_hide_mouse = true;
vd->pool = PoolVideo;
vd->prepare = NULL;
if (sys->pool)
picture_pool_Delete(sys->pool);
+ if (sys->pic_nosignal)
+ picture_Release(sys->pic_nosignal);
+
free(sys);
ReleaseDLSys(p_this);
struct decklink_sys_t *decklink_sys = GetDLSys(VLC_OBJECT(aout));
vlc_mutex_lock(&decklink_sys->lock);
- decklink_sys->aconn = getAConn(aout);
//decklink_sys->i_channels = var_InheritInteger(vd, AUDIO_CFG_PREFIX "audio-channels");
decklink_sys->i_rate = var_InheritInteger(aout, AUDIO_CFG_PREFIX "audio-rate");
decklink_sys->users++;
{
struct decklink_sys_t *decklink_sys = GetDLSys(p_this);
vlc_mutex_lock(&decklink_sys->lock);
- decklink_sys->aconn = 0;
vlc_mutex_unlock(&decklink_sys->lock);
ReleaseDLSys(p_this);
}