]> git.sesse.net Git - mlt/blob - src/modules/decklink/consumer_decklink.cpp
Avoid float rounding error when calculating audio timestamp.
[mlt] / src / modules / decklink / consumer_decklink.cpp
1 /*
2  * consumer_decklink.c -- output through Blackmagic Design DeckLink
3  * Copyright (C) 2010 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 <string.h>
23 #include <pthread.h>
24 #include <unistd.h>
25 #include <sys/time.h>
26 #include <limits.h>
27 #ifdef WIN32
28 #include <objbase.h>
29 #include "DeckLinkAPI_h.h"
30 #else
31 #include "DeckLinkAPI.h"
32 #endif
33
34 static const unsigned PREROLL_MINIMUM = 3;
35
36 class DeckLinkConsumer
37         : public IDeckLinkVideoOutputCallback
38 {
39 private:
40         mlt_consumer_s              m_consumer;
41         IDeckLink*                  m_deckLink;
42         IDeckLinkOutput*            m_deckLinkOutput;
43         IDeckLinkDisplayMode*       m_displayMode;
44         int                         m_width;
45         int                         m_height;
46         BMDTimeValue                m_duration;
47         BMDTimeScale                m_timescale;
48         double                      m_fps;
49         uint64_t                    m_count;
50         int                         m_channels;
51         unsigned                    m_dropped;
52         IDeckLinkMutableVideoFrame* m_decklinkFrame;
53         bool                        m_isAudio;
54         int                         m_isKeyer;
55         IDeckLinkKeyer*             m_deckLinkKeyer;
56         bool                        m_terminate_on_pause;
57
58         IDeckLinkDisplayMode* getDisplayMode()
59         {
60                 mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( getConsumer() ) );
61                 IDeckLinkDisplayModeIterator* iter;
62                 IDeckLinkDisplayMode* mode;
63                 IDeckLinkDisplayMode* result = 0;
64                 
65                 if ( m_deckLinkOutput->GetDisplayModeIterator( &iter ) == S_OK )
66                 {
67                         while ( !result && iter->Next( &mode ) == S_OK )
68                         {
69                                 m_width = mode->GetWidth();
70                                 m_height = mode->GetHeight();
71                                 mode->GetFrameRate( &m_duration, &m_timescale );
72                                 m_fps = (double) m_timescale / m_duration;
73                                 int p = mode->GetFieldDominance() == bmdProgressiveFrame;
74                                 mlt_log_verbose( getConsumer(), "BMD mode %dx%d %.3f fps prog %d\n", m_width, m_height, m_fps, p );
75                                 
76                                 if ( m_width == profile->width && m_height == profile->height && p == profile->progressive
77                                          && m_fps == mlt_profile_fps( profile ) )
78                                         result = mode;
79                         }
80                 }
81                 
82                 return result;
83         }
84         
85 public:
86         mlt_consumer getConsumer()
87                 { return &m_consumer; }
88         
89         ~DeckLinkConsumer()
90         {
91                 if ( m_deckLinkKeyer )
92                         m_deckLinkKeyer->Release();
93                 if ( m_deckLinkOutput )
94                         m_deckLinkOutput->Release();
95                 if ( m_deckLink )
96                         m_deckLink->Release();
97         }
98         
99         bool open( unsigned card = 0 )
100         {
101                 unsigned i = 0;
102 #ifdef WIN32
103                 IDeckLinkIterator* deckLinkIterator = NULL;
104                 HRESULT result =  CoInitialize( NULL );
105                 if ( FAILED( result ) )
106                 {
107                         mlt_log_error( getConsumer(), "COM initialization failed\n" );
108                         return false;
109                 }
110                 result = CoCreateInstance( CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL, IID_IDeckLinkIterator, (void**) &deckLinkIterator );
111                 if ( FAILED( result ) )
112                 {
113                         mlt_log_error( getConsumer(), "The DeckLink drivers not installed.\n" );
114                         return false;
115                 }
116 #else
117                 IDeckLinkIterator* deckLinkIterator = CreateDeckLinkIteratorInstance();
118                 
119                 if ( !deckLinkIterator )
120                 {
121                         mlt_log_error( getConsumer(), "The DeckLink drivers not installed.\n" );
122                         return false;
123                 }
124 #endif
125                 
126                 // Connect to the Nth DeckLink instance
127                 do {
128                         if ( deckLinkIterator->Next( &m_deckLink ) != S_OK )
129                         {
130                                 mlt_log_error( getConsumer(), "DeckLink card not found\n" );
131                                 deckLinkIterator->Release();
132                                 return false;
133                         }
134                 } while ( ++i <= card );
135                 deckLinkIterator->Release();
136                 
137                 // Obtain the audio/video output interface (IDeckLinkOutput)
138                 if ( m_deckLink->QueryInterface( IID_IDeckLinkOutput, (void**)&m_deckLinkOutput ) != S_OK )
139                 {
140                         mlt_log_error( getConsumer(), "No DeckLink cards support output\n" );
141                         m_deckLink->Release();
142                         m_deckLink = 0;
143                         return false;
144                 }
145                 
146                 // Get the keyer interface
147                 IDeckLinkAttributes *deckLinkAttributes = 0;
148                 m_deckLinkKeyer = 0;
149                 if ( m_deckLink->QueryInterface( IID_IDeckLinkAttributes, (void**) &deckLinkAttributes ) == S_OK )
150                 {
151 #ifdef WIN32
152                         BOOL flag = FALSE;
153 #else
154                         bool flag = false;
155 #endif
156                         if ( deckLinkAttributes->GetFlag( BMDDeckLinkSupportsInternalKeying, &flag ) == S_OK && flag )
157                         {
158                                 if ( m_deckLink->QueryInterface( IID_IDeckLinkKeyer, (void**) &m_deckLinkKeyer ) != S_OK )
159                                 {
160                                         mlt_log_error( getConsumer(), "Failed to get keyer\n" );
161                                         m_deckLinkOutput->Release();
162                                         m_deckLinkOutput = 0;
163                                         m_deckLink->Release();
164                                         m_deckLink = 0;
165                                         return false;
166                                 }
167                         }
168                         deckLinkAttributes->Release();
169                 }
170
171                 // Provide this class as a delegate to the audio and video output interfaces
172                 m_deckLinkOutput->SetScheduledFrameCompletionCallback( this );
173                 
174                 return true;
175         }
176         
177         bool start( unsigned preroll )
178         {
179                 unsigned i;
180                 mlt_properties properties = MLT_CONSUMER_PROPERTIES( getConsumer() );
181
182                 // Initialize members
183                 m_count = 0;
184                 m_dropped = 0;
185                 m_decklinkFrame = NULL;
186                 preroll = preroll < PREROLL_MINIMUM ? PREROLL_MINIMUM : preroll;
187                 m_channels = mlt_properties_get_int( properties, "channels" );
188                 m_isAudio = !mlt_properties_get_int( properties, "audio_off" );
189                 m_terminate_on_pause = mlt_properties_get_int( properties, "terminate_on_pause" );
190
191
192                 m_displayMode = getDisplayMode();
193                 if ( !m_displayMode )
194                 {
195                         mlt_log_error( getConsumer(), "Profile is not compatible with decklink.\n" );
196                         return false;
197                 }
198                 
199                 // Set the keyer
200                 if ( m_deckLinkKeyer && ( m_isKeyer = mlt_properties_get_int( properties, "keyer" ) ) )
201                 {
202                         bool external = (m_isKeyer == 2);
203                         double level = mlt_properties_get_double( properties, "keyer_level" );
204
205                         if ( m_deckLinkKeyer->Enable( external ) != S_OK )
206                                 mlt_log_error( getConsumer(), "Failed to enable %s keyer\n",
207                                         external ? "external" : "internal" );
208                         m_deckLinkKeyer->SetLevel( level <= 1 ? ( level > 0 ? 255 * level : 255 ) : 255 );
209                 }
210                 else if ( m_deckLinkKeyer )
211                 {
212                         m_deckLinkKeyer->Disable();
213                 }
214
215                 // Set the video output mode
216                 if ( S_OK != m_deckLinkOutput->EnableVideoOutput( m_displayMode->GetDisplayMode(), bmdVideoOutputFlagDefault) )
217                 {
218                         mlt_log_error( getConsumer(), "Failed to enable video output\n" );
219                         return false;
220                 }
221
222                 // Set the audio output mode
223                 if ( !m_isAudio )
224                 {
225                         m_deckLinkOutput->DisableAudioOutput();
226                         return true;
227                 }
228                 if ( S_OK != m_deckLinkOutput->EnableAudioOutput( bmdAudioSampleRate48kHz, bmdAudioSampleType16bitInteger,
229                         m_channels, bmdAudioOutputStreamTimestamped ) )
230                 {
231                         mlt_log_error( getConsumer(), "Failed to enable audio output\n" );
232                         stop();
233                         return false;
234                 }
235
236                 // preroll frames
237                 for( i = 0; i < preroll; i++ )
238                         ScheduleNextFrame( true );
239
240                 // start scheduled playback
241                 m_deckLinkOutput->StartScheduledPlayback( 0, m_timescale, 1.0 );
242
243                 // Set the running state
244                 mlt_properties_set_int( properties, "running", 1 );
245
246                 return true;
247         }
248         
249         bool stop()
250         {
251                 mlt_properties properties = MLT_CONSUMER_PROPERTIES( getConsumer() );
252
253                 // set running state is 0
254                 mlt_properties_set_int( properties, "running", 0 );
255                 mlt_consumer_stopped( getConsumer() );
256
257                 // release decklink frame
258                 if ( m_decklinkFrame )
259                         m_decklinkFrame->Release();
260                 m_decklinkFrame = NULL;
261
262                 // Stop the audio and video output streams immediately
263                 if ( m_deckLinkOutput )
264                 {
265                         m_deckLinkOutput->StopScheduledPlayback( 0, 0, 0 );
266                         m_deckLinkOutput->DisableAudioOutput();
267                         m_deckLinkOutput->DisableVideoOutput();
268                 }
269
270                 return true;
271         }
272
273         void renderAudio( mlt_frame frame )
274         {
275                 mlt_audio_format format = mlt_audio_s16;
276                 int frequency = bmdAudioSampleRate48kHz;
277                 int samples = mlt_sample_calculator( m_fps, frequency, m_count );
278                 int16_t *pcm = 0;
279
280                 if ( !mlt_frame_get_audio( frame, (void**) &pcm, &format, &frequency, &m_channels, &samples ) )
281                 {
282                         uint32_t written = 0;
283                         BMDTimeValue streamTime = m_count * frequency * m_duration / m_timescale;
284
285 #ifdef WIN32
286                         m_deckLinkOutput->ScheduleAudioSamples( pcm, samples, streamTime, frequency, (unsigned long*) &written );
287 #else
288                         m_deckLinkOutput->ScheduleAudioSamples( pcm, samples, streamTime, frequency, &written );
289 #endif
290
291                         if ( written != (uint32_t) samples )
292                                 mlt_log_verbose( getConsumer(), "renderAudio: samples=%d, written=%u\n", samples, written );
293                 }
294         }
295
296         bool createFrame( IDeckLinkMutableVideoFrame** decklinkFrame )
297         {
298                 BMDPixelFormat format = m_isKeyer? bmdFormat8BitARGB : bmdFormat8BitYUV;
299                 IDeckLinkMutableVideoFrame* frame = 0;
300                 uint8_t *buffer = 0;
301                 int stride = m_width * ( m_isKeyer? 4 : 2 );
302
303                 *decklinkFrame = NULL;
304
305                 // Generate a DeckLink video frame
306                 if ( S_OK != m_deckLinkOutput->CreateVideoFrame( m_width, m_height,
307                         stride, format, bmdFrameFlagDefault, &frame ) )
308                 {
309                         mlt_log_verbose( getConsumer(), "Failed to create video frame\n" );
310                         stop();
311                         return false;
312                 }
313                 
314                 // Make the first line black for field order correction.
315                 if ( S_OK == frame->GetBytes( (void**) &buffer ) && buffer )
316                 {
317                         if ( m_isKeyer )
318                         {
319                                 memset( buffer, 0, stride );
320                         }
321                         else for ( int i = 0; i < m_width; i++ )
322                         {
323                                 *buffer++ = 128;
324                                 *buffer++ = 16;
325                         }
326                 }
327
328                 *decklinkFrame = frame;
329
330                 return true;
331         }
332
333         void renderVideo( mlt_frame frame )
334         {
335                 mlt_image_format format = m_isKeyer? mlt_image_rgb24a : mlt_image_yuv422;
336                 uint8_t* image = 0;
337                 int rendered = mlt_properties_get_int( MLT_FRAME_PROPERTIES(frame), "rendered");
338
339                 if ( rendered && !mlt_frame_get_image( frame, &image, &format, &m_width, &m_height, 0 ) )
340                 {
341                         uint8_t* buffer = 0;
342                         int stride = m_width * ( m_isKeyer? 4 : 2 );
343
344                         if ( m_decklinkFrame )
345                                 m_decklinkFrame->Release();
346                         if ( createFrame( &m_decklinkFrame ) )
347                                 m_decklinkFrame->GetBytes( (void**) &buffer );
348
349                         if ( buffer )
350                         {
351                                 int progressive = mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "progressive" );
352
353                                 if ( !m_isKeyer )
354                                 {
355                                         // Normal non-keyer playout - needs byte swapping
356                                         if ( !progressive && m_displayMode->GetFieldDominance() == bmdUpperFieldFirst )
357                                                 // convert lower field first to top field first
358                                                 swab( (char*) image, (char*) buffer + stride, stride * ( m_height - 1 ) );
359                                         else
360                                                 swab( (char*) image, (char*) buffer, stride * m_height );
361                                 }
362                                 else if ( !mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "test_image" ) )
363                                 {
364                                         // Normal keyer output
365                                         int y = m_height + 1;
366                                         uint32_t* s = (uint32_t*) image;
367                                         uint32_t* d = (uint32_t*) buffer;
368
369                                         if ( !progressive && m_displayMode->GetFieldDominance() == bmdUpperFieldFirst )
370                                         {
371                                                 // Correct field order
372                                                 m_height--;
373                                                 y--;
374                                                 d += m_width;
375                                         }
376
377                                         // Need to relocate alpha channel RGBA => ARGB
378                                         while ( --y )
379                                         {
380                                                 int x = m_width + 1;
381                                                 while ( --x )
382                                                 {
383                                                         *d++ = ( *s << 8 ) | ( *s >> 24 );
384                                                         s++;
385                                                 }
386                                         }
387                                 }
388                                 else
389                                 {
390                                         // Keying blank frames - nullify alpha
391                                         memset( buffer, 0, stride * m_height );
392                                 }
393                         }
394                 }
395                 if ( m_decklinkFrame )
396                         m_deckLinkOutput->ScheduleVideoFrame( m_decklinkFrame, m_count * m_duration, m_duration, m_timescale );
397
398                 if ( !rendered )
399                         mlt_log_verbose( getConsumer(), "dropped video frame %u\n", ++m_dropped );
400         }
401
402         HRESULT render( mlt_frame frame )
403         {
404                 HRESULT result = S_OK;
405
406                 // Get the audio
407                 double speed = mlt_properties_get_double( MLT_FRAME_PROPERTIES(frame), "_speed" );
408                 if ( m_isAudio && speed == 1.0 )
409                         renderAudio( frame );
410
411                 // Get the video
412                 renderVideo( frame );
413                 ++m_count;
414
415                 return result;
416         }
417         
418         // *** DeckLink API implementation of IDeckLinkVideoOutputCallback IDeckLinkAudioOutputCallback *** //
419
420         // IUnknown needs only a dummy implementation
421         virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID iid, LPVOID *ppv )
422                 { return E_NOINTERFACE; }
423         virtual ULONG STDMETHODCALLTYPE AddRef()
424                 { return 1; }
425         virtual ULONG STDMETHODCALLTYPE Release()
426                 { return 1; }
427         
428         /************************* DeckLink API Delegate Methods *****************************/
429         
430         virtual HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted( IDeckLinkVideoFrame* completedFrame, BMDOutputFrameCompletionResult completed )
431         {
432                 // When a video frame has been released by the API, schedule another video frame to be output
433
434                 // ignore handler if frame was flushed
435                 if(bmdOutputFrameFlushed == completed)
436                         return S_OK;
437
438                 // schedule next frame
439                 ScheduleNextFrame(false);
440
441                 // step forward frames counter if underrun
442                 if(bmdOutputFrameDisplayedLate == completed)
443                 {
444                         mlt_log_verbose( getConsumer(), "ScheduledFrameCompleted: bmdOutputFrameDisplayedLate == completed\n");
445                         m_count++;
446                 }
447
448                 return S_OK;
449         }
450
451         virtual HRESULT STDMETHODCALLTYPE ScheduledPlaybackHasStopped()
452         {
453                 return mlt_consumer_is_stopped( getConsumer() ) ? S_FALSE : S_OK;
454         }
455         
456
457         void ScheduleNextFrame(bool preroll)
458         {
459                 // get the consumer
460                 mlt_consumer consumer = getConsumer();
461
462                 // Get the properties
463                 mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer );
464
465                 // Frame and size
466                 mlt_frame frame = NULL;
467
468                 if( mlt_properties_get_int( properties, "running" ) || preroll )
469                 {
470                         frame = mlt_consumer_rt_frame( consumer );
471                         if ( frame != NULL )
472                         {
473                                 render( frame );
474
475                                 mlt_events_fire( properties, "consumer-frame-show", frame, NULL );
476
477                                 // terminate on pause
478                                 if (m_terminate_on_pause &&
479                                         mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame ), "_speed" ) == 0.0)
480                                         stop();
481
482                                 mlt_frame_close( frame );
483                         }
484                 }
485         }
486 };
487
488 /** Start the consumer.
489  */
490
491 static int start( mlt_consumer consumer )
492 {
493         // Get the properties
494         mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer );
495         DeckLinkConsumer* decklink = (DeckLinkConsumer*) consumer->child;
496         return decklink->start( mlt_properties_get_int( properties, "preroll" ) ) ? 0 : 1;
497 }
498
499 /** Stop the consumer.
500  */
501
502 static int stop( mlt_consumer consumer )
503 {
504         // Get the properties
505         DeckLinkConsumer* decklink = (DeckLinkConsumer*) consumer->child;
506         return decklink->stop();
507 }
508
509 /** Determine if the consumer is stopped.
510  */
511
512 static int is_stopped( mlt_consumer consumer )
513 {
514         // Get the properties
515         mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer );
516         return !mlt_properties_get_int( properties, "running" );
517 }
518
519 /** Close the consumer.
520  */
521
522 static void close( mlt_consumer consumer )
523 {
524         // Stop the consumer
525         mlt_consumer_stop( consumer );
526
527         // Close the parent
528         consumer->close = NULL;
529         mlt_consumer_close( consumer );
530
531         // Free the memory
532         delete (DeckLinkConsumer*) consumer->child;
533 }
534
535 extern "C" {
536
537 /** Initialise the consumer.
538  */
539
540 mlt_consumer consumer_decklink_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
541 {
542         // Allocate the consumer
543         DeckLinkConsumer* decklink = new DeckLinkConsumer();
544         mlt_consumer consumer = NULL;
545
546         // If allocated
547         if ( decklink && !mlt_consumer_init( decklink->getConsumer(), decklink, profile ) )
548         {
549                 // If initialises without error
550                 if ( decklink->open( arg? atoi(arg) : 0 ) )
551                 {
552                         consumer = decklink->getConsumer();
553                         
554                         // Setup callbacks
555                         consumer->close = close;
556                         consumer->start = start;
557                         consumer->stop = stop;
558                         consumer->is_stopped = is_stopped;
559                         mlt_properties_set( MLT_CONSUMER_PROPERTIES(consumer), "deinterlace_method", "onefield" );
560                 }
561         }
562
563         // Return consumer
564         return consumer;
565 }
566
567 extern mlt_producer producer_decklink_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
568
569 static mlt_properties metadata( mlt_service_type type, const char *id, void *data )
570 {
571         char file[ PATH_MAX ];
572         const char *service_type = NULL;
573         switch ( type )
574         {
575                 case consumer_type:
576                         service_type = "consumer";
577                         break;
578                 case producer_type:
579                         service_type = "producer";
580                         break;
581                 default:
582                         return NULL;
583         }
584         snprintf( file, PATH_MAX, "%s/decklink/%s_%s.yml", mlt_environment( "MLT_DATA" ), service_type, id );
585         return mlt_properties_parse_yaml( file );
586 }
587
588 MLT_REPOSITORY
589 {
590         MLT_REGISTER( consumer_type, "decklink", consumer_decklink_init );
591         MLT_REGISTER( producer_type, "decklink", producer_decklink_init );
592         MLT_REGISTER_METADATA( consumer_type, "decklink", metadata, NULL );
593         MLT_REGISTER_METADATA( producer_type, "decklink", metadata, NULL );
594 }
595
596 } // extern C