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;
52 BMDDisplayMode getDisplayMode( mlt_profile profile, int vancLines )
54 IDeckLinkDisplayModeIterator* iter;
55 IDeckLinkDisplayMode* mode;
56 BMDDisplayMode result = (BMDDisplayMode) bmdDisplayModeNotSupported;
58 if ( m_decklinkInput->GetDisplayModeIterator( &iter ) == S_OK )
60 while ( !result && iter->Next( &mode ) == S_OK )
62 int width = mode->GetWidth();
63 int height = mode->GetHeight();
64 BMDTimeValue duration;
65 BMDTimeScale timescale;
66 mode->GetFrameRate( &duration, ×cale );
67 double fps = (double) timescale / duration;
68 int p = mode->GetFieldDominance() == bmdProgressiveFrame;
69 m_topFieldFirst = mode->GetFieldDominance() == bmdUpperFieldFirst;
70 m_colorspace = ( mode->GetFlags() & bmdDisplayModeColorspaceRec709 ) ? 709 : 601;
71 mlt_log_verbose( getProducer(), "BMD mode %dx%d %.3f fps prog %d tff %d\n", width, height, fps, p, m_topFieldFirst );
73 if ( width == profile->width && p == profile->progressive
74 && ( height + vancLines == profile->height || ( height == 486 && profile->height == 480 + vancLines ) )
75 && fps == mlt_profile_fps( profile ) )
76 result = mode->GetDisplayMode();
85 void setProducer( mlt_producer producer )
86 { m_producer = producer; }
88 mlt_producer getProducer() const
89 { return m_producer; }
96 mlt_deque_close( m_queue );
97 pthread_mutex_destroy( &m_mutex );
98 pthread_cond_destroy( &m_condition );
99 mlt_cache_close( m_cache );
101 if ( m_decklinkInput )
102 m_decklinkInput->Release();
104 m_decklink->Release();
107 bool open( unsigned card = 0 )
109 IDeckLinkIterator* decklinkIterator = NULL;
113 HRESULT result = CoInitialize( NULL );
114 if ( FAILED( result ) )
115 throw "COM initialization failed";
116 result = CoCreateInstance( CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL, IID_IDeckLinkIterator, (void**) &decklinkIterator );
117 if ( FAILED( result ) )
118 throw "The DeckLink drivers are not installed.";
120 decklinkIterator = CreateDeckLinkIteratorInstance();
121 if ( !decklinkIterator )
122 throw "The DeckLink drivers are not installed.";
125 // Connect to the Nth DeckLink instance
128 if ( decklinkIterator->Next( &m_decklink ) != S_OK )
129 throw "DeckLink card not found.";
130 } while ( ++i <= card );
131 decklinkIterator->Release();
133 // Get the input interface
134 if ( m_decklink->QueryInterface( IID_IDeckLinkInput, (void**) &m_decklinkInput ) != S_OK )
135 throw "No DeckLink cards support input.";
137 // Provide this class as a delegate to the input callback
138 m_decklinkInput->SetCallback( this );
140 // Initialize other members
141 pthread_mutex_init( &m_mutex, NULL );
142 pthread_cond_init( &m_condition, NULL );
143 m_queue = mlt_deque_init();
146 m_isBuffering = true;
147 m_cache = mlt_cache_init();
149 // 3 covers YADIF and increasing framerate use cases
150 mlt_cache_set_size( m_cache, 3 );
152 catch ( const char *error )
154 if ( decklinkIterator )
155 decklinkIterator->Release();
156 mlt_log_error( getProducer(), "%s\n", error );
162 bool start( mlt_profile profile = 0 )
168 // Initialize some members
169 m_vancLines = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "vanc" );
170 if ( m_vancLines == -1 )
171 m_vancLines = profile->height <= 512 ? 26 : 32;
174 profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) );
176 // Get the display mode
177 BMDDisplayMode displayMode = getDisplayMode( profile, m_vancLines );
178 if ( displayMode == (BMDDisplayMode) bmdDisplayModeNotSupported )
180 mlt_log_info( getProducer(), "profile = %dx%d %f fps %s\n", profile->width, profile->height,
181 mlt_profile_fps( profile ), profile->progressive? "progressive" : "interlace" );
182 throw "Profile is not compatible with decklink.";
185 // Determine if supports input format detection
187 BOOL doesDetectFormat = FALSE;
189 bool doesDetectFormat = false;
191 IDeckLinkAttributes *decklinkAttributes = 0;
192 if ( m_decklink->QueryInterface( IID_IDeckLinkAttributes, (void**) &decklinkAttributes ) == S_OK )
194 if ( decklinkAttributes->GetFlag( BMDDeckLinkSupportsInputFormatDetection, &doesDetectFormat ) != S_OK )
195 doesDetectFormat = false;
196 decklinkAttributes->Release();
198 mlt_log_verbose( getProducer(), "%s format detection\n", doesDetectFormat ? "supports" : "does not support" );
200 // Enable video capture
201 BMDPixelFormat pixelFormat = bmdFormat8BitYUV;
202 BMDVideoInputFlags flags = doesDetectFormat ? bmdVideoInputEnableFormatDetection : bmdVideoInputFlagDefault;
203 if ( S_OK != m_decklinkInput->EnableVideoInput( displayMode, pixelFormat, flags ) )
204 throw "Failed to enable video capture.";
206 // Enable audio capture
207 BMDAudioSampleRate sampleRate = bmdAudioSampleRate48kHz;
208 BMDAudioSampleType sampleType = bmdAudioSampleType16bitInteger;
209 int channels = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" );
210 if ( S_OK != m_decklinkInput->EnableAudioInput( sampleRate, sampleType, channels ) )
211 throw "Failed to enable audio capture.";
215 mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "dropped", m_dropped );
216 m_started = m_decklinkInput->StartStreams() == S_OK;
218 throw "Failed to start capture.";
220 catch ( const char *error )
222 m_decklinkInput->DisableVideoInput();
223 mlt_log_error( getProducer(), "%s\n", error );
235 // Release the wait in getFrame
236 pthread_mutex_lock( &m_mutex );
237 pthread_cond_broadcast( &m_condition );
238 pthread_mutex_unlock( &m_mutex );
240 m_decklinkInput->StopStreams();
243 pthread_mutex_lock( &m_mutex );
244 while ( mlt_frame frame = (mlt_frame) mlt_deque_pop_back( m_queue ) )
245 mlt_frame_close( frame );
246 pthread_mutex_unlock( &m_mutex );
249 mlt_frame cloneFrame( mlt_frame frame )
251 mlt_frame new_frame = mlt_frame_init( NULL );
252 mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
253 mlt_properties new_props = MLT_FRAME_PROPERTIES( new_frame );
258 mlt_properties_inherit( new_props, properties );
259 mlt_properties_set_int( new_props, "audio_samples", 0 );
260 data = mlt_properties_get_data( properties, "image", &size );
261 copy = mlt_pool_alloc( size );
262 memcpy( copy, data, size );
263 mlt_properties_set_data( new_props, "image", copy, size, mlt_pool_release, NULL );
270 mlt_frame frame = NULL;
273 double fps = mlt_producer_get_fps( getProducer() );
274 mlt_position position = mlt_producer_position( getProducer() );
275 mlt_cache_item cached = mlt_cache_get( m_cache, (void*) position );
277 // Allow the buffer to fill to the requested initial buffer level.
280 int prefill = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "prefill" );
281 int buffer = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "buffer" );
283 m_isBuffering = false;
284 prefill = prefill > buffer ? buffer : prefill;
285 pthread_mutex_lock( &m_mutex );
286 while ( mlt_deque_count( m_queue ) < prefill )
288 // Wait up to buffer/fps seconds
289 gettimeofday( &now, NULL );
290 long usec = now.tv_sec * 1000000 + now.tv_usec;
291 usec += 1000000 * buffer / fps;
292 tm.tv_sec = usec / 1000000;
293 tm.tv_nsec = (usec % 1000000) * 1000;
294 if ( pthread_cond_timedwait( &m_condition, &m_mutex, &tm ) )
297 pthread_mutex_unlock( &m_mutex );
302 // Copy cached frame instead of pulling from queue
303 frame = cloneFrame( (mlt_frame) mlt_cache_item_data( cached, NULL ) );
304 mlt_cache_item_close( cached );
308 // Wait if queue is empty
309 pthread_mutex_lock( &m_mutex );
310 while ( mlt_deque_count( m_queue ) < 1 )
312 // Wait up to twice frame duration
313 gettimeofday( &now, NULL );
314 long usec = now.tv_sec * 1000000 + now.tv_usec;
315 usec += 2000000 / fps;
316 tm.tv_sec = usec / 1000000;
317 tm.tv_nsec = (usec % 1000000) * 1000;
318 if ( pthread_cond_timedwait( &m_condition, &m_mutex, &tm ) )
319 // Stop waiting if error (timed out)
322 frame = ( mlt_frame ) mlt_deque_pop_front( m_queue );
323 pthread_mutex_unlock( &m_mutex );
327 mlt_cache_put( m_cache, (void*) position, cloneFrame( frame ), 0,
328 (mlt_destructor) mlt_frame_close );
331 // Set frame timestamp and properties
334 mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) );
335 mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
336 mlt_properties_set_int( properties, "progressive", profile->progressive );
337 mlt_properties_set_int( properties, "meta.media.progressive", profile->progressive );
338 mlt_properties_set_int( properties, "top_field_first", m_topFieldFirst );
339 mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile ) );
340 mlt_properties_set_int( properties, "meta.media.sample_aspect_num", profile->sample_aspect_num );
341 mlt_properties_set_int( properties, "meta.media.sample_aspect_den", profile->sample_aspect_den );
342 mlt_properties_set_int( properties, "meta.media.frame_rate_num", profile->frame_rate_num );
343 mlt_properties_set_int( properties, "meta.media.frame_rate_den", profile->frame_rate_den );
344 mlt_properties_set_int( properties, "width", profile->width );
345 mlt_properties_set_int( properties, "real_width", profile->width );
346 mlt_properties_set_int( properties, "meta.media.width", profile->width );
347 mlt_properties_set_int( properties, "height", profile->height );
348 mlt_properties_set_int( properties, "real_height", profile->height );
349 mlt_properties_set_int( properties, "meta.media.height", profile->height );
350 mlt_properties_set_int( properties, "format", mlt_image_yuv422 );
351 mlt_properties_set_int( properties, "colorspace", m_colorspace );
352 mlt_properties_set_int( properties, "meta.media.colorspace", m_colorspace );
353 mlt_properties_set_int( properties, "audio_frequency", 48000 );
354 mlt_properties_set_int( properties, "audio_channels",
355 mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" ) );
358 mlt_log_warning( getProducer(), "buffer underrun\n" );
363 // *** DeckLink API implementation of IDeckLinkInputCallback *** //
365 // IUnknown needs only a dummy implementation
366 virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID iid, LPVOID *ppv )
367 { return E_NOINTERFACE; }
368 virtual ULONG STDMETHODCALLTYPE AddRef()
370 virtual ULONG STDMETHODCALLTYPE Release()
373 /************************* DeckLink API Delegate Methods *****************************/
375 virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(
376 IDeckLinkVideoInputFrame* video,
377 IDeckLinkAudioInputPacket* audio )
380 mlt_frame frame = mlt_frame_init( MLT_PRODUCER_SERVICE( getProducer() ) );
385 if ( !( video->GetFlags() & bmdFrameHasNoInputSource ) )
387 int size = video->GetRowBytes() * ( video->GetHeight() + m_vancLines );
388 void* image = mlt_pool_alloc( size );
390 unsigned char* p = (unsigned char*) image;
393 // Initialize VANC lines to nominal black
401 if ( m_vancLines > 0 )
403 IDeckLinkVideoFrameAncillary* vanc = 0;
404 if ( video->GetAncillaryData( &vanc ) == S_OK && vanc )
406 for ( int i = 1; i < m_vancLines + 1; i++ )
408 if ( vanc->GetBufferForVerticalBlankingLine( i, &buffer ) == S_OK )
409 swab( (char*) buffer, (char*) image + ( i - 1 ) * video->GetRowBytes(), video->GetRowBytes() );
411 mlt_log_debug( getProducer(), "failed capture vanc line %d\n", i );
418 video->GetBytes( &buffer );
419 if ( image && buffer )
421 size = video->GetRowBytes() * video->GetHeight();
422 swab( (char*) buffer, (char*) image + m_vancLines * video->GetRowBytes(), size );
423 mlt_frame_set_image( frame, (uint8_t*) image, size, mlt_pool_release );
427 mlt_log_verbose( getProducer(), "no video\n" );
428 mlt_pool_release( image );
433 mlt_log_verbose( getProducer(), "no signal\n" );
434 mlt_frame_close( frame );
439 IDeckLinkTimecode* timecode = 0;
440 if ( video->GetTimecode( bmdTimecodeVITC, &timecode ) == S_OK && timecode )
442 const char* timecodeString = 0;
445 if ( timecode->GetString( (BSTR*) &timecodeString ) == S_OK )
447 if ( timecode->GetString( &timecodeString ) == S_OK )
450 mlt_properties_set( MLT_FRAME_PROPERTIES( frame ), "meta.attr.vitc.markup", timecodeString );
451 mlt_log_debug( getProducer(), "timecode %s\n", timecodeString );
453 if ( timecodeString )
454 free( (void*) timecodeString );
460 mlt_log_verbose( getProducer(), "no video\n" );
461 mlt_frame_close( frame );
466 if ( frame && audio )
468 int channels = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" );
469 int size = audio->GetSampleFrameCount() * channels * sizeof(int16_t);
470 mlt_audio_format format = mlt_audio_s16;
471 void* pcm = mlt_pool_alloc( size );
474 audio->GetBytes( &buffer );
477 memcpy( pcm, buffer, size );
478 mlt_frame_set_audio( frame, pcm, format, size, mlt_pool_release );
479 mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "audio_samples", audio->GetSampleFrameCount() );
483 mlt_log_verbose( getProducer(), "no audio\n" );
484 mlt_pool_release( pcm );
489 mlt_log_verbose( getProducer(), "no audio\n" );
492 // Put frame in queue
495 int queueMax = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "buffer" );
496 pthread_mutex_lock( &m_mutex );
497 if ( mlt_deque_count( m_queue ) < queueMax )
499 mlt_deque_push_back( m_queue, frame );
500 pthread_cond_broadcast( &m_condition );
504 mlt_frame_close( frame );
505 mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "dropped", ++m_dropped );
506 mlt_log_warning( getProducer(), "frame dropped %d\n", m_dropped );
508 pthread_mutex_unlock( &m_mutex );
514 virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(
515 BMDVideoInputFormatChangedEvents events,
516 IDeckLinkDisplayMode* mode,
517 BMDDetectedVideoInputFormatFlags flags )
519 mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) );
520 if ( events & bmdVideoInputDisplayModeChanged )
522 BMDTimeValue duration;
523 BMDTimeScale timescale;
524 mode->GetFrameRate( &duration, ×cale );
525 profile->width = mode->GetWidth();
526 profile->height = mode->GetHeight() + m_vancLines;
527 profile->frame_rate_num = timescale;
528 profile->frame_rate_den = duration;
529 if ( profile->width == 720 )
531 if ( profile->height == 576 )
533 profile->sample_aspect_num = 16;
534 profile->sample_aspect_den = 15;
538 profile->sample_aspect_num = 8;
539 profile->sample_aspect_den = 9;
541 profile->display_aspect_num = 4;
542 profile->display_aspect_den = 3;
546 profile->sample_aspect_num = 1;
547 profile->sample_aspect_den = 1;
548 profile->display_aspect_num = 16;
549 profile->display_aspect_den = 9;
551 free( profile->description );
552 profile->description = strdup( "decklink" );
553 mlt_log_verbose( getProducer(), "format changed %dx%d %.3f fps\n",
554 profile->width, profile->height, (double) profile->frame_rate_num / profile->frame_rate_den );
556 if ( events & bmdVideoInputFieldDominanceChanged )
558 profile->progressive = mode->GetFieldDominance() == bmdProgressiveFrame;
559 m_topFieldFirst = mode->GetFieldDominance() == bmdUpperFieldFirst;
560 mlt_log_verbose( getProducer(), "field dominance changed prog %d tff %d\n",
561 profile->progressive, m_topFieldFirst );
563 if ( events & bmdVideoInputColorspaceChanged )
565 profile->colorspace = m_colorspace =
566 ( mode->GetFlags() & bmdDisplayModeColorspaceRec709 ) ? 709 : 601;
567 mlt_log_verbose( getProducer(), "colorspace changed %d\n", profile->colorspace );
573 static int get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
575 return mlt_frame_get_audio( frame, (void**) buffer, format, frequency, channels, samples );
578 static int get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
580 return mlt_frame_get_image( frame, buffer, format, width, height, writable );
583 static int get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
585 DeckLinkProducer* decklink = (DeckLinkProducer*) producer->child;
586 mlt_position pos = mlt_producer_position( producer );
587 mlt_position end = mlt_producer_get_playtime( producer );
588 end = ( mlt_producer_get_length( producer ) < end ? mlt_producer_get_length( producer ) : end ) - 1;
591 if ( !decklink && pos < end )
593 producer->child = decklink = new DeckLinkProducer();
594 decklink->setProducer( producer );
595 decklink->open( mlt_properties_get_int( MLT_PRODUCER_PROPERTIES(producer), "resource" ) );
601 decklink->start( mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ) );
603 // Get the next frame from the decklink object
604 if ( ( *frame = decklink->getFrame() ))
606 // Add audio and video getters
607 mlt_frame_push_audio( *frame, (void*) get_audio );
608 mlt_frame_push_get_image( *frame, get_image );
612 *frame = mlt_frame_init( MLT_PRODUCER_SERVICE(producer) );
614 // Calculate the next timecode
615 mlt_frame_set_position( *frame, mlt_producer_position( producer ) );
616 mlt_producer_prepare_next( producer );
618 // Close DeckLink if at end
619 if ( pos >= end && decklink )
623 producer->child = NULL;
629 static void producer_close( mlt_producer producer )
631 delete (DeckLinkProducer*) producer->child;
632 producer->close = NULL;
633 mlt_producer_close( producer );
638 /** Initialise the producer.
641 mlt_producer producer_decklink_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
643 // Allocate the producer
644 DeckLinkProducer* decklink = new DeckLinkProducer();
645 mlt_producer producer = (mlt_producer) calloc( 1, sizeof( *producer ) );
647 // If allocated and initializes
648 if ( decklink && !mlt_producer_init( producer, decklink ) )
650 if ( decklink->open( arg? atoi( arg ) : 0 ) )
652 mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );
654 // Close DeckLink and defer re-open to get_frame
656 producer->child = NULL;
659 producer->close = (mlt_destructor) producer_close;
660 producer->get_frame = get_frame;
663 mlt_properties_set( properties, "resource", (arg && strcmp( arg, ""))? arg : "0" );
664 mlt_properties_set_int( properties, "channels", 2 );
665 mlt_properties_set_int( properties, "buffer", 25 );
666 mlt_properties_set_int( properties, "prefill", 25 );
668 // These properties effectively make it infinite.
669 mlt_properties_set_int( properties, "length", INT_MAX );
670 mlt_properties_set_int( properties, "out", INT_MAX - 1 );
671 mlt_properties_set( properties, "eof", "loop" );