X-Git-Url: http://research.m1stereo.tv/gitweb?a=blobdiff_plain;f=src%2Fframework%2Fmlt_consumer.c;h=8f99db4dce52086ca24c6b8d73e35bb658af1279;hb=833934cc90094c909078f709532e6fe6f8f13b60;hp=6c859888557f7f8b779a3106b4e2390a7e7ff0e7;hpb=37e6bec1491c345e093e4bedc1ad241c78515d2f;p=melted diff --git a/src/framework/mlt_consumer.c b/src/framework/mlt_consumer.c index 6c85988..8f99db4 100644 --- a/src/framework/mlt_consumer.c +++ b/src/framework/mlt_consumer.c @@ -28,6 +28,7 @@ #include #include +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 ); /** Public final methods @@ -52,6 +53,8 @@ int mlt_consumer_init( mlt_consumer this, void *child ) { mlt_properties_set( properties, "normalisation", "PAL" ); mlt_properties_set_double( properties, "fps", 25.0 ); + mlt_properties_set_int( properties, "frame_rate_den", 25 ); + mlt_properties_set_int( properties, "frame_rate_num", 1 ); mlt_properties_set_int( properties, "width", 720 ); mlt_properties_set_int( properties, "height", 576 ); mlt_properties_set_int( properties, "progressive", 0 ); @@ -61,6 +64,8 @@ int mlt_consumer_init( mlt_consumer this, void *child ) { mlt_properties_set( properties, "normalisation", "NTSC" ); mlt_properties_set_double( properties, "fps", 30000.0 / 1001.0 ); + mlt_properties_set_int( properties, "frame_rate_den", 30000 ); + mlt_properties_set_int( properties, "frame_rate_num", 1001 ); mlt_properties_set_int( properties, "width", 720 ); mlt_properties_set_int( properties, "height", 480 ); mlt_properties_set_int( properties, "progressive", 0 ); @@ -87,6 +92,7 @@ int mlt_consumer_init( mlt_consumer this, void *child ) this->format = mlt_image_yuv422; 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 ); mlt_events_register( properties, "consumer-stopped", NULL ); // Create the push mutex and condition @@ -103,6 +109,12 @@ static void mlt_consumer_frame_show( mlt_listener listener, mlt_properties owner listener( owner, this, ( mlt_frame )args[ 0 ] ); } +static void mlt_consumer_frame_render( mlt_listener listener, mlt_properties owner, mlt_service this, void **args ) +{ + if ( listener != NULL ) + listener( owner, this, ( mlt_frame )args[ 0 ] ); +} + /** Create a new consumer. */ @@ -157,6 +169,7 @@ int mlt_consumer_start( mlt_consumer this ) // Just to make sure nothing is hanging around... mlt_frame_close( this->put ); this->put = NULL; + this->put_active = 1; // Deal with it now. if ( test_card != NULL ) @@ -170,9 +183,9 @@ int mlt_consumer_start( mlt_consumer this ) if ( producer != NULL ) { // Test card should loop I guess... - mlt_properties_set( MLT_PRODUCER_PROPERTIES( producer ), "eof", "pause" ); - mlt_producer_set_speed( producer, 0 ); - mlt_producer_set_in_and_out( producer, 0, 0 ); + mlt_properties_set( MLT_PRODUCER_PROPERTIES( producer ), "eof", "loop" ); + //mlt_producer_set_speed( producer, 0 ); + //mlt_producer_set_in_and_out( producer, 0, 0 ); // Set the test card on the consumer mlt_properties_set_data( properties, "test_card_producer", producer, 0, ( mlt_destructor )mlt_producer_close, NULL ); @@ -215,14 +228,14 @@ int mlt_consumer_put_frame( mlt_consumer this, mlt_frame frame ) struct timeval now; struct timespec tm; pthread_mutex_lock( &this->put_mutex ); - while ( !mlt_consumer_is_stopped( this ) && this->put != NULL ) + while ( this->put_active && this->put != NULL ) { gettimeofday( &now, NULL ); tm.tv_sec = now.tv_sec + 1; tm.tv_nsec = now.tv_usec * 1000; pthread_cond_timedwait( &this->put_cond, &this->put_mutex, &tm ); } - if ( !mlt_consumer_is_stopped( this ) && this->put == NULL ) + if ( this->put_active && this->put == NULL ) this->put = frame; else mlt_frame_close( frame ); @@ -257,7 +270,7 @@ mlt_frame mlt_consumer_get_frame( mlt_consumer this ) struct timeval now; struct timespec tm; pthread_mutex_lock( &this->put_mutex ); - while ( !mlt_consumer_is_stopped( this ) && this->put == NULL ) + while ( this->put_active && this->put == NULL ) { gettimeofday( &now, NULL ); tm.tv_sec = now.tv_sec + 1; @@ -275,6 +288,10 @@ mlt_frame mlt_consumer_get_frame( mlt_consumer this ) { mlt_service_get_frame( service, &frame, 0 ); } + else + { + frame = mlt_frame_init( ); + } if ( frame != NULL ) { @@ -293,8 +310,8 @@ mlt_frame mlt_consumer_get_frame( mlt_consumer this ) // Aspect ratio and other jiggery pokery mlt_properties_set_double( frame_properties, "consumer_aspect_ratio", mlt_properties_get_double( properties, "aspect_ratio" ) ); - if ( mlt_properties_get_int( properties, "progressive" ) || mlt_properties_get_int( properties, "deinterlace" ) ) - mlt_properties_set_int( frame_properties, "consumer_deinterlace", 1 ); + 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" ) ); } // Return the frame @@ -354,21 +371,34 @@ static void *consumer_read_ahead_thread( void *arg ) int64_t time_frame = 0; int64_t time_process = 0; int skip_next = 0; + mlt_service lock_object = NULL; // Get the first frame frame = mlt_consumer_get_frame( this ); + // Get the lock object + lock_object = mlt_properties_get_data( MLT_FRAME_PROPERTIES( frame ), "consumer_lock_service", NULL ); + + // Lock it + if ( lock_object ) mlt_service_lock( lock_object ); + // Get the image of the first frame if ( !video_off ) + { + mlt_events_fire( MLT_CONSUMER_PROPERTIES( this ), "consumer-frame-render", frame, NULL ); mlt_frame_get_image( frame, &image, &this->format, &width, &height, 0 ); + } if ( !audio_off ) { samples = mlt_sample_calculator( fps, frequency, counter++ ); mlt_frame_get_audio( frame, &pcm, &afmt, &frequency, &channels, &samples ); - frame->get_audio = NULL; } + // Unlock the lock object + if ( lock_object ) mlt_service_unlock( lock_object ); + + // Mark as rendered mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "rendered", 1 ); // Get the starting time (can ignore the times above) @@ -395,12 +425,19 @@ static void *consumer_read_ahead_thread( void *arg ) if ( frame == NULL ) continue; + // Attempt to fetch the lock object + lock_object = mlt_properties_get_data( MLT_FRAME_PROPERTIES( frame ), "consumer_lock_service", NULL ); + // Increment the count count ++; + // Lock if there's a lock object + if ( lock_object ) mlt_service_lock( lock_object ); + // All non normal playback frames should be shown if ( mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "_speed" ) != 1 ) { + mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "consumer_deinterlace", 1 ); skipped = 0; time_frame = 0; time_process = 0; @@ -414,7 +451,10 @@ static void *consumer_read_ahead_thread( void *arg ) { // Get the image, mark as rendered and time it if ( !video_off ) + { + mlt_events_fire( MLT_CONSUMER_PROPERTIES( this ), "consumer-frame-render", frame, NULL ); mlt_frame_get_image( frame, &image, &this->format, &width, &height, 0 ); + } mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "rendered", 1 ); } else @@ -439,7 +479,6 @@ static void *consumer_read_ahead_thread( void *arg ) { samples = mlt_sample_calculator( fps, frequency, counter++ ); mlt_frame_get_audio( frame, &pcm, &afmt, &frequency, &channels, &samples ); - frame->get_audio = NULL; } // Increment the time take for this frame @@ -448,6 +487,9 @@ static void *consumer_read_ahead_thread( void *arg ) // 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; + + // Unlock if there's a lock object + if ( lock_object ) mlt_service_unlock( lock_object ); } // Remove the last frame @@ -458,8 +500,6 @@ static void *consumer_read_ahead_thread( void *arg ) static void consumer_read_ahead_start( mlt_consumer this ) { - pthread_attr_t thread_attributes; - // We're running now this->ahead = 1; @@ -472,12 +512,8 @@ static void consumer_read_ahead_start( mlt_consumer this ) // Create the condition pthread_cond_init( &this->cond, NULL ); - // Inherit the scheduling priority - pthread_attr_init( &thread_attributes ); - pthread_attr_setinheritsched( &thread_attributes, PTHREAD_INHERIT_SCHED ); - // Create the read ahead - pthread_create( &this->ahead_thread, &thread_attributes, consumer_read_ahead_thread, this ); + pthread_create( &this->ahead_thread, NULL, consumer_read_ahead_thread, this ); } static void consumer_read_ahead_stop( mlt_consumer this ) @@ -588,25 +624,25 @@ int mlt_consumer_stop( mlt_consumer this ) { // Get the properies mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); + char *debug = mlt_properties_get( MLT_CONSUMER_PROPERTIES( this ), "debug" ); + + // Just in case... + if ( debug ) fprintf( stderr, "%s: stopping put waiting\n", debug ); + pthread_mutex_lock( &this->put_mutex ); + this->put_active = 0; + pthread_cond_broadcast( &this->put_cond ); + pthread_mutex_unlock( &this->put_mutex ); // Stop the consumer + if ( debug ) fprintf( stderr, "%s: stopping consumer\n", debug ); if ( this->stop != NULL ) this->stop( this ); // Check if the user has requested real time or not and stop if necessary + if ( debug ) fprintf( stderr, "%s: stopping read_ahead\n", debug ); if ( mlt_properties_get_int( properties, "real_time" ) ) consumer_read_ahead_stop( this ); - // Just in case... - pthread_mutex_lock( &this->put_mutex ); - if ( this->put != NULL ) - { - mlt_frame_close( this->put ); - this->put = NULL; - } - pthread_cond_broadcast( &this->put_cond ); - pthread_mutex_unlock( &this->put_mutex ); - // Kill the test card mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL ); @@ -614,6 +650,8 @@ int mlt_consumer_stop( mlt_consumer this ) if ( mlt_properties_get( properties, "post" ) ) system( mlt_properties_get( properties, "post" ) ); + if ( debug ) fprintf( stderr, "%s: stopped\n", debug ); + return 0; } @@ -639,19 +677,24 @@ void mlt_consumer_close( mlt_consumer this ) // Get the childs close function void ( *consumer_close )( ) = this->close; - // Make sure it only gets called once - this->close = NULL; - this->parent.close = NULL; - - // Destroy the push mutex and condition - pthread_cond_broadcast( &this->put_cond ); - pthread_mutex_destroy( &this->put_mutex ); - pthread_cond_destroy( &this->put_cond ); + if ( consumer_close ) + { + // Just in case... + //mlt_consumer_stop( this ); - // Call the childs close if available - if ( consumer_close != NULL ) + this->close = NULL; consumer_close( this ); + } else + { + // Make sure it only gets called once + this->parent.close = NULL; + + // Destroy the push mutex and condition + pthread_mutex_destroy( &this->put_mutex ); + pthread_cond_destroy( &this->put_cond ); + mlt_service_close( &this->parent ); + } } }