4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "bcsignals.h"
26 #include "condition.h"
28 #include "edlsession.h"
30 #include "mainsession.h"
33 #include "mwindowgui.h"
35 #include "packagedispatcher.h"
36 #include "preferences.h"
37 #include "renderfarm.h"
60 BRender::BRender(MWindow *mwindow)
63 this->mwindow = mwindow;
64 map_lock = new Mutex("BRender::map_lock");
65 completion_lock = new Condition(0, "BRender::completion_lock", 1);
70 arguments[0] = arguments[1] = arguments[2] = 0;
86 kill(master_pid, SIGKILL);
90 delete completion_lock;
91 UNSET_TEMP(socket_path);
93 if(arguments[0]) delete [] arguments[0];
94 if(arguments[1]) delete [] arguments[1];
95 if(arguments[2]) delete [] arguments[2];
96 if(map) delete [] map;
100 void BRender::initialize()
103 // Create socket for background process.
105 sprintf(socket_path, "/tmp/cinelerra.");
106 uuid_generate(socket_temp);
107 uuid_unparse(socket_temp, socket_path + strlen(socket_path));
108 SET_TEMP(socket_path);
110 // Start background instance of executable since codecs aren't reentrant
113 // Wait for local node to start
114 thread = new BRenderThread(mwindow, this);
115 thread->initialize();
120 char string[BCTEXTLEN];
122 //printf("BRender::run 1 %d\n", getpid());
125 // Construct executable command with the designated filesystem port
126 fd = fopen("/proc/self/cmdline", "r");
129 (void)fread(string, 1, BCTEXTLEN, fd);
133 perror(_("BRender::fork_background: can't open /proc/self/cmdline.\n"));
135 arguments[0] = new char[strlen(string) + 1];
136 strcpy(arguments[0], string);
138 strcpy(string, "-b");
139 arguments[1] = new char[strlen(string) + 1];
140 strcpy(arguments[1], string);
142 arguments[2] = new char[strlen(socket_path) + 1];
143 strcpy(arguments[2], socket_path);
144 //printf("BRender::fork_background 1 %s\n", socket_path);
151 execvp(arguments[0], arguments);
152 perror("BRender::fork_background");
157 //printf("BRender::fork_background 1 %d\n", master_pid);
162 if(waitpid(master_pid, &return_value, WUNTRACED) < 0)
164 perror("BRender::run waitpid");
168 // Give the last position of the EDL which hasn't changed.
169 // We copy the EDL and restart rendering at the lesser of position and
171 void BRender::restart(EDL *edl)
173 //printf("BRender::restart 1\n");
174 BRenderCommand *new_command = new BRenderCommand;
176 new_command->copy_edl(edl);
177 new_command->command = BRenderCommand::BRENDER_RESTART;
178 //printf("BRender::restart 2\n");
179 thread->send_command(new_command);
180 //printf("BRender::restart 3\n");
181 // Map should be reallocated before this returns.
186 if( !running() || !thread->running() ) return;
187 BRenderCommand *new_command = new BRenderCommand;
188 new_command->command = BRenderCommand::BRENDER_STOP;
189 thread->send_command(new_command);
190 completion_lock->lock("BRender::stop");
195 int BRender::get_last_contiguous(int64_t brender_start)
198 map_lock->lock("BRender::get_last_contiguous");
200 result = last_contiguous;
202 result = brender_start;
207 void BRender::allocate_map(int64_t brender_start, int64_t start, int64_t end)
209 map_lock->lock("BRender::allocate_map");
210 unsigned char *old_map = map;
211 map = new unsigned char[end];
214 memcpy(map, old_map, start);
218 // Zero all before brender start
219 bzero(map, brender_start);
220 // Zero all after current start
221 bzero(map + start, end - start);
225 last_contiguous = start;
226 mwindow->session->brender_end = (double)last_contiguous /
227 mwindow->edl->session->frame_rate;
231 int BRender::set_video_map(int64_t position, int value)
234 map_lock->lock("BRender::set_video_map");
237 if(value == BRender::NOT_SCANNED)
239 printf(_("BRender::set_video_map called to set NOT_SCANNED\n"));
249 if(position < map_size)
251 map[position] = value;
256 printf(_("BRender::set_video_map %jd: attempt to set beyond end of map %jd.\n"),
260 // Maintain last contiguous here to reduce search time
261 if(position == last_contiguous && last_contiguous < map_size )
264 for(i = position + 1; i < map_size && map[i]; i++)
269 mwindow->session->brender_end = (double)last_contiguous /
270 mwindow->edl->session->frame_rate;
272 if(timer->get_difference() > 1000 || last_contiguous >= map_size)
283 mwindow->gui->lock_window("BRender::set_video_map");
284 mwindow->gui->update_timebar(1);
285 mwindow->gui->unlock_window();
303 BRenderCommand::BRenderCommand()
306 command = BRENDER_NONE;
310 BRenderCommand::~BRenderCommand()
312 // EDL should be zeroed if copied
313 if(edl) edl->Garbage::remove_user();
316 void BRenderCommand::copy_from(BRenderCommand *src)
318 this->edl = src->edl;
320 this->position = src->position;
321 this->command = src->command;
325 void BRenderCommand::copy_edl(EDL *edl)
328 this->edl->create_objects();
329 this->edl->copy_all(edl);
344 BRenderThread::BRenderThread(MWindow *mwindow, BRender *brender)
347 this->mwindow = mwindow;
348 this->brender = brender;
349 input_lock = new Condition(0, "BRenderThread::input_lock");
350 thread_lock = new Mutex("BRenderThread::thread_lock");
351 total_frames_lock = new Mutex("BRenderThread::total_frames_lock");
360 BRenderThread::~BRenderThread()
362 thread_lock->lock("BRenderThread::~BRenderThread");
364 input_lock->unlock();
365 thread_lock->unlock();
370 delete total_frames_lock;
372 delete command_queue;
377 void BRenderThread::initialize()
382 void BRenderThread::send_command(BRenderCommand *command)
384 thread_lock->lock("BRenderThread::send_command");
385 delete this->command_queue;
386 this->command_queue = command;
387 input_lock->unlock();
388 thread_lock->unlock();
391 void BRenderThread::run()
393 thread_lock->lock("BRenderThread::run");
395 if( !command_queue ) {
396 thread_lock->unlock();
397 input_lock->lock("BRenderThread::run");
398 thread_lock->lock("BRenderThread::run 1");
402 BRenderCommand *new_command = command_queue;
404 if( !new_command ) continue;
405 thread_lock->unlock();
407 switch( new_command->command ) {
408 case BRenderCommand::BRENDER_STOP:
410 brender->completion_lock->unlock();
412 case BRenderCommand::BRENDER_RESTART:
413 new_command->position = command && command->edl ?
414 new_command->edl->equivalent_output(command->edl) : 0;
415 delete command; command = 0;
416 if( new_command->edl->tracks->total_playable_vtracks() ) {
417 command = new_command;
422 thread_lock->lock("BRenderThread::run 2");
424 thread_lock->unlock();
427 void BRenderThread::stop()
429 if( !farm_server ) return;
431 farm_server->wait_clients();
432 delete farm_server; farm_server = 0;
433 delete packages; packages = 0;
434 delete preferences; preferences = 0;
437 void BRenderThread::start()
439 // Reset return parameters
445 // Allocate render farm.
448 //printf("BRenderThread::start 1\n");
449 preferences = new Preferences;
450 preferences->copy_from(mwindow->preferences);
451 packages = new PackageDispatcher;
453 // Fix preferences to use local node
454 if(!preferences->use_renderfarm)
456 preferences->use_renderfarm = 1;
457 preferences->delete_nodes();
459 preferences->add_node(brender->socket_path,
462 preferences->local_rate);
463 //printf("BRenderThread::start 1 %s\n", brender->socket_path);
464 preferences->brender_asset->use_header = 0;
465 preferences->brender_asset->frame_rate = command->edl->session->frame_rate;
466 preferences->brender_asset->width = command->edl->session->output_w;
467 preferences->brender_asset->height = command->edl->session->output_h;
468 preferences->brender_asset->interlace_mode = command->edl->session->interlace_mode;
470 // Get last contiguous and reset map.
471 // If the framerate changes, last good should be 0 from the user.
472 int brender_start = (int)(command->edl->session->brender_start *
473 command->edl->session->frame_rate);
474 int last_contiguous = brender->last_contiguous;
475 int last_good = (int)(command->edl->session->frame_rate *
477 if(last_good < 0) last_good = last_contiguous;
478 int start_frame = MIN(last_contiguous, last_good);
479 start_frame = MAX(start_frame, brender_start);
480 // int64_t end_frame = Units::round(command->edl->tracks->total_video_length() *
481 // command->edl->session->frame_rate);
482 int64_t end_frame = Units::round(command->edl->session->brender_end *
483 command->edl->session->frame_rate);
484 if(end_frame < start_frame) end_frame = start_frame;
487 printf("BRenderThread::start 1 map=%d equivalent=%d brender_start=%d result=%d end=%jd\n",
488 last_contiguous, last_good, brender_start, start_frame, end_frame);
492 brender->allocate_map(brender_start, start_frame, end_frame);
494 //printf("BRenderThread::start 2\n");
496 result = packages->create_packages(mwindow,
500 preferences->brender_asset,
501 (double)start_frame / command->edl->session->frame_rate,
502 (double)end_frame / command->edl->session->frame_rate,
506 //printf("BRenderThread::start 3 %d\n", result);
507 farm_server = new RenderFarmServer(mwindow,
514 preferences->brender_asset,
519 //printf("BRenderThread::start 4\n");
520 result = farm_server->start_clients();
523 // No local rendering because of codec problems.
529 // No-one must be retrieving a package when packages are deleted.
530 //printf("BRenderThread::start 7 %p\n", farm_server);
533 //printf("BRenderThread::start 8 %p\n", preferences);
535 //printf("BRenderThread::start 9\n");
541 //printf("BRenderThread::start 10\n");