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