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;
51 BMDDisplayMode getDisplayMode( mlt_profile profile, int vancLines )
53 IDeckLinkDisplayModeIterator* iter;
54 IDeckLinkDisplayMode* mode;
55 BMDDisplayMode result = (BMDDisplayMode) bmdDisplayModeNotSupported;
57 if ( m_decklinkInput->GetDisplayModeIterator( &iter ) == S_OK )
59 while ( !result && iter->Next( &mode ) == S_OK )
61 int width = mode->GetWidth();
62 int height = mode->GetHeight();
63 BMDTimeValue duration;
64 BMDTimeScale timescale;
65 mode->GetFrameRate( &duration, ×cale );
66 double fps = (double) timescale / duration;
67 int p = mode->GetFieldDominance() == bmdProgressiveFrame;
68 m_topFieldFirst = mode->GetFieldDominance() == bmdUpperFieldFirst;
69 m_colorspace = ( mode->GetFlags() & bmdDisplayModeColorspaceRec709 ) ? 709 : 601;
70 mlt_log_verbose( getProducer(), "BMD mode %dx%d %.3f fps prog %d tff %d\n", width, height, fps, p, m_topFieldFirst );
72 if ( width == profile->width && p == profile->progressive
73 && ( height + vancLines == profile->height || ( height == 486 && profile->height == 480 + vancLines ) )
74 && fps == mlt_profile_fps( profile ) )
75 result = mode->GetDisplayMode();
84 mlt_producer getProducer()
85 { return &m_producer; }
89 if ( m_decklinkInput )
90 m_decklinkInput->Release();
92 m_decklink->Release();
96 mlt_deque_close( m_queue );
97 pthread_mutex_destroy( &m_mutex );
98 pthread_cond_destroy( &m_condition );
102 bool open( mlt_profile profile, unsigned card = 0 )
104 IDeckLinkIterator* decklinkIterator = NULL;
108 HRESULT result = CoInitialize( NULL );
109 if ( FAILED( result ) )
110 throw "COM initialization failed";
111 result = CoCreateInstance( CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL, IID_IDeckLinkIterator, (void**) &decklinkIterator );
112 if ( FAILED( result ) )
113 throw "The DeckLink drivers are not installed.";
115 decklinkIterator = CreateDeckLinkIteratorInstance();
116 if ( !decklinkIterator )
117 throw "The DeckLink drivers are not installed.";
120 // Connect to the Nth DeckLink instance
123 if ( decklinkIterator->Next( &m_decklink ) != S_OK )
124 throw "DeckLink card not found.";
125 } while ( ++i <= card );
126 decklinkIterator->Release();
128 // Get the input interface
129 if ( m_decklink->QueryInterface( IID_IDeckLinkInput, (void**) &m_decklinkInput ) != S_OK )
130 throw "No DeckLink cards support input.";
132 // Provide this class as a delegate to the input callback
133 m_decklinkInput->SetCallback( this );
135 // Initialize other members
136 pthread_mutex_init( &m_mutex, NULL );
137 pthread_cond_init( &m_condition, NULL );
138 m_queue = mlt_deque_init();
141 m_isBuffering = true;
143 catch ( const char *error )
145 if ( decklinkIterator )
146 decklinkIterator->Release();
147 mlt_log_error( getProducer(), "%s\n", error );
153 bool start( mlt_profile profile = 0 )
159 // Initialize some members
160 m_vancLines = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "vanc" );
161 if ( m_vancLines == -1 )
162 m_vancLines = profile->height <= 512 ? 26 : 32;
165 profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) );
167 // Get the display mode
168 BMDDisplayMode displayMode = getDisplayMode( profile, m_vancLines );
169 if ( displayMode == (BMDDisplayMode) bmdDisplayModeNotSupported )
170 throw "Profile is not compatible with decklink.";
172 // Determine if supports input format detection
174 BOOL doesDetectFormat = FALSE;
176 bool doesDetectFormat = false;
178 IDeckLinkAttributes *decklinkAttributes = 0;
179 if ( m_decklink->QueryInterface( IID_IDeckLinkAttributes, (void**) &decklinkAttributes ) == S_OK )
181 if ( decklinkAttributes->GetFlag( BMDDeckLinkSupportsInputFormatDetection, &doesDetectFormat ) != S_OK )
182 doesDetectFormat = false;
183 decklinkAttributes->Release();
185 mlt_log_verbose( getProducer(), "%s format detection\n", doesDetectFormat ? "supports" : "does not support" );
187 // Enable video capture
188 BMDPixelFormat pixelFormat = bmdFormat8BitYUV;
189 BMDVideoInputFlags flags = doesDetectFormat ? bmdVideoInputEnableFormatDetection : bmdVideoInputFlagDefault;
190 if ( S_OK != m_decklinkInput->EnableVideoInput( displayMode, pixelFormat, flags ) )
191 throw "Failed to enable video capture.";
193 // Enable audio capture
194 BMDAudioSampleRate sampleRate = bmdAudioSampleRate48kHz;
195 BMDAudioSampleType sampleType = bmdAudioSampleType16bitInteger;
196 int channels = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" );
197 if ( S_OK != m_decklinkInput->EnableAudioInput( sampleRate, sampleType, channels ) )
198 throw "Failed to enable audio capture.";
202 mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "dropped", m_dropped );
203 m_started = m_decklinkInput->StartStreams() == S_OK;
205 throw "Failed to start capture.";
207 catch ( const char *error )
209 m_decklinkInput->DisableVideoInput();
210 mlt_log_error( getProducer(), "%s\n", error );
221 // Release the wait in getFrame
222 pthread_mutex_lock( &m_mutex );
223 pthread_cond_broadcast( &m_condition );
224 pthread_mutex_unlock( &m_mutex );
226 m_decklinkInput->StopStreams();
229 pthread_mutex_lock( &m_mutex );
230 while ( mlt_frame frame = (mlt_frame) mlt_deque_pop_back( m_queue ) )
231 mlt_frame_close( frame );
232 pthread_mutex_unlock( &m_mutex );
239 mlt_frame frame = NULL;
242 double fps = mlt_producer_get_fps( getProducer() );
244 // Allow the buffer to fill to the requested initial buffer level.
247 int prefill = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "prefill" );
248 int buffer = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "buffer" );
250 m_isBuffering = false;
251 prefill = prefill > buffer ? buffer : prefill;
252 pthread_mutex_lock( &m_mutex );
253 while ( mlt_deque_count( m_queue ) < prefill )
255 // Wait up to buffer/fps seconds
256 gettimeofday( &now, NULL );
257 long usec = now.tv_sec * 1000000 + now.tv_usec;
258 usec += 1000000 * buffer / fps;
259 tm.tv_sec = usec / 1000000;
260 tm.tv_nsec = (usec % 1000000) * 1000;
261 if ( pthread_cond_timedwait( &m_condition, &m_mutex, &tm ) )
264 pthread_mutex_unlock( &m_mutex );
267 // Wait if queue is empty
268 pthread_mutex_lock( &m_mutex );
269 while ( mlt_deque_count( m_queue ) < 1 )
271 // Wait up to twice frame duration
272 gettimeofday( &now, NULL );
273 long usec = now.tv_sec * 1000000 + now.tv_usec;
274 usec += 2000000 / fps;
275 tm.tv_sec = usec / 1000000;
276 tm.tv_nsec = (usec % 1000000) * 1000;
277 if ( pthread_cond_timedwait( &m_condition, &m_mutex, &tm ) )
278 // Stop waiting if error (timed out)
282 // Get the first frame from the queue
283 frame = ( mlt_frame ) mlt_deque_pop_front( m_queue );
284 pthread_mutex_unlock( &m_mutex );
286 // Set frame timestamp and properties
289 mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) );
290 mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
291 mlt_properties_set_int( properties, "progressive", profile->progressive );
292 mlt_properties_set_int( properties, "meta.media.progressive", profile->progressive );
293 mlt_properties_set_int( properties, "top_field_first", m_topFieldFirst );
294 mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile ) );
295 mlt_properties_set_int( properties, "meta.media.sample_aspect_num", profile->sample_aspect_num );
296 mlt_properties_set_int( properties, "meta.media.sample_aspect_den", profile->sample_aspect_den );
297 mlt_properties_set_int( properties, "meta.media.frame_rate_num", profile->frame_rate_num );
298 mlt_properties_set_int( properties, "meta.media.frame_rate_den", profile->frame_rate_den );
299 mlt_properties_set_int( properties, "width", profile->width );
300 mlt_properties_set_int( properties, "real_width", profile->width );
301 mlt_properties_set_int( properties, "meta.media.width", profile->width );
302 mlt_properties_set_int( properties, "height", profile->height );
303 mlt_properties_set_int( properties, "real_height", profile->height );
304 mlt_properties_set_int( properties, "meta.media.height", profile->height );
305 mlt_properties_set_int( properties, "format", mlt_image_yuv422 );
306 mlt_properties_set_int( properties, "colorspace", m_colorspace );
307 mlt_properties_set_int( properties, "meta.media.colorspace", m_colorspace );
308 mlt_properties_set_int( properties, "audio_frequency", 48000 );
309 mlt_properties_set_int( properties, "audio_channels",
310 mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" ) );
315 // *** DeckLink API implementation of IDeckLinkInputCallback *** //
317 // IUnknown needs only a dummy implementation
318 virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID iid, LPVOID *ppv )
319 { return E_NOINTERFACE; }
320 virtual ULONG STDMETHODCALLTYPE AddRef()
322 virtual ULONG STDMETHODCALLTYPE Release()
325 /************************* DeckLink API Delegate Methods *****************************/
327 virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(
328 IDeckLinkVideoInputFrame* video,
329 IDeckLinkAudioInputPacket* audio )
332 mlt_frame frame = mlt_frame_init( MLT_PRODUCER_SERVICE( getProducer() ) );
337 if ( !( video->GetFlags() & bmdFrameHasNoInputSource ) )
339 int size = video->GetRowBytes() * ( video->GetHeight() + m_vancLines );
340 void* image = mlt_pool_alloc( size );
342 unsigned char* p = (unsigned char*) image;
345 // Initialize VANC lines to nominal black
353 if ( m_vancLines > 0 )
355 IDeckLinkVideoFrameAncillary* vanc = 0;
356 if ( video->GetAncillaryData( &vanc ) == S_OK && vanc )
358 for ( int i = 1; i < m_vancLines + 1; i++ )
360 if ( vanc->GetBufferForVerticalBlankingLine( i, &buffer ) == S_OK )
361 swab( (char*) buffer, (char*) image + ( i - 1 ) * video->GetRowBytes(), video->GetRowBytes() );
363 mlt_log_debug( getProducer(), "failed capture vanc line %d\n", i );
370 video->GetBytes( &buffer );
371 if ( image && buffer )
373 size = video->GetRowBytes() * video->GetHeight();
374 swab( (char*) buffer, (char*) image + m_vancLines * video->GetRowBytes(), size );
375 mlt_frame_set_image( frame, (uint8_t*) image, size, mlt_pool_release );
379 mlt_log_verbose( getProducer(), "no video\n" );
380 mlt_pool_release( image );
385 mlt_log_verbose( getProducer(), "no signal\n" );
386 mlt_frame_close( frame );
391 IDeckLinkTimecode* timecode = 0;
392 if ( video->GetTimecode( bmdTimecodeVITC, &timecode ) == S_OK && timecode )
394 const char* timecodeString = 0;
396 if ( timecode->GetString( &timecodeString ) == S_OK )
398 mlt_properties_set( MLT_FRAME_PROPERTIES( frame ), "meta.attr.vitc.markup", timecodeString );
399 mlt_log_debug( getProducer(), "timecode %s\n", timecodeString );
401 if ( timecodeString )
402 free( (void*) timecodeString );
408 mlt_log_verbose( getProducer(), "no video\n" );
409 mlt_frame_close( frame );
414 if ( frame && audio )
416 int channels = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" );
417 int size = audio->GetSampleFrameCount() * channels * sizeof(int16_t);
418 mlt_audio_format format = mlt_audio_s16;
419 void* pcm = mlt_pool_alloc( size );
422 audio->GetBytes( &buffer );
425 memcpy( pcm, buffer, size );
426 mlt_frame_set_audio( frame, pcm, format, size, mlt_pool_release );
427 mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "audio_samples", audio->GetSampleFrameCount() );
431 mlt_log_verbose( getProducer(), "no audio\n" );
432 mlt_pool_release( pcm );
437 mlt_log_verbose( getProducer(), "no audio\n" );
440 // Put frame in queue
443 int queueMax = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "buffer" );
444 pthread_mutex_lock( &m_mutex );
445 if ( mlt_deque_count( m_queue ) < queueMax )
447 mlt_deque_push_back( m_queue, frame );
448 pthread_cond_broadcast( &m_condition );
452 mlt_frame_close( frame );
453 mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "dropped", ++m_dropped );
454 mlt_log_warning( getProducer(), "frame dropped %d\n", m_dropped );
456 pthread_mutex_unlock( &m_mutex );
462 virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(
463 BMDVideoInputFormatChangedEvents events,
464 IDeckLinkDisplayMode* mode,
465 BMDDetectedVideoInputFormatFlags flags )
467 mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) );
468 if ( events & bmdVideoInputDisplayModeChanged )
470 BMDTimeValue duration;
471 BMDTimeScale timescale;
472 mode->GetFrameRate( &duration, ×cale );
473 profile->width = mode->GetWidth();
474 profile->height = mode->GetHeight() + m_vancLines;
475 profile->frame_rate_num = timescale;
476 profile->frame_rate_den = duration;
477 if ( profile->width == 720 )
479 if ( profile->height == 576 )
481 profile->sample_aspect_num = 16;
482 profile->sample_aspect_den = 15;
486 profile->sample_aspect_num = 8;
487 profile->sample_aspect_den = 9;
489 profile->display_aspect_num = 4;
490 profile->display_aspect_den = 3;
494 profile->sample_aspect_num = 1;
495 profile->sample_aspect_den = 1;
496 profile->display_aspect_num = 16;
497 profile->display_aspect_den = 9;
499 free( profile->description );
500 profile->description = strdup( "decklink" );
501 mlt_log_verbose( getProducer(), "format changed %dx%d %.3f fps\n",
502 profile->width, profile->height, (double) profile->frame_rate_num / profile->frame_rate_den );
504 if ( events & bmdVideoInputFieldDominanceChanged )
506 profile->progressive = mode->GetFieldDominance() == bmdProgressiveFrame;
507 m_topFieldFirst = mode->GetFieldDominance() == bmdUpperFieldFirst;
508 mlt_log_verbose( getProducer(), "field dominance changed prog %d tff %d\n",
509 profile->progressive, m_topFieldFirst );
511 if ( events & bmdVideoInputColorspaceChanged )
513 profile->colorspace = m_colorspace =
514 ( mode->GetFlags() & bmdDisplayModeColorspaceRec709 ) ? 709 : 601;
515 mlt_log_verbose( getProducer(), "colorspace changed %d\n", profile->colorspace );
521 static int get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
523 return mlt_frame_get_audio( frame, (void**) buffer, format, frequency, channels, samples );
526 static int get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
528 return mlt_frame_get_image( frame, buffer, format, width, height, writable );
531 static int get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
533 DeckLinkProducer* decklink = (DeckLinkProducer*) producer->child;
536 decklink->start( mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ) );
538 // Get the next frame from the decklink object
539 *frame = decklink->getFrame();
541 *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) );
543 // Calculate the next timecode
544 mlt_frame_set_position( *frame, mlt_producer_position( producer ) );
545 mlt_producer_prepare_next( producer );
547 // Add audio and video getters
548 mlt_frame_push_audio( *frame, (void*) get_audio );
549 mlt_frame_push_get_image( *frame, get_image );
554 static void producer_close( mlt_producer producer )
556 producer->close = NULL;
557 mlt_producer_close( producer );
558 delete (DeckLinkProducer*) producer->child;
563 /** Initialise the producer.
566 mlt_producer producer_decklink_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
568 // Allocate the producer
569 DeckLinkProducer* decklink = new DeckLinkProducer();
570 mlt_producer producer = NULL;
572 // If allocated and initializes
573 if ( decklink && !mlt_producer_init( decklink->getProducer(), decklink ) )
575 if ( decklink->open( profile, arg? atoi( arg ) : 0 ) )
577 producer = decklink->getProducer();
578 mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );
581 producer->close = (mlt_destructor) producer_close;
582 producer->get_frame = get_frame;
585 mlt_properties_set( properties, "resource", arg? arg : "0" );
586 mlt_properties_set_int( properties, "channels", 2 );
587 mlt_properties_set_int( properties, "buffer", 25 );
588 mlt_properties_set_int( properties, "prefill", 25 );
590 // These properties effectively make it infinite.
591 mlt_properties_set_int( properties, "length", INT_MAX );
592 mlt_properties_set_int( properties, "out", INT_MAX - 1 );
593 mlt_properties_set( properties, "eof", "loop" );