* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#define __STDC_FORMAT_MACROS /* see inttypes.h */
#include <framework/mlt.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <limits.h>
+#ifdef WIN32
+#include <objbase.h>
+#include "DeckLinkAPI_h.h"
+#else
#include "DeckLinkAPI.h"
+#endif
static const unsigned PREROLL_MINIMUM = 3;
int m_isKeyer;
IDeckLinkKeyer* m_deckLinkKeyer;
bool m_terminate_on_pause;
+ uint32_t m_preroll;
+ uint32_t m_acnt;
+ bool m_reprio;
IDeckLinkDisplayMode* getDisplayMode()
{
bool open( unsigned card = 0 )
{
- IDeckLinkIterator* deckLinkIterator = CreateDeckLinkIteratorInstance();
unsigned i = 0;
+#ifdef WIN32
+ IDeckLinkIterator* deckLinkIterator = NULL;
+ HRESULT result = CoInitialize( NULL );
+ if ( FAILED( result ) )
+ {
+ mlt_log_error( getConsumer(), "COM initialization failed\n" );
+ return false;
+ }
+ result = CoCreateInstance( CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL, IID_IDeckLinkIterator, (void**) &deckLinkIterator );
+ if ( FAILED( result ) )
+ {
+ mlt_log_error( getConsumer(), "The DeckLink drivers not installed.\n" );
+ return false;
+ }
+#else
+ IDeckLinkIterator* deckLinkIterator = CreateDeckLinkIteratorInstance();
if ( !deckLinkIterator )
{
mlt_log_error( getConsumer(), "The DeckLink drivers not installed.\n" );
return false;
}
+#endif
// Connect to the Nth DeckLink instance
do {
m_deckLinkKeyer = 0;
if ( m_deckLink->QueryInterface( IID_IDeckLinkAttributes, (void**) &deckLinkAttributes ) == S_OK )
{
+#ifdef WIN32
+ BOOL flag = FALSE;
+#else
bool flag = false;
+#endif
if ( deckLinkAttributes->GetFlag( BMDDeckLinkSupportsInternalKeying, &flag ) == S_OK && flag )
{
if ( m_deckLink->QueryInterface( IID_IDeckLinkKeyer, (void**) &m_deckLinkKeyer ) != S_OK )
// Set the keyer
if ( m_deckLinkKeyer && ( m_isKeyer = mlt_properties_get_int( properties, "keyer" ) ) )
{
- bool external = (m_isKeyer == 2);
+ bool external = ( m_isKeyer == 2 );
double level = mlt_properties_get_double( properties, "keyer_level" );
if ( m_deckLinkKeyer->Enable( external ) != S_OK )
}
// Set the video output mode
- if ( S_OK != m_deckLinkOutput->EnableVideoOutput( m_displayMode->GetDisplayMode(), bmdVideoOutputFlagDefault) )
+ if ( S_OK != m_deckLinkOutput->EnableVideoOutput( m_displayMode->GetDisplayMode(), bmdVideoOutputFlagDefault ) )
{
mlt_log_error( getConsumer(), "Failed to enable video output\n" );
return false;
return false;
}
+ m_preroll = preroll;
+ m_reprio = false;
+
// preroll frames
for( i = 0; i < preroll; i++ )
ScheduleNextFrame( true );
if ( !mlt_frame_get_audio( frame, (void**) &pcm, &format, &frequency, &m_channels, &samples ) )
{
uint32_t written = 0;
-
- m_deckLinkOutput->ScheduleAudioSamples( pcm, samples, m_count * frequency / m_fps, frequency, &written );
-
- if ( written != samples )
- mlt_log_verbose( getConsumer(), "renderAudio: samples=%d, written=%d\n", samples, written );
+ BMDTimeValue streamTime = m_count * frequency * m_duration / m_timescale;
+ m_deckLinkOutput->GetBufferedAudioSampleFrameCount( &written );
+ if ( written > (m_preroll + 1) * samples )
+ {
+ mlt_log_verbose( getConsumer(), "renderAudio: will flush %d audiosamples\n", written );
+ m_deckLinkOutput->FlushBufferedAudioSamples();
+ };
+#ifdef WIN32
+ m_deckLinkOutput->ScheduleAudioSamples( pcm, samples, streamTime, frequency, (unsigned long*) &written );
+#else
+ m_deckLinkOutput->ScheduleAudioSamples( pcm, samples, streamTime, frequency, &written );
+#endif
+
+ if ( written != (uint32_t) samples )
+ mlt_log_verbose( getConsumer(), "renderAudio: samples=%d, written=%u\n", samples, written );
}
}
// Normal non-keyer playout - needs byte swapping
if ( !progressive && m_displayMode->GetFieldDominance() == bmdUpperFieldFirst )
// convert lower field first to top field first
- swab( image, buffer + stride, stride * ( m_height - 1 ) );
+ swab( (char*) image, (char*) buffer + stride, stride * ( m_height - 1 ) );
else
- swab( image, buffer, stride * m_height );
+ swab( (char*) image, (char*) buffer, stride * m_height );
}
else if ( !mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "test_image" ) )
{
virtual HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted( IDeckLinkVideoFrame* completedFrame, BMDOutputFrameCompletionResult completed )
{
+ if( !m_reprio )
+ {
+ mlt_properties properties = MLT_CONSUMER_PROPERTIES( getConsumer() );
+
+ if ( mlt_properties_get( properties, "priority" ) )
+ {
+ int r;
+ pthread_t thread;
+ pthread_attr_t tattr;
+ struct sched_param param;
+
+ pthread_attr_init(&tattr);
+ pthread_attr_setschedpolicy(&tattr, SCHED_FIFO);
+
+ if ( !strcmp( "max", mlt_properties_get( properties, "priority" ) ) )
+ param.sched_priority = sched_get_priority_max(SCHED_FIFO) - 1;
+ else if ( !strcmp( "min", mlt_properties_get( properties, "priority" ) ) )
+ param.sched_priority = sched_get_priority_min(SCHED_FIFO) + 1;
+ else
+ param.sched_priority = mlt_properties_get_int( properties, "priority" );
+
+ pthread_attr_setschedparam(&tattr, ¶m);
+
+ thread = pthread_self();
+
+ r = pthread_setschedparam(thread, SCHED_FIFO, ¶m);
+ if( r )
+ mlt_log_verbose( getConsumer(),
+ "ScheduledFrameCompleted: pthread_setschedparam retured %d\n", r);
+ else
+ mlt_log_verbose( getConsumer(),
+ "ScheduledFrameCompleted: param.sched_priority=%d\n", param.sched_priority);
+ };
+
+ m_reprio = true;
+ };
+
+ uint32_t cnt;
+ m_deckLinkOutput->GetBufferedAudioSampleFrameCount( &cnt );
+ if ( cnt != m_acnt )
+ {
+ mlt_log_verbose( getConsumer(),
+ "ScheduledFrameCompleted: GetBufferedAudioSampleFrameCount %u -> %u, m_count=%"PRIu64"\n",
+ m_acnt, cnt, m_count );
+ m_acnt = cnt;
+ }
+
// When a video frame has been released by the API, schedule another video frame to be output
// ignore handler if frame was flushed
- if(bmdOutputFrameFlushed == completed)
+ if ( bmdOutputFrameFlushed == completed )
return S_OK;
// schedule next frame
- ScheduleNextFrame(false);
+ ScheduleNextFrame( false );
// step forward frames counter if underrun
- if(bmdOutputFrameDisplayedLate == completed)
+ if ( bmdOutputFrameDisplayedLate == completed )
+ {
+ mlt_log_verbose( getConsumer(), "ScheduledFrameCompleted: bmdOutputFrameDisplayedLate == completed\n" );
+ m_count++;
+ }
+ if ( bmdOutputFrameDropped == completed )
{
- mlt_log_verbose( getConsumer(), "ScheduledFrameCompleted: bmdOutputFrameDisplayedLate == completed\n");
+ mlt_log_verbose( getConsumer(), "ScheduledFrameCompleted: bmdOutputFrameDropped == completed\n" );
m_count++;
}
}
- void ScheduleNextFrame(bool preroll)
+ void ScheduleNextFrame( bool preroll )
{
// get the consumer
mlt_consumer consumer = getConsumer();
mlt_events_fire( properties, "consumer-frame-show", frame, NULL );
// terminate on pause
- if (m_terminate_on_pause &&
- mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame ), "_speed" ) == 0.0)
+ if ( m_terminate_on_pause &&
+ mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame ), "_speed" ) == 0.0 )
stop();
mlt_frame_close( frame );