X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=src%2Fmodules%2Fsdl%2Fconsumer_sdl_preview.c;h=6f33e2c230ec9d5f962b2eac9fa56bdb63e7d10b;hb=76ec3ea18ead8d1add8703e05c5f734738a54ec1;hp=ec2d608fca50f65aa96277077579037139a1a140;hpb=b4b1daf82f6d8da343a5606266716de25b94660f;p=mlt diff --git a/src/modules/sdl/consumer_sdl_preview.c b/src/modules/sdl/consumer_sdl_preview.c index ec2d608f..6f33e2c2 100644 --- a/src/modules/sdl/consumer_sdl_preview.c +++ b/src/modules/sdl/consumer_sdl_preview.c @@ -1,6 +1,6 @@ /* * consumer_sdl_preview.c -- A Simple DirectMedia Layer consumer - * Copyright (C) 2004-2005 Ushodaya Enterprises Limited + * Copyright (C) 2004-2005, 2010 Ushodaya Enterprises Limited * Author: Charles Yates * * This library is free software; you can redistribute it and/or @@ -22,13 +22,15 @@ #include #include #include +#include #include #include #include -#include -#include +#include +#include +#include -pthread_mutex_t mlt_sdl_mutex = PTHREAD_MUTEX_INITIALIZER; +extern pthread_mutex_t mlt_sdl_mutex; typedef struct consumer_sdl_s *consumer_sdl; @@ -44,6 +46,7 @@ struct consumer_sdl_s int running; int sdl_flags; double last_speed; + mlt_position last_position; pthread_cond_t refresh_cond; pthread_mutex_t refresh_mutex; @@ -56,19 +59,20 @@ struct consumer_sdl_s static int consumer_start( mlt_consumer parent ); static int consumer_stop( mlt_consumer parent ); static int consumer_is_stopped( mlt_consumer parent ); +static void consumer_purge( mlt_consumer parent ); static void consumer_close( mlt_consumer parent ); static void *consumer_thread( void * ); -static void consumer_frame_show_cb( mlt_consumer sdl, mlt_consumer this, mlt_frame frame ); -static void consumer_sdl_event_cb( mlt_consumer sdl, mlt_consumer this, SDL_Event *event ); -static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer this, char *name ); +static void consumer_frame_show_cb( mlt_consumer sdl, mlt_consumer self, mlt_frame frame ); +static void consumer_sdl_event_cb( mlt_consumer sdl, mlt_consumer self, SDL_Event *event ); +static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer self, char *name ); mlt_consumer consumer_sdl_preview_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { - consumer_sdl this = calloc( sizeof( struct consumer_sdl_s ), 1 ); - if ( this != NULL && mlt_consumer_init( &this->parent, this, profile ) == 0 ) + consumer_sdl self = calloc( 1, sizeof( struct consumer_sdl_s ) ); + if ( self != NULL && mlt_consumer_init( &self->parent, self, profile ) == 0 ) { // Get the parent consumer object - mlt_consumer parent = &this->parent; + mlt_consumer parent = &self->parent; // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( parent ); @@ -85,32 +89,38 @@ mlt_consumer consumer_sdl_preview_init( mlt_profile profile, mlt_service_type ty } // Create child consumers - this->play = mlt_factory_consumer( profile, "sdl", arg ); - this->still = mlt_factory_consumer( profile, "sdl_still", arg ); - mlt_properties_set( MLT_CONSUMER_PROPERTIES( parent ), "real_time", "0" ); - mlt_properties_set( MLT_CONSUMER_PROPERTIES( parent ), "rescale", "nearest" ); + self->play = mlt_factory_consumer( profile, "sdl", arg ); + self->still = mlt_factory_consumer( profile, "sdl_still", arg ); + mlt_properties_set( properties, "rescale", "nearest" ); + mlt_properties_set( properties, "deinterlace_method", "onefield" ); + mlt_properties_set_int( properties, "prefill", 1 ); + mlt_properties_set_int( properties, "top_field_first", -1 ); + parent->close = consumer_close; parent->start = consumer_start; parent->stop = consumer_stop; parent->is_stopped = consumer_is_stopped; - this->joined = 1; - mlt_events_listen( MLT_CONSUMER_PROPERTIES( this->play ), this, "consumer-frame-show", ( mlt_listener )consumer_frame_show_cb ); - mlt_events_listen( MLT_CONSUMER_PROPERTIES( this->still ), this, "consumer-frame-show", ( mlt_listener )consumer_frame_show_cb ); - mlt_events_listen( MLT_CONSUMER_PROPERTIES( this->play ), this, "consumer-sdl-event", ( mlt_listener )consumer_sdl_event_cb ); - mlt_events_listen( MLT_CONSUMER_PROPERTIES( this->still ), this, "consumer-sdl-event", ( mlt_listener )consumer_sdl_event_cb ); - pthread_cond_init( &this->refresh_cond, NULL ); - pthread_mutex_init( &this->refresh_mutex, NULL ); - mlt_events_listen( MLT_CONSUMER_PROPERTIES( parent ), this, "property-changed", ( mlt_listener )consumer_refresh_cb ); + parent->purge = consumer_purge; + self->joined = 1; + mlt_events_listen( MLT_CONSUMER_PROPERTIES( self->play ), self, "consumer-frame-show", ( mlt_listener )consumer_frame_show_cb ); + mlt_events_listen( MLT_CONSUMER_PROPERTIES( self->still ), self, "consumer-frame-show", ( mlt_listener )consumer_frame_show_cb ); + mlt_events_listen( MLT_CONSUMER_PROPERTIES( self->play ), self, "consumer-sdl-event", ( mlt_listener )consumer_sdl_event_cb ); + mlt_events_listen( MLT_CONSUMER_PROPERTIES( self->still ), self, "consumer-sdl-event", ( mlt_listener )consumer_sdl_event_cb ); + pthread_cond_init( &self->refresh_cond, NULL ); + pthread_mutex_init( &self->refresh_mutex, NULL ); + mlt_events_listen( MLT_CONSUMER_PROPERTIES( parent ), self, "property-changed", ( mlt_listener )consumer_refresh_cb ); + mlt_events_register( properties, "consumer-sdl-paused", NULL ); return parent; } - free( this ); + free( self ); return NULL; } void consumer_frame_show_cb( mlt_consumer sdl, mlt_consumer parent, mlt_frame frame ) { - consumer_sdl this = parent->child; - this->last_speed = mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame ), "_speed" ); + consumer_sdl self = parent->child; + self->last_speed = mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame ), "_speed" ); + self->last_position = mlt_frame_get_position( frame ); mlt_events_fire( MLT_CONSUMER_PROPERTIES( parent ), "consumer-frame-show", frame, NULL ); } @@ -123,24 +133,24 @@ static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer parent, char *na { if ( !strcmp( name, "refresh" ) ) { - consumer_sdl this = parent->child; - pthread_mutex_lock( &this->refresh_mutex ); - this->refresh_count = this->refresh_count <= 0 ? 1 : this->refresh_count ++; - pthread_cond_broadcast( &this->refresh_cond ); - pthread_mutex_unlock( &this->refresh_mutex ); + consumer_sdl self = parent->child; + pthread_mutex_lock( &self->refresh_mutex ); + self->refresh_count = self->refresh_count <= 0 ? 1 : self->refresh_count + 1; + pthread_cond_broadcast( &self->refresh_cond ); + pthread_mutex_unlock( &self->refresh_mutex ); } } static int consumer_start( mlt_consumer parent ) { - consumer_sdl this = parent->child; + consumer_sdl self = parent->child; - if ( !this->running ) + if ( !self->running ) { // properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( parent ); - mlt_properties play = MLT_CONSUMER_PROPERTIES( this->play ); - mlt_properties still = MLT_CONSUMER_PROPERTIES( this->still ); + mlt_properties play = MLT_CONSUMER_PROPERTIES( self->play ); + mlt_properties still = MLT_CONSUMER_PROPERTIES( self->still ); char *window_id = mlt_properties_get( properties, "window_id" ); char *audio_driver = mlt_properties_get( properties, "audio_driver" ); @@ -151,9 +161,9 @@ static int consumer_start( mlt_consumer parent ) consumer_stop( parent ); - this->running = 1; - this->joined = 0; - this->last_speed = 1; + self->running = 1; + self->joined = 0; + self->last_speed = 1; if ( output_display != NULL ) setenv( "DISPLAY", output_display, 1 ); @@ -170,7 +180,10 @@ static int consumer_start( mlt_consumer parent ) if ( audio_device != NULL ) setenv( "AUDIODEV", audio_device, 1 ); - if ( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE ) < 0 ) + pthread_mutex_lock( &mlt_sdl_mutex ); + int ret = SDL_Init( SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE ); + pthread_mutex_unlock( &mlt_sdl_mutex ); + if ( ret < 0 ) { fprintf( stderr, "Failed to initialize SDL: %s\n", SDL_GetError() ); return -1; @@ -188,12 +201,12 @@ static int consumer_start( mlt_consumer parent ) mlt_properties_set_int( play, "progressive", progressive ); mlt_properties_set_int( still, "progressive", progressive ); - mlt_properties_pass_list( play, properties, "resize,rescale,width,height,aspect_ratio,display_ratio,volume" ); - mlt_properties_pass_list( still, properties, "resize,rescale,width,height,aspect_ratio,display_ratio" ); - mlt_properties_pass_list( play, properties, "deinterlace_method" ); - mlt_properties_pass_list( still, properties, "deinterlace_method" ); - mlt_properties_pass_list( play, properties, "preview_off,preview_format,window_background" ); - mlt_properties_pass_list( still, properties, "preview_off,preview_format,window_background" ); + mlt_properties_pass_list( play, properties, + "deinterlace_method,resize,rescale,width,height,aspect_ratio,display_ratio,preview_off,preview_format,window_background" + ",top_field_first,volume,real_time,buffer,prefill,audio_off,frequency,drop_max" ); + mlt_properties_pass_list( still, properties, + "deinterlace_method,resize,rescale,width,height,aspect_ratio,display_ratio,preview_off,preview_format,window_background" + ",top_field_first"); mlt_properties_pass( play, properties, "play." ); mlt_properties_pass( still, properties, "still." ); @@ -205,16 +218,17 @@ static int consumer_start( mlt_consumer parent ) mlt_properties_set_int( play, "put_mode", 1 ); mlt_properties_set_int( still, "put_mode", 1 ); + mlt_properties_set_int( play, "terminate_on_pause", 1 ); // Start the still producer just to initialise the gui - mlt_consumer_start( this->still ); - this->active = this->still; + mlt_consumer_start( self->still ); + self->active = self->still; // Inform child consumers that we control the sdl mlt_properties_set_int( play, "sdl_started", 1 ); mlt_properties_set_int( still, "sdl_started", 1 ); - pthread_create( &this->thread, NULL, consumer_thread, this ); + pthread_create( &self->thread, NULL, consumer_thread, self ); } return 0; @@ -223,9 +237,9 @@ static int consumer_start( mlt_consumer parent ) static int consumer_stop( mlt_consumer parent ) { // Get the actual object - consumer_sdl this = parent->child; + consumer_sdl self = parent->child; - if ( this->joined == 0 ) + if ( self->joined == 0 ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( parent ); int app_locked = mlt_properties_get_int( properties, "app_locked" ); @@ -235,17 +249,19 @@ static int consumer_stop( mlt_consumer parent ) if ( app_locked && unlock ) unlock( ); // Kill the thread and clean up - this->running = 0; + self->running = 0; - pthread_mutex_lock( &this->refresh_mutex ); - pthread_cond_broadcast( &this->refresh_cond ); - pthread_mutex_unlock( &this->refresh_mutex ); - if ( this->thread ) - pthread_join( this->thread, NULL ); - this->joined = 1; + pthread_mutex_lock( &self->refresh_mutex ); + pthread_cond_broadcast( &self->refresh_cond ); + pthread_mutex_unlock( &self->refresh_mutex ); +#ifndef WIN32 + if ( self->thread ) +#endif + pthread_join( self->thread, NULL ); + self->joined = 1; if ( app_locked && lock ) lock( ); - + pthread_mutex_lock( &mlt_sdl_mutex ); SDL_Quit( ); pthread_mutex_unlock( &mlt_sdl_mutex ); @@ -256,39 +272,51 @@ static int consumer_stop( mlt_consumer parent ) static int consumer_is_stopped( mlt_consumer parent ) { - consumer_sdl this = parent->child; - return !this->running; + consumer_sdl self = parent->child; + return !self->running; +} + +void consumer_purge( mlt_consumer parent ) +{ + consumer_sdl self = parent->child; + if ( self->running ) + mlt_consumer_purge( self->play ); } static void *consumer_thread( void *arg ) { // Identify the arg - consumer_sdl this = arg; + consumer_sdl self = arg; // Get the consumer - mlt_consumer consumer = &this->parent; + mlt_consumer consumer = &self->parent; // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); // internal intialization - int first = 1; mlt_frame frame = NULL; int last_position = -1; + int eos = 0; + int eos_threshold = 20; + if ( self->play ) + eos_threshold = eos_threshold + mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( self->play ), "buffer" ); // Determine if the application is dealing with the preview int preview_off = mlt_properties_get_int( properties, "preview_off" ); - this->refresh_count = 0; + pthread_mutex_lock( &self->refresh_mutex ); + self->refresh_count = 0; + pthread_mutex_unlock( &self->refresh_mutex ); // Loop until told not to - while( this->running ) + while( self->running ) { // Get a frame from the attached producer frame = mlt_consumer_get_frame( consumer ); // Ensure that we have a frame - if ( this->running && frame != NULL ) + if ( self->running && frame != NULL ) { // Get the speed of the frame double speed = mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame ), "_speed" ); @@ -317,59 +345,110 @@ static void *consumer_thread( void *arg ) if ( speed == 1.0 ) { if ( last_position != -1 && last_position + 1 != mlt_frame_get_position( frame ) ) - mlt_consumer_purge( this->play ); + mlt_consumer_purge( self->play ); last_position = mlt_frame_get_position( frame ); } else { - //mlt_consumer_purge( this->play ); + //mlt_consumer_purge( self->play ); last_position = -1; } - // If we're not the first frame and both consumers are stopped, then stop ourselves - if ( !first && mlt_consumer_is_stopped( this->play ) && mlt_consumer_is_stopped( this->still ) ) - { - this->running = 0; - mlt_frame_close( frame ); - } - // Allow a little grace time before switching consumers on speed changes - else if ( this->ignore_change -- > 0 && this->active != NULL && !mlt_consumer_is_stopped( this->active ) ) - { - mlt_consumer_put_frame( this->active, frame ); - } // If we aren't playing normally, then use the still - else if ( speed != 1 ) + if ( speed != 1 ) { - if ( !mlt_consumer_is_stopped( this->play ) ) - mlt_consumer_stop( this->play ); - if ( mlt_consumer_is_stopped( this->still ) ) + mlt_producer producer = MLT_PRODUCER( mlt_service_get_producer( MLT_CONSUMER_SERVICE( consumer ) ) ); + mlt_position duration = producer? mlt_producer_get_playtime( producer ) : -1; + int pause = 0; + +#ifndef SKIP_WAIT_EOS + if ( self->active == self->play ) { - this->last_speed = speed; - this->active = this->still; - this->ignore_change = 0; - mlt_consumer_start( this->still ); + // Do not interrupt the play consumer near the end + if ( duration - self->last_position > eos_threshold ) + { + // Get a new frame at the sought position + mlt_frame_close( frame ); + if ( producer ) + mlt_producer_seek( producer, self->last_position ); + frame = mlt_consumer_get_frame( consumer ); + pause = 1; + } + else + { + // Send frame with speed 0 to stop it + if ( frame && !mlt_consumer_is_stopped( self->play ) ) + { + mlt_consumer_put_frame( self->play, frame ); + frame = NULL; + eos = 1; + } + + // Check for end of stream + if ( mlt_consumer_is_stopped( self->play ) ) + { + // Stream has ended + mlt_log_verbose( MLT_CONSUMER_SERVICE( consumer ), "END OF STREAM\n" ); + pause = 1; + eos = 0; // reset eos indicator + } + else + { + // Prevent a tight busy loop + struct timespec tm = { 0, 100000L }; // 100 usec + nanosleep( &tm, NULL ); + } + } + } +#else + pause = self->active == self->play; +#endif + if ( pause ) + { + // Start the still consumer + if ( !mlt_consumer_is_stopped( self->play ) ) + mlt_consumer_stop( self->play ); + self->last_speed = speed; + self->active = self->still; + self->ignore_change = 0; + mlt_consumer_start( self->still ); + } + // Send the frame to the active child + if ( frame && !eos ) + { + mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "refresh", 1 ); + mlt_consumer_put_frame( self->active, frame ); + } + if ( pause && speed == 0.0 ) + { + mlt_events_fire( properties, "consumer-sdl-paused", NULL ); } - mlt_consumer_put_frame( this->still, frame ); + } + // Allow a little grace time before switching consumers on speed changes + else if ( self->ignore_change -- > 0 && self->active != NULL && !mlt_consumer_is_stopped( self->active ) ) + { + mlt_consumer_put_frame( self->active, frame ); } // Otherwise use the normal player else { - if ( !mlt_consumer_is_stopped( this->still ) ) - mlt_consumer_stop( this->still ); - if ( mlt_consumer_is_stopped( this->play ) ) + if ( !mlt_consumer_is_stopped( self->still ) ) + mlt_consumer_stop( self->still ); + if ( mlt_consumer_is_stopped( self->play ) ) { - this->last_speed = speed; - this->active = this->play; - this->ignore_change = 25; - mlt_consumer_start( this->play ); + self->last_speed = speed; + self->active = self->play; + self->ignore_change = 0; + mlt_consumer_start( self->play ); } - mlt_consumer_put_frame( this->play, frame ); + if ( self->play ) + mlt_consumer_put_frame( self->play, frame ); } // Copy the rectangle info from the active consumer - if ( this->running && preview_off == 0 ) + if ( self->running && preview_off == 0 ) { - mlt_properties active = MLT_CONSUMER_PROPERTIES( this->active ); + mlt_properties active = MLT_CONSUMER_PROPERTIES( self->active ); mlt_service_lock( MLT_CONSUMER_SERVICE( consumer ) ); mlt_properties_set_int( properties, "rect_x", mlt_properties_get_int( active, "rect_x" ) ); mlt_properties_set_int( properties, "rect_y", mlt_properties_get_int( active, "rect_y" ) ); @@ -378,28 +457,28 @@ static void *consumer_thread( void *arg ) mlt_service_unlock( MLT_CONSUMER_SERVICE( consumer ) ); } - if ( this->active == this->still ) + if ( self->active == self->still ) { - pthread_mutex_lock( &this->refresh_mutex ); - if ( this->running && speed == 0 && this->refresh_count <= 0 ) - pthread_cond_wait( &this->refresh_cond, &this->refresh_mutex ); - this->refresh_count --; - pthread_mutex_unlock( &this->refresh_mutex ); + pthread_mutex_lock( &self->refresh_mutex ); + if ( self->running && speed == 0 && self->refresh_count <= 0 ) + { + mlt_events_fire( properties, "consumer-sdl-paused", NULL ); + pthread_cond_wait( &self->refresh_cond, &self->refresh_mutex ); + } + self->refresh_count --; + pthread_mutex_unlock( &self->refresh_mutex ); } - - // We are definitely not waiting on the first frame any more - first = 0; } else { if ( frame ) mlt_frame_close( frame ); - mlt_consumer_put_frame( this->active, NULL ); - this->running = 0; + mlt_consumer_put_frame( self->active, NULL ); + self->running = 0; } } - if ( this->play ) mlt_consumer_stop( this->play ); - if ( this->still ) mlt_consumer_stop( this->still ); + if ( self->play ) mlt_consumer_stop( self->play ); + if ( self->still ) mlt_consumer_stop( self->still ); return NULL; } @@ -410,18 +489,18 @@ static void *consumer_thread( void *arg ) static void consumer_close( mlt_consumer parent ) { // Get the actual object - consumer_sdl this = parent->child; + consumer_sdl self = parent->child; // Stop the consumer mlt_consumer_stop( parent ); // Close the child consumers - mlt_consumer_close( this->play ); - mlt_consumer_close( this->still ); + mlt_consumer_close( self->play ); + mlt_consumer_close( self->still ); // Now clean up the rest mlt_consumer_close( parent ); - // Finally clean up this - free( this ); + // Finally clean up self + free( self ); }