]> git.sesse.net Git - mlt/blob - src/modules/decklink/producer_decklink.cpp
Fix memory leak in decklink producer.
[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
39         BMDDisplayMode getDisplayMode( mlt_profile profile )
40         {
41                 IDeckLinkDisplayModeIterator* iter;
42                 IDeckLinkDisplayMode* mode;
43                 BMDDisplayMode result = bmdDisplayModeNotSupported;
44
45                 if ( m_decklinkInput->GetDisplayModeIterator( &iter ) == S_OK )
46                 {
47                         while ( !result && iter->Next( &mode ) == S_OK )
48                         {
49                                 int width = mode->GetWidth();
50                                 int height = mode->GetHeight();
51                                 BMDTimeValue duration;
52                                 BMDTimeScale timescale;
53                                 mode->GetFrameRate( &duration, &timescale );
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 );
57
58                                 if ( width == profile->width && height == profile->height && p == profile->progressive
59                                          && fps == mlt_profile_fps( profile ) )
60                                         result = mode->GetDisplayMode();
61                         }
62                 }
63
64                 return result;
65         }
66
67 public:
68
69         mlt_producer getProducer()
70                 { return &m_producer; }
71
72         ~DeckLinkProducer()
73         {
74                 if ( m_decklinkInput )
75                         m_decklinkInput->Release();
76                 if ( m_decklink )
77                         m_decklink->Release();
78                 if ( m_queue )
79                 {
80                         stop();
81                         mlt_deque_close( m_queue );
82                         pthread_mutex_destroy( &m_mutex );
83                         pthread_cond_destroy( &m_condition );
84                 }
85         }
86
87         bool open( mlt_profile profile, unsigned card =  0 )
88         {
89                 IDeckLinkIterator* decklinkIterator = CreateDeckLinkIteratorInstance();
90                 try
91                 {
92                         if ( !decklinkIterator )
93                                 throw "The DeckLink drivers are not installed.";
94
95                         // Connect to the Nth DeckLink instance
96                         unsigned i = 0;
97                         do {
98                                 if ( decklinkIterator->Next( &m_decklink ) != S_OK )
99                                         throw "DeckLink card not found.";
100                         } while ( ++i <= card );
101                         decklinkIterator->Release();
102
103                         // Get the input interface
104                         if ( m_decklink->QueryInterface( IID_IDeckLinkInput, (void**) &m_decklinkInput ) != S_OK )
105                                 throw "No DeckLink cards support input.";
106
107                         // Provide this class as a delegate to the input callback
108                         m_decklinkInput->SetCallback( this );
109
110                         // Initialize other members
111                         pthread_mutex_init( &m_mutex, NULL );
112                         pthread_cond_init( &m_condition, NULL );
113                         m_queue = mlt_deque_init();
114                         m_started = false;
115                 }
116                 catch ( const char *error )
117                 {
118                         if ( decklinkIterator )
119                                 decklinkIterator->Release();
120                         mlt_log_error( getProducer(), "%s\n", error );
121                         return false;
122                 }
123                 return true;
124         }
125
126         bool start( mlt_profile profile = 0 )
127         {
128                 if ( m_started )
129                         return false;
130                 try
131                 {
132                         if ( !profile )
133                                 profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) );
134
135                         // Get the display mode
136                         BMDDisplayMode displayMode = getDisplayMode( profile );
137                         if ( displayMode == bmdDisplayModeNotSupported )
138                                 throw "Profile is not compatible with decklink.";
139
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.";
145
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.";
152
153                         // Start capture
154                         m_started = m_decklinkInput->StartStreams() == S_OK;
155                         if ( !m_started )
156                                 throw "Failed to start capture.";
157                 }
158                 catch ( const char *error )
159                 {
160                         m_decklinkInput->DisableVideoInput();
161                         mlt_log_error( getProducer(), "%s\n", error );
162                         return false;
163                 }
164                 return true;
165         }
166
167         void stop()
168         {
169                 if ( m_started )
170                         return;
171
172                 // Release the wait in getFrame
173                 pthread_mutex_lock( &m_mutex );
174                 pthread_cond_broadcast( &m_condition );
175                 pthread_mutex_unlock( &m_mutex );
176
177                 m_decklinkInput->StopStreams();
178
179                 // Cleanup queue
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 );
184
185                 m_started = false;
186         }
187
188         mlt_frame getFrame()
189         {
190                 mlt_frame frame = NULL;
191
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 );
196
197                 // Get the first frame from the queue
198                 frame = ( mlt_frame ) mlt_deque_pop_front( m_queue );
199                 pthread_mutex_unlock( &m_mutex );
200
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" ) );
214
215                 return frame;
216         }
217
218         // *** DeckLink API implementation of IDeckLinkInputCallback *** //
219
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()
224                 { return 1; }
225         virtual ULONG STDMETHODCALLTYPE Release()
226                 { return 1; }
227
228         /************************* DeckLink API Delegate Methods *****************************/
229
230         virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(
231                         IDeckLinkVideoInputFrame* video,
232                         IDeckLinkAudioInputPacket* audio )
233         {
234                 // Create mlt_frame
235                 mlt_frame frame = mlt_frame_init( MLT_PRODUCER_SERVICE( getProducer() ) );
236
237                 // Copy video
238                 if ( video )
239                 {
240                         if ( !( video->GetFlags() & bmdFrameHasNoInputSource ) )
241                         {
242                                 int size = video->GetRowBytes() * video->GetHeight();
243                                 void* image = mlt_pool_alloc( size );
244                                 void* buffer = 0;
245
246                                 video->GetBytes( &buffer );
247                                 if ( image && buffer )
248                                 {
249                                         swab( buffer, image, size );
250                                         mlt_frame_set_image( frame, (uint8_t*) image, size, mlt_pool_release );
251                                 }
252                                 else if ( image )
253                                 {
254                                         mlt_log_verbose( getProducer(), "no video\n" );
255                                         mlt_pool_release( image );
256                                 }
257                         }
258                         else
259                         {
260                                 mlt_log_verbose( getProducer(), "no signal\n" );
261                                 mlt_frame_close( frame );
262                                 frame = 0;
263                         }
264                 }
265                 else
266                 {
267                         mlt_log_verbose( getProducer(), "no video\n" );
268                         mlt_frame_close( frame );
269                         frame = 0;
270                 }
271
272                 // Copy audio
273                 if ( frame && audio )
274                 {
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 );
279                         void* buffer = 0;
280
281                         audio->GetBytes( &buffer );
282                         if ( buffer )
283                         {
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() );
287                         }
288                         else
289                         {
290                                 mlt_log_verbose( getProducer(), "no audio\n" );
291                                 mlt_pool_release( pcm );
292                         }
293                 }
294                 else
295                 {
296                         mlt_log_verbose( getProducer(), "no audio\n" );
297                 }
298
299                 // Put frame in queue
300                 if ( frame )
301                 {
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 )
305                         {
306                                 mlt_deque_push_back( m_queue, frame );
307                                 pthread_cond_broadcast( &m_condition );
308                         }
309                         else
310                                 mlt_frame_close( frame );
311                         pthread_mutex_unlock( &m_mutex );
312                 }
313
314                 return S_OK;
315         }
316
317         virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(
318                         BMDVideoInputFormatChangedEvents events,
319                         IDeckLinkDisplayMode* mode,
320                         BMDDetectedVideoInputFormatFlags flags )
321         {
322                 return S_OK;
323         }
324 };
325
326 static int get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
327 {
328         return mlt_frame_get_audio( frame, (void**) buffer, format, frequency, channels, samples );
329 }
330
331 static int get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
332 {
333         return mlt_frame_get_image( frame, buffer, format, width, height, writable );
334 }
335
336 static int get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
337 {
338         DeckLinkProducer* decklink = (DeckLinkProducer*) producer->child;
339
340         // Get the next frame from the decklink object
341         *frame = decklink->getFrame();
342
343         // Calculate the next timecode
344         mlt_frame_set_position( *frame, mlt_producer_position( producer ) );
345         mlt_producer_prepare_next( producer );
346
347         // Add audio and video getters
348         mlt_frame_push_audio( *frame, (void*) get_audio );
349         mlt_frame_push_get_image( *frame, get_image );
350
351         return 0;
352 }
353
354 static void producer_close( mlt_producer producer )
355 {
356         producer->close = NULL;
357         mlt_producer_close( producer );
358         delete (DeckLinkProducer*) producer->child;
359 }
360
361 extern "C" {
362
363 /** Initialise the producer.
364  */
365
366 mlt_producer producer_decklink_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
367 {
368         // Allocate the producer
369         DeckLinkProducer* decklink = new DeckLinkProducer();
370         mlt_producer producer = NULL;
371
372         // If allocated and initializes
373         if ( decklink && !mlt_producer_init( decklink->getProducer(), decklink ) )
374         {
375                 if ( decklink->open( profile, arg? atoi( arg ) : 0 ) )
376                 {
377                         producer = decklink->getProducer();
378
379                         // Set callbacks
380                         producer->close = (mlt_destructor) producer_close;
381                         producer->get_frame = get_frame;
382
383                         // Set properties
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 );
387
388                         // Start immediately
389                         if ( !decklink->start( profile ) )
390                         {
391                                 producer_close( producer );
392                                 producer = NULL;
393                         }
394                 }
395         }
396
397         return producer;
398 }
399
400 }