X-Git-Url: http://research.m1stereo.tv/gitweb?a=blobdiff_plain;f=src%2Fmodules%2Fsdl%2Fconsumer_sdl.c;h=aac59c887db54491e8b199b8bc319f27e0a4c0ab;hb=11410cf74f5de6c8f4460a8b12119fa5558153a1;hp=6b9ad0ce20549a61b7ad58bed1a28388d1b9819a;hpb=757e8d55530954c3002b71f78d5027a222e810f7;p=melted diff --git a/src/modules/sdl/consumer_sdl.c b/src/modules/sdl/consumer_sdl.c index 6b9ad0c..aac59c8 100644 --- a/src/modules/sdl/consumer_sdl.c +++ b/src/modules/sdl/consumer_sdl.c @@ -55,6 +55,7 @@ struct consumer_sdl_s int sdl_flags; SDL_Surface *sdl_screen; SDL_Overlay *sdl_overlay; + SDL_Rect rect; uint8_t *buffer; }; @@ -109,6 +110,9 @@ mlt_consumer consumer_sdl_init( char *arg ) // Default progressive true mlt_properties_set_int( this->properties, "progressive", 0 ); + // Default audio buffer + mlt_properties_set_int( this->properties, "audio_buffer", 1024 ); + // Get sample aspect ratio this->aspect_ratio = mlt_properties_get_double( this->properties, "aspect_ratio" ); @@ -142,7 +146,7 @@ mlt_consumer consumer_sdl_init( char *arg ) } // Set the sdl flags - this->sdl_flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL | SDL_RESIZABLE; + this->sdl_flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL | SDL_RESIZABLE | SDL_DOUBLEBUF; // Allow thread to be started/stopped parent->start = consumer_start; @@ -242,7 +246,7 @@ static void sdl_fill_audio( void *udata, uint8_t *stream, int len ) if ( this->audio_avail >= len ) { // Place in the audio buffer - SDL_MixAudio( stream, this->audio_buffer, len, ( int )( ( float )SDL_MIX_MAXVOLUME * volume ) ); + memcpy( stream, this->audio_buffer, len ); // Remove len from the audio available this->audio_avail -= len; @@ -303,13 +307,15 @@ static int consumer_play_audio( consumer_sdl this, mlt_frame frame, int init_aud SDL_AudioSpec request; SDL_AudioSpec got; + int audio_buffer = mlt_properties_get_int( properties, "audio_buffer" ); + // specify audio format memset( &request, 0, sizeof( SDL_AudioSpec ) ); this->playing = 0; request.freq = frequency; request.format = AUDIO_S16; request.channels = channels; - request.samples = 1024; + request.samples = audio_buffer; request.callback = sdl_fill_audio; request.userdata = (void *)this; if ( SDL_OpenAudio( &request, &got ) != 0 ) @@ -406,8 +412,6 @@ static int consumer_play_video( consumer_sdl this, mlt_frame frame ) if ( this->sdl_screen == NULL || changed ) { - SDL_Rect rect; - // Determine frame's display aspect ratio float frame_aspect = mlt_frame_get_aspect_ratio( frame ) * this->width / this->height; @@ -423,18 +427,18 @@ static int consumer_play_video( consumer_sdl this, mlt_frame frame ) if ( ( (int)( this_aspect * 1000 ) == (int)( this->display_aspect * 1000 ) ) && ( (int)( mlt_frame_get_aspect_ratio( frame ) * 1000 ) == (int)( this->aspect_ratio * 1000 ) ) ) { - rect.w = this->window_width; - rect.h = this->window_height; + this->rect.w = this->window_width; + this->rect.h = this->window_height; } else { // Use hardware scaler to normalise display aspect ratio - rect.w = frame_aspect / this_aspect * this->window_width + 0.5; - rect.h = this->window_height; - if ( rect.w > this->window_width ) + this->rect.w = frame_aspect / this_aspect * this->window_width + 0.5; + this->rect.h = this->window_height; + if ( this->rect.w > this->window_width ) { - rect.w = this->window_width; - rect.h = this_aspect / frame_aspect * this->window_height + 0.5; + this->rect.w = this->window_width; + this->rect.h = this_aspect / frame_aspect * this->window_height + 0.5; } } } @@ -442,23 +446,23 @@ static int consumer_play_video( consumer_sdl this, mlt_frame frame ) // not corresponding exactly with image resolution. else if ( (int)( this_aspect * 1000 ) == (int)( this->display_aspect * 1000 ) ) { - rect.w = this->window_width; - rect.h = this->window_height; + this->rect.w = this->window_width; + this->rect.h = this->window_height; } // Use hardware scaler to normalise sample aspect ratio else if ( this->window_height * frame_aspect > this->window_width ) { - rect.w = this->window_width; - rect.h = this->window_width / frame_aspect + 0.5; + this->rect.w = this->window_width; + this->rect.h = this->window_width / frame_aspect + 0.5; } else { - rect.w = this->window_height * frame_aspect + 0.5; - rect.h = this->window_height; + this->rect.w = this->window_height * frame_aspect + 0.5; + this->rect.h = this->window_height; } - rect.x = ( this->window_width - rect.w ) / 2; - rect.y = ( this->window_height - rect.h ) / 2; + this->rect.x = ( this->window_width - this->rect.w ) / 2; + this->rect.y = ( this->window_height - this->rect.h ) / 2; // Force an overlay recreation if ( this->sdl_overlay != NULL ) @@ -469,13 +473,23 @@ static int consumer_play_video( consumer_sdl this, mlt_frame frame ) if ( this->sdl_screen != NULL ) { - SDL_SetClipRect( this->sdl_screen, &rect ); + SDL_SetClipRect( this->sdl_screen, &this->rect ); sdl_lock_display(); this->sdl_overlay = SDL_CreateYUVOverlay( this->width, this->height, SDL_YUY2_OVERLAY, this->sdl_screen ); sdl_unlock_display(); } } + if ( mlt_properties_get_int( properties, "changed" ) ) + { + sdl_lock_display(); + this->sdl_screen = SDL_SetVideoMode( this->window_width, this->window_height, 0, this->sdl_flags ); + SDL_SetClipRect( this->sdl_screen, &this->rect ); + SDL_Flip( this->sdl_screen ); + sdl_unlock_display(); + mlt_properties_set_int( properties, "changed", 0 ); + } + if ( this->sdl_screen != NULL && this->sdl_overlay != NULL ) { this->buffer = this->sdl_overlay->pixels[ 0 ]; @@ -487,10 +501,8 @@ static int consumer_play_video( consumer_sdl this, mlt_frame frame ) SDL_DisplayYUVOverlay( this->sdl_overlay, &this->sdl_screen->clip_rect ); } } - } - // Close the frame - mlt_frame_close( frame ); + } return 0; } @@ -518,6 +530,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 +550,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 +576,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 >= 30000 && mlt_deque_count( this->queue ) < 10 ) + 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