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 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 void setProducer( mlt_producer producer )
85 { m_producer = producer; }
87 mlt_producer getProducer() const
88 { return m_producer; }
92 if ( m_decklinkInput )
93 m_decklinkInput->Release();
95 m_decklink->Release();
99 mlt_deque_close( m_queue );
100 pthread_mutex_destroy( &m_mutex );
101 pthread_cond_destroy( &m_condition );
105 bool open( unsigned card = 0 )
107 IDeckLinkIterator* decklinkIterator = NULL;
111 HRESULT result = CoInitialize( NULL );
112 if ( FAILED( result ) )
113 throw "COM initialization failed";
114 result = CoCreateInstance( CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL, IID_IDeckLinkIterator, (void**) &decklinkIterator );
115 if ( FAILED( result ) )
116 throw "The DeckLink drivers are not installed.";
118 decklinkIterator = CreateDeckLinkIteratorInstance();
119 if ( !decklinkIterator )
120 throw "The DeckLink drivers are not installed.";
123 // Connect to the Nth DeckLink instance
126 if ( decklinkIterator->Next( &m_decklink ) != S_OK )
127 throw "DeckLink card not found.";
128 } while ( ++i <= card );
129 decklinkIterator->Release();
131 // Get the input interface
132 if ( m_decklink->QueryInterface( IID_IDeckLinkInput, (void**) &m_decklinkInput ) != S_OK )
133 throw "No DeckLink cards support input.";
135 // Provide this class as a delegate to the input callback
136 m_decklinkInput->SetCallback( this );
138 // Initialize other members
139 pthread_mutex_init( &m_mutex, NULL );
140 pthread_cond_init( &m_condition, NULL );
141 m_queue = mlt_deque_init();
144 m_isBuffering = true;
146 catch ( const char *error )
148 if ( decklinkIterator )
149 decklinkIterator->Release();
150 mlt_log_error( getProducer(), "%s\n", error );
156 bool start( mlt_profile profile = 0 )
162 // Initialize some members
163 m_vancLines = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "vanc" );
164 if ( m_vancLines == -1 )
165 m_vancLines = profile->height <= 512 ? 26 : 32;
168 profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) );
170 // Get the display mode
171 BMDDisplayMode displayMode = getDisplayMode( profile, m_vancLines );
172 if ( displayMode == (BMDDisplayMode) bmdDisplayModeNotSupported )
173 throw "Profile is not compatible with decklink.";
175 // Determine if supports input format detection
177 BOOL doesDetectFormat = FALSE;
179 bool doesDetectFormat = false;
181 IDeckLinkAttributes *decklinkAttributes = 0;
182 if ( m_decklink->QueryInterface( IID_IDeckLinkAttributes, (void**) &decklinkAttributes ) == S_OK )
184 if ( decklinkAttributes->GetFlag( BMDDeckLinkSupportsInputFormatDetection, &doesDetectFormat ) != S_OK )
185 doesDetectFormat = false;
186 decklinkAttributes->Release();
188 mlt_log_verbose( getProducer(), "%s format detection\n", doesDetectFormat ? "supports" : "does not support" );
190 // Enable video capture
191 BMDPixelFormat pixelFormat = bmdFormat8BitYUV;
192 BMDVideoInputFlags flags = doesDetectFormat ? bmdVideoInputEnableFormatDetection : bmdVideoInputFlagDefault;
193 if ( S_OK != m_decklinkInput->EnableVideoInput( displayMode, pixelFormat, flags ) )
194 throw "Failed to enable video capture.";
196 // Enable audio capture
197 BMDAudioSampleRate sampleRate = bmdAudioSampleRate48kHz;
198 BMDAudioSampleType sampleType = bmdAudioSampleType16bitInteger;
199 int channels = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" );
200 if ( S_OK != m_decklinkInput->EnableAudioInput( sampleRate, sampleType, channels ) )
201 throw "Failed to enable audio capture.";
205 mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "dropped", m_dropped );
206 m_started = m_decklinkInput->StartStreams() == S_OK;
208 throw "Failed to start capture.";
210 catch ( const char *error )
212 m_decklinkInput->DisableVideoInput();
213 mlt_log_error( getProducer(), "%s\n", error );
225 // Release the wait in getFrame
226 pthread_mutex_lock( &m_mutex );
227 pthread_cond_broadcast( &m_condition );
228 pthread_mutex_unlock( &m_mutex );
230 m_decklinkInput->StopStreams();
233 pthread_mutex_lock( &m_mutex );
234 while ( mlt_frame frame = (mlt_frame) mlt_deque_pop_back( m_queue ) )
235 mlt_frame_close( frame );
236 pthread_mutex_unlock( &m_mutex );
241 mlt_frame frame = NULL;
244 double fps = mlt_producer_get_fps( getProducer() );
246 // Allow the buffer to fill to the requested initial buffer level.
249 int prefill = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "prefill" );
250 int buffer = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "buffer" );
252 m_isBuffering = false;
253 prefill = prefill > buffer ? buffer : prefill;
254 pthread_mutex_lock( &m_mutex );
255 while ( mlt_deque_count( m_queue ) < prefill )
257 // Wait up to buffer/fps seconds
258 gettimeofday( &now, NULL );
259 long usec = now.tv_sec * 1000000 + now.tv_usec;
260 usec += 1000000 * buffer / fps;
261 tm.tv_sec = usec / 1000000;
262 tm.tv_nsec = (usec % 1000000) * 1000;
263 if ( pthread_cond_timedwait( &m_condition, &m_mutex, &tm ) )
266 pthread_mutex_unlock( &m_mutex );
269 // Wait if queue is empty
270 pthread_mutex_lock( &m_mutex );
271 while ( mlt_deque_count( m_queue ) < 1 )
273 // Wait up to twice frame duration
274 gettimeofday( &now, NULL );
275 long usec = now.tv_sec * 1000000 + now.tv_usec;
276 usec += 2000000 / fps;
277 tm.tv_sec = usec / 1000000;
278 tm.tv_nsec = (usec % 1000000) * 1000;
279 if ( pthread_cond_timedwait( &m_condition, &m_mutex, &tm ) )
280 // Stop waiting if error (timed out)
284 // Get the first frame from the queue
285 frame = ( mlt_frame ) mlt_deque_pop_front( m_queue );
286 pthread_mutex_unlock( &m_mutex );
288 // Set frame timestamp and properties
291 mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) );
292 mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
293 mlt_properties_set_int( properties, "progressive", profile->progressive );
294 mlt_properties_set_int( properties, "meta.media.progressive", profile->progressive );
295 mlt_properties_set_int( properties, "top_field_first", m_topFieldFirst );
296 mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile ) );
297 mlt_properties_set_int( properties, "meta.media.sample_aspect_num", profile->sample_aspect_num );
298 mlt_properties_set_int( properties, "meta.media.sample_aspect_den", profile->sample_aspect_den );
299 mlt_properties_set_int( properties, "meta.media.frame_rate_num", profile->frame_rate_num );
300 mlt_properties_set_int( properties, "meta.media.frame_rate_den", profile->frame_rate_den );
301 mlt_properties_set_int( properties, "width", profile->width );
302 mlt_properties_set_int( properties, "real_width", profile->width );
303 mlt_properties_set_int( properties, "meta.media.width", profile->width );
304 mlt_properties_set_int( properties, "height", profile->height );
305 mlt_properties_set_int( properties, "real_height", profile->height );
306 mlt_properties_set_int( properties, "meta.media.height", profile->height );
307 mlt_properties_set_int( properties, "format", mlt_image_yuv422 );
308 mlt_properties_set_int( properties, "colorspace", m_colorspace );
309 mlt_properties_set_int( properties, "meta.media.colorspace", m_colorspace );
310 mlt_properties_set_int( properties, "audio_frequency", 48000 );
311 mlt_properties_set_int( properties, "audio_channels",
312 mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" ) );
317 // *** DeckLink API implementation of IDeckLinkInputCallback *** //
319 // IUnknown needs only a dummy implementation
320 virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID iid, LPVOID *ppv )
321 { return E_NOINTERFACE; }
322 virtual ULONG STDMETHODCALLTYPE AddRef()
324 virtual ULONG STDMETHODCALLTYPE Release()
327 /************************* DeckLink API Delegate Methods *****************************/
329 virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(
330 IDeckLinkVideoInputFrame* video,
331 IDeckLinkAudioInputPacket* audio )
334 mlt_frame frame = mlt_frame_init( MLT_PRODUCER_SERVICE( getProducer() ) );
339 if ( !( video->GetFlags() & bmdFrameHasNoInputSource ) )
341 int size = video->GetRowBytes() * ( video->GetHeight() + m_vancLines );
342 void* image = mlt_pool_alloc( size );
344 unsigned char* p = (unsigned char*) image;
347 // Initialize VANC lines to nominal black
355 if ( m_vancLines > 0 )
357 IDeckLinkVideoFrameAncillary* vanc = 0;
358 if ( video->GetAncillaryData( &vanc ) == S_OK && vanc )
360 for ( int i = 1; i < m_vancLines + 1; i++ )
362 if ( vanc->GetBufferForVerticalBlankingLine( i, &buffer ) == S_OK )
363 swab( (char*) buffer, (char*) image + ( i - 1 ) * video->GetRowBytes(), video->GetRowBytes() );
365 mlt_log_debug( getProducer(), "failed capture vanc line %d\n", i );
372 video->GetBytes( &buffer );
373 if ( image && buffer )
375 size = video->GetRowBytes() * video->GetHeight();
376 swab( (char*) buffer, (char*) image + m_vancLines * video->GetRowBytes(), size );
377 mlt_frame_set_image( frame, (uint8_t*) image, size, mlt_pool_release );
381 mlt_log_verbose( getProducer(), "no video\n" );
382 mlt_pool_release( image );
387 mlt_log_verbose( getProducer(), "no signal\n" );
388 mlt_frame_close( frame );
393 IDeckLinkTimecode* timecode = 0;
394 if ( video->GetTimecode( bmdTimecodeVITC, &timecode ) == S_OK && timecode )
396 const char* timecodeString = 0;
399 if ( timecode->GetString( (BSTR*) &timecodeString ) == S_OK )
401 if ( timecode->GetString( &timecodeString ) == S_OK )
404 mlt_properties_set( MLT_FRAME_PROPERTIES( frame ), "meta.attr.vitc.markup", timecodeString );
405 mlt_log_debug( getProducer(), "timecode %s\n", timecodeString );
407 if ( timecodeString )
408 free( (void*) timecodeString );
414 mlt_log_verbose( getProducer(), "no video\n" );
415 mlt_frame_close( frame );
420 if ( frame && audio )
422 int channels = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" );
423 int size = audio->GetSampleFrameCount() * channels * sizeof(int16_t);
424 mlt_audio_format format = mlt_audio_s16;
425 void* pcm = mlt_pool_alloc( size );
428 audio->GetBytes( &buffer );
431 memcpy( pcm, buffer, size );
432 mlt_frame_set_audio( frame, pcm, format, size, mlt_pool_release );
433 mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "audio_samples", audio->GetSampleFrameCount() );
437 mlt_log_verbose( getProducer(), "no audio\n" );
438 mlt_pool_release( pcm );
443 mlt_log_verbose( getProducer(), "no audio\n" );
446 // Put frame in queue
449 int queueMax = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "buffer" );
450 pthread_mutex_lock( &m_mutex );
451 if ( mlt_deque_count( m_queue ) < queueMax )
453 mlt_deque_push_back( m_queue, frame );
454 pthread_cond_broadcast( &m_condition );
458 mlt_frame_close( frame );
459 mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "dropped", ++m_dropped );
460 mlt_log_warning( getProducer(), "frame dropped %d\n", m_dropped );
462 pthread_mutex_unlock( &m_mutex );
468 virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(
469 BMDVideoInputFormatChangedEvents events,
470 IDeckLinkDisplayMode* mode,
471 BMDDetectedVideoInputFormatFlags flags )
473 mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) );
474 if ( events & bmdVideoInputDisplayModeChanged )
476 BMDTimeValue duration;
477 BMDTimeScale timescale;
478 mode->GetFrameRate( &duration, ×cale );
479 profile->width = mode->GetWidth();
480 profile->height = mode->GetHeight() + m_vancLines;
481 profile->frame_rate_num = timescale;
482 profile->frame_rate_den = duration;
483 if ( profile->width == 720 )
485 if ( profile->height == 576 )
487 profile->sample_aspect_num = 16;
488 profile->sample_aspect_den = 15;
492 profile->sample_aspect_num = 8;
493 profile->sample_aspect_den = 9;
495 profile->display_aspect_num = 4;
496 profile->display_aspect_den = 3;
500 profile->sample_aspect_num = 1;
501 profile->sample_aspect_den = 1;
502 profile->display_aspect_num = 16;
503 profile->display_aspect_den = 9;
505 free( profile->description );
506 profile->description = strdup( "decklink" );
507 mlt_log_verbose( getProducer(), "format changed %dx%d %.3f fps\n",
508 profile->width, profile->height, (double) profile->frame_rate_num / profile->frame_rate_den );
510 if ( events & bmdVideoInputFieldDominanceChanged )
512 profile->progressive = mode->GetFieldDominance() == bmdProgressiveFrame;
513 m_topFieldFirst = mode->GetFieldDominance() == bmdUpperFieldFirst;
514 mlt_log_verbose( getProducer(), "field dominance changed prog %d tff %d\n",
515 profile->progressive, m_topFieldFirst );
517 if ( events & bmdVideoInputColorspaceChanged )
519 profile->colorspace = m_colorspace =
520 ( mode->GetFlags() & bmdDisplayModeColorspaceRec709 ) ? 709 : 601;
521 mlt_log_verbose( getProducer(), "colorspace changed %d\n", profile->colorspace );
527 static int get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
529 return mlt_frame_get_audio( frame, (void**) buffer, format, frequency, channels, samples );
532 static int get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
534 return mlt_frame_get_image( frame, buffer, format, width, height, writable );
537 static int get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
539 DeckLinkProducer* decklink = (DeckLinkProducer*) producer->child;
540 mlt_position pos = mlt_producer_position( producer );
541 mlt_position end = mlt_producer_get_playtime( producer );
542 end = ( mlt_producer_get_length( producer ) < end ? mlt_producer_get_length( producer ) : end ) - 1;
545 if ( !decklink && pos < end )
547 producer->child = decklink = new DeckLinkProducer();
548 decklink->setProducer( producer );
549 decklink->open( mlt_properties_get_int( MLT_PRODUCER_PROPERTIES(producer), "resource" ) );
555 decklink->start( mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ) );
557 // Get the next frame from the decklink object
558 if ( ( *frame = decklink->getFrame() ))
560 // Add audio and video getters
561 mlt_frame_push_audio( *frame, (void*) get_audio );
562 mlt_frame_push_get_image( *frame, get_image );
566 *frame = mlt_frame_init( MLT_PRODUCER_SERVICE(producer) );
568 // Calculate the next timecode
569 mlt_frame_set_position( *frame, mlt_producer_position( producer ) );
570 mlt_producer_prepare_next( producer );
572 // Close DeckLink if at end
573 if ( pos >= end && decklink )
577 producer->child = NULL;
583 static void producer_close( mlt_producer producer )
585 delete (DeckLinkProducer*) producer->child;
586 producer->close = NULL;
587 mlt_producer_close( producer );
592 /** Initialise the producer.
595 mlt_producer producer_decklink_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
597 // Allocate the producer
598 DeckLinkProducer* decklink = new DeckLinkProducer();
599 mlt_producer producer = (mlt_producer) calloc( 1, sizeof( *producer ) );
601 // If allocated and initializes
602 if ( decklink && !mlt_producer_init( producer, decklink ) )
604 if ( decklink->open( arg? atoi( arg ) : 0 ) )
606 mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );
608 // Close DeckLink and defer re-open to get_frame
610 producer->child = NULL;
613 producer->close = (mlt_destructor) producer_close;
614 producer->get_frame = get_frame;
617 mlt_properties_set( properties, "resource", (arg && strcmp( arg, ""))? arg : "0" );
618 mlt_properties_set_int( properties, "channels", 2 );
619 mlt_properties_set_int( properties, "buffer", 25 );
620 mlt_properties_set_int( properties, "prefill", 25 );
622 // These properties effectively make it infinite.
623 mlt_properties_set_int( properties, "length", INT_MAX );
624 mlt_properties_set_int( properties, "out", INT_MAX - 1 );
625 mlt_properties_set( properties, "eof", "loop" );