prevent popup deactivation while button_down
[goodguy/history.git] / cinelerra-5.0 / cinelerra / brender.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  * 
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.
10  * 
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.
15  * 
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
19  * 
20  */
21
22 #include "asset.h"
23 #include "bcsignals.h"
24 #include "brender.h"
25 #include "clip.h"
26 #include "condition.h"
27 #include "edl.h"
28 #include "edlsession.h"
29 #include "format.inc"
30 #include "language.h"
31 #include "mainsession.h"
32 #include "mtimebar.h"
33 #include "mutex.h"
34 #include "mwindowgui.h"
35 #include "mwindow.h"
36 #include "packagedispatcher.h"
37 #include "preferences.h"
38 #include "renderfarm.h"
39 #include "tracks.h"
40 #include "units.h"
41
42
43 #include <errno.h>
44 #include <signal.h>
45 #include <string.h>
46 #include <sys/wait.h>
47 #include <unistd.h>
48
49
50
51 extern "C"
52 {
53 #include <uuid.h>
54 }
55
56
57
58
59
60
61 BRender::BRender(MWindow *mwindow)
62  : Thread(1, 0, 0)
63 {
64         this->mwindow = mwindow;
65         map_lock = new Mutex("BRender::map_lock");
66         completion_lock = new Condition(0, "BRender::completion_lock");
67         timer = new Timer;
68         socket_path[0] = 0;
69         thread = 0;
70         master_pid = -1;
71         arguments[0] = arguments[1] = arguments[2] = 0;
72         map = 0;
73         map_size = 0;
74         map_valid = 0;
75         last_contiguous = 0;
76         set_synchronous(1);
77 }
78
79 BRender::~BRender()
80 {
81 TRACE("BRender::~BRender 1\n");
82         if(thread) 
83         {
84 TRACE("BRender::~BRender 2\n");
85                 stop();
86 TRACE("BRender::~BRender 3\n");
87                 delete thread;
88 TRACE("BRender::~BRender 4\n");
89         }
90
91
92 TRACE("BRender::~BRender 5\n");
93         if(master_pid >= 0)
94         {
95                 kill(master_pid, SIGKILL);
96 TRACE("BRender::~BRender 6\n");
97                 Thread::join();
98 TRACE("BRender::~BRender 7\n");
99         }
100
101 TRACE("BRender::~BRender 8\n");
102         delete map_lock;
103 TRACE("BRender::~BRender 9\n");
104         delete completion_lock;
105 TRACE("BRender::~BRender 10\n");
106 UNSET_TEMP(socket_path);
107         remove(socket_path);
108 TRACE("BRender::~BRender 11\n");
109         if(arguments[0]) delete [] arguments[0];
110 TRACE("BRender::~BRender 12\n");
111         if(arguments[1]) delete [] arguments[1];
112 TRACE("BRender::~BRender 13\n");
113         if(arguments[2]) delete [] arguments[2];
114 TRACE("BRender::~BRender 14\n");
115         if(map) delete [] map;
116 TRACE("BRender::~BRender 15\n");
117         delete timer;
118 TRACE("BRender::~BRender 100\n");
119 }
120
121 void BRender::initialize()
122 {
123         timer->update();
124 // Create socket for background process.
125         uuid_t socket_temp;
126         sprintf(socket_path, "/tmp/cinelerra.");
127         uuid_generate(socket_temp);
128         uuid_unparse(socket_temp, socket_path + strlen(socket_path));
129 SET_TEMP(socket_path);
130
131 // Start background instance of executable since codecs aren't reentrant
132         Thread::start();
133
134 // Wait for local node to start
135         thread = new BRenderThread(mwindow, this);
136         thread->initialize();
137 }
138
139 void BRender::run()
140 {
141         char string[BCTEXTLEN];
142         FILE *fd;
143 //printf("BRender::run 1 %d\n", getpid());
144
145
146 // Construct executable command with the designated filesystem port
147         fd = fopen("/proc/self/cmdline", "r");
148         if(fd)
149         {
150                 (void)fread(string, 1, BCTEXTLEN, fd);
151                 fclose(fd);
152         }
153         else
154                 perror(_("BRender::fork_background: can't open /proc/self/cmdline.\n"));
155
156         arguments[0] = new char[strlen(string) + 1];
157         strcpy(arguments[0], string);
158
159         strcpy(string, "-b");
160         arguments[1] = new char[strlen(string) + 1];
161         strcpy(arguments[1], string);
162
163         arguments[2] = new char[strlen(socket_path) + 1];
164         strcpy(arguments[2], socket_path);
165 //printf("BRender::fork_background 1 %s\n", socket_path);
166
167         arguments[3] = 0;
168
169         int pid = vfork();
170         if(!pid)
171         {
172                 execvp(arguments[0], arguments);
173                 perror("BRender::fork_background");
174                 _exit(0);
175         }
176
177         master_pid = pid;
178 //printf("BRender::fork_background 1 %d\n", master_pid);
179
180
181
182         int return_value;
183         if(waitpid(master_pid, &return_value, WUNTRACED) < 0)
184         {
185                 perror("BRender::run waitpid");
186         }
187 }
188
189 // Give the last position of the EDL which hasn't changed.
190 // We copy the EDL and restart rendering at the lesser of position and
191 // our position.
192 void BRender::restart(EDL *edl)
193 {
194         BRenderCommand *new_command = new BRenderCommand;
195         map_valid = 0;
196         new_command->copy_edl(edl);
197         new_command->command = BRenderCommand::BRENDER_RESTART;
198         thread->send_command(new_command);
199 // Map should be reallocated before this returns.
200 }
201
202 void BRender::stop()
203 {
204 //printf("BRender::stop 1\n");
205         BRenderCommand *new_command = new BRenderCommand;
206 //printf("BRender::stop 1\n");
207         new_command->command = BRenderCommand::BRENDER_STOP;
208 //printf("BRender::stop 1\n");
209         thread->send_command(new_command);
210 //printf("BRender::stop 1\n");
211         completion_lock->lock("BRender::stop");
212 //printf("BRender::stop 2\n");
213 }
214
215
216
217 int BRender::get_last_contiguous(int64_t brender_start)
218 {
219         int result;
220         map_lock->lock("BRender::get_last_contiguous");
221         if(map_valid)
222                 result = last_contiguous;
223         else
224                 result = brender_start;
225         map_lock->unlock();
226         return result;
227 }
228
229 void BRender::allocate_map(int64_t brender_start, int64_t start, int64_t end)
230 {
231         map_lock->lock("BRender::allocate_map");
232         unsigned char *old_map = map;
233         map = new unsigned char[end];
234         if(old_map)
235         {
236                 memcpy(map, old_map, start);
237                 delete [] old_map;
238         }
239
240 // Zero all before brender start
241         bzero(map, brender_start);
242 // Zero all after current start
243         bzero(map + start, end - start);
244
245         map_size = end;
246         map_valid = 1;
247         last_contiguous = start;
248         mwindow->session->brender_end = (double)last_contiguous / 
249                 mwindow->edl->session->frame_rate;
250         map_lock->unlock();
251 }
252
253 int BRender::set_video_map(int64_t position, int value)
254 {
255         int update_gui = 0;
256         map_lock->lock("BRender::set_video_map");
257
258
259         if(value == BRender::NOT_SCANNED)
260         {
261                 printf(_("BRender::set_video_map called to set NOT_SCANNED\n"));
262         }
263
264 // Preroll
265         if(position < 0)
266         {
267                 ;
268         }
269         else
270 // In range
271         if(position < map_size)
272         {
273                 map[position] = value;
274         }
275         else
276 // Obsolete EDL
277         {
278                 printf(_("BRender::set_video_map " _LD ": attempt to set beyond end of map " _LD ".\n"),
279                         position, map_size);
280         }
281
282 // Maintain last contiguous here to reduce search time
283         if(position == last_contiguous)
284         {
285                 int i;
286                 for(i = position + 1; i < map_size && map[i]; i++)
287                 {
288                         ;
289                 }
290                 last_contiguous = i;
291                 mwindow->session->brender_end = (double)last_contiguous / 
292                         mwindow->edl->session->frame_rate;
293
294                 if(timer->get_difference() > 1000 || last_contiguous >= map_size)
295                 {
296                         update_gui = 1;
297                         timer->update();
298                 }
299         }
300
301         map_lock->unlock();
302
303         if(update_gui)
304         {
305                 mwindow->gui->lock_window("BRender::set_video_map");
306                 mwindow->gui->update_timebar(1);
307                 mwindow->gui->unlock_window();
308         }
309         return 0;
310 }
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325 BRenderCommand::BRenderCommand()
326 {
327         edl = 0;
328         command = BRENDER_NONE;
329         position = 0.0;
330 }
331
332 BRenderCommand::~BRenderCommand()
333 {
334 // EDL should be zeroed if copied
335         if(edl) edl->Garbage::remove_user();
336 }
337
338 void BRenderCommand::copy_from(BRenderCommand *src)
339 {
340         this->edl = src->edl;
341         src->edl = 0;
342         this->position = src->position;
343         this->command = src->command;
344 }
345
346
347 void BRenderCommand::copy_edl(EDL *edl)
348 {
349         this->edl = new EDL;
350         this->edl->create_objects();
351         this->edl->copy_all(edl);
352         this->position = 0;
353 }
354
355
356
357
358
359
360
361
362
363
364
365
366 BRenderThread::BRenderThread(MWindow *mwindow, BRender *brender)
367  : Thread(1, 0, 0)
368 {
369         this->mwindow = mwindow;
370         this->brender = brender;
371         input_lock = new Condition(0, "BRenderThread::input_lock");
372         thread_lock = new Mutex("BRenderThread::thread_lock");
373         total_frames_lock = new Mutex("BRenderThread::total_frames_lock");
374         command_queue = 0;
375         command = 0;
376         done = 0;
377         farm_server = 0;
378         farm_result = 0;
379         preferences = 0;
380 }
381
382 BRenderThread::~BRenderThread()
383 {
384         thread_lock->lock("BRenderThread::~BRenderThread");
385         done = 1;
386         input_lock->unlock();
387         thread_lock->unlock();
388         Thread::join();
389         delete input_lock;
390         delete thread_lock;
391         delete total_frames_lock;
392         if(command) delete command;
393         if(command_queue) delete command_queue;
394         if(preferences) delete preferences;
395 }
396
397
398 void BRenderThread::initialize()
399 {
400         Thread::start();
401 }
402
403 void BRenderThread::send_command(BRenderCommand *command)
404 {
405 TRACE("BRenderThread::send_command 1");
406         thread_lock->lock("BRenderThread::send_command");
407 TRACE("BRenderThread::send_command 10");
408
409         if(this->command_queue)
410         {
411                 delete this->command_queue;
412                 this->command_queue = 0;
413         }
414         this->command_queue = command;
415 TRACE("BRenderThread::send_command 20");
416
417
418         input_lock->unlock();
419         thread_lock->unlock();
420 }
421
422 int BRenderThread::is_done(int do_lock)
423 {
424         if(do_lock) thread_lock->lock("BRenderThread::is_done");
425         int result = done;
426         if(do_lock) thread_lock->unlock();
427         return result;
428 }
429
430 void BRenderThread::run()
431 {
432         while(!is_done(1))
433         {
434                 BRenderCommand *new_command = 0;
435                 thread_lock->lock("BRenderThread::run 1");
436
437
438 // Got new command
439                 if(command_queue)
440                 {
441                         ;
442                 }
443                 else
444 // Wait for new command
445                 {
446                         thread_lock->unlock();
447                         input_lock->lock("BRenderThread::run 2");
448                         thread_lock->lock("BRenderThread::run 3");
449                 }
450
451 // Pull the command off
452                 if(!is_done(0))
453                 {
454                         new_command = command_queue;
455                         command_queue = 0;
456                 }
457
458                 thread_lock->unlock();
459
460
461
462
463 // Process the command here to avoid delay.
464 // Quit condition
465                 if(!new_command)
466                 {
467                         ;
468                 }
469                 else
470                 if(new_command->command == BRenderCommand::BRENDER_STOP)
471                 {
472                         stop();
473                         delete new_command;
474                         new_command = 0;
475 //                      if(command) delete command;
476 //                      command = new_command;
477                 }
478                 else
479                 if(new_command->command == BRenderCommand::BRENDER_RESTART)
480                 {
481 // Compare EDL's and get last equivalent position in new EDL
482                         if(command && command->edl)
483                                 new_command->position = 
484                                         new_command->edl->equivalent_output(command->edl);
485                         else
486                                 new_command->position = 0;
487
488
489                         stop();
490                         brender->completion_lock->lock("BRenderThread::run 4");
491
492                         if(new_command->edl->tracks->total_playable_vtracks())
493                         {
494                                 if(command) delete command;
495                                 command = new_command;
496                                 start();
497                         }
498                         else
499                         {
500                                 delete new_command;
501                                 new_command = 0;
502                         }
503                 }
504         }
505 }
506
507 void BRenderThread::stop()
508 {
509         if(farm_server)
510         {
511                 farm_result = 1;
512                 farm_server->wait_clients();
513                 delete farm_server;
514                 delete packages;
515                 delete preferences;
516                 farm_server = 0;
517                 packages = 0;
518                 preferences = 0;
519         }
520         brender->completion_lock->unlock();
521 }
522
523 void BRenderThread::start()
524 {
525 // Reset return parameters
526         farm_result = 0;
527         fps_result = 0;
528         total_frames = 0;
529         int result = 0;
530
531 // Allocate render farm.
532         if(!farm_server)
533         {
534 //printf("BRenderThread::start 1\n");
535                 preferences = new Preferences;
536                 preferences->copy_from(mwindow->preferences);
537                 packages = new PackageDispatcher;
538
539 // Fix preferences to use local node
540                 if(!preferences->use_renderfarm)
541                 {
542                         preferences->use_renderfarm = 1;
543                         preferences->delete_nodes();
544                 }
545                 preferences->add_node(brender->socket_path,
546                         0,
547                         1,
548                         preferences->local_rate);
549 //printf("BRenderThread::start 1 %s\n", brender->socket_path);
550                 preferences->brender_asset->use_header = 0;
551                 preferences->brender_asset->frame_rate = command->edl->session->frame_rate;
552                 preferences->brender_asset->width = command->edl->session->output_w;
553                 preferences->brender_asset->height = command->edl->session->output_h;
554
555 // Get last contiguous and reset map.
556 // If the framerate changes, last good should be 0 from the user.
557                 int brender_start = (int)(command->edl->session->brender_start *
558                         command->edl->session->frame_rate);
559                 int last_contiguous = brender->last_contiguous;
560                 int last_good = (int)(command->edl->session->frame_rate * 
561                         command->position);
562                 if(last_good < 0) last_good = last_contiguous;
563                 int start_frame = MIN(last_contiguous, last_good);
564                 start_frame = MAX(start_frame, brender_start);
565                 int64_t end_frame = Units::round(command->edl->tracks->total_video_length() * 
566                         command->edl->session->frame_rate);
567                 if(end_frame < start_frame) end_frame = start_frame;
568
569
570 printf("BRenderThread::start 1 map=%d equivalent=%d brender_start=%d result=%d end=" _LD "\n", 
571   last_contiguous, last_good, brender_start, start_frame, end_frame);
572
573 //sleep(1);
574
575                 brender->allocate_map(brender_start, start_frame, end_frame);
576 //sleep(1);
577 //printf("BRenderThread::start 2\n");
578
579                 result = packages->create_packages(mwindow,
580                         command->edl,
581                         preferences,
582                         BRENDER_FARM, 
583                         preferences->brender_asset, 
584                         (double)start_frame / command->edl->session->frame_rate, 
585                         (double)end_frame / command->edl->session->frame_rate,
586                         0);
587
588 //sleep(1);
589 //printf("BRenderThread::start 3 %d\n", result);
590                 farm_server = new RenderFarmServer(mwindow,
591                         packages,
592                         preferences,
593                         0,
594                         &farm_result,
595                         &total_frames,
596                         total_frames_lock,
597                         preferences->brender_asset,
598                         command->edl,
599                         brender);
600
601 //sleep(1);
602 //printf("BRenderThread::start 4\n");
603                 result = farm_server->start_clients();
604
605 //sleep(1);
606 // No local rendering because of codec problems.
607
608
609 // Abort
610                 if(result)
611                 {
612 // No-one must be retrieving a package when packages are deleted.
613 //printf("BRenderThread::start 7 %p\n", farm_server);
614                         delete farm_server;
615                         delete packages;
616 //printf("BRenderThread::start 8 %p\n", preferences);
617                         delete preferences;
618 //printf("BRenderThread::start 9\n");
619                         farm_server = 0;
620                         packages = 0;
621                         preferences = 0;
622                 }
623 //sleep(1);
624 //printf("BRenderThread::start 10\n");
625
626         }
627 }
628
629