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