]> git.sesse.net Git - mlt/blob - src/modules/decklink/producer_decklink.cpp
Merge branch 'master' of dennedy.org:git/mltframework.org/mlt
[mlt] / src / modules / decklink / producer_decklink.cpp
1 /*
2  * producer_decklink.c -- input from Blackmagic Design DeckLink
3  * Copyright (C) 2011 Dan Dennedy <dan@dennedy.org>
4  *
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.
9  *
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.
14  *
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
18  */
19
20 #include <framework/mlt.h>
21 #include <stdlib.h>
22 #include <pthread.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include "DeckLinkAPI.h"
26
27 class DeckLinkProducer
28         : public IDeckLinkInputCallback
29 {
30 private:
31         mlt_producer_s   m_producer;
32         IDeckLink*       m_decklink;
33         IDeckLinkInput*  m_decklinkInput;
34         mlt_deque        m_queue;
35         pthread_mutex_t  m_mutex;
36         pthread_cond_t   m_condition;
37         bool             m_started;
38         int              m_dropped;
39
40         BMDDisplayMode getDisplayMode( mlt_profile profile )
41         {
42                 IDeckLinkDisplayModeIterator* iter;
43                 IDeckLinkDisplayMode* mode;
44                 BMDDisplayMode result = bmdDisplayModeNotSupported;
45
46                 if ( m_decklinkInput->GetDisplayModeIterator( &iter ) == S_OK )
47                 {
48                         while ( !result && iter->Next( &mode ) == S_OK )
49                         {
50                                 int width = mode->GetWidth();
51                                 int height = mode->GetHeight();
52                                 BMDTimeValue duration;
53                                 BMDTimeScale timescale;
54                                 mode->GetFrameRate( &duration, &timescale );
55                                 double fps = (double) timescale / duration;
56                                 int p = mode->GetFieldDominance() == bmdProgressiveFrame;
57                                 mlt_log_verbose( getProducer(), "BMD mode %dx%d %.3f fps prog %d\n", width, height, fps, p );
58
59                                 if ( width == profile->width && height == profile->height && p == profile->progressive
60                                          && fps == mlt_profile_fps( profile ) )
61                                         result = mode->GetDisplayMode();
62                         }
63                 }
64
65                 return result;
66         }
67
68 public:
69
70         mlt_producer getProducer()
71                 { return &m_producer; }
72
73         ~DeckLinkProducer()
74         {
75                 if ( m_decklinkInput )
76                         m_decklinkInput->Release();
77                 if ( m_decklink )
78                         m_decklink->Release();
79                 if ( m_queue )
80                 {
81                         stop();
82                         mlt_deque_close( m_queue );
83                         pthread_mutex_destroy( &m_mutex );
84                         pthread_cond_destroy( &m_condition );
85                 }
86         }
87
88         bool open( mlt_profile profile, unsigned card =  0 )
89         {
90                 IDeckLinkIterator* decklinkIterator = CreateDeckLinkIteratorInstance();
91                 try
92                 {
93                         if ( !decklinkIterator )
94                                 throw "The DeckLink drivers are not installed.";
95
96                         // Connect to the Nth DeckLink instance
97                         unsigned i = 0;
98                         do {
99                                 if ( decklinkIterator->Next( &m_decklink ) != S_OK )
100                                         throw "DeckLink card not found.";
101                         } while ( ++i <= card );
102                         decklinkIterator->Release();
103
104                         // Get the input interface
105                         if ( m_decklink->QueryInterface( IID_IDeckLinkInput, (void**) &m_decklinkInput ) != S_OK )
106                                 throw "No DeckLink cards support input.";
107
108                         // Provide this class as a delegate to the input callback
109                         m_decklinkInput->SetCallback( this );
110
111                         // Initialize other members
112                         pthread_mutex_init( &m_mutex, NULL );
113                         pthread_cond_init( &m_condition, NULL );
114                         m_queue = mlt_deque_init();
115                         m_started = false;
116                         m_dropped = 0;
117                 }
118                 catch ( const char *error )
119                 {
120                         if ( decklinkIterator )
121                                 decklinkIterator->Release();
122                         mlt_log_error( getProducer(), "%s\n", error );
123                         return false;
124                 }
125                 return true;
126         }
127
128         bool start( mlt_profile profile = 0 )
129         {
130                 if ( m_started )
131                         return false;
132                 try
133                 {
134                         if ( !profile )
135                                 profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) );
136
137                         // Get the display mode
138                         BMDDisplayMode displayMode = getDisplayMode( profile );
139                         if ( displayMode == bmdDisplayModeNotSupported )
140                                 throw "Profile is not compatible with decklink.";
141
142                         // Enable video capture
143                         BMDPixelFormat pixelFormat = bmdFormat8BitYUV;
144                         BMDVideoInputFlags flags = bmdVideoInputFlagDefault;
145                         if ( S_OK != m_decklinkInput->EnableVideoInput( displayMode, pixelFormat, flags ) )
146                                 throw "Failed to enable video capture.";
147
148                         // Enable audio capture
149                         BMDAudioSampleRate sampleRate = bmdAudioSampleRate48kHz;
150                         BMDAudioSampleType sampleType = bmdAudioSampleType16bitInteger;
151                         int channels = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" );
152                         if ( S_OK != m_decklinkInput->EnableAudioInput( sampleRate, sampleType, channels ) )
153                                 throw "Failed to enable audio capture.";
154
155                         // Start capture
156                         m_dropped = 0;
157                         mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "dropped", m_dropped );
158                         m_started = m_decklinkInput->StartStreams() == S_OK;
159                         if ( !m_started )
160                                 throw "Failed to start capture.";
161                 }
162                 catch ( const char *error )
163                 {
164                         m_decklinkInput->DisableVideoInput();
165                         mlt_log_error( getProducer(), "%s\n", error );
166                         return false;
167                 }
168                 return true;
169         }
170
171         void stop()
172         {
173                 if ( m_started )
174                         return;
175
176                 // Release the wait in getFrame
177                 pthread_mutex_lock( &m_mutex );
178                 pthread_cond_broadcast( &m_condition );
179                 pthread_mutex_unlock( &m_mutex );
180
181                 m_decklinkInput->StopStreams();
182
183                 // Cleanup queue
184                 pthread_mutex_lock( &m_mutex );
185                 while ( mlt_frame frame = (mlt_frame) mlt_deque_pop_back( m_queue ) )
186                         mlt_frame_close( frame );
187                 pthread_mutex_unlock( &m_mutex );
188
189                 m_started = false;
190         }
191
192         mlt_frame getFrame()
193         {
194                 mlt_frame frame = NULL;
195
196                 // Wait if queue is empty
197                 pthread_mutex_lock( &m_mutex );
198                 while ( mlt_deque_count( m_queue ) < 1 )
199                         pthread_cond_wait( &m_condition, &m_mutex );
200
201                 // Get the first frame from the queue
202                 frame = ( mlt_frame ) mlt_deque_pop_front( m_queue );
203                 pthread_mutex_unlock( &m_mutex );
204
205                 // Set frame timestamp and properties
206                 mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) );
207                 mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
208                 mlt_properties_set_int( properties, "progressive", profile->progressive );
209                 mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile ) );
210                 mlt_properties_set_int( properties, "width", profile->width );
211                 mlt_properties_set_int( properties, "real_width", profile->width );
212                 mlt_properties_set_int( properties, "height", profile->height );
213                 mlt_properties_set_int( properties, "real_height", profile->height );
214                 mlt_properties_set_int( properties, "format", mlt_image_yuv422 );
215                 mlt_properties_set_int( properties, "audio_frequency", 48000 );
216                 mlt_properties_set_int( properties, "audio_channels",
217                         mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" ) );
218
219                 return frame;
220         }
221
222         // *** DeckLink API implementation of IDeckLinkInputCallback *** //
223
224         // IUnknown needs only a dummy implementation
225         virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID iid, LPVOID *ppv )
226                 { return E_NOINTERFACE; }
227         virtual ULONG STDMETHODCALLTYPE AddRef()
228                 { return 1; }
229         virtual ULONG STDMETHODCALLTYPE Release()
230                 { return 1; }
231
232         /************************* DeckLink API Delegate Methods *****************************/
233
234         virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(
235                         IDeckLinkVideoInputFrame* video,
236                         IDeckLinkAudioInputPacket* audio )
237         {
238                 // Create mlt_frame
239                 mlt_frame frame = mlt_frame_init( MLT_PRODUCER_SERVICE( getProducer() ) );
240
241                 // Copy video
242                 if ( video )
243                 {
244                         if ( !( video->GetFlags() & bmdFrameHasNoInputSource ) )
245                         {
246                                 int size = video->GetRowBytes() * video->GetHeight();
247                                 void* image = mlt_pool_alloc( size );
248                                 void* buffer = 0;
249
250                                 video->GetBytes( &buffer );
251                                 if ( image && buffer )
252                                 {
253                                         swab( buffer, image, size );
254                                         mlt_frame_set_image( frame, (uint8_t*) image, size, mlt_pool_release );
255                                 }
256                                 else if ( image )
257                                 {
258                                         mlt_log_verbose( getProducer(), "no video\n" );
259                                         mlt_pool_release( image );
260                                 }
261                         }
262                         else
263                         {
264                                 mlt_log_verbose( getProducer(), "no signal\n" );
265                                 mlt_frame_close( frame );
266                                 frame = 0;
267                         }
268                 }
269                 else
270                 {
271                         mlt_log_verbose( getProducer(), "no video\n" );
272                         mlt_frame_close( frame );
273                         frame = 0;
274                 }
275
276                 // Copy audio
277                 if ( frame && audio )
278                 {
279                         int channels = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" );
280                         int size = audio->GetSampleFrameCount() * channels * sizeof(int16_t);
281                         mlt_audio_format format = mlt_audio_s16;
282                         void* pcm = mlt_pool_alloc( size );
283                         void* buffer = 0;
284
285                         audio->GetBytes( &buffer );
286                         if ( buffer )
287                         {
288                                 memcpy( pcm, buffer, size );
289                                 mlt_frame_set_audio( frame, pcm, format, size, mlt_pool_release );
290                                 mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "audio_samples", audio->GetSampleFrameCount() );
291                         }
292                         else
293                         {
294                                 mlt_log_verbose( getProducer(), "no audio\n" );
295                                 mlt_pool_release( pcm );
296                         }
297                 }
298                 else
299                 {
300                         mlt_log_verbose( getProducer(), "no audio\n" );
301                 }
302
303                 // Put frame in queue
304                 if ( frame )
305                 {
306                         int queueMax = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "buffer" );
307                         pthread_mutex_lock( &m_mutex );
308                         if ( mlt_deque_count( m_queue ) < queueMax )
309                         {
310                                 mlt_deque_push_back( m_queue, frame );
311                                 pthread_cond_broadcast( &m_condition );
312                         }
313                         else
314                         {
315                                 mlt_frame_close( frame );
316                                 mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "dropped", ++m_dropped );
317                                 mlt_log_warning( getProducer(), "frame dropped %d\n", m_dropped );
318                         }
319                         pthread_mutex_unlock( &m_mutex );
320                 }
321
322                 return S_OK;
323         }
324
325         virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(
326                         BMDVideoInputFormatChangedEvents events,
327                         IDeckLinkDisplayMode* mode,
328                         BMDDetectedVideoInputFormatFlags flags )
329         {
330                 return S_OK;
331         }
332 };
333
334 static int get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
335 {
336         return mlt_frame_get_audio( frame, (void**) buffer, format, frequency, channels, samples );
337 }
338
339 static int get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
340 {
341         return mlt_frame_get_image( frame, buffer, format, width, height, writable );
342 }
343
344 static int get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
345 {
346         DeckLinkProducer* decklink = (DeckLinkProducer*) producer->child;
347
348         // Get the next frame from the decklink object
349         *frame = decklink->getFrame();
350
351         // Calculate the next timecode
352         mlt_frame_set_position( *frame, mlt_producer_position( producer ) );
353         mlt_producer_prepare_next( producer );
354
355         // Add audio and video getters
356         mlt_frame_push_audio( *frame, (void*) get_audio );
357         mlt_frame_push_get_image( *frame, get_image );
358
359         return 0;
360 }
361
362 static void producer_close( mlt_producer producer )
363 {
364         producer->close = NULL;
365         mlt_producer_close( producer );
366         delete (DeckLinkProducer*) producer->child;
367 }
368
369 extern "C" {
370
371 /** Initialise the producer.
372  */
373
374 mlt_producer producer_decklink_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
375 {
376         // Allocate the producer
377         DeckLinkProducer* decklink = new DeckLinkProducer();
378         mlt_producer producer = NULL;
379
380         // If allocated and initializes
381         if ( decklink && !mlt_producer_init( decklink->getProducer(), decklink ) )
382         {
383                 if ( decklink->open( profile, arg? atoi( arg ) : 0 ) )
384                 {
385                         producer = decklink->getProducer();
386
387                         // Set callbacks
388                         producer->close = (mlt_destructor) producer_close;
389                         producer->get_frame = get_frame;
390
391                         // Set properties
392                         mlt_properties_set( MLT_PRODUCER_PROPERTIES( producer ), "resource", arg );
393                         mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( producer ), "channels", 2 );
394                         mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( producer ), "buffer", 25 );
395
396                         // Start immediately
397                         if ( !decklink->start( profile ) )
398                         {
399                                 producer_close( producer );
400                                 producer = NULL;
401                         }
402                 }
403         }
404
405         return producer;
406 }
407
408 }