r105: This commit was manufactured by cvs2svn to create tag
[cinelerra_cv/mob.git] / hvirtual / cinelerra / brender.C
blob19248a69aac42216a309ebf549d0fdfde79d6f08
1 #include "assets.h"
2 #include "brender.h"
3 #include "clip.h"
4 #include "edl.h"
5 #include "edlsession.h"
6 #include "mainsession.h"
7 #include "mutex.h"
8 #include "mwindow.h"
9 #include "mwindowgui.h"
10 #include "preferences.h"
11 #include "renderfarm.h"
12 #include "packagedispatcher.h"
13 #include "mtimebar.h"
14 #include "tracks.h"
15 #include "units.h"
18 #include <errno.h>
19 #include <signal.h>
20 #include <string.h>
21 #include <sys/wait.h>
22 #include <unistd.h>
25 #include <libintl.h>
26 #define _(String) gettext(String)
27 #define gettext_noop(String) String
28 #define N_(String) gettext_noop (String)
30 extern "C"
32 #include <uuid/uuid.h>
40 BRender::BRender(MWindow *mwindow)
41  : Thread()
43         this->mwindow = mwindow;
44         map_lock = new Mutex;
45         completion_lock = new Mutex;
46         timer = new Timer;
47         completion_lock->lock();
48         socket_path[0] = 0;
49         thread = 0;
50         master_pid = -1;
51         arguments[0] = arguments[1] = arguments[2] = 0;
52         map = 0;
53         map_size = 0;
54         map_valid = 0;
55         last_contiguous + 0;
56         set_synchronous(1);
59 BRender::~BRender()
61         if(thread) 
62         {
63 //printf("BRender::~BRender 1\n");
64                 stop();
65 //printf("BRender::~BRender 2\n");
66                 delete thread;
67         }
69 //printf("BRender::~BRender 3\n");
71         if(master_pid >= 0)
72         {
73                 kill(master_pid, SIGKILL);
74                 Thread::join();
75         }
77 //printf("BRender::~BRender 2\n");
78         delete map_lock;
79 //printf("BRender::~BRender 2\n");
80         delete completion_lock;
81 //printf("BRender::~BRender 2\n");
82         remove(socket_path);
83 //printf("BRender::~BRender 2\n");
84         if(arguments[0]) delete [] arguments[0];
85 //printf("BRender::~BRender 2\n");
86         if(arguments[1]) delete [] arguments[1];
87 //printf("BRender::~BRender 2\n");
88         if(arguments[2]) delete [] arguments[2];
89         if(map) delete [] map;
90         delete timer;
91 //printf("BRender::~BRender 3\n");
94 void BRender::initialize()
96         timer->update();
97 // Create socket for background process.
98         uuid_t socket_temp;
99         sprintf(socket_path, "/tmp/cinelerra.");
100         uuid_generate(socket_temp);
101         uuid_unparse(socket_temp, socket_path + strlen(socket_path));
103 // Start background instance of executable since codecs aren't reentrant
104         Thread::start();
106 // Wait for local node to start
107         thread = new BRenderThread(mwindow, this);
108         thread->initialize();
111 void BRender::run()
113         char string[BCTEXTLEN];
114         int size;
115         FILE *fd;
119 // Construct executable command with the designated filesystem port
120         fd = fopen("/proc/self/cmdline", "r");
121         if(fd)
122         {
123                 fread(string, 1, BCTEXTLEN, fd);
124                 fclose(fd);
125         }
126         else
127                 perror(_("BRender::fork_background: can't open /proc/self/cmdline.\n"));
129         arguments[0] = new char[strlen(string) + 1];
130         strcpy(arguments[0], string);
132         strcpy(string, "-b");
133         arguments[1] = new char[strlen(string) + 1];
134         strcpy(arguments[1], string);
136         arguments[2] = new char[strlen(socket_path) + 1];
137         strcpy(arguments[2], socket_path);
138 //printf("BRender::fork_background 1 %s\n", socket_path);
140         arguments[3] = 0;
142         int pid = vfork();
143         if(!pid)
144         {
145                 execvp(arguments[0], arguments);
146                 perror("BRender::fork_background");
147                 _exit(0);
148         }
150         master_pid = pid;
151 //printf("BRender::fork_background 1 %d\n", master_pid);
155         int return_value;
156         if(waitpid(master_pid, &return_value, WUNTRACED) < 0)
157         {
158                 perror("BRender::run waitpid");
159         }
162 // Give the last position of the EDL which hasn't changed.
163 // We copy the EDL and restart rendering at the lesser of position and
164 // our position.
165 void BRender::restart(EDL *edl)
167 //printf("BRender::restart 1\n");
168         BRenderCommand *new_command = new BRenderCommand;
169         map_valid = 0;
170         new_command->copy_edl(edl);
171         new_command->command = BRenderCommand::BRENDER_RESTART;
172 //printf("BRender::restart 2\n");
173         thread->send_command(new_command);
174 //printf("BRender::restart 3\n");
175 // Map should be reallocated before this returns.
178 void BRender::stop()
180 //printf("BRender::stop 1\n");
181         BRenderCommand *new_command = new BRenderCommand;
182 //printf("BRender::stop 1\n");
183         new_command->command = BRenderCommand::BRENDER_STOP;
184 //printf("BRender::stop 1\n");
185         thread->send_command(new_command);
186 //printf("BRender::stop 1\n");
187         completion_lock->lock();
188 //printf("BRender::stop 2\n");
193 int BRender::get_last_contiguous(int64_t brender_start)
195         int result;
196         map_lock->lock();
197         if(map_valid)
198                 result = last_contiguous;
199         else
200                 result = brender_start;
201         map_lock->unlock();
202         return result;
205 void BRender::allocate_map(int64_t brender_start, int64_t start, int64_t end)
207         map_lock->lock();
208         unsigned char *old_map = map;
209         map = new unsigned char[end];
210         if(old_map)
211         {
212                 memcpy(map, old_map, start);
213                 delete [] old_map;
214         }
216 // Zero all before brender start
217         bzero(map, brender_start);
218 // Zero all after current start
219         bzero(map + start, end - start);
221         map_size = end;
222         map_valid = 1;
223         last_contiguous = start;
224         mwindow->session->brender_end = (double)last_contiguous / 
225                 mwindow->edl->session->frame_rate;
226         map_lock->unlock();
229 void BRender::set_video_map(int64_t position, int value)
231         int update_gui = 0;
232         map_lock->lock();
234 //printf("BRender::set_video_map 1 %d %d\n", position, value);
236         if(value == BRender::NOT_SCANNED)
237         {
238                 printf(_("BRender::set_video_map called to set NOT_SCANNED\n"));
239         }
241 // Preroll
242         if(position < 0)
243         {
244                 ;
245         }
246         else
247 // In range
248         if(position < map_size)
249         {
250                 map[position] = value;
251         }
252         else
253 // Obsolete EDL
254         {
255                 printf(_("BRender::set_video_map %d: attempt to set beyond end of map %d.\n"),
256                         position,
257                         map_size);
258         }
260 // Maintain last contiguous here to reduce search time
261 //printf("BRender::set_video_map 1 %d %d\n", position, last_contiguous + 1);
262         if(position == last_contiguous)
263         {
264                 int i;
265                 for(i = position + 1; i < map_size && map[i]; i++)
266                 {
267                         ;
268                 }
269                 last_contiguous = i;
270                 mwindow->session->brender_end = (double)last_contiguous / 
271                         mwindow->edl->session->frame_rate;
273                 if(timer->get_difference() > 1000 || last_contiguous >= map_size)
274                 {
275 //printf("BRender::set_video_map 2\n");
276                         update_gui = 1;
277                         timer->update();
278                 }
279         }
281         map_lock->unlock();
283         if(update_gui)
284         {
285                 mwindow->gui->lock_window();
286                 mwindow->gui->timebar->update(1, 0);
287                 mwindow->gui->timebar->flush();
288                 mwindow->gui->unlock_window();
289         }
305 BRenderCommand::BRenderCommand()
307         edl = 0;
308         command = BRENDER_NONE;
309         position = 0.0;
312 BRenderCommand::~BRenderCommand()
314 // EDL should be zeroed if copied
315         if(edl) delete edl;
318 void BRenderCommand::copy_from(BRenderCommand *src)
320         this->edl = src->edl;
321         src->edl = 0;
322         this->position = src->position;
323         this->command = src->command;
327 void BRenderCommand::copy_edl(EDL *edl)
329         this->edl = new EDL;
330         this->edl->create_objects();
331         this->edl->copy_all(edl);
332         this->position = 0;
346 BRenderThread::BRenderThread(MWindow *mwindow, BRender *brender)
347  : Thread(1)
349         this->mwindow = mwindow;
350         this->brender = brender;
351         input_lock = new Mutex;
352         thread_lock = new Mutex;
353         total_frames_lock = new Mutex;
354         input_lock->lock();
355         command_queue = 0;
356         command = 0;
357         done = 0;
358         farm_server = 0;
359         farm_result = 0;
360         preferences = 0;
363 BRenderThread::~BRenderThread()
365         thread_lock->lock();
366         done = 1;
367         input_lock->unlock();
368         thread_lock->unlock();
369         Thread::join();
370         delete input_lock;
371         delete thread_lock;
372         delete total_frames_lock;
373         if(command) delete command;
374         if(command_queue) delete command_queue;
375         if(preferences) delete preferences;
379 void BRenderThread::initialize()
381         Thread::start();
384 void BRenderThread::send_command(BRenderCommand *command)
386         thread_lock->lock();
388         if(this->command_queue)
389         {
390                 delete this->command_queue;
391                 this->command_queue = 0;
392         }
393         this->command_queue = command;
396         input_lock->unlock();
397         thread_lock->unlock();
400 int BRenderThread::is_done(int do_lock)
402         if(do_lock) thread_lock->lock();
403         int result = done;
404         if(do_lock) thread_lock->unlock();
405         return result;
408 void BRenderThread::run()
410         while(!is_done(1))
411         {
412                 BRenderCommand *new_command = 0;
413                 thread_lock->lock();
415 // Got new command
416                 if(command_queue)
417                 {
418                         ;
419                 }
420                 else
421 // Wait for new command
422                 {
423                         thread_lock->unlock();
424                         input_lock->lock();
425                         thread_lock->lock();
426                 }
428 // Pull the command off
429                 if(!is_done(0))
430                 {
431                         new_command = command_queue;
432                         command_queue = 0;
433                 }
435                 thread_lock->unlock();
440 // Process the command here to avoid delay.
441 // Quit condition
442                 if(!new_command)
443                 {
444                         ;
445                 }
446                 else
447                 if(new_command->command == BRenderCommand::BRENDER_STOP)
448                 {
449                         stop();
450                         delete new_command;
451                         new_command = 0;
452 //                      if(command) delete command;
453 //                      command = new_command;
454                 }
455                 else
456                 if(new_command->command == BRenderCommand::BRENDER_RESTART)
457                 {
458 // Compare EDL's and get last equivalent position in new EDL
459                         if(command && command->edl)
460                                 new_command->position = 
461                                         new_command->edl->equivalent_output(command->edl);
462                         else
463                                 new_command->position = 0;
466                         stop();
467 //printf("BRenderThread::run 4\n");
468                         brender->completion_lock->lock();
469 //printf("BRenderThread::run 5\n");
471                         if(new_command->edl->tracks->total_playable_vtracks())
472                         {
473                                 if(command) delete command;
474                                 command = new_command;
475 //printf("BRenderThread::run 6\n");
476                                 start();
477 //printf("BRenderThread::run 7\n");
478                         }
479                         else
480                         {
481 //printf("BRenderThread::run 8 %p\n", farm_server);
482                                 delete new_command;
483                                 new_command = 0;
484                         }
485                 }
486         }
489 void BRenderThread::stop()
491         if(farm_server)
492         {
493                 farm_result = 1;
494                 farm_server->wait_clients();
495                 delete farm_server;
496                 delete packages;
497                 delete preferences;
498                 farm_server = 0;
499                 packages = 0;
500                 preferences = 0;
501         }
502         brender->completion_lock->unlock();
505 void BRenderThread::start()
507 // Reset return parameters
508         farm_result = 0;
509         fps_result = 0;
510         total_frames = 0;
511         int result = 0;
513 // Allocate render farm.
514         if(!farm_server)
515         {
516 //printf("BRenderThread::start 1\n");
517                 preferences = new Preferences;
518                 *preferences = *mwindow->preferences;
519                 packages = new PackageDispatcher;
521 // Fix preferences to use local node
522                 if(!preferences->use_renderfarm)
523                 {
524                         preferences->use_renderfarm = 1;
525                         preferences->delete_nodes();
526                 }
527                 preferences->add_node(brender->socket_path,
528                         0,
529                         1,
530                         preferences->local_rate);
531 //printf("BRenderThread::start 1 %s\n", brender->socket_path);
532                 preferences->brender_asset->use_header = 0;
533                 preferences->brender_asset->frame_rate = command->edl->session->frame_rate;
534                 preferences->brender_asset->width = command->edl->session->output_w;
535                 preferences->brender_asset->height = command->edl->session->output_h;
537 // Get last contiguous and reset map.
538 // If the framerate changes, last good should be 0 from the user.
539                 int brender_start = (int)(command->edl->session->brender_start *
540                         command->edl->session->frame_rate);
541                 int last_contiguous = brender->last_contiguous;
542                 int last_good = (int)(command->edl->session->frame_rate * 
543                         command->position);
544                 if(last_good < 0) last_good = last_contiguous;
545                 int start_frame = MIN(last_contiguous, last_good);
546                 start_frame = MAX(start_frame, brender_start);
547                 int64_t end_frame = Units::round(command->edl->tracks->total_video_length() * 
548                         command->edl->session->frame_rate);
549                 if(end_frame < start_frame) end_frame = start_frame;
550 printf("BRenderThread::start 1 map=%d equivalent=%d brender_start=%d result=%d end=%d\n", 
551 last_contiguous, 
552 last_good, 
553 brender_start, 
554 start_frame,
555 end_frame);
557 //sleep(1);
559                 brender->allocate_map(brender_start, start_frame, end_frame);
560 //sleep(1);
561 //printf("BRenderThread::start 2\n");
563                 result = packages->create_packages(mwindow,
564                         command->edl,
565                         preferences,
566                         BRENDER_FARM, 
567                         preferences->brender_asset, 
568                         (double)start_frame / command->edl->session->frame_rate, 
569                         (double)end_frame / command->edl->session->frame_rate);
571 //sleep(1);
572 //printf("BRenderThread::start 3 %d\n", result);
573                 farm_server = new RenderFarmServer(mwindow, 
574                         packages,
575                         preferences,
576                         0,
577                         &farm_result,
578                         &total_frames,
579                         total_frames_lock,
580                         preferences->brender_asset,
581                         command->edl,
582                         brender);
584 //sleep(1);
585 //printf("BRenderThread::start 4\n");
586                 result = farm_server->start_clients();
588 //sleep(1);
589 // No local rendering because of codec problems.
592 // Abort
593                 if(result)
594                 {
595 // No-one must be retrieving a package when packages are deleted.
596 //printf("BRenderThread::start 7 %p\n", farm_server);
597                         delete farm_server;
598                         delete packages;
599 //printf("BRenderThread::start 8 %p\n", preferences);
600                         delete preferences;
601 //printf("BRenderThread::start 9\n");
602                         farm_server = 0;
603                         packages = 0;
604                         preferences = 0;
605                 }
606 //sleep(1);
607 //printf("BRenderThread::start 10\n");
609         }