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 )
174 mlt_log_info( getProducer(), "profile = %dx%d %f fps %s\n", profile->width, profile->height,
175 mlt_profile_fps( profile ), profile->progressive? "progressive" : "interlace" );
176 throw "Profile is not compatible with decklink.";
179 // Determine if supports input format detection
181 BOOL doesDetectFormat = FALSE;
183 bool doesDetectFormat = false;
185 IDeckLinkAttributes *decklinkAttributes = 0;
186 if ( m_decklink->QueryInterface( IID_IDeckLinkAttributes, (void**) &decklinkAttributes ) == S_OK )
188 if ( decklinkAttributes->GetFlag( BMDDeckLinkSupportsInputFormatDetection, &doesDetectFormat ) != S_OK )
189 doesDetectFormat = false;
190 decklinkAttributes->Release();
192 mlt_log_verbose( getProducer(), "%s format detection\n", doesDetectFormat ? "supports" : "does not support" );
194 // Enable video capture
195 BMDPixelFormat pixelFormat = bmdFormat8BitYUV;
196 BMDVideoInputFlags flags = doesDetectFormat ? bmdVideoInputEnableFormatDetection : bmdVideoInputFlagDefault;
197 if ( S_OK != m_decklinkInput->EnableVideoInput( displayMode, pixelFormat, flags ) )
198 throw "Failed to enable video capture.";
200 // Enable audio capture
201 BMDAudioSampleRate sampleRate = bmdAudioSampleRate48kHz;
202 BMDAudioSampleType sampleType = bmdAudioSampleType16bitInteger;
203 int channels = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" );
204 if ( S_OK != m_decklinkInput->EnableAudioInput( sampleRate, sampleType, channels ) )
205 throw "Failed to enable audio capture.";
209 mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "dropped", m_dropped );
210 m_started = m_decklinkInput->StartStreams() == S_OK;
212 throw "Failed to start capture.";
214 catch ( const char *error )
216 m_decklinkInput->DisableVideoInput();
217 mlt_log_error( getProducer(), "%s\n", error );
229 // Release the wait in getFrame
230 pthread_mutex_lock( &m_mutex );
231 pthread_cond_broadcast( &m_condition );
232 pthread_mutex_unlock( &m_mutex );
234 m_decklinkInput->StopStreams();
237 pthread_mutex_lock( &m_mutex );
238 while ( mlt_frame frame = (mlt_frame) mlt_deque_pop_back( m_queue ) )
239 mlt_frame_close( frame );
240 pthread_mutex_unlock( &m_mutex );
245 mlt_frame frame = NULL;
248 double fps = mlt_producer_get_fps( getProducer() );
250 // Allow the buffer to fill to the requested initial buffer level.
253 int prefill = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "prefill" );
254 int buffer = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "buffer" );
256 m_isBuffering = false;
257 prefill = prefill > buffer ? buffer : prefill;
258 pthread_mutex_lock( &m_mutex );
259 while ( mlt_deque_count( m_queue ) < prefill )
261 // Wait up to buffer/fps seconds
262 gettimeofday( &now, NULL );
263 long usec = now.tv_sec * 1000000 + now.tv_usec;
264 usec += 1000000 * buffer / fps;
265 tm.tv_sec = usec / 1000000;
266 tm.tv_nsec = (usec % 1000000) * 1000;
267 if ( pthread_cond_timedwait( &m_condition, &m_mutex, &tm ) )
270 pthread_mutex_unlock( &m_mutex );
273 // Wait if queue is empty
274 pthread_mutex_lock( &m_mutex );
275 while ( mlt_deque_count( m_queue ) < 1 )
277 // Wait up to twice frame duration
278 gettimeofday( &now, NULL );
279 long usec = now.tv_sec * 1000000 + now.tv_usec;
280 usec += 2000000 / fps;
281 tm.tv_sec = usec / 1000000;
282 tm.tv_nsec = (usec % 1000000) * 1000;
283 if ( pthread_cond_timedwait( &m_condition, &m_mutex, &tm ) )
284 // Stop waiting if error (timed out)
288 // Get the first frame from the queue
289 frame = ( mlt_frame ) mlt_deque_pop_front( m_queue );
290 pthread_mutex_unlock( &m_mutex );
292 // Set frame timestamp and properties
295 mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) );
296 mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
297 mlt_properties_set_int( properties, "progressive", profile->progressive );
298 mlt_properties_set_int( properties, "meta.media.progressive", profile->progressive );
299 mlt_properties_set_int( properties, "top_field_first", m_topFieldFirst );
300 mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile ) );
301 mlt_properties_set_int( properties, "meta.media.sample_aspect_num", profile->sample_aspect_num );
302 mlt_properties_set_int( properties, "meta.media.sample_aspect_den", profile->sample_aspect_den );
303 mlt_properties_set_int( properties, "meta.media.frame_rate_num", profile->frame_rate_num );
304 mlt_properties_set_int( properties, "meta.media.frame_rate_den", profile->frame_rate_den );
305 mlt_properties_set_int( properties, "width", profile->width );
306 mlt_properties_set_int( properties, "real_width", profile->width );
307 mlt_properties_set_int( properties, "meta.media.width", profile->width );
308 mlt_properties_set_int( properties, "height", profile->height );
309 mlt_properties_set_int( properties, "real_height", profile->height );
310 mlt_properties_set_int( properties, "meta.media.height", profile->height );
311 mlt_properties_set_int( properties, "format", mlt_image_yuv422 );
312 mlt_properties_set_int( properties, "colorspace", m_colorspace );
313 mlt_properties_set_int( properties, "meta.media.colorspace", m_colorspace );
314 mlt_properties_set_int( properties, "audio_frequency", 48000 );
315 mlt_properties_set_int( properties, "audio_channels",
316 mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" ) );
321 // *** DeckLink API implementation of IDeckLinkInputCallback *** //
323 // IUnknown needs only a dummy implementation
324 virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID iid, LPVOID *ppv )
325 { return E_NOINTERFACE; }
326 virtual ULONG STDMETHODCALLTYPE AddRef()
328 virtual ULONG STDMETHODCALLTYPE Release()
331 /************************* DeckLink API Delegate Methods *****************************/
333 virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(
334 IDeckLinkVideoInputFrame* video,
335 IDeckLinkAudioInputPacket* audio )
338 mlt_frame frame = mlt_frame_init( MLT_PRODUCER_SERVICE( getProducer() ) );
343 if ( !( video->GetFlags() & bmdFrameHasNoInputSource ) )
345 int size = video->GetRowBytes() * ( video->GetHeight() + m_vancLines );
346 void* image = mlt_pool_alloc( size );
348 unsigned char* p = (unsigned char*) image;
351 // Initialize VANC lines to nominal black
359 if ( m_vancLines > 0 )
361 IDeckLinkVideoFrameAncillary* vanc = 0;
362 if ( video->GetAncillaryData( &vanc ) == S_OK && vanc )
364 for ( int i = 1; i < m_vancLines + 1; i++ )
366 if ( vanc->GetBufferForVerticalBlankingLine( i, &buffer ) == S_OK )
367 swab( (char*) buffer, (char*) image + ( i - 1 ) * video->GetRowBytes(), video->GetRowBytes() );
369 mlt_log_debug( getProducer(), "failed capture vanc line %d\n", i );
376 video->GetBytes( &buffer );
377 if ( image && buffer )
379 size = video->GetRowBytes() * video->GetHeight();
380 swab( (char*) buffer, (char*) image + m_vancLines * video->GetRowBytes(), size );
381 mlt_frame_set_image( frame, (uint8_t*) image, size, mlt_pool_release );
385 mlt_log_verbose( getProducer(), "no video\n" );
386 mlt_pool_release( image );
391 mlt_log_verbose( getProducer(), "no signal\n" );
392 mlt_frame_close( frame );
397 IDeckLinkTimecode* timecode = 0;
398 if ( video->GetTimecode( bmdTimecodeVITC, &timecode ) == S_OK && timecode )
400 const char* timecodeString = 0;
403 if ( timecode->GetString( (BSTR*) &timecodeString ) == S_OK )
405 if ( timecode->GetString( &timecodeString ) == S_OK )
408 mlt_properties_set( MLT_FRAME_PROPERTIES( frame ), "meta.attr.vitc.markup", timecodeString );
409 mlt_log_debug( getProducer(), "timecode %s\n", timecodeString );
411 if ( timecodeString )
412 free( (void*) timecodeString );
418 mlt_log_verbose( getProducer(), "no video\n" );
419 mlt_frame_close( frame );
424 if ( frame && audio )
426 int channels = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" );
427 int size = audio->GetSampleFrameCount() * channels * sizeof(int16_t);
428 mlt_audio_format format = mlt_audio_s16;
429 void* pcm = mlt_pool_alloc( size );
432 audio->GetBytes( &buffer );
435 memcpy( pcm, buffer, size );
436 mlt_frame_set_audio( frame, pcm, format, size, mlt_pool_release );
437 mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "audio_samples", audio->GetSampleFrameCount() );
441 mlt_log_verbose( getProducer(), "no audio\n" );
442 mlt_pool_release( pcm );
447 mlt_log_verbose( getProducer(), "no audio\n" );
450 // Put frame in queue
453 int queueMax = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "buffer" );
454 pthread_mutex_lock( &m_mutex );
455 if ( mlt_deque_count( m_queue ) < queueMax )
457 mlt_deque_push_back( m_queue, frame );
458 pthread_cond_broadcast( &m_condition );
462 mlt_frame_close( frame );
463 mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "dropped", ++m_dropped );
464 mlt_log_warning( getProducer(), "frame dropped %d\n", m_dropped );
466 pthread_mutex_unlock( &m_mutex );
472 virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(
473 BMDVideoInputFormatChangedEvents events,
474 IDeckLinkDisplayMode* mode,
475 BMDDetectedVideoInputFormatFlags flags )
477 mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) );
478 if ( events & bmdVideoInputDisplayModeChanged )
480 BMDTimeValue duration;
481 BMDTimeScale timescale;
482 mode->GetFrameRate( &duration, ×cale );
483 profile->width = mode->GetWidth();
484 profile->height = mode->GetHeight() + m_vancLines;
485 profile->frame_rate_num = timescale;
486 profile->frame_rate_den = duration;
487 if ( profile->width == 720 )
489 if ( profile->height == 576 )
491 profile->sample_aspect_num = 16;
492 profile->sample_aspect_den = 15;
496 profile->sample_aspect_num = 8;
497 profile->sample_aspect_den = 9;
499 profile->display_aspect_num = 4;
500 profile->display_aspect_den = 3;
504 profile->sample_aspect_num = 1;
505 profile->sample_aspect_den = 1;
506 profile->display_aspect_num = 16;
507 profile->display_aspect_den = 9;
509 free( profile->description );
510 profile->description = strdup( "decklink" );
511 mlt_log_verbose( getProducer(), "format changed %dx%d %.3f fps\n",
512 profile->width, profile->height, (double) profile->frame_rate_num / profile->frame_rate_den );
514 if ( events & bmdVideoInputFieldDominanceChanged )
516 profile->progressive = mode->GetFieldDominance() == bmdProgressiveFrame;
517 m_topFieldFirst = mode->GetFieldDominance() == bmdUpperFieldFirst;
518 mlt_log_verbose( getProducer(), "field dominance changed prog %d tff %d\n",
519 profile->progressive, m_topFieldFirst );
521 if ( events & bmdVideoInputColorspaceChanged )
523 profile->colorspace = m_colorspace =
524 ( mode->GetFlags() & bmdDisplayModeColorspaceRec709 ) ? 709 : 601;
525 mlt_log_verbose( getProducer(), "colorspace changed %d\n", profile->colorspace );
531 static int get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
533 return mlt_frame_get_audio( frame, (void**) buffer, format, frequency, channels, samples );
536 static int get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
538 return mlt_frame_get_image( frame, buffer, format, width, height, writable );
541 static int get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
543 DeckLinkProducer* decklink = (DeckLinkProducer*) producer->child;
544 mlt_position pos = mlt_producer_position( producer );
545 mlt_position end = mlt_producer_get_playtime( producer );
546 end = ( mlt_producer_get_length( producer ) < end ? mlt_producer_get_length( producer ) : end ) - 1;
549 if ( !decklink && pos < end )
551 producer->child = decklink = new DeckLinkProducer();
552 decklink->setProducer( producer );
553 decklink->open( mlt_properties_get_int( MLT_PRODUCER_PROPERTIES(producer), "resource" ) );
559 decklink->start( mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ) );
561 // Get the next frame from the decklink object
562 if ( ( *frame = decklink->getFrame() ))
564 // Add audio and video getters
565 mlt_frame_push_audio( *frame, (void*) get_audio );
566 mlt_frame_push_get_image( *frame, get_image );
570 *frame = mlt_frame_init( MLT_PRODUCER_SERVICE(producer) );
572 // Calculate the next timecode
573 mlt_frame_set_position( *frame, mlt_producer_position( producer ) );
574 mlt_producer_prepare_next( producer );
576 // Close DeckLink if at end
577 if ( pos >= end && decklink )
581 producer->child = NULL;
587 static void producer_close( mlt_producer producer )
589 delete (DeckLinkProducer*) producer->child;
590 producer->close = NULL;
591 mlt_producer_close( producer );
596 /** Initialise the producer.
599 mlt_producer producer_decklink_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
601 // Allocate the producer
602 DeckLinkProducer* decklink = new DeckLinkProducer();
603 mlt_producer producer = (mlt_producer) calloc( 1, sizeof( *producer ) );
605 // If allocated and initializes
606 if ( decklink && !mlt_producer_init( producer, decklink ) )
608 if ( decklink->open( arg? atoi( arg ) : 0 ) )
610 mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );
612 // Close DeckLink and defer re-open to get_frame
614 producer->child = NULL;
617 producer->close = (mlt_destructor) producer_close;
618 producer->get_frame = get_frame;
621 mlt_properties_set( properties, "resource", (arg && strcmp( arg, ""))? arg : "0" );
622 mlt_properties_set_int( properties, "channels", 2 );
623 mlt_properties_set_int( properties, "buffer", 25 );
624 mlt_properties_set_int( properties, "prefill", 25 );
626 // These properties effectively make it infinite.
627 mlt_properties_set_int( properties, "length", INT_MAX );
628 mlt_properties_set_int( properties, "out", INT_MAX - 1 );
629 mlt_properties_set( properties, "eof", "loop" );