mlt_producer.c, mlt_playlist.h, mlt_field.h, mlt_playlist.c, mlt_tractor.c, mlt_events.c:
[melted] / src / framework / mlt_consumer.c
index 668fe2f..8ed90c7 100644 (file)
@@ -1,7 +1,9 @@
-/*
- * mlt_consumer.c -- abstraction for all consumer services
- * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
- * Author: Charles Yates <charles.yates@pandora.be>
+/**
+ * \file mlt_consumer.c
+ * \brief abstraction for all consumer services
+ *
+ * Copyright (C) 2003-2008 Ushodaya Enterprises Limited
+ * \author Charles Yates <charles.yates@pandora.be>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #include <stdlib.h>
 #include <sys/time.h>
 
+#undef DEINTERLACE_ON_NOT_NORMAL_SPEED
+
 static void mlt_consumer_frame_render( mlt_listener listener, mlt_properties owner, mlt_service this, void **args );
 static void mlt_consumer_frame_show( mlt_listener listener, mlt_properties owner, mlt_service this, void **args );
 static void mlt_consumer_property_changed( mlt_service owner, mlt_consumer this, char *name );
 static void apply_profile_properties( mlt_consumer this, mlt_profile profile, mlt_properties properties );
 
-/** Public final methods
-*/
-
 int mlt_consumer_init( mlt_consumer this, void *child, mlt_profile profile )
 {
        int error = 0;
@@ -47,7 +48,7 @@ int mlt_consumer_init( mlt_consumer this, void *child, mlt_profile profile )
        {
                // Get the properties from the service
                mlt_properties properties = MLT_SERVICE_PROPERTIES( &this->parent );
-       
+
                // Apply profile to properties
                if ( profile == NULL )
                {
@@ -322,6 +323,11 @@ int mlt_consumer_start( mlt_consumer this )
                mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL );
        }
 
+       // 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" );
+       mlt_properties_set_int( properties, "frame_duration", frame_duration );
+
        // Check and run an ante command
        if ( mlt_properties_get( properties, "ante" ) )
                system( mlt_properties_get( properties, "ante" ) );
@@ -570,7 +576,9 @@ static void *consumer_read_ahead_thread( void *arg )
                // All non normal playback frames should be shown
                if ( mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "_speed" ) != 1 )
                {
+#ifdef DEINTERLACE_ON_NOT_NORMAL_SPEED
                        mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "consumer_deinterlace", 1 );
+#endif
                        skipped = 0;
                        time_frame = 0;
                        time_process = 0;
@@ -580,7 +588,7 @@ static void *consumer_read_ahead_thread( void *arg )
                }
 
                // Get the image
-               if ( !skip_next )
+               if ( !skip_next || this->real_time == -1 )
                {
                        // Get the image, mark as rendered and time it
                        if ( !video_off )
@@ -618,8 +626,12 @@ static void *consumer_read_ahead_thread( void *arg )
                time_process += time_difference( &ante );
 
                // Determine if the next frame should be skipped
-               if ( mlt_deque_count( this->queue ) <= 5 && ( ( time_wait + time_frame + time_process ) / count ) > 40000 )
-                       skip_next = 1;
+               if ( mlt_deque_count( this->queue ) <= 5 )
+               {
+                       int frame_duration = mlt_properties_get_int( properties, "frame_duration" );
+                       if ( ( ( time_wait + time_frame + time_process ) / count ) > frame_duration )
+                               skip_next = 1;
+               }
 
                // Unlock if there's a lock object
                if ( lock_object ) mlt_service_unlock( lock_object );
@@ -645,8 +657,25 @@ static void consumer_read_ahead_start( mlt_consumer this )
        // Create the condition
        pthread_cond_init( &this->cond, NULL );
 
-       // Create the read ahead 
-       pthread_create( &this->ahead_thread, NULL, consumer_read_ahead_thread, this );
+       // Create the read ahead
+       if ( mlt_properties_get( MLT_CONSUMER_PROPERTIES( this ), "priority" ) )
+       {
+               struct sched_param priority;
+               priority.sched_priority = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( this ), "priority" );
+               pthread_attr_t thread_attributes;
+               pthread_attr_init( &thread_attributes );
+               pthread_attr_setschedpolicy( &thread_attributes, SCHED_OTHER );
+               pthread_attr_setschedparam( &thread_attributes, &priority );
+               pthread_attr_setinheritsched( &thread_attributes, PTHREAD_EXPLICIT_SCHED );
+               pthread_attr_setscope( &thread_attributes, PTHREAD_SCOPE_SYSTEM );
+               if ( pthread_create( &this->ahead_thread, &thread_attributes, consumer_read_ahead_thread, this ) < 0 )
+                       pthread_create( &this->ahead_thread, NULL, consumer_read_ahead_thread, this );
+               pthread_attr_destroy( &thread_attributes );
+       }
+       else
+       {
+               pthread_create( &this->ahead_thread, NULL, consumer_read_ahead_thread, this );
+       }
 }
 
 static void consumer_read_ahead_stop( mlt_consumer this )
@@ -719,7 +748,7 @@ mlt_frame mlt_consumer_rt_frame( mlt_consumer this )
                        if ( buffer > 1 )
                                size = prefill > 0 && prefill < buffer ? prefill : buffer;
                }
-       
+
                // Get frame from queue
                pthread_mutex_lock( &this->mutex );
                while( this->ahead && mlt_deque_count( this->queue ) < size )