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 #if defined(__TERMUX__)
107 sprintf(socket_path, "/data/data/com.termux/files/home/tmp/cinelerra.");
109 uuid_generate(socket_temp);
110 uuid_unparse(socket_temp, socket_path + strlen(socket_path));
111 SET_TEMP(socket_path);
113 // Start background instance of executable since codecs aren't reentrant
116 // Wait for local node to start
117 thread = new BRenderThread(mwindow, this);
118 thread->initialize();
123 char string[BCTEXTLEN];
125 //printf("BRender::run 1 %d\n", getpid());
128 // Construct executable command with the designated filesystem port
129 fd = fopen("/proc/self/cmdline", "r");
132 (void)fread(string, 1, BCTEXTLEN, fd);
136 perror(_("BRender::fork_background: can't open /proc/self/cmdline.\n"));
138 arguments[0] = new char[strlen(string) + 1];
139 strcpy(arguments[0], string);
141 strcpy(string, "-b");
142 arguments[1] = new char[strlen(string) + 1];
143 strcpy(arguments[1], string);
145 arguments[2] = new char[strlen(socket_path) + 1];
146 strcpy(arguments[2], socket_path);
147 //printf("BRender::fork_background 1 %s\n", socket_path);
154 execvp(arguments[0], arguments);
155 perror("BRender::fork_background");
160 //printf("BRender::fork_background 1 %d\n", master_pid);
165 if(waitpid(master_pid, &return_value, WUNTRACED) < 0)
167 perror("BRender::run waitpid");
171 // Give the last position of the EDL which hasn't changed.
172 // We copy the EDL and restart rendering at the lesser of position and
174 void BRender::restart(EDL *edl)
176 //printf("BRender::restart 1\n");
177 BRenderCommand *new_command = new BRenderCommand;
179 new_command->copy_edl(edl);
180 new_command->command = BRenderCommand::BRENDER_RESTART;
181 //printf("BRender::restart 2\n");
182 thread->send_command(new_command);
183 //printf("BRender::restart 3\n");
184 // Map should be reallocated before this returns.
189 if( !running() || !thread->running() ) return;
190 BRenderCommand *new_command = new BRenderCommand;
191 new_command->command = BRenderCommand::BRENDER_STOP;
192 thread->send_command(new_command);
193 completion_lock->lock("BRender::stop");
198 int BRender::get_last_contiguous(int64_t brender_start)
201 map_lock->lock("BRender::get_last_contiguous");
203 result = last_contiguous;
205 result = brender_start;
210 void BRender::allocate_map(int64_t brender_start, int64_t start, int64_t end)
212 map_lock->lock("BRender::allocate_map");
213 unsigned char *old_map = map;
214 map = new unsigned char[end];
217 memcpy(map, old_map, start);
221 // Zero all before brender start
222 bzero(map, brender_start);
223 // Zero all after current start
224 bzero(map + start, end - start);
228 last_contiguous = start;
229 mwindow->session->brender_end = (double)last_contiguous /
230 mwindow->edl->session->frame_rate;
234 int BRender::set_video_map(int64_t position, int value)
236 //printf("BRender::set_video_map(%jd, %d)\n", position, value);
237 map_lock->lock("BRender::set_video_map");
239 if(value == BRender::NOT_SCANNED)
241 printf(_("BRender::set_video_map called to set NOT_SCANNED\n"));
243 if( position < 0) {} // Preroll
244 else if( position < map_size ) map[position] = value; // In range
246 printf(_("BRender::set_video_map %jd: attempt to set beyond end of map %jd.\n"),
250 // Maintain last contiguous here to reduce search time
251 if( position == last_contiguous && last_contiguous < map_size ) {
252 while( last_contiguous < map_size && map[last_contiguous] )
254 if( last_contiguous >= map_size ) update_gui = 1;
255 mwindow->session->brender_end = (double)last_contiguous /
256 mwindow->edl->session->frame_rate;
259 if( timer->get_difference() > 1000 )
266 mwindow->gui->lock_window("BRender::set_video_map");
267 mwindow->gui->update_timebar(1);
268 mwindow->gui->unlock_window();
286 BRenderCommand::BRenderCommand()
289 command = BRENDER_NONE;
293 BRenderCommand::~BRenderCommand()
295 // EDL should be zeroed if copied
296 if(edl) edl->Garbage::remove_user();
299 void BRenderCommand::copy_from(BRenderCommand *src)
301 this->edl = src->edl;
303 this->position = src->position;
304 this->command = src->command;
308 void BRenderCommand::copy_edl(EDL *edl)
311 this->edl->create_objects();
312 this->edl->copy_all(edl);
327 BRenderThread::BRenderThread(MWindow *mwindow, BRender *brender)
330 this->mwindow = mwindow;
331 this->brender = brender;
332 input_lock = new Condition(0, "BRenderThread::input_lock");
333 thread_lock = new Mutex("BRenderThread::thread_lock");
334 total_frames_lock = new Mutex("BRenderThread::total_frames_lock");
343 BRenderThread::~BRenderThread()
345 thread_lock->lock("BRenderThread::~BRenderThread");
347 input_lock->unlock();
348 thread_lock->unlock();
353 delete total_frames_lock;
355 delete command_queue;
360 void BRenderThread::initialize()
365 void BRenderThread::send_command(BRenderCommand *command)
367 thread_lock->lock("BRenderThread::send_command");
368 delete this->command_queue;
369 this->command_queue = command;
370 input_lock->unlock();
371 thread_lock->unlock();
374 void BRenderThread::run()
376 thread_lock->lock("BRenderThread::run");
378 if( !command_queue ) {
379 thread_lock->unlock();
380 input_lock->lock("BRenderThread::run");
381 thread_lock->lock("BRenderThread::run 1");
385 BRenderCommand *new_command = command_queue;
387 if( !new_command ) continue;
388 thread_lock->unlock();
390 switch( new_command->command ) {
391 case BRenderCommand::BRENDER_STOP:
393 brender->completion_lock->unlock();
395 case BRenderCommand::BRENDER_RESTART:
396 new_command->position = command && command->edl ?
397 new_command->edl->equivalent_output(command->edl) : 0;
398 delete command; command = 0;
399 if( new_command->edl->tracks->total_playable_vtracks() ) {
400 command = new_command;
405 thread_lock->lock("BRenderThread::run 2");
407 thread_lock->unlock();
410 void BRenderThread::stop()
412 if( !farm_server ) return;
414 farm_server->wait_clients();
415 delete farm_server; farm_server = 0;
416 delete packages; packages = 0;
417 delete preferences; preferences = 0;
420 void BRenderThread::start()
422 // Reset return parameters
428 // Allocate render farm.
431 //printf("BRenderThread::start 1\n");
432 preferences = new Preferences;
433 preferences->copy_from(mwindow->preferences);
434 packages = new PackageDispatcher;
436 // Fix preferences to use local node
437 if(!preferences->use_renderfarm)
439 preferences->use_renderfarm = 1;
440 preferences->delete_nodes();
442 preferences->add_node(brender->socket_path,
445 preferences->local_rate);
446 //printf("BRenderThread::start 1 %s\n", brender->socket_path);
447 preferences->brender_asset->use_header = 0;
448 preferences->brender_asset->frame_rate = command->edl->session->frame_rate;
449 preferences->brender_asset->width = command->edl->session->output_w;
450 preferences->brender_asset->height = command->edl->session->output_h;
451 preferences->brender_asset->interlace_mode = command->edl->session->interlace_mode;
453 // Get last contiguous and reset map.
454 // If the framerate changes, last good should be 0 from the user.
455 int brender_start = (int)(command->edl->session->brender_start *
456 command->edl->session->frame_rate);
457 int last_contiguous = brender->last_contiguous;
458 int last_good = (int)(command->edl->session->frame_rate *
460 if(last_good < 0) last_good = last_contiguous;
461 int start_frame = MIN(last_contiguous, last_good);
462 start_frame = MAX(start_frame, brender_start);
463 // int64_t end_frame = Units::round(command->edl->tracks->total_video_length() *
464 // command->edl->session->frame_rate);
465 int64_t end_frame = Units::round(command->edl->session->brender_end *
466 command->edl->session->frame_rate);
467 if(end_frame < start_frame) end_frame = start_frame;
470 printf("BRenderThread::start 1 map=%d equivalent=%d brender_start=%d result=%d end=%jd\n",
471 last_contiguous, last_good, brender_start, start_frame, end_frame);
475 brender->allocate_map(brender_start, start_frame, end_frame);
477 //printf("BRenderThread::start 2\n");
479 result = packages->create_packages(mwindow,
483 preferences->brender_asset,
484 (double)start_frame / command->edl->session->frame_rate,
485 (double)end_frame / command->edl->session->frame_rate,
489 //printf("BRenderThread::start 3 %d\n", result);
490 farm_server = new RenderFarmServer(mwindow,
497 preferences->brender_asset,
502 //printf("BRenderThread::start 4\n");
503 result = farm_server->start_clients();
506 // No local rendering because of codec problems.
512 // No-one must be retrieving a package when packages are deleted.
513 //printf("BRenderThread::start 7 %p\n", farm_server);
516 //printf("BRenderThread::start 8 %p\n", preferences);
518 //printf("BRenderThread::start 9\n");
524 //printf("BRenderThread::start 10\n");