From a038d8a6f14b30dd52242d2f69601e6393e44475 Mon Sep 17 00:00:00 2001 From: lilo_booter Date: Fri, 30 Apr 2004 13:23:13 +0000 Subject: [PATCH] Sundry consumer modifications; albino compile fix; minor mods to avformat producer git-svn-id: https://mlt.svn.sourceforge.net/svnroot/mlt/trunk/mlt@296 d19143bc-622f-0410-bfdd-b5b2a6649095 --- src/albino/Makefile | 2 +- src/framework/mlt_consumer.c | 16 ++++-- src/modules/avformat/consumer_avformat.c | 42 ++++++++++++++-- src/modules/avformat/producer_avformat.c | 19 ++++--- src/modules/core/filter_mirror.c | 36 +++++++++++++ src/modules/fezzik.ini | 4 +- src/modules/sdl/consumer_sdl.c | 83 +++++++++++++++++------------ 7 files changed, 150 insertions(+), 52 deletions(-) diff --git a/src/albino/Makefile b/src/albino/Makefile index 4947457..05daf22 100644 --- a/src/albino/Makefile +++ b/src/albino/Makefile @@ -6,7 +6,7 @@ OBJS = albino.o CFLAGS += -I.. -rdynamic -LDFLAGS += -L../miracle -lmiracle -L../valerie -lvalerie -L../miracle -lmiracle +LDFLAGS += -L../miracle -lmiracle -L../valerie -lvalerie -L../miracle -lmiracle -L../framework -lmlt SRCS := $(OBJS:.o=.c) diff --git a/src/framework/mlt_consumer.c b/src/framework/mlt_consumer.c index 5f00b6c..ef2760e 100644 --- a/src/framework/mlt_consumer.c +++ b/src/framework/mlt_consumer.c @@ -234,6 +234,8 @@ static void *consumer_read_ahead_thread( void *arg ) // Get the properties of the consumer mlt_properties properties = mlt_consumer_properties( this ); + char *service = mlt_properties_get( properties, "mlt_service" ); + // Get the width and height int width = mlt_properties_get_int( properties, "width" ); int height = mlt_properties_get_int( properties, "height" ); @@ -269,13 +271,14 @@ static void *consumer_read_ahead_thread( void *arg ) while ( this->ahead ) { // Put the current frame into the queue + time_difference( &ante ); pthread_mutex_lock( &this->mutex ); while( this->ahead && mlt_deque_count( this->queue ) >= buffer ) pthread_cond_wait( &this->cond, &this->mutex ); mlt_deque_push_back( this->queue, frame ); pthread_cond_broadcast( &this->cond ); pthread_mutex_unlock( &this->mutex ); - time_wait += time_difference( &ante ); + time_wait = time_difference( &ante ); // Get the next frame frame = mlt_consumer_get_frame( this ); @@ -294,8 +297,10 @@ static void *consumer_read_ahead_thread( void *arg ) count = 1; } + //fprintf( stderr, "%s: %d %d %lld %lld\n", service, mlt_deque_count( this->queue ), buffer, ( time_frame + time_image ) / count, ( time_wait / count ) ); + // Get the image - if ( ( time_frame + time_image ) / count < ( 40000 - ( time_wait / count ) ) ) + if ( ( time_frame + time_image ) / count < 40000 ) { // Get the image, mark as rendered and time it mlt_frame_get_image( frame, &image, &this->format, &width, &height, 0 ); @@ -307,16 +312,19 @@ static void *consumer_read_ahead_thread( void *arg ) } else { + fprintf( stderr, "Dropped a frame for %s\n", service ); + // Increment the number of sequentially skipped frames skipped ++; + time_wait = 0; + // If we've reached an unacceptable level, reset everything if ( skipped > 10 ) { skipped = 0; time_frame = 0; time_image = 0; - time_wait = 0; count = 0; } } @@ -402,7 +410,7 @@ mlt_frame mlt_consumer_rt_frame( mlt_consumer this ) int buffer = mlt_properties_get_int( properties, "buffer" ); consumer_read_ahead_start( this ); if ( buffer > 1 ) - size = buffer / 2; + size = buffer; } // Get frame from queue diff --git a/src/modules/avformat/consumer_avformat.c b/src/modules/avformat/consumer_avformat.c index 77142e2..52fe9da 100644 --- a/src/modules/avformat/consumer_avformat.c +++ b/src/modules/avformat/consumer_avformat.c @@ -29,7 +29,7 @@ #include #include #include - +#include #include // avformat header files @@ -420,6 +420,13 @@ void close_video(AVFormatContext *oc, AVStream *st) avcodec_close(&st->codec); } +static inline long time_difference( struct timeval *time1 ) +{ + struct timeval time2; + gettimeofday( &time2, NULL ); + return time2.tv_sec * 1000000 + time2.tv_usec - time1->tv_sec * 1000000 - time1->tv_usec; +} + /** The main thread - the argument is simply the consumer. */ @@ -434,6 +441,12 @@ static void *consumer_thread( void *arg ) // Get the terminate on pause property int terminate_on_pause = mlt_properties_get_int( properties, "terminate_on_pause" ); + // Determine if feed is slow (for realtime stuff) + int real_time_output = mlt_properties_get_int( properties, "real_time" ); + + // Time structures + struct timeval ante; + // Get the frame rate int fps = mlt_properties_get_double( properties, "fps" ); @@ -493,6 +506,10 @@ static void *consumer_thread( void *arg ) // Loop variable int i; + // Frames despatched + long int frames = 0; + long int total_time = 0; + // Determine the format AVOutputFormat *fmt = NULL; char *filename = mlt_properties_get( properties, "target" ); @@ -584,9 +601,6 @@ static void *consumer_thread( void *arg ) } } - if ( url_is_streamed( &oc->pb ) ) - fprintf( stderr, "FUCK!\n" ); - // Write the stream header, if any if ( mlt_properties_get_int( properties, "running" ) ) av_write_header( oc ); @@ -601,6 +615,9 @@ static void *consumer_thread( void *arg ) if ( audio_st == NULL && video_st == NULL ) mlt_properties_set_int( properties, "running", 0 ); + // Get the starting time (can ignore the times above) + gettimeofday( &ante, NULL ); + // Loop while running while( mlt_properties_get_int( properties, "running" ) ) { @@ -610,6 +627,9 @@ static void *consumer_thread( void *arg ) // Check that we have a frame to work with if ( frame != NULL ) { + // Increment frames despatched + frames ++; + // Default audio args frame_properties = mlt_frame_properties( frame ); @@ -619,6 +639,7 @@ static void *consumer_thread( void *arg ) samples = mlt_sample_calculator( fps, frequency, count ); mlt_frame_get_audio( frame, &pcm, &aud_fmt, &frequency, &channels, &samples ); sample_fifo_append( fifo, pcm, samples * channels ); + total_time += ( samples * 1000000 ) / frequency; } // Encode the image @@ -735,6 +756,19 @@ static void *consumer_thread( void *arg ) } } } + + if ( real_time_output && frames % 25 == 0 ) + { + long passed = time_difference( &ante ); + long pending = ( ( ( long )sample_fifo_used( fifo ) * 1000 ) / frequency ) * 1000; + passed -= pending; + if ( passed < total_time ) + { + long total = ( total_time - passed ); + struct timespec t = { total / 1000000, ( total % 1000000 ) * 1000 }; + nanosleep( &t, NULL ); + } + } } // close each codec diff --git a/src/modules/avformat/producer_avformat.c b/src/modules/avformat/producer_avformat.c index 9da63d4..e0c246d 100644 --- a/src/modules/avformat/producer_avformat.c +++ b/src/modules/avformat/producer_avformat.c @@ -267,6 +267,9 @@ static int producer_open( mlt_producer this, char *file ) mlt_properties_set_position( properties, "length", frames - 1 ); } + // Check if we're seekable + mlt_properties_set_int( properties, "seekable", av_seek_frame( context, -1, 0 ) == 0 ); + // Find default audio and video streams find_default_streams( context, &audio_index, &video_index ); @@ -700,6 +703,9 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form // Get the audio_index int index = mlt_properties_get_int( properties, "audio_index" ); + // Get the seekable status + int seekable = mlt_properties_get_int( properties, "seekable" ); + // Obtain the expected frame numer mlt_position expected = mlt_properties_get_position( properties, "audio_expected" ); @@ -729,7 +735,6 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form // Flag for paused (silence) int paused = 0; - int locked = 0; // Lock the mutex now avformat_lock( ); @@ -775,12 +780,11 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form else { // Set to the real timecode - av_seek_frame( context, -1, real_timecode * 1000000.0 ); + if ( !seekable || av_seek_frame( context, -1, real_timecode * 1000000.0 ) != 0 ) + paused = 1; // Clear the usage in the audio buffer audio_used = 0; - - locked = 1; } } @@ -865,7 +869,7 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form mlt_properties_set_double( properties, "discrepancy", discrepancy ); } - if ( !ignore && discrepancy * current_pts <= ( real_timecode - 0.02 ) ) + if ( seekable && ( !ignore && discrepancy * current_pts <= ( real_timecode - 0.02 ) ) ) ignore = 1; } @@ -901,8 +905,9 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); } - // Regardless of speed, we expect to get the next frame (cos we ain't too bright) - mlt_properties_set_position( properties, "audio_expected", position + 1 ); + // Regardless of speed (other than paused), we expect to get the next frame + if ( !paused ) + mlt_properties_set_position( properties, "audio_expected", position + 1 ); // Unlock the mutex now avformat_unlock( ); diff --git a/src/modules/core/filter_mirror.c b/src/modules/core/filter_mirror.c index bc8927a..e007ac2 100644 --- a/src/modules/core/filter_mirror.c +++ b/src/modules/core/filter_mirror.c @@ -145,6 +145,42 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format } } } + else if ( !strcmp( mirror, "xdiagonal" ) ) + { + uint8_t *end = ( uint8_t *)*image + *width * *height * 2; + uint8_t *p = NULL; + uint8_t *q = NULL; + int i; + int j; + for ( i = 0; i < *height; i ++ ) + { + p = ( uint8_t * )*image + ( i + 1 ) * *width * 2; + q = end - ( i + 1 ) * *width * 2; + j = ( ( *width * ( *height - i ) ) / *height ) / 2; + if ( !reverse ) + { + while ( j -- ) + { + *q ++ = *( p - 2 ); + *q ++ = *( p - 3 ); + *q ++ = *( p - 4 ); + *q ++ = *( p - 1 ); + p -= 4; + } + } + else + { + while ( j -- ) + { + *( p - 2 ) = *q ++; + *( p - 3 ) = *q ++; + *( p - 4 ) = *q ++; + *( p - 1 ) = *q ++; + p -= 4; + } + } + } + } else if ( !strcmp( mirror, "flip" ) ) { uint8_t t[ 4 ]; diff --git a/src/modules/fezzik.ini b/src/modules/fezzik.ini index 9e7caaa..153f60d 100644 --- a/src/modules/fezzik.ini +++ b/src/modules/fezzik.ini @@ -6,7 +6,7 @@ # The names of the services on the right dictate the preference used (if unavailable # the second and third are applied as applicable). -deinterlace=deinterlace,avdeinterlace +deinterlace=avdeinterlace rescaler=mcrescale,gtkrescale,rescale resizer=resize -resampler=resample,soxresample,avresample +resampler=soxresample,avresample diff --git a/src/modules/sdl/consumer_sdl.c b/src/modules/sdl/consumer_sdl.c index 6b9ad0c..b2dcd90 100644 --- a/src/modules/sdl/consumer_sdl.c +++ b/src/modules/sdl/consumer_sdl.c @@ -489,9 +489,6 @@ static int consumer_play_video( consumer_sdl this, mlt_frame frame ) } } - // Close the frame - mlt_frame_close( frame ); - return 0; } @@ -518,6 +515,7 @@ static void *consumer_thread( void *arg ) struct timespec tm; mlt_frame next = NULL; mlt_frame frame = NULL; + mlt_properties properties = NULL; if ( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE ) < 0 ) { @@ -537,23 +535,24 @@ static void *consumer_thread( void *arg ) // Ensure that we have a frame if ( frame != NULL ) { + // Get the frame properties + properties = mlt_frame_properties( frame ); + // Play audio init_audio = consumer_play_audio( this, frame, init_audio, &duration ); - if ( this->playing ) + // Determine the start time now + if ( this->playing && start == 0 ) { // Get the current time gettimeofday( &now, NULL ); - // Determine elapsed time - if ( start == 0 ) - start = ( int64_t )now.tv_sec * 1000000 + now.tv_usec; - else - elapsed = ( ( int64_t )now.tv_sec * 1000000 + now.tv_usec) - start; + // Determine start time + start = ( int64_t )now.tv_sec * 1000000 + now.tv_usec; } // Set playtime for this frame - mlt_properties_set_position( mlt_frame_properties( frame ), "playtime", playtime ); + mlt_properties_set_position( properties, "playtime", playtime ); // Push this frame to the back of the queue mlt_deque_push_back( this->queue, frame ); @@ -562,41 +561,57 @@ static void *consumer_thread( void *arg ) playtime += ( duration * 1000 ); } - if ( this->playing ) + // Pop the next frame + next = mlt_deque_pop_front( this->queue ); + + while ( next != NULL && this->playing ) { - // Pop the next frame - next = mlt_deque_pop_front( this->queue ); + // Get the properties + properties = mlt_frame_properties( next ); + + // Get the current time + gettimeofday( &now, NULL ); + + // Get the elapsed time + elapsed = ( ( int64_t )now.tv_sec * 1000000 + now.tv_usec ) - start; // See if we have to delay the display of the current frame - if ( next != NULL && mlt_properties_get_int( mlt_frame_properties( next ), "rendered" ) == 1 ) + if ( mlt_properties_get_int( properties, "rendered" ) == 1 ) { - mlt_position scheduled = mlt_properties_get_position( mlt_frame_properties( next ), "playtime" ) + 5000; - if ( scheduled > elapsed && mlt_deque_count( this->queue ) > 25 ) + // Obtain the scheduled playout time + mlt_position scheduled = mlt_properties_get_position( properties, "playtime" ); + + // Determine the difference between the elapsed time and the scheduled playout time + mlt_position difference = scheduled - elapsed; + + // If the frame is quite some way in the future, go get another + if ( difference > 80000 && mlt_deque_count( this->queue ) < 6 ) + break; + + // Smooth playback a bit + if ( difference > 20000 && mlt_properties_get_double( properties, "_speed" ) == 1.0 ) { - tm.tv_sec = ( scheduled - elapsed ) / 1000000; - tm.tv_nsec = ( ( scheduled - elapsed ) % 1000000 ) * 1000; + tm.tv_sec = difference / 1000000; + tm.tv_nsec = ( difference % 1000000 ) * 1000; nanosleep( &tm, NULL ); + } - // Show current frame + // Show current frame if not too old + if ( difference > -10000 || mlt_properties_get_double( properties, "_speed" ) != 1.0 ) consumer_play_video( this, next ); - } - else if ( scheduled > elapsed ) - { - // More time to kill - mlt_deque_push_front( this->queue, next ); - } else - { - // Show current frame - consumer_play_video( this, next ); - } - } - else - { - // This is an unrendered frame - just close it - mlt_frame_close( next ); + start = start - difference; } + + // This is an unrendered frame - just close it + mlt_frame_close( next ); + + // Pop the next frame + next = mlt_deque_pop_front( this->queue ); } + + if ( next != NULL ) + mlt_deque_push_front( this->queue, next ); } // internal cleanup -- 1.7.4.4