1 /*****************************************************************************
2 * decklink.cpp: BlackMagic DeckLink SDI input module
3 *****************************************************************************
4 * Copyright (C) 2010 Steinar H. Gunderson
6 * Authors: Steinar H. Gunderson <steinar+vlc@gunderson.no>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 *****************************************************************************/
24 #define __STDC_CONSTANT_MACROS 1
30 #include <vlc_common.h>
31 #include <vlc_plugin.h>
32 #include <vlc_demux.h>
33 #include <vlc_atomic.h>
35 #include <arpa/inet.h>
37 #include <DeckLinkAPI.h>
38 #include <DeckLinkAPIDispatch.cpp>
40 static int Open ( vlc_object_t
* );
41 static void Close( vlc_object_t
* );
43 #define CARD_INDEX_TEXT N_("Input card to use")
44 #define CARD_INDEX_LONGTEXT N_( \
45 "DeckLink capture card to use, if multiple exist. " \
46 "The cards are numbered from 0." )
48 #define MODE_TEXT N_("Desired input video mode")
49 #define MODE_LONGTEXT N_( \
50 "Desired input video mode for DeckLink captures. " \
51 "This value should be a FOURCC code in textual " \
52 "form, e.g. \"ntsc\"." )
54 #define AUDIO_CONNECTION_TEXT N_("Audio connection")
55 #define AUDIO_CONNECTION_LONGTEXT N_( \
56 "Audio connection to use for DeckLink captures. " \
57 "Valid choices: embedded, aesebu, analog. " \
58 "Leave blank for card default." )
60 #define RATE_TEXT N_("Audio sampling rate in Hz")
61 #define RATE_LONGTEXT N_( \
62 "Audio sampling rate (in hertz) for DeckLink captures. " \
63 "0 disables audio input." )
65 #define CHANNELS_TEXT N_("Number of audio channels")
66 #define CHANNELS_LONGTEXT N_( \
67 "Number of input audio channels for DeckLink captures. " \
68 "Must be 2, 8 or 16. 0 disables audio input." )
70 #define VIDEO_CONNECTION_TEXT N_("Video connection")
71 #define VIDEO_CONNECTION_LONGTEXT N_( \
72 "Video connection to use for DeckLink captures. " \
73 "Valid choices: sdi, hdmi, opticalsdi, component, " \
74 "composite, svideo. " \
75 "Leave blank for card default." )
77 static const char *const ppsz_videoconns
[] = {
78 "sdi", "hdmi", "opticalsdi", "component", "composite", "svideo"
80 static const char *const ppsz_videoconns_text
[] = {
81 N_("SDI"), N_("HDMI"), N_("Optical SDI"), N_("Component"), N_("Composite"), N_("S-video")
84 static const char *const ppsz_audioconns
[] = {
85 "embedded", "aesebu", "analog"
87 static const char *const ppsz_audioconns_text
[] = {
88 N_("Embedded"), N_("AES/EBU"), N_("Analog")
91 #define ASPECT_RATIO_TEXT N_("Aspect ratio")
92 #define ASPECT_RATIO_LONGTEXT N_( \
93 "Aspect ratio (4:3, 16:9). Default assumes square pixels." )
96 set_shortname( N_("DeckLink") )
97 set_description( N_("Blackmagic DeckLink SDI input") )
98 set_category( CAT_INPUT
)
99 set_subcategory( SUBCAT_INPUT_ACCESS
)
101 add_integer( "decklink-card-index", 0,
102 CARD_INDEX_TEXT
, CARD_INDEX_LONGTEXT
, true )
103 add_string( "decklink-mode", "pal ",
104 MODE_TEXT
, MODE_LONGTEXT
, true )
105 add_string( "decklink-audio-connection", 0,
106 AUDIO_CONNECTION_TEXT
, AUDIO_CONNECTION_LONGTEXT
, true )
107 change_string_list( ppsz_audioconns
, ppsz_audioconns_text
, 0 )
108 add_integer( "decklink-audio-rate", 48000,
109 RATE_TEXT
, RATE_LONGTEXT
, true )
110 add_integer( "decklink-audio-channels", 2,
111 CHANNELS_TEXT
, CHANNELS_LONGTEXT
, true )
112 add_string( "decklink-video-connection", 0,
113 VIDEO_CONNECTION_TEXT
, VIDEO_CONNECTION_LONGTEXT
, true )
114 change_string_list( ppsz_videoconns
, ppsz_videoconns_text
, 0 )
115 add_string( "decklink-aspect-ratio", NULL
,
116 ASPECT_RATIO_TEXT
, ASPECT_RATIO_LONGTEXT
, true )
118 add_shortcut( "decklink" )
119 set_capability( "access_demux", 10 )
120 set_callbacks( Open
, Close
)
123 static int Control( demux_t
*, int, va_list );
125 class DeckLinkCaptureDelegate
;
130 IDeckLinkInput
*p_input
;
131 DeckLinkCaptureDelegate
*p_delegate
;
133 /* We need to hold onto the IDeckLinkConfiguration object, or our settings will not apply.
134 See section 2.4.15 of the Blackmagic Decklink SDK documentation. */
135 IDeckLinkConfiguration
*p_config
;
137 es_out_id_t
*p_video_es
;
138 es_out_id_t
*p_audio_es
;
140 vlc_mutex_t pts_lock
;
141 int i_last_pts
; /* protected by <pts_lock> */
143 uint32_t i_dominance_flags
;
147 class DeckLinkCaptureDelegate
: public IDeckLinkInputCallback
150 DeckLinkCaptureDelegate( demux_t
*p_demux
) : p_demux_(p_demux
)
152 vlc_atomic_set( &m_ref_
, 1 );
155 virtual HRESULT STDMETHODCALLTYPE
QueryInterface(REFIID iid
, LPVOID
*ppv
) { return E_NOINTERFACE
; }
157 virtual ULONG STDMETHODCALLTYPE
AddRef(void)
159 return vlc_atomic_inc( &m_ref_
);
162 virtual ULONG STDMETHODCALLTYPE
Release(void)
164 uintptr_t new_ref
= vlc_atomic_dec( &m_ref_
);
170 virtual HRESULT STDMETHODCALLTYPE
VideoInputFormatChanged(BMDVideoInputFormatChangedEvents
, IDeckLinkDisplayMode
*, BMDDetectedVideoInputFormatFlags
)
172 msg_Dbg( p_demux_
, "Video input format changed" );
176 virtual HRESULT STDMETHODCALLTYPE
VideoInputFrameArrived(IDeckLinkVideoInputFrame
*, IDeckLinkAudioInputPacket
*);
183 HRESULT
DeckLinkCaptureDelegate::VideoInputFrameArrived(IDeckLinkVideoInputFrame
* videoFrame
, IDeckLinkAudioInputPacket
* audioFrame
)
185 demux_sys_t
*p_sys
= p_demux_
->p_sys
;
186 block_t
*p_video_frame
= NULL
;
187 block_t
*p_audio_frame
= NULL
;
191 if( videoFrame
->GetFlags() & bmdFrameHasNoInputSource
)
193 msg_Warn( p_demux_
, "No input signal detected" );
197 const int i_width
= videoFrame
->GetWidth();
198 const int i_height
= videoFrame
->GetHeight();
199 const int i_stride
= videoFrame
->GetRowBytes();
202 p_video_frame
= block_New( p_demux_
, i_width
* i_height
* i_bpp
);
205 msg_Err( p_demux_
, "Could not allocate memory for video frame" );
210 videoFrame
->GetBytes( &frame_bytes
);
211 for( int y
= 0; y
< i_height
; ++y
)
213 const uint8_t *src
= (const uint8_t *)frame_bytes
+ i_stride
* y
;
214 uint8_t *dst
= p_video_frame
->p_buffer
+ i_width
* i_bpp
* y
;
215 memcpy( dst
, src
, i_width
* i_bpp
);
218 BMDTimeValue stream_time
, frame_duration
;
219 videoFrame
->GetStreamTime( &stream_time
, &frame_duration
, CLOCK_FREQ
);
220 p_video_frame
->i_flags
= BLOCK_FLAG_TYPE_I
| p_sys
->i_dominance_flags
;
221 p_video_frame
->i_pts
= p_video_frame
->i_dts
= VLC_TS_0
+ stream_time
;
223 vlc_mutex_lock( &p_sys
->pts_lock
);
224 if( p_video_frame
->i_pts
> p_sys
->i_last_pts
)
225 p_sys
->i_last_pts
= p_video_frame
->i_pts
;
226 vlc_mutex_unlock( &p_sys
->pts_lock
);
228 es_out_Control( p_demux_
->out
, ES_OUT_SET_PCR
, p_video_frame
->i_pts
);
229 es_out_Send( p_demux_
->out
, p_sys
->p_video_es
, p_video_frame
);
234 const int i_bytes
= audioFrame
->GetSampleFrameCount() * sizeof(int16_t) * p_sys
->i_channels
;
236 p_audio_frame
= block_New( p_demux_
, i_bytes
);
239 msg_Err( p_demux_
, "Could not allocate memory for audio frame" );
241 block_Release( p_video_frame
);
246 audioFrame
->GetBytes( &frame_bytes
);
247 memcpy( p_audio_frame
->p_buffer
, frame_bytes
, i_bytes
);
249 BMDTimeValue packet_time
;
250 audioFrame
->GetPacketTime( &packet_time
, CLOCK_FREQ
);
251 p_audio_frame
->i_pts
= p_audio_frame
->i_dts
= VLC_TS_0
+ packet_time
;
253 vlc_mutex_lock( &p_sys
->pts_lock
);
254 if( p_audio_frame
->i_pts
> p_sys
->i_last_pts
)
255 p_sys
->i_last_pts
= p_audio_frame
->i_pts
;
256 vlc_mutex_unlock( &p_sys
->pts_lock
);
257 if( p_audio_frame
->i_pts
> p_sys
->i_last_pts
)
259 es_out_Control( p_demux_
->out
, ES_OUT_SET_PCR
, p_audio_frame
->i_pts
);
260 es_out_Send( p_demux_
->out
, p_sys
->p_audio_es
, p_audio_frame
);
266 static int Open( vlc_object_t
*p_this
)
268 demux_t
*p_demux
= (demux_t
*)p_this
;
270 int ret
= VLC_EGENERIC
;
272 char *psz_display_mode
= NULL
;
273 char *psz_video_connection
= NULL
;
274 char *psz_audio_connection
= NULL
;
277 int i_width
, i_height
, i_fps_num
, i_fps_den
;
279 unsigned u_aspect_num
, u_aspect_den
;
281 /* Only when selected */
282 if( *p_demux
->psz_access
== '\0' )
286 p_demux
->pf_demux
= NULL
;
287 p_demux
->pf_control
= Control
;
288 p_demux
->info
.i_update
= 0;
289 p_demux
->info
.i_title
= 0;
290 p_demux
->info
.i_seekpoint
= 0;
291 p_demux
->p_sys
= p_sys
= (demux_sys_t
*)calloc( 1, sizeof( demux_sys_t
) );
295 vlc_mutex_init( &p_sys
->pts_lock
);
297 IDeckLinkDisplayModeIterator
*p_display_iterator
= NULL
;
299 IDeckLinkIterator
*decklink_iterator
= CreateDeckLinkIteratorInstance();
300 if( !decklink_iterator
)
302 msg_Err( p_demux
, "DeckLink drivers not found." );
308 i_card_index
= var_InheritInteger( p_demux
, "decklink-card-index" );
309 if( i_card_index
< 0 )
311 msg_Err( p_demux
, "Invalid card index %d", i_card_index
);
315 for( int i
= 0; i
<= i_card_index
; ++i
)
318 p_sys
->p_card
->Release();
319 result
= decklink_iterator
->Next( &p_sys
->p_card
);
326 msg_Err( p_demux
, "DeckLink PCI card %d not found", i_card_index
);
330 const char *psz_model_name
;
331 result
= p_sys
->p_card
->GetModelName( &psz_model_name
);
335 msg_Err( p_demux
, "Could not get model name" );
339 msg_Dbg( p_demux
, "Opened DeckLink PCI card %d (%s)", i_card_index
, psz_model_name
);
341 if( p_sys
->p_card
->QueryInterface( IID_IDeckLinkInput
, (void**)&p_sys
->p_input
) != S_OK
)
343 msg_Err( p_demux
, "Card has no inputs" );
347 /* Set up the video and audio sources. */
348 if( p_sys
->p_card
->QueryInterface( IID_IDeckLinkConfiguration
, (void**)&p_sys
->p_config
) != S_OK
)
350 msg_Err( p_demux
, "Failed to get configuration interface" );
354 psz_video_connection
= var_InheritString( p_demux
, "decklink-video-connection" );
355 if( psz_video_connection
)
357 BMDVideoConnection conn
;
358 if ( !strcmp( psz_video_connection
, "sdi" ) )
359 conn
= bmdVideoConnectionSDI
;
360 else if ( !strcmp( psz_video_connection
, "hdmi" ) )
361 conn
= bmdVideoConnectionHDMI
;
362 else if ( !strcmp( psz_video_connection
, "opticalsdi" ) )
363 conn
= bmdVideoConnectionOpticalSDI
;
364 else if ( !strcmp( psz_video_connection
, "component" ) )
365 conn
= bmdVideoConnectionComponent
;
366 else if ( !strcmp( psz_video_connection
, "composite" ) )
367 conn
= bmdVideoConnectionComposite
;
368 else if ( !strcmp( psz_video_connection
, "svideo" ) )
369 conn
= bmdVideoConnectionSVideo
;
372 msg_Err( p_demux
, "Invalid --decklink-video-connection specified; choose one of " \
373 "sdi, hdmi, opticalsdi, component, composite, or svideo." );
377 msg_Dbg( p_demux
, "Setting video input connection to 0x%x", conn
);
378 result
= p_sys
->p_config
->SetInt( bmdDeckLinkConfigVideoInputConnection
, conn
);
381 msg_Err( p_demux
, "Failed to set video input connection" );
386 psz_audio_connection
= var_CreateGetNonEmptyString( p_demux
, "decklink-audio-connection" );
387 if( psz_audio_connection
)
389 BMDAudioConnection conn
;
390 if ( !strcmp( psz_audio_connection
, "embedded" ) )
391 conn
= bmdAudioConnectionEmbedded
;
392 else if ( !strcmp( psz_audio_connection
, "aesebu" ) )
393 conn
= bmdAudioConnectionAESEBU
;
394 else if ( !strcmp( psz_audio_connection
, "analog" ) )
395 conn
= bmdAudioConnectionAnalog
;
398 msg_Err( p_demux
, "Invalid --decklink-audio-connection specified; choose one of " \
399 "embedded, aesebu, or analog." );
403 msg_Dbg( p_demux
, "Setting audio input format to 0x%x", conn
);
404 result
= p_sys
->p_config
->SetInt( bmdDeckLinkConfigAudioInputConnection
, conn
);
407 msg_Err( p_demux
, "Failed to set audio input connection" );
412 /* Get the list of display modes. */
413 result
= p_sys
->p_input
->GetDisplayModeIterator( &p_display_iterator
);
416 msg_Err( p_demux
, "Failed to enumerate display modes" );
420 psz_display_mode
= var_CreateGetNonEmptyString( p_demux
, "decklink-mode" );
421 if( !psz_display_mode
|| strlen( psz_display_mode
) > 4 ) {
422 msg_Err( p_demux
, "Missing or invalid --decklink-mode string" );
427 * Pad the --decklink-mode string to four characters, so the user can specify e.g. "pal"
428 * without having to add the trailing space.
430 char sz_display_mode_padded
[5];
431 strcpy(sz_display_mode_padded
, " ");
432 for( int i
= 0; i
< strlen( psz_display_mode
); ++i
)
433 sz_display_mode_padded
[i
] = psz_display_mode
[i
];
435 BMDDisplayMode wanted_mode_id
;
436 memcpy( &wanted_mode_id
, &sz_display_mode_padded
, sizeof(wanted_mode_id
) );
438 b_found_mode
= false;
442 IDeckLinkDisplayMode
*p_display_mode
;
443 result
= p_display_iterator
->Next( &p_display_mode
);
444 if( result
!= S_OK
|| !p_display_mode
)
447 char sz_mode_id_text
[5] = {0};
448 BMDDisplayMode mode_id
= ntohl( p_display_mode
->GetDisplayMode() );
449 memcpy( sz_mode_id_text
, &mode_id
, sizeof(mode_id
) );
451 const char *psz_mode_name
;
452 result
= p_display_mode
->GetName( &psz_mode_name
);
455 msg_Err( p_demux
, "Failed to get display mode name" );
456 p_display_mode
->Release();
460 BMDTimeValue frame_duration
, time_scale
;
461 result
= p_display_mode
->GetFrameRate( &frame_duration
, &time_scale
);
464 msg_Err( p_demux
, "Failed to get frame rate" );
465 p_display_mode
->Release();
469 const char *psz_field_dominance
;
470 uint32_t i_dominance_flags
= 0;
471 switch( p_display_mode
->GetFieldDominance() )
473 case bmdProgressiveFrame
:
474 psz_field_dominance
= "";
476 case bmdProgressiveSegmentedFrame
:
477 psz_field_dominance
= ", segmented";
479 case bmdLowerFieldFirst
:
480 psz_field_dominance
= ", interlaced [BFF]";
481 i_dominance_flags
= BLOCK_FLAG_BOTTOM_FIELD_FIRST
;
483 case bmdUpperFieldFirst
:
484 psz_field_dominance
= ", interlaced [TFF]";
485 i_dominance_flags
= BLOCK_FLAG_TOP_FIELD_FIRST
;
487 case bmdUnknownFieldDominance
:
489 psz_field_dominance
= ", unknown field dominance";
493 msg_Dbg( p_demux
, "Found mode '%s': %s (%dx%d, %.3f fps%s)",
494 sz_mode_id_text
, psz_mode_name
,
495 p_display_mode
->GetWidth(), p_display_mode
->GetHeight(),
496 double(time_scale
) / frame_duration
, psz_field_dominance
);
498 if( wanted_mode_id
== mode_id
)
501 i_width
= p_display_mode
->GetWidth();
502 i_height
= p_display_mode
->GetHeight();
503 i_fps_num
= time_scale
;
504 i_fps_den
= frame_duration
;
505 p_sys
->i_dominance_flags
= i_dominance_flags
;
508 p_display_mode
->Release();
513 msg_Err( p_demux
, "Unknown video mode specified. " \
514 "Run VLC with -v --verbose-objects=-all,+decklink " \
515 "to get a list of supported modes." );
519 result
= p_sys
->p_input
->EnableVideoInput( htonl( wanted_mode_id
), bmdFormat8BitYUV
, 0 );
522 msg_Err( p_demux
, "Failed to enable video input" );
527 p_sys
->i_channels
= var_InheritInteger( p_demux
, "decklink-audio-channels" );
528 i_rate
= var_InheritInteger( p_demux
, "decklink-audio-rate" );
529 if( i_rate
> 0 && p_sys
->i_channels
> 0 )
531 result
= p_sys
->p_input
->EnableAudioInput( i_rate
, bmdAudioSampleType16bitInteger
, p_sys
->i_channels
);
534 msg_Err( p_demux
, "Failed to enable audio input" );
539 p_sys
->p_delegate
= new DeckLinkCaptureDelegate( p_demux
);
540 p_sys
->p_input
->SetCallback( p_sys
->p_delegate
);
542 result
= p_sys
->p_input
->StartStreams();
545 msg_Err( p_demux
, "Could not start streaming from SDI card. This could be caused "
546 "by invalid video mode or flags, access denied, or card already in use." );
550 /* Declare elementary streams */
551 es_format_t video_fmt
;
552 es_format_Init( &video_fmt
, VIDEO_ES
, VLC_CODEC_UYVY
);
553 video_fmt
.video
.i_width
= i_width
;
554 video_fmt
.video
.i_height
= i_height
;
555 video_fmt
.video
.i_sar_num
= 1;
556 video_fmt
.video
.i_sar_den
= 1;
557 video_fmt
.video
.i_frame_rate
= i_fps_num
;
558 video_fmt
.video
.i_frame_rate_base
= i_fps_den
;
559 video_fmt
.i_bitrate
= video_fmt
.video
.i_width
* video_fmt
.video
.i_height
* video_fmt
.video
.i_frame_rate
* 2 * 8;
561 if ( !var_InheritURational( p_demux
, &u_aspect_num
, &u_aspect_den
, "decklink-aspect-ratio" ) &&
562 u_aspect_num
> 0 && u_aspect_den
> 0 ) {
563 video_fmt
.video
.i_sar_num
= u_aspect_num
* video_fmt
.video
.i_height
;
564 video_fmt
.video
.i_sar_den
= u_aspect_den
* video_fmt
.video
.i_width
;
567 msg_Dbg( p_demux
, "added new video es %4.4s %dx%d",
568 (char*)&video_fmt
.i_codec
, video_fmt
.video
.i_width
, video_fmt
.video
.i_height
);
569 p_sys
->p_video_es
= es_out_Add( p_demux
->out
, &video_fmt
);
571 es_format_t audio_fmt
;
572 es_format_Init( &audio_fmt
, AUDIO_ES
, VLC_CODEC_S16N
);
573 audio_fmt
.audio
.i_channels
= p_sys
->i_channels
;
574 audio_fmt
.audio
.i_rate
= i_rate
;
575 audio_fmt
.audio
.i_bitspersample
= 16;
576 audio_fmt
.audio
.i_blockalign
= audio_fmt
.audio
.i_channels
* audio_fmt
.audio
.i_bitspersample
/ 8;
577 audio_fmt
.i_bitrate
= audio_fmt
.audio
.i_channels
* audio_fmt
.audio
.i_rate
* audio_fmt
.audio
.i_bitspersample
;
579 msg_Dbg( p_demux
, "added new audio es %4.4s %dHz %dbpp %dch",
580 (char*)&audio_fmt
.i_codec
, audio_fmt
.audio
.i_rate
, audio_fmt
.audio
.i_bitspersample
, audio_fmt
.audio
.i_channels
);
581 p_sys
->p_audio_es
= es_out_Add( p_demux
->out
, &audio_fmt
);
586 if( decklink_iterator
)
587 decklink_iterator
->Release();
589 free( psz_video_connection
);
590 free( psz_audio_connection
);
591 free( psz_display_mode
);
593 if( p_display_iterator
)
594 p_display_iterator
->Release();
596 if( ret
!= VLC_SUCCESS
)
602 static void Close( vlc_object_t
*p_this
)
604 demux_t
*p_demux
= (demux_t
*)p_this
;
605 demux_sys_t
*p_sys
= p_demux
->p_sys
;
607 if( p_sys
->p_config
)
608 p_sys
->p_config
->Release();
612 p_sys
->p_input
->StopStreams();
613 p_sys
->p_input
->Release();
617 p_sys
->p_card
->Release();
619 if( p_sys
->p_delegate
)
620 p_sys
->p_delegate
->Release();
622 vlc_mutex_destroy( &p_sys
->pts_lock
);
626 static int Control( demux_t
*p_demux
, int i_query
, va_list args
)
628 demux_sys_t
*p_sys
= p_demux
->p_sys
;
634 /* Special for access_demux */
635 case DEMUX_CAN_PAUSE
:
637 case DEMUX_CAN_CONTROL_PACE
:
638 pb
= (bool*)va_arg( args
, bool * );
642 case DEMUX_GET_PTS_DELAY
:
643 pi64
= (int64_t*)va_arg( args
, int64_t * );
645 INT64_C(1000) * var_InheritInteger( p_demux
, "live-caching" );
649 pi64
= (int64_t*)va_arg( args
, int64_t * );
650 vlc_mutex_lock( &p_sys
->pts_lock
);
651 *pi64
= p_sys
->i_last_pts
;
652 vlc_mutex_unlock( &p_sys
->pts_lock
);