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