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