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