extern pthread_mutex_t mlt_sdl_mutex;
-#define MIN(a,b) ((a) > (b) ? (b) : (a))
-
/** This classes definition.
*/
pthread_cond_t refresh_cond;
pthread_mutex_t refresh_mutex;
int refresh_count;
+ int is_purge;
};
/** Forward references to static functions.
static int consumer_start( mlt_consumer parent );
static int consumer_stop( mlt_consumer parent );
static int consumer_is_stopped( mlt_consumer parent );
+static void consumer_purge( mlt_consumer parent );
static void consumer_close( mlt_consumer parent );
static void *consumer_thread( void * );
static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer self, char *name );
mlt_consumer consumer_sdl_audio_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
{
// Create the consumer object
- consumer_sdl self = calloc( sizeof( struct consumer_sdl_s ), 1 );
+ consumer_sdl self = calloc( 1, sizeof( struct consumer_sdl_s ) );
// If no malloc'd and consumer init ok
if ( self != NULL && mlt_consumer_init( &self->parent, self, profile ) == 0 )
// Default scaler (for now we'll use nearest)
mlt_properties_set( self->properties, "rescale", "nearest" );
mlt_properties_set( self->properties, "deinterlace_method", "onefield" );
+ mlt_properties_set_int( self->properties, "top_field_first", -1 );
// Default buffer for low latency
mlt_properties_set_int( self->properties, "buffer", 1 );
parent->start = consumer_start;
parent->stop = consumer_stop;
parent->is_stopped = consumer_is_stopped;
+ parent->purge = consumer_purge;
// Initialize the refresh handler
pthread_cond_init( &self->refresh_cond, NULL );
{
consumer_sdl self = parent->child;
pthread_mutex_lock( &self->refresh_mutex );
- self->refresh_count = self->refresh_count <= 0 ? 1 : self->refresh_count + 1;
+ if ( self->refresh_count < 2 )
+ self->refresh_count = self->refresh_count <= 0 ? 1 : self->refresh_count + 1;
pthread_cond_broadcast( &self->refresh_cond );
pthread_mutex_unlock( &self->refresh_mutex );
}
return !self->running;
}
+void consumer_purge( mlt_consumer parent )
+{
+ consumer_sdl self = parent->child;
+ if ( self->running )
+ {
+ pthread_mutex_lock( &self->video_mutex );
+ mlt_frame frame = MLT_FRAME( mlt_deque_peek_back( self->queue ) );
+ // When playing rewind or fast forward then we need to keep one
+ // frame in the queue to prevent playback stalling.
+ double speed = frame? mlt_properties_get_double( MLT_FRAME_PROPERTIES(frame), "_speed" ) : 0;
+ int n = ( speed == 0.0 || speed == 1.0 ) ? 0 : 1;
+ while ( mlt_deque_count( self->queue ) > n )
+ mlt_frame_close( mlt_deque_pop_back( self->queue ) );
+ self->is_purge = 1;
+ pthread_cond_broadcast( &self->video_cond );
+ pthread_mutex_unlock( &self->video_mutex );
+ }
+}
+
static void sdl_fill_audio( void *udata, uint8_t *stream, int len )
{
consumer_sdl self = udata;
pthread_mutex_lock( &self->audio_mutex );
// Block until audio received
-#ifndef WIN32
+#ifdef __DARWIN__
while ( self->running && len > self->audio_avail )
pthread_cond_wait( &self->audio_cond, &self->audio_mutex );
#endif
memset( stream, 0, len );
// Mix the audio
- SDL_MixAudio( stream, self->audio_buffer, MIN(len, self->audio_avail),
+ SDL_MixAudio( stream, self->audio_buffer, self->audio_avail,
( int )( ( float )SDL_MIX_MAXVOLUME * volume ) );
// No audio left
// Set the preferred params of the test card signal
int channels = mlt_properties_get_int( properties, "channels" );
int frequency = mlt_properties_get_int( properties, "frequency" );
+ int scrub = mlt_properties_get_int( properties, "scrub_audio" );
static int counter = 0;
int samples = mlt_sample_calculator( mlt_properties_get_double( self->properties, "fps" ), frequency, counter++ );
pthread_cond_wait( &self->audio_cond, &self->audio_mutex );
if ( self->running )
{
- if ( mlt_properties_get_double( properties, "_speed" ) == 1 )
+ if ( scrub || mlt_properties_get_double( properties, "_speed" ) == 1 )
memcpy( &self->audio_buffer[ self->audio_avail ], pcm, bytes );
else
memset( &self->audio_buffer[ self->audio_avail ], 0, bytes );
mlt_properties properties = self->properties;
if ( self->running && !mlt_consumer_is_stopped( &self->parent ) )
mlt_events_fire( properties, "consumer-frame-show", frame, NULL );
-
return 0;
}
int64_t playtime = 0;
struct timespec tm = { 0, 100000 };
// int last_position = -1;
+
+ pthread_mutex_lock( &self->refresh_mutex );
self->refresh_count = 0;
+ pthread_mutex_unlock( &self->refresh_mutex );
// Loop until told not to
while( self->running )
if ( self->running && speed )
{
pthread_mutex_lock( &self->video_mutex );
- mlt_deque_push_back( self->queue, frame );
- pthread_cond_broadcast( &self->video_cond );
+ if ( self->is_purge && speed == 1.0 )
+ {
+ mlt_frame_close( frame );
+ self->is_purge = 0;
+ }
+ else
+ {
+ mlt_deque_push_back( self->queue, frame );
+ pthread_cond_broadcast( &self->video_cond );
+ }
pthread_mutex_unlock( &self->video_mutex );
// Calculate the next playtime
else if ( self->running )
{
pthread_mutex_lock( &self->refresh_mutex );
- if ( refresh == 0 && self->refresh_count <= 0 )
+ if ( ( refresh == 0 && self->refresh_count <= 0 ) || self->refresh_count > 1 )
{
consumer_play_video( self, frame );
pthread_cond_wait( &self->refresh_cond, &self->refresh_mutex );