update ru.po/andrew, edge gui init fix, dual monitor root coords tweaks, rm debug...
[goodguy/cinelerra.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", 1);
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         if(thread) {
81                 stop();
82                 delete thread;
83         }
84
85         if( master_pid >= 0 )
86                 kill(master_pid, SIGKILL);
87         Thread::join();
88
89         delete map_lock;
90         delete completion_lock;
91         UNSET_TEMP(socket_path);
92         remove(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;
97         delete timer;
98 }
99
100 void BRender::initialize()
101 {
102         timer->update();
103 // Create socket for background process.
104         uuid_t socket_temp;
105         sprintf(socket_path, "/tmp/cinelerra.");
106         uuid_generate(socket_temp);
107         uuid_unparse(socket_temp, socket_path + strlen(socket_path));
108 SET_TEMP(socket_path);
109
110 // Start background instance of executable since codecs aren't reentrant
111         Thread::start();
112
113 // Wait for local node to start
114         thread = new BRenderThread(mwindow, this);
115         thread->initialize();
116 }
117
118 void BRender::run()
119 {
120         char string[BCTEXTLEN];
121         FILE *fd;
122 //printf("BRender::run 1 %d\n", getpid());
123
124
125 // Construct executable command with the designated filesystem port
126         fd = fopen("/proc/self/cmdline", "r");
127         if(fd)
128         {
129                 (void)fread(string, 1, BCTEXTLEN, fd);
130                 fclose(fd);
131         }
132         else
133                 perror(_("BRender::fork_background: can't open /proc/self/cmdline.\n"));
134
135         arguments[0] = new char[strlen(string) + 1];
136         strcpy(arguments[0], string);
137
138         strcpy(string, "-b");
139         arguments[1] = new char[strlen(string) + 1];
140         strcpy(arguments[1], string);
141
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);
145
146         arguments[3] = 0;
147
148         int pid = vfork();
149         if(!pid)
150         {
151                 execvp(arguments[0], arguments);
152                 perror("BRender::fork_background");
153                 _exit(0);
154         }
155
156         master_pid = pid;
157 //printf("BRender::fork_background 1 %d\n", master_pid);
158
159
160
161         int return_value;
162         if(waitpid(master_pid, &return_value, WUNTRACED) < 0)
163         {
164                 perror("BRender::run waitpid");
165         }
166 }
167
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)
172 {
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.
182 }
183
184 void BRender::stop()
185 {
186         if( !running() || !thread->running() ) return;
187         BRenderCommand *new_command = new BRenderCommand;
188         new_command->command = BRenderCommand::BRENDER_STOP;
189         thread->send_command(new_command);
190         completion_lock->lock("BRender::stop");
191 }
192
193
194
195 int BRender::get_last_contiguous(int64_t brender_start)
196 {
197         int result;
198         map_lock->lock("BRender::get_last_contiguous");
199         if(map_valid)
200                 result = last_contiguous;
201         else
202                 result = brender_start;
203         map_lock->unlock();
204         return result;
205 }
206
207 void BRender::allocate_map(int64_t brender_start, int64_t start, int64_t end)
208 {
209         map_lock->lock("BRender::allocate_map");
210         unsigned char *old_map = map;
211         map = new unsigned char[end];
212         if(old_map)
213         {
214                 memcpy(map, old_map, start);
215                 delete [] old_map;
216         }
217
218 // Zero all before brender start
219         bzero(map, brender_start);
220 // Zero all after current start
221         bzero(map + start, end - start);
222
223         map_size = end;
224         map_valid = 1;
225         last_contiguous = start;
226         mwindow->session->brender_end = (double)last_contiguous /
227                 mwindow->edl->session->frame_rate;
228         map_lock->unlock();
229 }
230
231 int BRender::set_video_map(int64_t position, int value)
232 {
233 //printf("BRender::set_video_map(%jd, %d)\n", position, value);
234         map_lock->lock("BRender::set_video_map");
235
236         if(value == BRender::NOT_SCANNED)
237         {
238                 printf(_("BRender::set_video_map called to set NOT_SCANNED\n"));
239         }
240         if( position < 0) {} // Preroll
241         else if( position < map_size ) map[position] = value; // In range
242         else // Obsolete EDL
243                 printf(_("BRender::set_video_map %jd: attempt to set beyond end of map %jd.\n"),
244                         position, map_size);
245
246         int update_gui = 0;
247 // Maintain last contiguous here to reduce search time
248         if( position == last_contiguous && last_contiguous < map_size ) {
249                 while( last_contiguous < map_size && map[last_contiguous] )
250                         ++last_contiguous;
251                 if( last_contiguous >= map_size ) update_gui = 1;
252                 mwindow->session->brender_end = (double)last_contiguous /
253                         mwindow->edl->session->frame_rate;
254
255         }
256         if( timer->get_difference() > 1000 )
257                 update_gui = 1;
258
259         map_lock->unlock();
260
261         if( update_gui ) {
262                 timer->update();
263                 mwindow->gui->lock_window("BRender::set_video_map");
264                 mwindow->gui->update_timebar(1);
265                 mwindow->gui->unlock_window();
266         }
267         return 0;
268 }
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283 BRenderCommand::BRenderCommand()
284 {
285         edl = 0;
286         command = BRENDER_NONE;
287         position = 0.0;
288 }
289
290 BRenderCommand::~BRenderCommand()
291 {
292 // EDL should be zeroed if copied
293         if(edl) edl->Garbage::remove_user();
294 }
295
296 void BRenderCommand::copy_from(BRenderCommand *src)
297 {
298         this->edl = src->edl;
299         src->edl = 0;
300         this->position = src->position;
301         this->command = src->command;
302 }
303
304
305 void BRenderCommand::copy_edl(EDL *edl)
306 {
307         this->edl = new EDL;
308         this->edl->create_objects();
309         this->edl->copy_all(edl);
310         this->position = 0;
311 }
312
313
314
315
316
317
318
319
320
321
322
323
324 BRenderThread::BRenderThread(MWindow *mwindow, BRender *brender)
325  : Thread(1, 0, 0)
326 {
327         this->mwindow = mwindow;
328         this->brender = brender;
329         input_lock = new Condition(0, "BRenderThread::input_lock");
330         thread_lock = new Mutex("BRenderThread::thread_lock");
331         total_frames_lock = new Mutex("BRenderThread::total_frames_lock");
332         command_queue = 0;
333         command = 0;
334         done = 0;
335         farm_server = 0;
336         farm_result = 0;
337         preferences = 0;
338 }
339
340 BRenderThread::~BRenderThread()
341 {
342         thread_lock->lock("BRenderThread::~BRenderThread");
343         done = 1;
344         input_lock->unlock();
345         thread_lock->unlock();
346         Thread::join();
347
348         delete input_lock;
349         delete thread_lock;
350         delete total_frames_lock;
351         delete command;
352         delete command_queue;
353         delete preferences;
354 }
355
356
357 void BRenderThread::initialize()
358 {
359         Thread::start();
360 }
361
362 void BRenderThread::send_command(BRenderCommand *command)
363 {
364         thread_lock->lock("BRenderThread::send_command");
365         delete this->command_queue;
366         this->command_queue = command;
367         input_lock->unlock();
368         thread_lock->unlock();
369 }
370
371 void BRenderThread::run()
372 {
373         thread_lock->lock("BRenderThread::run");
374         while( !done ) {
375                 if( !command_queue ) {
376                         thread_lock->unlock();
377                         input_lock->lock("BRenderThread::run");
378                         thread_lock->lock("BRenderThread::run 1");
379                         continue;
380                 }
381
382                 BRenderCommand *new_command = command_queue;
383                 command_queue = 0;
384                 if( !new_command ) continue;
385                 thread_lock->unlock();
386                 stop();
387                 switch( new_command->command ) {
388                 case BRenderCommand::BRENDER_STOP:
389                         delete new_command;
390                         brender->completion_lock->unlock();
391                         break;
392                 case BRenderCommand::BRENDER_RESTART:
393                         new_command->position = command && command->edl ?
394                                 new_command->edl->equivalent_output(command->edl) : 0;
395                         delete command;  command = 0;
396                         if( new_command->edl->tracks->total_playable_vtracks() ) {
397                                 command = new_command;
398                                 start();
399                         }
400                         break;
401                 }
402                 thread_lock->lock("BRenderThread::run 2");
403         }
404         thread_lock->unlock();
405 }
406
407 void BRenderThread::stop()
408 {
409         if( !farm_server ) return;
410         farm_result = 1;
411         farm_server->wait_clients();
412         delete farm_server;  farm_server = 0;
413         delete packages;     packages = 0;
414         delete preferences;  preferences = 0;
415 }
416
417 void BRenderThread::start()
418 {
419 // Reset return parameters
420         farm_result = 0;
421         fps_result = 0;
422         total_frames = 0;
423         int result = 0;
424
425 // Allocate render farm.
426         if(!farm_server)
427         {
428 //printf("BRenderThread::start 1\n");
429                 preferences = new Preferences;
430                 preferences->copy_from(mwindow->preferences);
431                 packages = new PackageDispatcher;
432
433 // Fix preferences to use local node
434                 if(!preferences->use_renderfarm)
435                 {
436                         preferences->use_renderfarm = 1;
437                         preferences->delete_nodes();
438                 }
439                 preferences->add_node(brender->socket_path,
440                         0,
441                         1,
442                         preferences->local_rate);
443 //printf("BRenderThread::start 1 %s\n", brender->socket_path);
444                 preferences->brender_asset->use_header = 0;
445                 preferences->brender_asset->frame_rate = command->edl->session->frame_rate;
446                 preferences->brender_asset->width = command->edl->session->output_w;
447                 preferences->brender_asset->height = command->edl->session->output_h;
448                 preferences->brender_asset->interlace_mode = command->edl->session->interlace_mode;
449
450 // Get last contiguous and reset map.
451 // If the framerate changes, last good should be 0 from the user.
452                 int brender_start = (int)(command->edl->session->brender_start *
453                         command->edl->session->frame_rate);
454                 int last_contiguous = brender->last_contiguous;
455                 int last_good = (int)(command->edl->session->frame_rate *
456                         command->position);
457                 if(last_good < 0) last_good = last_contiguous;
458                 int start_frame = MIN(last_contiguous, last_good);
459                 start_frame = MAX(start_frame, brender_start);
460 //              int64_t end_frame = Units::round(command->edl->tracks->total_video_length() *
461 //                      command->edl->session->frame_rate);
462                 int64_t end_frame = Units::round(command->edl->session->brender_end *
463                         command->edl->session->frame_rate);
464                 if(end_frame < start_frame) end_frame = start_frame;
465
466
467 printf("BRenderThread::start 1 map=%d equivalent=%d brender_start=%d result=%d end=%jd\n",
468   last_contiguous, last_good, brender_start, start_frame, end_frame);
469
470 //sleep(1);
471
472                 brender->allocate_map(brender_start, start_frame, end_frame);
473 //sleep(1);
474 //printf("BRenderThread::start 2\n");
475
476                 result = packages->create_packages(mwindow,
477                         command->edl,
478                         preferences,
479                         BRENDER_FARM,
480                         preferences->brender_asset,
481                         (double)start_frame / command->edl->session->frame_rate,
482                         (double)end_frame / command->edl->session->frame_rate,
483                         0);
484
485 //sleep(1);
486 //printf("BRenderThread::start 3 %d\n", result);
487                 farm_server = new RenderFarmServer(mwindow,
488                         packages,
489                         preferences,
490                         0,
491                         &farm_result,
492                         &total_frames,
493                         total_frames_lock,
494                         preferences->brender_asset,
495                         command->edl,
496                         brender);
497
498 //sleep(1);
499 //printf("BRenderThread::start 4\n");
500                 result = farm_server->start_clients();
501
502 //sleep(1);
503 // No local rendering because of codec problems.
504
505
506 // Abort
507                 if(result)
508                 {
509 // No-one must be retrieving a package when packages are deleted.
510 //printf("BRenderThread::start 7 %p\n", farm_server);
511                         delete farm_server;
512                         delete packages;
513 //printf("BRenderThread::start 8 %p\n", preferences);
514                         delete preferences;
515 //printf("BRenderThread::start 9\n");
516                         farm_server = 0;
517                         packages = 0;
518                         preferences = 0;
519                 }
520 //sleep(1);
521 //printf("BRenderThread::start 10\n");
522
523         }
524 }
525
526