r668: Configure.in and autogen.sh cleanup based on ideas by giskard.
[cinelerra_cv.git] / cinelerra / brender.C
blobbf3382c0e570d19774db9ba2943464cd3ed3dfd3
1 #include "asset.h"
2 #include "bcsignals.h"
3 #include "brender.h"
4 #include "clip.h"
5 #include "condition.h"
6 #include "edl.h"
7 #include "edlsession.h"
8 #include "language.h"
9 #include "mainsession.h"
10 #include "mtimebar.h"
11 #include "mutex.h"
12 #include "mwindowgui.h"
13 #include "mwindow.h"
14 #include "packagedispatcher.h"
15 #include "preferences.h"
16 #include "renderfarm.h"
17 #include "tracks.h"
18 #include "units.h"
21 #include <errno.h>
22 #include <signal.h>
23 #include <string.h>
24 #include <sys/wait.h>
25 #include <unistd.h>
29 extern "C"
31 #include <uuid/uuid.h>
39 BRender::BRender(MWindow *mwindow)
40  : Thread()
42         this->mwindow = mwindow;
43         map_lock = new Mutex("BRender::map_lock");
44         completion_lock = new Condition(0, "BRender::completion_lock");
45         timer = new Timer;
46         socket_path[0] = 0;
47         thread = 0;
48         master_pid = -1;
49         arguments[0] = arguments[1] = arguments[2] = 0;
50         map = 0;
51         map_size = 0;
52         map_valid = 0;
53         last_contiguous + 0;
54         set_synchronous(1);
57 BRender::~BRender()
59 TRACE("BRender::~BRender 1\n");
60         if(thread) 
61         {
62 TRACE("BRender::~BRender 2\n");
63                 stop();
64 TRACE("BRender::~BRender 3\n");
65                 delete thread;
66 TRACE("BRender::~BRender 4\n");
67         }
70 TRACE("BRender::~BRender 5\n");
71         if(master_pid >= 0)
72         {
73                 kill(master_pid, SIGKILL);
74 TRACE("BRender::~BRender 6\n");
75                 Thread::join();
76 TRACE("BRender::~BRender 7\n");
77         }
79 TRACE("BRender::~BRender 8\n");
80         delete map_lock;
81 TRACE("BRender::~BRender 9\n");
82         delete completion_lock;
83 TRACE("BRender::~BRender 10\n");
84 UNSET_TEMP(socket_path);
85         remove(socket_path);
86 TRACE("BRender::~BRender 11\n");
87         if(arguments[0]) delete [] arguments[0];
88 TRACE("BRender::~BRender 12\n");
89         if(arguments[1]) delete [] arguments[1];
90 TRACE("BRender::~BRender 13\n");
91         if(arguments[2]) delete [] arguments[2];
92 TRACE("BRender::~BRender 14\n");
93         if(map) delete [] map;
94 TRACE("BRender::~BRender 15\n");
95         delete timer;
96 TRACE("BRender::~BRender 100\n");
99 void BRender::initialize()
101         timer->update();
102 // Create socket for background process.
103         uuid_t socket_temp;
104         sprintf(socket_path, "/tmp/cinelerra.");
105         uuid_generate(socket_temp);
106         uuid_unparse(socket_temp, socket_path + strlen(socket_path));
107 SET_TEMP(socket_path);
109 // Start background instance of executable since codecs aren't reentrant
110         Thread::start();
112 // Wait for local node to start
113         thread = new BRenderThread(mwindow, this);
114         thread->initialize();
117 void BRender::run()
119         char string[BCTEXTLEN];
120         int size;
121         FILE *fd;
122 //printf("BRender::run 1 %d\n", getpid());
125 // Construct executable command with the designated filesystem port
126         fd = fopen("/proc/self/cmdline", "r");
127         if(fd)
128         {
129                 fread(string, 1, BCTEXTLEN, fd);
130                 fclose(fd);
131         }
132         else
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);
146         arguments[3] = 0;
148         int pid = vfork();
149         if(!pid)
150         {
151                 execvp(arguments[0], arguments);
152                 perror("BRender::fork_background");
153                 _exit(0);
154         }
156         master_pid = pid;
157 //printf("BRender::fork_background 1 %d\n", master_pid);
161         int return_value;
162         if(waitpid(master_pid, &return_value, WUNTRACED) < 0)
163         {
164                 perror("BRender::run waitpid");
165         }
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
170 // our position.
171 void BRender::restart(EDL *edl)
173 //printf("BRender::restart 1\n");
174         BRenderCommand *new_command = new BRenderCommand;
175         map_valid = 0;
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.
184 void BRender::stop()
186 //printf("BRender::stop 1\n");
187         BRenderCommand *new_command = new BRenderCommand;
188 //printf("BRender::stop 1\n");
189         new_command->command = BRenderCommand::BRENDER_STOP;
190 //printf("BRender::stop 1\n");
191         thread->send_command(new_command);
192 //printf("BRender::stop 1\n");
193         completion_lock->lock("BRender::stop");
194 //printf("BRender::stop 2\n");
199 int BRender::get_last_contiguous(int64_t brender_start)
201         int result;
202         map_lock->lock("BRender::get_last_contiguous");
203         if(map_valid)
204                 result = last_contiguous;
205         else
206                 result = brender_start;
207         map_lock->unlock();
208         return result;
211 void BRender::allocate_map(int64_t brender_start, int64_t start, int64_t end)
213         map_lock->lock("BRender::allocate_map");
214         unsigned char *old_map = map;
215         map = new unsigned char[end];
216         if(old_map)
217         {
218                 memcpy(map, old_map, start);
219                 delete [] old_map;
220         }
222 // Zero all before brender start
223         bzero(map, brender_start);
224 // Zero all after current start
225         bzero(map + start, end - start);
227         map_size = end;
228         map_valid = 1;
229         last_contiguous = start;
230         mwindow->session->brender_end = (double)last_contiguous / 
231                 mwindow->edl->session->frame_rate;
232         map_lock->unlock();
235 int BRender::set_video_map(int64_t position, int value)
237         int update_gui = 0;
238         map_lock->lock("BRender::set_video_map");
241         if(value == BRender::NOT_SCANNED)
242         {
243                 printf(_("BRender::set_video_map called to set NOT_SCANNED\n"));
244         }
246 // Preroll
247         if(position < 0)
248         {
249                 ;
250         }
251         else
252 // In range
253         if(position < map_size)
254         {
255                 map[position] = value;
256         }
257         else
258 // Obsolete EDL
259         {
260                 printf(_("BRender::set_video_map %d: attempt to set beyond end of map %d.\n"),
261                         position,
262                         map_size);
263         }
265 // Maintain last contiguous here to reduce search time
266         if(position == last_contiguous)
267         {
268                 int i;
269                 for(i = position + 1; i < map_size && map[i]; i++)
270                 {
271                         ;
272                 }
273                 last_contiguous = i;
274                 mwindow->session->brender_end = (double)last_contiguous / 
275                         mwindow->edl->session->frame_rate;
277                 if(timer->get_difference() > 1000 || last_contiguous >= map_size)
278                 {
279                         update_gui = 1;
280                         timer->update();
281                 }
282         }
284         map_lock->unlock();
286         if(update_gui)
287         {
288                 mwindow->gui->lock_window("BRender::set_video_map");
289                 mwindow->gui->timebar->update(1, 0);
290                 mwindow->gui->timebar->flush();
291                 mwindow->gui->unlock_window();
292         }
293         return 0;
309 BRenderCommand::BRenderCommand()
311         edl = 0;
312         command = BRENDER_NONE;
313         position = 0.0;
316 BRenderCommand::~BRenderCommand()
318 // EDL should be zeroed if copied
319         if(edl) delete edl;
322 void BRenderCommand::copy_from(BRenderCommand *src)
324         this->edl = src->edl;
325         src->edl = 0;
326         this->position = src->position;
327         this->command = src->command;
331 void BRenderCommand::copy_edl(EDL *edl)
333         this->edl = new EDL;
334         this->edl->create_objects();
335         this->edl->copy_all(edl);
336         this->position = 0;
350 BRenderThread::BRenderThread(MWindow *mwindow, BRender *brender)
351  : Thread(1)
353         this->mwindow = mwindow;
354         this->brender = brender;
355         input_lock = new Condition(0, "BRenderThread::input_lock");
356         thread_lock = new Mutex("BRenderThread::thread_lock");
357         total_frames_lock = new Mutex("BRenderThread::total_frames_lock");
358         command_queue = 0;
359         command = 0;
360         done = 0;
361         farm_server = 0;
362         farm_result = 0;
363         preferences = 0;
366 BRenderThread::~BRenderThread()
368         thread_lock->lock("BRenderThread::~BRenderThread");
369         done = 1;
370         input_lock->unlock();
371         thread_lock->unlock();
372         Thread::join();
373         delete input_lock;
374         delete thread_lock;
375         delete total_frames_lock;
376         if(command) delete command;
377         if(command_queue) delete command_queue;
378         if(preferences) delete preferences;
382 void BRenderThread::initialize()
384         Thread::start();
387 void BRenderThread::send_command(BRenderCommand *command)
389 TRACE("BRenderThread::send_command 1");
390         thread_lock->lock("BRenderThread::send_command");
391 TRACE("BRenderThread::send_command 10");
393         if(this->command_queue)
394         {
395                 delete this->command_queue;
396                 this->command_queue = 0;
397         }
398         this->command_queue = command;
399 TRACE("BRenderThread::send_command 20");
402         input_lock->unlock();
403         thread_lock->unlock();
406 int BRenderThread::is_done(int do_lock)
408         if(do_lock) thread_lock->lock("BRenderThread::is_done");
409         int result = done;
410         if(do_lock) thread_lock->unlock();
411         return result;
414 void BRenderThread::run()
416         while(!is_done(1))
417         {
418                 BRenderCommand *new_command = 0;
419                 thread_lock->lock("BRenderThread::run 1");
421 // Got new command
422                 if(command_queue)
423                 {
424                         ;
425                 }
426                 else
427 // Wait for new command
428                 {
429                         thread_lock->unlock();
430                         input_lock->lock("BRenderThread::run 2");
431                         thread_lock->lock("BRenderThread::run 3");
432                 }
434 // Pull the command off
435                 if(!is_done(0))
436                 {
437                         new_command = command_queue;
438                         command_queue = 0;
439                 }
441                 thread_lock->unlock();
446 // Process the command here to avoid delay.
447 // Quit condition
448                 if(!new_command)
449                 {
450                         ;
451                 }
452                 else
453                 if(new_command->command == BRenderCommand::BRENDER_STOP)
454                 {
455                         stop();
456                         delete new_command;
457                         new_command = 0;
458 //                      if(command) delete command;
459 //                      command = new_command;
460                 }
461                 else
462                 if(new_command->command == BRenderCommand::BRENDER_RESTART)
463                 {
464 // Compare EDL's and get last equivalent position in new EDL
465                         if(command && command->edl)
466                                 new_command->position = 
467                                         new_command->edl->equivalent_output(command->edl);
468                         else
469                                 new_command->position = 0;
472                         stop();
473 //printf("BRenderThread::run 4\n");
474                         brender->completion_lock->lock("BRenderThread::run 4");
475 //printf("BRenderThread::run 5\n");
477                         if(new_command->edl->tracks->total_playable_vtracks())
478                         {
479                                 if(command) delete command;
480                                 command = new_command;
481 //printf("BRenderThread::run 6\n");
482                                 start();
483 //printf("BRenderThread::run 7\n");
484                         }
485                         else
486                         {
487 //printf("BRenderThread::run 8 %p\n", farm_server);
488                                 delete new_command;
489                                 new_command = 0;
490                         }
491                 }
492         }
495 void BRenderThread::stop()
497         if(farm_server)
498         {
499                 farm_result = 1;
500                 farm_server->wait_clients();
501                 delete farm_server;
502                 delete packages;
503                 delete preferences;
504                 farm_server = 0;
505                 packages = 0;
506                 preferences = 0;
507         }
508         brender->completion_lock->unlock();
511 void BRenderThread::start()
513 // Reset return parameters
514         farm_result = 0;
515         fps_result = 0;
516         total_frames = 0;
517         int result = 0;
519 // Allocate render farm.
520         if(!farm_server)
521         {
522 //printf("BRenderThread::start 1\n");
523                 preferences = new Preferences;
524                 preferences->copy_from(mwindow->preferences);
525                 packages = new PackageDispatcher;
527 // Fix preferences to use local node
528                 if(!preferences->use_renderfarm)
529                 {
530                         preferences->use_renderfarm = 1;
531                         preferences->delete_nodes();
532                 }
533                 preferences->add_node(brender->socket_path,
534                         0,
535                         1,
536                         preferences->local_rate);
537 //printf("BRenderThread::start 1 %s\n", brender->socket_path);
538                 preferences->brender_asset->use_header = 0;
539                 preferences->brender_asset->frame_rate = command->edl->session->frame_rate;
540                 preferences->brender_asset->width = command->edl->session->output_w;
541                 preferences->brender_asset->height = command->edl->session->output_h;
542                 preferences->brender_asset->interlace_mode = command->edl->session->interlace_mode;
544 // Get last contiguous and reset map.
545 // If the framerate changes, last good should be 0 from the user.
546                 int brender_start = (int)(command->edl->session->brender_start *
547                         command->edl->session->frame_rate);
548                 int last_contiguous = brender->last_contiguous;
549                 int last_good = (int)(command->edl->session->frame_rate * 
550                         command->position);
551                 if(last_good < 0) last_good = last_contiguous;
552                 int start_frame = MIN(last_contiguous, last_good);
553                 start_frame = MAX(start_frame, brender_start);
554                 int64_t end_frame = Units::round(command->edl->tracks->total_video_length() * 
555                         command->edl->session->frame_rate);
556                 if(end_frame < start_frame) end_frame = start_frame;
559 printf("BRenderThread::start 1 map=%d equivalent=%d brender_start=%d result=%d end=%d\n", 
560 last_contiguous, 
561 last_good, 
562 brender_start, 
563 start_frame,
564 end_frame);
566 //sleep(1);
568                 brender->allocate_map(brender_start, start_frame, end_frame);
569 //sleep(1);
570 //printf("BRenderThread::start 2\n");
572                 result = packages->create_packages(mwindow,
573                         command->edl,
574                         preferences,
575                         BRENDER_FARM, 
576                         preferences->brender_asset, 
577                         (double)start_frame / command->edl->session->frame_rate, 
578                         (double)end_frame / command->edl->session->frame_rate,
579                         0);
581 //sleep(1);
582 //printf("BRenderThread::start 3 %d\n", result);
583                 farm_server = new RenderFarmServer(mwindow->plugindb, 
584                         packages,
585                         preferences,
586                         0,
587                         &farm_result,
588                         &total_frames,
589                         total_frames_lock,
590                         preferences->brender_asset,
591                         command->edl,
592                         brender);
594 //sleep(1);
595 //printf("BRenderThread::start 4\n");
596                 result = farm_server->start_clients();
598 //sleep(1);
599 // No local rendering because of codec problems.
602 // Abort
603                 if(result)
604                 {
605 // No-one must be retrieving a package when packages are deleted.
606 //printf("BRenderThread::start 7 %p\n", farm_server);
607                         delete farm_server;
608                         delete packages;
609 //printf("BRenderThread::start 8 %p\n", preferences);
610                         delete preferences;
611 //printf("BRenderThread::start 9\n");
612                         farm_server = 0;
613                         packages = 0;
614                         preferences = 0;
615                 }
616 //sleep(1);
617 //printf("BRenderThread::start 10\n");
619         }