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