int m_topFieldFirst;
int m_colorspace;
int m_vancLines;
+ mlt_cache m_cache;
BMDDisplayMode getDisplayMode( mlt_profile profile, int vancLines )
{
~DeckLinkProducer()
{
- if ( m_decklinkInput )
- m_decklinkInput->Release();
- if ( m_decklink )
- m_decklink->Release();
if ( m_queue )
{
stop();
mlt_deque_close( m_queue );
pthread_mutex_destroy( &m_mutex );
pthread_cond_destroy( &m_condition );
+ mlt_cache_close( m_cache );
}
+ if ( m_decklinkInput )
+ m_decklinkInput->Release();
+ if ( m_decklink )
+ m_decklink->Release();
}
bool open( unsigned card = 0 )
m_started = false;
m_dropped = 0;
m_isBuffering = true;
+ m_cache = mlt_cache_init();
+
+ // 3 covers YADIF and increasing framerate use cases
+ mlt_cache_set_size( m_cache, 3 );
}
catch ( const char *error )
{
pthread_mutex_unlock( &m_mutex );
}
+ mlt_frame cloneFrame( mlt_frame frame )
+ {
+ mlt_frame new_frame = mlt_frame_init( NULL );
+ mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
+ mlt_properties new_props = MLT_FRAME_PROPERTIES( new_frame );
+ void *data;
+ void *copy;
+ int size;
+
+ mlt_properties_inherit( new_props, properties );
+ mlt_properties_set_int( new_props, "audio_samples", 0 );
+ data = mlt_properties_get_data( properties, "image", &size );
+ copy = mlt_pool_alloc( size );
+ memcpy( copy, data, size );
+ mlt_properties_set_data( new_props, "image", copy, size, mlt_pool_release, NULL );
+
+ return new_frame;
+ }
+
mlt_frame getFrame()
{
mlt_frame frame = NULL;
struct timeval now;
struct timespec tm;
double fps = mlt_producer_get_fps( getProducer() );
+ mlt_position position = mlt_producer_position( getProducer() );
+ mlt_cache_item cached = mlt_cache_get( m_cache, (void*) position );
// Allow the buffer to fill to the requested initial buffer level.
if ( m_isBuffering )
pthread_mutex_unlock( &m_mutex );
}
- // Wait if queue is empty
- pthread_mutex_lock( &m_mutex );
- while ( mlt_deque_count( m_queue ) < 1 )
+ if ( cached )
{
- // Wait up to twice frame duration
- gettimeofday( &now, NULL );
- long usec = now.tv_sec * 1000000 + now.tv_usec;
- usec += 2000000 / fps;
- tm.tv_sec = usec / 1000000;
- tm.tv_nsec = (usec % 1000000) * 1000;
- if ( pthread_cond_timedwait( &m_condition, &m_mutex, &tm ) )
- // Stop waiting if error (timed out)
- break;
+ // Copy cached frame instead of pulling from queue
+ frame = cloneFrame( (mlt_frame) mlt_cache_item_data( cached, NULL ) );
+ mlt_cache_item_close( cached );
}
+ else
+ {
+ // Wait if queue is empty
+ pthread_mutex_lock( &m_mutex );
+ while ( mlt_deque_count( m_queue ) < 1 )
+ {
+ // Wait up to twice frame duration
+ gettimeofday( &now, NULL );
+ long usec = now.tv_sec * 1000000 + now.tv_usec;
+ usec += 2000000 / fps;
+ tm.tv_sec = usec / 1000000;
+ tm.tv_nsec = (usec % 1000000) * 1000;
+ if ( pthread_cond_timedwait( &m_condition, &m_mutex, &tm ) )
+ // Stop waiting if error (timed out)
+ break;
+ }
+ frame = ( mlt_frame ) mlt_deque_pop_front( m_queue );
+ pthread_mutex_unlock( &m_mutex );
- // Get the first frame from the queue
- frame = ( mlt_frame ) mlt_deque_pop_front( m_queue );
- pthread_mutex_unlock( &m_mutex );
+ // add to cache
+ if ( frame )
+ mlt_cache_put( m_cache, (void*) position, cloneFrame( frame ), 0,
+ (mlt_destructor) mlt_frame_close );
+ }
// Set frame timestamp and properties
if ( frame )
mlt_properties_set_int( properties, "audio_channels",
mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" ) );
}
+ else
+ mlt_log_warning( getProducer(), "buffer underrun\n" );
+
return frame;
}