2 * consumer_decklink.c -- output through Blackmagic Design DeckLink
3 * Copyright (C) 2010 Dan Dennedy <dan@dennedy.org>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with consumer library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #define __STDC_FORMAT_MACROS /* see inttypes.h */
21 #include <framework/mlt.h>
31 static const unsigned PREROLL_MINIMUM = 3;
33 class DeckLinkConsumer
34 : public IDeckLinkVideoOutputCallback
37 mlt_consumer_s m_consumer;
38 IDeckLink* m_deckLink;
39 IDeckLinkOutput* m_deckLinkOutput;
40 IDeckLinkDisplayMode* m_displayMode;
43 BMDTimeValue m_duration;
44 BMDTimeScale m_timescale;
49 IDeckLinkMutableVideoFrame* m_decklinkFrame;
52 IDeckLinkKeyer* m_deckLinkKeyer;
53 bool m_terminate_on_pause;
57 pthread_t m_prerollThread;
59 IDeckLinkDisplayMode* getDisplayMode()
61 mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( getConsumer() ) );
62 IDeckLinkDisplayModeIterator* iter = NULL;
63 IDeckLinkDisplayMode* mode = NULL;
64 IDeckLinkDisplayMode* result = 0;
66 if ( m_deckLinkOutput->GetDisplayModeIterator( &iter ) == S_OK )
68 while ( !result && iter->Next( &mode ) == S_OK )
70 m_width = mode->GetWidth();
71 m_height = mode->GetHeight();
72 mode->GetFrameRate( &m_duration, &m_timescale );
73 m_fps = (double) m_timescale / m_duration;
74 int p = mode->GetFieldDominance() == bmdProgressiveFrame;
75 mlt_log_verbose( getConsumer(), "BMD mode %dx%d %.3f fps prog %d\n", m_width, m_height, m_fps, p );
77 if ( m_width == profile->width && p == profile->progressive
78 && (int) m_fps == (int) mlt_profile_fps( profile )
79 && ( m_height == profile->height || ( m_height == 486 && profile->height == 480 ) ) )
91 mlt_consumer getConsumer()
92 { return &m_consumer; }
97 m_deckLinkKeyer = NULL;
98 m_deckLinkOutput = NULL;
100 m_decklinkFrame = NULL;
105 SAFE_RELEASE( m_displayMode );
106 SAFE_RELEASE( m_deckLinkKeyer );
107 SAFE_RELEASE( m_deckLinkOutput );
108 SAFE_RELEASE( m_deckLink );
111 bool open( unsigned card = 0 )
115 IDeckLinkIterator* deckLinkIterator = NULL;
116 HRESULT result = CoInitialize( NULL );
117 if ( FAILED( result ) )
119 mlt_log_error( getConsumer(), "COM initialization failed\n" );
122 result = CoCreateInstance( CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL, IID_IDeckLinkIterator, (void**) &deckLinkIterator );
123 if ( FAILED( result ) )
125 mlt_log_error( getConsumer(), "The DeckLink drivers not installed.\n" );
129 IDeckLinkIterator* deckLinkIterator = CreateDeckLinkIteratorInstance();
131 if ( !deckLinkIterator )
133 mlt_log_error( getConsumer(), "The DeckLink drivers not installed.\n" );
138 // Connect to the Nth DeckLink instance
139 for ( i = 0; deckLinkIterator->Next( &m_deckLink ) == S_OK ; i++)
144 SAFE_RELEASE( m_deckLink );
146 SAFE_RELEASE( deckLinkIterator );
149 mlt_log_error( getConsumer(), "DeckLink card not found\n" );
153 // Obtain the audio/video output interface (IDeckLinkOutput)
154 if ( m_deckLink->QueryInterface( IID_IDeckLinkOutput, (void**)&m_deckLinkOutput ) != S_OK )
156 mlt_log_error( getConsumer(), "No DeckLink cards support output\n" );
157 SAFE_RELEASE( m_deckLink );
161 // Get the keyer interface
162 IDeckLinkAttributes *deckLinkAttributes = 0;
163 if ( m_deckLink->QueryInterface( IID_IDeckLinkAttributes, (void**) &deckLinkAttributes ) == S_OK )
170 if ( deckLinkAttributes->GetFlag( BMDDeckLinkSupportsInternalKeying, &flag ) == S_OK && flag )
172 if ( m_deckLink->QueryInterface( IID_IDeckLinkKeyer, (void**) &m_deckLinkKeyer ) != S_OK )
174 mlt_log_error( getConsumer(), "Failed to get keyer\n" );
175 SAFE_RELEASE( m_deckLinkOutput );
176 SAFE_RELEASE( m_deckLink );
180 SAFE_RELEASE( deckLinkAttributes );
183 // Provide this class as a delegate to the audio and video output interfaces
184 m_deckLinkOutput->SetScheduledFrameCompletionCallback( this );
190 void* preroll_thread()
192 mlt_properties properties = MLT_CONSUMER_PROPERTIES( getConsumer() );
195 for ( unsigned i = 0; i < m_preroll && mlt_properties_get_int( properties, "running" ); i++ )
196 ScheduleNextFrame( true );
198 // start scheduled playback
199 if ( mlt_properties_get_int( properties, "running" ) )
200 m_deckLinkOutput->StartScheduledPlayback( 0, m_timescale, 1.0 );
205 static void* preroll_thread_proxy( void* arg )
207 DeckLinkConsumer* self = static_cast< DeckLinkConsumer* >( arg );
208 return self->preroll_thread();
211 bool start( unsigned preroll )
213 mlt_properties properties = MLT_CONSUMER_PROPERTIES( getConsumer() );
215 // Initialize members
218 m_decklinkFrame = NULL;
219 preroll = preroll < PREROLL_MINIMUM ? PREROLL_MINIMUM : preroll;
220 m_channels = mlt_properties_get_int( properties, "channels" );
221 m_isAudio = !mlt_properties_get_int( properties, "audio_off" );
222 m_terminate_on_pause = mlt_properties_get_int( properties, "terminate_on_pause" );
225 m_displayMode = getDisplayMode();
226 if ( !m_displayMode )
228 mlt_log_error( getConsumer(), "Profile is not compatible with decklink.\n" );
233 if ( m_deckLinkKeyer && ( m_isKeyer = mlt_properties_get_int( properties, "keyer" ) ) )
235 bool external = ( m_isKeyer == 2 );
236 double level = mlt_properties_get_double( properties, "keyer_level" );
238 if ( m_deckLinkKeyer->Enable( external ) != S_OK )
239 mlt_log_error( getConsumer(), "Failed to enable %s keyer\n",
240 external ? "external" : "internal" );
241 m_deckLinkKeyer->SetLevel( level <= 1 ? ( level > 0 ? 255 * level : 255 ) : 255 );
243 else if ( m_deckLinkKeyer )
245 m_deckLinkKeyer->Disable();
248 // Set the video output mode
249 if ( S_OK != m_deckLinkOutput->EnableVideoOutput( m_displayMode->GetDisplayMode(), bmdVideoOutputFlagDefault ) )
251 mlt_log_error( getConsumer(), "Failed to enable video output\n" );
255 // Set the audio output mode
258 m_deckLinkOutput->DisableAudioOutput();
261 if ( S_OK != m_deckLinkOutput->EnableAudioOutput( bmdAudioSampleRate48kHz, bmdAudioSampleType16bitInteger,
262 m_channels, bmdAudioOutputStreamTimestamped ) )
264 mlt_log_error( getConsumer(), "Failed to enable audio output\n" );
272 // Set the running state
273 mlt_properties_set_int( properties, "running", 1 );
275 // Do preroll in thread to ensure asynchronicity of mlt_consumer_start().
276 pthread_create( &m_prerollThread, NULL, preroll_thread_proxy, this );
283 mlt_properties properties = MLT_CONSUMER_PROPERTIES( getConsumer() );
284 bool wasRunning = !!mlt_properties_get_int( properties, "running" );
286 // set running state is 0
287 mlt_properties_set_int( properties, "running", 0 );
290 pthread_join( m_prerollThread, NULL );
292 // Stop the audio and video output streams immediately
293 if ( m_deckLinkOutput )
295 m_deckLinkOutput->StopScheduledPlayback( 0, 0, 0 );
296 m_deckLinkOutput->DisableAudioOutput();
297 m_deckLinkOutput->DisableVideoOutput();
300 // release decklink frame
301 SAFE_RELEASE( m_decklinkFrame );
303 mlt_consumer_stopped( getConsumer() );
308 void renderAudio( mlt_frame frame )
310 mlt_audio_format format = mlt_audio_s16;
311 int frequency = bmdAudioSampleRate48kHz;
312 int samples = mlt_sample_calculator( m_fps, frequency, m_count );
315 if ( !mlt_frame_get_audio( frame, (void**) &pcm, &format, &frequency, &m_channels, &samples ) )
318 #define DECKLINK_UNSIGNED_FORMAT "%lu"
319 unsigned long written = 0;
321 #define DECKLINK_UNSIGNED_FORMAT "%u"
322 uint32_t written = 0;
324 BMDTimeValue streamTime = m_count * frequency * m_duration / m_timescale;
325 m_deckLinkOutput->GetBufferedAudioSampleFrameCount( &written );
326 if ( written > (m_preroll + 1) * samples )
328 mlt_log_verbose( getConsumer(), "renderAudio: will flush " DECKLINK_UNSIGNED_FORMAT " audiosamples\n", written );
329 m_deckLinkOutput->FlushBufferedAudioSamples();
332 m_deckLinkOutput->ScheduleAudioSamples( pcm, samples, streamTime, frequency, (unsigned long*) &written );
334 m_deckLinkOutput->ScheduleAudioSamples( pcm, samples, streamTime, frequency, &written );
337 if ( written != (uint32_t) samples )
338 mlt_log_verbose( getConsumer(), "renderAudio: samples=%d, written=" DECKLINK_UNSIGNED_FORMAT "\n", samples, written );
342 bool createFrame( IDeckLinkMutableVideoFrame** decklinkFrame )
344 BMDPixelFormat format = m_isKeyer? bmdFormat8BitARGB : bmdFormat8BitYUV;
345 IDeckLinkMutableVideoFrame* frame = 0;
347 int stride = m_width * ( m_isKeyer? 4 : 2 );
349 *decklinkFrame = NULL;
351 // Generate a DeckLink video frame
352 if ( S_OK != m_deckLinkOutput->CreateVideoFrame( m_width, m_height,
353 stride, format, bmdFrameFlagDefault, &frame ) )
355 mlt_log_verbose( getConsumer(), "Failed to create video frame\n" );
360 // Make the first line black for field order correction.
361 if ( S_OK == frame->GetBytes( (void**) &buffer ) && buffer )
365 memset( buffer, 0, stride );
367 else for ( int i = 0; i < m_width; i++ )
374 *decklinkFrame = frame;
379 void renderVideo( mlt_frame frame )
381 mlt_image_format format = m_isKeyer? mlt_image_rgb24a : mlt_image_yuv422;
383 int rendered = mlt_properties_get_int( MLT_FRAME_PROPERTIES(frame), "rendered");
384 int height = m_height;
386 if ( rendered && !mlt_frame_get_image( frame, &image, &format, &m_width, &height, 0 ) )
389 int stride = m_width * ( m_isKeyer? 4 : 2 );
391 SAFE_RELEASE( m_decklinkFrame );
392 if ( createFrame( &m_decklinkFrame ) )
393 m_decklinkFrame->GetBytes( (void**) &buffer );
397 int progressive = mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "progressive" );
399 // NTSC SDI is always 486 lines
400 if ( m_height == 486 && height == 480 )
402 // blank first 6 lines
405 memset( buffer, 0, stride * 6 );
406 buffer += stride * 6;
408 else for ( int i = 0; i < m_width * 6; i++ )
416 // Normal non-keyer playout - needs byte swapping
417 if ( !progressive && m_displayMode->GetFieldDominance() == bmdUpperFieldFirst )
418 // convert lower field first to top field first
419 swab( (char*) image, (char*) buffer + stride, stride * ( height - 1 ) );
421 swab( (char*) image, (char*) buffer, stride * height );
423 else if ( !mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "test_image" ) )
425 // Normal keyer output
427 uint32_t* s = (uint32_t*) image;
428 uint32_t* d = (uint32_t*) buffer;
430 if ( !progressive && m_displayMode->GetFieldDominance() == bmdUpperFieldFirst )
432 // Correct field order
438 // Need to relocate alpha channel RGBA => ARGB
444 *d++ = ( *s << 8 ) | ( *s >> 24 );
451 // Keying blank frames - nullify alpha
452 memset( buffer, 0, stride * height );
456 if ( m_decklinkFrame )
457 m_deckLinkOutput->ScheduleVideoFrame( m_decklinkFrame, m_count * m_duration, m_duration, m_timescale );
460 mlt_log_verbose( getConsumer(), "dropped video frame %u\n", ++m_dropped );
463 HRESULT render( mlt_frame frame )
465 HRESULT result = S_OK;
468 double speed = mlt_properties_get_double( MLT_FRAME_PROPERTIES(frame), "_speed" );
469 if ( m_isAudio && speed == 1.0 )
470 renderAudio( frame );
473 renderVideo( frame );
479 // *** DeckLink API implementation of IDeckLinkVideoOutputCallback IDeckLinkAudioOutputCallback *** //
481 // IUnknown needs only a dummy implementation
482 virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID iid, LPVOID *ppv )
483 { return E_NOINTERFACE; }
484 virtual ULONG STDMETHODCALLTYPE AddRef()
486 virtual ULONG STDMETHODCALLTYPE Release()
489 /************************* DeckLink API Delegate Methods *****************************/
491 virtual HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted( IDeckLinkVideoFrame* completedFrame, BMDOutputFrameCompletionResult completed )
495 mlt_properties properties = MLT_CONSUMER_PROPERTIES( getConsumer() );
497 if ( mlt_properties_get( properties, "priority" ) )
501 pthread_attr_t tattr;
502 struct sched_param param;
504 pthread_attr_init(&tattr);
505 pthread_attr_setschedpolicy(&tattr, SCHED_FIFO);
507 if ( !strcmp( "max", mlt_properties_get( properties, "priority" ) ) )
508 param.sched_priority = sched_get_priority_max(SCHED_FIFO) - 1;
509 else if ( !strcmp( "min", mlt_properties_get( properties, "priority" ) ) )
510 param.sched_priority = sched_get_priority_min(SCHED_FIFO) + 1;
512 param.sched_priority = mlt_properties_get_int( properties, "priority" );
514 pthread_attr_setschedparam(&tattr, ¶m);
516 thread = pthread_self();
518 r = pthread_setschedparam(thread, SCHED_FIFO, ¶m);
520 mlt_log_verbose( getConsumer(),
521 "ScheduledFrameCompleted: pthread_setschedparam returned %d\n", r);
523 mlt_log_verbose( getConsumer(),
524 "ScheduledFrameCompleted: param.sched_priority=%d\n", param.sched_priority);
535 m_deckLinkOutput->GetBufferedAudioSampleFrameCount( &cnt );
538 mlt_log_debug( getConsumer(),
539 "ScheduledFrameCompleted: GetBufferedAudioSampleFrameCount %u -> " DECKLINK_UNSIGNED_FORMAT
540 ", m_count=%"PRIu64"\n", m_acnt, cnt, m_count );
544 // When a video frame has been released by the API, schedule another video frame to be output
546 // ignore handler if frame was flushed
547 if ( bmdOutputFrameFlushed == completed )
550 // schedule next frame
551 ScheduleNextFrame( false );
553 // step forward frames counter if underrun
554 if ( bmdOutputFrameDisplayedLate == completed )
556 mlt_log_verbose( getConsumer(), "ScheduledFrameCompleted: bmdOutputFrameDisplayedLate == completed\n" );
559 if ( bmdOutputFrameDropped == completed )
561 mlt_log_verbose( getConsumer(), "ScheduledFrameCompleted: bmdOutputFrameDropped == completed\n" );
568 virtual HRESULT STDMETHODCALLTYPE ScheduledPlaybackHasStopped()
570 return mlt_consumer_is_stopped( getConsumer() ) ? S_FALSE : S_OK;
574 void ScheduleNextFrame( bool preroll )
577 mlt_consumer consumer = getConsumer();
579 // Get the properties
580 mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer );
583 mlt_frame frame = NULL;
585 if( mlt_properties_get_int( properties, "running" ) || preroll )
587 frame = mlt_consumer_rt_frame( consumer );
592 mlt_events_fire( properties, "consumer-frame-show", frame, NULL );
594 // terminate on pause
595 if ( m_terminate_on_pause &&
596 mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame ), "_speed" ) == 0.0 )
599 mlt_frame_close( frame );
605 /** Start the consumer.
608 static int start( mlt_consumer consumer )
610 // Get the properties
611 mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer );
612 DeckLinkConsumer* decklink = (DeckLinkConsumer*) consumer->child;
613 return decklink->start( mlt_properties_get_int( properties, "preroll" ) ) ? 0 : 1;
616 /** Stop the consumer.
619 static int stop( mlt_consumer consumer )
621 // Get the properties
622 DeckLinkConsumer* decklink = (DeckLinkConsumer*) consumer->child;
623 return decklink->stop();
626 /** Determine if the consumer is stopped.
629 static int is_stopped( mlt_consumer consumer )
631 // Get the properties
632 mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer );
633 return !mlt_properties_get_int( properties, "running" );
636 /** Close the consumer.
639 static void close( mlt_consumer consumer )
642 mlt_consumer_stop( consumer );
645 consumer->close = NULL;
646 mlt_consumer_close( consumer );
649 delete (DeckLinkConsumer*) consumer->child;
654 // Listen for the list_devices property to be set
655 static void on_property_changed( void*, mlt_properties properties, const char *name )
657 IDeckLinkIterator* decklinkIterator = NULL;
658 IDeckLink* decklink = NULL;
659 IDeckLinkInput* decklinkOutput = NULL;
662 if ( name && !strcmp( name, "list_devices" ) )
663 mlt_event_block( (mlt_event) mlt_properties_get_data( properties, "list-devices-event", NULL ) );
668 if ( FAILED( CoInitialize( NULL ) ) )
670 if ( FAILED( CoCreateInstance( CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL, IID_IDeckLinkIterator, (void**) &decklinkIterator ) ) )
673 if ( !( decklinkIterator = CreateDeckLinkIteratorInstance() ) )
676 for ( ; decklinkIterator->Next( &decklink ) == S_OK; i++ )
678 if ( decklink->QueryInterface( IID_IDeckLinkOutput, (void**) &decklinkOutput ) == S_OK )
680 DLString name = NULL;
681 if ( decklink->GetModelName( &name ) == S_OK )
683 char *name_cstr = getCString( name );
684 const char *format = "device.%d";
685 char *key = (char*) calloc( 1, strlen( format ) + 1 );
687 sprintf( key, format, i );
688 mlt_properties_set( properties, key, name_cstr );
690 freeDLString( name );
691 freeCString( name_cstr );
693 SAFE_RELEASE( decklinkOutput );
695 SAFE_RELEASE( decklink );
697 SAFE_RELEASE( decklinkIterator );
698 mlt_properties_set_int( properties, "devices", i );
701 /** Initialise the consumer.
704 mlt_consumer consumer_decklink_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
706 // Allocate the consumer
707 DeckLinkConsumer* decklink = new DeckLinkConsumer();
708 mlt_consumer consumer = NULL;
711 if ( decklink && !mlt_consumer_init( decklink->getConsumer(), decklink, profile ) )
713 // If initialises without error
714 if ( decklink->open( arg? atoi(arg) : 0 ) )
716 consumer = decklink->getConsumer();
717 mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer );
720 consumer->close = close;
721 consumer->start = start;
722 consumer->stop = stop;
723 consumer->is_stopped = is_stopped;
724 mlt_properties_set( properties, "deinterlace_method", "onefield" );
726 mlt_event event = mlt_events_listen( properties, properties, "property-changed", (mlt_listener) on_property_changed );
727 mlt_properties_set_data( properties, "list-devices-event", event, 0, NULL, NULL );
735 extern mlt_producer producer_decklink_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
737 static mlt_properties metadata( mlt_service_type type, const char *id, void *data )
739 char file[ PATH_MAX ];
740 const char *service_type = NULL;
744 service_type = "consumer";
747 service_type = "producer";
752 snprintf( file, PATH_MAX, "%s/decklink/%s_%s.yml", mlt_environment( "MLT_DATA" ), service_type, id );
753 return mlt_properties_parse_yaml( file );
758 MLT_REGISTER( consumer_type, "decklink", consumer_decklink_init );
759 MLT_REGISTER( producer_type, "decklink", producer_decklink_init );
760 MLT_REGISTER_METADATA( consumer_type, "decklink", metadata, NULL );
761 MLT_REGISTER_METADATA( producer_type, "decklink", metadata, NULL );