X-Git-Url: http://git.cinelerra-gg.org/git/?a=blobdiff_plain;f=cinelerra-5.1%2Fcinelerra%2Fbrender.C;fp=cinelerra-5.1%2Fcinelerra%2Fbrender.C;h=94a569a7faaf8bf7bbbe6dd545ecf319ad36574c;hb=30bdb85eb33a8ee7ba675038a86c6be59c43d7bd;hp=0000000000000000000000000000000000000000;hpb=52fcc46226f9df46f9ce9d0566dc568455a7db0b;p=goodguy%2Fhistory.git diff --git a/cinelerra-5.1/cinelerra/brender.C b/cinelerra-5.1/cinelerra/brender.C new file mode 100644 index 00000000..94a569a7 --- /dev/null +++ b/cinelerra-5.1/cinelerra/brender.C @@ -0,0 +1,636 @@ + +/* + * CINELERRA + * Copyright (C) 2008 Adam Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "asset.h" +#include "bcsignals.h" +#include "brender.h" +#include "clip.h" +#include "condition.h" +#include "edl.h" +#include "edlsession.h" +#include "language.h" +#include "mainsession.h" +#include "mtimebar.h" +#include "mutex.h" +#include "mwindowgui.h" +#include "mwindow.h" +#include "packagedispatcher.h" +#include "preferences.h" +#include "renderfarm.h" +#include "tracks.h" +#include "units.h" + + +#include +#include +#include +#include +#include + + + +extern "C" +{ +#include +} + + + + + + +BRender::BRender(MWindow *mwindow) + : Thread(1, 0, 0) +{ + this->mwindow = mwindow; + map_lock = new Mutex("BRender::map_lock"); + completion_lock = new Condition(0, "BRender::completion_lock"); + timer = new Timer; + socket_path[0] = 0; + thread = 0; + master_pid = -1; + arguments[0] = arguments[1] = arguments[2] = 0; + map = 0; + map_size = 0; + map_valid = 0; + last_contiguous = 0; + set_synchronous(1); +} + +BRender::~BRender() +{ +TRACE("BRender::~BRender 1\n"); + if(thread) + { +TRACE("BRender::~BRender 2\n"); + stop(); +TRACE("BRender::~BRender 3\n"); + delete thread; +TRACE("BRender::~BRender 4\n"); + } + + +TRACE("BRender::~BRender 5\n"); + if(master_pid >= 0) + { + kill(master_pid, SIGKILL); +TRACE("BRender::~BRender 6\n"); + Thread::join(); +TRACE("BRender::~BRender 7\n"); + } + +TRACE("BRender::~BRender 8\n"); + delete map_lock; +TRACE("BRender::~BRender 9\n"); + delete completion_lock; +TRACE("BRender::~BRender 10\n"); +UNSET_TEMP(socket_path); + remove(socket_path); +TRACE("BRender::~BRender 11\n"); + if(arguments[0]) delete [] arguments[0]; +TRACE("BRender::~BRender 12\n"); + if(arguments[1]) delete [] arguments[1]; +TRACE("BRender::~BRender 13\n"); + if(arguments[2]) delete [] arguments[2]; +TRACE("BRender::~BRender 14\n"); + if(map) delete [] map; +TRACE("BRender::~BRender 15\n"); + delete timer; +TRACE("BRender::~BRender 100\n"); +} + +void BRender::initialize() +{ + timer->update(); +// Create socket for background process. + uuid_t socket_temp; + sprintf(socket_path, "/tmp/cinelerra."); + uuid_generate(socket_temp); + uuid_unparse(socket_temp, socket_path + strlen(socket_path)); +SET_TEMP(socket_path); + +// Start background instance of executable since codecs aren't reentrant + Thread::start(); + +// Wait for local node to start + thread = new BRenderThread(mwindow, this); + thread->initialize(); +} + +void BRender::run() +{ + char string[BCTEXTLEN]; + FILE *fd; +//printf("BRender::run 1 %d\n", getpid()); + + +// Construct executable command with the designated filesystem port + fd = fopen("/proc/self/cmdline", "r"); + if(fd) + { + (void)fread(string, 1, BCTEXTLEN, fd); + fclose(fd); + } + else + perror(_("BRender::fork_background: can't open /proc/self/cmdline.\n")); + + arguments[0] = new char[strlen(string) + 1]; + strcpy(arguments[0], string); + + strcpy(string, "-b"); + arguments[1] = new char[strlen(string) + 1]; + strcpy(arguments[1], string); + + arguments[2] = new char[strlen(socket_path) + 1]; + strcpy(arguments[2], socket_path); +//printf("BRender::fork_background 1 %s\n", socket_path); + + arguments[3] = 0; + + int pid = vfork(); + if(!pid) + { + execvp(arguments[0], arguments); + perror("BRender::fork_background"); + _exit(0); + } + + master_pid = pid; +//printf("BRender::fork_background 1 %d\n", master_pid); + + + + int return_value; + if(waitpid(master_pid, &return_value, WUNTRACED) < 0) + { + perror("BRender::run waitpid"); + } +} + +// Give the last position of the EDL which hasn't changed. +// We copy the EDL and restart rendering at the lesser of position and +// our position. +void BRender::restart(EDL *edl) +{ +//printf("BRender::restart 1\n"); + BRenderCommand *new_command = new BRenderCommand; + map_valid = 0; + new_command->copy_edl(edl); + new_command->command = BRenderCommand::BRENDER_RESTART; +//printf("BRender::restart 2\n"); + thread->send_command(new_command); +//printf("BRender::restart 3\n"); +// Map should be reallocated before this returns. +} + +void BRender::stop() +{ +//printf("BRender::stop 1\n"); + BRenderCommand *new_command = new BRenderCommand; +//printf("BRender::stop 1\n"); + new_command->command = BRenderCommand::BRENDER_STOP; +//printf("BRender::stop 1\n"); + thread->send_command(new_command); +//printf("BRender::stop 1\n"); + completion_lock->lock("BRender::stop"); +//printf("BRender::stop 2\n"); +} + + + +int BRender::get_last_contiguous(int64_t brender_start) +{ + int result; + map_lock->lock("BRender::get_last_contiguous"); + if(map_valid) + result = last_contiguous; + else + result = brender_start; + map_lock->unlock(); + return result; +} + +void BRender::allocate_map(int64_t brender_start, int64_t start, int64_t end) +{ + map_lock->lock("BRender::allocate_map"); + unsigned char *old_map = map; + map = new unsigned char[end]; + if(old_map) + { + memcpy(map, old_map, start); + delete [] old_map; + } + +// Zero all before brender start + bzero(map, brender_start); +// Zero all after current start + bzero(map + start, end - start); + + map_size = end; + map_valid = 1; + last_contiguous = start; + mwindow->session->brender_end = (double)last_contiguous / + mwindow->edl->session->frame_rate; + map_lock->unlock(); +} + +int BRender::set_video_map(int64_t position, int value) +{ + int update_gui = 0; + map_lock->lock("BRender::set_video_map"); + + + if(value == BRender::NOT_SCANNED) + { + printf(_("BRender::set_video_map called to set NOT_SCANNED\n")); + } + +// Preroll + if(position < 0) + { + ; + } + else +// In range + if(position < map_size) + { + map[position] = value; + } + else +// Obsolete EDL + { + printf(_("BRender::set_video_map %jd: attempt to set beyond end of map %jd.\n"), + position, map_size); + } + +// Maintain last contiguous here to reduce search time + if(position == last_contiguous) + { + int i; + for(i = position + 1; i < map_size && map[i]; i++) + { + ; + } + last_contiguous = i; + mwindow->session->brender_end = (double)last_contiguous / + mwindow->edl->session->frame_rate; + + if(timer->get_difference() > 1000 || last_contiguous >= map_size) + { + update_gui = 1; + timer->update(); + } + } + + map_lock->unlock(); + + if(update_gui) + { + mwindow->gui->lock_window("BRender::set_video_map"); + mwindow->gui->update_timebar(1); + mwindow->gui->unlock_window(); + } + return 0; +} + + + + + + + + + + + + + + +BRenderCommand::BRenderCommand() +{ + edl = 0; + command = BRENDER_NONE; + position = 0.0; +} + +BRenderCommand::~BRenderCommand() +{ +// EDL should be zeroed if copied + if(edl) edl->Garbage::remove_user(); +} + +void BRenderCommand::copy_from(BRenderCommand *src) +{ + this->edl = src->edl; + src->edl = 0; + this->position = src->position; + this->command = src->command; +} + + +void BRenderCommand::copy_edl(EDL *edl) +{ + this->edl = new EDL; + this->edl->create_objects(); + this->edl->copy_all(edl); + this->position = 0; +} + + + + + + + + + + + + +BRenderThread::BRenderThread(MWindow *mwindow, BRender *brender) + : Thread(1, 0, 0) +{ + this->mwindow = mwindow; + this->brender = brender; + input_lock = new Condition(0, "BRenderThread::input_lock"); + thread_lock = new Mutex("BRenderThread::thread_lock"); + total_frames_lock = new Mutex("BRenderThread::total_frames_lock"); + command_queue = 0; + command = 0; + done = 0; + farm_server = 0; + farm_result = 0; + preferences = 0; +} + +BRenderThread::~BRenderThread() +{ + thread_lock->lock("BRenderThread::~BRenderThread"); + done = 1; + input_lock->unlock(); + thread_lock->unlock(); + Thread::join(); + delete input_lock; + delete thread_lock; + delete total_frames_lock; + if(command) delete command; + if(command_queue) delete command_queue; + if(preferences) delete preferences; +} + + +void BRenderThread::initialize() +{ + Thread::start(); +} + +void BRenderThread::send_command(BRenderCommand *command) +{ +TRACE("BRenderThread::send_command 1"); + thread_lock->lock("BRenderThread::send_command"); +TRACE("BRenderThread::send_command 10"); + + if(this->command_queue) + { + delete this->command_queue; + this->command_queue = 0; + } + this->command_queue = command; +TRACE("BRenderThread::send_command 20"); + + + input_lock->unlock(); + thread_lock->unlock(); +} + +int BRenderThread::is_done(int do_lock) +{ + if(do_lock) thread_lock->lock("BRenderThread::is_done"); + int result = done; + if(do_lock) thread_lock->unlock(); + return result; +} + +void BRenderThread::run() +{ + while(!is_done(1)) + { + BRenderCommand *new_command = 0; + thread_lock->lock("BRenderThread::run 1"); + +// Got new command + if(command_queue) + { + ; + } + else +// Wait for new command + { + thread_lock->unlock(); + input_lock->lock("BRenderThread::run 2"); + thread_lock->lock("BRenderThread::run 3"); + } + +// Pull the command off + if(!is_done(0)) + { + new_command = command_queue; + command_queue = 0; + } + + thread_lock->unlock(); + + + + +// Process the command here to avoid delay. +// Quit condition + if(!new_command) + { + ; + } + else + if(new_command->command == BRenderCommand::BRENDER_STOP) + { + stop(); + delete new_command; + new_command = 0; +// if(command) delete command; +// command = new_command; + } + else + if(new_command->command == BRenderCommand::BRENDER_RESTART) + { +// Compare EDL's and get last equivalent position in new EDL + if(command && command->edl) + new_command->position = + new_command->edl->equivalent_output(command->edl); + else + new_command->position = 0; + + + stop(); +//printf("BRenderThread::run 4\n"); + brender->completion_lock->lock("BRenderThread::run 4"); +//printf("BRenderThread::run 5\n"); + + if(new_command->edl->tracks->total_playable_vtracks()) + { + if(command) delete command; + command = new_command; +//printf("BRenderThread::run 6\n"); + start(); +//printf("BRenderThread::run 7\n"); + } + else + { +//printf("BRenderThread::run 8 %p\n", farm_server); + delete new_command; + new_command = 0; + } + } + } +} + +void BRenderThread::stop() +{ + if(farm_server) + { + farm_result = 1; + farm_server->wait_clients(); + delete farm_server; + delete packages; + delete preferences; + farm_server = 0; + packages = 0; + preferences = 0; + } + brender->completion_lock->unlock(); +} + +void BRenderThread::start() +{ +// Reset return parameters + farm_result = 0; + fps_result = 0; + total_frames = 0; + int result = 0; + +// Allocate render farm. + if(!farm_server) + { +//printf("BRenderThread::start 1\n"); + preferences = new Preferences; + preferences->copy_from(mwindow->preferences); + packages = new PackageDispatcher; + +// Fix preferences to use local node + if(!preferences->use_renderfarm) + { + preferences->use_renderfarm = 1; + preferences->delete_nodes(); + } + preferences->add_node(brender->socket_path, + 0, + 1, + preferences->local_rate); +//printf("BRenderThread::start 1 %s\n", brender->socket_path); + preferences->brender_asset->use_header = 0; + preferences->brender_asset->frame_rate = command->edl->session->frame_rate; + preferences->brender_asset->width = command->edl->session->output_w; + preferences->brender_asset->height = command->edl->session->output_h; + preferences->brender_asset->interlace_mode = command->edl->session->interlace_mode; + +// Get last contiguous and reset map. +// If the framerate changes, last good should be 0 from the user. + int brender_start = (int)(command->edl->session->brender_start * + command->edl->session->frame_rate); + int last_contiguous = brender->last_contiguous; + int last_good = (int)(command->edl->session->frame_rate * + command->position); + if(last_good < 0) last_good = last_contiguous; + int start_frame = MIN(last_contiguous, last_good); + start_frame = MAX(start_frame, brender_start); + int64_t end_frame = Units::round(command->edl->tracks->total_video_length() * + command->edl->session->frame_rate); + if(end_frame < start_frame) end_frame = start_frame; + + +printf("BRenderThread::start 1 map=%d equivalent=%d brender_start=%d result=%d end=%jd\n", + last_contiguous, last_good, brender_start, start_frame, end_frame); + +//sleep(1); + + brender->allocate_map(brender_start, start_frame, end_frame); +//sleep(1); +//printf("BRenderThread::start 2\n"); + + result = packages->create_packages(mwindow, + command->edl, + preferences, + BRENDER_FARM, + preferences->brender_asset, + (double)start_frame / command->edl->session->frame_rate, + (double)end_frame / command->edl->session->frame_rate, + 0); + +//sleep(1); +//printf("BRenderThread::start 3 %d\n", result); + farm_server = new RenderFarmServer(mwindow, + packages, + preferences, + 0, + &farm_result, + &total_frames, + total_frames_lock, + preferences->brender_asset, + command->edl, + brender); + +//sleep(1); +//printf("BRenderThread::start 4\n"); + result = farm_server->start_clients(); + +//sleep(1); +// No local rendering because of codec problems. + + +// Abort + if(result) + { +// No-one must be retrieving a package when packages are deleted. +//printf("BRenderThread::start 7 %p\n", farm_server); + delete farm_server; + delete packages; +//printf("BRenderThread::start 8 %p\n", preferences); + delete preferences; +//printf("BRenderThread::start 9\n"); + farm_server = 0; + packages = 0; + preferences = 0; + } +//sleep(1); +//printf("BRenderThread::start 10\n"); + + } +} + +