add auto zoombar/status color, fix 3 batchrender boobies, rotate plugin tweaks, add...
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / main.C
1 /*
2  * CINELERRA
3  * Copyright (C) 2010 Adam Williams <broadcast at earthling dot net>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  */
20
21 #include "aboutprefs.h"
22 #include "arraylist.h"
23 #include "batchrender.h"
24 #include "bcsignals.h"
25 #include "edl.h"
26 #include "file.h"
27 #include "filexml.h"
28 #include "filesystem.h"
29 #include "language.h"
30 #include "langinfo.h"
31 #include "loadfile.inc"
32 #include "mainmenu.h"
33 #include "mutex.h"
34 #include "mwindow.h"
35 #include "mwindowgui.h"
36 #include "pluginserver.h"
37 #include "preferences.h"
38 #include "renderfarmclient.h"
39 #include "units.h"
40 #include "versioninfo.h"
41
42 #include <locale.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <sys/time.h>
46 #include <sys/resource.h>
47
48 #ifdef LEAKER
49 #define STRC(v) printf("==new %p from %p sz %jd\n", v, __builtin_return_address(0), n)
50 #define STRD(v) printf("==del %p from %p\n", v, __builtin_return_address(0))
51 void *operator new(size_t n) { void *vp = malloc(n); STRC(vp); bzero(vp,n); return vp; }
52 void operator delete(void *t) { STRD(t); free(t); }
53 void operator delete(void *t,size_t n) { STRD(t); free(t); }
54 void *operator new[](size_t n) { void *vp = malloc(n); STRC(vp); bzero(vp,n); return vp; }
55 void operator delete[](void *t) { STRD(t); free(t); }
56 void operator delete[](void *t,size_t n) { STRD(t); free(t); }
57 #endif
58
59 enum
60 {
61         DO_GUI,
62         DO_DEAMON,
63         DO_DEAMON_FG,
64         DO_BRENDER,
65         DO_USAGE,
66         DO_BATCHRENDER
67 };
68
69 #include "thread.h"
70
71
72 class CommandLineThread : public Thread
73 {
74 public:
75         CommandLineThread(ArrayList<char*> *filenames,
76                 MWindow *mwindow)
77         {
78                 this->filenames = filenames;
79                 this->mwindow = mwindow;
80         }
81
82
83         ~CommandLineThread()
84         {
85         }
86
87         void run()
88         {
89 //PRINT_TRACE
90                 mwindow->gui->lock_window("main");
91 //PRINT_TRACE
92                 mwindow->load_filenames(filenames, LOADMODE_REPLACE);
93 //PRINT_TRACE
94                 if( filenames->size() == 1 )
95                         mwindow->gui->mainmenu->add_load(filenames->get(0));
96 //PRINT_TRACE
97                 mwindow->gui->unlock_window();
98 //PRINT_TRACE
99         }
100
101         MWindow *mwindow;
102         ArrayList<char*> *filenames;
103 };
104
105 long cin_timezone;
106
107 int main(int argc, char *argv[])
108 {
109 // handle command line arguments first
110         srand(time(0));
111         ArrayList<char*> filenames;
112         FileSystem fs;
113
114         time_t st; time(&st);
115         struct tm ltm, gtm;
116         localtime_r(&st, &ltm);
117         gmtime_r(&st, &gtm);
118         int tzofs = ltm.tm_hour - gtm.tm_hour;
119         cin_timezone = tzofs * 60*60;
120
121         int operation = DO_GUI;
122         int deamon_port = DEAMON_PORT;
123         char deamon_path[BCTEXTLEN];
124         char config_path[BCTEXTLEN];
125         char batch_path[BCTEXTLEN];
126         int nice_value = 20;
127         int load_perpetual = 1;
128         config_path[0] = 0;
129         batch_path[0] = 0;
130         deamon_path[0] = 0;
131         Units::init();
132
133         File::init_cin_path();
134         const char *locale_path = File::get_locale_path();
135         const char *cin = File::get_cin();
136
137         bindtextdomain(cin, locale_path);
138         textdomain(cin);
139         setlocale(LC_MESSAGES, "");
140
141 #ifdef X_HAVE_UTF8_STRING
142         char *loc = setlocale(LC_CTYPE, "");
143         if( loc ) {
144                 strcpy(BC_Resources::encoding, nl_langinfo(CODESET));
145                 BC_Resources::locale_utf8 = !strcmp(BC_Resources::encoding, "UTF-8");
146
147                 // Extract from locale language & region
148                 char locbuf[32], *p;
149                 locbuf[0] = 0;
150                 if( (p = strchr(loc, '.')) != 0 && (p - loc) < (int)sizeof(locbuf)-1 ) {
151                         strncpy(locbuf, loc, p - loc);
152                         locbuf[p - loc] = 0;
153                 }
154                 else if( strlen(loc) < sizeof(locbuf)-1 )
155                         strcpy(locbuf, loc);
156
157                 // Locale 'C' does not give useful language info - assume en
158                 if( !locbuf[0] || locbuf[0] == 'C' )
159                         strcpy(locbuf, "en");
160
161                 if( (p = strchr(locbuf, '_')) && p - locbuf < LEN_LANG ) {
162                         *p++ = 0;
163                         strcpy(BC_Resources::language, locbuf);
164                         if( strlen(p) < LEN_LANG )
165                                 strcpy(BC_Resources::region, p);
166                 }
167                 else if( strlen(locbuf) < LEN_LANG )
168                         strcpy(BC_Resources::language, locbuf);
169         }
170         else
171                 printf(_(PROGRAM_NAME ": Could not set locale.\n"));
172 #else
173         setlocale(LC_CTYPE, "");
174 #endif
175         tzset();
176
177         int load_backup = 0;
178         int start_remote_control = 0;
179
180         for( int i = 1; i < argc; i++ ) {
181                 if( !strcmp(argv[i], "-h") ) {
182                         operation = DO_USAGE;
183                 }
184                 else if( !strcmp(argv[i], "-z") ) {
185                         start_remote_control = 1;
186                 }
187                 else if( !strcmp(argv[i], "-r") ) {
188                         operation = DO_BATCHRENDER;
189                         if( argc > i + 1 ) {
190                                 if( argv[i + 1][0] != '-' ) {
191                                         strcpy(batch_path, argv[i + 1]);
192                                         i++;
193                                 }
194                         }
195                 }
196                 else if( !strcmp(argv[i], "-c") ) {
197                         if( argc > i + 1 ) {
198                                 strcpy(config_path, argv[i + 1]);
199                                 i++;
200                         }
201                         else {
202                                 fprintf(stderr, _("%s: -c needs a filename.\n"), argv[0]);
203                         }
204                 }
205                 else if( !strcmp(argv[i], "-d") || !strcmp(argv[i], "-f") ) {
206                         operation = !strcmp(argv[i], "-d") ? DO_DEAMON : DO_DEAMON_FG;
207                         if( argc > i + 1 ) {
208                                 if( atol(argv[i + 1]) > 0 ) {
209                                         deamon_port = atol(argv[i + 1]);
210                                         i++;
211                                 }
212                         }
213                 }
214                 else if( !strcmp(argv[i], "-b") ) {
215                         operation = DO_BRENDER;
216                         if( i > argc - 2 ) {
217                                 fprintf(stderr, _("-b may not be used by the user.\n"));
218                                 exit(1);
219                         }
220                         else
221                                 strcpy(deamon_path, argv[i + 1]);
222                 }
223                 else if( !strcmp(argv[i], "-n") ) {
224                         if( argc > i + 1 ) {
225                                 nice_value = atol(argv[i + 1]);
226                                 i++;
227                         }
228                 }
229                 else if( !strcmp(argv[i], "-x") ) {
230                         load_backup = 1;
231                 }
232                 else if( !strcmp(argv[i], "-S") ) {
233                         load_perpetual = 0;
234                 }
235                 else {
236                         char *new_filename;
237                         new_filename = new char[BCTEXTLEN];
238                         strcpy(new_filename, argv[i]);
239                         fs.complete_path(new_filename);
240                         filenames.append(new_filename);
241                 }
242         }
243
244
245
246         if( operation == DO_GUI ||
247             operation == DO_DEAMON || operation == DO_DEAMON_FG ||
248             operation == DO_USAGE  || operation == DO_BATCHRENDER) {
249
250 #ifndef REPOMAINTXT
251 #define REPOMAINTXT ""
252 #endif
253 #ifndef COPYRIGHTTEXT1
254 #define COPYRIGHTTEXT1 ""
255 #endif
256 #ifndef COPYRIGHTTEXT2
257 #define COPYRIGHTTEXT2 ""
258 #endif
259                 fprintf(stderr, "%s %s - %s\n%s",
260                         PROGRAM_NAME,CINELERRA_VERSION, AboutPrefs::build_timestamp,
261                         REPOMAINTXT COPYRIGHTTEXT1 COPYRIGHTTEXT2);
262                 fprintf(stderr, "%s is free software, covered by the GNU General Public License,\n"
263                         "and you are welcome to change it and/or distribute copies of it under\n"
264                         "certain conditions. There is absolutely no warranty for %s.\n\n",
265                         PROGRAM_NAME, PROGRAM_NAME);
266         }
267
268         switch( operation ) {
269                 case DO_USAGE:
270                         printf(_("\nUsage:\n"));
271                         printf(_("%s [-f] [-c configuration] [-d port] [-n nice] [-r batch file] [filenames]\n\n"), argv[0]);
272                         printf(_("-d = Run in the background as renderfarm client.  The port (400) is optional.\n"));
273                         printf(_("-f = Run in the foreground as renderfarm client.  Substitute for -d.\n"));
274                         printf(_("-n = Nice value if running as renderfarm client. (19)\n"));
275                         printf(_("-c = Configuration file to use instead of %s/%s.\n"),
276                                 File::get_config_path(), CONFIG_FILE);
277                         printf(_("-r = batch render the contents of the batch file (%s/%s) with no GUI.  batch file is optional.\n"),
278                                 File::get_config_path(), BATCH_PATH);
279                         printf(_("-S = do not reload perpetual session\n"));
280                         printf(_("-x = reload from backup\n"));
281                         printf(_("filenames = files to load\n\n\n"));
282                         exit(0);
283                         break;
284
285                 case DO_DEAMON:
286                 case DO_DEAMON_FG: {
287                         if( operation == DO_DEAMON ) {
288                                 int pid = fork();
289
290                                 if( pid ) {
291 // Redhat 9 requires _exit instead of exit here.
292                                         _exit(0);
293                                 }
294                         }
295
296                         RenderFarmClient client(deamon_port,
297                                 0,
298                                 nice_value,
299                                 config_path);
300                         client.main_loop();
301                         break; }
302
303 // Same thing without detachment
304                 case DO_BRENDER: {
305                         RenderFarmClient client(0,
306                                 deamon_path,
307                                 20,
308                                 config_path);
309                         client.main_loop();
310                         break; }
311
312                 case DO_BATCHRENDER: {
313                         BatchRenderThread *thread = new BatchRenderThread;
314                         thread->start_rendering(config_path,
315                                 batch_path);
316                         break; }
317
318                 case DO_GUI: {
319                         int restart = 0, done = 0;
320                         while( !done ) {
321                                 BC_WindowBase::get_resources()->vframe_shm = 0;
322                                 MWindow mwindow;
323                                 mwindow.create_objects(1, !filenames.total, config_path);
324                                 CommandLineThread *thread  = 0;
325                                 if( mwindow.preferences->perpetual_session && load_perpetual )
326                                         mwindow.load_undo_data();
327 //SET_TRACE
328 // load the initial files on seperate tracks
329 // use a new thread so it doesn't block the GUI
330                                 if( filenames.total ) {
331                                         thread  = new CommandLineThread(&filenames, &mwindow);
332                                         thread->start();
333 //PRINT_TRACE
334                                 }
335                                 if( load_backup ) {
336                                         load_backup = 0;
337                                         mwindow.gui->lock_window("main");
338                                         mwindow.load_backup();
339                                         mwindow.gui->unlock_window();
340                                 }
341                                 if( start_remote_control ) {
342                                         start_remote_control = 0;
343                                         mwindow.gui->remote_control->activate();
344                                 }
345 // run the program
346 //PRINT_TRACE
347                                 mwindow.start();
348                                 mwindow.run();
349 //PRINT_TRACE
350                                 restart = mwindow.restart();
351                                 if( restart ) {
352                                         mwindow.save_backup();
353                                         load_backup = 1;
354                                         start_remote_control =
355                                                 mwindow.gui->remote_control->is_active();
356                                 }
357                                 if( restart <= 0 )
358                                         done = 1;
359
360                                 mwindow.save_defaults();
361                                 if( mwindow.preferences->perpetual_session )
362                                         mwindow.save_undo_data();
363 //PRINT_TRACE
364                                 filenames.remove_all_objects();
365                                 delete thread;
366                         }
367
368                         if( restart < 0 ) {
369                                 char exe_path[BCTEXTLEN];
370                                 int len = readlink("/proc/self/exe", exe_path, sizeof(exe_path)-1);
371                                 if( len < 0 ) break;
372                                 exe_path[len] = 0;
373                                 char *av[4] = { 0, };  int ac = 0;
374                                 av[ac++] = exe_path;
375                                 if( load_backup ) av[ac++] = (char*) "-x";
376                                 if( start_remote_control ) av[ac++] = (char*) "-z";
377                                 av[ac++] = 0;
378                                 execv(exe_path, av);
379                         }
380 //SET_TRACE
381 DISABLE_BUFFER
382                 break; }
383         }
384
385         filenames.remove_all_objects();
386         Units::finit();
387
388         time_t et; time(&et);
389         long dt = et - st;
390         printf("Session time: %ld:%02ld:%02ld\n", dt/3600, dt%3600/60, dt%60);
391         struct rusage ru;
392         getrusage(RUSAGE_SELF, &ru);
393         long usr_ms = ru.ru_utime.tv_sec*1000 + ru.ru_utime.tv_usec/1000;
394         long us = usr_ms/1000;  int ums = usr_ms%1000;
395         long sys_ms = ru.ru_stime.tv_sec*1000 + ru.ru_stime.tv_usec/1000;
396         long ss = sys_ms/1000;  int sms = sys_ms%1000;
397         printf("Cpu time: user: %ld:%02ld:%02ld.%03d sys: %ld:%02ld:%02ld.%03d\n",
398                 us/3600, us%3600/60, us%60, ums, ss/3600, ss%3600/60, ss%60, sms);
399         return 0;
400 }
401