X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmodules%2Fsdl%2Fconsumer_sdl_audio.c;h=e8036beddf659059ca7ede5b89301ae861d4a2ad;hb=c78b8c108bc24df6915352c25f41aa58fecec0e2;hp=5c340d716676759e6dc1bce3bd56b0e7906adc27;hpb=d766cbd6c0a0f6f426bfdaf81feaa13b7accbbbe;p=mlt diff --git a/src/modules/sdl/consumer_sdl_audio.c b/src/modules/sdl/consumer_sdl_audio.c index 5c340d71..e8036bed 100644 --- a/src/modules/sdl/consumer_sdl_audio.c +++ b/src/modules/sdl/consumer_sdl_audio.c @@ -33,8 +33,6 @@ extern pthread_mutex_t mlt_sdl_mutex; -#define MIN(a,b) ((a) > (b) ? (b) : (a)) - /** This classes definition. */ @@ -59,6 +57,7 @@ struct consumer_sdl_s pthread_cond_t refresh_cond; pthread_mutex_t refresh_mutex; int refresh_count; + int is_purge; }; /** Forward references to static functions. @@ -67,6 +66,7 @@ struct consumer_sdl_s 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 ); @@ -78,7 +78,7 @@ 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 ) @@ -108,6 +108,7 @@ mlt_consumer consumer_sdl_audio_init( mlt_profile profile, mlt_service_type type // 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 ); @@ -122,6 +123,7 @@ mlt_consumer consumer_sdl_audio_init( mlt_profile profile, mlt_service_type type 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 ); @@ -145,7 +147,8 @@ static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer parent, char *na { 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 ); } @@ -220,6 +223,25 @@ int consumer_is_stopped( mlt_consumer parent ) 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; @@ -230,7 +252,7 @@ static void sdl_fill_audio( void *udata, uint8_t *stream, int len ) 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 @@ -255,7 +277,7 @@ static void sdl_fill_audio( void *udata, uint8_t *stream, int len ) 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 @@ -278,6 +300,7 @@ static int consumer_play_audio( consumer_sdl self, mlt_frame frame, int init_aud // 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++ ); @@ -332,7 +355,7 @@ static int consumer_play_audio( consumer_sdl self, mlt_frame frame, int init_aud 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 ); @@ -355,7 +378,6 @@ static int consumer_play_video( consumer_sdl self, mlt_frame frame ) 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; } @@ -476,7 +498,10 @@ static void *consumer_thread( void *arg ) 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 ) @@ -524,8 +549,16 @@ static void *consumer_thread( void *arg ) 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 @@ -534,7 +567,7 @@ static void *consumer_thread( void *arg ) 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 );