X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fframework%2Fmlt_consumer.c;h=2a350a76abf8ecf4e529bfdcd2d9cee93a9b3bb3;hb=cba203d87044ecd96a4f1f849ff46377faa38fad;hp=05f69e026bd123c51560851aca27ef148dd1a427;hpb=59bfa7dc0635c8efefa3798066de9a3a326d8430;p=mlt diff --git a/src/framework/mlt_consumer.c b/src/framework/mlt_consumer.c index 05f69e02..2a350a76 100644 --- a/src/framework/mlt_consumer.c +++ b/src/framework/mlt_consumer.c @@ -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;