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 );
222 // Release the wait in getFrame
223 pthread_mutex_lock( &m_mutex );
224 pthread_cond_broadcast( &m_condition );
225 pthread_mutex_unlock( &m_mutex );
227 m_decklinkInput->StopStreams();
230 pthread_mutex_lock( &m_mutex );
231 while ( mlt_frame frame = (mlt_frame) mlt_deque_pop_back( m_queue ) )
232 mlt_frame_close( frame );
233 pthread_mutex_unlock( &m_mutex );
238 mlt_frame frame = NULL;
241 double fps = mlt_producer_get_fps( getProducer() );
243 // Allow the buffer to fill to the requested initial buffer level.
246 int prefill = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "prefill" );
247 int buffer = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "buffer" );
249 m_isBuffering = false;
250 prefill = prefill > buffer ? buffer : prefill;
251 pthread_mutex_lock( &m_mutex );
252 while ( mlt_deque_count( m_queue ) < prefill )
254 // Wait up to buffer/fps seconds
255 gettimeofday( &now, NULL );
256 long usec = now.tv_sec * 1000000 + now.tv_usec;
257 usec += 1000000 * buffer / fps;
258 tm.tv_sec = usec / 1000000;
259 tm.tv_nsec = (usec % 1000000) * 1000;
260 if ( pthread_cond_timedwait( &m_condition, &m_mutex, &tm ) )
263 pthread_mutex_unlock( &m_mutex );
266 // Wait if queue is empty
267 pthread_mutex_lock( &m_mutex );
268 while ( mlt_deque_count( m_queue ) < 1 )
270 // Wait up to twice frame duration
271 gettimeofday( &now, NULL );
272 long usec = now.tv_sec * 1000000 + now.tv_usec;
273 usec += 2000000 / fps;
274 tm.tv_sec = usec / 1000000;
275 tm.tv_nsec = (usec % 1000000) * 1000;
276 if ( pthread_cond_timedwait( &m_condition, &m_mutex, &tm ) )
277 // Stop waiting if error (timed out)
281 // Get the first frame from the queue
282 frame = ( mlt_frame ) mlt_deque_pop_front( m_queue );
283 pthread_mutex_unlock( &m_mutex );
285 // Set frame timestamp and properties
288 mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) );
289 mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
290 mlt_properties_set_int( properties, "progressive", profile->progressive );
291 mlt_properties_set_int( properties, "meta.media.progressive", profile->progressive );
292 mlt_properties_set_int( properties, "top_field_first", m_topFieldFirst );
293 mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile ) );
294 mlt_properties_set_int( properties, "meta.media.sample_aspect_num", profile->sample_aspect_num );
295 mlt_properties_set_int( properties, "meta.media.sample_aspect_den", profile->sample_aspect_den );
296 mlt_properties_set_int( properties, "meta.media.frame_rate_num", profile->frame_rate_num );
297 mlt_properties_set_int( properties, "meta.media.frame_rate_den", profile->frame_rate_den );
298 mlt_properties_set_int( properties, "width", profile->width );
299 mlt_properties_set_int( properties, "real_width", profile->width );
300 mlt_properties_set_int( properties, "meta.media.width", profile->width );
301 mlt_properties_set_int( properties, "height", profile->height );
302 mlt_properties_set_int( properties, "real_height", profile->height );
303 mlt_properties_set_int( properties, "meta.media.height", profile->height );
304 mlt_properties_set_int( properties, "format", mlt_image_yuv422 );
305 mlt_properties_set_int( properties, "colorspace", m_colorspace );
306 mlt_properties_set_int( properties, "meta.media.colorspace", m_colorspace );
307 mlt_properties_set_int( properties, "audio_frequency", 48000 );
308 mlt_properties_set_int( properties, "audio_channels",
309 mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" ) );
314 // *** DeckLink API implementation of IDeckLinkInputCallback *** //
316 // IUnknown needs only a dummy implementation
317 virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID iid, LPVOID *ppv )
318 { return E_NOINTERFACE; }
319 virtual ULONG STDMETHODCALLTYPE AddRef()
321 virtual ULONG STDMETHODCALLTYPE Release()
324 /************************* DeckLink API Delegate Methods *****************************/
326 virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(
327 IDeckLinkVideoInputFrame* video,
328 IDeckLinkAudioInputPacket* audio )
331 mlt_frame frame = mlt_frame_init( MLT_PRODUCER_SERVICE( getProducer() ) );
336 if ( !( video->GetFlags() & bmdFrameHasNoInputSource ) )
338 int size = video->GetRowBytes() * ( video->GetHeight() + m_vancLines );
339 void* image = mlt_pool_alloc( size );
341 unsigned char* p = (unsigned char*) image;
344 // Initialize VANC lines to nominal black
352 if ( m_vancLines > 0 )
354 IDeckLinkVideoFrameAncillary* vanc = 0;
355 if ( video->GetAncillaryData( &vanc ) == S_OK && vanc )
357 for ( int i = 1; i < m_vancLines + 1; i++ )
359 if ( vanc->GetBufferForVerticalBlankingLine( i, &buffer ) == S_OK )
360 swab( (char*) buffer, (char*) image + ( i - 1 ) * video->GetRowBytes(), video->GetRowBytes() );
362 mlt_log_debug( getProducer(), "failed capture vanc line %d\n", i );
369 video->GetBytes( &buffer );
370 if ( image && buffer )
372 size = video->GetRowBytes() * video->GetHeight();
373 swab( (char*) buffer, (char*) image + m_vancLines * video->GetRowBytes(), size );
374 mlt_frame_set_image( frame, (uint8_t*) image, size, mlt_pool_release );
378 mlt_log_verbose( getProducer(), "no video\n" );
379 mlt_pool_release( image );
384 mlt_log_verbose( getProducer(), "no signal\n" );
385 mlt_frame_close( frame );
390 IDeckLinkTimecode* timecode = 0;
391 if ( video->GetTimecode( bmdTimecodeVITC, &timecode ) == S_OK && timecode )
393 const char* timecodeString = 0;
396 if ( timecode->GetString( (BSTR*) &timecodeString ) == S_OK )
398 if ( timecode->GetString( &timecodeString ) == S_OK )
401 mlt_properties_set( MLT_FRAME_PROPERTIES( frame ), "meta.attr.vitc.markup", timecodeString );
402 mlt_log_debug( getProducer(), "timecode %s\n", timecodeString );
404 if ( timecodeString )
405 free( (void*) timecodeString );
411 mlt_log_verbose( getProducer(), "no video\n" );
412 mlt_frame_close( frame );
417 if ( frame && audio )
419 int channels = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" );
420 int size = audio->GetSampleFrameCount() * channels * sizeof(int16_t);
421 mlt_audio_format format = mlt_audio_s16;
422 void* pcm = mlt_pool_alloc( size );
425 audio->GetBytes( &buffer );
428 memcpy( pcm, buffer, size );
429 mlt_frame_set_audio( frame, pcm, format, size, mlt_pool_release );
430 mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "audio_samples", audio->GetSampleFrameCount() );
434 mlt_log_verbose( getProducer(), "no audio\n" );
435 mlt_pool_release( pcm );
440 mlt_log_verbose( getProducer(), "no audio\n" );
443 // Put frame in queue
446 int queueMax = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "buffer" );
447 pthread_mutex_lock( &m_mutex );
448 if ( mlt_deque_count( m_queue ) < queueMax )
450 mlt_deque_push_back( m_queue, frame );
451 pthread_cond_broadcast( &m_condition );
455 mlt_frame_close( frame );
456 mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "dropped", ++m_dropped );
457 mlt_log_warning( getProducer(), "frame dropped %d\n", m_dropped );
459 pthread_mutex_unlock( &m_mutex );
465 virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(
466 BMDVideoInputFormatChangedEvents events,
467 IDeckLinkDisplayMode* mode,
468 BMDDetectedVideoInputFormatFlags flags )
470 mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) );
471 if ( events & bmdVideoInputDisplayModeChanged )
473 BMDTimeValue duration;
474 BMDTimeScale timescale;
475 mode->GetFrameRate( &duration, ×cale );
476 profile->width = mode->GetWidth();
477 profile->height = mode->GetHeight() + m_vancLines;
478 profile->frame_rate_num = timescale;
479 profile->frame_rate_den = duration;
480 if ( profile->width == 720 )
482 if ( profile->height == 576 )
484 profile->sample_aspect_num = 16;
485 profile->sample_aspect_den = 15;
489 profile->sample_aspect_num = 8;
490 profile->sample_aspect_den = 9;
492 profile->display_aspect_num = 4;
493 profile->display_aspect_den = 3;
497 profile->sample_aspect_num = 1;
498 profile->sample_aspect_den = 1;
499 profile->display_aspect_num = 16;
500 profile->display_aspect_den = 9;
502 free( profile->description );
503 profile->description = strdup( "decklink" );
504 mlt_log_verbose( getProducer(), "format changed %dx%d %.3f fps\n",
505 profile->width, profile->height, (double) profile->frame_rate_num / profile->frame_rate_den );
507 if ( events & bmdVideoInputFieldDominanceChanged )
509 profile->progressive = mode->GetFieldDominance() == bmdProgressiveFrame;
510 m_topFieldFirst = mode->GetFieldDominance() == bmdUpperFieldFirst;
511 mlt_log_verbose( getProducer(), "field dominance changed prog %d tff %d\n",
512 profile->progressive, m_topFieldFirst );
514 if ( events & bmdVideoInputColorspaceChanged )
516 profile->colorspace = m_colorspace =
517 ( mode->GetFlags() & bmdDisplayModeColorspaceRec709 ) ? 709 : 601;
518 mlt_log_verbose( getProducer(), "colorspace changed %d\n", profile->colorspace );
524 static int get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
526 return mlt_frame_get_audio( frame, (void**) buffer, format, frequency, channels, samples );
529 static int get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
531 return mlt_frame_get_image( frame, buffer, format, width, height, writable );
534 static int get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
536 DeckLinkProducer* decklink = (DeckLinkProducer*) producer->child;
539 decklink->start( mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ) );
541 // Get the next frame from the decklink object
542 *frame = decklink->getFrame();
544 *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) );
546 // Calculate the next timecode
547 mlt_frame_set_position( *frame, mlt_producer_position( producer ) );
548 mlt_producer_prepare_next( producer );
550 // Add audio and video getters
551 mlt_frame_push_audio( *frame, (void*) get_audio );
552 mlt_frame_push_get_image( *frame, get_image );
557 static void producer_close( mlt_producer producer )
559 producer->close = NULL;
560 mlt_producer_close( producer );
561 delete (DeckLinkProducer*) producer->child;
566 /** Initialise the producer.
569 mlt_producer producer_decklink_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
571 // Allocate the producer
572 DeckLinkProducer* decklink = new DeckLinkProducer();
573 mlt_producer producer = NULL;
575 // If allocated and initializes
576 if ( decklink && !mlt_producer_init( decklink->getProducer(), decklink ) )
578 if ( decklink->open( profile, arg? atoi( arg ) : 0 ) )
580 producer = decklink->getProducer();
581 mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );
584 producer->close = (mlt_destructor) producer_close;
585 producer->get_frame = get_frame;
588 mlt_properties_set( properties, "resource", arg? arg : "0" );
589 mlt_properties_set_int( properties, "channels", 2 );
590 mlt_properties_set_int( properties, "buffer", 25 );
591 mlt_properties_set_int( properties, "prefill", 25 );
593 // These properties effectively make it infinite.
594 mlt_properties_set_int( properties, "length", INT_MAX );
595 mlt_properties_set_int( properties, "out", INT_MAX - 1 );
596 mlt_properties_set( properties, "eof", "loop" );