Commit 3119a2c5 authored by Steinar H. Gunderson's avatar Steinar H. Gunderson Committed by Jean-Baptiste Kempf

Add access module for BlackMagic SDI cards ("decklink").

Adds a driver for the BlackMagic DeckLink series of SDI cards (input only).
It requires BlackMagic's proprietary (but free-to-download) SDK to compile
and run. I've only tested it on Linux -- the Windows API is very similar but
not identical, so some adjustments will probably have to happen if anybody
wants this to work on Windows. (Windows users can, AFAIK, already access the
card via DirectShow, though.) It supports multiple cards, all the various
A/V inputs and video modes including setting field dominance and multichannel
input (2, 8 or 16 channels).

All testing has been with a DeckLink HD Extreme 3, which I have very
graciously been given access to by Frikanalen.
Signed-off-by: Jean-Baptiste Kempf's avatarJean-Baptiste Kempf <jb@videolan.org>
parent d7fa382b
......@@ -17,6 +17,7 @@ Access
* Support for VDR recordings
* Blu-Ray integration with libbluray
* HTTP Live Streaming (IETF draft) playback support
* Blackmagic DeckLink SDI card input support (Linux only currently)
Codecs
* You can now use ffmpeg-mt in conjunction with vlc
......
......@@ -2144,6 +2144,29 @@ then
fi
fi
dnl
dnl special access module for Blackmagic SDI cards
dnl
AC_ARG_ENABLE(decklink,
[ --enable-decklink Blackmagic DeckLink SDI access module (default enabled)])
if test "${enable_decklink}" != "no"
then
AC_ARG_WITH(decklink_sdk,
[ --with-decklink-sdk=DIR Location of Blackmagic DeckLink SDI SDK],[],[])
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_decklink}"
AC_LANG_PUSH(C++)
AC_CHECK_HEADERS(DeckLinkAPIDispatch.cpp, [
VLC_ADD_PLUGIN([decklink])
],[AC_MSG_WARN(Blackmagic DeckLink SDI include files not found, decklink disabled)])
AC_LANG_POP(C++)
CPPFLAGS="${CPPFLAGS_save}"
fi
dnl
dnl gnomeVFS access module
dnl
......
......@@ -81,6 +81,7 @@ $Id$
* cvdsub: CVD subtitles decoder
* dbus: D-Bus control interface
* dc1394: firewire input module
* decklink: input module to read from a Blackmagic SDI card
* decomp: Decompression module
* deinterlace: naive deinterlacing filter
* demux_cdg: Demuxer for CD-G files (Karaoke)
......
......@@ -52,6 +52,7 @@ SOURCES_access_avio = avio.c avio.h
SOURCES_access_attachment = attachment.c
SOURCES_access_vdr = vdr.c
SOURCES_libbluray = bluray.c
SOURCES_decklink = decklink.cpp
SOURCES_access_rar = rar/rar.c rar/rar.h rar/access.c
SOURCES_stream_filter_rar = rar/rar.c rar/rar.h rar/stream.c
......
/*****************************************************************************
* decklink.cpp: BlackMagic DeckLink SDI input module
*****************************************************************************
* Copyright (C) 2010 Steinar H. Gunderson
*
* Authors: Steinar H. Gunderson <steinar+vlc@gunderson.no>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#define __STDC_CONSTANT_MACROS 1
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_demux.h>
#include <vlc_atomic.h>
#include <arpa/inet.h>
#include <DeckLinkAPI.h>
#include <DeckLinkAPIDispatch.cpp>
static int Open ( vlc_object_t * );
static void Close( vlc_object_t * );
#define CARD_INDEX_TEXT N_("Input card to use")
#define CARD_INDEX_LONGTEXT N_( \
"DeckLink capture card to use, if multiple exist. " \
"The cards are numbered from 0." )
#define MODE_TEXT N_("Desired input video mode")
#define MODE_LONGTEXT N_( \
"Desired input video mode for DeckLink captures. " \
"This value should be a FOURCC code in textual " \
"form, e.g. \"ntsc\"." )
#define CACHING_TEXT N_("Caching value in ms")
#define CACHING_LONGTEXT N_( \
"Caching value for DeckLink captures. This " \
"value should be set in milliseconds." )
#define AUDIO_CONNECTION_TEXT N_("Audio connection")
#define AUDIO_CONNECTION_LONGTEXT N_( \
"Audio connection to use for DeckLink captures. " \
"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 captures. " \
"0 disables audio input." )
#define CHANNELS_TEXT N_("Number of audio channels")
#define CHANNELS_LONGTEXT N_( \
"Number of input audio channels for DeckLink captures. " \
"Must be 2, 8 or 16. 0 disables audio input." )
#define VIDEO_CONNECTION_TEXT N_("Video connection")
#define VIDEO_CONNECTION_LONGTEXT N_( \
"Video connection to use for DeckLink captures. " \
"Valid choices: sdi, hdmi, opticalsdi, component, " \
"composite, svideo. " \
"Leave blank for card default." )
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")
};
#define ASPECT_RATIO_TEXT N_("Aspect ratio")
#define ASPECT_RATIO_LONGTEXT N_( \
"Aspect ratio (4:3, 16:9). Default assumes square pixels." )
vlc_module_begin ()
set_shortname( N_("DeckLink") )
set_description( N_("Blackmagic DeckLink SDI input") )
set_category( CAT_INPUT )
set_subcategory( SUBCAT_INPUT_ACCESS )
add_integer( "decklink-card-index", 0, NULL,
CARD_INDEX_TEXT, CARD_INDEX_LONGTEXT, true )
add_string( "decklink-mode", "pal ", NULL,
MODE_TEXT, MODE_LONGTEXT, true )
add_integer( "decklink-caching", DEFAULT_PTS_DELAY / 1000, NULL,
CACHING_TEXT, CACHING_LONGTEXT, true )
add_string( "decklink-audio-connection", 0, NULL,
AUDIO_CONNECTION_TEXT, AUDIO_CONNECTION_LONGTEXT, true )
add_integer( "decklink-audio-rate", 48000, NULL,
RATE_TEXT, RATE_LONGTEXT, true )
add_integer( "decklink-audio-channels", 2, NULL,
CHANNELS_TEXT, CHANNELS_LONGTEXT, true )
add_string( "decklink-video-connection", 0, NULL,
VIDEO_CONNECTION_TEXT, VIDEO_CONNECTION_LONGTEXT, true )
change_string_list( ppsz_videoconns, ppsz_videoconns_text, 0 )
add_string( "decklink-aspect-ratio", NULL, NULL,
ASPECT_RATIO_TEXT, ASPECT_RATIO_LONGTEXT, true )
add_shortcut( "decklink" )
set_capability( "access_demux", 10 )
set_callbacks( Open, Close )
vlc_module_end ()
static int Control( demux_t *, int, va_list );
class DeckLinkCaptureDelegate;
struct demux_sys_t
{
IDeckLink *p_card;
IDeckLinkInput *p_input;
DeckLinkCaptureDelegate *p_delegate;
es_out_id_t *p_video_es;
es_out_id_t *p_audio_es;
vlc_mutex_t pts_lock;
int i_last_pts; /* protected by <pts_lock> */
uint32_t i_dominance_flags;
int i_channels;
};
class DeckLinkCaptureDelegate : public IDeckLinkInputCallback
{
public:
DeckLinkCaptureDelegate( demux_t *p_demux ) : p_demux_(p_demux)
{
vlc_atomic_set( &m_ref_, 1 );
}
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) { return E_NOINTERFACE; }
virtual ULONG STDMETHODCALLTYPE AddRef(void)
{
return vlc_atomic_inc( &m_ref_ );
}
virtual ULONG STDMETHODCALLTYPE Release(void)
{
uintptr_t new_ref = vlc_atomic_dec( &m_ref_ );
if ( new_ref == 0 )
delete this;
return new_ref;
}
virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(BMDVideoInputFormatChangedEvents, IDeckLinkDisplayMode*, BMDDetectedVideoInputFormatFlags)
{
msg_Dbg( p_demux_, "Video input format changed" );
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame*, IDeckLinkAudioInputPacket*);
private:
vlc_atomic_t m_ref_;
demux_t *p_demux_;
};
HRESULT DeckLinkCaptureDelegate::VideoInputFrameArrived(IDeckLinkVideoInputFrame* videoFrame, IDeckLinkAudioInputPacket* audioFrame)
{
demux_sys_t *p_sys = p_demux_->p_sys;
block_t *p_video_frame = NULL;
block_t *p_audio_frame = NULL;
if( videoFrame )
{
if( videoFrame->GetFlags() & bmdFrameHasNoInputSource )
{
msg_Warn( p_demux_, "No input signal detected" );
return S_OK;
}
const int i_width = videoFrame->GetWidth();
const int i_height = videoFrame->GetHeight();
const int i_stride = videoFrame->GetRowBytes();
const int i_bpp = 2;
p_video_frame = block_New( p_demux_, i_width * i_height * i_bpp );
if( !p_video_frame )
{
msg_Err( p_demux_, "Could not allocate memory for video frame" );
return S_OK;
}
void *frame_bytes;
videoFrame->GetBytes( &frame_bytes );
for( int y = 0; y < i_height; ++y )
{
const uint8_t *src = (const uint8_t *)frame_bytes + i_stride * y;
uint8_t *dst = p_video_frame->p_buffer + i_width * i_bpp * y;
memcpy( dst, src, i_width * i_bpp );
}
BMDTimeValue stream_time, frame_duration;
videoFrame->GetStreamTime( &stream_time, &frame_duration, CLOCK_FREQ );
p_video_frame->i_flags = BLOCK_FLAG_TYPE_I | p_sys->i_dominance_flags;
p_video_frame->i_pts = p_video_frame->i_dts = VLC_TS_0 + stream_time;
vlc_mutex_lock( &p_sys->pts_lock );
if( p_video_frame->i_pts > p_sys->i_last_pts )
p_sys->i_last_pts = p_video_frame->i_pts;
vlc_mutex_unlock( &p_sys->pts_lock );
es_out_Control( p_demux_->out, ES_OUT_SET_PCR, p_video_frame->i_pts );
es_out_Send( p_demux_->out, p_sys->p_video_es, p_video_frame );
}
if( audioFrame )
{
const int i_bytes = audioFrame->GetSampleFrameCount() * sizeof(int16_t) * p_sys->i_channels;
p_audio_frame = block_New( p_demux_, i_bytes );
if( !p_audio_frame )
{
msg_Err( p_demux_, "Could not allocate memory for audio frame" );
if( p_video_frame )
block_Release( p_video_frame );
return S_OK;
}
void *frame_bytes;
audioFrame->GetBytes( &frame_bytes );
memcpy( p_audio_frame->p_buffer, frame_bytes, i_bytes );
BMDTimeValue packet_time;
audioFrame->GetPacketTime( &packet_time, CLOCK_FREQ );
p_audio_frame->i_pts = p_audio_frame->i_dts = VLC_TS_0 + packet_time;
vlc_mutex_lock( &p_sys->pts_lock );
if( p_audio_frame->i_pts > p_sys->i_last_pts )
p_sys->i_last_pts = p_audio_frame->i_pts;
vlc_mutex_unlock( &p_sys->pts_lock );
if( p_audio_frame->i_pts > p_sys->i_last_pts )
es_out_Control( p_demux_->out, ES_OUT_SET_PCR, p_audio_frame->i_pts );
es_out_Send( p_demux_->out, p_sys->p_audio_es, p_audio_frame );
}
return S_OK;
}
static int Open( vlc_object_t *p_this )
{
demux_t *p_demux = (demux_t*)p_this;
demux_sys_t *p_sys;
int ret = VLC_EGENERIC;
char *psz_aspect;
char *psz_display_mode = NULL;
char *psz_video_connection = NULL;
char *psz_audio_connection = NULL;
bool b_found_mode;
int i_card_index;
int i_width, i_height, i_fps_num, i_fps_den;
int i_rate;
unsigned u_aspect_num, u_aspect_den;
/* Only when selected */
if( *p_demux->psz_access == '\0' )
return VLC_EGENERIC;
/* Set up p_demux */
p_demux->pf_demux = NULL;
p_demux->pf_control = Control;
p_demux->info.i_update = 0;
p_demux->info.i_title = 0;
p_demux->info.i_seekpoint = 0;
p_demux->p_sys = p_sys = (demux_sys_t*)calloc( 1, sizeof( demux_sys_t ) );
if( !p_sys )
return VLC_ENOMEM;
vlc_mutex_init( &p_sys->pts_lock );
IDeckLinkIterator *decklink_iterator = CreateDeckLinkIteratorInstance();
if( !decklink_iterator )
{
msg_Err( p_demux, "DeckLink drivers not found." );
goto finish;
}
HRESULT result;
i_card_index = var_InheritInteger( p_demux, "decklink-card-index" );
if( i_card_index < 0 )
{
msg_Err( p_demux, "Invalid card index %d", i_card_index );
goto finish;
}
for( int i = 0; i <= i_card_index; ++i )
{
if( p_sys->p_card )
p_sys->p_card->Release();
result = decklink_iterator->Next( &p_sys->p_card );
if( result != S_OK )
break;
}
if( result != S_OK )
{
msg_Err( p_demux, "DeckLink PCI card %d not found", i_card_index );
goto finish;
}
const char *psz_model_name;
result = p_sys->p_card->GetModelName( &psz_model_name );
if( result != S_OK )
{
msg_Err( p_demux, "Could not get model name" );
goto finish;
}
msg_Dbg( p_demux, "Opened DeckLink PCI card %d (%s)", i_card_index, psz_model_name );
if( p_sys->p_card->QueryInterface( IID_IDeckLinkInput, (void**)&p_sys->p_input) != S_OK )
{
msg_Err( p_demux, "Card has no inputs" );
goto finish;
}
/* Set up the video and audio sources. */
IDeckLinkConfiguration *p_config;
if( p_sys->p_card->QueryInterface( IID_IDeckLinkConfiguration, (void**)&p_config) != S_OK )
{
msg_Err( p_demux, "Failed to get configuration interface" );
goto finish;
}
psz_video_connection = var_InheritString( p_demux, "decklink-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_demux, "Invalid --decklink-video-connection specified; choose one of " \
"sdi, hdmi, opticalsdi, component, composite, or svideo." );
goto finish;
}
msg_Dbg( p_demux, "Setting video input format to 0x%x", conn);
result = p_config->SetVideoInputFormat( conn );
if( result != S_OK )
{
msg_Err( p_demux, "Failed to set video input connection" );
goto finish;
}
}
psz_audio_connection = var_CreateGetNonEmptyString( p_demux, "decklink-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_demux, "Invalid --decklink-audio-connection specified; choose one of " \
"embedded, aesebu, or analog." );
goto finish;
}
msg_Dbg( p_demux, "Setting audio input format to 0x%x", conn);
result = p_config->SetAudioInputFormat( conn );
if( result != S_OK )
{
msg_Err( p_demux, "Failed to set audio input connection" );
goto finish;
}
}
/* Get the list of display modes. */
IDeckLinkDisplayModeIterator *p_display_iterator;
result = p_sys->p_input->GetDisplayModeIterator( &p_display_iterator );
if( result != S_OK )
{
msg_Err( p_demux, "Failed to enumerate display modes" );
goto finish;
}
psz_display_mode = var_CreateGetNonEmptyString( p_demux, "decklink-mode" );
if( !psz_display_mode || strlen( psz_display_mode ) > 4 ) {
msg_Err( p_demux, "Missing or invalid --decklink-mode string" );
goto finish;
}
/*
* 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 = 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_demux, "Failed to get display mode name" );
p_display_mode->Release();
goto finish;
}
BMDTimeValue frame_duration, time_scale;
result = p_display_mode->GetFrameRate( &frame_duration, &time_scale );
if( result != S_OK )
{
msg_Err( p_demux, "Failed to get frame rate" );
p_display_mode->Release();
goto finish;
}
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_demux, "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;
i_width = p_display_mode->GetWidth();
i_height = p_display_mode->GetHeight();
i_fps_num = time_scale;
i_fps_den = frame_duration;
p_sys->i_dominance_flags = i_dominance_flags;
}
p_display_mode->Release();
}
if( !b_found_mode )
{
msg_Err( p_demux, "Unknown video mode specified. " \
"Run VLC with -v --verbose-objects=-all,+decklink " \
"to get a list of supported modes." );
goto finish;
}
result = p_sys->p_input->EnableVideoInput( htonl( wanted_mode_id ), bmdFormat8BitYUV, 0 );
if( result != S_OK )
{
msg_Err( p_demux, "Failed to enable video input" );
goto finish;
}
/* Set up audio. */
p_sys->i_channels = var_InheritInteger( p_demux, "decklink-audio-channels" );
i_rate = var_InheritInteger( p_demux, "decklink-audio-rate" );
if( i_rate > 0 && p_sys->i_channels > 0 )
{
result = p_sys->p_input->EnableAudioInput( i_rate, bmdAudioSampleType16bitInteger, p_sys->i_channels );
if( result != S_OK )
{
msg_Err( p_demux, "Failed to enable audio input" );
goto finish;
}
}
p_sys->p_delegate = new DeckLinkCaptureDelegate( p_demux );
p_sys->p_input->SetCallback( p_sys->p_delegate );
result = p_sys->p_input->StartStreams();
if( result != S_OK )
{
msg_Err( p_demux, "Could not start streaming from SDI card. This could be caused "
"by invalid video mode or flags, access denied, or card already in use." );
goto finish;
}
/* Declare elementary streams */
es_format_t video_fmt;
es_format_Init( &video_fmt, VIDEO_ES, VLC_CODEC_UYVY );
video_fmt.video.i_width = i_width;
video_fmt.video.i_height = i_height;
video_fmt.video.i_sar_num = 1;
video_fmt.video.i_sar_den = 1;
video_fmt.video.i_frame_rate = i_fps_num;
video_fmt.video.i_frame_rate_base = i_fps_den;
video_fmt.i_bitrate = video_fmt.video.i_width * video_fmt.video.i_height * video_fmt.video.i_frame_rate * 2 * 8;
if ( !var_InheritURational( p_demux, &u_aspect_num, &u_aspect_den, "decklink-aspect-ratio" ) &&
u_aspect_num > 0 && u_aspect_den > 0 ) {
video_fmt.video.i_sar_num = u_aspect_num * video_fmt.video.i_height;
video_fmt.video.i_sar_den = u_aspect_den * video_fmt.video.i_width;
}
msg_Dbg( p_demux, "added new video es %4.4s %dx%d",
(char*)&video_fmt.i_codec, video_fmt.video.i_width, video_fmt.video.i_height );
p_sys->p_video_es = es_out_Add( p_demux->out, &video_fmt );
es_format_t audio_fmt;
es_format_Init( &audio_fmt, AUDIO_ES, VLC_CODEC_S16N );
audio_fmt.audio.i_channels = p_sys->i_channels;
audio_fmt.audio.i_rate = i_rate;
audio_fmt.audio.i_bitspersample = 16;
audio_fmt.audio.i_blockalign = audio_fmt.audio.i_channels * audio_fmt.audio.i_bitspersample / 8;
audio_fmt.i_bitrate = audio_fmt.audio.i_channels * audio_fmt.audio.i_rate * audio_fmt.audio.i_bitspersample;
msg_Dbg( p_demux, "added new audio es %4.4s %dHz %dbpp %dch",
(char*)&audio_fmt.i_codec, audio_fmt.audio.i_rate, audio_fmt.audio.i_bitspersample, audio_fmt.audio.i_channels);
p_sys->p_audio_es = es_out_Add( p_demux->out, &audio_fmt );
ret = VLC_SUCCESS;
finish:
if( decklink_iterator )
decklink_iterator->Release();
if( p_config )
p_config->Release();
free( psz_video_connection );
free( psz_audio_connection );
free( psz_display_mode );
if( p_display_iterator )
p_display_iterator->Release();
if( ret != VLC_SUCCESS )
Close( p_this );
return ret;
}
static void Close( vlc_object_t *p_this )
{
demux_t *p_demux = (demux_t *)p_this;
demux_sys_t *p_sys = p_demux->p_sys;
if( p_sys->p_input )
{
p_sys->p_input->StopStreams();
p_sys->p_input->Release();
}
if( p_sys->p_card )
p_sys->p_card->Release();
if( p_sys->p_delegate )
p_sys->p_delegate->Release();
free( p_sys );
}
static int Control( demux_t *p_demux, int i_query, va_list args )
{
demux_sys_t *p_sys = p_demux->p_sys;
bool *pb;
int64_t *pi64;
switch( i_query )
{
/* Special for access_demux */
case DEMUX_CAN_PAUSE:
case DEMUX_CAN_SEEK:
case DEMUX_CAN_CONTROL_PACE:
pb = (bool*)va_arg( args, bool * );
*pb = false;
return VLC_SUCCESS;
case DEMUX_GET_PTS_DELAY:
pi64 = (int64_t*)va_arg( args, int64_t * );
*pi64 = var_InheritInteger( p_demux, "decklink-caching" ) * 1000;
return VLC_SUCCESS;
case DEMUX_GET_TIME:
pi64 = (int64_t*)va_arg( args, int64_t * );
vlc_mutex_lock( &p_sys->pts_lock );
*pi64 = p_sys->i_last_pts;
vlc_mutex_unlock( &p_sys->pts_lock );
return VLC_SUCCESS;
default:
return VLC_EGENERIC;
}
return VLC_EGENERIC;
}
......@@ -205,6 +205,7 @@ modules/access/bda/bdagraph.cpp
modules/access/bda/bdagraph.h
modules/access/cdda.c
modules/access/dc1394.c
modules/access/decklink.cpp
modules/access/directory.c
modules/access/dshow/common.h
modules/access/dshow/crossbar.cpp
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment