1 // main.c
2 // LiVES (lives-exe)
3 // (c) G. Finch 2003 - 2020 <salsaman+lives@gmail.com>
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 version 3 or higher as published by
7 the Free Software Foundation.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 */
18
19 // flow is: main() -> real_main() [entry point for liblives]
20 // real_main() -> pre_init() [early initialisation, initialise prefs system]
21 // initialise prefs
22 // initialise weed_memory
23 // initialise message log
24 // initialise widget_helper
25 // real_main() [parse startup opts]
26 // real_main() -> lives_startup() [added as idle function]
27 // lives_startup ->lives_init
28 // lives_startup2 [added as idle from lives_startup]
29 // real_main() -> gtk_main()
30
31 // idlefuncion:
32 // lives_startup() [handle any prefs touched by opts which are needed for the GUI]
33 // on fresh install: do_workdir_query()
34 // create_LiVES() [create the GUI interface]
35 // splash_end -> create MT interface if wanted
36 // show_lives()
37 // check_for_recovery files, load them if wanted
38 // do_layout_recovery
39 // lives_init() [set remaining variables and preferences]
40
41 #ifdef USE_GLIB
42 #include <glib.h>
43 #endif
44
45 #define NEED_ENDIAN_TEST
46
47 #define _MAIN_C_
48 #include "main.h"
49 #include "interface.h"
50 #include "callbacks.h"
51
52 #include "effects.h"
53 #include "rte_window.h"
54 #include "resample.h"
55 #include "audio.h"
56 #include "paramwindow.h"
57 #include "stream.h"
58 #include "startup.h"
59 #include "cvirtual.h"
60 #include "ce_thumbs.h"
61 #include "rfx-builder.h"
62
63 #ifndef ENABLE_DIAGNOSTICS
64 #include "diagnostics.h"
65 #endif
66
67 #ifdef ENABLE_OSC
68 #include "omc-learn.h"
69 #endif
70
71 #ifdef HAVE_YUV4MPEG
72 #include "lives-yuv4mpeg.h"
73 #endif
74
75 #ifdef HAVE_UNICAP
76 #include "videodev.h"
77 #endif
78
79 #include <getopt.h>
80
81 #ifdef IS_DARWIN
82 #include <mach/mach.h>
83 #include <mach/processor_info.h>
84 #include <mach/mach_host.h>
85 #endif
86 #ifdef USE_LIBPNG
87 #include <png.h>
88 #include <setjmp.h>
89 #endif
90
91 #ifdef HAVE_PRCTL
92 #include <sys/prctl.h>
93 #endif
94
95 #ifdef LIVES_OS_UNIX
96 #include <glib-unix.h>
97 #endif
98
99
100 ////////////////////////////////
101 _palette *palette;
102 ssize_t sizint, sizdbl, sizshrt;
103 mainwindow *mainw;
104
105 //////////////////////////////////////////
106 static char buff[256];
107
108 static char devmap[PATH_MAX];
109
110 static boolean no_recover = FALSE, auto_recover = FALSE;
111 static boolean upgrade_error = FALSE;
112 static boolean info_only;
113
114 static char *newconfigfile = NULL;
115
116 static char start_file[PATH_MAX];
117 static double start = 0.;
118 static int end = 0;
119
120 static boolean theme_error;
121
122 static _ign_opts ign_opts;
123
124 static int zargc;
125 static char **zargv;
126
127 #ifndef NO_PROG_LOAD
128 static int xxwidth = 0, xxheight = 0;
129 #endif
130
131 static char *old_vhash = NULL;
132 static int initial_startup_phase = 0;
133 static boolean needs_workdir = FALSE;
134 static boolean ran_ds_dlg = FALSE;
135
136 static void do_start_messages(void);
137
138 ////////////////////
139
140 #ifdef GUI_GTK
141 LiVESTargetEntry target_table[] = {
142 { "STRING", GTK_TARGET_OTHER_APP, 0 },
143 { "text/uri-list", GTK_TARGET_OTHER_APP, 0 },
144 };
145 #endif
146
147 /////////////////////////////////
148 #ifdef NO_COMPILE // never compile this
tr_msg(void)149 void tr_msg(void) {
150 // TRANSLATORS: do not translate this message
151 char *msg =
152 (_("Attention Translators !\nThis message is intended for you, so please do not translate it.\n\n"
153 "All translators should read the LiVES translation notes at\n"
154 "http://lives-video.com/TRANS-README.txt"));
155 }
156 #endif
157
158
break_me(const char * brkstr)159 void break_me(const char *brkstr) {
160 if (prefs && prefs->show_dev_opts)
161 g_print("BANG ! hit breakpoint %s\n", brkstr ? brkstr : "???");
162 // breakpoint for gdb
163 }
164
165
166 // in library we run gtk in a thread so we can return to caller
gtk_thread_wrapper(void * data)167 void *gtk_thread_wrapper(void *data) {
168 gtk_main();
169 return NULL;
170 }
171
172
173 #ifdef USE_GLIB
lives_log_handler(const char * domain,LiVESLogLevelFlags level,const char * message,livespointer data)174 static void lives_log_handler(const char *domain, LiVESLogLevelFlags level, const char *message, livespointer data) {
175 if (prefs && prefs->vj_mode) return;
176 if (level & LIVES_LOG_FATAL_MASK) {
177 #ifndef IGNORE_FATAL_ERRORS
178 raise(LIVES_SIGSEGV);
179 #endif
180 } else {
181 char *msg;
182 LiVESLogLevelFlags xlevel = level & LIVES_LOG_LEVEL_MASK;
183
184 #ifdef LIVES_NO_DEBUG
185 if (prefs && !prefs->show_dev_opts) return;
186 #endif
187
188 #ifndef SHOW_ALL_ERRORS
189 #ifdef LIVES_NO_DEBUG
190 if (xlevel >= LIVES_LOG_LEVEL_DEBUG) return;
191 #endif
192 //#define SHOW_INFO_ERRORS
193 #ifndef SHOW_INFO_ERRORS
194 if (xlevel == LIVES_LOG_LEVEL_INFO) return;
195 #endif
196 //#define SHOW_MSG_ERRORS
197 #ifndef SHOW_MSG_ERRORS
198 if (xlevel == LIVES_LOG_LEVEL_MESSAGE) return;
199 #endif
200 #define NO_WARN_ERRORS
201 #ifdef NO_WARN_ERRORS
202 if (xlevel == LIVES_LOG_LEVEL_WARNING) {
203 return;
204 }
205 #endif
206 #define NO_CRITICAL_ERRORS
207 #ifdef NO_CRITICAL_ERRORS
208 if (xlevel == LIVES_LOG_LEVEL_CRITICAL) return;
209 #endif
210 #endif
211
212 //#define TRAP_THEME_ERRORS
213 //#define SHOW_THEME_ERRORS
214 #ifndef SHOW_THEME_ERRORS
215 if (prefs->show_dev_opts)
216 if (!strncmp(message, "Theme parsing", strlen("Theme parsing"))) {
217 #ifdef TRAP_THEME_ERRORS
218 raise(LIVES_SIGTRAP);
219 #endif
220 return;
221 }
222 #endif
223
224 //#define TRAP_ERRMSG ""
225 #ifdef TRAP_ERRMSG
226 if (!strncmp(message, TRAP_ERRMSG, strlen(TRAP_ERRMSG))) {
227 fprintf(stderr, "Trapped message %s\n", message);
228 raise(LIVES_SIGTRAP);
229 }
230 #endif
231 if (xlevel == LIVES_LOG_LEVEL_FATAL)
232 msg = lives_strdup_printf("%s Fatal error: %s\n", domain, message);
233 else if (xlevel == LIVES_LOG_LEVEL_CRITICAL)
234 msg = lives_strdup_printf("%s Critical error: %s\n", domain, message);
235 else if (xlevel == LIVES_LOG_LEVEL_WARNING)
236 msg = lives_strdup_printf("%s Warning: %s\n", domain, message);
237 else if (xlevel == LIVES_LOG_LEVEL_MESSAGE)
238 msg = lives_strdup_printf("%s Warning: %s\n", domain, message);
239 else if (xlevel == LIVES_LOG_LEVEL_INFO)
240 msg = lives_strdup_printf("%s Warning: %s\n", domain, message);
241 else if (xlevel == LIVES_LOG_LEVEL_DEBUG)
242 msg = lives_strdup_printf("%s Warning: %s\n", domain, message);
243 else {
244 msg = lives_strdup_printf("%s (Unknown level %u error: %s\n", domain, xlevel, message);
245 }
246
247 if (mainw->is_ready) d_print(msg);
248 fprintf(stderr, "%s", msg);
249 lives_free(msg);
250
251 #define BREAK_ON_CRIT
252 if (xlevel <= LIVES_LOG_LEVEL_CRITICAL) {
253 #ifdef BREAK_ON_CRIT
254 raise(LIVES_SIGTRAP);
255 #endif
256 }
257
258 //#define BREAK_ON_WARN
259 #ifdef BREAK_ON_WARN
260 if (xlevel <= LIVES_LOG_LEVEL_WARNING) raise(LIVES_SIGTRAP);
261 #endif
262
263 //#define BREAK_ON_ALL
264 #ifdef BREAK_ON_ALL
265 raise(LIVES_SIGTRAP);
266 #endif
267 }
268 }
269 #endif // USE_GLIB
270
271
272 #ifdef ENABLE_JACK
jack_warn()273 LIVES_LOCAL_INLINE void jack_warn() {
274 do_jack_noopen_warn3();
275 if (prefs->startup_phase == 4) {
276 do_jack_noopen_warn2();
277 } else do_jack_noopen_warn4();
278 }
279 #endif
280
281
defer_sigint(int signum)282 void defer_sigint(int signum) {
283 mainw->signal_caught = signum;
284 switch (mainw->crash_possible) {
285 case 1:
286 // crash in jack_client_open()
287 //jack_warn();
288 break;
289 default:
290 break;
291 }
292 return;
293 }
294
295 //#define QUICK_EXIT
catch_sigint(int signum)296 void catch_sigint(int signum) {
297 // trap for ctrl-C and others
298 //if (mainw->jackd) lives_jack_end();
299
300 if (prefs->show_desktop_panel && (capable->wm_caps.pan_annoy & ANNOY_DISPLAY)
301 && (capable->wm_caps.pan_annoy & ANNOY_FS) && (capable->wm_caps.pan_res & RES_HIDE) &&
302 capable->wm_caps.pan_res & RESTYPE_ACTION) {
303 mainw->ignore_screen_size = TRUE;
304 show_desktop_panel();
305 }
306
307 if (capable && !pthread_equal(capable->main_thread, pthread_self())) {
308 lives_proc_thread_t lpt = THREADVAR(tinfo);
309 weed_set_int_value(lpt, WEED_LEAF_SIGNALLED, signum);
310 weed_set_voidptr_value(lpt, WEED_LEAF_SIGNAL_DATA, THREADVAR(mydata));
311 g_print("Thread got signal %d\n", signum);
312 sleep(3600);
313 pthread_exit(NULL);
314 }
315 if (mainw->record) backup_recording(NULL, NULL);
316 #ifdef QUICK_EXIT
317 /* shoatend(); */
318 /* fprintf(stderr, "shoatt end"); */
319 /* fflush(stderr); */
320 exit(signum);
321 #endif
322 if (mainw) {
323 if (LIVES_MAIN_WINDOW_WIDGET) {
324 if (mainw->foreign) {
325 exit(signum);
326 }
327
328 if (mainw->multitrack) mainw->multitrack->idlefunc = 0;
329 mainw->fatal = TRUE;
330
331 if (signum == LIVES_SIGABRT || signum == LIVES_SIGSEGV) {
332 mainw->memok = FALSE;
333 signal(LIVES_SIGSEGV, SIG_DFL);
334 signal(LIVES_SIGABRT, SIG_DFL);
335 fprintf(stderr, _("\nUnfortunately LiVES crashed.\nPlease report this bug at %s\n"
336 "Thanks. Recovery should be possible if you restart LiVES.\n"), LIVES_BUG_URL);
337 fprintf(stderr, _("\n\nWhen reporting crashes, please include details of your operating system, "
338 "distribution, and the LiVES version (%s)\n"), LiVES_VERSION);
339
340 if (capable->has_gdb) {
341 if (mainw->debug) fprintf(stderr, "%s", _("and any information shown below:\n\n"));
342 else fprintf(stderr, "%s", _("Please try running LiVES with the -debug option to collect more information.\n\n"));
343 } else {
344 fprintf(stderr, "%s", _("Please install gdb and then run LiVES with the -debug option "
345 "to collect more information.\n\n"));
346 }
347
348 #ifdef USE_GLIB
349 #ifdef LIVES_NO_DEBUG
350 if (mainw->debug) {
351 #endif
352 #ifdef HAVE_PRCTL
353 prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY);
354 #endif
355 g_on_error_query(capable->myname_full);
356 #ifdef LIVES_NO_DEBUG
357 }
358 #endif
359 #endif
360 #ifndef GDB_ON
361 _exit(signum);
362 #endif
363 }
364
365 if (mainw->was_set) {
366 if (mainw->memok) fprintf(stderr, "%s", _("Preserving set.\n"));
367 }
368
369 mainw->leave_recovery = mainw->leave_files = TRUE;
370
371 mainw->only_close = FALSE;
372 lives_exit(signum);
373 }
374 }
375 exit(signum);
376 }
377
378 #ifdef USE_GLIB
glib_sighandler(livespointer data)379 static boolean glib_sighandler(livespointer data) {
380 int signum = LIVES_POINTER_TO_INT(data);
381 catch_sigint(signum);
382 return TRUE;
383 }
384 #endif
385
386
387 #ifdef GUI_GTK
get_screen_scale(GdkScreen * screen,double * pdpi)388 static double get_screen_scale(GdkScreen *screen, double *pdpi) {
389 double scale = 1.0;
390 double dpi = gdk_screen_get_resolution(screen);
391 if (dpi == 120.) scale = 1.25;
392 else if (dpi == 144.) scale = 1.5;
393 else if (dpi == 192.) scale = 2.0;
394 if (pdpi) *pdpi = dpi;
395 return scale;
396 }
397 #endif
398
399
get_monitors(boolean reset)400 void get_monitors(boolean reset) {
401 #ifdef GUI_GTK
402 GdkDisplay *disp;
403 GdkScreen *screen;
404 #if GTK_CHECK_VERSION(3, 22, 0)
405 GdkMonitor *moni;
406 #endif
407 GdkRectangle rect;
408 GdkDevice *device;
409 double scale, dpi;
410 int play_moni = 1;
411 #if !GTK_CHECK_VERSION(3, 22, 0)
412 GSList *dlist, *dislist;
413 int nscreens, nmonitors;
414 #if LIVES_HAS_DEVICE_MANAGER
415 GdkDeviceManager *devman;
416 LiVESList *devlist;
417 int k;
418 #endif
419 int i, j;
420 #endif
421 int idx = 0;
422
423 if (mainw->ignore_screen_size) return;
424
425 lives_freep((void **)&mainw->mgeom);
426 capable->nmonitors = 0;
427
428 #if !GTK_CHECK_VERSION(3, 22, 0)
429 dlist = dislist = gdk_display_manager_list_displays(gdk_display_manager_get());
430
431 // for each display get list of screens
432
433 while (dlist) {
434 disp = (GdkDisplay *)dlist->data;
435
436 // get screens
437 nscreens = lives_display_get_n_screens(disp);
438 for (i = 0; i < nscreens; i++) {
439 screen = gdk_display_get_screen(disp, i);
440 capable->nmonitors += gdk_screen_get_n_monitors(screen);
441 }
442 dlist = dlist->next;
443 }
444 #else
445 disp = gdk_display_get_default();
446 capable->nmonitors += gdk_display_get_n_monitors(disp);
447 #endif
448
449 mainw->mgeom = (lives_mgeometry_t *)lives_calloc(capable->nmonitors, sizeof(lives_mgeometry_t));
450
451
452 #if !GTK_CHECK_VERSION(3, 22, 0)
453 dlist = dislist;
454
455 while (dlist) {
456 disp = (GdkDisplay *)dlist->data;
457
458 #if LIVES_HAS_DEVICE_MANAGER
459 devman = gdk_display_get_device_manager(disp);
460 devlist = gdk_device_manager_list_devices(devman, GDK_DEVICE_TYPE_MASTER);
461 #endif
462 // get screens
463 nscreens = lives_display_get_n_screens(disp);
464 for (i = 0; i < nscreens; i++) {
465 screen = gdk_display_get_screen(disp, i);
466 scale = get_screen_scale(screen, &dpi);
467 nmonitors = gdk_screen_get_n_monitors(screen);
468 for (j = 0; j < nmonitors; j++) {
469 gdk_screen_get_monitor_geometry(screen, j, &(rect));
470 mainw->mgeom[idx].x = rect.x;
471 mainw->mgeom[idx].y = rect.y;
472 mainw->mgeom[idx].width = mainw->mgeom[idx].phys_width = rect.width;
473 mainw->mgeom[idx].height = mainw->mgeom[idx].phys_height = rect.height;
474 mainw->mgeom[idx].mouse_device = NULL;
475 mainw->mgeom[idx].dpi = dpi;
476 mainw->mgeom[idx].scale = scale;
477 #if GTK_CHECK_VERSION(3, 4, 0)
478 gdk_screen_get_monitor_workarea(screen, j, &(rect));
479 mainw->mgeom[idx].width = rect.width;
480 mainw->mgeom[idx].height = rect.height;
481 #endif
482 #if LIVES_HAS_DEVICE_MANAGER
483 // get (virtual) mouse device for this screen
484 for (k = 0; k < lives_list_length(devlist); k++) {
485 device = (GdkDevice *)lives_list_nth_data(devlist, k);
486 if (gdk_device_get_display(device) == disp &&
487 gdk_device_get_source(device) == GDK_SOURCE_MOUSE) {
488 mainw->mgeom[idx].mouse_device = device;
489 break;
490 }
491 }
492 #endif
493 mainw->mgeom[idx].disp = disp;
494 mainw->mgeom[idx].screen = screen;
495 idx++;
496 if (idx >= capable->nmonitors) break;
497 }
498 }
499 #if LIVES_HAS_DEVICE_MANAGER
500 lives_list_free(devlist);
501 #endif
502 dlist = dlist->next;
503 }
504
505 lives_slist_free(dislist);
506 #else
507 screen = gdk_display_get_default_screen(disp);
508 scale = get_screen_scale(screen, &dpi);
509 device = gdk_seat_get_pointer(gdk_display_get_default_seat(disp));
510 for (idx = 0; idx < capable->nmonitors; idx++) {
511 mainw->mgeom[idx].disp = disp;
512 mainw->mgeom[idx].monitor = moni = gdk_display_get_monitor(disp, idx);
513 mainw->mgeom[idx].screen = screen;
514 gdk_monitor_get_geometry(moni, (GdkRectangle *)&rect);
515 mainw->mgeom[idx].x = rect.x;
516 mainw->mgeom[idx].y = rect.y;
517 mainw->mgeom[idx].phys_width = rect.width;
518 mainw->mgeom[idx].phys_height = rect.height;
519 mainw->mgeom[idx].mouse_device = device;
520 mainw->mgeom[idx].dpi = dpi;
521 mainw->mgeom[idx].scale = scale;
522 gdk_monitor_get_workarea(moni, &(rect));
523 mainw->mgeom[idx].width = rect.width;
524 mainw->mgeom[idx].height = rect.height;
525 if (gdk_monitor_is_primary(moni)) {
526 capable->primary_monitor = idx;
527 mainw->mgeom[idx].primary = TRUE;
528 } else if (play_moni == 1) play_moni = idx + 1;
529 }
530 #endif
531 #endif
532
533 if (prefs->force_single_monitor) capable->nmonitors = 1; // force for clone mode
534
535 if (!reset) return;
536
537 prefs->gui_monitor = 0;
538 prefs->play_monitor = play_moni;
539
540 if (capable->nmonitors > 1) {
541 get_string_pref(PREF_MONITORS, buff, 256);
542
543 if (*buff && get_token_count(buff, ',') > 1) {
544 char **array = lives_strsplit(buff, ",", 2);
545 prefs->gui_monitor = atoi(array[0]);
546 prefs->play_monitor = atoi(array[1]);
547 lives_strfreev(array);
548 }
549
550 if (prefs->gui_monitor < 1) prefs->gui_monitor = 1;
551 if (prefs->play_monitor < 0) prefs->play_monitor = 0;
552 if (prefs->gui_monitor > capable->nmonitors) prefs->gui_monitor = capable->nmonitors;
553 if (prefs->play_monitor > capable->nmonitors) prefs->play_monitor = capable->nmonitors;
554 }
555
556 widget_opts.monitor = prefs->gui_monitor > 0 ? prefs->gui_monitor - 1 : capable->primary_monitor;
557
558 mainw->old_scr_width = GUI_SCREEN_WIDTH;
559 mainw->old_scr_height = GUI_SCREEN_HEIGHT;
560
561 prefs->screen_scale = get_double_prefd(PREF_SCREEN_SCALE, 0.);
562 if (prefs->screen_scale == 0.) {
563 prefs->screen_scale = (double)GUI_SCREEN_WIDTH / (double)SCREEN_SCALE_DEF_WIDTH;
564 prefs->screen_scale = (prefs->screen_scale - 1.) * 1.5 + 1.;
565 }
566
567 if (!prefs->vj_mode && GUI_SCREEN_HEIGHT >= MIN_MSG_AREA_SCRNHEIGHT) prefs->show_msg_area = TRUE;
568 else prefs->show_msg_area = FALSE;
569
570 widget_opts_rescale(prefs->screen_scale);
571 }
572
573
print_notice(void)574 static void print_notice(void) {
575 fprintf(stderr, "\nLiVES %s\n", LiVES_VERSION);
576 fprintf(stderr, "Copyright "LIVES_COPYRIGHT_YEARS" Gabriel Finch ("LIVES_AUTHOR_EMAIL") and others.\n");
577 fprintf(stderr, "LiVES comes with ABSOLUTELY NO WARRANTY\nThis is free software, and you are welcome to redistribute it\n"
578 "under certain conditions; "
579 "see the file COPYING for details.\n\n");
580 }
581
582
pre_init(void)583 static boolean pre_init(void) {
584 // stuff which should be done *before* mainwindow is created
585 // returns TRUE if we got an error loading the theme
586
587 #ifdef GUI_GTK
588 LiVESError *gerr = NULL;
589 char *icon;
590 #endif
591
592 pthread_mutexattr_t mattr;
593
594 char *msg, *tmp, *tmp2, *cfgdir;
595
596 boolean needs_update = FALSE;
597
598 int i;
599
600 /// create context data for main thread; must be called before get_capabilities()
601 lives_thread_data_create(0);
602
603 // need to create directory for configfile before calling get_capabilities()
604 cfgdir = get_dir(prefs->configfile);
605 lives_make_writeable_dir(cfgdir);
606 lives_free(cfgdir);
607
608 // pre-checked conditions. We will check for these agian
609 if (capable->has_perl && capable->can_write_to_workdir && capable->can_write_to_config &&
610 capable->can_write_to_config_backup && capable->can_write_to_config_new && capable->can_read_from_config &&
611 capable->has_smogrify && capable->smog_version_correct) {
612 // check the backend is there, get some system details and prefs
613 capable = get_capabilities();
614 }
615
616 //FATAL ERRORS
617
618 if (!mainw->foreign) {
619 if (!capable->has_perl) {
620 startup_message_fatal(lives_strdup(
621 _("\nPerl must be installed and in your path.\n\n"
622 "Please review the README file which came with this package\nbefore running LiVES.\n\n"
623 "Thankyou.\n")));
624 }
625 if (!capable->has_smogrify) {
626 msg = lives_strdup(
627 _("\n`smogrify` must be in your path, and be executable\n\n"
628 "Please review the README file which came with this package\nbefore running LiVES.\n"));
629 startup_message_fatal(msg);
630 }
631 if (!capable->smog_version_correct) {
632 startup_message_fatal(lives_strdup(
633 _("\nAn incorrect version of smogrify was found in your path.\n\n"
634 "Please review the README file which came with this package\nbefore running LiVES."
635 "\n\nThankyou.\n")));
636 }
637
638 if (!capable->can_read_from_config) {
639 msg = lives_strdup_printf(
640 _("\nLiVES was unable to read from its configuration file\n%s\n\n"
641 "Please check the file permissions for this file and try again.\n"),
642 (tmp = lives_filename_to_utf8(prefs->configfile, -1, NULL, NULL, NULL)));
643 lives_free(tmp);
644 startup_message_fatal(msg);
645 }
646
647 if (!capable->can_write_to_config_new || !capable->can_write_to_config_backup || !capable->can_write_to_config) {
648 msg = lives_strdup_printf(
649 _("\nAn error occurred when writing to the configuration files\n%s*\n\n"
650 "Please check the file permissions for this file and directory\nand try again.\n"),
651 (tmp2 = ensure_extension((tmp = lives_filename_to_utf8(prefs->configfile, -1, NULL, NULL, NULL)),
652 LIVES_FILE_EXT_NEW)));
653 lives_free(tmp);
654 lives_free(tmp2);
655 startup_message_fatal(msg);
656 }
657
658 if (!capable->can_write_to_workdir) {
659 if (!mainw->has_session_workdir) {
660 tmp2 = lives_strdup_printf(_("Please check the %s setting in \n%s\nand try again.\n"),
661 (mainw->old_vhash && atoi(mainw->old_vhash) != 0 && atoi(mainw->old_vhash) < 3003003)
662 ? "<tempdir>" : "<workdir>",
663 (tmp = lives_filename_to_utf8(prefs->configfile, -1, NULL, NULL, NULL)));
664 lives_free(tmp);
665 } else tmp2 = lives_strdup("");
666
667 msg = lives_strdup_printf(_("\nLiVES was unable to use the working directory\n%s\n\n%s"),
668 prefs->workdir, tmp2);
669 lives_free(tmp2);
670 startup_message_fatal(msg);
671 }
672 if (mainw->error) {
673 msg = lives_strdup_printf(_("\nSomething went wrong during startup\n%s"), mainw->msg);
674 startup_message_fatal(msg);
675 }
676 }
677
678 sizint = sizeof(int);
679 sizdbl = sizeof(double);
680 sizshrt = sizeof(short);
681
682 // TRANSLATORS: text saying "Any", for encoder and output format (as in "does not matter")
683 mainw->string_constants[LIVES_STRING_CONSTANT_ANY] = (_("Any"));
684 // TRANSLATORS: text saying "None", for playback plugin name (as in "none specified")
685 mainw->string_constants[LIVES_STRING_CONSTANT_NONE] = (_("None"));
686 // TRANSLATORS: text saying "recommended", for plugin names, etc.
687 mainw->string_constants[LIVES_STRING_CONSTANT_RECOMMENDED] = (_("recommended"));
688 // TRANSLATORS: text saying "disabled", (as in "not enabled")
689 mainw->string_constants[LIVES_STRING_CONSTANT_DISABLED] = (_("disabled !"));
690 // TRANSLATORS: text saying "**The current layout**", to warn users that the current layout is affected
691 mainw->string_constants[LIVES_STRING_CONSTANT_CL] = (_("**The current layout**"));
692 // TRANSLATORS: adjective for "Built in" type effects
693 mainw->string_constants[LIVES_STRING_CONSTANT_BUILTIN] = (_("Builtin"));
694 // TRANSLATORS: adjective for "Custom" type effects
695 mainw->string_constants[LIVES_STRING_CONSTANT_CUSTOM] = (_("Custom"));
696 // TRANSLATORS: adjective for "Test" type effects
697 mainw->string_constants[LIVES_STRING_CONSTANT_TEST] = (_("Test"));
698
699 // now we can use PREFS properly
700 mainw->prefs_cache = cache_file_contents(prefs->configfile);
701
702 prefs->show_dev_opts = get_boolean_prefd(PREF_SHOW_DEVOPTS, FALSE);
703 prefs->dev_show_dabg = prefs->dev_show_timing = FALSE;
704
705 prefs->back_compat = get_boolean_prefd(PREF_BACK_COMPAT, TRUE);
706
707 future_prefs->vj_mode = get_boolean_prefd(PREF_VJMODE, FALSE);
708 if (!ign_opts.ign_vjmode) prefs->vj_mode = future_prefs->vj_mode;
709
710 #ifdef GUI_GTK
711 if (!prefs->show_dev_opts || prefs->vj_mode) {
712 // don't crash on GTK+ fatals
713 g_log_set_always_fatal((GLogLevelFlags)0);
714 }
715 #endif
716
717 if (!prefs->vj_mode) {
718 check_for_executable(&capable->has_mplayer, EXEC_MPLAYER);
719 check_for_executable(&capable->has_mplayer2, EXEC_MPLAYER2);
720 check_for_executable(&capable->has_mpv, EXEC_MPV);
721
722 check_for_executable(&capable->has_convert, EXEC_CONVERT);
723 check_for_executable(&capable->has_composite, EXEC_COMPOSITE);
724 check_for_executable(&capable->has_identify, EXEC_IDENTIFY);
725
726 check_for_executable(&capable->has_gzip, EXEC_GZIP);
727 check_for_executable(&capable->has_gdb, EXEC_GDB);
728 }
729
730 /// kick off the thread pool ////////////////////////////////
731 /// this must be done before we can check the disk status
732 future_prefs->nfx_threads = prefs->nfx_threads = get_int_prefd(PREF_NFX_THREADS, capable->ncpus);
733
734 #ifdef VALGRIND_ON
735 prefs->nfx_threads = 2;
736 #endif
737
738 lives_threadpool_init();
739
740 capable->gui_thread = pthread_self();
741
742 /// check disk storage status /////////////////////////////////////
743 mainw->ds_status = LIVES_STORAGE_STATUS_UNKNOWN;
744
745 if (!ign_opts.ign_dscrit)
746 prefs->ds_crit_level = (uint64_t)get_int64_prefd(PREF_DS_CRIT_LEVEL, DEF_DS_CRIT_LEVEL);
747 if (prefs->ds_crit_level < 0) prefs->ds_crit_level = 0;
748
749 prefs->ds_warn_level = (uint64_t)get_int64_prefd(PREF_DS_WARN_LEVEL, DEF_DS_WARN_LEVEL);
750 if (prefs->ds_warn_level < prefs->ds_crit_level) prefs->ds_warn_level = prefs->ds_crit_level;
751 mainw->next_ds_warn_level = prefs->ds_warn_level;
752 prefs->show_disk_quota = get_boolean_prefd(PREF_SHOW_QUOTA, prefs->show_disk_quota);
753 prefs->disk_quota = get_int64_prefd(PREF_DISK_QUOTA, 0);
754 if (prefs->disk_quota < 0) prefs->disk_quota = 0;
755
756 prefs->quota_limit = 90.0;
757
758 if (mainw->has_session_workdir) {
759 prefs->show_disk_quota = FALSE;
760 prefs->disk_quota = 0;
761 }
762
763 future_prefs->disk_quota = prefs->disk_quota;
764
765 if (!prefs->vj_mode) {
766 /// start a bg thread to get diskspace used
767 if (!needs_workdir && prefs->disk_quota && !needs_workdir && initial_startup_phase == 0)
768 mainw->helper_procthreads[PT_LAZY_DSUSED] = disk_monitor_start(prefs->workdir);
769
770 if (!needs_workdir && mainw->next_ds_warn_level > 0) {
771 int64_t dsval = disk_monitor_check_result(prefs->workdir);
772 if (dsval > 0) capable->ds_used = dsval;
773 else dsval = capable->ds_used;
774 mainw->ds_status = get_storage_status(prefs->workdir, mainw->next_ds_warn_level, &dsval, 0);
775 capable->ds_free = dsval;
776 if (mainw->ds_status == LIVES_STORAGE_STATUS_CRITICAL) {
777 tmp = ds_critical_msg(prefs->workdir, &capable->mountpoint, dsval);
778 msg = lives_strdup_printf("\n%s\n", tmp);
779 lives_free(tmp);
780 widget_opts.use_markup = TRUE;
781 startup_message_nonfatal(msg);
782 widget_opts.use_markup = FALSE;
783 lives_free(msg);
784 }
785 }
786 }
787
788 // get some prefs we need to set menu options
789 prefs->gui_monitor = -1;
790
791 if (prefs->vj_mode) {
792 check_for_executable(&capable->has_wmctrl, EXEC_WMCTRL);
793 check_for_executable(&capable->has_xwininfo, EXEC_XWININFO);
794 check_for_executable(&capable->has_xdotool, EXEC_XDOTOOL);
795 }
796 mainw->mgeom = NULL;
797
798 prefs->force_single_monitor = get_boolean_pref(PREF_FORCE_SINGLE_MONITOR);
799 mainw->ignore_screen_size = FALSE;
800
801 capable->primary_monitor = 0;
802
803 // sets prefs->screen_scale, capable->nmonitors, mainw->mgeom, prefs->play_monitor, prefs->gui_monitor
804 // prefs->show_msg_area, mainw->old_screen_height, mainw->old_screen_width
805 // widget_opts.monitor, widget_opts.screen and various widget_opts sizes
806 get_monitors(TRUE);
807
808 // set to allow multiple locking by the same thread
809 pthread_mutexattr_init(&mattr);
810 pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
811
812 // recursive locks
813 pthread_mutex_init(&mainw->abuf_mutex, &mattr);
814 pthread_mutex_init(&mainw->instance_ref_mutex, &mattr);
815
816 // non-recursive
817 pthread_mutex_init(&mainw->abuf_frame_mutex, NULL);
818 pthread_mutex_init(&mainw->fxd_active_mutex, NULL);
819 pthread_mutex_init(&mainw->event_list_mutex, NULL);
820 pthread_mutex_init(&mainw->clip_list_mutex, NULL);
821 pthread_mutex_init(&mainw->vpp_stream_mutex, NULL);
822 pthread_mutex_init(&mainw->cache_buffer_mutex, NULL);
823 pthread_mutex_init(&mainw->audio_filewriteend_mutex, NULL);
824 pthread_mutex_init(&mainw->exit_mutex, NULL);
825 pthread_mutex_init(&mainw->fbuffer_mutex, NULL);
826 pthread_mutex_init(&mainw->avseek_mutex, NULL);
827 pthread_mutex_init(&mainw->alarmlist_mutex, NULL);
828
829 // conds
830 pthread_cond_init(&mainw->avseek_cond, NULL);
831
832 if (prefs->vj_mode)
833 prefs->load_rfx_builtin = FALSE;
834 else
835 prefs->load_rfx_builtin = get_boolean_prefd(PREF_LOAD_RFX_BUILTIN, TRUE);
836
837 for (i = 0; i < FX_KEYS_MAX; i++) {
838 pthread_mutex_init(&mainw->fx_mutex[i], NULL);
839 }
840
841 mainw->vrfx_update = NULL;
842
843 mainw->kb_timer = -1;
844
845 prefs->sleep_time = 1000;
846
847 prefs->present = FALSE;
848
849 get_string_prefd(PREF_DEFAULT_IMAGE_TYPE, prefs->image_type, 16, LIVES_IMAGE_TYPE_PNG);
850 lives_snprintf(prefs->image_ext, 16, "%s",
851 get_image_ext_for_type(lives_image_type_to_img_type(prefs->image_type)));
852
853 /// eye candy
854 prefs->extra_colours = get_boolean_prefd(PREF_EXTRA_COLOURS, TRUE);
855 prefs->show_button_images = widget_opts.show_button_images =
856 get_boolean_prefd(PREF_SHOW_BUTTON_ICONS, TRUE);
857
858 prefs->mt_show_ctx = get_boolean_prefd(PREF_MT_SHOW_CTX, TRUE);
859
860 mainw->threaded_dialog = FALSE;
861 clear_mainw_msg();
862
863 info_only = FALSE;
864 palette = (_palette *)(lives_malloc(sizeof(_palette)));
865
866 prefs->sepwin_type = future_prefs->sepwin_type = get_int_prefd(PREF_SEPWIN_TYPE, SEPWIN_TYPE_STICKY);
867
868 if (!ign_opts.ign_aplayer) {
869 prefs->audio_player = AUD_PLAYER_SOX;
870 lives_snprintf(prefs->aplayer, 512, "%s", AUDIO_PLAYER_SOX);
871 }
872
873 prefs->open_decorated = TRUE;
874
875 #ifdef ENABLE_GIW
876 prefs->lamp_buttons = TRUE;
877 #else
878 prefs->lamp_buttons = FALSE;
879 #endif
880
881 prefs->autoload_subs = get_boolean_prefd(PREF_AUTOLOAD_SUBS, TRUE);
882 prefs->show_subtitles = get_boolean_prefd(PREF_SHOW_SUBS, TRUE);
883
884 prefs->pa_restart = get_boolean_prefd(PREF_PARESTART, FALSE);
885 get_string_prefd(PREF_PASTARTOPTS, prefs->pa_start_opts, 255, "--high-priority");
886
887 prefs->letterbox = get_boolean_prefd(PREF_LETTERBOX, TRUE);
888 future_prefs->letterbox_mt = prefs->letterbox_mt = get_boolean_prefd(PREF_LETTERBOXMT, TRUE);
889
890 prefs->rte_keys_virtual = get_int_prefd(PREF_RTE_KEYS_VIRTUAL, FX_KEYS_PHYSICAL_EXTRA);
891 if (prefs->rte_keys_virtual < 0) prefs->rte_keys_virtual = 0;
892 if (prefs->rte_keys_virtual > FX_KEYS_MAX_VIRTUAL) prefs->rte_keys_virtual = FX_KEYS_MAX_VIRTUAL;
893
894 prefs->bigendbug = 0;
895
896 #if GTK_CHECK_VERSION(3, 0, 0)
897 prefs->funky_widgets = TRUE;
898 #else
899 prefs->funky_widgets = FALSE;
900 #endif
901
902 prefs->show_splash = TRUE;
903 prefs->hide_framebar = FALSE;
904
905 // get some prefs we need to set menu options
906 future_prefs->show_recent = prefs->show_recent = get_boolean_prefd(PREF_SHOW_RECENT_FILES, TRUE);
907
908 get_string_pref(PREF_PREFIX_DIR, prefs->prefix_dir, PATH_MAX);
909
910 if (!(*prefs->prefix_dir)) {
911 if (strcmp(PREFIX, "NONE")) {
912 lives_snprintf(prefs->prefix_dir, PATH_MAX, "%s", PREFIX);
913 } else {
914 lives_snprintf(prefs->prefix_dir, PATH_MAX, "%s", PREFIX_DEFAULT);
915 }
916 needs_update = TRUE;
917 }
918
919 if (ensure_isdir(prefs->prefix_dir)) needs_update = TRUE;
920
921 if (needs_update) set_string_pref(PREF_PREFIX_DIR, prefs->prefix_dir);
922
923 #ifdef GUI_GTK
924 icon = lives_build_filename(prefs->prefix_dir, DESKTOP_ICON_DIR, "lives." LIVES_FILE_EXT_PNG, NULL);
925 gtk_window_set_default_icon_from_file(icon, &gerr);
926 lives_free(icon);
927
928 if (gerr) lives_error_free(gerr);
929 #endif
930 mainw->first_free_file = 1;
931
932 needs_update = FALSE;
933
934 get_string_pref(PREF_LIB_DIR, prefs->lib_dir, PATH_MAX);
935
936 if (!(*prefs->lib_dir)) {
937 lives_snprintf(prefs->lib_dir, PATH_MAX, "%s", LIVES_LIBDIR);
938 needs_update = TRUE;
939 }
940
941 if (ensure_isdir(prefs->lib_dir)) needs_update = TRUE;
942 if (needs_update) set_string_pref(PREF_LIB_DIR, prefs->lib_dir);
943
944 lives_memset(mainw->sepimg_path, 0, 1);
945 lives_memset(mainw->frameblank_path, 0, 1);
946
947 mainw->imsep = mainw->imframe = NULL;
948
949 prefs->max_messages = get_int_prefd(PREF_MAX_MSGS, DEF_MAX_MSGS);
950 future_prefs->msg_textsize = prefs->msg_textsize = get_int_prefd(PREF_MSG_TEXTSIZE, DEF_MSG_TEXTSIZE);
951
952 mainw->msg_list = NULL;
953 mainw->n_messages = 0;
954 mainw->ref_message = NULL;
955 mainw->ref_message_n = 0;
956 add_messages_to_list(_("Starting...\n"));
957
958 get_string_pref(PREF_GUI_THEME, prefs->theme, 64);
959
960 if (!(*prefs->theme)) {
961 lives_snprintf(prefs->theme, 64, LIVES_THEME_NONE);
962 }
963
964 lives_snprintf(future_prefs->theme, 64, "%s", prefs->theme);
965
966 if (!set_palette_colours(initial_startup_phase == -1)) {
967 lives_snprintf(prefs->theme, 64, LIVES_THEME_NONE);
968 set_palette_colours(initial_startup_phase != -1);
969 } else if (palette->style & STYLE_1) {
970 widget_opts.apply_theme = 1;
971 }
972 if (!mainw->foreign) {
973 if (prefs->startup_phase == -1 && prefs->show_splash) splash_init();
974 print_notice();
975 }
976
977 get_string_pref(PREF_CDPLAY_DEVICE, prefs->cdplay_device, PATH_MAX);
978
979 prefs->warning_mask = (uint64_t)get_int64_prefd(PREF_LIVES_WARNING_MASK, DEF_WARNING_MASK);
980
981 if (!ign_opts.ign_jackopts) {
982 prefs->jack_opts = future_prefs->jack_opts = get_int_prefd(PREF_JACK_OPTS, 16);
983 }
984
985 #ifdef GUI_GTK
986 if (!has_pref(PREF_SHOW_TOOLTIPS)) {
987 lives_widget_object_get(gtk_settings_get_default(), "gtk-enable-tooltips", &prefs->show_tooltips);
988 } else
989 #endif
990 prefs->show_tooltips = get_boolean_prefd(PREF_SHOW_TOOLTIPS, TRUE);
991
992 prefs->show_urgency_msgs = get_boolean_prefd(PREF_SHOW_URGENCY, TRUE);
993 prefs->show_overlay_msgs = get_boolean_prefd(PREF_SHOW_OVERLAY_MSGS, TRUE);
994
995 prefs->allow_easing = get_boolean_prefd(PREF_ALLOW_EASING, TRUE);
996
997 prefs->render_overlay = prefs->show_dev_opts;
998
999 if (prefs->show_dev_opts) {
1000 prefs->btgamma = get_boolean_prefd(PREF_BTGAMMA, FALSE);
1001 }
1002
1003 for (i = 0; i < MAX_FX_CANDIDATE_TYPES; i++) {
1004 mainw->fx_candidates[i].delegate = -1;
1005 mainw->fx_candidates[i].list = NULL;
1006 mainw->fx_candidates[i].func = 0l;
1007 mainw->fx_candidates[i].rfx = NULL;
1008 }
1009
1010 prefs->volume = (float)get_double_prefd(PREF_MASTER_VOLUME, 1.0);
1011 future_prefs->volume = prefs->volume;
1012 mainw->uflow_count = 0;
1013
1014 prefs->open_maximised = get_boolean_prefd(PREF_OPEN_MAXIMISED, TRUE);
1015
1016 for (i = 0; i < MAX_EXT_CNTL; i++) mainw->ext_cntl[i] = FALSE;
1017
1018 prefs->omc_dev_opts = get_int_prefd(PREF_OMC_DEV_OPTS, 3);
1019
1020 get_utf8_pref(PREF_OMC_JS_FNAME, prefs->omc_js_fname, PATH_MAX);
1021
1022 #ifdef ENABLE_OSC
1023 #ifdef OMC_JS_IMPL
1024 if (!*prefs->omc_js_fname) {
1025 const char *tmp = get_js_filename();
1026 if (tmp) {
1027 lives_snprintf(prefs->omc_js_fname, PATH_MAX, "%s", tmp);
1028 }
1029 }
1030 #endif
1031 #endif
1032
1033 get_utf8_pref(PREF_OMC_MIDI_FNAME, prefs->omc_midi_fname, PATH_MAX);
1034 #ifdef ENABLE_OSC
1035 #ifdef OMC_MIDI_IMPL
1036 if (!*prefs->omc_midi_fname) {
1037 const char *tmp = get_midi_filename();
1038 if (tmp) {
1039 lives_snprintf(prefs->omc_midi_fname, PATH_MAX, "%s", tmp);
1040 }
1041 }
1042 #endif
1043 #endif
1044
1045 #ifdef ALSA_MIDI
1046 prefs->use_alsa_midi = TRUE;
1047 prefs->alsa_midi_dummy = FALSE;
1048 mainw->seq_handle = NULL;
1049
1050 if (prefs->omc_dev_opts & OMC_DEV_FORCE_RAW_MIDI) prefs->use_alsa_midi = FALSE;
1051 if (prefs->omc_dev_opts & OMC_DEV_MIDI_DUMMY) prefs->alsa_midi_dummy = TRUE;
1052 #endif
1053
1054 prefs->midi_rcv_channel = get_int_prefd(PREF_MIDI_RCV_CHANNEL, MIDI_OMNI);
1055
1056 mainw->ccpd_with_sound = TRUE;
1057 mainw->loop = TRUE;
1058 mainw->loop_cont = FALSE;
1059 mainw->fs = FALSE;
1060
1061 if (prefs->vj_mode) {
1062 auto_recover = TRUE;
1063 mainw->loop_cont = TRUE;
1064 mainw->ccpd_with_sound = FALSE;
1065 prefs->sepwin_type = SEPWIN_TYPE_NON_STICKY;
1066 prefs->letterbox = FALSE;
1067 prefs->autoload_subs = FALSE;
1068 prefs->use_screen_gamma = TRUE;
1069 prefs->screen_gamma = 1.5;
1070 }
1071
1072 #ifdef GUI_GTK
1073 mainw->target_table = target_table;
1074 #endif
1075
1076 prefs->show_asrc = get_boolean_prefd(PREF_SHOW_ASRC, TRUE);
1077 prefs->hfbwnp = get_boolean_prefd(PREF_HFBWNP, FALSE);
1078
1079 mainw->next_free_alarm = 0;
1080
1081 for (i = 0; i < LIVES_MAX_ALARMS; i++) {
1082 mainw->alarms[i].lastcheck = 0;
1083 }
1084
1085 if (lives_ascii_strcasecmp(prefs->theme, future_prefs->theme)) return TRUE;
1086 return FALSE;
1087 }
1088
1089
replace_with_delegates(void)1090 void replace_with_delegates(void) {
1091 weed_plant_t *filter;
1092
1093 lives_rfx_t *rfx;
1094
1095 int resize_fx;
1096 int deint_idx;
1097
1098 if (mainw->fx_candidates[FX_CANDIDATE_RESIZER].delegate != -1) {
1099 resize_fx = LIVES_POINTER_TO_INT(lives_list_nth_data(mainw->fx_candidates[FX_CANDIDATE_RESIZER].list,
1100 mainw->fx_candidates[FX_CANDIDATE_RESIZER].delegate));
1101 filter = get_weed_filter(resize_fx);
1102 rfx = weed_to_rfx(filter, TRUE);
1103
1104 rfx->is_template = FALSE;
1105 rfx->props |= RFX_PROPS_MAY_RESIZE;
1106
1107 lives_free(rfx->action_desc);
1108 rfx->action_desc = (_("Resizing"));
1109
1110 rfx->min_frames = 1;
1111
1112 lives_free(rfx->menu_text);
1113
1114 if (!mainw->resize_menuitem) {
1115 rfx->menu_text = (_("_Resize All Frames..."));
1116 mainw->resize_menuitem = lives_standard_menu_item_new_with_label(rfx->menu_text);
1117 lives_widget_show(mainw->resize_menuitem);
1118 lives_menu_shell_insert(LIVES_MENU_SHELL(mainw->tools_menu), mainw->resize_menuitem, RFX_TOOL_MENU_POSN);
1119 } else {
1120 // disconnect old menu entry
1121 lives_signal_handler_disconnect(mainw->resize_menuitem, mainw->fx_candidates[FX_CANDIDATE_RESIZER].func);
1122 }
1123 // connect new menu entry
1124 mainw->fx_candidates[FX_CANDIDATE_RESIZER].func = lives_signal_connect(LIVES_GUI_OBJECT(mainw->resize_menuitem),
1125 LIVES_WIDGET_ACTIVATE_SIGNAL,
1126 LIVES_GUI_CALLBACK(on_render_fx_pre_activate),
1127 (livespointer)rfx);
1128 mainw->fx_candidates[FX_CANDIDATE_RESIZER].rfx = rfx;
1129 }
1130
1131 if (mainw->resize_menuitem) lives_widget_set_sensitive(mainw->resize_menuitem, CURRENT_CLIP_HAS_VIDEO);
1132
1133 deint_idx = weed_get_idx_for_hashname("deinterlacedeinterlace", FALSE);
1134 if (deint_idx > -1) {
1135 mainw->fx_candidates[FX_CANDIDATE_DEINTERLACE].list
1136 = lives_list_append(mainw->fx_candidates[FX_CANDIDATE_DEINTERLACE].list,
1137 LIVES_INT_TO_POINTER(deint_idx));
1138 mainw->fx_candidates[FX_CANDIDATE_DEINTERLACE].delegate = 0;
1139 }
1140 }
1141
1142
lives_init(_ign_opts * ign_opts)1143 static void lives_init(_ign_opts *ign_opts) {
1144 // init mainwindow data
1145 LiVESList *encoders = NULL;
1146 LiVESList *encoder_capabilities = NULL;
1147
1148 char **array;
1149 char mppath[PATH_MAX];
1150
1151 char *weed_plugin_path;
1152 #ifdef HAVE_FREI0R
1153 char *frei0r_path;
1154 #endif
1155 #ifdef HAVE_LADSPA
1156 char *ladspa_path;
1157 #endif
1158 #ifdef HAVE_LIBVISUAL
1159 char *libvis_path;
1160 #endif
1161 char *msg;
1162
1163 boolean needs_free;
1164
1165 int naudp = 0;
1166
1167 int i;
1168
1169 for (i = 0; i <= MAX_FILES; mainw->files[i++] = NULL);
1170 mainw->prefs_changed = FALSE;
1171 mainw->insert_after = TRUE;
1172 mainw->mute = FALSE;
1173 mainw->faded = FALSE;
1174 if (!prefs->vj_mode)
1175 mainw->save_with_sound = TRUE; // also affects loading
1176 else
1177 mainw->save_with_sound = FALSE;
1178 mainw->preview = FALSE;
1179 mainw->selwidth_locked = FALSE;
1180 mainw->untitled_number = mainw->cap_number = 1;
1181 mainw->sel_start = 0;
1182 mainw->sel_move = SEL_MOVE_AUTO;
1183 mainw->record_foreign = FALSE;
1184 mainw->play_window = NULL;
1185 mainw->opwx = mainw->opwy = -1;
1186 mainw->frame_layer = NULL;
1187 mainw->in_fs_preview = FALSE;
1188 mainw->effects_paused = FALSE;
1189 mainw->play_start = 0;
1190 mainw->opening_loc = FALSE;
1191 mainw->toy_type = LIVES_TOY_NONE;
1192 mainw->framedraw = mainw->framedraw_spinbutton = NULL;
1193 mainw->fd_layer = NULL;
1194 mainw->fd_layer_orig = NULL;
1195 mainw->is_processing = FALSE;
1196 mainw->is_rendering = FALSE;
1197 mainw->is_generating = FALSE;
1198 mainw->resizing = FALSE;
1199 mainw->switch_during_pb = FALSE;
1200 mainw->playing_sel = FALSE;
1201 mainw->aframeno = 0;
1202 if (capable->byte_order == LIVES_LITTLE_ENDIAN) {
1203 mainw->endian = 0;
1204 } else {
1205 mainw->endian = AFORM_BIG_ENDIAN;
1206 }
1207
1208 mainw->leave_files = FALSE;
1209 mainw->was_set = FALSE;
1210 mainw->toy_go_wild = FALSE;
1211
1212 for (i = 0; i < FN_KEYS - 1; i++) {
1213 mainw->clipstore[i][0] = -1;
1214 }
1215
1216 mainw->ping_pong = FALSE;
1217
1218 mainw->nervous = FALSE;
1219 fx_dialog[0] = fx_dialog[1] = NULL;
1220
1221 mainw->rte_keys = -1;
1222 rte_window = NULL;
1223
1224 mainw->rte = EFFECT_NONE;
1225
1226 mainw->preview_box = NULL;
1227 mainw->prv_link = PRV_PTR;
1228
1229 mainw->internal_messaging = FALSE;
1230 mainw->progress_fn = NULL;
1231
1232 mainw->last_grabbable_effect = -1;
1233 mainw->blend_file = -1;
1234
1235 mainw->pre_src_file = -2;
1236 mainw->pre_src_audio_file = -1;
1237
1238 mainw->size_warn = 0;
1239 mainw->dvgrab_preview = FALSE;
1240
1241 mainw->file_open_params = NULL;
1242 mainw->whentostop = NEVER_STOP;
1243
1244 mainw->audio_start = mainw->audio_end = 0;
1245 mainw->cliplist = NULL;
1246
1247 // rendered_fx number of last transition
1248 mainw->last_transition_idx = -1;
1249 mainw->last_transition_loops = 1;
1250 mainw->last_transition_align_start = TRUE;
1251 mainw->last_transition_loop_to_fit = mainw->last_transition_ins_frames = FALSE;
1252 mainw->num_tr_applied = 0;
1253
1254 mainw->blend_factor = 0.;
1255
1256 mainw->fixed_fps_numer = -1;
1257 mainw->fixed_fps_denom = 1;
1258 mainw->fixed_fpsd = -1.;
1259 mainw->noswitch = mainw->cs_permitted = mainw->cs_is_permitted = FALSE;
1260 mainw->osc_block = FALSE;
1261
1262 mainw->cancelled = CANCEL_NONE;
1263 mainw->cancel_type = CANCEL_KILL;
1264
1265 mainw->framedraw_reset = NULL;
1266
1267 // setting this to TRUE can possibly increase smoothness for lower framerates
1268 // needs more testing and a preference in prefs window- TODO
1269 // can also be set through OSC: /output/nodrop/enable
1270 prefs->noframedrop = get_boolean_prefd(PREF_NOFRAMEDROP, FALSE);
1271
1272 prefs->omc_noisy = FALSE;
1273 prefs->omc_events = TRUE;
1274
1275 if (!ign_opts->ign_osc) {
1276 prefs->osc_udp_started = FALSE;
1277 prefs->osc_udp_port = 0;
1278 #ifdef ENABLE_OSC
1279 if (!mainw->foreign) {
1280 prefs->osc_udp_port = get_int_prefd(PREF_OSC_PORT, DEF_OSC_LISTEN_PORT);
1281 future_prefs->osc_start = prefs->osc_start = get_boolean_prefd(PREF_OSC_START, FALSE);
1282 } else {
1283 future_prefs->osc_start = prefs->osc_start = FALSE;
1284 }
1285 #endif
1286 }
1287
1288 prefs->fps_tolerance = .0005;
1289 prefs->rec_opts = get_int_prefd(PREF_RECORD_OPTS, -1);
1290
1291 if (prefs->rec_opts == -1) {
1292 prefs->rec_opts = REC_FPS | REC_FRAMES | REC_EFFECTS | REC_CLIPS | REC_AUDIO;
1293 set_int_pref(PREF_RECORD_OPTS, prefs->rec_opts);
1294 }
1295
1296 prefs->rec_opts |= (REC_FPS + REC_FRAMES);
1297
1298 mainw->new_clip = -1;
1299 mainw->record = FALSE;
1300 mainw->event_list = NULL;
1301 mainw->clip_switched = FALSE;
1302 mainw->scrap_file = -1;
1303 mainw->ascrap_file = -1;
1304
1305 mainw->jack_can_stop = FALSE;
1306 mainw->jack_can_start = TRUE;
1307
1308 if (!mainw->foreign) mainw->video_seek_ready = mainw->audio_seek_ready = FALSE;
1309 else mainw->video_seek_ready = mainw->audio_seek_ready = TRUE;
1310
1311 mainw->filter_map = NULL; // filter map for video rendering
1312 mainw->afilter_map = NULL; // filter map for audio rendering
1313 mainw->audio_event = NULL;
1314
1315 mainw->did_rfx_preview = FALSE;
1316
1317 prefsw = NULL;
1318 rdet = NULL;
1319 resaudw = NULL;
1320
1321 mainw->actual_frame = 0;
1322
1323 mainw->scratch = SCRATCH_NONE;
1324
1325 mainw->clip_index = NULL;
1326 mainw->frame_index = NULL;
1327
1328 mainw->affected_layouts_map = mainw->current_layouts_map = NULL;
1329
1330 mainw->leave_recovery = TRUE;
1331
1332 mainw->pchains = NULL;
1333
1334 mainw->preview_frame = 0;
1335
1336 mainw->unordered_blocks = FALSE;
1337
1338 mainw->only_close = FALSE;
1339
1340 mainw->no_exit = FALSE;
1341
1342 mainw->multi_opts.set = FALSE;
1343
1344 mainw->clip_header = NULL;
1345
1346 mainw->new_blend_file = -1;
1347
1348 mainw->jackd = mainw->jackd_read = NULL;
1349
1350 mainw->pulsed = mainw->pulsed_read = NULL;
1351
1352 mainw->show_procd = TRUE;
1353
1354 mainw->framedraw_preview = mainw->framedraw_reset = NULL;
1355
1356 mainw->block_param_updates = mainw->no_interp = FALSE;
1357
1358 mainw->cevent_tc = 0;
1359
1360 mainw->opening_multi = FALSE;
1361
1362 mainw->img_concat_clip = -1;
1363
1364 mainw->record_paused = mainw->record_starting = FALSE;
1365
1366 mainw->gen_to_clipboard = FALSE;
1367
1368 mainw->open_deint = FALSE;
1369
1370 mainw->write_vpp_file = FALSE;
1371
1372 mainw->stream_ticks = -1;
1373
1374 mainw->keep_pre = FALSE;
1375
1376 mainw->reverse_pb = FALSE;
1377
1378 mainw->osc_auto = 0;
1379 mainw->osc_enc_width = mainw->osc_enc_height = 0;
1380
1381 mainw->no_switch_dprint = FALSE;
1382
1383 mainw->rte_textparm = NULL;
1384
1385 mainw->abufs_to_fill = 0;
1386
1387 mainw->recoverable_layout = mainw->recording_recovered = FALSE;
1388
1389 mainw->iochan = NULL;
1390
1391 mainw->stored_event_list = NULL;
1392 mainw->stored_event_list_changed = mainw->stored_event_list_auto_changed = FALSE;
1393 mainw->stored_layout_save_all_vals = TRUE;
1394
1395 mainw->affected_layout_marks = NULL;
1396
1397 mainw->stored_layout_undos = NULL;
1398 mainw->sl_undo_mem = NULL;
1399 mainw->sl_undo_buffer_used = 0;
1400 mainw->sl_undo_offset = 0;
1401
1402 mainw->go_away = TRUE;
1403
1404 mainw->aud_file_to_kill = -1;
1405
1406 mainw->aud_rec_fd = -1;
1407
1408 mainw->decoders_loaded = FALSE;
1409 mainw->decoder_list = NULL;
1410
1411 mainw->subt_save_file = NULL;
1412
1413 mainw->fonts_array = get_font_list();
1414
1415 mainw->nfonts = 0;
1416 if (mainw->fonts_array)
1417 while (mainw->fonts_array[mainw->nfonts++]);
1418
1419 mainw->videodevs = NULL;
1420
1421 mainw->camframe = NULL;
1422
1423 mainw->has_custom_effects = FALSE;
1424 mainw->has_custom_tools = FALSE;
1425 mainw->has_custom_gens = FALSE;
1426 mainw->has_custom_utilities = FALSE;
1427
1428 mainw->log_fd = -2;
1429
1430 mainw->last_display_ticks = 0;
1431
1432 mainw->alives_pgid = 0;
1433
1434 mainw->aplayer_broken = FALSE;
1435
1436 mainw->render_error = LIVES_RENDER_ERROR_NONE;
1437
1438 mainw->add_clear_ds_button = FALSE;
1439 mainw->add_clear_ds_adv = FALSE;
1440 mainw->tried_ds_recover = FALSE;
1441
1442 mainw->foreign_visual = NULL;
1443
1444 mainw->pconx = NULL;
1445 mainw->cconx = NULL;
1446
1447 cached_key = cached_mod = 0;
1448
1449 mainw->agen_key = 0;
1450 mainw->agen_needs_reinit = FALSE;
1451 mainw->agen_samps_count = 0;
1452
1453 mainw->ce_frame_height = mainw->ce_frame_width = -1;
1454
1455 mainw->cursor_style = LIVES_CURSOR_NORMAL;
1456
1457 mainw->sepwin_minwidth = MIN_SEPWIN_WIDTH;
1458 mainw->sepwin_minheight = PREVIEW_BOX_HT;
1459
1460 mainw->signal_caught = 0;
1461 mainw->signals_deferred = FALSE;
1462
1463 mainw->n_screen_areas = SCREEN_AREA_USER_DEFINED1;
1464 mainw->screen_areas = (lives_screen_area_t *)lives_malloc(mainw->n_screen_areas * sizeof(lives_screen_area_t));
1465 mainw->screen_areas[SCREEN_AREA_FOREGROUND].name = (_("Foreground"));
1466 mainw->screen_areas[SCREEN_AREA_BACKGROUND].name = (_("Background"));
1467
1468 mainw->active_sa_clips = mainw->active_sa_fx = SCREEN_AREA_FOREGROUND;
1469
1470 mainw->file_buffers = NULL;
1471
1472 mainw->blend_layer = NULL;
1473
1474 mainw->ce_upd_clip = FALSE;
1475
1476 mainw->clips_group = NULL;
1477
1478 mainw->fx_is_auto = FALSE;
1479 mainw->gen_started_play = FALSE;
1480
1481 mainw->audio_frame_buffer = NULL;
1482 mainw->afbuffer_clients = mainw->afbuffer_clients_read = 0;
1483 mainw->afb[0] = mainw->afb[1] = NULL;
1484
1485 lives_memset(mainw->recent_file, 0, 1);
1486
1487 mainw->aud_data_written = 0;
1488
1489 mainw->rendered_fx = NULL;
1490
1491 mainw->midi_channel_lock = FALSE;
1492
1493 mainw->crash_possible = 0;
1494
1495 mainw->scrap_pixbuf = NULL;
1496
1497 mainw->close_keep_frames = FALSE;
1498
1499 #ifdef ENABLE_JACK
1500 mainw->jack_inited = FALSE;
1501 mainw->jack_trans_poll = FALSE;
1502 #endif
1503
1504 mainw->recovering_files = FALSE;
1505
1506 mainw->num_rendered_effects_builtin = mainw->num_rendered_effects_custom = mainw->num_rendered_effects_test = 0;
1507
1508 mainw->flush_audio_tc = 0;
1509
1510 mainw->idlemax = 0;
1511 mainw->reconfig = FALSE;
1512
1513 mainw->fsp_func = 0;
1514
1515 mainw->swapped_clip = -1;
1516
1517 mainw->urgency_msg = mainw->overlay_msg = NULL;
1518
1519 mainw->xlays = NULL;
1520
1521 mainw->preview_rendering = FALSE;
1522
1523 mainw->new_lmap_errors = NULL;
1524
1525 mainw->ncbstores = 0;
1526
1527 mainw->loop_locked = FALSE;
1528
1529 mainw->invalid_clips = FALSE;
1530
1531 mainw->blend_palette = WEED_PALETTE_END;
1532 mainw->blend_width = mainw->blend_height = 0;
1533
1534 mainw->force_show = FALSE;
1535
1536 mainw->effort = 0;
1537
1538 mainw->frame_layer_preload = NULL;
1539 mainw->pred_frame = 0;
1540 mainw->pred_clip = 0;
1541
1542 mainw->lockstats = FALSE;
1543
1544 mainw->audio_stretch = 1.0;
1545
1546 mainw->play_sequence = 0;
1547
1548 mainw->record_frame = -1;
1549
1550 mainw->debug_ptr = NULL;
1551
1552 mainw->inst_fps = 0.;
1553
1554 mainw->pre_play_file = -1;
1555
1556 mainw->st_fcache = mainw->en_fcache = mainw->pr_fcache = NULL;
1557
1558 mainw->ptrtime = 0.;
1559
1560 mainw->proc_ptr = NULL;
1561
1562 mainw->permmgr = NULL;
1563
1564 mainw->set_list = NULL;
1565 mainw->num_sets = -1;
1566
1567 mainw->mt_needs_idlefunc = FALSE;
1568
1569 mainw->suppress_layout_warnings = FALSE;
1570
1571 mainw->add_trash_rb = FALSE;
1572
1573 mainw->cs_manage = FALSE;
1574
1575 mainw->dsu_valid = FALSE;
1576 mainw->dsu_widget = NULL;
1577
1578 mainw->drawsrc = -1;
1579
1580 mainw->lazy = 0;
1581
1582 mainw->disk_mon = 0;
1583
1584 mainw->wall_ticks = -1;
1585
1586 /////////////////////////////////////////////////// add new stuff just above here ^^
1587
1588 lives_memset(mainw->set_name, 0, 1);
1589 mainw->clips_available = 0;
1590
1591 prefs->pause_effect_during_preview = FALSE;
1592
1593 future_prefs->pb_quality = prefs->pb_quality = get_int_prefd(PREF_PB_QUALITY, PB_QUALITY_MED);
1594 if (prefs->pb_quality != PB_QUALITY_LOW && prefs->pb_quality != PB_QUALITY_HIGH &&
1595 prefs->pb_quality != PB_QUALITY_MED) prefs->pb_quality = PB_QUALITY_MED;
1596
1597 prefs->pbq_adaptive = get_boolean_prefd(PREF_PBQ_ADAPTIVE, TRUE);
1598
1599 mainw->ext_playback = mainw->ext_audio = FALSE;
1600
1601 prefs->loop_recording = TRUE;
1602 prefs->no_bandwidth = FALSE;
1603 prefs->ocp = get_int_prefd(PREF_OPEN_COMPRESSION_PERCENT, 15);
1604
1605 prefs->stop_screensaver = get_boolean_prefd(PREF_STOP_SCREENSAVER, TRUE);
1606 prefs->show_tool = get_boolean_prefd(PREF_SHOW_TOOLBAR, TRUE);
1607
1608 if (prefs->gui_monitor != 0) {
1609 lives_window_center(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET));
1610 }
1611
1612 prefs->default_fps = get_double_prefd(PREF_DEFAULT_FPS, DEF_FPS);
1613 if (prefs->default_fps < 1.) prefs->default_fps = 1.;
1614 if (prefs->default_fps > FPS_MAX) prefs->default_fps = FPS_MAX;
1615
1616 // values for trickplay
1617 prefs->blendchange_amount = get_double_prefd(PREF_BLEND_AMOUNT, DEF_BLENDCHANGE_AMOUNT);
1618 prefs->scratchfwd_amount = get_int_prefd(PREF_SCFWD_AMOUNT, DEF_SCRATCHFWD_AMOUNT);
1619 prefs->scratchback_amount = get_int_prefd(PREF_SCBACK_AMOUNT, DEF_SCRATCHBACK_AMOUNT);
1620 prefs->fpschange_amount = get_double_prefd(PREF_FPSCHANGE_AMOUNT, DEF_FPSCHANGE_AMOUNT);
1621
1622 prefs->q_type = Q_SMOOTH;
1623
1624 prefs->event_window_show_frame_events = FALSE;
1625 if (!mainw->foreign) prefs->crash_recovery = TRUE;
1626 else prefs->crash_recovery = FALSE;
1627
1628 prefs->acodec_list = NULL;
1629
1630 prefs->render_audio = TRUE;
1631 prefs->normalise_audio = TRUE;
1632
1633 prefs->num_rtaudiobufs = 4;
1634
1635 prefs->safe_symlinks = FALSE; // set to TRUE for dynebolic and other live CDs
1636
1637 prefs->ce_maxspect = get_boolean_prefd(PREF_CE_MAXSPECT, TRUE);
1638
1639 prefs->rec_stop_gb = get_double_prefd(PREF_REC_STOP_GB, DEF_REC_STOP_GB);
1640
1641 if (prefs->max_modes_per_key == 0) prefs->max_modes_per_key = atoi(DEF_FX_KEYMODES);
1642
1643 prefs->stream_audio_out = get_boolean_pref(PREF_STREAM_AUDIO_OUT);
1644
1645 prefs->unstable_fx = get_boolean_prefd(PREF_UNSTABLE_FX, TRUE);
1646
1647 prefs->disabled_decoders = get_list_pref(PREF_DISABLED_DECODERS);
1648
1649 prefs->enc_letterbox = FALSE;
1650
1651 prefs->clear_disk_opts = get_int_prefd(PREF_CLEAR_DISK_OPTS, 0);
1652
1653 prefs->force_system_clock = TRUE;
1654
1655 prefs->alpha_post = FALSE; ///< allow pre-multiplied alpha internally
1656
1657 prefs->auto_trim_audio = get_boolean_prefd(PREF_AUTO_TRIM_PAD_AUDIO, TRUE);
1658 prefs->keep_all_audio = get_boolean_prefd(PREF_KEEP_ALL_AUDIO, FALSE);
1659
1660 prefs->force64bit = FALSE;
1661
1662 #if LIVES_HAS_GRID_WIDGET
1663 prefs->ce_thumb_mode = get_boolean_prefd(PREF_CE_THUMB_MODE, FALSE);
1664 #else
1665 prefs->ce_thumb_mode = FALSE;
1666 #endif
1667
1668 prefs->push_audio_to_gens = get_boolean_prefd(PREF_PUSH_AUDIO_TO_GENS, TRUE);
1669
1670 prefs->perm_audio_reader = TRUE;
1671
1672 prefs->max_disp_vtracks = get_int_prefd(PREF_MAX_DISP_VTRACKS, DEF_MT_DISP_TRACKS);
1673
1674 prefs->mt_load_fuzzy = FALSE;
1675
1676 prefs->ahold_threshold = get_double_pref(PREF_AHOLD_THRESHOLD);
1677
1678 prefs->use_screen_gamma = get_boolean_prefd(PREF_USE_SCREEN_GAMMA, FALSE);
1679 prefs->screen_gamma = get_double_prefd(PREF_SCREEN_GAMMA, DEF_SCREEN_GAMMA);
1680 prefs->apply_gamma = get_boolean_prefd(PREF_APPLY_GAMMA, TRUE);
1681 prefs->btgamma = FALSE;
1682
1683 prefs->msgs_pbdis = get_boolean_prefd(PREF_MSG_PBDIS, TRUE);
1684
1685 prefs->cb_is_switch = FALSE;
1686
1687 prefs->autoclean = get_boolean_prefd(PREF_AUTOCLEAN_TRASH, TRUE);
1688
1689 future_prefs->pref_trash = prefs->pref_trash = get_boolean_prefd(PREF_PREF_TRASH, FALSE);
1690
1691 // get window manager capabilities
1692 #ifdef GDK_WINDOWING_WAYLAND
1693 if (GDK_IS_WAYLAND_DISPLAY(mainw->mgeom[0].disp))
1694 capable->wm_name = lives_strdup("Wayland");
1695 #endif
1696 #ifdef GDK_WINDOWING_X11
1697 if (GDK_IS_X11_DISPLAY(mainw->mgeom[0].disp))
1698 capable->wm_name = lives_strdup(gdk_x11_screen_get_window_manager_name(gdk_screen_get_default()));
1699 #endif
1700
1701 *capable->wm_caps.wm_name = 0;
1702 capable->has_wm_caps = FALSE;
1703 get_wm_caps();
1704
1705 if (*capable->wm_caps.panel)
1706 prefs->show_desktop_panel = get_x11_visible(capable->wm_caps.panel);
1707 //prefs->show_desktop_panel = TRUE;
1708
1709 prefs->show_msgs_on_startup = get_boolean_prefd(PREF_MSG_START, TRUE);
1710
1711 /// record rendering options
1712 prefs->rr_crash = get_boolean_prefd(PREF_RRCRASH, TRUE);
1713 prefs->rr_super = get_boolean_prefd(PREF_RRSUPER, TRUE);
1714 prefs->rr_pre_smooth = get_boolean_prefd(PREF_RRPRESMOOTH, TRUE);
1715 prefs->rr_qsmooth = get_boolean_prefd(PREF_RRQSMOOTH, TRUE);
1716 prefs->rr_amicro = get_boolean_prefd(PREF_RRAMICRO, TRUE);
1717 prefs->rr_ramicro = get_boolean_prefd(PREF_RRRAMICRO, TRUE);
1718
1719 prefs->rr_qmode = get_int_prefd(PREF_RRQMODE, 0);
1720 prefs->rr_qmode = INT_CLAMP(prefs->rr_qmode, 0, 1);
1721 prefs->rr_fstate = get_int_prefd(PREF_RRFSTATE, 0);
1722 prefs->rr_fstate = INT_CLAMP(prefs->rr_fstate, 0, 1);
1723
1724 /// new prefs here:
1725 //////////////////////////////////////////////////////////////////
1726
1727 get_string_prefd(PREF_DEF_AUTHOR, prefs->def_author, 1024, "");
1728
1729 if (!mainw->foreign) {
1730 prefs->midi_check_rate = get_int_pref(PREF_MIDI_CHECK_RATE);
1731 if (prefs->midi_check_rate == 0) prefs->midi_check_rate = DEF_MIDI_CHECK_RATE;
1732
1733 if (prefs->midi_check_rate < 1) prefs->midi_check_rate = 1;
1734
1735 prefs->midi_rpt = get_int_pref(PREF_MIDI_RPT);
1736 if (prefs->midi_rpt == 0) prefs->midi_rpt = DEF_MIDI_RPT;
1737
1738 prefs->mouse_scroll_clips = get_boolean_prefd(PREF_MOUSE_SCROLL_CLIPS, TRUE);
1739
1740 prefs->mt_auto_back = get_int_prefd(PREF_MT_AUTO_BACK, 120);
1741
1742 get_string_pref(PREF_VIDEO_OPEN_COMMAND, prefs->video_open_command, PATH_MAX * 2);
1743
1744 if (!*prefs->video_open_command) {
1745 lives_memset(mppath, 0, 1);
1746
1747 if (!(*prefs->video_open_command) && capable->has_mplayer) {
1748 get_location(EXEC_MPLAYER, mppath, PATH_MAX);
1749 }
1750
1751 if (!(*prefs->video_open_command) && capable->has_mplayer2) {
1752 get_location(EXEC_MPLAYER2, mppath, PATH_MAX);
1753 }
1754
1755 if (!(*prefs->video_open_command) && capable->has_mpv) {
1756 get_location(EXEC_MPV, mppath, PATH_MAX);
1757 }
1758
1759 if (*mppath) {
1760 lives_snprintf(prefs->video_open_command, PATH_MAX + 2, "\"%s\"", mppath);
1761 set_string_pref(PREF_VIDEO_OPEN_COMMAND, prefs->video_open_command);
1762 }
1763 }
1764
1765 prefs->warn_file_size = get_int_prefd(PREF_WARN_FILE_SIZE, WARN_FILE_SIZE);
1766
1767 prefs->show_rdet = TRUE;
1768 prefs->move_effects = TRUE;
1769 prefs->mt_undo_buf = get_int_prefd(PREF_MT_UNDO_BUF, DEF_MT_UNDO_SIZE);
1770 prefs->mt_enter_prompt = get_boolean_prefd(PREF_MT_ENTER_PROMPT, TRUE);
1771
1772 // default frame sizes (TODO - allow pref)
1773 mainw->def_width = DEF_FRAME_HSIZE;
1774 mainw->def_height = DEF_FRAME_HSIZE;
1775
1776 prefs->mt_def_width = get_int_prefd(PREF_MT_DEF_WIDTH, DEF_FRAME_HSIZE_UNSCALED);
1777 prefs->mt_def_height = get_int_prefd(PREF_MT_DEF_HEIGHT, DEF_FRAME_VSIZE_UNSCALED);
1778 prefs->mt_def_fps = get_double_prefd(PREF_MT_DEF_FPS, prefs->default_fps);
1779 prefs->mt_def_arate = get_int_prefd(PREF_MT_DEF_ARATE, DEFAULT_AUDIO_RATE);
1780 prefs->mt_def_achans = get_int_prefd(PREF_MT_DEF_ACHANS, DEFAULT_AUDIO_CHANS);
1781 prefs->mt_def_asamps = get_int_prefd(PREF_MT_DEF_ASAMPS, DEFAULT_AUDIO_SAMPS);
1782 prefs->mt_def_signed_endian = get_int_prefd(PREF_MT_DEF_SIGNED_ENDIAN, (capable->byte_order == LIVES_BIG_ENDIAN)
1783 ? 2 : 0 + ((prefs->mt_def_asamps == 8) ? 1 : 0));
1784
1785 prefs->mt_exit_render = get_boolean_prefd(PREF_MT_EXIT_RENDER, TRUE);
1786 prefs->render_prompt = get_boolean_prefd(PREF_RENDER_PROMPT, TRUE);
1787
1788 prefs->mt_pertrack_audio = get_boolean_prefd(PREF_MT_PERTRACK_AUDIO, TRUE);
1789 prefs->mt_backaudio = get_int_prefd(PREF_MT_BACKAUDIO, 1);
1790
1791 prefs->instant_open = get_boolean_prefd(PREF_INSTANT_OPEN, TRUE);
1792 prefs->auto_deint = get_boolean_prefd(PREF_AUTO_DEINTERLACE, TRUE);
1793 prefs->auto_nobord = get_boolean_prefd(PREF_AUTO_CUT_BORDERS, FALSE);
1794
1795 future_prefs->ar_clipset = FALSE;
1796
1797 if (!ign_opts->ign_clipset) {
1798 get_string_prefd(PREF_AR_CLIPSET, prefs->ar_clipset_name, 128, "");
1799 if (*prefs->ar_clipset_name) future_prefs->ar_clipset = prefs->ar_clipset = TRUE;
1800 else prefs->ar_clipset = FALSE;
1801 } else set_string_pref(PREF_AR_CLIPSET, "");
1802
1803 if (!ign_opts->ign_layout) {
1804 get_string_prefd(PREF_AR_LAYOUT, prefs->ar_layout_name, PATH_MAX, "");
1805 if (*prefs->ar_layout_name) prefs->ar_layout = TRUE;
1806 else prefs->ar_layout = FALSE;
1807 } else set_string_pref(PREF_AR_LAYOUT, "");
1808
1809 prefs->rec_desktop_audio = get_boolean_prefd(PREF_REC_DESKTOP_AUDIO, FALSE);
1810
1811 future_prefs->startup_interface = get_int_prefd(PREF_STARTUP_INTERFACE, STARTUP_CE);
1812 if (!ign_opts->ign_stmode) {
1813 prefs->startup_interface = future_prefs->startup_interface;
1814 }
1815
1816 // scan for encoder plugins
1817 if ((encoders = get_plugin_list(PLUGIN_ENCODERS, FALSE, NULL, NULL)) != NULL) {
1818 capable->has_encoder_plugins = TRUE;
1819 lives_list_free_all(&encoders);
1820 }
1821
1822 lives_memset(prefs->encoder.of_name, 0, 1);
1823 lives_memset(prefs->encoder.of_desc, 0, 1);
1824
1825 if ((prefs->startup_phase == 1 || prefs->startup_phase == -1) && capable->has_encoder_plugins && capable->has_python) {
1826 LiVESList *ofmt_all = NULL;
1827 char **array;
1828 if (check_for_executable(&capable->has_ffmpeg, EXEC_FFMPEG)) {
1829 lives_snprintf(prefs->encoder.name, 64, "%s", FFMPEG_ENCODER_NAME);
1830 } else {
1831 if (capable->python_version >= 3000000)
1832 lives_snprintf(prefs->encoder.name, 64, "%s", MULTI_ENCODER3_NAME);
1833 else
1834 lives_snprintf(prefs->encoder.name, 64, "%s", MULTI_ENCODER_NAME);
1835 }
1836 // need to change the output format
1837
1838 if ((ofmt_all = plugin_request_by_line(PLUGIN_ENCODERS, prefs->encoder.name, "get_formats")) != NULL) {
1839 set_string_pref(PREF_ENCODER, prefs->encoder.name);
1840
1841 for (i = 0; i < lives_list_length(ofmt_all); i++) {
1842 if (get_token_count((char *)lives_list_nth_data(ofmt_all, i), '|') > 2) {
1843 array = lives_strsplit((char *)lives_list_nth_data(ofmt_all, i), "|", -1);
1844
1845 if (!strcmp(array[0], HI_THEORA_FORMAT)) {
1846 lives_snprintf(prefs->encoder.of_name, 64, "%s", array[0]);
1847 lives_strfreev(array);
1848 break;
1849 }
1850 if (!strcmp(array[0], HI_MPEG_FORMAT)) {
1851 lives_snprintf(prefs->encoder.of_name, 64, "%s", array[0]);
1852 } else if (!strcmp(array[0], HI_H_MKV_FORMAT) && strcmp(prefs->encoder.of_name, HI_MPEG_FORMAT)) {
1853 lives_snprintf(prefs->encoder.of_name, 64, "%s", array[0]);
1854 } else if (!strcmp(array[0], HI_H_AVI_FORMAT) && strcmp(prefs->encoder.of_name, HI_MPEG_FORMAT) &&
1855 strcmp(prefs->encoder.of_name, HI_H_MKV_FORMAT)) {
1856 lives_snprintf(prefs->encoder.of_name, 64, "%s", array[0]);
1857 } else if (!(*prefs->encoder.of_name)) {
1858 lives_snprintf(prefs->encoder.of_name, 64, "%s", array[0]);
1859 }
1860
1861 lives_strfreev(array);
1862 }
1863 }
1864
1865 set_string_pref(PREF_OUTPUT_TYPE, prefs->encoder.of_name);
1866
1867 lives_list_free_all(&ofmt_all);
1868 }
1869 }
1870
1871 if (!(*prefs->encoder.of_name)) {
1872 get_string_pref(PREF_ENCODER, prefs->encoder.name, 64);
1873 get_string_pref(PREF_OUTPUT_TYPE, prefs->encoder.of_name, 64);
1874 }
1875
1876 future_prefs->encoder.audio_codec = prefs->encoder.audio_codec = get_int_prefd(PREF_ENCODER_ACODEC, -1);
1877 prefs->encoder.capabilities = 0;
1878 prefs->encoder.of_allowed_acodecs = AUDIO_CODEC_UNKNOWN;
1879
1880 lives_snprintf(future_prefs->encoder.name, 64, "%s", prefs->encoder.name);
1881
1882 lives_memset(future_prefs->encoder.of_restrict, 0, 1);
1883 lives_memset(prefs->encoder.of_restrict, 0, 1);
1884
1885 if (capable->has_encoder_plugins) {
1886 char **array;
1887 int numtok;
1888 LiVESList *ofmt_all, *dummy_list;
1889
1890 dummy_list = plugin_request("encoders", prefs->encoder.name, "init");
1891 lives_list_free_all(&dummy_list);
1892
1893 if (((encoder_capabilities = plugin_request(PLUGIN_ENCODERS, prefs->encoder.name, "get_capabilities")) != NULL)) {
1894 prefs->encoder.capabilities = atoi((char *)lives_list_nth_data(encoder_capabilities, 0));
1895 lives_list_free_all(&encoder_capabilities);
1896 if ((ofmt_all = plugin_request_by_line(PLUGIN_ENCODERS, prefs->encoder.name, "get_formats")) != NULL) {
1897 // get any restrictions for the current format
1898 LiVESList *list = ofmt_all;
1899 while (list) {
1900 if ((numtok = get_token_count((char *)list->data, '|')) > 2) {
1901 array = lives_strsplit((char *)list->data, "|", -1);
1902 if (!strcmp(array[0], prefs->encoder.of_name)) {
1903 if (numtok > 1) {
1904 lives_snprintf(prefs->encoder.of_desc, 128, "%s", array[1]);
1905 }
1906 lives_strfreev(array);
1907 break;
1908 }
1909 lives_strfreev(array);
1910 }
1911 list = list->next;
1912 }
1913 lives_list_free_all(&ofmt_all);
1914 }
1915 }
1916 }
1917
1918 get_utf8_pref(PREF_VID_LOAD_DIR, prefs->def_vid_load_dir, PATH_MAX);
1919 if (!(*prefs->def_vid_load_dir)) {
1920 #ifdef USE_GLIB
1921 #if GLIB_CHECK_VERSION(2, 14, 0)
1922 lives_snprintf(prefs->def_vid_load_dir, PATH_MAX, "%s", g_get_user_special_dir(G_USER_DIRECTORY_VIDEOS));
1923 #else
1924 lives_snprintf(prefs->def_vid_load_dir, PATH_MAX, "%s", capable->home_dir);
1925 #endif
1926 #endif
1927 set_utf8_pref(PREF_VID_LOAD_DIR, prefs->def_vid_load_dir);
1928 }
1929 lives_snprintf(mainw->vid_load_dir, PATH_MAX, "%s", prefs->def_vid_load_dir);
1930 ensure_isdir(mainw->vid_load_dir);
1931
1932 get_utf8_pref(PREF_VID_SAVE_DIR, prefs->def_vid_save_dir, PATH_MAX);
1933 if (!(*prefs->def_vid_save_dir)) {
1934 #ifdef USE_GLIB
1935 #if GLIB_CHECK_VERSION(2, 14, 0)
1936 lives_snprintf(prefs->def_vid_save_dir, PATH_MAX, "%s", g_get_user_special_dir(G_USER_DIRECTORY_VIDEOS));
1937 #else
1938 lives_snprintf(prefs->def_vid_save_dir, PATH_MAX, "%s", capable->home_dir);
1939 #endif
1940 #endif
1941 set_utf8_pref(PREF_VID_SAVE_DIR, prefs->def_vid_save_dir);
1942 }
1943 lives_snprintf(mainw->vid_save_dir, PATH_MAX, "%s", prefs->def_vid_save_dir);
1944 ensure_isdir(mainw->vid_save_dir);
1945
1946 lives_snprintf(mainw->vid_dl_dir, PATH_MAX, "%s", mainw->vid_save_dir);
1947
1948 get_utf8_pref(PREF_AUDIO_DIR, prefs->def_audio_dir, PATH_MAX);
1949 if (!(*prefs->def_audio_dir)) {
1950 #ifdef USE_GLIB
1951 #if GLIB_CHECK_VERSION(2, 14, 0)
1952 lives_snprintf(prefs->def_audio_dir, PATH_MAX, "%s", g_get_user_special_dir(G_USER_DIRECTORY_MUSIC));
1953 #else
1954 lives_snprintf(prefs->def_audio_dir, PATH_MAX, "%s", capable->home_dir);
1955 #endif
1956 #endif
1957 set_utf8_pref(PREF_AUDIO_DIR, prefs->def_audio_dir);
1958 }
1959 lives_snprintf(mainw->audio_dir, PATH_MAX, "%s", prefs->def_audio_dir);
1960 ensure_isdir(mainw->audio_dir);
1961
1962 get_utf8_pref(PREF_IMAGE_DIR, prefs->def_image_dir, PATH_MAX);
1963 if (!(*prefs->def_image_dir)) {
1964 #ifdef USE_GLIB
1965 #if GLIB_CHECK_VERSION(2, 14, 0)
1966 lives_snprintf(prefs->def_image_dir, PATH_MAX, "%s", g_get_user_special_dir(G_USER_DIRECTORY_PICTURES));
1967 #else
1968 lives_snprintf(prefs->def_image_dir, PATH_MAX, "%s", capable->home_dir);
1969 #endif
1970 #endif
1971 set_utf8_pref(PREF_IMAGE_DIR, prefs->def_image_dir);
1972 }
1973 lives_snprintf(mainw->image_dir, PATH_MAX, "%s", prefs->def_image_dir);
1974 ensure_isdir(mainw->image_dir);
1975
1976 get_utf8_pref(PREF_PROJ_DIR, prefs->def_proj_dir, PATH_MAX);
1977 if (!(*prefs->def_proj_dir)) {
1978 lives_snprintf(prefs->def_proj_dir, PATH_MAX, "%s", capable->home_dir);
1979 set_utf8_pref(PREF_PROJ_DIR, prefs->def_proj_dir);
1980 }
1981 lives_snprintf(mainw->proj_load_dir, PATH_MAX, "%s", prefs->def_proj_dir);
1982 ensure_isdir(mainw->proj_load_dir);
1983 lives_snprintf(mainw->proj_save_dir, PATH_MAX, "%s", mainw->proj_load_dir);
1984
1985 prefs->show_player_stats = get_boolean_prefd(PREF_SHOW_PLAYER_STATS, FALSE);
1986
1987 prefs->dl_bandwidth = get_int_prefd(PREF_DL_BANDWIDTH_K, DEF_DL_BANDWIDTH);
1988 prefs->fileselmax = get_boolean_prefd(PREF_FILESEL_MAXIMISED, TRUE);
1989
1990 prefs->midisynch = get_boolean_prefd(PREF_MIDISYNCH, FALSE);
1991 if (prefs->midisynch && !capable->has_midistartstop) {
1992 set_boolean_pref(PREF_MIDISYNCH, FALSE);
1993 prefs->midisynch = FALSE;
1994 }
1995
1996 prefs->discard_tv = FALSE;
1997
1998 // conserve disk space ?
1999 prefs->conserve_space = get_boolean_prefd(PREF_CONSERVE_SPACE, FALSE);
2000 prefs->ins_resample = get_boolean_prefd(PREF_INSERT_RESAMPLE, TRUE);
2001
2002 // need better control of audio channels first
2003 prefs->pause_during_pb = FALSE;
2004
2005 // should we always use the last directory ?
2006 // TODO - add to GUI
2007 prefs->save_directories = get_boolean_prefd(PREF_SAVE_DIRECTORIES, FALSE);
2008 prefs->antialias = get_boolean_prefd(PREF_ANTIALIAS, TRUE);
2009
2010 prefs->concat_images = get_boolean_prefd(PREF_CONCAT_IMAGES, TRUE);
2011
2012 prefs->fxdefsfile = NULL;
2013 prefs->fxsizesfile = NULL;
2014
2015 if (!needs_workdir && initial_startup_phase == 0) {
2016 disk_monitor_start(prefs->workdir);
2017 }
2018
2019 // anything that d_prints messages should go here:
2020 do_start_messages();
2021
2022 needs_free = FALSE;
2023 get_string_pref(PREF_WEED_PLUGIN_PATH, prefs->weed_plugin_path, PATH_MAX);
2024 if (!*prefs->weed_plugin_path) {
2025 weed_plugin_path = getenv("WEED_PLUGIN_PATH");
2026 if (!weed_plugin_path) {
2027 weed_plugin_path = lives_build_path(prefs->lib_dir, PLUGIN_EXEC_DIR,
2028 PLUGIN_WEED_FX_BUILTIN, NULL);
2029 needs_free = TRUE;
2030 }
2031 lives_snprintf(prefs->weed_plugin_path, PATH_MAX, "%s", weed_plugin_path);
2032 if (needs_free) lives_free(weed_plugin_path);
2033 set_string_pref(PREF_WEED_PLUGIN_PATH, prefs->weed_plugin_path);
2034 }
2035 lives_setenv("WEED_PLUGIN_PATH", prefs->weed_plugin_path);
2036
2037 #ifdef HAVE_FREI0R
2038 needs_free = FALSE;
2039 get_string_pref(PREF_FREI0R_PATH, prefs->frei0r_path, PATH_MAX);
2040 if (!*prefs->frei0r_path) {
2041 frei0r_path = getenv("FREI0R_PATH");
2042 if (!frei0r_path) {
2043 frei0r_path =
2044 lives_strdup_printf("/usr/lib/frei0r-1:/usr/local/lib/frei0r-1:%s/frei0r-1",
2045 capable->home_dir);
2046 needs_free = TRUE;
2047 }
2048 lives_snprintf(prefs->frei0r_path, PATH_MAX, "%s", frei0r_path);
2049 if (needs_free) lives_free(frei0r_path);
2050 set_string_pref(PREF_FREI0R_PATH, prefs->frei0r_path);
2051 }
2052 lives_setenv("FREI0R_PATH", prefs->frei0r_path);
2053 #endif
2054
2055 #if HAVE_LADSPA
2056 needs_free = FALSE;
2057 get_string_pref(PREF_LADSPA_PATH, prefs->ladspa_path, PATH_MAX);
2058 if (!*prefs->ladspa_path) {
2059 ladspa_path = getenv("LADSPA_PATH");
2060 if (!ladspa_path) {
2061 ladspa_path = lives_build_path(prefs->lib_dir, "ladspa", NULL);
2062 needs_free = TRUE;
2063 }
2064 lives_snprintf(prefs->ladspa_path, PATH_MAX, "%s", ladspa_path);
2065 if (needs_free) lives_free(ladspa_path);
2066 set_string_pref(PREF_LADSPA_PATH, prefs->ladspa_path);
2067 }
2068 lives_setenv("LADSPA_PATH", prefs->ladspa_path);
2069 #endif
2070
2071 #if HAVE_LIBVISUAL
2072 needs_free = FALSE;
2073 get_string_pref(PREF_LIBVISUAL_PATH, prefs->libvis_path, PATH_MAX);
2074 if (!*prefs->libvis_path) {
2075 libvis_path = getenv("VISUAL_PLUGIN_PATH");
2076 if (!libvis_path) {
2077 libvis_path = "";
2078 }
2079 lives_snprintf(prefs->libvis_path, PATH_MAX, "%s", libvis_path);
2080 set_string_pref(PREF_LIBVISUAL_PATH, prefs->libvis_path);
2081 }
2082 lives_setenv("VISUAL_PLUGIN_PATH", prefs->libvis_path);
2083 #endif
2084
2085 splash_msg(_("Loading realtime effect plugins..."), SPLASH_LEVEL_LOAD_RTE);
2086 weed_load_all();
2087
2088 // replace any multi choice effects with their delegates
2089 replace_with_delegates();
2090
2091 threaded_dialog_spin(0.);
2092 load_default_keymap();
2093 threaded_dialog_spin(0.);
2094
2095 future_prefs->audio_opts = prefs->audio_opts = get_int_prefd(PREF_AUDIO_OPTS, 3);
2096
2097 #ifdef ENABLE_JACK
2098 lives_snprintf(prefs->jack_aserver, PATH_MAX, "%s/.jackdrc", capable->home_dir);
2099 lives_snprintf(prefs->jack_tserver, PATH_MAX, "%s/.jackdrc", capable->home_dir);
2100 #endif
2101
2102 array = lives_strsplit(DEF_AUTOTRANS, "|", 3);
2103 mainw->def_trans_idx = weed_filter_highest_version(array[0], array[1], array[2], NULL);
2104 if (mainw->def_trans_idx == - 1) {
2105 msg = lives_strdup_printf(_("System default transition (%s from package %s by %s) not found."),
2106 array[1], array[0], array[2]);
2107 LIVES_WARN(msg);
2108 lives_free(msg);
2109 }
2110 lives_strfreev(array);
2111
2112 get_string_prefd(PREF_ACTIVE_AUTOTRANS, buff, 256, DEF_AUTOTRANS);
2113 if (!strcmp(buff, "none")) prefs->atrans_fx = -1;
2114 else {
2115 if (!lives_utf8_strcasecmp(buff, DEF_AUTOTRANS) || get_token_count(buff, '|') < 3)
2116 prefs->atrans_fx = mainw->def_trans_idx;
2117 else {
2118 array = lives_strsplit(buff, "|", 3);
2119 prefs->atrans_fx = weed_filter_highest_version(array[0], array[1], array[2], NULL);
2120 if (prefs->atrans_fx == - 1) {
2121 msg = lives_strdup_printf(_("User default transition (%s from package %s by %s) not found."),
2122 array[1], array[0], array[2]);
2123 LIVES_WARN(msg);
2124 lives_free(msg);
2125 }
2126 lives_strfreev(array);
2127 }
2128 }
2129
2130 mainw->recovery_file = lives_strdup_printf("%s/recovery.%d.%d.%d", prefs->workdir, lives_getuid(),
2131 lives_getgid(), capable->mainpid);
2132
2133 if (capable->has_jackd) naudp++;
2134 if (capable->has_pulse_audio) naudp++;
2135 if (capable->has_sox_play) naudp++;
2136
2137 if (naudp > 1) {
2138 if (prefs->startup_phase > 0 && prefs->startup_phase <= 4) {
2139 splash_end();
2140 if (!do_audio_choice_dialog(prefs->startup_phase)) {
2141 lives_exit(0);
2142 }
2143 if (prefs->audio_player == AUD_PLAYER_JACK) future_prefs->jack_opts = prefs->jack_opts = JACK_OPTS_START_ASERVER;
2144 else future_prefs->jack_opts = prefs->jack_opts = 0;
2145 set_int_pref(PREF_JACK_OPTS, prefs->jack_opts);
2146
2147 prefs->startup_phase = 4;
2148 set_int_pref(PREF_STARTUP_PHASE, 4);
2149 }
2150
2151 // audio startup
2152 #ifdef ENABLE_JACK
2153 if (prefs->jack_opts & JACK_OPTS_TRANSPORT_MASTER || prefs->jack_opts & JACK_OPTS_TRANSPORT_CLIENT ||
2154 prefs->jack_opts & JACK_OPTS_START_ASERVER ||
2155 prefs->jack_opts & JACK_OPTS_START_TSERVER) {
2156 // start jack transport polling
2157 if (prefs->jack_opts & JACK_OPTS_START_ASERVER) splash_msg(_("Starting jack audio server..."),
2158 SPLASH_LEVEL_LOAD_APLAYER);
2159 else {
2160 if (prefs->jack_opts & JACK_OPTS_START_TSERVER) splash_msg(_("Starting jack transport server..."),
2161 SPLASH_LEVEL_LOAD_APLAYER);
2162 else splash_msg(_("Connecting to jack server..."), SPLASH_LEVEL_LOAD_APLAYER);
2163 }
2164 if (!lives_jack_init()) {
2165 if ((prefs->jack_opts & JACK_OPTS_START_ASERVER) || (prefs->jack_opts & JACK_OPTS_START_TSERVER))
2166 do_jack_noopen_warn();
2167 else do_jack_noopen_warn3();
2168 if (prefs->startup_phase == 4) {
2169 do_jack_noopen_warn2();
2170 }
2171 future_prefs->jack_opts = 0; // jack is causing hassle, get rid of it
2172 set_int_pref(PREF_JACK_OPTS, 0);
2173 lives_exit(0);
2174 }
2175 }
2176
2177 if (prefs->audio_player == AUD_PLAYER_JACK) {
2178 jack_audio_init();
2179 jack_audio_read_init();
2180 mainw->jackd = jack_get_driver(0, TRUE);
2181 if (mainw->jackd) {
2182 if (!jack_create_client_writer(mainw->jackd)) mainw->jackd = NULL;
2183
2184 if (!mainw->jackd && prefs->startup_phase == 0) {
2185 #ifdef HAVE_PULSE_AUDIO
2186 char *otherbit = lives_strdup("\"lives -aplayer pulse\".");
2187 #else
2188 char *otherbit = lives_strdup("\"lives -aplayer sox\".");
2189 #endif
2190 char *tmp;
2191
2192 char *msg = lives_strdup_printf(
2193 _("\n\nManual start of jackd required. Please make sure jackd is running, \n"
2194 "or else change the value of <jack_opts> in %s to 16\nand restart LiVES.\n\n"
2195 "Alternatively, try to start lives with either \"lives -jackopts 16\", or "),
2196 (tmp = lives_filename_to_utf8(prefs->configfile, -1, NULL, NULL, NULL)));
2197 fprintf(stderr, "%s%s\n\n", msg, otherbit);
2198 lives_free(msg);
2199 lives_free(tmp);
2200 lives_free(otherbit);
2201 }
2202
2203 if (!mainw->jackd) {
2204 do_jack_noopen_warn3();
2205 if (prefs->startup_phase == 4) {
2206 do_jack_noopen_warn2();
2207 } else do_jack_noopen_warn4();
2208 lives_exit(0);
2209 }
2210
2211 mainw->jackd->whentostop = &mainw->whentostop;
2212 mainw->jackd->cancelled = &mainw->cancelled;
2213 mainw->jackd->in_use = FALSE;
2214 mainw->jackd->play_when_stopped = (prefs->jack_opts & JACK_OPTS_NOPLAY_WHEN_PAUSED)
2215 ? FALSE : TRUE;
2216
2217 jack_write_driver_activate(mainw->jackd);
2218
2219 if (prefs->perm_audio_reader) {
2220 // create reader connection now, if permanent
2221 jack_rec_audio_to_clip(-1, -1, RECA_EXTERNAL);
2222 // *INDENT-OFF*
2223 }}}
2224 // *INDENT-ON*
2225 #endif
2226 }
2227
2228 #ifdef HAVE_PULSE_AUDIO
2229 if (prefs->audio_player == AUD_PLAYER_PULSE) {
2230 splash_msg(_("Starting pulseaudio server..."), SPLASH_LEVEL_LOAD_APLAYER);
2231
2232 if (!mainw->foreign) {
2233 if (prefs->pa_restart && !prefs->vj_mode) {
2234 char *com = lives_strdup_printf("%s -k %s", EXEC_PULSEAUDIO, prefs->pa_start_opts);
2235 lives_system(com, TRUE);
2236 lives_free(com);
2237 }
2238 }
2239
2240 if (!lives_pulse_init(prefs->startup_phase)) {
2241 if (prefs->startup_phase == 4) {
2242 lives_exit(0);
2243 }
2244 } else {
2245 pulse_audio_init();
2246 pulse_audio_read_init();
2247 mainw->pulsed = pulse_get_driver(TRUE);
2248 mainw->pulsed->whentostop = &mainw->whentostop;
2249 mainw->pulsed->cancelled = &mainw->cancelled;
2250 mainw->pulsed->in_use = FALSE;
2251
2252 pulse_driver_activate(mainw->pulsed);
2253
2254 if (prefs->perm_audio_reader) {
2255 // create reader connection now, if permanent
2256 pulse_rec_audio_to_clip(-1, -1, RECA_EXTERNAL);
2257 // *INDENT-OFF*
2258 }}}
2259 // *INDENT-ON*
2260 #endif
2261 }
2262
2263 if (prefs->startup_phase != 0) {
2264 splash_end();
2265 set_int_pref(PREF_STARTUP_PHASE, 5);
2266 prefs->startup_phase = 5;
2267 do_startup_interface_query();
2268
2269 set_int_pref(PREF_STARTUP_PHASE, 6);
2270 prefs->startup_phase = 6;
2271
2272 if (prefs->show_disk_quota && !prefs->vj_mode) {
2273 if (!disk_monitor_running(prefs->workdir))
2274 disk_monitor_start(prefs->workdir);
2275
2276 capable->ds_used = disk_monitor_wait_result(prefs->workdir, LIVES_DEFAULT_TIMEOUT);
2277 if (capable->ds_used >= 0) {
2278 ran_ds_dlg = TRUE;
2279 run_diskspace_dialog();
2280 } else {
2281 disk_monitor_forget();
2282 if (prefs->show_disk_quota)
2283 mainw->helper_procthreads[PT_LAZY_DSUSED] = disk_monitor_start(prefs->workdir);
2284 }
2285 } else {
2286 disk_monitor_forget();
2287 }
2288
2289 set_int_pref(PREF_STARTUP_PHASE, 100); // tell backend to delete this
2290 prefs->startup_phase = 100;
2291
2292 /* if (prefs->show_splash) { */
2293 /* splash_init(); */
2294 /* } */
2295 }
2296
2297 if (strcmp(future_prefs->theme, prefs->theme)) {
2298 // we set the theme here in case it got reset to 'none'
2299 set_string_pref(PREF_GUI_THEME, prefs->theme);
2300 lives_snprintf(future_prefs->theme, 64, "%s", prefs->theme);
2301 }
2302
2303 if (mainw->vpp && mainw->vpp->get_audio_fmts) mainw->vpp->audio_codec = get_best_audio(mainw->vpp);
2304 } // end of lives_init
2305
2306
show_detected_or_not(boolean cap,const char * pname)2307 static void show_detected_or_not(boolean cap, const char *pname) {
2308 if (cap) d_print(_("%s...detected... "), pname);
2309 else d_print(_("%s...NOT DETECTED... "), pname);
2310 }
2311
2312 #define SHOWDETx(cap, exec) show_detected_or_not(capable->has_##cap, exec)
2313 #define SHOWDET(cap) SHOWDETx(cap, QUOTEME(cap))
2314 // SHOWDET(, EXEC_);
2315
do_start_messages(void)2316 static void do_start_messages(void) {
2317 int w, h;
2318 char *tmp, *endian, *fname, *phase = NULL;
2319
2320 if (prefs->vj_mode) {
2321 d_print(_("Starting in VJ MODE: Skipping most startup checks\n"));
2322 #ifndef IS_MINGW
2323 SHOWDET(wmctrl);
2324 SHOWDET(xdotool);
2325 SHOWDET(xwininfo);
2326 #endif
2327 d_print("\n\n");
2328 return;
2329 }
2330
2331 d_print(_("\nMachine details:\n"));
2332
2333 get_machine_dets();
2334 d_print(_("OS is %s %s, running on %s\n"),
2335 capable->os_name ? capable->os_name : _("unknown"),
2336 capable->os_release ? capable->os_release : "?",
2337 capable->os_hardware ? capable->os_hardware : "????");
2338
2339 d_print(_("CPU type is %s "), capable->cpu_name);
2340 d_print(P_("(%d core, ", "(%d cores, ", capable->ncpus), capable->ncpus);
2341
2342 if (capable->byte_order == LIVES_LITTLE_ENDIAN) endian = (_("little endian"));
2343 else endian = (_("big endian"));
2344 d_print(_("%d bits, %s)\n"), capable->cpu_bits, endian);
2345 lives_free(endian);
2346
2347 d_print(_("Machine name is '%s'\n"), capable->mach_name);
2348
2349 d_print(_("Number of monitors detected: %d: "), capable->nmonitors);
2350
2351 d_print(_("GUI screen size is %d X %d (usable: %d X %d); %d dpi.\nWidget scaling has been set to %.3f.\n"),
2352 mainw->mgeom[widget_opts.monitor].phys_width, mainw->mgeom[widget_opts.monitor].phys_height,
2353 GUI_SCREEN_WIDTH, GUI_SCREEN_HEIGHT,
2354 (int)mainw->mgeom[widget_opts.monitor].dpi,
2355 widget_opts.scale);
2356
2357 if (get_screen_usable_size(&w, &h)) {
2358 d_print(_("Actual usable size appears to be %d X %d\n"), w, h);
2359 }
2360
2361 get_wm_caps();
2362
2363 d_print(_("Window manager reports as \"%s\" (%s)"),
2364 capable->wm_name ? capable->wm_name : _("UNKNOWN - please patch me !"),
2365 capable->wm_caps.wm_name ? capable->wm_caps.wm_name : "unknown");
2366
2367 if (capable->wm_type && *capable->wm_type)
2368 d_print(_(", running on %s"), capable->wm_type);
2369
2370 d_print(_("; compositing is %s.\n"), capable->wm_caps.is_composited ? _("supported") : _("not supported"));
2371
2372 get_distro_dets();
2373
2374 if (capable->distro_codename) tmp = lives_strdup_printf(" (%s)", capable->distro_codename);
2375 else tmp = lives_strdup("");
2376
2377 d_print(_("Distro is %s %s %s\n"), capable->distro_name ? capable->distro_name : "?????",
2378 capable->distro_ver ? capable->distro_ver : "?????", tmp);
2379 lives_free(tmp);
2380
2381 d_print("%s", _("GUI type is: "));
2382
2383 #ifdef GUI_GTK
2384 #if GTK_CHECK_VERSION(3, 0, 0)
2385 d_print(_("GTK+ version %d.%d.%d (compiled with %d.%d.%d)"),
2386 gtk_get_major_version(), gtk_get_minor_version(),
2387 gtk_get_micro_version(),
2388 GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
2389 GTK_MICRO_VERSION
2390 );
2391 #else
2392 d_print(_("GTK+ (compiled with %d.%d.%d)"),
2393 GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION);
2394 #endif
2395 #endif
2396
2397 #ifdef LIVES_PAINTER_IS_CAIRO
2398 d_print(_(", with cairo support\n"));
2399 #else
2400 d_print(_("\n"));
2401 #endif
2402
2403 if (*capable->gui_theme_name) tmp = lives_strdup(capable->gui_theme_name);
2404 else tmp = lives_strdup_printf("lives-%s-dynamic", prefs->theme);
2405
2406 d_print("GUI theme set to %s, icon theme set to %s\n", tmp,
2407 capable->icon_theme_name);
2408
2409 lives_free(tmp);
2410
2411
2412 #ifndef RT_AUDIO
2413 d_print(_("WARNING - this version of LiVES was compiled without either\njack or pulseaudio support.\n"
2414 "Many audio features will be unavailable.\n"));
2415 # else
2416 #ifdef ENABLE_JACK
2417 d_print(_("Compiled with jack support, good !\n"));
2418 #endif
2419 #ifdef HAVE_PULSE_AUDIO
2420 d_print(_("Compiled with pulseaudio support, wonderful !\n"));
2421 #endif
2422 #endif
2423
2424 if (ign_opts.ign_configfile) {
2425 tmp = (_("set via -configfile commandline option"));
2426 } else {
2427 tmp = (_("default value"));
2428 }
2429 d_print(_("\nConfig file is %s (%s)\n"), prefs->configfile, tmp);
2430 lives_free(tmp);
2431
2432 if (!capable->mountpoint || !*capable->mountpoint)
2433 capable->mountpoint = get_mountpoint_for(prefs->workdir);
2434 if (capable->mountpoint && *capable->mountpoint) tmp = lives_strdup_printf(_(", contained in volume %s"), capable->mountpoint);
2435 else tmp = lives_strdup("");
2436
2437 d_print(_("\nWorking directory is %s%s\n"), prefs->workdir, tmp);
2438 lives_free(tmp);
2439
2440 if (mainw->has_session_workdir) {
2441 d_print(_("(Set by -workdir commandline option)\n"));
2442 } else {
2443 if (initial_startup_phase != -1) {
2444 if (!strcmp(mainw->version_hash, mainw->old_vhash)) {
2445 lives_free(old_vhash);
2446 old_vhash = lives_strdup(LiVES_VERSION);
2447 }
2448 d_print(_("(Retrieved from %s, version %s)\n"), prefs->configfile, old_vhash);
2449 } else {
2450 d_print(_("(Set by user during setup phase)\n"));
2451 }
2452 }
2453
2454 if (initial_startup_phase == 0) {
2455 if (!*mainw->old_vhash || !strcmp(mainw->old_vhash, "0")) {
2456 phase = (_("STARTUP ERROR OCCURRED - FORCED REINSTALL"));
2457 } else {
2458 if (atoi(mainw->old_vhash) < atoi(mainw->version_hash)) {
2459 phase = lives_strdup_printf(_("upgrade from version %s. Welcome !"), mainw->old_vhash);
2460 } else if (atoi(mainw->old_vhash) > atoi(mainw->version_hash)) {
2461 phase = lives_strdup_printf(_("downgrade from version %s !"), mainw->old_vhash);
2462 }
2463 }
2464 } else if (initial_startup_phase == -1) {
2465 if (!strcmp(mainw->old_vhash, "0")) {
2466 phase = (_("REINSTALL AFTER FAILED RECOVERY"));
2467 fname = lives_strdup_printf("%s.damaged", prefs->configfile);
2468 if (lives_file_test(fname, LIVES_FILE_TEST_EXISTS)) {
2469 tmp = lives_strdup_printf(_("%s; check %s for possible errors before re-running LiVES"), phase, fname);
2470 lives_free(phase);
2471 phase = tmp;
2472 }
2473 lives_free(fname);
2474 d_print("\n");
2475 } else {
2476 phase = (_("fresh install. Welcome !"));
2477 }
2478 } else {
2479 phase = lives_strdup_printf(_("continue with installation"), initial_startup_phase);
2480 }
2481 if (!phase) phase = (_("normal startup"));
2482 d_print(_("Initial startup phase was %d: (%s)\n"), initial_startup_phase, phase);
2483 lives_free(phase);
2484 lives_free(old_vhash);
2485
2486 if (initial_startup_phase == 0) {
2487 fname = lives_strdup_printf("%s.recovery.tried.succeeded", prefs->configfile);
2488 if (lives_file_test(fname, LIVES_FILE_TEST_EXISTS)) {
2489 phase = lives_strdup_printf(_("%s WAS POSSIBLY RECOVERED FROM %s.recovery\n"), prefs->configfile, prefs->configfile);
2490 d_print("%s", phase);
2491 lives_free(phase);
2492 }
2493 lives_free(fname);
2494 }
2495
2496
2497 d_print(_("\nChecking RECOMMENDED dependencies: "));
2498
2499 SHOWDET(mplayer);
2500 if (!capable->has_mplayer) {
2501 SHOWDET(mplayer2);
2502 if (!capable->has_mplayer2) {
2503 SHOWDET(mpv);
2504 }
2505 }
2506 //SHOWDET(file);
2507 SHOWDET(identify);
2508 if (!capable->has_jackd)
2509 SHOWDETx(pulse_audio, EXEC_PULSEAUDIO);
2510 SHOWDETx(sox_sox, EXEC_SOX);
2511 SHOWDET(convert);
2512 SHOWDET(composite);
2513 SHOWDET(ffprobe);
2514 SHOWDET(gzip);
2515 SHOWDET(md5sum);
2516 if (!check_for_executable(&capable->has_youtube_dl, EXEC_YOUTUBE_DL)
2517 && check_for_executable(&capable->has_youtube_dlc, EXEC_YOUTUBE_DLC)) {
2518 SHOWDETx(youtube_dlc, EXEC_YOUTUBE_DLC);
2519 } else SHOWDETx(youtube_dl, EXEC_YOUTUBE_DL);
2520
2521 d_print(_("\n\nChecking OPTIONAL dependencies: "));
2522 SHOWDET(jackd);
2523 SHOWDET(python);
2524 SHOWDET(xwininfo);
2525 SHOWDETx(cdda2wav, "cdda2wav/icedax");
2526 SHOWDET(dvgrab);
2527 SHOWDET(gdb);
2528 SHOWDETx(gconftool_2, EXEC_GCONFTOOL_2);
2529 SHOWDETx(xdg_screensaver, EXEC_XDG_SCREENSAVER);
2530
2531 d_print("\n\n");
2532 }
2533 #undef SHOWDETx
2534 #undef SHOWDET
2535
set_toolkit_theme(int prefer)2536 static void set_toolkit_theme(int prefer) {
2537 char *lname, *ic_dir;
2538 // LiVESList *list;
2539 char *tmp;
2540
2541 lives_widget_object_get(gtk_settings_get_default(), "gtk-double-click-time", &capable->dclick_time);
2542 if (capable->dclick_time <= 0) capable->dclick_time = LIVES_DEF_DCLICK_TIME;
2543
2544 lives_widget_object_get(gtk_settings_get_default(), "gtk-double-click-distance", &capable->dclick_dist);
2545 if (capable->dclick_dist <= 0) capable->dclick_dist = LIVES_DEF_DCLICK_DIST;
2546
2547 lives_widget_object_get(gtk_settings_get_default(), "gtk-font-name", &tmp);
2548
2549 /// stretch, style, weight not used
2550 lives_parse_font_string(tmp, &widget_opts.font_name, &widget_opts.font_size, NULL, NULL, NULL);
2551 lives_free(tmp);
2552
2553 lives_widget_object_get(gtk_settings_get_default(), "gtk-alternative-button-order", &widget_opts.alt_button_order);
2554
2555 lives_widget_object_get(gtk_settings_get_default(), "gtk-icon-theme-name", &capable->icon_theme_name);
2556 lives_widget_object_get(gtk_settings_get_default(), "gtk-theme-name", &capable->gui_theme_name);
2557
2558 if (prefer & LIVES_THEME_DARK) {
2559 lives_widget_object_set(gtk_settings_get_default(), "gtk-application-prefer-dark-theme", TRUE);
2560 }
2561
2562 if (prefer & USE_LIVES_THEMEING) {
2563 lives_widget_object_set(gtk_settings_get_default(), "gtk-theme-name", "");
2564
2565 lname = lives_strdup("-lives-hybrid");
2566 capable->icon_theme_name = lives_concat(capable->icon_theme_name, lname);
2567
2568 lname = lives_strdup("-lives-hybrid-dynamic");
2569 capable->gui_theme_name = lives_concat(capable->gui_theme_name, lname);
2570 }
2571
2572 capable->extra_icon_path = lives_build_path(prefs->config_datadir, STOCK_ICONS_DIR, NULL);
2573
2574 widget_opts.icon_theme = gtk_icon_theme_new();
2575
2576 gtk_icon_theme_set_custom_theme((LiVESIconTheme *)widget_opts.icon_theme, capable->icon_theme_name);
2577 gtk_icon_theme_prepend_search_path((LiVESIconTheme *)widget_opts.icon_theme, capable->extra_icon_path);
2578
2579 ic_dir = lives_build_path(prefs->prefix_dir, ICON_DIR, NULL);
2580 gtk_icon_theme_prepend_search_path((LiVESIconTheme *)widget_opts.icon_theme, ic_dir);
2581 lives_free(ic_dir);
2582
2583 capable->all_icons = gtk_icon_theme_list_icons((LiVESIconTheme *)widget_opts.icon_theme, NULL);
2584 if (0) {
2585 LiVESList *list = capable->all_icons;
2586 for (; list; list = list->next) if (!strncmp((char *)list->data, "gtk-", 4)) g_print("icon: %s\n", (char *)list->data);
2587 }
2588
2589 widget_helper_set_stock_icon_alts((LiVESIconTheme *)widget_opts.icon_theme);
2590 }
2591
2592
2593 #ifndef VALGRIND_ON
pick_custom_colours(void)2594 static void pick_custom_colours(void) {
2595 double lmin, lmax;
2596 uint8_t ncr, ncg, ncb;
2597 if (!(palette->style & STYLE_LIGHT)) {
2598 lmin = .05; lmax = .4;
2599 } else {
2600 lmin = .6; lmax = .8;
2601 }
2602 ncr = palette->menu_and_bars.red * 255.;
2603 ncg = palette->menu_and_bars.green * 255.;
2604 ncb = palette->menu_and_bars.blue * 255.;
2605 prefs->pb_quality = PB_QUALITY_HIGH;
2606 if (pick_nice_colour(palette->normal_back.red * 255., palette->normal_back.green * 255.,
2607 palette->normal_back.blue * 255., &ncr, &ncg, &ncb, 1.5, .25, .75)) {
2608 // nice1 - used for outlines
2609 palette->nice1.red = LIVES_WIDGET_COLOR_SCALE_255(ncr);
2610 palette->nice1.green = LIVES_WIDGET_COLOR_SCALE_255(ncg);
2611 palette->nice1.blue = LIVES_WIDGET_COLOR_SCALE_255(ncb);
2612 palette->nice1.alpha = 1.;
2613
2614 ncr = palette->menu_and_bars.red * 255.;
2615 ncg = palette->menu_and_bars.green * 255.;
2616 ncb = palette->menu_and_bars.blue * 255.;
2617
2618 if (pick_nice_colour(palette->nice1.red * 255., palette->nice1.green * 255.,
2619 palette->nice1.blue * 255., &ncr, &ncg, &ncb, 1., lmin, lmax)) {
2620 // nice2 - alt for menu_and_bars
2621 // insensitive colour ?
2622 palette->nice2.red = LIVES_WIDGET_COLOR_SCALE_255(ncr);
2623 palette->nice2.green = LIVES_WIDGET_COLOR_SCALE_255(ncg);
2624 palette->nice2.blue = LIVES_WIDGET_COLOR_SCALE_255(ncb);
2625 palette->nice2.alpha = 1.;
2626 mainw->pretty_colours = TRUE;
2627
2628 if (!(palette->style & STYLE_LIGHT)) {
2629 lmin = .6; lmax = .8;
2630 } else {
2631 lmin = .2; lmax = .4;
2632 }
2633 pick_nice_colour(palette->normal_fore.red * 255., palette->normal_fore.green * 255.,
2634 palette->normal_fore.blue * 255., &ncr, &ncg, &ncb, 1., lmin, lmax);
2635 // nice3 - alt for menu_and_bars_fore
2636 palette->nice3.red = LIVES_WIDGET_COLOR_SCALE_255(ncr);
2637 palette->nice3.green = LIVES_WIDGET_COLOR_SCALE_255(ncg);
2638 palette->nice3.blue = LIVES_WIDGET_COLOR_SCALE_255(ncb);
2639 palette->nice3.alpha = 1.;
2640 }
2641 }
2642 if (prefs->extra_colours && mainw->pretty_colours) {
2643 char *colref, *tmp;
2644 colref = gdk_rgba_to_string(&palette->nice1);
2645 set_css_value_direct(NULL, LIVES_WIDGET_STATE_PRELIGHT, "combobox window menu menuitem", "border-color", colref);
2646
2647 tmp = lives_strdup_printf("0 -3px %s inset", colref);
2648 set_css_value_direct(NULL, LIVES_WIDGET_STATE_CHECKED, "notebook header tabs *", "box-shadow", tmp);
2649 set_css_value_direct(NULL, LIVES_WIDGET_STATE_PRELIGHT, "menuitem", "box-shadow", tmp);
2650 set_css_value_direct(NULL, LIVES_WIDGET_STATE_PRELIGHT, "menu menuitem", "box-shadow", "none");
2651 lives_free(tmp);
2652
2653 set_css_value_direct(NULL, LIVES_WIDGET_STATE_ACTIVE, "scrollbar slider", "background-color", colref);
2654 tmp = lives_strdup_printf("0 0 0 4px %s inset", colref);
2655 set_css_value_direct(NULL, LIVES_WIDGET_STATE_PRELIGHT, "combobox window menu menuitem", "box-shadow", tmp);
2656 lives_free(tmp);
2657 lives_free(colref);
2658 }
2659 }
2660 #endif
2661
2662
set_palette_colours(boolean force_reload)2663 boolean set_palette_colours(boolean force_reload) {
2664 // force_reload should only be set when the theme changes in prefs.
2665 lives_colRGBA64_t lcol;
2666 LiVESList *cache_backup;
2667
2668 char *themedir, *themefile, *othemefile, *fname, *tmp;
2669 char *pstyle, *colref;
2670
2671 boolean is_OK = TRUE;
2672 boolean cached = FALSE;
2673
2674 lcol.alpha = 65535;
2675
2676 // set configurable colours and theme colours for the app
2677 lcol.red = lcol.green = lcol.blue = 0;
2678 lives_rgba_to_widget_color(&palette->black, &lcol);
2679
2680 lcol.red = lcol.green = lcol.blue = 65535;
2681 lives_rgba_to_widget_color(&palette->white, &lcol);
2682
2683 // salmon
2684 lcol.red = 63750;
2685 lcol.green = 32767;
2686 lcol.blue = 29070;
2687 lives_rgba_to_widget_color(&palette->light_red, &lcol);
2688
2689 // SeaGreen3
2690 lcol.red = 17219;
2691 lcol.green = 52685;
2692 lcol.blue = 32896;
2693 lives_rgba_to_widget_color(&palette->light_green, &lcol);
2694
2695 // dark red
2696 lcol.red = 30723;
2697 lcol.green = 0;
2698 lcol.blue = 0;
2699 lives_rgba_to_widget_color(&palette->dark_red, &lcol);
2700
2701 // darkorange4
2702 lcol.red = 35723;
2703 lcol.green = 17733;
2704 lcol.blue = 0;
2705 lives_rgba_to_widget_color(&palette->dark_orange, &lcol);
2706
2707 lives_widget_color_copy(&palette->fade_colour, &palette->black);
2708 lives_widget_color_copy(&palette->banner_fade_text, &palette->white);
2709
2710 palette->style = STYLE_PLAIN;
2711
2712 // defaults
2713 palette->frame_surround.red = palette->frame_surround.green
2714 = palette->frame_surround.blue = palette->frame_surround.alpha = 65535;
2715
2716 palette->audcol.blue = palette->audcol.red = 16384;
2717 palette->audcol.green = palette->audcol.alpha = 65535;
2718
2719 palette->vidcol.red = 0;
2720 palette->vidcol.green = 16384;
2721 palette->vidcol.blue = palette->vidcol.alpha = 65535;
2722
2723 palette->fxcol.red = palette->fxcol.alpha = 65535;
2724 palette->fxcol.green = palette->fxcol.blue = 0;
2725
2726 palette->mt_mark.red = palette->mt_mark.green = 0;
2727 palette->mt_mark.blue = palette->mt_mark.alpha = 65535;
2728
2729 palette->mt_timeline_reg.red = palette->mt_timeline_reg.green = palette->mt_timeline_reg.blue = 0;
2730 palette->mt_timeline_reg.alpha = 65535;
2731
2732 palette->mt_evbox.red = palette->mt_evbox.green = palette->mt_evbox.blue = palette->mt_evbox.alpha = 65535;
2733
2734 palette->ce_unsel.red = palette->ce_unsel.green = palette->ce_unsel.blue = 0;
2735 palette->ce_unsel.alpha = 65535;
2736
2737 palette->ce_sel.red = palette->ce_sel.green = palette->ce_sel.blue = palette->ce_sel.alpha = 65535;
2738
2739 lives_widget_color_copy(&palette->mt_timecode_bg, &palette->black);
2740 lives_widget_color_copy(&palette->mt_timecode_fg, &palette->light_green);
2741
2742 lcol.red = 0;
2743
2744 // if theme is not "none" and we dont find stuff in prefs then we must reload
2745 if (!lives_ascii_strcasecmp(future_prefs->theme, LIVES_THEME_NONE)) {
2746 set_toolkit_theme(0);
2747 return TRUE;
2748 } else if (!get_colour_pref(THEME_DETAIL_STYLE, &lcol)) {
2749 force_reload = TRUE;
2750 } else {
2751 // pull our colours from normal prefs
2752 palette->style = lcol.red;
2753 if (!(palette->style & STYLE_LIGHT)) {
2754 if (mainw->sep_image) lives_widget_set_opacity(mainw->sep_image, 0.8);
2755 if (mainw->multitrack && mainw->multitrack->sep_image)
2756 lives_widget_set_opacity(mainw->multitrack->sep_image, 0.8);
2757 palette->ce_unsel.red = palette->ce_unsel.green = palette->ce_unsel.blue = 6554;
2758 set_toolkit_theme(USE_LIVES_THEMEING | LIVES_THEME_DARK | LIVES_THEME_COMPACT);
2759 } else {
2760 set_toolkit_theme(USE_LIVES_THEMEING | LIVES_THEME_COMPACT);
2761 palette->ce_unsel.red = palette->ce_unsel.green = palette->ce_unsel.blue = 0;
2762 if (mainw->sep_image) lives_widget_set_opacity(mainw->sep_image, 0.4);
2763 if (mainw->multitrack && mainw->multitrack->sep_image)
2764 lives_widget_set_opacity(mainw->multitrack->sep_image, 0.4);
2765 }
2766 get_string_pref(THEME_DETAIL_SEPWIN_IMAGE, mainw->sepimg_path, PATH_MAX);
2767 get_string_pref(THEME_DETAIL_FRAMEBLANK_IMAGE, mainw->frameblank_path, PATH_MAX);
2768
2769 get_colour_pref(THEME_DETAIL_NORMAL_FORE, &lcol);
2770 lives_rgba_to_widget_color(&palette->normal_fore, &lcol);
2771
2772 get_colour_pref(THEME_DETAIL_NORMAL_BACK, &lcol);
2773 lives_rgba_to_widget_color(&palette->normal_back, &lcol);
2774
2775 get_colour_pref(THEME_DETAIL_ALT_FORE, &lcol);
2776 lives_rgba_to_widget_color(&palette->menu_and_bars_fore, &lcol);
2777
2778 get_colour_pref(THEME_DETAIL_ALT_BACK, &lcol);
2779 lives_rgba_to_widget_color(&palette->menu_and_bars, &lcol);
2780
2781 get_colour_pref(THEME_DETAIL_INFO_TEXT, &lcol);
2782 lives_rgba_to_widget_color(&palette->info_text, &lcol);
2783
2784 get_colour_pref(THEME_DETAIL_INFO_BASE, &lcol);
2785 lives_rgba_to_widget_color(&palette->info_base, &lcol);
2786
2787 // extended colours
2788
2789 get_colour_pref(THEME_DETAIL_MT_TCFG, &lcol);
2790 lives_rgba_to_widget_color(&palette->mt_timecode_fg, &lcol);
2791
2792 get_colour_pref(THEME_DETAIL_MT_TCBG, &lcol);
2793 lives_rgba_to_widget_color(&palette->mt_timecode_bg, &lcol);
2794
2795 get_colour_pref(THEME_DETAIL_AUDCOL, &palette->audcol);
2796 get_colour_pref(THEME_DETAIL_VIDCOL, &palette->vidcol);
2797 get_colour_pref(THEME_DETAIL_FXCOL, &palette->fxcol);
2798
2799 get_colour_pref(THEME_DETAIL_MT_TLREG, &palette->mt_timeline_reg);
2800 get_colour_pref(THEME_DETAIL_MT_MARK, &palette->mt_mark);
2801 get_colour_pref(THEME_DETAIL_MT_EVBOX, &palette->mt_evbox);
2802
2803 get_colour_pref(THEME_DETAIL_FRAME_SURROUND, &palette->frame_surround);
2804
2805 get_colour_pref(THEME_DETAIL_CE_SEL, &palette->ce_sel);
2806 get_colour_pref(THEME_DETAIL_CE_UNSEL, &palette->ce_unsel);
2807 }
2808
2809 if (force_reload) {
2810 // check if theme is custom:
2811 themedir = lives_build_path(prefs->config_datadir, PLUGIN_THEMES, prefs->theme, NULL);
2812 if (!lives_file_test(themedir, LIVES_FILE_TEST_IS_DIR)) {
2813 lives_free(themedir);
2814 // if not custom, check if builtin
2815 themedir = lives_build_path(prefs->prefix_dir, THEME_DIR, prefs->theme, NULL);
2816 if (!lives_file_test(themedir, LIVES_FILE_TEST_IS_DIR)) {
2817 if (!mainw->is_ready) {
2818 lives_free(themedir);
2819 set_toolkit_theme(0);
2820 return FALSE;
2821 }
2822 is_OK = FALSE;
2823 }
2824 }
2825
2826 fname = lives_strdup_printf("%s.%s", THEME_SEP_IMG_LITERAL, LIVES_FILE_EXT_JPG);
2827 tmp = lives_build_filename(themedir, fname, NULL);
2828 lives_free(fname);
2829 if (lives_file_test(tmp, LIVES_FILE_TEST_EXISTS)) {
2830 lives_snprintf(mainw->sepimg_path, PATH_MAX, "%s", tmp);
2831 lives_free(tmp);
2832 } else {
2833 fname = lives_strdup_printf("%s.%s", THEME_SEP_IMG_LITERAL, LIVES_FILE_EXT_PNG);
2834 lives_free(tmp);
2835 tmp = lives_build_filename(themedir, fname, NULL);
2836 lives_free(fname);
2837 lives_snprintf(mainw->sepimg_path, PATH_MAX, "%s", tmp);
2838 lives_free(tmp);
2839 }
2840
2841 fname = lives_strdup_printf("%s.%s", THEME_FRAME_IMG_LITERAL, LIVES_FILE_EXT_JPG);
2842 tmp = lives_build_filename(themedir, fname, NULL);
2843 lives_free(fname);
2844 if (lives_file_test(tmp, LIVES_FILE_TEST_EXISTS)) {
2845 lives_snprintf(mainw->frameblank_path, PATH_MAX, "%s", tmp);
2846 lives_free(tmp);
2847 } else {
2848 fname = lives_strdup_printf("%s.%s", THEME_FRAME_IMG_LITERAL, LIVES_FILE_EXT_PNG);
2849 tmp = lives_build_filename(themedir, fname, NULL);
2850 lives_free(fname);
2851 lives_snprintf(mainw->frameblank_path, PATH_MAX, "%s", tmp);
2852 lives_free(tmp);
2853 }
2854
2855 // load from file
2856 themefile = lives_build_filename(themedir, THEME_HEADER, NULL);
2857 #ifdef GUI_GTK
2858 #if !GTK_CHECK_VERSION(3, 0, 0)
2859 lives_free(themefile);
2860 themefile = lives_build_filename(themedir, THEME_HEADER_2, NULL);
2861 #endif
2862 #endif
2863
2864 if (!lives_file_test(themefile, LIVES_FILE_TEST_EXISTS)) {
2865 lives_free(themefile);
2866 themefile = lives_build_filename(themedir, THEME_HEADER_2, NULL);
2867 #ifdef GUI_GTK
2868 #if !GTK_CHECK_VERSION(3, 0, 0)
2869 lives_free(themefile);
2870 themefile = lives_build_filename(themedir, THEME_HEADER, NULL);
2871 #endif
2872 #endif
2873 if (!lives_file_test(themefile, LIVES_FILE_TEST_EXISTS)) {
2874 is_OK = FALSE;
2875 }
2876 }
2877
2878 lives_free(themedir);
2879
2880 // cache the themefile
2881 othemefile = themefile;
2882 cache_backup = mainw->gen_cache;
2883 if (!(mainw->gen_cache = cache_file_contents(themefile))) themefile = NULL;
2884 else cached = TRUE;
2885
2886 /// get mandatory details
2887
2888 if (!is_OK || !(pstyle = get_val_from_cached_list(THEME_DETAIL_STYLE, 8, mainw->gen_cache))) {
2889 if (pstyle) lives_free(pstyle);
2890 is_OK = FALSE;
2891 set_toolkit_theme(0);
2892 } else {
2893 palette->style = atoi(pstyle);
2894 lives_free(pstyle);
2895 if (!(palette->style & STYLE_LIGHT)) {
2896 palette->ce_unsel.red = palette->ce_unsel.green = palette->ce_unsel.blue = 6554;
2897 if (mainw->sep_image) lives_widget_set_opacity(mainw->sep_image, 0.8);
2898 if (mainw->multitrack && mainw->multitrack->sep_image)
2899 lives_widget_set_opacity(mainw->multitrack->sep_image, 0.8);
2900 set_toolkit_theme(USE_LIVES_THEMEING | LIVES_THEME_DARK | LIVES_THEME_COMPACT);
2901 } else {
2902 if (mainw->sep_image) lives_widget_set_opacity(mainw->sep_image, 0.4);
2903 if (mainw->multitrack && mainw->multitrack->sep_image)
2904 lives_widget_set_opacity(mainw->multitrack->sep_image, 0.4);
2905 set_toolkit_theme(USE_LIVES_THEMEING | LIVES_THEME_COMPACT);
2906 palette->ce_unsel.red = palette->ce_unsel.green = palette->ce_unsel.blue = 0;
2907 }
2908 }
2909
2910 if (!is_OK || !get_theme_colour_pref(THEME_DETAIL_NORMAL_FORE, &lcol)) {
2911 is_OK = FALSE;
2912 } else lives_rgba_to_widget_color(&palette->normal_fore, &lcol);
2913
2914 if (!is_OK || !get_theme_colour_pref(THEME_DETAIL_NORMAL_BACK, &lcol)) {
2915 is_OK = FALSE;
2916 } else lives_rgba_to_widget_color(&palette->normal_back, &lcol);
2917
2918 if (!is_OK || !get_theme_colour_pref(THEME_DETAIL_ALT_FORE, &lcol)) {
2919 is_OK = FALSE;
2920 } else lives_rgba_to_widget_color(&palette->menu_and_bars_fore, &lcol);
2921
2922 if (!is_OK || !get_theme_colour_pref(THEME_DETAIL_ALT_BACK, &lcol)) {
2923 is_OK = FALSE;
2924 } else lives_rgba_to_widget_color(&palette->menu_and_bars, &lcol);
2925
2926 if (!is_OK || !get_theme_colour_pref(THEME_DETAIL_INFO_TEXT, &lcol)) {
2927 is_OK = FALSE;
2928 } else lives_rgba_to_widget_color(&palette->info_text, &lcol);
2929
2930 if (!is_OK || !get_theme_colour_pref(THEME_DETAIL_INFO_BASE, &lcol)) {
2931 is_OK = FALSE;
2932 } else lives_rgba_to_widget_color(&palette->info_base, &lcol);
2933
2934 if (!is_OK) {
2935 if (cached) {
2936 lives_list_free_all(&mainw->gen_cache);
2937 mainw->gen_cache = cache_backup;
2938 themefile = othemefile;
2939 }
2940 if (mainw->is_ready) do_bad_theme_error(themefile);
2941 lives_free(themefile);
2942 return FALSE;
2943 }
2944
2945 // get optional elements
2946 if (get_theme_colour_pref(THEME_DETAIL_MT_TCFG, &lcol)) {
2947 lives_rgba_to_widget_color(&palette->mt_timecode_fg, &lcol);
2948 }
2949
2950 if (get_theme_colour_pref(THEME_DETAIL_MT_TCBG, &lcol)) {
2951 lives_rgba_to_widget_color(&palette->mt_timecode_bg, &lcol);
2952 }
2953
2954 get_theme_colour_pref(THEME_DETAIL_AUDCOL, &palette->audcol);
2955 get_theme_colour_pref(THEME_DETAIL_VIDCOL, &palette->vidcol);
2956 get_theme_colour_pref(THEME_DETAIL_FXCOL, &palette->fxcol);
2957
2958 get_theme_colour_pref(THEME_DETAIL_MT_TLREG, &palette->mt_timeline_reg);
2959 get_theme_colour_pref(THEME_DETAIL_MT_MARK, &palette->mt_mark);
2960 get_theme_colour_pref(THEME_DETAIL_MT_EVBOX, &palette->mt_evbox);
2961
2962 get_theme_colour_pref(THEME_DETAIL_FRAME_SURROUND, &palette->frame_surround);
2963
2964 get_theme_colour_pref(THEME_DETAIL_CE_SEL, &palette->ce_sel);
2965 get_theme_colour_pref(THEME_DETAIL_CE_UNSEL, &palette->ce_unsel);
2966
2967 if (cached) {
2968 lives_list_free_all(&mainw->gen_cache);
2969 mainw->gen_cache = cache_backup;
2970 themefile = othemefile;
2971 }
2972
2973 lives_free(themefile);
2974
2975 // set details in prefs
2976 set_palette_prefs(force_reload);
2977 }
2978
2979 #ifndef VALGRIND_ON
2980 /// generate some complementary colours
2981 // still experimenting...some values may need tweaking
2982 // suggested uses for each colour in the process of being defined
2983 // TODO - run a bg thread until we create GUI
2984 if (!prefs->vj_mode) {
2985 /// create thread to pick custom colours
2986 lives_proc_thread_create(LIVES_THRDATTR_NONE, (lives_funcptr_t)pick_custom_colours, 0, "");
2987 }
2988 #endif
2989 /// set global values
2990
2991 set_css_value_direct(NULL, LIVES_WIDGET_STATE_PRELIGHT, "toolbutton *", "background-image", "none");
2992
2993 colref = gdk_rgba_to_string(&palette->normal_back);
2994 set_css_value_direct(NULL, LIVES_WIDGET_STATE_NORMAL, "combobox window menu", "background-color", colref);
2995 lives_free(colref);
2996 colref = gdk_rgba_to_string(&palette->normal_fore);
2997 set_css_value_direct(NULL, LIVES_WIDGET_STATE_NORMAL, "combobox window menu", "color", colref);
2998 lives_free(colref);
2999
3000 colref = gdk_rgba_to_string(&palette->menu_and_bars);
3001 set_css_value_direct(NULL, LIVES_WIDGET_STATE_NORMAL, "scrollbar", "background-color", colref);
3002 set_css_value_direct(NULL, LIVES_WIDGET_STATE_PRELIGHT, "combobox window menu menuitem", "background-color", colref);
3003 lives_free(colref);
3004 colref = gdk_rgba_to_string(&palette->menu_and_bars_fore);
3005 set_css_value_direct(NULL, LIVES_WIDGET_STATE_PRELIGHT, "combobox window menu menuitem", "color", colref);
3006 lives_free(colref);
3007
3008 set_css_value_direct(NULL, LIVES_WIDGET_STATE_NORMAL, "combobox window menu menuitem", "border-width", "2px");
3009
3010 tmp = lives_strdup_printf("%dpx", ((widget_opts.css_min_height * 3 + 3) >> 2) << 1);
3011 set_css_value_direct(NULL, LIVES_WIDGET_STATE_NORMAL, "combobox window menu menuitem", "min-height", tmp);
3012 lives_free(tmp);
3013 colref = gdk_rgba_to_string(&palette->menu_and_bars_fore);
3014 set_css_value_direct(NULL, LIVES_WIDGET_STATE_NORMAL, "scrollbar", "color", colref);
3015 lives_free(colref);
3016
3017 //set_css_value_direct(NULL, LIVES_WIDGET_STATE_INSENSITIVE, "spinbutton button", "opacity", "0.5");
3018
3019 return TRUE;
3020 }
3021
3022
get_capabilities(void)3023 capability *get_capabilities(void) {
3024 // get capabilities of backend system
3025 char **array;
3026 char *msg, *tmp;
3027
3028 char buffer[PATH_MAX * 4];
3029 char command[PATH_MAX * 4];
3030 char dir[PATH_MAX];
3031 int numtok;
3032 size_t xs;
3033
3034 #ifdef IS_DARWIN
3035 processor_info_array_t processorInfo;
3036 mach_msg_type_number_t numProcessorInfo;
3037 natural_t numProcessors = 0U;
3038 kern_return_t kerr;
3039 #endif
3040
3041 buffer[0] = '\0';
3042 command[0] = '\0';
3043
3044 if (!check_for_executable(&capable->has_perl, EXEC_PERL)) return capable;
3045
3046 // this is _compile time_ bits, not runtime bits
3047 capable->cpu_bits = (sizeof(void *)) * 8;
3048
3049 capable->ds_used = capable->ds_free = capable->ds_tot = -1;
3050
3051 capable->mainpid = lives_getpid();
3052
3053 get_location("cp", capable->cp_cmd, PATH_MAX);
3054 capable->sysbindir = get_dir(capable->cp_cmd);
3055
3056 get_location("mv", capable->mv_cmd, PATH_MAX);
3057 get_location("ln", capable->ln_cmd, PATH_MAX);
3058 get_location("chmod", capable->chmod_cmd, PATH_MAX);
3059 get_location("cat", capable->cat_cmd, PATH_MAX);
3060 get_location("echo", capable->echo_cmd, PATH_MAX);
3061 get_location("eject", capable->eject_cmd, PATH_MAX);
3062
3063 capable->wm_name = NULL;
3064 capable->wm_type = NULL;
3065
3066 capable->python_version = 0;
3067 capable->xstdout = STDOUT_FILENO;
3068
3069 lives_snprintf(capable->backend_path, PATH_MAX, "%s", (tmp = lives_find_program_in_path(BACKEND_NAME)));
3070 lives_free(tmp);
3071 if (!*capable->backend_path) return capable;
3072 capable->has_smogrify = PRESENT;
3073
3074 retry_configfile:
3075
3076 if (!mainw->has_session_workdir) {
3077 lives_snprintf(prefs->backend, PATH_MAX * 4, "%s -s \"%s\" -CONFIGFILE=\"%s\" --", EXEC_PERL, capable->backend_path,
3078 prefs->configfile);
3079 lives_snprintf(prefs->backend_sync, PATH_MAX * 4, "%s", prefs->backend);
3080 } else {
3081 // if the user passed a -workdir option, we will use that, and the backend won't attempt to find an existing value
3082 lives_snprintf(prefs->backend, PATH_MAX * 4, "%s -s \"%s\" -WORKDIR=\"%s\" -CONFIGFILE=\"%s\" --", EXEC_PERL,
3083 capable->backend_path, prefs->workdir, prefs->configfile);
3084 lives_snprintf(prefs->backend_sync, PATH_MAX * 4, "%s", prefs->backend);
3085 }
3086
3087 if (!newconfigfile) {
3088 capable->has_smogrify = UNCHECKED;
3089 lives_snprintf(command, PATH_MAX * 4, "%s version", prefs->backend_sync);
3090
3091 lives_popen(command, TRUE, buffer, PATH_MAX * 4);
3092
3093 if (THREADVAR(com_failed)) {
3094 return capable;
3095 }
3096
3097 xs = lives_strlen(buffer);
3098 if (xs < 5) return capable;
3099
3100 lives_chomp(buffer);
3101 numtok = get_token_count(buffer, ' ') ;
3102 if (numtok < 2) return capable;
3103
3104 array = lives_strsplit(buffer, " ", numtok);
3105 if (strcmp(array[0], "smogrify")) {
3106 lives_strfreev(array);
3107 return capable;
3108 }
3109
3110 capable->has_smogrify = PRESENT;
3111 capable->smog_version_correct = FALSE;
3112
3113 if (strcmp(array[1], LiVES_VERSION)) {
3114 msg = lives_strdup_printf("Version mismatch: smogrify = %s, LiVES = %s\n", array[1], LiVES_VERSION);
3115 LIVES_ERROR(msg);
3116 lives_free(msg);
3117 lives_strfreev(array);
3118 return capable;
3119 }
3120
3121 lives_strfreev(array);
3122 capable->smog_version_correct = TRUE;
3123 }
3124
3125 if (!newconfigfile)
3126 lives_snprintf(command, PATH_MAX * 4, "%s report -", prefs->backend_sync);
3127 else
3128 lives_snprintf(command, PATH_MAX * 4, "%s report", prefs->backend_sync);
3129
3130 // check_settings:
3131
3132 capable->has_smogrify = UNCHECKED;
3133 lives_popen(command, TRUE, buffer, PATH_MAX * 4);
3134 if (THREADVAR(com_failed) || lives_strlen(buffer) < 6) return capable;
3135 capable->has_smogrify = PRESENT;
3136
3137 numtok = get_token_count(buffer, '|');
3138 if (numtok < 2) {
3139 capable->smog_version_correct = FALSE;
3140 return capable;
3141 }
3142
3143 array = lives_strsplit(buffer, "|", numtok);
3144
3145 if (!newconfigfile) {
3146 if (!strcmp(array[0], "smogrify::error")) {
3147 LIVES_ERROR(buffer);
3148 if (!strcmp(array[1], "config_get")) {
3149 lives_strfreev(array);
3150 capable->can_read_from_config = FALSE;
3151 return capable;
3152 }
3153 if (!strcmp(array[1], "config_set_new")) {
3154 lives_strfreev(array);
3155 capable->can_write_to_config_new = FALSE;
3156 return capable;
3157 }
3158 if (!strcmp(array[1], "config_set_rec")) {
3159 lives_strfreev(array);
3160 capable->can_write_to_config_backup = FALSE;
3161 return capable;
3162 }
3163 if (!strcmp(array[1], "config_set")) {
3164 lives_strfreev(array);
3165 capable->can_write_to_config = FALSE;
3166 return capable;
3167 }
3168 // other unspecified error
3169 mainw->error = TRUE;
3170 lives_snprintf(mainw->msg, MAINW_MSG_SIZE, "%s", buff);
3171 return capable;
3172 }
3173 }
3174
3175 // the startup phase
3176 // this is 0 for normal operation
3177 // -1 for a fresh install
3178 // after this the value goes to 1....n
3179 // then finally gets set to 100, which instructs the backend to remove this preference, and return 0
3180 initial_startup_phase = prefs->startup_phase = atoi(array[2]);
3181
3182 if (!newconfigfile) {
3183 if (initial_startup_phase == -1 && !ign_opts.ign_configfile) {
3184 /// if no configfile:
3185 /// check for migration:
3186 /// if $HOME/.lives exists, get the verhash from it
3187 char *oldconfig = lives_build_filename(capable->home_dir, LIVES_DEF_CONFIG_FILE_OLD, NULL);
3188 if (lives_file_test(oldconfig, LIVES_FILE_TEST_EXISTS)) {
3189 lives_strfreev(array);
3190 newconfigfile = lives_strdup(prefs->configfile);
3191 lives_snprintf(prefs->configfile, PATH_MAX, "%s", oldconfig);
3192 lives_free(oldconfig);
3193 goto retry_configfile;
3194 }
3195 lives_free(oldconfig);
3196 }
3197 }
3198
3199 // hash of last version used,
3200 // or 0 if rcfile existed, but we couldn't extract a version
3201 if (numtok > 3) {
3202 mainw->old_vhash = lives_strdup(array[3]);
3203 }
3204
3205 if (!mainw->old_vhash) {
3206 old_vhash = lives_strdup("NULL");
3207 } else if (!*mainw->old_vhash) {
3208 old_vhash = lives_strdup("not present");
3209 } else if (!strcmp(mainw->old_vhash, "0")) {
3210 old_vhash = lives_strdup("unrecoverable");
3211 } else {
3212 old_vhash = lives_strdup(mainw->old_vhash);
3213
3214 if (newconfigfile && *newconfigfile) {
3215 /// if < 3200000, migrate (copy) .lives and .lives-dir
3216 /// this should only happen once, since version will now have been updated in .lives
3217 /// after startup, we will offer to remove the old files
3218 migrate_config(old_vhash, newconfigfile);
3219 }
3220 }
3221
3222 if (newconfigfile && *newconfigfile) {
3223 lives_strfreev(array);
3224 lives_snprintf(prefs->configfile, PATH_MAX, "%s", newconfigfile);
3225 lives_free(newconfigfile);
3226 newconfigfile = lives_strdup("");
3227 lives_free(old_vhash);
3228 lives_free(mainw->old_vhash);
3229 goto retry_configfile;
3230 }
3231
3232 lives_snprintf(dir, PATH_MAX, "%s", array[1]);
3233
3234 if (!mainw->has_session_workdir) {
3235 size_t dirlen = lives_strlen(dir);
3236 boolean dir_valid = TRUE;
3237
3238 if (dirlen && strncmp(dir, "(null)", 6)) {
3239 if (!mainw->old_vhash || !*mainw->old_vhash || !strcmp(mainw->old_vhash, "0")) {
3240 msg = lives_strdup_printf("The backend found a workdir (%s), but claimed old version was %s !", dir, old_vhash);
3241 LIVES_WARN(msg);
3242 lives_free(msg);
3243 }
3244
3245 if (dirlen < PATH_MAX - MAX_SET_NAME_LEN * 2) {
3246 ensure_isdir(dir);
3247
3248 if (dirlen >= PATH_MAX - MAX_SET_NAME_LEN * 2) {
3249 dir_toolong_error(dir, (tmp = (_("working directory"))), PATH_MAX - MAX_SET_NAME_LEN * 2, TRUE);
3250 lives_free(tmp);
3251 dir_valid = FALSE;
3252 }
3253
3254 if (!lives_make_writeable_dir(dir)) {
3255 do_dir_perm_error(dir, FALSE);
3256 dir_valid = FALSE;
3257 }
3258 }
3259
3260 if (dir_valid) {
3261 lives_snprintf(prefs->workdir, PATH_MAX, "%s", dir);
3262 lives_snprintf(prefs->backend, PATH_MAX * 4, "%s -s \"%s\" -WORKDIR=\"%s\" -CONFIGFILE=\"%s\" --", EXEC_PERL,
3263 capable->backend_path, prefs->workdir, prefs->configfile);
3264 lives_snprintf(prefs->backend_sync, PATH_MAX * 4, "%s", prefs->backend);
3265
3266 set_string_pref_priority(PREF_WORKING_DIR, prefs->workdir);
3267
3268 // for backwards compatibility only
3269 set_string_pref(PREF_WORKING_DIR_OLD, prefs->workdir);
3270 } else {
3271 needs_workdir = TRUE;
3272 prefs->startup_phase = -1;
3273 }
3274 } else {
3275 if (prefs->startup_phase != -1) {
3276 msg = lives_strdup_printf("The backend found no workdir, but set startup_phase to %d !\n%s",
3277 prefs->startup_phase, prefs->workdir);
3278 LIVES_ERROR(msg);
3279 lives_free(msg);
3280 }
3281 needs_workdir = TRUE;
3282 prefs->startup_phase = -1;
3283 }
3284
3285 if (*mainw->old_vhash && strcmp(mainw->old_vhash, "0")) {
3286 if (atoi(mainw->old_vhash) < atoi(mainw->version_hash)) {
3287 if (prefs->startup_phase == 0) {
3288 msg = get_upd_msg();
3289 lives_snprintf(capable->startup_msg, 1024, "%s", msg);
3290 lives_free(msg);
3291 if (numtok > 4 && *array[4]) {
3292 lives_strappend(capable->startup_msg, 1024, array[4]);
3293 // *INDENT-OFF*
3294 }}}}}
3295 // *INDENT-ON*
3296
3297 if ((prefs->startup_phase == 1 || prefs->startup_phase == -1)) {
3298 needs_workdir = TRUE;
3299 }
3300
3301 lives_strfreev(array);
3302
3303 ///////////////////////////////////////////////////////
3304
3305 check_for_executable(&capable->has_md5sum, EXEC_MD5SUM);
3306 check_for_executable(&capable->has_du, EXEC_DU);
3307 check_for_executable(&capable->has_ffprobe, EXEC_FFPROBE);
3308 check_for_executable(&capable->has_sox_play, EXEC_PLAY);
3309
3310 if (!check_for_executable(&capable->has_youtube_dl, EXEC_YOUTUBE_DL)) {
3311 check_for_executable(&capable->has_youtube_dlc, EXEC_YOUTUBE_DLC);
3312 }
3313 check_for_executable(&capable->has_sox_sox, EXEC_SOX);
3314 check_for_executable(&capable->has_dvgrab, EXEC_DVGRAB);
3315
3316 if (!check_for_executable(&capable->has_cdda2wav, EXEC_CDDA2WAV)) {
3317 check_for_executable(&capable->has_icedax, EXEC_ICEDAX);
3318 }
3319
3320 check_for_executable(&capable->has_jackd, EXEC_JACKD);
3321 check_for_executable(&capable->has_pulse_audio, EXEC_PULSEAUDIO);
3322
3323 if (check_for_executable(&capable->has_python, EXEC_PYTHON)) {
3324 capable->python_version = get_version_hash(EXEC_PYTHON " -V 2>&1", " ", 1);
3325 }
3326
3327 check_for_executable(&capable->has_xwininfo, EXEC_XWININFO);
3328 check_for_executable(&capable->has_gconftool_2, EXEC_GCONFTOOL_2);
3329 check_for_executable(&capable->has_xdg_screensaver, EXEC_XDG_SCREENSAVER);
3330
3331 if (check_for_executable(NULL, EXEC_MIDISTART)) {
3332 check_for_executable(&capable->has_midistartstop, EXEC_MIDISTOP);
3333 }
3334
3335 capable->ncpus = get_num_cpus();
3336 if (capable->ncpus == 0) capable->ncpus = 1;
3337
3338 return capable;
3339 }
3340
3341
print_opthelp(void)3342 void print_opthelp(void) {
3343 char *tmp;
3344 print_notice();
3345
3346 lives_printerr(_("\nStartup syntax is: %s [OPTS] [filename [start_time] [frames]]\n"), capable->myname);
3347 fprintf(stderr, "%s", _("Where: filename is the name of a media file or backup file to import\n"));
3348 fprintf(stderr, "%s", _("start_time : filename start time in seconds\n"));
3349 fprintf(stderr, "%s", _("frames : maximum number of frames to open\n"));
3350 fprintf(stderr, "%s", "\n");
3351 fprintf(stderr, "%s", _("OPTS can be:\n"));
3352 fprintf(stderr, "%s", _("-help | --help \t\t\t: print this help text on stderr and exit\n"));
3353 fprintf(stderr, "%s", _("-version | --version\t\t: print the LiVES version on stderr and exit\n"));
3354 fprintf(stderr, "%s", _("-workdir <workdir>\t\t: specify the working directory for the session, "
3355 "overriding any value set in preferences\n"));
3356 fprintf(stderr, "%s", _("\t\t\t\t\t(disables any disk quota checking)"));
3357 fprintf(stderr, "%s", _("-configfile <path_to_file>\t: override the default configuration file for the session\n"));
3358 tmp = lives_build_filename(capable->home_dir, LIVES_DEF_CONFIG_DIR, "lives", LIVES_DEF_CONFIG_FILE, NULL);
3359 fprintf(stderr, _("\t\t\t\t\t(default is %s)\n"), tmp);
3360 lives_free(tmp);
3361
3362 tmp = lives_build_path(capable->home_dir, LOCAL_HOME_DIR, LIVES_DEF_CONFIG_DATADIR, NULL);
3363 fprintf(stderr, "%s", _("-configdatadir <dir>\t\t: override the default configuration data directory for the session\n"));
3364 fprintf(stderr, _("\t\t\t\t\t(default is %s\n"), tmp);
3365 lives_free(tmp);
3366
3367 fprintf(stderr, "%s", _("-dscrit <bytes>\t\t\t: temporarily sets the free disk space critical level for workdir to <bytes>\n"));
3368 fprintf(stderr, "%s", _("\t\t\t\t\t(intended to allow correction of erroneous values within the app; "
3369 "<= 0 disables checks)\n"));
3370 fprintf(stderr, "%s", _("-set <setname>\t\t\t: autoload clip set <setname>\n"));
3371 fprintf(stderr, "%s", _("-noset\t\t\t\t: do not reload any clip set on startup (overrides -set)\n"));
3372 fprintf(stderr, "%s", _("-layout <layout_name>\t\t: autoload multitrack layout <layout_name> (if successful, "
3373 "overrides -startup-ce)\n"));
3374 fprintf(stderr, "%s", _("-nolayout\t\t\t: do not reload any multitrack layout on startup (overrides -layout)\n"));
3375 fprintf(stderr, "%s", _("-norecover\t\t\t: force non-loading of crash recovery files (overrides -recover / -autorecover)\n"));
3376 fprintf(stderr, "%s",
3377 _("-recover | -autorecover\t\t: force reloading of any crash recovery files (may override -noset and -nolayout)\n"));
3378 fprintf(stderr, "%s", _("-nogui\t\t\t\t: do not show the gui (still shows the play window when active)\n"));
3379 fprintf(stderr, "%s", _("-nosplash\t\t\t: do not show the splash window\n"));
3380 fprintf(stderr, "%s",
3381 _("-noplaywin\t\t\t: do not show the play window (still shows the internal player; intended for remote streaming)\n"));
3382 fprintf(stderr, "%s",
3383 _("-noninteractive\t\t\t: disable menu interactivity (intended for scripting applications, e.g liblives)\n"));
3384 fprintf(stderr, "%s", _("-startup-ce\t\t\t: start in clip editor mode (overrides -startup-mt)\n"));
3385 fprintf(stderr, "%s", _("-startup-mt\t\t\t: start in multitrack mode\n"));
3386 fprintf(stderr, "%s", _("-vjmode\t\t\t\t: start in VJ mode (implicitly sets -startup-ce -autorecover "
3387 "-nolayout -asource external)\n"));
3388 fprintf(stderr, "%s",
3389 _("-fxmodesmax <n>\t\t\t: allow <n> modes per effect key (overrides any value set in preferences; minimum is 1)\n"));
3390 #ifdef ENABLE_OSC
3391 fprintf(stderr, _("-oscstart <port>\t\t: start OSC listener on UDP port <port> (default is %d)\n"), DEF_OSC_LISTEN_PORT);
3392 fprintf(stderr, "%s",
3393 _("-nooscstart\t\t\t: do not start the OSC listener (the default, unless set in preferences)\n"));
3394 #endif
3395 fprintf(stderr, "%s",
3396 _("-asource <source>\t\t: set the initial audio source (<source> can be 'internal' or 'external')\n"));
3397 fprintf(stderr, _("\t\t\t\t\t(only valid for %s and %s players)\n"), AUDIO_PLAYER_JACK, AUDIO_PLAYER_PULSE_AUDIO);
3398 fprintf(stderr, "%s", _("-aplayer <ap>\t\t\t: start with the selected audio player (<ap> can be: "));
3399 #ifdef HAVE_PULSE_AUDIO
3400 fprintf(stderr, "'%s'", AUDIO_PLAYER_PULSE);
3401 #endif
3402 #ifdef ENABLE_JACK
3403 #ifdef HAVE_PULSE_AUDIO
3404 fprintf(stderr, ", "); // comma after pulse
3405 #endif
3406 fprintf(stderr, "'%s'", AUDIO_PLAYER_JACK);
3407 if (capable->has_sox_play) lives_printerr(", '%s'", AUDIO_PLAYER_SOX); // comma after jack
3408 fprintf(stderr, " or '%s')\n", AUDIO_PLAYER_NONE);
3409 fprintf(stderr, "%s",
3410 _("-jackopts <opts>\t\t: opts is a bitmap of jackd startup / playback options (default is 16, "
3411 "unless set in Preferences)\n"
3412 "\t\t\t\t\t 1 = LiVES is a jack transport slave, \n"
3413 "\t\t\t\t\t 2 = LiVES is a jack transport master, \n"
3414 "\t\t\t\t\t 4 = start/stop jack transport server on LiVES playback start / stop\n"
3415 "\t\t\t\t\t\t(must be transport master), \n"
3416 "\t\t\t\t\t 8 = pause jack transport when video paused\n"
3417 "\t\t\t\t\t\t(must be transport master),\n"
3418 "\t\t\t\t\t16 = start/stop jack audio server on LiVES startup / shutdown\n"
3419 "\t\t\t\t\t\t(only if audio player is jack)) \n"));
3420 #else // no jack
3421 if (capable->has_sox_play) {
3422 #ifdef HAVE_PULSE_AUDIO
3423 fprintf(stderr, ", "); // comma after pulse
3424 #endif
3425 fprintf(stderr, _("'%s' or "), AUDIO_PLAYER_SOX);
3426 }
3427 #ifdef HAVE_PULSE_AUDIO
3428 else fprintf(stderr, "%s", _(" or ")); // no sox, 'or' after pulse
3429 #endif
3430 fprintf(stderr, "'%s')\n", AUDIO_PLAYER_NONE);
3431 #endif
3432 fprintf(stderr, "%s", _("-devicemap <mapname>\t\t: autoload devicemap <mapname> (for MIDI / joystick control)\n"));
3433 fprintf(stderr, "%s", _("-vppdefaults <file>\t\t: load defaults for video playback plugin from <file>\n"
3434 "\t\t\t\t\t(Note: only affects the plugin settings, not the plugin type)\n"));
3435 #ifdef HAVE_YUV4MPEG
3436 fprintf(stderr, "%s", _("-yuvin <fifo>\t\t\t: autoplay yuv4mpeg from stream <fifo> on startup\n"));
3437 fprintf(stderr, "%s", _("\t\t\t\t\t(only valid in clip edit startup mode)\n"));
3438 #endif
3439 fprintf(stderr, "%s", _("-debug\t\t\t\t: try to debug crashes (requires 'gdb' to be installed)\n"));
3440 fprintf(stderr, "%s", "\n");
3441 }
3442
3443 //// things to do - on startup
3444 #ifdef HAVE_YUV4MPEG
open_yuv4m_startup(livespointer data)3445 static boolean open_yuv4m_startup(livespointer data) {
3446 on_open_yuv4m_activate(NULL, data);
3447 return FALSE;
3448 }
3449 #endif
3450
3451
3452 ///////////////////////////////// TODO - move idle functions into another file //////////////////////////////////////
3453
render_choice_idle(livespointer data)3454 boolean render_choice_idle(livespointer data) {
3455 static boolean norecurse = FALSE;
3456 boolean rec_recovered = FALSE;
3457 boolean is_recovery = LIVES_POINTER_TO_INT(data);
3458 if (norecurse) return FALSE;
3459 if (mainw->noswitch) return TRUE;
3460 norecurse = TRUE;
3461 if (!is_recovery || mt_load_recovery_layout(NULL)) {
3462 if (mainw->event_list) {
3463 if (mainw->multitrack) {
3464 /// exit multitrack, backup mainw->event_as it will get set to NULL
3465 weed_plant_t *backup_elist = mainw->event_list;
3466 multitrack_delete(mainw->multitrack, FALSE);
3467 mainw->event_list = backup_elist;
3468 }
3469
3470 deal_with_render_choice(is_recovery);
3471 if (is_recovery && mainw->multitrack) rec_recovered = TRUE;
3472 }
3473 }
3474 if (is_recovery) mainw->recording_recovered = rec_recovered;
3475 norecurse = FALSE;
3476 return FALSE;
3477 }
3478
3479
lazy_startup_checks(void * data)3480 boolean lazy_startup_checks(void *data) {
3481 static boolean checked_trash = FALSE;
3482 static boolean mwshown = FALSE;
3483 static boolean dqshown = FALSE;
3484 static boolean tlshown = FALSE;
3485 static boolean extra_caps = FALSE;
3486 static boolean is_first = TRUE;
3487
3488 if (LIVES_IS_PLAYING) {
3489 dqshown = mwshown = tlshown = TRUE;
3490 return FALSE;
3491 }
3492
3493 if (is_first) {
3494 if (prefs->open_maximised && prefs->show_gui)
3495 lives_window_maximize(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET));
3496 is_first = FALSE;
3497 return TRUE;
3498 }
3499
3500 if (!tlshown) {
3501 //g_print("val is $d\n", check_snap("youtube-dl"));
3502 if (!mainw->multitrack) redraw_timeline(mainw->current_file);
3503 tlshown = TRUE;
3504 return TRUE;
3505 }
3506
3507 if (prefs->vj_mode) {
3508 resize(1.);
3509 if (prefs->open_maximised) {
3510 int bx, by;
3511 get_border_size(LIVES_MAIN_WINDOW_WIDGET, &bx, &by);
3512 if (by > MENU_HIDE_LIM)
3513 lives_window_set_hide_titlebar_when_maximized(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), TRUE);
3514 lives_window_maximize(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET));
3515 }
3516 return FALSE;
3517 }
3518
3519 if (mainw->dsu_widget) return TRUE;
3520
3521 if (!checked_trash) {
3522 if (prefs->autoclean) {
3523 char *com = lives_strdup_printf("%s empty_trash . general %s", prefs->backend, TRASH_NAME);
3524 lives_system(com, FALSE);
3525 lives_free(com);
3526 }
3527 checked_trash = TRUE;
3528 }
3529 if (!dqshown) {
3530 boolean do_show_quota = prefs->show_disk_quota;
3531 if (ran_ds_dlg) do_show_quota = FALSE;
3532 dqshown = TRUE;
3533 if (mainw->helper_procthreads[PT_LAZY_DSUSED]) {
3534 if (disk_monitor_running(prefs->workdir)) {
3535 int64_t dsval = capable->ds_used = disk_monitor_check_result(prefs->workdir);
3536 mainw->ds_status = get_storage_status(prefs->workdir, mainw->next_ds_warn_level, &dsval, 0);
3537 capable->ds_free = dsval;
3538 if (capable->ds_used < 0)
3539 capable->ds_used = disk_monitor_check_result(prefs->workdir);
3540 if (!prefs->disk_quota && (mainw->ds_status == LIVES_STORAGE_STATUS_NORMAL
3541 || mainw->ds_status == LIVES_STORAGE_STATUS_UNKNOWN)) {
3542 if (capable->ds_used < 0) disk_monitor_forget();
3543 } else {
3544 if (capable->ds_used < 0) {
3545 capable->ds_used = disk_monitor_wait_result(prefs->workdir, LIVES_DEFAULT_TIMEOUT);
3546 }
3547 }
3548 }
3549 mainw->helper_procthreads[PT_LAZY_DSUSED] = NULL;
3550 if (capable->ds_used > prefs->disk_quota * .9 || (mainw->ds_status != LIVES_STORAGE_STATUS_NORMAL
3551 && mainw->ds_status != LIVES_STORAGE_STATUS_UNKNOWN)) {
3552 if (capable->ds_used > prefs->disk_quota * .9 && (mainw->ds_status == LIVES_STORAGE_STATUS_NORMAL
3553 || mainw->ds_status == LIVES_STORAGE_STATUS_UNKNOWN)) {
3554 mainw->ds_status = LIVES_STORAGE_STATUS_OVER_QUOTA;
3555 }
3556 do_show_quota = TRUE;
3557 }
3558 }
3559 if (do_show_quota) {
3560 run_diskspace_dialog();
3561 return TRUE;
3562 }
3563 }
3564
3565 if (!mwshown) {
3566 mwshown = TRUE;
3567 if (prefs->show_msgs_on_startup) do_messages_window(TRUE);
3568 }
3569
3570 if (!extra_caps) {
3571 extra_caps = TRUE;
3572 capable->boot_time = get_cpu_load(-1);
3573 }
3574
3575 if (mainw->ldg_menuitem) {
3576 if (!RFX_LOADED) return TRUE;
3577 lives_widget_destroy(mainw->ldg_menuitem);
3578 mainw->ldg_menuitem = NULL;
3579 add_rfx_effects2(RFX_STATUS_ANY);
3580 if (LIVES_IS_SENSITIZED) sensitize(); // call fn again to sens. new menu entries
3581 }
3582
3583 mainw->lazy = 0;
3584 return FALSE;
3585 }
3586
3587
resize_message_area(livespointer data)3588 boolean resize_message_area(livespointer data) {
3589 // workaround because the window manager will resize the window asynchronously
3590 static boolean isfirst = TRUE;
3591 int bx, by;
3592
3593 if (data) isfirst = TRUE;
3594
3595 if (!prefs->show_gui || LIVES_IS_PLAYING || mainw->is_processing || mainw->is_rendering || !prefs->show_msg_area) {
3596 mainw->assumed_height = mainw->assumed_width = -1;
3597 mainw->idlemax = 0;
3598 return FALSE;
3599 }
3600
3601 if (mainw->idlemax-- == DEF_IDLE_MAX) mainw->msg_area_configed = FALSE;
3602
3603 get_border_size(LIVES_MAIN_WINDOW_WIDGET, &bx, &by);
3604
3605 if (mainw->idlemax == DEF_IDLE_MAX / 2 && prefs->open_maximised && (by > 0 || bx > 0)) {
3606 if (by > MENU_HIDE_LIM)
3607 lives_window_set_hide_titlebar_when_maximized(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), TRUE);
3608 lives_window_maximize(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET));
3609 mainw->assumed_height = mainw->assumed_width = -1;
3610 return TRUE;
3611 }
3612
3613 if (mainw->msg_area_configed) mainw->idlemax = 0;
3614
3615 if (mainw->idlemax > 0 && mainw->assumed_height != -1 &&
3616 mainw->assumed_height != lives_widget_get_allocation_height(LIVES_MAIN_WINDOW_WIDGET)) return TRUE;
3617 if (mainw->idlemax > 0 && lives_widget_get_allocation_height(mainw->end_image) != mainw->ce_frame_height) return TRUE;
3618
3619 mainw->idlemax = 0;
3620 mainw->assumed_height = mainw->assumed_width = -1;
3621 msg_area_scroll(LIVES_ADJUSTMENT(mainw->msg_adj), mainw->msg_area);
3622 //#if !GTK_CHECK_VERSION(3, 0, 0)
3623 msg_area_config(mainw->msg_area);
3624 //#endif
3625 if (isfirst) {
3626 lives_widget_set_vexpand(mainw->msg_area, TRUE);
3627 if (prefs->open_maximised && prefs->show_gui) {
3628 lives_window_maximize(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET));
3629 }
3630 if (!CURRENT_CLIP_IS_VALID) {
3631 d_print("");
3632 }
3633 msg_area_scroll_to_end(mainw->msg_area, mainw->msg_adj);
3634 lives_widget_queue_draw_if_visible(mainw->msg_area);
3635 isfirst = FALSE;
3636 }
3637 resize(1.);
3638 lives_widget_queue_draw(mainw->LiVES);
3639 return FALSE;
3640 }
3641
3642 /////////////////////////////////////////////////////////////////////////////////////////////////
3643 static boolean got_files = FALSE;
3644 static boolean lives_startup2(livespointer data);
lives_startup(livespointer data)3645 static boolean lives_startup(livespointer data) {
3646 // this is run in an idlefunc
3647
3648 char *tmp, *tmp2, *msg;
3649
3650 // check the working directory
3651 if (needs_workdir) {
3652 // get initial workdir
3653 if (!do_workdir_query()) {
3654 lives_exit(0);
3655 }
3656 prefs->startup_phase = 2;
3657 set_int_pref(PREF_STARTUP_PHASE, 2);
3658 }
3659 if (prefs->startup_phase > 0 && prefs->startup_phase < 3) {
3660 if (!do_startup_tests(FALSE)) {
3661 lives_exit(0);
3662 }
3663 prefs->startup_phase = 3;
3664 set_int_pref(PREF_STARTUP_PHASE, 3);
3665
3666 // we can show this now
3667 if (prefs->show_splash) splash_init();
3668 }
3669
3670 if (newconfigfile || prefs->startup_phase == 3) {
3671 /// CREATE prefs->config_datadir, and default items inside it
3672 build_init_config(prefs->config_datadir, ign_opts.ign_config_datadir);
3673 }
3674
3675 get_string_pref(PREF_VID_PLAYBACK_PLUGIN, buff, 256);
3676
3677 if (*buff && strcmp(buff, "(null)") && strcmp(buff, "none")) {
3678 mainw->vpp = open_vid_playback_plugin(buff, TRUE);
3679 } else if (prefs->startup_phase == 3) {
3680 mainw->vpp = open_vid_playback_plugin(DEFAULT_VPP, TRUE);
3681 if (mainw->vpp) {
3682 lives_snprintf(future_prefs->vpp_name, 64, "%s", mainw->vpp->name);
3683 set_string_pref(PREF_VID_PLAYBACK_PLUGIN, mainw->vpp->name);
3684 }
3685 }
3686
3687 if (!ign_opts.ign_aplayer) {
3688 get_string_pref(PREF_AUDIO_PLAYER, buff, 256);
3689 if (!strcmp(buff, AUDIO_PLAYER_NONE)) {
3690 prefs->audio_player = AUD_PLAYER_NONE; ///< experimental
3691 lives_snprintf(prefs->aplayer, 512, "%s", AUDIO_PLAYER_NONE);
3692 } else if (!strcmp(buff, AUDIO_PLAYER_SOX)) {
3693 prefs->audio_player = AUD_PLAYER_SOX;
3694 lives_snprintf(prefs->aplayer, 512, "%s", AUDIO_PLAYER_SOX);
3695 } else if (!strcmp(buff, AUDIO_PLAYER_JACK)) {
3696 prefs->audio_player = AUD_PLAYER_JACK;
3697 lives_snprintf(prefs->aplayer, 512, "%s", AUDIO_PLAYER_JACK);
3698 } else if (!strcmp(buff, AUDIO_PLAYER_PULSE) || !strcmp(buff, AUDIO_PLAYER_PULSE_AUDIO)) {
3699 prefs->audio_player = AUD_PLAYER_PULSE;
3700 lives_snprintf(prefs->aplayer, 512, "%s", AUDIO_PLAYER_PULSE);
3701 }
3702 } else {
3703 set_string_pref(PREF_AUDIO_PLAYER, prefs->aplayer);
3704 }
3705
3706 #ifdef HAVE_PULSE_AUDIO
3707 if ((prefs->startup_phase == 1 || prefs->startup_phase == -1) && capable->has_pulse_audio) {
3708 if (prefs->pa_restart) {
3709 char *com = lives_strdup_printf("%s -k %s", EXEC_PULSEAUDIO, prefs->pa_start_opts);
3710 lives_system(com, TRUE);
3711 lives_free(com);
3712 }
3713 prefs->audio_player = AUD_PLAYER_PULSE;
3714 lives_snprintf(prefs->aplayer, 512, "%s", AUDIO_PLAYER_PULSE);
3715 set_string_pref(PREF_AUDIO_PLAYER, AUDIO_PLAYER_PULSE);
3716 } else {
3717 #endif
3718 #ifdef ENABLE_JACK
3719 if ((prefs->startup_phase == 1 || prefs->startup_phase == -1) && capable->has_jackd && prefs->audio_player == -1) {
3720 prefs->audio_player = AUD_PLAYER_JACK;
3721 lives_snprintf(prefs->aplayer, 512, "%s", AUDIO_PLAYER_JACK);
3722 set_string_pref(PREF_AUDIO_PLAYER, AUDIO_PLAYER_JACK);
3723 }
3724 #endif
3725 #ifdef HAVE_PULSE_AUDIO
3726 }
3727 #endif
3728
3729 if (!ign_opts.ign_asource) {
3730 if (prefs->vj_mode)
3731 prefs->audio_src = AUDIO_SRC_EXT;
3732 else
3733 prefs->audio_src = get_int_prefd(PREF_AUDIO_SRC, AUDIO_SRC_INT);
3734 }
3735
3736 if (!((prefs->audio_player == AUD_PLAYER_JACK && capable->has_jackd) || (prefs->audio_player == AUD_PLAYER_PULSE &&
3737 capable->has_pulse_audio)) && prefs->audio_src == AUDIO_SRC_EXT) {
3738 prefs->audio_src = AUDIO_SRC_INT;
3739 set_int_pref(PREF_AUDIO_SRC, prefs->audio_src);
3740 }
3741
3742 future_prefs->audio_src = prefs->audio_src;
3743
3744 splash_msg(_("Starting GUI..."), SPLASH_LEVEL_BEGIN);
3745 LIVES_MAIN_WINDOW_WIDGET = NULL;
3746
3747 create_LiVES();
3748
3749 if (prefs->open_maximised && prefs->show_gui) {
3750 int bx, by;
3751 get_border_size(LIVES_MAIN_WINDOW_WIDGET, &bx, &by);
3752 if (by > MENU_HIDE_LIM)
3753 lives_window_set_hide_titlebar_when_maximized(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), TRUE);
3754 lives_window_maximize(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET));
3755 }
3756
3757 // needed to avoid priv->pulse2 > priv->pulse1 gtk error
3758 lives_widget_context_update();
3759
3760 lives_widget_queue_draw(LIVES_MAIN_WINDOW_WIDGET);
3761 lives_widget_context_update();
3762
3763 mainw->startup_error = FALSE;
3764
3765 if (theme_error && !mainw->foreign) {
3766 // non-fatal errors
3767 msg = lives_strdup_printf(
3768 _("\n\nThe theme you requested (%s) could not be located.\n"
3769 "Please make sure you have the themes installed in\n%s/%s.\n"
3770 "(Maybe you need to change the value of <prefix_dir> in your %s file)\n"
3771 "or you may be missing a custom theme.\n"), future_prefs->theme,
3772 (tmp = lives_filename_to_utf8(prefs->prefix_dir, -1, NULL, NULL, NULL)), THEME_DIR,
3773 (tmp2 = lives_filename_to_utf8(prefs->configfile, -1, NULL, NULL, NULL)));
3774 lives_free(tmp2);
3775 lives_free(tmp);
3776 startup_message_nonfatal(msg);
3777 lives_free(msg);
3778 lives_snprintf(prefs->theme, 64, LIVES_THEME_NONE);
3779 upgrade_error = TRUE;
3780 }
3781
3782 lives_init(&ign_opts);
3783
3784 // non-fatal errors
3785
3786 if (!mainw->foreign) {
3787 if (*capable->startup_msg) {
3788 if (info_only) startup_message_info(capable->startup_msg);
3789 else startup_message_nonfatal(capable->startup_msg);
3790 } else {
3791 if (!prefs->vj_mode) {
3792 if (!capable->has_mplayer && !capable->has_mplayer2 && !capable->has_mpv
3793 && !(prefs->warning_mask & WARN_MASK_NO_MPLAYER)) {
3794 startup_message_nonfatal_dismissable(
3795 _("\nLiVES was unable to locate 'mplayer','mplayer2' or 'mpv'. "
3796 "You may wish to install one of these to use LiVES more fully.\n"),
3797 WARN_MASK_NO_MPLAYER);
3798 }
3799 if (!capable->has_convert) {
3800 startup_message_nonfatal_dismissable(
3801 _("\nLiVES was unable to locate 'convert'. "
3802 "You should install convert and image-magick "
3803 "if you want to use rendered effects.\n"),
3804 WARN_MASK_NO_MPLAYER);
3805 }
3806 if (!capable->has_composite) {
3807 startup_message_nonfatal_dismissable(
3808 _("\nLiVES was unable to locate 'composite'. "
3809 "You should install composite and image-magick "
3810 "if you want to use the merge function.\n"),
3811 WARN_MASK_NO_MPLAYER);
3812 }
3813 if (!capable->has_sox_sox) {
3814 startup_message_nonfatal_dismissable(
3815 _("\nLiVES was unable to locate 'sox'. Some audio features may not work. "
3816 "You should install 'sox'.\n"),
3817 WARN_MASK_NO_MPLAYER);
3818 }
3819 if (!capable->has_encoder_plugins) {
3820 msg = lives_strdup_printf(
3821 _("\nLiVES was unable to find any encoder plugins.\n"
3822 "Please check that you have them installed correctly in\n%s%s%s/\n"
3823 "You will not be able to 'Save' without them.\n"
3824 "You may need to change the value of <lib_dir> in %s\n"),
3825 prefs->lib_dir, PLUGIN_EXEC_DIR, PLUGIN_ENCODERS,
3826 (tmp = lives_filename_to_utf8(prefs->configfile, -1, NULL, NULL, NULL)));
3827 lives_free(tmp);
3828 startup_message_nonfatal_dismissable(msg, WARN_MASK_NO_ENCODERS);
3829 lives_free(msg);
3830 upgrade_error = TRUE;
3831 }
3832
3833 if (mainw->next_ds_warn_level > 0) {
3834 if (mainw->ds_status == LIVES_STORAGE_STATUS_WARNING) {
3835 uint64_t curr_ds_warn = mainw->next_ds_warn_level;
3836 mainw->next_ds_warn_level >>= 1;
3837 if (mainw->next_ds_warn_level > (capable->ds_free >> 1)) mainw->next_ds_warn_level = capable->ds_free >> 1;
3838 if (mainw->next_ds_warn_level < prefs->ds_crit_level) mainw->next_ds_warn_level = prefs->ds_crit_level;
3839 tmp = ds_warning_msg(prefs->workdir, &capable->mountpoint, capable->ds_free, curr_ds_warn, mainw->next_ds_warn_level);
3840 msg = lives_strdup_printf("\n%s\n", tmp);
3841 lives_free(tmp);
3842 startup_message_nonfatal(msg);
3843 lives_free(msg);
3844 // *INDENT-OFF*
3845 }}}}
3846 // *INDENT-ON*
3847 splash_msg(_("Loading rendered effect plugins..."), SPLASH_LEVEL_LOAD_RFX);
3848 // must call this at least to set up rendered_fx[0]
3849 } else {
3850 // capture mode
3851 mainw->foreign_key = atoi(zargv[2]);
3852
3853 #if GTK_CHECK_VERSION(3, 0, 0) || defined GUI_QT
3854 mainw->foreign_id = (Window)atoi(zargv[3]);
3855 #else
3856 mainw->foreign_id = (GdkNativeWindow)atoi(zargv[3]);
3857 #endif
3858
3859 mainw->foreign_width = atoi(zargv[4]);
3860 mainw->foreign_height = atoi(zargv[5]);
3861 lives_snprintf(prefs->image_ext, 16, "%s", zargv[6]);
3862 lives_snprintf(prefs->image_type, 16, "%s", image_ext_to_lives_image_type(prefs->image_ext));
3863 mainw->foreign_bpp = atoi(zargv[7]);
3864 mainw->rec_vid_frames = atoi(zargv[8]);
3865 mainw->rec_fps = strtod(zargv[9], NULL);
3866 mainw->rec_arate = atoi(zargv[10]);
3867 mainw->rec_asamps = atoi(zargv[11]);
3868 mainw->rec_achans = atoi(zargv[12]);
3869 mainw->rec_signed_endian = atoi(zargv[13]);
3870
3871 if (zargc > 14) {
3872 mainw->foreign_visual = lives_strdup(zargv[14]);
3873 if (!strcmp(mainw->foreign_visual, "(null)")) {
3874 lives_free(mainw->foreign_visual);
3875 mainw->foreign_visual = NULL;
3876 }
3877 }
3878
3879 #ifdef ENABLE_JACK
3880 if (prefs->audio_player == AUD_PLAYER_JACK && capable->has_jackd && mainw->rec_achans > 0) {
3881 lives_jack_init();
3882 jack_audio_read_init();
3883 }
3884 #endif
3885 #ifdef HAVE_PULSE_AUDIO
3886 if (prefs->audio_player == AUD_PLAYER_PULSE && capable->has_pulse_audio && mainw->rec_achans > 0) {
3887 lives_pulse_init(0);
3888 pulse_audio_read_init();
3889 }
3890 #endif
3891
3892 lives_widget_show(LIVES_MAIN_WINDOW_WIDGET);
3893 lives_widget_context_update();
3894 mainw->go_away = FALSE;
3895 on_capture2_activate(); // exits
3896 }
3897
3898 //#define NOTTY
3899 #ifdef NOTTY
3900 if (!mainw->foreign) {
3901 capable->xstdout = dup(STDOUT_FILENO);
3902 close(STDOUT_FILENO);
3903 }
3904 #endif
3905
3906 if (mainw->prefs_cache) cached_list_free(&mainw->prefs_cache);
3907
3908 if (!prefs->show_gui) lives_widget_hide(LIVES_MAIN_WINDOW_WIDGET);
3909
3910 if (prefs->startup_phase == 100) {
3911 if (upgrade_error) {
3912 do_upgrade_error_dialog();
3913 }
3914 prefs->startup_phase = 0;
3915 }
3916
3917 // splash_end() will start up multitrack if in STARTUP_MT mode
3918 if (*start_file && strcmp(start_file, "-")) {
3919 splash_end();
3920 deduce_file(start_file, start, end);
3921 got_files = TRUE;
3922 } else {
3923 set_main_title(NULL, 0);
3924 splash_end();
3925 }
3926
3927 if (prefs->startup_phase == 0) show_lives();
3928 mainw->is_ready = TRUE;
3929
3930 if (!strcmp(buff, AUDIO_PLAYER_SOX)) {
3931 switch_aud_to_sox(FALSE);
3932 }
3933 if (!strcmp(buff, AUDIO_PLAYER_NONE)) {
3934 // still experimental
3935 switch_aud_to_none(FALSE);
3936 }
3937
3938 lives_idle_add_simple(lives_startup2, NULL);
3939 return FALSE;
3940 }
3941
3942
lives_startup2(livespointer data)3943 static boolean lives_startup2(livespointer data) {
3944 char *ustr;
3945 boolean layout_recovered = FALSE;
3946
3947 if (prefs->crash_recovery && !no_recover) got_files = check_for_recovery_files(auto_recover);
3948
3949 if (!mainw->foreign && !got_files && prefs->ar_clipset) {
3950 d_print(lives_strdup_printf(_("Autoloading set %s..."), prefs->ar_clipset_name));
3951 if (!reload_set(prefs->ar_clipset_name) || mainw->current_file == -1) {
3952 set_string_pref(PREF_AR_CLIPSET, "");
3953 prefs->ar_clipset = FALSE;
3954 }
3955 future_prefs->ar_clipset = FALSE;
3956 }
3957
3958 #ifdef ENABLE_OSC
3959 if (prefs->osc_start) prefs->osc_udp_started = lives_osc_init(prefs->osc_udp_port);
3960 #endif
3961
3962 if (mainw->recoverable_layout) {
3963 if (!prefs->vj_mode) layout_recovered = do_layout_recover_dialog();
3964 else mainw->recoverable_layout = FALSE;
3965 }
3966
3967 if (!mainw->recording_recovered) {
3968 if (mainw->ascrap_file != -1) {
3969 if (!layout_recovered || !mainw->multitrack || !used_in_current_layout(mainw->multitrack, mainw->ascrap_file)) {
3970 close_ascrap_file(FALSE); // ignore but leave file on disk for recovery purposes
3971 }
3972 }
3973 if (mainw->scrap_file != -1) {
3974 if (!layout_recovered || mainw->multitrack || !used_in_current_layout(mainw->multitrack, mainw->scrap_file)) {
3975 close_scrap_file(FALSE); // ignore but leave file on disk for recovery purposes
3976 }
3977 }
3978 } else {
3979 if (mainw->multitrack) multitrack_delete(mainw->multitrack, FALSE);
3980 }
3981
3982 #ifdef HAVE_YUV4MPEG
3983 if (*prefs->yuvin) lives_idle_add_simple(open_yuv4m_startup, NULL);
3984 #endif
3985
3986 mainw->no_switch_dprint = TRUE;
3987 if (mainw->current_file > -1 && !mainw->multitrack) {
3988 switch_clip(1, mainw->current_file, TRUE);
3989 }
3990
3991 if (!palette || !(palette->style & STYLE_LIGHT)) {
3992 lives_widget_set_opacity(mainw->sep_image, 0.4);
3993 } else {
3994 lives_widget_set_opacity(mainw->sep_image, 0.8);
3995 }
3996 lives_widget_queue_draw(mainw->sep_image);
3997
3998 if (*devmap) on_devicemap_load_activate(NULL, devmap);
3999
4000 if (capable->username)
4001 ustr = lives_strdup_printf(", %s", capable->username);
4002 else
4003 ustr = lives_strdup("");
4004
4005 d_print(_("\nWelcome to LiVES version %s%s !\n"), LiVES_VERSION, ustr);
4006 lives_free(ustr);
4007
4008 mainw->no_switch_dprint = FALSE;
4009 d_print("");
4010
4011 if (!mainw->multitrack) {
4012 if (mainw->current_file == -1) {
4013 resize(1.);
4014 if (prefs->show_msg_area) {
4015 // the message area must fit exactly to the screen size, so we update it in an idle function
4016 // due to the fact that the window manager may resize the window asynchronously
4017 if (mainw->idlemax == 0)
4018 lives_idle_add_simple(resize_message_area, NULL);
4019 mainw->idlemax = DEF_IDLE_MAX;
4020 }
4021 }
4022 } else {
4023 lives_idle_add_simple(mt_idle_show_current_frame, (livespointer)mainw->multitrack);
4024 if (mainw->multitrack->idlefunc == 0) {
4025 mainw->multitrack->idlefunc = mt_idle_add(mainw->multitrack);
4026 }
4027 }
4028
4029 mainw->go_away = FALSE;
4030 if (!mainw->multitrack) sensitize();
4031
4032 if (prefs->vj_mode) {
4033 char *wid = lives_strdup_printf("0x%08lx",
4034 (uint64_t)LIVES_XWINDOW_XID(lives_widget_get_xwindow(LIVES_MAIN_WINDOW_WIDGET)));
4035 if (wid) activate_x11_window(wid);
4036 }
4037 if (mainw->recording_recovered) {
4038 lives_idle_add_simple(render_choice_idle, LIVES_INT_TO_POINTER(TRUE));
4039 }
4040
4041 mainw->overlay_alarm = lives_alarm_set(0);
4042
4043 if (!mainw->multitrack)
4044 lives_notify_int(LIVES_OSC_NOTIFY_MODE_CHANGED, STARTUP_CE);
4045 else
4046 lives_notify_int(LIVES_OSC_NOTIFY_MODE_CHANGED, STARTUP_MT);
4047
4048 if (!prefs->vj_mode && !prefs->startup_phase) {
4049 mainw->helper_procthreads[PT_LAZY_RFX] =
4050 lives_proc_thread_create(LIVES_THRDATTR_NONE, (lives_funcptr_t)add_rfx_effects, -1, "i", RFX_STATUS_ANY);
4051 }
4052
4053 mainw->lazy = lives_idle_add_simple(lazy_startup_checks, NULL);
4054
4055 // timer to poll for external commands: MIDI, joystick, jack transport, osc, etc.
4056 mainw->kb_timer = lives_timer_add_simple(EXT_TRIGGER_INTERVAL, &ext_triggers_poll, NULL);
4057
4058 if (!CURRENT_CLIP_IS_VALID) lives_ce_update_timeline(0, 0.);
4059
4060 if (newconfigfile) {
4061 cleanup_old_config();
4062 lives_free(newconfigfile);
4063 }
4064
4065 if (!mainw->mute) {
4066 lives_widget_set_opacity(mainw->m_mutebutton, .75);
4067 }
4068 lives_widget_set_opacity(mainw->m_sepwinbutton, .75);
4069 lives_widget_set_opacity(mainw->m_loopbutton, .75);
4070
4071 if (prefs->interactive) set_interactive(TRUE);
4072
4073 return FALSE;
4074 } // end lives_startup2()
4075
4076
set_signal_handlers(SignalHandlerPointer sigfunc)4077 void set_signal_handlers(SignalHandlerPointer sigfunc) {
4078 sigset_t smask;
4079 struct sigaction sact;
4080
4081 sigemptyset(&smask);
4082
4083 #define USE_GLIB_SIGHANDLER
4084 #ifdef USE_GLIB_SIGHANDLER
4085 g_unix_signal_add(LIVES_SIGINT, glib_sighandler, LIVES_INT_TO_POINTER(LIVES_SIGINT));
4086 g_unix_signal_add(LIVES_SIGTERM, glib_sighandler, LIVES_INT_TO_POINTER(LIVES_SIGTERM));
4087 #else
4088 sigaddset(&smask, LIVES_SIGINT);
4089 sigaddset(&smask, LIVES_SIGTERM);
4090 #endif
4091
4092 sigaddset(&smask, LIVES_SIGSEGV);
4093 sigaddset(&smask, LIVES_SIGABRT);
4094
4095 sact.sa_handler = sigfunc;
4096 sact.sa_flags = 0;
4097 sact.sa_mask = smask;
4098
4099 sigaction(LIVES_SIGINT, &sact, NULL);
4100 sigaction(LIVES_SIGTERM, &sact, NULL);
4101 sigaction(LIVES_SIGSEGV, &sact, NULL);
4102 sigaction(LIVES_SIGABRT, &sact, NULL);
4103
4104 if (mainw) {
4105 if (sigfunc == defer_sigint) mainw->signals_deferred = TRUE;
4106 else mainw->signals_deferred = FALSE;
4107 }
4108 }
4109
4110
real_main(int argc,char * argv[],pthread_t * gtk_thread,ulong id)4111 int real_main(int argc, char *argv[], pthread_t *gtk_thread, ulong id) {
4112 weed_error_t werr;
4113 ssize_t mynsize;
4114 char cdir[PATH_MAX];
4115 boolean toolong = FALSE;
4116 char *tmp, *dir, *msg;
4117 pthread_mutexattr_t mattr;
4118 #ifndef IS_LIBLIVES
4119 weed_plant_t *test_plant;
4120 #endif
4121
4122 mainw = NULL;
4123 prefs = NULL;
4124 capable = NULL;
4125
4126 set_signal_handlers((SignalHandlerPointer)catch_sigint);
4127
4128 lives_memset(&ign_opts, 0, sizeof(ign_opts));
4129
4130 #ifdef ENABLE_OIL
4131 oil_init();
4132 #endif
4133
4134 init_memfuncs();
4135
4136 #ifdef IS_LIBLIVES
4137 #ifdef GUI_GTK
4138 if (gtk_thread) {
4139 pthread_create(gtk_thread, NULL, gtk_thread_wrapper, NULL);
4140 }
4141 #endif
4142 #endif
4143
4144 capable = (capability *)lives_calloc(1, sizeof(capability));
4145 capable->cacheline_size = sizeof(void *) * 8;
4146
4147 // _runtime_ byte order, needed for lives_strlen and other things
4148 if (IS_BIG_ENDIAN)
4149 capable->byte_order = LIVES_BIG_ENDIAN;
4150 else
4151 capable->byte_order = LIVES_LITTLE_ENDIAN;
4152
4153 capable->main_thread = pthread_self();
4154
4155 zargc = argc;
4156 zargv = argv;
4157
4158 //setlocale(LC_ALL, "");
4159
4160 // force decimal point to be a "."
4161 putenv("LC_NUMERIC=C");
4162 setlocale(LC_NUMERIC, "C");
4163
4164 #ifdef ENABLE_NLS
4165 textdomain(GETTEXT_PACKAGE);
4166 bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
4167 #ifdef UTF8_CHARSET
4168 bind_textdomain_codeset(GETTEXT_PACKAGE, nl_langinfo(CODESET));
4169 #endif
4170 #endif
4171
4172 #ifdef GDK_WINDOWING_X11
4173 XInitThreads();
4174 #endif
4175
4176 #ifdef GUI_GTK
4177 #if GTK_CHECK_VERSION(4, 0, 0)
4178 gtk_init();
4179 #else
4180 gtk_init(&argc, &argv);
4181 #endif
4182 #endif
4183
4184 g_log_set_default_handler(lives_log_handler, NULL);
4185
4186 //gtk_window_set_interactive_debugging(TRUE);
4187 #ifndef LIVES_NO_DEBUG
4188 g_printerr("FULL DEBUGGING IS ON !!\n");
4189 #endif
4190
4191 #ifndef IS_LIBLIVES
4192 // start up the Weed system
4193 weed_abi_version = weed_get_abi_version();
4194 if (weed_abi_version > WEED_ABI_VERSION) weed_abi_version = WEED_ABI_VERSION;
4195 //werr = weed_init(weed_abi_version, WEED_INIT_DEBUGMODE);
4196 werr = weed_init(weed_abi_version, 0);
4197 if (werr != WEED_SUCCESS) {
4198 lives_notify(LIVES_OSC_NOTIFY_QUIT, "Failed to init Weed");
4199 LIVES_FATAL("Failed to init Weed");
4200 _exit(1);
4201 }
4202 #ifndef USE_STD_MEMFUNCS
4203 weed_utils_set_custom_memfuncs(lives_malloc, lives_calloc, lives_memcpy, NULL, lives_free);
4204 #endif
4205 #endif
4206
4207 // backup the core functions so we can override them
4208 _weed_plant_new = weed_plant_new;
4209 _weed_plant_free = weed_plant_free;
4210 _weed_leaf_set = weed_leaf_set;
4211 _weed_leaf_get = weed_leaf_get;
4212 _weed_leaf_delete = weed_leaf_delete;
4213 _weed_plant_list_leaves = weed_plant_list_leaves;
4214 _weed_leaf_num_elements = weed_leaf_num_elements;
4215 _weed_leaf_element_size = weed_leaf_element_size;
4216 _weed_leaf_seed_type = weed_leaf_seed_type;
4217 _weed_leaf_get_flags = weed_leaf_get_flags;
4218 _weed_leaf_set_flags = weed_leaf_set_flags;
4219
4220 mainw = (mainwindow *)(lives_calloc(1, sizeof(mainwindow)));
4221 init_random();
4222
4223 #ifdef ENABLE_DIAGNOSTICS
4224 run_weed_startup_tests();
4225 check_random();
4226 lives_struct_test();
4227 test_palette_conversions();
4228 #endif
4229
4230 // allow us to set immutable values (plugins can't)
4231 weed_leaf_set = weed_leaf_set_host;
4232
4233 // allow us to delete undeletable leaves (plugins can't)
4234 weed_leaf_delete = weed_leaf_delete_host;
4235
4236 // allow us to set immutable values (plugins can't)
4237 //weed_leaf_get = weed_leaf_get_monitor;
4238
4239 // allow us to free undeletable plants (plugins cant')
4240 weed_plant_free = weed_plant_free_host;
4241 // weed_plant_new = weed_plant_new_host;
4242
4243 init_colour_engine();
4244
4245 weed_threadsafe = FALSE;
4246 test_plant = weed_plant_new(0);
4247 if (weed_leaf_set_private_data(test_plant, WEED_LEAF_TYPE, NULL) == WEED_ERROR_CONCURRENCY)
4248 weed_threadsafe = TRUE;
4249 else weed_threadsafe = FALSE;
4250 weed_plant_free(test_plant);
4251
4252 widget_helper_init();
4253
4254 /* TRANSLATORS: localised name may be used here */
4255 lives_set_application_name(_("LiVES"));
4256 widget_opts.title_prefix = lives_strdup_printf("%s-%s: - ", lives_get_application_name(), LiVES_VERSION);
4257
4258 // init prefs
4259 prefs = (_prefs *)lives_calloc(1, sizeof(_prefs));
4260 future_prefs = (_future_prefs *)lives_calloc(1, sizeof(_future_prefs));
4261 prefs->workdir[0] = '\0';
4262 future_prefs->workdir[0] = '\0';
4263 prefs->config_datadir[0] = '\0';
4264 prefs->configfile[0] = '\0';
4265
4266 prefs->show_gui = TRUE;
4267 prefs->show_splash = FALSE;
4268 prefs->show_playwin = TRUE;
4269 prefs->show_dev_opts = FALSE;
4270 prefs->interactive = TRUE;
4271 prefs->show_disk_quota = FALSE;
4272
4273 lives_snprintf(prefs->cmd_log, PATH_MAX, LIVES_DEVNULL);
4274
4275 #ifdef HAVE_YUV4MPEG
4276 prefs->yuvin[0] = '\0';
4277 #endif
4278
4279 mainw->version_hash = lives_strdup_printf("%d", verhash(LiVES_VERSION));
4280 mainw->mgeom = NULL;
4281 mainw->msg[0] = '\0';
4282 mainw->error = FALSE;
4283 mainw->is_exiting = FALSE;
4284 mainw->multitrack = NULL;
4285 mainw->splash_window = NULL;
4286 mainw->is_ready = mainw->fatal = FALSE;
4287 mainw->memok = TRUE;
4288 mainw->go_away = TRUE;
4289 mainw->last_dprint_file = mainw->current_file = mainw->playing_file = -1;
4290 mainw->no_context_update = FALSE;
4291 mainw->ce_thumbs = FALSE;
4292 mainw->LiVES = NULL;
4293 mainw->suppress_dprint = FALSE;
4294 mainw->clutch = TRUE;
4295 mainw->mbar_res = 0;
4296 mainw->max_textsize = N_TEXT_SIZES;
4297 mainw->no_configs = FALSE;
4298
4299 pthread_mutexattr_init(&mattr);
4300 pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
4301
4302 mainw->has_session_workdir = FALSE;
4303 mainw->old_vhash = NULL;
4304
4305 mainw->prefs_cache = mainw->hdrs_cache = mainw->gen_cache = NULL;
4306
4307 // mainw->foreign is set if we are grabbing an external window
4308 mainw->foreign = FALSE;
4309
4310 mainw->debug = FALSE;
4311
4312 mainw->sense_state = LIVES_SENSE_STATE_INSENSITIZED;
4313
4314 prefs->max_modes_per_key = atoi(DEF_FX_KEYMODES);
4315
4316 devmap[0] = '\0';
4317 capable->mountpoint = NULL;
4318 capable->startup_msg[0] = '\0';
4319 capable->has_perl = TRUE;
4320 capable->has_smogrify = TRUE;
4321 capable->smog_version_correct = TRUE;
4322 capable->can_read_from_config = TRUE;
4323 capable->can_write_to_config = TRUE;
4324 capable->can_write_to_config_backup = TRUE;
4325 capable->can_write_to_config_new = TRUE;
4326 capable->can_write_to_workdir = TRUE;
4327
4328 // this is the version we should pass into mkdir
4329 capable->umask = umask(0);
4330 umask(capable->umask);
4331 capable->umask = (0777 & ~capable->umask);
4332
4333 #ifdef GUI_GTK
4334 lives_snprintf(capable->home_dir, PATH_MAX, "%s", g_get_home_dir());
4335 #else
4336 tmp = getenv("HOME");
4337 lives_snprintf(capable->home_dir, PATH_MAX, "%s", tmp);
4338 lives_free(tmp);
4339 #endif
4340
4341 ensure_isdir(capable->home_dir);
4342 get_location("touch", capable->touch_cmd, PATH_MAX); // needed for make_writeable_dir()
4343 get_location("rm", capable->rm_cmd, PATH_MAX); // ditto
4344 get_location("rmdir", capable->rmdir_cmd, PATH_MAX); // ditto
4345 get_location("sed", capable->sed_cmd, PATH_MAX); // nice to know
4346 get_location("grep", capable->grep_cmd, PATH_MAX); // ditto
4347 get_location("wc", capable->wc_cmd, PATH_MAX); // ditto
4348
4349 // get opts first
4350 if (argc > 1) {
4351 if (!strcmp(argv[1], "-capture")) {
4352 // special mode for grabbing external window
4353 mainw->foreign = TRUE;
4354 future_prefs->audio_src = prefs->audio_src = AUDIO_SRC_EXT;
4355 ign_opts.ign_asource = TRUE;
4356 } else if (!strcmp(argv[1], "-help") || !strcmp(argv[1], "--help")) {
4357 char string[256];
4358 get_location(EXEC_PLAY, string, 256);
4359 if (*string) capable->has_sox_play = TRUE;
4360
4361 capable->myname_full = lives_find_program_in_path(argv[0]);
4362
4363 if ((mynsize = lives_readlink(capable->myname_full, cdir, PATH_MAX)) != -1) {
4364 lives_memset(cdir + mynsize, 0, 1);
4365 lives_free(capable->myname_full);
4366 capable->myname_full = lives_strdup(cdir);
4367 }
4368
4369 lives_snprintf(cdir, PATH_MAX, "%s", capable->myname_full);
4370 get_basename(cdir);
4371 capable->myname = lives_strdup(cdir);
4372
4373 print_opthelp();
4374 exit(0);
4375 } else if (!strcmp(argv[1], "-version") || !strcmp(argv[1], "--version")) {
4376 print_notice();
4377 exit(0);
4378 } else {
4379 struct option longopts[] = {
4380 {"aplayer", 1, 0, 0},
4381 {"asource", 1, 0, 0},
4382 {"workdir", 1, 0, 0},
4383 {"configfile", 1, 0, 0},
4384 {"configdatadir", 1, 0, 0},
4385 {"dscrit", 1, 0, 0},
4386 {"set", 1, 0, 0},
4387 {"noset", 0, 0, 0},
4388 #ifdef ENABLE_OSC
4389 {"devicemap", 1, 0, 0},
4390 #endif
4391 {"vppdefaults", 1, 0, 0},
4392 {"recover", 0, 0, 0},
4393 {"autorecover", 0, 0, 0},
4394 {"norecover", 0, 0, 0},
4395 {"nogui", 0, 0, 0},
4396 {"nosplash", 0, 0, 0},
4397 {"noplaywin", 0, 0, 0},
4398 {"noninteractive", 0, 0, 0},
4399 {"startup-ce", 0, 0, 0},
4400 {"startup-mt", 0, 0, 0},
4401 {"vjmode", 0, 0, 0},
4402 {"fxmodesmax", 1, 0, 0},
4403 {"yuvin", 1, 0, 0},
4404 {"debug", 0, 0, 0},
4405 #ifdef ENABLE_OSC
4406 {"oscstart", 1, 0, 0},
4407 {"nooscstart", 0, 0, 0},
4408 #endif
4409 #ifdef ENABLE_JACK
4410 {"jackopts", 1, 0, 0},
4411 #endif
4412 // deprecated
4413 {"nothreaddialog", 0, 0, 0},
4414 {"bigendbug", 1, 0, 0},
4415 {"tmpdir", 1, 0, 0},
4416 {0, 0, 0, 0}
4417 };
4418
4419 int option_index = 0;
4420 const char *charopt;
4421 int c;
4422 int count = 0;
4423
4424 while (1) {
4425 count++;
4426 c = getopt_long_only(argc, argv, "", longopts, &option_index);
4427 if (c == -1) break; // end of options
4428 charopt = longopts[option_index].name;
4429 if (c == '?') {
4430 msg = lives_strdup_printf(_("Invalid option %s on commandline\n"), argv[count]);
4431 LIVES_FATAL(msg);
4432 }
4433 if (!strcmp(charopt, "workdir") || !strcmp(charopt, "tmpdir")) {
4434 if (!*optarg) {
4435 do_abortblank_error(charopt);
4436 continue;
4437 }
4438 if (optarg[0] == '-') {
4439 do_abortblank_error(charopt);
4440 optind--;
4441 continue;
4442 }
4443 if (lives_strlen(optarg) > PATH_MAX - MAX_SET_NAME_LEN * 2) {
4444 toolong = TRUE;
4445 } else {
4446 ensure_isdir(optarg);
4447 if (lives_strlen(optarg) > PATH_MAX - MAX_SET_NAME_LEN * 2) {
4448 toolong = TRUE;
4449 }
4450 }
4451 if (toolong) {
4452 dir_toolong_error(optarg, (tmp = (_("working directory"))), PATH_MAX - MAX_SET_NAME_LEN * 2, TRUE);
4453 lives_free(tmp);
4454 capable->can_write_to_workdir = FALSE;
4455 break;
4456 }
4457
4458 mainw->has_session_workdir = TRUE;
4459 lives_snprintf(prefs->workdir, PATH_MAX, "%s", optarg);
4460
4461 if (!lives_make_writeable_dir(prefs->workdir)) {
4462 // abort if we cannot write to the specified workdir
4463 capable->can_write_to_workdir = FALSE;
4464 break;
4465 }
4466 continue;
4467 }
4468
4469 if (!strcmp(charopt, "configdatadir")) {
4470 if (!*optarg) {
4471 do_abortblank_error(charopt);
4472 continue;
4473 }
4474 if (optarg[0] == '-') {
4475 do_abortblank_error(charopt);
4476 optind--;
4477 continue;
4478 }
4479 if (lives_strlen(optarg) > PATH_MAX - 64) {
4480 toolong = TRUE;
4481 } else {
4482 ensure_isdir(optarg);
4483 if (lives_strlen(optarg) > PATH_MAX - 64) {
4484 toolong = TRUE;
4485 }
4486 }
4487 if (toolong) {
4488 /// FALSE => exit via startup_msg_fatal()
4489 dir_toolong_error(optarg, _("config data directory"), PATH_MAX - 64, FALSE);
4490 }
4491
4492 lives_snprintf(prefs->config_datadir, PATH_MAX, "%s", optarg);
4493 ign_opts.ign_config_datadir = TRUE;
4494 continue;
4495 }
4496
4497 if (!strcmp(charopt, "configfile")) {
4498 if (!*optarg) {
4499 do_abortblank_error(charopt);
4500 continue;
4501 }
4502 if (optarg[0] == '-') {
4503 do_abortblank_error(charopt);
4504 optind--;
4505 continue;
4506 }
4507 if (lives_strlen(optarg) > PATH_MAX - 64) {
4508 toolong = TRUE;
4509 }
4510 if (toolong) {
4511 /// FALSE => exit via startup_msg_fatal()
4512 filename_toolong_error(optarg, _("configuration file"), PATH_MAX, FALSE);
4513 }
4514
4515 lives_snprintf(prefs->configfile, PATH_MAX, "%s", optarg);
4516 ign_opts.ign_configfile = TRUE;
4517 continue;
4518 }
4519
4520 if (!strcmp(charopt, "norecover")) {
4521 // auto no-recovery
4522 no_recover = TRUE;
4523 continue;
4524 }
4525
4526 if (!strcmp(charopt, "recover") || !strcmp(charopt, "autorecover")) {
4527 // auto recovery
4528 auto_recover = TRUE;
4529 continue;
4530 }
4531
4532 if (!strcmp(charopt, "debug")) {
4533 // debug crashes
4534 mainw->debug = TRUE;
4535 continue;
4536 }
4537
4538 if (!strcmp(charopt, "yuvin")) {
4539 #ifdef HAVE_YUV4MPEG
4540 char *dir;
4541 if (!*optarg) {
4542 continue;
4543 }
4544 if (optarg[0] == '-') {
4545 optind--;
4546 continue;
4547 }
4548 lives_snprintf(prefs->yuvin, PATH_MAX, "%s", optarg);
4549 prefs->startup_interface = STARTUP_CE;
4550 ign_opts.ign_stmode = TRUE;
4551 dir = get_dir(prefs->yuvin);
4552 get_basename(prefs->yuvin);
4553 lives_snprintf(prefs->yuvin, PATH_MAX, "%s", (tmp = lives_build_filename(dir, prefs->yuvin, NULL)));
4554 lives_free(tmp);
4555 lives_free(dir);
4556 #else
4557 msg = (_("Must have mjpegtools installed for -yuvin to work"));
4558 do_abort_ok_dialog(msg);
4559 lives_free(msg);
4560 #endif
4561 continue;
4562 }
4563
4564 if (!strcmp(charopt, "dscrit") && optarg) {
4565 // force clipset loading
4566 if (!*optarg) {
4567 do_abortblank_error(charopt);
4568 continue;
4569 }
4570 if (optarg[0] == '-') {
4571 do_abortblank_error(charopt);
4572 optind--;
4573 continue;
4574 }
4575 prefs->ds_crit_level = atoll(optarg);
4576 ign_opts.ign_dscrit = TRUE;
4577 continue;
4578 }
4579
4580 if (!strcmp(charopt, "noset")) {
4581 // override clipset loading
4582 lives_memset(prefs->ar_clipset_name, 0, 1);
4583 prefs->ar_clipset = FALSE;
4584 ign_opts.ign_clipset = TRUE;
4585 continue;
4586 }
4587
4588 if (!strcmp(charopt, "set") && optarg) {
4589 // force clipset loading
4590 if (!*optarg) {
4591 do_abortblank_error(charopt);
4592 continue;
4593 }
4594 if (optarg[0] == '-') {
4595 do_abortblank_error(charopt);
4596 optind--;
4597 continue;
4598 }
4599 if (!is_legal_set_name(optarg, TRUE, TRUE)) {
4600 msg = (_("Abort and retry or continue ?"));
4601 do_abort_ok_dialog(msg);
4602 lives_free(msg);
4603 }
4604 lives_snprintf(prefs->ar_clipset_name, 128, "%s", optarg);
4605 prefs->ar_clipset = TRUE;
4606 ign_opts.ign_clipset = TRUE;
4607 continue;
4608 }
4609
4610 if (!strcmp(charopt, "nolayout")) {
4611 // override layout loading
4612 lives_memset(prefs->ar_layout_name, 0, 1);
4613 prefs->ar_layout = FALSE;
4614 ign_opts.ign_layout = TRUE;
4615 continue;
4616 }
4617
4618 if (!strcmp(charopt, "layout") && optarg) {
4619 // force layout loading
4620 if (!*optarg) {
4621 do_optarg_blank_err(charopt);
4622 continue;
4623 }
4624 if (optarg[0] == '-') {
4625 do_optarg_blank_err(charopt);
4626 optind--;
4627 continue;
4628 }
4629 lives_snprintf(prefs->ar_layout_name, PATH_MAX, "%s", optarg);
4630 prefs->ar_layout = TRUE;
4631 ign_opts.ign_layout = TRUE;
4632 continue;
4633 }
4634
4635 #ifdef ENABLE_OSC
4636 if (!strcmp(charopt, "devicemap") && optarg) {
4637 // force devicemap loading
4638 char *devmap2;
4639 if (!*optarg) {
4640 do_optarg_blank_err(charopt);
4641 continue;
4642 }
4643 if (optarg[0] == '-') {
4644 do_optarg_blank_err(charopt);
4645 optind--;
4646 continue;
4647 }
4648 lives_snprintf(devmap, PATH_MAX, "%s", optarg);
4649 devmap2 = lives_strdup(devmap);
4650 get_basename(devmap);
4651 if (!strcmp(devmap, devmap2)) {
4652 dir = lives_build_filename(prefs->config_datadir, LIVES_DEVICEMAP_DIR, NULL);
4653 } else dir = get_dir(devmap);
4654 lives_snprintf(devmap, PATH_MAX, "%s", (tmp = lives_build_filename(dir, devmap, NULL)));
4655 lives_free(tmp);
4656 lives_free(dir);
4657 lives_free(devmap2);
4658 continue;
4659 }
4660 #endif
4661
4662 if (!strcmp(charopt, "vppdefaults") && optarg) {
4663 // load alternate vpp file
4664 if (!*optarg) {
4665 do_optarg_blank_err(charopt);
4666 continue;
4667 }
4668 if (optarg[0] == '-') {
4669 do_optarg_blank_err(charopt);
4670 optind--;
4671 continue;
4672 }
4673 lives_snprintf(mainw->vpp_defs_file, PATH_MAX, "%s", optarg);
4674 ign_opts.ign_vppdefs = TRUE;
4675 dir = get_dir(mainw->vpp_defs_file);
4676 get_basename(mainw->vpp_defs_file);
4677 lives_snprintf(mainw->vpp_defs_file, PATH_MAX, "%s", (tmp = lives_build_filename(dir, mainw->vpp_defs_file, NULL)));
4678 lives_free(tmp);
4679 lives_free(dir);
4680 continue;
4681 }
4682
4683 if (!strcmp(charopt, "aplayer")) {
4684 boolean apl_valid = FALSE;
4685 if (!*optarg) {
4686 do_optarg_blank_err(charopt);
4687 continue;
4688 }
4689 if (optarg[0] == '-') {
4690 do_optarg_blank_err(charopt);
4691 optind--;
4692 continue;
4693 }
4694 lives_snprintf(buff, 256, "%s", optarg);
4695 // override aplayer default
4696 if (!strcmp(buff, AUDIO_PLAYER_SOX)) {
4697 prefs->audio_player = AUD_PLAYER_SOX;
4698 lives_snprintf(prefs->aplayer, 512, "%s", AUDIO_PLAYER_SOX);
4699 apl_valid = TRUE;
4700 }
4701
4702 if (!strcmp(buff, AUDIO_PLAYER_NONE)) {
4703 // still experimental
4704 prefs->audio_player = AUD_PLAYER_NONE;
4705 lives_snprintf(prefs->aplayer, 512, "%s", AUDIO_PLAYER_NONE);
4706 apl_valid = TRUE;
4707 }
4708
4709 if (!strcmp(buff, AUDIO_PLAYER_JACK)) {
4710 #ifdef ENABLE_JACK
4711 prefs->audio_player = AUD_PLAYER_JACK;
4712 lives_snprintf(prefs->aplayer, 512, "%s", AUDIO_PLAYER_JACK);
4713 apl_valid = TRUE;
4714 #endif
4715 }
4716
4717 if (!strcmp(buff, AUDIO_PLAYER_PULSE) || !strcmp(buff, AUDIO_PLAYER_PULSE_AUDIO)) {
4718 #ifdef HAVE_PULSE_AUDIO
4719 prefs->audio_player = AUD_PLAYER_PULSE;
4720 lives_snprintf(prefs->aplayer, 512, "%s", AUDIO_PLAYER_PULSE);
4721 apl_valid = TRUE;
4722 #endif
4723 }
4724 if (apl_valid) ign_opts.ign_aplayer = TRUE;
4725 else {
4726 msg = lives_strdup_printf(_("Invalid audio player %s"), buff);
4727 LIVES_ERROR(msg);
4728 lives_free(msg);
4729 }
4730 continue;
4731 }
4732
4733 if (!strcmp(charopt, "asource")) {
4734 if (!*optarg) {
4735 do_optarg_blank_err(charopt);
4736 continue;
4737 }
4738 if (optarg[0] == '-') {
4739 do_optarg_blank_err(charopt);
4740 optind--;
4741 continue;
4742 }
4743 lives_snprintf(buff, 256, "%s", optarg);
4744 // override audio source
4745 if (!strcmp(buff, _("external")) || !strcmp(buff, "external")) { // handle translated and original strings
4746 future_prefs->audio_src = prefs->audio_src = AUDIO_SRC_EXT;
4747 ign_opts.ign_asource = TRUE;
4748 } else if (strcmp(buff, _("internal")) && strcmp(buff, "internal")) { // handle translated and original strings
4749 fprintf(stderr, _("Invalid audio source %s\n"), buff);
4750 } else {
4751 future_prefs->audio_src = prefs->audio_src = AUDIO_SRC_INT;
4752 ign_opts.ign_asource = TRUE;
4753 }
4754 continue;
4755 }
4756
4757 if (!strcmp(charopt, "nogui")) {
4758 // force headless mode
4759 prefs->show_gui = FALSE;
4760 continue;
4761 }
4762
4763 if (!strcmp(charopt, "nosplash")) {
4764 // do not show splash
4765 prefs->show_splash = FALSE;
4766 continue;
4767 }
4768
4769 if (!strcmp(charopt, "noplaywin")) {
4770 // do not show the play window
4771 prefs->show_playwin = FALSE;
4772 continue;
4773 }
4774
4775 if (!strcmp(charopt, "noninteractive")) {
4776 // disable menu/toolbar interactivity
4777 prefs->interactive = FALSE;
4778 continue;
4779 }
4780
4781 if (!strcmp(charopt, "nothreaddialog")) {
4782 continue;
4783 }
4784
4785 if (!strcmp(charopt, "fxmodesmax") && optarg) {
4786 if (!*optarg) {
4787 do_optarg_blank_err(charopt);
4788 continue;
4789 }
4790 if (optarg[0] == '-') {
4791 do_optarg_blank_err(charopt);
4792 optind--;
4793 continue;
4794 }
4795 // set number of fx modes
4796 prefs->max_modes_per_key = atoi(optarg);
4797 if (prefs->max_modes_per_key < 1) prefs->max_modes_per_key = 1;
4798 continue;
4799 }
4800
4801 if (!strcmp(charopt, "bigendbug")) {
4802 // only for backwards comptaibility
4803 if (optarg) {
4804 // set bigendbug
4805 prefs->bigendbug = atoi(optarg);
4806 } else prefs->bigendbug = 1;
4807 continue;
4808 }
4809 #ifdef ENABLE_OSC
4810
4811 if (!strcmp(charopt, "oscstart") && optarg) {
4812 if (!*optarg) {
4813 do_optarg_blank_err(charopt);
4814 continue;
4815 }
4816 if (optarg[0] == '-') {
4817 do_optarg_blank_err(charopt);
4818 optind--;
4819 continue;
4820 }
4821 // force OSC start
4822 prefs->osc_udp_port = atoi(optarg);
4823 prefs->osc_start = TRUE;
4824 ign_opts.ign_osc = TRUE;
4825 continue;
4826 }
4827
4828 if (!strcmp(charopt, "nooscstart")) {
4829 // force no OSC start
4830 prefs->osc_start = FALSE;
4831 ign_opts.ign_osc = TRUE;
4832 continue;
4833 }
4834 #endif
4835
4836 #ifdef ENABLE_JACK
4837 if (!strcmp(charopt, "jackopts") && optarg) {
4838 if (!*optarg) {
4839 do_optarg_blank_err(charopt);
4840 continue;
4841 }
4842 if (optarg[0] == '-') {
4843 do_optarg_blank_err(charopt);
4844 optind--;
4845 continue;
4846 }
4847 // override jackopts in config file
4848 ign_opts.ign_jackopts = TRUE;
4849 future_prefs->jack_opts = prefs->jack_opts = atoi(optarg);
4850 continue;
4851 }
4852 #endif
4853 if (!strcmp(charopt, "startup-ce")) {
4854 // force start in clip editor mode
4855 if (!ign_opts.ign_stmode) {
4856 prefs->startup_interface = STARTUP_CE;
4857 ign_opts.ign_stmode = TRUE;
4858 }
4859 continue;
4860 }
4861
4862 if (!strcmp(charopt, "startup-mt")) {
4863 // force start in multitrack mode
4864 if (!ign_opts.ign_stmode) {
4865 prefs->startup_interface = STARTUP_MT;
4866 ign_opts.ign_stmode = TRUE;
4867 }
4868 continue;
4869 }
4870
4871 if (!strcmp(charopt, "vjmode")) {
4872 // force start in multitrack mode
4873 prefs->vj_mode = TRUE;
4874 ign_opts.ign_vjmode = TRUE;
4875 continue;
4876 }
4877 }
4878
4879 if (optind < argc) {
4880 // remaining opts are filename [start_time] [end_frame]
4881 char *dir;
4882 lives_snprintf(start_file, PATH_MAX, "%s", argv[optind++]); // filename
4883 if (optind < argc) start = lives_strtod(argv[optind++], NULL); // start time (seconds)
4884 if (optind < argc) end = atoi(argv[optind++]); // number of frames
4885
4886 if (lives_strrstr(start_file, "://") == NULL) {
4887 // prepend current directory if needed (unless file contains :// - eg. dvd:// or http://)
4888 dir = get_dir(start_file);
4889 get_basename(start_file);
4890 lives_snprintf(start_file, PATH_MAX, "%s", (tmp = lives_build_filename(dir, start_file, NULL)));
4891 lives_free(tmp);
4892 lives_free(dir);
4893 // *INDENT-OFF*
4894 }}}}
4895 // *INDENT-ON*
4896
4897 if (!ign_opts.ign_configfile) {
4898 tmp = lives_build_filename(capable->home_dir, LIVES_DEF_CONFIG_DIR, "lives", LIVES_DEF_CONFIG_FILE, NULL);
4899 lives_snprintf(prefs->configfile, PATH_MAX, "%s", tmp);
4900 lives_free(tmp);
4901 }
4902
4903 if (!ign_opts.ign_config_datadir) {
4904 tmp = lives_build_path(capable->home_dir, LOCAL_HOME_DIR, LIVES_DEF_CONFIG_DATADIR, NULL);
4905 lives_snprintf(prefs->config_datadir, PATH_MAX, "%s", tmp);
4906 lives_free(tmp);
4907 }
4908
4909 // get capabilities and if OK set some initial prefs
4910 theme_error = pre_init();
4911
4912 lives_memset(start_file, 0, 1);
4913
4914 mainw->libthread = gtk_thread;
4915
4916 // what's my name ?
4917 capable->myname_full = lives_find_program_in_path(argv[0]);
4918
4919 if ((mynsize = lives_readlink(capable->myname_full, cdir, PATH_MAX)) != -1) {
4920 // no. i mean, what's my real name ?
4921 lives_memset(cdir + mynsize, 0, 1);
4922 lives_free(capable->myname_full);
4923 capable->myname_full = lives_strdup(cdir);
4924 }
4925
4926 // what's my short name (without the path) ?
4927 lives_snprintf(cdir, PATH_MAX, "%s", capable->myname_full);
4928 get_basename(cdir);
4929 capable->myname = lives_strdup(cdir);
4930
4931 // format is:
4932 // lives [opts] [filename [start_time] [frames]]
4933
4934 // need to do this here, before lives_startup but afer setting ign_opts
4935 mainw->new_vpp = NULL;
4936 mainw->vpp = NULL;
4937 lives_memset(future_prefs->vpp_name, 0, 64);
4938 future_prefs->vpp_argv = NULL;
4939
4940 if (!ign_opts.ign_vppdefs) {
4941 tmp = lives_build_filename(prefs->config_datadir, VPP_DEFS_FILE, NULL);
4942 lives_snprintf(mainw->vpp_defs_file, PATH_MAX, "%s", tmp);
4943 lives_free(tmp);
4944 }
4945
4946 lives_idle_add_simple(lives_startup, NULL);
4947
4948 #ifdef GUI_GTK
4949 if (!gtk_thread) {
4950 gtk_main();
4951 }
4952 #endif
4953
4954 #ifdef GUI_QT
4955 return qapp->exec();
4956 #endif
4957
4958 return 0;
4959 }
4960
4961
startup_message_fatal(char * msg)4962 void startup_message_fatal(char *msg) {
4963 if (mainw) {
4964 if (mainw->splash_window) splash_end();
4965
4966 lives_freep((void **)&mainw->old_vhash);
4967 lives_freep((void **)&old_vhash);
4968 }
4969
4970 do_error_dialog(msg);
4971
4972 LIVES_FATAL(msg);
4973 // needs notify_socket and prefs->omc_events, so seems unlikely it will do anything, but anyway...
4974 lives_notify(LIVES_OSC_NOTIFY_QUIT, msg);
4975 lives_free(msg);
4976 _exit(1);
4977 }
4978
4979
startup_message_nonfatal(const char * msg)4980 LIVES_GLOBAL_INLINE boolean startup_message_nonfatal(const char *msg) {
4981 if (mainw && mainw->ds_status == LIVES_STORAGE_STATUS_CRITICAL) do_abort_ok_dialog(msg);
4982 else do_error_dialog(msg);
4983 return TRUE;
4984 }
4985
4986
startup_message_info(const char * msg)4987 boolean startup_message_info(const char *msg) {
4988 widget_opts.non_modal = TRUE;
4989 do_info_dialog(msg);
4990 widget_opts.non_modal = FALSE;
4991 return TRUE;
4992 }
4993
4994
startup_message_nonfatal_dismissable(const char * msg,uint64_t warning_mask)4995 boolean startup_message_nonfatal_dismissable(const char *msg, uint64_t warning_mask) {
4996 widget_opts.non_modal = TRUE;
4997 do_error_dialog_with_check(msg, warning_mask);
4998 widget_opts.non_modal = FALSE;
4999 return TRUE;
5000 }
5001
5002
5003 ///////////////////////////////// GUI section - TODO: move into another file //////////////////////////////////////
5004
set_main_title(const char * file,int untitled)5005 void set_main_title(const char *file, int untitled) {
5006 char *title, *tmp, *tmp2;
5007 char short_file[256];
5008
5009 if (file && CURRENT_CLIP_IS_VALID) {
5010 if (untitled) {
5011 title = lives_strdup_printf((tmp = _("<%s> %dx%d : %d frames %d bpp %.3f fps")), (tmp2 = get_untitled_name(untitled)),
5012 cfile->hsize, cfile->vsize, cfile->frames, cfile->bpp, cfile->fps);
5013 } else {
5014 lives_snprintf(short_file, 256, "%s", file);
5015 if (cfile->restoring || (cfile->opening && cfile->frames == 123456789)) {
5016 title = lives_strdup_printf((tmp = _("<%s> %dx%d : ??? frames ??? bpp %.3f fps")),
5017 (tmp2 = lives_path_get_basename(file)), cfile->hsize, cfile->vsize, cfile->fps);
5018 } else {
5019 title = lives_strdup_printf((tmp = _("<%s> %dx%d : %d frames %d bpp %.3f fps")),
5020 cfile->clip_type != CLIP_TYPE_VIDEODEV ? (tmp2 = lives_path_get_basename(file))
5021 : (tmp2 = lives_strdup(file)), cfile->hsize, cfile->vsize, cfile->frames, cfile->bpp, cfile->fps);
5022 }
5023 }
5024 lives_free(tmp); lives_free(tmp2);
5025 } else {
5026 title = (_("<No File>"));
5027 }
5028
5029 lives_window_set_title(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), title);
5030 lives_free(title);
5031
5032 if (!LIVES_IS_PLAYING && mainw->play_window) play_window_set_title();
5033 }
5034
5035
sensitize_rfx(void)5036 void sensitize_rfx(void) {
5037 if (!mainw->foreign) {
5038 if (mainw->rendered_fx) {
5039 for (int i = 1; i <= mainw->num_rendered_effects_builtin + mainw->num_rendered_effects_custom +
5040 mainw->num_rendered_effects_test; i++)
5041 if (mainw->rendered_fx[i].menuitem && mainw->rendered_fx[i].min_frames >= 0)
5042 lives_widget_set_sensitive(mainw->rendered_fx[i].menuitem, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO);
5043 if (mainw->rendered_fx[0].menuitem && LIVES_IS_WIDGET(mainw->rendered_fx[0].menuitem)) {
5044 if (!CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID
5045 && ((has_video_filters(FALSE) && !has_video_filters(TRUE)) ||
5046 (cfile->achans > 0 && prefs->audio_src == AUDIO_SRC_INT
5047 && has_audio_filters(AF_TYPE_ANY))
5048 || mainw->agen_key != 0)) {
5049 lives_widget_set_sensitive(mainw->rendered_fx[0].menuitem, TRUE);
5050 } else lives_widget_set_sensitive(mainw->rendered_fx[0].menuitem, FALSE);
5051 // *INDENT-OFF*
5052 }}
5053 // *INDENT-ON*
5054
5055 if (mainw->num_rendered_effects_test > 0) {
5056 lives_widget_set_sensitive(mainw->run_test_rfx_submenu, TRUE);
5057 }
5058
5059 if (mainw->has_custom_gens) {
5060 lives_widget_set_sensitive(mainw->custom_gens_submenu, TRUE);
5061 }
5062
5063 if (mainw->has_custom_tools) {
5064 lives_widget_set_sensitive(mainw->custom_tools_submenu, TRUE);
5065 }
5066
5067 if (mainw->has_custom_effects) {
5068 lives_widget_set_sensitive(mainw->custom_effects_submenu, TRUE);
5069 }
5070
5071 if (mainw->resize_menuitem) {
5072 lives_widget_set_sensitive(mainw->resize_menuitem, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO);
5073 }
5074 }
5075 }
5076
5077
sensitize(void)5078 void sensitize(void) {
5079 // sensitize main window controls
5080 // READY MODE
5081 int i;
5082
5083 if (LIVES_IS_PLAYING || mainw->is_processing || mainw->go_away) return;
5084
5085 if (mainw->multitrack) {
5086 mt_sensitise(mainw->multitrack);
5087 return;
5088 }
5089
5090 mainw->sense_state &= LIVES_SENSE_STATE_INTERACTIVE;
5091 mainw->sense_state |= LIVES_SENSE_STATE_SENSITIZED;
5092
5093 lives_widget_set_sensitive(mainw->open, TRUE);
5094 lives_widget_set_sensitive(mainw->open_sel, TRUE);
5095 lives_widget_set_sensitive(mainw->open_vcd_menu, TRUE);
5096 #ifdef HAVE_WEBM
5097 lives_widget_set_sensitive(mainw->open_loc_menu, TRUE);
5098 #else
5099 lives_widget_set_sensitive(mainw->open_loc, TRUE);
5100 #endif
5101 lives_widget_set_sensitive(mainw->open_device_menu, TRUE);
5102 lives_widget_set_sensitive(mainw->restore, TRUE);
5103 lives_widget_set_sensitive(mainw->recent_menu, TRUE);
5104 lives_widget_set_sensitive(mainw->save_as, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID
5105 && capable->has_encoder_plugins);
5106 #ifdef LIBAV_TRANSCODE
5107 lives_widget_set_sensitive(mainw->transcode, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO);
5108 #endif
5109 if (!prefs->vj_mode) {
5110 lives_widget_set_sensitive(mainw->backup, CURRENT_CLIP_IS_VALID && !CURRENT_CLIP_IS_CLIPBOARD);
5111 lives_widget_set_sensitive(mainw->save_selection, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO &&
5112 capable->has_encoder_plugins);
5113 }
5114 lives_widget_set_sensitive(mainw->clear_ds, TRUE);
5115 lives_widget_set_sensitive(mainw->load_cdtrack, TRUE);
5116 lives_widget_set_sensitive(mainw->playsel, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO);
5117
5118 if (!prefs->vj_mode) {
5119 lives_widget_set_sensitive(mainw->copy, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO);
5120 lives_widget_set_sensitive(mainw->cut, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO);
5121 lives_widget_set_sensitive(mainw->rev_clipboard, !(clipboard == NULL));
5122 lives_widget_set_sensitive(mainw->playclip, !(clipboard == NULL));
5123 lives_widget_set_sensitive(mainw->paste_as_new, !(clipboard == NULL));
5124 lives_widget_set_sensitive(mainw->insert, !(clipboard == NULL));
5125 lives_widget_set_sensitive(mainw->merge, (clipboard != NULL && !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO));
5126 }
5127 lives_widget_set_sensitive(mainw->xdelete, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO);
5128 lives_widget_set_sensitive(mainw->playall, CURRENT_CLIP_IS_VALID && !CURRENT_CLIP_IS_CLIPBOARD);
5129 lives_widget_set_sensitive(mainw->m_playbutton, CURRENT_CLIP_IS_VALID && !CURRENT_CLIP_IS_CLIPBOARD);
5130 lives_widget_set_sensitive(mainw->m_playselbutton, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO);
5131 lives_widget_set_sensitive(mainw->m_rewindbutton, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID &&
5132 cfile->real_pointer_time > 0.);
5133 lives_widget_set_sensitive(mainw->m_loopbutton, TRUE);
5134 lives_widget_set_sensitive(mainw->m_mutebutton, TRUE);
5135 if (mainw->preview_box) {
5136 lives_widget_set_sensitive(mainw->p_playbutton, CURRENT_CLIP_IS_VALID && !CURRENT_CLIP_IS_CLIPBOARD);
5137 lives_widget_set_sensitive(mainw->p_playselbutton, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO);
5138 lives_widget_set_sensitive(mainw->p_rewindbutton, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID &&
5139 cfile->real_pointer_time > 0.);
5140 lives_widget_set_sensitive(mainw->p_loopbutton, TRUE);
5141 lives_widget_set_sensitive(mainw->p_mutebutton, TRUE);
5142 }
5143
5144 lives_widget_set_sensitive(mainw->rewind, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID && cfile->real_pointer_time > 0.);
5145 lives_widget_set_sensitive(mainw->show_file_info, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID);
5146 lives_widget_set_sensitive(mainw->show_file_comments, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID);
5147 lives_widget_set_sensitive(mainw->full_screen, TRUE);
5148 if (!prefs->vj_mode)
5149 lives_widget_set_sensitive(mainw->mt_menu, TRUE);
5150 lives_widget_set_sensitive(mainw->unicap, TRUE);
5151 lives_widget_set_sensitive(mainw->firewire, TRUE);
5152 lives_widget_set_sensitive(mainw->tvdev, TRUE);
5153
5154 if (!prefs->vj_mode) {
5155 lives_widget_set_sensitive(mainw->export_proj, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID);
5156 lives_widget_set_sensitive(mainw->import_proj, TRUE);
5157 }
5158
5159 if (is_realtime_aplayer(prefs->audio_player) && prefs->audio_player != AUD_PLAYER_NONE) {
5160 lives_widget_set_sensitive(mainw->int_audio_checkbutton, prefs->audio_src != AUDIO_SRC_INT);
5161 lives_widget_set_sensitive(mainw->ext_audio_checkbutton, prefs->audio_src != AUDIO_SRC_EXT);
5162 }
5163
5164 if (!prefs->vj_mode) {
5165 if (RFX_LOADED) {
5166 sensitize_rfx();
5167 }
5168 }
5169 lives_widget_set_sensitive(mainw->record_perf, TRUE);
5170 if (!prefs->vj_mode) {
5171 lives_widget_set_sensitive(mainw->export_submenu, !CURRENT_CLIP_IS_CLIPBOARD && (CURRENT_CLIP_HAS_AUDIO));
5172 lives_widget_set_sensitive(mainw->export_selaudio, (CURRENT_CLIP_HAS_VIDEO && CURRENT_CLIP_HAS_AUDIO));
5173 lives_widget_set_sensitive(mainw->export_allaudio, CURRENT_CLIP_HAS_AUDIO);
5174 lives_widget_set_sensitive(mainw->normalize_audio, CURRENT_CLIP_HAS_AUDIO);
5175 lives_widget_set_sensitive(mainw->recaudio_submenu, TRUE);
5176 lives_widget_set_sensitive(mainw->recaudio_sel, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO);
5177 lives_widget_set_sensitive(mainw->append_audio, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_AUDIO);
5178 lives_widget_set_sensitive(mainw->trim_submenu, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_AUDIO);
5179 lives_widget_set_sensitive(mainw->voladj, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_AUDIO);
5180 lives_widget_set_sensitive(mainw->fade_aud_in, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_AUDIO);
5181 lives_widget_set_sensitive(mainw->fade_aud_out, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_AUDIO);
5182 lives_widget_set_sensitive(mainw->trim_audio, !CURRENT_CLIP_IS_CLIPBOARD
5183 && CURRENT_CLIP_HAS_VIDEO && CURRENT_CLIP_HAS_AUDIO);
5184 lives_widget_set_sensitive(mainw->trim_to_pstart, !CURRENT_CLIP_IS_CLIPBOARD && (CURRENT_CLIP_HAS_AUDIO &&
5185 cfile->real_pointer_time > 0.));
5186 lives_widget_set_sensitive(mainw->delaudio_submenu, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_AUDIO);
5187 lives_widget_set_sensitive(mainw->delsel_audio, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO
5188 && CURRENT_CLIP_HAS_AUDIO);
5189 lives_widget_set_sensitive(mainw->delall_audio, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO
5190 && CURRENT_CLIP_HAS_AUDIO);
5191 lives_widget_set_sensitive(mainw->resample_audio, !CURRENT_CLIP_IS_CLIPBOARD && (CURRENT_CLIP_HAS_AUDIO &&
5192 capable->has_sox_sox));
5193 }
5194 lives_widget_set_sensitive(mainw->dsize, TRUE);
5195 lives_widget_set_sensitive(mainw->fade, !(mainw->fs));
5196 lives_widget_set_sensitive(mainw->mute_audio, TRUE);
5197 lives_widget_set_sensitive(mainw->loop_video, !CURRENT_CLIP_IS_CLIPBOARD && (CURRENT_CLIP_TOTAL_TIME > 0.));
5198 lives_widget_set_sensitive(mainw->loop_continue, TRUE);
5199 lives_widget_set_sensitive(mainw->load_audio, TRUE);
5200 lives_widget_set_sensitive(mainw->load_subs, CURRENT_CLIP_IS_VALID && !CURRENT_CLIP_IS_CLIPBOARD);
5201 lives_widget_set_sensitive(mainw->erase_subs, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID && cfile->subt != NULL);
5202 if ((check_for_executable(&capable->has_cdda2wav, EXEC_CDDA2WAV)
5203 || check_for_executable(&capable->has_icedax, EXEC_ICEDAX))
5204 && *prefs->cdplay_device) lives_widget_set_sensitive(mainw->load_cdtrack, TRUE);
5205 lives_widget_set_sensitive(mainw->rename, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID && !cfile->opening);
5206 lives_widget_set_sensitive(mainw->change_speed, CURRENT_CLIP_IS_VALID && !CURRENT_CLIP_IS_CLIPBOARD);
5207 if (!prefs->vj_mode)
5208 lives_widget_set_sensitive(mainw->resample_video, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO);
5209 lives_widget_set_sensitive(mainw->preferences, TRUE);
5210 if (!prefs->vj_mode)
5211 lives_widget_set_sensitive(mainw->ins_silence, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO);
5212 lives_widget_set_sensitive(mainw->close, CURRENT_CLIP_IS_VALID && !CURRENT_CLIP_IS_CLIPBOARD);
5213 lives_widget_set_sensitive(mainw->select_submenu, !CURRENT_CLIP_IS_CLIPBOARD && !mainw->selwidth_locked &&
5214 CURRENT_CLIP_HAS_VIDEO);
5215 update_sel_menu();
5216 #ifdef HAVE_YUV4MPEG
5217 lives_widget_set_sensitive(mainw->open_yuv4m, TRUE);
5218 #endif
5219
5220 lives_widget_set_sensitive(mainw->select_new, !CURRENT_CLIP_IS_CLIPBOARD
5221 && CURRENT_CLIP_IS_VALID && (cfile->insert_start > 0));
5222 lives_widget_set_sensitive(mainw->select_last, !CURRENT_CLIP_IS_CLIPBOARD
5223 && CURRENT_CLIP_IS_VALID && (cfile->undo_start > 0));
5224 lives_widget_set_sensitive(mainw->lock_selwidth, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO);
5225
5226 lives_widget_set_sensitive(mainw->undo, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID && cfile->undoable);
5227 lives_widget_set_sensitive(mainw->redo, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID && cfile->redoable);
5228 lives_widget_set_sensitive(mainw->show_clipboard_info, !(clipboard == NULL));
5229 lives_widget_set_sensitive(mainw->capture, TRUE);
5230 lives_widget_set_sensitive(mainw->vj_save_set, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID);
5231 lives_widget_set_sensitive(mainw->vj_load_set, !*mainw->set_name);
5232 lives_widget_set_sensitive(mainw->vj_reset, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID);
5233 lives_widget_set_sensitive(mainw->vj_realize, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID &&
5234 cfile->frame_index != NULL);
5235 lives_widget_set_sensitive(mainw->midi_learn, TRUE);
5236 lives_widget_set_sensitive(mainw->midi_save, has_devicemap(-1));
5237 lives_widget_set_sensitive(mainw->toy_tv, TRUE);
5238 lives_widget_set_sensitive(mainw->autolives, TRUE);
5239 lives_widget_set_sensitive(mainw->toy_random_frames, TRUE);
5240 //lives_widget_set_sensitive(mainw->open_lives2lives, TRUE);
5241 if (!prefs->vj_mode)
5242 lives_widget_set_sensitive(mainw->gens_submenu, TRUE);
5243 lives_widget_set_sensitive(mainw->troubleshoot, TRUE);
5244 lives_widget_set_sensitive(mainw->expl_missing, TRUE);
5245
5246 lives_widget_set_sensitive(mainw->show_quota, TRUE);
5247
5248 if (!CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID && (cfile->start == 1 || cfile->end == cfile->frames) &&
5249 !(cfile->start == 1 &&
5250 cfile->end == cfile->frames)) {
5251 lives_widget_set_sensitive(mainw->select_invert, TRUE);
5252 } else {
5253 lives_widget_set_sensitive(mainw->select_invert, FALSE);
5254 }
5255
5256 if (!CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID && cfile->menuentry) {
5257 lives_signal_handler_block(mainw->spinbutton_end, mainw->spin_end_func);
5258 lives_spin_button_set_range(LIVES_SPIN_BUTTON(mainw->spinbutton_end), 1, cfile->frames);
5259 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), cfile->end);
5260 lives_signal_handler_unblock(mainw->spinbutton_end, mainw->spin_end_func);
5261
5262 lives_signal_handler_block(mainw->spinbutton_start, mainw->spin_start_func);
5263 lives_spin_button_set_range(LIVES_SPIN_BUTTON(mainw->spinbutton_start), 1, cfile->frames);
5264 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), cfile->start);
5265 lives_signal_handler_unblock(mainw->spinbutton_start, mainw->spin_start_func);
5266
5267 if (LIVES_IS_INTERACTIVE) {
5268 lives_widget_set_sensitive(mainw->spinbutton_start, TRUE);
5269 lives_widget_set_sensitive(mainw->spinbutton_end, TRUE);
5270 }
5271
5272 if (mainw->play_window && (mainw->prv_link == PRV_START || mainw->prv_link == PRV_END)) {
5273 // unblock spinbutton in play window
5274 lives_widget_set_sensitive(mainw->preview_spinbutton, TRUE);
5275 }
5276 }
5277
5278 // clips menu
5279 for (i = 1; i < MAX_FILES; i++) {
5280 if (mainw->files[i]) {
5281 if (mainw->files[i]->menuentry) {
5282 lives_widget_set_sensitive(mainw->files[i]->menuentry, TRUE);
5283 // *INDENT-OFF*
5284 }}}
5285 // *INDENT-ON*
5286 if (prefs->vj_mode) {
5287 #ifdef LIBAV_TRANSCODE
5288 lives_widget_set_sensitive(mainw->transcode, FALSE);
5289 #endif
5290 lives_widget_set_sensitive(mainw->import_theme, FALSE);
5291 lives_widget_set_sensitive(mainw->export_theme, FALSE);
5292 lives_widget_set_sensitive(mainw->backup, FALSE);
5293 lives_widget_set_sensitive(mainw->capture, FALSE);
5294 lives_widget_set_sensitive(mainw->save_as, FALSE);
5295 lives_widget_set_sensitive(mainw->mt_menu, FALSE);
5296 lives_widget_set_sensitive(mainw->gens_submenu, FALSE);
5297 lives_widget_set_sensitive(mainw->utilities_submenu, FALSE);
5298 }
5299 }
5300
5301
desensitize(void)5302 void desensitize(void) {
5303 // desensitize the main window when we are playing/processing a clip
5304 int i;
5305
5306 if (mainw->multitrack) {
5307 mt_desensitise(mainw->multitrack);
5308 return;
5309 }
5310
5311 mainw->sense_state &= LIVES_SENSE_STATE_INTERACTIVE;
5312 mainw->sense_state |= LIVES_SENSE_STATE_INSENSITIZED;
5313
5314 //lives_widget_set_sensitive (mainw->open, mainw->playing_file>-1);
5315 lives_widget_set_sensitive(mainw->open, FALSE);
5316 lives_widget_set_sensitive(mainw->open_sel, FALSE);
5317 lives_widget_set_sensitive(mainw->open_vcd_menu, FALSE);
5318 #ifdef HAVE_WEBM
5319 lives_widget_set_sensitive(mainw->open_loc_menu, FALSE);
5320 #else
5321 lives_widget_set_sensitive(mainw->open_loc, FALSE);
5322 #endif
5323 lives_widget_set_sensitive(mainw->open_device_menu, FALSE);
5324 #ifdef HAVE_YUV4MPEG
5325 lives_widget_set_sensitive(mainw->open_yuv4m, FALSE);
5326 #endif
5327
5328 lives_widget_set_sensitive(mainw->firewire, FALSE);
5329 lives_widget_set_sensitive(mainw->tvdev, FALSE);
5330
5331 lives_widget_set_sensitive(mainw->recent_menu, FALSE);
5332 lives_widget_set_sensitive(mainw->restore, FALSE);
5333 lives_widget_set_sensitive(mainw->clear_ds, FALSE);
5334 lives_widget_set_sensitive(mainw->midi_learn, FALSE);
5335 lives_widget_set_sensitive(mainw->midi_save, FALSE);
5336 lives_widget_set_sensitive(mainw->load_cdtrack, FALSE);
5337 lives_widget_set_sensitive(mainw->save_as, FALSE);
5338 #ifdef LIBAV_TRANSCODE
5339 lives_widget_set_sensitive(mainw->transcode, FALSE);
5340 #endif
5341 lives_widget_set_sensitive(mainw->backup, FALSE);
5342 lives_widget_set_sensitive(mainw->playsel, FALSE);
5343 lives_widget_set_sensitive(mainw->playclip, FALSE);
5344 lives_widget_set_sensitive(mainw->copy, FALSE);
5345 lives_widget_set_sensitive(mainw->cut, FALSE);
5346 lives_widget_set_sensitive(mainw->preferences, FALSE);
5347 lives_widget_set_sensitive(mainw->rev_clipboard, FALSE);
5348 lives_widget_set_sensitive(mainw->insert, FALSE);
5349 lives_widget_set_sensitive(mainw->merge, FALSE);
5350 lives_widget_set_sensitive(mainw->xdelete, FALSE);
5351 if (!prefs->pause_during_pb) {
5352 lives_widget_set_sensitive(mainw->playall, FALSE);
5353 }
5354 lives_widget_set_sensitive(mainw->rewind, FALSE);
5355 if (!prefs->vj_mode) {
5356 if (RFX_LOADED) {
5357 if (!mainw->foreign) {
5358 for (i = 0; i <= mainw->num_rendered_effects_builtin + mainw->num_rendered_effects_custom +
5359 mainw->num_rendered_effects_test; i++)
5360 if (mainw->rendered_fx[i].menuitem && mainw->rendered_fx[i].menuitem &&
5361 mainw->rendered_fx[i].min_frames >= 0)
5362 lives_widget_set_sensitive(mainw->rendered_fx[i].menuitem, FALSE);
5363 }
5364 }
5365 }
5366
5367 if (mainw->resize_menuitem) {
5368 lives_widget_set_sensitive(mainw->resize_menuitem, FALSE);
5369 }
5370
5371 if (!prefs->vj_mode)
5372 if (mainw->num_rendered_effects_test > 0) {
5373 lives_widget_set_sensitive(mainw->run_test_rfx_submenu, FALSE);
5374 }
5375
5376
5377 if (mainw->has_custom_gens) {
5378 lives_widget_set_sensitive(mainw->custom_gens_submenu, FALSE);
5379 }
5380
5381 if (mainw->has_custom_tools) {
5382 lives_widget_set_sensitive(mainw->custom_tools_submenu, FALSE);
5383 }
5384
5385 if (!mainw->foreign)
5386 if (mainw->has_custom_effects) {
5387 lives_widget_set_sensitive(mainw->custom_effects_submenu, FALSE);
5388 }
5389
5390 lives_widget_set_sensitive(mainw->export_submenu, FALSE);
5391 lives_widget_set_sensitive(mainw->recaudio_submenu, FALSE);
5392 lives_widget_set_sensitive(mainw->append_audio, FALSE);
5393 lives_widget_set_sensitive(mainw->trim_submenu, FALSE);
5394 lives_widget_set_sensitive(mainw->delaudio_submenu, FALSE);
5395 lives_widget_set_sensitive(mainw->gens_submenu, FALSE);
5396 lives_widget_set_sensitive(mainw->troubleshoot, FALSE);
5397 lives_widget_set_sensitive(mainw->expl_missing, FALSE);
5398 lives_widget_set_sensitive(mainw->resample_audio, FALSE);
5399 lives_widget_set_sensitive(mainw->voladj, FALSE);
5400 lives_widget_set_sensitive(mainw->fade_aud_in, FALSE);
5401 lives_widget_set_sensitive(mainw->fade_aud_out, FALSE);
5402 lives_widget_set_sensitive(mainw->normalize_audio, FALSE);
5403 lives_widget_set_sensitive(mainw->ins_silence, FALSE);
5404 lives_widget_set_sensitive(mainw->loop_video, is_realtime_aplayer(prefs->audio_player));
5405 if (!is_realtime_aplayer(prefs->audio_player)) lives_widget_set_sensitive(mainw->mute_audio, FALSE);
5406 lives_widget_set_sensitive(mainw->load_audio, FALSE);
5407 lives_widget_set_sensitive(mainw->load_subs, FALSE);
5408 lives_widget_set_sensitive(mainw->erase_subs, FALSE);
5409 lives_widget_set_sensitive(mainw->save_selection, FALSE);
5410 lives_widget_set_sensitive(mainw->close, FALSE);
5411 lives_widget_set_sensitive(mainw->change_speed, FALSE);
5412 lives_widget_set_sensitive(mainw->resample_video, FALSE);
5413 lives_widget_set_sensitive(mainw->undo, FALSE);
5414 lives_widget_set_sensitive(mainw->redo, FALSE);
5415 lives_widget_set_sensitive(mainw->paste_as_new, FALSE);
5416 lives_widget_set_sensitive(mainw->capture, FALSE);
5417 lives_widget_set_sensitive(mainw->toy_tv, FALSE);
5418 lives_widget_set_sensitive(mainw->vj_save_set, FALSE);
5419 lives_widget_set_sensitive(mainw->vj_load_set, FALSE);
5420 lives_widget_set_sensitive(mainw->vj_realize, FALSE);
5421 lives_widget_set_sensitive(mainw->vj_reset, FALSE);
5422 lives_widget_set_sensitive(mainw->show_quota, FALSE);
5423 lives_widget_set_sensitive(mainw->export_proj, FALSE);
5424 lives_widget_set_sensitive(mainw->import_proj, FALSE);
5425 lives_widget_set_sensitive(mainw->recaudio_sel, FALSE);
5426 lives_widget_set_sensitive(mainw->mt_menu, FALSE);
5427
5428 lives_widget_set_sensitive(mainw->int_audio_checkbutton, FALSE);
5429 lives_widget_set_sensitive(mainw->ext_audio_checkbutton, FALSE);
5430
5431 if (mainw->current_file >= 0 && (!LIVES_IS_PLAYING || mainw->foreign)) {
5432 // if (!cfile->opening||mainw->dvgrab_preview||mainw->preview||cfile->opening_only_audio) {
5433 // disable the 'clips' menu entries
5434 for (i = 1; i < MAX_FILES; i++) {
5435 if (mainw->files[i]) {
5436 if (mainw->files[i]->menuentry) {
5437 if (i != mainw->current_file) {
5438 lives_widget_set_sensitive(mainw->files[i]->menuentry, FALSE);
5439 // *INDENT-OFF*
5440 }}}}}
5441 // *INDENT-ON*
5442 }
5443
5444
procw_desensitize(void)5445 void procw_desensitize(void) {
5446 // switch on/off a few extra widgets in the processing dialog
5447
5448 int current_file;
5449
5450 if (mainw->multitrack) return;
5451
5452 mainw->sense_state &= LIVES_SENSE_STATE_INTERACTIVE;
5453 mainw->sense_state |= LIVES_SENSE_STATE_PROC_INSENSITIZED | LIVES_SENSE_STATE_INSENSITIZED;
5454
5455 if (!CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID
5456 && (cfile->menuentry || cfile->opening) && !mainw->preview) {
5457 // an effect etc,
5458 lives_widget_set_sensitive(mainw->loop_video, CURRENT_CLIP_HAS_AUDIO && CURRENT_CLIP_HAS_VIDEO);
5459 lives_widget_set_sensitive(mainw->loop_continue, TRUE);
5460
5461 if (CURRENT_CLIP_HAS_AUDIO && CURRENT_CLIP_HAS_VIDEO) {
5462 mainw->loop = lives_check_menu_item_get_active(LIVES_CHECK_MENU_ITEM(mainw->loop_video));
5463 }
5464 if (CURRENT_CLIP_HAS_AUDIO && CURRENT_CLIP_HAS_VIDEO) {
5465 mainw->mute = lives_check_menu_item_get_active(LIVES_CHECK_MENU_ITEM(mainw->mute_audio));
5466 }
5467 }
5468 if (!CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID && !cfile->menuentry) {
5469 lives_widget_set_sensitive(mainw->rename, FALSE);
5470 if (cfile->opening || cfile->restoring) {
5471 // loading, restoring etc
5472 lives_widget_set_sensitive(mainw->lock_selwidth, FALSE);
5473 lives_widget_set_sensitive(mainw->show_file_comments, FALSE);
5474 if (!cfile->opening_only_audio) {
5475 lives_widget_set_sensitive(mainw->toy_random_frames, FALSE);
5476 }
5477 }
5478 }
5479
5480 current_file = mainw->current_file;
5481 if (CURRENT_CLIP_IS_VALID && cfile->cb_src != -1) mainw->current_file = cfile->cb_src;
5482
5483 if (CURRENT_CLIP_IS_VALID) {
5484 // stop the start and end from being changed
5485 // better to clamp the range than make insensitive, this way we stop
5486 // other widgets (like the video bar) updating it
5487 lives_signal_handler_block(mainw->spinbutton_end, mainw->spin_end_func);
5488 lives_spin_button_set_range(LIVES_SPIN_BUTTON(mainw->spinbutton_end), cfile->end, cfile->end);
5489 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), cfile->end);
5490 lives_signal_handler_unblock(mainw->spinbutton_end, mainw->spin_end_func);
5491 lives_signal_handler_block(mainw->spinbutton_start, mainw->spin_start_func);
5492 lives_spin_button_set_range(LIVES_SPIN_BUTTON(mainw->spinbutton_start), cfile->start, cfile->start);
5493 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), cfile->start);
5494 lives_signal_handler_unblock(mainw->spinbutton_start, mainw->spin_start_func);
5495 }
5496
5497 mainw->current_file = current_file;
5498
5499 if (mainw->play_window && (mainw->prv_link == PRV_START || mainw->prv_link == PRV_END)) {
5500 // block spinbutton in play window
5501 lives_widget_set_sensitive(mainw->preview_spinbutton, FALSE);
5502 }
5503
5504 lives_widget_set_sensitive(mainw->sa_button, FALSE);
5505 lives_widget_set_sensitive(mainw->select_submenu, FALSE);
5506 lives_widget_set_sensitive(mainw->toy_tv, FALSE);
5507 lives_widget_set_sensitive(mainw->autolives, FALSE);
5508 lives_widget_set_sensitive(mainw->export_submenu, FALSE);
5509 lives_widget_set_sensitive(mainw->trim_submenu, FALSE);
5510 lives_widget_set_sensitive(mainw->delaudio_submenu, FALSE);
5511 lives_widget_set_sensitive(mainw->load_cdtrack, FALSE);
5512 lives_widget_set_sensitive(mainw->open_lives2lives, FALSE);
5513 lives_widget_set_sensitive(mainw->record_perf, FALSE);
5514 lives_widget_set_sensitive(mainw->unicap, FALSE);
5515
5516 if (!CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID && cfile->nopreview) {
5517 lives_widget_set_sensitive(mainw->m_playbutton, FALSE);
5518 if (mainw->preview_box) lives_widget_set_sensitive(mainw->p_playbutton, FALSE);
5519 lives_widget_set_sensitive(mainw->m_playselbutton, FALSE);
5520 if (mainw->preview_box) lives_widget_set_sensitive(mainw->p_playselbutton, FALSE);
5521 }
5522 }
5523
5524
set_drawing_area_from_pixbuf(LiVESWidget * widget,LiVESPixbuf * pixbuf,lives_painter_surface_t * surface)5525 void set_drawing_area_from_pixbuf(LiVESWidget * widget, LiVESPixbuf * pixbuf,
5526 lives_painter_surface_t *surface) {
5527 LiVESXWindow *xwin;
5528 lives_rect_t update_rect;
5529 lives_painter_t *cr;
5530 int cx, cy;
5531 int rwidth, rheight, width, height, owidth, oheight;
5532
5533 if (!surface || !widget) return;
5534
5535 xwin = lives_widget_get_xwindow(widget);
5536 if (!LIVES_IS_XWINDOW(xwin)) return;
5537
5538 cr = lives_painter_create_from_surface(surface);
5539
5540 if (!cr) return;
5541
5542 rwidth = lives_widget_get_allocation_width(widget);
5543 rheight = lives_widget_get_allocation_height(widget);
5544
5545 if (!rwidth || !rheight) return;
5546
5547 rwidth = (rwidth >> 1) << 1;
5548 rheight = (rheight >> 1) << 1;
5549
5550 if (pixbuf) {
5551 owidth = width = lives_pixbuf_get_width(pixbuf);
5552 oheight = height = lives_pixbuf_get_height(pixbuf);
5553
5554 cx = (rwidth - width) >> 1;
5555 if (cx < 0) cx = 0;
5556 cy = (rheight - height) >> 1;
5557 if (cy < 0) cy = 0;
5558
5559 if (widget == mainw->start_image || widget == mainw->end_image
5560 || (mainw->multitrack && widget == mainw->play_image)
5561 || (widget == mainw->play_window && !mainw->fs)) {
5562 int xrwidth, xrheight;
5563 LiVESWidget *p = lives_widget_get_parent(widget);
5564
5565 p = lives_widget_get_parent(p);
5566
5567 xrwidth = lives_widget_get_allocation_width(p);
5568 xrheight = lives_widget_get_allocation_height(p);
5569 lives_painter_render_background(p, cr, 0., 0., xrwidth, xrheight);
5570
5571 if (mainw->multitrack) {
5572 rwidth = xrwidth;
5573 rheight = xrheight;
5574 }
5575
5576 if (!mainw->multitrack && (prefs->ce_maxspect || prefs->letterbox)) {
5577 calc_maxspect(rwidth, rheight, &width, &height);
5578
5579 width = (width >> 1) << 1;
5580 height = (height >> 1) << 1;
5581
5582 if (width > owidth && height > oheight) {
5583 width = owidth;
5584 height = oheight;
5585 }
5586 }
5587
5588 if (mainw->multitrack) {
5589 cx = (rwidth - width) >> 1;
5590 if (cx < 0) cx = 0;
5591 cy = (rheight - height) >> 1;
5592 if (cy < 0) cy = 0;
5593 }
5594 }
5595
5596 lives_widget_set_opacity(widget, 1.);
5597
5598 if ((!mainw->multitrack || widget != mainw->play_image) && widget != mainw->preview_image) {
5599 if (!LIVES_IS_PLAYING && mainw->multitrack && widget == mainw->play_image) clear_widget_bg(widget, surface);
5600 if (prefs->funky_widgets) {
5601 lives_painter_set_source_rgb_from_lives_rgba(cr, &palette->frame_surround);
5602 if (widget == mainw->start_image || widget == mainw->end_image || widget == mainw->play_image) {
5603 lives_painter_move_to(cr, 0, 0);
5604 lives_painter_line_to(cr, rwidth, 0);
5605 lives_painter_move_to(cr, 0, rheight);
5606 lives_painter_line_to(cr, rwidth, rheight);
5607 } else lives_painter_rectangle(cr, cx - 1, cy - 1, width + 2, height + 2);
5608 // frame
5609 lives_painter_stroke(cr);
5610 cx += 2;
5611 cy += 4;
5612 }
5613 }
5614
5615 /// x, y values are offset of top / left of image in drawing area
5616 lives_painter_set_source_pixbuf(cr, pixbuf, cx, cy);
5617 lives_painter_rectangle(cr, cx, cy, rwidth - cx * 2, rheight + 2 - cy * 2);
5618 } else {
5619 lives_widget_set_opacity(widget, 0.);
5620 clear_widget_bg(widget, surface);
5621 }
5622 lives_painter_fill(cr);
5623 lives_painter_destroy(cr);
5624
5625 if (widget == mainw->play_window && rheight > mainw->pheight) rheight = mainw->pheight;
5626
5627 update_rect.x = update_rect.y = 0;
5628 update_rect.width = rwidth;
5629 update_rect.height = rheight;
5630
5631 if (!LIVES_IS_XWINDOW(xwin)) return;
5632 lives_xwindow_invalidate_rect(lives_widget_get_xwindow(widget), &update_rect, FALSE);
5633 }
5634
5635
showclipimgs(void)5636 void showclipimgs(void) {
5637 if (CURRENT_CLIP_IS_VALID) {
5638 load_end_image(cfile->end);
5639 load_start_image(cfile->start);
5640 } else {
5641 load_end_image(0);
5642 load_start_image(0);
5643 }
5644 lives_widget_queue_draw(mainw->start_image);
5645 lives_widget_queue_draw(mainw->end_image);
5646 lives_widget_context_update();
5647 }
5648
5649
load_start_image(int frame)5650 void load_start_image(int frame) {
5651 LiVESPixbuf *start_pixbuf = NULL;
5652 LiVESPixbuf *orig_pixbuf = NULL;
5653 weed_layer_t *layer = NULL;
5654 weed_timecode_t tc;
5655 LiVESInterpType interp;
5656 char *xmd5sum = NULL;
5657 char *fname = NULL;
5658 boolean expose = FALSE;
5659 boolean cache_it = TRUE;
5660 int rwidth, rheight, width, height;
5661 int tries = 2;
5662 frames_t xpf;
5663
5664 if (!prefs->show_gui) return;
5665 if (mainw->multitrack) return;
5666
5667 if (LIVES_IS_PLAYING && mainw->fs && (!mainw->sep_win || ((prefs->gui_monitor == prefs->play_monitor ||
5668 capable->nmonitors == 1) &&
5669 (!mainw->ext_playback ||
5670 (mainw->vpp->capabilities & VPP_LOCAL_DISPLAY))))) return;
5671 if (frame < 0) {
5672 frame = -frame;
5673 expose = TRUE;
5674 }
5675
5676 lives_widget_set_opacity(mainw->start_image, 1.);
5677
5678 if (!CURRENT_CLIP_IS_NORMAL || frame < 1 || frame > cfile->frames) {
5679 int bx, by, hsize, vsize;
5680 int scr_width = GUI_SCREEN_WIDTH;
5681 int scr_height = GUI_SCREEN_HEIGHT;
5682 int vspace = get_vspace();
5683 get_border_size(LIVES_MAIN_WINDOW_WIDGET, &bx, &by);
5684 if (by > MENU_HIDE_LIM)
5685 lives_window_set_hide_titlebar_when_maximized(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), TRUE);
5686 hsize = (scr_width - (H_RESIZE_ADJUST * 3 + bx)) / 3;
5687 vsize = scr_height - (CE_TIMELINE_VSPACE * 1.01 / sqrt(widget_opts.scale) + vspace + by
5688 + (prefs->show_msg_area ? mainw->mbar_res : 0)
5689 + widget_opts.border_width * 2);
5690 if (LIVES_IS_PLAYING && mainw->double_size) {
5691 hsize /= 2;
5692 vsize /= 2;
5693 }
5694 lives_widget_set_size_request(mainw->start_image, hsize, vsize);
5695 lives_widget_set_size_request(mainw->frame1, hsize, vsize);
5696 lives_widget_set_size_request(mainw->eventbox3, hsize, vsize);
5697
5698 lives_widget_set_hexpand(mainw->frame1, FALSE);
5699 lives_widget_set_vexpand(mainw->frame1, FALSE);
5700 }
5701
5702 if (CURRENT_CLIP_IS_VALID && (cfile->clip_type == CLIP_TYPE_YUV4MPEG || cfile->clip_type == CLIP_TYPE_VIDEODEV)) {
5703 if (!mainw->camframe) {
5704 LiVESError *error = NULL;
5705 char *fname = lives_strdup_printf("%s.%s", THEME_FRAME_IMG_LITERAL, LIVES_FILE_EXT_JPG);
5706 char *tmp = lives_build_filename(prefs->prefix_dir, THEME_DIR, LIVES_THEME_CAMERA, fname, NULL);
5707 mainw->camframe = lives_pixbuf_new_from_file(tmp, &error);
5708 if (mainw->camframe) lives_pixbuf_saturate_and_pixelate(mainw->camframe, mainw->camframe, 0.0, FALSE);
5709 lives_free(tmp); lives_free(fname);
5710 }
5711 set_drawing_area_from_pixbuf(mainw->start_image, mainw->camframe, mainw->si_surface);
5712 return;
5713 }
5714
5715 if (!CURRENT_CLIP_IS_NORMAL || mainw->current_file == mainw->scrap_file || frame < 1 || frame > cfile->frames) {
5716 if (mainw->imframe) {
5717 set_drawing_area_from_pixbuf(mainw->start_image, mainw->imframe, mainw->si_surface);
5718 } else {
5719 set_drawing_area_from_pixbuf(mainw->start_image, NULL, mainw->si_surface);
5720 }
5721 if (!palette || !(palette->style & STYLE_LIGHT)) {
5722 lives_widget_set_opacity(mainw->start_image, 0.8);
5723 } else {
5724 lives_widget_set_opacity(mainw->start_image, 0.4);
5725 }
5726 return;
5727 }
5728
5729 xpf = ABS(get_indexed_frame(mainw->current_file, frame));
5730
5731 check_stcache:
5732 if (mainw->st_fcache) {
5733 if (lives_layer_get_clip(mainw->st_fcache) == mainw->current_file
5734 && lives_layer_get_frame(mainw->st_fcache) == xpf) {
5735 if (is_virtual_frame(mainw->current_file, frame)) layer = mainw->st_fcache;
5736 else {
5737 if (cfile->clip_type == CLIP_TYPE_DISK && capable->has_md5sum) {
5738 char *md5sum = weed_get_string_value(mainw->st_fcache, WEED_LEAF_MD5SUM, NULL);
5739 if (md5sum) {
5740 if (!fname) fname = make_image_file_name(cfile, frame, get_image_ext_for_type(cfile->img_type));
5741 if (!xmd5sum) xmd5sum = get_md5sum(fname);
5742 if (!lives_strcmp(md5sum, xmd5sum)) layer = mainw->st_fcache;
5743 lives_free(md5sum);
5744 // *INDENT-OFF*
5745 }}}}}
5746 // *INDENT-ON*
5747
5748 if (!layer) {
5749 if (mainw->st_fcache) {
5750 if (mainw->st_fcache != mainw->en_fcache && mainw->st_fcache != mainw->pr_fcache)
5751 weed_layer_free(mainw->st_fcache);
5752 mainw->st_fcache = NULL;
5753 }
5754 if (tries--) {
5755 if (tries == 1) mainw->st_fcache = mainw->pr_fcache;
5756 else mainw->st_fcache = mainw->en_fcache;
5757 goto check_stcache;
5758 }
5759 }
5760 lives_freep((void **)&fname);
5761
5762 tc = ((frame - 1.)) / cfile->fps * TICKS_PER_SECOND;
5763
5764 if (!prefs->ce_maxspect && !prefs->letterbox) {
5765 // if we are not playing, and it would be slow to seek to the frame, convert it to an image
5766 if (!LIVES_IS_PLAYING && !layer && cfile->clip_type == CLIP_TYPE_FILE && is_virtual_frame(mainw->current_file, frame) &&
5767 cfile->ext_src) {
5768 lives_clip_data_t *cdata = ((lives_decoder_t *)cfile->ext_src)->cdata;
5769 if (cdata && (expose || !(cdata->seek_flag & LIVES_SEEK_FAST))) {
5770 virtual_to_images(mainw->current_file, frame, frame, FALSE, &start_pixbuf);
5771 cache_it = FALSE;
5772 }
5773 }
5774
5775 if (!layer && !start_pixbuf) {
5776 layer = lives_layer_new_for_frame(mainw->current_file, frame);
5777 if (pull_frame_at_size(layer, get_image_ext_for_type(cfile->img_type), tc, cfile->hsize, cfile->vsize,
5778 WEED_PALETTE_RGB24)) {
5779 check_layer_ready(layer);
5780 interp = get_interp_value(prefs->pb_quality, TRUE);
5781 if (!resize_layer(layer, cfile->hsize, cfile->vsize, interp, WEED_PALETTE_RGB24, 0) ||
5782 !convert_layer_palette(layer, WEED_PALETTE_RGB24, 0)) {
5783 if (xmd5sum) lives_free(xmd5sum);
5784 return;
5785 }
5786 }
5787 }
5788
5789 if (!start_pixbuf) start_pixbuf = layer_to_pixbuf(layer, TRUE, TRUE);
5790
5791 if (LIVES_IS_PIXBUF(start_pixbuf)) {
5792 set_drawing_area_from_pixbuf(mainw->start_image, start_pixbuf, mainw->si_surface);
5793 if (!cache_it || weed_layer_get_pixel_data_packed(layer) || !(pixbuf_to_layer(layer, start_pixbuf)))
5794 lives_widget_object_unref(start_pixbuf);
5795 } else cache_it = FALSE;
5796
5797 if (!cache_it) {
5798 if (layer) weed_layer_free(layer);
5799 mainw->st_fcache = NULL;
5800 } else {
5801 if (!mainw->st_fcache) {
5802 mainw->st_fcache = layer;
5803 if (!is_virtual_frame(mainw->current_file, frame)) {
5804 if (cfile->clip_type == CLIP_TYPE_DISK && capable->has_md5sum) {
5805 if (!xmd5sum) {
5806 char *fname = make_image_file_name(cfile, frame, get_image_ext_for_type(cfile->img_type));
5807 xmd5sum = get_md5sum(fname);
5808 lives_free(fname);
5809 }
5810 weed_set_string_value(layer, WEED_LEAF_MD5SUM, xmd5sum);
5811 // *INDENT-OFF*
5812 }}
5813 lives_layer_set_frame(layer, xpf);
5814 lives_layer_set_clip(layer, mainw->current_file);
5815 }}
5816 // *INDENT-ON*
5817 if (xmd5sum) lives_free(xmd5sum);
5818 return;
5819 }
5820
5821 do {
5822 width = cfile->hsize;
5823 height = cfile->vsize;
5824
5825 // TODO *** - if width*height==0, show broken frame image
5826
5827 rwidth = lives_widget_get_allocation_width(mainw->start_image);
5828 rheight = lives_widget_get_allocation_height(mainw->start_image);
5829
5830 calc_maxspect(rwidth, rheight, &width, &height);
5831 width = (width >> 2) << 2;
5832 height = (height >> 2) << 2;
5833
5834 // if we are not playing, and it would be slow to seek to the frame, convert it to an image
5835 if (!LIVES_IS_PLAYING && !layer && cfile->clip_type == CLIP_TYPE_FILE && is_virtual_frame(mainw->current_file, frame) &&
5836 cfile->ext_src) {
5837 lives_clip_data_t *cdata = ((lives_decoder_t *)cfile->ext_src)->cdata;
5838 if (cdata && (expose || !(cdata->seek_flag & LIVES_SEEK_FAST))) {
5839 // TODO: make background thread
5840 virtual_to_images(mainw->current_file, frame, frame, FALSE, &start_pixbuf);
5841 cache_it = FALSE;
5842 }
5843 }
5844
5845 if (!layer && !start_pixbuf) {
5846 layer = lives_layer_new_for_frame(mainw->current_file, frame);
5847 if (pull_frame_at_size(layer, get_image_ext_for_type(cfile->img_type), tc, width, height, WEED_PALETTE_RGB24)) {
5848 check_layer_ready(layer);
5849 interp = get_interp_value(prefs->pb_quality, TRUE);
5850 if (!resize_layer(layer, width, height, interp, WEED_PALETTE_RGB24, 0) ||
5851 !convert_layer_palette(layer, WEED_PALETTE_RGB24, 0)) {
5852 weed_layer_free(layer);
5853 if (xmd5sum) lives_free(xmd5sum);
5854 return;
5855 }
5856 }
5857 }
5858
5859 if (!start_pixbuf || lives_pixbuf_get_width(start_pixbuf) != width || lives_pixbuf_get_height(start_pixbuf) != height) {
5860 if (!orig_pixbuf) {
5861 if (layer) orig_pixbuf = layer_to_pixbuf(layer, TRUE, TRUE);
5862 else orig_pixbuf = start_pixbuf;
5863 }
5864 if (start_pixbuf != orig_pixbuf && LIVES_IS_PIXBUF(start_pixbuf)) {
5865 start_pixbuf = NULL;
5866 }
5867 if (LIVES_IS_PIXBUF(orig_pixbuf)) {
5868 if (lives_pixbuf_get_width(orig_pixbuf) == width && lives_pixbuf_get_height(orig_pixbuf) == height)
5869 start_pixbuf = orig_pixbuf;
5870 else {
5871 start_pixbuf = lives_pixbuf_scale_simple(orig_pixbuf, width, height, LIVES_INTERP_BEST);
5872 }
5873 }
5874 }
5875
5876 if (LIVES_IS_PIXBUF(start_pixbuf)) {
5877 set_drawing_area_from_pixbuf(mainw->start_image, start_pixbuf, mainw->si_surface);
5878 }
5879
5880 #if !GTK_CHECK_VERSION(3, 0, 0)
5881 lives_widget_queue_resize(mainw->start_image);
5882 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
5883 } while (rwidth != lives_widget_get_allocation_width(mainw->start_image) ||
5884 rheight != lives_widget_get_allocation_height(mainw->start_image));
5885 #else
5886 }
5887 while (FALSE);
5888 #endif
5889 if (start_pixbuf != orig_pixbuf && LIVES_IS_PIXBUF(start_pixbuf)) {
5890 lives_widget_object_unref(start_pixbuf);
5891 }
5892
5893 if (LIVES_IS_PIXBUF(orig_pixbuf)) {
5894 if (!cache_it || weed_layer_get_pixel_data_packed(layer) || !(pixbuf_to_layer(layer, orig_pixbuf)))
5895 lives_widget_object_unref(orig_pixbuf);
5896 } else cache_it = FALSE;
5897
5898 if (!cache_it) {
5899 weed_layer_free(layer);
5900 mainw->st_fcache = NULL;
5901 } else {
5902 if (!mainw->st_fcache) {
5903 mainw->st_fcache = layer;
5904 if (!is_virtual_frame(mainw->current_file, frame)) {
5905 if (cfile->clip_type == CLIP_TYPE_DISK && capable->has_md5sum) {
5906 if (!xmd5sum) {
5907 char *fname = make_image_file_name(cfile, frame, get_image_ext_for_type(cfile->img_type));
5908 xmd5sum = get_md5sum(fname);
5909 lives_free(fname);
5910 }
5911 weed_set_string_value(layer, WEED_LEAF_MD5SUM, xmd5sum);
5912 // *INDENT-OFF*
5913 }}
5914 lives_layer_set_frame(layer, xpf);
5915 lives_layer_set_clip(layer, mainw->current_file);
5916 }}
5917 // *INDENT-ON*
5918 if (xmd5sum) lives_free(xmd5sum);
5919 }
5920
5921
load_end_image(int frame)5922 void load_end_image(int frame) {
5923 LiVESPixbuf *end_pixbuf = NULL;
5924 LiVESPixbuf *orig_pixbuf = NULL;
5925 weed_layer_t *layer = NULL;
5926 weed_timecode_t tc;
5927 LiVESInterpType interp;
5928 char *xmd5sum = NULL;
5929 char *fname = NULL;
5930 boolean expose = FALSE;
5931 boolean cache_it = TRUE;
5932 int rwidth, rheight, width, height;
5933 int tries = 2;
5934 frames_t xpf;
5935
5936 if (!prefs->show_gui) return;
5937 if (mainw->multitrack) return;
5938
5939 if (LIVES_IS_PLAYING && mainw->fs && (!mainw->sep_win || ((prefs->gui_monitor == prefs->play_monitor ||
5940 capable->nmonitors == 1) &&
5941 (!mainw->ext_playback ||
5942 (mainw->vpp->capabilities & VPP_LOCAL_DISPLAY))))) return;
5943 if (frame < 0) {
5944 frame = -frame;
5945 expose = TRUE;
5946 }
5947
5948 lives_widget_set_opacity(mainw->end_image, 1.);
5949
5950 if (!CURRENT_CLIP_IS_NORMAL || frame < 1 || frame > cfile->frames) {
5951 int bx, by, hsize, vsize;
5952 int scr_width = GUI_SCREEN_WIDTH;
5953 int scr_height = GUI_SCREEN_HEIGHT;
5954 int vspace = get_vspace();
5955 get_border_size(LIVES_MAIN_WINDOW_WIDGET, &bx, &by);
5956 if (by > MENU_HIDE_LIM)
5957 lives_window_set_hide_titlebar_when_maximized(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), TRUE);
5958 hsize = (scr_width - (H_RESIZE_ADJUST * 3 + bx)) / 3;
5959 vsize = scr_height - (CE_TIMELINE_VSPACE * 1.01 / sqrt(widget_opts.scale) + vspace + by
5960 + (prefs->show_msg_area ? mainw->mbar_res : 0)
5961 + widget_opts.border_width * 2);
5962 if (LIVES_IS_PLAYING && mainw->double_size) {
5963 hsize /= 2;
5964 vsize /= 2;
5965 }
5966 lives_widget_set_size_request(mainw->end_image, hsize, vsize);
5967 lives_widget_set_size_request(mainw->frame2, hsize, vsize);
5968 lives_widget_set_size_request(mainw->eventbox4, hsize, vsize);
5969
5970 lives_widget_set_hexpand(mainw->frame2, FALSE);
5971 lives_widget_set_vexpand(mainw->frame2, FALSE);
5972 }
5973
5974 if (CURRENT_CLIP_IS_VALID && (cfile->clip_type == CLIP_TYPE_YUV4MPEG || cfile->clip_type == CLIP_TYPE_VIDEODEV)) {
5975 if (!mainw->camframe) {
5976 LiVESError *error = NULL;
5977 char *fname = lives_strdup_printf("%s.%s", THEME_FRAME_IMG_LITERAL, LIVES_FILE_EXT_JPG);
5978 char *tmp = lives_build_filename(prefs->prefix_dir, THEME_DIR, LIVES_THEME_CAMERA, fname, NULL);
5979 mainw->camframe = lives_pixbuf_new_from_file(tmp, &error);
5980 if (mainw->camframe) lives_pixbuf_saturate_and_pixelate(mainw->camframe, mainw->camframe, 0.0, FALSE);
5981 lives_free(tmp); lives_free(fname);
5982 }
5983
5984 set_drawing_area_from_pixbuf(mainw->end_image, mainw->camframe, mainw->ei_surface);
5985 return;
5986 }
5987
5988 if (!CURRENT_CLIP_IS_NORMAL || mainw->current_file == mainw->scrap_file || frame < 1 || frame > cfile->frames) {
5989 if (mainw->imframe) {
5990 set_drawing_area_from_pixbuf(mainw->end_image, mainw->imframe, mainw->ei_surface);
5991 } else {
5992 set_drawing_area_from_pixbuf(mainw->end_image, NULL, mainw->ei_surface);
5993 }
5994 if (!palette || !(palette->style & STYLE_LIGHT)) {
5995 lives_widget_set_opacity(mainw->end_image, 0.8);
5996 } else {
5997 lives_widget_set_opacity(mainw->end_image, 0.4);
5998 }
5999 return;
6000 }
6001
6002 xpf = ABS(get_indexed_frame(mainw->current_file, frame));
6003 check_encache:
6004 if (mainw->en_fcache) {
6005 if (lives_layer_get_clip(mainw->en_fcache) == mainw->current_file
6006 && lives_layer_get_frame(mainw->en_fcache) == xpf) {
6007 if (is_virtual_frame(mainw->current_file, frame)) layer = mainw->en_fcache;
6008 else {
6009 if (cfile->clip_type == CLIP_TYPE_DISK && capable->has_md5sum) {
6010 char *md5sum = weed_get_string_value(mainw->en_fcache, WEED_LEAF_MD5SUM, NULL);
6011 if (md5sum) {
6012 if (!fname) fname = make_image_file_name(cfile, frame, get_image_ext_for_type(cfile->img_type));
6013 if (!xmd5sum) xmd5sum = get_md5sum(fname);
6014 if (!lives_strcmp(md5sum, xmd5sum)) layer = mainw->en_fcache;
6015 lives_free(md5sum);
6016 // *INDENT-OFF*
6017 }}}}}
6018 // *INDENT-ON*
6019
6020 if (!layer) {
6021 if (mainw->en_fcache) {
6022 if (mainw->en_fcache != mainw->st_fcache && mainw->en_fcache != mainw->pr_fcache)
6023 weed_layer_free(mainw->en_fcache);
6024 mainw->en_fcache = NULL;
6025 }
6026 if (tries--) {
6027 if (tries == 1) mainw->en_fcache = mainw->pr_fcache;
6028 else mainw->en_fcache = mainw->st_fcache;
6029 goto check_encache;
6030 }
6031 }
6032
6033 lives_freep((void **)&fname);
6034
6035 tc = (frame - 1.) / cfile->fps * TICKS_PER_SECOND;
6036
6037 if (!prefs->ce_maxspect && !prefs->letterbox) {
6038 // if we are not playing, and it would be slow to seek to the frame, convert it to an image
6039 if (!LIVES_IS_PLAYING && !layer && cfile->clip_type == CLIP_TYPE_FILE && is_virtual_frame(mainw->current_file, frame) &&
6040 cfile->ext_src) {
6041 lives_clip_data_t *cdata = ((lives_decoder_t *)cfile->ext_src)->cdata;
6042 if (cdata && (expose || !(cdata->seek_flag & LIVES_SEEK_FAST))) {
6043 virtual_to_images(mainw->current_file, frame, frame, FALSE, &end_pixbuf);
6044 cache_it = FALSE;
6045 }
6046 }
6047
6048 if (!layer && !end_pixbuf) {
6049 layer = lives_layer_new_for_frame(mainw->current_file, frame);
6050 if (pull_frame_at_size(layer, get_image_ext_for_type(cfile->img_type), tc, cfile->hsize, cfile->vsize,
6051 WEED_PALETTE_RGB24)) {
6052 check_layer_ready(layer);
6053 interp = get_interp_value(prefs->pb_quality, TRUE);
6054 if (!resize_layer(layer, cfile->hsize, cfile->vsize, interp, WEED_PALETTE_RGB24, 0) ||
6055 !convert_layer_palette(layer, WEED_PALETTE_RGB24, 0)) {
6056 if (xmd5sum) lives_free(xmd5sum);
6057 return;
6058 }
6059 }
6060 }
6061
6062 if (!end_pixbuf) end_pixbuf = layer_to_pixbuf(layer, TRUE, TRUE);
6063
6064 if (LIVES_IS_PIXBUF(end_pixbuf)) {
6065 set_drawing_area_from_pixbuf(mainw->end_image, end_pixbuf, mainw->ei_surface);
6066 if (!cache_it || weed_layer_get_pixel_data_packed(layer) || !(pixbuf_to_layer(layer, end_pixbuf)))
6067 lives_widget_object_unref(end_pixbuf);
6068 } else cache_it = FALSE;
6069
6070 if (!cache_it) {
6071 if (layer) weed_layer_free(layer);
6072 mainw->en_fcache = NULL;
6073 } else {
6074 if (!mainw->en_fcache) {
6075 mainw->en_fcache = layer;
6076 if (!is_virtual_frame(mainw->current_file, frame)) {
6077 if (cfile->clip_type == CLIP_TYPE_DISK && capable->has_md5sum) {
6078 if (!xmd5sum) {
6079 char *fname = make_image_file_name(cfile, frame, get_image_ext_for_type(cfile->img_type));
6080 xmd5sum = get_md5sum(fname);
6081 lives_free(fname);
6082 }
6083 weed_set_string_value(layer, WEED_LEAF_MD5SUM, xmd5sum);
6084 // *INDENT-OFF*
6085 }}
6086 lives_layer_set_frame(layer, xpf);
6087 lives_layer_set_clip(layer, mainw->current_file);
6088 }}
6089 // *INDENT-ON*
6090 return;
6091 }
6092
6093 do {
6094 width = cfile->hsize;
6095 height = cfile->vsize;
6096
6097 rwidth = lives_widget_get_allocation_width(mainw->end_image);
6098 rheight = lives_widget_get_allocation_height(mainw->end_image);
6099
6100 calc_maxspect(rwidth, rheight, &width, &height);
6101 width = (width >> 2) << 2;
6102 height = (height >> 2) << 2;
6103
6104 // if we are not playing, and it would be slow to seek to the frame, convert it to an image
6105 if (!LIVES_IS_PLAYING && !layer && cfile->clip_type == CLIP_TYPE_FILE && is_virtual_frame(mainw->current_file, frame) &&
6106 cfile->ext_src) {
6107 lives_clip_data_t *cdata = ((lives_decoder_t *)cfile->ext_src)->cdata;
6108 if (cdata && (expose || !(cdata->seek_flag & LIVES_SEEK_FAST))) {
6109 virtual_to_images(mainw->current_file, frame, frame, FALSE, &end_pixbuf);
6110 cache_it = FALSE;
6111 }
6112 }
6113
6114 if (!layer && !end_pixbuf) {
6115 layer = lives_layer_new_for_frame(mainw->current_file, frame);
6116 if (pull_frame_at_size(layer, get_image_ext_for_type(cfile->img_type), tc, width, height, WEED_PALETTE_RGB24)) {
6117 check_layer_ready(layer);
6118 interp = get_interp_value(prefs->pb_quality, TRUE);
6119 if (!resize_layer(layer, width, height, interp, WEED_PALETTE_RGB24, 0) ||
6120 !convert_layer_palette(layer, WEED_PALETTE_RGB24, 0)) {
6121 weed_layer_free(layer);
6122 if (xmd5sum) lives_free(xmd5sum);
6123 return;
6124 }
6125 }
6126 }
6127
6128 if (!end_pixbuf || lives_pixbuf_get_width(end_pixbuf) != width || lives_pixbuf_get_height(end_pixbuf) != height) {
6129 if (!orig_pixbuf) {
6130 if (layer) orig_pixbuf = layer_to_pixbuf(layer, TRUE, TRUE);
6131 else orig_pixbuf = end_pixbuf;
6132 }
6133 if (end_pixbuf != orig_pixbuf && LIVES_IS_PIXBUF(end_pixbuf)) {
6134 lives_widget_object_unref(end_pixbuf);
6135 end_pixbuf = NULL;
6136 }
6137 if (LIVES_IS_PIXBUF(orig_pixbuf)) {
6138 if (lives_pixbuf_get_width(orig_pixbuf) == width && lives_pixbuf_get_height(orig_pixbuf) == height)
6139 end_pixbuf = orig_pixbuf;
6140 else {
6141 end_pixbuf = lives_pixbuf_scale_simple(orig_pixbuf, width, height, LIVES_INTERP_BEST);
6142 }
6143 }
6144 }
6145
6146 if (LIVES_IS_PIXBUF(end_pixbuf)) {
6147 set_drawing_area_from_pixbuf(mainw->end_image, end_pixbuf, mainw->ei_surface);
6148 }
6149
6150 #if !GTK_CHECK_VERSION(3, 0, 0)
6151 lives_widget_queue_resize(mainw->end_image);
6152 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET, TRUE);
6153 } while (rwidth != lives_widget_get_allocation_width(mainw->end_image) ||
6154 rheight != lives_widget_get_allocation_height(mainw->end_image));
6155 #if 0
6156 {
6157 #endif
6158 #else
6159 } while (FALSE);
6160 #endif
6161
6162 if (end_pixbuf != orig_pixbuf && LIVES_IS_PIXBUF(end_pixbuf)) {
6163 lives_widget_object_unref(end_pixbuf);
6164 }
6165
6166 if (LIVES_IS_PIXBUF(orig_pixbuf)) {
6167 if (!cache_it || weed_layer_get_pixel_data_packed(layer) || !(pixbuf_to_layer(layer, orig_pixbuf)))
6168 lives_widget_object_unref(orig_pixbuf);
6169 } else cache_it = FALSE;
6170
6171 if (!cache_it) {
6172 weed_layer_free(layer);
6173 mainw->en_fcache = NULL;
6174 } else {
6175 if (!mainw->en_fcache) {
6176 mainw->en_fcache = layer;
6177 if (!is_virtual_frame(mainw->current_file, frame)) {
6178 if (cfile->clip_type == CLIP_TYPE_DISK && capable->has_md5sum) {
6179 if (!xmd5sum) {
6180 char *fname = make_image_file_name(cfile, frame, get_image_ext_for_type(cfile->img_type));
6181 xmd5sum = get_md5sum(fname);
6182 lives_free(fname);
6183 }
6184 weed_set_string_value(layer, WEED_LEAF_MD5SUM, xmd5sum);
6185 // *INDENT-OFF*
6186 }}
6187 lives_layer_set_frame(layer, xpf);
6188 lives_layer_set_clip(layer, mainw->current_file);
6189 }}
6190 // *INDENT-ON*
6191 if (xmd5sum) lives_free(xmd5sum);
6192 }
6193 #if 0
6194 }
6195 #endif
6196
6197 #ifndef IS_LIBLIVES
main(int argc,char * argv[])6198 int main(int argc, char *argv[]) {
6199 // call any hooks here
6200 return real_main(argc, argv, NULL, 0l);
6201 }
6202 #endif
6203
6204
load_preview_image(boolean update_always)6205 void load_preview_image(boolean update_always) {
6206 // this is for the sepwin preview
6207 // update_always==TRUE = update widgets from mainw->preview_frame
6208 LiVESPixbuf *pixbuf = NULL;
6209 weed_layer_t *layer = NULL;
6210 boolean cache_it = TRUE;
6211 char *xmd5sum = NULL;
6212 char *fname = NULL;
6213 frames_t xpf = -1;
6214 int tries = 2;
6215 int preview_frame;
6216 int width, height;
6217
6218 if (!prefs->show_gui) return;
6219 if (LIVES_IS_PLAYING) return;
6220
6221 lives_widget_set_opacity(mainw->preview_image, 1.);
6222
6223 if (CURRENT_CLIP_IS_VALID && (cfile->clip_type == CLIP_TYPE_YUV4MPEG || cfile->clip_type == CLIP_TYPE_VIDEODEV)) {
6224 if (!mainw->camframe) {
6225 LiVESError *error = NULL;
6226 char *fname = lives_strdup_printf("%s.%s", THEME_FRAME_IMG_LITERAL, LIVES_FILE_EXT_JPG);
6227 char *tmp = lives_build_filename(prefs->prefix_dir, THEME_DIR, LIVES_THEME_CAMERA, fname, NULL);
6228 mainw->camframe = lives_pixbuf_new_from_file(tmp, &error);
6229 if (mainw->camframe) lives_pixbuf_saturate_and_pixelate(mainw->camframe, mainw->camframe, 0.0, FALSE);
6230 lives_free(tmp); lives_free(fname);
6231 fname = NULL;
6232 }
6233 pixbuf = lives_pixbuf_scale_simple(mainw->camframe, mainw->pwidth, mainw->pheight, LIVES_INTERP_BEST);
6234 set_drawing_area_from_pixbuf(mainw->preview_image, pixbuf, mainw->pi_surface);
6235 if (pixbuf) lives_widget_object_unref(pixbuf);
6236 mainw->preview_frame = 1;
6237 lives_signal_handler_block(mainw->preview_spinbutton, mainw->preview_spin_func);
6238 lives_spin_button_set_range(LIVES_SPIN_BUTTON(mainw->preview_spinbutton), 1, 1);
6239 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->preview_spinbutton), 1);
6240 lives_signal_handler_unblock(mainw->preview_spinbutton, mainw->preview_spin_func);
6241 lives_widget_set_size_request(mainw->preview_image, mainw->pwidth, mainw->pheight);
6242 return;
6243 }
6244
6245 if (!CURRENT_CLIP_IS_NORMAL || !CURRENT_CLIP_HAS_VIDEO) {
6246 mainw->preview_frame = 0;
6247 lives_signal_handler_block(mainw->preview_spinbutton, mainw->preview_spin_func);
6248 lives_spin_button_set_range(LIVES_SPIN_BUTTON(mainw->preview_spinbutton), 0, 0);
6249 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->preview_spinbutton), 0);
6250 lives_signal_handler_unblock(mainw->preview_spinbutton, mainw->preview_spin_func);
6251 if (mainw->imframe) {
6252 lives_widget_set_size_request(mainw->preview_image, lives_pixbuf_get_width(mainw->imframe),
6253 lives_pixbuf_get_height(mainw->imframe));
6254 set_drawing_area_from_pixbuf(mainw->preview_image, mainw->imframe, mainw->pi_surface);
6255 } else set_drawing_area_from_pixbuf(mainw->preview_image, NULL, mainw->pi_surface);
6256 if (!palette || !(palette->style & STYLE_LIGHT)) {
6257 lives_widget_set_opacity(mainw->preview_image, 0.8);
6258 } else {
6259 lives_widget_set_opacity(mainw->preview_image, 0.4);
6260 }
6261 return;
6262 }
6263
6264 if (!update_always) {
6265 // set current frame from spins, set range
6266 // set mainw->preview_frame to 0 before calling to force an update (e.g after a clip switch)
6267 switch (mainw->prv_link) {
6268 case PRV_END:
6269 preview_frame = cfile->end;
6270 break;
6271 case PRV_PTR:
6272 preview_frame = calc_frame_from_time(mainw->current_file, cfile->pointer_time);
6273 break;
6274 case PRV_START:
6275 preview_frame = cfile->start;
6276 break;
6277 default:
6278 preview_frame = mainw->preview_frame > 0 ? mainw->preview_frame : 1;
6279 if (preview_frame > cfile->frames) preview_frame = cfile->frames;
6280 break;
6281 }
6282
6283 lives_signal_handler_block(mainw->preview_spinbutton, mainw->preview_spin_func);
6284 lives_spin_button_set_range(LIVES_SPIN_BUTTON(mainw->preview_spinbutton), 1, cfile->frames);
6285 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->preview_spinbutton), preview_frame);
6286 lives_signal_handler_unblock(mainw->preview_spinbutton, mainw->preview_spin_func);
6287
6288 mainw->preview_frame = preview_frame;
6289 }
6290
6291 if (mainw->preview_frame < 1 || mainw->preview_frame > cfile->frames) {
6292 pixbuf = lives_pixbuf_scale_simple(mainw->imframe, cfile->hsize, cfile->vsize, LIVES_INTERP_BEST);
6293 if (!palette || !(palette->style & STYLE_LIGHT)) {
6294 lives_widget_set_opacity(mainw->preview_image, 0.4);
6295 } else {
6296 lives_widget_set_opacity(mainw->preview_image, 0.8);
6297 }
6298 } else {
6299 weed_timecode_t tc;
6300 xpf = ABS(get_indexed_frame(mainw->current_file, mainw->preview_frame));
6301 check_prcache:
6302 if (mainw->pr_fcache) {
6303 if (lives_layer_get_clip(mainw->pr_fcache) == mainw->current_file
6304 && lives_layer_get_frame(mainw->pr_fcache) == xpf) {
6305 if (is_virtual_frame(mainw->current_file, mainw->preview_frame)) layer = mainw->pr_fcache;
6306 else {
6307 if (cfile->clip_type == CLIP_TYPE_DISK && capable->has_md5sum) {
6308 char *md5sum = weed_get_string_value(mainw->pr_fcache, WEED_LEAF_MD5SUM, NULL);
6309 if (md5sum) {
6310 if (!fname) fname = make_image_file_name(cfile, mainw->preview_frame, get_image_ext_for_type(cfile->img_type));
6311 if (!xmd5sum) xmd5sum = get_md5sum(fname);
6312 if (!lives_strcmp(md5sum, xmd5sum)) layer = mainw->pr_fcache;
6313 lives_free(md5sum);
6314 // *INDENT-OFF*
6315 }}}}}
6316 // *INDENT-ON*
6317 if (!layer) {
6318 if (mainw->pr_fcache) {
6319 if (mainw->pr_fcache != mainw->st_fcache && mainw->pr_fcache != mainw->en_fcache)
6320 weed_layer_free(mainw->pr_fcache);
6321 mainw->pr_fcache = NULL;
6322 }
6323 if (tries--) {
6324 if (tries == 1) mainw->pr_fcache = mainw->st_fcache;
6325 else mainw->pr_fcache = mainw->en_fcache;
6326 goto check_prcache;
6327 }
6328 }
6329 lives_freep((void **)&fname);
6330
6331 // if we are not playing, and it would be slow to seek to the frame, convert it to an image
6332 if (!LIVES_IS_PLAYING && !layer && cfile->clip_type == CLIP_TYPE_FILE &&
6333 is_virtual_frame(mainw->current_file, mainw->preview_frame) &&
6334 cfile->ext_src) {
6335 lives_clip_data_t *cdata = ((lives_decoder_t *)cfile->ext_src)->cdata;
6336 if (cdata && !(cdata->seek_flag & LIVES_SEEK_FAST)) {
6337 virtual_to_images(mainw->current_file, mainw->preview_frame, mainw->preview_frame, FALSE, &pixbuf);
6338 cache_it = FALSE;
6339 }
6340 }
6341
6342 width = cfile->hsize;
6343 height = cfile->vsize;
6344 if (prefs->ce_maxspect && !prefs->letterbox) {
6345 width = mainw->pwidth;
6346 height = mainw->pheight;
6347 }
6348 if (prefs->letterbox) {
6349 calc_maxspect(mainw->pwidth, mainw->pheight, &width, &height);
6350 }
6351
6352 if (!layer && !pixbuf) {
6353 layer = lives_layer_new_for_frame(mainw->current_file, mainw->preview_frame);
6354 tc = ((mainw->preview_frame - 1.)) / cfile->fps * TICKS_PER_SECOND;
6355 if (pull_frame_at_size(layer, get_image_ext_for_type(cfile->img_type), tc, width, height,
6356 WEED_PALETTE_RGB24)) {
6357 LiVESInterpType interp = get_interp_value(prefs->pb_quality, TRUE);
6358 check_layer_ready(layer);
6359 if (!resize_layer(layer, width, height, interp, WEED_PALETTE_RGB24, 0) ||
6360 !convert_layer_palette(layer, WEED_PALETTE_RGB24, 0)) {
6361 weed_layer_free(layer);
6362 if (xmd5sum) lives_free(xmd5sum);
6363 return;
6364 }
6365 }
6366 }
6367
6368 if (!pixbuf || lives_pixbuf_get_width(pixbuf) != mainw->pwidth
6369 || lives_pixbuf_get_height(pixbuf) != mainw->pheight) {
6370 if (!pixbuf) {
6371 if (layer) pixbuf = layer_to_pixbuf(layer, TRUE, TRUE);
6372 }
6373 }
6374
6375 if (LIVES_IS_PIXBUF(pixbuf)) {
6376 LiVESPixbuf *pr_pixbuf = NULL;
6377 if (lives_pixbuf_get_width(pixbuf) == width && lives_pixbuf_get_height(pixbuf) == height)
6378 pr_pixbuf = pixbuf;
6379 else {
6380 pr_pixbuf = lives_pixbuf_scale_simple(pixbuf, width, height, LIVES_INTERP_BEST);
6381 }
6382 if (LIVES_IS_PIXBUF(pr_pixbuf)) {
6383 lives_widget_set_size_request(mainw->preview_image, MAX(width, mainw->sepwin_minwidth), height);
6384 set_drawing_area_from_pixbuf(mainw->preview_image, pr_pixbuf, mainw->pi_surface);
6385 if (pr_pixbuf != pixbuf) lives_widget_object_unref(pr_pixbuf);
6386 if (!layer || !cache_it || weed_layer_get_pixel_data_packed(layer) || !(pixbuf_to_layer(layer, pixbuf)))
6387 lives_widget_object_unref(pixbuf);
6388 } else cache_it = FALSE;
6389 } else cache_it = FALSE;
6390 }
6391
6392 if (!cache_it) {
6393 weed_layer_free(layer);
6394 mainw->pr_fcache = NULL;
6395 } else {
6396 if (!mainw->pr_fcache) {
6397 mainw->pr_fcache = layer;
6398 if (!is_virtual_frame(mainw->current_file, mainw->preview_frame)) {
6399 if (cfile->clip_type == CLIP_TYPE_DISK && capable->has_md5sum) {
6400 if (!xmd5sum) {
6401 char *fname = make_image_file_name(cfile, mainw->preview_frame,
6402 get_image_ext_for_type(cfile->img_type));
6403 xmd5sum = get_md5sum(fname);
6404 lives_free(fname);
6405 }
6406 weed_set_string_value(layer, WEED_LEAF_MD5SUM, xmd5sum);
6407 // *INDENT-OFF*
6408 }}
6409 lives_layer_set_frame(layer, xpf);
6410 lives_layer_set_clip(layer, mainw->current_file);
6411 }}
6412 // *INDENT-ON*
6413
6414 if (update_always) {
6415 // set spins from current frame
6416 switch (mainw->prv_link) {
6417 case PRV_PTR:
6418 //cf. hrule_reset
6419 cfile->pointer_time = lives_ce_update_timeline(mainw->preview_frame, 0.);
6420 if (cfile->frames > 0) cfile->frameno = calc_frame_from_time(mainw->current_file,
6421 cfile->pointer_time);
6422 if (cfile->pointer_time > 0.) {
6423 lives_widget_set_sensitive(mainw->rewind, TRUE);
6424 lives_widget_set_sensitive(mainw->trim_to_pstart, CURRENT_CLIP_HAS_AUDIO);
6425 lives_widget_set_sensitive(mainw->m_rewindbutton, TRUE);
6426 if (mainw->preview_box) {
6427 lives_widget_set_sensitive(mainw->p_rewindbutton, TRUE);
6428 }
6429 }
6430 mainw->ptrtime = cfile->pointer_time;
6431 lives_widget_queue_draw(mainw->eventbox2);
6432 break;
6433
6434 case PRV_START:
6435 if (mainw->st_fcache && mainw->st_fcache != mainw->pr_fcache && mainw->st_fcache != mainw->en_fcache) {
6436 weed_layer_free(mainw->st_fcache);
6437 }
6438 mainw->st_fcache = mainw->pr_fcache;
6439 if (cfile->start != mainw->preview_frame) {
6440 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), mainw->preview_frame);
6441 lives_spin_button_update(LIVES_SPIN_BUTTON(mainw->spinbutton_start));
6442 get_play_times();
6443 }
6444 break;
6445
6446 case PRV_END:
6447 if (mainw->en_fcache && mainw->en_fcache != mainw->pr_fcache && mainw->en_fcache != mainw->st_fcache) {
6448 weed_layer_free(mainw->en_fcache);
6449 }
6450 mainw->en_fcache = mainw->pr_fcache;
6451 if (cfile->end != mainw->preview_frame) {
6452 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), mainw->preview_frame);
6453 lives_spin_button_update(LIVES_SPIN_BUTTON(mainw->spinbutton_end));
6454 get_play_times();
6455 }
6456 break;
6457
6458 default:
6459 lives_widget_set_sensitive(mainw->rewind, FALSE);
6460 lives_widget_set_sensitive(mainw->trim_to_pstart, FALSE);
6461 lives_widget_set_sensitive(mainw->m_rewindbutton, FALSE);
6462 if (mainw->preview_box) {
6463 lives_widget_set_sensitive(mainw->p_rewindbutton, FALSE);
6464 }
6465 break;
6466 }
6467 }
6468 if (xmd5sum) lives_free(xmd5sum);
6469 }
6470
6471
6472 #ifndef NO_PROG_LOAD
6473
6474 #ifdef GUI_GTK
pbsize_set(GdkPixbufLoader * pbload,int xxwidth,int xxheight,livespointer ptr)6475 static void pbsize_set(GdkPixbufLoader * pbload, int xxwidth, int xxheight, livespointer ptr) {
6476 if (xxwidth * xxheight > 0) gdk_pixbuf_loader_set_size(pbload, xxwidth, xxheight);
6477 }
6478 #endif
6479
6480 #endif
6481
6482
6483 #ifdef USE_LIBPNG
6484 #ifdef PNG_ASSEMBLER_CODE_SUPPORTED
6485 static png_uint_32 png_flags;
6486 #endif
6487 static int png_flagstate = 0;
6488
png_init(png_structp png_ptr)6489 static void png_init(png_structp png_ptr) {
6490 png_uint_32 mask = 0;
6491 #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
6492 #ifdef PNG_SELECT_READ
6493 int selection = PNG_SELECT_READ;// | PNG_SELECT_WRITE;
6494 int mmxsupport = png_mmx_support(); // -1 = not compiled, 0 = not on machine, 1 = OK
6495 mask = png_get_asm_flagmask(selection);
6496
6497 if (mmxsupport < 1) {
6498 int compilerID;
6499 mask &= ~(png_get_mmx_flagmask(selection, &compilerID));
6500 /* if (prefs->show_dev_opts) { */
6501 /* g_printerr(" without MMX features (%d)\n", mmxsupport); */
6502 /* } */
6503 } else {
6504 /* if (prefs->show_dev_opts) { */
6505 /* g_printerr(" with MMX features\n"); */
6506 /* } */
6507 }
6508 #endif
6509 #endif
6510
6511 #if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) \
6512 && defined(PNG_THREAD_UNSAFE_OK)
6513 /* Disable thread-unsafe features of pnggccrd */
6514 if (png_access_version() >= 10200) {
6515 mask &= ~(PNG_ASM_FLAG_MMX_READ_COMBINE_ROW
6516 | PNG_ASM_FLAG_MMX_READ_FILTER_SUB
6517 | PNG_ASM_FLAG_MMX_READ_FILTER_AVG
6518 | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH);
6519
6520 if (prefs->show_dev_opts) {
6521 g_printerr("Thread unsafe features of libpng disabled.\n");
6522 }
6523 }
6524 #endif
6525
6526 if (prefs->show_dev_opts && mask != 0) {
6527 uint64_t xmask = (uint64_t)mask;
6528 g_printerr("enabling png opts %lu\n", xmask);
6529 }
6530
6531 if (!mask) png_flagstate = -1;
6532 else {
6533 #ifdef PNG_ASSEMBLER_CODE_SUPPORTED
6534 png_flags = png_get_asm_flags(png_ptr);
6535 png_flags |= mask;
6536 png_flagstate = 1;
6537 #endif
6538 }
6539 }
6540
6541 #define PNG_BIO
6542 #ifdef PNG_BIO
png_read_func(png_structp png_ptr,png_bytep data,png_size_t length)6543 static void png_read_func(png_structp png_ptr, png_bytep data, png_size_t length) {
6544 int fd = LIVES_POINTER_TO_INT(png_get_io_ptr(png_ptr));
6545 //lives_file_buffer_t *fbuff = find_in_file_buffers(fd);
6546 if (lives_read_buffered(fd, data, length, TRUE) < length) {
6547 png_error(png_ptr, "read_fn error");
6548 }
6549 }
6550 #endif
6551
6552 typedef struct {
6553 weed_layer_t *layer;
6554 int width, height;
6555 LiVESInterpType interp;
6556 int pal, clamp;
6557 } resl_priv_data;
6558
6559
6560 #ifdef USE_RESTHREAD
res_thrdfunc(void * arg)6561 static void res_thrdfunc(void *arg) {
6562 resl_priv_data *priv = (resl_priv_data *)arg;
6563 resize_layer(priv->layer, priv->width, priv->height, priv->interp, priv->pal, priv->clamp);
6564 weed_set_voidptr_value(priv->layer, WEED_LEAF_RESIZE_THREAD, NULL);
6565 lives_free(priv);
6566 }
6567
6568
reslayer_thread(weed_layer_t * layer,int twidth,int theight,LiVESInterpType interp,int tpalette,int clamp,double file_gamma)6569 static void reslayer_thread(weed_layer_t *layer, int twidth, int theight, LiVESInterpType interp,
6570 int tpalette, int clamp, double file_gamma) {
6571 resl_priv_data *priv = (resl_priv_data *)lives_malloc(sizeof(resl_priv_data));
6572 lives_proc_thread_t resthread;
6573 weed_set_double_value(layer, "file_gamma", file_gamma);
6574 priv->layer = layer;
6575 priv->width = twidth;
6576 priv->height = theight;
6577 priv->interp = interp;
6578 priv->pal = tpalette;
6579 priv->clamp = clamp;
6580 resthread = lives_proc_thread_create(LIVES_THRDATTR_NO_GUI, (lives_funcptr_t)res_thrdfunc, -1, "v", priv);
6581 weed_set_voidptr_value(layer, WEED_LEAF_RESIZE_THREAD, resthread);
6582 }
6583 #endif
6584
6585
layer_from_png(int fd,weed_layer_t * layer,int twidth,int theight,int tpalette,boolean prog)6586 boolean layer_from_png(int fd, weed_layer_t *layer, int twidth, int theight, int tpalette, boolean prog) {
6587 png_structp png_ptr;
6588 png_infop info_ptr;
6589 double file_gamma;
6590 int gval;
6591 #ifndef PNG_BIO
6592 FILE *fp = fdopen(fd, "rb");
6593 size_t bsize = fread(ibuff, 1, 8, fp);
6594 boolean is_png = TRUE;
6595 unsigned char ibuff[8];
6596 #endif
6597
6598 unsigned char **row_ptrs;
6599 unsigned char *ptr;
6600
6601 boolean is16bit = FALSE;
6602
6603 png_uint_32 xwidth, xheight;
6604
6605 int width, height;
6606 int color_type, bit_depth;
6607 int rowstride;
6608 int flags, privflags;
6609
6610 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL);
6611
6612 if (!png_ptr) {
6613 #ifndef PNG_BIO
6614 fclose(fp);
6615 #endif
6616 return FALSE;
6617 }
6618
6619 #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
6620 if (!png_flagstate) png_init(png_ptr);
6621 #ifdef PNG_ASSEMBLER_CODE_SUPPORTED
6622 if (png_flagstate == 1) png_set_asm_flags(png_ptr, png_flags);
6623 #endif
6624 #endif
6625
6626 info_ptr = png_create_info_struct(png_ptr);
6627
6628 if (!info_ptr) {
6629 png_destroy_read_struct(&png_ptr, NULL, NULL);
6630 #ifndef PNG_BIO
6631 fclose(fp);
6632 #endif
6633 return FALSE;
6634 }
6635
6636 if (setjmp(png_jmpbuf(png_ptr))) {
6637 // libpng will longjump to here on error
6638 #ifdef USE_RESTHREAD
6639 weed_set_int_value(layer, WEED_LEAF_PROGSCAN, 0);
6640 #endif
6641 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
6642 #ifndef PNG_BIO
6643 fclose(fp);
6644 #endif
6645 return FALSE;
6646 }
6647
6648 #ifdef PNG_BIO
6649 png_set_read_fn(png_ptr, LIVES_INT_TO_POINTER(fd), png_read_func);
6650 #ifndef VALGRIND_ON
6651 png_set_sig_bytes(png_ptr, 8);
6652 #else
6653 png_set_sig_bytes(png_ptr, 0);
6654 #endif
6655 #else
6656 png_init_io(png_ptr, fp);
6657 png_set_sig_bytes(png_ptr, bsize);
6658 #endif
6659
6660 // read header info
6661 png_read_info(png_ptr, info_ptr);
6662 png_get_IHDR(png_ptr, info_ptr, &xwidth, &xheight,
6663 NULL, NULL, NULL,
6664 NULL, NULL);
6665 if (xwidth > 0 && xheight > 0) {
6666 weed_set_int_value(layer, WEED_LEAF_WIDTH, xwidth);
6667 weed_set_int_value(layer, WEED_LEAF_HEIGHT, xheight);
6668
6669 privflags = weed_get_int_value(layer, WEED_LEAF_HOST_FLAGS, NULL);
6670 weed_set_int_value(layer, WEED_LEAF_HOST_FLAGS, privflags | LIVES_LAYER_HAS_SIZE_NOW);
6671 if (privflags == LIVES_LAYER_GET_SIZE_ONLY
6672 || (privflags == LIVES_LAYER_LOAD_IF_NEEDS_RESIZE
6673 && (int)xwidth == twidth && (int)xheight == theight)) {
6674 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
6675 #ifndef PNG_BIO
6676 fclose(fp);
6677 #endif
6678 return TRUE;
6679 }
6680 }
6681
6682 flags = weed_layer_get_flags(layer);
6683
6684 #if PNG_LIBPNG_VER >= 10504
6685 if (prefs->alpha_post) {
6686 if (flags & WEED_LAYER_ALPHA_PREMULT) flags ^= WEED_LAYER_ALPHA_PREMULT;
6687 png_set_alpha_mode(png_ptr, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB);
6688 } else {
6689 flags |= WEED_LAYER_ALPHA_PREMULT;
6690 png_set_alpha_mode(png_ptr, PNG_ALPHA_PREMULTIPLIED, PNG_DEFAULT_sRGB);
6691 }
6692 #endif
6693
6694 weed_set_int_value(layer, WEED_LEAF_FLAGS, flags);
6695
6696 color_type = png_get_color_type(png_ptr, info_ptr);
6697 bit_depth = png_get_bit_depth(png_ptr, info_ptr);
6698 gval = png_get_gAMA(png_ptr, info_ptr, &file_gamma);
6699
6700 if (!gval) {
6701 // b > a, brighter
6702 //png_set_gamma(png_ptr, 1.0, .45455); /// default, seemingly
6703 //png_set_gamma(png_ptr, 1. / .45455, 1.0); /// too bright
6704 png_set_gamma(png_ptr, 1.0, 1.0);
6705 }
6706
6707 if (gval == PNG_INFO_gAMA) {
6708 weed_set_int_value(layer, WEED_LEAF_GAMMA_TYPE, WEED_GAMMA_LINEAR);
6709 }
6710
6711 // want to convert everything (greyscale, RGB, RGBA64 etc.) to RGBA32 (or RGB24)
6712 if (color_type == PNG_COLOR_TYPE_PALETTE)
6713 png_set_palette_to_rgb(png_ptr);
6714
6715 if (png_get_valid(png_ptr, info_ptr,
6716 PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr);
6717
6718 if (color_type == PNG_COLOR_TYPE_GRAY &&
6719 bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr);
6720
6721 if (color_type == PNG_COLOR_TYPE_GRAY ||
6722 color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
6723 png_set_gray_to_rgb(png_ptr);
6724
6725 if (bit_depth == 16) {
6726 // if tpalette is YUV, then recreate the pixel_data with double the width
6727 // and mark as 16bpc, then >> 8 when doing the conversion
6728 #ifdef xUSE_16BIT_PCONV
6729 /// needs testing
6730 if (weed_palette_is_yuv(tpalette)) {
6731 width *= 2;
6732 is16bit = TRUE;
6733 } else {
6734 #endif
6735 #if PNG_LIBPNG_VER >= 10504
6736 png_set_scale_16(png_ptr);
6737 #else
6738 png_set_strip_16(png_ptr);
6739 #endif
6740 #ifdef xUSE_16BIT_PCONV
6741 }
6742 #endif
6743 }
6744
6745 if (tpalette != WEED_PALETTE_END) {
6746 if (weed_palette_has_alpha(tpalette)) {
6747 // if target has alpha, add a channel
6748 if (color_type != PNG_COLOR_TYPE_RGB_ALPHA &&
6749 color_type != PNG_COLOR_TYPE_GRAY_ALPHA) {
6750 if (tpalette == WEED_PALETTE_ARGB32)
6751 png_set_add_alpha(png_ptr, 255, PNG_FILLER_BEFORE);
6752 else
6753 png_set_add_alpha(png_ptr, 255, PNG_FILLER_AFTER);
6754 color_type = PNG_COLOR_TYPE_RGB_ALPHA;
6755 } else {
6756 if (tpalette == WEED_PALETTE_ARGB32) {
6757 png_set_swap_alpha(png_ptr);
6758 }
6759 }
6760 } else {
6761 // else remove it
6762 if (color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
6763 color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
6764 png_set_strip_alpha(png_ptr);
6765 color_type = PNG_COLOR_TYPE_RGB;
6766 }
6767 }
6768 if (tpalette == WEED_PALETTE_BGR24 || tpalette == WEED_PALETTE_BGRA32) {
6769 png_set_bgr(png_ptr);
6770 }
6771 }
6772
6773 // unnecessary for read_image or if we set npass
6774 //png_set_interlace_handling(png_ptr);
6775
6776 // read updated info with the new palette
6777 png_read_update_info(png_ptr, info_ptr);
6778
6779 width = png_get_image_width(png_ptr, info_ptr);
6780 height = png_get_image_height(png_ptr, info_ptr);
6781
6782 weed_set_int_value(layer, WEED_LEAF_WIDTH, width);
6783 weed_set_int_value(layer, WEED_LEAF_HEIGHT, height);
6784
6785 if (weed_palette_is_rgb(tpalette)) {
6786 weed_layer_set_palette(layer, tpalette);
6787 } else {
6788 if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
6789 weed_layer_set_palette(layer, WEED_PALETTE_RGBA32);
6790 } else {
6791 weed_layer_set_palette(layer, WEED_PALETTE_RGB24);
6792 }
6793 }
6794
6795 weed_layer_pixel_data_free(layer);
6796
6797 if (!create_empty_pixel_data(layer, FALSE, TRUE)) {
6798 create_blank_layer(layer, LIVES_FILE_EXT_PNG, 4, 4, weed_layer_get_palette(layer));
6799 #ifndef PNG_BIO
6800 fclose(fp);
6801 #endif
6802 return FALSE;
6803 }
6804
6805 // TODO: rowstride must be at least png_get_rowbytes(png_ptr, info_ptr)
6806
6807 rowstride = weed_layer_get_rowstride(layer);
6808 ptr = weed_layer_get_pixel_data_packed(layer);
6809
6810 // libpng needs pointers to each row
6811 row_ptrs = (unsigned char **)lives_malloc(height * sizeof(unsigned char *));
6812 for (int j = 0; j < height; j++) {
6813 row_ptrs[j] = ptr;
6814 ptr += rowstride;
6815 }
6816
6817 #ifdef USE_RESTHREAD
6818 if (weed_threadsafe && twidth * theight != 0 && (twidth != width || theight != height) &&
6819 !png_get_interlace_type(png_ptr, info_ptr)) {
6820 weed_set_int_value(layer, WEED_LEAF_PROGSCAN, 1);
6821 reslayer_thread(layer, twidth, theight, get_interp_value(prefs->pb_quality, TRUE),
6822 tpalette, weed_layer_get_yuv_clamping(layer),
6823 gval == PNG_INFO_gAMA ? file_gamma : 1.);
6824 for (int j = 0; j < height; j++) {
6825 png_read_row(png_ptr, row_ptrs[j], NULL);
6826 weed_set_int_value(layer, WEED_LEAF_PROGSCAN, j + 1);
6827 }
6828 weed_set_int_value(layer, WEED_LEAF_PROGSCAN, -1);
6829 } else
6830 #endif
6831 png_read_image(png_ptr, row_ptrs);
6832
6833 //png_read_end(png_ptr, NULL);
6834
6835 // end read
6836
6837 lives_free(row_ptrs);
6838
6839 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
6840
6841 /// it seems that if no gAMA is set then libpng (rather wastefully) always tries to convert to linear
6842 /// assuming a file gamma of approx. 1.2* (this is not accurate since sRGB -> linear doesnt use a power law)
6843 /// if gAMA is set, then we (correctly) need to convert to linear using the file gamma
6844 /// *I think this comes from 0.5 (approx linear to sRGB) * 2,4 (guessed display gamma)
6845
6846 if (gval == PNG_INFO_gAMA) {
6847 /// img needs gamma converting
6848 /// TODO: can we do this using png_set_gamma ?
6849 weed_layer_set_gamma(layer, WEED_GAMMA_LINEAR);
6850 } else weed_layer_set_gamma(layer, WEED_GAMMA_SRGB);
6851
6852 if (is16bit) {
6853 #ifdef USE_RESTHREAD
6854 lives_proc_thread_t resthread;
6855 #endif
6856 int clamping, sampling, subspace;
6857 weed_layer_get_palette_yuv(layer, &clamping, &sampling, &subspace);
6858 weed_set_int_value(layer, WEED_LEAF_PIXEL_BITS, 16);
6859 if (weed_palette_has_alpha(tpalette)) tpalette = WEED_PALETTE_YUVA4444P;
6860 else {
6861 if (tpalette != WEED_PALETTE_YUV420P) tpalette = WEED_PALETTE_YUV444P;
6862 }
6863 #ifdef USE_RESTHREAD
6864 if ((resthread = weed_get_voidptr_value(layer, WEED_LEAF_RESIZE_THREAD, NULL))) {
6865 lives_proc_thread_join(resthread);
6866 weed_set_voidptr_value(layer, WEED_LEAF_RESIZE_THREAD, NULL);
6867 }
6868 #endif
6869 // convert RGBA -> YUVA4444P or RGB -> 444P or 420
6870 // 16 bit conversion
6871 convert_layer_palette_full(layer, tpalette, clamping, sampling, subspace, WEED_GAMMA_UNKNOWN);
6872 }
6873 #ifndef PNG_BIO
6874 fclose(fp);
6875 #endif
6876 return TRUE;
6877 }
6878
6879
6880 // unused
save_to_png(FILE * fp,weed_layer_t * layer,int comp)6881 boolean save_to_png(FILE * fp, weed_layer_t *layer, int comp) {
6882 // comp is 0 (none) - 9 (full)
6883 png_structp png_ptr;
6884 png_infop info_ptr;
6885
6886 unsigned char *ptr;
6887
6888 int width, height, palette;
6889 #if PNG_LIBPNG_VER >= 10504
6890 int flags = 0;
6891 #endif
6892 int rowstride;
6893
6894 register int i;
6895
6896 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL);
6897
6898 if (!png_ptr) {
6899 fclose(fp);
6900 return FALSE;
6901 }
6902
6903 info_ptr = png_create_info_struct(png_ptr);
6904
6905 if (!info_ptr) {
6906 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
6907 fclose(fp);
6908 return FALSE;
6909 }
6910
6911 if (setjmp(png_jmpbuf(png_ptr))) {
6912 // libpng will longjump to here on error
6913 if (info_ptr) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
6914 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
6915 return FALSE;
6916 }
6917
6918 png_init_io(png_ptr, fp);
6919
6920 width = weed_layer_get_width(layer);
6921 height = weed_layer_get_height(layer);
6922 rowstride = weed_layer_get_rowstride(layer);
6923 palette = weed_layer_get_palette(layer);
6924
6925 if (width <= 0 || height <= 0 || rowstride <= 0) {
6926 LIVES_WARN("Cannot make png with 0 width or height");
6927 return FALSE;
6928 }
6929
6930 switch (palette) {
6931 case WEED_PALETTE_RGB24:
6932 case WEED_PALETTE_BGR24:
6933 png_set_IHDR(png_ptr, info_ptr, width, height,
6934 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
6935 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
6936 break;
6937 case WEED_PALETTE_RGBA32:
6938 case WEED_PALETTE_BGRA32:
6939 png_set_IHDR(png_ptr, info_ptr, width, height,
6940 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
6941 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
6942 break;
6943 default:
6944 LIVES_ERROR("Bad png palette !\n");
6945 break;
6946 }
6947
6948 png_set_compression_level(png_ptr, comp);
6949
6950 //png_set_write_status_fn(png_ptr, png_row_callback);
6951
6952 #if PNG_LIBPNG_VER >= 10504
6953 flags = weed_layer_get_flags(layer);
6954 if (flags & WEED_LAYER_ALPHA_PREMULT) {
6955 png_set_alpha_mode(png_ptr, PNG_ALPHA_PREMULTIPLIED, PNG_DEFAULT_sRGB);
6956 } else {
6957 png_set_alpha_mode(png_ptr, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB);
6958 }
6959 #endif
6960
6961 if (weed_layer_get_gamma(layer) == WEED_GAMMA_LINEAR)
6962 png_set_gAMA(png_ptr, info_ptr, 1.0);
6963 else
6964 png_set_gAMA(png_ptr, info_ptr, 0.45455);
6965
6966 png_write_info(png_ptr, info_ptr);
6967
6968 ptr = (unsigned char *)weed_layer_get_pixel_data_packed(layer);
6969
6970 // Write image data
6971 for (i = 0 ; i < height ; i++) {
6972 png_write_row(png_ptr, ptr);
6973 ptr += rowstride;
6974 }
6975
6976 // end write
6977 png_write_end(png_ptr, (png_infop)NULL);
6978
6979 if (info_ptr) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
6980 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
6981
6982 fflush(fp);
6983
6984 return TRUE;
6985 }
6986 #endif
6987
6988
weed_layer_create_from_file_progressive(weed_layer_t * layer,const char * fname,int width,int height,int tpalette,const char * img_ext)6989 boolean weed_layer_create_from_file_progressive(weed_layer_t *layer, const char *fname, int width,
6990 int height, int tpalette, const char *img_ext) {
6991 LiVESPixbuf *pixbuf = NULL;
6992 LiVESError *gerror = NULL;
6993 boolean ret = TRUE;
6994 #ifndef VALGRIND_ON
6995 boolean is_png = FALSE;
6996 #endif
6997 int fd = -1;
6998
6999 #ifndef NO_PROG_LOAD
7000 #ifdef GUI_GTK
7001 GdkPixbufLoader *pbload;
7002 #endif
7003 uint8_t ibuff[IMG_BUFF_SIZE];
7004 size_t bsize;
7005
7006 #ifndef VALGRIND_ON
7007 if (!strcmp(img_ext, LIVES_FILE_EXT_PNG)) is_png = TRUE;
7008 #endif
7009
7010 #ifdef PNG_BIO
7011 fd = lives_open_buffered_rdonly(fname);
7012 if (fd < 0) break_me(fname);
7013 if (fd < 0) return FALSE;
7014 #ifndef VALGRIND_ON
7015 if (is_png) lives_buffered_rdonly_slurp(fd, 8);
7016 else
7017 lives_buffered_rdonly_slurp(fd, 0);
7018 #endif
7019 #else
7020 fd = lives_open2(fname, O_RDONLY);
7021 #endif
7022 if (fd < 0) return FALSE;
7023 #ifndef PNG_BIO
7024 #ifdef HAVE_POSIX_FADVISE
7025 posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
7026 #endif
7027 #endif
7028
7029 xxwidth = width;
7030 xxheight = height;
7031
7032 if (!strcmp(img_ext, LIVES_FILE_EXT_PNG)) {
7033 #ifdef USE_LIBPNG
7034 tpalette = weed_layer_get_palette(layer);
7035 ret = layer_from_png(fd, layer, width, height, tpalette, TRUE);
7036 goto fndone;
7037 #endif
7038
7039 #ifdef GUI_GTK
7040 pbload = gdk_pixbuf_loader_new_with_type(LIVES_IMAGE_TYPE_PNG, &gerror);
7041 #endif
7042 }
7043 #ifdef GUI_GTK
7044 else if (!strcmp(img_ext, LIVES_FILE_EXT_JPG)) pbload = gdk_pixbuf_loader_new_with_type(LIVES_IMAGE_TYPE_JPEG, &gerror);
7045 else pbload = gdk_pixbuf_loader_new();
7046
7047 lives_signal_connect(LIVES_WIDGET_OBJECT(pbload), LIVES_WIDGET_SIZE_PREPARED_SIGNAL,
7048 LIVES_GUI_CALLBACK(pbsize_set), NULL);
7049
7050 while (1) {
7051 #ifndef PNG_BIO
7052 if ((bsize = read(fd, ibuff, IMG_BUFF_SIZE)) <= 0) break;
7053 #else
7054 if ((bsize = lives_read_buffered(fd, ibuff, IMG_BUFF_SIZE, TRUE)) <= 0) break;
7055 #endif
7056 if (!gdk_pixbuf_loader_write(pbload, ibuff, bsize, &gerror)) {
7057 ret = FALSE;
7058 goto fndone;
7059 }
7060 }
7061
7062 if (!gdk_pixbuf_loader_close(pbload, &gerror)) {
7063 ret = FALSE;
7064 goto fndone;
7065 }
7066 pixbuf = gdk_pixbuf_loader_get_pixbuf(pbload);
7067 lives_widget_object_ref(pixbuf);
7068 if (pbload) lives_widget_object_unref(pbload);
7069
7070 #endif
7071
7072 # else //PROG_LOAD
7073
7074 #ifdef USE_LIBPNG
7075 {
7076 #ifdef PNG_BIO
7077 fd = lives_open_buffered_rdonly(fname);
7078 #else
7079 fd = lives_open2(fname, O_RDONLY);
7080 #endif
7081
7082 if (fd < 0) return FALSE;
7083
7084 #ifndef PNG_BIO
7085 #ifdef HAVE_POSIX_FADVISE
7086 posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
7087 #endif
7088 #endif
7089 tpalette = weed_layer_get_palette(layer);
7090 ret = layer_from_png(fd, layer, width, height, tpalette, FALSE);
7091 goto fndone;
7092 }
7093 #endif
7094
7095 pixbuf = lives_pixbuf_new_from_file_at_scale(fname, width > 0 ? width : -1, height > 0 ? height : -1, FALSE, gerror);
7096 #endif
7097
7098 if (gerror) {
7099 LIVES_ERROR(gerror->message);
7100 lives_error_free(gerror);
7101 pixbuf = NULL;
7102 }
7103
7104 if (!pixbuf) {
7105 ret = FALSE;
7106 goto fndone;
7107 }
7108
7109 if (lives_pixbuf_get_has_alpha(pixbuf)) {
7110 /* unfortunately gdk pixbuf loader does not preserve the original alpha channel, instead it adds its own.
7111 We need to hence reset it back to opaque */
7112 lives_pixbuf_set_opaque(pixbuf);
7113 weed_layer_set_palette(layer, WEED_PALETTE_RGBA32);
7114 } else weed_layer_set_palette(layer, WEED_PALETTE_RGB24);
7115
7116 if (!pixbuf_to_layer(layer, pixbuf)) {
7117 lives_widget_object_unref(pixbuf);
7118 }
7119
7120 fndone:
7121 #ifdef PNG_BIO
7122 if (fd >= 0) {
7123 lives_close_buffered(fd);
7124 }
7125 #else
7126 if (fd >= 0) close(fd);
7127 #endif
7128
7129 return ret;
7130 }
7131
7132
render_subs_from_file(lives_clip_t * sfile,double xtime,weed_layer_t * layer)7133 static weed_plant_t *render_subs_from_file(lives_clip_t *sfile, double xtime, weed_layer_t *layer) {
7134 // render subtitles from whatever (.srt or .sub) file
7135 // uses default values for colours, fonts, size, etc.
7136
7137 // TODO - allow prefs settings for colours, fonts, size, alpha (use plugin for this)
7138
7139 //char *sfont=mainw->font_list[prefs->sub_font];
7140 const char *sfont = "Sans";
7141 lives_colRGBA64_t col_white, col_black_a;
7142
7143 int error, size;
7144
7145 xtime -= (double)sfile->subt->offset / sfile->fps;
7146
7147 // round to 2 dp
7148 xtime = (double)((int)(xtime * 100. + .5)) / 100.;
7149
7150 if (xtime < 0.) return layer;
7151
7152 get_subt_text(sfile, xtime);
7153
7154 if (!sfile->subt->text) return layer;
7155
7156 size = weed_get_int_value(layer, WEED_LEAF_WIDTH, &error) / 32;
7157
7158 col_white = lives_rgba_col_new(65535, 65535, 65535, 65535);
7159 col_black_a = lives_rgba_col_new(0, 0, 0, SUB_OPACITY);
7160
7161 if (prefs->apply_gamma && prefs->pb_quality == PB_QUALITY_HIGH) {
7162 // make it look nicer by dimming relative to luma
7163 gamma_convert_layer(WEED_GAMMA_LINEAR, layer);
7164 }
7165
7166 layer = render_text_to_layer(layer, sfile->subt->text, sfont, size,
7167 LIVES_TEXT_MODE_FOREGROUND_AND_BACKGROUND, &col_white, &col_black_a, TRUE, TRUE, 0.);
7168 return layer;
7169 }
7170
7171
pull_frame_at_size(weed_layer_t * layer,const char * image_ext,weed_timecode_t tc,int width,int height,int target_palette)7172 boolean pull_frame_at_size(weed_layer_t *layer, const char *image_ext, weed_timecode_t tc, int width, int height,
7173 int target_palette) {
7174 // pull a frame from an external source into a layer
7175 // the WEED_LEAF_CLIP and WEED_LEAF_FRAME leaves must be set in layer
7176 // tc is used instead of WEED_LEAF_FRAME for some sources (e.g. generator plugins)
7177 // image_ext is used if the source is an image file (eg. "jpg" or "png")
7178 // width and height are hints only, the caller should resize if necessary
7179 // target_palette is also a hint
7180
7181 // if we pull from a decoder plugin, then we may also deinterlace
7182 weed_plant_t *vlayer;
7183 lives_clip_t *sfile = NULL;
7184 int clip = lives_layer_get_clip(layer);
7185 frames_t frame = lives_layer_get_frame(layer);
7186 int clip_type;
7187
7188 boolean is_thread = FALSE;
7189
7190 // the default unless overridden
7191 weed_layer_set_gamma(layer, WEED_GAMMA_SRGB);
7192
7193 if (weed_plant_has_leaf(layer, WEED_LEAF_HOST_PTHREAD)) is_thread = TRUE;
7194
7195 weed_layer_pixel_data_free(layer);
7196 weed_leaf_delete(layer, WEED_LEAF_NATURAL_SIZE);
7197
7198 mainw->osc_block = TRUE; // block OSC until we are done
7199
7200 if (clip < 0 && frame == 0) clip_type = CLIP_TYPE_DISK;
7201 else {
7202 sfile = mainw->files[clip];
7203 if (!sfile) {
7204 mainw->osc_block = FALSE;
7205 return FALSE;
7206 }
7207 clip_type = sfile->clip_type;
7208 }
7209
7210 switch (clip_type) {
7211 case CLIP_TYPE_NULL_VIDEO:
7212 mainw->osc_block = FALSE;
7213 create_blank_layer(layer, image_ext, width, height, target_palette);
7214 return TRUE;
7215 case CLIP_TYPE_DISK:
7216 case CLIP_TYPE_FILE:
7217 // frame number can be 0 during rendering
7218 if (frame == 0) {
7219 mainw->osc_block = FALSE;
7220 create_blank_layer(layer, image_ext, width, height, target_palette);
7221 return TRUE;
7222 } else if (clip == mainw->scrap_file) {
7223 boolean res = load_from_scrap_file(layer, frame);
7224 if (!res) {
7225 create_blank_layer(layer, image_ext, width, height, target_palette);
7226 return FALSE;
7227 }
7228 weed_leaf_delete(layer, WEED_LEAF_HOST_PIXBUF_SRC);
7229 weed_leaf_delete(layer, WEED_LEAF_HOST_SURFACE_SRC);
7230 // clip width and height may vary dynamically
7231 if (LIVES_IS_PLAYING) {
7232 sfile->hsize = weed_layer_get_width(layer);
7233 sfile->vsize = weed_layer_get_height(layer);
7234 }
7235 // realign
7236 copy_pixel_data(layer, NULL, THREADVAR(rowstride_alignment));
7237 mainw->osc_block = FALSE;
7238 return TRUE;
7239 } else {
7240 if (sfile->clip_type == CLIP_TYPE_FILE && sfile->frame_index && frame > 0 &&
7241 frame <= sfile->frames && is_virtual_frame(clip, frame)) {
7242 // pull frame from video clip
7243 ///
7244 #ifdef USE_REC_RS
7245 int nplanes;
7246 #endif
7247 void **pixel_data;
7248 boolean res = TRUE;
7249 int *rowstrides;
7250 lives_decoder_t *dplug = NULL;
7251 /// HOST_DECODER is set in mulitrack, there is 1 decoder per track since multiple tracks can have the same clip
7252 if (weed_plant_has_leaf(layer, WEED_LEAF_HOST_DECODER)) {
7253 dplug = (lives_decoder_t *)weed_get_voidptr_value(layer, WEED_LEAF_HOST_DECODER, NULL);
7254 } else {
7255 /// experimental, multiple decoder plugins for each sfile,,,
7256 if (weed_plant_has_leaf(layer, "alt_src")) {
7257 int srcnum = weed_get_int_value(layer, "alt_src", NULL);
7258 dplug = sfile->alt_srcs[srcnum];
7259 }
7260 if (!dplug) dplug = (lives_decoder_t *)sfile->ext_src;
7261 }
7262 if (!dplug || !dplug->cdata) {
7263 create_blank_layer(layer, image_ext, width, height, target_palette);
7264 return FALSE;
7265 }
7266 if (target_palette != dplug->cdata->current_palette) {
7267 if (dplug->decoder->set_palette) {
7268 int opal = dplug->cdata->current_palette;
7269 int pal = best_palette_match(dplug->cdata->palettes, -1, target_palette);
7270 if (pal != opal) {
7271 dplug->cdata->current_palette = pal;
7272 if (!(*dplug->decoder->set_palette)(dplug->cdata)) {
7273 dplug->cdata->current_palette = opal;
7274 (*dplug->decoder->set_palette)(dplug->cdata);
7275 } else if (dplug->cdata->rec_rowstrides) {
7276 lives_free(dplug->cdata->rec_rowstrides);
7277 dplug->cdata->rec_rowstrides = NULL;
7278 // *INDENT-OFF*
7279 }}}}
7280 // *INDENT-ON*
7281
7282 // TODO *** - check for auto-border : we might use width,height instead of frame_width,frame_height,
7283 // and handle this in the plugin
7284
7285 if (!prefs->auto_nobord) {
7286 width = dplug->cdata->frame_width / weed_palette_get_pixels_per_macropixel(dplug->cdata->current_palette);
7287 height = dplug->cdata->frame_height;
7288 } else {
7289 width = dplug->cdata->width / weed_palette_get_pixels_per_macropixel(dplug->cdata->current_palette);
7290 height = dplug->cdata->height;
7291 }
7292
7293 weed_layer_set_size(layer, width, height);
7294
7295 if (weed_palette_is_yuv(dplug->cdata->current_palette))
7296 weed_layer_set_palette_yuv(layer, dplug->cdata->current_palette,
7297 dplug->cdata->YUV_clamping,
7298 dplug->cdata->YUV_sampling,
7299 dplug->cdata->YUV_subspace);
7300 else weed_layer_set_palette(layer, dplug->cdata->current_palette);
7301
7302 #ifdef USE_REC_RS
7303 nplanes = weed_palette_get_nplanes(dplug->cdata->current_palette);
7304 if (!dplug->cdata->rec_rowstrides) {
7305 dplug->cdata->rec_rowstrides = lives_calloc(nplanes, sizint);
7306 } else {
7307 if (dplug->cdata->rec_rowstrides[0]) {
7308 weed_layer_set_rowstrides(layer, dplug->cdata->rec_rowstrides, nplanes);
7309 weed_leaf_set_flagbits(layer, WEED_LEAF_ROWSTRIDES, LIVES_FLAG_MAINTAIN_VALUE);
7310 lives_memset(dplug->cdata->rec_rowstrides, 0, nplanes * sizint);
7311 }
7312 }
7313 #endif
7314 if (create_empty_pixel_data(layer, TRUE, TRUE)) {
7315 #ifdef USE_REC_RS
7316 weed_leaf_clear_flagbits(layer, WEED_LEAF_ROWSTRIDES, LIVES_FLAG_MAINTAIN_VALUE);
7317 #endif
7318 pixel_data = weed_layer_get_pixel_data(layer, NULL);
7319 } else {
7320 #ifdef USE_REC_RS
7321 weed_leaf_clear_flagbits(layer, WEED_LEAF_ROWSTRIDES, LIVES_FLAG_MAINTAIN_VALUE);
7322 #endif
7323 create_blank_layer(layer, image_ext, width, height, target_palette);
7324 return FALSE;
7325 }
7326
7327 if (!pixel_data || !pixel_data[0]) {
7328 char *msg = lives_strdup_printf("NULL pixel data for layer size %d X %d, palette %s\n", width, height,
7329 weed_palette_get_name_full(dplug->cdata->current_palette,
7330 dplug->cdata->YUV_clamping, dplug->cdata->YUV_subspace));
7331 LIVES_WARN(msg);
7332 lives_free(msg);
7333 create_blank_layer(layer, image_ext, width, height, target_palette);
7334 return FALSE;
7335 }
7336
7337 rowstrides = weed_layer_get_rowstrides(layer, NULL);
7338
7339 //static int last = -1;
7340 // try to pull frame from decoder plugin
7341 //if (sfile->frame_index[frame - 1] == last) break_me();
7342 //last = sfile->frame_index[frame - 1];
7343 if (!(*dplug->decoder->get_frame)(dplug->cdata, (int64_t)(sfile->frame_index[frame - 1]),
7344 rowstrides, sfile->vsize, pixel_data)) {
7345
7346 #ifdef USE_REC_RS
7347 if (dplug->cdata->rec_rowstrides) lives_memset(dplug->cdata->rec_rowstrides, 0, nplanes * sizint);
7348 #endif
7349 if (prefs->show_dev_opts) g_print("Error loading frame %d (index value %d)\n", frame,
7350 sfile->frame_index[frame - 1]);
7351 // if get_frame fails, return a black frame
7352 if (!is_thread) {
7353 weed_layer_pixel_data_free(layer);
7354 if (!create_empty_pixel_data(layer, TRUE, TRUE)) {
7355 create_blank_layer(layer, image_ext, width, height, target_palette);
7356 return FALSE;
7357 }
7358 }
7359 res = FALSE;
7360 }
7361
7362 lives_free(pixel_data);
7363 lives_free(rowstrides);
7364 if (res) {
7365 if (prefs->apply_gamma && prefs->pb_quality != PB_QUALITY_LOW) {
7366 if (dplug->cdata->frame_gamma != WEED_GAMMA_UNKNOWN) {
7367 weed_layer_set_gamma(layer, dplug->cdata->frame_gamma);
7368 } else if (dplug->cdata->YUV_subspace == WEED_YUV_SUBSPACE_BT709) {
7369 weed_layer_set_gamma(layer, WEED_GAMMA_BT709);
7370 }
7371 }
7372
7373 // get_frame may now update YUV_clamping, YUV_sampling, YUV_subspace
7374 if (weed_palette_is_yuv(dplug->cdata->current_palette)) {
7375 weed_layer_set_palette_yuv(layer, dplug->cdata->current_palette,
7376 dplug->cdata->YUV_clamping,
7377 dplug->cdata->YUV_sampling,
7378 dplug->cdata->YUV_subspace);
7379 if (prefs->apply_gamma && prefs->pb_quality != PB_QUALITY_LOW) {
7380 if (weed_get_int_value(layer, WEED_LEAF_GAMMA_TYPE, NULL) == WEED_GAMMA_BT709) {
7381 weed_set_int_value(layer, WEED_LEAF_YUV_SUBSPACE, WEED_YUV_SUBSPACE_BT709);
7382 }
7383 if (weed_get_int_value(layer, WEED_LEAF_YUV_SUBSPACE, NULL) == WEED_YUV_SUBSPACE_BT709) {
7384 weed_set_int_value(layer, WEED_LEAF_GAMMA_TYPE, WEED_GAMMA_BT709);
7385 }
7386 }
7387 }
7388 // deinterlace
7389 if (sfile->deinterlace || (prefs->auto_deint && dplug->cdata->interlace != LIVES_INTERLACE_NONE)) {
7390 if (!is_thread) {
7391 deinterlace_frame(layer, tc);
7392 } else weed_set_boolean_value(layer, WEED_LEAF_HOST_DEINTERLACE, WEED_TRUE);
7393 }
7394 }
7395 mainw->osc_block = FALSE;
7396 return res;
7397 } else {
7398 // pull frame from decoded images
7399 boolean ret;
7400 char *fname = make_image_file_name(sfile, frame, image_ext);
7401 #ifdef USE_RESTHREAD
7402 lives_proc_thread_t resthread;
7403 #endif
7404 if (!*image_ext) image_ext = get_image_ext_for_type(sfile->img_type);
7405 ret = weed_layer_create_from_file_progressive(layer, fname, width, height, target_palette, image_ext);
7406
7407 #ifdef USE_RESTHREAD
7408 if ((resthread = weed_get_voidptr_value(layer, WEED_LEAF_RESIZE_THREAD, NULL))) {
7409 lives_proc_thread_join(resthread);
7410 weed_set_voidptr_value(layer, WEED_LEAF_RESIZE_THREAD, NULL);
7411 }
7412 #endif
7413
7414 lives_free(fname);
7415 mainw->osc_block = FALSE;
7416 if (!ret) {
7417 break_me("bad frame load from file");
7418 create_blank_layer(layer, image_ext, width, height, target_palette);
7419 return FALSE;
7420 }
7421 }
7422 }
7423 break;
7424
7425 // handle other types of sources
7426
7427 #ifdef HAVE_YUV4MPEG
7428 case CLIP_TYPE_YUV4MPEG:
7429 weed_layer_set_from_yuv4m(layer, sfile);
7430 if (sfile->deinterlace) {
7431 if (!is_thread) {
7432 deinterlace_frame(layer, tc);
7433 } else weed_set_boolean_value(layer, WEED_LEAF_HOST_DEINTERLACE, WEED_TRUE);
7434 }
7435 mainw->osc_block = FALSE;
7436 return TRUE;
7437 #endif
7438 #ifdef HAVE_UNICAP
7439 case CLIP_TYPE_VIDEODEV:
7440 weed_layer_set_from_lvdev(layer, sfile, 4. / cfile->pb_fps);
7441 if (sfile->deinterlace) {
7442 if (!is_thread) {
7443 deinterlace_frame(layer, tc);
7444 } else weed_set_boolean_value(layer, WEED_LEAF_HOST_DEINTERLACE, WEED_TRUE);
7445 }
7446 mainw->osc_block = FALSE;
7447 return TRUE;
7448 #endif
7449 case CLIP_TYPE_LIVES2LIVES:
7450 weed_layer_set_from_lives2lives(layer, clip, (lives_vstream_t *)sfile->ext_src);
7451 mainw->osc_block = FALSE;
7452 return TRUE;
7453 case CLIP_TYPE_GENERATOR: {
7454 // special handling for clips where host controls size
7455 // Note: vlayer is actually the out channel of the generator, so we should
7456 // never free it !
7457 weed_plant_t *inst = (weed_plant_t *)sfile->ext_src;
7458 if (inst) {
7459 int key = weed_get_int_value(inst, WEED_LEAF_HOST_KEY, NULL);
7460 while (filter_mutex_trylock(key)) {
7461 sched_yield();
7462 lives_usleep(prefs->sleep_time);
7463 }
7464 vlayer = weed_layer_create_from_generator(inst, tc, clip);
7465 weed_layer_copy(layer, vlayer); // layer is non-NULL, so copy by reference
7466 weed_layer_nullify_pixel_data(vlayer);
7467 filter_mutex_unlock(key);
7468 } else {
7469 mainw->osc_block = FALSE;
7470 create_blank_layer(layer, image_ext, width, height, target_palette);
7471 }
7472 mainw->osc_block = FALSE;
7473 }
7474 return TRUE;
7475 default:
7476 mainw->osc_block = FALSE;
7477 create_blank_layer(layer, image_ext, width, height, target_palette);
7478 return FALSE;
7479 }
7480 mainw->osc_block = FALSE;
7481
7482 if (!is_thread) {
7483 // render subtitles from file
7484 if (prefs->show_subtitles && sfile->subt && sfile->subt->tfile > 0) {
7485 double xtime = (double)(frame - 1) / sfile->fps;
7486 layer = render_subs_from_file(sfile, xtime, layer);
7487 }
7488 }
7489
7490 return TRUE;
7491 }
7492
7493
7494 /**
7495 @brief pull a frame from an external source into a layer
7496 the WEED_LEAF_CLIP and WEED_LEAF_FRAME leaves must be set in layer
7497 tc is used instead of WEED_LEAF_FRAME for some sources (e.g. generator plugins)
7498 image_ext is used if the source is an image file (eg. "jpg" or "png")
7499 */
pull_frame(weed_layer_t * layer,const char * image_ext,weed_timecode_t tc)7500 LIVES_GLOBAL_INLINE boolean pull_frame(weed_layer_t *layer, const char *image_ext, weed_timecode_t tc) {
7501 return pull_frame_at_size(layer, image_ext, tc, 0, 0, WEED_PALETTE_END);
7502 }
7503
7504
7505 /**
7506 @brief block until layer pixel_data is ready.
7507 This function should always be called for threaded layers, prior to freeing the layer, reading it's properites, pixel data,
7508 resizing etc.
7509
7510 We may also deinterlace and overlay subs here
7511 for the blend layer, we may also resize, convert palette, apply gamma in preparation for combining with the main layer
7512
7513 if effects were applied then the frame_layer can depend on other layers, however
7514 these wil have been checked already when the effects were applied
7515
7516 see also MACRO: is_layer_ready(layer) which can be called first to avoid the block, e.g.
7517
7518 while (!is_layer_ready(layer)) {
7519 do_something_else();
7520 }
7521 check_layer_ready(layer); // won't block
7522
7523 This function must be called at some point for every threaded frame, otherwise thread resources will be leaked.
7524
7525 N.B. the name if this function is not the best, it will probably get renamed in th future to something like
7526 finish_layer.
7527 */
check_layer_ready(weed_layer_t * layer)7528 boolean check_layer_ready(weed_layer_t *layer) {
7529 int clip;
7530 boolean ready = TRUE;
7531 lives_clip_t *sfile;
7532 lives_thread_t *thrd;
7533 #ifdef USE_RESTHREAD
7534 lives_proc_thread_t resthread;
7535 #endif
7536 if (!layer) return FALSE;
7537
7538 thrd = (lives_thread_t *)weed_get_voidptr_value(layer, WEED_LEAF_HOST_PTHREAD, NULL);
7539 if (thrd) {
7540 ready = FALSE;
7541 lives_thread_join(*thrd, NULL);
7542 weed_leaf_delete(layer, WEED_LEAF_HOST_PTHREAD);
7543 lives_free(thrd);
7544 }
7545
7546 #ifdef USE_RESTHREAD
7547 if ((resthread = weed_get_voidptr_value(layer, WEED_LEAF_RESIZE_THREAD, NULL))) {
7548 ready = FALSE;
7549 lives_proc_thread_join(resthread);
7550 weed_set_voidptr_value(layer, WEED_LEAF_RESIZE_THREAD, NULL);
7551 }
7552 #endif
7553
7554 if (ready) return TRUE;
7555
7556 if (weed_get_boolean_value(layer, WEED_LEAF_HOST_DEINTERLACE, NULL) == WEED_TRUE) {
7557 weed_timecode_t tc = weed_get_int64_value(layer, WEED_LEAF_HOST_TC, NULL);
7558 deinterlace_frame(layer, tc);
7559 weed_set_boolean_value(layer, WEED_LEAF_HOST_DEINTERLACE, WEED_FALSE);
7560 }
7561
7562 if (weed_plant_has_leaf(layer, WEED_LEAF_CLIP)) {
7563 // TODO: we should render subs before display, to avoid the text size changing
7564 clip = weed_get_int_value(layer, WEED_LEAF_CLIP, NULL);
7565 if (IS_VALID_CLIP(clip)) {
7566 sfile = mainw->files[clip];
7567 // render subtitles from file
7568 if (sfile->subt && sfile->subt->tfile >= 0 && prefs->show_subtitles) {
7569 frames_t frame = weed_get_int_value(layer, WEED_LEAF_FRAME, NULL);
7570 double xtime = (double)(frame - 1) / sfile->fps;
7571 layer = render_subs_from_file(sfile, xtime, layer);
7572 // *INDENT-OFF*
7573 }}}
7574 // *INDENT-ON*
7575
7576 return TRUE;
7577 }
7578
7579
7580 typedef struct {
7581 weed_layer_t *layer;
7582 weed_timecode_t tc;
7583 const char *img_ext;
7584 int width, height;
7585 } pft_priv_data;
7586
7587
pft_thread(void * in)7588 static void *pft_thread(void *in) {
7589 pft_priv_data *data = (pft_priv_data *)in;
7590 weed_layer_t *layer = data->layer;
7591 weed_timecode_t tc = data->tc;
7592 const char *img_ext = data->img_ext;
7593 int width = data->width, height = data->height;
7594 lives_free(in);
7595 /// if loading the blend frame in clip editor, then we recall the palette details and size @ injection,
7596 //and prepare it in this thread
7597 if (mainw->blend_file != -1 && mainw->blend_palette != WEED_PALETTE_END
7598 && LIVES_IS_PLAYING && !mainw->multitrack && mainw->blend_file != mainw->current_file
7599 && weed_get_int_value(layer, WEED_LEAF_CLIP, NULL) == mainw->blend_file) {
7600 int tgamma = WEED_GAMMA_UNKNOWN;
7601 short interp = get_interp_value(prefs->pb_quality, TRUE);
7602 pull_frame_at_size(layer, img_ext, tc, mainw->blend_width, mainw->blend_height, mainw->blend_palette);
7603 if (is_layer_ready(layer)) {
7604 resize_layer(layer, mainw->blend_width,
7605 mainw->blend_height, interp, mainw->blend_palette, mainw->blend_clamping);
7606 }
7607 if (mainw->blend_palette != WEED_PALETTE_END) {
7608 if (weed_palette_is_rgb(mainw->blend_palette))
7609 tgamma = mainw->blend_gamma;
7610 }
7611 if (mainw->blend_palette != WEED_PALETTE_END) {
7612 if (is_layer_ready(layer) && weed_layer_get_width(layer) == mainw->blend_width
7613 && weed_layer_get_height(layer) == mainw->blend_height) {
7614 convert_layer_palette_full(layer, mainw->blend_palette, mainw->blend_clamping, mainw->blend_sampling,
7615 mainw->blend_subspace, tgamma);
7616 }
7617 }
7618 if (tgamma != WEED_GAMMA_UNKNOWN && is_layer_ready(layer)
7619 && weed_layer_get_width(layer) == mainw->blend_width
7620 && weed_layer_get_height(layer) == mainw->blend_height
7621 && weed_layer_get_palette(layer) == mainw->blend_palette)
7622 gamma_convert_layer(mainw->blend_gamma, layer);
7623 } else {
7624 pull_frame_at_size(layer, img_ext, tc, width, height, WEED_PALETTE_END);
7625 }
7626 weed_set_boolean_value(layer, WEED_LEAF_THREAD_PROCESSING, WEED_FALSE);
7627 return NULL;
7628 }
7629
7630
pull_frame_threaded(weed_layer_t * layer,const char * img_ext,weed_timecode_t tc,int width,int height)7631 void pull_frame_threaded(weed_layer_t *layer, const char *img_ext, weed_timecode_t tc, int width, int height) {
7632 // pull a frame from an external source into a layer
7633 // the WEED_LEAF_CLIP and WEED_LEAF_FRAME leaves must be set in layer
7634
7635 // done in a threaded fashion
7636 // call check_layer_ready() to block until the frame thread is completed
7637 #ifdef NO_FRAME_THREAD
7638 pull_frame(layer, img_ext, tc);
7639 return;
7640 #else
7641 //#define MULT_SRC_TEST
7642 #ifdef MULT_SRC_TEST
7643 if (layer == mainw->frame_layer_preload) {
7644 int clip = mainw->pred_clip;
7645 if (IS_VALID_CLIP(clip)) {
7646 lives_clip_t *sfile = mainw->files[clip];
7647 if (sfile->clip_type == CLIP_TYPE_FILE) {
7648 if (!sfile->alt_srcs) {
7649 sfile->alt_srcs = lives_calloc(1, sizeof(void *));
7650 sfile->alt_srcs[0] = clone_decoder(clip);
7651 if (sfile->alt_srcs[0]) {
7652 weed_set_int_value(layer, "alt_src", 0);
7653 sfile->alt_src_types = lives_calloc(1, sizint);
7654 sfile->alt_src_types[0] = LIVES_EXT_SRC_DECODER;
7655 // *INDENT-OFF*
7656 }}}}}
7657 #endif
7658 // *INDENT-ON*
7659 weed_set_boolean_value(layer, WEED_LEAF_THREAD_PROCESSING, WEED_TRUE);
7660 if (1) {
7661 lives_thread_attr_t attr = LIVES_THRDATTR_PRIORITY;
7662 pft_priv_data *in = (pft_priv_data *)lives_calloc(1, sizeof(pft_priv_data));
7663 lives_thread_t *frame_thread = (lives_thread_t *)lives_calloc(1, sizeof(lives_thread_t));
7664 weed_set_int64_value(layer, WEED_LEAF_HOST_TC, tc);
7665 weed_set_boolean_value(layer, WEED_LEAF_HOST_DEINTERLACE, WEED_FALSE);
7666 weed_set_voidptr_value(layer, WEED_LEAF_HOST_PTHREAD, (void *)frame_thread);
7667 in->img_ext = img_ext;
7668 in->layer = layer;
7669 in->width = width;
7670 in->height = height;
7671 in->tc = tc;
7672 lives_thread_create(frame_thread, attr, pft_thread, (void *)in);
7673 }
7674 #endif
7675 // *INDENT-ON*
7676 }
7677
pull_lives_pixbuf_at_size(int clip,int frame,const char * image_ext,weed_timecode_t tc,int width,int height,LiVESInterpType interp,boolean fordisp)7678 LiVESPixbuf *pull_lives_pixbuf_at_size(int clip, int frame, const char *image_ext, weed_timecode_t tc,
7679 int width, int height, LiVESInterpType interp, boolean fordisp) {
7680 // return a correctly sized (Gdk)Pixbuf (RGB24 for jpeg, RGB24 / RGBA32 for png) for the given clip and frame
7681 // tc is used instead of WEED_LEAF_FRAME for some sources (e.g. generator plugins)
7682 // image_ext is used if the source is an image file (eg. "jpg" or "png")
7683 // pixbuf will be sized to width x height pixels using interp
7684
7685 LiVESPixbuf *pixbuf = NULL;
7686 weed_layer_t *layer = lives_layer_new_for_frame(clip, frame);
7687 int palette;
7688
7689 #ifndef ALLOW_PNG24
7690 if (!strcmp(image_ext, LIVES_FILE_EXT_PNG)) palette = WEED_PALETTE_RGBA32;
7691 else palette = WEED_PALETTE_RGB24;
7692 #else
7693 if (strcmp(image_ext, LIVES_FILE_EXT_PNG)) palette = WEED_PALETTE_RGB24;
7694 else palette = WEED_PALETTE_END;
7695 #endif
7696
7697 if (pull_frame_at_size(layer, image_ext, tc, width, height, palette)) {
7698 check_layer_ready(layer);
7699 pixbuf = layer_to_pixbuf(layer, TRUE, fordisp);
7700 }
7701 weed_layer_free(layer);
7702 if (pixbuf && ((width != 0 && lives_pixbuf_get_width(pixbuf) != width)
7703 || (height != 0 && lives_pixbuf_get_height(pixbuf) != height))) {
7704 LiVESPixbuf *pixbuf2;
7705 // TODO - could use resize plugin here
7706 pixbuf2 = lives_pixbuf_scale_simple(pixbuf, width, height, interp);
7707 if (pixbuf) lives_widget_object_unref(pixbuf);
7708 pixbuf = pixbuf2;
7709 }
7710
7711 return pixbuf;
7712 }
7713
7714
pull_lives_pixbuf(int clip,int frame,const char * image_ext,weed_timecode_t tc)7715 LIVES_GLOBAL_INLINE LiVESPixbuf *pull_lives_pixbuf(int clip, int frame, const char *image_ext, weed_timecode_t tc) {
7716 return pull_lives_pixbuf_at_size(clip, frame, image_ext, tc, 0, 0, LIVES_INTERP_NORMAL, FALSE);
7717 }
7718
7719
get_player_size(int * opwidth,int * opheight)7720 void get_player_size(int *opwidth, int *opheight) {
7721 // calc output size for display
7722 int rwidth, rheight;
7723
7724 ///// external playback plugin
7725 if (mainw->ext_playback) {
7726 // playback plugin (therefore fullscreen / separate window)
7727 if (mainw->vpp->capabilities & VPP_LOCAL_DISPLAY) {
7728 if (mainw->vpp->capabilities & VPP_CAN_RESIZE) {
7729 // plugin can resize, max is the screen size
7730 get_play_screen_size(opwidth, opheight);
7731 } else {
7732 // ext plugin can't resize, use its fixed size
7733 *opwidth = mainw->vpp->fwidth;
7734 *opheight = mainw->vpp->fheight;
7735 }
7736 } else {
7737 // remote display
7738 if (!(mainw->vpp->capabilities & VPP_CAN_RESIZE)) {
7739 // cant resize, we use the width it gave us if it can't resize
7740 *opwidth = mainw->vpp->fwidth;
7741 *opheight = mainw->vpp->fheight;
7742 } else {
7743 // else the clip size
7744 *opwidth = cfile->hsize;
7745 *opheight = cfile->vsize;
7746 }
7747 }
7748 goto align;
7749 }
7750
7751 if (mainw->play_window) {
7752 // playback in separate window
7753 // use values set in resize_play_window
7754 *opwidth = mainw->pwidth;
7755 *opheight = mainw->pheight;
7756 if (mainw->multitrack && prefs->letterbox_mt) {
7757 rwidth = *opwidth;
7758 rheight = *opheight;
7759 *opwidth = cfile->hsize;
7760 *opheight = cfile->vsize;
7761 calc_maxspect(rwidth, rheight, opwidth, opheight);
7762 }
7763 goto align;
7764 }
7765
7766 /////////////////////////////////////////////////////////////////////////////////
7767 // multitrack: we ignore double size, and fullscreen unless playing in the separate window
7768 if (mainw->multitrack) {
7769 // frame max sizes for multitrack
7770 /* *opwidth = mainw->files[mainw->multitrack->render_file]->hsize; */
7771 /* *opheight = mainw->files[mainw->multitrack->render_file]->vsize; */
7772 /* if (!mainw->multitrack->is_rendering) { */
7773 /* calc_maxspect(mainw->multitrack->play_width, mainw->multitrack->play_height, opwidth, opheight); */
7774 /* } */
7775 *opwidth = mainw->multitrack->play_width;
7776 *opheight = mainw->multitrack->play_height;
7777 goto align;
7778 }
7779
7780 ////////////////////////////////////////////////////////////////////////////////////
7781 // clip edit mode
7782 if (mainw->is_rendering && !mainw->preview) {
7783 *opwidth = cfile->hsize;
7784 *opheight = cfile->vsize;
7785 goto align;
7786 }
7787
7788 if (!mainw->fs) {
7789 // embedded player
7790 rwidth = lives_widget_get_allocation_width(mainw->play_image);// - H_RESIZE_ADJUST;
7791 rheight = lives_widget_get_allocation_height(mainw->play_image);// - V_RESIZE_ADJUST;
7792
7793 if (0 && prefs->letterbox) {
7794 *opwidth = cfile->hsize;
7795 *opheight = cfile->vsize;
7796 calc_maxspect(rwidth, rheight, opwidth, opheight);
7797 } else {
7798 *opwidth = rwidth;
7799 *opheight = rheight;
7800 }
7801 } else {
7802 // try to get exact inner size of the main window
7803 lives_window_get_inner_size(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), opwidth, opheight);
7804 //*opheight -= 2; // necessary, or screen expands too much (!?)
7805 if (prefs->show_tool) *opheight -= lives_widget_get_allocation_height(mainw->btoolbar);
7806 }
7807
7808 align:
7809 *opwidth = (*opwidth >> 2) << 2;
7810 *opheight = (*opheight >> 2) << 2;
7811 mainw->pwidth = *opwidth;
7812 mainw->pheight = *opheight;
7813 }
7814
7815
init_track_decoders(void)7816 void init_track_decoders(void) {
7817 int i;
7818 for (i = 0; i < MAX_TRACKS; i++) {
7819 mainw->track_decoders[i] = NULL;
7820 mainw->old_active_track_list[i] = mainw->active_track_list[i] = 0;
7821 }
7822 for (i = 0; i < MAX_FILES; i++) mainw->ext_src_used[i] = FALSE;
7823 }
7824
7825
free_track_decoders(void)7826 LIVES_GLOBAL_INLINE void free_track_decoders(void) {
7827 for (int i = 0; i < MAX_TRACKS; i++) {
7828 if (mainw->track_decoders[i] &&
7829 (mainw->active_track_list[i] <= 0 || mainw->track_decoders[i] != mainw->files[mainw->active_track_list[i]]->ext_src))
7830 close_decoder_plugin(mainw->track_decoders[i]);
7831 }
7832 }
7833
7834
check_for_overlay_text(weed_layer_t * layer)7835 static boolean check_for_overlay_text(weed_layer_t *layer) {
7836 if (mainw->urgency_msg && prefs->show_urgency_msgs) {
7837 ticks_t timeout = lives_alarm_check(LIVES_URGENCY_ALARM);
7838 if (!timeout) {
7839 lives_freep((void **)&mainw->urgency_msg);
7840 return FALSE;
7841 }
7842 render_text_overlay(layer, mainw->urgency_msg);
7843 return TRUE;
7844 }
7845
7846 if ((mainw->overlay_msg && prefs->show_overlay_msgs) || mainw->lockstats) {
7847 if (mainw->lockstats) {
7848 lives_freep((void **)&mainw->overlay_msg);
7849 show_sync_callback(NULL, NULL, 0, 0, LIVES_INT_TO_POINTER(1));
7850 if (mainw->overlay_msg) {
7851 render_text_overlay(layer, mainw->overlay_msg);
7852 if (prefs->render_overlay && mainw->record && !mainw->record_paused) {
7853 weed_plant_t *event = get_last_frame_event(mainw->event_list);
7854 if (event) weed_set_string_value(event, WEED_LEAF_OVERLAY_TEXT, mainw->overlay_msg);
7855 }
7856 }
7857 return TRUE;
7858 } else {
7859 if (!mainw->preview_rendering) {
7860 ticks_t timeout = lives_alarm_check(mainw->overlay_alarm);
7861 if (timeout == 0) {
7862 lives_freep((void **)&mainw->overlay_msg);
7863 return FALSE;
7864 }
7865 }
7866 render_text_overlay(layer, mainw->overlay_msg);
7867 if (mainw->preview_rendering) lives_freep((void **)&mainw->overlay_msg);
7868 return TRUE;
7869 }
7870 }
7871 return FALSE;
7872 }
7873
7874
do_cleanup(weed_layer_t * layer,int success)7875 static void do_cleanup(weed_layer_t *layer, int success) {
7876 /// cleanup any resources after showing a frame. This run as a thread, so the main thread can return to the player
7877 lives_clip_t *sfile = NULL;
7878 int clip = -1;
7879 double fps = DEF_FPS;
7880 frames_t frame = 0;
7881
7882 if (layer) {
7883 clip = lives_layer_get_clip(layer);
7884 frame = lives_layer_get_frame(layer);
7885 if (IS_VALID_CLIP(clip)) {
7886 sfile = mainw->files[clip];
7887 fps = sfile->pb_fps;
7888 }
7889 }
7890
7891 if (success) {
7892 char *tmp;
7893 // format is now msg|timecode|fgclip|fgframe|fgfps|
7894 lives_notify(LIVES_OSC_NOTIFY_FRAME_SYNCH, (const char *)
7895 (tmp = lives_strdup_printf("%.8f|%d|%d|%.3f|", (double)mainw->currticks / TICKS_PER_SECOND_DBL,
7896 clip, frame, fps)));
7897 lives_free(tmp);
7898 }
7899
7900 if (layer) {
7901 check_layer_ready(layer);
7902 ///mainw->frame_layer_postload = mainw->frame_layer;
7903 if (layer == mainw->frame_layer) mainw->frame_layer = NULL;
7904 weed_layer_free(layer);
7905 }
7906 }
7907
7908
7909 //static weed_plant_t *cleaner = NULL;
7910
7911 /* void wait_for_cleaner(void) { */
7912 /* if (cleaner) { */
7913 /* lives_nanosleep_until_nonzero(weed_get_boolean_value(cleaner, WEED_LEAF_DONE, NULL)); */
7914 /* weed_plant_free(cleaner); */
7915 /* cleaner = NULL; */
7916 /* } */
7917 /* } */
7918
7919 #define USEC_WAIT_FOR_SYNC 500000
7920
avsync_check(void)7921 static boolean avsync_check(void) {
7922 register int count = USEC_WAIT_FOR_SYNC / 10, rc = 0;
7923 struct timespec ts;
7924
7925 #ifdef VALGRIND_ON
7926 count *= 10;
7927 #endif
7928
7929 if (mainw->foreign || !LIVES_IS_PLAYING || prefs->audio_src == AUDIO_SRC_EXT || prefs->force_system_clock
7930 || (mainw->event_list && !(mainw->record || mainw->record_paused)) || prefs->audio_player == AUD_PLAYER_NONE
7931 || !is_realtime_aplayer(prefs->audio_player)) {
7932 mainw->video_seek_ready = mainw->audio_seek_ready = TRUE;
7933 return TRUE;
7934 }
7935
7936 if (!mainw->video_seek_ready) {
7937 #ifdef ENABLE_JACK
7938 if (!mainw->foreign && mainw->jackd && prefs->audio_player == AUD_PLAYER_JACK) {
7939 /// try to improve sync by delaying audio pb start
7940 if (LIVES_UNLIKELY(mainw->event_list && LIVES_IS_PLAYING && !mainw->record
7941 && !mainw->record_paused && mainw->jackd->is_paused)) {
7942 mainw->video_seek_ready = TRUE;
7943 if (!mainw->switch_during_pb) mainw->force_show = TRUE;
7944 return TRUE;
7945 }
7946 }
7947 #endif
7948 #ifdef HAVE_PULSE_AUDIO
7949 if (!mainw->foreign && mainw->pulsed && prefs->audio_player == AUD_PLAYER_PULSE) {
7950 /// try to improve sync by delaying audio pb start
7951 if (LIVES_UNLIKELY(mainw->event_list && LIVES_IS_PLAYING && !mainw->record
7952 && !mainw->record_paused && mainw->pulsed->is_paused)) {
7953 mainw->video_seek_ready = TRUE;
7954 if (!mainw->switch_during_pb) mainw->force_show = TRUE;
7955 return TRUE;
7956 }
7957 }
7958 #endif
7959 }
7960
7961 clock_gettime(CLOCK_REALTIME, &ts);
7962 pthread_mutex_lock(&mainw->avseek_mutex);
7963 mainw->video_seek_ready = TRUE;
7964 while (!mainw->audio_seek_ready && --count) {
7965 ts.tv_nsec += 10000; // def. 10 usec (* 50000 = 0.5 sec)
7966 if (ts.tv_nsec >= ONE_BILLION) {
7967 ts.tv_sec++;
7968 ts.tv_nsec -= ONE_BILLION;
7969 }
7970 sched_yield();
7971 rc = pthread_cond_timedwait(&mainw->avseek_cond, &mainw->avseek_mutex, &ts);
7972 mainw->video_seek_ready = TRUE;
7973 }
7974 if (!mainw->audio_seek_ready && rc == ETIMEDOUT) {
7975 pthread_mutex_unlock(&mainw->avseek_mutex);
7976 mainw->cancelled = handle_audio_timeout();
7977 return FALSE;
7978 }
7979 pthread_mutex_unlock(&mainw->avseek_mutex);
7980 return TRUE;
7981 }
7982
7983
load_frame_image(int frame)7984 void load_frame_image(int frame) {
7985 // this is where we do the actual load/record of a playback frame
7986 // it is called every 1/fps from do_progress_dialog() via process_one() in dialogs.c
7987
7988 // for the multitrack window we set mainw->frame_image; this is used to display the
7989 // preview image
7990
7991 // NOTE: we should be careful if load_frame_image() is called from anywhere inside load_frame_image()
7992 // e.g. by calling g_main_context_iteration() --> user presses sepwin button --> load_frame_image() is called
7993 // this is because mainw->frame_layer is global and gets freed() before exit from load_frame_image()
7994
7995 void **pd_array, **retdata = NULL;
7996 LiVESPixbuf *pixbuf = NULL;
7997
7998 char *framecount = NULL, *tmp;
7999 char *fname_next = NULL, *info_file = NULL;
8000 const char *img_ext = NULL;
8001
8002 LiVESInterpType interp;
8003 double scrap_file_size = -1;
8004
8005 ticks_t audio_timed_out = 1;
8006
8007 boolean was_preview = FALSE;
8008 boolean rec_after_pb = FALSE;
8009 boolean success = FALSE;
8010 boolean size_ok = TRUE;
8011 boolean player_v2 = FALSE;
8012
8013 int retval;
8014 int layer_palette, cpal;
8015
8016 static int old_pwidth = 0, old_pheight = 0;
8017 int opwidth = 0, opheight = 0;
8018 int pwidth, pheight;
8019 int lb_width = 0, lb_height = 0;
8020 int bad_frame_count = 0;
8021 int fg_file = mainw->current_file;
8022 int tgamma = WEED_GAMMA_UNKNOWN;
8023 boolean was_letterboxed = FALSE;
8024
8025 #if defined ENABLE_JACK || defined HAVE_PULSE_AUDIO
8026 lives_alarm_t alarm_handle;
8027 #endif
8028
8029 #define BFC_LIMIT 1000
8030 if (LIVES_UNLIKELY(cfile->frames == 0 && !mainw->foreign && !mainw->is_rendering)) {
8031 if (mainw->record && !mainw->record_paused) {
8032 // add blank frame
8033 weed_plant_t *event = get_last_event(mainw->event_list);
8034 weed_plant_t *event_list = insert_blank_frame_event_at(mainw->event_list, lives_get_relative_ticks(mainw->origsecs,
8035 mainw->orignsecs),
8036 &event);
8037 if (!mainw->event_list) mainw->event_list = event_list;
8038 if (mainw->rec_aclip != -1 && (prefs->rec_opts & REC_AUDIO) && !mainw->record_starting) {
8039 // we are recording, and the audio clip changed; add audio
8040 if (mainw->rec_aclip == mainw->ascrap_file) {
8041 mainw->rec_aseek = (double)mainw->files[mainw->ascrap_file]->aseek_pos /
8042 (double)(mainw->files[mainw->ascrap_file]->arps * mainw->files[mainw->ascrap_file]->achans *
8043 mainw->files[mainw->ascrap_file]->asampsize >> 3);
8044 mainw->rec_avel = 1.;
8045 }
8046 if (!mainw->mute) {
8047 insert_audio_event_at(event, -1, mainw->rec_aclip, mainw->rec_aseek, mainw->rec_avel);
8048 mainw->rec_aclip = -1;
8049 }
8050 }
8051 }
8052 if (!mainw->fs && !mainw->faded) get_play_times();
8053
8054 return;
8055 }
8056
8057 if (!mainw->foreign) {
8058 mainw->actual_frame = frame;
8059 if (!mainw->preview_rendering && (!((was_preview = mainw->preview) || mainw->is_rendering))) {
8060 /////////////////////////////////////////////////////////
8061
8062 // normal play
8063
8064 if (LIVES_UNLIKELY(mainw->nervous) && clip_can_reverse(mainw->playing_file)) {
8065 // nervous mode
8066 if ((mainw->actual_frame += (-10 + (int)(21.*rand() / (RAND_MAX + 1.0)))) > cfile->frames ||
8067 mainw->actual_frame < 1) mainw->actual_frame = frame;
8068 else resync_audio(mainw->actual_frame);
8069 }
8070
8071 if (mainw->opening_loc || !CURRENT_CLIP_IS_NORMAL) {
8072 framecount = lives_strdup_printf("%9d", mainw->actual_frame);
8073 } else {
8074 framecount = lives_strdup_printf("%9d / %d", mainw->actual_frame, cfile->frames);
8075 }
8076
8077 /////////////////////////////////////////////////
8078
8079 // record performance
8080 if ((mainw->record && !mainw->record_paused) || mainw->record_starting) {
8081 ticks_t actual_ticks;
8082 int fg_frame = mainw->record_frame;
8083 int bg_file = IS_VALID_CLIP(mainw->blend_file) && mainw->blend_file != mainw->current_file
8084 ? mainw->blend_file : -1;
8085 int bg_frame = bg_file > 0 && bg_file != mainw->current_file ? mainw->files[bg_file]->frameno : 0;
8086 int numframes;
8087 int *clips;
8088 int64_t *frames;
8089 weed_plant_t *event_list;
8090
8091 // should we record the output from the playback plugin ?
8092 if (mainw->record && (prefs->rec_opts & REC_AFTER_PB) && mainw->ext_playback &&
8093 (mainw->vpp->capabilities & VPP_CAN_RETURN)) {
8094 rec_after_pb = TRUE;
8095 }
8096
8097 if (rec_after_pb || !CURRENT_CLIP_IS_NORMAL ||
8098 (prefs->rec_opts & REC_EFFECTS && bg_file != -1 && !IS_NORMAL_CLIP(bg_file))) {
8099 // TODO - handle non-opening of scrap_file
8100 if (mainw->scrap_file == -1) open_scrap_file();
8101 fg_file = mainw->scrap_file;
8102 fg_frame = mainw->files[mainw->scrap_file]->frames + 1;
8103 scrap_file_size = mainw->files[mainw->scrap_file]->f_size;
8104 bg_file = -1;
8105 bg_frame = 0;
8106 }
8107
8108 //actual_ticks = mainw->clock_ticks;//mainw->currticks;
8109 actual_ticks = mainw->startticks; ///< use the "thoretical" time
8110
8111 if (mainw->record_starting) {
8112 if (!mainw->event_list) {
8113 mainw->event_list = lives_event_list_new(NULL, NULL);
8114 }
8115
8116 // mark record start
8117 mainw->event_list = append_marker_event(mainw->event_list, actual_ticks, EVENT_MARKER_RECORD_START);
8118
8119 if (prefs->rec_opts & REC_EFFECTS) {
8120 // add init events and pchanges for all active fx
8121 add_filter_init_events(mainw->event_list, actual_ticks);
8122 }
8123
8124 #ifdef ENABLE_JACK
8125 if (prefs->audio_player == AUD_PLAYER_JACK && mainw->jackd &&
8126 (prefs->rec_opts & REC_AUDIO) && prefs->audio_src == AUDIO_SRC_INT && mainw->rec_aclip != mainw->ascrap_file) {
8127 // get current seek postion
8128 alarm_handle = lives_alarm_set(LIVES_SHORT_TIMEOUT);
8129
8130 while ((audio_timed_out = lives_alarm_check(alarm_handle)) > 0 && jack_get_msgq(mainw->jackd) != NULL) {
8131 // wait for audio player message queue clearing
8132 sched_yield();
8133 lives_usleep(prefs->sleep_time);
8134 }
8135 lives_alarm_clear(alarm_handle);
8136 if (audio_timed_out == 0) {
8137 mainw->cancelled = handle_audio_timeout();
8138 goto lfi_done;
8139 }
8140 jack_get_rec_avals(mainw->jackd);
8141 }
8142 #endif
8143 #ifdef HAVE_PULSE_AUDIO
8144 if (prefs->audio_player == AUD_PLAYER_PULSE && mainw->pulsed &&
8145 (prefs->rec_opts & REC_AUDIO) && prefs->audio_src == AUDIO_SRC_INT && mainw->rec_aclip != mainw->ascrap_file) {
8146 // get current seek postion
8147 alarm_handle = lives_alarm_set(LIVES_SHORT_TIMEOUT);
8148 while ((audio_timed_out = lives_alarm_check(alarm_handle)) > 0 && pulse_get_msgq(mainw->pulsed) != NULL) {
8149 // wait for audio player message queue clearing
8150 sched_yield();
8151 lives_usleep(prefs->sleep_time);
8152 }
8153 lives_alarm_clear(alarm_handle);
8154 pulse_get_rec_avals(mainw->pulsed);
8155 }
8156 #endif
8157 mainw->record_starting = FALSE;
8158 if (audio_timed_out == 0) {
8159 mainw->cancelled = handle_audio_timeout();
8160 goto lfi_done;
8161 }
8162 mainw->record = TRUE;
8163 mainw->record_paused = FALSE;
8164 }
8165
8166 numframes = (bg_file == -1) ? 1 : 2;
8167 clips = (int *)lives_malloc(numframes * sizint);
8168 frames = (int64_t *)lives_malloc(numframes * 8);
8169
8170 clips[0] = fg_file;
8171 frames[0] = (int64_t)fg_frame;
8172 if (numframes == 2) {
8173 clips[1] = bg_file;
8174 frames[1] = (int64_t)bg_frame;
8175 }
8176 if (framecount) lives_free(framecount);
8177 pthread_mutex_lock(&mainw->event_list_mutex);
8178
8179 /// usual function to record a frame event
8180 if ((event_list = append_frame_event(mainw->event_list, actual_ticks, numframes, clips, frames)) != NULL) {
8181 if (!mainw->event_list) mainw->event_list = event_list;
8182
8183 // TODO ***: do we need to perform more checks here ???
8184 if (scrap_file_size != -1 || (mainw->rec_aclip != -1 && (prefs->rec_opts & REC_AUDIO))) {
8185 weed_plant_t *event = get_last_frame_event(mainw->event_list);
8186
8187 if (scrap_file_size != -1) weed_set_int64_value(event, WEED_LEAF_HOST_SCRAP_FILE_OFFSET, scrap_file_size);
8188
8189 if (mainw->rec_aclip != -1) {
8190 if (mainw->rec_aclip == mainw->ascrap_file) {
8191 mainw->rec_aseek = (double)mainw->files[mainw->ascrap_file]->aseek_pos /
8192 (double)(mainw->files[mainw->ascrap_file]->arps * mainw->files[mainw->ascrap_file]->achans *
8193 mainw->files[mainw->ascrap_file]->asampsize >> 3);
8194 mainw->rec_avel = 1.;
8195
8196 }
8197 if (!mainw->mute) {
8198 weed_event_t *xevent = get_prev_frame_event(event);
8199 if (!xevent) xevent = event;
8200 insert_audio_event_at(xevent, -1, mainw->rec_aclip, mainw->rec_aseek, mainw->rec_avel);
8201 }
8202 mainw->rec_aclip = -1;
8203 }
8204 }
8205 pthread_mutex_unlock(&mainw->event_list_mutex);
8206
8207 /* TRANSLATORS: rec(ord) */
8208 framecount = lives_strdup_printf((tmp = _("rec %9d / %d")), mainw->actual_frame,
8209 cfile->frames > mainw->actual_frame ? cfile->frames : mainw->actual_frame);
8210 } else {
8211 pthread_mutex_unlock(&mainw->event_list_mutex);
8212 /* TRANSLATORS: out of memory (rec(ord)) */
8213 framecount = lives_strdup_printf((tmp = _("!rec %9d / %d")), mainw->actual_frame, cfile->frames);
8214 }
8215 lives_free(tmp);
8216 lives_free(clips);
8217 lives_free(frames);
8218 } else {
8219 if (mainw->toy_type != LIVES_TOY_NONE) {
8220 if (mainw->toy_type == LIVES_TOY_MAD_FRAMES && !mainw->fs && CURRENT_CLIP_IS_NORMAL) {
8221 int current_file = mainw->current_file;
8222 if (mainw->toy_go_wild) {
8223 int i, other_file;
8224 for (i = 0; i < 11; i++) {
8225 other_file = (1 + (int)((double)(mainw->clips_available) * rand() / (RAND_MAX + 1.0)));
8226 other_file = LIVES_POINTER_TO_INT(lives_list_nth_data(mainw->cliplist, other_file));
8227 if (mainw->files[other_file]) {
8228 // steal a frame from another clip
8229 mainw->current_file = other_file;
8230 }
8231 }
8232 }
8233 load_end_image(1 + (int)((double)cfile->frames * rand() / (RAND_MAX + 1.0)));
8234 load_start_image(1 + (int)((double)cfile->frames * rand() / (RAND_MAX + 1.0)));
8235 mainw->current_file = current_file;
8236 }
8237 }
8238 }
8239
8240 if ((!mainw->fs || (prefs->play_monitor != widget_opts.monitor && capable->nmonitors > 1) ||
8241 (mainw->ext_playback && !(mainw->vpp->capabilities & VPP_LOCAL_DISPLAY)))
8242 && !prefs->hide_framebar) {
8243 lives_entry_set_text(LIVES_ENTRY(mainw->framecounter), framecount);
8244 //lives_widget_queue_draw(mainw->framecounter);
8245 }
8246 lives_freep((void **)&framecount);
8247 }
8248
8249 if (was_preview) {
8250 // preview
8251 if (mainw->proc_ptr && mainw->proc_ptr->frames_done > 0 &&
8252 frame >= (mainw->proc_ptr->frames_done - cfile->progress_start + cfile->start)) {
8253 if (cfile->opening) {
8254 mainw->proc_ptr->frames_done = cfile->opening_frames = get_frame_count(mainw->current_file, cfile->opening_frames);
8255 }
8256 }
8257 if (mainw->proc_ptr && mainw->proc_ptr->frames_done > 0 &&
8258 frame >= (mainw->proc_ptr->frames_done - cfile->progress_start + cfile->start)) {
8259 mainw->cancelled = CANCEL_PREVIEW_FINISHED;
8260 goto lfi_done;
8261 }
8262
8263 // play preview
8264 if (cfile->opening || (cfile->next_event && !mainw->proc_ptr)) {
8265 fname_next = make_image_file_name(cfile, frame + 1, get_image_ext_for_type(cfile->img_type));
8266 if (!mainw->fs && !prefs->hide_framebar && !mainw->is_rendering) {
8267 lives_freep((void **)&framecount);
8268 if (CURRENT_CLIP_HAS_VIDEO && cfile->frames != 123456789) {
8269 framecount = lives_strdup_printf("%9d / %d", frame, cfile->frames);
8270 } else {
8271 framecount = lives_strdup_printf("%9d", frame);
8272 }
8273 lives_entry_set_text(LIVES_ENTRY(mainw->framecounter), framecount);
8274 lives_widget_queue_draw(mainw->framecounter);
8275 lives_freep((void **)&framecount);
8276 }
8277 if (mainw->toy_type != LIVES_TOY_NONE) {
8278 // TODO - move into toys.c
8279 if (mainw->toy_type == LIVES_TOY_MAD_FRAMES && !mainw->fs) {
8280 if (cfile->opening_only_audio) {
8281 load_end_image(1 + (int)((double)cfile->frames * rand() / (RAND_MAX + 1.0)));
8282 load_start_image(1 + (int)((double)cfile->frames * rand() / (RAND_MAX + 1.0)));
8283 } else {
8284 load_end_image(1 + (int)((double)frame * rand() / (RAND_MAX + 1.0)));
8285 load_start_image(1 + (int)((double)frame * rand() / (RAND_MAX + 1.0)));
8286 }
8287 }
8288 }
8289 } else {
8290 if (mainw->is_rendering || mainw->is_generating) {
8291 fname_next = make_image_file_name(cfile, frame + 1, get_image_ext_for_type(cfile->img_type));
8292 } else {
8293 if (!mainw->keep_pre) {
8294 img_ext = LIVES_FILE_EXT_MGK;
8295 } else {
8296 img_ext = LIVES_FILE_EXT_PRE;
8297 }
8298 fname_next = make_image_file_name(cfile, frame + 1, img_ext);
8299 }
8300 }
8301 mainw->actual_frame = frame;
8302
8303 // maybe the performance finished and we weren't looping
8304 if ((mainw->actual_frame < 1 || mainw->actual_frame > cfile->frames) &&
8305 CURRENT_CLIP_IS_NORMAL && (!mainw->is_rendering || mainw->preview)) {
8306 goto lfi_done;
8307 return;
8308 }
8309 }
8310
8311 // limit max frame size unless we are saving to disk or rendering
8312 // frame_layer will in any case be equal to or smaller than this depending on maximum source frame size
8313
8314 if (!(mainw->record && !mainw->record_paused && (prefs->rec_opts & REC_EFFECTS) &&
8315 (!CURRENT_CLIP_IS_NORMAL || (IS_VALID_CLIP(mainw->blend_file) && !IS_NORMAL_CLIP(mainw->blend_file))))) {
8316 get_player_size(&opwidth, &opheight);
8317 }
8318
8319 ////////////////////////////////////////////////////////////
8320 // load a frame from disk buffer
8321
8322 if (mainw->preview && !mainw->frame_layer && (!mainw->event_list || cfile->opening)) {
8323 info_file = lives_build_filename(prefs->workdir, cfile->handle, LIVES_STATUS_FILE_NAME, NULL);
8324 }
8325
8326 do {
8327 //wait_for_cleaner();
8328 if (mainw->frame_layer) {
8329 // free the old mainw->frame_layer
8330 check_layer_ready(mainw->frame_layer); // ensure all threads are complete
8331 weed_layer_free(mainw->frame_layer);
8332 mainw->frame_layer = NULL;
8333 }
8334
8335 if (mainw->is_rendering && !(mainw->proc_ptr && mainw->preview)) {
8336 // here if we are rendering from multitrack, previewing a recording, or applying realtime effects to a selection
8337 weed_timecode_t tc = mainw->cevent_tc;
8338 if (mainw->scrap_file != -1 && mainw->clip_index[0] == mainw->scrap_file && mainw->num_tracks == 1) {
8339 // do not apply fx, just pull frame
8340 mainw->frame_layer = lives_layer_new_for_frame(mainw->clip_index[0], mainw->frame_index[0]);
8341 pull_frame_threaded(mainw->frame_layer, NULL, (weed_timecode_t)mainw->currticks, 0, 0);
8342 /* if (!pull_frame(mainw->frame_layer, get_image_ext_for_type(cfile->img_type), tc)) { */
8343 /* weed_plant_free(mainw->frame_layer); */
8344 /* mainw->frame_layer = NULL; */
8345 /* if (mainw->preview_rendering) { */
8346 /* mainw->cancelled = CANCEL_NO_MORE_PREVIEW; */
8347 /* goto lfi_done; */
8348 /* } */
8349 /* } */
8350 } else {
8351 int oclip, nclip;
8352 register int i;
8353 weed_plant_t **layers = (weed_plant_t **)lives_calloc((mainw->num_tracks + 1), sizeof(weed_plant_t *));
8354 // get list of active tracks from mainw->filter map
8355 get_active_track_list(mainw->clip_index, mainw->num_tracks, mainw->filter_map);
8356 for (i = 0; i < mainw->num_tracks; i++) {
8357 oclip = mainw->old_active_track_list[i];
8358 mainw->ext_src_used[oclip] = FALSE;
8359 if (oclip > 0 && oclip == (nclip = mainw->active_track_list[i])) {
8360 // check if ext_src survives old->new
8361 if (mainw->track_decoders[i] == mainw->files[oclip]->ext_src) mainw->ext_src_used[oclip] = TRUE;
8362 }
8363 }
8364
8365 for (i = 0; i < mainw->num_tracks; i++) {
8366 layers[i] = lives_layer_new_for_frame(mainw->clip_index[i], mainw->frame_index[i]);
8367 weed_set_int_value(layers[i], WEED_LEAF_CURRENT_PALETTE, (mainw->clip_index[i] == -1 ||
8368 mainw->files[mainw->clip_index[i]]->img_type ==
8369 IMG_TYPE_JPEG) ? WEED_PALETTE_RGB24 : WEED_PALETTE_RGBA32);
8370 if ((oclip = mainw->old_active_track_list[i]) != (nclip = mainw->active_track_list[i])) {
8371 // now using threading, we want to start pulling all pixel_data for all active layers here
8372 // however, we may have more than one copy of the same clip -
8373 // in this case we want to create clones of the decoder plugin
8374 // this is to prevent constant seeking between different frames in the clip
8375 if (oclip > 0) {
8376 if (mainw->files[oclip]->clip_type == CLIP_TYPE_FILE) {
8377 if (mainw->track_decoders[i] != (lives_decoder_t *)mainw->files[oclip]->ext_src) {
8378 // remove the clone for oclip
8379 close_decoder_plugin(mainw->track_decoders[i]);
8380 }
8381 mainw->track_decoders[i] = NULL;
8382 }
8383 }
8384
8385 if (nclip > 0) {
8386 if (mainw->files[nclip]->clip_type == CLIP_TYPE_FILE) {
8387 if (!mainw->ext_src_used[nclip]) {
8388 mainw->track_decoders[i] = (lives_decoder_t *)mainw->files[nclip]->ext_src;
8389 mainw->ext_src_used[nclip] = TRUE;
8390 } else {
8391 // add new clone for nclip
8392 mainw->track_decoders[i] = clone_decoder(nclip);
8393 // *INDENT-OFF*
8394 }}}}
8395 // *INDENT-ON*
8396
8397 mainw->old_active_track_list[i] = mainw->active_track_list[i];
8398
8399 if (nclip > 0) {
8400 img_ext = get_image_ext_for_type(mainw->files[nclip]->img_type);
8401 // set alt src in layer
8402 weed_set_voidptr_value(layers[i], WEED_LEAF_HOST_DECODER, (void *)mainw->track_decoders[i]);
8403 pull_frame_threaded(layers[i], img_ext, (weed_timecode_t)mainw->currticks, 0, 0);
8404 } else {
8405 weed_layer_pixel_data_free(layers[i]);
8406 }
8407 }
8408 layers[i] = NULL;
8409
8410 mainw->frame_layer = weed_apply_effects(layers, mainw->filter_map, tc, opwidth, opheight, mainw->pchains);
8411
8412 for (i = 0; layers[i]; i++) {
8413 if (layers[i] != mainw->frame_layer) {
8414 check_layer_ready(layers[i]);
8415 weed_layer_free(layers[i]);
8416 }
8417 }
8418 lives_free(layers);
8419
8420 if (mainw->internal_messaging) {
8421 // this happens if we are calling from multitrack, or apply rte. We get our mainw->frame_layer and exit.
8422 // DO NOT goto lfi_done, as that will free mainw->frame_layer.
8423 lives_freep((void **)&framecount);
8424 lives_freep((void **)&info_file);
8425 return;
8426 }
8427 }
8428 } else {
8429 if (prefs->dev_show_timing)
8430 g_printerr("pull_frame @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8431 // normal playback in the clip editor, or applying a non-realtime effect
8432 if (cfile->clip_type != CLIP_TYPE_DISK
8433 || !mainw->preview || lives_file_test(fname_next, LIVES_FILE_TEST_EXISTS)) {
8434 mainw->frame_layer = lives_layer_new_for_frame(mainw->current_file, mainw->actual_frame);
8435 if (!img_ext) img_ext = get_image_ext_for_type(cfile->img_type);
8436 if (mainw->preview && !mainw->frame_layer
8437 && (!mainw->event_list || cfile->opening)) {
8438 if (!pull_frame_at_size(mainw->frame_layer, img_ext, (weed_timecode_t)mainw->currticks,
8439 cfile->hsize, cfile->vsize, WEED_PALETTE_END)) {
8440 if (mainw->frame_layer) {
8441 weed_layer_free(mainw->frame_layer);
8442 mainw->frame_layer = NULL;
8443 }
8444
8445 if (cfile->clip_type == CLIP_TYPE_DISK &&
8446 cfile->opening && cfile->img_type == IMG_TYPE_PNG
8447 && sget_file_size(fname_next) <= 0) {
8448 if (++bad_frame_count > BFC_LIMIT) {
8449 mainw->cancelled = check_for_bad_ffmpeg();
8450 bad_frame_count = 0;
8451 } else lives_usleep(prefs->sleep_time);
8452 }
8453 }
8454 } else {
8455 boolean got_preload = FALSE;
8456 if (mainw->frame_layer_preload && mainw->pred_clip == mainw->playing_file
8457 && mainw->pred_frame != 0 && is_layer_ready(mainw->frame_layer_preload)) {
8458 frames_t delta = (labs(mainw->pred_frame) - mainw->actual_frame) * sig(cfile->pb_fps);
8459 /* g_print("THANKS for %p,! %d %ld should be %d, right -- %d",
8460 // mainw->frame_layer_preload, mainw->pred_clip, */
8461 /* mainw->pred_frame, mainw->actual_frame, delta); */
8462 if (delta <= 0 || (mainw->pred_frame < 0 && delta > 0)) {
8463 check_layer_ready(mainw->frame_layer_preload);
8464 if (weed_layer_get_pixel_data_packed(mainw->frame_layer_preload) != NULL) {
8465 //g_print("YAH !\n");
8466 got_preload = TRUE;
8467 if (mainw->pred_frame < 0) {
8468 if (mainw->frame_layer) weed_layer_free(mainw->frame_layer);
8469 mainw->frame_layer = weed_layer_copy(NULL, mainw->frame_layer_preload);
8470 } else {
8471 weed_layer_copy(mainw->frame_layer, mainw->frame_layer_preload);
8472 weed_layer_nullify_pixel_data(mainw->frame_layer_preload);
8473 }
8474 }
8475 }
8476 if (prefs->show_dev_opts) {
8477 if (delta < 0) g_printerr("cached frame TOO LATE, got %ld, wanted %d !!!\n",
8478 labs(mainw->pred_frame), mainw->actual_frame);
8479 }
8480 //if (delta > 0) g_print(" waiting...\n");
8481 }
8482 if (!got_preload) {
8483 pull_frame_threaded(mainw->frame_layer, img_ext, (weed_timecode_t)mainw->currticks, 0, 0);
8484 //pull_frame(mainw->frame_layer, img_ext, (weed_timecode_t)mainw->currticks);
8485 }
8486 if ((mainw->rte != 0 || (mainw->is_rendering && !mainw->event_list))
8487 && (mainw->current_file != mainw->scrap_file || mainw->multitrack)) {
8488 /// will set mainw->blend_layer
8489 get_blend_layer((weed_timecode_t)mainw->currticks);
8490 }
8491 }
8492 }
8493
8494 if (prefs->dev_show_timing)
8495 g_printerr("pull_frame done @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8496 if ((!cfile->next_event && mainw->is_rendering && !mainw->switch_during_pb &&
8497 (!mainw->multitrack || (!mainw->multitrack->is_rendering && !mainw->is_generating))) ||
8498 ((!mainw->multitrack || (mainw->multitrack && mainw->multitrack->is_rendering)) &&
8499 mainw->preview && !mainw->frame_layer)) {
8500 // preview ended
8501 if (!cfile->opening) mainw->cancelled = CANCEL_NO_MORE_PREVIEW;
8502 if (mainw->cancelled) {
8503 lives_free(fname_next);
8504 lives_freep((void **)&info_file);
8505 goto lfi_done;
8506 }
8507 // ???
8508 mainw->currticks = lives_get_current_playback_ticks(mainw->origsecs, mainw->orignsecs, NULL);
8509 }
8510
8511 img_ext = NULL;
8512
8513 if (mainw->internal_messaging) {
8514 // here we are rendering to an effect or timeline, need to keep mainw->frame_layer and return
8515 lives_freep((void **)&framecount);
8516 lives_freep((void **)&info_file);
8517 check_layer_ready(mainw->frame_layer);
8518 return;
8519 }
8520
8521 if (!mainw->frame_layer && (!mainw->preview || (mainw->multitrack && !cfile->opening))) {
8522 lives_freep((void **)&info_file);
8523 goto lfi_done;
8524 }
8525
8526 if (mainw->preview && !mainw->frame_layer && (!mainw->event_list || cfile->opening)) {
8527 FILE *fp;
8528 // non-realtime effect preview
8529 // check effect to see if it finished yet
8530 if ((fp = fopen(info_file, "r"))) {
8531 clear_mainw_msg();
8532 do {
8533 retval = 0;
8534 lives_fgets(mainw->msg, MAINW_MSG_SIZE, fp);
8535 if (THREADVAR(read_failed) && THREADVAR(read_failed) == fileno(fp) + 1) {
8536 THREADVAR(read_failed) = 0;
8537 retval = do_read_failed_error_s_with_retry(info_file, NULL);
8538 }
8539 } while (retval == LIVES_RESPONSE_RETRY);
8540 fclose(fp);
8541 if (!lives_strncmp(mainw->msg, "completed", 9) || !strncmp(mainw->msg, "error", 5)) {
8542 // effect completed whilst we were busy playing a preview
8543 if (mainw->preview_box) lives_widget_set_tooltip_text(mainw->p_playbutton, _("Play"));
8544 lives_widget_set_tooltip_text(mainw->m_playbutton, _("Play"));
8545 if (cfile->opening && !cfile->is_loaded) {
8546 if (mainw->toy_type == LIVES_TOY_TV) {
8547 on_toy_activate(NULL, LIVES_INT_TO_POINTER(LIVES_TOY_NONE));
8548 }
8549 }
8550 mainw->preview = FALSE;
8551 } else {
8552 lives_usleep(prefs->sleep_time);
8553 }
8554 } else {
8555 lives_usleep(prefs->sleep_time);
8556 }
8557
8558 // or we reached the end of the preview
8559 if ((!cfile->opening && frame >= (mainw->proc_ptr->frames_done - cfile->progress_start + cfile->start)) ||
8560 (cfile->opening && (mainw->toy_type == LIVES_TOY_TV || !mainw->preview || mainw->effects_paused))) {
8561 if (mainw->toy_type == LIVES_TOY_TV) {
8562 // force a loop (set mainw->cancelled to CANCEL_KEEP_LOOPING to play selection again)
8563 mainw->cancelled = CANCEL_KEEP_LOOPING;
8564 } else mainw->cancelled = CANCEL_NO_MORE_PREVIEW;
8565 lives_free(fname_next);
8566 // end of playback, so this is no longer needed
8567 lives_freep((void **)&info_file);
8568 goto lfi_done;
8569 } else if (mainw->preview || cfile->opening) lives_widget_context_update();
8570 }
8571 }
8572 } while (!mainw->frame_layer && mainw->cancelled == CANCEL_NONE && cfile->clip_type == CLIP_TYPE_DISK);
8573
8574 lives_freep((void **)&info_file);
8575
8576 if (LIVES_UNLIKELY((!mainw->frame_layer) || mainw->cancelled > 0)) {
8577 // NULL frame or user cancelled
8578 if (mainw->frame_layer) {
8579 check_layer_ready(mainw->frame_layer);
8580 weed_layer_free(mainw->frame_layer);
8581 mainw->frame_layer = NULL;
8582 }
8583 goto lfi_done;
8584 }
8585
8586 if (was_preview) {
8587 lives_free(fname_next);
8588 }
8589
8590 // OK. Here is the deal now. We have a layer from the current file, current frame.
8591 // (or at least we sent out a thread to fetch it).
8592 // We will pass this into the effects, and we will get back a layer.
8593 // The palette of the effected layer could be any Weed palette.
8594 // We will pass the layer to all playback plugins.
8595 // Finally we may want to end up with a GkdPixbuf (unless the playback plugin is VPP_DISPLAY_LOCAL
8596 // and we are in full screen mode).
8597
8598 if (!prefs->vj_mode && (mainw->current_file != mainw->scrap_file || mainw->multitrack)
8599 && mainw->pwidth > 0 && mainw->pheight > 0
8600 && !(mainw->is_rendering && !(mainw->proc_ptr && mainw->preview))
8601 && !cfile->opening && !mainw->resizing && CURRENT_CLIP_IS_NORMAL
8602 && !is_virtual_frame(mainw->current_file, mainw->actual_frame)
8603 && is_layer_ready(mainw->frame_layer)) {
8604 // if we are pulling the frame from an image and playing back normally, check the size is what it should be
8605 // this used to cause problems with some effects, but that may no longer be the case with the layers model
8606 int wl = weed_layer_get_width(mainw->frame_layer) *
8607 weed_palette_get_pixels_per_macropixel(weed_layer_get_palette(mainw->frame_layer));
8608 int hl = weed_layer_get_height(mainw->frame_layer);
8609 if ((wl != cfile->hsize && wl != mainw->pwidth)
8610 || (hl != cfile->vsize && hl != mainw->pheight)) {
8611 break_me("bad frame size");
8612 mainw->size_warn = mainw->current_file;
8613 size_ok = FALSE;
8614 }
8615 }
8616
8617 if (size_ok) {
8618 // if frame size is OK we apply real time effects
8619 if ((mainw->rte != 0 || (mainw->is_rendering && !mainw->event_list))
8620 && (mainw->current_file != mainw->scrap_file || mainw->multitrack)) {
8621 if (prefs->dev_show_timing)
8622 g_printerr("rte start @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8623 mainw->frame_layer = on_rte_apply(mainw->frame_layer, lb_width, lb_height, (weed_timecode_t)mainw->currticks);
8624 }
8625 }
8626
8627 if (prefs->dev_show_timing)
8628 g_printerr("rte done @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8629
8630 ////////////////////////
8631
8632 // save to scrap_file now if we have to
8633 if (mainw->record && !mainw->record_paused && mainw->scrap_file != -1 && fg_file == mainw->scrap_file) {
8634 if (!rec_after_pb) {
8635 check_layer_ready(mainw->frame_layer);
8636 save_to_scrap_file(mainw->frame_layer);
8637 }
8638 get_player_size(&opwidth, &opheight);
8639 }
8640
8641 if (mainw->ext_playback && (mainw->vpp->capabilities & VPP_CAN_RESIZE)
8642 && ((((!prefs->letterbox && !mainw->multitrack) || (mainw->multitrack && !prefs->letterbox_mt)))
8643 || (mainw->vpp->capabilities & VPP_CAN_LETTERBOX))) {
8644 // here we are outputing video through a video playback plugin which can resize: thus we just send whatever we have
8645 // we need only to convert the palette to whatever was agreed with the plugin when we called set_palette()
8646 // in plugins.c
8647 //
8648 // if we want letterboxing we do this ourselves, later in the code
8649
8650 weed_plant_t *frame_layer = NULL;
8651 weed_plant_t *return_layer = NULL;
8652 int lwidth, lheight;
8653 int ovpppalette = mainw->vpp->palette;
8654
8655 /// check if function exists - it accepts rowstrides
8656 if (mainw->vpp->play_frame) player_v2 = TRUE;
8657
8658 //g_print("clr1 start @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8659 check_layer_ready(mainw->frame_layer);
8660 mainw->video_seek_ready = TRUE;
8661 //g_print("clr1 done @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8662
8663 layer_palette = weed_layer_get_palette(mainw->frame_layer);
8664 if (!weed_palette_is_valid(layer_palette)) {
8665 goto lfi_done;
8666 }
8667
8668 if ((mainw->vpp->capabilities & VPP_CAN_CHANGE_PALETTE)
8669 && mainw->vpp->palette != layer_palette) vpp_try_match_palette(mainw->vpp, mainw->frame_layer);
8670
8671 if (!(mainw->vpp->capabilities & VPP_LOCAL_DISPLAY) &&
8672 ((weed_palette_is_rgb(layer_palette) &&
8673 !(weed_palette_is_rgb(mainw->vpp->palette))) ||
8674 (weed_palette_is_lower_quality(mainw->vpp->palette, layer_palette)))) {
8675 // mainw->frame_layer is RGB and so is our screen, but plugin is YUV
8676 // so copy layer and convert, retaining original
8677 if (!player_v2) THREADVAR(rowstride_alignment_hint) = -1;
8678 frame_layer = weed_layer_copy(NULL, mainw->frame_layer);
8679 } else frame_layer = mainw->frame_layer;
8680
8681 if (mainw->vpp->capabilities & VPP_LOCAL_DISPLAY) {
8682 if (!check_for_overlay_text(frame_layer)) {
8683 if (mainw->multitrack && mainw->multitrack->opts.overlay_timecode) {
8684 frame_layer = render_text_overlay(frame_layer, mainw->multitrack->timestring);
8685 }
8686 }
8687 }
8688
8689 if (prefs->apply_gamma) {
8690 // gamma correction
8691 if (weed_palette_is_rgb(mainw->vpp->palette)) {
8692 if (mainw->vpp->capabilities & VPP_LINEAR_GAMMA)
8693 tgamma = WEED_GAMMA_LINEAR;
8694 else {
8695 tgamma = WEED_GAMMA_SRGB;
8696 }
8697 }
8698 }
8699
8700 if (!player_v2) THREADVAR(rowstride_alignment_hint) = -1;
8701 if (!convert_layer_palette_full(frame_layer, mainw->vpp->palette, mainw->vpp->YUV_clamping,
8702 mainw->vpp->YUV_sampling, mainw->vpp->YUV_subspace, tgamma)) {
8703 goto lfi_done;
8704 }
8705 if (prefs->dev_show_timing)
8706 g_print("cl palette done %d to %d @ %f\n", weed_layer_get_palette(frame_layer), mainw->vpp->palette,
8707 lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8708
8709 if (!player_v2) {
8710 // vid plugin expects compacted rowstrides (i.e. no padding/alignment after pixel row)
8711 if (!compact_rowstrides(frame_layer)) {
8712 goto lfi_done;
8713 }
8714 }
8715 if (prefs->dev_show_timing)
8716 g_print("comp rs done @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8717 if (mainw->stream_ticks == -1) mainw->stream_ticks = mainw->currticks;
8718
8719 if (rec_after_pb) {
8720 // record output from playback plugin
8721
8722 int retwidth = mainw->pwidth / weed_palette_get_pixels_per_macropixel(mainw->vpp->palette);
8723 int retheight = mainw->pheight;
8724
8725 return_layer = weed_layer_create(retwidth, retheight, NULL, ovpppalette);
8726
8727 if (weed_palette_is_yuv(ovpppalette)) {
8728 weed_set_int_value(return_layer, WEED_LEAF_YUV_CLAMPING, mainw->vpp->YUV_clamping);
8729 weed_set_int_value(return_layer, WEED_LEAF_YUV_SUBSPACE, mainw->vpp->YUV_subspace);
8730 weed_set_int_value(return_layer, WEED_LEAF_YUV_SAMPLING, mainw->vpp->YUV_sampling);
8731 }
8732
8733 // vid plugin expects compacted rowstrides (i.e. no padding/alignment after pixel row)
8734 if (!player_v2) THREADVAR(rowstride_alignment_hint) = -1;
8735 if (create_empty_pixel_data(return_layer, FALSE, TRUE))
8736 retdata = weed_layer_get_pixel_data(return_layer, NULL);
8737 else return_layer = NULL;
8738 }
8739
8740 // chain any data to the playback plugin
8741 if (!(mainw->preview || mainw->is_rendering)) {
8742 // chain any data pipelines
8743 if (mainw->pconx) {
8744 pconx_chain_data(FX_DATA_KEY_PLAYBACK_PLUGIN, 0, FALSE);
8745 }
8746 if (mainw->cconx) cconx_chain_data(FX_DATA_KEY_PLAYBACK_PLUGIN, 0);
8747 }
8748
8749 if (prefs->apply_gamma) {
8750 // gamma correction
8751 gamma_convert_layer(tgamma, frame_layer);
8752 }
8753 if (prefs->dev_show_timing)
8754 g_print("gamma conv done @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8755
8756 if (return_layer) weed_leaf_dup(return_layer, frame_layer, WEED_LEAF_GAMMA_TYPE);
8757 pd_array = weed_layer_get_pixel_data(frame_layer, NULL);
8758 lb_width = lwidth = weed_layer_get_width_pixels(frame_layer);
8759 lb_height = lheight = weed_layer_get_height(frame_layer);
8760 pwidth = mainw->pwidth;
8761 pheight = mainw->pheight;
8762 if (player_v2) {
8763 if ((!mainw->multitrack && prefs->letterbox) || (mainw->multitrack && prefs->letterbox_mt)) {
8764 // pretend it cant resize, just to get the offsets
8765 get_letterbox_sizes(&pwidth, &pheight, &lb_width, &lb_height, FALSE);
8766 weed_set_double_value(frame_layer, "x_range", (double)lb_width / (double)pwidth);
8767 weed_set_double_value(frame_layer, "y_range", (double)lb_height / (double)pheight);
8768 } else {
8769 weed_set_double_value(frame_layer, "x_range", 1.0);
8770 weed_set_double_value(frame_layer, "y_range", 1.0);
8771 }
8772 }
8773
8774 if (!avsync_check()) goto lfi_done;
8775
8776 lwidth = weed_layer_get_width(frame_layer);
8777 if (tgamma == WEED_GAMMA_SRGB && prefs->use_screen_gamma) {
8778 // TODO - do conversion before letterboxing
8779 gamma_convert_layer(WEED_GAMMA_MONITOR, frame_layer);
8780 }
8781 if ((player_v2 && !(*mainw->vpp->play_frame)(frame_layer, mainw->currticks - mainw->stream_ticks, return_layer))
8782 || (!player_v2 && !(*mainw->vpp->render_frame)(lwidth, weed_layer_get_height(frame_layer),
8783 mainw->currticks - mainw->stream_ticks, pd_array, retdata, mainw->vpp->play_params))) {
8784 //vid_playback_plugin_exit();
8785 if (return_layer) {
8786 weed_layer_free(return_layer);
8787 lives_free(retdata);
8788 return_layer = NULL;
8789 }
8790 } else success = TRUE;
8791 if (prefs->dev_show_timing)
8792 g_printerr("rend fr done @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8793 lives_free(pd_array);
8794 if (frame_layer != mainw->frame_layer) {
8795 weed_layer_free(frame_layer);
8796 }
8797
8798 if (return_layer) {
8799 int width = MIN(weed_layer_get_width(mainw->frame_layer)
8800 / weed_palette_get_pixels_per_macropixel(weed_layer_get_palette(mainw->frame_layer)),
8801 weed_layer_get_width(return_layer)
8802 / weed_palette_get_pixels_per_macropixel(weed_layer_get_palette(return_layer)));
8803 int height = MIN(weed_layer_get_height(mainw->frame_layer), weed_layer_get_height(return_layer));
8804 if (!resize_layer(return_layer, width, height, LIVES_INTERP_FAST, WEED_PALETTE_END, 0)) {
8805 if (tgamma == WEED_GAMMA_SRGB && prefs->use_screen_gamma) {
8806 /// TODO - save w. screen_gamma
8807 gamma_convert_layer(WEED_GAMMA_SRGB, return_layer);
8808 }
8809 save_to_scrap_file(return_layer);
8810 }
8811 weed_layer_free(return_layer);
8812 lives_free(retdata);
8813 return_layer = NULL;
8814 }
8815
8816 if (mainw->vpp->capabilities & VPP_LOCAL_DISPLAY) goto lfi_done;
8817 }
8818
8819 get_player_size(&mainw->pwidth, &mainw->pheight);
8820 if (prefs->dev_show_timing)
8821 g_printerr("ext start @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8822
8823 if (mainw->ext_playback && (!(mainw->vpp->capabilities & VPP_CAN_RESIZE)
8824 || (((!mainw->multitrack && prefs->letterbox) || (mainw->multitrack && prefs->letterbox_mt))
8825 & !(mainw->vpp->capabilities & VPP_CAN_LETTERBOX)))) {
8826 // here we are either: playing through an external video playback plugin which cannot resize
8827 // - we must resize to whatever width and height we set when we called init_screen() in the plugin
8828 // i.e. mainw->vpp->fwidth, mainw->vpp fheight
8829
8830 // both dimensions are in RGB(A) pixels, so we must adjust here and send the correct
8831 // macropixel size in the plugin's render_frame() (in case of exotic palettes)
8832
8833 // - this is also used if we are letterboxing with an external plugin
8834
8835 weed_plant_t *frame_layer = NULL;
8836 weed_plant_t *return_layer = NULL;
8837 int ovpppalette = mainw->vpp->palette;
8838 boolean needs_lb = FALSE;
8839
8840 /// check if function exists - it accepts rowstrides
8841 if (mainw->vpp->play_frame) player_v2 = TRUE;
8842
8843 check_layer_ready(mainw->frame_layer);
8844 mainw->video_seek_ready = TRUE;
8845 if (prefs->dev_show_timing)
8846 g_printerr("clr2 @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8847
8848 layer_palette = weed_layer_get_palette(mainw->frame_layer);
8849 if (!weed_palette_is_valid(layer_palette)) goto lfi_done;
8850
8851 if ((mainw->vpp->capabilities & VPP_CAN_CHANGE_PALETTE)
8852 && mainw->vpp->palette != layer_palette) vpp_try_match_palette(mainw->vpp, mainw->frame_layer);
8853 interp = get_interp_value(prefs->pb_quality, TRUE);
8854
8855 if (mainw->fs && (mainw->vpp->capabilities & VPP_LOCAL_DISPLAY)) {
8856 mainw->vpp->fwidth = mainw->pwidth;
8857 mainw->vpp->fheight = mainw->pheight;
8858 }
8859
8860 if (!(mainw->vpp->capabilities & VPP_LOCAL_DISPLAY) && !(mainw->vpp->capabilities & VPP_CAN_RESIZE) &&
8861 ((mainw->vpp->fwidth < mainw->pwidth || mainw->vpp->fheight < mainw->pheight))) {
8862 // mainw->frame_layer will be downsized for the plugin but upsized for screen
8863 // so copy layer and convert, retaining original
8864 if (!player_v2) THREADVAR(rowstride_alignment_hint) = -1;
8865 frame_layer = weed_layer_copy(NULL, mainw->frame_layer);
8866 } else frame_layer = mainw->frame_layer;
8867
8868 if (frame_layer == mainw->frame_layer && !(mainw->vpp->capabilities & VPP_LOCAL_DISPLAY) &&
8869 ((weed_palette_is_rgb(layer_palette) &&
8870 !(weed_palette_is_rgb(mainw->vpp->palette))) ||
8871 (weed_palette_is_lower_quality(mainw->vpp->palette, layer_palette)))) {
8872 // mainw->frame_layer is RGB and so is our screen, but plugin is YUV
8873 // so copy layer and convert, retaining original
8874 if (!player_v2) THREADVAR(rowstride_alignment_hint) = -1;
8875 frame_layer = weed_layer_copy(NULL, mainw->frame_layer);
8876 }
8877 if (prefs->dev_show_timing)
8878 g_printerr("copied @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8879
8880 pwidth = mainw->vpp->fwidth;
8881 pheight = mainw->vpp->fheight;
8882
8883 if ((mainw->multitrack && prefs->letterbox_mt) || (!mainw->multitrack && prefs->letterbox)) {
8884 /// letterbox external
8885 lb_width = weed_layer_get_width_pixels(mainw->frame_layer);
8886 lb_height = weed_layer_get_height(mainw->frame_layer);
8887 get_letterbox_sizes(&pwidth, &pheight, &lb_width, &lb_height, (mainw->vpp->capabilities & VPP_CAN_RESIZE) != 0);
8888 if (pwidth != lb_width || pheight != lb_height) {
8889 needs_lb = TRUE;
8890 if (!(mainw->vpp->capabilities & VPP_CAN_LETTERBOX)) {
8891 if (frame_layer == mainw->frame_layer) {
8892 if (layer_palette != mainw->vpp->palette && (pwidth > lb_width || pheight > lb_height)) {
8893 frame_layer = weed_layer_copy(NULL, mainw->frame_layer);
8894 if (!player_v2) THREADVAR(rowstride_alignment_hint) = -1;
8895 if (!convert_layer_palette_full(frame_layer, mainw->vpp->palette, mainw->vpp->YUV_clamping,
8896 mainw->vpp->YUV_sampling, mainw->vpp->YUV_subspace, tgamma)) {
8897 goto lfi_done;
8898 }
8899 } else {
8900 frame_layer = weed_layer_new(WEED_LAYER_TYPE_VIDEO);
8901 weed_layer_copy(frame_layer, mainw->frame_layer);
8902 }
8903 }
8904 if (!player_v2) THREADVAR(rowstride_alignment_hint) = -1;
8905 if (!letterbox_layer(frame_layer, pwidth, pheight, lb_width, lb_height, interp,
8906 mainw->vpp->palette, mainw->vpp->YUV_clamping)) goto lfi_done;
8907 was_letterboxed = TRUE;
8908 // *INDENT-OFF*
8909 } else {
8910 weed_set_double_value(frame_layer, "x_range", (double)lb_width / (double)pwidth);
8911 weed_set_double_value(frame_layer, "y_range", (double)lb_height / (double)pheight);
8912 }
8913 }
8914 }
8915 // *INDENT-ON*
8916
8917 if (prefs->dev_show_timing)
8918 g_printerr("lbb @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8919 layer_palette = weed_layer_get_palette(frame_layer);
8920
8921 if (((weed_layer_get_width_pixels(frame_layer) ^ pwidth) >> 2) ||
8922 ((weed_layer_get_height(frame_layer) ^ pheight) >> 1)) {
8923 if (!player_v2) THREADVAR(rowstride_alignment_hint) = -1;
8924 if (!needs_lb || was_letterboxed) {
8925 lb_width = pwidth;
8926 lb_height = pheight;
8927 }
8928 if (!resize_layer(frame_layer, lb_width, lb_height, interp,
8929 mainw->vpp->palette, mainw->vpp->YUV_clamping)) goto lfi_done;
8930 }
8931 if (prefs->dev_show_timing)
8932 g_printerr("resize done @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8933
8934 // resize_layer can change palette
8935
8936 if (frame_layer == mainw->frame_layer && !(mainw->vpp->capabilities & VPP_LOCAL_DISPLAY) &&
8937 ((weed_palette_is_rgb(layer_palette) &&
8938 !(weed_palette_is_rgb(mainw->vpp->palette))) ||
8939 (weed_palette_is_lower_quality(mainw->vpp->palette, layer_palette)))) {
8940 // mainw->frame_layer is RGB and so is our screen, but plugin is YUV
8941 // so copy layer and convert, retaining original
8942 if (!player_v2) THREADVAR(rowstride_alignment_hint) = -1;
8943 frame_layer = weed_layer_copy(NULL, mainw->frame_layer);
8944 }
8945
8946 layer_palette = weed_layer_get_palette(frame_layer);
8947
8948 pwidth = weed_layer_get_width(frame_layer) * weed_palette_get_pixels_per_macropixel(layer_palette);
8949 pheight = weed_layer_get_height(frame_layer);
8950
8951 if (mainw->vpp->capabilities & VPP_LOCAL_DISPLAY) {
8952 if (!check_for_overlay_text(frame_layer)) {
8953 if (mainw->multitrack && mainw->multitrack->opts.overlay_timecode) {
8954 frame_layer = render_text_overlay(frame_layer, mainw->multitrack->timestring);
8955 }
8956 }
8957 }
8958
8959 if (prefs->apply_gamma) {
8960 // gamma correction
8961 if (weed_palette_is_rgb(mainw->vpp->palette)) {
8962 if (mainw->vpp->capabilities & VPP_LINEAR_GAMMA)
8963 tgamma = WEED_GAMMA_LINEAR;
8964 else {
8965 tgamma = WEED_GAMMA_SRGB;
8966 }
8967 }
8968 }
8969 //g_print("clp start %d %d %d %d @\n", weed_layer_get_palette(frame_layer),
8970 //mainw->vpp->palette, weed_layer_get_gamma(frame_layer), tgamma);
8971 if (!player_v2) THREADVAR(rowstride_alignment_hint) = -1;
8972 if (!convert_layer_palette_full(frame_layer, mainw->vpp->palette, mainw->vpp->YUV_clamping,
8973 mainw->vpp->YUV_sampling, mainw->vpp->YUV_subspace, tgamma)) {
8974 goto lfi_done;
8975 }
8976
8977 if (prefs->dev_show_timing)
8978 g_printerr("clp done @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8979
8980 if (mainw->stream_ticks == -1) mainw->stream_ticks = mainw->currticks;
8981
8982 if (!player_v2) {
8983 // vid plugin expects compacted rowstrides (i.e. no padding/alignment after pixel row)
8984 if (!compact_rowstrides(frame_layer)) goto lfi_done;
8985 if (prefs->dev_show_timing)
8986 g_printerr("c rows done @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8987 }
8988 if (rec_after_pb) {
8989 // record output from playback plugin
8990 int retwidth = mainw->vpp->fwidth;
8991 int retheight = mainw->vpp->fheight;
8992
8993 if (!player_v2) THREADVAR(rowstride_alignment_hint) = -1;
8994 return_layer = weed_layer_create(retwidth, retheight, NULL, ovpppalette);
8995
8996 if (weed_palette_is_yuv(mainw->vpp->palette)) {
8997 weed_layer_set_yuv_clamping(return_layer, mainw->vpp->YUV_clamping);
8998 weed_layer_set_yuv_sampling(return_layer, mainw->vpp->YUV_sampling);
8999 weed_layer_set_yuv_subspace(return_layer, mainw->vpp->YUV_subspace);
9000 }
9001
9002 if (!player_v2) THREADVAR(rowstride_alignment_hint) = -1 ; /// special value to compact the rowstrides
9003 if (create_empty_pixel_data(return_layer, FALSE, TRUE)) {
9004 retdata = weed_layer_get_pixel_data(return_layer, NULL);
9005 } else return_layer = NULL;
9006 }
9007
9008 // chain any data to the playback plugin
9009 if (!(mainw->preview || mainw->is_rendering)) {
9010 // chain any data pipelines
9011 if (mainw->pconx) {
9012 pconx_chain_data(-2, 0, FALSE);
9013 }
9014 if (mainw->cconx) cconx_chain_data(-2, 0);
9015 }
9016
9017 if (tgamma != WEED_GAMMA_UNKNOWN) {
9018 if (!was_letterboxed) {
9019 gamma_convert_layer(tgamma, frame_layer);
9020 } else {
9021 gamma_convert_sub_layer(tgamma, 1.0, frame_layer, (pwidth - lb_width) / 2, (pheight - lb_height) / 2,
9022 lb_width, lb_height, TRUE);
9023 }
9024 }
9025
9026 if (return_layer) weed_layer_set_gamma(return_layer, weed_layer_get_gamma(frame_layer));
9027
9028 if (!avsync_check()) goto lfi_done;
9029
9030 pd_array = weed_layer_get_pixel_data(frame_layer, NULL);
9031
9032 if (player_v2) {
9033 weed_set_double_value(frame_layer, "x_range", 1.0);
9034 weed_set_double_value(frame_layer, "y_range", 1.0);
9035 }
9036
9037 if (tgamma == WEED_GAMMA_SRGB && prefs->use_screen_gamma) {
9038 // TODO - do conversion before letterboxing
9039 gamma_convert_layer(WEED_GAMMA_MONITOR, frame_layer);
9040 }
9041
9042 if ((player_v2 && !(*mainw->vpp->play_frame)(frame_layer,
9043 mainw->currticks - mainw->stream_ticks, return_layer))
9044 || (!player_v2 && !(*mainw->vpp->render_frame)(weed_layer_get_width(frame_layer),
9045 weed_layer_get_height(frame_layer),
9046 mainw->currticks - mainw->stream_ticks, pd_array, retdata,
9047 mainw->vpp->play_params))) {
9048 //vid_playback_plugin_exit();
9049 if (return_layer) {
9050 weed_layer_free(return_layer);
9051 lives_free(retdata);
9052 return_layer = NULL;
9053 }
9054 goto lfi_done;
9055 } else success = TRUE;
9056 lives_free(pd_array);
9057 if (prefs->dev_show_timing)
9058 g_printerr("rend done @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
9059
9060 if (return_layer) {
9061 int width = MIN(weed_layer_get_width(mainw->frame_layer)
9062 * weed_palette_get_pixels_per_macropixel(weed_layer_get_palette(mainw->frame_layer)),
9063 weed_layer_get_width(return_layer)
9064 * weed_palette_get_pixels_per_macropixel(weed_layer_get_palette(return_layer)));
9065 int height = MIN(weed_layer_get_height(mainw->frame_layer), weed_layer_get_height(return_layer));
9066 if (resize_layer(return_layer, width, height, LIVES_INTERP_FAST, WEED_PALETTE_END, 0)) {
9067 if (tgamma == WEED_GAMMA_SRGB && prefs->use_screen_gamma) {
9068 // TODO - save w. screen_gamma
9069 gamma_convert_layer(WEED_GAMMA_SRGB, frame_layer);
9070 }
9071 save_to_scrap_file(return_layer);
9072 }
9073 weed_layer_free(return_layer);
9074 lives_free(retdata);
9075 return_layer = NULL;
9076 }
9077
9078 if (frame_layer != mainw->frame_layer) {
9079 weed_layer_free(frame_layer);
9080 }
9081
9082 // frame display was handled by a playback plugin, skip the rest
9083 if (mainw->vpp->capabilities & VPP_LOCAL_DISPLAY) goto lfi_done;
9084 }
9085
9086 ////////////////////////////////////////////////////////
9087 // local display - either we are playing with no playback plugin, or else the playback plugin has no
9088 // local display of its own
9089 if (prefs->dev_show_timing)
9090 g_printerr("clr @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
9091 check_layer_ready(mainw->frame_layer); // wait for all threads to complete
9092 mainw->video_seek_ready = TRUE;
9093 if (prefs->dev_show_timing)
9094 g_printerr("clr end @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
9095 if (weed_layer_get_width(mainw->frame_layer) == 0) return;
9096 if ((mainw->sep_win && !prefs->show_playwin) || (!mainw->sep_win && !prefs->show_gui)) {
9097 // no display to output, skip the rest
9098 success = TRUE;
9099 goto lfi_done;
9100 }
9101
9102 if (mainw->ext_playback && !player_v2) THREADVAR(rowstride_alignment_hint) = -1 ; /// special value to compact the rowstrides
9103 layer_palette = weed_layer_get_palette(mainw->frame_layer);
9104 if (!weed_palette_is_valid(layer_palette) || !CURRENT_CLIP_IS_VALID) goto lfi_done;
9105
9106 if (cfile->img_type == IMG_TYPE_JPEG || !weed_palette_has_alpha(layer_palette)) cpal = WEED_PALETTE_RGB24;
9107 else {
9108 cpal = WEED_PALETTE_RGBA32;
9109 }
9110 if (mainw->fs && !mainw->ext_playback && (!mainw->multitrack || mainw->sep_win)) {
9111 // set again, in case vpp was turned off because of preview conditions
9112 get_player_size(&mainw->pwidth, &mainw->pheight);
9113 }
9114
9115 interp = get_interp_value(prefs->pb_quality, TRUE);
9116
9117 pwidth = opwidth;
9118 pheight = opheight;
9119
9120 if (prefs->dev_show_timing)
9121 g_printerr("res start @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
9122
9123 lb_width = weed_layer_get_width_pixels(mainw->frame_layer);
9124 lb_height = weed_layer_get_height(mainw->frame_layer);
9125
9126 if ((lb_width != pwidth || lb_height != pheight)
9127 || weed_get_boolean_value(mainw->frame_layer, "letterboxed", NULL) == WEED_FALSE) {
9128 if ((!mainw->multitrack && prefs->letterbox) || (mainw->multitrack && prefs->letterbox_mt)) {
9129 /// letterbox internal
9130 get_letterbox_sizes(&pwidth, &pheight, &lb_width, &lb_height, FALSE);
9131 if (!letterbox_layer(mainw->frame_layer, pwidth, pheight, lb_width, lb_height, interp, cpal, 0)) goto lfi_done;
9132 was_letterboxed = TRUE;
9133 weed_set_boolean_value(mainw->frame_layer, "letterboxed", WEED_TRUE);
9134 lb_width = pwidth;
9135 lb_height = pheight;
9136 }
9137 }
9138
9139 if (lb_width != pwidth || lb_height != pheight ||
9140 weed_get_boolean_value(mainw->frame_layer, "letterboxed", NULL) == WEED_FALSE) {
9141 if (weed_layer_get_width_pixels(mainw->frame_layer) != pwidth ||
9142 weed_layer_get_height(mainw->frame_layer) != pheight) {
9143 if (!resize_layer(mainw->frame_layer, pwidth, pheight, interp, cpal, 0)) goto lfi_done;
9144 }
9145 }
9146 if (prefs->dev_show_timing)
9147 g_printerr("res end @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
9148
9149 if (!convert_layer_palette_full(mainw->frame_layer, cpal, 0, 0, 0, WEED_GAMMA_SRGB)) goto lfi_done;
9150
9151 if (prefs->dev_show_timing)
9152 g_printerr("clp end @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
9153 if (LIVES_IS_PLAYING) {
9154 if (!check_for_overlay_text(mainw->frame_layer)) {
9155 if (mainw->multitrack && mainw->multitrack->opts.overlay_timecode) {
9156 mainw->frame_layer = render_text_overlay(mainw->frame_layer, mainw->multitrack->timestring);
9157 }
9158 }
9159 }
9160
9161 /* if (1 || !was_letterboxed) { */
9162 /* if (!prefs->gamma_srgb) */
9163 /* gamma_convert_layer(WEED_GAMMA_MONITOR, mainw->frame_layer); */
9164 /* else */
9165 /* gamma_convert_layer(WEED_GAMMA_SRGB, mainw->frame_layer); */
9166 /* } else { */
9167 /* if (!prefs->gamma_srgb) */
9168 /* gamma_convert_sub_layer(WEED_GAMMA_MONITOR, mainw->frame_layer, (pwidth - lb_width) / 2, (pheight - lb_height / 2), */
9169 /* lb_width, lb_height); */
9170 /* else */
9171 /* gamma_convert_sub_layer(WEED_GAMMA_SRGB, mainw->frame_layer, (pwidth - lb_width) / 2, (pheight - lb_height / 2), */
9172 /* lb_width, lb_height); */
9173 /* } */
9174
9175 if (prefs->dev_show_timing)
9176 g_printerr("l2p start @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
9177
9178 pixbuf = layer_to_pixbuf(mainw->frame_layer, TRUE, TRUE);
9179
9180 if (prefs->dev_show_timing)
9181 g_printerr("l2p @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
9182
9183 if (!avsync_check()) goto lfi_done;
9184
9185 // internal player, double size or fullscreen, or multitrack
9186
9187 if (mainw->play_window && LIVES_IS_XWINDOW(lives_widget_get_xwindow(mainw->play_window))) {
9188 set_drawing_area_from_pixbuf(mainw->preview_image, pixbuf, mainw->pi_surface);
9189 lives_widget_queue_draw(mainw->preview_image);
9190 } else {
9191 pwidth = lives_widget_get_allocation_width(mainw->play_image);
9192 pheight = lives_widget_get_allocation_height(mainw->play_image);
9193 if (pwidth < old_pwidth || pheight < old_pheight)
9194 clear_widget_bg(mainw->play_image, mainw->play_surface);
9195 old_pwidth = pwidth;
9196 old_pheight = pheight;
9197 set_drawing_area_from_pixbuf(mainw->play_image, pixbuf, mainw->play_surface);
9198 lives_widget_queue_draw(mainw->play_image);
9199 }
9200
9201 if (pixbuf) lives_widget_object_unref(pixbuf);
9202 success = TRUE;
9203 if (prefs->dev_show_timing)
9204 g_print("paint @ %f\n\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
9205 goto lfi_done;
9206 }
9207
9208 // record external window
9209 if (mainw->record_foreign) {
9210 char fname[PATH_MAX];
9211 int xwidth, xheight;
9212 LiVESError *gerror = NULL;
9213 lives_painter_t *cr = lives_painter_create_from_surface(mainw->play_surface);
9214
9215 if (!cr) return;
9216
9217 if (mainw->rec_vid_frames == -1) {
9218 lives_entry_set_text(LIVES_ENTRY(mainw->framecounter), (tmp = lives_strdup_printf("%9d", frame)));
9219 lives_widget_queue_draw(mainw->framecounter);
9220 } else {
9221 if (frame > mainw->rec_vid_frames) {
9222 mainw->cancelled = CANCEL_KEEP;
9223 if (CURRENT_CLIP_HAS_VIDEO) cfile->frames = mainw->rec_vid_frames;
9224 return;
9225 }
9226
9227 lives_entry_set_text(LIVES_ENTRY(mainw->framecounter), (tmp = lives_strdup_printf("%9d / %9d",
9228 frame, mainw->rec_vid_frames)));
9229 lives_widget_queue_draw(mainw->framecounter);
9230 lives_free(tmp);
9231 }
9232
9233 #ifdef GUI_GTK
9234 #if GTK_CHECK_VERSION(3, 0, 0)
9235 xwidth = gdk_window_get_width(mainw->foreign_window);
9236 xheight = gdk_window_get_height(mainw->foreign_window);
9237 if ((pixbuf = gdk_pixbuf_get_from_window(mainw->foreign_window, 0, 0, xwidth, xheight))) {
9238 #else
9239 gdk_window_get_size(mainw->foreign_window, &xwidth, &xheight);
9240 if ((pixbuf = gdk_pixbuf_get_from_drawable(NULL, GDK_DRAWABLE(mainw->foreign_window),
9241 mainw->foreign_cmap, 0, 0, 0, 0, xwidth, xheight))) {
9242 #endif
9243 #endif
9244 tmp = make_image_file_name(cfile, frame, get_image_ext_for_type(cfile->img_type));
9245 lives_snprintf(fname, PATH_MAX, "%s", tmp);
9246 lives_free(tmp);
9247
9248 do {
9249 // TODO ***: add a timeout here
9250 if (gerror) lives_error_free(gerror);
9251 lives_pixbuf_save(pixbuf, fname, cfile->img_type, 100, cfile->hsize, cfile->vsize, &gerror);
9252 } while (gerror);
9253
9254 lives_painter_set_source_pixbuf(cr, pixbuf, 0, 0);
9255 lives_painter_paint(cr);
9256 lives_painter_destroy(cr);
9257
9258 if (pixbuf) lives_widget_object_unref(pixbuf);
9259 cfile->frames = frame;
9260 } else {
9261 widget_opts.non_modal = TRUE;
9262 do_error_dialog(_("LiVES was unable to capture this image\n\n"));
9263 widget_opts.non_modal = FALSE;
9264 mainw->cancelled = CANCEL_CAPTURE_ERROR;
9265 }
9266 if (frame > mainw->rec_vid_frames && mainw->rec_vid_frames > -1)
9267 mainw->cancelled = CANCEL_KEEP;
9268 lives_freep((void **)&framecount);
9269 return;
9270 }
9271
9272 lfi_done:
9273 // here is where we free the mainw->frame_layer (the output video "frame" we just worked with)
9274 // we also animate the timeline and frame counters
9275 // if success is TRUE we may send an OSC FRAME_SYNCH notification
9276
9277 /* if (cleaner) { */
9278 /* lives_nanosleep_until_nonzero(weed_get_boolean_value(cleaner, WEED_LEAF_DONE, NULL)); */
9279 /* weed_plant_free(cleaner); */
9280 /* cleaner = NULL; */
9281 /* } */
9282
9283 do_cleanup(mainw->frame_layer, success);
9284 mainw->frame_layer = NULL;
9285 THREADVAR(rowstride_alignment_hint) = 0;
9286 lives_freep((void **)&framecount);
9287 if (success) {
9288 if (!mainw->multitrack &&
9289 !mainw->faded && (!mainw->fs || (prefs->gui_monitor != prefs->play_monitor
9290 && prefs->play_monitor != 0 && capable->nmonitors > 1))
9291 && mainw->current_file != mainw->scrap_file) {
9292 double ptrtime = ((double)mainw->actual_frame - 1.) / cfile->fps;
9293 mainw->ptrtime = ptrtime;
9294 lives_widget_queue_draw(mainw->eventbox2);
9295 }
9296 if (mainw->multitrack && !cfile->opening) animate_multitrack(mainw->multitrack);
9297 }
9298 }
9299
9300
9301 /**
9302 @brief Save a pixbuf to a file using the specified imgtype and the specified quality/compression value
9303 */
9304 boolean lives_pixbuf_save(LiVESPixbuf * pixbuf, char *fname, lives_img_type_t imgtype, int quality, int width, int height,
9305 LiVESError **gerrorptr) {
9306 ticks_t timeout;
9307 lives_alarm_t alarm_handle;
9308 boolean retval = TRUE;
9309 int fd;
9310
9311 // CALLER should check for errors
9312 // fname should be in local charset
9313
9314 if (!LIVES_IS_PIXBUF(pixbuf)) {
9315 /// invalid pixbuf, we will save a blank image
9316 const char *img_ext = get_image_ext_for_type(imgtype);
9317 weed_layer_t *layer = create_blank_layer(NULL, img_ext, width, height, WEED_PALETTE_END);
9318 pixbuf = layer_to_pixbuf(layer, TRUE, FALSE);
9319 weed_layer_free(layer);
9320 retval = FALSE;
9321 }
9322
9323 fd = lives_open3(fname, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
9324 alarm_handle = lives_alarm_set(LIVES_SHORTEST_TIMEOUT);
9325 while (flock(fd, LOCK_EX) && (timeout = lives_alarm_check(alarm_handle)) > 0) {
9326 lives_nanosleep(1000);
9327 }
9328 lives_alarm_clear(alarm_handle);
9329 if (timeout == 0) return FALSE;
9330
9331 if (imgtype == IMG_TYPE_JPEG) {
9332 char *qstr = lives_strdup_printf("%d", quality);
9333 #ifdef GUI_GTK
9334 gdk_pixbuf_save(pixbuf, fname, LIVES_IMAGE_TYPE_JPEG, gerrorptr, "quality", qstr, NULL);
9335 #endif
9336 #ifdef GUI_QT
9337 qt_jpeg_save(pixbuf, fname, gerrorptr, quality);
9338 #endif
9339 lives_free(qstr);
9340 } else if (imgtype == IMG_TYPE_PNG) {
9341 char *cstr = lives_strdup_printf("%d", (int)((100. - (double)quality + 5.) / 10.));
9342 if (LIVES_IS_PIXBUF(pixbuf)) {
9343 #ifdef GUI_GTK
9344 gdk_pixbuf_save(pixbuf, fname, LIVES_IMAGE_TYPE_PNG, gerrorptr, "compression", cstr, NULL);
9345 #endif
9346 #ifdef GUI_QT
9347 qt_png_save(pixbuf, fname, gerrorptr, (int)((100. - (double)quality + 5.) / 10.));
9348 #endif
9349 } else retval = FALSE;
9350 lives_free(cstr);
9351 } else {
9352 //gdk_pixbuf_save_to_callback(...);
9353 }
9354
9355 close(fd);
9356 if (*gerrorptr) return FALSE;
9357 return retval;
9358 }
9359
9360 /**
9361 @brief save frame to pixbuf in a thread.
9362 The renderer uses this now so that it can be saving the current output frame
9363 at the same time as it prepares the following frame
9364 */
9365 void *lives_pixbuf_save_threaded(void *args) {
9366 savethread_priv_t *saveargs = (savethread_priv_t *)args;
9367 lives_pixbuf_save(saveargs->pixbuf, saveargs->fname, saveargs->img_type, saveargs->compression, saveargs->width,
9368 saveargs->height, &saveargs->error);
9369 return saveargs;
9370 }
9371
9372
9373 void close_current_file(int file_to_switch_to) {
9374 // close the current file, and free the file struct and all sub storage
9375 LiVESList *list_index;
9376 char *com;
9377 boolean need_new_blend_file = FALSE;
9378 int index = -1;
9379 int old_file = mainw->current_file;
9380
9381 //update the bar text
9382 if (CURRENT_CLIP_IS_VALID) {
9383 int i;
9384 if (cfile->clip_type == CLIP_TYPE_TEMP) {
9385 close_temp_handle(file_to_switch_to);
9386 return;
9387 }
9388 if (cfile->clip_type != CLIP_TYPE_GENERATOR && mainw->current_file != mainw->scrap_file &&
9389 mainw->current_file != mainw->ascrap_file && mainw->current_file != 0 &&
9390 (!mainw->multitrack || mainw->current_file != mainw->multitrack->render_file)) {
9391 d_print(_("Closed clip %s\n"), cfile->file_name);
9392 lives_notify(LIVES_OSC_NOTIFY_CLIP_CLOSED, "");
9393 }
9394
9395 cfile->hsize = mainw->def_width;
9396 cfile->vsize = mainw->def_height;
9397
9398 if (cfile->laudio_drawable) {
9399 if (mainw->laudio_drawable == cfile->laudio_drawable
9400 || mainw->drawsrc == mainw->current_file) mainw->laudio_drawable = NULL;
9401 if (!mainw->multitrack) {
9402 if (cairo_surface_get_reference_count(cfile->laudio_drawable))
9403 lives_painter_surface_destroy(cfile->laudio_drawable);
9404 }
9405 cfile->laudio_drawable = NULL;
9406 }
9407 if (cfile->raudio_drawable) {
9408 if (mainw->raudio_drawable == cfile->raudio_drawable
9409 || mainw->drawsrc == mainw->current_file) mainw->raudio_drawable = NULL;
9410 if (!mainw->multitrack) {
9411 if (cairo_surface_get_reference_count(cfile->raudio_drawable))
9412 lives_painter_surface_destroy(cfile->raudio_drawable);
9413 }
9414 cfile->raudio_drawable = NULL;
9415 }
9416 if (mainw->drawsrc == mainw->current_file) mainw->drawsrc = -1;
9417
9418 if (mainw->st_fcache) {
9419 if (mainw->en_fcache == mainw->st_fcache) mainw->en_fcache = NULL;
9420 if (mainw->pr_fcache == mainw->st_fcache) mainw->pr_fcache = NULL;
9421 weed_layer_free(mainw->st_fcache);
9422 mainw->st_fcache = NULL;
9423 }
9424 if (mainw->en_fcache) {
9425 if (mainw->pr_fcache == mainw->en_fcache) mainw->pr_fcache = NULL;
9426 weed_layer_free(mainw->en_fcache);
9427 mainw->en_fcache = NULL;
9428 }
9429 if (mainw->pr_fcache) {
9430 weed_layer_free(mainw->pr_fcache);
9431 mainw->pr_fcache = NULL;
9432 }
9433
9434 for (i = 0; i < FN_KEYS - 1; i++) {
9435 if (mainw->clipstore[i][0] == mainw->current_file) mainw->clipstore[i][0] = -1;
9436 }
9437
9438 // this must all be done last...
9439 if (cfile->menuentry) {
9440 // c.f. on_prevclip_activate
9441 list_index = lives_list_find(mainw->cliplist, LIVES_INT_TO_POINTER(mainw->current_file));
9442 do {
9443 if (!(list_index = lives_list_previous(list_index))) list_index = lives_list_last(mainw->cliplist);
9444 index = LIVES_POINTER_TO_INT(lives_list_nth_data(list_index, 0));
9445 } while ((mainw->files[index] || mainw->files[index]->opening || mainw->files[index]->restoring ||
9446 (index == mainw->scrap_file && index > -1) || (index == mainw->ascrap_file && index > -1)
9447 || (mainw->files[index]->frames == 0 &&
9448 LIVES_IS_PLAYING)) &&
9449 index != mainw->current_file);
9450 if (index == mainw->current_file) index = -1;
9451 if (mainw->current_file != mainw->scrap_file && mainw->current_file != mainw->ascrap_file) remove_from_clipmenu();
9452 }
9453
9454 if (CURRENT_CLIP_IS_NORMAL && cfile->ext_src) {
9455 if (cfile->ext_src_type == LIVES_EXT_SRC_DECODER) {
9456 close_clip_decoder(mainw->current_file);
9457 }
9458 }
9459 free_thumb_cache(mainw->current_file, 0);
9460 lives_freep((void **)&cfile->frame_index);
9461 lives_freep((void **)&cfile->frame_index_back);
9462
9463 if (cfile->clip_type != CLIP_TYPE_GENERATOR && !mainw->close_keep_frames) {
9464 char *clipd = lives_build_path(prefs->workdir, cfile->handle, NULL);
9465 if (lives_file_test(clipd, LIVES_FILE_TEST_EXISTS)) {
9466 // as a safety feature we create a special file which allows the back end to delete the directory
9467 char *permitname = lives_build_filename(clipd, TEMPFILE_MARKER "." LIVES_FILE_EXT_TMP, NULL);
9468 lives_touch(permitname);
9469 lives_free(permitname);
9470
9471 com = lives_strdup_printf("%s close \"%s\"", prefs->backend_sync, cfile->handle);
9472 lives_system(com, TRUE);
9473 lives_free(com);
9474 }
9475 lives_free(clipd);
9476 if (cfile->event_list_back) event_list_free(cfile->event_list_back);
9477 if (cfile->event_list) event_list_free(cfile->event_list);
9478
9479 lives_list_free_all(&cfile->layout_map);
9480 }
9481
9482 if (cfile->subt) subtitles_free(cfile);
9483
9484 if (cfile->clip_type == CLIP_TYPE_YUV4MPEG) {
9485 #ifdef HAVE_YUV4MPEG
9486 lives_yuv_stream_stop_read((lives_yuv4m_t *)cfile->ext_src);
9487 lives_free(cfile->ext_src);
9488 #endif
9489 }
9490
9491 if (cfile->clip_type == CLIP_TYPE_VIDEODEV) {
9492 #ifdef HAVE_UNICAP
9493 lives_vdev_free((lives_vdev_t *)cfile->ext_src);
9494 lives_free(cfile->ext_src);
9495 #endif
9496 }
9497
9498 if (cfile->audio_waveform) {
9499 for (i = 0; i < cfile->achans; i++) lives_freep((void **)&cfile->audio_waveform[i]);
9500 lives_freep((void **)&cfile->audio_waveform);
9501 lives_free(cfile->aw_sizes);
9502 }
9503
9504 lives_freep((void **)&cfile);
9505
9506 if (mainw->multitrack && mainw->current_file != mainw->multitrack->render_file) {
9507 mt_delete_clips(mainw->multitrack, mainw->current_file);
9508 }
9509
9510 if (mainw->first_free_file == ALL_USED || mainw->first_free_file > mainw->current_file)
9511 mainw->first_free_file = mainw->current_file;
9512
9513 if (!mainw->only_close) {
9514 if (IS_VALID_CLIP(file_to_switch_to) && file_to_switch_to > 0) {
9515 if (!mainw->multitrack) {
9516 if (!LIVES_IS_PLAYING) {
9517 mainw->current_file = file_to_switch_to;
9518 switch_clip(1, file_to_switch_to, TRUE);
9519 d_print("");
9520 } else {
9521 if (file_to_switch_to != mainw->playing_file) mainw->new_clip = file_to_switch_to;
9522 }
9523 } else if (old_file != mainw->multitrack->render_file) {
9524 mt_clip_select(mainw->multitrack, TRUE);
9525 }
9526 return;
9527 }
9528 }
9529 // file we were asked to switch to is invalid, thus we must find one
9530
9531 if (mainw->current_file == mainw->blend_file) {
9532 need_new_blend_file = TRUE;
9533 // set blend_file to -1. This in case the file is a generator - we need to distinguish between the cases where
9534 // the generator is the blend file and we switch because it was deinited, and when we switch fg <-> bg
9535 // in the former case the generator is killed off, in the latter it survives
9536 mainw->blend_file = -1;
9537 }
9538
9539 mainw->preview_frame = 0;
9540
9541 if (!mainw->only_close) {
9542 // find another clip to switch to
9543 if (index > -1) {
9544 if (!mainw->multitrack) {
9545 if (!LIVES_IS_PLAYING) {
9546 switch_clip(1, index, TRUE);
9547 d_print("");
9548 } else mainw->new_clip = index;
9549 if (need_new_blend_file) mainw->blend_file = mainw->current_file;
9550 } else {
9551 mainw->multitrack->clip_selected = -mainw->multitrack->clip_selected;
9552 mt_clip_select(mainw->multitrack, TRUE);
9553 }
9554 return;
9555 }
9556 if (mainw->clips_available > 0) {
9557 for (i = mainw->current_file - 1; i > 0; i--) {
9558 if (mainw->files[i]) {
9559 if (!mainw->multitrack) {
9560 if (!LIVES_IS_PLAYING) {
9561 switch_clip(1, i, TRUE);
9562 d_print("");
9563 } else mainw->new_clip = index;
9564 if (need_new_blend_file) mainw->blend_file = mainw->current_file;
9565 } else {
9566 mainw->multitrack->clip_selected = -mainw->multitrack->clip_selected;
9567 mt_clip_select(mainw->multitrack, TRUE);
9568 }
9569 return;
9570 }
9571 }
9572 for (i = 1; i < MAX_FILES; i++) {
9573 if (mainw->files[i]) {
9574 if (!mainw->multitrack) {
9575 if (!LIVES_IS_PLAYING) {
9576 switch_clip(1, i, TRUE);
9577 d_print("");
9578 } else mainw->new_clip = index;
9579 if (need_new_blend_file) mainw->blend_file = mainw->current_file;
9580 } else {
9581 mainw->multitrack->clip_selected = -mainw->multitrack->clip_selected;
9582 mt_clip_select(mainw->multitrack, TRUE);
9583 }
9584 return;
9585 // *INDENT-OFF*
9586 }}}}}
9587 // *INDENT-ON*
9588
9589 // no other clips
9590 mainw->current_file = mainw->blend_file = -1;
9591 set_main_title(NULL, 0);
9592
9593 lives_widget_set_sensitive(mainw->vj_save_set, FALSE);
9594 lives_widget_set_sensitive(mainw->vj_load_set, TRUE);
9595 lives_widget_set_sensitive(mainw->export_proj, FALSE);
9596 lives_widget_set_sensitive(mainw->import_proj, FALSE);
9597
9598 if (mainw->multitrack) lives_widget_set_sensitive(mainw->multitrack->load_set, TRUE);
9599
9600 // can't use set_undoable, as we don't have a cfile
9601 lives_menu_item_set_text(mainw->undo, _("_Undo"), TRUE);
9602 lives_menu_item_set_text(mainw->redo, _("_Redo"), TRUE);
9603 lives_widget_hide(mainw->redo);
9604 lives_widget_show(mainw->undo);
9605 lives_widget_set_sensitive(mainw->undo, FALSE);
9606
9607 if (!mainw->is_ready || mainw->recovering_files) return;
9608
9609 if (LIVES_IS_PLAYING) mainw->cancelled = CANCEL_GENERATOR_END;
9610
9611 if (!mainw->multitrack) {
9612 //resize(1);
9613 lives_widget_set_opacity(mainw->playframe, 0.);
9614 //lives_widget_hide(mainw->playframe);
9615 load_start_image(0);
9616 load_end_image(0);
9617 if (prefs->show_msg_area && !mainw->only_close) {
9618 if (mainw->idlemax == 0) {
9619 lives_idle_add_simple(resize_message_area, NULL);
9620 }
9621 mainw->idlemax = DEF_IDLE_MAX;
9622 }
9623 }
9624
9625 set_sel_label(mainw->sel_label);
9626
9627 zero_spinbuttons();
9628 show_playbar_labels(-1);
9629
9630 if (!mainw->only_close) {
9631 lives_widget_queue_draw(LIVES_MAIN_WINDOW_WIDGET);
9632 if (!LIVES_IS_PLAYING) d_print("");
9633
9634 if (mainw->multitrack) {
9635 mainw->multitrack->clip_selected = -mainw->multitrack->clip_selected;
9636 mt_clip_select(mainw->multitrack, TRUE);
9637 }
9638 }
9639 if (!LIVES_IS_PLAYING && !mainw->is_processing && !mainw->preview) {
9640 if (mainw->multitrack) mt_sensitise(mainw->multitrack);
9641 else sensitize();
9642 }
9643 }
9644
9645
9646 void switch_to_file(int old_file, int new_file) {
9647 // this function is used for full clip switching (during non-playback or non fs)
9648
9649 // calling this function directly is now deprecated in favour of switch_clip()
9650
9651 int orig_file = mainw->current_file;
9652
9653 // should use close_current_file
9654 if (!IS_VALID_CLIP(new_file)) {
9655 char *msg = lives_strdup_printf("attempt to switch to invalid clip %d", new_file);
9656 LIVES_WARN(msg);
9657 lives_free(msg);
9658 return;
9659 }
9660
9661 if (mainw->multitrack) return;
9662
9663 if (LIVES_IS_PLAYING) {
9664 mainw->new_clip = new_file;
9665 return;
9666 }
9667
9668 mainw->current_file = new_file;
9669
9670 if (old_file != new_file) {
9671 if (CURRENT_CLIP_IS_VALID) {
9672 mainw->laudio_drawable = cfile->laudio_drawable;
9673 mainw->raudio_drawable = cfile->raudio_drawable;
9674 mainw->drawsrc = mainw->current_file;
9675 }
9676 if (old_file != 0 && new_file != 0) mainw->preview_frame = 0;
9677 if (1) {
9678 // TODO - indicate "opening" in clipmenu
9679
9680 // if (old_file>0&&mainw->files[old_file]!=NULL&&mainw->files[old_file]->menuentry!=NULL&&
9681 // (mainw->files[old_file]->clip_type==CLIP_TYPE_DISK||mainw->files[old_file]->clip_type==CLIP_TYPE_FILE)) {
9682 //char menutext[32768];
9683 //get_menu_text_long(mainw->files[old_file]->menuentry,menutext);
9684
9685 //lives_menu_item_set_text(mainw->files[old_file]->menuentry,menutext,FALSE);
9686 //}
9687 lives_widget_set_sensitive(mainw->select_new, (cfile->insert_start > 0));
9688 lives_widget_set_sensitive(mainw->select_last, (cfile->undo_start > 0));
9689 if ((cfile->start == 1 || cfile->end == cfile->frames) && !(cfile->start == 1 && cfile->end == cfile->frames)) {
9690 lives_widget_set_sensitive(mainw->select_invert, TRUE);
9691 } else {
9692 lives_widget_set_sensitive(mainw->select_invert, FALSE);
9693 }
9694 if (IS_VALID_CLIP(old_file) && mainw->files[old_file]->opening) {
9695 // switch while opening - come out of processing dialog
9696 if (mainw->proc_ptr) {
9697 lives_widget_destroy(mainw->proc_ptr->processing);
9698 lives_freep((void **)&mainw->proc_ptr);
9699 // *INDENT-OFF*
9700 }}}}
9701 // *INDENT-ON*
9702
9703 if (mainw->play_window && cfile->is_loaded && orig_file != new_file) {
9704 resize_play_window();
9705
9706 // if the clip is loaded
9707 if (!mainw->preview_box) {
9708 // create the preview box that shows frames...
9709 make_preview_box();
9710 }
9711 // add it the play window...
9712 if (!lives_widget_get_parent(mainw->preview_box)) {
9713 lives_widget_queue_draw(mainw->play_window);
9714 lives_container_add(LIVES_CONTAINER(mainw->play_window), mainw->preview_box);
9715 }
9716
9717 lives_widget_set_no_show_all(mainw->preview_controls, FALSE);
9718 lives_widget_show_all(mainw->preview_box);
9719 lives_widget_show_now(mainw->preview_box);
9720 lives_widget_set_no_show_all(mainw->preview_controls, TRUE);
9721
9722 // and resize it
9723 lives_widget_grab_focus(mainw->preview_spinbutton);
9724 load_preview_image(FALSE);
9725 }
9726
9727 if (!mainw->go_away && !LIVES_IS_PLAYING && CURRENT_CLIP_IS_NORMAL) {
9728 mainw->no_context_update = TRUE;
9729 reget_afilesize(mainw->current_file);
9730 mainw->no_context_update = FALSE;
9731 }
9732
9733 if (!CURRENT_CLIP_IS_VALID) return;
9734 //chill_decoder_plugin(mainw->current_file);
9735
9736 if (!CURRENT_CLIP_IS_NORMAL || cfile->opening) {
9737 lives_widget_set_sensitive(mainw->rename, FALSE);
9738 }
9739
9740 if (cfile->menuentry) {
9741 reset_clipmenu();
9742 }
9743
9744 if (!mainw->switch_during_pb && !cfile->opening) sensitize();
9745
9746 lives_menu_item_set_text(mainw->undo, cfile->undo_text, TRUE);
9747 lives_menu_item_set_text(mainw->redo, cfile->redo_text, TRUE);
9748
9749 set_sel_label(mainw->sel_label);
9750
9751 if (mainw->eventbox5) lives_widget_show(mainw->eventbox5);
9752 lives_widget_show(mainw->hruler);
9753 lives_widget_show(mainw->vidbar);
9754 lives_widget_show(mainw->laudbar);
9755
9756 if (cfile->achans < 2) {
9757 lives_widget_hide(mainw->raudbar);
9758 } else {
9759 lives_widget_show(mainw->raudbar);
9760 }
9761
9762 if (cfile->redoable) {
9763 lives_widget_show(mainw->redo);
9764 lives_widget_hide(mainw->undo);
9765 } else {
9766 lives_widget_hide(mainw->redo);
9767 lives_widget_show(mainw->undo);
9768 }
9769
9770 if (new_file > 0) {
9771 if (cfile->menuentry) {
9772 set_main_title(cfile->name, 0);
9773 } else set_main_title(cfile->file_name, 0);
9774 }
9775
9776 if (cfile->frames == 0) {
9777 zero_spinbuttons();
9778 }
9779
9780 resize(1);
9781 if (!mainw->go_away) {
9782 get_play_times();
9783 }
9784
9785 // if the file was opening, continue...
9786 if (cfile->opening) {
9787 open_file(cfile->file_name);
9788 } else {
9789 showclipimgs();
9790 redraw_timeline(mainw->current_file);
9791 lives_ce_update_timeline(0, cfile->pointer_time);
9792 mainw->ptrtime = cfile->pointer_time;
9793 lives_widget_queue_draw(mainw->eventbox2);
9794 }
9795
9796 if (!mainw->multitrack && !mainw->reconfig) {
9797 if (prefs->show_msg_area && !mainw->only_close) {
9798 reset_message_area(); // necessary
9799 if (mainw->idlemax == 0) {
9800 lives_idle_add_simple(resize_message_area, NULL);
9801 }
9802 mainw->idlemax = DEF_IDLE_MAX;
9803 }
9804 }
9805 }
9806
9807
9808 boolean switch_audio_clip(int new_file, boolean activate) {
9809 ticks_t timeout;
9810 lives_alarm_t alarm_handle;
9811
9812 if (prefs->audio_player == AUD_PLAYER_JACK) {
9813 #ifdef ENABLE_JACK
9814 if (mainw->jackd) {
9815 if (mainw->jackd->playing_file == new_file ||
9816 (IS_VALID_CLIP(mainw->playing_file) && mainw->files[mainw->playing_file]->achans > 0
9817 && mainw->jackd->playing_file != mainw->playing_file)) return FALSE;
9818
9819 if (mainw->scratch == SCRATCH_JUMP) {
9820 mainw->files[new_file]->aseek_pos =
9821 (off_t)((double)mainw->files[new_file]->frameno / mainw->files[new_file]->fps * mainw->files[new_file]->arate)
9822 * mainw->files[new_file]->achans * mainw->files[new_file]->asampsize / 8;
9823 }
9824
9825 if (!activate) mainw->jackd->in_use = FALSE;
9826
9827 alarm_handle = lives_alarm_set(LIVES_DEFAULT_TIMEOUT);
9828 while ((timeout = lives_alarm_check(alarm_handle)) > 0 && jack_get_msgq(mainw->jackd) != NULL) {
9829 // wait for seek
9830 lives_nanosleep(1000);
9831 }
9832 lives_alarm_clear(alarm_handle);
9833 if (timeout == 0) {
9834 mainw->cancelled = handle_audio_timeout();
9835 return FALSE;
9836 }
9837
9838 if (mainw->jackd->playing_file > 0) {
9839 if (!CLIP_HAS_AUDIO(new_file)) {
9840 jack_get_rec_avals(mainw->jackd);
9841 mainw->rec_avel = 0.;
9842 }
9843 jack_message.command = ASERVER_CMD_FILE_CLOSE;
9844 jack_message.data = NULL;
9845 jack_message.next = NULL;
9846 mainw->jackd->msgq = &jack_message;
9847
9848 alarm_handle = lives_alarm_set(LIVES_DEFAULT_TIMEOUT);
9849 while ((timeout = lives_alarm_check(alarm_handle)) > 0 && jack_get_msgq(mainw->jackd) != NULL) {
9850 // wait for seek
9851 lives_nanosleep(1000);
9852 }
9853 lives_alarm_clear(alarm_handle);
9854 if (timeout == 0) {
9855 mainw->cancelled = handle_audio_timeout();
9856 return FALSE;
9857 }
9858 }
9859 }
9860 if (!IS_VALID_CLIP(new_file)) {
9861 mainw->jackd->in_use = FALSE;
9862 return FALSE;
9863 }
9864
9865 if (CLIP_HAS_AUDIO(new_file)) {
9866 int asigned = !(mainw->files[new_file]->signed_endian & AFORM_UNSIGNED);
9867 int aendian = !(mainw->files[new_file]->signed_endian & AFORM_BIG_ENDIAN);
9868 mainw->jackd->num_input_channels = mainw->files[new_file]->achans;
9869 mainw->jackd->bytes_per_channel = mainw->files[new_file]->asampsize / 8;
9870 if (activate && (prefs->audio_opts & AUDIO_OPTS_FOLLOW_FPS)) {
9871 if (!mainw->files[new_file]->play_paused)
9872 mainw->jackd->sample_in_rate = mainw->files[new_file]->arate * mainw->files[new_file]->pb_fps /
9873 mainw->files[new_file]->fps;
9874 else mainw->jackd->sample_in_rate = mainw->files[new_file]->arate * mainw->files[new_file]->freeze_fps /
9875 mainw->files[new_file]->fps;
9876 } else mainw->jackd->sample_in_rate = mainw->files[new_file]->arate;
9877 if (mainw->files[new_file]->adirection == LIVES_DIRECTION_REVERSE)
9878 mainw->jackd->sample_in_rate = -abs(mainw->jackd->sample_in_rate);
9879 else
9880 mainw->jackd->sample_in_rate = abs(mainw->jackd->sample_in_rate);
9881 mainw->jackd->usigned = !asigned;
9882 mainw->jackd->seek_end = mainw->files[new_file]->afilesize;
9883
9884 if ((aendian && (capable->byte_order == LIVES_BIG_ENDIAN)) ||
9885 (!aendian && (capable->byte_order == LIVES_LITTLE_ENDIAN)))
9886 mainw->jackd->reverse_endian = TRUE;
9887 else mainw->jackd->reverse_endian = FALSE;
9888
9889 if (mainw->ping_pong) mainw->jackd->loop = AUDIO_LOOP_PINGPONG;
9890 else mainw->jackd->loop = AUDIO_LOOP_FORWARD;
9891
9892 avsync_force();
9893
9894 // tell jack server to open audio file and start playing it
9895
9896 jack_message.command = ASERVER_CMD_FILE_OPEN;
9897
9898 jack_message.data = lives_strdup_printf("%d", new_file);
9899
9900 jack_message2.command = ASERVER_CMD_FILE_SEEK;
9901 jack_message.next = &jack_message2;
9902 jack_message2.data = lives_strdup_printf("%"PRId64, mainw->files[new_file]->aseek_pos);
9903 if (LIVES_IS_PLAYING && !mainw->preview) jack_message2.tc = lives_get_current_ticks();
9904 jack_message2.next = NULL;
9905
9906 mainw->jackd->msgq = &jack_message;
9907 mainw->jackd->in_use = TRUE;
9908
9909 mainw->jackd->is_paused = mainw->files[new_file]->play_paused;
9910 mainw->jackd->is_silent = FALSE;
9911 mainw->rec_aclip = new_file;
9912 mainw->rec_avel = (double)mainw->jackd->sample_in_rate / (double)mainw->files[new_file]->arps;
9913 mainw->rec_aseek = fabs((double)(mainw->files[new_file]->aseek_pos
9914 / (mainw->files[new_file]->achans * mainw->files[new_file]->asampsize / 8))
9915 / (double)mainw->files[new_file]->arps);
9916 } else {
9917 mainw->video_seek_ready = mainw->audio_seek_ready = TRUE;
9918 }
9919 /* event = get_last_frame_event(mainw->event_list); */
9920 /* insert_audio_event_at(event, -1, mainw->rec_aclip, mainw->rec_aseek, mainw->rec_avel); */
9921 /* mainw->rec_aclip = -1; */
9922 #endif
9923 }
9924
9925 if (prefs->audio_player == AUD_PLAYER_PULSE) {
9926 #ifdef HAVE_PULSE_AUDIO
9927 if (mainw->pulsed) {
9928 if (mainw->pulsed->playing_file == new_file ||
9929 (IS_VALID_CLIP(mainw->playing_file) && mainw->files[mainw->playing_file]->achans > 0
9930 && mainw->pulsed->playing_file != mainw->playing_file)) return FALSE;
9931
9932 if (mainw->scratch == SCRATCH_JUMP) {
9933 mainw->files[new_file]->aseek_pos =
9934 (off_t)((double)mainw->files[new_file]->frameno / mainw->files[new_file]->fps * mainw->files[new_file]->arate)
9935 * mainw->files[new_file]->achans * mainw->files[new_file]->asampsize / 8;
9936 }
9937
9938 if (!activate) mainw->pulsed->in_use = FALSE;
9939
9940 alarm_handle = lives_alarm_set(LIVES_DEFAULT_TIMEOUT);
9941 while ((timeout = lives_alarm_check(alarm_handle)) > 0 && pulse_get_msgq(mainw->pulsed)) {
9942 // wait for seek
9943 lives_nanosleep(1000);
9944 }
9945 lives_alarm_clear(alarm_handle);
9946 if (timeout == 0) {
9947 mainw->cancelled = handle_audio_timeout();
9948 return FALSE;
9949 }
9950
9951 if (mainw->pulsed->fd > 0) {
9952 if (!CLIP_HAS_AUDIO(new_file)) {
9953 pulse_get_rec_avals(mainw->pulsed);
9954 mainw->rec_avel = 0.;
9955 }
9956 pulse_message.command = ASERVER_CMD_FILE_CLOSE;
9957 pulse_message.data = NULL;
9958 pulse_message.next = NULL;
9959 mainw->pulsed->msgq = &pulse_message;
9960
9961 alarm_handle = lives_alarm_set(LIVES_DEFAULT_TIMEOUT);
9962 while ((timeout = lives_alarm_check(alarm_handle)) > 0 && pulse_get_msgq(mainw->pulsed) != NULL) {
9963 // wait for seek
9964 lives_nanosleep(1000);
9965 }
9966 lives_alarm_clear(alarm_handle);
9967 if (timeout == 0) {
9968 mainw->cancelled = handle_audio_timeout();
9969 return FALSE;
9970 }
9971 }
9972
9973 if (!IS_VALID_CLIP(new_file)) {
9974 mainw->pulsed->in_use = FALSE;
9975 return FALSE;
9976 }
9977
9978 mainw->pulsed->in_use = TRUE;
9979
9980 if (CLIP_HAS_AUDIO(new_file)) {
9981 int asigned = !(mainw->files[new_file]->signed_endian & AFORM_UNSIGNED);
9982 int aendian = !(mainw->files[new_file]->signed_endian & AFORM_BIG_ENDIAN);
9983 mainw->pulsed->in_achans = mainw->files[new_file]->achans;
9984 mainw->pulsed->in_asamps = mainw->files[new_file]->asampsize;
9985 if (activate && (prefs->audio_opts & AUDIO_OPTS_FOLLOW_FPS)) {
9986 if (!mainw->files[new_file]->play_paused)
9987 mainw->pulsed->in_arate = mainw->files[new_file]->arate
9988 * mainw->files[new_file]->pb_fps /
9989 mainw->files[new_file]->fps;
9990 else mainw->pulsed->in_arate = mainw->files[new_file]->arate
9991 * mainw->files[new_file]->freeze_fps /
9992 mainw->files[new_file]->fps;
9993 } else mainw->pulsed->in_arate = mainw->files[new_file]->arate;
9994 if (mainw->files[new_file]->adirection == LIVES_DIRECTION_REVERSE)
9995 mainw->pulsed->in_arate = -abs(mainw->pulsed->in_arate);
9996 else
9997 mainw->pulsed->in_arate = abs(mainw->pulsed->in_arate);
9998 mainw->pulsed->usigned = !asigned;
9999 mainw->pulsed->seek_end = mainw->files[new_file]->afilesize;
10000
10001 if ((aendian && (capable->byte_order == LIVES_BIG_ENDIAN)) ||
10002 (!aendian && (capable->byte_order == LIVES_LITTLE_ENDIAN)))
10003 mainw->pulsed->reverse_endian = TRUE;
10004 else mainw->pulsed->reverse_endian = FALSE;
10005
10006 if (mainw->ping_pong) mainw->pulsed->loop = AUDIO_LOOP_PINGPONG;
10007 else mainw->pulsed->loop = AUDIO_LOOP_FORWARD;
10008
10009 avsync_force();
10010
10011 // tell pulse server to open audio file and start playing it
10012
10013 pulse_message.command = ASERVER_CMD_FILE_OPEN;
10014 pulse_message.data = lives_strdup_printf("%d", new_file);
10015
10016 pulse_message2.command = ASERVER_CMD_FILE_SEEK;
10017 if (LIVES_IS_PLAYING && !mainw->preview) pulse_message2.tc = lives_get_current_ticks();
10018 pulse_message.next = &pulse_message2;
10019 pulse_message2.data = lives_strdup_printf("%"PRId64, mainw->files[new_file]->aseek_pos);
10020 pulse_message2.next = NULL;
10021 mainw->pulsed->msgq = &pulse_message;
10022 mainw->pulsed->in_use = TRUE;
10023
10024 mainw->pulsed->is_paused = mainw->files[new_file]->play_paused;
10025 mainw->rec_aclip = new_file;
10026 mainw->rec_avel = (double)mainw->pulsed->in_arate / (double)mainw->files[new_file]->arps;
10027 mainw->rec_aseek = fabs((double)(mainw->files[new_file]->aseek_pos
10028 / (mainw->files[new_file]->achans * mainw->files[new_file]->asampsize / 8))
10029 / (double)mainw->files[new_file]->arps);
10030 } else {
10031 mainw->video_seek_ready = mainw->audio_seek_ready = TRUE;
10032 }
10033 }
10034 #endif
10035 }
10036
10037 #if 0
10038 if (prefs->audio_player == AUD_PLAYER_NONE) {
10039 if (!IS_VALID_CLIP(new_file)) {
10040 mainw->nullaudio_playing_file = -1;
10041 return FALSE;
10042 }
10043 if (mainw->nullaudio->playing_file == new_file) return FALSE;
10044 nullaudio_clip_set(new_file);
10045 if (activate && (prefs->audio_opts & AUDIO_OPTS_FOLLOW_FPS)) {
10046 if (!mainw->files[new_file]->play_paused)
10047 nullaudio_arate_set(mainw->files[new_file]->arate * mainw->files[new_file]->pb_fps /
10048 mainw->files[new_file]->fps);
10049 else nullaudio_arate_set(mainw->files[new_file]->arate
10050 * mainw->files[new_file]->freeze_fps /
10051 mainw->files[new_file]->fps);
10052 } else nullaudio_arate_set(mainw->files[new_file]->arate);
10053 nullaudio_seek_set(mainw->files[new_file]->aseek_pos);
10054 if (CLIP_HAS_AUDIO(new_file)) {
10055 nullaudio_get_rec_avals();
10056 } else {
10057 nullaudio_get_rec_avals();
10058 mainw->rec_avel = 0.;
10059 }
10060 }
10061 #endif
10062 return TRUE;
10063 }
10064
10065
10066 void do_quick_switch(int new_file) {
10067 // handle clip switching during playback
10068 // calling this function directly is now deprecated in favour of switch_clip()
10069 boolean osc_block;
10070 int old_file = mainw->current_file;// area = 0;
10071
10072 if (mainw->current_file < 1 || !mainw->files[new_file]) return;
10073
10074 if (mainw->multitrack
10075 || (mainw->record && !mainw->record_paused && !(prefs->rec_opts & REC_CLIPS)) ||
10076 mainw->foreign || (mainw->preview && !mainw->is_rendering)) return;
10077
10078 if (!LIVES_IS_PLAYING) {
10079 switch_to_file(mainw->current_file, new_file);
10080 return;
10081 }
10082
10083 if (mainw->noswitch) {
10084 mainw->new_clip = new_file;
10085 return;
10086 }
10087
10088 mainw->blend_palette = WEED_PALETTE_END;
10089
10090 if (CURRENT_CLIP_IS_VALID && new_file != mainw->current_file && mainw->current_file != mainw->blend_file
10091 && !mainw->is_rendering) {
10092 if (cfile->clip_type == CLIP_TYPE_GENERATOR && cfile->ext_src) {
10093 if (new_file != mainw->blend_file) {
10094 // switched from generator to another clip, end the generator
10095 weed_plant_t *inst = (weed_plant_t *)cfile->ext_src;
10096 mainw->gen_started_play = FALSE;
10097 mainw->whentostop = NEVER_STOP;
10098 weed_generator_end(inst);
10099 } else {
10100 rte_swap_fg_bg();
10101 }
10102 }
10103 if (new_file == mainw->blend_file && mainw->files[mainw->blend_file]->clip_type == CLIP_TYPE_GENERATOR
10104 && mainw->files[mainw->blend_file]->ext_src) {
10105 rte_swap_fg_bg();
10106 }
10107 }
10108
10109 osc_block = mainw->osc_block;
10110 mainw->osc_block = TRUE;
10111
10112 if (mainw->loop_locked) {
10113 unlock_loop_lock();
10114 }
10115
10116 mainw->whentostop = NEVER_STOP;
10117
10118 // TODO - can these be combined ?
10119 mainw->switch_during_pb = TRUE;
10120 mainw->clip_switched = TRUE;
10121
10122 if (CURRENT_CLIP_IS_NORMAL) cfile->last_play_sequence = mainw->play_sequence;
10123
10124 mainw->current_file = new_file;
10125
10126 mainw->drawsrc = mainw->current_file;
10127 mainw->laudio_drawable = cfile->laudio_drawable;
10128 mainw->raudio_drawable = cfile->raudio_drawable;
10129
10130 if (!mainw->fs && !mainw->faded) {
10131 redraw_timeline(mainw->current_file);
10132 show_playbar_labels(mainw->current_file);
10133 }
10134
10135 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_pb_fps), mainw->files[new_file]->pb_fps);
10136 changed_fps_during_pb(LIVES_SPIN_BUTTON(mainw->spinbutton_pb_fps), LIVES_INT_TO_POINTER(1));
10137
10138 // switch audio clip
10139 if (is_realtime_aplayer(prefs->audio_player) && (prefs->audio_opts & AUDIO_OPTS_FOLLOW_CLIPS)
10140 && !mainw->is_rendering && (mainw->preview || !(mainw->agen_key != 0 || mainw->agen_needs_reinit
10141 || prefs->audio_src == AUDIO_SRC_EXT))) {
10142 switch_audio_clip(new_file, TRUE);
10143 }
10144
10145 mainw->deltaticks = 0;
10146
10147 set_main_title(cfile->name, 0);
10148
10149 if (mainw->ce_thumbs && mainw->active_sa_clips == SCREEN_AREA_FOREGROUND) ce_thumbs_highlight_current_clip();
10150
10151 if (CURRENT_CLIP_IS_NORMAL) {
10152 char *tmp;
10153 tmp = lives_build_filename(prefs->workdir, cfile->handle, LIVES_STATUS_FILE_NAME, NULL);
10154 lives_snprintf(cfile->info_file, PATH_MAX, "%s", tmp);
10155 lives_free(tmp);
10156 }
10157
10158 if (!CURRENT_CLIP_IS_NORMAL || (mainw->event_list && !mainw->record))
10159 mainw->play_end = INT_MAX;
10160
10161 // act like we are not playing a selection (but we will try to keep to
10162 // selection bounds)
10163 mainw->playing_sel = FALSE;
10164
10165 if (!cfile->frameno && cfile->frames) cfile->frameno = calc_frame_from_time(mainw->current_file, cfile->pointer_time);
10166 cfile->last_frameno = cfile->frameno;
10167
10168 mainw->playing_file = new_file;
10169
10170 cfile->next_event = NULL;
10171
10172 #if GTK_CHECK_VERSION(3, 0, 0)
10173 if (LIVES_IS_PLAYING && !mainw->play_window && (!IS_VALID_CLIP(old_file)
10174 || !CURRENT_CLIP_IS_VALID || cfile->hsize != mainw->files[old_file]->hsize
10175 || cfile->vsize != mainw->files[old_file]->vsize)) {
10176 clear_widget_bg(mainw->play_image, mainw->play_surface);
10177 }
10178 #endif
10179
10180 if (CURRENT_CLIP_HAS_VIDEO) {
10181 if (!mainw->fs && !mainw->faded) {
10182 lives_signal_handler_block(mainw->spinbutton_end, mainw->spin_end_func);
10183 lives_spin_button_set_range(LIVES_SPIN_BUTTON(mainw->spinbutton_end), 1, cfile->frames);
10184 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), cfile->end);
10185 lives_signal_handler_unblock(mainw->spinbutton_end, mainw->spin_end_func);
10186
10187 lives_signal_handler_block(mainw->spinbutton_start, mainw->spin_start_func);
10188 lives_spin_button_set_range(LIVES_SPIN_BUTTON(mainw->spinbutton_start), 1, cfile->frames);
10189 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), cfile->start);
10190 lives_signal_handler_unblock(mainw->spinbutton_start, mainw->spin_start_func);
10191
10192 if (!mainw->play_window && mainw->double_size) {
10193 //frame_size_update();
10194 resize(2.);
10195 } else resize(1);
10196 }
10197 } else resize(1);
10198
10199 if (!mainw->fs && !mainw->faded) {
10200 showclipimgs();
10201 }
10202
10203 if (new_file == mainw->blend_file) {
10204 check_layer_ready(mainw->blend_layer);
10205 mainw->blend_file = old_file;
10206 }
10207
10208 // force loading of a frame from the new clip
10209 mainw->force_show = TRUE;
10210
10211 mainw->fps_mini_measure = 1.;
10212 mainw->fps_mini_ticks = mainw->currticks;
10213
10214 if (mainw->play_window && prefs->show_playwin) {
10215 lives_window_present(LIVES_WINDOW(mainw->play_window));
10216 lives_xwindow_raise(lives_widget_get_xwindow(mainw->play_window));
10217 }
10218
10219 //mainw->switch_during_pb = FALSE;
10220 mainw->osc_block = osc_block;
10221 lives_ruler_set_upper(LIVES_RULER(mainw->hruler), CURRENT_CLIP_TOTAL_TIME);
10222
10223 if (!mainw->fs && !mainw->faded) {
10224 redraw_timeline(mainw->current_file);
10225 set_sel_label(mainw->sel_label);
10226 }
10227 }
10228
10229
10230 void resize(double scale) {
10231 // resize the frame widgets
10232 // set scale < 0. to _force_ the playback frame to expand (for external capture)
10233 LiVESXWindow *xwin;
10234 double oscale = scale;
10235
10236 int xsize, vspace;
10237 int bx, by;
10238
10239 // height of the separator imeage
10240
10241 // maximum values
10242 int hsize, vsize;
10243 int w, h;
10244 int scr_width = GUI_SCREEN_WIDTH;
10245 int scr_height = GUI_SCREEN_HEIGHT;
10246
10247 if (!prefs->show_gui || mainw->multitrack) return;
10248 vspace = get_vspace();
10249
10250 get_border_size(LIVES_MAIN_WINDOW_WIDGET, &bx, &by);
10251 bx *= 2;
10252
10253 if (prefs->open_maximised && by > MENU_HIDE_LIM)
10254 lives_window_set_hide_titlebar_when_maximized(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), TRUE);
10255
10256 w = lives_widget_get_allocation_width(LIVES_MAIN_WINDOW_WIDGET);
10257 h = lives_widget_get_allocation_height(LIVES_MAIN_WINDOW_WIDGET);
10258
10259 // resize the main window so it fits the gui monitor
10260 if (prefs->open_maximised)
10261 lives_window_maximize(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET));
10262 else if (w > scr_width - bx || h > scr_height - by) {
10263 w = scr_width - bx;
10264 h = scr_height - by - mainw->mbar_res;
10265 lives_window_unmaximize(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET));
10266 lives_window_resize(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), w, h);
10267 }
10268
10269 //if (mainw->play_window) return;
10270
10271 hsize = (scr_width - (H_RESIZE_ADJUST * 3 + bx)) / 3;
10272 vsize = scr_height - (CE_TIMELINE_VSPACE * 1.01 / sqrt(widget_opts.scale) + vspace + by
10273 + (prefs->show_msg_area ? mainw->mbar_res : 0)
10274 + widget_opts.border_width * 2);
10275
10276 if (scale < 0.) {
10277 // foreign capture
10278 scale = -scale;
10279 hsize = (scr_width - H_RESIZE_ADJUST - bx) / scale;
10280 vsize = (scr_height - V_RESIZE_ADJUST - by) / scale;
10281 }
10282
10283 mainw->ce_frame_width = hsize;
10284 mainw->ce_frame_height = vsize;
10285
10286 if (oscale == 2.) {
10287 if (hsize * 2 > scr_width - SCR_WIDTH_SAFETY) {
10288 scale = 1.;
10289 }
10290 }
10291
10292 if (oscale > 0.) {
10293 if (scale > 1.) {
10294 // this is the size for the start and end frames
10295 // they shrink when scale is 2.0
10296 mainw->ce_frame_width = hsize / scale;
10297 mainw->ce_frame_height = vsize / scale + V_RESIZE_ADJUST;
10298
10299 lives_widget_set_margin_left(mainw->playframe, widget_opts.packing_width);
10300 lives_widget_set_margin_right(mainw->playframe, widget_opts.packing_width);
10301 }
10302
10303 if (CURRENT_CLIP_IS_VALID) {
10304 if (cfile->clip_type == CLIP_TYPE_YUV4MPEG || cfile->clip_type == CLIP_TYPE_VIDEODEV) {
10305 if (!mainw->camframe) {
10306 LiVESError *error = NULL;
10307 char *fname = lives_strdup_printf("%s.%s", THEME_FRAME_IMG_LITERAL, LIVES_FILE_EXT_JPG);
10308 char *tmp = lives_build_filename(prefs->prefix_dir, THEME_DIR, LIVES_THEME_CAMERA, fname, NULL);
10309 mainw->camframe = lives_pixbuf_new_from_file(tmp, &error);
10310 if (mainw->camframe) lives_pixbuf_saturate_and_pixelate(mainw->camframe, mainw->camframe, 0.0, FALSE);
10311 lives_free(tmp); lives_free(fname);
10312 }
10313 }
10314 }
10315
10316 // THE SIZES OF THE FRAME CONTAINERS
10317 lives_widget_set_size_request(mainw->frame1, mainw->ce_frame_width, mainw->ce_frame_height);
10318 lives_widget_set_size_request(mainw->eventbox3, mainw->ce_frame_width, mainw->ce_frame_height);
10319 lives_widget_set_size_request(mainw->frame2, mainw->ce_frame_width, mainw->ce_frame_height);
10320 lives_widget_set_size_request(mainw->eventbox4, mainw->ce_frame_width, mainw->ce_frame_height);
10321
10322 lives_widget_set_size_request(mainw->start_image, mainw->ce_frame_width, mainw->ce_frame_height);
10323 lives_widget_set_size_request(mainw->end_image, mainw->ce_frame_width, mainw->ce_frame_height);
10324
10325 // use unscaled size in dblsize
10326 if (scale > 1.) {
10327 hsize *= scale;
10328 vsize *= scale;
10329 }
10330 lives_widget_set_size_request(mainw->playframe, hsize, vsize);
10331 lives_widget_set_size_request(mainw->pl_eventbox, hsize, vsize);
10332 lives_widget_set_size_request(mainw->playarea, hsize, vsize);
10333
10334 // IMPORTANT (or the entire image will not be shown)
10335 lives_widget_set_size_request(mainw->play_image, hsize, vsize);
10336 xwin = lives_widget_get_xwindow(mainw->play_image);
10337 if (LIVES_IS_XWINDOW(xwin)) {
10338 if (mainw->play_surface) lives_painter_surface_destroy(mainw->play_surface);
10339 mainw->play_surface =
10340 lives_xwindow_create_similar_surface(xwin, LIVES_PAINTER_CONTENT_COLOR,
10341 hsize, vsize);
10342 clear_widget_bg(mainw->play_image, mainw->play_surface);
10343 }
10344 } else {
10345 // capture window size
10346 xsize = (scr_width - hsize * -oscale - H_RESIZE_ADJUST) / 2;
10347 if (xsize > 0) {
10348 lives_widget_set_size_request(mainw->frame1, xsize / scale, vsize + V_RESIZE_ADJUST);
10349 lives_widget_set_size_request(mainw->eventbox3, xsize / scale, vsize + V_RESIZE_ADJUST);
10350 lives_widget_set_size_request(mainw->frame2, xsize / scale, vsize + V_RESIZE_ADJUST);
10351 lives_widget_set_size_request(mainw->eventbox4, xsize / scale, vsize + V_RESIZE_ADJUST);
10352 mainw->ce_frame_width = xsize / scale;
10353 mainw->ce_frame_height = vsize + V_RESIZE_ADJUST;
10354 } else {
10355 lives_widget_hide(mainw->frame1);
10356 lives_widget_hide(mainw->frame2);
10357 lives_widget_hide(mainw->eventbox3);
10358 lives_widget_hide(mainw->eventbox4);
10359 }
10360 }
10361
10362 if (!mainw->foreign && mainw->current_file == -1) {
10363 lives_table_set_column_homogeneous(LIVES_TABLE(mainw->pf_grid), TRUE);
10364 load_start_image(0);
10365 load_end_image(0);
10366 }
10367
10368 update_sel_menu();
10369
10370 if (scale != oscale) {
10371 lives_widget_context_update();
10372 if (prefs->open_maximised)
10373 lives_window_maximize(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET));
10374 else if (w > scr_width - bx || h > scr_height - by) {
10375 w = scr_width - bx;
10376 h = scr_height - by;
10377 lives_window_unmaximize(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET));
10378 lives_window_resize(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), w, h);
10379 }
10380 }
10381 }
10382