Code: Select all
vlc_module_begin()
set_shortname( N_("Decklink Output") )
set_description( N_("Decklink Output plug-in") )
set_callbacks (Open, Close)
add_shortcut( "decklink-output" )
add_integer( VIDEO_CFG_PREFIX "card-index", 0,
CARD_INDEX_TEXT, CARD_INDEX_LONGTEXT, true )
add_string( AUDIO_CFG_PREFIX "audio-connection", 0,
AUDIO_CONNECTION_TEXT, AUDIO_CONNECTION_LONGTEXT, true )
change_string_list( ppsz_audioconns, ppsz_audioconns_text, 0 )
add_submodule ()
set_shortname (N_("Decklink Video Output"))
set_description (N_("Decklink Video Output module"))
set_category(CAT_VIDEO)
set_subcategory(SUBCAT_VIDEO_VOUT)
set_capability("vout display", 0)
set_callbacks (VideoOpen, VideoClose)
add_shortcut( "decklink-vout" )
add_submodule ()
set_shortname (N_("Decklink Audio Output"))
set_description (N_("Decklink Audio Output module"))
set_category( CAT_AUDIO )
set_subcategory( SUBCAT_AUDIO_AOUT )
set_capability( "audio output", 0 )
set_callbacks (AudioOpen, AudioClose)
add_shortcut( "decklink-aout" )
vlc_module_end ()
Code: Select all
/*****************************************************************************
*****************************************************************************/
//vlc -vvv file --aout decklinkoutput --vout decklinkoutput
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <math.h>
#include <stdio.h>
#include <stdint.h>
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_vout_display.h>
#include <vlc_picture_pool.h>
#include <vlc_fs.h>
#include <vlc_block.h>
#include <vlc_atomic.h>
#include <vlc_aout.h>
#include <arpa/inet.h>
#include <DeckLinkAPI.h>
#include <DeckLinkAPIDispatch.cpp>
# if __WORDSIZE == 64
# define INT64_C(c) c ## L
# else
# define INT64_C(c) c ## LL
# endif
#define CLOCK_FREQ INT64_C(1000000)
#define DECKLINK_VIDEO_CODEC VLC_CODEC_UYVY
#define DECKLINK_AUDIO_CODEC VLC_CODEC_S16N
#define FRAME_SIZE 1920
#define CHANNELS_MAX 6
static const int pi_channels_maps[CHANNELS_MAX+1] =
{
0,
AOUT_CHAN_CENTER,
AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
AOUT_CHAN_CENTER | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT
| AOUT_CHAN_REARRIGHT,
AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
| AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT,
AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
| AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE
};
#define CARD_INDEX_TEXT N_("Output card to use")
#define CARD_INDEX_LONGTEXT N_( \
"DeckLink output card to use, if multiple exist. " \
"The cards are numbered from 0." )
#define MODE_TEXT N_("Desired output video mode")
#define MODE_LONGTEXT N_( \
"Desired output video mode for DeckLink output. " \
"This value should be a FOURCC code in textual " \
"form, e.g. \"ntsc\"." )
#define AUDIO_CONNECTION_TEXT N_("Audio connection")
#define AUDIO_CONNECTION_LONGTEXT N_( \
"Audio connection to use for DeckLink output. " \
"Valid choices: embedded, aesebu, analog. " \
"Leave blank for card default." )
#define RATE_TEXT N_("Audio sampling rate in Hz")
#define RATE_LONGTEXT N_( \
"Audio sampling rate (in hertz) for DeckLink output. " \
"0 disables audio output." )
#define CHANNELS_TEXT N_("Number of audio channels")
#define CHANNELS_LONGTEXT N_( \
"Number of output audio channels for DeckLink output. " \
"Must be 2, 8 or 16. 0 disables audio output." )
#define VIDEO_CONNECTION_TEXT N_("Video connection")
#define VIDEO_CONNECTION_LONGTEXT N_( \
"Video connection to use for DeckLink output. " \
"Valid choices: sdi, hdmi, opticalsdi, component, " \
"composite, svideo. " \
"Leave blank for card default." )
#define CFG_PREFIX "decklink-output-"
#define VIDEO_CFG_PREFIX "decklink-vout-"
#define AUDIO_CFG_PREFIX "decklink-aout-"
/* Main functions */
static const char *const ppsz_videoconns[] = {
"sdi", "hdmi", "opticalsdi", "component", "composite", "svideo"
};
static const char *const ppsz_videoconns_text[] = {
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 aout_sys_t
{
uint64_t aoutTotalAudioPackages;
};
struct vout_display_sys_t {
picture_pool_t *pool;
uint64_t vdTotalFrames;
vlc_mutex_t pts_lock;
};
typedef struct {
IDeckLink *p_card;
IDeckLinkOutput *p_output;
IDeckLinkConfiguration *p_config;
IDeckLinkDisplayModeIterator *p_display_iterator;
IDeckLinkIterator *decklink_iterator;
int i_card_index;
char *psz_video_connection;
BMDDisplayMode display_mode;
BMDVideoOutputFlags videoOutputFlags;
char *psz_audio_connection;
int i_channels;
int i_rate;
uint32_t i_dominance_flags;
int i_width;
int i_height;
BMDTimeScale i_timescale;
BMDTimeValue i_frameduration;
vlc_mutex_t m_lock;
vlc_atomic_t m_ref;
} decklink_sys_t;
static decklink_sys_t decklink_sys = {NULL,NULL,NULL,NULL,NULL,
-1,NULL,0,0,NULL,-1,-1,
0,-1,-1,0,0,
NULL,NULL
};
/*****************************************************************************
* Local prototypes.
*****************************************************************************/
void FillSine (void* audioBuffer, uint32_t samplesToWrite, uint32_t channels, uint32_t sampleDepth);
static int OpenDecklink ( vlc_object_t *);
static void CloseDecklink ( vlc_object_t *);
static int OpenVideo ( vlc_object_t * );
static void CloseVideo ( vlc_object_t * );
static picture_pool_t *PoolVideo (vout_display_t *, unsigned);
static void DisplayVideo(vout_display_t *, picture_t *, subpicture_t *subpicture);
static int ControlVideo(vout_display_t *, int, va_list);
static int OpenAudio ( vlc_object_t * );
static void CloseAudio ( vlc_object_t * );
static void PlayAudio ( audio_output_t *, block_t * );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
//
//
vlc_module_begin()
set_shortname( N_("DecklinkOutput") )
set_description( N_("Decklink Output plug-in") )
// add_shortcut( "decklink-output" )
set_section( N_("Decklink General Options"), NULL )
add_integer( CFG_PREFIX "card-index", 0,
CARD_INDEX_TEXT, CARD_INDEX_LONGTEXT, true )
add_submodule ()
// set_shortname (N_("DecklinkVOut"))
set_description (N_("Decklink Video Output module"))
set_category(CAT_VIDEO)
set_subcategory(SUBCAT_VIDEO_VOUT)
set_capability("vout display", 0)
set_callbacks (OpenVideo, CloseVideo)
set_section( N_("Decklink Video Options"), NULL )
// add_shortcut( "decklink-vout" )
add_string( VIDEO_CFG_PREFIX "video-connection", 0,
VIDEO_CONNECTION_TEXT, VIDEO_CONNECTION_LONGTEXT, true )
change_string_list( ppsz_videoconns, ppsz_videoconns_text, 0 )
add_string( VIDEO_CFG_PREFIX "mode", "pal ",
MODE_TEXT, MODE_LONGTEXT, true )
add_submodule ()
// set_shortname (N_("DecklinkAOut"))
set_description (N_("Decklink Audio Output module"))
set_category( CAT_AUDIO )
set_subcategory( SUBCAT_AUDIO_AOUT )
set_capability( "audio output", 0 )
set_callbacks (OpenAudio, CloseAudio)
// add_shortcut( "decklink-aout" )
set_section( N_("Decklink Audio Options"), NULL )
add_string( AUDIO_CFG_PREFIX "audio-connection", 0,
AUDIO_CONNECTION_TEXT, AUDIO_CONNECTION_LONGTEXT, true )
change_string_list( ppsz_audioconns, ppsz_audioconns_text, 0 )
add_integer( AUDIO_CFG_PREFIX "audio-rate", 48000,
RATE_TEXT, RATE_LONGTEXT, true )
add_integer( AUDIO_CFG_PREFIX "audio-channels", 2,
CHANNELS_TEXT, CHANNELS_LONGTEXT, true )
vlc_module_end ()
/*****************************************************************************
* Open: initialize interface , public IDeckLinkAudioOutputCallback
*****************************************************************************/
static int OpenDecklink( vlc_object_t *p_this )
{
if(!(vlc_atomic_get( &decklink_sys.m_ref ))){
//if(!(decklink_sys.m_ref)){
vlc_mutex_init(&decklink_sys.m_lock);
vlc_mutex_lock(&decklink_sys.m_lock);
vlc_atomic_set( &(decklink_sys.m_ref), 0 );
int i_rate;
int i_card_index;
int i_channels;
BMDVideoOutputFlags videoOutputFlags = 0;
bool b_found_mode;
i_card_index = var_InheritInteger( p_this, CFG_PREFIX "card-index" );
//IDeckLinkDisplayModeIterator *p_display_iterator = NULL;
decklink_sys.decklink_iterator = CreateDeckLinkIteratorInstance();
if( !decklink_sys.decklink_iterator )
{
msg_Err( p_this, "DeckLink drivers not found." );
if( decklink_sys.p_display_iterator )
decklink_sys.p_display_iterator->Release();
vlc_mutex_unlock(&decklink_sys.m_lock);
return VLC_EGENERIC;
}
HRESULT result;
if( i_card_index < 0 )
{
msg_Err( p_this, "Invalid card index %d", i_card_index );
if( decklink_sys.decklink_iterator )
decklink_sys.decklink_iterator->Release();
if( decklink_sys.p_display_iterator )
decklink_sys.p_display_iterator->Release();
vlc_mutex_unlock(&decklink_sys.m_lock);
return VLC_EGENERIC;
}
for( int i = 0; i <= i_card_index; ++i )
{
if( decklink_sys.p_card ){
//decklink_sys.p_card->Release();
msg_Dbg( p_this, "Error here %d Cannot Release Pcard dc", i);
}
result = decklink_sys.decklink_iterator->Next( &decklink_sys.p_card );
if( result != S_OK )
break;
}
if( result != S_OK )
{
msg_Err( p_this, "DeckLink PCI card %d not found", i_card_index );
if( decklink_sys.decklink_iterator )
decklink_sys.decklink_iterator->Release();
if( decklink_sys.p_display_iterator )
decklink_sys.p_display_iterator->Release();
vlc_mutex_unlock(&decklink_sys.m_lock);
return VLC_EGENERIC;
}
const char *psz_model_name;
result = decklink_sys.p_card->GetModelName( &psz_model_name );
if( result != S_OK )
{
msg_Err( p_this, "Could not get model name" );
if( decklink_sys.decklink_iterator )
decklink_sys.decklink_iterator->Release();
if( decklink_sys.p_display_iterator )
decklink_sys.p_display_iterator->Release();
vlc_mutex_unlock(&decklink_sys.m_lock);
return VLC_EGENERIC;
}
msg_Dbg( p_this, "Opened DeckLink PCI card %d (%s)", i_card_index, psz_model_name );
if( decklink_sys.p_card->QueryInterface( IID_IDeckLinkOutput, (void**)&decklink_sys.p_output) != S_OK )
{
msg_Err( p_this, "Card has no outputs" );
if( decklink_sys.decklink_iterator )
decklink_sys.decklink_iterator->Release();
if( decklink_sys.p_display_iterator )
decklink_sys.p_display_iterator->Release();
vlc_mutex_unlock(&decklink_sys.m_lock);
return VLC_EGENERIC;
}
if( decklink_sys.p_card->QueryInterface( IID_IDeckLinkConfiguration, (void**)&decklink_sys.p_config) != S_OK )
{
msg_Err( p_this, "Failed to get configuration interface" );
if( decklink_sys.decklink_iterator )
decklink_sys.decklink_iterator->Release();
if( decklink_sys.p_display_iterator )
decklink_sys.p_display_iterator->Release();
vlc_mutex_unlock(&decklink_sys.m_lock);
return VLC_EGENERIC;
}
decklink_sys.i_card_index = i_card_index ;
//Setting up Video Connection
char* psz_video_connection;
psz_video_connection = var_InheritString( p_this, VIDEO_CFG_PREFIX "video-connection" );
if( psz_video_connection )
{
BMDVideoConnection conn;
if ( !strcmp( psz_video_connection, "sdi" ) )
conn = bmdVideoConnectionSDI;
else if ( !strcmp( psz_video_connection, "hdmi" ) )
conn = bmdVideoConnectionHDMI;
else if ( !strcmp( psz_video_connection, "opticalsdi" ) )
conn = bmdVideoConnectionOpticalSDI;
else if ( !strcmp( psz_video_connection, "component" ) )
conn = bmdVideoConnectionComponent;
else if ( !strcmp( psz_video_connection, "composite" ) )
conn = bmdVideoConnectionComposite;
else if ( !strcmp( psz_video_connection, "svideo" ) )
conn = bmdVideoConnectionSVideo;
else
{
msg_Err( p_this, "Invalid video-connection specified; choose one of " \
"sdi, hdmi, opticalsdi, component, composite, or svideo." );
if( decklink_sys.decklink_iterator )
decklink_sys.decklink_iterator->Release();
free( psz_video_connection );
if( decklink_sys.p_display_iterator )
decklink_sys.p_display_iterator->Release();
vlc_mutex_unlock(&decklink_sys.m_lock);
return VLC_EGENERIC;
}
msg_Dbg( p_this, "Setting video output connection to 0x%x", conn);
result = decklink_sys.p_config->SetInt( bmdDeckLinkConfigVideoOutputConnection, conn );
if( result != S_OK )
{
msg_Err( p_this, "Failed to set video output connection" );
if( decklink_sys.decklink_iterator )
decklink_sys.decklink_iterator->Release();
free( psz_video_connection );
if( decklink_sys.p_display_iterator )
decklink_sys.p_display_iterator->Release();
vlc_mutex_unlock(&decklink_sys.m_lock);
return VLC_EGENERIC;
}
decklink_sys.psz_video_connection = psz_video_connection;
free( psz_video_connection );
}
//End of Setting up Video Connection
// Setting up Audio Connection
char *psz_audio_connection;
psz_audio_connection = var_CreateGetNonEmptyString( p_this, AUDIO_CFG_PREFIX "audio-connection" );
if( psz_audio_connection )
{
BMDAudioConnection conn;
if ( !strcmp( psz_audio_connection, "embedded" ) )
conn = bmdAudioConnectionEmbedded;
else if ( !strcmp( psz_audio_connection, "aesebu" ) )
conn = bmdAudioConnectionAESEBU;
else if ( !strcmp( psz_audio_connection, "analog" ) )
conn = bmdAudioConnectionAnalog;
else
{
msg_Err( p_this, "Invalid audio-connection specified; choose one of " \
"embedded, aesebu, or analog." );
if( decklink_sys.decklink_iterator )
decklink_sys.decklink_iterator->Release();
free( psz_audio_connection );
if( decklink_sys.p_display_iterator )
decklink_sys.p_display_iterator->Release();
vlc_mutex_unlock(&decklink_sys.m_lock);
return VLC_EGENERIC;
}
msg_Dbg( p_this, "Setting audio output format to 0x%x", conn);
result = decklink_sys.p_config->SetInt( bmdDeckLinkConfigAudioInputConnection, conn );
if( result != S_OK )
{
msg_Err( p_this, "Failed to set audio output connection" );
if( decklink_sys.decklink_iterator )
decklink_sys.decklink_iterator->Release();
free( psz_audio_connection );
if( decklink_sys.p_display_iterator )
decklink_sys.p_display_iterator->Release();
vlc_mutex_unlock(&decklink_sys.m_lock);
return VLC_EGENERIC;
}
decklink_sys.psz_audio_connection = psz_audio_connection;
free( psz_audio_connection );
}
// End of Setting up Audio Connection
//Find Display Mode
result = decklink_sys.p_output->GetDisplayModeIterator( &decklink_sys.p_display_iterator );
if( result != S_OK )
{
msg_Err( p_this, "Failed to enumerate display modes" );
if( decklink_sys.decklink_iterator )
decklink_sys.decklink_iterator->Release();
if( decklink_sys.p_display_iterator )
decklink_sys.p_display_iterator->Release();
vlc_mutex_unlock(&decklink_sys.m_lock);
return VLC_EGENERIC;
}
char *psz_display_mode;
psz_display_mode = var_CreateGetNonEmptyString( p_this, VIDEO_CFG_PREFIX "mode" );
if( !psz_display_mode || strlen( psz_display_mode ) > 4 ) {
msg_Err( p_this, "Missing or invalid mode string" );
if( decklink_sys.decklink_iterator )
decklink_sys.decklink_iterator->Release();
if( decklink_sys.p_display_iterator )
decklink_sys.p_display_iterator->Release();
vlc_mutex_unlock(&decklink_sys.m_lock);
return VLC_EGENERIC;
}
/*
* Pad the --decklink-mode string to four characters, so the user can specify e.g. "pal"
* without having to add the trailing space.
*/
char sz_display_mode_padded[5];
strcpy(sz_display_mode_padded, " ");
for( int i = 0; i < strlen( psz_display_mode ); ++i )
sz_display_mode_padded[i] = psz_display_mode[i];
BMDDisplayMode wanted_mode_id;
memcpy( &wanted_mode_id, &sz_display_mode_padded, sizeof(wanted_mode_id) );
b_found_mode = false;
for (;;)
{
IDeckLinkDisplayMode *p_display_mode;
result = decklink_sys.p_display_iterator->Next( &p_display_mode );
if( result != S_OK || !p_display_mode )
break;
char sz_mode_id_text[5] = {0};
BMDDisplayMode mode_id = ntohl( p_display_mode->GetDisplayMode() );
memcpy( sz_mode_id_text, &mode_id, sizeof(mode_id) );
const char *psz_mode_name;
result = p_display_mode->GetName( &psz_mode_name );
if( result != S_OK )
{
msg_Err( p_this, "Failed to get display mode name" );
p_display_mode->Release();
if( decklink_sys.decklink_iterator )
decklink_sys.decklink_iterator->Release();
if( decklink_sys.p_display_iterator )
decklink_sys.p_display_iterator->Release();
vlc_mutex_unlock(&decklink_sys.m_lock);
return VLC_EGENERIC;
}
BMDTimeValue frame_duration, time_scale;
result = p_display_mode->GetFrameRate( &frame_duration, &time_scale );
if( result != S_OK )
{
msg_Err( p_this, "Failed to get frame rate" );
p_display_mode->Release();
if( decklink_sys.decklink_iterator )
decklink_sys.decklink_iterator->Release();
if( decklink_sys.p_display_iterator )
decklink_sys.p_display_iterator->Release();
vlc_mutex_unlock(&decklink_sys.m_lock);
return VLC_EGENERIC;
}
const char *psz_field_dominance;
uint32_t i_dominance_flags = 0;
switch( p_display_mode->GetFieldDominance() )
{
case bmdProgressiveFrame:
psz_field_dominance = "";
break;
case bmdProgressiveSegmentedFrame:
psz_field_dominance = ", segmented";
break;
case bmdLowerFieldFirst:
psz_field_dominance = ", interlaced [BFF]";
i_dominance_flags = BLOCK_FLAG_BOTTOM_FIELD_FIRST;
break;
case bmdUpperFieldFirst:
psz_field_dominance = ", interlaced [TFF]";
i_dominance_flags = BLOCK_FLAG_TOP_FIELD_FIRST;
break;
case bmdUnknownFieldDominance:
default:
psz_field_dominance = ", unknown field dominance";
break;
}
msg_Dbg( p_this, "Found mode '%s': %s (%dx%d, %.3f fps%s)",
sz_mode_id_text, psz_mode_name,
p_display_mode->GetWidth(), p_display_mode->GetHeight(),
double(time_scale) / frame_duration, psz_field_dominance );
if( wanted_mode_id == mode_id )
{
b_found_mode = true;
decklink_sys.i_width = p_display_mode->GetWidth();
decklink_sys.i_height = p_display_mode->GetHeight();
decklink_sys.i_timescale = time_scale;
decklink_sys.i_frameduration = frame_duration;
decklink_sys.i_dominance_flags = i_dominance_flags;
decklink_sys.display_mode = wanted_mode_id;
if (p_display_mode->GetDisplayMode() == bmdModeNTSC ||
p_display_mode->GetDisplayMode() == bmdModeNTSC2398 ||
p_display_mode->GetDisplayMode() == bmdModePAL)
{
//timeCodeFormat = bmdTimecodeVITC;
videoOutputFlags |= bmdVideoOutputVITC;
}
else
{
//timeCodeFormat = bmdTimecodeRP188;
videoOutputFlags |= bmdVideoOutputRP188;
}
decklink_sys.videoOutputFlags = videoOutputFlags;
//if (timeCode)
// delete timeCode;
//timeCode = new Timecode(framesPerSecond);
}
p_display_mode->Release();
}
if( !b_found_mode )
{
msg_Err( p_this, "Unknown video mode specified." );
if( decklink_sys.decklink_iterator )
decklink_sys.decklink_iterator->Release();
if( decklink_sys.p_display_iterator )
decklink_sys.p_display_iterator->Release();
vlc_mutex_unlock(&decklink_sys.m_lock);
return VLC_EGENERIC;
}
//End of Find Display Mode
// Get Audio rate and Audio Channels
i_channels = var_InheritInteger( p_this, AUDIO_CFG_PREFIX "audio-channels" );
i_rate = var_InheritInteger( p_this, AUDIO_CFG_PREFIX "audio-rate" );
msg_Dbg( p_this, "audio rate = %d and audio channels = %d ", i_rate, i_channels );
if( !(i_rate > 0 && i_channels > 0) )
{
msg_Err( p_this, "Invalid audio rate or audio channels" );
if( decklink_sys.decklink_iterator )
decklink_sys.decklink_iterator->Release();
if( decklink_sys.p_display_iterator )
decklink_sys.p_display_iterator->Release();
vlc_mutex_unlock(&decklink_sys.m_lock);
return VLC_EGENERIC;
}
decklink_sys.i_channels = i_channels;
decklink_sys.i_rate = i_rate;
// End of Get Audio rate and Audio Channels
//vlc_mutex_lock(&decklink_sys.m_lock);
result = decklink_sys.p_output->EnableVideoOutput( htonl( decklink_sys.display_mode ), decklink_sys.videoOutputFlags );
if( result != S_OK )
{
msg_Err( p_this, "Failed to Enable Video Output" );
//p_display_mode->Release();
if( decklink_sys.decklink_iterator )
decklink_sys.decklink_iterator->Release();
if( decklink_sys.p_display_iterator )
decklink_sys.p_display_iterator->Release();
vlc_mutex_unlock(&decklink_sys.m_lock);
return VLC_EGENERIC;
}
result = decklink_sys.p_output->EnableAudioOutput( decklink_sys.i_rate, bmdAudioSampleType16bitInteger, decklink_sys.i_channels,bmdAudioOutputStreamContinuous );
if( result != S_OK )
{
msg_Err( p_this, "Failed to Enable Audio Output" );
if( decklink_sys.decklink_iterator )
decklink_sys.decklink_iterator->Release();
if( decklink_sys.p_display_iterator )
decklink_sys.p_display_iterator->Release();
vlc_mutex_unlock(&decklink_sys.m_lock);
return VLC_EGENERIC;
}
//decklink_sys.p_output->StartScheduledPlayback(0,decklink_sys.i_timescale,1.0);
decklink_sys.p_output->StartScheduledPlayback(0,100,1.0);
//decklink_sys.p_output->StartScheduledPlayback(0, 100, 1.0);
// msg_Dbg(p_this,"Start Playback");
vlc_mutex_unlock(&decklink_sys.m_lock);
msg_Dbg(p_this,"Finish Open Decklink, Decklink ref = %d", (int)vlc_atomic_get( &decklink_sys.m_ref ));
return VLC_SUCCESS;
}else{
msg_Dbg(p_this,"Finish Open Decklink, Decklink ref = %d", (int)vlc_atomic_get( &decklink_sys.m_ref ));
return VLC_SUCCESS;
}
}
/*****************************************************************************
* Close: destroy interface
*****************************************************************************/
static void CloseDecklink(vlc_object_t *p_this){
int result;
uintptr_t _ref = vlc_atomic_get( &decklink_sys.m_ref );
if ( _ref == 0 ){
vlc_mutex_lock(&decklink_sys.m_lock);
decklink_sys.p_output->StopScheduledPlayback(0, NULL, 0);
result = decklink_sys.p_output->DisableVideoOutput();
result = decklink_sys.p_output->DisableAudioOutput();
if( decklink_sys.decklink_iterator )
decklink_sys.decklink_iterator->Release();
if( decklink_sys.p_display_iterator )
decklink_sys.p_display_iterator->Release();
if( decklink_sys.p_config )
decklink_sys.p_config->Release();
if( decklink_sys.p_output )
{
decklink_sys.p_output->Release();
}
if( decklink_sys.p_card )
decklink_sys.p_card->Release();
vlc_mutex_unlock(&decklink_sys.m_lock);
vlc_mutex_destroy(&decklink_sys.m_lock);
msg_Dbg(p_this,"Finish destroy Decklink, Decklink ref = %d", _ref);
}
return;
}
static int OpenVideo( vlc_object_t *p_this )
{
int result;
result = OpenDecklink( p_this );
if( result != VLC_SUCCESS ){
CloseVideo(p_this);
return VLC_EGENERIC;
}
vout_display_t *vd = (vout_display_t *)p_this;
vout_display_sys_t *sys;
/* Allocate instance and initialize some members */
vd->sys = sys = (vout_display_sys_t*)malloc(sizeof(*sys));
if (!sys)
return VLC_ENOMEM;
vlc_mutex_init( &sys->pts_lock );
sys->pool = NULL;
sys->vdTotalFrames = 1;
vd->fmt.i_chroma = DECKLINK_VIDEO_CODEC;
video_format_FixRgb(&(vd->fmt));
vd->info.has_hide_mouse = true;
vd->pool = PoolVideo;
vd->prepare = NULL;
vd->display = DisplayVideo;
vd->control = ControlVideo;
vd->manage = NULL;
vout_display_SendEventFullscreen(vd, false);
vlc_mutex_lock(&decklink_sys.m_lock);
uintptr_t new_ref = vlc_atomic_inc( &decklink_sys.m_ref );
vlc_mutex_unlock(&decklink_sys.m_lock);
msg_Dbg(vd,"Open Decklink Video, Decklink ref = %d", (int)vlc_atomic_get( &decklink_sys.m_ref ));
return VLC_SUCCESS;
}
/*****************************************************************************
* Close: destroy interface
*****************************************************************************/
static void CloseVideo( vlc_object_t *p_this )
{
vout_display_t *vd = (vout_display_t *)p_this;
vout_display_sys_t *sys = vd->sys;
sys->vdTotalFrames = 0;
if (sys->pool)
picture_pool_Delete(sys->pool);
vlc_mutex_destroy( &sys->pts_lock );
free(sys);
//If ref = 0
vlc_mutex_lock(&decklink_sys.m_lock);
uintptr_t new_ref = vlc_atomic_dec( &decklink_sys.m_ref );
vlc_mutex_unlock(&decklink_sys.m_lock);
msg_Dbg(vd,"Close Decklink Video, Decklink ref = %d", (int)vlc_atomic_get( &decklink_sys.m_ref ));
CloseDecklink((vlc_object_t *)vd);
}
static picture_pool_t *PoolVideo(vout_display_t *vd, unsigned requested_count)
{
vout_display_sys_t *sys = vd->sys;
if (!sys->pool)
sys->pool = picture_pool_NewFromFormat(&vd->fmt, requested_count);
return sys->pool;
}
static void DisplayVideo(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
{
vout_display_sys_t *sys = vd->sys;
/* picture_t* to IDeckLinkMutableVideoFrame* */
if(picture){
int i_width = decklink_sys.i_width;
int i_height = decklink_sys.i_height;
BMDTimeScale i_timescale = decklink_sys.i_timescale;
BMDTimeValue i_frameduration = decklink_sys.i_frameduration;
//Export picture sang block_t
block_t *_vdblock ;
size_t result;
video_format_t *_fmt;
_fmt = (video_format_t *)malloc(sizeof(*_fmt));
video_format_Setup(_fmt,DECKLINK_VIDEO_CODEC,picture->format.i_width,picture->format.i_height,1,1 );
video_format_FixRgb(_fmt);
picture_Export(VLC_OBJECT(vd), &_vdblock, _fmt ,picture,DECKLINK_VIDEO_CODEC, i_width, i_height);
free(_fmt);
//Render to Decklink
IDeckLinkMutableVideoFrame *pDLVideoFrame;
if (decklink_sys.p_output->CreateVideoFrame(i_width, i_height, i_width*2,bmdFormat8BitYUV , bmdFrameFlagDefault, &pDLVideoFrame) != S_OK){
msg_Dbg( vd, "Failed to create video frame");
block_Release( _vdblock );
pDLVideoFrame->Release();
return;
}
void *_frame_bytes;
pDLVideoFrame->GetBytes( (void**)&_frame_bytes );
int i_stride = pDLVideoFrame->GetRowBytes();
int i_bpp = 2;
for( int y = 0; y < i_height; ++y )
{
uint8_t *dst = (uint8_t *)_frame_bytes + i_stride * y;
const uint8_t *src = (const uint8_t *)_vdblock->p_buffer + i_width * i_bpp * y;
memcpy( dst, src, i_width * i_bpp );
}
//end of block_t to Decklink Frame
if (decklink_sys.p_output->ScheduleVideoFrame(pDLVideoFrame, (sys->vdTotalFrames * i_frameduration)+VLC_TS_0, i_frameduration, i_timescale) != S_OK)
{
block_Release( _vdblock );
pDLVideoFrame->Release();
return ;
}
sys->vdTotalFrames ++;
pDLVideoFrame->Release();
block_Release( _vdblock );
//free(_vdblock);
//End of Render to Decklink
}
/* End of picture_t* to IDeckLinkMutableVideoFrame* */
picture_Release(picture);
VLC_UNUSED(subpicture);
return;
}
static int ControlVideo(vout_display_t *vd, int query, va_list args)
{
VLC_UNUSED(vd);
switch (query) {
case VOUT_DISPLAY_CHANGE_FULLSCREEN: {
const vout_display_cfg_t *cfg = va_arg(args, const vout_display_cfg_t *);
if (cfg->is_fullscreen)
return VLC_EGENERIC;
return VLC_SUCCESS;
}
default:
return VLC_EGENERIC;
}
}
static int OpenAudio( vlc_object_t *p_this )
{
//return Open( p_this, Audio );
int result;
result = OpenDecklink( p_this );
if( result != VLC_SUCCESS ){
CloseAudio(p_this);
return VLC_EGENERIC;
}
audio_output_t * aout = (audio_output_t *)p_this;
struct aout_sys_t *a_sys = NULL;
a_sys = ( aout_sys_t *)calloc( 1, sizeof( aout_sys_t ) );
if( !(a_sys))
{
return VLC_ENOMEM;
}
aout->sys = a_sys;
//Audio preferences go here
a_sys->aoutTotalAudioPackages = 1;
aout->pf_play = PlayAudio;
aout->pf_pause = NULL;
aout->pf_flush = NULL;
aout->format.i_format = DECKLINK_AUDIO_CODEC;
aout->format.i_channels = decklink_sys.i_channels;
aout->format.i_physical_channels = pi_channels_maps[aout->format.i_channels];
aout->format.i_rate = decklink_sys.i_rate;
aout->format.i_bitspersample = 16;
aout->format.i_blockalign = aout->format.i_channels * aout->format.i_bitspersample /8 ;
aout->format.i_frame_length = FRAME_SIZE;
aout_VolumeSoftInit( aout );
//End of Audio preferences go here
vlc_mutex_lock(&decklink_sys.m_lock);
uintptr_t new_ref = vlc_atomic_inc( &decklink_sys.m_ref );
msg_Dbg( aout, "Open Audio Decklink ref = %d", (int)new_ref);
vlc_mutex_unlock(&decklink_sys.m_lock);
return VLC_SUCCESS;
}
/*****************************************************************************
* Close: destroy interface
*****************************************************************************/
static void CloseAudio( vlc_object_t *p_this )
{
audio_output_t * aout = (audio_output_t *)p_this;
aout_sys_t *a_sys = aout->sys;
HRESULT result;
a_sys->aoutTotalAudioPackages = 0;
free(a_sys);
//If ref = 0
vlc_mutex_lock(&decklink_sys.m_lock);
uintptr_t new_ref = vlc_atomic_dec( &decklink_sys.m_ref );
vlc_mutex_unlock(&decklink_sys.m_lock);
msg_Dbg(aout,"Close Decklink Video, Decklink ref = %d", (int)vlc_atomic_get( &decklink_sys.m_ref ));
CloseDecklink((vlc_object_t *)aout);
}
static void PlayAudio( audio_output_t * aout, block_t *p_buffer){
aout_sys_t *a_sys = aout->sys;
//aout_buffer_t * p_buffer;
// p_buffer = aout_FifoPop( &aout->output.fifo );
uint32_t sampleFrameCount = p_buffer->i_buffer / (sizeof(int16_t) * aout->format.i_channels);
BMDTimeValue streamLength = p_buffer->i_length;
if ((decklink_sys.p_output->ScheduleAudioSamples (p_buffer->p_buffer, sampleFrameCount,a_sys->aoutTotalAudioPackages * streamLength, CLOCK_FREQ, NULL)) != S_OK){
msg_Dbg( aout, "Failed to schedule audio sample");
}
a_sys->aoutTotalAudioPackages++;
aout_BufferFree( p_buffer );
}
Code: Select all
SOURCES_logger = logger.c
SOURCES_vod_rtsp = rtsp.c
SOURCES_gnutls = gnutls.c dhparams.h
SOURCES_audioscrobbler = audioscrobbler.c
SOURCES_inhibit = inhibit.c
SOURCES_sqlite = sqlite.c
SOURCES_xml = xml/libxml.c
SOURCES_decklinkoutput = decklinkoutput.cpp
libxdg_screensaver_plugin_la_SOURCES = inhibit/xdg.c
libxdg_screensaver_plugin_la_CFLAGS = $(AM_CFLAGS)
libxdg_screensaver_plugin_la_LIBADD = $(AM_LIBADD)
libxdg_screensaver_plugin_la_DEPENDENCIES =
libxscreensaver_plugin_la_SOURCES = inhibit/xscreensaver.c
libxscreensaver_plugin_la_CFLAGS = $(AM_CFLAGS)
libxscreensaver_plugin_la_LIBADD = $(AM_LIBADD)
libxscreensaver_plugin_la_DEPENDENCIES =
if HAVE_XCB
libvlc_LTLIBRARIES += \
libxdg_screensaver_plugin.la \
libxscreensaver_plugin.la
endif
SOURCES_osso_screensaver = inhibit/osso.c
libvlc_LTLIBRARIES += \
libaudioscrobbler_plugin.la \
liblogger_plugin.la \
libdecklinkoutput_plugin.la
if HAVE_WINCE
libvlc_LTLIBRARIES += libwin32text_plugin.la
endif
if ENABLE_SOUT
libvlc_LTLIBRARIES += \
libvod_rtsp_plugin.la \
$(NULL)
endif
Code: Select all
dnl
dnl test module
dnl
AC_ARG_ENABLE(decklinkoutput,
[AS_HELP_STRING([--disable-decklinkoutput],
[disable Blackmagic DeckLink SDI Output (default auto)])])
AC_ARG_WITH(decklink_sdk,
[AS_HELP_STRING[--with-decklink-sdk=DIR],
[location of Blackmagic DeckLink SDI SDK])])
if test "${enable_decklinkoutput}" != "no"
then
if test "${with_decklink_sdk}" != "no" -a -n "${with_decklink_sdk}"
then
VLC_ADD_CPPFLAGS([decklink],[-I${with_decklink_sdk}/include])
fi
CPPFLAGS="${CPPFLAGS_save} ${CPPFLAGS_decklinkoutput}"
AC_LANG_PUSH(C++)
AC_CHECK_HEADERS(DeckLinkAPIDispatch.cpp, [
VLC_ADD_PLUGIN([decklinkoutput])
],[AC_MSG_WARN(Blackmagic DeckLink SDI include files not found, decklinkoutput disabled)])
AC_LANG_POP(C++)
CPPFLAGS="${CPPFLAGS_save}"
fi
dnl End of test
Code: Select all
/usr/bin/cvlc rtp://10.10.10.138:5000 --decklink-card-index 0 --decklink-mode "pal" --sout-transcode-audio-sync -v
Code: Select all
[0x22f7f68] packetizer_h264 packetizer warning: waiting for SPS/PPS
[0x22f7f68] packetizer_h264 packetizer warning: waiting for SPS/PPS
[0x22f7f68] packetizer_h264 packetizer warning: waiting for SPS/PPS
[0x22f7f68] packetizer_h264 packetizer warning: waiting for SPS/PPS
[0x22f7f68] packetizer_h264 packetizer warning: waiting for SPS/PPS
[0x2306e98] main audio output warning: buffer too late (101679), up-sampling
[0x22f7f68] packetizer_h264 packetizer warning: waiting for SPS/PPS
[0x22f7f68] packetizer_h264 packetizer warning: waiting for SPS/PPS
[0x22f7f68] packetizer_h264 packetizer warning: waiting for SPS/PPS
[0x22f7f68] packetizer_h264 packetizer warning: waiting for SPS/PPS
[0x13b14ea8] main vout display error: Failed to set on top
[0x2306e98] main audio output warning: resampling stopped after 3939966 usec (drift: -47107)
[0x2306e98] main audio output warning: buffer too late (81565), up-sampling
[0x2306e98] main audio output warning: resampling stopped after 6160102 usec (drift: -52056)
[0x2306e98] main audio output warning: buffer too late (62140), up-sampling
[0x2306e98] main audio output warning: resampling stopped after 3900574 usec (drift: -23397)
[0x2306e98] main audio output warning: buffer too late (61055), up-sampling
[0x2306e98] main audio output warning: resampling stopped after 9580038 usec (drift: -6103)
hey, my is ozHello VLC developers.
I'm writing a output plugin for BlackMagic Decklink SDI card. I have video playout over SDI working, but I have problem about getting audio playout working well. The code I've added resides file modules/video_output/decklinkout.cpp where the Decklink API is initialized and used for video playback.
The audio output plugin in modules/audio_output/decklink.cpp but this code won't be able to access the object created in modules/video_output/decklink.cpp.
I can only have one instance of a Decklink board object, so how would I share an object created in a video_output module with code in an audio_output?
Or how can i write a plugin that can handle both audio and video data for output?
Thank you.
There is a patch for Decklink output in SDI lying around.
Please can you help find this patch?There is a patch for Decklink output in SDI lying around.
Return to “Development around libVLC”
Users browsing this forum: No registered users and 8 guests