Credit Andrew - fix vorbis audio which was scratchy and ensure aging plugin does...
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / main.C
1 /*
2  * CINELERRA
3  * Copyright (C) 2010 Adam Williams <broadcast at earthling dot net>
4  * Copyright (C) 2003-2016 Cinelerra CV contributors
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 "aboutprefs.h"
23 #include "arraylist.h"
24 #include "batchrender.h"
25 #include "bcsignals.h"
26 #include "cstrdup.h"
27 #include "edl.h"
28 #include "file.h"
29 #include "filexml.h"
30 #include "filesystem.h"
31 #include "language.h"
32 #include "langinfo.h"
33 #include "loadfile.inc"
34 #include "mainmenu.h"
35 #include "mutex.h"
36 #include "mwindow.h"
37 #include "mwindowgui.h"
38 #include "pluginserver.h"
39 #include "preferences.h"
40 #include "renderfarmclient.h"
41 #include "units.h"
42 #include "versioninfo.h"
43
44 #include <locale.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <sys/time.h>
48 #include <sys/resource.h>
49
50 #ifdef LEAKER
51 #if 0  // track allocators
52 #include <execinfo.h>
53 #define BT_BUF_SIZE 100
54 static void leaker()
55 {
56         void *buffer[BT_BUF_SIZE];
57         int nptrs = backtrace(buffer, BT_BUF_SIZE);
58         char **trace = backtrace_symbols(buffer, nptrs);
59         if( !trace ) return;
60         for( int i=0; i<nptrs; ) printf("%s ", trace[i++]);
61         printf("\n");
62         free(trace);
63 }
64 #define STRB ;leaker()
65 #else
66 #define STRB
67 #endif
68 #define STRC(v) printf("==new %p from %p sz %jd\n", v, __builtin_return_address(0), n)STRB
69 #define STRD(v) printf("==del %p from %p\n", v, __builtin_return_address(0))
70 void *operator new(size_t n) { void *vp = malloc(n); STRC(vp); bzero(vp,n); return vp; }
71 void operator delete(void *t) { STRD(t); free(t); }
72 void operator delete(void *t,size_t n) { STRD(t); free(t); }
73 void *operator new[](size_t n) { void *vp = malloc(n); STRC(vp); bzero(vp,n); return vp; }
74 void operator delete[](void *t) { STRD(t); free(t); }
75 void operator delete[](void *t,size_t n) { STRD(t); free(t); }
76 #endif
77
78 enum
79 {
80         DO_GUI,
81         DO_DEAMON,
82         DO_DEAMON_FG,
83         DO_BRENDER,
84         DO_USAGE,
85         DO_BATCHRENDER
86 };
87
88 #include "thread.h"
89
90
91 class CommandLineThread : public Thread
92 {
93 public:
94         CommandLineThread(ArrayList<char*> *filenames,
95                 MWindow *mwindow)
96         {
97                 this->filenames = filenames;
98                 this->mwindow = mwindow;
99         }
100
101
102         ~CommandLineThread()
103         {
104         }
105
106         void run()
107         {
108 //PRINT_TRACE
109                 mwindow->gui->lock_window("main");
110 //PRINT_TRACE
111                 mwindow->load_filenames(filenames,
112                         LOADMODE_REPLACE, LOADMODE_EDL_CLIP);
113 //PRINT_TRACE
114                 if( filenames->size() == 1 )
115                         mwindow->gui->mainmenu->add_load(filenames->get(0));
116 //PRINT_TRACE
117                 mwindow->gui->unlock_window();
118 //PRINT_TRACE
119         }
120
121         MWindow *mwindow;
122         ArrayList<char*> *filenames;
123 };
124
125 long cin_timezone;
126
127 static float get_layout_scale()
128 {
129         char config_path[BCTEXTLEN];
130         sprintf(config_path,"%s/%s", File::get_config_path(), CONFIG_FILE);
131         FILE *fp = fopen(config_path,"r");
132         if( !fp ) return 0;
133         float scale = 0;
134         char line[BCTEXTLEN];
135         line[BCTEXTLEN-1] = 0;
136         while( fgets(line, BCTEXTLEN-1, fp) ) {
137                 if( !strncmp(line, "LAYOUT_SCALE ",12+1) ) {
138                         scale = atof(line+12);
139                         break;
140                 }
141         }
142         fclose(fp);
143         return scale;
144 }
145
146 /*******************************************************************
147 * @mainpage
148 * Cinelerra-GG is a professional video editor for Linux. It is timeline
149 * based, supports hundreds of (de)coders, LADSPA and LV2 audio plugins,
150 * FFMPEG audio/video plugins, plus built-in audio/video plugins.
151 * Screen sizes up to 8K, any frame rate, extensive compositing features,
152 * title generator and more.
153 *
154 ********************************************************************/
155 int main(int argc, char *argv[])
156 {
157 // handle command line arguments first
158         srand(time(0));
159         ArrayList<char*> filenames;
160         filenames.set_array_delete();
161         FileSystem fs;
162
163         time_t st; time(&st);
164         struct tm ltm, gtm;
165         localtime_r(&st, &ltm);
166         gmtime_r(&st, &gtm);
167         int tzofs = ltm.tm_hour - gtm.tm_hour;
168         cin_timezone = tzofs * 60*60;
169
170         int operation = DO_GUI;
171         int deamon_port = DEAMON_PORT;
172         char deamon_path[BCTEXTLEN];
173         char config_path[BCTEXTLEN];
174         char batch_path[BCTEXTLEN];
175         int nice_value = 20;
176         int load_perpetual = 1;
177         config_path[0] = 0;
178         batch_path[0] = 0;
179         deamon_path[0] = 0;
180         Units::init();
181         const char *lang = getenv("LANGUAGE");
182         if( lang ) lang = cstrdup(lang);
183         File::init_cin_env_vars();
184         const char *locale_path = File::get_locale_path();
185         const char *cin = File::get_cin();
186
187         bindtextdomain(cin, locale_path);
188         textdomain(cin);
189         setlocale(LC_MESSAGES, "");
190
191 #ifdef X_HAVE_UTF8_STRING
192         char *loc = setlocale(LC_CTYPE, "");
193         if( loc ) {
194                 strcpy(BC_Resources::encoding, nl_langinfo(CODESET));
195                 BC_Resources::locale_utf8 = !strcmp(BC_Resources::encoding, "UTF-8");
196
197                 // Extract from locale language & region
198                 char locbuf[32], *p;
199                 locbuf[0] = 0;
200                 if( (p = strchr(loc, '.')) != 0 && (p - loc) < (int)sizeof(locbuf)-1 ) {
201                         strncpy(locbuf, loc, p - loc);
202                         locbuf[p - loc] = 0;
203                 }
204                 else if( strlen(loc) < sizeof(locbuf)-1 )
205                         strcpy(locbuf, loc);
206
207                 // Locale 'C' does not give useful language info - assume en
208                 if( !locbuf[0] || locbuf[0] == 'C' )
209                         strcpy(locbuf, "en");
210
211                 if( (p = strchr(locbuf, '_')) && p - locbuf < LEN_LANG ) {
212                         *p++ = 0;
213                         strcpy(BC_Resources::language, locbuf);
214                         if( strlen(p) < LEN_LANG )
215                                 strcpy(BC_Resources::region, p);
216                 }
217                 else if( strlen(locbuf) < LEN_LANG )
218                         strcpy(BC_Resources::language, locbuf);
219         }
220         else
221                 printf(_(PROGRAM_NAME ": Could not set locale.\n"));
222 #else
223         setlocale(LC_CTYPE, "");
224 #endif
225         tzset();
226
227         int load_backup = 0;
228         int start_remote_control = 0;
229
230         for( int i = 1; i < argc; i++ ) {
231                 if( !strcmp(argv[i], "-h") ) {
232                         operation = DO_USAGE;
233                 }
234                 else if( !strcmp(argv[i], "-z") ) {
235                         start_remote_control = 1;
236                 }
237                 else if( !strcmp(argv[i], "-r") ) {
238                         operation = DO_BATCHRENDER;
239                         if( argc > i + 1 ) {
240                                 if( argv[i + 1][0] != '-' ) {
241                                         strcpy(batch_path, argv[i + 1]);
242                                         i++;
243                                 }
244                         }
245                 }
246                 else if( !strcmp(argv[i], "-c") ) {
247                         if( argc > i + 1 ) {
248                                 strcpy(config_path, argv[i + 1]);
249                                 i++;
250                         }
251                         else {
252                                 fprintf(stderr, _("%s: -c needs a filename.\n"), argv[0]);
253                         }
254                 }
255                 else if( !strcmp(argv[i], "-d") || !strcmp(argv[i], "-f") ) {
256                         operation = !strcmp(argv[i], "-d") ? DO_DEAMON : DO_DEAMON_FG;
257                         if( argc > i + 1 ) {
258                                 if( atol(argv[i + 1]) > 0 ) {
259                                         deamon_port = atol(argv[i + 1]);
260                                         i++;
261                                 }
262                         }
263                 }
264                 else if( !strcmp(argv[i], "-b") ) {
265                         operation = DO_BRENDER;
266                         if( i > argc - 2 ) {
267                                 fprintf(stderr, _("-b may not be used by the user.\n"));
268                                 exit(1);
269                         }
270                         else
271                                 strcpy(deamon_path, argv[i + 1]);
272                 }
273                 else if( !strcmp(argv[i], "-n") ) {
274                         if( argc > i + 1 ) {
275                                 nice_value = atol(argv[i + 1]);
276                                 i++;
277                         }
278                 }
279                 else if( !strcmp(argv[i], "-x") ) {
280                         load_backup = 1;
281                 }
282                 else if( !strcmp(argv[i], "-S") ) {
283                         load_perpetual = 0;
284                 }
285                 else {
286                         char *new_filename;
287                         new_filename = new char[BCTEXTLEN];
288                         strcpy(new_filename, argv[i]);
289                         fs.complete_path(new_filename);
290                         filenames.append(new_filename);
291                 }
292         }
293
294         float scale = operation == DO_GUI ?
295                 get_layout_scale() : 1;
296         // runs XInitThreads
297         BC_WindowBase::init_resources(scale);
298
299         if( operation == DO_GUI ||
300             operation == DO_DEAMON || operation == DO_DEAMON_FG ||
301             operation == DO_USAGE  || operation == DO_BATCHRENDER) {
302
303 #ifndef REPOMAINTXT
304 #define REPOMAINTXT ""
305 #endif
306 #ifndef COPYRIGHTTEXT1
307 #define COPYRIGHTTEXT1 ""
308 #endif
309 #ifndef COPYRIGHTTEXT2
310 #define COPYRIGHTTEXT2 ""
311 #endif
312 #ifndef COPYRIGHTTEXT3
313 #define COPYRIGHTTEXT3 ""
314 #endif
315
316                 fprintf(stderr, "%s %s - %s\n%s",
317                         PROGRAM_NAME,CINELERRA_VERSION, AboutPrefs::build_timestamp,
318                         REPOMAINTXT COPYRIGHTTEXT1 COPYRIGHTTEXT2);
319                 fprintf(stderr, "%s", COPYRIGHTTEXT3);
320                 fprintf(stderr, "%s", COPYRIGHTTEXT4);
321                 fprintf(stderr,"\n");
322                 fprintf(stderr, "%s \n", AboutPrefs::ffmpeg_version);
323                 fprintf(stderr,"\n");
324                 fprintf(stderr, "%s is free software, covered by the GNU General Public License,\n"
325                         "and you are welcome to change it and/or distribute copies of it under\n"
326                         "certain conditions. There is absolutely no warranty for %s.\n\n",
327                         PROGRAM_NAME, PROGRAM_NAME);
328         }
329
330         switch( operation ) {
331                 case DO_USAGE:
332                         printf(_("\nUsage:\n"));
333                         printf(_("%s [-f] [-c configuration] [-d port] [-n nice] [-r batch file] [filenames]\n\n"), argv[0]);
334                         printf(_("-d = Run in the background as renderfarm client.  The port (400) is optional.\n"));
335                         printf(_("-f = Run in the foreground as renderfarm client.  Substitute for -d.\n"));
336                         printf(_("-n = Nice value if running as renderfarm client. (19)\n"));
337                         printf(_("-c = Configuration file to use instead of %s/%s.\n"),
338                                 File::get_config_path(), CONFIG_FILE);
339                         printf(_("-r = batch render the contents of the batch file (%s/%s) with no GUI.  batch file is optional.\n"),
340                                 File::get_config_path(), BATCH_PATH);
341                         printf(_("-S = do not reload perpetual session\n"));
342                         printf(_("-x = reload from backup\n"));
343                         printf(_("filenames = files to load\n\n\n"));
344                         exit(0);
345                         break;
346
347                 case DO_DEAMON:
348                 case DO_DEAMON_FG: {
349                         if( operation == DO_DEAMON ) {
350                                 int pid = fork();
351
352                                 if( pid ) {
353 // Redhat 9 requires _exit instead of exit here.
354                                         _exit(0);
355                                 }
356                         }
357
358                         RenderFarmClient client(deamon_port,
359                                 0,
360                                 nice_value,
361                                 config_path);
362                         client.main_loop();
363                         break; }
364
365 // Same thing without detachment
366                 case DO_BRENDER: {
367                         RenderFarmClient client(0,
368                                 deamon_path,
369                                 20,
370                                 config_path);
371                         client.main_loop();
372                         break; }
373
374                 case DO_BATCHRENDER: {
375                         BatchRenderThread *thread = new BatchRenderThread(0);
376                         thread->start_rendering(config_path,
377                                 batch_path);
378                         break; }
379
380                 case DO_GUI: {
381                         int restart = 0, done = 0;
382                         while( !done ) {
383                                 BC_WindowBase::get_resources()->vframe_shm = 0;
384                                 MWindow mwindow;
385                                 mwindow.create_objects(1, !filenames.total, config_path);
386                                 CommandLineThread *thread  = 0;
387                                 if( load_perpetual )
388                                         mwindow.load_undo_data();
389 //SET_TRACE
390 // load the initial files on seperate tracks
391 // use a new thread so it doesn't block the GUI
392                                 if( filenames.total ) {
393                                         thread  = new CommandLineThread(&filenames, &mwindow);
394                                         thread->start();
395 //PRINT_TRACE
396                                 }
397                                 if( load_backup ) {
398                                         load_backup = 0;
399                                         mwindow.gui->lock_window("main");
400                                         mwindow.load_backup();
401                                         mwindow.gui->unlock_window();
402                                 }
403                                 if( start_remote_control ) {
404                                         start_remote_control = 0;
405                                         mwindow.gui->remote_control->activate();
406                                 }
407 // run the program
408 //PRINT_TRACE
409                                 mwindow.start();
410                                 mwindow.run();
411 //PRINT_TRACE
412                                 restart = mwindow.restart();
413                                 if( restart ) {
414                                         mwindow.save_backup();
415                                         load_backup = 1;
416                                         start_remote_control =
417                                                 mwindow.gui->remote_control->is_active();
418                                 }
419                                 if( restart <= 0 )
420                                         done = 1;
421                                 mwindow.save_defaults();
422                                 mwindow.save_undo_data();
423 //PRINT_TRACE
424                                 filenames.remove_all_objects();
425                                 delete thread;
426                         }
427
428                         if( restart < 0 ) {
429                                 if( lang ) // reset to cmdline state
430                                         setenv("LANGUAGE", lang, 1);
431                                 else
432                                         unsetenv("LANGUAGE");
433                                 char exe_path[BCTEXTLEN];
434                                 int len = readlink("/proc/self/exe", exe_path, sizeof(exe_path)-1);
435                                 if( len < 0 ) break;
436                                 exe_path[len] = 0;
437                                 char *av[4] = { 0, };  int ac = 0;
438                                 av[ac++] = exe_path;
439                                 if( load_backup ) av[ac++] = (char*) "-x";
440                                 if( start_remote_control ) av[ac++] = (char*) "-z";
441                                 av[ac++] = 0;
442                                 execv(exe_path, av);
443                         }
444 //SET_TRACE
445 DISABLE_BUFFER
446                 break; }
447         }
448
449         filenames.remove_all_objects();
450         delete [] lang;
451         Units::finit();
452         BC_WindowBase::finit_resources();
453
454         time_t et; time(&et);
455         long dt = et - st;
456         printf("Session time: %ld:%02ld:%02ld\n", dt/3600, dt%3600/60, dt%60);
457         struct rusage ru;
458         getrusage(RUSAGE_SELF, &ru);
459         long usr_ms = ru.ru_utime.tv_sec*1000 + ru.ru_utime.tv_usec/1000;
460         long us = usr_ms/1000;  int ums = usr_ms%1000;
461         long sys_ms = ru.ru_stime.tv_sec*1000 + ru.ru_stime.tv_usec/1000;
462         long ss = sys_ms/1000;  int sms = sys_ms%1000;
463         printf("Cpu time: user: %ld:%02ld:%02ld.%03d sys: %ld:%02ld:%02ld.%03d\n",
464                 us/3600, us%3600/60, us%60, ums, ss/3600, ss%3600/60, ss%60, sms);
465         return 0;
466 }
467