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 #include <framework/mlt.h>
26 #include "DeckLinkAPI.h"
28 const unsigned PREROLL_MINIMUM = 3;
35 pthread_mutex_t mutex;
38 static sample_fifo sample_fifo_init()
40 sample_fifo fifo = (sample_fifo) calloc( 1, sizeof( *fifo ) );
41 pthread_mutex_init( &fifo->mutex, NULL );
45 static void sample_fifo_append( sample_fifo fifo, int16_t *samples, int count )
47 pthread_mutex_lock( &fifo->mutex );
48 if ( ( fifo->size - fifo->used ) < count )
50 fifo->size += count * 5;
51 fifo->buffer = (int16_t*) realloc( fifo->buffer, fifo->size * sizeof( int16_t ) );
53 memcpy( fifo->buffer + fifo->used, samples, count * sizeof( int16_t ) );
55 pthread_mutex_unlock( &fifo->mutex );
58 static void sample_fifo_remove( sample_fifo fifo, int count )
60 pthread_mutex_lock( &fifo->mutex );
61 if ( count > fifo->used )
64 memmove( fifo->buffer, fifo->buffer + count, fifo->used * sizeof( int16_t ) );
65 pthread_mutex_unlock( &fifo->mutex );
68 static void sample_fifo_close( sample_fifo fifo )
71 pthread_mutex_destroy( &fifo->mutex );
76 class DeckLinkConsumer
77 : public IDeckLinkVideoOutputCallback
78 , public IDeckLinkAudioOutputCallback
81 mlt_consumer_s m_consumer;
82 IDeckLink* m_deckLink;
83 IDeckLinkOutput* m_deckLinkOutput;
84 IDeckLinkMutableVideoFrame* m_videoFrame;
85 IDeckLinkDisplayMode* m_displayMode;
86 pthread_mutex_t m_mutex;
87 pthread_cond_t m_condition;
90 BMDTimeValue m_duration;
91 BMDTimeScale m_timescale;
97 unsigned m_prerollCounter;
99 uint32_t m_maxAudioBuffer;
100 mlt_deque m_videoFrameQ;
104 IDeckLinkDisplayMode* getDisplayMode()
106 mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( &m_consumer ) );
107 IDeckLinkDisplayModeIterator* iter;
108 IDeckLinkDisplayMode* mode;
109 IDeckLinkDisplayMode* result = 0;
111 if ( m_deckLinkOutput->GetDisplayModeIterator( &iter ) == S_OK )
113 while ( !result && iter->Next( &mode ) == S_OK )
115 m_width = mode->GetWidth();
116 m_height = mode->GetHeight();
117 mode->GetFrameRate( &m_duration, &m_timescale );
118 m_fps = (double) m_timescale / m_duration;
119 int p = mode->GetFieldDominance() == bmdProgressiveFrame;
120 mlt_log_verbose( &m_consumer, "BMD mode %dx%d %.3f fps prog %d\n", m_width, m_height, m_fps, p );
122 if ( m_width == profile->width && m_height == profile->height && p == profile->progressive
123 && m_fps == mlt_profile_fps( profile ) )
132 mlt_consumer getConsumer()
133 { return &m_consumer; }
134 uint64_t isBuffering() const
135 { return m_prerollCounter < m_preroll; }
139 if ( m_deckLinkOutput )
140 m_deckLinkOutput->Release();
142 m_deckLink->Release();
144 mlt_deque_close( m_videoFrameQ );
147 bool open( unsigned card = 0 )
149 IDeckLinkIterator* deckLinkIterator = CreateDeckLinkIteratorInstance();
152 if ( !deckLinkIterator )
154 mlt_log_verbose( NULL, "The DeckLink drivers not installed.\n" );
158 // Connect to the Nth DeckLink instance
160 if ( deckLinkIterator->Next( &m_deckLink ) != S_OK )
162 mlt_log_verbose( NULL, "DeckLink card not found\n" );
163 deckLinkIterator->Release();
166 } while ( ++i <= card );
168 // Obtain the audio/video output interface (IDeckLinkOutput)
169 if ( m_deckLink->QueryInterface( IID_IDeckLinkOutput, (void**)&m_deckLinkOutput ) != S_OK )
171 mlt_log_verbose( NULL, "No DeckLink cards support output\n" );
172 m_deckLink->Release();
174 deckLinkIterator->Release();
178 // Provide this class as a delegate to the audio and video output interfaces
179 m_deckLinkOutput->SetScheduledFrameCompletionCallback( this );
180 m_deckLinkOutput->SetAudioCallback( this );
182 pthread_mutex_init( &m_mutex, NULL );
183 pthread_cond_init( &m_condition, NULL );
184 m_maxAudioBuffer = bmdAudioSampleRate48kHz;
185 m_videoFrameQ = mlt_deque_init();
190 bool start( unsigned preroll )
192 m_displayMode = getDisplayMode();
193 if ( !m_displayMode )
195 mlt_log_error( &m_consumer, "Profile is not compatible with decklink.\n" );
199 // Set the video output mode
200 if ( S_OK != m_deckLinkOutput->EnableVideoOutput( m_displayMode->GetDisplayMode(), bmdVideoOutputFlagDefault) )
202 mlt_log_error( &m_consumer, "Failed to enable video output\n" );
206 // Set the audio output mode
208 if ( S_OK != m_deckLinkOutput->EnableAudioOutput( bmdAudioSampleRate48kHz, bmdAudioSampleType16bitInteger,
209 m_channels, bmdAudioOutputStreamContinuous ) )
211 mlt_log_error( &m_consumer, "Failed to enable audio output\n" );
215 m_fifo = sample_fifo_init();
218 m_isPrerolling = true;
219 m_prerollCounter = 0;
220 m_preroll = preroll < PREROLL_MINIMUM ? PREROLL_MINIMUM : preroll;
222 m_deckLinkOutput->BeginAudioPreroll();
231 pthread_mutex_lock( &m_mutex );
232 pthread_cond_broadcast( &m_condition );
233 pthread_mutex_unlock( &m_mutex );
241 gettimeofday( &tv, NULL );
242 ts.tv_sec = tv.tv_sec + 1;
243 ts.tv_nsec = tv.tv_usec * 1000;
244 pthread_mutex_lock( &m_mutex );
245 pthread_cond_timedwait( &m_condition, &m_mutex, &ts );
246 pthread_mutex_unlock( &m_mutex );
251 // Stop the audio and video output streams immediately
252 if ( m_deckLinkOutput )
254 m_deckLinkOutput->StopScheduledPlayback( 0, 0, 0 );
255 m_deckLinkOutput->DisableAudioOutput();
256 m_deckLinkOutput->DisableVideoOutput();
258 while ( mlt_deque_count( m_videoFrameQ ) )
260 m_videoFrame = (IDeckLinkMutableVideoFrame*) mlt_deque_pop_back( m_videoFrameQ );
261 m_videoFrame->Release();
264 if ( m_fifo ) sample_fifo_close( m_fifo );
265 mlt_frame_close( m_frame );
271 // Generate a DeckLink video frame
272 if ( S_OK != m_deckLinkOutput->CreateVideoFrame( m_width, m_height,
273 m_width * 2, bmdFormat8BitYUV, bmdFrameFlagDefault, &m_videoFrame ) )
275 mlt_log_verbose( &m_consumer, "Failed to create video frame\n" );
280 // Make the first line black for field order correction.
282 if ( S_OK == m_videoFrame->GetBytes( (void**) &buffer ) && buffer )
284 for ( int i = 0; i < m_width; i++ )
290 mlt_log_debug( &m_consumer, "created video frame\n" );
291 mlt_deque_push_back( m_videoFrameQ, m_videoFrame );
294 HRESULT render( mlt_frame frame )
296 HRESULT result = S_OK;
298 double speed = mlt_properties_get_double( MLT_FRAME_PROPERTIES(frame), "_speed" );
301 mlt_audio_format format = mlt_audio_s16;
302 int frequency = bmdAudioSampleRate48kHz;
303 int samples = mlt_sample_calculator( m_fps, frequency, m_count );
306 if ( !mlt_frame_get_audio( frame, (void**) &pcm, &format, &frequency, &m_channels, &samples ) )
310 if ( !m_isPrerolling )
312 uint32_t audioCount = 0;
313 uint32_t videoCount = 0;
316 m_deckLinkOutput->GetBufferedAudioSampleFrameCount( &audioCount );
317 m_deckLinkOutput->GetBufferedVideoFrameCount( &videoCount );
319 // Underflow typically occurs during non-normal speed playback.
320 if ( audioCount < 1 || videoCount < 1 )
322 // Upon switching to normal playback, buffer some frames faster than realtime.
323 mlt_log_info( &m_consumer, "buffer underrun: audio buf %u video buf %u frames\n", audioCount, videoCount );
324 m_prerollCounter = 0;
330 // Only append audio to reach the ideal level and not overbuffer.
331 int ideal = ( m_preroll - 1 ) * bmdAudioSampleRate48kHz / m_fps;
332 int actual = m_fifo->used / m_channels + audioCount;
333 int diff = ideal / 2 - actual;
334 count = diff < 0 ? 0 : diff < count ? diff : count;
338 sample_fifo_append( m_fifo, pcm, count * m_channels );
342 // Create video frames while pre-rolling
343 if ( m_isPrerolling )
348 mlt_log_error( &m_consumer, "failed to create video frame\n" );
353 if ( mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "rendered") )
355 // Close the previous frame and use the new one
356 mlt_frame_close( m_frame );
363 // Reuse the last frame
364 mlt_log_verbose( &m_consumer, "dropped video frame %u\n", ++m_dropped );
368 mlt_image_format format = mlt_image_yuv422;
371 if ( !mlt_frame_get_image( m_frame, &image, &format, &m_width, &m_height, 0 ) )
373 m_videoFrame = (IDeckLinkMutableVideoFrame*) mlt_deque_pop_back( m_videoFrameQ );
374 m_videoFrame->GetBytes( (void**) &buffer );
375 if ( m_displayMode->GetFieldDominance() == bmdUpperFieldFirst )
376 // convert lower field first to top field first
377 swab( image, buffer + m_width * 2, m_width * ( m_height - 1 ) * 2 );
379 swab( image, buffer, m_width * m_height * 2 );
380 m_deckLinkOutput->ScheduleVideoFrame( m_videoFrame, m_count * m_duration, m_duration, m_timescale );
381 mlt_deque_push_front( m_videoFrameQ, m_videoFrame );
385 // Check for end of pre-roll
386 if ( ++m_prerollCounter > m_preroll && m_isPrerolling )
388 // Start audio and video output
389 m_deckLinkOutput->EndAudioPreroll();
390 m_deckLinkOutput->StartScheduledPlayback( 0, m_timescale, 1.0 );
391 m_isPrerolling = false;
397 // *** DeckLink API implementation of IDeckLinkVideoOutputCallback IDeckLinkAudioOutputCallback *** //
399 // IUnknown needs only a dummy implementation
400 virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID iid, LPVOID *ppv )
401 { return E_NOINTERFACE; }
402 virtual ULONG STDMETHODCALLTYPE AddRef()
404 virtual ULONG STDMETHODCALLTYPE Release()
407 /************************* DeckLink API Delegate Methods *****************************/
409 virtual HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted( IDeckLinkVideoFrame* completedFrame, BMDOutputFrameCompletionResult completed )
411 // When a video frame has been released by the API, schedule another video frame to be output
417 virtual HRESULT STDMETHODCALLTYPE ScheduledPlaybackHasStopped()
419 return mlt_consumer_is_stopped( &m_consumer ) ? S_FALSE : S_OK;
422 virtual HRESULT STDMETHODCALLTYPE RenderAudioSamples( bool preroll )
424 // Provide more audio samples to the DeckLink API
425 HRESULT result = S_OK;
427 uint32_t count = m_fifo->used / m_channels;
428 uint32_t buffered = count;
431 // Stay under preferred buffer level
432 && ( S_OK == m_deckLinkOutput->GetBufferedAudioSampleFrameCount( &buffered ) )
433 && buffered < m_maxAudioBuffer )
435 uint32_t written = 0;
437 buffered = m_maxAudioBuffer - buffered;
438 count = buffered > count ? count : buffered;
439 result = m_deckLinkOutput->ScheduleAudioSamples( m_fifo->buffer, count, 0, 0, &written );
441 sample_fifo_remove( m_fifo, written * m_channels );
451 static void *run( void *arg )
453 // Map the argument to the object
454 DeckLinkConsumer* decklink = (DeckLinkConsumer*) arg;
455 mlt_consumer consumer = decklink->getConsumer();
457 // Get the properties
458 mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer );
460 // Convenience functionality
461 int terminate_on_pause = mlt_properties_get_int( properties, "terminate_on_pause" );
465 mlt_frame frame = NULL;
467 // Loop while running
468 while ( !terminated && mlt_properties_get_int( properties, "running" ) )
471 frame = mlt_consumer_rt_frame( consumer );
473 // Check for termination
474 if ( terminate_on_pause && frame )
475 terminated = mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame ), "_speed" ) == 0.0;
477 // Check that we have a frame to work with
480 decklink->render( frame );
481 if ( !decklink->isBuffering() )
485 mlt_events_fire( properties, "consumer-frame-show", frame, NULL );
489 // Indicate that the consumer is stopped
491 mlt_properties_set_int( properties, "running", 0 );
492 mlt_consumer_stopped( consumer );
497 /** Start the consumer.
500 static int start( mlt_consumer consumer )
502 // Get the properties
503 mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer );
504 DeckLinkConsumer* decklink = (DeckLinkConsumer*) consumer->child;
505 int result = decklink->start( mlt_properties_get_int( properties, "preroll" ) ) ? 0 : 1;
507 // Check that we're not already running
508 if ( !result && !mlt_properties_get_int( properties, "running" ) )
511 pthread_t *pthread = (pthread_t*) calloc( 1, sizeof( pthread_t ) );
513 // Assign the thread to properties
514 mlt_properties_set_data( properties, "pthread", pthread, sizeof( pthread_t ), free, NULL );
516 // Set the running state
517 mlt_properties_set_int( properties, "running", 1 );
518 mlt_properties_set_int( properties, "joined", 0 );
521 pthread_create( pthread, NULL, run, consumer->child );
526 /** Stop the consumer.
529 static int stop( mlt_consumer consumer )
531 // Get the properties
532 mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer );
534 // Check that we're running
535 if ( !mlt_properties_get_int( properties, "joined" ) )
538 pthread_t *pthread = (pthread_t*) mlt_properties_get_data( properties, "pthread", NULL );
543 mlt_properties_set_int( properties, "running", 0 );
544 mlt_properties_set_int( properties, "joined", 1 );
546 // Wait for termination
547 pthread_join( *pthread, NULL );
554 /** Determine if the consumer is stopped.
557 static int is_stopped( mlt_consumer consumer )
559 // Get the properties
560 mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer );
561 return !mlt_properties_get_int( properties, "running" );
564 /** Close the consumer.
567 static void close( mlt_consumer consumer )
570 mlt_consumer_stop( consumer );
573 consumer->close = NULL;
574 mlt_consumer_close( consumer );
577 delete (DeckLinkConsumer*) consumer->child;
582 /** Initialise the consumer.
585 mlt_consumer consumer_decklink_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
587 // Allocate the consumer
588 DeckLinkConsumer* decklink = new DeckLinkConsumer();
589 mlt_consumer consumer = NULL;
592 if ( decklink && !mlt_consumer_init( decklink->getConsumer(), decklink, profile ) )
594 // If initialises without error
595 if ( decklink->open( arg? atoi(arg) : 0 ) )
597 consumer = decklink->getConsumer();
600 consumer->close = close;
601 consumer->start = start;
602 consumer->stop = stop;
603 consumer->is_stopped = is_stopped;
614 MLT_REGISTER( consumer_type, "decklink", consumer_decklink_init );