1 // cvirtual.c
2 // LiVES
3 // (c) G. Finch 2008 - 2020 <salsaman@gmail.com>
4 // released under the GNU GPL 3 or later
5 // see file ../COPYING or www.gnu.org for licensing details
6
7 // functions for handling "virtual" clips (CLIP_TYPE_FILE)
8
9 #include "main.h"
10
11 // frame_index is for files of type CLIP_TYPE_FILE
12 // a positive number is a pointer to a frame within the video file
13 // -1 means frame is stored as the corresponding image file
14 // e.g 00000001.jpg or 00000010.png etc.
15
16 #include "resample.h"
17 #include "cvirtual.h"
18
19 /** count virtual frames between start and end (inclusive) */
count_virtual_frames(frames_t * findex,frames_t start,frames_t end)20 frames_t count_virtual_frames(frames_t *findex, frames_t start, frames_t end) {
21 frames_t count = 0;
22 for (register int i = start - 1; i < end; i++) if (findex[i] != -1) count++;
23 return count;
24 }
25
26
create_frame_index(int fileno,boolean init,frames_t start_offset,frames_t nframes)27 boolean create_frame_index(int fileno, boolean init, frames_t start_offset, frames_t nframes) {
28 lives_clip_t *sfile = mainw->files[fileno];
29 size_t idxsize = (ALIGN_CEIL(nframes * sizeof(frames_t), DEF_ALIGN)) / DEF_ALIGN;
30 if (!IS_VALID_CLIP(fileno) || sfile->frame_index) return FALSE;
31 sfile->frame_index = (frames_t *)lives_calloc(idxsize, DEF_ALIGN);
32 if (!sfile->frame_index) return FALSE;
33 if (init) for (int i = 0; i < sfile->frames; i++) sfile->frame_index[i] = i + start_offset;
34 return TRUE;
35 }
36
37
extend_frame_index(int fileno,frames_t start,frames_t end)38 static boolean extend_frame_index(int fileno, frames_t start, frames_t end) {
39 lives_clip_t *sfile = mainw->files[fileno];
40 size_t idxsize = (ALIGN_CEIL(end * sizeof(frames_t), DEF_ALIGN)) / DEF_ALIGN;
41 if (!IS_VALID_CLIP(fileno) || start > end) return FALSE;
42 if (sfile->frame_index_back) lives_free(sfile->frame_index_back);
43 sfile->frame_index_back = sfile->frame_index;
44 sfile->frame_index = (frames_t *)lives_calloc(idxsize, DEF_ALIGN);
45 if (!sfile->frame_index) {
46 sfile->frame_index = sfile->frame_index_back;
47 sfile->frame_index_back = NULL;
48 return FALSE;
49 }
50 for (int i = start; i < end; i++) sfile->frame_index[i] = -1;
51 return TRUE;
52 }
53
54
55 // save frame_index to disk
save_frame_index(int fileno)56 boolean save_frame_index(int fileno) {
57 int fd, i;
58 int retval;
59 char *fname, *fname_new;
60 lives_clip_t *sfile = mainw->files[fileno];
61
62 if (fileno == 0) return TRUE;
63
64 if (!sfile || !sfile->frame_index) return FALSE;
65
66 fname = lives_build_filename(prefs->workdir, sfile->handle, FRAME_INDEX_FNAME "." LIVES_FILE_EXT_BACK, NULL);
67 fname_new = lives_build_filename(prefs->workdir, sfile->handle, FRAME_INDEX_FNAME, NULL);
68
69 do {
70 retval = 0;
71 fd = lives_create_buffered(fname, DEF_FILE_PERMS);
72 if (fd < 0) {
73 retval = do_write_failed_error_s_with_retry(fname, lives_strerror(errno));
74 } else {
75 for (i = 0; i < sfile->frames; i++) {
76 lives_write_le_buffered(fd, &sfile->frame_index[i], sizeof(frames_t), TRUE);
77 if (THREADVAR(write_failed) == fd + 1) {
78 THREADVAR(write_failed) = 0;
79 break;
80 }
81 }
82
83 lives_close_buffered(fd);
84
85 if (mainw->is_exiting) return TRUE;
86
87 if (THREADVAR(write_failed) == fd + 1) {
88 THREADVAR(write_failed) = 0;
89 retval = do_write_failed_error_s_with_retry(fname, NULL);
90 } else {
91 if (sget_file_size(fname) != (off_t)sfile->frames * sizeof(frames_t)) {
92 retval = do_write_failed_error_s_with_retry(fname, NULL);
93 } else {
94 lives_cp(fname, fname_new);
95 if (sget_file_size(fname_new) != (off_t)sfile->frames * sizeof(frames_t)) {
96 retval = do_write_failed_error_s_with_retry(fname, NULL);
97 // *INDENT-OFF*
98 }}}}
99 // *INDENT-ON*
100 } while (retval == LIVES_RESPONSE_RETRY);
101
102 lives_free(fname);
103 lives_free(fname_new);
104
105 if (retval == LIVES_RESPONSE_CANCEL) return FALSE;
106
107 return TRUE;
108 }
109
110 // load frame_index from disk
111 // returns -1 (error)
112 // or maxframe pointed to in clip
113
load_frame_index(int fileno)114 frames_t load_frame_index(int fileno) {
115 lives_clip_t *sfile = mainw->files[fileno];
116 off_t filesize;
117 char *fname, *fname_back;
118 boolean backuptried = FALSE;
119 int fd, retval;
120 frames_t maxframe = -1;
121
122 int i;
123
124 if (!sfile || sfile->frame_index) return -1;
125
126 lives_freep((void **)&sfile->frame_index);
127
128 fname = lives_build_filename(prefs->workdir, sfile->handle, FRAME_INDEX_FNAME, NULL);
129 filesize = sget_file_size(fname);
130
131 if (filesize <= 0) {
132 lives_free(fname);
133 return 0;
134 }
135
136 if (filesize >> 2 > (off_t)sfile->frames) sfile->frames = (frames_t)(filesize >> 2);
137 fname_back = lives_build_filename(prefs->workdir, sfile->handle, FRAME_INDEX_FNAME "." LIVES_FILE_EXT_BACK, NULL);
138
139 do {
140 retval = 0;
141 fd = lives_open_buffered_rdonly(fname);
142 if (fd < 0) {
143 THREADVAR(read_failed) = 0;
144 retval = do_read_failed_error_s_with_retry(fname, lives_strerror(errno));
145 if (!backuptried) {
146 fd = lives_open_buffered_rdonly(fname_back);
147 if (fd >= 0) {
148 lives_close_buffered(fd);
149 if (findex_bk_dialog(fname_back)) {
150 lives_cp(fname_back, fname);
151 backuptried = TRUE;
152 continue;
153 }
154 }
155 } else if (sfile->frame_index_back) {
156 if (findex_bk_dialog(fname_back)) {
157 sfile->frame_index = sfile->frame_index_back;
158 }
159 }
160 if (retval == LIVES_RESPONSE_CANCEL) {
161 lives_free(fname);
162 lives_free(fname_back);
163 return -1;
164 }
165 } else {
166 LiVESResponseType response;
167 char *what = (_("creating the frame index for the clip"));
168 do {
169 response = LIVES_RESPONSE_OK;
170 create_frame_index(fileno, FALSE, 0, sfile->frames);
171 if (!cfile->frame_index) {
172 response = do_memory_error_dialog(what, sfile->frames * sizeof(frames_t));
173 }
174 } while (response == LIVES_RESPONSE_RETRY);
175 lives_free(what);
176 if (response == LIVES_RESPONSE_CANCEL) {
177 break;
178 }
179
180 for (i = 0; i < sfile->frames; i++) {
181 lives_read_le_buffered(fd, &sfile->frame_index[i], sizeof(frames_t), FALSE);
182 if (THREADVAR(read_failed) == fd + 1) {
183 break;
184 }
185 if (sfile->frame_index[i] > maxframe) {
186 maxframe = sfile->frame_index[i];
187 }
188 }
189 lives_close_buffered(fd);
190
191 if (THREADVAR(read_failed) == fd + 1) {
192 THREADVAR(read_failed) = 0;
193 retval = do_read_failed_error_s_with_retry(fname, NULL);
194 }
195
196 if (!backuptried) {
197 backuptried = TRUE;
198 fd = lives_open_buffered_rdonly(fname_back);
199 if (fd >= 0) {
200 LiVESList *list = NULL;
201 frames_t vframe;
202 int count = 0;
203 for (; lives_read_le_buffered(fd, &vframe, sizeof(frames_t), TRUE) == sizeof(frames_t); count++) {
204 if (THREADVAR(read_failed) == fd + 1) break;
205 list = lives_list_prepend(list, LIVES_INT_TO_POINTER(vframe));
206 }
207 lives_close_buffered(fd);
208 if (THREADVAR(read_failed) == fd + 1) {
209 THREADVAR(read_failed) = 0;
210 } else if (count) {
211 frames_t *f_index = sfile->frame_index;
212 list = lives_list_reverse(list);
213 lives_freep((void **)&sfile->frame_index_back);
214 sfile->frame_index = NULL;
215 create_frame_index(fileno, FALSE, 0, count);
216 sfile->frame_index_back = sfile->frame_index;
217 sfile->frame_index = f_index;
218 if (sfile->frame_index_back) {
219 LiVESList *xlist;
220 sfile->old_frames = count;
221 count = 0;
222 for (xlist = list; xlist; xlist = xlist->next) {
223 sfile->frame_index_back[count++] = LIVES_POINTER_TO_INT(xlist->data);
224 // *INDENT-OFF*
225 }}}
226 if (list) lives_list_free(list);
227 }}}} while (retval == LIVES_RESPONSE_RETRY);
228 // *INDENT-ON*
229
230 lives_free(fname);
231 lives_free(fname_back);
232
233 if (maxframe >= 0) sfile->clip_type = CLIP_TYPE_FILE;
234 return ++maxframe;
235 }
236
237
del_frame_index(lives_clip_t * sfile)238 void del_frame_index(lives_clip_t *sfile) {
239 // physically delete the frame_index for a clip
240 // only done once all
241
242 char *idxfile;
243
244 // cannot call check_if_non_virtual() else we end up recursing
245
246 if (sfile->frame_index) {
247 for (frames_t i = 1; i <= sfile->frames; i++) {
248 if (sfile->frame_index[i - 1] != -1) {
249 LIVES_ERROR("deleting frame_index with virtual frames in it !");
250 return;
251 }
252 }
253 }
254
255 if (sfile != clipboard) {
256 idxfile = lives_build_filename(prefs->workdir, sfile->handle, FRAME_INDEX_FNAME, NULL);
257 lives_rm(idxfile);
258 lives_free(idxfile);
259 }
260
261 lives_freep((void **)&sfile->frame_index);
262 }
263
264
scan_frames(lives_clip_t * sfile,frames_t vframes,frames_t last_real_frame)265 static frames_t scan_frames(lives_clip_t *sfile, frames_t vframes, frames_t last_real_frame) {
266 frames_t i;
267 for (i = 0; i < sfile->frames; i++) {
268 // assume all real frames up to last_real_frame are there
269 if ((sfile->frame_index[i] == -1 && i >= last_real_frame) || (sfile->frame_index[i] > vframes)) return i;
270 }
271 return i;
272 }
273
274
resolve_img_type(lives_clip_t * sfile)275 lives_img_type_t resolve_img_type(lives_clip_t *sfile) {
276 lives_img_type_t ximgtype;
277 int nimty = (int)N_IMG_TYPES;
278 char *fname;
279 for (frames_t i = sfile->frames - 1; i >= 0; i--) {
280 if (!sfile->frame_index || sfile->frame_index[i] == -1) {
281 for (int j = 1; j < nimty; j++) {
282 ximgtype = (lives_img_type_t)j;
283 fname = make_image_file_name(sfile, i + 1, get_image_ext_for_type(ximgtype));
284 if (lives_file_test(fname, LIVES_FILE_TEST_EXISTS)) {
285 lives_free(fname);
286 return j;
287 }
288 lives_free(fname);
289 // *INDENT-OFF*
290 }}}
291 // *INDENT-ON*
292 return IMG_TYPE_BEST;
293 }
294
295
check_clip_integrity(int fileno,const lives_clip_data_t * cdata,frames_t maxframe)296 boolean check_clip_integrity(int fileno, const lives_clip_data_t *cdata, frames_t maxframe) {
297 lives_clip_t *sfile = mainw->files[fileno], *binf = NULL;
298 lives_img_type_t empirical_img_type = sfile->img_type, oemp = empirical_img_type;
299 lives_img_type_t ximgtype;
300 frames_t last_real_frame = sfile->frames;
301 int nimty = (int)N_IMG_TYPES, j;
302 boolean has_missing_frames = FALSE, bad_imgfmts = FALSE;
303 boolean mismatch = FALSE;
304 boolean isfirst = TRUE;
305 boolean backup_more_correct = FALSE;
306 char *fname;
307
308 frames_t i;
309 // check clip integrity upon loading
310
311 // check that cached values match with sfile (on disk) values
312 // also check sfile->frame_index to make sure all frames are present
313
314 // return FALSE if we find any omissions/inconsistencies
315
316 /* if (sfile->frames > maxframe) { */
317 /* has_missing_frames = TRUE; */
318 /* sfile->frames = maxframe; */
319 /* } */
320
321 if (prefs->vj_mode) return TRUE;
322
323 // check the image type
324 for (i = sfile->frames - 1; i >= 0; i--) {
325 if (!sfile->frame_index || sfile->frame_index[i] == -1) {
326 // this is a non-virtual frame
327 ximgtype = empirical_img_type;
328 fname = NULL;
329 if (ximgtype != IMG_TYPE_UNKNOWN) fname = make_image_file_name(sfile, i + 1, get_image_ext_for_type(ximgtype));
330 if (!fname || !lives_file_test(fname, LIVES_FILE_TEST_EXISTS)) {
331 if (fname) lives_free(fname);
332 for (j = 1; j < nimty; j++) {
333 ximgtype = (lives_img_type_t)j;
334 if (ximgtype == empirical_img_type) continue;
335 fname = make_image_file_name(sfile, i + 1, get_image_ext_for_type(ximgtype));
336 if (lives_file_test(fname, LIVES_FILE_TEST_EXISTS)) {
337 if (isfirst) {
338 empirical_img_type = ximgtype;
339 if (oemp == IMG_TYPE_UNKNOWN) oemp = ximgtype;
340 } else {
341 if (ximgtype == oemp) empirical_img_type = oemp;
342 bad_imgfmts = TRUE;
343 }
344 lives_free(fname);
345 isfirst = FALSE;
346 break;
347 }
348 lives_free(fname);
349 }
350 if (j == nimty) {
351 has_missing_frames = TRUE;
352 if (prefs->show_dev_opts) {
353 g_printerr("clip %s is missing image frame %d\n", sfile->handle, i + 1);
354 }
355 } else {
356 last_real_frame = i;
357 isfirst = FALSE;
358 // *INDENT-OFF*
359 }}
360 else lives_free(fname);
361 }}
362 // *INDENT-ON*
363
364 if (empirical_img_type == IMG_TYPE_UNKNOWN) {
365 /// this is possible if clip is only virtual frames
366 empirical_img_type = sfile->img_type = IMG_TYPE_BEST; // read_headers() will have set this to "jpeg" (default)
367 }
368
369 if (cdata) {
370 // check frame count
371 if (maxframe > cdata->nframes || has_missing_frames) {
372 if (prefs->show_dev_opts) {
373 if (maxframe > cdata->nframes) {
374 g_printerr("frame count mismatch for clip %d, %s, maxframe is %d, decoder claims only %ld\nRescaning...",
375 fileno, sfile->handle, maxframe, cdata-> nframes);
376 }
377 }
378
379 has_missing_frames = TRUE;
380 sfile->frames = scan_frames(sfile, cdata->nframes, last_real_frame);
381 if (prefs->show_dev_opts) {
382 g_printerr("rescan counted %d frames\n.", sfile->frames);
383 }
384 }
385 }
386
387 if (sfile->frame_index) {
388 frames_t lgoodframe = -1;
389 int goodidx;
390 frames_t xframes = sfile->frames;
391
392 if (sfile->frame_index_back) {
393 if (sfile->old_frames > sfile->frames) xframes = sfile->old_frames;
394 backup_more_correct = TRUE;
395 }
396
397 // check and attempt to correct frame_index
398 for (i = 0; i < xframes; i++) {
399 frames_t fr;
400 if (i < sfile->frames) fr = sfile->frame_index[i];
401 else fr = sfile->frame_index_back[i];
402 if (fr < -1 || (!cdata && (frames64_t)fr > sfile->frames - 1)
403 || (cdata && (frames64_t)fr > cdata->nframes - 1)) {
404 if (i >= sfile->frames) {
405 backup_more_correct = FALSE;
406 break;
407 }
408 if (backup_more_correct && i < sfile->old_frames) {
409 frames_t fr2 = sfile->frame_index_back[i];
410 if (fr2 < -1 || (!cdata && (frames64_t)fr2 > sfile->frames - 1)
411 || (cdata && (frames64_t)fr2 > cdata->nframes - 1)) {
412 backup_more_correct = FALSE;
413 }
414 }
415
416 if (prefs->show_dev_opts) {
417 g_printerr("bad frame index %d, points to %d.....", i, fr);
418 }
419 if (fr < sfile->frames) has_missing_frames = TRUE;
420 fname = make_image_file_name(sfile, i + 1, get_image_ext_for_type(empirical_img_type));
421 if (lives_file_test(fname, LIVES_FILE_TEST_EXISTS)) {
422 sfile->frame_index[i] = -1;
423 if (prefs->show_dev_opts) {
424 g_printerr("relinked to image frame %d\n", i + 1);
425 }
426 } else {
427 if (backup_more_correct && i < sfile->old_frames && sfile->frame_index_back[i] == -1)
428 backup_more_correct = FALSE;
429 if (lgoodframe != -1) {
430 sfile->frame_index[i] = lgoodframe + i - goodidx;
431 if (prefs->show_dev_opts) {
432 g_printerr("relinked to clip frame %d\n", lgoodframe + i - goodidx);
433 }
434 } else {
435 sfile->frame_index[i] = i;
436 if (prefs->show_dev_opts) {
437 g_printerr("reset to clip frame %d\n", i);
438 }
439 }
440 if (sfile->frame_index[i] >= cdata->nframes) sfile->frame_index[i] = cdata->nframes - 1;
441 }
442 lives_free(fname);
443 } else {
444 if (cdata && fr != -1) {
445 lgoodframe = fr;
446 goodidx = i;
447 // *INDENT-OFF*
448 }}}}
449 // *INDENT-ON*
450 if (has_missing_frames && backup_more_correct) {
451 lives_freep((void **)&sfile->frame_index);
452 sfile->frame_index = sfile->frame_index_back;
453 if (sfile->old_frames > sfile->frames) {
454 sfile->frames = sfile->old_frames;
455 sfile->frames = scan_frames(sfile, sfile->frames, last_real_frame);
456 } else sfile->frames = sfile->old_frames;
457 }
458
459 if (sfile->frames > 0) {
460 int hsize = sfile->hsize, chsize = hsize;
461 int vsize = sfile->vsize, cvsize = vsize;
462 frames_t last_img_frame = -1;
463 if (last_real_frame > 0) {
464 if (sfile->frame_index) {
465 for (i = last_real_frame; i > 0; i--) {
466 if (sfile->frame_index[i - 1] == -1) {
467 last_img_frame = i;
468 break;
469 }
470 }
471 } else last_img_frame = last_real_frame;
472 if (last_img_frame > -1) {
473 sfile->img_type = empirical_img_type;
474 get_frames_sizes(fileno, last_img_frame, &hsize, &vsize);
475 }
476 }
477
478 if (cdata) {
479 if (!prefs->auto_nobord) {
480 chsize = cdata->frame_width * weed_palette_get_pixels_per_macropixel(cdata->current_palette);
481 cvsize = cdata->frame_height;
482 } else {
483 chsize = cdata->width * weed_palette_get_pixels_per_macropixel(cdata->current_palette);
484 cvsize = cdata->height;
485 }
486 }
487
488 if (chsize == hsize && hsize != sfile->hsize) sfile->hsize = hsize;
489 if (cvsize == vsize && vsize != sfile->vsize) sfile->vsize = vsize;
490
491 if (last_real_frame > 0) {
492 if (hsize == sfile->hsize && vsize == sfile->vsize) {
493 frames_t fframe = 0;
494 /// last frame is most likely to return correct size
495 /// we should also check first frame, as it is more likely to be wrong
496 if (sfile->clip_type == CLIP_TYPE_DISK) fframe = 1;
497 else {
498 for (i = 1; i < last_real_frame; i++) {
499 if (sfile->frame_index[i - 1] == -1) {
500 fname = make_image_file_name(sfile, i, get_image_ext_for_type(empirical_img_type));
501 if (lives_file_test(fname, LIVES_FILE_TEST_EXISTS)) {
502 fframe = i;
503 lives_free(fname);
504 break;
505 }
506 has_missing_frames = TRUE;
507 lives_free(fname);
508 // *INDENT-OFF*
509 }}}
510 if (fframe) get_frames_sizes(fileno, fframe, &hsize, &vsize);
511 }}
512 // *INDENT-ON*
513
514 if (sfile->hsize != hsize || sfile->vsize != vsize) {
515 LiVESResponseType resp = do_resize_dlg(sfile->hsize, sfile->vsize, hsize, vsize);
516 if (prefs->show_dev_opts) {
517 g_printerr("incorrect frame size %d X %d, corrected to %d X %d\n", hsize, vsize, sfile->hsize, sfile->vsize);
518 }
519 if (resp == LIVES_RESPONSE_ACCEPT) {
520 sfile->hsize = hsize;
521 sfile->vsize = vsize;
522 } else if (resp == LIVES_RESPONSE_YES) {
523 int missing = 0, nbadsized = 0;
524 threaded_dialog_push();
525 do_threaded_dialog(_("Resizing all frames\n"), TRUE);
526 lives_widget_show_all(mainw->proc_ptr->processing);
527 if (resize_all(fileno, sfile->hsize, sfile->vsize, empirical_img_type, FALSE,
528 &nbadsized, &missing)) {
529 g_printerr("resize detected %d bad sized, %d missing \n", nbadsized, missing);
530 if (missing) has_missing_frames = TRUE;
531 if (mainw->cancelled == CANCEL_NONE) bad_imgfmts = FALSE;
532 else mismatch = TRUE;
533 }
534 mainw->cancelled = CANCEL_NONE;
535 end_threaded_dialog();
536 threaded_dialog_pop();
537 } else mismatch = TRUE;
538 }
539 }
540 if (bad_imgfmts) {
541 LiVESResponseType resp = do_imgfmts_error(empirical_img_type);
542 if (resp == LIVES_RESPONSE_OK) {
543 int missing = 0, nbadsized = 0;
544 threaded_dialog_push();
545 do_threaded_dialog(_("Correcting Image Formats\n"), TRUE);
546 if (resize_all(fileno, sfile->hsize, sfile->vsize, empirical_img_type, FALSE,
547 &nbadsized, &missing)) {
548 g_printerr("change fmts detected %d bad sized, %d missing \n", nbadsized, missing);
549 if (missing) has_missing_frames = TRUE;
550 if (mainw->cancelled == CANCEL_NONE) bad_imgfmts = FALSE;
551 else mismatch = TRUE;
552 }
553 mainw->cancelled = CANCEL_NONE;
554 end_threaded_dialog();
555 threaded_dialog_pop();
556 } else mismatch = TRUE;
557 mainw->cancelled = CANCEL_NONE;
558 }
559
560 if (has_missing_frames) mismatch = TRUE;
561 else {
562 if (sfile->frame_index) {
563 for (i = 0; i < sfile->frames; i++) {
564 if (sfile->frame_index[i] != -1) {
565 fname = make_image_file_name(sfile, i + 1, get_image_ext_for_type(empirical_img_type));
566 if (lives_file_test(fname, LIVES_FILE_TEST_EXISTS)) {
567 lives_rm(fname);
568 // *INDENT-OFF*
569 }
570 lives_free(fname);
571 }}}}
572 // *INDENT-ON*
573 if (cdata && (fabs(sfile->fps - (double)cdata->fps) > prefs->fps_tolerance)) {
574 if (prefs->show_dev_opts) {
575 g_printerr("fps mismtach, claimed %f, cdata said %f\n", sfile->fps, cdata->fps);
576 }
577 mismatch = TRUE;
578 }
579 if (sfile->img_type != empirical_img_type) {
580 if (prefs->show_dev_opts) {
581 g_printerr("corrected image type from %d to %d\n", sfile->img_type, empirical_img_type);
582 }
583 sfile->img_type = empirical_img_type;
584 }
585
586 if (mismatch) goto mismatch;
587
588 /*
589 // ignore since we may have resampled audio
590 if (sfile->achans != cdata->achans || sfile->arps != cdata->arate || sfile->asampsize != cdata->asamps ||
591 cdata->asigned == (sfile->signed_endian & AFORM_UNSIGNED)) return FALSE;
592 */
593
594 // all things equal as far as we can tell
595 return TRUE;
596
597 mismatch:
598 // something mismatched - commence further investigation
599
600 if ((binf = clip_forensic(mainw->current_file))) {
601 if (has_missing_frames) {
602 if (cdata) {
603 if (binf->frames == cdata->nframes && binf->frames < sfile->frames) sfile->frames = binf->frames;
604 else if (binf->frames == sfile->frames && binf->frames < sfile->frames) {
605 if (sfile->frames > cdata->nframes) if (!extend_frame_index(fileno, cdata->nframes, sfile->frames)) return FALSE;
606 ((lives_clip_data_t *)cdata)->nframes = sfile->frames;
607 }
608 } else if (binf->frames <= sfile->frames) sfile->frames = binf->frames;
609 }
610 if (binf->fps == cdata->fps) {
611 ((lives_clip_data_t *)cdata)->fps = sfile->pb_fps = sfile->fps;
612 }
613 }
614
615 sfile->img_type = empirical_img_type;
616
617 sfile->needs_update = TRUE;
618
619 sfile->afilesize = reget_afilesize_inner(fileno);
620
621 if (has_missing_frames && sfile->frame_index) {
622 if (sfile->frames > maxframe) extend_frame_index(fileno, maxframe, sfile->frames);
623 save_frame_index(fileno);
624 }
625 return FALSE;
626 }
627
628
first_virtual_frame(int fileno,frames_t start,frames_t end)629 frames_t first_virtual_frame(int fileno, frames_t start, frames_t end) {
630 // check all franes in frame_index betweem start and end inclusive
631 // if we find a virtual frame, we stop checking and return the frame number
632 // if all are non - virtual we return 0
633 lives_clip_t *sfile = mainw->files[fileno];
634
635 if (!sfile->frame_index) return 0;
636 for (frames_t i = start; i <= end; i++) {
637 if (sfile->frame_index[i - 1] != -1) return i;
638 }
639
640 return 0;
641 }
642
643
check_if_non_virtual(int fileno,frames_t start,frames_t end)644 boolean check_if_non_virtual(int fileno, frames_t start, frames_t end) {
645 // check if there are no virtual frames from start to end inclusive in clip fileno
646
647 // return FALSE if any virtual frames are found in the region
648 // return TRUE if all frames in region are non-virtual
649
650 // also may change the clip_type and the interlace
651
652 lives_clip_t *sfile = mainw->files[fileno];
653 frames_t i;
654
655 if (sfile->clip_type != CLIP_TYPE_FILE) return TRUE;
656
657 if (sfile->frame_index) {
658 for (i = start; i <= end; i++) {
659 if (sfile->frame_index[i - 1] != -1) return FALSE;
660 }
661 }
662
663 if (start > 1 || end < sfile->frames) return TRUE;
664
665 // no virtual frames in entire clip - change to CLIP_TYPE_DISK
666
667 sfile->clip_type = CLIP_TYPE_DISK;
668 del_frame_index(sfile);
669 close_clip_decoder(fileno);
670
671 if (sfile->interlace != LIVES_INTERLACE_NONE) {
672 sfile->interlace = LIVES_INTERLACE_NONE; // all frames should have been deinterlaced
673 sfile->deinterlace = FALSE;
674 if (fileno > 0) {
675 if (!save_clip_value(fileno, CLIP_DETAILS_INTERLACE, &sfile->interlace))
676 do_header_write_error(fileno);
677 }
678 }
679
680 return TRUE;
681 }
682
683 #define DS_SPACE_CHECK_FRAMES 100
684
save_decoded(int fileno,frames_t i,LiVESPixbuf * pixbuf,boolean silent,int progress)685 static boolean save_decoded(int fileno, frames_t i, LiVESPixbuf * pixbuf, boolean silent, int progress) {
686 lives_clip_t *sfile = mainw->files[fileno];
687 boolean retb;
688 int retval;
689 LiVESError *error = NULL;
690 char *oname = make_image_file_name(sfile, i, get_image_ext_for_type(sfile->img_type));
691
692 do {
693 retval = LIVES_RESPONSE_NONE;
694 retb = lives_pixbuf_save(pixbuf, oname, sfile->img_type, 100 - prefs->ocp, sfile->hsize, sfile->vsize, &error);
695 if (error && !silent) {
696 retval = do_write_failed_error_s_with_retry(oname, error->message);
697 lives_error_free(error);
698 error = NULL;
699 } else if (!retb) {
700 retval = do_write_failed_error_s_with_retry(oname, NULL);
701 }
702 } while (retval == LIVES_RESPONSE_RETRY);
703
704 lives_freep((void **)&oname);
705
706 if (progress % DS_SPACE_CHECK_FRAMES == 1) {
707 if (!check_storage_space(fileno, FALSE)) {
708 retval = LIVES_RESPONSE_CANCEL;
709 }
710 }
711
712 if (retval == LIVES_RESPONSE_CANCEL) return FALSE;
713 return TRUE;
714 }
715
716
717 #define STRG_CHECK 1000
718
virtual_to_images(int sfileno,frames_t sframe,frames_t eframe,boolean update_progress,LiVESPixbuf ** pbr)719 frames_t virtual_to_images(int sfileno, frames_t sframe, frames_t eframe, boolean update_progress, LiVESPixbuf **pbr) {
720 // pull frames from a clip to images
721 // from sframe to eframe inclusive (first frame is 1)
722
723 // if update_progress, set mainw->msg with number of frames pulled
724
725 // should be threadsafe apart from progress update
726
727 // if pbr is non-null, it will be set to point to the pulled pixbuf
728
729 // return FALSE on write error
730
731 lives_clip_t *sfile = mainw->files[sfileno];
732 LiVESPixbuf *pixbuf = NULL;
733 lives_proc_thread_t tinfo = THREADVAR(tinfo);
734 int progress = 1, count = 0;
735 frames_t i;
736
737 if (tinfo) lives_proc_thread_set_cancellable(tinfo);
738
739 if (sframe < 1) sframe = 1;
740
741 for (i = sframe; i <= eframe; i++) {
742 if (i > sfile->frames) break;
743
744 if (sfile->pumper && lives_proc_thread_cancelled(sfile->pumper)) break;
745
746 if (update_progress) {
747 threaded_dialog_spin((double)(i - sframe) / (double)(eframe - sframe + 1));
748 }
749
750 if (sfile->frame_index[i - 1] >= 0) {
751 if (pbr && pixbuf) lives_widget_object_unref(pixbuf);
752
753 pixbuf = pull_lives_pixbuf_at_size(sfileno, i, get_image_ext_for_type(sfile->img_type),
754 q_gint64((i - 1.) / sfile->fps, sfile->fps), sfile->hsize,
755 sfile->vsize, LIVES_INTERP_BEST, FALSE);
756
757 if (!pixbuf) return -i;
758 if (!save_decoded(sfileno, i, pixbuf, pbr != NULL, progress)) {
759 check_storage_space(-1, TRUE);
760 return -i;
761 }
762 if (!pbr) {
763 if (pixbuf) lives_widget_object_unref(pixbuf);
764 pixbuf = NULL;
765 }
766 if (++count == STRG_CHECK) {
767 if (!check_storage_space(-1, TRUE)) break;
768 }
769
770 // another thread may have called check_if_non_virtual - TODO : use a mutex
771 if (!sfile->frame_index) break;
772 sfile->frame_index[i - 1] = -1;
773
774 if (update_progress) {
775 // sig_progress...
776 lives_snprintf(mainw->msg, MAINW_MSG_SIZE, "%d", progress++);
777 threaded_dialog_spin((double)(i - sframe) / (double)(eframe - sframe + 1));
778 lives_widget_context_update();
779 }
780
781 if (mainw->cancelled != CANCEL_NONE) {
782 if (!check_if_non_virtual(sfileno, 1, sfile->frames)) save_frame_index(sfileno);
783 if (pbr) *pbr = pixbuf;
784 return i;
785 }
786 }
787 }
788
789 if (pbr) *pbr = pixbuf;
790 if (!check_if_non_virtual(sfileno, 1, sfile->frames) && !save_frame_index(sfileno)) {
791 check_storage_space(-1, FALSE);
792 return -i;
793 }
794 return i;
795 }
796
797
restore_gamma_cb(int gamma_type)798 static void restore_gamma_cb(int gamma_type) {
799 // experimental, will move to another file
800 lives_clip_t *ocb = clipboard, *ncb;
801 LiVESPixbuf *pixbuf;
802 int cf = mainw->current_file;
803 int ogamma;
804 int i, found = -1, progress = 0;
805 boolean is_stored = FALSE;
806
807 for (i = 0; i < mainw->ncbstores; i++) {
808 if (mainw->cbstores[i] == clipboard) is_stored = TRUE;
809 if (mainw->cbstores[i]->gamma_type == cfile->gamma_type) found = i;
810 if (found > -1 && is_stored) break;
811 }
812 if (!is_stored) {
813 if (mainw->ncbstores >= MAX_CBSTORES) return;
814 mainw->cbstores[mainw->ncbstores++] = clipboard;
815 }
816 if (found > -1) {
817 clipboard = mainw->cbstores[found];
818 return;
819 }
820 // not found,
821 // we'll actually make a copy of the clipboard but with the new gamma_type
822 clipboard = NULL;
823 init_clipboard();
824 lives_memcpy(clipboard, ocb, sizeof(lives_clip_t));
825 lives_memcpy(clipboard->frame_index, ocb->frame_index, clipboard->frames * sizeof(frames_t));
826 ncb = clipboard;
827 ogamma = ocb->gamma_type;
828 ocb->gamma_type = ncb->gamma_type = gamma_type; // force conversion
829 for (i = 0; i < clipboard->frames; i++) {
830 if (clipboard->frame_index[i] == -1) {
831 progress++;
832 clipboard = ocb;
833 pixbuf = pull_lives_pixbuf_at_size(0, i, get_image_ext_for_type(ocb->img_type),
834 0, 0, 0, LIVES_INTERP_BEST, FALSE);
835 clipboard = ncb;
836 if (!save_decoded(0, i, pixbuf, FALSE, progress)) {
837 mainw->current_file = 0;
838 close_current_file(cf);
839 clipboard = ocb;
840 ocb->gamma_type = ogamma;
841 return;
842 }
843 }
844 }
845 ocb->gamma_type = ogamma;
846 }
847
848
realize_all_frames(int clipno,const char * msg,boolean enough)849 frames_t realize_all_frames(int clipno, const char *msg, boolean enough) {
850 // if enough is set, we show Enough button instead of Cancel.
851 frames_t ret;
852 int current_file = mainw->current_file;
853 mainw->cancelled = CANCEL_NONE;
854 if (!IS_VALID_CLIP(clipno)) return 0;
855
856 // if its the clipboard and we have exotic gamma types we need to do a special thing
857 // - fix the gamma_type of the clipboard existing frames before inserting in cfile
858 if (clipno == 0 && prefs->btgamma && CURRENT_CLIP_HAS_VIDEO && cfile->gamma_type
859 != clipboard->gamma_type) {
860 restore_gamma_cb(cfile->gamma_type);
861 }
862
863 if (!check_if_non_virtual(clipno, 1, mainw->files[clipno]->frames)) {
864 mainw->current_file = clipno;
865 cfile->progress_start = 1;
866 cfile->progress_end = count_virtual_frames(cfile->frame_index, 1, cfile->frames);
867 if (enough) mainw->cancel_type = CANCEL_SOFT; // force "Enough" button to be shown
868 do_threaded_dialog((char *)msg, TRUE);
869 lives_widget_show_all(mainw->proc_ptr->processing);
870 mainw->cancel_type = CANCEL_KILL;
871 ret = virtual_to_images(mainw->current_file, 1, cfile->frames, TRUE, NULL);
872 end_threaded_dialog();
873 mainw->current_file = current_file;
874
875 if (mainw->cancelled != CANCEL_NONE) {
876 mainw->cancelled = CANCEL_USER;
877 return ret;
878 }
879 if (ret <= 0) return ret;
880 }
881 return mainw->files[clipno]->frames;
882 }
883
884
insert_images_in_virtual(int sfileno,frames_t where,frames_t frames,frames_t * frame_index,frames_t start)885 void insert_images_in_virtual(int sfileno, frames_t where, frames_t frames, frames_t *frame_index, frames_t start) {
886 // insert physical (frames) images (or virtual possibly) into sfile at position where [0 = before first frame]
887 // this is the virtual (book-keeping) part
888
889 // need to update the frame_index
890
891 // this is for clip type CLIP_TYPE_FILE only
892
893 lives_clip_t *sfile = mainw->files[sfileno];
894 LiVESResponseType response;
895
896 char *what;
897 frames_t nframes = sfile->frames;
898 frames_t i, j = start - 1;
899
900 if (!sfile->frame_index) return;
901
902 what = (_("creating the new frame index for the clip"));
903 lives_freep((void **)&sfile->frame_index_back);
904
905 sfile->frame_index_back = sfile->frame_index;
906 sfile->frame_index = NULL;
907
908 do {
909 response = LIVES_RESPONSE_OK;
910 create_frame_index(sfileno, FALSE, 0, nframes + frames);
911 if (!sfile->frame_index) {
912 response = do_memory_error_dialog(what, (nframes + frames) * sizeof(frames_t));
913 }
914 } while (response == LIVES_RESPONSE_RETRY);
915 lives_free(what);
916 if (response == LIVES_RESPONSE_CANCEL) {
917 sfile->frame_index = sfile->frame_index_back;
918 sfile->frame_index_back = NULL;
919 return;
920 }
921
922 lives_memcpy(sfile->frame_index, sfile->frame_index_back, where * sizeof(frames_t));
923
924 for (i = where; i < where + frames; i++) {
925 if (frame_index && frame_index[j] != -1) sfile->frame_index[i] = frame_index[j];
926 else sfile->frame_index[i] = -1;
927 if (++j >= sfile->frames) j = 0;
928 }
929
930 lives_memcpy(&sfile->frame_index[where + frames], &sfile->frame_index_back[where], (nframes - where) * sizeof(frames_t));
931
932 sfile->frames += frames;
933 save_frame_index(sfileno);
934 sfile->frames -= frames;
935 }
936
937
delete_frames_from_virtual(int sfileno,frames_t start,frames_t end)938 void delete_frames_from_virtual(int sfileno, frames_t start, frames_t end) {
939 // delete (frames) images from sfile at position start to end
940 // this is the virtual (book-keeping) part
941
942 // need to update the frame_index
943
944 // this is for clip type CLIP_TYPE_FILE only
945
946 lives_clip_t *sfile = mainw->files[sfileno];
947 LiVESResponseType response;
948
949 char *what = (_("creating the new frame index for the clip"));
950 frames_t nframes = sfile->frames, frames = end - start + 1;
951
952 lives_freep((void **)&sfile->frame_index_back);
953
954 sfile->frame_index_back = sfile->frame_index;
955 sfile->frame_index = NULL;
956
957 if (nframes - frames == 0) {
958 del_frame_index(sfile);
959 return;
960 }
961
962 do {
963 response = LIVES_RESPONSE_OK;
964 create_frame_index(sfileno, FALSE, 0, nframes - frames);
965 if (!sfile->frame_index) {
966 response = do_memory_error_dialog(what, (nframes - frames) * sizeof(frames_t));
967 }
968 } while (response == LIVES_RESPONSE_RETRY);
969 lives_free(what);
970 if (response == LIVES_RESPONSE_CANCEL) {
971 sfile->frame_index = sfile->frame_index_back;
972 sfile->frame_index_back = NULL;
973 return;
974 }
975
976 lives_memcpy(sfile->frame_index, sfile->frame_index_back, (start - 1) * sizeof(frames_t));
977 lives_memcpy(&sfile->frame_index[start - 1], &sfile->frame_index_back[end], (nframes - end) * sizeof(frames_t));
978
979 sfile->frames = nframes - frames;
980 save_frame_index(sfileno);
981 sfile->frames = nframes;
982 }
983
984
reverse_frame_index(int sfileno)985 void reverse_frame_index(int sfileno) {
986 // reverse order of (virtual) frames in clip (only used fro clipboard)
987 lives_clip_t *sfile = mainw->files[sfileno];
988 int bck;
989
990 if (!sfile || !sfile->frame_index) return;
991
992 for (frames_t i = 0; i < sfile->frames >> 1; i++) {
993 bck = sfile->frame_index[i];
994 sfile->frame_index[i] = sfile->frame_index[sfile->frames - 1 - i];
995 sfile->frame_index[sfile->frames - 1 - i] = bck;
996 }
997 }
998
999
restore_frame_index_back(int sfileno)1000 void restore_frame_index_back(int sfileno) {
1001 // undo an operation
1002 // this is the virtual (book-keeping) part
1003
1004 // need to update the frame_index
1005
1006 // this is for clip type CLIP_TYPE_FILE only
1007
1008 lives_clip_t *sfile = mainw->files[sfileno];
1009
1010 lives_freep((void **)&sfile->frame_index);
1011
1012 sfile->frame_index = sfile->frame_index_back;
1013 sfile->frame_index_back = NULL;
1014
1015 if (sfile->frame_index) {
1016 sfile->clip_type = CLIP_TYPE_FILE;
1017 save_frame_index(sfileno);
1018 } else {
1019 del_frame_index(sfile);
1020 sfile->clip_type = CLIP_TYPE_DISK;
1021 }
1022 }
1023
1024
clean_images_from_virtual(lives_clip_t * sfile,frames_t oldsframe,frames_t oldframes)1025 void clean_images_from_virtual(lives_clip_t *sfile, frames_t oldsframe, frames_t oldframes) {
1026 // remove images on disk where the frame_index points to a frame in
1027 // the original clip
1028
1029 // only needed if frames were reordered when rendered and the process is
1030 // then undone
1031
1032 // oldsframe is > 1 if we rendered to a selection
1033
1034 // should be threadsafe, provided the frame_index does not change
1035
1036 // the only purpose of this is to reclaim disk space
1037
1038 char *iname = NULL;
1039
1040 if (!sfile || !sfile->frame_index) return;
1041
1042 for (frames_t i = oldsframe; i <= oldframes; i++) {
1043 threaded_dialog_spin(0.);
1044 if ((i <= sfile->frames && sfile->frame_index[i - 1] != -1) || i > sfile->frames) {
1045 iname = make_image_file_name(sfile, i, get_image_ext_for_type(sfile->img_type));
1046 lives_rm(iname);
1047 }
1048 }
1049 }
1050
1051
frame_index_copy(frames_t * findex,frames_t nframes,frames_t offset)1052 frames_t *frame_index_copy(frames_t *findex, frames_t nframes, frames_t offset) {
1053 // copy first nframes from findex and return them, adding offset to each value
1054 // no checking is done to make sure nframes is in range
1055
1056 // start at frame offset
1057 frames_t *findexc = (frames_t *)lives_calloc(nframes, sizeof(frames_t));;
1058 for (int i = 0; i < nframes; i++) findexc[i] = findex[i + offset];
1059 return findexc;
1060 }
1061
1062
is_virtual_frame(int sfileno,frames_t frame)1063 boolean is_virtual_frame(int sfileno, frames_t frame) {
1064 // frame is virtual if it is still inside a video clip (read only)
1065 // once a frame is on disk as an image it is no longer virtual
1066
1067 // frame starts at 1 here
1068
1069 // a CLIP_TYPE_FILE with no virtual frames becomes a CLIP_TYPE_DISK
1070
1071 lives_clip_t *sfile = mainw->files[sfileno];
1072 if (!IS_VALID_CLIP(sfileno)) return FALSE;
1073 if (!sfile->frame_index) return FALSE;
1074 if (frame < 1 || frame > sfile->frames) return FALSE;
1075 if (sfile->frame_index[frame - 1] != -1) return TRUE;
1076 return FALSE;
1077 }
1078
1079
insert_blank_frames(int sfileno,frames_t nframes,frames_t after,int palette)1080 void insert_blank_frames(int sfileno, frames_t nframes, frames_t after, int palette) {
1081 // insert blank frames in clip (only valid just after clip is opened)
1082
1083 // this is ugly, it should be moved to another file
1084
1085 lives_clip_t *sfile = mainw->files[sfileno];
1086 LiVESPixbuf *blankp = NULL;
1087 LiVESError *error = NULL;
1088 char oname[PATH_MAX];
1089 char nname[PATH_MAX];
1090 char *tmp;
1091
1092 frames_t i;
1093
1094 if (first_virtual_frame(sfileno, 1, sfile->frames) != 0) {
1095 for (i = after + 1; i <= sfile->frames; i++) {
1096 if (!sfile->frame_index || sfile->frame_index[i - 1] == -1) {
1097 tmp = make_image_file_name(sfile, i, get_image_ext_for_type(sfile->img_type));
1098 lives_snprintf(oname, PATH_MAX, "%s", tmp);
1099 lives_free(tmp);
1100 if (lives_file_test(oname, LIVES_FILE_TEST_EXISTS)) {
1101 tmp = make_image_file_name(sfile, i + nframes, get_image_ext_for_type(sfile->img_type));
1102 lives_snprintf(nname, PATH_MAX, "%s", tmp);
1103 lives_free(tmp);
1104 lives_mv(oname, nname);
1105 if (THREADVAR(com_failed)) {
1106 return;
1107 // *INDENT-OFF*
1108 }}}}}
1109 // *INDENT-ON*
1110
1111 for (i = after; i < after + nframes; i++) {
1112 tmp = make_image_file_name(sfile, i + 1, get_image_ext_for_type(sfile->img_type));
1113 lives_snprintf(oname, PATH_MAX, "%s", tmp);
1114 lives_free(tmp);
1115 if (!blankp) blankp = lives_pixbuf_new_blank(sfile->hsize, sfile->vsize, palette);
1116 lives_pixbuf_save(blankp, oname, sfile->img_type, 100 - prefs->ocp, sfile->hsize, sfile->vsize, &error);
1117 if (error) {
1118 char *msg = lives_strdup_printf(_("Padding: Unable to write blank frame with size %d x %d to %s"),
1119 sfile->hsize, sfile->vsize, oname);
1120 LIVES_ERROR(msg);
1121 lives_free(msg);
1122 lives_error_free(error);
1123 break;
1124 }
1125 }
1126
1127 nframes = i - after; // in case we bailed
1128
1129 if (sfile->clip_type == CLIP_TYPE_FILE)
1130 insert_images_in_virtual(sfileno, after, nframes, NULL, 0);
1131
1132 sfile->frames += nframes;
1133
1134 if (blankp) lives_widget_object_unref(blankp);
1135 }
1136
1137
pull_frame_idle(livespointer data)1138 boolean pull_frame_idle(livespointer data) {
1139 if (cfile->fx_frame_pump >= cfile->end) return FALSE;
1140 if (virtual_to_images(mainw->current_file, cfile->fx_frame_pump, cfile->fx_frame_pump, FALSE, NULL) <= 0) {
1141 return FALSE;
1142 }
1143 cfile->fx_frame_pump++;
1144 return TRUE;
1145 }
1146