]> git.sesse.net Git - mlt/blobdiff - src/framework/mlt_consumer.c
add ability to ignore field order as used by sdl consumer
[mlt] / src / framework / mlt_consumer.c
index 05f69e026bd123c51560851aca27ef148dd1a427..2a350a76abf8ecf4e529bfdcd2d9cee93a9b3bb3 100644 (file)
@@ -86,6 +86,7 @@ int mlt_consumer_init( mlt_consumer self, void *child, mlt_profile profile )
 
                // Default read ahead buffer size
                mlt_properties_set_int( properties, "buffer", 25 );
+               mlt_properties_set_int( properties, "drop_max", 5 );
 
                // Default audio frequency and channels
                mlt_properties_set_int( properties, "frequency", 48000 );
@@ -99,6 +100,8 @@ int mlt_consumer_init( mlt_consumer self, void *child, mlt_profile profile )
 
                // Hmm - default all consumers to yuv422 :-/
                self->format = mlt_image_yuv422;
+               mlt_properties_set( properties, "mlt_image_format", mlt_image_format_name( self->format ) );
+               mlt_properties_set( properties, "mlt_audio_format", mlt_audio_format_name( mlt_audio_s16 ) );
 
                mlt_events_register( properties, "consumer-frame-show", ( mlt_transmitter )mlt_consumer_frame_show );
                mlt_events_register( properties, "consumer-frame-render", ( mlt_transmitter )mlt_consumer_frame_render );
@@ -173,7 +176,6 @@ static void mlt_consumer_property_changed( mlt_properties owner, mlt_consumer se
                                free( profile->description );
                                memcpy( profile, new_profile, sizeof( struct mlt_profile_s ) );
                                profile->description = strdup( new_profile->description );
-                               mlt_profile_close( new_profile );
                        }
                        else
                        {
@@ -182,6 +184,7 @@ static void mlt_consumer_property_changed( mlt_properties owner, mlt_consumer se
 
                        // Apply to properties
                        apply_profile_properties( self, profile, properties );
+                       mlt_profile_close( new_profile );
                }
        }
        else if ( !strcmp( name, "frame_rate_num" ) )
@@ -229,17 +232,21 @@ static void mlt_consumer_property_changed( mlt_properties owner, mlt_consumer se
        {
                mlt_properties properties = MLT_CONSUMER_PROPERTIES( self );
                mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) );
-               profile->sample_aspect_num = mlt_properties_get_int( properties, "sample_aspect_num" );
                if ( profile )
+               {
+                       profile->sample_aspect_num = mlt_properties_get_int( properties, "sample_aspect_num" );
                        mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile )  );
+               }
        }
        else if ( !strcmp( name, "sample_aspect_den" ) )
        {
                mlt_properties properties = MLT_CONSUMER_PROPERTIES( self );
                mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) );
-               profile->sample_aspect_den = mlt_properties_get_int( properties, "sample_aspect_den" );
                if ( profile )
+               {
+                       profile->sample_aspect_den = mlt_properties_get_int( properties, "sample_aspect_den" );
                        mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile )  );
+               }
        }
        else if ( !strcmp( name, "display_aspect_num" ) )
        {
@@ -277,8 +284,8 @@ static void mlt_consumer_property_changed( mlt_properties owner, mlt_consumer se
  * \private \memberof mlt_consumer_s
  * \param listener a function pointer that will be invoked
  * \param owner the events object that will be passed to \p listener
- * \param self  a service that will be passed to \p listener
- * \param args an array of pointers - the first entry is passed as a string to \p listener
+ * \param self a service that will be passed to \p listener
+ * \param args an array of pointers - the first entry is passed as a frame to \p listener
  */
 
 static void mlt_consumer_frame_show( mlt_listener listener, mlt_properties owner, mlt_service self, void **args )
@@ -294,8 +301,8 @@ static void mlt_consumer_frame_show( mlt_listener listener, mlt_properties owner
  * \private \memberof mlt_consumer_s
  * \param listener a function pointer that will be invoked
  * \param owner the events object that will be passed to \p listener
- * \param self  a service that will be passed to \p listener
- * \param args an array of pointers - the first entry is passed as a string to \p listener
+ * \param self a service that will be passed to \p listener
+ * \param args an array of pointers - the first entry is passed as a frame to \p listener
  */
 
 static void mlt_consumer_frame_render( mlt_listener listener, mlt_properties owner, mlt_service self, void **args )
@@ -333,11 +340,16 @@ mlt_consumer mlt_consumer_new( mlt_profile profile )
        mlt_consumer self = malloc( sizeof( struct mlt_consumer_s ) );
 
        // Initialise it
-       if ( self != NULL )
-               mlt_consumer_init( self, NULL, profile );
-
-       // Return it
-       return self;
+       if ( self != NULL && mlt_consumer_init( self, NULL, profile ) == 0 )
+       {
+               // Return it
+               return self;
+       }
+       else
+       {
+               free(self);
+               return NULL;
+       }
 }
 
 /** Get the parent service object.
@@ -404,8 +416,10 @@ int mlt_consumer_start( mlt_consumer self )
        char *test_card = mlt_properties_get( properties, "test_card" );
 
        // Just to make sure nothing is hanging around...
+       pthread_mutex_lock( &self->put_mutex );
        self->put = NULL;
        self->put_active = 1;
+       pthread_mutex_unlock( &self->put_mutex );
 
        // Deal with it now.
        if ( test_card != NULL )
@@ -435,9 +449,19 @@ int mlt_consumer_start( mlt_consumer self )
                mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL );
        }
 
+       // The profile could have changed between a stop and a restart.
+       apply_profile_properties( self, mlt_service_profile( MLT_CONSUMER_SERVICE(self) ), properties );
+
        // Set the frame duration in microseconds for the frame-dropping heuristic
-       int frame_duration = 1000000 / mlt_properties_get_int( properties, "frame_rate_num" ) *
-                       mlt_properties_get_int( properties, "frame_rate_den" );
+       int frame_rate_num = mlt_properties_get_int( properties, "frame_rate_num" );
+       int frame_rate_den = mlt_properties_get_int( properties, "frame_rate_den" );
+       int frame_duration = 0;
+
+       if ( frame_rate_num && frame_rate_den )
+       {
+               frame_duration = 1000000 / frame_rate_num * frame_rate_den;
+       }
+
        mlt_properties_set_int( properties, "frame_duration", frame_duration );
 
        // Check and run an ante command
@@ -452,6 +476,22 @@ int mlt_consumer_start( mlt_consumer self )
        if ( abs( self->real_time ) > 1 && mlt_properties_get_int( properties, "buffer" ) <= abs( self->real_time ) )
                mlt_properties_set_int( properties, "_buffer", abs( self->real_time ) + 1 );
 
+       // Get the image format to use for rendering threads
+       const char* format = mlt_properties_get( properties, "mlt_image_format" );
+       if ( format )
+       {
+               if ( !strcmp( format, "rgb24" ) )
+                       self->format = mlt_image_rgb24;
+               else if ( !strcmp( format, "rgb24a" ) )
+                       self->format = mlt_image_rgb24a;
+               else if ( !strcmp( format, "yuv420p" ) )
+                       self->format = mlt_image_yuv420p;
+               else if ( !strcmp( format, "none" ) )
+                       self->format = mlt_image_none;
+               else
+                       self->format = mlt_image_yuv422;
+       }
+
        // Start the service
        if ( self->start != NULL )
                return self->start( self );
@@ -562,13 +602,12 @@ mlt_frame mlt_consumer_get_frame( mlt_consumer self )
                if ( test_card != NULL )
                        mlt_properties_set_data( frame_properties, "test_card_producer", test_card, 0, NULL, NULL );
 
-               // Attach the rescale property
+               // Pass along the interpolation and deinterlace options
+               // TODO: get rid of consumer_deinterlace and use profile.progressive
                mlt_properties_set( frame_properties, "rescale.interp", mlt_properties_get( properties, "rescale" ) );
-
-               // Aspect ratio and other jiggery pokery
-               mlt_properties_set_double( frame_properties, "consumer_aspect_ratio", mlt_properties_get_double( properties, "aspect_ratio" ) );
                mlt_properties_set_int( frame_properties, "consumer_deinterlace", mlt_properties_get_int( properties, "progressive" ) | mlt_properties_get_int( properties, "deinterlace" ) );
                mlt_properties_set( frame_properties, "deinterlace_method", mlt_properties_get( properties, "deinterlace_method" ) );
+               mlt_properties_set_int( frame_properties, "consumer_tff", mlt_properties_get_int( properties, "top_field_first" ) );
        }
 
        // Return the frame
@@ -617,6 +656,20 @@ static void *consumer_read_ahead_thread( void *arg )
 
        // Get the audio settings
        mlt_audio_format afmt = mlt_audio_s16;
+       const char *format = mlt_properties_get( properties, "mlt_audio_format" );
+       if ( format )
+       {
+               if ( !strcmp( format, "none" ) )
+                       afmt = mlt_audio_none;
+               else if ( !strcmp( format, "s32" ) )
+                       afmt = mlt_audio_s32;
+               else if ( !strcmp( format, "s32le" ) )
+                       afmt = mlt_audio_s32le;
+               else if ( !strcmp( format, "float" ) )
+                       afmt = mlt_audio_float;
+               else if ( !strcmp( format, "f32le" ) )
+                       afmt = mlt_audio_f32le;
+       }
        int counter = 0;
        double fps = mlt_properties_get_double( properties, "fps" );
        int channels = mlt_properties_get_int( properties, "channels" );
@@ -646,6 +699,7 @@ static void *consumer_read_ahead_thread( void *arg )
        mlt_position start_pos = 0;
        mlt_position last_pos = 0;
        int frame_duration = mlt_properties_get_int( properties, "frame_duration" );
+       int drop_max = mlt_properties_get_int( properties, "drop_max" );
 
        if ( preview_off && preview_format != 0 )
                self->format = preview_format;
@@ -734,7 +788,7 @@ static void *consumer_read_ahead_thread( void *arg )
                        skipped++;
 
                        // If too many (1 sec) consecutively-skipped frames
-                       if ( skipped > fps )
+                       if ( skipped > drop_max )
                        {
                                // Reset cost tracker
                                time_process = 0;
@@ -967,6 +1021,7 @@ static void consumer_work_start( mlt_consumer self )
 
        // We're running now
        self->ahead = 1;
+       self->threads = thread;
        
        // These keep track of the accelleration of frame dropping or recovery.
        self->consecutive_dropped = 0;
@@ -1103,8 +1158,8 @@ static void consumer_work_stop( mlt_consumer self )
                        pthread_join( *thread, NULL );
 
                // Deallocate the array of threads
-               if ( thread )
-                       free( thread );
+               if ( self->threads )
+                       free( self->threads );
 
                // Indicate that worker threads no longer running
                self->started = 0;
@@ -1135,7 +1190,7 @@ static void consumer_work_stop( mlt_consumer self )
 
 void mlt_consumer_purge( mlt_consumer self )
 {
-       if ( self->ahead )
+       if ( self && self->ahead )
        {
                pthread_mutex_lock( &self->queue_mutex );
                while ( mlt_deque_count( self->queue ) )
@@ -1209,8 +1264,9 @@ static mlt_frame worker_get_frame( mlt_consumer self, mlt_properties properties
        }
 
        // Wait if not realtime.
+       mlt_frame head_frame = MLT_FRAME( mlt_deque_peek_front( self->queue ) );
        while ( self->ahead && self->real_time < 0 &&
-               ! mlt_properties_get_int( MLT_FRAME_PROPERTIES( MLT_FRAME( mlt_deque_peek_front( self->queue ) ) ), "rendered" ) )
+               !( head_frame && mlt_properties_get_int( MLT_FRAME_PROPERTIES( head_frame ), "rendered" ) ) )
        {
                pthread_mutex_lock( &self->done_mutex );
                pthread_cond_wait( &self->done_cond, &self->done_mutex );
@@ -1245,7 +1301,7 @@ static mlt_frame worker_get_frame( mlt_consumer self, mlt_properties properties
 //                     self->consecutive_dropped, self->consecutive_rendered, self->process_head );
 
                // Check for too many consecutively dropped frames
-               if ( self->consecutive_dropped > fps )
+               if ( self->consecutive_dropped > mlt_properties_get_int( properties, "drop_max" ) )
                {
                        int orig_buffer = mlt_properties_get_int( properties, "buffer" );
                        int prefill = mlt_properties_get_int( properties, "prefill" );
@@ -1411,7 +1467,7 @@ int mlt_consumer_stop( mlt_consumer self )
 int mlt_consumer_is_stopped( mlt_consumer self )
 {
        // Check if the consumer is stopped
-       if ( self->is_stopped != NULL )
+       if ( self && self->is_stopped )
                return self->is_stopped( self );
 
        return 0;