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)
233 //printf("BRender::set_video_map(%jd, %d)\n", position, value);
234 map_lock->lock("BRender::set_video_map");
236 if(value == BRender::NOT_SCANNED)
238 printf(_("BRender::set_video_map called to set NOT_SCANNED\n"));
240 if( position < 0) {} // Preroll
241 else if( position < map_size ) map[position] = value; // In range
243 printf(_("BRender::set_video_map %jd: attempt to set beyond end of map %jd.\n"),
247 // Maintain last contiguous here to reduce search time
248 if( position == last_contiguous && last_contiguous < map_size ) {
249 while( last_contiguous < map_size && map[last_contiguous] )
251 if( last_contiguous >= map_size ) update_gui = 1;
252 mwindow->session->brender_end = (double)last_contiguous /
253 mwindow->edl->session->frame_rate;
256 if( timer->get_difference() > 1000 )
263 mwindow->gui->lock_window("BRender::set_video_map");
264 mwindow->gui->update_timebar(1);
265 mwindow->gui->unlock_window();
283 BRenderCommand::BRenderCommand()
286 command = BRENDER_NONE;
290 BRenderCommand::~BRenderCommand()
292 // EDL should be zeroed if copied
293 if(edl) edl->Garbage::remove_user();
296 void BRenderCommand::copy_from(BRenderCommand *src)
298 this->edl = src->edl;
300 this->position = src->position;
301 this->command = src->command;
305 void BRenderCommand::copy_edl(EDL *edl)
308 this->edl->create_objects();
309 this->edl->copy_all(edl);
324 BRenderThread::BRenderThread(MWindow *mwindow, BRender *brender)
327 this->mwindow = mwindow;
328 this->brender = brender;
329 input_lock = new Condition(0, "BRenderThread::input_lock");
330 thread_lock = new Mutex("BRenderThread::thread_lock");
331 total_frames_lock = new Mutex("BRenderThread::total_frames_lock");
340 BRenderThread::~BRenderThread()
342 thread_lock->lock("BRenderThread::~BRenderThread");
344 input_lock->unlock();
345 thread_lock->unlock();
350 delete total_frames_lock;
352 delete command_queue;
357 void BRenderThread::initialize()
362 void BRenderThread::send_command(BRenderCommand *command)
364 thread_lock->lock("BRenderThread::send_command");
365 delete this->command_queue;
366 this->command_queue = command;
367 input_lock->unlock();
368 thread_lock->unlock();
371 void BRenderThread::run()
373 thread_lock->lock("BRenderThread::run");
375 if( !command_queue ) {
376 thread_lock->unlock();
377 input_lock->lock("BRenderThread::run");
378 thread_lock->lock("BRenderThread::run 1");
382 BRenderCommand *new_command = command_queue;
384 if( !new_command ) continue;
385 thread_lock->unlock();
387 switch( new_command->command ) {
388 case BRenderCommand::BRENDER_STOP:
390 brender->completion_lock->unlock();
392 case BRenderCommand::BRENDER_RESTART:
393 new_command->position = command && command->edl ?
394 new_command->edl->equivalent_output(command->edl) : 0;
395 delete command; command = 0;
396 if( new_command->edl->tracks->total_playable_vtracks() ) {
397 command = new_command;
402 thread_lock->lock("BRenderThread::run 2");
404 thread_lock->unlock();
407 void BRenderThread::stop()
409 if( !farm_server ) return;
411 farm_server->wait_clients();
412 delete farm_server; farm_server = 0;
413 delete packages; packages = 0;
414 delete preferences; preferences = 0;
417 void BRenderThread::start()
419 // Reset return parameters
425 // Allocate render farm.
428 //printf("BRenderThread::start 1\n");
429 preferences = new Preferences;
430 preferences->copy_from(mwindow->preferences);
431 packages = new PackageDispatcher;
433 // Fix preferences to use local node
434 if(!preferences->use_renderfarm)
436 preferences->use_renderfarm = 1;
437 preferences->delete_nodes();
439 preferences->add_node(brender->socket_path,
442 preferences->local_rate);
443 //printf("BRenderThread::start 1 %s\n", brender->socket_path);
444 preferences->brender_asset->use_header = 0;
445 preferences->brender_asset->frame_rate = command->edl->session->frame_rate;
446 preferences->brender_asset->width = command->edl->session->output_w;
447 preferences->brender_asset->height = command->edl->session->output_h;
448 preferences->brender_asset->interlace_mode = command->edl->session->interlace_mode;
450 // Get last contiguous and reset map.
451 // If the framerate changes, last good should be 0 from the user.
452 int brender_start = (int)(command->edl->session->brender_start *
453 command->edl->session->frame_rate);
454 int last_contiguous = brender->last_contiguous;
455 int last_good = (int)(command->edl->session->frame_rate *
457 if(last_good < 0) last_good = last_contiguous;
458 int start_frame = MIN(last_contiguous, last_good);
459 start_frame = MAX(start_frame, brender_start);
460 // int64_t end_frame = Units::round(command->edl->tracks->total_video_length() *
461 // command->edl->session->frame_rate);
462 int64_t end_frame = Units::round(command->edl->session->brender_end *
463 command->edl->session->frame_rate);
464 if(end_frame < start_frame) end_frame = start_frame;
467 printf("BRenderThread::start 1 map=%d equivalent=%d brender_start=%d result=%d end=%jd\n",
468 last_contiguous, last_good, brender_start, start_frame, end_frame);
472 brender->allocate_map(brender_start, start_frame, end_frame);
474 //printf("BRenderThread::start 2\n");
476 result = packages->create_packages(mwindow,
480 preferences->brender_asset,
481 (double)start_frame / command->edl->session->frame_rate,
482 (double)end_frame / command->edl->session->frame_rate,
486 //printf("BRenderThread::start 3 %d\n", result);
487 farm_server = new RenderFarmServer(mwindow,
494 preferences->brender_asset,
499 //printf("BRenderThread::start 4\n");
500 result = farm_server->start_clients();
503 // No local rendering because of codec problems.
509 // No-one must be retrieving a package when packages are deleted.
510 //printf("BRenderThread::start 7 %p\n", farm_server);
513 //printf("BRenderThread::start 8 %p\n", preferences);
515 //printf("BRenderThread::start 9\n");
521 //printf("BRenderThread::start 10\n");