static void on_jack_stopped( mlt_properties owner, mlt_consumer consumer, mlt_position *position ) { mlt_producer producer = mlt_properties_get_data( MLT_CONSUMER_PROPERTIES(consumer), "transport_producer", NULL ); if ( producer ) { mlt_producer_set_speed( producer, 0 ); mlt_consumer_purge( consumer ); mlt_producer_seek( producer, *position ); mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( consumer ), "refresh", 1 ); } }
void MltRuntime::stop_ulk() throw (Exception) { if (status == StatusRunning) { mlt_consumer_purge(consumer); mlt_consumer_stop(consumer); while ( mlt_consumer_is_stopped(consumer) == 0) { struct timespec req = {1,0}; nanosleep(&req,NULL); } status = StatusStopped; } if (consumer) { mlt_consumer_close(consumer); consumer = NULL; } }
static void on_jack_started( mlt_properties owner, mlt_consumer consumer, mlt_position *position ) { mlt_producer producer = mlt_properties_get_data( MLT_CONSUMER_PROPERTIES(consumer), "transport_producer", NULL ); if ( producer ) { if ( mlt_producer_get_speed( producer ) != 0 ) { mlt_properties jack = mlt_properties_get_data( MLT_CONSUMER_PROPERTIES( consumer ), "jack_filter", NULL ); mlt_events_fire( jack, "jack-stop", NULL ); } else { mlt_producer_set_speed( producer, 1 ); mlt_consumer_purge( consumer ); mlt_producer_seek( producer, *position ); mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( consumer ), "refresh", 1 ); } } }
static void *consumer_thread( void *arg ) { // Identify the arg consumer_sdl self = arg; // Get the consumer mlt_consumer consumer = &self->parent; // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); // internal intialization 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" ); pthread_mutex_lock( &self->refresh_mutex ); self->refresh_count = 0; pthread_mutex_unlock( &self->refresh_mutex ); // Loop until told not to while( self->running ) { // Get a frame from the attached producer frame = mlt_consumer_get_frame( consumer ); // Ensure that we have a frame if ( self->running && frame != NULL ) { // Get the speed of the frame double speed = mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame ), "_speed" ); // Lock during the operation mlt_service_lock( MLT_CONSUMER_SERVICE( consumer ) ); // Get refresh request for the current frame int refresh = mlt_properties_get_int( properties, "refresh" ); // Decrement refresh and clear changed mlt_events_block( properties, properties ); mlt_properties_set_int( properties, "refresh", 0 ); mlt_events_unblock( properties, properties ); // Unlock after the operation mlt_service_unlock( MLT_CONSUMER_SERVICE( consumer ) ); // Set the changed property on this frame for the benefit of still mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "refresh", refresh ); // Make sure the recipient knows that this frame isn't really rendered mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "rendered", 0 ); // Optimisation to reduce latency if ( speed == 1.0 ) { if ( last_position != -1 && last_position + 1 != mlt_frame_get_position( frame ) ) mlt_consumer_purge( self->play ); last_position = mlt_frame_get_position( frame ); } else { //mlt_consumer_purge( self->play ); last_position = -1; } // If we aren't playing normally, then use the still if ( speed != 1 ) { 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 ) { // 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 ); if ( self->active ) mlt_consumer_put_frame( self->active, frame ); } if ( pause && speed == 0.0 ) { mlt_events_fire( properties, "consumer-sdl-paused", NULL ); } } // 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( self->still ) ) mlt_consumer_stop( self->still ); if ( mlt_consumer_is_stopped( self->play ) ) { self->last_speed = speed; self->active = self->play; self->ignore_change = 0; mlt_consumer_start( self->play ); } if ( self->play ) mlt_consumer_put_frame( self->play, frame ); } // Copy the rectangle info from the active consumer if ( self->running && preview_off == 0 && self->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" ) ); mlt_properties_set_int( properties, "rect_w", mlt_properties_get_int( active, "rect_w" ) ); mlt_properties_set_int( properties, "rect_h", mlt_properties_get_int( active, "rect_h" ) ); mlt_service_unlock( MLT_CONSUMER_SERVICE( consumer ) ); } if ( self->active == self->still ) { 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 ); } } else { if ( frame ) mlt_frame_close( frame ); mlt_consumer_put_frame( self->active, NULL ); self->running = 0; } } if ( self->play ) mlt_consumer_stop( self->play ); if ( self->still ) mlt_consumer_stop( self->still ); return NULL; }
void consumer_purge( mlt_consumer parent ) { consumer_sdl self = parent->child; if ( self->running ) mlt_consumer_purge( self->play ); }
static void transport_action( mlt_producer producer, char *value ) { mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); mlt_multitrack multitrack = mlt_properties_get_data( properties, "multitrack", NULL ); mlt_consumer consumer = mlt_properties_get_data( properties, "transport_consumer", NULL ); mlt_properties jack = mlt_properties_get_data( MLT_CONSUMER_PROPERTIES( consumer ), "jack_filter", NULL ); mlt_position position = producer? mlt_producer_position( producer ) : 0; mlt_properties_set_int( properties, "stats_off", 1 ); if ( strlen( value ) == 1 ) { switch( value[ 0 ] ) { case 'q': case 'Q': mlt_properties_set_int( properties, "done", 1 ); mlt_events_fire( jack, "jack-stop", NULL ); break; case '0': position = 0; mlt_producer_set_speed( producer, 1 ); mlt_producer_seek( producer, position ); mlt_consumer_purge( consumer ); mlt_events_fire( jack, "jack-seek", &position, NULL ); break; case '1': mlt_producer_set_speed( producer, -10 ); break; case '2': mlt_producer_set_speed( producer, -5 ); break; case '3': mlt_producer_set_speed( producer, -2 ); break; case '4': mlt_producer_set_speed( producer, -1 ); break; case '5': mlt_producer_set_speed( producer, 0 ); mlt_consumer_purge( consumer ); mlt_producer_seek( producer, mlt_consumer_position( consumer ) + 1 ); mlt_events_fire( jack, "jack-stop", NULL ); break; case '6': case ' ': if ( !jack || mlt_producer_get_speed( producer ) != 0 ) mlt_producer_set_speed( producer, 1 ); mlt_consumer_purge( consumer ); mlt_events_fire( jack, "jack-start", NULL ); break; case '7': mlt_producer_set_speed( producer, 2 ); break; case '8': mlt_producer_set_speed( producer, 5 ); break; case '9': mlt_producer_set_speed( producer, 10 ); break; case 'd': if ( multitrack != NULL ) { int i = 0; mlt_position last = -1; fprintf( stderr, "\n" ); for ( i = 0; 1; i ++ ) { position = mlt_multitrack_clip( multitrack, mlt_whence_relative_start, i ); if ( position == last ) break; last = position; fprintf( stderr, "%d: %d\n", i, (int)position ); } } break; case 'g': if ( multitrack != NULL ) { position = mlt_multitrack_clip( multitrack, mlt_whence_relative_current, 0 ); mlt_producer_seek( producer, position ); mlt_consumer_purge( consumer ); mlt_events_fire( jack, "jack-seek", &position, NULL ); } break; case 'H': if ( producer != NULL ) { position -= mlt_producer_get_fps( producer ) * 60; mlt_consumer_purge( consumer ); mlt_producer_seek( producer, position ); mlt_events_fire( jack, "jack-seek", &position, NULL ); } break; case 'h': if ( producer != NULL ) { position--; mlt_producer_set_speed( producer, 0 ); mlt_consumer_purge( consumer ); mlt_producer_seek( producer, position ); mlt_events_fire( jack, "jack-stop", NULL ); mlt_events_fire( jack, "jack-seek", &position, NULL ); } break; case 'j': if ( multitrack != NULL ) { position = mlt_multitrack_clip( multitrack, mlt_whence_relative_current, 1 ); mlt_consumer_purge( consumer ); mlt_producer_seek( producer, position ); mlt_events_fire( jack, "jack-seek", &position, NULL ); } break; case 'k': if ( multitrack != NULL ) { position = mlt_multitrack_clip( multitrack, mlt_whence_relative_current, -1 ); mlt_consumer_purge( consumer ); mlt_producer_seek( producer, position ); mlt_events_fire( jack, "jack-seek", &position, NULL ); } break; case 'l': if ( producer != NULL ) { position++; mlt_consumer_purge( consumer ); if ( mlt_producer_get_speed( producer ) != 0 ) { mlt_producer_set_speed( producer, 0 ); mlt_events_fire( jack, "jack-stop", NULL ); } else { mlt_producer_seek( producer, position ); mlt_events_fire( jack, "jack-seek", &position, NULL ); } } break; case 'L': if ( producer != NULL ) { position += mlt_producer_get_fps( producer ) * 60; mlt_consumer_purge( consumer ); mlt_producer_seek( producer, position ); mlt_events_fire( jack, "jack-seek", &position, NULL ); } break; } mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( consumer ), "refresh", 1 ); } mlt_properties_set_int( properties, "stats_off", 0 ); }
static void *consumer_thread( void *arg ) { // Identify the arg consumer_sdl self = arg; // Get the consumer mlt_consumer consumer = &self->parent; // Get the properties mlt_properties consumer_props = MLT_CONSUMER_PROPERTIES( consumer ); // Video thread pthread_t thread; // internal intialization int init_audio = 1; int init_video = 1; mlt_frame frame = NULL; mlt_properties properties = NULL; int duration = 0; int64_t playtime = 0; struct timespec tm = { 0, 100000 }; // int last_position = -1; pthread_mutex_lock( &self->refresh_mutex ); self->refresh_count = 0; pthread_mutex_unlock( &self->refresh_mutex ); // Loop until told not to while( self->running ) { // Get a frame from the attached producer frame = mlt_consumer_rt_frame( consumer ); // Ensure that we have a frame if ( frame ) { // Get the frame properties properties = MLT_FRAME_PROPERTIES( frame ); // Get the speed of the frame double speed = mlt_properties_get_double( properties, "_speed" ); // Clear refresh mlt_events_block( consumer_props, consumer_props ); mlt_properties_set_int( consumer_props, "refresh", 0 ); mlt_events_unblock( consumer_props, consumer_props ); // Play audio init_audio = consumer_play_audio( self, frame, init_audio, &duration ); // Determine the start time now if ( self->playing && init_video ) { // Create the video thread pthread_create( &thread, NULL, video_thread, self ); // Video doesn't need to be initialised any more init_video = 0; } // Set playtime for this frame mlt_properties_set_int( properties, "playtime", playtime ); while ( self->running && speed != 0 && mlt_deque_count( self->queue ) > 15 ) nanosleep( &tm, NULL ); // Push this frame to the back of the queue if ( self->running && speed ) { pthread_mutex_lock( &self->video_mutex ); if ( self->is_purge && speed == 1.0 ) { mlt_frame_close( frame ); frame = NULL; self->is_purge = 0; } else { mlt_deque_push_back( self->queue, frame ); pthread_cond_broadcast( &self->video_cond ); } pthread_mutex_unlock( &self->video_mutex ); // Calculate the next playtime playtime += ( duration * 1000 ); } else if ( self->running ) { pthread_mutex_lock( &self->refresh_mutex ); consumer_play_video( self, frame ); mlt_frame_close( frame ); frame = NULL; self->refresh_count --; if ( self->refresh_count <= 0 ) { pthread_cond_wait( &self->refresh_cond, &self->refresh_mutex ); } pthread_mutex_unlock( &self->refresh_mutex ); } // Optimisation to reduce latency if ( speed == 1.0 ) { // TODO: disabled due to misbehavior on parallel-consumer // if ( last_position != -1 && last_position + 1 != mlt_frame_get_position( frame ) ) // mlt_consumer_purge( consumer ); // last_position = mlt_frame_get_position( frame ); } else { mlt_consumer_purge( consumer ); // last_position = -1; } } } // Kill the video thread if ( init_video == 0 ) { pthread_mutex_lock( &self->video_mutex ); pthread_cond_broadcast( &self->video_cond ); pthread_mutex_unlock( &self->video_mutex ); pthread_join( thread, NULL ); } if ( frame ) { // The video thread has cleared out the queue. But the audio was played // for this frame. So play the video before stopping so the display has // the option to catch up with the audio. consumer_play_video( self, frame ); mlt_frame_close( frame ); frame = NULL; } self->audio_avail = 0; return NULL; }