X-Git-Url: https://git.cinelerra-gg.org/git/?p=goodguy%2Fcinelerra.git;a=blobdiff_plain;f=cinelerra-5.1%2Fcinelerra%2Fplaybackengine.C;h=3b2b9ed4313f2ac01699179015e7fd61a85c9bf4;hp=71cd3911c33cba6aaf09419f10c2c333be4febd1;hb=1db0dacec8f9d7f5687e582bd282d9bf83bd58f0;hpb=7fd85fb66168f6b518c5f2d73e04036e87faa0e1 diff --git a/cinelerra-5.1/cinelerra/playbackengine.C b/cinelerra-5.1/cinelerra/playbackengine.C index 71cd3911..3b2b9ed4 100644 --- a/cinelerra-5.1/cinelerra/playbackengine.C +++ b/cinelerra-5.1/cinelerra/playbackengine.C @@ -22,6 +22,7 @@ #include "bchash.h" #include "bcsignals.h" #include "cache.h" +#include "canvas.h" #include "condition.h" #include "edl.h" #include "edlsession.h" @@ -32,6 +33,7 @@ #include "mwindowgui.h" #include "patchbay.h" #include "tracking.h" +#include "tracks.h" #include "playbackengine.h" #include "playtransport.h" #include "preferences.h" @@ -39,6 +41,8 @@ #include "mainsession.h" #include "trackcanvas.h" #include "transportque.h" +#include "videodevice.h" +#include "vdevicex11.h" #include "vrender.h" @@ -52,12 +56,25 @@ PlaybackEngine::PlaybackEngine(MWindow *mwindow, Canvas *output) tracking_active = 0; audio_cache = 0; video_cache = 0; - last_command = STOP; + command = new TransportCommand(); + command->command = STOP; + next_command = new TransportCommand(); + next_command->change_type = CHANGE_ALL; + stop_command = new TransportCommand(); + stop_command->command = STOP; + stop_command->realtime = 1; + sent_command = new TransportCommand(); + sent_command->command = -1; + send_active = 0; tracking_lock = new Mutex("PlaybackEngine::tracking_lock"); renderengine_lock = new Mutex("PlaybackEngine::renderengine_lock"); tracking_done = new Condition(1, "PlaybackEngine::tracking_done"); pause_lock = new Condition(0, "PlaybackEngine::pause_lock"); start_lock = new Condition(0, "PlaybackEngine::start_lock"); + cache_lock = new Mutex("PlaybackEngine::cache_lock"); + input_lock = new Condition(1, "PlaybackEngine::input_lock"); + output_lock = new Condition(0, "PlaybackEngine::output_lock", 1); + render_engine = 0; debug = 0; } @@ -65,34 +82,31 @@ PlaybackEngine::PlaybackEngine(MWindow *mwindow, Canvas *output) PlaybackEngine::~PlaybackEngine() { done = 1; - que->send_command(STOP, - CHANGE_NONE, - 0, - 0); - interrupt_playback(); - + output_lock->unlock(); Thread::join(); - delete preferences; - delete command; - delete que; delete_render_engine(); - delete audio_cache; - delete video_cache; + delete preferences; + if( audio_cache ) + audio_cache->remove_user(); + if( video_cache ) + video_cache->remove_user(); delete tracking_lock; delete tracking_done; delete pause_lock; delete start_lock; + delete cache_lock; delete renderengine_lock; + delete command; + delete next_command; + delete stop_command; + delete sent_command; + delete input_lock; + delete output_lock; } void PlaybackEngine::create_objects() { preferences = new Preferences; - command = new TransportCommand; - que = new TransportQue; -// Set the first change to maximum - que->command.change_type = CHANGE_ALL; - preferences->copy_from(mwindow->preferences); done = 0; @@ -123,52 +137,68 @@ int PlaybackEngine::create_render_engine() void PlaybackEngine::delete_render_engine() { renderengine_lock->lock("PlaybackEngine::delete_render_engine"); - delete render_engine; - render_engine = 0; + if( render_engine ) { + render_engine->interrupt_playback(); + render_engine->wait_done(); + delete render_engine; render_engine = 0; + } renderengine_lock->unlock(); } void PlaybackEngine::arm_render_engine() { - if(render_engine) + renderengine_lock->lock("PlaybackEngine::arm_render_engine"); + if( render_engine ) render_engine->arm_command(command); + renderengine_lock->unlock(); } void PlaybackEngine::start_render_engine() { - if(render_engine) render_engine->start_command(); + renderengine_lock->lock("PlaybackEngine::start_render_engine"); + if( render_engine ) + render_engine->start_command(); + renderengine_lock->unlock(); } void PlaybackEngine::wait_render_engine() { - if(command->realtime && render_engine) - { + if( command->realtime && render_engine ) { render_engine->join(); } } void PlaybackEngine::create_cache() { - if(audio_cache) { delete audio_cache; audio_cache = 0; } - if(video_cache) { delete video_cache; video_cache = 0; } - if(!audio_cache) audio_cache = new CICache(preferences); - if(!video_cache) video_cache = new CICache(preferences); + cache_lock->lock("PlaybackEngine::create_cache"); + if( audio_cache ) + audio_cache->remove_user(); + if( video_cache ) + video_cache->remove_user(); + audio_cache = new CICache(preferences); + video_cache = new CICache(preferences); + cache_lock->unlock(); } void PlaybackEngine::perform_change() { - switch(command->change_type) - { - case CHANGE_ALL: - create_cache(); - case CHANGE_EDL: - create_render_engine(); - case CHANGE_PARAMS: - if(command->change_type != CHANGE_EDL && - (uint32_t)command->change_type != CHANGE_ALL) - render_engine->get_edl()->synchronize_params(command->get_edl()); - case CHANGE_NONE: + switch( command->change_type ) { + case CHANGE_ALL: + create_cache(); + case CHANGE_EDL: + create_render_engine(); + break; + case CHANGE_PARAMS: { + renderengine_lock->lock("PlaybackEngine::perform_change"); + EDL *edl = render_engine ? render_engine->get_edl() : 0; + if( edl ) edl->add_user(); + renderengine_lock->unlock(); + if( !edl ) break; + edl->synchronize_params(command->get_edl()); + edl->remove_user(); + } + case CHANGE_NONE: break; } } @@ -177,14 +207,14 @@ void PlaybackEngine::sync_parameters(EDL *edl) { // TODO: lock out render engine from keyframe deletions command->get_edl()->synchronize_params(edl); - if(render_engine) render_engine->get_edl()->synchronize_params(edl); + if( render_engine ) + render_engine->get_edl()->synchronize_params(edl); } - void PlaybackEngine::interrupt_playback(int wait_tracking) { renderengine_lock->lock("PlaybackEngine::interrupt_playback"); - if(render_engine) + if( render_engine ) render_engine->interrupt_playback(); renderengine_lock->unlock(); @@ -192,22 +222,19 @@ void PlaybackEngine::interrupt_playback(int wait_tracking) pause_lock->unlock(); // Wait for tracking to finish if it is running - if(wait_tracking) - { + if( wait_tracking ) { tracking_done->lock("PlaybackEngine::interrupt_playback"); tracking_done->unlock(); } } - // Return 1 if levels exist int PlaybackEngine::get_output_levels(double *levels, long position) { int result = 0; - if(render_engine && render_engine->do_audio) - { - result = 1; + if( render_engine && render_engine->do_audio ) { render_engine->get_output_levels(levels, position); + result = 1; } return result; } @@ -216,10 +243,9 @@ int PlaybackEngine::get_output_levels(double *levels, long position) int PlaybackEngine::get_module_levels(ArrayList *module_levels, long position) { int result = 0; - if(render_engine && render_engine->do_audio) - { - result = 1; + if( render_engine && render_engine->do_audio ) { render_engine->get_module_levels(module_levels, position); + result = 1; } return result; } @@ -251,8 +277,9 @@ void PlaybackEngine::init_tracking() init_meters(); } -void PlaybackEngine::stop_tracking() +void PlaybackEngine::stop_tracking(double position) { + tracking_position = position; tracking_active = 0; stop_cursor(); tracking_done->unlock(); @@ -284,17 +311,15 @@ double PlaybackEngine::get_tracking_position() // Don't interpolate when every frame is played. - if(command->get_edl()->session->video_every_frame && - render_engine && - render_engine->do_video) - { + if( command->get_edl()->session->video_every_frame && + render_engine && render_engine->do_video ) { result = tracking_position; } else // Interpolate { double loop_start, loop_end; - int play_loop = command->play_loop ? 1 : 0; + int play_loop = command->loop_play ? 1 : 0; EDL *edl = command->get_edl(); int loop_playback = edl->local_session->loop_playback ? 1 : 0; if( play_loop || !loop_playback ) { @@ -360,22 +385,23 @@ void PlaybackEngine::run() while( !done ) { // Wait for current command to finish - que->output_lock->lock("PlaybackEngine::run"); - wait_render_engine(); - + output_lock->lock("PlaybackEngine::run"); + if( done ) break; // Read the new command - que->input_lock->lock("PlaybackEngine::run"); - if(done) return; - - command->copy_from(&que->command); - que->command.reset(); - que->input_lock->unlock(); -//printf("PlaybackEngine::run 1 %d\n", command->command); + input_lock->lock("PlaybackEngine::run"); + command->copy_from(sent_command); +//printf("sent command=%d\n", sent_command->command); + int active = this->send_active; + this->send_active = 0; + input_lock->unlock(); + if( !active ) continue; + + interrupt_playback(0); + wait_render_engine(); switch( command->command ) { // Parameter change only case COMMAND_NONE: -// command->command = last_command; perform_change(); break; @@ -391,65 +417,88 @@ void PlaybackEngine::run() case CURRENT_FRAME: case LAST_FRAME: - last_command = command->command; perform_change(); arm_render_engine(); // Dispatch the command start_render_engine(); break; - - case SINGLE_FRAME_FWD: - case SINGLE_FRAME_REWIND: // fall through default: - last_command = command->command; is_playing_back = 1; - + case REWIND: + case GOTO_END: perform_change(); arm_render_engine(); // Start tracking after arming so the tracking position doesn't change. // The tracking for a single frame command occurs during PAUSE init_tracking(); - + clear_borders(); // Dispatch the command start_render_engine(); break; } - - //printf("PlaybackEngine::run 100\n"); } } +void PlaybackEngine::clear_borders() +{ + EDL *edl = command->get_edl(); + PlaybackConfig *config = edl->session->playback_config; + if( config->vconfig->driver == PLAYBACK_X11_GL ) { + if( render_engine && render_engine->video ) { + VDeviceBase *vdriver = render_engine->video->get_output_base(); + ((VDeviceX11*)vdriver)->clear_output(); + return; + } + } + BC_WindowBase *window = output->get_canvas(); + if( !window ) return; + window->lock_window("PlaybackEngine::clear_output"); + output->clear_borders(edl); + window->unlock_window(); +} -void PlaybackEngine::stop_playback(int wait) +void PlaybackEngine::stop_playback(int wait_tracking) { - que->send_command(STOP, CHANGE_NONE, 0, 0); - interrupt_playback(wait); + transport_stop(wait_tracking); renderengine_lock->lock("PlaybackEngine::stop_playback"); - if(render_engine) + if( render_engine ) { + render_engine->interrupt_playback(); render_engine->wait_done(); + } renderengine_lock->unlock(); } +int PlaybackEngine::get_direction() +{ + int curr_command = is_playing_back ? this->command->command : STOP; + return TransportCommand::get_direction(curr_command); +} -void PlaybackEngine::issue_command(EDL *edl, int command, int wait_tracking, - int use_inout, int update_refresh, int toggle_audio, int loop_play) +void PlaybackEngine::update_preferences(Preferences *prefs) { -//printf("PlaybackEngine::issue_command 1 %d\n", command); -// Stop requires transferring the output buffer to a refresh buffer. - int do_stop = 0, resume = 0; - int prev_command = this->command->command; - int prev_single_frame = this->command->single_frame(); - int prev_audio = this->command->audio_toggle ? - !prev_single_frame : prev_single_frame; - int cur_single_frame = TransportCommand::single_frame(command); - int cur_audio = toggle_audio ? - !cur_single_frame : cur_single_frame; + preferences->copy_from(prefs); + create_render_engine(); +} +void PlaybackEngine::send_command(int command, EDL *edl, int wait_tracking, int use_inout) +{ +//printf("PlaybackEngine::send_command 1 %d\n", command); +// Stop requires transferring the output buffer to a refresh buffer. + int curr_command = is_playing_back ? this->command->command : STOP; + int curr_single_frame = TransportCommand::single_frame(curr_command); + int curr_audio = this->command->toggle_audio ? + !curr_single_frame : curr_single_frame; + int single_frame = TransportCommand::single_frame(command); + int next_audio = next_command->toggle_audio ? !single_frame : single_frame; + float next_speed = next_command->speed; // Dispatch command - switch(command) { + switch( command ) { + case STOP: + transport_stop(wait_tracking); + break; case FAST_REWIND: // Commands that play back case NORMAL_REWIND: case SLOW_REWIND: @@ -460,51 +509,99 @@ void PlaybackEngine::issue_command(EDL *edl, int command, int wait_tracking, case FAST_FWD: case CURRENT_FRAME: case LAST_FRAME: - if( !prev_single_frame && - prev_command == command && - cur_audio == prev_audio ) { -// Same direction pressed twice and no change in audio state, Stop - do_stop = 1; +// run shuttle as no prev command + if( next_speed ) curr_command = COMMAND_NONE; +// Same direction pressed twice, not shuttle, and no change in audio state, Stop + if( curr_command == command && !curr_single_frame && + curr_audio == next_audio ) { + transport_stop(wait_tracking); break; } // Resume or change direction - switch( prev_command ) { - default: - que->send_command(STOP, CHANGE_NONE, 0, 0); - interrupt_playback(wait_tracking); - resume = 1; -// fall through + switch( curr_command ) { + case REWIND: + case GOTO_END: case STOP: case COMMAND_NONE: case SINGLE_FRAME_FWD: case SINGLE_FRAME_REWIND: case CURRENT_FRAME: case LAST_FRAME: -// Start from scratch - que->send_command(command, CHANGE_NONE, edl, - 1, resume, use_inout, toggle_audio, loop_play, - mwindow->preferences->forward_render_displacement); +// already stopped + break; + default: + transport_stop(0); + next_command->resume = 1; break; } + next_command->realtime = 1; + transport_command(command, CHANGE_NONE, edl, use_inout); break; - -// Commands that stop - case STOP: case REWIND: case GOTO_END: - do_stop = 1; + transport_stop(1); + next_command->realtime = 1; + transport_command(command, CHANGE_NONE, edl, use_inout); + stop_tracking(this->command->playbackstart); break; } +} + +int PlaybackEngine::put_command(TransportCommand *command, int reset) +{ + input_lock->lock("PlaybackEngine::put_command"); + int prev_change_type = sent_command->change_type; + sent_command->copy_from(command); +// run only last command, sum change type + if( send_active ) + sent_command->change_type |= prev_change_type; + send_active = 1; + if( reset ) command->reset(); + output_lock->unlock(); + input_lock->unlock(); + return 0; +} + +int PlaybackEngine::transport_stop(int wait_tracking) +{ + put_command(stop_command, 0); + if( wait_tracking ) { + tracking_done->lock("PlaybackEngine::transport_stop"); + tracking_done->unlock(); + } +//printf("send: %d (STOP) 0\n", STOP); + return 0; +} - if( do_stop ) { - que->send_command(STOP, CHANGE_NONE, 0, 0); - interrupt_playback(wait_tracking); +int PlaybackEngine::transport_command(int command, int change_type, EDL *new_edl, int use_inout) +{ + next_command->command = command; + next_command->change_type |= change_type; + if( new_edl ) { +// Just change the EDL if the change requires it because renderengine +// structures won't point to the new EDL otherwise and because copying the +// EDL for every cursor movement is slow. + if( change_type == CHANGE_EDL || change_type == CHANGE_ALL ) + next_command->get_edl()->copy_all(new_edl); + else if( change_type == CHANGE_PARAMS ) + next_command->get_edl()->synchronize_params(new_edl); + next_command->set_playback_range(new_edl, use_inout, + preferences->forward_render_displacement); } + put_command(next_command, 1); +//static const char *types[] = { "NONE", +// "FRAME_FWD", "NORMAL_FWD", "FAST_FWD", "FRAME_REV", "NORMAL_REV", "FAST_REV", +// "STOP", "PAUSE", "SLOW_FWD", "SLOW_REV", "REWIND", "GOTO_END", "CURRENT_FRAME", +// "LAST_FRAME" }; +//printf("send= %d (%s) %d\n", sent_command->command, +// types[sent_command->command], sent_command->locked); + return 0; } void PlaybackEngine::refresh_frame(int change_type, EDL *edl, int dir) { - que->send_command(dir >= 0 ? CURRENT_FRAME : LAST_FRAME, - change_type, edl, 1); + int command = dir >= 0 ? CURRENT_FRAME : LAST_FRAME; + next_command->realtime = 1; + transport_command(command, change_type, edl); }