]> git.sesse.net Git - mlt/blobdiff - src/modules/sdl/consumer_sdl_audio.c
Replace glFinish with OpenGL fences.
[mlt] / src / modules / sdl / consumer_sdl_audio.c
index 5c340d716676759e6dc1bce3bd56b0e7906adc27..e8036beddf659059ca7ede5b89301ae861d4a2ad 100644 (file)
@@ -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 );