1 // saveplay.c
2 // LiVES (lives-exe)
3 // (c) G. Finch 2003 - 2018 (salsaman+lives@gmail.com)
4 // released under the GNU GPL 3 or later
5 // see file ../COPYING or www.gnu.org for licensing details
6
7 #include <fcntl.h>
8 #include <glib.h>
9
10 #include "main.h"
11 #include "callbacks.h"
12 #include "resample.h"
13 #include "effects.h"
14 #include "audio.h"
15 #include "htmsocket.h"
16 #include "cvirtual.h"
17 #include "interface.h"
18
_start_playback(livespointer data)19 boolean _start_playback(livespointer data) {
20 int new_file, old_file;
21 int play_type = LIVES_POINTER_TO_INT(data);
22 if (play_type != 8 && mainw->noswitch) return TRUE;
23 switch (play_type) {
24 case 8: case 6: case 0:
25 /// normal play
26 play_all(play_type == 8);
27 if (play_type == 6) {
28 /// triggered by generator
29 // need to set this after playback ends; this stops the key from being activated (again) in effects.c
30 // also stops the (now defunct instance being unreffed)
31 mainw->gen_started_play = TRUE;
32 }
33 break;
34 case 1:
35 /// play selection
36 if (!mainw->multitrack) play_sel();
37 else multitrack_play_sel(NULL, mainw->multitrack);
38 break;
39 case 2:
40 /// play stream
41 mainw->play_start = 1;
42 mainw->play_end = INT_MAX;
43 play_file();
44 break;
45 case 3:
46 /// osc playall
47 mainw->osc_auto = 1; ///< request notifiction of success
48 play_all(FALSE);
49 mainw->osc_auto = 0;
50 break;
51 case 4:
52 /// osc playsel
53 mainw->osc_auto = 1; ///< request notifiction of success
54 if (!mainw->multitrack) play_sel();
55 else multitrack_play_sel(NULL, mainw->multitrack);
56 mainw->osc_auto = 0;
57 break;
58 case 5:
59 /// clipboard
60 play_file();
61 mainw->loop = mainw->oloop;
62 mainw->loop_cont = mainw->oloop_cont;
63
64 if (mainw->pre_play_file > 0) {
65 switch_to_file(0, mainw->pre_play_file);
66 } else {
67 mainw->current_file = -1;
68 close_current_file(0);
69 }
70 if (mainw->cancelled == CANCEL_AUDIO_ERROR) {
71 handle_audio_timeout();
72 mainw->cancelled = CANCEL_ERROR;
73 }
74 break;
75 case 7:
76 /// yuv4mpeg
77 new_file = mainw->current_file;
78 old_file = mainw->pre_play_file;
79 play_file();
80 if (mainw->current_file != old_file && mainw->current_file != new_file)
81 old_file = mainw->current_file; // we could have rendered to a new file
82 mainw->current_file = new_file;
83 // close this temporary clip
84 close_current_file(old_file);
85 mainw->pre_play_file = -1;
86 break;
87 default:
88 /// do nothing
89 break;
90 }
91 return FALSE;
92 }
93
start_playback(int type)94 LIVES_GLOBAL_INLINE boolean start_playback(int type) {return _start_playback(LIVES_INT_TO_POINTER(type));}
95
start_playback_async(int type)96 LIVES_GLOBAL_INLINE void start_playback_async(int type) {
97 lives_idle_add(_start_playback, LIVES_INT_TO_POINTER(type));
98 //lives_proc_thread_create(0, (lives_funcptr_t)_start_playback, 0, "i", type);
99 //_start_playback(LIVES_INT_TO_POINTER(type));
100 }
101
102
save_clip_values(int which)103 boolean save_clip_values(int which) {
104 lives_clip_t *sfile = mainw->files[which];
105 char *lives_header_new;
106 boolean all_ok = FALSE;
107 int asigned, endian;
108 int retval;
109
110 if (which == 0 || which == mainw->scrap_file || which == mainw->ascrap_file) return TRUE;
111
112 set_signal_handlers((SignalHandlerPointer)defer_sigint); // ignore ctrl-c
113
114 asigned = !(sfile->signed_endian & AFORM_UNSIGNED);
115 endian = sfile->signed_endian & AFORM_BIG_ENDIAN;
116 if (which == mainw->ascrap_file)
117 lives_header_new = lives_build_filename(prefs->workdir, sfile->handle, LIVES_ACLIP_HEADER_NEW, NULL);
118 else
119 lives_header_new = lives_build_filename(prefs->workdir, sfile->handle, LIVES_CLIP_HEADER_NEW, NULL);
120
121 do {
122 THREADVAR(com_failed) = THREADVAR(write_failed) = FALSE;
123 mainw->clip_header = fopen(lives_header_new, "w");
124 if (!mainw->clip_header) {
125 retval = do_write_failed_error_s_with_retry(lives_header_new, lives_strerror(errno));
126 if (retval == LIVES_RESPONSE_CANCEL) {
127 set_signal_handlers((SignalHandlerPointer)catch_sigint);
128 if (mainw->signal_caught) catch_sigint(mainw->signal_caught);
129 lives_free(lives_header_new);
130 return FALSE;
131 }
132 } else {
133 sfile->header_version = LIVES_CLIP_HEADER_VERSION;
134 do {
135 retval = 0;
136 if (!save_clip_value(which, CLIP_DETAILS_HEADER_VERSION, &sfile->header_version)) break;
137 if (!save_clip_value(which, CLIP_DETAILS_BPP, &sfile->bpp)) break;
138 if (sfile->clip_type == CLIP_TYPE_FILE && sfile->ext_src) {
139 lives_clip_data_t *cdata = ((lives_decoder_t *)sfile->ext_src)->cdata;
140 double dfps = (double)cdata->fps;
141 if (!save_clip_value(which, CLIP_DETAILS_FPS, &dfps)) break;
142 if (!save_clip_value(which, CLIP_DETAILS_PB_FPS, &sfile->fps)) break;
143 } else {
144 if (!save_clip_value(which, CLIP_DETAILS_FPS, &sfile->fps)) break;
145 if (!save_clip_value(which, CLIP_DETAILS_PB_FPS, &sfile->pb_fps)) break;
146 }
147 if (!save_clip_value(which, CLIP_DETAILS_WIDTH, &sfile->hsize)) break;
148 if (!save_clip_value(which, CLIP_DETAILS_HEIGHT, &sfile->vsize)) break;
149 if (!save_clip_value(which, CLIP_DETAILS_INTERLACE, &sfile->interlace)) break;
150 if (!save_clip_value(which, CLIP_DETAILS_UNIQUE_ID, &sfile->unique_id)) break;
151 if (!save_clip_value(which, CLIP_DETAILS_ARATE, &sfile->arps)) break;
152 if (!save_clip_value(which, CLIP_DETAILS_PB_ARATE, &sfile->arate)) break;
153 if (!save_clip_value(which, CLIP_DETAILS_ACHANS, &sfile->achans)) break;
154 if (sfile->achans > 0) {
155 if (!save_clip_value(which, CLIP_DETAILS_ASIGNED, &asigned)) break;
156 if (!save_clip_value(which, CLIP_DETAILS_AENDIAN, &endian)) break;
157 }
158 if (!save_clip_value(which, CLIP_DETAILS_ASAMPS, &sfile->asampsize)) break;
159 if (!save_clip_value(which, CLIP_DETAILS_FRAMES, &sfile->frames)) break;
160 if (!save_clip_value(which, CLIP_DETAILS_GAMMA_TYPE, &sfile->gamma_type)) break;
161 if (!save_clip_value(which, CLIP_DETAILS_TITLE, sfile->title)) break;
162 if (!save_clip_value(which, CLIP_DETAILS_AUTHOR, sfile->author)) break;
163 if (!save_clip_value(which, CLIP_DETAILS_COMMENT, sfile->comment)) break;
164 if (!save_clip_value(which, CLIP_DETAILS_PB_FRAMENO, &sfile->frameno)) break;
165 if (!save_clip_value(which, CLIP_DETAILS_CLIPNAME, sfile->name)) break;
166 if (!save_clip_value(which, CLIP_DETAILS_FILENAME, sfile->file_name)) break;
167 if (!save_clip_value(which, CLIP_DETAILS_KEYWORDS, sfile->keywords)) break;
168 if (sfile->clip_type == CLIP_TYPE_FILE && sfile->ext_src) {
169 lives_decoder_t *dplug = (lives_decoder_t *)sfile->ext_src;
170 if (!save_clip_value(which, CLIP_DETAILS_DECODER_NAME, (void *)dplug->decoder->name)) break;
171 }
172 all_ok = TRUE;
173 } while (FALSE);
174
175 fclose(mainw->clip_header);
176
177 if (!all_ok) {
178 retval = do_write_failed_error_s_with_retry(lives_header_new, NULL);
179 } else {
180 char *lives_header;
181 if (which == mainw->ascrap_file)
182 lives_header = lives_build_filename(prefs->workdir, sfile->handle, LIVES_ACLIP_HEADER, NULL);
183 else
184 lives_header = lives_build_filename(prefs->workdir, sfile->handle, LIVES_CLIP_HEADER, NULL);
185 // TODO - check the sizes before and after
186 lives_cp(lives_header_new, lives_header);
187 lives_free(lives_header);
188 if (THREADVAR(com_failed) || THREADVAR(write_failed)) {
189 retval = do_write_failed_error_s_with_retry(lives_header_new, NULL);
190 } else lives_rm(lives_header_new);
191 }
192 }
193 } while (retval == LIVES_RESPONSE_RETRY);
194
195 if (mainw->signal_caught) catch_sigint(mainw->signal_caught);
196 set_signal_handlers((SignalHandlerPointer)catch_sigint);
197
198 lives_free(lives_header_new);
199 mainw->clip_header = NULL;
200
201 if (retval == LIVES_RESPONSE_CANCEL) return FALSE;
202
203 return TRUE;
204 }
205
206
read_file_details(const char * file_name,boolean is_audio,boolean is_img)207 boolean read_file_details(const char *file_name, boolean is_audio, boolean is_img) {
208 // get preliminary details
209
210 // is_audio set to TRUE prevents us from checking for images, and deleting the (existing) first frame
211 // therefore it is IMPORTANT to set it when loading new audio for an existing clip !
212
213 // is_img will force unpacking of img into frames and return the count
214
215 char *tmp, *com = lives_strdup_printf("%s get_details \"%s\" \"%s\" \"%s\" %d", prefs->backend_sync, cfile->handle,
216 (tmp = lives_filename_from_utf8(file_name, -1, NULL, NULL, NULL)),
217 get_image_ext_for_type(IMG_TYPE_BEST), mainw->opening_loc ? 3 :
218 is_audio ? 2 : is_img ? 4 : 0);
219 lives_free(tmp);
220 lives_popen(com, FALSE, mainw->msg, MAINW_MSG_SIZE);
221 lives_free(com);
222 if (THREADVAR(com_failed)) {
223 THREADVAR(com_failed) = FALSE;
224 return FALSE;
225 }
226 return TRUE;
227 }
228
229
get_deinterlace_string(void)230 const char *get_deinterlace_string(void) {
231 if (mainw->open_deint) {
232 if (USE_MPV) return "--deinterlace=yes";
233 return "-vf pp=ci";
234 } else return "";
235 }
236
237
deduce_file(const char * file_name,double start,int end)238 ulong deduce_file(const char *file_name, double start, int end) {
239 // this is a utility function to deduce whether we are dealing with a file,
240 // a selection, a backup, or a location
241 char short_file_name[PATH_MAX];
242 ulong uid;
243 mainw->img_concat_clip = -1;
244
245 if (lives_strrstr(file_name, "://") && strncmp(file_name, "dvd://", 6)) {
246 mainw->opening_loc = TRUE;
247 uid = open_file(file_name);
248 mainw->opening_loc = FALSE;
249 } else {
250 lives_snprintf(short_file_name, PATH_MAX, "%s", file_name);
251 if (!(strcmp(file_name + strlen(file_name) - 4, "."LIVES_FILE_EXT_BACKUP))) {
252 uid = restore_file(file_name);
253 } else {
254 uid = open_file_sel(file_name, start, end);
255 }
256 }
257 return uid;
258 }
259
260
open_file(const char * file_name)261 ulong open_file(const char *file_name) {
262 // this function should be called to open a whole file
263 return open_file_sel(file_name, 0., 0);
264 }
265
266
rip_audio_cancelled(int old_file,weed_plant_t * mt_pb_start_event,boolean mt_has_audio_file)267 static boolean rip_audio_cancelled(int old_file, weed_plant_t *mt_pb_start_event,
268 boolean mt_has_audio_file) {
269
270 if (mainw->cancelled == CANCEL_KEEP) {
271 // user clicked "enough"
272 mainw->cancelled = CANCEL_NONE;
273 return TRUE;
274 }
275
276 end_threaded_dialog();
277
278 d_print("\n");
279 d_print_cancelled();
280 close_current_file(old_file);
281
282 if (mainw->multitrack) {
283 mainw->multitrack->pb_start_event = mt_pb_start_event;
284 mainw->multitrack->has_audio_file = mt_has_audio_file;
285 }
286
287 lives_freep((void **)&mainw->file_open_params);
288 lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
289 return FALSE;
290 }
291
292
pad_init_silence(void)293 void pad_init_silence(void) {
294 cfile->undo1_dbl = 0.;
295 cfile->undo2_dbl = CLIP_TOTAL_TIME(mainw->current_file) - cfile->laudio_time;
296 cfile->undo_arate = cfile->arate;
297 cfile->undo_signed_endian = cfile->signed_endian;
298 cfile->undo_achans = cfile->achans;
299 cfile->undo_asampsize = cfile->asampsize;
300 cfile->undo_arps = cfile->arps;
301 d_print(_("Auto padding with %.4f seconds of silence at start..."), cfile->undo2_dbl);
302 if (on_ins_silence_activate(NULL, NULL)) d_print_done();
303 else d_print("\n");
304 }
305
306
307 #define AUDIO_FRAMES_TO_READ 100
308
open_file_sel(const char * file_name,double start,int frames)309 ulong open_file_sel(const char *file_name, double start, int frames) {
310 LiVESResponseType response;
311 char msg[256], loc[PATH_MAX];
312 char *tmp = NULL;
313 char *isubfname = NULL;
314 char *fname = lives_strdup(file_name), *msgstr;
315 char *com, *what;
316
317 int withsound = 1;
318 int old_file = mainw->current_file;
319 int new_file = old_file;
320
321 int achans, arate, arps, asampsize;
322 int current_file;
323 int extra_frames = 0;
324 int probed_achans = 0;
325
326 boolean mt_has_audio_file = TRUE;
327
328 const lives_clip_data_t *cdata;
329
330 weed_plant_t *mt_pb_start_event = NULL;
331
332 if (!lives_file_test(fname, LIVES_FILE_TEST_EXISTS)) {
333 do_no_loadfile_error(fname);
334 lives_free(fname);
335 return 0;
336 }
337
338 if (old_file == -1 || !CURRENT_CLIP_IS_VALID || !cfile->opening) {
339 new_file = mainw->first_free_file;
340
341 if (!get_new_handle(new_file, fname)) {
342 lives_free(fname);
343 return 0;
344 }
345 lives_free(fname);
346
347 lives_set_cursor_style(LIVES_CURSOR_BUSY, NULL);
348 lives_widget_context_update();
349
350 if (frames == 0) {
351 com = lives_strdup_printf(_("Opening %s"), file_name);
352 } else {
353 com = lives_strdup_printf(_("Opening %s start time %.2f sec. frames %d"), file_name, start, frames);
354 }
355 d_print(""); // exhaust "switch" message
356
357 d_print(com);
358 lives_free(com);
359
360 if (!mainw->save_with_sound) {
361 d_print(_(" without sound"));
362 withsound = 0;
363 }
364
365 mainw->current_file = new_file;
366
367 /// probe the file to see what it might be...
368 read_file_details(file_name, FALSE, FALSE);
369 lives_rm(cfile->info_file);
370 if (THREADVAR(com_failed)) return 0;
371
372 if (*mainw->msg) add_file_info(cfile->handle, FALSE);
373
374 if (mainw->multitrack) {
375 // set up for opening preview
376 mt_pb_start_event = mainw->multitrack->pb_start_event;
377 mt_has_audio_file = mainw->multitrack->has_audio_file;
378 mainw->multitrack->pb_start_event = NULL;
379 mainw->multitrack->has_audio_file = TRUE;
380 }
381
382 cfile->img_type = lives_image_ext_to_img_type(prefs->image_ext);
383 if ((!strcmp(cfile->type, LIVES_IMAGE_TYPE_JPEG) || !strcmp(cfile->type, LIVES_IMAGE_TYPE_PNG))) {
384 read_file_details(file_name, FALSE, TRUE);
385 add_file_info(cfile->handle, FALSE);
386 if (cfile->frames == 0) {
387 d_print_failed();
388 close_current_file(old_file);
389 if (mainw->multitrack) {
390 mainw->multitrack->pb_start_event = mt_pb_start_event;
391 mainw->multitrack->has_audio_file = mt_has_audio_file;
392 }
393 lives_freep((void **)&mainw->file_open_params);
394 lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
395 return 0;
396 }
397 goto img_load;
398 }
399
400 if (prefs->instant_open && !mainw->opening_loc) {
401 // cd to clip directory - so decoder plugins can write temp files
402 char *ppath = lives_build_filename(prefs->workdir, cfile->handle, NULL);
403 char *cwd = lives_get_current_dir();
404
405 if (!mainw->decoders_loaded) {
406 mainw->decoder_list = load_decoders();
407 mainw->decoders_loaded = TRUE;
408 }
409
410 lives_chdir(ppath, FALSE);
411 lives_free(ppath);
412
413 cdata = get_decoder_cdata(mainw->current_file, prefs->disabled_decoders, NULL);
414
415 lives_chdir(cwd, FALSE);
416 lives_free(cwd);
417
418 if (cfile->ext_src) {
419 lives_decoder_t *dplug = (lives_decoder_t *)cfile->ext_src;
420 cfile->opening = TRUE;
421 cfile->clip_type = CLIP_TYPE_FILE;
422 cfile->img_type = IMG_TYPE_BEST; // override the pref
423
424 if (cdata->frame_width > 0) {
425 cfile->hsize = cdata->frame_width;
426 cfile->vsize = cdata->frame_height;
427 } else {
428 cfile->hsize = cdata->width;
429 cfile->vsize = cdata->height;
430 }
431
432 if (cfile->frames > cdata->nframes && cfile->frames != 123456789) {
433 extra_frames = cfile->frames - cdata->nframes;
434 }
435 cfile->frames = cdata->nframes;
436 if (!*cfile->author)
437 lives_snprintf(cfile->author, 1024, "%s", cdata->author);
438 if (!*cfile->title)
439 lives_snprintf(cfile->title, 1024, "%s", cdata->title);
440 if (!*cfile->comment)
441 lives_snprintf(cfile->comment, 1024, "%s", cdata->comment);
442
443 if (frames > 0 && cfile->frames > frames) {
444 cfile->frames = frames;
445 extra_frames = 0;
446 }
447
448 cfile->start = 1;
449 cfile->end = cfile->frames;
450
451 what = (_("creating the frame index for the clip"));
452
453 do {
454 response = LIVES_RESPONSE_OK;
455 create_frame_index(mainw->current_file, TRUE, cfile->fps * (start == 0 ? 0 : start - 1),
456 frames == 0 ? cfile->frames : frames);
457 if (!cfile->frame_index) {
458 response = do_memory_error_dialog(what, (frames == 0 ? cfile->frames : frames) * 4);
459 }
460 } while (response == LIVES_RESPONSE_RETRY);
461 lives_free(what);
462 if (response == LIVES_RESPONSE_CANCEL) {
463 return 0;
464 }
465 probed_achans = cfile->achans;
466 cfile->arate = cfile->arps = cdata->arate;
467 cfile->achans = cdata->achans;
468 cfile->asampsize = cdata->asamps;
469
470 cfile->signed_endian = get_signed_endian(cdata->asigned, capable->byte_order == LIVES_LITTLE_ENDIAN);
471
472 if (cfile->achans > 0 && (dplug->decoder->rip_audio) && withsound == 1) {
473 // call rip_audio() in the decoder plugin
474 // the plugin gets a chance to do any internal cleanup in rip_audio_cleanup()
475
476 int64_t stframe = cfile->fps * start + .5;
477 int64_t maxframe = (stframe + (frames == 0)) ? cfile->frames : frames;
478 int64_t nframes = AUDIO_FRAMES_TO_READ;
479 char *afile = get_audio_file_name(mainw->current_file, TRUE);
480
481 msgstr = lives_strdup_printf(_("Opening audio for %s"), file_name);
482
483 if (!LIVES_IS_PLAYING) resize(1);
484
485 mainw->cancelled = CANCEL_NONE;
486
487 if (!LIVES_IS_PLAYING) {
488 mainw->cancel_type = CANCEL_SOFT;
489 do_threaded_dialog(msgstr, TRUE);
490 mainw->cancel_type = CANCEL_KILL;
491 }
492
493 do {
494 if (stframe + nframes > maxframe) nframes = maxframe - stframe;
495 if (nframes <= 0) break;
496 (dplug->decoder->rip_audio)(cdata, afile, stframe, nframes, NULL);
497 threaded_dialog_spin(0.);
498 stframe += nframes;
499 } while (mainw->cancelled == CANCEL_NONE);
500
501 if (dplug->decoder->rip_audio_cleanup) {
502 (dplug->decoder->rip_audio_cleanup)(cdata);
503 }
504
505 if (mainw->cancelled != CANCEL_NONE) {
506 if (!rip_audio_cancelled(old_file, mt_pb_start_event, mt_has_audio_file)) {
507 lives_free(afile);
508 return 0;
509 }
510 }
511 end_threaded_dialog();
512 lives_free(msgstr);
513 lives_free(afile);
514 } else {
515 cfile->arate = 0.;
516 cfile->achans = cfile->asampsize = 0;
517 }
518
519 cfile->fps = cfile->pb_fps = cdata->fps;
520 d_print("\n");
521
522 if (cfile->achans == 0 && probed_achans > 0 && withsound == 1) {
523 // plugin returned no audio, try with mplayer / mpv
524 if (probed_achans > MAX_ACHANS) {
525 probed_achans = MAX_ACHANS;
526 d_print(_("Forcing audio channels to %d\n"), MAX_ACHANS);
527 }
528
529 if (!mainw->file_open_params) {
530 #if 1
531 mainw->file_open_params = lives_strdup("alang eng");
532 #else
533 mainw->file_open_params = lives_strdup("");
534 #endif
535 }
536 com = lives_strdup_printf("%s open \"%s\" \"%s\" %d %s:%s %.2f %d %d \"%s\"", prefs->backend, cfile->handle,
537 (tmp = lives_filename_from_utf8(file_name, -1, NULL, NULL, NULL)), -1,
538 prefs->image_ext, get_image_ext_for_type(IMG_TYPE_BEST), start, frames, probed_achans,
539 mainw->file_open_params);
540
541 lives_free(tmp);
542
543 lives_rm(cfile->info_file);
544 lives_system(com, FALSE);
545 lives_free(com);
546
547 // if we have a quick-opening file, display the first and last frames now
548 // for some codecs this can be helpful since we can locate the last frame while audio is loading
549 if (cfile->clip_type == CLIP_TYPE_FILE && !LIVES_IS_PLAYING) resize(1);
550
551 mainw->effects_paused = FALSE; // set to TRUE if user clicks "Enough"
552
553 msgstr = lives_strdup_printf(_("Opening audio"), file_name);
554 if (!do_progress_dialog(TRUE, TRUE, msgstr)) {
555 // error or user cancelled or switched to another clip
556 lives_free(msgstr);
557
558 cfile->opening_frames = -1;
559
560 if (mainw->multitrack) {
561 mainw->multitrack->pb_start_event = mt_pb_start_event;
562 mainw->multitrack->has_audio_file = mt_has_audio_file;
563 }
564
565 if (mainw->cancelled == CANCEL_NO_PROPOGATE) {
566 lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
567 mainw->cancelled = CANCEL_NONE;
568 return 0;
569 }
570
571 // cancelled
572 if (mainw->cancelled != CANCEL_ERROR) {
573 lives_kill_subprocesses(cfile->handle, TRUE);
574 }
575
576 lives_freep((void **)&mainw->file_open_params);
577 close_current_file(old_file);
578 lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
579 if (mainw->error) {
580 do_error_dialog(mainw->msg);
581 mainw->error = 0;
582 clear_mainw_msg();
583 }
584 sensitize();
585 return 0;
586 }
587 lives_free(msgstr);
588
589 cfile->opening = FALSE;
590
591 wait_for_bg_audio_sync(mainw->current_file);
592 if (mainw->error == 0) add_file_info(cfile->handle, TRUE);
593 mainw->error = 0;
594 get_total_time(cfile);
595
596 if (prefs->auto_trim_audio) {
597 if ((cdata->sync_hint & SYNC_HINT_VIDEO_PAD_START) && cdata->video_start_time <= 1.) {
598 // pad with blank frames at start
599 int st_extra_frames = cdata->video_start_time * cfile->fps;
600 insert_blank_frames(mainw->current_file, st_extra_frames, 0, WEED_PALETTE_RGB24);
601 cfile->video_time += st_extra_frames / cfile->fps;
602 extra_frames -= st_extra_frames;
603 showclipimgs();
604 if (!mainw->multitrack)
605 redraw_timeline(mainw->current_file);
606 }
607
608 if ((cfile->frames + extra_frames) / cfile->fps > cfile->laudio_time) {
609 extra_frames = (cfile->laudio_time - (double)cfile->frames / cfile->fps) * cfile->fps;
610 }
611
612 if (extra_frames > 0 || ((cdata->sync_hint & SYNC_HINT_VIDEO_PAD_END)
613 && (double)cfile->frames / cfile->fps < cfile->laudio_time)) {
614 // pad with blank frames at end
615 if (cdata->sync_hint & SYNC_HINT_VIDEO_PAD_END) {
616 int xextra_frames = (cfile->laudio_time - (double)cfile->frames / cfile->fps) * cfile->fps;
617 if (xextra_frames > extra_frames) extra_frames = xextra_frames;
618 }
619 insert_blank_frames(mainw->current_file, extra_frames, cfile->frames, WEED_PALETTE_RGB24);
620 cfile->video_time += extra_frames / cfile->fps;
621 load_end_image(cfile->end);
622 }
623 if (cfile->laudio_time > cfile->video_time + AV_TRACK_MIN_DIFF && cfile->frames > 0) {
624 if (cdata->sync_hint & SYNC_HINT_AUDIO_TRIM_START) {
625 cfile->undo1_dbl = 0.;
626 cfile->undo2_dbl = cfile->laudio_time - cfile->video_time;
627 d_print(_("Auto trimming %.4f seconds of audio at start..."), cfile->undo2_dbl);
628 if (on_del_audio_activate(NULL, NULL)) d_print_done();
629 else d_print("\n");
630 cfile->changed = FALSE;
631 }
632 }
633 if (cfile->laudio_time > cfile->video_time + AV_TRACK_MIN_DIFF && cfile->frames > 0) {
634 if (cdata->sync_hint & SYNC_HINT_AUDIO_TRIM_END) {
635 cfile->end = cfile->frames;
636 d_print(_("Auto trimming %.4f seconds of audio at end..."), cfile->laudio_time - cfile->video_time);
637 if (on_trim_audio_activate(NULL, LIVES_INT_TO_POINTER(0))) d_print_done();
638 else d_print("\n");
639 cfile->changed = FALSE;
640 }
641 }
642 if (!mainw->effects_paused && cfile->afilesize > 0 && cfile->achans > 0
643 && CLIP_TOTAL_TIME(mainw->current_file) > cfile->laudio_time + AV_TRACK_MIN_DIFF) {
644 if (cdata->sync_hint & SYNC_HINT_AUDIO_PAD_START) {
645 pad_init_silence();
646 cfile->changed = FALSE;
647 }
648 if (cdata->sync_hint & SYNC_HINT_AUDIO_PAD_END) {
649 cfile->undo1_dbl = cfile->laudio_time;
650 cfile->undo2_dbl = CLIP_TOTAL_TIME(mainw->current_file) - cfile->laudio_time;
651 cfile->undo_arate = cfile->arate;
652 cfile->undo_signed_endian = cfile->signed_endian;
653 cfile->undo_achans = cfile->achans;
654 cfile->undo_asampsize = cfile->asampsize;
655 cfile->undo_arps = cfile->arps;
656 d_print(_("Auto padding with %.4f seconds of silence at end..."), cfile->undo2_dbl);
657 if (on_ins_silence_activate(NULL, NULL)) d_print_done();
658 else d_print("\n");
659 cfile->changed = FALSE;
660 // *INDENT-OFF*
661 }}}}
662 // *INDENT-ON*
663
664 get_mime_type(cfile->type, 40, cdata);
665 save_frame_index(mainw->current_file);
666 }
667 }
668
669 if (cfile->ext_src) {
670 if (mainw->open_deint) {
671 // override what the plugin says
672 cfile->deinterlace = TRUE;
673 cfile->interlace = LIVES_INTERLACE_TOP_FIRST; // guessing
674 save_clip_value(mainw->current_file, CLIP_DETAILS_INTERLACE, &cfile->interlace);
675 if (THREADVAR(com_failed) || THREADVAR(write_failed)) do_header_write_error(mainw->current_file);
676 }
677 } else {
678 // be careful, here we switch from mainw->opening_loc to cfile->opening_loc
679 if (mainw->opening_loc) {
680 cfile->opening_loc = TRUE;
681 mainw->opening_loc = FALSE;
682 } else {
683 if (cfile->f_size > prefs->warn_file_size * 1000000. && mainw->is_ready && frames == 0) {
684 char *fsize_ds = lives_format_storage_space_string((uint64_t)cfile->f_size);
685 char *warn = lives_strdup_printf(
686 _("\nLiVES cannot Instant Open this file, it may take some time to load.\n"
687 "Are you sure you wish to continue ?"),
688 fsize_ds);
689 lives_free(fsize_ds);
690 if (!do_warning_dialog_with_check(warn, WARN_MASK_FSIZE)) {
691 lives_free(warn);
692 close_current_file(old_file);
693 if (mainw->multitrack) {
694 mainw->multitrack->pb_start_event = mt_pb_start_event;
695 mainw->multitrack->has_audio_file = mt_has_audio_file;
696 }
697 lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
698 return 0;
699 }
700 lives_free(warn);
701 d_print(_(" - please be patient."));
702
703 }
704 d_print("\n");
705 #if defined DEBUG
706 g_print("open_file: dpd in\n");
707 #endif
708 }
709 }
710
711 // set undo_start and undo_end for preview
712 cfile->undo_start = 1;
713 cfile->undo_end = cfile->frames;
714
715 if (cfile->achans > 0) {
716 cfile->opening_audio = TRUE;
717 }
718
719 // these will get reset as we have no audio file yet, so preserve them
720 achans = cfile->achans;
721 arate = cfile->arate;
722 arps = cfile->arps;
723 asampsize = cfile->asampsize;
724 cfile->old_frames = cfile->frames;
725 cfile->frames = 0;
726
727 // we need this FALSE here, otherwise we will switch straight back here...
728 cfile->opening = FALSE;
729
730 // force a resize
731 current_file = mainw->current_file;
732
733 cfile->opening = TRUE;
734 cfile->achans = achans;
735 cfile->arate = arate;
736 cfile->arps = arps;
737 cfile->asampsize = asampsize;
738 cfile->frames = cfile->old_frames;
739
740 if (cfile->frames <= 0) {
741 cfile->undo_end = cfile->frames = 123456789;
742 }
743 if (cfile->hsize * cfile->vsize == 0) {
744 cfile->frames = 0;
745 }
746
747 if (!mainw->multitrack) get_play_times();
748
749 add_to_clipmenu();
750 set_main_title(cfile->file_name, 0);
751
752 mainw->effects_paused = FALSE;
753
754 if (!cfile->ext_src) {
755 if (!mainw->file_open_params) mainw->file_open_params = lives_strdup("");
756
757 tmp = lives_strconcat(mainw->file_open_params, get_deinterlace_string(), NULL);
758 lives_free(mainw->file_open_params);
759 mainw->file_open_params = tmp;
760
761 if (cfile->achans > MAX_ACHANS) {
762 cfile->achans = MAX_ACHANS;
763 d_print(_("Forcing audio channels to %d\n"), MAX_ACHANS);
764 }
765
766 com = lives_strdup_printf("%s open \"%s\" \"%s\" %d %s:%s %.2f %d %d \"%s\"", prefs->backend, cfile->handle,
767 (tmp = lives_filename_from_utf8(file_name, -1, NULL, NULL, NULL)), withsound,
768 prefs->image_ext, get_image_ext_for_type(IMG_TYPE_BEST), start, frames, cfile->achans,
769 mainw->file_open_params);
770
771 lives_rm(cfile->info_file);
772 lives_system(com, FALSE);
773 lives_free(com);
774 lives_free(tmp);
775
776 if (mainw->toy_type == LIVES_TOY_TV) {
777 // for LiVES TV we do an auto-preview
778 mainw->play_start = cfile->start = cfile->undo_start;
779 mainw->play_end = cfile->end = cfile->undo_end;
780 mainw->preview = TRUE;
781 do {
782 desensitize();
783 procw_desensitize();
784 on_playsel_activate(NULL, NULL);
785 } while (mainw->cancelled == CANCEL_KEEP_LOOPING);
786 mainw->preview = FALSE;
787 on_toy_activate(NULL, LIVES_INT_TO_POINTER(LIVES_TOY_NONE));
788 lives_freep((void **)&mainw->file_open_params);
789 mainw->cancelled = CANCEL_NONE;
790 lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
791 return 0;
792 }
793 }
794
795 // loading:
796
797 // 'entry point' when we switch back
798
799 // spin until loading is complete
800 // afterwards, mainw->msg will contain file details
801 cfile->progress_start = cfile->progress_end = 0;
802
803 // (also check for cancel)
804 msgstr = lives_strdup_printf(_("Opening %s"), file_name);
805
806 if (!cfile->ext_src && mainw->toy_type != LIVES_TOY_TV) {
807 mainw->cs_permitted = TRUE;
808 mainw->disk_mon = MONITOR_QUOTA;
809 if (!do_progress_dialog(TRUE, TRUE, msgstr)) {
810 // user cancelled or switched to another clip
811 mainw->cs_permitted = FALSE;
812 mainw->disk_mon = 0;
813
814 lives_free(msgstr);
815 mainw->effects_paused = FALSE;
816
817 if (mainw->cancelled == CANCEL_NO_PROPOGATE) {
818 mainw->cancelled = CANCEL_NONE;
819 lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
820 return 0;
821 }
822
823 // cancelled
824 // clean up our temp files
825 if (IS_VALID_CLIP(current_file)) mainw->current_file = current_file;
826 lives_kill_subprocesses(cfile->handle, TRUE);
827 lives_freep((void **)&mainw->file_open_params);
828 close_current_file(old_file);
829 if (mainw->multitrack) {
830 mainw->multitrack->pb_start_event = mt_pb_start_event;
831 mainw->multitrack->has_audio_file = mt_has_audio_file;
832 }
833 lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
834
835 // mainw->error is TRUE if we could not open the file
836 if (mainw->error) {
837 d_print_failed();
838 do_error_dialog(mainw->msg);
839 }
840 if (!mainw->multitrack)
841 redraw_timeline(mainw->current_file);
842 showclipimgs();
843 return 0;
844 }
845 mainw->cs_permitted = FALSE;
846 mainw->disk_mon = 0;
847 }
848 lives_free(msgstr);
849 }
850
851 if (cfile->ext_src && cfile->achans > 0) {
852 char *afile = get_audio_file_name(mainw->current_file, TRUE);
853 char *ofile = get_audio_file_name(mainw->current_file, FALSE);
854 rename(afile, ofile);
855 lives_free(afile);
856 lives_free(ofile);
857 }
858
859 cfile->opening = cfile->opening_audio = cfile->opening_only_audio = FALSE;
860 cfile->opening_frames = -1;
861 mainw->effects_paused = FALSE;
862
863 #if defined DEBUG
864 g_print("Out of dpd\n");
865 #endif
866
867 if (mainw->multitrack) {
868 mainw->multitrack->pb_start_event = mt_pb_start_event;
869 mainw->multitrack->has_audio_file = mt_has_audio_file;
870 }
871
872 // mainw->error is TRUE if we could not open the file
873 if (mainw->error) {
874 do_error_dialog(mainw->msg);
875 d_print_failed();
876 close_current_file(old_file);
877 lives_freep((void **)&mainw->file_open_params);
878 lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
879 return 0;
880 }
881
882 if (cfile->opening_loc) {
883 cfile->changed = TRUE;
884 cfile->opening_loc = FALSE;
885 } else {
886 if (prefs->autoload_subs) {
887 char filename[512];
888 char *subfname;
889 lives_subtitle_type_t subtype = SUBTITLE_TYPE_NONE;
890
891 lives_snprintf(filename, 512, "%s", file_name);
892 get_filename(filename, FALSE); // strip extension
893 isubfname = lives_strdup_printf("%s.%s", filename, LIVES_FILE_EXT_SRT);
894 if (lives_file_test(isubfname, LIVES_FILE_TEST_EXISTS)) {
895 subfname = lives_build_filename(prefs->workdir, cfile->handle, SUBS_FILENAME "." LIVES_FILE_EXT_SRT, NULL);
896 subtype = SUBTITLE_TYPE_SRT;
897 } else {
898 lives_free(isubfname);
899 isubfname = lives_strdup_printf("%s.%s", filename, LIVES_FILE_EXT_SUB);
900 if (lives_file_test(isubfname, LIVES_FILE_TEST_EXISTS)) {
901 subfname = lives_build_filename(prefs->workdir, cfile->handle, SUBS_FILENAME "." LIVES_FILE_EXT_SUB, NULL);
902 subtype = SUBTITLE_TYPE_SUB;
903 }
904 }
905 if (subtype != SUBTITLE_TYPE_NONE) {
906 lives_cp(isubfname, subfname);
907 if (!THREADVAR(com_failed))
908 subtitles_init(cfile, subfname, subtype);
909 lives_free(subfname);
910 } else {
911 lives_freep((void **)&isubfname);
912 }
913 }
914 }
915
916 // now file should be loaded...get full details
917 if (!cfile->ext_src) add_file_info(cfile->handle, FALSE);
918 cfile->is_loaded = TRUE;
919
920 if (cfile->frames <= 0) {
921 if (cfile->afilesize == 0l) {
922 // we got neither video nor audio...
923 lives_snprintf(msg, 256, "%s", _
924 ("\n\nLiVES was unable to extract either video or audio.\n"
925 "Please check the terminal window for more details.\n"));
926
927 if (!capable->has_mplayer && !capable->has_mplayer2 && !capable->has_mpv) {
928 lives_strappend(msg, 256, _("\n\nYou may need to install mplayer, mplayer2 or mpv to open this file.\n"));
929 } else {
930 if (capable->has_mplayer) {
931 get_location(EXEC_MPLAYER, loc, PATH_MAX);
932 } else if (capable->has_mplayer2) {
933 get_location(EXEC_MPLAYER2, loc, PATH_MAX);
934 } else if (capable->has_mpv) {
935 get_location(EXEC_MPV, loc, PATH_MAX);
936 }
937
938 if (strcmp(prefs->video_open_command, loc) && strncmp(prefs->video_open_command + 1, loc, strlen(loc))) {
939 lives_strappend(msg, 256, _("\n\nPlease check the setting of Video Open Command in\nTools|Preferences|Decoding\n"));
940 }
941 }
942 widget_opts.non_modal = TRUE;
943 do_error_dialog(msg);
944 widget_opts.non_modal = FALSE;
945 d_print_failed();
946 close_current_file(old_file);
947 if (mainw->multitrack) {
948 mainw->multitrack->pb_start_event = mt_pb_start_event;
949 mainw->multitrack->has_audio_file = mt_has_audio_file;
950 }
951 lives_freep((void **)&mainw->file_open_params);
952 lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
953 return 0;
954 }
955 cfile->frames = 0;
956 }
957
958 if (!cfile->ext_src) {
959 extra_frames = cfile->frames;
960 add_file_info(cfile->handle, FALSE);
961 extra_frames -= cfile->frames;
962 cfile->end = cfile->frames;
963 cfile->video_time = cfile->frames / cfile->fps;
964 } else {
965 add_file_info(NULL, FALSE);
966 if (cfile->f_size == 0) {
967 off_t fsize = sget_file_size((char *)file_name);
968 if (fsize < 0) fsize = 0;
969 cfile->f_size = (size_t)fsize;
970 }
971 }
972
973 if (!cfile->ext_src) {
974 reget_afilesize(mainw->current_file);
975 if (prefs->auto_trim_audio || prefs->keep_all_audio) {
976 if (cfile->laudio_time > cfile->video_time && cfile->frames > 0) {
977 if (!prefs->keep_all_audio || start != 0. || extra_frames <= 0) {
978 d_print(_("Auto trimming %.2f seconds of audio at end..."), cfile->laudio_time - cfile->video_time);
979 if (on_trim_audio_activate(NULL, LIVES_INT_TO_POINTER(0))) d_print_done();
980 else d_print("\n");
981 cfile->changed = FALSE;
982 } else {
983 /// insert blank frames
984 if (prefs->keep_all_audio && (cfile->laudio_time - cfile->video_time) * cfile->fps > extra_frames)
985 extra_frames = (cfile->laudio_time - cfile->video_time) * cfile->fps;
986 insert_blank_frames(mainw->current_file, extra_frames, cfile->frames, WEED_PALETTE_RGB24);
987 cfile->video_time += extra_frames / cfile->fps;
988 cfile->end = cfile->frames;
989 showclipimgs();
990 if (!mainw->multitrack)
991 redraw_timeline(mainw->current_file);
992 }
993 }
994 if (cfile->laudio_time < cfile->video_time && cfile->achans > 0) {
995 cfile->undo1_dbl = cfile->laudio_time;
996 cfile->undo2_dbl = CLIP_TOTAL_TIME(mainw->current_file) - cfile->laudio_time;
997 cfile->undo_arate = cfile->arate;
998 cfile->undo_signed_endian = cfile->signed_endian;
999 cfile->undo_achans = cfile->achans;
1000 cfile->undo_asampsize = cfile->asampsize;
1001 cfile->undo_arps = cfile->arps;
1002 d_print(_("Auto padding with %.2f seconds of silence at end..."), cfile->undo2_dbl);
1003 if (on_ins_silence_activate(NULL, NULL)) d_print_done();
1004 else d_print("\n");
1005 cfile->changed = FALSE;
1006 }
1007 }
1008 }
1009
1010 if (isubfname) {
1011 d_print(_("Loaded subtitle file: %s\n"), isubfname);
1012 lives_free(isubfname);
1013 }
1014
1015 img_load:
1016 current_file = mainw->current_file;
1017
1018 #ifdef GET_MD5
1019 g_print("md5sum is %s\n", get_md5sum(file_name));
1020 #endif
1021
1022 // TODO - prompt for copy to origs (unless it is already there)
1023
1024 lives_notify(LIVES_OSC_NOTIFY_CLIP_OPENED, "");
1025
1026 if (prefs->show_recent && !mainw->is_generating) {
1027 add_to_recent(file_name, start, frames, mainw->file_open_params);
1028 }
1029 lives_freep((void **)&mainw->file_open_params);
1030
1031 if (!strcmp(cfile->type, "Frames") || !strcmp(cfile->type, LIVES_IMAGE_TYPE_JPEG) ||
1032 !strcmp(cfile->type, LIVES_IMAGE_TYPE_PNG) ||
1033 !strcmp(cfile->type, "Audio")) {
1034 cfile->is_untitled = TRUE;
1035 }
1036
1037 if ((!strcmp(cfile->type, LIVES_IMAGE_TYPE_JPEG) || !strcmp(cfile->type, LIVES_IMAGE_TYPE_PNG))) {
1038 if (mainw->img_concat_clip == -1) {
1039 cfile->img_type = lives_image_type_to_img_type(cfile->type);
1040 mainw->img_concat_clip = mainw->current_file;
1041 add_to_clipmenu();
1042 set_main_title(cfile->file_name, 0);
1043 cfile->opening = cfile->opening_audio = cfile->opening_only_audio = FALSE;
1044 cfile->opening_frames = -1;
1045 mainw->effects_paused = FALSE;
1046 cfile->is_loaded = TRUE;
1047 } else if (prefs->concat_images) {
1048 // insert this image into our image clip, close this file
1049
1050 com = lives_strdup_printf("%s insert \"%s\" \"%s\" %d 1 1 \"%s\" 0 %d %d %d", prefs->backend,
1051 mainw->files[mainw->img_concat_clip]->handle,
1052 get_image_ext_for_type(mainw->files[mainw->img_concat_clip]->img_type),
1053 mainw->files[mainw->img_concat_clip]->frames,
1054 cfile->handle, mainw->files[mainw->img_concat_clip]->frames,
1055 mainw->files[mainw->img_concat_clip]->hsize, mainw->files[mainw->img_concat_clip]->vsize);
1056
1057 mainw->current_file = mainw->img_concat_clip;
1058
1059 lives_rm(cfile->info_file);
1060
1061 mainw->cancelled = CANCEL_NONE;
1062 mainw->error = FALSE;
1063 lives_system(com, FALSE);
1064 lives_free(com);
1065
1066 do_auto_dialog(_("Adding image..."), 2);
1067
1068 if (current_file != mainw->img_concat_clip) {
1069 mainw->current_file = current_file;
1070 close_current_file(mainw->img_concat_clip);
1071 }
1072
1073 if (mainw->cancelled || mainw->error) {
1074 goto load_done;
1075 }
1076
1077 cfile->frames++;
1078 cfile->end++;
1079
1080 lives_signal_handler_block(mainw->spinbutton_end, mainw->spin_end_func);
1081 lives_spin_button_set_range(LIVES_SPIN_BUTTON(mainw->spinbutton_end), cfile->frames == 0 ? 0 : 1, cfile->frames);
1082 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), cfile->end);
1083 lives_signal_handler_unblock(mainw->spinbutton_end, mainw->spin_end_func);
1084
1085 lives_signal_handler_block(mainw->spinbutton_start, mainw->spin_start_func);
1086 lives_spin_button_set_range(LIVES_SPIN_BUTTON(mainw->spinbutton_start), cfile->frames == 0 ? 0 : 1, cfile->frames);
1087 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), cfile->start);
1088 lives_signal_handler_unblock(mainw->spinbutton_start, mainw->spin_start_func);
1089 lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
1090 return 0;
1091 }
1092 }
1093
1094 // set new style file details
1095 if (!save_clip_values(current_file)) {
1096 close_current_file(old_file);
1097 return 0;
1098 }
1099
1100 if (prefs->crash_recovery) add_to_recovery_file(cfile->handle);
1101
1102 load_done:
1103 if (!mainw->multitrack) {
1104 // update widgets
1105 switch_to_file((mainw->current_file = 0), current_file);
1106 lives_widget_queue_draw(LIVES_MAIN_WINDOW_WIDGET);
1107 } else {
1108 lives_mt *multi = mainw->multitrack;
1109 mainw->multitrack = NULL; // allow getting of afilesize
1110 current_file = mainw->current_file;
1111 mainw->current_file = -1; // stop framebars from being drawn
1112 reget_afilesize(current_file);
1113 mainw->current_file = current_file;
1114 mainw->multitrack = multi;
1115 get_total_time(cfile);
1116 if (!mainw->is_generating) mainw->current_file = mainw->multitrack->render_file;
1117 mt_init_clips(mainw->multitrack, current_file, TRUE);
1118 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
1119 mt_clip_select(mainw->multitrack, TRUE);
1120 }
1121 lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
1122 check_storage_space(-1, FALSE);
1123 return cfile->unique_id;
1124 }
1125
1126
save_subs_to_file(lives_clip_t * sfile,char * fname)1127 static void save_subs_to_file(lives_clip_t *sfile, char *fname) {
1128 char *ext;
1129 lives_subtitle_type_t otype, itype;
1130
1131 if (!sfile->subt) return;
1132
1133 itype = sfile->subt->type;
1134
1135 ext = get_extension(fname);
1136
1137 if (!strcmp(ext, LIVES_FILE_EXT_SUB)) otype = SUBTITLE_TYPE_SUB;
1138 else if (!strcmp(ext, LIVES_FILE_EXT_SRT)) otype = SUBTITLE_TYPE_SRT;
1139 else otype = itype;
1140
1141 lives_free(ext);
1142
1143 // TODO - use sfile->subt->save_fn
1144 switch (otype) {
1145 case SUBTITLE_TYPE_SUB:
1146 save_sub_subtitles(sfile, (double)(sfile->start - 1) / sfile->fps, (double)sfile->end / sfile->fps,
1147 (double)(sfile->start - 1) / sfile->fps, fname);
1148 break;
1149
1150 case SUBTITLE_TYPE_SRT:
1151 save_srt_subtitles(sfile, (double)(sfile->start - 1) / sfile->fps, (double)sfile->end / sfile->fps,
1152 (double)(sfile->start - 1) / sfile->fps, fname);
1153 break;
1154
1155 default:
1156 return;
1157 }
1158
1159 d_print(_("Subtitles were saved as %s\n"), mainw->subt_save_file);
1160 }
1161
1162
get_handle_from_info_file(int index)1163 boolean get_handle_from_info_file(int index) {
1164 // called from get_new_handle to get the 'real' file handle
1165 // because until we know the handle we can't use the normal info file yet
1166 char *com = lives_strdup_printf("%s new", prefs->backend_sync);
1167
1168 lives_popen(com, FALSE, mainw->msg, MAINW_MSG_SIZE);
1169 lives_free(com);
1170
1171 if (!strncmp(mainw->msg, "error|", 6)) {
1172 handle_backend_errors(FALSE);
1173 return FALSE;
1174 }
1175
1176 if (!mainw->files[index]) {
1177 mainw->files[index] = (lives_clip_t *)(lives_calloc(1, sizeof(lives_clip_t)));
1178 mainw->files[index]->clip_type = CLIP_TYPE_DISK; // the default
1179 }
1180 lives_snprintf(mainw->files[index]->handle, 256, "%s", mainw->msg);
1181
1182 return TRUE;
1183 }
1184
1185
save_frame(LiVESMenuItem * menuitem,livespointer user_data)1186 void save_frame(LiVESMenuItem * menuitem, livespointer user_data) {
1187 int frame;
1188 // save a single frame from a clip
1189 char *filt[2];
1190 char *ttl;
1191 char *filename, *defname;
1192
1193 filt[0] = lives_strdup_printf("*.%s", get_image_ext_for_type(cfile->img_type));
1194 filt[1] = NULL;
1195
1196 frame = LIVES_POINTER_TO_INT(user_data);
1197
1198 if (frame > 0)
1199 ttl = lives_strdup_printf(_("Save Frame %d"), frame);
1200
1201 else
1202 ttl = (_("Save Frame"));
1203
1204 defname = lives_strdup_printf("frame%08d.%s", frame, get_image_ext_for_type(cfile->img_type));
1205
1206 filename = choose_file(*mainw->image_dir ? mainw->image_dir : NULL, defname,
1207 filt, LIVES_FILE_CHOOSER_ACTION_SAVE, ttl, NULL);
1208
1209 lives_free(defname); lives_free(filt[0]); lives_free(ttl);
1210
1211 if (!filename) return;
1212 if (!*filename) {
1213 lives_free(filename);
1214 return;
1215 }
1216
1217 if (!save_frame_inner(mainw->current_file, frame, filename, -1, -1, FALSE)) {
1218 lives_free(filename);
1219 return;
1220 }
1221
1222 lives_snprintf(mainw->image_dir, PATH_MAX, "%s", filename);
1223 lives_free(filename);
1224 get_dirname(mainw->image_dir);
1225 if (prefs->save_directories) {
1226 set_utf8_pref(PREF_IMAGE_DIR, mainw->image_dir);
1227 }
1228 }
1229
1230
save_log_file(const char * prefix)1231 static void save_log_file(const char *prefix) {
1232 int logfd;
1233
1234 // save the logfile in workdir
1235 #ifndef IS_MINGW
1236 char *logfile = lives_strdup_printf("%s/%s_%d_%d.txt", prefs->workdir, prefix, lives_getuid(), lives_getgid());
1237 if ((logfd = creat(logfile, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) != -1) {
1238 #else
1239 char *logfile = lives_strdup_printf("%s\\%s_%d_%d.txt", prefs->workdir, prefix, lives_getuid(), lives_getgid());
1240 if ((logfd = creat(logfile, S_IRUSR | S_IWUSR)) != -1) {
1241 #endif
1242 char *btext = lives_text_view_get_text(mainw->optextview);
1243 lives_write(logfd, btext, strlen(btext), TRUE); // not really important if it fails
1244 lives_free(btext);
1245 close(logfd);
1246 }
1247 lives_free(logfile);
1248 }
1249
1250
1251 LIVES_GLOBAL_INLINE void set_default_comment(lives_clip_t *sfile, const char *extrat) {
1252 if (!*sfile->comment)
1253 lives_snprintf(sfile->comment, 1024, "Created with LiVES version %s.\nSee: %s\n%s",
1254 LiVES_VERSION, LIVES_WEBSITE, extrat);
1255 if (!*sfile->author && *prefs->def_author)
1256 lives_snprintf(sfile->author, 1024, "%s", prefs->def_author);
1257 }
1258
1259
1260 void save_file(int clip, int start, int end, const char *filename) {
1261 // save clip from frame start to frame end
1262 lives_clip_t *sfile = mainw->files[clip], *nfile = NULL;
1263 double aud_start = 0., aud_end = 0.;
1264
1265 char *n_file_name = NULL;
1266 char *fps_string;
1267 char *extra_params = NULL;
1268 char *redir = lives_strdup("1>&2 2>"LIVES_DEVNULL);
1269 char *new_stderr_name = NULL;
1270 char *mesg, *bit, *tmp;
1271 char *com, *msg;
1272 char *full_file_name = NULL;
1273 char *enc_exec_name = NULL;
1274 char *clipdir;
1275 char *cwd;
1276
1277 boolean recheck_name = FALSE;
1278
1279 int new_stderr = -1;
1280 int retval;
1281 int startframe = 1;
1282 int current_file = mainw->current_file;
1283 int asigned = !(sfile->signed_endian & AFORM_UNSIGNED); // 1 is signed (in backend)
1284 int aendian = (sfile->signed_endian & AFORM_BIG_ENDIAN); // 2 is bigend
1285 int arate;
1286 int new_file = -1;
1287
1288 #ifdef GUI_GTK
1289 GError *gerr = NULL;
1290 #endif
1291
1292 struct stat filestat;
1293
1294 off_t fsize;
1295
1296 LiVESWidget *hbox;
1297 frames_t res;
1298
1299 boolean safe_symlinks = prefs->safe_symlinks;
1300 boolean not_cancelled = FALSE;
1301 boolean output_exists = FALSE;
1302 boolean save_all = FALSE;
1303 boolean debug_mode = FALSE;
1304
1305 if (!check_storage_space(mainw->current_file, FALSE)) return;
1306
1307 lives_set_cursor_style(LIVES_CURSOR_BUSY, NULL);
1308 lives_widget_context_update();
1309
1310 if (start == 1 && end == sfile->frames) save_all = TRUE;
1311
1312 // new handling for save selection:
1313 // symlink images 1 - n to the encoded frames
1314 // symlinks are now created in /tmp (for dynebolic)
1315 // then encode the symlinked frames
1316
1317 if (!filename) {
1318 // prompt for encoder type/output format
1319 if (prefs->show_rdet) {
1320 int response;
1321 rdet = create_render_details(1); // WARNING !! - rdet is global in events.h
1322
1323 while (1) {
1324 response = lives_dialog_run(LIVES_DIALOG(rdet->dialog));
1325 lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
1326 lives_widget_hide(rdet->dialog);
1327
1328 if (response == LIVES_RESPONSE_CANCEL) {
1329 lives_widget_destroy(rdet->dialog);
1330 lives_free(rdet->encoder_name);
1331 lives_freep((void **)&rdet);
1332 lives_freep((void **)&resaudw);
1333 return;
1334 }
1335
1336 clear_mainw_msg();
1337 // initialise new plugin
1338
1339 if (enc_exec_name) lives_free(enc_exec_name);
1340 enc_exec_name = lives_build_filename(prefs->lib_dir, PLUGIN_EXEC_DIR, PLUGIN_ENCODERS, prefs->encoder.name, NULL);
1341
1342 com = lives_strdup_printf("\"%s\" init", enc_exec_name);
1343 lives_popen(com, TRUE, mainw->msg, MAINW_MSG_SIZE);
1344 lives_free(com);
1345
1346 if (strcmp(mainw->msg, "initialised\n")) {
1347 if (*mainw->msg) {
1348 msg = lives_strdup_printf(_("\n\nThe '%s' plugin reports:\n%s\n"), prefs->encoder.name, mainw->msg);
1349 } else {
1350 msg = lives_strdup_printf
1351 (_("\n\nUnable to find the 'init' method in the %s plugin.\n"
1352 "The plugin may be broken or not installed correctly."), prefs->encoder.name);
1353 }
1354 do_error_dialog(msg);
1355 lives_free(msg);
1356 } else break;
1357 }
1358 if (rdet->debug && lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(rdet->debug)))
1359 debug_mode = TRUE;
1360 }
1361 }
1362
1363 if (!enc_exec_name)
1364 enc_exec_name = lives_build_filename(prefs->lib_dir, PLUGIN_EXEC_DIR, PLUGIN_ENCODERS, prefs->encoder.name, NULL);
1365
1366 // get file extension
1367 check_encoder_restrictions(TRUE, FALSE, save_all);
1368
1369 hbox = lives_hbox_new(FALSE, 0);
1370 mainw->fx1_bool = TRUE;
1371 add_suffix_check(LIVES_BOX(hbox), prefs->encoder.of_def_ext);
1372 lives_widget_show_all(hbox);
1373
1374 if (palette->style & STYLE_1) {
1375 lives_widget_set_fg_color(hbox, LIVES_WIDGET_STATE_NORMAL, &palette->normal_fore);
1376 lives_widget_set_bg_color(hbox, LIVES_WIDGET_STATE_NORMAL, &palette->normal_back);
1377 }
1378
1379 if (!filename) {
1380 char *ttl = (_("Save Clip"));
1381 do {
1382 lives_freep((void **)&n_file_name);
1383 n_file_name = choose_file_bg(mainw->vid_save_dir, NULL, NULL, LIVES_FILE_CHOOSER_ACTION_SAVE, ttl, hbox);
1384 if (mainw->fc_buttonresponse == LIVES_RESPONSE_CANCEL) return;
1385 } while (!*n_file_name);
1386 lives_snprintf(mainw->vid_save_dir, PATH_MAX, "%s", n_file_name);
1387 get_dirname(mainw->vid_save_dir);
1388 if (prefs->save_directories) {
1389 set_utf8_pref(PREF_VID_SAVE_DIR, mainw->vid_save_dir);
1390 }
1391 lives_free(ttl);
1392 } else n_file_name = lives_strdup(filename);
1393
1394 //append default extension (if necessary)
1395 if (!*prefs->encoder.of_def_ext) {
1396 // encoder adds its own extension
1397 get_filename(n_file_name, FALSE);
1398 } else {
1399 if (mainw->fx1_bool && (strlen(n_file_name) <= strlen(prefs->encoder.of_def_ext) ||
1400 strncmp(n_file_name + strlen(n_file_name) - strlen(prefs->encoder.of_def_ext) - 1, ".", 1) ||
1401 strcmp(n_file_name + strlen(n_file_name) - strlen(prefs->encoder.of_def_ext),
1402 prefs->encoder.of_def_ext))) {
1403 full_file_name = lives_strconcat(n_file_name, ".", prefs->encoder.of_def_ext, NULL);
1404 recheck_name = TRUE;
1405 }
1406 }
1407
1408 if (!full_file_name) {
1409 full_file_name = lives_strdup(n_file_name);
1410 }
1411
1412 if (!filename && recheck_name) {
1413 if (!check_file(full_file_name, strcmp(full_file_name, n_file_name))) {
1414 lives_free(full_file_name);
1415 lives_free(n_file_name);
1416 if (rdet) {
1417 lives_widget_destroy(rdet->dialog);
1418 lives_free(rdet->encoder_name);
1419 lives_freep((void **)&rdet);
1420 lives_freep((void **)&resaudw);
1421 }
1422 return;
1423 }
1424 sfile->orig_file_name = FALSE;
1425 }
1426
1427 if (!*sfile->comment) set_default_comment(sfile, NULL);
1428
1429 if (!do_comments_dialog(clip, full_file_name)) {
1430 lives_free(full_file_name);
1431 if (rdet) {
1432 lives_widget_destroy(rdet->dialog);
1433 lives_free(rdet->encoder_name);
1434 lives_freep((void **)&rdet);
1435 lives_freep((void **)&resaudw);
1436 }
1437 lives_freep((void **)&mainw->subt_save_file);
1438 return;
1439 }
1440
1441 if (rdet) {
1442 lives_widget_destroy(rdet->dialog);
1443 lives_freep((void **)&rdet->encoder_name);
1444 lives_freep((void **)&rdet);
1445 lives_freep((void **)&resaudw);
1446 }
1447
1448 if (sfile->arate * sfile->achans != 0) {
1449 aud_start = calc_time_from_frame(clip, start) * sfile->arps / sfile->arate;
1450 aud_end = calc_time_from_frame(clip, end + 1) * sfile->arps / sfile->arate;
1451 }
1452
1453 // get extra params for encoder
1454
1455 if (!sfile->ratio_fps) {
1456 fps_string = lives_strdup_printf("%.3f", sfile->fps);
1457 } else {
1458 fps_string = lives_strdup_printf("%.8f", sfile->fps);
1459 }
1460
1461 arate = sfile->arate;
1462
1463 if (!mainw->save_with_sound || prefs->encoder.of_allowed_acodecs == 0) {
1464 arate = 0;
1465 }
1466
1467 /// get extra parameters for saving
1468 if (prefs->encoder.capabilities & HAS_RFX) {
1469 char buff[65536];
1470
1471 com = lives_strdup_printf("\"%s\" get_rfx %s %d %d %d", enc_exec_name, prefs->encoder.of_name,
1472 prefs->encoder.audio_codec, cfile->hsize, cfile->vsize);
1473 if (debug_mode) {
1474 fprintf(stderr, "Running command: %s\n", com);
1475 }
1476 lives_popen(com, TRUE, buff, 65536);
1477 lives_free(com);
1478
1479 if (!THREADVAR(com_failed)) {
1480 extra_params = plugin_run_param_window(buff, NULL, NULL);
1481 }
1482 if (!extra_params) {
1483 lives_free(fps_string);
1484 if (!mainw->multitrack) {
1485 switch_to_file(mainw->current_file, current_file);
1486 }
1487 lives_freep((void **)&mainw->subt_save_file);
1488 return;
1489 }
1490 }
1491
1492 if (!save_all && !safe_symlinks) {
1493 // we are saving a selection - make symlinks from a temporary clip
1494
1495 if ((new_file = mainw->first_free_file) == ALL_USED) {
1496 too_many_files();
1497 lives_freep((void **)&mainw->subt_save_file);
1498 return;
1499 }
1500
1501 // create new clip
1502 if (!get_new_handle(new_file, (_("selection")))) {
1503 lives_freep((void **)&mainw->subt_save_file);
1504 return;
1505 }
1506
1507 if (sfile->clip_type == CLIP_TYPE_FILE) {
1508 mainw->cancelled = CANCEL_NONE;
1509 cfile->progress_start = 1;
1510 cfile->progress_end = count_virtual_frames(sfile->frame_index, start, end);
1511 do_threaded_dialog(_("Pulling frames from clip..."), TRUE);
1512 res = virtual_to_images(clip, start, end, TRUE, NULL);
1513 end_threaded_dialog();
1514
1515 if (mainw->cancelled != CANCEL_NONE || res < 0) {
1516 mainw->cancelled = CANCEL_USER;
1517 lives_freep((void **)&mainw->subt_save_file);
1518 if (res <= 0) d_print_file_error_failed();
1519 return;
1520 }
1521 }
1522
1523 mainw->effects_paused = FALSE;
1524
1525 nfile = mainw->files[new_file];
1526 nfile->hsize = sfile->hsize;
1527 nfile->vsize = sfile->vsize;
1528 cfile->progress_start = nfile->start = 1;
1529 cfile->progress_end = nfile->frames = nfile->end = end - start + 1;
1530 nfile->fps = sfile->fps;
1531 nfile->arps = sfile->arps;
1532 nfile->arate = sfile->arate;
1533 nfile->achans = sfile->achans;
1534 nfile->asampsize = sfile->asampsize;
1535 nfile->signed_endian = sfile->signed_endian;
1536 nfile->img_type = sfile->img_type;
1537
1538 com = lives_strdup_printf("%s link_frames \"%s\" %d %d %.8f %.8f %d %d %d %d %d \"%s\"", prefs->backend, nfile->handle,
1539 start, end, aud_start, aud_end, nfile->arate, nfile->achans, nfile->asampsize,
1540 !(nfile->signed_endian & AFORM_UNSIGNED), !(nfile->signed_endian & AFORM_BIG_ENDIAN),
1541 sfile->handle);
1542
1543 lives_rm(nfile->info_file);
1544 lives_system(com, FALSE);
1545 lives_free(com);
1546
1547 // TODO - eliminate this
1548 mainw->current_file = new_file;
1549
1550 if (THREADVAR(com_failed)) {
1551 char *permitname = lives_build_filename(prefs->workdir, cfile->handle, TEMPFILE_MARKER "." LIVES_FILE_EXT_TMP, NULL);
1552 #ifdef IS_MINGW
1553 // kill any active processes: for other OSes the backend does this
1554 lives_kill_subprocesses(cfile->handle, TRUE);
1555 #endif
1556 lives_touch(permitname);
1557 lives_free(permitname);
1558 lives_system(lives_strdup_printf("%s close \"%s\"", prefs->backend, cfile->handle), TRUE);
1559 lives_freep((void **)&cfile);
1560 if (mainw->first_free_file == ALL_USED || mainw->first_free_file > new_file)
1561 mainw->first_free_file = new_file;
1562 if (!mainw->multitrack) {
1563 switch_to_file(mainw->current_file, current_file);
1564 }
1565 d_print_cancelled();
1566 lives_freep((void **)&mainw->subt_save_file);
1567 return;
1568 }
1569
1570 cfile->nopreview = TRUE;
1571 if (!(do_progress_dialog(TRUE, TRUE, _("Linking selection")))) {
1572 char *permitname = lives_build_filename(prefs->workdir, cfile->handle, TEMPFILE_MARKER "." LIVES_FILE_EXT_TMP, NULL);
1573 #ifdef IS_MINGW
1574 // kill any active processes: for other OSes the backend does this
1575 lives_kill_subprocesses(cfile->handle, TRUE);
1576 #endif
1577 lives_touch(permitname);
1578 lives_free(permitname);
1579 lives_system((tmp = lives_strdup_printf("%s close \"%s\"", prefs->backend, cfile->handle)), TRUE);
1580 lives_free(tmp);
1581 lives_freep((void **)&cfile);
1582 if (mainw->first_free_file == ALL_USED || mainw->first_free_file > new_file)
1583 mainw->first_free_file = new_file;
1584
1585 if (!mainw->multitrack) {
1586 switch_to_file(mainw->current_file, current_file);
1587 }
1588 if (mainw->error) d_print_failed();
1589 else d_print_cancelled();
1590 lives_freep((void **)&mainw->subt_save_file);
1591 return;
1592 }
1593
1594 // cfile->arate, etc., would have been reset by calls to do_progress_dialog() which calls get_total_time() [since cfile->afilesize==0]
1595 // so we need to set these again now that link_frames has provided an actual audio clip
1596
1597 nfile->arps = sfile->arps;
1598 nfile->arate = sfile->arate;
1599 nfile->achans = sfile->achans;
1600 nfile->asampsize = sfile->asampsize;
1601 nfile->signed_endian = sfile->signed_endian;
1602
1603 reget_afilesize(new_file);
1604
1605 aud_start = calc_time_from_frame(new_file, 1) * nfile->arps / nfile->arate;
1606 aud_end = calc_time_from_frame(new_file, nfile->frames + 1) * nfile->arps / nfile->arate;
1607 cfile->nopreview = FALSE;
1608 } else mainw->current_file = clip; // for encoder restns
1609
1610 if (rdet) rdet->is_encoding = TRUE;
1611
1612 if (!check_encoder_restrictions(FALSE, FALSE, save_all)) {
1613 if (!save_all && !safe_symlinks) {
1614 char *permitname = lives_build_filename(prefs->workdir, nfile->handle, TEMPFILE_MARKER "." LIVES_FILE_EXT_TMP, NULL);
1615 #ifdef IS_MINGW
1616 lives_kill_subprocesses(nfile->handle, TRUE);
1617 #endif
1618 lives_touch(permitname);
1619 lives_free(permitname);
1620 lives_system((com = lives_strdup_printf("%s close \"%s\"", prefs->backend, nfile->handle)), TRUE);
1621 lives_free(com);
1622 lives_free(nfile);
1623 mainw->files[new_file] = NULL;
1624 if (mainw->first_free_file == ALL_USED || new_file) mainw->first_free_file = new_file;
1625 }
1626 if (!mainw->multitrack) {
1627 switch_to_file(mainw->current_file, current_file);
1628 }
1629 d_print_cancelled();
1630 lives_freep((void **)&mainw->subt_save_file);
1631 return;
1632 }
1633
1634 if (!save_all && safe_symlinks) {
1635 int xarps, xarate, xachans, xasamps, xasigned_endian;
1636 // we are saving a selection - make symlinks in /tmp
1637
1638 startframe = -1;
1639
1640 if (sfile->clip_type == CLIP_TYPE_FILE) {
1641 mainw->cancelled = CANCEL_NONE;
1642 cfile->progress_start = 1;
1643 cfile->progress_end = count_virtual_frames(sfile->frame_index, start, end);
1644 do_threaded_dialog(_("Pulling frames from clip..."), TRUE);
1645 res = virtual_to_images(clip, start, end, TRUE, NULL);
1646 end_threaded_dialog();
1647
1648 if (mainw->cancelled != CANCEL_NONE || res <= 0) {
1649 if (mainw->cancelled != CANCEL_NONE) mainw->cancelled = CANCEL_USER;
1650 lives_freep((void **)&mainw->subt_save_file);
1651 if (res <= 0) d_print_file_error_failed();
1652 return;
1653 }
1654 }
1655
1656 com = lives_strdup_printf("%s link_frames \"%s\" %d %d %.8f %.8f %d %d %d %d %d", prefs->backend, sfile->handle,
1657 start, end, aud_start, aud_end, sfile->arate, sfile->achans, sfile->asampsize,
1658 !(sfile->signed_endian & AFORM_UNSIGNED), !(sfile->signed_endian & AFORM_BIG_ENDIAN));
1659
1660 lives_rm(sfile->info_file);
1661 lives_system(com, FALSE);
1662 lives_free(com);
1663
1664 mainw->current_file = clip;
1665
1666 xarps = sfile->arps;
1667 xarate = sfile->arate;
1668 xachans = sfile->achans;
1669 xasamps = sfile->asampsize;
1670 xasigned_endian = sfile->signed_endian;
1671
1672 if (THREADVAR(com_failed)) {
1673 com = lives_strdup_printf("%s clear_symlinks \"%s\"", prefs->backend_sync, cfile->handle);
1674 lives_system(com, TRUE);
1675 lives_free(com);
1676 cfile->nopreview = FALSE;
1677 if (!mainw->multitrack) {
1678 switch_to_file(mainw->current_file, current_file);
1679 }
1680 d_print_cancelled();
1681 lives_freep((void **)&mainw->subt_save_file);
1682 return;
1683 }
1684
1685 cfile->nopreview = TRUE;
1686 if (!(do_progress_dialog(TRUE, TRUE, _("Linking selection")))) {
1687 com = lives_strdup_printf("%s clear_symlinks \"%s\"", prefs->backend_sync, cfile->handle);
1688 lives_system(com, TRUE);
1689 lives_free(com);
1690 cfile->nopreview = FALSE;
1691 if (!mainw->multitrack) {
1692 switch_to_file(mainw->current_file, current_file);
1693 }
1694 if (mainw->error) d_print_failed();
1695 else d_print_cancelled();
1696 lives_freep((void **)&mainw->subt_save_file);
1697 return;
1698 }
1699
1700 // cfile->arate, etc., would have been reset by calls to do_progress_dialog() which calls get_total_time() [since cfile->afilesize==0]
1701 // so we need to set these again now that link_frames has provided an actual audio clip
1702
1703 sfile->arps = xarps;
1704 sfile->arate = xarate;
1705 sfile->achans = xachans;
1706 sfile->asampsize = xasamps;
1707 sfile->signed_endian = xasigned_endian;
1708
1709 reget_afilesize(clip);
1710
1711 aud_start = calc_time_from_frame(clip, 1) * sfile->arps / sfile->arate;
1712 aud_end = calc_time_from_frame(clip, end - start + 1) * sfile->arps / sfile->arate;
1713 cfile->nopreview = FALSE;
1714 }
1715
1716 if (save_all) {
1717 if (sfile->clip_type == CLIP_TYPE_FILE) {
1718 frames_t ret;
1719 char *msg = (_("Pulling frames from clip..."));
1720 if ((ret = realize_all_frames(clip, msg, FALSE)) < sfile->frames) {
1721 lives_free(msg);
1722 lives_freep((void **)&mainw->subt_save_file);
1723 if (ret > 0) d_print_cancelled();
1724 if (!mainw->multitrack) {
1725 switch_to_file(mainw->current_file, current_file);
1726 }
1727 return;
1728 }
1729 lives_free(msg);
1730 }
1731 }
1732
1733 if (!mainw->save_with_sound || prefs->encoder.of_allowed_acodecs == 0) {
1734 bit = (_(" (with no sound)\n"));
1735 } else {
1736 bit = lives_strdup("\n");
1737 }
1738
1739 if (!save_all) {
1740 mesg = lives_strdup_printf(_("Saving frames %d to %d%s as \"%s\" : encoder = %s : format = %s..."),
1741 start, end, bit, full_file_name, prefs->encoder.name, prefs->encoder.of_desc);
1742 } // end selection
1743 else {
1744 mesg = lives_strdup_printf(_("Saving frames 1 to %d%s as \"%s\" : encoder %s : format = %s..."),
1745 sfile->frames, bit, full_file_name, prefs->encoder.name, prefs->encoder.of_desc);
1746 }
1747 lives_free(bit);
1748
1749 mainw->no_switch_dprint = TRUE;
1750 d_print(mesg);
1751 mainw->no_switch_dprint = FALSE;
1752 lives_free(mesg);
1753
1754 if (prefs->show_gui && !debug_mode) {
1755 // open a file for stderr
1756 new_stderr_name = lives_build_filename(prefs->workdir, cfile->handle, LIVES_ENC_DEBUG_FILE_NAME, NULL);
1757 lives_free(redir);
1758
1759 do {
1760 retval = 0;
1761 new_stderr = lives_open3(new_stderr_name, O_CREAT | O_RDONLY | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR);
1762 if (new_stderr < 0) {
1763 retval = do_write_failed_error_s_with_retry(new_stderr_name, lives_strerror(errno));
1764 if (retval == LIVES_RESPONSE_CANCEL) redir = lives_strdup("1>&2");
1765 } else {
1766
1767 #ifdef IS_MINGW
1768
1769 #ifdef GUI_GTK
1770 mainw->iochan = g_io_channel_win32_new_fd(new_stderr);
1771 #endif
1772 redir = lives_strdup_printf("2>&1 >\"%s\"", new_stderr_name);
1773 #else
1774 #ifdef GUI_GTK
1775 mainw->iochan = g_io_channel_unix_new(new_stderr);
1776 #endif
1777 redir = lives_strdup_printf("2>\"%s\"", new_stderr_name);
1778 #endif
1779
1780 #ifdef GUI_QT
1781 mainw->iochan = new QFile;
1782 mainw->iochan->open(new_stderr, QIODevice::ReadOnly);
1783 #endif
1784
1785 #ifdef GUI_GTK
1786 g_io_channel_set_encoding(mainw->iochan, NULL, NULL);
1787 g_io_channel_set_buffer_size(mainw->iochan, 0);
1788 g_io_channel_set_flags(mainw->iochan, G_IO_FLAG_NONBLOCK, &gerr);
1789 if (gerr) lives_error_free(gerr);
1790 gerr = NULL;
1791 #endif
1792 mainw->optextview = create_output_textview();
1793 }
1794 } while (retval == LIVES_RESPONSE_RETRY);
1795 } else {
1796 lives_free(redir);
1797 redir = lives_strdup("1>&2");
1798 }
1799
1800 if (lives_file_test((tmp = lives_filename_from_utf8(full_file_name, -1, NULL, NULL, NULL)), LIVES_FILE_TEST_EXISTS)) {
1801 lives_rm(tmp);
1802 }
1803 lives_free(tmp);
1804
1805 /// re-read values in case they were resampled
1806
1807 if (arate != 0) arate = cfile->arate;
1808
1809 if (!cfile->ratio_fps) {
1810 fps_string = lives_strdup_printf("%.3f", cfile->fps);
1811 } else {
1812 fps_string = lives_strdup_printf("%.8f", cfile->fps);
1813 }
1814
1815 // if startframe is -ve, we will use the links created for safe_symlinks - in /tmp
1816 // for non-safe symlinks, cfile will be our new links file
1817 // for save_all, cfile will be sfile
1818
1819 if (prefs->encoder.capabilities & ENCODER_NON_NATIVE) {
1820 com = lives_strdup_printf("%s save \"%s\" \"%s\" \"%s\" \"%s\" %d %d %d %d %d %d %.4f %.4f %s %s", prefs->backend,
1821 cfile->handle,
1822 enc_exec_name, fps_string, (tmp = lives_filename_from_utf8(full_file_name, -1, NULL, NULL, NULL)),
1823 startframe, cfile->frames, arate, cfile->achans, cfile->asampsize,
1824 asigned | aendian, aud_start, aud_end, (extra_params == NULL) ? "" : extra_params, redir);
1825 } else {
1826 com = lives_strdup_printf("%s save \"%s\" \"native:%s\" \"%s\" \"%s\" %d %d %d %d %d %d %.4f %.4f %s %s", prefs->backend,
1827 cfile->handle,
1828 enc_exec_name, fps_string, (tmp = lives_filename_from_utf8(full_file_name, -1, NULL, NULL, NULL)),
1829 startframe, cfile->frames, arate, cfile->achans, cfile->asampsize,
1830 asigned | aendian, aud_start, aud_end, (extra_params == NULL) ? "" : extra_params, redir);
1831
1832 }
1833 lives_free(tmp);
1834 lives_free(fps_string);
1835
1836 lives_freep((void **)&extra_params);
1837
1838 mainw->effects_paused = FALSE;
1839 cfile->nokeep = TRUE;
1840
1841 lives_rm(cfile->info_file);
1842 THREADVAR(write_failed) = FALSE;
1843 save_file_comments(current_file);
1844
1845 if (debug_mode) {
1846 fprintf(stderr, "Running command: %s\n", com);
1847 }
1848
1849 lives_system(com, FALSE);
1850 lives_free(com);
1851 mainw->error = FALSE;
1852
1853 if (THREADVAR(com_failed) || THREADVAR(write_failed)) {
1854 mainw->error = TRUE;
1855 }
1856
1857 if (!mainw->error) {
1858 //char *pluginstr;
1859
1860 cfile->progress_start = 1;
1861 cfile->progress_end = cfile->frames;
1862
1863 not_cancelled = do_progress_dialog(TRUE, TRUE, _("Saving [can take a long time]"));
1864
1865 if (mainw->iochan) {
1866 /// flush last of stdout/stderr from plugin
1867
1868 lives_fsync(new_stderr);
1869 pump_io_chan(mainw->iochan);
1870
1871 #ifdef GUI_GTK
1872 g_io_channel_shutdown(mainw->iochan, FALSE, &gerr);
1873 g_io_channel_unref(mainw->iochan);
1874 if (gerr) lives_error_free(gerr);
1875 #endif
1876 #ifdef GUI_QT
1877 delete mainw->iochan;
1878 #endif
1879 mainw->iochan = NULL;
1880
1881 close(new_stderr);
1882 lives_rm(new_stderr_name);
1883 lives_free(new_stderr_name);
1884 lives_free(redir);
1885 }
1886
1887 mainw->effects_paused = FALSE;
1888 cfile->nokeep = FALSE;
1889 } else {
1890 if (mainw->iochan) {
1891 /// flush last of stdout/stderr from plugin
1892
1893 lives_fsync(new_stderr);
1894 pump_io_chan(mainw->iochan);
1895
1896 #ifdef GUI_GTK
1897 g_io_channel_shutdown(mainw->iochan, FALSE, &gerr);
1898 g_io_channel_unref(mainw->iochan);
1899 if (gerr) lives_error_free(gerr);
1900 #endif
1901 #ifdef GUI_QT
1902 delete mainw->iochan;
1903 #endif
1904 mainw->iochan = NULL;
1905 close(new_stderr);
1906 lives_rm(new_stderr_name);
1907 lives_free(new_stderr_name);
1908 lives_free(redir);
1909 }
1910 }
1911
1912 cwd = lives_get_current_dir();
1913
1914 clipdir = lives_build_path(prefs->workdir, cfile->handle, NULL);
1915 lives_chdir(clipdir, FALSE);
1916 lives_free(clipdir);
1917
1918 com = lives_strdup_printf("\"%s\" clear", enc_exec_name);
1919
1920 if (debug_mode) {
1921 fprintf(stderr, "Running command: %s\n", com);
1922 }
1923 lives_system(com, FALSE);
1924 lives_free(com);
1925
1926 lives_chdir(cwd, FALSE);
1927 lives_free(cwd);
1928
1929 lives_free(enc_exec_name);
1930
1931 if (not_cancelled || mainw->error) {
1932 if (mainw->error) {
1933 mainw->no_switch_dprint = TRUE;
1934 d_print_failed();
1935 mainw->no_switch_dprint = FALSE;
1936 lives_free(full_file_name);
1937 if (!save_all && !safe_symlinks) {
1938 char *permitname = lives_build_filename(prefs->workdir, cfile->handle, TEMPFILE_MARKER "." LIVES_FILE_EXT_TMP, NULL);
1939 lives_kill_subprocesses(cfile->handle, TRUE);
1940 lives_touch(permitname);
1941 lives_free(permitname);
1942 lives_system((com = lives_strdup_printf("%s close \"%s\"", prefs->backend, cfile->handle)), TRUE);
1943 lives_free(com);
1944 lives_freep((void **)&cfile);
1945 if (mainw->first_free_file == ALL_USED || mainw->first_free_file > mainw->current_file)
1946 mainw->first_free_file = mainw->current_file;
1947 } else if (!save_all && safe_symlinks) {
1948 com = lives_strdup_printf("%s clear_symlinks \"%s\"", prefs->backend_sync, cfile->handle);
1949 lives_system(com, TRUE);
1950 lives_free(com);
1951 }
1952
1953 switch_to_file(mainw->current_file, current_file);
1954
1955 lives_freep((void **)&mainw->subt_save_file);
1956 sensitize();
1957 return;
1958 }
1959
1960 if (lives_file_test((tmp = lives_filename_from_utf8(full_file_name, -1, NULL, NULL, NULL)), LIVES_FILE_TEST_EXISTS)) {
1961 lives_free(tmp);
1962 stat((tmp = lives_filename_from_utf8(full_file_name, -1, NULL, NULL, NULL)), &filestat);
1963 if (filestat.st_size > 0) output_exists = TRUE;
1964 }
1965 if (!output_exists) {
1966 lives_free(tmp);
1967
1968 mainw->no_switch_dprint = TRUE;
1969 d_print_failed();
1970 mainw->no_switch_dprint = FALSE;
1971 lives_free(full_file_name);
1972 if (!save_all && !safe_symlinks) {
1973 char *permitname = lives_build_filename(prefs->workdir, cfile->handle, TEMPFILE_MARKER "." LIVES_FILE_EXT_TMP, NULL);
1974 lives_kill_subprocesses(cfile->handle, TRUE);
1975 lives_touch(permitname);
1976 lives_free(permitname);
1977 lives_system((com = lives_strdup_printf("%s close \"%s\"", prefs->backend, cfile->handle)), TRUE);
1978 lives_free(com);
1979 lives_freep((void **)&cfile);
1980 if (mainw->first_free_file == ALL_USED || mainw->first_free_file > mainw->current_file)
1981 mainw->first_free_file = mainw->current_file;
1982 } else if (!save_all && safe_symlinks) {
1983 com = lives_strdup_printf("%s clear_symlinks \"%s\"", prefs->backend_sync, cfile->handle);
1984 lives_system(com, TRUE);
1985 lives_free(com);
1986 }
1987
1988 if (!mainw->multitrack) {
1989 switch_to_file(mainw->current_file, current_file);
1990 }
1991 retval = do_error_dialog(_("\n\nEncoder error - output file was not created !\n"));
1992
1993 if (retval == LIVES_RESPONSE_SHOW_DETAILS) {
1994 /// show iochan (encoder) details
1995 on_details_button_clicked();
1996 }
1997
1998 if (mainw->iochan) {
1999 save_log_file("failed_encoder_log");
2000 mainw->iochan = NULL;
2001 lives_widget_object_unref(mainw->optextview);
2002 }
2003
2004 lives_freep((void **)&mainw->subt_save_file);
2005 sensitize();
2006 if (mainw->error) d_print_failed();
2007
2008 return;
2009 }
2010 lives_free(tmp);
2011
2012 if (save_all) {
2013 if (prefs->enc_letterbox) {
2014 /// replace letterboxed frames with maxspect frames
2015 int iwidth = sfile->ohsize;
2016 int iheight = sfile->ovsize;
2017 boolean bad_header = FALSE;
2018
2019 com = lives_strdup_printf("%s mv_mgk \"%s\" %d %d \"%s\" 1", prefs->backend, sfile->handle, 1, sfile->frames,
2020 get_image_ext_for_type(sfile->img_type));
2021
2022 lives_rm(sfile->info_file);
2023 lives_system(com, FALSE);
2024
2025 do_progress_dialog(TRUE, FALSE, _("Clearing letterbox"));
2026
2027 if (mainw->error) {
2028 // cfile->may_be_damaged=TRUE;
2029 d_print_failed();
2030 return;
2031 }
2032
2033 calc_maxspect(sfile->hsize, sfile->vsize, &iwidth, &iheight);
2034
2035 sfile->hsize = iwidth;
2036 sfile->vsize = iheight;
2037
2038 save_clip_value(clip, CLIP_DETAILS_WIDTH, &sfile->hsize);
2039 if (THREADVAR(com_failed) || THREADVAR(write_failed)) bad_header = TRUE;
2040 save_clip_value(clip, CLIP_DETAILS_HEIGHT, &sfile->vsize);
2041 if (THREADVAR(com_failed) || THREADVAR(write_failed)) bad_header = TRUE;
2042 if (bad_header) do_header_write_error(mainw->current_file);
2043 }
2044
2045 lives_snprintf(sfile->save_file_name, PATH_MAX, "%s", full_file_name);
2046 sfile->changed = FALSE;
2047
2048 /// save was successful
2049 /// TODO - check for size < 0 !!!
2050 fsize = sget_file_size(full_file_name);
2051 if (fsize < 0) fsize = 0;
2052 cfile->f_size = (size_t)fsize;
2053
2054 if (sfile->is_untitled) {
2055 sfile->is_untitled = FALSE;
2056 }
2057 if (!sfile->was_renamed) {
2058 lives_menu_item_set_text(sfile->menuentry, full_file_name, FALSE);
2059 lives_snprintf(sfile->name, CLIP_NAME_MAXLEN, "%s", full_file_name);
2060 }
2061 set_main_title(cfile->name, 0);
2062 if (prefs->show_recent) {
2063 add_to_recent(full_file_name, 0., 0, NULL);
2064 global_recent_manager_add(full_file_name);
2065 }
2066 } else {
2067 if (!safe_symlinks) {
2068 char *permitname = lives_build_filename(prefs->workdir, nfile->handle, TEMPFILE_MARKER "." LIVES_FILE_EXT_TMP, NULL);
2069 #ifdef IS_MINGW
2070 lives_kill_subprocesses(nfile->handle, TRUE);
2071 #endif
2072 lives_touch(permitname);
2073 lives_free(permitname);
2074 lives_system((com = lives_strdup_printf("%s close \"%s\"", prefs->backend, nfile->handle)), TRUE);
2075 lives_free(com);
2076 lives_free(nfile);
2077 mainw->files[new_file] = NULL;
2078 if (mainw->first_free_file == ALL_USED || mainw->first_free_file > mainw->current_file)
2079 mainw->first_free_file = new_file;
2080 } else {
2081 com = lives_strdup_printf("%s clear_symlinks \"%s\"", prefs->backend_sync, cfile->handle);
2082 lives_system(com, TRUE);
2083 lives_free(com);
2084 }
2085 }
2086 }
2087
2088 if (!mainw->multitrack) {
2089 switch_to_file(mainw->current_file, current_file);
2090 }
2091 if (mainw->iochan) {
2092 save_log_file("encoder_log");
2093 lives_widget_object_unref(mainw->optextview);
2094 mainw->iochan = NULL;
2095 }
2096
2097 if (not_cancelled) {
2098 char *fsize_ds;
2099 mainw->no_switch_dprint = TRUE;
2100 d_print_done();
2101
2102 /// get size of file and show it
2103
2104 fsize = sget_file_size(full_file_name);
2105 if (fsize >= 0) {
2106 /// TODO - handle file errors !!!!!
2107
2108 fsize_ds = lives_format_storage_space_string(fsize);
2109 d_print(_("File size was %s\n"), fsize_ds);
2110 lives_free(fsize_ds);
2111
2112 if (mainw->subt_save_file) {
2113 save_subs_to_file(sfile, mainw->subt_save_file);
2114 lives_freep((void **)&mainw->subt_save_file);
2115 }
2116 }
2117 mainw->no_switch_dprint = FALSE;
2118
2119 lives_notify(LIVES_OSC_NOTIFY_SUCCESS,
2120 (mesg = lives_strdup_printf("encode %d \"%s\"", clip,
2121 (tmp = lives_filename_from_utf8(full_file_name, -1, NULL, NULL, NULL)))));
2122 lives_free(tmp);
2123 lives_free(mesg);
2124 } else {
2125 lives_rm((tmp = lives_filename_from_utf8(full_file_name, -1, NULL, NULL, NULL)));
2126 lives_free(tmp);
2127 }
2128
2129 lives_free(full_file_name);
2130 }
2131
2132
2133 char *prep_audio_player(char *com2, char *com3, frames_t audio_end, int arate, int asigned, int aendian) {
2134 char *stfile = NULL;
2135 char *stopcom = NULL, *com;
2136 short audio_player = prefs->audio_player;
2137 int loop = 0;
2138
2139 if (cfile->achans > 0) {
2140 cfile->aseek_pos = (off64_t)(cfile->real_pointer_time * (double)cfile->arate) * cfile->achans * (cfile->asampsize / 8);
2141 if (mainw->playing_sel) {
2142 off64_t apos = (off64_t)((double)(mainw->play_start - 1.) / cfile->fps * (double)cfile->arate) * cfile->achans *
2143 (cfile->asampsize / 8);
2144 if (apos > cfile->aseek_pos) cfile->aseek_pos = apos;
2145 }
2146 if (cfile->aseek_pos > cfile->afilesize) cfile->aseek_pos = 0.;
2147 if (mainw->current_file == 0 && cfile->arate < 0) cfile->aseek_pos = cfile->afilesize;
2148 }
2149 // start up our audio player (jack or pulse)
2150 if (audio_player == AUD_PLAYER_JACK) {
2151 #ifdef ENABLE_JACK
2152 if (mainw->jackd) jack_aud_pb_ready(mainw->current_file);
2153 return NULL;
2154 #endif
2155 } else if (audio_player == AUD_PLAYER_PULSE) {
2156 #ifdef HAVE_PULSE_AUDIO
2157 if (mainw->pulsed) pulse_aud_pb_ready(mainw->current_file);
2158 return NULL;
2159 #endif
2160 } else if (audio_player != AUD_PLAYER_NONE && cfile->achans > 0) {
2161 // sox or mplayer audio - run as background process
2162 if (com3) {
2163 if (mainw->loop_cont) {
2164 // tell audio to loop forever
2165 loop = -1;
2166 }
2167
2168 stfile = lives_build_filename(prefs->workdir, cfile->handle, ".stoploop", NULL);
2169 lives_rm(stfile);
2170
2171 if (cfile->achans > 0 || (!cfile->is_loaded && !mainw->is_generating)) {
2172 if (loop) {
2173 lives_free(com3);
2174 com3 = lives_strdup_printf("%s \"%s\" 2>\"%s\" 1>&2", capable->touch_cmd, stfile, prefs->cmd_log);
2175 }
2176
2177 if (com2) {
2178 if (cfile->achans > 0) {
2179 com2 = lives_strdup_printf("%s stop_audio %s", prefs->backend_sync, cfile->handle);
2180 }
2181 stopcom = lives_strconcat(com3, com2, NULL);
2182 }
2183 }
2184 }
2185
2186 lives_freep((void **)&stfile);
2187
2188 stfile = lives_build_filename(prefs->workdir, cfile->handle, LIVES_STATUS_FILE_NAME".play", NULL);
2189
2190 lives_snprintf(cfile->info_file, PATH_MAX, "%s", stfile);
2191 lives_free(stfile);
2192 if (cfile->clip_type == CLIP_TYPE_DISK) lives_rm(cfile->info_file);
2193
2194 // PLAY
2195
2196 if (cfile->clip_type == CLIP_TYPE_DISK && cfile->opening) {
2197 com = lives_strdup_printf("%s play_opening_preview \"%s\" %.3f %d %d %d %d %d %d %d %d", prefs->backend,
2198 cfile->handle, cfile->fps, mainw->audio_start, audio_end, 0,
2199 arate, cfile->achans, cfile->asampsize, asigned, aendian);
2200 } else {
2201 // this is only used now for sox or mplayer audio player
2202 com = lives_strdup_printf("%s play %s %.3f %d %d %d %d %d %d %d %d", prefs->backend, cfile->handle,
2203 cfile->fps, mainw->audio_start, audio_end, loop,
2204 arate, cfile->achans, cfile->asampsize, asigned, aendian);
2205 }
2206 if (!mainw->multitrack && com) lives_system(com, FALSE);
2207 }
2208 return stopcom;
2209 }
2210
2211
2212 /// play the current clip from 'mainw->play_start' to 'mainw->play_end'
2213 void play_file(void) {
2214 LiVESWidgetClosure *freeze_closure, *bg_freeze_closure;
2215 LiVESList *cliplist;
2216 weed_plant_t *pb_start_event = NULL;
2217
2218 #ifdef GDK_WINDOWING_X11
2219 uint64_t awinid = -1;
2220 #endif
2221
2222 char *com, *com2 = lives_strdup(" "), *com3 = lives_strdup(" ");
2223 char *stopcom = NULL;
2224 char *stfile;
2225 #ifdef GDK_WINDOWING_X11
2226 char *tmp;
2227 #endif
2228
2229 double fps_med = 0.;
2230 double pointer_time = cfile->pointer_time;
2231 double real_pointer_time = cfile->real_pointer_time;
2232
2233 short audio_player = prefs->audio_player;
2234
2235 boolean mute;
2236 boolean needsadone = FALSE;
2237
2238 #ifdef RT_AUDIO
2239 boolean exact_preview = FALSE;
2240 #endif
2241 boolean has_audio_buffers = FALSE;
2242
2243 int arate;
2244
2245 int asigned = !(cfile->signed_endian & AFORM_UNSIGNED);
2246 int aendian = !(cfile->signed_endian & AFORM_BIG_ENDIAN);
2247 int current_file = mainw->current_file;
2248 int audio_end = 0;
2249
2250 /// from now on we can only switch at the designated SWITCH POINT
2251 mainw->noswitch = TRUE;
2252 mainw->cancelled = CANCEL_NONE;
2253
2254 asigned = !(cfile->signed_endian & AFORM_UNSIGNED);
2255 aendian = !(cfile->signed_endian & AFORM_BIG_ENDIAN);
2256 current_file = mainw->current_file;
2257 if (mainw->pre_play_file == -1) mainw->pre_play_file = current_file;
2258
2259 if (!is_realtime_aplayer(audio_player)) mainw->aud_file_to_kill = mainw->current_file;
2260 else mainw->aud_file_to_kill = -1;
2261
2262 #ifdef ENABLE_JACK_TRANSPORT
2263 if (!mainw->preview && !mainw->foreign) {
2264 if (!mainw->multitrack)
2265 jack_pb_start(cfile->achans > 0 ? cfile->real_pointer_time : cfile->pointer_time);
2266 else
2267 jack_pb_start(mainw->multitrack->pb_start_time);
2268 }
2269 #endif
2270
2271 mainw->ext_playback = FALSE;
2272
2273 mainw->rec_aclip = -1;
2274
2275 init_conversions(LIVES_INTENTION_PLAY);
2276
2277 if (mainw->pre_src_file == -2) mainw->pre_src_file = mainw->current_file;
2278 mainw->pre_src_audio_file = mainw->current_file;
2279
2280 /// enable the freeze button
2281 lives_accel_group_connect(LIVES_ACCEL_GROUP(mainw->accel_group), LIVES_KEY_BackSpace,
2282 (LiVESXModifierType)LIVES_CONTROL_MASK,
2283 (LiVESAccelFlags)0, (freeze_closure = lives_cclosure_new(LIVES_GUI_CALLBACK(freeze_callback),
2284 LIVES_INT_TO_POINTER(SCREEN_AREA_FOREGROUND), NULL)));
2285 lives_accel_group_connect(LIVES_ACCEL_GROUP(mainw->accel_group), LIVES_KEY_BackSpace,
2286 (LiVESXModifierType)(LIVES_CONTROL_MASK | LIVES_ALT_MASK),
2287 (LiVESAccelFlags)0, (bg_freeze_closure = lives_cclosure_new(LIVES_GUI_CALLBACK(freeze_callback),
2288 LIVES_INT_TO_POINTER(SCREEN_AREA_BACKGROUND), NULL)));
2289
2290 /// disable ctrl-q since it can be activated by user error
2291 lives_accel_path_disconnect(mainw->accel_group, LIVES_ACCEL_PATH_QUIT);
2292
2293 if (mainw->multitrack) {
2294 mainw->event_list = mainw->multitrack->event_list;
2295 pb_start_event = mainw->multitrack->pb_start_event;
2296 #ifdef RT_AUDIO
2297 exact_preview = mainw->multitrack->exact_preview;
2298 #endif
2299 }
2300
2301 // reinit all active effects
2302 if (!mainw->preview && !mainw->is_rendering && !mainw->foreign) weed_reinit_all();
2303
2304 if (mainw->record) {
2305 if (mainw->preview) {
2306 mainw->record = FALSE;
2307 d_print(_("recording aborted by preview.\n"));
2308 } else if (mainw->current_file == 0) {
2309 mainw->record = FALSE;
2310 d_print(_("recording aborted by clipboard playback.\n"));
2311 } else {
2312 d_print(_("Recording performance..."));
2313 needsadone = TRUE;
2314 mainw->clip_switched = FALSE;
2315 // TODO
2316 if (mainw->current_file > 0 && (cfile->undo_action == UNDO_RESAMPLE || cfile->undo_action == UNDO_RENDER)) {
2317 lives_widget_set_sensitive(mainw->undo, FALSE);
2318 lives_widget_set_sensitive(mainw->redo, FALSE);
2319 cfile->undoable = cfile->redoable = FALSE;
2320 }
2321 }
2322 }
2323 /// set performance at right place
2324 else if (mainw->event_list) cfile->next_event = get_first_event(mainw->event_list);
2325
2326 if (!mainw->multitrack && CURRENT_CLIP_HAS_VIDEO) {
2327 lives_widget_set_frozen(mainw->spinbutton_start, TRUE);
2328 lives_widget_set_frozen(mainw->spinbutton_end, TRUE);
2329 //lives_signal_handler_block(mainw->spinbutton_start, mainw->spin_start_func);
2330 //lives_signal_handler_block(mainw->spinbutton_end, mainw->spin_end_func);
2331 }
2332
2333 #ifdef ENABLE_JACK_TRANSPORT
2334 if (mainw->jack_can_stop && !mainw->event_list && !mainw->preview
2335 && (prefs->jack_opts & (JACK_OPTS_TIMEBASE_START | JACK_OPTS_TIMEBASE_CLIENT))) {
2336 // calculate the start position from jack transport
2337 double sttime = (double)jack_transport_get_current_ticks() / TICKS_PER_SECOND_DBL;
2338 cfile->pointer_time = cfile->real_pointer_time = sttime;
2339 if (cfile->real_pointer_time > CLIP_TOTAL_TIME(mainw->current_file))
2340 cfile->real_pointer_time = CLIP_TOTAL_TIME(mainw->current_file);
2341 if (cfile->pointer_time > cfile->video_time) cfile->pointer_time = 0.;
2342 mainw->play_start = calc_frame_from_time(mainw->current_file, cfile->pointer_time);
2343 }
2344 #endif
2345
2346 /// these values are only relevant for non-realtime audio players (e.g. sox)
2347 mainw->audio_start = mainw->audio_end = 0;
2348
2349 if (cfile->achans > 0) {
2350 if (mainw->event_list &&
2351 !(mainw->preview && mainw->is_rendering) &&
2352 !(mainw->multitrack && mainw->preview && mainw->multitrack->is_rendering)) {
2353 /// play performance data
2354 if (event_list_get_end_secs(mainw->event_list) > cfile->frames / cfile->fps && !mainw->playing_sel) {
2355 mainw->audio_end = (event_list_get_end_secs(mainw->event_list) * cfile->fps + 1.) * cfile->arate / cfile->arps;
2356 }
2357 }
2358
2359 if (mainw->audio_end == 0) {
2360 mainw->audio_start = calc_time_from_frame(mainw->current_file,
2361 mainw->play_start) * cfile->fps + 1. * cfile->arate / cfile->arps;
2362 mainw->audio_end = calc_time_from_frame(mainw->current_file, mainw->play_end) * cfile->fps
2363 + 1. * cfile->arate / cfile->arps;
2364 if (!mainw->playing_sel) {
2365 mainw->audio_end = 0;
2366 }
2367 }
2368 }
2369
2370 if (!cfile->opening_audio && !mainw->loop) {
2371 /** if we are opening audio or looping we just play to the end of audio,
2372 otherwise...*/
2373 audio_end = mainw->audio_end;
2374 }
2375
2376 if (!mainw->multitrack) {
2377 if (!mainw->preview) {
2378 lives_frame_set_label(LIVES_FRAME(mainw->playframe), _("Play"));
2379 } else {
2380 lives_frame_set_label(LIVES_FRAME(mainw->playframe), _("Preview"));
2381 }
2382
2383 if (palette->style & STYLE_1) {
2384 lives_widget_set_fg_color(lives_frame_get_label_widget(LIVES_FRAME(mainw->playframe)),
2385 LIVES_WIDGET_STATE_NORMAL, &palette->normal_fore);
2386 }
2387
2388 if (mainw->foreign) {
2389 lives_widget_show_all(mainw->top_vbox);
2390 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
2391 }
2392
2393 /// blank the background if asked to
2394 if ((mainw->faded || (prefs->show_playwin && !prefs->show_gui)
2395 || (mainw->fs && (!mainw->sep_win))) && (cfile->frames > 0 ||
2396 mainw->foreign)) {
2397 fade_background();
2398 }
2399
2400 if ((!mainw->sep_win || (!mainw->faded && (prefs->sepwin_type != SEPWIN_TYPE_STICKY)))
2401 && (cfile->frames > 0 ||
2402 mainw->foreign)) {
2403 /// show the frame in the main window
2404 lives_widget_set_opacity(mainw->playframe, 1.);
2405 lives_widget_show_all(mainw->playframe);
2406 }
2407
2408 /// plug the plug into the playframe socket if we need to
2409 add_to_playframe();
2410 }
2411
2412 arate = cfile->arate;
2413
2414 mute = mainw->mute;
2415
2416 if (!is_realtime_aplayer(audio_player)) {
2417 if (cfile->achans == 0 || mainw->is_rendering) mainw->mute = TRUE;
2418 if (mainw->mute && !cfile->opening_only_audio) arate = arate ? -arate : -1;
2419 }
2420
2421 cfile->frameno = mainw->play_start;
2422 cfile->pb_fps = cfile->fps;
2423 if (mainw->reverse_pb) {
2424 cfile->pb_fps = -cfile->pb_fps;
2425 cfile->frameno = mainw->play_end;
2426 }
2427 cfile->last_frameno = cfile->frameno;
2428 mainw->reverse_pb = FALSE;
2429
2430 mainw->swapped_clip = -1;
2431 mainw->blend_palette = WEED_PALETTE_END;
2432
2433 cfile->play_paused = FALSE;
2434 mainw->period = TICKS_PER_SECOND_DBL / cfile->pb_fps;
2435
2436 if (audio_player == AUD_PLAYER_JACK
2437 || (mainw->event_list && (!mainw->is_rendering || !mainw->preview || mainw->preview_rendering)))
2438 audio_cache_init();
2439
2440 if (mainw->blend_file != -1 && !IS_VALID_CLIP(mainw->blend_file)) mainw->blend_file = -1;
2441
2442 lives_widget_set_sensitive(mainw->m_stopbutton, TRUE);
2443 mainw->playing_file = mainw->current_file;
2444
2445 if (!mainw->preview || !cfile->opening) {
2446 enable_record();
2447 desensitize();
2448 lives_widget_set_sensitive(mainw->spinbutton_pb_fps, TRUE);
2449 }
2450
2451 if (mainw->record) {
2452 if (mainw->event_list) event_list_free(mainw->event_list);
2453 mainw->record_starting = TRUE;
2454 }
2455
2456 if (prefs->show_msg_area && mainw->double_size && !mainw->multitrack) {
2457 lives_widget_hide(mainw->message_box);
2458 }
2459
2460 lives_widget_set_sensitive(mainw->stop, TRUE);
2461
2462 if (!mainw->multitrack) lives_widget_set_sensitive(mainw->m_playbutton, FALSE);
2463 else if (!cfile->opening) {
2464 if (!mainw->is_processing) mt_swap_play_pause(mainw->multitrack, TRUE);
2465 else {
2466 lives_widget_set_sensitive(mainw->multitrack->playall, FALSE);
2467 lives_widget_set_sensitive(mainw->m_playbutton, FALSE);
2468 }
2469 }
2470
2471 lives_table_set_column_homogeneous(LIVES_TABLE(mainw->pf_grid), !mainw->double_size);
2472
2473 lives_widget_set_sensitive(mainw->m_playselbutton, FALSE);
2474 lives_widget_set_sensitive(mainw->m_rewindbutton, FALSE);
2475 lives_widget_set_sensitive(mainw->m_mutebutton, is_realtime_aplayer(audio_player) || mainw->multitrack);
2476
2477 lives_widget_set_sensitive(mainw->m_loopbutton, (!cfile->achans || mainw->mute || mainw->multitrack ||
2478 mainw->loop_cont || is_realtime_aplayer(audio_player))
2479 && mainw->current_file > 0);
2480 lives_widget_set_sensitive(mainw->loop_continue, (!cfile->achans || mainw->mute || mainw->loop_cont ||
2481 is_realtime_aplayer(audio_player))
2482 && mainw->current_file > 0);
2483
2484 if (cfile->frames == 0 && !mainw->multitrack) {
2485 if (mainw->preview_box && lives_widget_get_parent(mainw->preview_box)) {
2486
2487 lives_container_remove(LIVES_CONTAINER(mainw->play_window), mainw->preview_box);
2488
2489 mainw->pw_scroll_func = lives_signal_connect(LIVES_GUI_OBJECT(mainw->play_window), LIVES_WIDGET_SCROLL_EVENT,
2490 LIVES_GUI_CALLBACK(on_mouse_scroll), NULL);
2491 }
2492 } else {
2493 if (mainw->sep_win) {
2494 /// create a separate window for the internal player if requested
2495 if (prefs->sepwin_type == SEPWIN_TYPE_NON_STICKY) {
2496 make_play_window();
2497 } else {
2498 if (!mainw->multitrack) {
2499 if (mainw->preview_controls) {
2500 lives_widget_hide(mainw->preview_controls);
2501 /* mainw->pw_scroll_func = lives_signal_connect(LIVES_GUI_OBJECT(mainw->play_window), LIVES_WIDGET_SCROLL_EVENT, */
2502 /* LIVES_GUI_CALLBACK(on_mouse_scroll), */
2503 /* NULL); */
2504 }
2505 }
2506
2507 if (!mainw->multitrack || mainw->fs) {
2508 resize_play_window();
2509 }
2510
2511 /// needed
2512 if (!mainw->multitrack) {
2513 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
2514 } else {
2515 /// this doesn't get called if we don't call resize_play_window()
2516 if (mainw->play_window) {
2517 if (prefs->show_playwin) {
2518 lives_window_present(LIVES_WINDOW(mainw->play_window));
2519 lives_xwindow_raise(lives_widget_get_xwindow(mainw->play_window));
2520 // *INDENT-OFF*
2521 }}}}}
2522 // *INDENT-ON*
2523
2524 if (mainw->play_window) {
2525 hide_cursor(lives_widget_get_xwindow(mainw->play_window));
2526 lives_widget_set_app_paintable(mainw->play_window, TRUE);
2527 play_window_set_title();
2528 }
2529
2530 if (!mainw->foreign && !mainw->sep_win) {
2531 hide_cursor(lives_widget_get_xwindow(mainw->playarea));
2532 }
2533
2534 if (!mainw->sep_win && !mainw->foreign) {
2535 if (mainw->double_size) resize(2.);
2536 else resize(1);
2537 }
2538
2539 /* if (mainw->vpp && mainw->vpp->fheight > -1 && mainw->vpp->fwidth > -1) { */
2540 /* // fixed o/p size for stream */
2541 /* if (mainw->vpp->fwidth * mainw->vpp->fheight == 0) { */
2542 /* mainw->vpp->fwidth = DEF_VPP_HSIZE; */
2543 /* mainw->vpp->fheight = DEF_VPP_VSIZE; */
2544 /* } */
2545 /* if (!(mainw->vpp->capabilities & VPP_CAN_RESIZE)) { */
2546 /* mainw->pwidth = mainw->vpp->fwidth; */
2547 /* mainw->pheight = mainw->vpp->fheight; */
2548 /* } */
2549 /* } */
2550
2551 if (mainw->fs && !mainw->sep_win && cfile->frames > 0) {
2552 fullscreen_internal();
2553 }
2554 }
2555
2556 // moved down because xdg-screensaver requires a mapped windowID
2557 if (prefs->stop_screensaver) {
2558 lives_freep((void **)&com2);
2559 #ifdef GDK_WINDOWING_X11
2560 if (!prefs->show_gui && prefs->show_playwin && mainw->play_window) {
2561 awinid = lives_widget_get_xwinid(mainw->play_window, NULL);
2562 } else if (prefs->show_gui) {
2563 awinid = lives_widget_get_xwinid(LIVES_MAIN_WINDOW_WIDGET, NULL);
2564 }
2565
2566 com2 = lives_strdup("xset s off 2>/dev/null; xset -dpms 2>/dev/null ;");
2567
2568 if (capable->has_gconftool_2) {
2569 char *xnew = lives_strdup(" gconftool-2 --set --type bool /apps/gnome-screensaver/idle_activation_enabled "
2570 "false 2>/dev/null ;");
2571 tmp = lives_concat(com2, xnew);
2572 com2 = tmp;
2573 }
2574 if (capable->has_xdg_screensaver && awinid != -1) {
2575 char *xnew = lives_strdup_printf(" xdg-screensaver suspend %"PRIu64" 2>/dev/null ;", awinid);
2576 tmp = lives_concat(com2, xnew);
2577 com2 = tmp;
2578 }
2579 #else
2580 if (capable->has_gconftool_2) {
2581 com2 = lives_strdup("gconftool-2 --set --type bool /apps/gnome-screensaver/idle_activation_enabled false 2>/dev/null ;");
2582 } else com2 = lives_strdup("");
2583 #endif
2584 if (!com2) com2 = lives_strdup("");
2585 }
2586
2587 if (!mainw->foreign && prefs->midisynch && !mainw->preview) {
2588 lives_free(com3);
2589 com3 = lives_strdup(EXEC_MIDISTART);
2590 }
2591 com = lives_strconcat(com2, com3, NULL);
2592 if (*com) {
2593 // allow this to fail - not all sub-commands may be present
2594 lives_system(com, TRUE);
2595 }
2596 lives_freep((void **)&com);
2597 lives_freep((void **)&com2);
2598 lives_free(com3);
2599 com3 = lives_strdup(" ");
2600
2601 if (!mainw->multitrack) {
2602 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_pb_fps), cfile->pb_fps);
2603
2604 mainw->last_blend_file = -1;
2605
2606 // show the framebar
2607 if (!mainw->multitrack && !mainw->faded
2608 && (!prefs->hide_framebar &&
2609 (!mainw->fs || (widget_opts.monitor + 1 != prefs->play_monitor && prefs->play_monitor != 0
2610 && capable->nmonitors > 1 &&
2611 mainw->sep_win) ||
2612 (mainw->vpp && mainw->sep_win && !(mainw->vpp->capabilities & VPP_LOCAL_DISPLAY))) &&
2613 ((!mainw->preview && (cfile->frames > 0 || mainw->foreign)) || cfile->opening))) {
2614 lives_widget_show(mainw->framebar);
2615 }
2616 }
2617
2618 cfile->play_paused = FALSE;
2619 mainw->actual_frame = 0;
2620
2621 mainw->currticks = 0;
2622 mainw->effort = -EFFORT_RANGE_MAX;
2623
2624 find_when_to_stop();
2625
2626 // reinit all active effects
2627 if (!mainw->preview && !mainw->is_rendering && !mainw->foreign) weed_reinit_all();
2628
2629 if (!mainw->foreign && (!(prefs->audio_src == AUDIO_SRC_EXT &&
2630 (audio_player == AUD_PLAYER_JACK ||
2631 audio_player == AUD_PLAYER_PULSE || audio_player == AUD_PLAYER_NONE)))) {
2632 stopcom = prep_audio_player(com2, com3, audio_end, arate, asigned, aendian);
2633 }
2634
2635 lives_free(com3);
2636
2637 // if recording, refrain from writing audio until we are ready
2638 if (mainw->record) mainw->record_paused = TRUE;
2639
2640 // if recording, set up recorder (jack or pulse)
2641 if (!mainw->preview && (prefs->audio_src == AUDIO_SRC_EXT || (mainw->record && mainw->agen_key != 0))
2642 && (audio_player == AUD_PLAYER_JACK || audio_player == AUD_PLAYER_PULSE)) {
2643 mainw->rec_samples = -1; // record unlimited
2644 if (mainw->record) {
2645 // create temp clip
2646 open_ascrap_file();
2647 if (mainw->ascrap_file != -1) {
2648 mainw->rec_aclip = mainw->ascrap_file;
2649 mainw->rec_avel = 1.;
2650 mainw->rec_aseek = 0;
2651 }
2652 }
2653 if (audio_player == AUD_PLAYER_JACK) {
2654 #ifdef ENABLE_JACK
2655 if ((prefs->audio_src == AUDIO_SRC_EXT || mainw->agen_key != 0 || mainw->agen_needs_reinit) && mainw->jackd) {
2656 if (mainw->agen_key != 0 || mainw->agen_needs_reinit) {
2657 mainw->jackd->playing_file = mainw->current_file;
2658 if (mainw->ascrap_file != -1 || !prefs->perm_audio_reader)
2659 jack_rec_audio_to_clip(mainw->ascrap_file, -1, RECA_GENERATED);
2660 } else {
2661 if (mainw->ascrap_file != -1 || !prefs->perm_audio_reader)
2662 jack_rec_audio_to_clip(mainw->ascrap_file, -1, RECA_EXTERNAL);
2663 }
2664 //mainw->jackd->in_use = TRUE;
2665 }
2666 if (prefs->audio_src == AUDIO_SRC_EXT && mainw->jackd_read) {
2667 mainw->jackd_read->num_input_channels = mainw->jackd_read->num_output_channels = 2;
2668 mainw->jackd_read->sample_in_rate = mainw->jackd_read->sample_out_rate;
2669 mainw->jackd_read->is_paused = TRUE;
2670 mainw->jackd_read->in_use = TRUE;
2671 }
2672 #endif
2673 }
2674 if (audio_player == AUD_PLAYER_PULSE) {
2675 #ifdef HAVE_PULSE_AUDIO
2676 if ((prefs->audio_src == AUDIO_SRC_EXT || mainw->agen_key != 0 || mainw->agen_needs_reinit) && mainw->pulsed) {
2677 if (mainw->agen_key != 0 || mainw->agen_needs_reinit) {
2678 mainw->pulsed->playing_file = mainw->current_file;
2679 if (mainw->ascrap_file != -1 || !prefs->perm_audio_reader)
2680 pulse_rec_audio_to_clip(mainw->ascrap_file, -1, RECA_GENERATED);
2681 } else {
2682 if (mainw->ascrap_file != -1 || !prefs->perm_audio_reader)
2683 pulse_rec_audio_to_clip(mainw->ascrap_file, -1, RECA_EXTERNAL);
2684 }
2685 //mainw->pulsed->in_use = TRUE;
2686 }
2687 if (prefs->audio_src == AUDIO_SRC_EXT && mainw->pulsed_read) {
2688 mainw->pulsed_read->in_achans = mainw->pulsed_read->out_achans = PA_ACHANS;
2689 mainw->pulsed_read->in_asamps = mainw->pulsed_read->out_asamps = PA_SAMPSIZE;
2690 mainw->pulsed_read->in_arate = mainw->pulsed_read->out_arate;
2691 mainw->pulsed_read->is_paused = TRUE;
2692 mainw->pulsed_read->in_use = TRUE;
2693 }
2694 #endif
2695 }
2696 }
2697
2698 // set in case audio lock gets actioned
2699 future_prefs->audio_opts = prefs->audio_opts;
2700
2701 if (mainw->foreign || weed_playback_gen_start()) {
2702 if (mainw->osc_auto)
2703 lives_notify(LIVES_OSC_NOTIFY_SUCCESS, "");
2704 lives_notify(LIVES_OSC_NOTIFY_PLAYBACK_STARTED, "");
2705
2706 #ifdef ENABLE_JACK
2707 if (mainw->event_list && !mainw->record && audio_player == AUD_PLAYER_JACK && mainw->jackd &&
2708 !(mainw->preview && mainw->is_processing &&
2709 !(mainw->multitrack && mainw->preview && mainw->multitrack->is_rendering))) {
2710 // if playing an event list, we switch to audio memory buffer mode
2711 if (mainw->multitrack) init_jack_audio_buffers(cfile->achans, cfile->arate, exact_preview);
2712 else init_jack_audio_buffers(DEFAULT_AUDIO_CHANS, DEFAULT_AUDIO_RATE, FALSE);
2713 has_audio_buffers = TRUE;
2714 }
2715 #endif
2716 #ifdef HAVE_PULSE_AUDIO
2717 if (mainw->event_list && !mainw->record && audio_player == AUD_PLAYER_PULSE && mainw->pulsed &&
2718 !(mainw->preview && mainw->is_processing &&
2719 !(mainw->multitrack && mainw->preview && mainw->multitrack->is_rendering))) {
2720 // if playing an event list, we switch to audio memory buffer mode
2721 if (mainw->multitrack) init_pulse_audio_buffers(cfile->achans, cfile->arate, exact_preview);
2722 else init_pulse_audio_buffers(DEFAULT_AUDIO_CHANS, DEFAULT_AUDIO_RATE, FALSE);
2723 has_audio_buffers = TRUE;
2724 }
2725 #endif
2726
2727 mainw->abufs_to_fill = 0;
2728 //lives_widget_context_update();
2729 //play until stopped or a stream finishes
2730 do {
2731 mainw->cancelled = CANCEL_NONE;
2732 mainw->play_sequence++;
2733 mainw->fps_measure = 0;
2734
2735 if (mainw->event_list && !mainw->record) {
2736 if (!pb_start_event) pb_start_event = get_first_event(mainw->event_list);
2737
2738 if (!(mainw->preview && mainw->multitrack && mainw->multitrack->is_rendering))
2739 init_track_decoders();
2740
2741 if (has_audio_buffers) {
2742 #ifdef ENABLE_JACK
2743 if (audio_player == AUD_PLAYER_JACK) {
2744 int i;
2745 mainw->write_abuf = 0;
2746
2747 // fill our audio buffers now
2748 // this will also get our effects state
2749
2750 // reset because audio sync may have set it
2751 if (mainw->multitrack) mainw->jackd->abufs[0]->arate = cfile->arate;
2752 else mainw->jackd->abufs[0]->arate = mainw->jackd->sample_out_rate;
2753 fill_abuffer_from(mainw->jackd->abufs[0], mainw->event_list, pb_start_event, exact_preview);
2754 for (i = 1; i < prefs->num_rtaudiobufs; i++) {
2755 // reset because audio sync may have set it
2756 if (mainw->multitrack) mainw->jackd->abufs[i]->arate = cfile->arate;
2757 else mainw->jackd->abufs[i]->arate = mainw->jackd->sample_out_rate;
2758 fill_abuffer_from(mainw->jackd->abufs[i], mainw->event_list, NULL, FALSE);
2759 }
2760
2761 pthread_mutex_lock(&mainw->abuf_mutex);
2762 mainw->jackd->read_abuf = 0;
2763 mainw->abufs_to_fill = 0;
2764 pthread_mutex_unlock(&mainw->abuf_mutex);
2765 if (mainw->event_list)
2766 mainw->jackd->in_use = TRUE;
2767 }
2768 #endif
2769 #ifdef HAVE_PULSE_AUDIO
2770 if (audio_player == AUD_PLAYER_PULSE) {
2771 int i;
2772 mainw->write_abuf = 0;
2773
2774 /// fill our audio buffers now
2775 /// this will also get our effects state
2776
2777 /// this is the IN rate, everything is resampled to this rate and then to output rate
2778 if (mainw->multitrack) mainw->pulsed->abufs[0]->arate = cfile->arate;
2779 else mainw->pulsed->abufs[0]->arate = mainw->pulsed->out_arate;
2780
2781 /// need to set asamps, in case padding with silence is needed
2782 mainw->pulsed->abufs[0]->out_asamps = mainw->pulsed->out_asamps;
2783
2784 fill_abuffer_from(mainw->pulsed->abufs[0], mainw->event_list, pb_start_event, exact_preview);
2785 for (i = 1; i < prefs->num_rtaudiobufs; i++) {
2786 if (mainw->multitrack) mainw->pulsed->abufs[i]->arate = cfile->arate;
2787 else mainw->pulsed->abufs[i]->arate = mainw->pulsed->out_arate;
2788 mainw->pulsed->abufs[i]->out_asamps = mainw->pulsed->out_asamps;
2789 fill_abuffer_from(mainw->pulsed->abufs[i], mainw->event_list, NULL, FALSE);
2790 }
2791
2792 pthread_mutex_lock(&mainw->abuf_mutex);
2793 mainw->pulsed->read_abuf = 0;
2794 mainw->abufs_to_fill = 0;
2795 pthread_mutex_unlock(&mainw->abuf_mutex);
2796 if (mainw->event_list) {
2797 mainw->pulsed->in_use = TRUE;
2798 }
2799 }
2800 #endif
2801 }
2802 }
2803
2804 if (!mainw->foreign && !mainw->multitrack)
2805 mainw->video_seek_ready = mainw->audio_seek_ready = FALSE;
2806 else
2807 mainw->video_seek_ready = mainw->audio_seek_ready = TRUE;
2808
2809 if (!mainw->multitrack || !mainw->multitrack->pb_start_event) {
2810 do_progress_dialog(FALSE, FALSE, NULL);
2811
2812 // reset audio buffers
2813 #ifdef ENABLE_JACK
2814 if (audio_player == AUD_PLAYER_JACK && mainw->jackd) {
2815 // must do this before deinit fx
2816 pthread_mutex_lock(&mainw->abuf_mutex);
2817 mainw->jackd->read_abuf = -1;
2818 mainw->jackd->in_use = FALSE;
2819 pthread_mutex_unlock(&mainw->abuf_mutex);
2820 }
2821 #endif
2822 #ifdef HAVE_PULSE_AUDIO
2823 if (audio_player == AUD_PLAYER_PULSE && mainw->pulsed) {
2824 // must do this before deinit fx
2825 pthread_mutex_lock(&mainw->abuf_mutex);
2826 mainw->pulsed->read_abuf = -1;
2827 mainw->pulsed->in_use = FALSE;
2828 pthread_mutex_unlock(&mainw->abuf_mutex);
2829 }
2830 #endif
2831 } else {
2832 // play from middle of mt timeline
2833 cfile->next_event = mainw->multitrack->pb_start_event;
2834
2835 if (!has_audio_buffers) {
2836 // no audio buffering
2837 // get just effects state
2838 get_audio_and_effects_state_at(mainw->multitrack->event_list, mainw->multitrack->pb_start_event, 0,
2839 LIVES_PREVIEW_TYPE_VIDEO_ONLY, mainw->multitrack->exact_preview);
2840 }
2841
2842 do_progress_dialog(FALSE, FALSE, NULL);
2843
2844 // reset audio read buffers
2845 #ifdef ENABLE_JACK
2846 if (audio_player == AUD_PLAYER_JACK && mainw->jackd) {
2847 // must do this before deinit fx
2848 pthread_mutex_lock(&mainw->abuf_mutex);
2849 mainw->jackd->read_abuf = -1;
2850 mainw->jackd->in_use = FALSE;
2851 pthread_mutex_unlock(&mainw->abuf_mutex);
2852 }
2853 #endif
2854 #ifdef HAVE_PULSE_AUDIO
2855 if (audio_player == AUD_PLAYER_PULSE && mainw->pulsed) {
2856 // must do this before deinit fx
2857 pthread_mutex_lock(&mainw->abuf_mutex);
2858 mainw->pulsed->read_abuf = -1;
2859 mainw->pulsed->in_use = FALSE;
2860 pthread_mutex_unlock(&mainw->abuf_mutex);
2861 }
2862 #endif
2863 // realtime effects off (for multitrack and event_list preview)
2864 deinit_render_effects();
2865
2866 cfile->next_event = NULL;
2867
2868 if (!(mainw->preview && mainw->multitrack && mainw->multitrack->is_rendering))
2869 free_track_decoders();
2870
2871 // multitrack loop - go back to loop start position unless external transport moved us
2872 if (mainw->scratch == SCRATCH_NONE) {
2873 mainw->multitrack->pb_start_event = mainw->multitrack->pb_loop_event;
2874 }
2875 }
2876 mainw->effort = 0;
2877 if (mainw->multitrack) pb_start_event = mainw->multitrack->pb_start_event;
2878 } while (mainw->multitrack && (mainw->loop_cont || mainw->scratch != SCRATCH_NONE) &&
2879 (mainw->cancelled == CANCEL_NONE || mainw->cancelled == CANCEL_EVENT_LIST_END));
2880 }
2881
2882 mainw->osc_block = TRUE;
2883 mainw->rte_textparm = NULL;
2884 mainw->playing_file = -1;
2885 mainw->abufs_to_fill = 0;
2886
2887 if (!mainw->foreign) {
2888 /// deinit any active real time effects
2889 if (prefs->allow_easing && !mainw->multitrack) {
2890 // any effects which were "easing out" should be deinited now
2891 deinit_easing_effects();
2892 }
2893 }
2894
2895 if (mainw->ext_playback) {
2896 #ifndef IS_MINGW
2897 vid_playback_plugin_exit();
2898 if (mainw->play_window) lives_window_unfullscreen(LIVES_WINDOW(mainw->play_window));
2899 #else
2900 if (mainw->play_window) lives_window_unfullscreen(LIVES_WINDOW(mainw->play_window));
2901 vid_playback_plugin_exit();
2902 #endif
2903 }
2904
2905 // play completed
2906 if (prefs->show_player_stats) {
2907 if (mainw->fps_measure > 0) {
2908 fps_med = (double)mainw->fps_measure / ((double)lives_get_relative_ticks(mainw->origsecs, mainw->orignsecs)
2909 / TICKS_PER_SECOND_DBL);
2910 }
2911 }
2912 mainw->video_seek_ready = mainw->audio_seek_ready = FALSE;
2913 mainw->osc_auto = 0;
2914
2915 if (mainw->loop_locked) unlock_loop_lock();
2916 if (prefs->show_msg_area) {
2917 lives_widget_set_size_request(mainw->message_box, -1, MIN_MSGBAR_HEIGHT);
2918 }
2919
2920 mainw->jack_can_stop = FALSE;
2921 if ((mainw->current_file == current_file) && CURRENT_CLIP_IS_VALID) {
2922 cfile->pointer_time = pointer_time;
2923 cfile->real_pointer_time = real_pointer_time;
2924 }
2925
2926 #ifdef ENABLE_JACK
2927 if (audio_player == AUD_PLAYER_JACK && (mainw->jackd || mainw->jackd_read)) {
2928 if (mainw->jackd_read || mainw->aud_rec_fd != -1)
2929 jack_rec_audio_end(!prefs->perm_audio_reader, TRUE);
2930
2931 if (mainw->jackd_read) {
2932 mainw->jackd_read->in_use = FALSE;
2933 }
2934
2935 // send jack transport stop
2936 if (!mainw->preview && !mainw->foreign) jack_pb_stop();
2937
2938 // tell jack client to close audio file
2939 if (mainw->jackd && mainw->jackd->playing_file > 0) {
2940 ticks_t timeout = 0;
2941 if (mainw->cancelled != CANCEL_AUDIO_ERROR) {
2942 lives_alarm_t alarm_handle = lives_alarm_set(LIVES_DEFAULT_TIMEOUT);
2943 while ((timeout = lives_alarm_check(alarm_handle)) > 0 && jack_get_msgq(mainw->jackd)) {
2944 sched_yield(); // wait for seek
2945 lives_usleep(prefs->sleep_time);
2946 }
2947 lives_alarm_clear(alarm_handle);
2948 }
2949 if (mainw->cancelled == CANCEL_AUDIO_ERROR) mainw->cancelled = CANCEL_ERROR;
2950 jack_message.command = ASERVER_CMD_FILE_CLOSE;
2951 jack_message.data = NULL;
2952 jack_message.next = NULL;
2953 mainw->jackd->msgq = &jack_message;
2954 if (timeout == 0) handle_audio_timeout();
2955 else {
2956 while (mainw->jackd->playing_file > -1) {
2957 sched_yield();
2958 lives_usleep(prefs->sleep_time);
2959 }
2960 }
2961 }
2962 } else {
2963 #endif
2964 #ifdef HAVE_PULSE_AUDIO
2965 if (audio_player == AUD_PLAYER_PULSE && (mainw->pulsed || mainw->pulsed_read)) {
2966 if (mainw->pulsed_read || mainw->aud_rec_fd != -1)
2967 pulse_rec_audio_end(!prefs->perm_audio_reader, TRUE);
2968
2969 if (mainw->pulsed_read) {
2970 mainw->pulsed_read->in_use = FALSE;
2971 pulse_driver_cork(mainw->pulsed_read);
2972 }
2973
2974 // tell pulse client to close audio file
2975 if (mainw->pulsed) {
2976 if (mainw->pulsed->playing_file > 0 || mainw->pulsed->fd > 0) {
2977 ticks_t timeout = 0;
2978 if (mainw->cancelled != CANCEL_AUDIO_ERROR) {
2979 lives_alarm_t alarm_handle = lives_alarm_set(LIVES_DEFAULT_TIMEOUT);
2980 while ((timeout = lives_alarm_check(alarm_handle)) > 0 && pulse_get_msgq(mainw->pulsed)) {
2981 sched_yield(); // wait for seek
2982 lives_usleep(prefs->sleep_time);
2983 }
2984 lives_alarm_clear(alarm_handle);
2985 }
2986 if (mainw->cancelled == CANCEL_AUDIO_ERROR) mainw->cancelled = CANCEL_ERROR;
2987 pulse_message.command = ASERVER_CMD_FILE_CLOSE;
2988 pulse_message.data = NULL;
2989 pulse_message.next = NULL;
2990 mainw->pulsed->msgq = &pulse_message;
2991 if (timeout == 0) {
2992 handle_audio_timeout();
2993 mainw->pulsed->playing_file = -1;
2994 mainw->pulsed->fd = -1;
2995 } else {
2996 while (mainw->pulsed->playing_file > -1 || mainw->pulsed->fd > 0) {
2997 sched_yield();
2998 lives_usleep(prefs->sleep_time);
2999 }
3000 pulse_driver_cork(mainw->pulsed);
3001 }
3002 } else {
3003 pulse_driver_cork(mainw->pulsed);
3004 }
3005 }
3006 } else {
3007 #endif
3008 if (!is_realtime_aplayer(audio_player) && stopcom) {
3009 // kill sound (if still playing)
3010 lives_system(stopcom, TRUE);
3011 mainw->aud_file_to_kill = -1;
3012 lives_free(stopcom);
3013 }
3014 #ifdef ENABLE_JACK
3015 }
3016 #endif
3017 #ifdef HAVE_PULSE_AUDIO
3018 }
3019 #endif
3020
3021 lives_freep((void **)&com);
3022 lives_freep((void **)&mainw->urgency_msg);
3023 mainw->actual_frame = 0;
3024
3025 lives_notify(LIVES_OSC_NOTIFY_PLAYBACK_STOPPED, "");
3026
3027 if (mainw->new_clip != -1) {
3028 mainw->current_file = mainw->new_clip;
3029 mainw->new_clip = -1;
3030 }
3031
3032 // stop the audio players
3033 #ifdef ENABLE_JACK
3034 if (audio_player == AUD_PLAYER_JACK && mainw->jackd) {
3035 mainw->jackd->in_use = FALSE;
3036 }
3037 #endif
3038 #ifdef HAVE_PULSE_AUDIO
3039 if (audio_player == AUD_PLAYER_PULSE && mainw->pulsed) {
3040 mainw->pulsed->in_use = FALSE;
3041 }
3042 #endif
3043
3044 /// stop the players before the cache thread, else the players may try to play from a non-existent file
3045 if (audio_player == AUD_PLAYER_JACK
3046 || (mainw->event_list && !mainw->record && (!mainw->is_rendering
3047 || !mainw->preview || mainw->preview_rendering)))
3048 audio_cache_end();
3049
3050 // terminate autolives if running
3051 lives_check_menu_item_set_active(LIVES_CHECK_MENU_ITEM(mainw->autolives), FALSE);
3052
3053 // PLAY FINISHED...
3054
3055 // allow this to fail - not all sub-commands may be present
3056 if (prefs->stop_screensaver) {
3057 #ifdef GDK_WINDOWING_X11
3058 com = lives_strdup("xset s on 2>/dev/null; xset +dpms 2>/dev/null ;");
3059
3060 if (capable->has_gconftool_2) {
3061 char *xnew = lives_strdup(" gconftool-2 --set --type bool /apps/gnome-screensaver/idle_activation_enabled "
3062 "true 2>/dev/null ;");
3063 tmp = lives_strconcat(com, xnew, NULL);
3064 lives_free(com);
3065 lives_free(xnew);
3066 com = tmp;
3067 }
3068 if (capable->has_xdg_screensaver && awinid != -1) {
3069 char *xnew = lives_strdup_printf(" xdg-screensaver resume %"PRIu64" 2>/dev/null ;", awinid);
3070 tmp = lives_strconcat(com, xnew, NULL);
3071 lives_free(com);
3072 lives_free(xnew);
3073 com = tmp;
3074 }
3075 #else
3076 if (capable->has_gconftool_2) {
3077 com = lives_strdup("gconftool-2 --set --type bool /apps/gnome-screensaver/idle_activation_enabled true 2>/dev/null ;");
3078 } else com = lives_strdup("");
3079 #endif
3080
3081 if (com) {
3082 lives_system(com, TRUE);
3083 lives_free(com);
3084 }
3085 }
3086
3087 if (!mainw->multitrack && mainw->ext_audio_mon)
3088 lives_toggle_tool_button_set_active(LIVES_TOGGLE_TOOL_BUTTON(mainw->ext_audio_mon), FALSE);
3089
3090 // reset in case audio lock was actioned
3091 prefs->audio_opts = future_prefs->audio_opts;
3092
3093 // TODO ***: use MIDI output port for this
3094 if (!mainw->foreign && prefs->midisynch) lives_system(EXEC_MIDISTOP, TRUE);
3095
3096 // we could have started by playing a generator, which could've been closed
3097 if (!mainw->files[current_file]) current_file = mainw->current_file;
3098
3099 if (!is_realtime_aplayer(audio_player)) {
3100 // wait for audio_ended...
3101 if (cfile->achans > 0 && com2) {
3102 wait_for_stop(com2);
3103 mainw->aud_file_to_kill = -1;
3104 }
3105 lives_freep((void **)&com2);
3106 }
3107
3108 if (CURRENT_CLIP_IS_NORMAL) {
3109 cfile->last_play_sequence = mainw->play_sequence;
3110 stfile = lives_build_filename(prefs->workdir, cfile->handle, LIVES_STATUS_FILE_NAME, NULL);
3111 lives_snprintf(cfile->info_file, PATH_MAX, "%s", stfile);
3112 lives_free(stfile);
3113 }
3114
3115 if (IS_VALID_CLIP(mainw->scrap_file) && mainw->files[mainw->scrap_file]->ext_src) {
3116 lives_close_buffered(LIVES_POINTER_TO_INT(mainw->files[mainw->scrap_file]->ext_src));
3117 mainw->files[mainw->scrap_file]->ext_src = NULL;
3118 mainw->files[mainw->scrap_file]->ext_src_type = LIVES_EXT_SRC_NONE;
3119 }
3120
3121 if (mainw->foreign) {
3122 // recording from external window capture
3123 mainw->pwidth = lives_widget_get_allocation_width(mainw->playframe) - H_RESIZE_ADJUST;
3124 mainw->pheight = lives_widget_get_allocation_height(mainw->playframe) - V_RESIZE_ADJUST;
3125
3126 cfile->hsize = mainw->pwidth;
3127 cfile->vsize = mainw->pheight;
3128
3129 lives_xwindow_set_keep_above(mainw->foreign_window, FALSE);
3130
3131 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
3132
3133 return;
3134 }
3135
3136 disable_record();
3137 prefs->pb_quality = future_prefs->pb_quality;
3138 mainw->lockstats = FALSE;
3139 mainw->blend_palette = WEED_PALETTE_END;
3140 mainw->audio_stretch = 1.;
3141
3142 if (!mainw->multitrack) {
3143 if (mainw->faded || mainw->fs) {
3144 unfade_background();
3145 }
3146
3147 if (mainw->sep_win) add_to_playframe();
3148
3149 if (CURRENT_CLIP_HAS_VIDEO) {
3150 resize(1.);
3151 lives_widget_show_all(mainw->playframe);
3152 lives_frame_set_label(LIVES_FRAME(mainw->playframe), NULL);
3153 }
3154
3155 if (palette->style & STYLE_1) {
3156 lives_widget_show(mainw->sep_image);
3157 }
3158
3159 if (prefs->show_msg_area && !mainw->multitrack) {
3160 lives_widget_show(mainw->message_box);
3161 reset_message_area(); ///< necessary
3162 }
3163
3164 lives_widget_show(mainw->frame1);
3165 lives_widget_show(mainw->frame2);
3166 lives_widget_show(mainw->eventbox3);
3167 lives_widget_show(mainw->eventbox4);
3168 lives_widget_show(mainw->sep_image);
3169
3170 if (!prefs->hide_framebar && !prefs->hfbwnp) {
3171 lives_widget_show(mainw->framebar);
3172 }
3173 }
3174
3175 if (!is_realtime_aplayer(audio_player)) mainw->mute = mute;
3176
3177 /// kill the separate play window
3178 if (mainw->play_window) {
3179 if (mainw->fs) {
3180 mainw->ignore_screen_size = TRUE;
3181 if (prefs->show_desktop_panel && (capable->wm_caps.pan_annoy & ANNOY_DISPLAY)
3182 && (capable->wm_caps.pan_annoy & ANNOY_FS) && (capable->wm_caps.pan_res & RES_HIDE) &&
3183 capable->wm_caps.pan_res & RESTYPE_ACTION) {
3184 show_desktop_panel();
3185 }
3186 lives_window_unfullscreen(LIVES_WINDOW(mainw->play_window));
3187 }
3188 if (prefs->sepwin_type == SEPWIN_TYPE_NON_STICKY) {
3189 kill_play_window();
3190 } else {
3191 /// or resize it back to single size
3192 if (CURRENT_CLIP_IS_VALID && cfile->is_loaded && cfile->frames > 0 && !mainw->is_rendering &&
3193 (cfile->clip_type != CLIP_TYPE_GENERATOR)) {
3194 if (mainw->preview_controls) {
3195 /// create the preview in the sepwin
3196 if (prefs->show_gui) {
3197 lives_widget_set_no_show_all(mainw->preview_controls, FALSE);
3198 lives_widget_show_all(mainw->preview_box);
3199 lives_widget_show_now(mainw->preview_box);
3200 lives_widget_set_no_show_all(mainw->preview_controls, TRUE);
3201 //lives_widget_grab_focus(mainw->preview_spinbutton);
3202 }
3203 }
3204 if (mainw->current_file != current_file) {
3205 // now we have to guess how to center the play window
3206 mainw->opwx = mainw->opwy = -1;
3207 mainw->preview_frame = 0;
3208 }
3209 }
3210
3211 if (!mainw->multitrack) {
3212 mainw->playing_file = -2;
3213 if (mainw->fs) mainw->ignore_screen_size = TRUE;
3214 resize_play_window();
3215 mainw->playing_file = -1;
3216 lives_widget_queue_draw(LIVES_MAIN_WINDOW_WIDGET);
3217
3218 if (!mainw->preview_box) {
3219 // create the preview box that shows frames
3220 make_preview_box();
3221 }
3222 // and add it to the play window
3223 if (!lives_widget_get_parent(mainw->preview_box) && CURRENT_CLIP_IS_NORMAL && !mainw->is_rendering) {
3224 lives_widget_queue_draw(mainw->play_window);
3225 lives_container_add(LIVES_CONTAINER(mainw->play_window), mainw->preview_box);
3226 play_window_set_title();
3227 }
3228
3229 if (mainw->play_window) {
3230 if (prefs->show_playwin) {
3231 lives_window_present(LIVES_WINDOW(mainw->play_window));
3232 lives_xwindow_raise(lives_widget_get_xwindow(mainw->play_window));
3233 unhide_cursor(lives_widget_get_xwindow(mainw->play_window));
3234 lives_widget_set_no_show_all(mainw->preview_controls, FALSE);
3235 lives_widget_show_all(mainw->preview_box);
3236 lives_widget_show_now(mainw->preview_box);
3237 lives_widget_grab_focus(mainw->preview_spinbutton);
3238 lives_widget_set_no_show_all(mainw->preview_controls, TRUE);
3239 lives_widget_process_updates(mainw->play_window);
3240 lives_window_center(LIVES_WINDOW(mainw->play_window));
3241 clear_widget_bg(mainw->play_image, mainw->play_surface);
3242 load_preview_image(FALSE);
3243 // *INDENT-OFF*
3244 }}}}}
3245 // *INDENT-ON*
3246
3247 /// free the last frame image
3248 if (mainw->frame_layer) {
3249 weed_layer_free(mainw->frame_layer);
3250 mainw->frame_layer = NULL;
3251 }
3252
3253 if (mainw->lazy) mainw->lazy = lives_idle_add_simple(lazy_startup_checks, NULL);
3254
3255 cliplist = mainw->cliplist;
3256 while (cliplist) {
3257 int i = LIVES_POINTER_TO_INT(cliplist->data);
3258 if (IS_NORMAL_CLIP(i) && mainw->files[i]->clip_type == CLIP_TYPE_FILE)
3259 chill_decoder_plugin(i);
3260 mainw->files[i]->adirection = LIVES_DIRECTION_FORWARD;
3261 cliplist = cliplist->next;
3262 }
3263
3264 if (!mainw->foreign) {
3265 unhide_cursor(lives_widget_get_xwindow(mainw->playarea));
3266 }
3267
3268 if (CURRENT_CLIP_IS_VALID) cfile->play_paused = FALSE;
3269
3270 if (mainw->blend_file != -1 && mainw->blend_file != mainw->current_file && mainw->files[mainw->blend_file] &&
3271 mainw->files[mainw->blend_file]->clip_type == CLIP_TYPE_GENERATOR) {
3272 int xcurrent_file = mainw->current_file;
3273 weed_bg_generator_end((weed_plant_t *)mainw->files[mainw->blend_file]->ext_src);
3274 mainw->current_file = xcurrent_file;
3275 }
3276
3277 mainw->filter_map = mainw->afilter_map = mainw->audio_event = NULL;
3278
3279 /// disable the freeze key
3280 lives_accel_group_disconnect(LIVES_ACCEL_GROUP(mainw->accel_group), freeze_closure);
3281 lives_accel_group_disconnect(LIVES_ACCEL_GROUP(mainw->accel_group), bg_freeze_closure);
3282
3283 if (needsadone) d_print_done();
3284
3285 /// free any pre-cached frame
3286 if (mainw->frame_layer_preload && mainw->pred_clip != -1) {
3287 check_layer_ready(mainw->frame_layer_preload);
3288 weed_layer_free(mainw->frame_layer_preload);
3289 }
3290 mainw->frame_layer_preload = NULL;
3291
3292 if (!prefs->vj_mode) {
3293 /// pop up error dialog if badly sized frames were detected
3294 if (mainw->size_warn) {
3295 if (mainw->size_warn > 0 && mainw->files[mainw->size_warn]) {
3296 char *smsg = lives_strdup_printf(
3297 _("\n\nSome frames in the clip\n%s\nare wrongly sized.\nYou should "
3298 "click on Tools--->Resize All\n"
3299 "and resize all frames to the current size.\n"),
3300 mainw->files[mainw->size_warn]->name);
3301 widget_opts.non_modal = TRUE;
3302 do_error_dialog(smsg);
3303 widget_opts.non_modal = FALSE;
3304 lives_free(smsg);
3305 }
3306 }
3307 }
3308 mainw->size_warn = 0;
3309
3310 // set processing state again if a previewe finished
3311 // CAUTION !!
3312 mainw->is_processing = mainw->preview;
3313 /////////////////
3314
3315 if (prefs->volume != (double)future_prefs->volume) pref_factory_float(PREF_MASTER_VOLUME, future_prefs->volume, TRUE);
3316
3317 // TODO - ????
3318 if (CURRENT_CLIP_IS_VALID && cfile->clip_type == CLIP_TYPE_DISK && cfile->frames == 0 && mainw->record_perf) {
3319 lives_signal_handler_block(mainw->record_perf, mainw->record_perf_func);
3320 lives_check_menu_item_set_active(LIVES_CHECK_MENU_ITEM(mainw->record_perf), FALSE);
3321 lives_signal_handler_unblock(mainw->record_perf, mainw->record_perf_func);
3322 }
3323
3324 // TODO - can this be done earlier ?
3325 if (mainw->cancelled == CANCEL_APP_QUIT) on_quit_activate(NULL, NULL);
3326
3327 /// end record performance
3328
3329 #ifdef ENABLE_JACK
3330 if (audio_player == AUD_PLAYER_JACK && mainw->jackd) {
3331 ticks_t timeout;
3332 lives_alarm_t alarm_handle = lives_alarm_set(LIVES_DEFAULT_TIMEOUT);
3333 while ((timeout = lives_alarm_check(alarm_handle)) > 0 && jack_get_msgq(mainw->jackd)) {
3334 sched_yield(); ///< wait for seek
3335 lives_usleep(prefs->sleep_time);
3336 }
3337 lives_alarm_clear(alarm_handle);
3338 if (timeout == 0) {
3339 handle_audio_timeout();
3340 }
3341 if (has_audio_buffers) {
3342 free_jack_audio_buffers();
3343 audio_free_fnames();
3344 }
3345 }
3346 #endif
3347 #ifdef HAVE_PULSE_AUDIO
3348 if (audio_player == AUD_PLAYER_PULSE && mainw->pulsed) {
3349 ticks_t timeout;
3350 lives_alarm_t alarm_handle = lives_alarm_set(LIVES_DEFAULT_TIMEOUT);
3351 while ((timeout = lives_alarm_check(alarm_handle)) > 0 && pulse_get_msgq(mainw->pulsed)) {
3352 sched_yield(); ///< wait for seek
3353 lives_usleep(prefs->sleep_time);
3354 }
3355 lives_alarm_clear(alarm_handle);
3356 if (timeout == 0) {
3357 handle_audio_timeout();
3358 }
3359
3360 if (has_audio_buffers) {
3361 free_pulse_audio_buffers();
3362 audio_free_fnames();
3363 }
3364 }
3365 #endif
3366
3367 if (prefs->show_player_stats) {
3368 if (mainw->fps_measure > 0) {
3369 d_print(_("Average FPS was %.4f (%d frames in clock time of %f)\n"), fps_med, mainw->fps_measure,
3370 (double)lives_get_relative_ticks(mainw->origsecs, mainw->orignsecs) / TICKS_PER_SECOND_DBL);
3371 }
3372 }
3373
3374 if (THREADVAR(bad_aud_file)) {
3375 /// we got an error recording audio
3376 do_write_failed_error_s(THREADVAR(bad_aud_file), NULL);
3377 lives_freep((void **)&THREADVAR(bad_aud_file));
3378 }
3379
3380 if (mainw->new_vpp) {
3381 mainw->noswitch = FALSE;
3382 mainw->vpp = open_vid_playback_plugin(mainw->new_vpp, TRUE);
3383 mainw->new_vpp = NULL;
3384 mainw->noswitch = TRUE;
3385 }
3386
3387 if (!mainw->multitrack && CURRENT_CLIP_HAS_VIDEO) {
3388 lives_widget_set_sensitive(mainw->spinbutton_start, TRUE);
3389 lives_widget_set_sensitive(mainw->spinbutton_end, TRUE);
3390 }
3391
3392 if (!mainw->preview && CURRENT_CLIP_IS_VALID && cfile->clip_type == CLIP_TYPE_GENERATOR) {
3393 mainw->osc_block = TRUE;
3394 weed_generator_end((weed_plant_t *)cfile->ext_src);
3395 mainw->osc_block = FALSE;
3396 } else {
3397 if (mainw->current_file > -1) {
3398 if (mainw->toy_type == LIVES_TOY_MAD_FRAMES && !cfile->opening) {
3399 showclipimgs();
3400 if (!mainw->multitrack)
3401 redraw_timeline(mainw->current_file);
3402 }
3403 }
3404 }
3405
3406 if (CURRENT_CLIP_IS_VALID) {
3407 if (!mainw->multitrack) {
3408 lives_ce_update_timeline(0, cfile->real_pointer_time);
3409 mainw->ptrtime = cfile->real_pointer_time;
3410 lives_widget_queue_draw(mainw->eventbox2);
3411 lives_widget_queue_draw_if_visible(mainw->framecounter);
3412 }
3413 }
3414
3415 if (!mainw->multitrack) {
3416 //lives_table_set_column_homogeneous(LIVES_TABLE(mainw->pf_grid), FALSE);
3417 }
3418
3419 if (prefs->show_gui && ((mainw->multitrack && mainw->double_size) ||
3420 (lives_widget_get_allocation_height(LIVES_MAIN_WINDOW_WIDGET) > GUI_SCREEN_HEIGHT ||
3421 lives_widget_get_allocation_width(LIVES_MAIN_WINDOW_WIDGET) > GUI_SCREEN_WIDTH))) {
3422 //if (prefs->gui_monitor == 0) lives_window_move(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), 0, 0);
3423 if (prefs->open_maximised)
3424 lives_window_maximize(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET));
3425 lives_widget_queue_draw(LIVES_MAIN_WINDOW_WIDGET);
3426 }
3427
3428 if (!mainw->preview && (mainw->current_file == -1 || (CURRENT_CLIP_IS_VALID && !cfile->opening))) {
3429 sensitize();
3430 }
3431
3432 if (CURRENT_CLIP_IS_VALID && cfile->opening) {
3433 lives_widget_set_sensitive(mainw->mute_audio, cfile->achans > 0);
3434 lives_widget_set_sensitive(mainw->loop_continue, TRUE);
3435 lives_widget_set_sensitive(mainw->loop_video, cfile->achans > 0 && cfile->frames > 0);
3436 }
3437
3438 if (mainw->cancelled != CANCEL_USER_PAUSED) {
3439 lives_widget_set_sensitive(mainw->stop, FALSE);
3440 lives_widget_set_sensitive(mainw->m_stopbutton, FALSE);
3441 }
3442
3443 lives_widget_set_sensitive(mainw->spinbutton_pb_fps, FALSE);
3444
3445 if (!mainw->multitrack) {
3446 /// update screen for internal players
3447 if (prefs->hfbwnp) {
3448 lives_widget_hide(mainw->framebar);
3449 }
3450 set_drawing_area_from_pixbuf(mainw->play_image, NULL, mainw->play_surface);
3451 lives_widget_set_opacity(mainw->play_image, 0.);
3452 }
3453
3454 if (!mainw->multitrack) mainw->osc_block = FALSE;
3455
3456 reset_clipmenu();
3457
3458 lives_menu_item_set_accel_path(LIVES_MENU_ITEM(mainw->quit), LIVES_ACCEL_PATH_QUIT);
3459
3460 if (!mainw->multitrack && CURRENT_CLIP_IS_VALID)
3461 set_main_title(cfile->name, 0);
3462
3463 if (!mainw->multitrack && !mainw->foreign && CURRENT_CLIP_IS_VALID && (!cfile->opening ||
3464 cfile->clip_type == CLIP_TYPE_FILE)) {
3465 showclipimgs();
3466 redraw_timeline(mainw->current_file);
3467 }
3468
3469 if (prefs->show_msg_area) {
3470 if (mainw->idlemax == 0) {
3471 lives_idle_add_simple(resize_message_area, NULL);
3472 }
3473 mainw->idlemax = DEF_IDLE_MAX;
3474 }
3475
3476 lives_widget_queue_draw(LIVES_MAIN_WINDOW_WIDGET);
3477
3478 /// need to do this here, in case we want to preview with only a generator and no other clips (which will close to -1)
3479 if (mainw->record) {
3480 lives_idle_add_simple(render_choice_idle, LIVES_INT_TO_POINTER(FALSE));
3481 }
3482
3483 mainw->record_paused = mainw->record_starting = mainw->record = FALSE;
3484
3485 mainw->ignore_screen_size = FALSE;
3486
3487 /// re-enable generic clip switching
3488 mainw->noswitch = FALSE;
3489 }
3490
3491
3492 /**
3493 @brief close cfile and switch to new clip (may be -1)
3494
3495 note this only closes the disk and basic resources, it does not affect the interface
3496 (c.f. close_current_file())
3497 returns new_clip */
3498 int close_temp_handle(int new_clip) {
3499 char *com, *permitname;
3500 int clipno = mainw->current_file;
3501
3502 if (!IS_VALID_CLIP(new_clip)) new_clip = -1;
3503 if (!IS_VALID_CLIP(clipno)) {
3504 mainw->current_file = new_clip;
3505 return new_clip;
3506 }
3507 if (cfile->clip_type != CLIP_TYPE_TEMP
3508 && mainw->current_file != mainw->scrap_file && mainw->current_file != mainw->ascrap_file) {
3509 close_current_file(new_clip);
3510 }
3511
3512 // as a safety feature we create a special file which allows the back end to delete the directory
3513 permitname = lives_build_filename(prefs->workdir, cfile->handle, TEMPFILE_MARKER "." LIVES_FILE_EXT_TMP, NULL);
3514 lives_touch(permitname);
3515 lives_free(permitname);
3516
3517 com = lives_strdup_printf("%s close \"%s\"", prefs->backend, cfile->handle);
3518 lives_system(com, TRUE);
3519 lives_free(com);
3520 lives_freep((void **)&mainw->files[clipno]);
3521
3522 mainw->current_file = new_clip;
3523
3524 if (mainw->first_free_file == ALL_USED || mainw->first_free_file > clipno)
3525 mainw->first_free_file = clipno;
3526 return new_clip;
3527 }
3528
3529
3530 /**
3531 @brief get next free file slot, or -1 if we are full
3532
3533 can support MAX_FILES files (default 65536) */
3534 static int get_next_free_file(void) {
3535 int idx = mainw->first_free_file++;
3536 while ((mainw->first_free_file != ALL_USED) && mainw->files[mainw->first_free_file]) {
3537 mainw->first_free_file++;
3538 if (mainw->first_free_file >= MAX_FILES) mainw->first_free_file = ALL_USED;
3539 }
3540 return idx;
3541 }
3542
3543
3544 /**
3545 @brief get a temp "handle" from disk.
3546
3547 Call this to get a temp handle for returning info from the backend
3548 (this is deprecated for simple data, use lives_popen() instead whenever possible)
3549
3550 This function is also called from get_new_handle() to create a permanent handle
3551 for an opened file.
3552
3553 there are two special instances when this is called with an index != -1:
3554 - when saving a set and a clip is moved from outside the set to inside it.
3555 we need a new handle which is guaranteed unique for the set, but we retain all the other details
3556 - when called from get_new_handle() to create the disk part of a clip
3557
3558 otherwise, index should be passed in as -1 (the normal case)
3559 -- handle will be fetched and a directory created in workdir.
3560 -- clip_type is set to CLIP_TYPE_TEMP.
3561 call close_temp_handle() on it after use, then restore mainw->current_file
3562
3563 function returns FALSE if write to workdir fails.
3564
3565 WARNING:
3566 this function changes mainw->current_file, unless it returns FALSE (could not create cfile)
3567
3568 get_new_handle() calls this with the index value passed to it, which should not be -1,
3569 sets defaults for the clip,
3570 and also sets the clip name and filename. That function should be used instead to create permanent clips. */
3571 boolean get_temp_handle(int index) {
3572 boolean is_unique, create = FALSE;
3573
3574 if (CURRENT_CLIP_IS_TEMP) {
3575 break_me("temp clip in temp clip !!");
3576 return TRUE;
3577 }
3578
3579 if (index < -1 || index > MAX_FILES) {
3580 char *msg = lives_strdup_printf("Attempt to create invalid new temp clip %d\n", index);
3581 LIVES_WARN(msg);
3582 lives_free(msg);
3583 return FALSE;
3584 }
3585
3586 if (index == -1) {
3587 if (mainw->first_free_file == ALL_USED) {
3588 too_many_files();
3589 return FALSE;
3590 }
3591 create = TRUE;
3592 index = mainw->first_free_file;
3593 get_next_free_file();
3594 }
3595
3596 do {
3597 is_unique = TRUE;
3598
3599 // get handle from info file, the first time we will also malloc a
3600 // new "file" struct here and create a directory in prefs->workdir
3601 if (!get_handle_from_info_file(index)) {
3602 lives_freep((void **)&mainw->files[index]);
3603 if (mainw->first_free_file == ALL_USED || index < mainw->first_free_file)
3604 mainw->first_free_file = index;
3605 return FALSE;
3606 }
3607
3608 if (*mainw->set_name) {
3609 char *setclipdir = CLIPDIR(cfile->handle);
3610 if (lives_file_test(setclipdir, LIVES_FILE_TEST_IS_DIR)) is_unique = FALSE;
3611 lives_free(setclipdir);
3612 }
3613 } while (!is_unique);
3614
3615 mainw->current_file = index;
3616
3617 if (create) {
3618 // create a marker file in directory, else we will be barred from
3619 // removing it
3620 char *canremove = lives_build_filename(prefs->workdir, cfile->handle,
3621 TEMPFILE_MARKER "." LIVES_FILE_EXT_TMP, NULL);
3622 lives_touch(canremove);
3623 lives_free(canremove);
3624 // fill with default values
3625 create_cfile(index, cfile->handle, FALSE);
3626 cfile->clip_type = CLIP_TYPE_TEMP;
3627 }
3628 return TRUE;
3629 }
3630
3631
3632 /**
3633 @brief set default values for a clip (in memory)
3634
3635 if new_file == -1 we create (malloc) a new clip and switch to it
3636 - setting its handle to "handle" (reload / crash recovery)
3637
3638 if new_file != -1 the parameter "handle" is ignored, and we switch to new_file, without mallocing anything
3639 - "handle" in the clip must have been set already (called from get_new_handle() and get_temp_handle())
3640 -- get_new_handle() will set name and fliename and switch back to original clip.
3641
3642 default values are then set for the clip
3643 - a "unique_id" is assigned via uuidgen or lives_random()
3644 - type is set to CLIP_TYPE_DISK
3645 - img_type is set depending on prefs->image_type
3646 - frames is set to 0
3647 etc.
3648
3649 - loaded is set = to is_loaded
3650
3651 WARNING: on success, returns the clip, and changes the value of
3652 mainw->current_file !! returns NULL if: new_file is out of range
3653 or points to a NULL clip; new_file is -1 and all free clips are
3654 in use (unlikely), or malloc fails.
3655 */
3656 lives_clip_t *create_cfile(int new_file, const char *handle, boolean is_loaded) {
3657 lives_clip_t *sfile;
3658 char *stfile;
3659
3660 if (new_file == -1) {
3661 // if new_file == -1, we are going to create a new clip
3662 new_file = mainw->first_free_file;
3663 if (new_file == -1) {
3664 too_many_files();
3665 return NULL;
3666 }
3667
3668 mainw->current_file = new_file;
3669 get_next_free_file();
3670
3671 if (new_file < 0 || new_file > MAX_FILES || IS_VALID_CLIP(new_file)) {
3672 char *msg = lives_strdup_printf("Attempt to create invalid new clip %d\n", new_file);
3673 LIVES_WARN(msg);
3674 lives_free(msg);
3675 return NULL;
3676 }
3677
3678 if (!handle) {
3679 // if handle is NULL, we create a new clip on disk, switch to it
3680 // (unused)
3681 if (!get_handle_from_info_file(new_file)) return NULL;
3682 sfile = mainw->files[new_file];
3683 } else {
3684 // else just create the in-memory part and set the handle
3685 sfile = mainw->files[new_file] = (lives_clip_t *)(lives_calloc(1, sizeof(lives_clip_t)));
3686 if (!sfile) return NULL;
3687 lives_snprintf(sfile->handle, 256, "%s", handle);
3688 }
3689 }
3690
3691 mainw->current_file = new_file;
3692
3693 cfile->is_loaded = is_loaded;
3694
3695 // any cfile (clip) initialisation goes in here
3696 lives_memcpy((void *)&cfile->binfmt_check.chars, "LiVESXXX", 8);
3697 cfile->binfmt_version.num = make_version_hash(LiVES_VERSION);
3698 cfile->binfmt_bytes.size = (size_t)((void *)&cfile->binfmt_end - (void *)cfile);
3699 cfile->menuentry = NULL;
3700 cfile->start = cfile->end = 0;
3701 cfile->old_frames = cfile->opening_frames = cfile->frames = 0;
3702 lives_snprintf(cfile->type, 40, "%s", _("Unknown"));
3703 cfile->f_size = 0l;
3704 cfile->achans = 0;
3705 cfile->arate = 0;
3706 cfile->arps = 0;
3707 cfile->afilesize = 0l;
3708 cfile->asampsize = 0;
3709 cfile->adirection = LIVES_DIRECTION_FORWARD;
3710 cfile->undoable = FALSE;
3711 cfile->redoable = FALSE;
3712 cfile->changed = FALSE;
3713 cfile->was_in_set = FALSE;
3714 cfile->hsize = cfile->vsize = cfile->ohsize = cfile->ovsize = 0;
3715 cfile->fps = cfile->pb_fps = prefs->default_fps;
3716 cfile->resample_events = NULL;
3717 cfile->insert_start = cfile->insert_end = 0;
3718 cfile->is_untitled = TRUE;
3719 cfile->was_renamed = FALSE;
3720 cfile->undo_action = UNDO_NONE;
3721 cfile->opening_audio = cfile->opening = cfile->opening_only_audio = FALSE;
3722 cfile->pointer_time = 0.;
3723 cfile->real_pointer_time = 0.;
3724 cfile->restoring = cfile->opening_loc = cfile->nopreview = FALSE;
3725 cfile->video_time = cfile->laudio_time = cfile->raudio_time = 0.;
3726 cfile->freeze_fps = 0.;
3727 cfile->last_vframe_played = 0;
3728 cfile->frameno = cfile->last_frameno = cfile->saved_frameno = 1;
3729 cfile->progress_start = cfile->progress_end = 0;
3730 cfile->play_paused = cfile->nokeep = FALSE;
3731 cfile->undo_start = cfile->undo_end = 0;
3732 cfile->ext_src = NULL;
3733 cfile->ext_src_type = LIVES_EXT_SRC_NONE;
3734 cfile->clip_type = CLIP_TYPE_DISK;
3735 cfile->ratio_fps = FALSE;
3736 cfile->aseek_pos = 0;
3737 cfile->unique_id = gen_unique_id();
3738 cfile->layout_map = NULL;
3739 cfile->frame_index = cfile->frame_index_back = NULL;
3740 cfile->fx_frame_pump = 0;
3741 cfile->pumper = NULL;
3742 cfile->stored_layout_frame = 0;
3743 cfile->stored_layout_audio = 0.;
3744 cfile->stored_layout_fps = 0.;
3745 cfile->stored_layout_idx = -1;
3746 cfile->interlace = LIVES_INTERLACE_NONE;
3747 cfile->subt = NULL;
3748 cfile->no_proc_sys_errors = cfile->no_proc_read_errors = cfile->no_proc_write_errors = FALSE;
3749 cfile->keep_without_preview = FALSE;
3750 cfile->cb_src = -1;
3751 cfile->needs_update = cfile->needs_silent_update = FALSE;
3752 cfile->audio_waveform = NULL;
3753 cfile->md5sum[0] = 0;
3754 cfile->gamma_type = WEED_GAMMA_SRGB;
3755 cfile->last_play_sequence = 0;
3756 cfile->tcache_dubious_from = 0;
3757 cfile->tcache_height = 0;
3758 cfile->tcache = NULL;
3759 cfile->checked = FALSE;
3760 cfile->has_binfmt = TRUE;
3761
3762 if (!strcmp(prefs->image_ext, LIVES_FILE_EXT_JPG)) cfile->img_type = IMG_TYPE_JPEG;
3763 else cfile->img_type = IMG_TYPE_PNG;
3764
3765 cfile->bpp = (cfile->img_type == IMG_TYPE_JPEG) ? 24 : 32;
3766 cfile->deinterlace = FALSE;
3767
3768 cfile->play_paused = FALSE;
3769 cfile->header_version = LIVES_CLIP_HEADER_VERSION;
3770
3771 cfile->event_list = cfile->event_list_back = NULL;
3772 cfile->next_event = NULL;
3773 cfile->vol = 1.;
3774
3775 lives_memset(cfile->name, 0, 1);
3776 lives_memset(cfile->mime_type, 0, 1);
3777 lives_memset(cfile->file_name, 0, 1);
3778 lives_memset(cfile->save_file_name, 0, 1);
3779
3780 lives_memset(cfile->comment, 0, 1);
3781 lives_memset(cfile->author, 0, 1);
3782 lives_memset(cfile->title, 0, 1);
3783 lives_memset(cfile->keywords, 0, 1);
3784
3785 cfile->signed_endian = AFORM_UNKNOWN;
3786 lives_snprintf(cfile->undo_text, 32, "%s", _("_Undo"));
3787 lives_snprintf(cfile->redo_text, 32, "%s", _("_Redo"));
3788
3789 stfile = lives_build_filename(prefs->workdir, cfile->handle, LIVES_STATUS_FILE_NAME, NULL);
3790
3791 lives_snprintf(cfile->info_file, PATH_MAX, "%s", stfile);
3792 lives_free(stfile);
3793
3794 // backwards compat.
3795 cfile->checked_for_old_header = FALSE;
3796 cfile->has_old_header = FALSE;
3797
3798 return cfile;
3799 }
3800
3801
3802 LIVES_GLOBAL_INLINE char *get_untitled_name(int number) {
3803 // utility function to get clip name
3804 return lives_strdup_printf(_("Untitled%d"), number);
3805 }
3806
3807
3808 int create_nullvideo_clip(const char *handle) {
3809 // create a file with no video, just produces blank frames
3810 // may be used to playback with audio, for testign etc.
3811 int new_file;
3812 int current_file = mainw->current_file;
3813 create_cfile(-1, handle, TRUE);
3814 new_file = mainw->current_file;
3815 mainw->current_file = current_file;
3816 mainw->files[new_file]->clip_type = CLIP_TYPE_NULL_VIDEO;
3817 return new_file;
3818 }
3819
3820
3821 boolean get_new_handle(int index, const char *name) {
3822 // here is where we first initialize for the clipboard
3823 // and for paste_as_new, and restore, etc.
3824 // pass in name as NULL or "" and it will be set with an untitled number
3825
3826 // this function *does not* change mainw->current_file (except briefly), or add to the menu
3827 // or update mainw->clips_available
3828
3829 // differences from get_temp_handle:
3830 // - here we dont't switch clips;
3831 // - index is normally passed in rather than generated (pulled from next_free_file) - this allows
3832 // the caller to know the index number and do preconfig before calling
3833 // - we set name and file_name from the name parameter, or if name is NULL, we set an untitled name
3834 // and increment mainw->untitled_number
3835 // - the clip should be closed using close_current_file() instead of close_temp_handle()
3836
3837 char *xname;
3838
3839 int current_file = mainw->current_file;
3840
3841 // if TRUE, changes mainw->current_file (and hence cfile)
3842 if (!get_temp_handle(index)) return FALSE;
3843
3844 // setup would have been done already in get_temp_handle()
3845 if (index == -1) index = mainw->current_file;
3846
3847 else create_cfile(index, cfile->handle, FALSE);
3848
3849 // note : don't need to update first_free_file for the clipboard
3850 // because we used index 0 instead of a free index number
3851 if (index != 0) {
3852 get_next_free_file();
3853 }
3854
3855 if (!name || !*name) {
3856 cfile->is_untitled = TRUE;
3857 xname = get_untitled_name(mainw->untitled_number++);
3858 } else xname = lives_strdup(name);
3859
3860 lives_snprintf(cfile->file_name, PATH_MAX, "%s", xname);
3861 lives_snprintf(cfile->name, CLIP_NAME_MAXLEN, "%s", xname);
3862
3863 mainw->current_file = current_file;
3864
3865 lives_free(xname);
3866 return TRUE;
3867 }
3868
3869
3870 boolean add_file_info(const char *check_handle, boolean aud_only) {
3871 // file information has been retrieved, set struct cfile with details
3872 // contained in mainw->msg. We do this twice, once before opening the file, once again after.
3873 // The first time, frames and afilesize may not be correct.
3874 char *mesg, *mesg1;
3875 char **array;
3876 char *test_fps_string1;
3877 char *test_fps_string2;
3878
3879 if (aud_only && !mainw->save_with_sound) {
3880 cfile->arps = cfile->arate = cfile->achans = cfile->asampsize = 0;
3881 cfile->afilesize = 0l;
3882 return TRUE;
3883 }
3884
3885 if (!strcmp(mainw->msg, "killed")) {
3886 char *com;
3887 // user pressed "enough"
3888 // just in case last frame is damaged, we delete it (physically, otherwise it will get dragged in when the file is opened)
3889 if (!cfile->ext_src) {
3890 cfile->frames = get_frame_count(mainw->current_file, cfile->opening_frames);
3891 if (cfile->frames > 1) {
3892 com = lives_strdup_printf("%s cut \"%s\" %d %d %d %d \"%s\" %.3f %d %d %d",
3893 prefs->backend, cfile->handle, cfile->frames, cfile->frames,
3894 FALSE, cfile->frames, get_image_ext_for_type(cfile->img_type),
3895 0., 0, 0, 0);
3896 lives_system(com, FALSE);
3897 lives_free(com);
3898 cfile->frames--;
3899 }
3900 }
3901
3902 // commit audio
3903 mainw->cancelled = CANCEL_NONE;
3904 lives_rm(cfile->info_file);
3905
3906 com = lives_strdup_printf("%s commit_audio \"%s\" 1", prefs->backend, cfile->handle);
3907 lives_system(com, TRUE);
3908 lives_free(com);
3909
3910 wait_for_bg_audio_sync(mainw->current_file);
3911
3912 reget_afilesize(mainw->current_file);
3913 d_print_enough(cfile->frames);
3914
3915 if (prefs->auto_trim_audio) {
3916 if (cfile->laudio_time > cfile->video_time) {
3917 d_print(_("Auto trimming %.2f seconds of audio at end..."), cfile->laudio_time - cfile->video_time);
3918 if (on_trim_audio_activate(NULL, LIVES_INT_TO_POINTER(0))) d_print_done();
3919 else d_print("\n");
3920 cfile->changed = FALSE;
3921 }
3922 }
3923 } else {
3924 if (check_handle) {
3925 int npieces = get_token_count(mainw->msg, '|');
3926 if (npieces < 2) return FALSE;
3927
3928 array = lives_strsplit(mainw->msg, "|", npieces);
3929
3930 if (!strcmp(array[0], "error")) {
3931 if (npieces >= 3) {
3932 mesg = lives_strdup_printf(_("\nAn error occurred doing\n%s\n"), array[2]);
3933 LIVES_ERROR(array[2]);
3934 } else mesg = (_("\nAn error occurred opening the file\n"));
3935 widget_opts.non_modal = TRUE;
3936 do_error_dialog(mesg);
3937 widget_opts.non_modal = FALSE;
3938 lives_free(mesg);
3939 lives_strfreev(array);
3940 return FALSE;
3941 }
3942
3943 // sanity check handle against status file
3944 // (this should never happen...)
3945 if (strcmp(check_handle, array[1])) {
3946 LIVES_ERROR("Handle!=statusfile !");
3947 mesg = lives_strdup_printf(_("\nError getting file info for clip %s.\nBad things may happen with this clip.\n"),
3948 check_handle);
3949 widget_opts.non_modal = TRUE;
3950 do_error_dialog(mesg);
3951 widget_opts.non_modal = FALSE;
3952 lives_free(mesg);
3953 lives_strfreev(array);
3954 return FALSE;
3955 }
3956
3957 cfile->arps = cfile->arate = atoi(array[9]);
3958 cfile->achans = atoi(array[10]);
3959 cfile->asampsize = atoi(array[11]);
3960 cfile->signed_endian = get_signed_endian(atoi(array[12]), atoi(array[13]));
3961 cfile->afilesize = strtol(array[14], NULL, 10);
3962 if (aud_only) {
3963 lives_strfreev(array);
3964 return TRUE;
3965 }
3966
3967 cfile->frames = atoi(array[2]);
3968 if (aud_only) {
3969 lives_strfreev(array);
3970 return TRUE;
3971 }
3972 lives_snprintf(cfile->type, 40, "%s", array[3]);
3973 cfile->hsize = atoi(array[4]);
3974 cfile->vsize = atoi(array[5]);
3975 cfile->bpp = atoi(array[6]);
3976 cfile->pb_fps = cfile->fps = lives_strtod(array[7], NULL);
3977 cfile->f_size = strtol(array[8], NULL, 10);
3978
3979 if (npieces > 15 && array[15]) {
3980 if (prefs->btgamma) {
3981 if (!strcmp(array[15], "bt709")) cfile->gamma_type = WEED_GAMMA_BT709;
3982 }
3983 }
3984
3985 if (!*cfile->title && npieces > 16 && array[16]) {
3986 lives_snprintf(cfile->title, 1024, "%s", lives_strstrip(array[16]));
3987 }
3988 if (!*cfile->author && npieces > 17 && array[17]) {
3989 lives_snprintf(cfile->author, 1024, "%s", lives_strstrip(array[17]));
3990 }
3991 if (!*cfile->comment && npieces > 18 && array[18]) {
3992 lives_snprintf(cfile->comment, 1024, "%s", lives_strstrip(array[18]));
3993 }
3994
3995 lives_strfreev(array);
3996 }
3997 }
3998
3999 cfile->video_time = 0;
4000
4001 test_fps_string1 = lives_strdup_printf("%.3f00000", cfile->fps);
4002 test_fps_string2 = lives_strdup_printf("%.8f", cfile->fps);
4003
4004 if (strcmp(test_fps_string1, test_fps_string2)) {
4005 cfile->ratio_fps = TRUE;
4006 } else {
4007 cfile->ratio_fps = FALSE;
4008 }
4009 lives_free(test_fps_string1);
4010 lives_free(test_fps_string2);
4011
4012 if (!mainw->save_with_sound) {
4013 cfile->arps = cfile->arate = cfile->achans = cfile->asampsize = 0;
4014 cfile->afilesize = 0l;
4015 }
4016
4017 if (cfile->frames <= 0) {
4018 if (cfile->afilesize == 0l && cfile->is_loaded) {
4019 // we got no video or audio...
4020 return FALSE;
4021 }
4022 cfile->start = cfile->end = cfile->undo_start = cfile->undo_end = 0;
4023 } else {
4024 // start with all selected
4025 cfile->start = 1;
4026 cfile->end = cfile->frames;
4027 cfile->undo_start = cfile->start;
4028 cfile->undo_end = cfile->end;
4029 }
4030
4031 cfile->orig_file_name = TRUE;
4032 cfile->is_untitled = FALSE;
4033
4034 // some files give us silly frame rates, even single frames...
4035 // fps of 1000. is used for some streams (i.e. play each frame as it is received)
4036 if (cfile->fps == 0. || cfile->fps == 1000. || (cfile->frames < 2 && cfile->is_loaded)) {
4037
4038 if ((cfile->afilesize * cfile->asampsize * cfile->arate * cfile->achans == 0) || cfile->frames < 2) {
4039 if (cfile->frames != 1) {
4040 d_print(_("\nPlayback speed not found or invalid ! Using default fps of %.3f fps. \n"
4041 "Default can be set in Tools | Preferences | Misc.\n"),
4042 prefs->default_fps);
4043 }
4044 cfile->pb_fps = cfile->fps = prefs->default_fps;
4045 } else {
4046 cfile->laudio_time = cfile->raudio_time = cfile->afilesize / cfile->asampsize * 8. / cfile->arate / cfile->achans;
4047 cfile->pb_fps = cfile->fps = 1.*(int)(cfile->frames / cfile->laudio_time);
4048 if (cfile->fps > FPS_MAX || cfile->fps < 1.) {
4049 cfile->pb_fps = cfile->fps = prefs->default_fps;
4050 }
4051 d_print(_("Playback speed was adjusted to %.3f frames per second to fit audio.\n"), cfile->fps);
4052 }
4053 }
4054
4055 cfile->video_time = (double)cfile->frames / cfile->fps;
4056
4057 if (cfile->opening) return TRUE;
4058
4059 if ((!strcmp(cfile->type, LIVES_IMAGE_TYPE_JPEG) || !strcmp(cfile->type, LIVES_IMAGE_TYPE_PNG))) {
4060 mesg = (_("Image format detected"));
4061 d_print(mesg);
4062 lives_free(mesg);
4063 return TRUE;
4064 }
4065
4066 if (cfile->bpp == 256) {
4067 mesg1 = lives_strdup_printf(_("Frames=%d type=%s size=%dx%d *bpp=Greyscale* fps=%.3f\nAudio:"), cfile->frames,
4068 cfile->type, cfile->hsize, cfile->vsize, cfile->fps);
4069 } else {
4070 if (cfile->bpp != 32) cfile->bpp = 24; // assume RGB24 *** TODO - check
4071 mesg1 = lives_strdup_printf(_("Frames=%d type=%s size=%dx%d bpp=%d fps=%.3f\nAudio:"), cfile->frames,
4072 cfile->type, cfile->hsize, cfile->vsize, cfile->bpp, cfile->fps);
4073 }
4074
4075 if (cfile->achans == 0) {
4076 mesg = lives_strdup_printf(_("%s none\n"), mesg1);
4077 } else {
4078 mesg = lives_strdup_printf(P_("%s %d Hz %d channel %d bps\n", "%s %d Hz %d channels %d bps\n", cfile->achans),
4079 mesg1, cfile->arate, cfile->achans, cfile->asampsize);
4080 }
4081 d_print(mesg);
4082 lives_free(mesg1);
4083 lives_free(mesg);
4084
4085 // get the author,title,comments
4086 if (*cfile->author) {
4087 d_print(_(" - Author: %s\n"), cfile->author);
4088 }
4089 if (*cfile->title) {
4090 d_print(_(" - Title: %s\n"), cfile->title);
4091 }
4092 if (*cfile->comment) {
4093 d_print(_(" - Comment: %s\n"), cfile->comment);
4094 }
4095
4096 return TRUE;
4097 }
4098
4099
4100 boolean save_file_comments(int fileno) {
4101 // save the comments etc for smogrify
4102 int retval;
4103 int comment_fd;
4104 char *comment_file = lives_strdup_printf("%s/%s/.comment", prefs->workdir, cfile->handle);
4105 lives_clip_t *sfile = mainw->files[fileno];
4106
4107 lives_rm(comment_file);
4108
4109 do {
4110 retval = 0;
4111 comment_fd = creat(comment_file, S_IRUSR | S_IWUSR);
4112 if (comment_fd < 0) {
4113 THREADVAR(write_failed) = TRUE;
4114 retval = do_write_failed_error_s_with_retry(comment_file, lives_strerror(errno));
4115 } else {
4116 THREADVAR(write_failed) = FALSE;
4117 lives_write(comment_fd, sfile->title, strlen(sfile->title), TRUE);
4118 lives_write(comment_fd, "||%", 3, TRUE);
4119 lives_write(comment_fd, sfile->author, strlen(sfile->author), TRUE);
4120 lives_write(comment_fd, "||%", 3, TRUE);
4121 lives_write(comment_fd, sfile->comment, strlen(sfile->comment), TRUE);
4122
4123 close(comment_fd);
4124
4125 if (THREADVAR(write_failed)) {
4126 retval = do_write_failed_error_s_with_retry(comment_file, NULL);
4127 }
4128 }
4129 } while (retval == LIVES_RESPONSE_RETRY);
4130
4131 lives_free(comment_file);
4132
4133 if (THREADVAR(write_failed)) return FALSE;
4134
4135 return TRUE;
4136 }
4137
4138
4139 void wait_for_stop(const char *stop_command) {
4140 FILE *infofile;
4141
4142 // only used for audio player mplayer or audio player sox
4143
4144 # define SECOND_STOP_TIME 0.1
4145 # define STOP_GIVE_UP_TIME 1.0
4146
4147 double time_waited = 0.;
4148 boolean sent_second_stop = FALSE;
4149
4150 // send another stop if necessary
4151 while (!(infofile = fopen(cfile->info_file, "r"))) {
4152 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
4153 lives_usleep(prefs->sleep_time);
4154 time_waited += 1000000. / prefs->sleep_time;
4155 if (time_waited > SECOND_STOP_TIME && !sent_second_stop) {
4156 lives_system(stop_command, TRUE);
4157 sent_second_stop = TRUE;
4158 }
4159
4160 if (time_waited > STOP_GIVE_UP_TIME) {
4161 // give up waiting, but send a last try...
4162 lives_system(stop_command, TRUE);
4163 break;
4164 }
4165 }
4166 if (infofile) fclose(infofile);
4167 }
4168
4169
4170 boolean save_frame_inner(int clip, int frame, const char *file_name, int width, int height, boolean from_osc) {
4171 // save 1 frame as an image
4172 // width==-1, height==-1 to use "natural" values
4173 LiVESResponseType resp;
4174 lives_clip_t *sfile = mainw->files[clip];
4175 char full_file_name[PATH_MAX];
4176 char *com, *tmp;
4177
4178 boolean allow_over = FALSE;
4179
4180 if (!from_osc && strrchr(file_name, '.') == NULL) {
4181 lives_snprintf(full_file_name, PATH_MAX, "%s.%s", file_name,
4182 get_image_ext_for_type(sfile->img_type));
4183 } else {
4184 lives_snprintf(full_file_name, PATH_MAX, "%s", file_name);
4185 if (!allow_over) allow_over = TRUE;
4186 }
4187
4188 // TODO - allow overwriting in sandbox
4189 if (from_osc && lives_file_test(full_file_name, LIVES_FILE_TEST_EXISTS)) return FALSE;
4190
4191 tmp = lives_filename_from_utf8(full_file_name, -1, NULL, NULL, NULL);
4192
4193 if (!mainw->multitrack) {
4194 d_print(_("Saving frame %d as %s..."), frame, full_file_name);
4195
4196 if (sfile->clip_type == CLIP_TYPE_FILE) {
4197 frames_t res = virtual_to_images(clip, frame, frame, FALSE, NULL);
4198 if (res <= 0) {
4199 d_print_file_error_failed();
4200 return FALSE;
4201 }
4202 }
4203
4204 do {
4205 resp = LIVES_RESPONSE_NONE;
4206
4207 com = lives_strdup_printf("%s save_frame %s %d \"%s\" %d %d", prefs->backend_sync, sfile->handle,
4208 frame, tmp, width, height);
4209 lives_system(com, FALSE);
4210 lives_free(com);
4211
4212 if (THREADVAR(write_failed)) {
4213 THREADVAR(write_failed) = 0;
4214 d_print_file_error_failed();
4215 resp = do_file_perm_error(tmp, TRUE);
4216 if (resp == LIVES_RESPONSE_CANCEL) {
4217 lives_free(tmp);
4218 return FALSE;
4219 }
4220 }
4221 if (!THREADVAR(com_failed)) {
4222 lives_free(tmp);
4223 d_print_done();
4224 return TRUE;
4225 }
4226 } while (resp == LIVES_RESPONSE_RETRY);
4227 } else {
4228 // multitrack mode
4229 LiVESError *gerr = NULL;
4230 LiVESPixbuf *pixbuf;
4231 int retval;
4232
4233 mt_show_current_frame(mainw->multitrack, TRUE);
4234 resize_layer(mainw->frame_layer, sfile->hsize, sfile->vsize, LIVES_INTERP_BEST, WEED_PALETTE_RGB24, 0);
4235 convert_layer_palette(mainw->frame_layer, WEED_PALETTE_RGB24, 0);
4236 weed_set_int_value(mainw->frame_layer, WEED_LEAF_GAMMA_TYPE, WEED_GAMMA_SRGB);
4237 pixbuf = layer_to_pixbuf(mainw->frame_layer, TRUE, FALSE);
4238 weed_plant_free(mainw->frame_layer);
4239 mainw->frame_layer = NULL;
4240
4241 do {
4242 retval = 0;
4243 if (sfile->img_type == IMG_TYPE_JPEG) lives_pixbuf_save(pixbuf, tmp, IMG_TYPE_JPEG, 100,
4244 sfile->hsize, sfile->vsize, &gerr);
4245 else if (sfile->img_type == IMG_TYPE_PNG) lives_pixbuf_save(pixbuf, tmp, IMG_TYPE_PNG, 100,
4246 sfile->hsize, sfile->vsize, &gerr);
4247
4248 if (gerr) {
4249 retval = do_write_failed_error_s_with_retry(full_file_name, gerr->message);
4250 lives_error_free(gerr);
4251 gerr = NULL;
4252 }
4253 } while (retval == LIVES_RESPONSE_RETRY);
4254
4255 free(tmp);
4256 lives_widget_object_unref(pixbuf);
4257 }
4258
4259 // some other error condition
4260 return FALSE;
4261 }
4262
4263
4264 void backup_file(int clip, int start, int end, const char *file_name) {
4265 lives_clip_t *sfile = mainw->files[clip];
4266 char **array;
4267
4268 char *title;
4269 char full_file_name[PATH_MAX];
4270
4271 char *com, *tmp;
4272
4273 boolean with_perf = FALSE;
4274 boolean retval, allow_over;
4275
4276 int withsound = 1;
4277 int current_file = mainw->current_file;
4278
4279 if (strrchr(file_name, '.') == NULL) {
4280 lives_snprintf(full_file_name, PATH_MAX, "%s.%s", file_name, LIVES_FILE_EXT_BACKUP);
4281 allow_over = FALSE;
4282 } else {
4283 lives_snprintf(full_file_name, PATH_MAX, "%s", file_name);
4284 allow_over = TRUE;
4285 }
4286
4287 // check if file exists
4288 if (!check_file(full_file_name, allow_over)) return;
4289
4290 // create header files
4291 retval = write_headers(sfile); // for pre LiVES 0.9.6
4292 retval = save_clip_values(clip); // new style (0.9.6+)
4293
4294 if (!retval) return;
4295
4296 //...and backup
4297 title = get_menu_name(sfile, FALSE);
4298 d_print(_("Backing up %s to %s"), title, full_file_name);
4299 lives_free(title);
4300
4301 if (!mainw->save_with_sound) {
4302 d_print(_(" without sound"));
4303 withsound = 0;
4304 }
4305
4306 d_print("...");
4307 cfile->progress_start = 1;
4308 cfile->progress_end = sfile->frames;
4309
4310 if (sfile->clip_type == CLIP_TYPE_FILE) {
4311 frames_t ret;
4312 char *msg = (_("Pulling frames from clip..."));
4313 if ((ret = realize_all_frames(clip, msg, FALSE)) < cfile->frames) {
4314 lives_free(msg);
4315 cfile->nopreview = FALSE;
4316 if (ret > 0) d_print_cancelled();
4317 return;
4318 }
4319 lives_free(msg);
4320 }
4321
4322 com = lives_strdup_printf("%s backup %s %d %d %d %s", prefs->backend, sfile->handle, withsound,
4323 start, end, (tmp = lives_filename_from_utf8(full_file_name, -1, NULL, NULL, NULL)));
4324 lives_free(tmp);
4325
4326 // TODO
4327 mainw->current_file = clip;
4328
4329 lives_rm(cfile->info_file);
4330 cfile->nopreview = TRUE;
4331 lives_system(com, FALSE);
4332 lives_free(com);
4333
4334 if (THREADVAR(com_failed)) {
4335 THREADVAR(com_failed) = FALSE;
4336 mainw->current_file = current_file;
4337 return;
4338 }
4339
4340 if (!(do_progress_dialog(TRUE, TRUE, _("Backing up"))) || mainw->error) {
4341 if (mainw->error) {
4342 d_print_failed();
4343 }
4344
4345 // cancelled - clear up files
4346 cfile->nopreview = FALSE;
4347
4348 // using restore details in the 'wrong' way here...it will also clear files
4349 com = lives_strdup_printf("%s restore_details %s", prefs->backend, cfile->handle);
4350 lives_popen(com, FALSE, mainw->msg, MAINW_MSG_SIZE);
4351 lives_free(com);
4352
4353 //save_clip_values(mainw->current_file);
4354 mainw->current_file = current_file;
4355 return;
4356 }
4357
4358 cfile->nopreview = FALSE;
4359
4360 mainw->current_file = current_file;
4361
4362 if (mainw->error) {
4363 widget_opts.non_modal = TRUE;
4364 do_error_dialog(mainw->msg);
4365 widget_opts.non_modal = FALSE;
4366 d_print_failed();
4367 return;
4368 }
4369
4370 if (with_perf) {
4371 d_print(_("performance data was backed up..."));
4372 }
4373
4374 array = lives_strsplit(mainw->msg, "|", 3);
4375 sfile->f_size = strtol(array[1], NULL, 10);
4376 lives_strfreev(array);
4377
4378 lives_snprintf(sfile->file_name, PATH_MAX, "%s", full_file_name);
4379 if (!sfile->was_renamed) {
4380 lives_snprintf(sfile->name, CLIP_NAME_MAXLEN, "%s", full_file_name);
4381 set_main_title(cfile->name, 0);
4382 lives_menu_item_set_text(sfile->menuentry, full_file_name, FALSE);
4383 }
4384 if (prefs->show_recent)
4385 add_to_recent(full_file_name, 0., 0, NULL);
4386
4387 sfile->changed = FALSE;
4388 // set is_untitled to stop users from saving with a .lv1 extension
4389 sfile->is_untitled = TRUE;
4390 d_print_done();
4391 }
4392
4393
4394 boolean write_headers(lives_clip_t *file) {
4395 // this function is included only for backwards compatibility with ancient builds of LiVES
4396 //
4397
4398 int retval;
4399 int header_fd;
4400 char *hdrfile;
4401
4402 // save the file details
4403 hdrfile = lives_build_filename(prefs->workdir, file->handle, LIVES_CLIP_HEADER_OLD, NULL);
4404
4405 do {
4406 retval = 0;
4407 header_fd = creat(hdrfile, S_IRUSR | S_IWUSR);
4408 if (header_fd < 0) {
4409 retval = do_write_failed_error_s_with_retry(hdrfile, lives_strerror(errno));
4410 } else {
4411 THREADVAR(write_failed) = FALSE;
4412
4413 lives_write_le(header_fd, &cfile->bpp, 4, TRUE);
4414 lives_write_le(header_fd, &cfile->fps, 8, TRUE);
4415 lives_write_le(header_fd, &cfile->hsize, 4, TRUE);
4416 lives_write_le(header_fd, &cfile->vsize, 4, TRUE);
4417 lives_write_le(header_fd, &cfile->arps, 4, TRUE);
4418 lives_write_le(header_fd, &cfile->signed_endian, 4, TRUE);
4419 lives_write_le(header_fd, &cfile->arate, 4, TRUE);
4420 lives_write_le(header_fd, &cfile->unique_id, 8, TRUE);
4421 lives_write_le(header_fd, &cfile->achans, 4, TRUE);
4422 lives_write_le(header_fd, &cfile->asampsize, 4, TRUE);
4423
4424 lives_write(header_fd, LiVES_VERSION, strlen(LiVES_VERSION), TRUE);
4425 close(header_fd);
4426
4427 if (THREADVAR(write_failed)) retval = do_write_failed_error_s_with_retry(hdrfile, NULL);
4428 }
4429 } while (retval == LIVES_RESPONSE_RETRY);
4430
4431 lives_free(hdrfile);
4432
4433 if (retval != LIVES_RESPONSE_CANCEL) {
4434 // more file details (since version 0.7.5)
4435 hdrfile = lives_build_filename(prefs->workdir, file->handle, LIVES_CLIP_HEADER_OLD2, NULL);
4436
4437 do {
4438 retval = 0;
4439 header_fd = creat(hdrfile, S_IRUSR | S_IWUSR);
4440
4441 if (header_fd < 0) {
4442 retval = do_write_failed_error_s_with_retry(hdrfile, lives_strerror(errno));
4443 } else {
4444 THREADVAR(write_failed) = FALSE;
4445 lives_write_le(header_fd, &file->frames, 4, TRUE);
4446 lives_write(header_fd, &file->title, 1024, TRUE);
4447 lives_write(header_fd, &file->author, 1024, TRUE);
4448 lives_write(header_fd, &file->comment, 1024, TRUE);
4449 close(header_fd);
4450 }
4451 if (THREADVAR(write_failed)) retval = do_write_failed_error_s_with_retry(hdrfile, NULL);
4452 } while (retval == LIVES_RESPONSE_RETRY);
4453
4454 lives_free(hdrfile);
4455 }
4456
4457 if (retval == LIVES_RESPONSE_CANCEL) {
4458 THREADVAR(write_failed) = FALSE;
4459 return FALSE;
4460 }
4461 return TRUE;
4462 }
4463
4464
4465 boolean read_headers(int fileno, const char *dir, const char *file_name) {
4466 // file_name is only used to get the file size on the disk
4467 lives_clip_t *sfile;
4468 char **array;
4469 char buff[1024];
4470 char version[32];
4471 char *com, *tmp;
4472 char *old_hdrfile, *lives_header = NULL;
4473
4474 off_t header_size;
4475 int version_hash;
4476 int pieces;
4477 int header_fd;
4478 int retval2;
4479 int asigned = 0, aendian = LIVES_LITTLE_ENDIAN;
4480
4481 lives_clip_details_t detail;
4482
4483 boolean retval, retvala;
4484 boolean is_ascrap = FALSE;
4485
4486 off_t sizhead = 28; //8 * 4 + 8 + 8;
4487
4488 time_t old_time = 0, new_time = 1;
4489 struct stat mystat;
4490
4491 if (!IS_VALID_CLIP(fileno)) return FALSE;
4492
4493 if (mainw->hdrs_cache) cached_list_free(&mainw->hdrs_cache);
4494
4495 sfile = mainw->files[fileno];
4496
4497 old_hdrfile = lives_build_filename(dir, LIVES_CLIP_HEADER_OLD, NULL);
4498
4499 if (fileno == mainw->ascrap_file) {
4500 is_ascrap = TRUE;
4501 /// ascrap_file now uses a different header name; this is to facilitate diskspace cleanup
4502 /// otherwise it may be wrongly classified as a recoverable clip
4503 lives_header = lives_build_filename(dir, LIVES_ACLIP_HEADER, NULL);
4504 if (!lives_file_test(lives_header, LIVES_FILE_TEST_EXISTS)) {
4505 lives_free(lives_header);
4506 lives_header = NULL;
4507 }
4508 }
4509 if (!lives_header) lives_header = lives_build_filename(dir, LIVES_CLIP_HEADER, NULL);
4510
4511 sfile->checked_for_old_header = TRUE;
4512 sfile->img_type = IMG_TYPE_UNKNOWN;
4513
4514 if (lives_file_test(lives_header, LIVES_FILE_TEST_EXISTS)) {
4515 do {
4516 retval2 = LIVES_RESPONSE_OK;
4517 if (!(mainw->hdrs_cache = cache_file_contents(lives_header))) {
4518 if (fileno != mainw->current_file) goto rhd_failed;
4519 retval2 = do_read_failed_error_s_with_retry(lives_header, NULL);
4520 }
4521 } while (retval2 == LIVES_RESPONSE_RETRY);
4522
4523 if (retval2 == LIVES_RESPONSE_CANCEL) {
4524 goto rhd_failed;
4525 }
4526
4527 if (fileno == mainw->current_file) {
4528 threaded_dialog_spin(0.);
4529 }
4530
4531 if (!is_ascrap) restore_clip_binfmt(fileno);
4532
4533 do {
4534 do {
4535 detail = CLIP_DETAILS_HEADER_VERSION;
4536 retval = get_clip_value(fileno, detail, &sfile->header_version, 16);
4537 if (retval) {
4538 if (sfile->header_version < 100) goto old_check;
4539 } else {
4540 if (lives_file_test(old_hdrfile, LIVES_FILE_TEST_EXISTS)) {
4541 goto old_check;
4542 }
4543 if (fileno != mainw->current_file) {
4544 goto rhd_failed;
4545 }
4546 if (mainw->hdrs_cache) {
4547 retval2 = do_header_missing_detail_error(fileno, CLIP_DETAILS_HEADER_VERSION);
4548 } else {
4549 retval2 = do_header_read_error_with_retry(fileno);
4550 }
4551 }
4552 } while (retval2 == LIVES_RESPONSE_RETRY);
4553
4554 if (retval2 == LIVES_RESPONSE_CANCEL) goto rhd_failed;
4555
4556 if (is_ascrap) goto get_avals;
4557
4558 detail = CLIP_DETAILS_FRAMES;
4559 retval = get_clip_value(fileno, detail, &sfile->frames, 0);
4560
4561 if (retval) {
4562 detail = CLIP_DETAILS_BPP;
4563 retval = get_clip_value(fileno, detail, &sfile->bpp, 0);
4564 }
4565 if (retval) {
4566 detail = CLIP_DETAILS_FPS;
4567 retval = get_clip_value(fileno, detail, &sfile->fps, 0);
4568 }
4569 if (retval) {
4570 detail = CLIP_DETAILS_PB_FPS;
4571 retval = get_clip_value(fileno, detail, &sfile->pb_fps, 0);
4572 if (!retval) {
4573 retval = TRUE;
4574 sfile->pb_fps = sfile->fps;
4575 }
4576 }
4577 if (retval) {
4578 retval = get_clip_value(fileno, CLIP_DETAILS_PB_FRAMENO, &sfile->frameno, 0);
4579 if (!retval) {
4580 retval = TRUE;
4581 sfile->frameno = 1;
4582 }
4583 if (sfile->frameno <= 0) sfile->frameno = 1;
4584 }
4585 if (retval) {
4586 detail = CLIP_DETAILS_WIDTH;
4587 retval = get_clip_value(fileno, detail, &sfile->hsize, 0);
4588 }
4589 if (retval) {
4590 detail = CLIP_DETAILS_HEIGHT;
4591 retval = get_clip_value(fileno, detail, &sfile->vsize, 0);
4592 }
4593 if (retval) {
4594 if (sfile->header_version > 100) {
4595 detail = CLIP_DETAILS_GAMMA_TYPE;
4596 get_clip_value(fileno, detail, &sfile->gamma_type, 0);
4597 if (sfile->gamma_type == 0) sfile->gamma_type = WEED_GAMMA_SRGB;
4598 if (sfile->gamma_type != WEED_GAMMA_SRGB) {
4599 if (!do_gamma_import_warn(sfile->has_binfmt ?
4600 sfile->binfmt_version.num : 0, sfile->gamma_type)) goto rhd_failed;
4601 }
4602 }
4603 }
4604 if (retval) {
4605 detail = CLIP_DETAILS_CLIPNAME;
4606 get_clip_value(fileno, detail, sfile->name, CLIP_NAME_MAXLEN);
4607 }
4608 if (retval) {
4609 detail = CLIP_DETAILS_FILENAME;
4610 get_clip_value(fileno, detail, sfile->file_name, PATH_MAX);
4611 }
4612
4613 get_avals:
4614 if (retval) {
4615 detail = CLIP_DETAILS_ACHANS;
4616 retvala = get_clip_value(fileno, detail, &sfile->achans, 0);
4617 if (!retvala) sfile->achans = 0;
4618 }
4619
4620 if (sfile->achans == 0) retvala = FALSE;
4621 else retvala = TRUE;
4622
4623 if (retval && retvala) {
4624 detail = CLIP_DETAILS_ARATE;
4625 retvala = get_clip_value(fileno, detail, &sfile->arps, 0);
4626 }
4627
4628 if (!retvala) sfile->arps = sfile->achans = sfile->arate = sfile->asampsize = 0;
4629 if (sfile->arps == 0) retvala = FALSE;
4630
4631 if (retvala && retval) {
4632 detail = CLIP_DETAILS_PB_ARATE;
4633 retvala = get_clip_value(fileno, detail, &sfile->arate, 0);
4634 if (!retvala) {
4635 retvala = TRUE;
4636 sfile->arate = sfile->arps;
4637 }
4638 }
4639 if (retvala && retval) {
4640 detail = CLIP_DETAILS_ASIGNED;
4641 retval = get_clip_value(fileno, detail, &asigned, 0);
4642 }
4643 if (retvala && retval) {
4644 detail = CLIP_DETAILS_AENDIAN;
4645 retval = get_clip_value(fileno, detail, &aendian, 0);
4646 }
4647
4648 sfile->signed_endian = asigned + aendian;
4649
4650 if (retvala && retval) {
4651 detail = CLIP_DETAILS_ASAMPS;
4652 retval = get_clip_value(fileno, detail, &sfile->asampsize, 0);
4653 }
4654 if (!retval) {
4655 if (fileno != mainw->current_file) goto rhd_failed;
4656 if (mainw->hdrs_cache) {
4657 retval2 = do_header_missing_detail_error(fileno, detail);
4658 } else {
4659 retval2 = do_header_read_error_with_retry(fileno);
4660 }
4661 } else {
4662 if (!is_ascrap) {
4663 get_clip_value(fileno, CLIP_DETAILS_TITLE, sfile->title, 1024);
4664 get_clip_value(fileno, CLIP_DETAILS_AUTHOR, sfile->author, 1024);
4665 get_clip_value(fileno, CLIP_DETAILS_COMMENT, sfile->comment, 1024);
4666 get_clip_value(fileno, CLIP_DETAILS_KEYWORDS, sfile->keywords, 1024);
4667 get_clip_value(fileno, CLIP_DETAILS_INTERLACE, &sfile->interlace, 0);
4668 // user must have selected this:
4669 if (sfile->interlace != LIVES_INTERLACE_NONE) sfile->deinterlace = TRUE;
4670 }
4671 lives_free(old_hdrfile);
4672 lives_free(lives_header);
4673 if (!prefs->vj_mode) {
4674 sfile->afilesize = reget_afilesize_inner(fileno);
4675 }
4676 /// need to maintain mainw->hdrs_cache in this case, as it may be
4677 // passed to further functions, but it needs to be freed and set to NULL
4678 // at some point
4679 return TRUE;
4680 }
4681 } while (retval2 == LIVES_RESPONSE_RETRY);
4682 goto rhd_failed;
4683 }
4684
4685 old_check:
4686
4687 if (lives_file_test(old_hdrfile, LIVES_FILE_TEST_EXISTS)) {
4688 sfile->has_old_header = TRUE;
4689 if (!stat(old_hdrfile, &mystat)) old_time = mystat.st_mtime;
4690 if (!stat(lives_header, &mystat)) new_time = mystat.st_mtime;
4691 }
4692
4693 lives_free(lives_header);
4694 lives_header = NULL;
4695 ///////////////
4696
4697 if (sfile->has_old_header && old_time <= new_time) {
4698 retval2 = LIVES_RESPONSE_OK;
4699 detail = CLIP_DETAILS_FRAMES;
4700
4701 if (get_clip_value(fileno, detail, &sfile->frames, 0)) {
4702 char *tmp;
4703
4704 // use new style header (LiVES 0.9.6+)
4705 // clean up and get file sizes
4706 if (file_name) {
4707 com = lives_strdup_printf("%s restore_details \"%s\" \"%s\" 0",
4708 prefs->backend_sync, sfile->handle,
4709 (tmp = lives_filename_from_utf8(file_name, -1, NULL, NULL, NULL)));
4710 lives_free(tmp);
4711 } else
4712 com = lives_strdup_printf("%s restore_details \"%s\" . 1", prefs->backend_sync, sfile->handle);
4713
4714 lives_popen(com, fileno != mainw->current_file, buff, 1024);
4715 lives_free(com);
4716
4717 if (THREADVAR(com_failed)) {
4718 THREADVAR(com_failed) = FALSE;
4719 goto rhd_failed;
4720 }
4721
4722 pieces = get_token_count(buff, '|');
4723
4724 if (pieces > 3) {
4725 array = lives_strsplit(buff, "|", pieces);
4726 sfile->f_size = strtol(array[1], NULL, 10);
4727 sfile->afilesize = strtol(array[2], NULL, 10);
4728 if (sfile->clip_type == CLIP_TYPE_DISK) {
4729 if (!strcmp(array[3], LIVES_FILE_EXT_JPG)) sfile->img_type = IMG_TYPE_JPEG;
4730 else sfile->img_type = IMG_TYPE_PNG;
4731 }
4732 lives_strfreev(array);
4733 }
4734 if (fileno == mainw->current_file) threaded_dialog_spin(0.);
4735 } else goto rhd_failed;
4736 lives_free(old_hdrfile);
4737 /// mainw->hdrs_cache never set
4738 return TRUE;
4739 }
4740
4741 do {
4742 // old style headers (pre 0.9.6)
4743 retval = LIVES_RESPONSE_OK;
4744 THREADVAR(read_failed) = FALSE;
4745 lives_memset(version, 0, 32);
4746 lives_memset(buff, 0, 1024);
4747
4748 header_fd = lives_open2(old_hdrfile, O_RDONLY);
4749
4750 if (header_fd < 0) {
4751 if (fileno != mainw->current_file) {
4752 goto rhd_failed;
4753 }
4754 retval = do_read_failed_error_s_with_retry(old_hdrfile, lives_strerror(errno));
4755 } else {
4756 THREADVAR(read_failed) = FALSE;
4757 header_size = get_file_size(header_fd);
4758
4759 if (header_size < sizhead) {
4760 close(header_fd);
4761 goto rhd_failed;
4762 } else {
4763 THREADVAR(read_failed) = FALSE;
4764 lives_read_le(header_fd, &sfile->fps, 4, FALSE);
4765 if (!THREADVAR(read_failed))
4766 lives_read_le(header_fd, &sfile->bpp, 8, FALSE);
4767 if (!THREADVAR(read_failed))
4768 lives_read_le(header_fd, &sfile->hsize, 4, FALSE);
4769 if (!THREADVAR(read_failed))
4770 lives_read_le(header_fd, &sfile->vsize, 4, FALSE);
4771 if (!THREADVAR(read_failed))
4772 lives_read_le(header_fd, &sfile->arps, 4, FALSE);
4773 if (!THREADVAR(read_failed))
4774 lives_read_le(header_fd, &sfile->signed_endian, 4, FALSE);
4775 if (!THREADVAR(read_failed))
4776 lives_read_le(header_fd, &sfile->arate, 4, FALSE);
4777 if (!THREADVAR(read_failed))
4778 lives_read_le(header_fd, &sfile->unique_id, 8, FALSE);
4779 if (!THREADVAR(read_failed))
4780 lives_read_le(header_fd, &sfile->achans, 4, FALSE);
4781 if (!THREADVAR(read_failed))
4782 lives_read_le(header_fd, &sfile->asampsize, 4, FALSE);
4783
4784 if (header_size > sizhead) {
4785 if (header_size - sizhead > 31) {
4786 if (!THREADVAR(read_failed))
4787 lives_read(header_fd, &version, 31, FALSE);
4788 version[31] = '\0';
4789 } else {
4790 if (!THREADVAR(read_failed))
4791 lives_read(header_fd, &version, header_size - sizhead, FALSE);
4792 version[header_size - sizhead] = '\0';
4793 }
4794 }
4795 }
4796 close(header_fd);
4797 }
4798
4799 if (THREADVAR(read_failed)) {
4800 if (fileno != mainw->current_file) goto rhd_failed;
4801 retval = do_read_failed_error_s_with_retry(old_hdrfile, NULL);
4802 if (retval == LIVES_RESPONSE_CANCEL) goto rhd_failed;
4803 }
4804 } while (retval == LIVES_RESPONSE_RETRY);
4805
4806 lives_freep((void **)&old_hdrfile);
4807
4808 if (retval == LIVES_RESPONSE_CANCEL) goto rhd_failed;
4809
4810 // handle version changes
4811 version_hash = verhash(version);
4812 if (version_hash < 7001) {
4813 sfile->arps = sfile->arate;
4814 sfile->signed_endian = mainw->endian;
4815 }
4816
4817 com = lives_strdup_printf("%s restore_details %s %s %d", prefs->backend_sync, sfile->handle,
4818 (tmp = lives_filename_from_utf8(file_name, -1, NULL, NULL, NULL)),
4819 !strcmp(file_name, "."));
4820
4821 lives_popen(com, FALSE, buff, 1024);
4822 lives_free(com);
4823 lives_free(tmp);
4824
4825 if (THREADVAR(com_failed)) {
4826 THREADVAR(com_failed) = FALSE;
4827 goto rhd_failed;
4828 }
4829
4830 pieces = get_token_count(buff, '|');
4831 array = lives_strsplit(buff, "|", pieces);
4832 sfile->f_size = strtol(array[1], NULL, 10);
4833 sfile->afilesize = strtol(array[2], NULL, 10);
4834
4835 if (sfile->clip_type == CLIP_TYPE_DISK) {
4836 if (!strcmp(array[3], LIVES_FILE_EXT_JPG)) sfile->img_type = IMG_TYPE_JPEG;
4837 else sfile->img_type = IMG_TYPE_PNG;
4838 }
4839
4840 sfile->frames = atoi(array[4]);
4841
4842 sfile->bpp = (sfile->img_type == IMG_TYPE_JPEG) ? 24 : 32;
4843
4844 if (pieces > 4 && array[5]) {
4845 lives_snprintf(sfile->title, 1024, "%s", lives_strstrip(array[4]));
4846 }
4847 if (pieces > 5 && array[6]) {
4848 lives_snprintf(sfile->author, 1024, "%s", lives_strstrip(array[5]));
4849 }
4850 if (pieces > 6 && array[7]) {
4851 lives_snprintf(sfile->comment, 1024, "%s", lives_strstrip(array[6]));
4852 }
4853
4854 lives_strfreev(array);
4855 return TRUE;
4856
4857 rhd_failed:
4858 lives_freep((void **)&lives_header);
4859 lives_freep((void **)&old_hdrfile);
4860 return FALSE;
4861 }
4862
4863
4864 void open_set_file(int clipnum) {
4865 char name[CLIP_NAME_MAXLEN];
4866
4867 if (mainw->current_file < 1) return;
4868
4869 lives_memset(name, 0, CLIP_NAME_MAXLEN);
4870
4871 if (mainw->hdrs_cache) {
4872 boolean retval;
4873 // LiVES 0.9.6+
4874
4875 retval = get_clip_value(mainw->current_file, CLIP_DETAILS_PB_FPS, &cfile->pb_fps, 0);
4876 if (!retval) {
4877 cfile->pb_fps = cfile->fps;
4878 }
4879 retval = get_clip_value(mainw->current_file, CLIP_DETAILS_PB_FRAMENO, &cfile->frameno, 0);
4880 if (!retval) {
4881 cfile->frameno = 1;
4882 }
4883
4884 retval = get_clip_value(mainw->current_file, CLIP_DETAILS_CLIPNAME, name, CLIP_NAME_MAXLEN);
4885 if (!retval) {
4886 char *tmp;
4887 lives_snprintf(name, CLIP_NAME_MAXLEN, "%s", (tmp = get_untitled_name(mainw->untitled_number++)));
4888 lives_free(tmp);
4889 cfile->needs_update = TRUE;
4890 }
4891 retval = get_clip_value(mainw->current_file, CLIP_DETAILS_UNIQUE_ID, &cfile->unique_id, 0);
4892 if (!retval) {
4893 cfile->unique_id = gen_unique_id();
4894 cfile->needs_silent_update = TRUE;
4895 }
4896 retval = get_clip_value(mainw->current_file, CLIP_DETAILS_INTERLACE, &cfile->interlace, 0);
4897 if (!retval) {
4898 cfile->interlace = LIVES_INTERLACE_NONE;
4899 cfile->needs_silent_update = TRUE;
4900 }
4901 if (cfile->interlace != LIVES_INTERLACE_NONE) cfile->deinterlace = TRUE;
4902 } else {
4903 // pre 0.9.6 <- ancient code
4904 ssize_t nlen;
4905 int set_fd;
4906 int pb_fps;
4907 int retval;
4908 char *setfile = lives_strdup_printf("%s/%s/set.%s", prefs->workdir, cfile->handle, mainw->set_name);
4909
4910 do {
4911 retval = 0;
4912 if ((set_fd = lives_open2(setfile, O_RDONLY)) > -1) {
4913 // get perf_start
4914 if ((nlen = lives_read_le(set_fd, &pb_fps, 4, TRUE)) > 0) {
4915 cfile->pb_fps = pb_fps / 1000.;
4916 lives_read_le(set_fd, &cfile->frameno, 4, TRUE);
4917 lives_read(set_fd, name, CLIP_NAME_MAXLEN, TRUE);
4918 }
4919 close(set_fd);
4920 } else retval = do_read_failed_error_s_with_retry(setfile, lives_strerror(errno));
4921 } while (retval == LIVES_RESPONSE_RETRY);
4922
4923 lives_free(setfile);
4924 cfile->needs_silent_update = TRUE;
4925 }
4926
4927 if (!*name) {
4928 lives_snprintf(name, CLIP_NAME_MAXLEN, "set_clip %.3d", clipnum);
4929 } else {
4930 // pre 3.x, files erroneously had the set name appended permanently, so here we undo that
4931 if (lives_string_ends_with(name, " (%s)", mainw->set_name)) {
4932 char *remove = lives_strdup_printf(" (%s)", mainw->set_name);
4933 if (strlen(name) > strlen(remove)) name[strlen(name) - strlen(remove)] = 0;
4934 lives_free(remove);
4935 cfile->needs_silent_update = TRUE;
4936 }
4937 lives_snprintf(cfile->name, CLIP_NAME_MAXLEN, "%s", name);
4938 }
4939 }
4940
4941
4942 void reload_subs(int fileno) {
4943 lives_clip_t *sfile;
4944 char *subfname;
4945 if (!IS_VALID_CLIP(fileno)) return;
4946
4947 sfile = mainw->files[fileno];
4948 subfname = lives_build_filename(prefs->workdir, sfile->handle, SUBS_FILENAME "."
4949 LIVES_FILE_EXT_SRT, NULL);
4950 if (lives_file_test(subfname, LIVES_FILE_TEST_EXISTS)) {
4951 subtitles_init(sfile, subfname, SUBTITLE_TYPE_SRT);
4952 } else {
4953 lives_free(subfname);
4954 subfname = lives_build_filename(prefs->workdir, sfile->handle, SUBS_FILENAME "."
4955 LIVES_FILE_EXT_SUB, NULL);
4956 if (lives_file_test(subfname, LIVES_FILE_TEST_EXISTS)) {
4957 subtitles_init(sfile, subfname, SUBTITLE_TYPE_SUB);
4958 }
4959 }
4960 lives_free(subfname);
4961 }
4962
4963
4964 ulong restore_file(const char *file_name) {
4965 char *com = lives_strdup("dummy");
4966 char *mesg, *mesg1, *tmp;
4967 boolean is_OK = TRUE;
4968 char *fname = lives_strdup(file_name);
4969 char *clipdir;
4970
4971 int old_file = mainw->current_file, current_file;
4972 int new_file = mainw->first_free_file;
4973 boolean not_cancelled;
4974
4975 // create a new file
4976 if (!get_new_handle(new_file, fname)) {
4977 return 0;
4978 }
4979
4980 d_print(_("Restoring %s..."), file_name);
4981
4982 mainw->current_file = new_file;
4983
4984 cfile->hsize = mainw->def_width;
4985 cfile->vsize = mainw->def_height;
4986
4987 if (!mainw->multitrack) {
4988 switch_to_file((mainw->current_file = old_file), new_file);
4989 set_main_title(cfile->file_name, 0);
4990 }
4991
4992 com = lives_strdup_printf("%s restore %s %s", prefs->backend, cfile->handle,
4993 (tmp = lives_filename_from_utf8(file_name, -1, NULL, NULL, NULL)));
4994
4995 lives_rm(cfile->info_file);
4996 lives_system(com, FALSE);
4997 lives_free(tmp);
4998 lives_free(com);
4999
5000 if (THREADVAR(com_failed)) {
5001 THREADVAR(com_failed) = FALSE;
5002 close_current_file(old_file);
5003 return 0;
5004 }
5005
5006 cfile->restoring = TRUE;
5007 not_cancelled = do_progress_dialog(TRUE, TRUE, _("Restoring"));
5008 cfile->restoring = FALSE;
5009
5010 if (mainw->error || !not_cancelled) {
5011 if (mainw->error && mainw->cancelled != CANCEL_ERROR) {
5012 do_error_dialog(mainw->msg);
5013 }
5014 close_current_file(old_file);
5015 return 0;
5016 }
5017
5018 // call function to return rest of file details
5019 // fsize, afilesize and frames
5020 clipdir = lives_build_path(prefs->workdir, cfile->handle, NULL);
5021 is_OK = read_headers(mainw->current_file, clipdir, file_name);
5022 lives_free(clipdir);
5023 if (mainw->hdrs_cache) cached_list_free(&mainw->hdrs_cache);
5024
5025 if (!is_OK) {
5026 mesg = lives_strdup_printf(_("\n\nThe file %s is corrupt.\nLiVES was unable to restore it.\n"),
5027 file_name);
5028 do_error_dialog(mesg);
5029 lives_free(mesg);
5030
5031 d_print_failed();
5032 close_current_file(old_file);
5033 return 0;
5034 }
5035
5036 // get img_type, check frame count and size
5037 if (!cfile->checked && !check_clip_integrity(mainw->current_file, NULL, cfile->frames)) {
5038 if (cfile->afilesize == 0) {
5039 reget_afilesize_inner(mainw->current_file);
5040 }
5041 if (!check_frame_count(mainw->current_file, FALSE)) {
5042 cfile->frames = get_frame_count(mainw->current_file, 1);
5043 }
5044 }
5045 cfile->checked = TRUE;
5046
5047 // add entry to window menu
5048 // TODO - do this earlier and allow switching during restore
5049 add_to_clipmenu();
5050
5051 if (prefs->show_recent) {
5052 add_to_recent(file_name, 0., 0, NULL);
5053 }
5054
5055 if (cfile->frames > 0) {
5056 cfile->start = 1;
5057 } else {
5058 cfile->start = 0;
5059 }
5060 cfile->end = cfile->frames;
5061 cfile->arps = cfile->arate;
5062 cfile->pb_fps = cfile->fps;
5063 cfile->opening = FALSE;
5064 cfile->changed = FALSE;
5065
5066 if (prefs->autoload_subs) {
5067 reload_subs(mainw->current_file);
5068 }
5069
5070 lives_snprintf(cfile->type, 40, "Frames");
5071 mesg1 = lives_strdup_printf(_("Frames=%d type=%s size=%dx%d bpp=%d fps=%.3f\nAudio:"), cfile->frames, cfile->type,
5072 cfile->hsize, cfile->vsize, cfile->bpp, cfile->fps);
5073
5074 if (cfile->afilesize == 0l) {
5075 cfile->achans = 0;
5076 mesg = lives_strdup_printf(_("%s none\n"), mesg1);
5077 } else {
5078 mesg = lives_strdup_printf(P_("%s %d Hz %d channel %d bps\n", "%s %d Hz %d channels %d bps\n", cfile->achans),
5079 mesg1, cfile->arate, cfile->achans, cfile->asampsize);
5080 }
5081 d_print(mesg);
5082 lives_free(mesg);
5083 lives_free(mesg1);
5084
5085 cfile->is_loaded = TRUE;
5086 current_file = mainw->current_file;
5087
5088 // set new bpp
5089 cfile->bpp = (cfile->img_type == IMG_TYPE_JPEG) ? 24 : 32;
5090
5091 cfile->saved_frameno = cfile->frameno;
5092 if (cfile->frameno > cfile->frames && cfile->frameno > 1) cfile->frameno = cfile->frames;
5093 cfile->last_frameno = cfile->frameno;
5094 cfile->pointer_time = cfile->real_pointer_time = calc_time_from_frame(mainw->current_file, cfile->frameno);
5095 if (cfile->real_pointer_time > CLIP_TOTAL_TIME(mainw->current_file))
5096 cfile->real_pointer_time = CLIP_TOTAL_TIME(mainw->current_file);
5097 if (cfile->pointer_time > cfile->video_time) cfile->pointer_time = 0.;
5098
5099 if (cfile->achans) {
5100 cfile->aseek_pos = (off64_t)((double)(cfile->real_pointer_time * cfile->arate) * cfile->achans *
5101 (cfile->asampsize / 8));
5102 if (cfile->aseek_pos > cfile->afilesize) cfile->aseek_pos = 0.;
5103 }
5104
5105 if (!save_clip_values(current_file)) {
5106 close_current_file(old_file);
5107 return 0;
5108 }
5109
5110 if (prefs->crash_recovery) add_to_recovery_file(cfile->handle);
5111
5112 if (!mainw->multitrack) {
5113 switch_to_file((mainw->current_file = old_file), current_file);
5114 }
5115 lives_notify(LIVES_OSC_NOTIFY_CLIP_OPENED, "");
5116
5117 return cfile->unique_id;
5118 }
5119
5120
5121 int save_event_frames(void) {
5122 // when doing a resample, we save a list of frames for the back end to do
5123 // a reorder
5124
5125 // here we also update the frame_index for clips of type CLIP_TYPE_FILE
5126
5127 char *hdrfile = lives_strdup_printf("%s/%s/event.frames", prefs->workdir, cfile->handle);
5128
5129 int header_fd, i = 0;
5130 int retval;
5131 int perf_start, perf_end;
5132 int nevents;
5133
5134 if (!cfile->event_list) {
5135 lives_rm(hdrfile);
5136 return -1;
5137 }
5138
5139 perf_start = (int)(cfile->fps * event_list_get_start_secs(cfile->event_list)) + 1;
5140 perf_end = perf_start + (nevents = count_events(cfile->event_list, FALSE, 0, 0)) - 1;
5141
5142 if (!event_list_to_block(cfile->event_list, nevents)) return -1;
5143
5144 if (cfile->frame_index) {
5145 LiVESResponseType response;
5146 int xframes = cfile->frames;
5147 char *what = (_("creating the frame index for resampling "));
5148
5149 if (cfile->frame_index_back) lives_free(cfile->frame_index_back);
5150 cfile->frame_index_back = cfile->frame_index;
5151 cfile->frame_index = NULL;
5152
5153 do {
5154 response = LIVES_RESPONSE_OK;
5155 create_frame_index(mainw->current_file, FALSE, 0, nevents);
5156 if (!cfile->frame_index) {
5157 response = do_memory_error_dialog(what, nevents * 4);
5158 }
5159 } while (response == LIVES_RESPONSE_RETRY);
5160 lives_free(what);
5161 if (response == LIVES_RESPONSE_CANCEL) {
5162 cfile->frame_index = cfile->frame_index_back;
5163 cfile->frame_index_back = NULL;
5164 return -1;
5165 }
5166
5167 for (i = 0; i < nevents; i++) {
5168 cfile->frame_index[i] = cfile->frame_index_back[(cfile->resample_events + i)->value - 1];
5169 }
5170
5171 cfile->frames = nevents;
5172 if (!check_if_non_virtual(mainw->current_file, 1, cfile->frames)) save_frame_index(mainw->current_file);
5173 cfile->frames = xframes;
5174 }
5175
5176 do {
5177 retval = 0;
5178 header_fd = creat(hdrfile, S_IRUSR | S_IWUSR);
5179 if (header_fd < 0) {
5180 retval = do_write_failed_error_s_with_retry(hdrfile, lives_strerror(errno));
5181 } else {
5182 // use machine endian.
5183 // When we call "smogrify reorder", we will pass the endianness as 3rd parameter
5184
5185 THREADVAR(write_failed) = FALSE;
5186 lives_write(header_fd, &perf_start, 4, FALSE);
5187
5188 if (cfile->resample_events) {
5189 for (i = 0; i <= perf_end - perf_start; i++) {
5190 if (THREADVAR(write_failed)) break;
5191 lives_write(header_fd, &((cfile->resample_events + i)->value), 4, TRUE);
5192 }
5193 lives_freep((void **)&cfile->resample_events);
5194 }
5195
5196 if (THREADVAR(write_failed)) {
5197 retval = do_write_failed_error_s_with_retry(hdrfile, NULL);
5198 }
5199
5200 close(header_fd);
5201 }
5202 } while (retval == LIVES_RESPONSE_RETRY);
5203
5204 if (retval == LIVES_RESPONSE_CANCEL) {
5205 i = -1;
5206 }
5207
5208 lives_free(hdrfile);
5209 return i;
5210 }
5211
5212
5213 /////////////////////////////////////////////////
5214 /// scrap file
5215 /// the scrap file is used during recording to dump any streamed (non-disk) clips to
5216 /// during render/preview we load frames from the scrap file, but only as necessary
5217
5218 /// ascrap file
5219 /// this is used to record external audio during playback with record on (if the user requests this)
5220 /// afterwards the audio from it can be rendered/played back
5221
5222 static double ascrap_mb; // MB written to audio file
5223 static uint64_t free_mb; // MB free to write
5224
5225 void add_to_ascrap_mb(uint64_t bytes) {
5226 ascrap_mb += bytes / 1000000.;
5227 }
5228
5229
5230 boolean open_scrap_file(void) {
5231 // create a scrap file for recording generated video frames
5232 int current_file = mainw->current_file;
5233 char *dir;
5234 char *handle, *scrap_handle;
5235
5236 if (!check_for_executable(&capable->has_mktemp, EXEC_MKTEMP)) {
5237 do_program_not_found_error(EXEC_MKTEMP);
5238 return FALSE;
5239 }
5240
5241 handle = get_worktmp("_scrap");
5242 if (!handle) {
5243 workdir_warning();
5244 return FALSE;
5245 }
5246 if (!create_cfile(-1, handle, FALSE)) {
5247 dir = lives_build_path(prefs->workdir, cfile->handle, NULL);
5248 lives_rmdir(dir, FALSE);
5249 lives_free(dir); lives_free(handle);
5250 return FALSE;
5251 }
5252 lives_free(handle);
5253
5254 mainw->scrap_file = mainw->current_file;
5255
5256 lives_snprintf(cfile->type, 40, "scrap");
5257
5258 scrap_handle = lives_strdup_printf("scrap|%s", cfile->handle);
5259 if (prefs->crash_recovery) add_to_recovery_file(scrap_handle);
5260 lives_free(scrap_handle);
5261
5262 pthread_mutex_lock(&mainw->clip_list_mutex);
5263 mainw->cliplist = lives_list_append(mainw->cliplist, LIVES_INT_TO_POINTER(mainw->current_file));
5264 pthread_mutex_unlock(&mainw->clip_list_mutex);
5265
5266 dir = lives_build_path(prefs->workdir, cfile->handle, NULL);
5267 free_mb = (double)get_ds_free(dir) / (double)ONE_MILLION;
5268 lives_free(dir);
5269
5270 mainw->current_file = current_file;
5271
5272 if (mainw->ascrap_file == -1) ascrap_mb = 0.;
5273
5274 return TRUE;
5275 }
5276
5277
5278 boolean open_ascrap_file(void) {
5279 // create a scrap file for recording audio
5280 int current_file = mainw->current_file;
5281 char *dir;
5282 char *handle, *ascrap_handle;
5283
5284 if (!check_for_executable(&capable->has_mktemp, EXEC_MKTEMP)) {
5285 do_program_not_found_error(EXEC_MKTEMP);
5286 return FALSE;
5287 }
5288
5289 handle = get_worktmp("_ascrap");
5290 if (!handle) {
5291 workdir_warning();
5292 return FALSE;
5293 }
5294 if (!create_cfile(-1, handle, FALSE)) {
5295 dir = lives_build_path(prefs->workdir, cfile->handle, NULL);
5296 lives_rmdir(dir, FALSE);
5297 lives_free(dir); lives_free(handle);
5298 return FALSE;
5299 }
5300 lives_free(handle);
5301
5302 mainw->ascrap_file = mainw->current_file;
5303 lives_snprintf(cfile->type, 40, "ascrap");
5304
5305 cfile->opening = FALSE;
5306
5307 cfile->achans = 2;
5308 cfile->arate = cfile->arps = DEFAULT_AUDIO_RATE;
5309 cfile->asampsize = 16;
5310 cfile->signed_endian = 0; // ???
5311
5312 #ifdef HAVE_PULSE_AUDIO
5313 if (prefs->audio_player == AUD_PLAYER_PULSE) {
5314 if (prefs->audio_src == AUDIO_SRC_EXT) {
5315 if (mainw->pulsed_read) {
5316 cfile->arate = cfile->arps = mainw->pulsed_read->in_arate;
5317 }
5318 } else {
5319 if (mainw->pulsed) {
5320 cfile->arate = cfile->arps = mainw->pulsed->out_arate;
5321 }
5322 }
5323 }
5324 #endif
5325
5326 #ifdef ENABLE_JACK
5327 if (prefs->audio_player == AUD_PLAYER_JACK) {
5328 if (prefs->audio_src == AUDIO_SRC_EXT) {
5329 if (mainw->jackd_read) {
5330 cfile->arate = cfile->arps = mainw->jackd_read->sample_in_rate;
5331 }
5332 } else {
5333 if (mainw->jackd) {
5334 cfile->arate = cfile->arps = mainw->jackd->sample_out_rate;
5335 }
5336 }
5337 }
5338 #endif
5339
5340 ascrap_handle = lives_strdup_printf("ascrap|%s", cfile->handle);
5341 if (prefs->crash_recovery) add_to_recovery_file(ascrap_handle);
5342 lives_free(ascrap_handle);
5343
5344 pthread_mutex_lock(&mainw->clip_list_mutex);
5345 mainw->cliplist = lives_list_append(mainw->cliplist, LIVES_INT_TO_POINTER(mainw->current_file));
5346 pthread_mutex_unlock(&mainw->clip_list_mutex);
5347
5348 dir = lives_build_path(prefs->workdir, cfile->handle, NULL);
5349 free_mb = (double)get_ds_free(dir) / (double)ONE_MILLION;
5350 lives_free(dir);
5351
5352 mainw->current_file = current_file;
5353
5354 ascrap_mb = 0.;
5355
5356 return TRUE;
5357 }
5358
5359
5360 boolean load_from_scrap_file(weed_layer_t *layer, int frame) {
5361 // load raw frame data from scrap file
5362
5363 // this will also set cfile width and height - for letterboxing etc.
5364
5365 // return FALSE if the frame does not exist/we are unable to read it
5366
5367 char *oname;
5368
5369 lives_clip_t *scrapfile = mainw->files[mainw->scrap_file];
5370
5371 int fd;
5372 if (!IS_VALID_CLIP(mainw->scrap_file)) return FALSE;
5373
5374 if (!scrapfile->ext_src) {
5375 oname = make_image_file_name(scrapfile, 1, LIVES_FILE_EXT_SCRAP);
5376 fd = lives_open_buffered_rdonly(oname);
5377 lives_free(oname);
5378 if (fd < 0) return FALSE;
5379 #ifdef HAVE_POSIX_FADVISE
5380 posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
5381 #endif
5382 scrapfile->ext_src = LIVES_INT_TO_POINTER(fd);
5383 scrapfile->ext_src_type = LIVES_EXT_SRC_FILE_BUFF;
5384 } else fd = LIVES_POINTER_TO_INT(scrapfile->ext_src);
5385
5386 if (frame < 0 || !layer) return TRUE; /// just open fd
5387
5388 if (!weed_plant_deserialise(fd, NULL, layer)) {
5389 //g_print("bad scrapfile frame\n");
5390 return FALSE;
5391 }
5392 return TRUE;
5393 }
5394
5395
5396 static void ds_warn(boolean freelow, uint64_t bytes) {
5397 char *reason, *aorb;
5398 char *amount = lives_format_storage_space_string(bytes);
5399 if (freelow) {
5400 reason = (_("FREE DISK SPACE"));
5401 aorb = (_("BELOW"));
5402 } else {
5403 reason = (_("DISK SPACE USED"));
5404 aorb = (_("ABOVE"));
5405 }
5406 d_print(_("\nRECORDING was PAUSED because %s in %s IS %s %s !\n"
5407 "Diskspace limits can be set in Preferences / Misc.\n"),
5408 reason, prefs->workdir, aorb, amount);
5409 on_record_perf_activate(NULL, NULL);
5410 d_print_urgency(URGENCY_MSG_TIMEOUT, _("RECORDING WAS PAUSED DUE TO DISKSPACE LIMITS\n"));
5411 lives_free(reason);
5412 lives_free(aorb);
5413 }
5414
5415
5416 boolean check_for_disk_space(boolean fullcheck) {
5417 /// fullcheck == FALSE, we MAY check ds used, and we WILL check free ds using cached value
5418 /// fullcheck == TRUE, we WILL update free ds
5419 static int64_t free_ds = -1;
5420 static double xscrap_mb = -1., xascrap_mb = -1.;
5421 static double xxscrap_mb = -1., xxascrap_mb = -1.;
5422 static int64_t ds_used = -1;
5423 static boolean wrtable = FALSE;
5424
5425 double scrap_mb = 0.;
5426
5427 if (prefs->disk_quota == 0 && prefs->rec_stop_gb < 0.) return TRUE;
5428
5429 if (fullcheck) ds_used = -1;
5430
5431 if (IS_VALID_CLIP(mainw->scrap_file)) {
5432 scrap_mb = (double)mainw->files[mainw->scrap_file]->f_size / (double)ONE_MILLION;
5433 }
5434
5435 if (prefs->disk_quota > 0) {
5436 int64_t xds_used = -1;
5437
5438 if ((ds_used = disk_monitor_check_result(prefs->workdir)) > -1) {
5439 xds_used = ds_used;
5440 xxscrap_mb = scrap_mb;
5441 xxascrap_mb = ascrap_mb;
5442 } else {
5443 if (xxscrap_mb == -1. || xxscrap_mb > scrap_mb) xxscrap_mb = scrap_mb;
5444 if (xxascrap_mb == -1. || xxascrap_mb > ascrap_mb) xxascrap_mb = ascrap_mb;
5445 if (ds_used > -1) xds_used = ds_used
5446 + (int64_t)(scrap_mb + ascrap_mb - xxscrap_mb - xxascrap_mb)
5447 * ONE_MILLION;
5448 }
5449 if (xds_used > -1) {
5450 /// value is in BYTES
5451 if ((uint64_t)xds_used >= prefs->disk_quota * ONE_BILLION) {
5452 if (mainw->record && !mainw->record_paused) {
5453 ds_warn(FALSE, (uint64_t)ds_used);
5454 }
5455 return FALSE;
5456 }
5457 }
5458 }
5459
5460 // check if we have enough free space left on the volume (return FALSE if not)
5461 if (prefs->rec_stop_gb > -1.) {
5462 // check free space again
5463 if (fullcheck || free_ds == -1 || xscrap_mb == -1 || xascrap_mb == -1
5464 || scrap_mb < xscrap_mb || ascrap_mb < xascrap_mb) {
5465 free_ds = (int64_t)get_ds_free(prefs->workdir);
5466 xscrap_mb = scrap_mb;
5467 xascrap_mb = ascrap_mb;
5468 if (free_ds == 0) wrtable = is_writeable_dir(prefs->workdir);
5469 else wrtable = TRUE;
5470 }
5471 if (wrtable) {
5472 double free_mb = (double)free_ds / (double)ONE_MILLION;
5473 double freesp = free_mb - (scrap_mb + ascrap_mb - xscrap_mb - xascrap_mb);
5474 if ((double)freesp / 1000. < prefs->rec_stop_gb) {
5475 if (mainw->record && !mainw->record_paused) {
5476 ds_warn(TRUE, freesp * ONE_MILLION);
5477 }
5478 return FALSE;
5479 }
5480 }
5481 }
5482 return TRUE;
5483 }
5484
5485
5486 static void _save_to_scrap_file(weed_layer_t *layer) {
5487 // returns frame number
5488 // dump the raw layer (frame) data to disk
5489
5490 // TODO: run as bg thread
5491
5492 size_t pdata_size;
5493
5494 lives_clip_t *scrapfile = mainw->files[mainw->scrap_file];
5495
5496 boolean writeable = TRUE;
5497
5498 char *framecount;
5499
5500 //int flags = O_WRONLY | O_CREAT | O_TRUNC;
5501 int fd;
5502
5503 if (!scrapfile->ext_src) {
5504 char *oname = make_image_file_name(scrapfile, 1, LIVES_FILE_EXT_SCRAP), *dirname;
5505
5506 #ifdef O_NOATIME
5507 //flags |= O_NOATIME;
5508 #endif
5509
5510 dirname = lives_build_filename(prefs->workdir, scrapfile->handle, NULL);
5511 lives_mkdir_with_parents(dirname, capable->umask);
5512 lives_free(dirname);
5513
5514 fd = lives_create_buffered_nosync(oname, DEF_FILE_PERMS);
5515 lives_free(oname);
5516
5517 if (fd < 0) {
5518 weed_layer_free(layer);
5519 return;
5520 }
5521 scrapfile->ext_src = LIVES_INT_TO_POINTER(fd);
5522 scrapfile->ext_src_type = LIVES_EXT_SRC_FILE_BUFF;
5523
5524 #ifdef HAVE_POSIX_FADVISE
5525 posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
5526 #endif
5527 } else fd = LIVES_POINTER_TO_INT(scrapfile->ext_src);
5528
5529
5530 // serialise entire frame to scrap file
5531 pdata_size = weed_plant_serialise(fd, layer, NULL);
5532 weed_layer_free(layer);
5533
5534 scrapfile->f_size += pdata_size;
5535
5536 // check free space every 256 frames or every 10 MB of audio (TODO ****)
5537 if ((scrapfile->frames & 0xFF) == 0) {
5538 char *dir = lives_build_filename(prefs->workdir, scrapfile->handle, NULL);
5539 free_mb = (double)get_ds_free(dir) / 1000000.;
5540 if (free_mb == 0) writeable = is_writeable_dir(dir);
5541 lives_free(dir);
5542 }
5543
5544 if ((!mainw->fs || (prefs->play_monitor != widget_opts.monitor + 1 && capable->nmonitors > 1)) && !prefs->hide_framebar &&
5545 !mainw->faded) {
5546 double scrap_mb = (double)scrapfile->f_size / 1000000.;
5547 if ((scrap_mb + ascrap_mb) < (double)free_mb * .75) {
5548 // TRANSLATORS: rec(ord) %.2f M(ega)B(ytes)
5549 framecount = lives_strdup_printf(_("rec %.2f MB"), scrap_mb + ascrap_mb);
5550 } else {
5551 // warn if scrap_file > 3/4 of free space
5552 // TRANSLATORS: !rec(ord) %.2f M(ega)B(ytes)
5553 if (writeable)
5554 framecount = lives_strdup_printf(_("!rec %.2f MB"), scrap_mb + ascrap_mb);
5555 else
5556 // TRANSLATORS: rec(ord) ?? M(ega)B(ytes)
5557 framecount = (_("rec ?? MB"));
5558 }
5559 lives_entry_set_text(LIVES_ENTRY(mainw->framecounter), framecount);
5560 lives_free(framecount);
5561 }
5562
5563 /// check every 64 frames for quota overrun, because its a background task
5564 check_for_disk_space((scrapfile->frames & 0x3F) ? TRUE : FALSE);
5565 }
5566
5567 static lives_proc_thread_t scrap_file_procthrd = NULL;
5568
5569 int save_to_scrap_file(weed_layer_t *layer) {
5570 weed_layer_t *orig_layer;
5571 lives_clip_t *scrapfile = mainw->files[mainw->scrap_file];
5572 if (!IS_VALID_CLIP(mainw->scrap_file)) return -1;
5573 if (!layer) return scrapfile->frames;
5574 orig_layer = weed_layer_copy(NULL, layer);
5575 if (scrap_file_procthrd) {
5576 lives_proc_thread_join(scrap_file_procthrd);
5577 }
5578 scrap_file_procthrd = lives_proc_thread_create(LIVES_THRDATTR_NONE,
5579 (lives_funcptr_t)_save_to_scrap_file, -1, "V", orig_layer);
5580 return scrapfile->frames;
5581 }
5582
5583 void close_scrap_file(boolean remove) {
5584 int current_file = mainw->current_file;
5585
5586 if (!IS_VALID_CLIP(mainw->scrap_file)) return;
5587
5588 if (scrap_file_procthrd) {
5589 lives_proc_thread_join(scrap_file_procthrd);
5590 scrap_file_procthrd = NULL;
5591 }
5592
5593 mainw->current_file = mainw->scrap_file;
5594 if (cfile->ext_src && cfile->ext_src_type == LIVES_EXT_SRC_FILE_BUFF)
5595 lives_close_buffered(LIVES_POINTER_TO_INT(cfile->ext_src));
5596 cfile->ext_src = NULL;
5597 cfile->ext_src_type = LIVES_EXT_SRC_NONE;
5598
5599 if (remove) close_temp_handle(current_file);
5600 else mainw->current_file = current_file;
5601
5602 pthread_mutex_lock(&mainw->clip_list_mutex);
5603 mainw->cliplist = lives_list_remove(mainw->cliplist, LIVES_INT_TO_POINTER(mainw->scrap_file));
5604 pthread_mutex_unlock(&mainw->clip_list_mutex);
5605
5606 if (prefs->crash_recovery) rewrite_recovery_file();
5607
5608 mainw->scrap_file = -1;
5609 }
5610
5611
5612 void close_ascrap_file(boolean remove) {
5613 int current_file = mainw->current_file;
5614
5615 if (mainw->ascrap_file == -1) return;
5616
5617 if (remove) {
5618 mainw->current_file = mainw->ascrap_file;
5619 close_temp_handle(current_file);
5620 }
5621
5622 pthread_mutex_lock(&mainw->clip_list_mutex);
5623 mainw->cliplist = lives_list_remove(mainw->cliplist, LIVES_INT_TO_POINTER(mainw->ascrap_file));
5624 pthread_mutex_unlock(&mainw->clip_list_mutex);
5625
5626 if (prefs->crash_recovery) rewrite_recovery_file();
5627
5628 mainw->ascrap_file = -1;
5629 }
5630
5631
5632 void recover_layout_map(int numclips) {
5633 // load global layout map for a set and assign entries to clips [mainw->files[i]->layout_map]
5634 LiVESList *omlist, *mlist, *lmap_node, *lmap_node_next, *lmap_entry_list, *lmap_entry_list_next;
5635
5636 layout_map *lmap_entry;
5637 uint32_t mask;
5638
5639 char **array;
5640 char *check_handle;
5641
5642 if (numclips > MAX_FILES) numclips = MAX_FILES;
5643
5644 if ((omlist = load_layout_map())) {
5645 int i;
5646
5647 mlist = omlist;
5648
5649 // assign layout map to clips
5650 for (i = 1; i <= numclips; i++) {
5651 lives_clip_t *sfile = mainw->files[i];
5652 if (!sfile) continue;
5653 lmap_node = mlist;
5654 while (lmap_node) {
5655 lmap_node_next = lmap_node->next;
5656 lmap_entry = (layout_map *)lmap_node->data;
5657 check_handle = lives_strdup(sfile->handle);
5658
5659 if (strstr(lmap_entry->handle, "/") == NULL) {
5660 lives_free(check_handle);
5661 check_handle = lives_path_get_basename(sfile->handle);
5662 }
5663
5664 if ((!strcmp(check_handle, lmap_entry->handle) && (sfile->unique_id == lmap_entry->unique_id)) ||
5665 (prefs->mt_load_fuzzy && (!strcmp(check_handle, lmap_entry->handle) || (sfile->unique_id == lmap_entry->unique_id)))
5666 ) {
5667 // check handle and unique id match
5668 // got a match, assign list to layout_map and delete this node
5669 lmap_entry_list = lmap_entry->list;
5670 while (lmap_entry_list) {
5671 lmap_entry_list_next = lmap_entry_list->next;
5672 array = lives_strsplit((char *)lmap_entry_list->data, "|", -1);
5673 if (!lives_file_test(array[0], LIVES_FILE_TEST_EXISTS)) {
5674 //g_print("removing layout because no file %s\n", array[0]);
5675 // layout file has been deleted, remove this entry
5676 if (lmap_entry_list->prev) lmap_entry_list->prev->next = lmap_entry_list_next;
5677 else lmap_entry->list = lmap_entry_list_next;
5678 if (lmap_entry_list_next) lmap_entry_list_next->prev = lmap_entry_list->prev;
5679 lives_free((livespointer)lmap_entry_list->data);
5680 lives_list_free(lmap_entry_list);
5681 }
5682 lives_strfreev(array);
5683 lmap_entry_list = lmap_entry_list_next;
5684 }
5685 sfile->layout_map = lmap_entry->list;
5686 lives_free(lmap_entry->handle);
5687 lives_free(lmap_entry->name);
5688 lives_free(lmap_entry);
5689 if (lmap_node->prev) lmap_node->prev->next = lmap_node_next;
5690 else omlist = mlist = lmap_node_next;
5691 if (lmap_node_next) lmap_node_next->prev = lmap_node->prev;
5692 lmap_node->prev = lmap_node->next = NULL;
5693 lives_list_free(lmap_node);
5694 /// check for missing frames and audio in layouts
5695 // TODO: -- needs checking ----
5696 mask = 0;
5697 mainw->xlays = layout_frame_is_affected(i, sfile->frames + 1, 0, mainw->xlays);
5698 if (mainw->xlays) {
5699 add_lmap_error(LMAP_ERROR_DELETE_FRAMES, sfile->name, (livespointer)sfile->layout_map, i,
5700 sfile->frames, 0., FALSE);
5701 lives_list_free_all(&mainw->xlays);
5702 mask |= WARN_MASK_LAYOUT_DELETE_FRAMES;
5703 //g_print("FRMS %d\n", cfile->frames);
5704 }
5705
5706 mainw->xlays = layout_audio_is_affected(i, sfile->laudio_time, 0., mainw->xlays);
5707 if (mainw->xlays) {
5708 add_lmap_error(LMAP_ERROR_DELETE_AUDIO, sfile->name, (livespointer)sfile->layout_map, i,
5709 sfile->frames, sfile->laudio_time, FALSE);
5710 lives_list_free_all(&mainw->xlays);
5711 mask |= WARN_MASK_LAYOUT_DELETE_AUDIO;
5712 //g_print("AUD %f\n", cfile->laudio_time);
5713 }
5714 if (mask != 0) popup_lmap_errors(NULL, LIVES_INT_TO_POINTER(mask));
5715 }
5716
5717 lives_free(check_handle);
5718 lmap_node = lmap_node_next;
5719 }
5720 }
5721
5722 lmap_node = mlist;
5723 while (lmap_node) {
5724 lmap_entry = (layout_map *)lmap_node->data;
5725 if (lmap_entry->name) lives_free(lmap_entry->name);
5726 if (lmap_entry->handle) lives_free(lmap_entry->handle);
5727 lives_list_free_all(&lmap_entry->list);
5728 lmap_node = lmap_node->next;
5729 }
5730 if (omlist) lives_list_free(omlist);
5731 }
5732 }
5733
5734
5735 boolean reload_clip(int fileno, int maxframe) {
5736 // reload clip -- for CLIP_TYPE_FILE
5737 // cd to clip directory - so decoder plugins can write temp files
5738 LiVESList *odeclist;
5739 lives_clip_t *sfile = mainw->files[fileno];
5740
5741 const lives_clip_data_t *cdata = NULL;
5742 lives_clip_data_t *fake_cdata = (lives_clip_data_t *)lives_calloc(sizeof(lives_clip_data_t), 1);
5743
5744 double orig_fps = sfile->fps;
5745
5746 char decoder_name[PATH_MAX];
5747 char *orig_filename = lives_strdup(sfile->file_name);
5748 char *cwd = lives_get_current_dir();
5749 char *ppath = lives_build_filename(prefs->workdir, sfile->handle, NULL);
5750
5751 LiVESResponseType response;
5752 boolean was_renamed = FALSE, retb = FALSE;
5753 int current_file;
5754
5755 fake_cdata = (lives_clip_data_t *)struct_from_template(LIVES_STRUCT_CLIP_DATA_T);
5756
5757 if (!mainw->decoders_loaded) {
5758 mainw->decoder_list = load_decoders();
5759 mainw->decoders_loaded = TRUE;
5760 }
5761
5762 odeclist = lives_list_copy(mainw->decoder_list); ///< retain original order to restore for freshly opened clips
5763 retb = get_clip_value(fileno, CLIP_DETAILS_DECODER_NAME, decoder_name, PATH_MAX);
5764 if (retb && *decoder_name) {
5765 decoder_plugin_move_to_first(decoder_name);
5766 }
5767 retb = FALSE;
5768 lives_chdir(ppath, FALSE);
5769 lives_free(ppath);
5770
5771 while (1) {
5772 threaded_dialog_spin(0.);
5773
5774 fake_cdata->URI = lives_strdup(sfile->file_name);
5775 fake_cdata->fps = sfile->fps;
5776 fake_cdata->nframes = maxframe;
5777
5778 response = LIVES_RESPONSE_NONE;
5779
5780 if ((cdata = get_decoder_cdata(fileno, prefs->disabled_decoders, fake_cdata->fps != 0. ? fake_cdata : NULL)) == NULL) {
5781 if (mainw->error) {
5782 manual_locate:
5783 response = do_file_notfound_dialog(_("The original file"), orig_filename);
5784 if (response == LIVES_RESPONSE_RETRY) {
5785 lives_freep((void **)&fake_cdata->URI);
5786 continue;
5787 }
5788 if (response == LIVES_RESPONSE_BROWSE) {
5789 int resp;
5790 char fname[PATH_MAX], dirname[PATH_MAX], *newname;
5791 LiVESWidget *chooser;
5792
5793 lives_snprintf(dirname, PATH_MAX, "%s", orig_filename);
5794 lives_snprintf(fname, PATH_MAX, "%s", orig_filename);
5795
5796 get_dirname(dirname);
5797 get_basename(fname);
5798
5799 chooser = choose_file_with_preview(dirname, fname, NULL, LIVES_FILE_SELECTION_VIDEO_AUDIO);
5800
5801 resp = lives_dialog_run(LIVES_DIALOG(chooser));
5802
5803 end_fs_preview();
5804
5805 if (resp == LIVES_RESPONSE_ACCEPT) {
5806 newname = lives_file_chooser_get_filename(LIVES_FILE_CHOOSER(chooser));
5807 lives_widget_destroy(LIVES_WIDGET(chooser));
5808
5809 if (newname && *newname) {
5810 char *tmp;
5811 lives_snprintf(sfile->file_name, PATH_MAX, "%s", (tmp = lives_filename_to_utf8(newname, -1, NULL, NULL, NULL)));
5812 lives_free(tmp);
5813 lives_free(newname);
5814 }
5815
5816 lives_freep((void **)&fake_cdata->URI);
5817
5818 //re-scan for these
5819 sfile->fps = 0.;
5820 maxframe = 0;
5821
5822 was_renamed = TRUE;
5823 // try again with the new file
5824 continue;
5825 }
5826 // cancelled from filechooser
5827 lives_widget_destroy(LIVES_WIDGET(chooser));
5828 goto manual_locate;
5829 }
5830 // cancelled
5831 } else {
5832 // unopenable
5833 if (was_renamed) goto manual_locate;
5834 do_no_decoder_error(sfile->file_name);
5835 }
5836
5837 lives_chdir(cwd, FALSE);
5838 lives_free(cwd);
5839
5840 // NOT openable, or not found and user cancelled, switch back to original clip
5841 if (!sfile->checked && cdata) {
5842 check_clip_integrity(fileno, cdata, maxframe);
5843 if (sfile->frames > 0 || sfile->afilesize > 0) {
5844 // recover whatever we can
5845 sfile->clip_type = CLIP_TYPE_FILE;
5846 retb = check_if_non_virtual(fileno, 1, sfile->frames);
5847 }
5848 sfile->checked = TRUE;
5849 }
5850 if (!retb) {
5851 current_file = mainw->current_file;
5852 mainw->current_file = fileno;
5853 close_current_file(current_file);
5854 }
5855 unref_struct(&fake_cdata->lsd);
5856
5857 lives_free(orig_filename);
5858 lives_list_free(mainw->decoder_list);
5859 mainw->decoder_list = odeclist;
5860 return retb;
5861 }
5862
5863 // got cdata
5864 if (was_renamed) {
5865 // manual relocation
5866 sfile->fps = orig_fps;
5867 if (!sfile->checked && !check_clip_integrity(fileno, cdata, maxframe)) {
5868 // get correct img_type, fps, etc.
5869 if (THREADVAR(com_failed) || THREADVAR(write_failed)) do_header_write_error(fileno);
5870 goto manual_locate;
5871 }
5872 sfile->checked = TRUE;
5873 sfile->needs_silent_update = TRUE; // force filename update in header
5874 if (prefs->show_recent) {
5875 // replace in recent menu
5876 char file[PATH_MAX];
5877 int i;
5878 for (i = 0; i < 4; i++) {
5879 char *tmp;
5880 char *pref = lives_strdup_printf("%s%d", PREF_RECENT, i + 1);
5881 get_utf8_pref(pref, file, PATH_MAX);
5882 tmp = subst(file, orig_filename, sfile->file_name);
5883 if (lives_utf8_strcmp(tmp, file)) {
5884 lives_snprintf(file, PATH_MAX, "%s", tmp);
5885 set_utf8_pref(pref, file);
5886 lives_menu_item_set_text(mainw->recent[i], file, FALSE);
5887 if (mainw->multitrack) lives_menu_item_set_text(mainw->multitrack->recent[i], file, FALSE);
5888 }
5889 lives_free(tmp);
5890 lives_free(pref);
5891 }
5892 if (mainw->prefs_cache) {
5893 // update recent files -> force reload of prefs
5894 cached_list_free(&mainw->prefs_cache);
5895 mainw->prefs_cache = cache_file_contents(prefs->configfile);
5896 }
5897 }
5898 }
5899
5900 threaded_dialog_spin(0.);
5901 unref_struct(&fake_cdata->lsd);
5902 break;
5903 }
5904
5905 lives_free(orig_filename);
5906 lives_chdir(cwd, FALSE);
5907 lives_free(cwd);
5908
5909 sfile->clip_type = CLIP_TYPE_FILE;
5910 get_mime_type(sfile->type, 40, cdata);
5911 sfile->img_type = IMG_TYPE_BEST; // read_headers() will have set this to "jpeg" (default)
5912 // we will set correct value in check_clip_integrity() if there are any real images
5913
5914 if (sfile->ext_src) {
5915 boolean bad_header = FALSE;
5916 boolean correct = TRUE;
5917 if (!was_renamed) {
5918 if (!sfile->checked)
5919 correct = check_clip_integrity(fileno, cdata, maxframe); // get correct img_type, fps, etc.
5920 sfile->checked = TRUE;
5921 }
5922 if (!correct) {
5923 if (THREADVAR(com_failed) || THREADVAR(write_failed)) bad_header = TRUE;
5924 } else {
5925 lives_decoder_t *dplug = (lives_decoder_t *)sfile->ext_src;
5926 if (dplug) {
5927 lives_decoder_sys_t *dpsys = (lives_decoder_sys_t *)dplug->decoder;
5928 if (dpsys && *dpsys->name && strcmp(dpsys->name, decoder_name)) {
5929 save_clip_value(fileno, CLIP_DETAILS_DECODER_NAME, (void *)dpsys->name);
5930 if (THREADVAR(com_failed) || THREADVAR(write_failed)) bad_header = TRUE;
5931 }
5932 }
5933 }
5934
5935 if (bad_header) do_header_write_error(fileno);
5936 }
5937 lives_list_free(mainw->decoder_list);
5938 mainw->decoder_list = odeclist;
5939 if (prefs->autoload_subs) {
5940 reload_subs(fileno);
5941 }
5942 return TRUE;
5943 }
5944
5945 #define _RELOAD(field) sfile->field = loaded->field
5946 #define _RELOAD_STRING(field, len) lives_snprintf(sfile->field, len, "%s", loaded->field)
5947
5948 #define DSIZE_MAX 100000
5949
5950 static lives_clip_t *_restore_binfmt(int clipno, boolean forensic) {
5951 if (IS_NORMAL_CLIP(clipno)) {
5952 lives_clip_t *sfile = mainw->files[clipno];
5953 char *fname = lives_build_filename(prefs->workdir, sfile->handle, TOTALSAVE_NAME, NULL);
5954 if (lives_file_test(fname, LIVES_FILE_TEST_EXISTS)) {
5955 ssize_t bytes;
5956 size_t cursize = (size_t)((char *)&sfile->binfmt_end - (char *)sfile), dsize;
5957 char *xloaded = (char *)lives_calloc(1, cursize);
5958 boolean badsize = FALSE;
5959 int fd = lives_open_buffered_rdonly(fname);
5960 size_t fsize = lives_buffered_orig_size(fd);
5961 lives_clip_t *loaded = (lives_clip_t *)xloaded;
5962 if (fsize < cursize) badsize = TRUE;
5963 else {
5964 bytes = lives_read_buffered(fd, xloaded, 8, TRUE);
5965 if (bytes < 8 || lives_memcmp(loaded->binfmt_check.chars, CLIP_BINFMT_CHECK, 8)) badsize = TRUE;
5966 else {
5967 bytes += lives_read_buffered(fd, xloaded + 8, 16, TRUE);
5968 if (bytes < 16) badsize = TRUE;
5969 else {
5970 dsize = loaded->binfmt_bytes.num;
5971 if (dsize < cursize) badsize = TRUE;
5972 else {
5973 if (dsize > cursize && dsize < DSIZE_MAX) {
5974 xloaded = lives_realloc(xloaded, dsize);
5975 loaded = (lives_clip_t *)xloaded;
5976 } else dsize = cursize;
5977 bytes += lives_read_buffered(fd, xloaded + 24, dsize - 24, TRUE);
5978 if (bytes < dsize) badsize = TRUE;
5979 }
5980 }
5981 }
5982 }
5983 lives_close_buffered(fd);
5984 //if (!forensic) lives_rm(fname);
5985 lives_free(fname);
5986
5987 if (badsize) {
5988 lives_free(xloaded);
5989 return FALSE;
5990 }
5991
5992 THREADVAR(com_failed) = FALSE;
5993 if (THREADVAR(read_failed) == fd + 1) {
5994 THREADVAR(read_failed) = 0;
5995 lives_free(xloaded);
5996 return NULL;
5997 }
5998
5999 sfile->has_binfmt = TRUE;
6000
6001 if (forensic) return loaded;
6002
6003 _RELOAD_STRING(save_file_name, PATH_MAX); _RELOAD(start); _RELOAD(end); _RELOAD(is_untitled); _RELOAD(was_in_set);
6004 _RELOAD(ratio_fps); _RELOAD_STRING(mime_type, 256);
6005 _RELOAD(changed); _RELOAD(deinterlace); _RELOAD(vol);
6006 if (sfile->start < 1) sfile->start = 1;
6007 if (sfile->end > sfile->frames) sfile->end = sfile->frames;
6008 if (sfile->start > sfile->end) sfile->start = sfile->end;
6009 if (lives_strlen(sfile->save_file_name) > PATH_MAX) lives_memset(sfile->save_file_name, 0, PATH_MAX);
6010 if (sfile->pointer_time > sfile->video_time) sfile->pointer_time = 0.;
6011 if (sfile->real_pointer_time > CLIP_TOTAL_TIME(clipno)) sfile->real_pointer_time = sfile->pointer_time;
6012 return loaded;
6013 }
6014 lives_free(fname);
6015 }
6016 return NULL;
6017 }
6018
6019 #undef _RELOAD
6020 #undef _RELOAD_STRING
6021
6022 boolean restore_clip_binfmt(int clipno) {
6023 lives_clip_t *recov = _restore_binfmt(clipno, FALSE);
6024 if (!recov) return FALSE;
6025 lives_free(recov);
6026 return TRUE;
6027 }
6028
6029 lives_clip_t *clip_forensic(int clipno) {
6030 return _restore_binfmt(clipno, TRUE);
6031 }
6032
6033 boolean recover_files(char *recovery_file, boolean auto_recover) {
6034 FILE *rfile = NULL;
6035
6036 char buff[256], *buffptr;
6037 char *clipdir;
6038
6039 LiVESResponseType resp;
6040
6041 int clipnum = 0;
6042 int maxframe;
6043 int last_good_file = -1, ngoodclips;
6044
6045 boolean is_scrap, is_ascrap;
6046 boolean did_set_check = FALSE;
6047 boolean is_ready = mainw->is_ready, mt_is_ready = FALSE;
6048 boolean mt_needs_idlefunc = FALSE;
6049 boolean retb = TRUE, retval;
6050 boolean load_from_set = TRUE;
6051 boolean rec_cleanup = FALSE;
6052
6053 // setting is_ready allows us to get the correct transient window for dialogs
6054 // otherwise the dialogs will appear behind the main interface
6055 // we do this for mainwindow and multitrack
6056
6057 // we will reset these before returning
6058 mainw->is_ready = TRUE;
6059
6060 if (mainw->multitrack) {
6061 if (mainw->multitrack->idlefunc > 0) {
6062 lives_source_remove(mainw->multitrack->idlefunc);
6063 mainw->multitrack->idlefunc = 0;
6064 mt_needs_idlefunc = TRUE;
6065 }
6066 mt_desensitise(mainw->multitrack);
6067 mt_is_ready = mainw->multitrack->is_ready;
6068 mainw->multitrack->is_ready = TRUE;
6069 }
6070
6071 if (!auto_recover) {
6072 if (1 || mainw->multitrack) {
6073 lives_widget_show_all(LIVES_MAIN_WINDOW_WIDGET);
6074 lives_widget_context_update();
6075 }
6076 if (!do_yesno_dialog
6077 (_("\nFiles from a previous run of LiVES were found.\nDo you want to attempt to recover them ?\n"))) {
6078 retb = FALSE;
6079 goto recovery_done;
6080 }
6081 }
6082
6083 if (recovery_file) {
6084 do {
6085 resp = LIVES_RESPONSE_NONE;
6086 rfile = fopen(recovery_file, "r");
6087 if (!rfile) {
6088 resp = do_read_failed_error_s_with_retry(recovery_file, lives_strerror(errno));
6089 if (resp == LIVES_RESPONSE_CANCEL) {
6090 retb = FALSE;
6091 goto recovery_done;
6092 }
6093 }
6094 } while (resp == LIVES_RESPONSE_RETRY);
6095 }
6096
6097 do_threaded_dialog(_("Recovering files"), FALSE);
6098 d_print(_("\nRecovering files..."));
6099
6100 threaded_dialog_spin(0.);
6101
6102 mainw->suppress_dprint = TRUE;
6103 mainw->recovering_files = TRUE;
6104
6105 while (1) {
6106 if (mainw->hdrs_cache) cached_list_free(&mainw->hdrs_cache);
6107
6108 threaded_dialog_spin(0.);
6109 is_scrap = FALSE;
6110 is_ascrap = FALSE;
6111
6112 THREADVAR(read_failed) = FALSE;
6113
6114 if (recovery_file) {
6115 if (!lives_fgets(buff, 256, rfile)) {
6116 reset_clipmenu();
6117 threaded_dialog_spin(0.);
6118 mainw->suppress_dprint = FALSE;
6119 if (THREADVAR(read_failed)) {
6120 d_print_failed();
6121 do_read_failed_error_s(recovery_file, NULL);
6122 } else d_print_done();
6123 break;
6124 }
6125 } else {
6126 if (!mainw->recovery_list) {
6127 reset_clipmenu();
6128 mainw->suppress_dprint = FALSE;
6129 d_print_done();
6130 break;
6131 }
6132 lives_snprintf(buff, 256, "%s", (char *)mainw->recovery_list->data);
6133 mainw->recovery_list = mainw->recovery_list->next;
6134 }
6135
6136 lives_chomp(buff);
6137
6138 if (buff[strlen(buff) - 1] == '*') {
6139 boolean crash_recovery = prefs->crash_recovery;
6140 LiVESResponseType resp;
6141 // set to be opened
6142 buff[strlen(buff) - 1 - strlen(LIVES_DIR_SEP)] = 0;
6143 do {
6144 resp = LIVES_RESPONSE_OK;
6145 if (!is_legal_set_name(buff, TRUE, TRUE)) {
6146 resp = do_abort_cancel_retry_dialog(_("Click Abort to exit LiVES immediately, Retry to try again,"
6147 " or Cancel to continue without reloading the set.\n"));
6148 }
6149 } while (resp == LIVES_RESPONSE_RETRY);
6150 if (resp == LIVES_RESPONSE_CANCEL) continue;
6151
6152 /** dont write an entry yet, in case of the unklikely chance we were assigned the same pid as the recovery file,
6153 otherwise we will end up in am endless loop of reloading the same set and appending it to the recovery file
6154 in any case, the old file is still there and we will create a fresh recovery file after a succesful reload */
6155 prefs->crash_recovery = FALSE;
6156
6157 if (!reload_set(buff)) {
6158 prefs->crash_recovery = crash_recovery; /// reset to original value
6159 mainw->suppress_dprint = FALSE;
6160 d_print_failed();
6161 mainw->suppress_dprint = FALSE;
6162 continue;
6163 }
6164 mainw->was_set = TRUE;
6165 prefs->crash_recovery = crash_recovery; /// reset to original value
6166 } else {
6167 /// load single file
6168 if (!strncmp(buff, "scrap|", 6)) {
6169 is_scrap = TRUE;
6170 buffptr = buff + 6;
6171 } else if (!strncmp(buff, "ascrap|", 7)) {
6172 is_ascrap = TRUE;
6173 buffptr = buff + 7;
6174 } else {
6175 if (!strncmp(buff, "ascrap", 6) || !strncmp(buff, "scrap", 5)) {
6176 rec_cleanup = TRUE;
6177 continue;
6178 }
6179 buffptr = buff;
6180 }
6181
6182 clipdir = lives_build_filename(prefs->workdir, buffptr, NULL);
6183
6184 if (!lives_file_test(clipdir, LIVES_FILE_TEST_IS_DIR)) {
6185 lives_free(clipdir);
6186 continue;
6187 }
6188 lives_free(clipdir);
6189
6190 if (strstr(buffptr, "/" CLIPS_DIRNAME "/")) {
6191 char **array;
6192 threaded_dialog_spin(0.);
6193 if (!load_from_set) continue;
6194 array = lives_strsplit(buffptr, "/" CLIPS_DIRNAME "/", -1);
6195 mainw->was_set = TRUE;
6196 lives_snprintf(mainw->set_name, 128, "%s", array[0]);
6197 lives_strfreev(array);
6198
6199 if (!did_set_check && !check_for_lock_file(mainw->set_name, 0)) {
6200 if (!do_set_locked_warning(mainw->set_name)) {
6201 load_from_set = FALSE;
6202 mainw->was_set = FALSE;
6203 mainw->set_name[0] = 0;
6204 }
6205 did_set_check = TRUE;
6206 }
6207 }
6208
6209 /// create a new cfile and fill in the details
6210 if (!create_cfile(-1, buffptr, FALSE)) {
6211 threaded_dialog_spin(0.);
6212 end_threaded_dialog();
6213 mainw->suppress_dprint = FALSE;
6214 d_print_failed();
6215 break;
6216 }
6217
6218 if (is_scrap || is_ascrap) {
6219 pthread_mutex_lock(&mainw->clip_list_mutex);
6220 mainw->cliplist = lives_list_append(mainw->cliplist, LIVES_INT_TO_POINTER(mainw->current_file));
6221 pthread_mutex_unlock(&mainw->clip_list_mutex);
6222 }
6223
6224 if (is_scrap) {
6225 mainw->scrap_file = mainw->current_file;
6226 cfile->opening = FALSE;
6227 lives_snprintf(cfile->type, 40, "scrap");
6228 cfile->frames = 1;
6229 cfile->hsize = 640;
6230 cfile->vsize = 480;
6231 continue;
6232 }
6233
6234 if (is_ascrap) {
6235 mainw->ascrap_file = mainw->current_file;
6236 cfile->opening = FALSE;
6237 lives_snprintf(cfile->type, 40, "ascrap");
6238 }
6239
6240 /// get file details; this will cache the header in mainw->hdrs_cache
6241 // we need to keep this around for open_set_file(), below.
6242 clipdir = lives_build_path(prefs->workdir, cfile->handle, NULL);
6243 retval = read_headers(mainw->current_file, clipdir, NULL);
6244 lives_free(clipdir);
6245
6246 if (is_ascrap) {
6247 if (!retval) {
6248 mainw->first_free_file = mainw->current_file;
6249 mainw->ascrap_file = -1;
6250 }
6251 continue;
6252 }
6253
6254 if (mainw->current_file < 1) continue;
6255
6256 /// see function reload_set() for detailed comments
6257 if ((maxframe = load_frame_index(mainw->current_file)) > 0) {
6258 /// CLIP_TYPE_FILE
6259 if (!*cfile->file_name) continue;
6260 if (!reload_clip(mainw->current_file, maxframe)) continue;
6261 if (cfile->img_type == IMG_TYPE_UNKNOWN) {
6262 lives_clip_data_t *cdata = ((lives_decoder_t *)cfile->ext_src)->cdata;
6263 int fvirt = count_virtual_frames(cfile->frame_index, 1, cfile->frames);
6264 if (fvirt < cfile->frames) {
6265 if (!cfile->checked && !check_clip_integrity(mainw->current_file, cdata, cfile->frames)) {
6266 cfile->needs_update = TRUE;
6267 }
6268 cfile->checked = TRUE;
6269 }
6270 if (cfile->header_version >= 102) cfile->fps = cfile->pb_fps;
6271 }
6272 } else {
6273 /// CLIP_TYPE_DISK
6274 boolean is_ok = TRUE;
6275 if (!cfile->checked) {
6276 if (!(is_ok = check_clip_integrity(mainw->current_file, NULL, cfile->frames))) {
6277 cfile->needs_update = TRUE;
6278 }
6279 cfile->checked = TRUE;
6280 }
6281 if (!prefs->vj_mode && !is_ok) {
6282 if (cfile->afilesize == 0) {
6283 reget_afilesize_inner(mainw->current_file);
6284 }
6285 if (!check_frame_count(mainw->current_file, is_ok)) {
6286 cfile->frames = get_frame_count(mainw->current_file, 1);
6287 cfile->needs_update = TRUE;
6288 }
6289 }
6290 }
6291 if (!recovery_file && !cfile->checked) {
6292 lives_clip_data_t *cdata = ((lives_decoder_t *)cfile->ext_src)->cdata;
6293 if (!check_clip_integrity(mainw->current_file, cdata, cfile->frames)) {
6294 cfile->needs_update = TRUE;
6295 if (cfile->header_version >= 102) cfile->fps = cfile->pb_fps;
6296 }
6297 }
6298
6299 threaded_dialog_spin(0.);
6300
6301 /** not really from a set, but let's pretend to get the details
6302 read the playback fps, play frame, and name */
6303
6304 /// NEED TO maintain mainw->hdrs_cache when entering the function,
6305 /// else it will be considered a legacy file load
6306 open_set_file(++clipnum);
6307
6308 threaded_dialog_spin(0.);
6309
6310 if (mainw->hdrs_cache) cached_list_free(&mainw->hdrs_cache);
6311
6312 if (mainw->current_file < 1) continue;
6313
6314 if (cfile->clip_type == CLIP_TYPE_FILE && cfile->header_version >= 102) cfile->fps = cfile->pb_fps;
6315 get_total_time(cfile);
6316
6317 if (CLIP_TOTAL_TIME(mainw->current_file) == 0.) {
6318 close_current_file(last_good_file);
6319 continue;
6320 }
6321
6322 last_good_file = mainw->current_file;
6323
6324 if (cfile->needs_update || cfile->needs_silent_update) {
6325 if (cfile->needs_update) do_clip_divergence_error(mainw->current_file);
6326 save_clip_values(mainw->current_file);
6327 cfile->needs_silent_update = cfile->needs_update = FALSE;
6328 }
6329
6330 // add to clip menu
6331 threaded_dialog_spin(0.);
6332 add_to_clipmenu();
6333 cfile->start = cfile->frames > 0 ? 1 : 0;
6334 cfile->end = cfile->frames;
6335 cfile->is_loaded = TRUE;
6336 cfile->changed = TRUE;
6337 lives_rm(cfile->info_file);
6338 if (!mainw->multitrack) set_main_title(cfile->name, 0);
6339
6340 if (cfile->frameno > cfile->frames) cfile->frameno = cfile->last_frameno = 1;
6341
6342 if (!mainw->multitrack) {
6343 lives_signal_handler_block(mainw->spinbutton_start, mainw->spin_start_func);
6344 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), cfile->start);
6345 lives_signal_handler_unblock(mainw->spinbutton_start, mainw->spin_start_func);
6346 lives_signal_handler_block(mainw->spinbutton_end, mainw->spin_end_func);
6347 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), cfile->end);
6348 lives_signal_handler_unblock(mainw->spinbutton_end, mainw->spin_end_func);
6349 showclipimgs();
6350 } else {
6351 int current_file = mainw->current_file;
6352 lives_mt *multi = mainw->multitrack;
6353 mainw->multitrack = NULL;
6354 mainw->current_file = -1;
6355 reget_afilesize(current_file);
6356 mainw->current_file = current_file;
6357 mainw->multitrack = multi;
6358 get_total_time(cfile);
6359 mainw->current_file = mainw->multitrack->render_file;
6360 mt_init_clips(mainw->multitrack, current_file, TRUE);
6361 set_poly_tab(mainw->multitrack, POLY_CLIPS);
6362 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
6363 mt_clip_select(mainw->multitrack, TRUE);
6364 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
6365 mainw->current_file = current_file;
6366 }
6367
6368 threaded_dialog_spin(0.);
6369
6370 if (cfile->frameno > cfile->frames && cfile->frameno > 1) cfile->frameno = cfile->frames;
6371 cfile->last_frameno = cfile->frameno;
6372 cfile->pointer_time = cfile->real_pointer_time = calc_time_from_frame(mainw->current_file, cfile->frameno);
6373 if (cfile->real_pointer_time > CLIP_TOTAL_TIME(mainw->current_file))
6374 cfile->real_pointer_time = CLIP_TOTAL_TIME(mainw->current_file);
6375 if (cfile->pointer_time > cfile->video_time) cfile->pointer_time = 0.;
6376
6377 if (cfile->achans) {
6378 cfile->aseek_pos = (off64_t)((double)(cfile->real_pointer_time * cfile->arate) * cfile->achans *
6379 (cfile->asampsize / 8));
6380 if (cfile->aseek_pos > cfile->afilesize) cfile->aseek_pos = 0.;
6381 }
6382
6383 if (mainw->current_file != -1)
6384 if (*mainw->set_name) recover_layout_map(mainw->current_file);
6385
6386 if (!mainw->multitrack) resize(1);
6387
6388 lives_notify(LIVES_OSC_NOTIFY_CLIP_OPENED, "");
6389 }
6390 }
6391
6392 if (mainw->hdrs_cache) cached_list_free(&mainw->hdrs_cache);
6393
6394 ngoodclips = lives_list_length(mainw->cliplist);
6395 if (!ngoodclips) {
6396 d_print(_("No clips were recovered.\n"));
6397 }
6398 d_print(P_("%d clip was recovered ", "%d clips were recovered ", ngoodclips), ngoodclips);
6399 if (recovery_file)
6400 d_print(_("from the previous session.\n"));
6401 else
6402 d_print(_("from previous sessions.\n"));
6403
6404 if (!mainw->multitrack) { // TODO check if we can do this in mt too
6405 int start_file = mainw->current_file;
6406 if (start_file > 1 && start_file == mainw->ascrap_file && mainw->files[start_file - 1]) {
6407 start_file--;
6408 }
6409 if (start_file > 1 && start_file == mainw->scrap_file && mainw->files[start_file - 1]) {
6410 start_file--;
6411 }
6412 if (start_file > 1 && start_file == mainw->ascrap_file && mainw->files[start_file - 1]) {
6413 start_file--;
6414 }
6415 if ((!IS_VALID_CLIP(start_file) || (mainw->files[start_file]->frames == 0 && mainw->files[start_file]->afilesize == 0))
6416 && mainw->files[1] && start_file != 1) {
6417 for (start_file = MAX_FILES; start_file > 0; start_file--) {
6418 if (mainw->files[start_file]
6419 && (mainw->files[start_file]->frames > 0 || mainw->files[start_file]->afilesize > 0))
6420 if (start_file != mainw->scrap_file && start_file != mainw->ascrap_file) break;
6421 }
6422 }
6423
6424 if (start_file != mainw->current_file) {
6425 rec_cleanup = TRUE;
6426 switch_to_file(mainw->current_file, start_file);
6427 showclipimgs();
6428 redraw_timeline(mainw->current_file);
6429 }
6430 } else {
6431 mt_clip_select(mainw->multitrack, TRUE); // scroll clip on screen
6432 }
6433
6434 if (recovery_file) fclose(rfile);
6435
6436 recovery_done:
6437
6438 end_threaded_dialog();
6439
6440 mainw->suppress_dprint = FALSE;
6441 lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
6442 mainw->recovering_files = FALSE;
6443 mainw->is_ready = is_ready;
6444 if (mainw->multitrack) {
6445 mainw->multitrack->is_ready = mt_is_ready;
6446 mainw->current_file = mainw->multitrack->render_file;
6447 polymorph(mainw->multitrack, POLY_NONE);
6448 polymorph(mainw->multitrack, POLY_CLIPS);
6449 mt_sensitise(mainw->multitrack);
6450 if (mt_needs_idlefunc) mainw->multitrack->idlefunc = mt_idle_add(mainw->multitrack);
6451 } else update_play_times();
6452 mainw->last_dprint_file = -1;
6453 mainw->no_switch_dprint = FALSE;
6454 d_print("");
6455 mainw->invalid_clips = rec_cleanup;
6456 return retb;
6457 }
6458
6459
6460 void add_to_recovery_file(const char *handle) {
6461 lives_echo(handle, mainw->recovery_file, TRUE);
6462
6463 if (THREADVAR(com_failed)) {
6464 THREADVAR(com_failed) = FALSE;
6465 return;
6466 }
6467
6468 if ((mainw->multitrack && mainw->multitrack->event_list) || mainw->stored_event_list)
6469 write_backup_layout_numbering(mainw->multitrack);
6470 }
6471
6472
6473 boolean rewrite_recovery_file(void) {
6474 // part of the crash recovery system
6475 // returns TRUE if successful
6476 LiVESList *clist = mainw->cliplist;
6477 char *recovery_entry;
6478 char *temp_recovery_file;
6479
6480 boolean opened = FALSE;
6481 boolean wrote_set_entry = FALSE;
6482
6483 int recovery_fd = -1;
6484 LiVESResponseType retval;
6485
6486 if (!clist || !prefs->crash_recovery) {
6487 lives_rm(mainw->recovery_file);
6488 return FALSE;
6489 }
6490
6491 temp_recovery_file = lives_strdup_printf("%s.%s", mainw->recovery_file, LIVES_FILE_EXT_TMP);
6492
6493 do {
6494 retval = LIVES_RESPONSE_NONE;
6495 THREADVAR(write_failed) = FALSE;
6496 opened = FALSE;
6497 recovery_fd = -1;
6498
6499 for (; clist; clist = clist->next) {
6500 int i = LIVES_POINTER_TO_INT(clist->data);
6501 if (IS_NORMAL_CLIP(i)) {
6502 lives_clip_t *sfile = mainw->files[i];
6503 if (i == mainw->scrap_file) {
6504 recovery_entry = lives_strdup_printf("scrap|%s\n", sfile->handle);
6505 } else if (i == mainw->ascrap_file) {
6506 recovery_entry = lives_strdup_printf("ascrap|%s\n", sfile->handle);
6507 } else {
6508 if (sfile->was_in_set && *mainw->set_name) {
6509 if (!wrote_set_entry) {
6510 recovery_entry = lives_build_filename(mainw->set_name, "*\n", NULL);
6511 wrote_set_entry = TRUE;
6512 } else continue;
6513 } else recovery_entry = lives_strdup_printf("%s\n", sfile->handle);
6514 }
6515
6516 if (!opened) recovery_fd = creat(temp_recovery_file, S_IRUSR | S_IWUSR);
6517 if (recovery_fd < 0) retval = do_write_failed_error_s_with_retry(temp_recovery_file, lives_strerror(errno));
6518 else {
6519 opened = TRUE;
6520 lives_write(recovery_fd, recovery_entry, strlen(recovery_entry), TRUE);
6521 if (THREADVAR(write_failed)) retval = do_write_failed_error_s_with_retry(temp_recovery_file, NULL);
6522 }
6523 lives_free(recovery_entry);
6524 }
6525 if (THREADVAR(write_failed)) break;
6526 }
6527 } while (retval == LIVES_RESPONSE_RETRY);
6528
6529 if (!opened) lives_rm(mainw->recovery_file);
6530 else if (recovery_fd >= 0) {
6531 close(recovery_fd);
6532 retval = LIVES_RESPONSE_INVALID;
6533 do {
6534 lives_mv(temp_recovery_file, mainw->recovery_file);
6535 if (THREADVAR(com_failed)) {
6536 retval = do_write_failed_error_s_with_retry(temp_recovery_file, NULL);
6537 }
6538 } while (retval == LIVES_RESPONSE_RETRY);
6539 }
6540
6541 lives_free(temp_recovery_file);
6542
6543 if ((mainw->multitrack && mainw->multitrack->event_list) || mainw->stored_event_list)
6544 write_backup_layout_numbering(mainw->multitrack);
6545
6546 return TRUE;
6547 }
6548
6549
6550 boolean check_for_recovery_files(boolean auto_recover) {
6551 uint32_t recpid = 0;
6552
6553 char *recovery_file, *recovery_numbering_file, *recording_file, *recording_numbering_file, *xfile;
6554 char *com;
6555
6556 boolean retval = FALSE;
6557 boolean found = FALSE, found_recording = FALSE;
6558
6559 int lgid = lives_getgid();
6560 int luid = lives_getuid();
6561
6562 lives_pgid_t lpid = capable->mainpid;
6563
6564 // ask backend to find the latest recovery file which is not owned by a running version of LiVES
6565 com = lives_strdup_printf("%s get_recovery_file %d %d %s recovery %d", prefs->backend_sync, luid, lgid,
6566 capable->myname, capable->mainpid);
6567
6568 lives_popen(com, FALSE, mainw->msg, MAINW_MSG_SIZE);
6569 lives_free(com);
6570
6571 if (THREADVAR(com_failed)) {
6572 THREADVAR(com_failed) = FALSE;
6573 return FALSE;
6574 }
6575
6576 recpid = atoi(mainw->msg);
6577 if (recpid == 0) return FALSE;
6578
6579 retval = recover_files((recovery_file = lives_strdup_printf("%s/recovery.%d.%d.%d", prefs->workdir, luid,
6580 lgid, recpid)), auto_recover);
6581 lives_free(recovery_file);
6582
6583 if (!retval || prefs->vj_mode) {
6584 com = lives_strdup_printf("%s clean_recovery_files %d %d \"%s\" %d %d", prefs->backend_sync, luid, lgid, capable->myname,
6585 capable->mainpid, prefs->vj_mode);
6586 lives_system(com, FALSE);
6587 lives_free(com);
6588 if (prefs->vj_mode) {
6589 rewrite_recovery_file();
6590 return TRUE;
6591 }
6592 return FALSE;
6593 }
6594
6595 #if !GTK_CHECK_VERSION(3, 0, 0)
6596 if (CURRENT_CLIP_IS_VALID) {
6597 showclipimgs();
6598 lives_widget_queue_resize(mainw->video_draw);
6599 lives_widget_queue_resize(mainw->laudio_draw);
6600 lives_widget_queue_resize(mainw->raudio_draw);
6601 }
6602 #endif
6603
6604 THREADVAR(com_failed) = FALSE;
6605
6606 /// CRITICAL: make sure this gets called even on system failure and abort
6607 if (prefs->crash_recovery) mainw->abort_hook_func = (lives_funcptr_t)rewrite_recovery_file;
6608
6609 // check for layout recovery file
6610 recovery_file = lives_strdup_printf("%s/%s.%d.%d.%d.%s", prefs->workdir, LAYOUT_FILENAME, luid, lgid, recpid,
6611 LIVES_FILE_EXT_LAYOUT);
6612 recovery_numbering_file = lives_strdup_printf("%s/%s.%d.%d.%d", prefs->workdir, LAYOUT_NUMBERING_FILENAME, luid, lgid, recpid);
6613
6614 recording_file = lives_strdup_printf("%s/recorded-%s.%d.%d.%d.%s", prefs->workdir, LAYOUT_FILENAME, luid, lgid, recpid,
6615 LIVES_FILE_EXT_LAYOUT);
6616
6617 recording_numbering_file = lives_strdup_printf("%s/recorded-%s.%d.%d.%d", prefs->workdir, LAYOUT_NUMBERING_FILENAME, luid, lgid,
6618 recpid);
6619
6620 if (!lives_file_test(recovery_file, LIVES_FILE_TEST_EXISTS)) {
6621 lives_free(recovery_file);
6622 recovery_file = lives_strdup_printf("%s/%s.%d.%d.%d", prefs->workdir, LAYOUT_FILENAME, luid, lgid, recpid);
6623 if (lives_file_test(recovery_file, LIVES_FILE_TEST_EXISTS)) {
6624 found = TRUE;
6625 }
6626 } else {
6627 found = TRUE;
6628 }
6629 if (found) {
6630 if (!lives_file_test(recovery_numbering_file, LIVES_FILE_TEST_EXISTS)) {
6631 found = FALSE;
6632 }
6633 }
6634
6635 if (prefs->rr_crash && lives_file_test(recording_file, LIVES_FILE_TEST_EXISTS)) {
6636 if (lives_file_test(recording_numbering_file, LIVES_FILE_TEST_EXISTS)) {
6637 found_recording = TRUE;
6638 xfile = lives_strdup_printf("%s/keep_recorded-layout.%d.%d.%d", prefs->workdir, luid, lgid, lpid);
6639 lives_mv(recording_file, xfile);
6640 lives_free(xfile);
6641 xfile = lives_strdup_printf("%s/keep_recorded-layout_numbering.%d.%d.%d", prefs->workdir, luid, lgid, lpid);
6642 lives_mv(recording_numbering_file, xfile);
6643 lives_free(xfile);
6644 mainw->recording_recovered = TRUE;
6645 }
6646 }
6647
6648 if (found) {
6649 // move files temporarily to stop them being cleansed
6650 xfile = lives_strdup_printf("%s/keep_layout.%d.%d.%d", prefs->workdir, luid, lgid, lpid);
6651 lives_mv(recovery_file, xfile);
6652 lives_free(xfile);
6653 xfile = lives_strdup_printf("%s/keep_layout_numbering.%d.%d.%d", prefs->workdir, luid, lgid, lpid);
6654 lives_mv(recovery_numbering_file, xfile);
6655 lives_free(xfile);
6656 mainw->recoverable_layout = TRUE;
6657 }
6658
6659 if (!found && !found_recording) {
6660 if (mainw->scrap_file != -1) close_scrap_file(TRUE);
6661 if (mainw->ascrap_file != -1) close_ascrap_file(TRUE);
6662 }
6663
6664 lives_free(recovery_file);
6665 lives_free(recovery_numbering_file);
6666 lives_free(recording_file);
6667 lives_free(recording_numbering_file);
6668
6669 if (THREADVAR(com_failed) && prefs->crash_recovery) {
6670 rewrite_recovery_file();
6671 return FALSE;
6672 }
6673
6674 com = lives_strdup_printf("%s clean_recovery_files %d %d \"%s\" %d 0", prefs->backend_sync, luid, lgid, capable->myname,
6675 capable->mainpid);
6676 lives_system(com, FALSE);
6677 lives_free(com);
6678
6679 recovery_file = lives_strdup_printf("%s/%s.%d.%d.%d.%s", prefs->workdir, LAYOUT_FILENAME, luid, lgid, lpid,
6680 LIVES_FILE_EXT_LAYOUT);
6681 recovery_numbering_file = lives_strdup_printf("%s/%s.%d.%d.%d", prefs->workdir, LAYOUT_NUMBERING_FILENAME, luid, lgid, lpid);
6682
6683 if (mainw->recoverable_layout) {
6684 // move files back
6685 xfile = lives_strdup_printf("%s/keep_layout.%d.%d.%d", prefs->workdir, luid, lgid, lpid);
6686 lives_mv(xfile, recovery_file);
6687 lives_free(xfile);
6688 xfile = lives_strdup_printf("%s/keep_layout_numbering.%d.%d.%d", prefs->workdir, luid, lgid, lpid);
6689 lives_mv(xfile, recovery_numbering_file);
6690 lives_free(xfile);
6691 }
6692
6693 recording_file = lives_strdup_printf("%s/recorded-%s.%d.%d.%d.%s", prefs->workdir, LAYOUT_FILENAME, luid, lgid, lpid,
6694 LIVES_FILE_EXT_LAYOUT);
6695 recording_numbering_file = lives_strdup_printf("%s/recorded-%s.%d.%d.%d", prefs->workdir, LAYOUT_NUMBERING_FILENAME, luid, lgid,
6696 lpid);
6697
6698 if (mainw->recording_recovered) {
6699 xfile = lives_strdup_printf("%s/keep_recorded-layout.%d.%d.%d", prefs->workdir, luid, lgid, lpid);
6700 /// may fail -> abort
6701 lives_mv(xfile, recording_file);
6702 lives_free(xfile);
6703 xfile = lives_strdup_printf("%s/keep_recorded-layout_numbering.%d.%d.%d", prefs->workdir, luid, lgid, lpid);
6704 lives_mv(xfile, recording_numbering_file);
6705 lives_free(xfile);
6706 }
6707
6708 lives_free(recovery_file);
6709 lives_free(recovery_numbering_file);
6710 lives_free(recording_file);
6711 lives_free(recording_numbering_file);
6712
6713 if (prefs->crash_recovery) rewrite_recovery_file();
6714 mainw->abort_hook_func = NULL;
6715
6716 if (!mainw->recoverable_layout && !mainw->recording_recovered) {
6717 if (mainw->invalid_clips && (prefs->warning_mask ^ (WARN_MASK_CLEAN_AFTER_CRASH | WARN_MASK_CLEAN_INVALID))
6718 == WARN_MASK_CLEAN_INVALID) do_after_invalid_warning();
6719 else do_after_crash_warning();
6720 mainw->invalid_clips = FALSE;
6721 }
6722 return retval;
6723 }
6724
6725