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>
25 #include "DeckLinkAPI.h"
27 class DeckLinkProducer
28 : public IDeckLinkInputCallback
31 mlt_producer_s m_producer;
32 IDeckLink* m_decklink;
33 IDeckLinkInput* m_decklinkInput;
35 pthread_mutex_t m_mutex;
36 pthread_cond_t m_condition;
39 BMDDisplayMode getDisplayMode( mlt_profile profile )
41 IDeckLinkDisplayModeIterator* iter;
42 IDeckLinkDisplayMode* mode;
43 BMDDisplayMode result = bmdDisplayModeNotSupported;
45 if ( m_decklinkInput->GetDisplayModeIterator( &iter ) == S_OK )
47 while ( !result && iter->Next( &mode ) == S_OK )
49 int width = mode->GetWidth();
50 int height = mode->GetHeight();
51 BMDTimeValue duration;
52 BMDTimeScale timescale;
53 mode->GetFrameRate( &duration, ×cale );
54 double fps = (double) timescale / duration;
55 int p = mode->GetFieldDominance() == bmdProgressiveFrame;
56 mlt_log_verbose( getProducer(), "BMD mode %dx%d %.3f fps prog %d\n", width, height, fps, p );
58 if ( width == profile->width && height == profile->height && p == profile->progressive
59 && fps == mlt_profile_fps( profile ) )
60 result = mode->GetDisplayMode();
69 mlt_producer getProducer()
70 { return &m_producer; }
74 if ( m_decklinkInput )
75 m_decklinkInput->Release();
77 m_decklink->Release();
81 mlt_deque_close( m_queue );
82 pthread_mutex_destroy( &m_mutex );
83 pthread_cond_destroy( &m_condition );
87 bool open( mlt_profile profile, unsigned card = 0 )
89 IDeckLinkIterator* decklinkIterator = CreateDeckLinkIteratorInstance();
92 if ( !decklinkIterator )
93 throw "The DeckLink drivers are not installed.";
95 // Connect to the Nth DeckLink instance
98 if ( decklinkIterator->Next( &m_decklink ) != S_OK )
99 throw "DeckLink card not found.";
100 } while ( ++i <= card );
101 decklinkIterator->Release();
103 // Get the input interface
104 if ( m_decklink->QueryInterface( IID_IDeckLinkInput, (void**) &m_decklinkInput ) != S_OK )
105 throw "No DeckLink cards support input.";
107 // Provide this class as a delegate to the input callback
108 m_decklinkInput->SetCallback( this );
110 // Initialize other members
111 pthread_mutex_init( &m_mutex, NULL );
112 pthread_cond_init( &m_condition, NULL );
113 m_queue = mlt_deque_init();
116 catch ( const char *error )
118 if ( decklinkIterator )
119 decklinkIterator->Release();
120 mlt_log_error( getProducer(), "%s\n", error );
126 bool start( mlt_profile profile = 0 )
133 profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) );
135 // Get the display mode
136 BMDDisplayMode displayMode = getDisplayMode( profile );
137 if ( displayMode == bmdDisplayModeNotSupported )
138 throw "Profile is not compatible with decklink.";
140 // Enable video capture
141 BMDPixelFormat pixelFormat = bmdFormat8BitYUV;
142 BMDVideoInputFlags flags = bmdVideoInputFlagDefault;
143 if ( S_OK != m_decklinkInput->EnableVideoInput( displayMode, pixelFormat, flags ) )
144 throw "Failed to enable video capture.";
146 // Enable audio capture
147 BMDAudioSampleRate sampleRate = bmdAudioSampleRate48kHz;
148 BMDAudioSampleType sampleType = bmdAudioSampleType16bitInteger;
149 int channels = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" );
150 if ( S_OK != m_decklinkInput->EnableAudioInput( sampleRate, sampleType, channels ) )
151 throw "Failed to enable audio capture.";
154 m_started = m_decklinkInput->StartStreams() == S_OK;
156 throw "Failed to start capture.";
158 catch ( const char *error )
160 m_decklinkInput->DisableVideoInput();
161 mlt_log_error( getProducer(), "%s\n", error );
172 // Release the wait in getFrame
173 pthread_mutex_lock( &m_mutex );
174 pthread_cond_broadcast( &m_condition );
175 pthread_mutex_unlock( &m_mutex );
177 m_decklinkInput->StopStreams();
180 pthread_mutex_lock( &m_mutex );
181 while ( mlt_frame frame = (mlt_frame) mlt_deque_pop_back( m_queue ) )
182 mlt_frame_close( frame );
183 pthread_mutex_unlock( &m_mutex );
190 mlt_frame frame = NULL;
192 // Wait if queue is empty
193 pthread_mutex_lock( &m_mutex );
194 while ( mlt_deque_count( m_queue ) < 1 )
195 pthread_cond_wait( &m_condition, &m_mutex );
197 // Get the first frame from the queue
198 frame = ( mlt_frame ) mlt_deque_pop_front( m_queue );
199 pthread_mutex_unlock( &m_mutex );
201 // Set frame timestamp and properties
202 mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) );
203 mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
204 mlt_properties_set_int( properties, "progressive", profile->progressive );
205 mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile ) );
206 mlt_properties_set_int( properties, "width", profile->width );
207 mlt_properties_set_int( properties, "real_width", profile->width );
208 mlt_properties_set_int( properties, "height", profile->height );
209 mlt_properties_set_int( properties, "real_height", profile->height );
210 mlt_properties_set_int( properties, "format", mlt_image_yuv422 );
211 mlt_properties_set_int( properties, "audio_frequency", 48000 );
212 mlt_properties_set_int( properties, "audio_channels",
213 mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" ) );
218 // *** DeckLink API implementation of IDeckLinkInputCallback *** //
220 // IUnknown needs only a dummy implementation
221 virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID iid, LPVOID *ppv )
222 { return E_NOINTERFACE; }
223 virtual ULONG STDMETHODCALLTYPE AddRef()
225 virtual ULONG STDMETHODCALLTYPE Release()
228 /************************* DeckLink API Delegate Methods *****************************/
230 virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(
231 IDeckLinkVideoInputFrame* video,
232 IDeckLinkAudioInputPacket* audio )
235 mlt_frame frame = mlt_frame_init( MLT_PRODUCER_SERVICE( getProducer() ) );
240 if ( !( video->GetFlags() & bmdFrameHasNoInputSource ) )
242 int size = video->GetRowBytes() * video->GetHeight();
243 void* image = mlt_pool_alloc( size );
246 video->GetBytes( &buffer );
247 if ( image && buffer )
249 swab( buffer, image, size );
250 mlt_frame_set_image( frame, (uint8_t*) image, size, mlt_pool_release );
254 mlt_log_verbose( getProducer(), "no video\n" );
255 mlt_pool_release( image );
260 mlt_log_verbose( getProducer(), "no signal\n" );
261 mlt_frame_close( frame );
267 mlt_log_verbose( getProducer(), "no video\n" );
268 mlt_frame_close( frame );
273 if ( frame && audio )
275 int channels = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" );
276 int size = audio->GetSampleFrameCount() * channels * sizeof(int16_t);
277 mlt_audio_format format = mlt_audio_s16;
278 void* pcm = mlt_pool_alloc( size );
281 audio->GetBytes( &buffer );
284 memcpy( pcm, buffer, size );
285 mlt_frame_set_audio( frame, pcm, format, size, mlt_pool_release );
286 mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "audio_samples", audio->GetSampleFrameCount() );
290 mlt_log_verbose( getProducer(), "no audio\n" );
291 mlt_pool_release( pcm );
296 mlt_log_verbose( getProducer(), "no audio\n" );
299 // Put frame in queue
302 int queueMax = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "buffer" );
303 pthread_mutex_lock( &m_mutex );
304 if ( mlt_deque_count( m_queue ) < queueMax )
306 mlt_deque_push_back( m_queue, frame );
307 pthread_cond_broadcast( &m_condition );
310 mlt_frame_close( frame );
311 pthread_mutex_unlock( &m_mutex );
317 virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(
318 BMDVideoInputFormatChangedEvents events,
319 IDeckLinkDisplayMode* mode,
320 BMDDetectedVideoInputFormatFlags flags )
326 static int get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
328 return mlt_frame_get_audio( frame, (void**) buffer, format, frequency, channels, samples );
331 static int get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
333 return mlt_frame_get_image( frame, buffer, format, width, height, writable );
336 static int get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
338 DeckLinkProducer* decklink = (DeckLinkProducer*) producer->child;
340 // Get the next frame from the decklink object
341 *frame = decklink->getFrame();
343 // Calculate the next timecode
344 mlt_frame_set_position( *frame, mlt_producer_position( producer ) );
345 mlt_producer_prepare_next( producer );
347 // Add audio and video getters
348 mlt_frame_push_audio( *frame, (void*) get_audio );
349 mlt_frame_push_get_image( *frame, get_image );
354 static void producer_close( mlt_producer producer )
356 producer->close = NULL;
357 mlt_producer_close( producer );
358 delete (DeckLinkProducer*) producer->child;
363 /** Initialise the producer.
366 mlt_producer producer_decklink_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
368 // Allocate the producer
369 DeckLinkProducer* decklink = new DeckLinkProducer();
370 mlt_producer producer = NULL;
372 // If allocated and initializes
373 if ( decklink && !mlt_producer_init( decklink->getProducer(), decklink ) )
375 if ( decklink->open( profile, arg? atoi( arg ) : 0 ) )
377 producer = decklink->getProducer();
380 producer->close = (mlt_destructor) producer_close;
381 producer->get_frame = get_frame;
384 mlt_properties_set( MLT_PRODUCER_PROPERTIES( producer ), "resource", arg );
385 mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( producer ), "channels", 2 );
386 mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( producer ), "buffer", 25 );
389 if ( !decklink->start( profile ) )
391 producer_close( producer );