2 * producer_decklink.c -- input from Blackmagic Design DeckLink
3 * Copyright (C) 2011 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>
29 #include "DeckLinkAPI_h.h"
31 #include "DeckLinkAPI.h"
34 class DeckLinkProducer
35 : public IDeckLinkInputCallback
38 mlt_producer_s m_producer;
39 IDeckLink* m_decklink;
40 IDeckLinkInput* m_decklinkInput;
42 pthread_mutex_t m_mutex;
43 pthread_cond_t m_condition;
50 BMDDisplayMode getDisplayMode( mlt_profile profile )
52 IDeckLinkDisplayModeIterator* iter;
53 IDeckLinkDisplayMode* mode;
54 BMDDisplayMode result = (BMDDisplayMode) bmdDisplayModeNotSupported;
56 if ( m_decklinkInput->GetDisplayModeIterator( &iter ) == S_OK )
58 while ( !result && iter->Next( &mode ) == S_OK )
60 int width = mode->GetWidth();
61 int height = mode->GetHeight();
62 BMDTimeValue duration;
63 BMDTimeScale timescale;
64 mode->GetFrameRate( &duration, ×cale );
65 double fps = (double) timescale / duration;
66 int p = mode->GetFieldDominance() == bmdProgressiveFrame;
67 m_topFieldFirst = mode->GetFieldDominance() == bmdUpperFieldFirst;
68 m_colorspace = ( mode->GetFlags() & bmdDisplayModeColorspaceRec709 ) ? 709 : 601;
69 mlt_log_verbose( getProducer(), "BMD mode %dx%d %.3f fps prog %d tff %d\n", width, height, fps, p, m_topFieldFirst );
71 if ( width == profile->width && p == profile->progressive
72 && ( height == profile->height || ( height == 486 && profile->height == 480 ) )
73 && fps == mlt_profile_fps( profile ) )
74 result = mode->GetDisplayMode();
83 mlt_producer getProducer()
84 { return &m_producer; }
88 if ( m_decklinkInput )
89 m_decklinkInput->Release();
91 m_decklink->Release();
95 mlt_deque_close( m_queue );
96 pthread_mutex_destroy( &m_mutex );
97 pthread_cond_destroy( &m_condition );
101 bool open( mlt_profile profile, unsigned card = 0 )
103 IDeckLinkIterator* decklinkIterator = NULL;
107 HRESULT result = CoInitialize( NULL );
108 if ( FAILED( result ) )
109 throw "COM initialization failed";
110 result = CoCreateInstance( CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL, IID_IDeckLinkIterator, (void**) &decklinkIterator );
111 if ( FAILED( result ) )
112 throw "The DeckLink drivers are not installed.";
114 decklinkIterator = CreateDeckLinkIteratorInstance();
115 if ( !decklinkIterator )
116 throw "The DeckLink drivers are not installed.";
119 // Connect to the Nth DeckLink instance
122 if ( decklinkIterator->Next( &m_decklink ) != S_OK )
123 throw "DeckLink card not found.";
124 } while ( ++i <= card );
125 decklinkIterator->Release();
127 // Get the input interface
128 if ( m_decklink->QueryInterface( IID_IDeckLinkInput, (void**) &m_decklinkInput ) != S_OK )
129 throw "No DeckLink cards support input.";
131 // Provide this class as a delegate to the input callback
132 m_decklinkInput->SetCallback( this );
134 // Initialize other members
135 pthread_mutex_init( &m_mutex, NULL );
136 pthread_cond_init( &m_condition, NULL );
137 m_queue = mlt_deque_init();
140 m_isBuffering = true;
142 catch ( const char *error )
144 if ( decklinkIterator )
145 decklinkIterator->Release();
146 mlt_log_error( getProducer(), "%s\n", error );
152 bool start( mlt_profile profile = 0 )
159 profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) );
161 // Get the display mode
162 BMDDisplayMode displayMode = getDisplayMode( profile );
163 if ( displayMode == (BMDDisplayMode) bmdDisplayModeNotSupported )
164 throw "Profile is not compatible with decklink.";
166 // Determine if supports input format detection
168 BOOL doesDetectFormat = FALSE;
170 bool doesDetectFormat = false;
172 IDeckLinkAttributes *decklinkAttributes = 0;
173 if ( m_decklink->QueryInterface( IID_IDeckLinkAttributes, (void**) &decklinkAttributes ) == S_OK )
175 if ( decklinkAttributes->GetFlag( BMDDeckLinkSupportsInputFormatDetection, &doesDetectFormat ) != S_OK )
176 doesDetectFormat = false;
177 decklinkAttributes->Release();
179 mlt_log_verbose( getProducer(), "%s format detection\n", doesDetectFormat ? "supports" : "does not support" );
181 // Enable video capture
182 BMDPixelFormat pixelFormat = bmdFormat8BitYUV;
183 BMDVideoInputFlags flags = doesDetectFormat ? bmdVideoInputEnableFormatDetection : bmdVideoInputFlagDefault;
184 if ( S_OK != m_decklinkInput->EnableVideoInput( displayMode, pixelFormat, flags ) )
185 throw "Failed to enable video capture.";
187 // Enable audio capture
188 BMDAudioSampleRate sampleRate = bmdAudioSampleRate48kHz;
189 BMDAudioSampleType sampleType = bmdAudioSampleType16bitInteger;
190 int channels = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" );
191 if ( S_OK != m_decklinkInput->EnableAudioInput( sampleRate, sampleType, channels ) )
192 throw "Failed to enable audio capture.";
196 mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "dropped", m_dropped );
197 m_started = m_decklinkInput->StartStreams() == S_OK;
199 throw "Failed to start capture.";
201 catch ( const char *error )
203 m_decklinkInput->DisableVideoInput();
204 mlt_log_error( getProducer(), "%s\n", error );
215 // Release the wait in getFrame
216 pthread_mutex_lock( &m_mutex );
217 pthread_cond_broadcast( &m_condition );
218 pthread_mutex_unlock( &m_mutex );
220 m_decklinkInput->StopStreams();
223 pthread_mutex_lock( &m_mutex );
224 while ( mlt_frame frame = (mlt_frame) mlt_deque_pop_back( m_queue ) )
225 mlt_frame_close( frame );
226 pthread_mutex_unlock( &m_mutex );
233 mlt_frame frame = NULL;
236 double fps = mlt_producer_get_fps( getProducer() );
238 // Allow the buffer to fill to the requested initial buffer level.
241 int prefill = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "prefill" );
242 int buffer = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "buffer" );
244 m_isBuffering = false;
245 prefill = prefill > buffer ? buffer : prefill;
246 pthread_mutex_lock( &m_mutex );
247 while ( mlt_deque_count( m_queue ) < prefill )
249 // Wait up to buffer/fps seconds
250 gettimeofday( &now, NULL );
251 long usec = now.tv_sec * 1000000 + now.tv_usec;
252 usec += 1000000 * buffer / fps;
253 tm.tv_sec = usec / 1000000;
254 tm.tv_nsec = (usec % 1000000) * 1000;
255 if ( pthread_cond_timedwait( &m_condition, &m_mutex, &tm ) )
258 pthread_mutex_unlock( &m_mutex );
261 // Wait if queue is empty
262 pthread_mutex_lock( &m_mutex );
263 while ( mlt_deque_count( m_queue ) < 1 )
265 // Wait up to twice frame duration
266 gettimeofday( &now, NULL );
267 long usec = now.tv_sec * 1000000 + now.tv_usec;
268 usec += 2000000 / fps;
269 tm.tv_sec = usec / 1000000;
270 tm.tv_nsec = (usec % 1000000) * 1000;
271 if ( pthread_cond_timedwait( &m_condition, &m_mutex, &tm ) )
272 // Stop waiting if error (timed out)
276 // Get the first frame from the queue
277 frame = ( mlt_frame ) mlt_deque_pop_front( m_queue );
278 pthread_mutex_unlock( &m_mutex );
280 // Set frame timestamp and properties
283 mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) );
284 mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
285 mlt_properties_set_int( properties, "progressive", profile->progressive );
286 mlt_properties_set_int( properties, "meta.media.progressive", profile->progressive );
287 mlt_properties_set_int( properties, "top_field_first", m_topFieldFirst );
288 mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile ) );
289 mlt_properties_set_int( properties, "meta.media.sample_aspect_num", profile->sample_aspect_num );
290 mlt_properties_set_int( properties, "meta.media.sample_aspect_den", profile->sample_aspect_den );
291 mlt_properties_set_int( properties, "meta.media.frame_rate_num", profile->frame_rate_num );
292 mlt_properties_set_int( properties, "meta.media.frame_rate_den", profile->frame_rate_den );
293 mlt_properties_set_int( properties, "width", profile->width );
294 mlt_properties_set_int( properties, "real_width", profile->width );
295 mlt_properties_set_int( properties, "meta.media.width", profile->width );
296 mlt_properties_set_int( properties, "height", profile->height );
297 mlt_properties_set_int( properties, "real_height", profile->height );
298 mlt_properties_set_int( properties, "meta.media.height", profile->height );
299 mlt_properties_set_int( properties, "format", mlt_image_yuv422 );
300 mlt_properties_set_int( properties, "colorspace", m_colorspace );
301 mlt_properties_set_int( properties, "meta.media.colorspace", m_colorspace );
302 mlt_properties_set_int( properties, "audio_frequency", 48000 );
303 mlt_properties_set_int( properties, "audio_channels",
304 mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" ) );
309 // *** DeckLink API implementation of IDeckLinkInputCallback *** //
311 // IUnknown needs only a dummy implementation
312 virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID iid, LPVOID *ppv )
313 { return E_NOINTERFACE; }
314 virtual ULONG STDMETHODCALLTYPE AddRef()
316 virtual ULONG STDMETHODCALLTYPE Release()
319 /************************* DeckLink API Delegate Methods *****************************/
321 virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(
322 IDeckLinkVideoInputFrame* video,
323 IDeckLinkAudioInputPacket* audio )
326 mlt_frame frame = mlt_frame_init( MLT_PRODUCER_SERVICE( getProducer() ) );
331 if ( !( video->GetFlags() & bmdFrameHasNoInputSource ) )
333 int size = video->GetRowBytes() * video->GetHeight();
334 void* image = mlt_pool_alloc( size );
337 video->GetBytes( &buffer );
338 if ( image && buffer )
340 swab( (char*) buffer, (char*) image, size );
341 mlt_frame_set_image( frame, (uint8_t*) image, size, mlt_pool_release );
345 mlt_log_verbose( getProducer(), "no video\n" );
346 mlt_pool_release( image );
351 mlt_log_verbose( getProducer(), "no signal\n" );
352 mlt_frame_close( frame );
357 IDeckLinkTimecode* timecode = 0;
358 if ( video->GetTimecode( bmdTimecodeVITC, &timecode ) == S_OK && timecode )
360 const char* timecodeString = 0;
362 if ( timecode->GetString( &timecodeString ) == S_OK )
364 mlt_properties_set( MLT_FRAME_PROPERTIES( frame ), "meta.attr.vitc.markup", timecodeString );
365 mlt_log_verbose( getProducer(), "timecode %s\n", timecodeString );
367 if ( timecodeString )
368 free( (void*) timecodeString );
374 mlt_log_verbose( getProducer(), "no video\n" );
375 mlt_frame_close( frame );
380 if ( frame && audio )
382 int channels = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" );
383 int size = audio->GetSampleFrameCount() * channels * sizeof(int16_t);
384 mlt_audio_format format = mlt_audio_s16;
385 void* pcm = mlt_pool_alloc( size );
388 audio->GetBytes( &buffer );
391 memcpy( pcm, buffer, size );
392 mlt_frame_set_audio( frame, pcm, format, size, mlt_pool_release );
393 mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "audio_samples", audio->GetSampleFrameCount() );
397 mlt_log_verbose( getProducer(), "no audio\n" );
398 mlt_pool_release( pcm );
403 mlt_log_verbose( getProducer(), "no audio\n" );
406 // Put frame in queue
409 int queueMax = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "buffer" );
410 pthread_mutex_lock( &m_mutex );
411 if ( mlt_deque_count( m_queue ) < queueMax )
413 mlt_deque_push_back( m_queue, frame );
414 pthread_cond_broadcast( &m_condition );
418 mlt_frame_close( frame );
419 mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "dropped", ++m_dropped );
420 mlt_log_warning( getProducer(), "frame dropped %d\n", m_dropped );
422 pthread_mutex_unlock( &m_mutex );
428 virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(
429 BMDVideoInputFormatChangedEvents events,
430 IDeckLinkDisplayMode* mode,
431 BMDDetectedVideoInputFormatFlags flags )
433 mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) );
434 if ( events & bmdVideoInputDisplayModeChanged )
436 BMDTimeValue duration;
437 BMDTimeScale timescale;
438 mode->GetFrameRate( &duration, ×cale );
439 profile->width = mode->GetWidth();
440 profile->height = mode->GetHeight();
441 profile->height = profile->height == 486 ? 480 : profile->height;
442 profile->frame_rate_num = timescale;
443 profile->frame_rate_den = duration;
444 if ( profile->width == 720 )
446 if ( profile->height == 576 )
448 profile->sample_aspect_num = 16;
449 profile->sample_aspect_den = 15;
453 profile->sample_aspect_num = 8;
454 profile->sample_aspect_den = 9;
456 profile->display_aspect_num = 4;
457 profile->display_aspect_den = 3;
461 profile->sample_aspect_num = 1;
462 profile->sample_aspect_den = 1;
463 profile->display_aspect_num = 16;
464 profile->display_aspect_den = 9;
466 free( profile->description );
467 profile->description = strdup( "decklink" );
468 mlt_log_verbose( getProducer(), "format changed %dx%d %.3f fps\n",
469 profile->width, profile->height, (double) profile->frame_rate_num / profile->frame_rate_den );
471 if ( events & bmdVideoInputFieldDominanceChanged )
473 profile->progressive = mode->GetFieldDominance() == bmdProgressiveFrame;
474 m_topFieldFirst = mode->GetFieldDominance() == bmdUpperFieldFirst;
475 mlt_log_verbose( getProducer(), "field dominance changed prog %d tff %d\n",
476 profile->progressive, m_topFieldFirst );
478 if ( events & bmdVideoInputColorspaceChanged )
480 profile->colorspace = m_colorspace =
481 ( mode->GetFlags() & bmdDisplayModeColorspaceRec709 ) ? 709 : 601;
482 mlt_log_verbose( getProducer(), "colorspace changed %d\n", profile->colorspace );
488 static int get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
490 return mlt_frame_get_audio( frame, (void**) buffer, format, frequency, channels, samples );
493 static int get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
495 return mlt_frame_get_image( frame, buffer, format, width, height, writable );
498 static int get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
500 DeckLinkProducer* decklink = (DeckLinkProducer*) producer->child;
502 // Get the next frame from the decklink object
503 *frame = decklink->getFrame();
505 *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) );
507 // Calculate the next timecode
508 mlt_frame_set_position( *frame, mlt_producer_position( producer ) );
509 mlt_producer_prepare_next( producer );
511 // Add audio and video getters
512 mlt_frame_push_audio( *frame, (void*) get_audio );
513 mlt_frame_push_get_image( *frame, get_image );
518 static void producer_close( mlt_producer producer )
520 producer->close = NULL;
521 mlt_producer_close( producer );
522 delete (DeckLinkProducer*) producer->child;
527 /** Initialise the producer.
530 mlt_producer producer_decklink_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
532 // Allocate the producer
533 DeckLinkProducer* decklink = new DeckLinkProducer();
534 mlt_producer producer = NULL;
536 // If allocated and initializes
537 if ( decklink && !mlt_producer_init( decklink->getProducer(), decklink ) )
539 if ( decklink->open( profile, arg? atoi( arg ) : 0 ) )
541 producer = decklink->getProducer();
542 mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );
545 producer->close = (mlt_destructor) producer_close;
546 producer->get_frame = get_frame;
549 mlt_properties_set( properties, "resource", arg? arg : "0" );
550 mlt_properties_set_int( properties, "channels", 2 );
551 mlt_properties_set_int( properties, "buffer", 25 );
552 mlt_properties_set_int( properties, "prefill", 25 );
554 // These properties effectively make it infinite.
555 mlt_properties_set_int( properties, "length", INT_MAX );
556 mlt_properties_set_int( properties, "out", INT_MAX - 1 );
557 mlt_properties_set( properties, "eof", "loop" );
560 if ( !decklink->start( profile ) )
562 producer_close( producer );