Blender V5.0
clip_editor.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cerrno>
10#include <cstddef>
11#include <fcntl.h>
12#include <sys/types.h>
13
14#ifndef WIN32
15# include <unistd.h>
16#else
17# include <io.h>
18#endif
19
20#include "MEM_guardedalloc.h"
21
22#include "DNA_defaults.h"
23#include "DNA_mask_types.h"
24
25#include "BLI_fileops.h"
26#include "BLI_listbase.h"
27#include "BLI_mutex.hh"
28#include "BLI_rect.h"
29#include "BLI_task.h"
30#include "BLI_utildefines.h"
31
32#include "BKE_context.hh"
33#include "BKE_global.hh"
34#include "BKE_lib_id.hh"
35#include "BKE_main.hh"
36#include "BKE_movieclip.h"
37#include "BKE_tracking.h"
38
40#include "IMB_imbuf.hh"
41#include "IMB_imbuf_types.hh"
42
43#include "ED_clip.hh"
44#include "ED_select_utils.hh"
45
46#include "WM_api.hh"
47#include "WM_types.hh"
48
49#include "UI_view2d.hh"
50
51#include "clip_intern.hh" /* own include */
52
53/* -------------------------------------------------------------------- */
56
58{
60
61 if (sc && sc->clip) {
62 return true;
63 }
64
65 return false;
66}
67
69{
71
72 if (sc) {
73 return sc->view == SC_VIEW_CLIP;
74 }
75
76 return false;
77}
78
80{
82
83 if (sc && sc->clip) {
85 }
86
87 return false;
88}
89
91{
93
94 if (sc && sc->clip) {
96 }
97
98 return false;
99}
100
102{
104 return false;
105 }
106
107 const SpaceClip *space_clip = CTX_wm_space_clip(C);
108 return space_clip->overlay.flag & SC_SHOW_OVERLAYS &&
110}
111
113{
116
117 if (clip) {
119
120 return sc->mask_info.mask != nullptr;
121 }
122 }
123
124 return false;
125}
126
128{
130 return false;
131 }
132
133 const SpaceClip *space_clip = CTX_wm_space_clip(C);
134 return space_clip->overlay.flag & SC_SHOW_OVERLAYS &&
136}
137
139
140/* -------------------------------------------------------------------- */
143
144void ED_space_clip_get_size(const SpaceClip *sc, int *r_width, int *r_height)
145{
146 if (sc->clip) {
147 BKE_movieclip_get_size(sc->clip, &sc->user, r_width, r_height);
148 }
149 else {
150 *r_width = *r_height = IMG_SIZE_FALLBACK;
151 }
152}
153
154void ED_space_clip_get_size_fl(const SpaceClip *sc, float r_size[2])
155{
156 int size_i[2];
157 ED_space_clip_get_size(sc, &size_i[0], &size_i[1]);
158 r_size[0] = size_i[0];
159 r_size[1] = size_i[1];
160}
161
163 const ARegion *region,
164 float *r_zoomx,
165 float *r_zoomy)
166{
167 int width, height;
168
169 ED_space_clip_get_size(sc, &width, &height);
170
171 *r_zoomx = float(BLI_rcti_size_x(&region->winrct) + 1) /
172 (BLI_rctf_size_x(&region->v2d.cur) * width);
173 *r_zoomy = float(BLI_rcti_size_y(&region->winrct) + 1) /
174 (BLI_rctf_size_y(&region->v2d.cur) * height);
175}
176
177void ED_space_clip_get_aspect(const SpaceClip *sc, float *r_aspx, float *r_aspy)
178{
180
181 if (clip) {
182 BKE_movieclip_get_aspect(clip, r_aspx, r_aspy);
183 }
184 else {
185 *r_aspx = *r_aspy = 1.0f;
186 }
187
188 if (*r_aspx < *r_aspy) {
189 *r_aspy = *r_aspy / *r_aspx;
190 *r_aspx = 1.0f;
191 }
192 else {
193 *r_aspx = *r_aspx / *r_aspy;
194 *r_aspy = 1.0f;
195 }
196}
197
198void ED_space_clip_get_aspect_dimension_aware(const SpaceClip *sc, float *r_aspx, float *r_aspy)
199{
200 int w, h;
201
202 /* most of tools does not require aspect to be returned with dimensions correction
203 * due to they're invariant to this stuff, but some transformation tools like rotation
204 * should be aware of aspect correction caused by different resolution in different
205 * directions.
206 * mainly this is used for transformation stuff
207 */
208
209 if (!sc->clip) {
210 *r_aspx = 1.0f;
211 *r_aspy = 1.0f;
212
213 return;
214 }
215
216 ED_space_clip_get_aspect(sc, r_aspx, r_aspy);
217 BKE_movieclip_get_size(sc->clip, &sc->user, &w, &h);
218
219 *r_aspx *= float(w);
220 *r_aspy *= float(h);
221
222 if (*r_aspx < *r_aspy) {
223 *r_aspy = *r_aspy / *r_aspx;
224 *r_aspx = 1.0f;
225 }
226 else {
227 *r_aspx = *r_aspx / *r_aspy;
228 *r_aspy = 1.0f;
229 }
230}
231
233{
235
236 /* Caller must ensure space does have a valid clip, otherwise it will crash, see #45017. */
238}
239
241{
242 if (sc->clip) {
243 ImBuf *ibuf;
244
246
247 if (ibuf && (ibuf->byte_buffer.data || ibuf->float_buffer.data)) {
248 return ibuf;
249 }
250
251 if (ibuf) {
252 IMB_freeImBuf(ibuf);
253 }
254 }
255
256 return nullptr;
257}
258
260 float loc[2],
261 float *scale,
262 float *angle)
263{
264 if (sc->clip) {
265 ImBuf *ibuf;
266
268 sc->clip, &sc->user, sc->postproc_flag, loc, scale, angle);
269
270 if (ibuf && (ibuf->byte_buffer.data || ibuf->float_buffer.data)) {
271 return ibuf;
272 }
273
274 if (ibuf) {
275 IMB_freeImBuf(ibuf);
276 }
277 }
278
279 return nullptr;
280}
281
283 const ARegion *region,
284 const int mval[2],
285 float r_fpos[2])
286{
288 if (!ibuf) {
289 return false;
290 }
291
292 /* map the mouse coords to the backdrop image space */
293 ED_clip_mouse_pos(sc, region, mval, r_fpos);
294
295 IMB_freeImBuf(ibuf);
296 return true;
297}
298
300 const ARegion *region,
301 const int mval[2],
302 float r_col[3])
303{
304 ImBuf *ibuf;
305 float fx, fy, co[2];
306 bool ret = false;
307
308 ibuf = ED_space_clip_get_buffer(sc);
309 if (!ibuf) {
310 return false;
311 }
312
313 /* map the mouse coords to the backdrop image space */
314 ED_clip_mouse_pos(sc, region, mval, co);
315
316 fx = co[0];
317 fy = co[1];
318
319 if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
320 const float *fp;
321 uchar *cp;
322 int x = int(fx * ibuf->x), y = int(fy * ibuf->y);
323
324 CLAMP(x, 0, ibuf->x - 1);
325 CLAMP(y, 0, ibuf->y - 1);
326
327 if (ibuf->float_buffer.data) {
328 fp = (ibuf->float_buffer.data + (ibuf->channels) * (y * ibuf->x + x));
329 copy_v3_v3(r_col, fp);
330 ret = true;
331 }
332 else if (ibuf->byte_buffer.data) {
333 cp = ibuf->byte_buffer.data + 4 * (y * ibuf->x + x);
334 rgb_uchar_to_float(r_col, cp);
336 ret = true;
337 }
338 }
339
340 IMB_freeImBuf(ibuf);
341
342 return ret;
343}
344
345void ED_clip_update_frame(const Main *mainp, int cfra)
346{
347 /* image window, compo node users */
348 LISTBASE_FOREACH (wmWindowManager *, wm, &mainp->wm) {
349 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
351
352 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
353 if (area->spacetype == SPACE_CLIP) {
354 SpaceClip *sc = static_cast<SpaceClip *>(area->spacedata.first);
355
356 sc->scopes.ok = false;
357
359 }
360 }
361 }
362 }
363}
364
365bool ED_clip_view_selection(const bContext *C, const ARegion * /*region*/, bool fit)
366{
367 float offset_x, offset_y;
368 float zoom;
369 if (!clip_view_calculate_view_selection(C, fit, &offset_x, &offset_y, &zoom)) {
370 return false;
371 }
372
374 sc->xof = offset_x;
375 sc->yof = offset_y;
376 sc->zoom = zoom;
377
378 return true;
379}
380
381void ED_clip_select_all(const SpaceClip *sc, int action, bool *r_has_selection)
382{
384 const MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(&clip->tracking);
385 const int framenr = ED_space_clip_get_clip_frame_number(sc);
386 bool has_selection = false;
387
388 if (action == SEL_TOGGLE) {
389 action = SEL_SELECT;
390
391 LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
392 if (!TRACK_VIEW_SELECTED(sc, track)) {
393 continue;
394 }
395
396 const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
397
398 if (ED_space_clip_marker_is_visible(sc, tracking_object, track, marker)) {
399 action = SEL_DESELECT;
400 break;
401 }
402 }
403
404 LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, &tracking_object->plane_tracks) {
405 if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
406 action = SEL_DESELECT;
407 break;
408 }
409 }
410 }
411
412 LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
413 if (track->flag & TRACK_HIDDEN) {
414 continue;
415 }
416
417 const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
418
419 if (ED_space_clip_marker_is_visible(sc, tracking_object, track, marker)) {
420 switch (action) {
421 case SEL_SELECT:
422 track->flag |= SELECT;
423 track->pat_flag |= SELECT;
424 track->search_flag |= SELECT;
425 break;
426 case SEL_DESELECT:
427 track->flag &= ~SELECT;
428 track->pat_flag &= ~SELECT;
429 track->search_flag &= ~SELECT;
430 break;
431 case SEL_INVERT:
432 track->flag ^= SELECT;
433 track->pat_flag ^= SELECT;
434 track->search_flag ^= SELECT;
435 break;
436 }
437 }
438
439 if (TRACK_VIEW_SELECTED(sc, track)) {
440 has_selection = true;
441 }
442 }
443
444 LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, &tracking_object->plane_tracks) {
445 if (plane_track->flag & PLANE_TRACK_HIDDEN) {
446 continue;
447 }
448
449 switch (action) {
450 case SEL_SELECT:
451 plane_track->flag |= SELECT;
452 break;
453 case SEL_DESELECT:
454 plane_track->flag &= ~SELECT;
455 break;
456 case SEL_INVERT:
457 plane_track->flag ^= SELECT;
458 break;
459 }
460 if (plane_track->flag & SELECT) {
461 has_selection = true;
462 }
463 }
464
465 if (r_has_selection) {
466 *r_has_selection = has_selection;
467 }
468}
469
470void ED_clip_point_undistorted_pos(const SpaceClip *sc, const float co[2], float r_co[2])
471{
472 copy_v2_v2(r_co, co);
473
476 float aspy = 1.0f / clip->tracking.camera.pixel_aspect;
477 int width, height;
478
479 BKE_movieclip_get_size(sc->clip, &sc->user, &width, &height);
480
481 r_co[0] *= width;
482 r_co[1] *= height * aspy;
483
484 BKE_tracking_undistort_v2(&clip->tracking, width, height, r_co, r_co);
485
486 r_co[0] /= width;
487 r_co[1] /= height * aspy;
488 }
489}
490
492 const SpaceClip *sc, const ARegion *region, float x, float y, float *xr, float *yr)
493{
494 int sx, sy, width, height;
495 float zoomx, zoomy, pos[3], imat[4][4];
496
497 ED_space_clip_get_zoom(sc, region, &zoomx, &zoomy);
498 ED_space_clip_get_size(sc, &width, &height);
499
500 UI_view2d_view_to_region(&region->v2d, 0.0f, 0.0f, &sx, &sy);
501
502 pos[0] = (x - sx) / zoomx;
503 pos[1] = (y - sy) / zoomy;
504 pos[2] = 0.0f;
505
506 invert_m4_m4(imat, sc->stabmat);
507 mul_v3_m4v3(pos, imat, pos);
508
509 *xr = pos[0] / width;
510 *yr = pos[1] / height;
511
514 if (clip != nullptr) {
515 MovieTracking *tracking = &clip->tracking;
516 float aspy = 1.0f / tracking->camera.pixel_aspect;
517 float tmp[2] = {*xr * width, *yr * height * aspy};
518
519 BKE_tracking_distort_v2(tracking, width, height, tmp, tmp);
520
521 *xr = tmp[0] / width;
522 *yr = tmp[1] / (height * aspy);
523 }
524 }
525}
526
528 const ARegion *region,
529 const float co[2],
530 float r_co[2])
531{
532 float zoomx, zoomy;
533 float pos[3];
534 int width, height;
535 int sx, sy;
536
537 UI_view2d_view_to_region(&region->v2d, 0.0f, 0.0f, &sx, &sy);
538 ED_space_clip_get_size(sc, &width, &height);
539 ED_space_clip_get_zoom(sc, region, &zoomx, &zoomy);
540
542 pos[2] = 0.0f;
543
544 /* untested */
545 mul_v3_m4v3(pos, sc->stabmat, pos);
546
547 r_co[0] = (pos[0] * width * zoomx) + float(sx);
548 r_co[1] = (pos[1] * height * zoomy) + float(sy);
549}
550
552 const ARegion *region,
553 const int mval[2],
554 float r_co[2])
555{
556 ED_clip_point_stable_pos(sc, region, mval[0], mval[1], &r_co[0], &r_co[1]);
557}
558
560{
561 if (sc) {
562 return sc->mode == SC_MODE_TRACKING;
563 }
564
565 return false;
566}
567
569{
570 if (sc) {
571 return sc->mode == SC_MODE_MASKEDIT;
572 }
573
574 return false;
575}
576
578
579/* -------------------------------------------------------------------- */
582
584{
585 return sc->clip;
586}
587
589{
590 MovieClip *old_clip;
591 bool old_clip_visible = false;
592
593 if (!screen && C) {
594 screen = CTX_wm_screen(C);
595 }
596
597 old_clip = sc->clip;
598 sc->clip = clip;
599
600 id_us_ensure_real((ID *)sc->clip);
601
602 if (screen && sc->view == SC_VIEW_CLIP) {
603 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
604 LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
605 if (sl->spacetype == SPACE_CLIP) {
606 SpaceClip *cur_sc = (SpaceClip *)sl;
607
608 if (cur_sc != sc) {
609 if (cur_sc->view == SC_VIEW_CLIP) {
610 if (cur_sc->clip == old_clip) {
611 old_clip_visible = true;
612 }
613 }
614 else {
615 if (ELEM(cur_sc->clip, old_clip, nullptr)) {
616 cur_sc->clip = clip;
617 }
618 }
619 }
620 }
621 }
622 }
623 }
624
625 /* If clip is no longer visible on screen, free memory used by its cache */
626 if (old_clip && old_clip != clip && !old_clip_visible) {
628 }
629
630 if (C) {
632 }
633}
634
636
637/* -------------------------------------------------------------------- */
640
642{
643 return sc->mask_info.mask;
644}
645
647{
648 sc->mask_info.mask = mask;
649
651
652 if (C) {
654 }
655}
656
658
659/* -------------------------------------------------------------------- */
662
666
667 /* Local copy of the clip which is used to decouple reading in a way which does not require
668 * threading lock which might "conflict" with the main thread,
669 *
670 * Used, for example, for animation prefetching (`clip->anim` can not be used from multiple
671 * threads and main thread might need it). */
673
676};
677
681
682 /* If true pre-fetching goes forward in time,
683 * otherwise it goes backwards in time (starting from current frame).
684 */
686
688
689 bool *stop;
691 float *progress;
692};
693
694/* check whether pre-fetching is allowed */
696{
697 return G.is_break;
698}
699
700/* read file for specified frame number to the memory */
702 MovieClip *clip, int current_frame, short render_size, short render_flag, size_t *r_size)
703{
705 user.framenr = current_frame;
706 user.render_size = render_size;
707 user.render_flag = render_flag;
708
709 char filepath[FILE_MAX];
710 BKE_movieclip_filepath_for_frame(clip, &user, filepath);
711
712 int file = BLI_open(filepath, O_BINARY | O_RDONLY, 0);
713 if (file == -1) {
714 return nullptr;
715 }
716
717 const size_t size = BLI_file_descriptor_size(file);
718 if (UNLIKELY(ELEM(size, 0, size_t(-1)))) {
719 close(file);
720 return nullptr;
721 }
722
723 uchar *mem = MEM_calloc_arrayN<uchar>(size, "movieclip prefetch memory file");
724 if (mem == nullptr) {
725 close(file);
726 return nullptr;
727 }
728
729 if (BLI_read(file, mem, size) != size) {
730 close(file);
731 MEM_freeN(mem);
732 return nullptr;
733 }
734
735 *r_size = size;
736
737 close(file);
738
739 return mem;
740}
741
742/* find first uncached frame within prefetching frame range */
744 int from_frame,
745 int end_frame,
746 short render_size,
747 short render_flag,
748 short direction)
749{
750 int current_frame;
752
753 user.render_size = render_size;
754 user.render_flag = render_flag;
755
756 if (direction > 0) {
757 for (current_frame = from_frame; current_frame <= end_frame; current_frame++) {
758 user.framenr = current_frame;
759
760 if (!BKE_movieclip_has_cached_frame(clip, &user)) {
761 break;
762 }
763 }
764 }
765 else {
766 for (current_frame = from_frame; current_frame >= end_frame; current_frame--) {
767 user.framenr = current_frame;
768
769 if (!BKE_movieclip_has_cached_frame(clip, &user)) {
770 break;
771 }
772 }
773 }
774
775 return current_frame;
776}
777
778/* get memory buffer for first uncached frame within prefetch frame range */
780 MovieClip *clip,
781 size_t *r_size,
782 int *r_current_frame)
783{
784 uchar *mem = nullptr;
785
786 std::lock_guard lock(queue->mutex);
787 if (!*queue->stop && !check_prefetch_break() &&
788 IN_RANGE_INCL(queue->current_frame, queue->start_frame, queue->end_frame))
789 {
790 int current_frame;
791
792 if (queue->forward) {
793 current_frame = prefetch_find_uncached_frame(clip,
794 queue->current_frame + 1,
795 queue->end_frame,
796 queue->render_size,
797 queue->render_flag,
798 1);
799 /* switch direction if read frames from current up to scene end frames */
800 if (current_frame > queue->end_frame) {
801 queue->current_frame = queue->initial_frame;
802 queue->forward = false;
803 }
804 }
805
806 if (!queue->forward) {
807 current_frame = prefetch_find_uncached_frame(clip,
808 queue->current_frame - 1,
809 queue->start_frame,
810 queue->render_size,
811 queue->render_flag,
812 -1);
813 }
814
815 if (IN_RANGE_INCL(current_frame, queue->start_frame, queue->end_frame)) {
816 int frames_processed;
817
819 clip, current_frame, queue->render_size, queue->render_flag, r_size);
820
821 *r_current_frame = current_frame;
822
823 queue->current_frame = current_frame;
824
825 if (queue->forward) {
826 frames_processed = queue->current_frame - queue->initial_frame;
827 }
828 else {
829 frames_processed = (queue->end_frame - queue->initial_frame) +
830 (queue->initial_frame - queue->current_frame);
831 }
832
833 *queue->do_update = true;
834 *queue->progress = float(frames_processed) / (queue->end_frame - queue->start_frame);
835 }
836 }
837
838 return mem;
839}
840
841static void prefetch_task_func(TaskPool *__restrict pool, void *task_data)
842{
844 MovieClip *clip = (MovieClip *)task_data;
845 uchar *mem;
846 size_t size;
847 int current_frame;
848
849 while ((mem = prefetch_thread_next_frame(queue, clip, &size, &current_frame))) {
850 ImBuf *ibuf;
853 int result;
854 char *colorspace_name = nullptr;
855 const bool use_proxy = (clip->flag & MCLIP_USE_PROXY) &&
857
858 user.framenr = current_frame;
859 user.render_size = queue->render_size;
860 user.render_flag = queue->render_flag;
861
862 /* Proxies are stored in the display space. */
863 if (!use_proxy) {
864 colorspace_name = clip->colorspace_settings.name;
865 }
866
867 ibuf = IMB_load_image_from_memory(mem, size, flag, "prefetch frame", nullptr, colorspace_name);
868 if (ibuf == nullptr) {
869 continue;
870 }
872
873 result = BKE_movieclip_put_frame_if_possible(clip, &user, ibuf);
874
875 IMB_freeImBuf(ibuf);
876
877 MEM_freeN(mem);
878
879 if (!result) {
880 /* no more space in the cache, stop reading frames */
881 *queue->stop = true;
882 break;
883 }
884 }
885}
886
888 int start_frame,
889 int current_frame,
890 int end_frame,
891 short render_size,
892 short render_flag,
893 bool *stop,
894 bool *do_update,
895 float *progress)
896{
897 int tot_thread = BLI_task_scheduler_num_threads();
898
899 /* initialize queue */
900 PrefetchQueue queue;
901 queue.current_frame = current_frame;
902 queue.initial_frame = current_frame;
903 queue.start_frame = start_frame;
904 queue.end_frame = end_frame;
905 queue.render_size = render_size;
906 queue.render_flag = render_flag;
907 queue.forward = true;
908
909 queue.stop = stop;
910 queue.do_update = do_update;
911 queue.progress = progress;
912
914 for (int i = 0; i < tot_thread; i++) {
915 BLI_task_pool_push(task_pool, prefetch_task_func, clip, false, nullptr);
916 }
919}
920
921/* NOTE: Reading happens from `clip_local` into `clip->cache`. */
923 MovieClip *clip_local,
924 int frame,
925 short render_size,
926 short render_flag,
927 bool *stop)
928{
930
931 if (check_prefetch_break() || *stop) {
932 return false;
933 }
934
935 user.framenr = frame;
936 user.render_size = render_size;
937 user.render_flag = render_flag;
938
939 if (!BKE_movieclip_has_cached_frame(clip, &user)) {
940 ImBuf *ibuf = BKE_movieclip_anim_ibuf_for_frame_no_lock(clip_local, &user);
941
942 if (ibuf) {
943 int result;
944
945 result = BKE_movieclip_put_frame_if_possible(clip, &user, ibuf);
946
947 if (!result) {
948 /* no more space in the cache, we could stop prefetching here */
949 *stop = true;
950 }
951
952 IMB_freeImBuf(ibuf);
953 }
954 else {
955 /* error reading frame, fair enough stop attempting further reading */
956 *stop = true;
957 }
958 }
959
960 return true;
961}
962
963static void do_prefetch_movie(MovieClip *clip,
964 MovieClip *clip_local,
965 int start_frame,
966 int current_frame,
967 int end_frame,
968 short render_size,
969 short render_flag,
970 bool *stop,
971 bool *do_update,
972 float *progress)
973{
974 int frame;
975 int frames_processed = 0;
976
977 /* read frames starting from current frame up to scene end frame */
978 for (frame = current_frame; frame <= end_frame; frame++) {
979 if (!prefetch_movie_frame(clip, clip_local, frame, render_size, render_flag, stop)) {
980 return;
981 }
982
983 frames_processed++;
984
985 *do_update = true;
986 *progress = float(frames_processed) / (end_frame - start_frame);
987 }
988
989 /* read frames starting from current frame up to scene start frame */
990 for (frame = current_frame; frame >= start_frame; frame--) {
991 if (!prefetch_movie_frame(clip, clip_local, frame, render_size, render_flag, stop)) {
992 return;
993 }
994
995 frames_processed++;
996
997 *do_update = true;
998 *progress = float(frames_processed) / (end_frame - start_frame);
999 }
1000}
1001
1002static void prefetch_startjob(void *pjv, wmJobWorkerStatus *worker_status)
1003{
1004 PrefetchJob *pj = static_cast<PrefetchJob *>(pjv);
1005
1006 if (pj->clip->source == MCLIP_SRC_SEQUENCE) {
1007 /* read sequence files in multiple threads */
1009 pj->start_frame,
1010 pj->current_frame,
1011 pj->end_frame,
1012 pj->render_size,
1013 pj->render_flag,
1014 &worker_status->stop,
1015 &worker_status->do_update,
1016 &worker_status->progress);
1017 }
1018 else if (pj->clip->source == MCLIP_SRC_MOVIE) {
1019 /* read movie in a single thread */
1021 pj->clip_local,
1022 pj->start_frame,
1023 pj->current_frame,
1024 pj->end_frame,
1025 pj->render_size,
1026 pj->render_flag,
1027 &worker_status->stop,
1028 &worker_status->do_update,
1029 &worker_status->progress);
1030 }
1031 else {
1032 BLI_assert_msg(0, "Unknown movie clip source when prefetching frames");
1033 }
1034}
1035
1036static void prefetch_freejob(void *pjv)
1037{
1038 PrefetchJob *pj = static_cast<PrefetchJob *>(pjv);
1039
1040 MovieClip *clip_local = pj->clip_local;
1041 if (clip_local != nullptr) {
1042 BKE_libblock_free_datablock(&clip_local->id, 0);
1043 BKE_libblock_free_data(&clip_local->id, false);
1044 BLI_assert(!clip_local->id.py_instance); /* Or call #BKE_libblock_free_data_py. */
1045 MEM_freeN(clip_local);
1046 }
1047
1048 MEM_freeN(pj);
1049}
1050
1052{
1053 Scene *scene = CTX_data_scene(C);
1054
1055 return scene->r.sfra;
1056}
1057
1059{
1060 Scene *scene = CTX_data_scene(C);
1063 int end_frame;
1064
1065 /* check whether all the frames from prefetch range are cached */
1066 end_frame = scene->r.efra;
1067
1068 if (clip->len) {
1069 end_frame = min_ii(end_frame, scene->r.sfra + clip->len - 1);
1070 }
1071
1072 return end_frame;
1073}
1074
1075/* returns true if early out is possible */
1077{
1080 int first_uncached_frame, end_frame;
1081 int clip_len;
1082
1083 if (clip == nullptr) {
1084 return true;
1085 }
1086
1087 clip_len = BKE_movieclip_get_duration(clip);
1088
1089 /* check whether all the frames from prefetch range are cached */
1090 end_frame = prefetch_get_final_frame(C);
1091
1092 first_uncached_frame = prefetch_find_uncached_frame(
1093 clip, sc->user.framenr, end_frame, sc->user.render_size, sc->user.render_flag, 1);
1094
1095 if (first_uncached_frame > end_frame || first_uncached_frame == clip_len) {
1096 int start_frame = prefetch_get_start_frame(C);
1097
1098 first_uncached_frame = prefetch_find_uncached_frame(
1099 clip, sc->user.framenr, start_frame, sc->user.render_size, sc->user.render_flag, -1);
1100
1101 if (first_uncached_frame < start_frame) {
1102 return true;
1103 }
1104 }
1105
1106 return false;
1107}
1108
1110{
1111 wmJob *wm_job;
1112 PrefetchJob *pj;
1114
1116 return;
1117 }
1118
1119 wm_job = WM_jobs_get(CTX_wm_manager(C),
1122 "Prefetching...",
1125
1126 /* create new job */
1127 pj = MEM_callocN<PrefetchJob>("prefetch job");
1128 pj->clip = ED_space_clip_get_clip(sc);
1130 pj->current_frame = sc->user.framenr;
1132 pj->render_size = sc->user.render_size;
1133 pj->render_flag = sc->user.render_flag;
1134
1135 /* Create a local copy of the clip, so that video file (clip->anim) access can happen without
1136 * acquiring the lock which will interfere with the main thread. */
1137 if (pj->clip->source == MCLIP_SRC_MOVIE) {
1138 BKE_id_copy_ex(nullptr, (&pj->clip->id), (ID **)&pj->clip_local, LIB_ID_COPY_LOCALIZE);
1139 }
1140
1142 WM_jobs_timer(wm_job, 0.2, NC_MOVIECLIP | ND_DISPLAY, 0);
1143 WM_jobs_callbacks(wm_job, prefetch_startjob, nullptr, nullptr, nullptr);
1144
1145 G.is_break = false;
1146
1147 /* and finally start the job */
1148 WM_jobs_start(CTX_wm_manager(C), wm_job);
1149}
1150
1152{
1153 SpaceClip *space_clip = CTX_wm_space_clip(C);
1154 BLI_assert(space_clip != nullptr);
1155
1156 state->offset_x = space_clip->xof;
1157 state->offset_y = space_clip->yof;
1158 state->zoom = space_clip->zoom;
1159
1160 state->lock_offset_x = 0.0f;
1161 state->lock_offset_y = 0.0f;
1162
1163 if ((space_clip->flag & SC_LOCK_SELECTION) == 0) {
1164 return;
1165 }
1166
1168 C, false, &state->offset_x, &state->offset_y, &state->zoom))
1169 {
1170 return;
1171 }
1172
1173 state->lock_offset_x = space_clip->xlockof;
1174 state->lock_offset_y = space_clip->ylockof;
1175}
1176
1178{
1179 SpaceClip *space_clip = CTX_wm_space_clip(C);
1180 BLI_assert(space_clip != nullptr);
1181
1182 if ((space_clip->flag & SC_LOCK_SELECTION) == 0) {
1183 return;
1184 }
1185
1186 float offset_x, offset_y;
1187 float zoom;
1188 if (!clip_view_calculate_view_selection(C, false, &offset_x, &offset_y, &zoom)) {
1189 return;
1190 }
1191
1192 space_clip->xlockof = state->offset_x + state->lock_offset_x - offset_x;
1193 space_clip->ylockof = state->offset_y + state->lock_offset_y - offset_y;
1194}
1195
bScreen * CTX_wm_screen(const bContext *C)
MovieClip * CTX_data_edit_movieclip(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
SpaceClip * CTX_wm_space_clip(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
void BKE_libblock_free_datablock(ID *id, int flag) ATTR_NONNULL()
void BKE_libblock_free_data(ID *id, bool do_id_user) ATTR_NONNULL()
void id_us_ensure_real(ID *id)
Definition lib_id.cc:313
ID * BKE_id_copy_ex(Main *bmain, const ID *id, ID **new_id_p, int flag)
Definition lib_id.cc:777
@ LIB_ID_COPY_LOCALIZE
struct ImBuf * BKE_movieclip_get_stable_ibuf(struct MovieClip *clip, const struct MovieClipUser *user, int postprocess_flag, float r_loc[2], float *r_scale, float *r_angle)
struct ImBuf * BKE_movieclip_get_postprocessed_ibuf(struct MovieClip *clip, const struct MovieClipUser *user, int postprocess_flag)
void BKE_movieclip_get_aspect(struct MovieClip *clip, float *aspx, float *aspy)
float BKE_movieclip_remap_scene_to_clip_frame(const struct MovieClip *clip, float framenr)
struct ImBuf * BKE_movieclip_anim_ibuf_for_frame_no_lock(struct MovieClip *clip, const struct MovieClipUser *user)
void BKE_movieclip_user_set_frame(struct MovieClipUser *user, int framenr)
bool BKE_movieclip_has_cached_frame(struct MovieClip *clip, const struct MovieClipUser *user)
int BKE_movieclip_get_duration(struct MovieClip *clip)
void BKE_movieclip_clear_cache(struct MovieClip *clip)
void BKE_movieclip_get_size(struct MovieClip *clip, const struct MovieClipUser *user, int *r_width, int *r_height)
bool BKE_movieclip_put_frame_if_possible(struct MovieClip *clip, const struct MovieClipUser *user, struct ImBuf *ibuf)
void BKE_movieclip_filepath_for_frame(struct MovieClip *clip, const struct MovieClipUser *user, char *filepath)
void BKE_movieclip_convert_multilayer_ibuf(struct ImBuf *ibuf)
Definition movieclip.cc:521
#define PLANE_TRACK_VIEW_SELECTED(plane_track)
struct MovieTrackingMarker * BKE_tracking_marker_get(struct MovieTrackingTrack *track, int framenr)
Definition tracking.cc:1358
struct MovieTrackingObject * BKE_tracking_object_get_active(const struct MovieTracking *tracking)
void BKE_tracking_distort_v2(struct MovieTracking *tracking, int image_width, int image_height, const float co[2], float r_co[2])
Definition tracking.cc:2415
#define TRACK_VIEW_SELECTED(sc, track)
void BKE_tracking_undistort_v2(struct MovieTracking *tracking, int image_width, int image_height, const float co[2], float r_co[2])
Definition tracking.cc:2442
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
File and directory operations.
#define O_BINARY
size_t BLI_file_descriptor_size(int file) ATTR_WARN_UNUSED_RESULT
Definition storage.cc:217
int BLI_open(const char *filepath, int oflag, int pmode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
int64_t BLI_read(int fd, void *buf, size_t nbytes)
Definition fileops_c.cc:96
#define LISTBASE_FOREACH(type, var, list)
MINLINE int min_ii(int a, int b)
MINLINE void rgb_uchar_to_float(float r_col[3], const unsigned char col_ub[3])
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define FILE_MAX
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:198
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:202
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition BLI_rect.h:206
unsigned char uchar
int BLI_task_scheduler_num_threads(void)
@ TASK_PRIORITY_LOW
Definition BLI_task.h:52
void * BLI_task_pool_user_data(TaskPool *pool)
Definition task_pool.cc:550
void BLI_task_pool_work_and_wait(TaskPool *pool)
Definition task_pool.cc:535
TaskPool * BLI_task_pool_create(void *userdata, eTaskPriority priority)
Definition task_pool.cc:484
void BLI_task_pool_free(TaskPool *pool)
Definition task_pool.cc:521
void BLI_task_pool_push(TaskPool *pool, TaskRunFunction run, void *taskdata, bool free_taskdata, TaskFreeFunction freedata)
Definition task_pool.cc:526
#define CLAMP(a, b, c)
#define UNLIKELY(x)
#define ELEM(...)
#define IN_RANGE_INCL(a, b, c)
#define DNA_struct_default_get(struct_name)
@ MASK_DRAWFLAG_SPLINE
@ MCLIP_USE_PROXY
@ MCLIP_PROXY_RENDER_UNDISTORT
@ MCLIP_PROXY_RENDER_SIZE_FULL
@ MCLIP_SRC_SEQUENCE
@ MCLIP_SRC_MOVIE
@ SPACE_CLIP
@ SC_VIEW_CLIP
@ SC_SHOW_OVERLAYS
@ SC_MODE_TRACKING
@ SC_MODE_MASKEDIT
@ SC_LOCK_SELECTION
#define IMG_SIZE_FALLBACK
@ TRACK_HIDDEN
@ PLANE_TRACK_HIDDEN
@ SEL_SELECT
@ SEL_INVERT
@ SEL_DESELECT
@ SEL_TOGGLE
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], const ColorSpace *colorspace)
ImBuf * IMB_load_image_from_memory(const unsigned char *mem, const size_t size, const int flags, const char *descr, const char *filepath=nullptr, char r_colorspace[IM_MAX_SPACE]=nullptr)
Definition readimage.cc:121
void IMB_freeImBuf(ImBuf *ibuf)
@ IB_byte_data
@ IB_metadata
@ IB_multilayer
@ IB_alphamode_detect
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
void UI_view2d_view_to_region(const View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL()
Definition view2d.cc:1723
@ WM_JOB_TYPE_CLIP_PREFETCH
Definition WM_api.hh:1791
@ WM_JOB_PROGRESS
Definition WM_api.hh:1766
#define ND_DISPLAY
Definition WM_types.hh:491
#define NC_MOVIECLIP
Definition WM_types.hh:397
#define NC_MASK
Definition WM_types.hh:398
#define NA_SELECTED
Definition WM_types.hh:589
volatile int lock
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
void ED_space_clip_set_clip(bContext *C, bScreen *screen, SpaceClip *sc, MovieClip *clip)
void ED_clip_view_lock_state_restore_no_jump(const bContext *C, const ClipViewLockState *state)
void ED_clip_point_stable_pos(const SpaceClip *sc, const ARegion *region, float x, float y, float *xr, float *yr)
static bool prefetch_movie_frame(MovieClip *clip, MovieClip *clip_local, int frame, short render_size, short render_flag, bool *stop)
void ED_space_clip_set_mask(bContext *C, SpaceClip *sc, Mask *mask)
MovieClip * ED_space_clip_get_clip(const SpaceClip *sc)
bool ED_space_clip_maskedit_visible_splines_poll(bContext *C)
bool ED_space_clip_check_show_trackedit(const SpaceClip *sc)
static int prefetch_get_start_frame(const bContext *C)
static bool prefetch_check_early_out(const bContext *C)
void ED_clip_mouse_pos(const SpaceClip *sc, const ARegion *region, const int mval[2], float r_co[2])
bool ED_space_clip_check_show_maskedit(const SpaceClip *sc)
void ED_clip_update_frame(const Main *mainp, int cfra)
Mask * ED_space_clip_get_mask(const SpaceClip *sc)
void ED_space_clip_get_size(const SpaceClip *sc, int *r_width, int *r_height)
static bool check_prefetch_break()
void ED_space_clip_get_zoom(const SpaceClip *sc, const ARegion *region, float *r_zoomx, float *r_zoomy)
bool ED_space_clip_maskedit_poll(bContext *C)
static uchar * prefetch_thread_next_frame(PrefetchQueue *queue, MovieClip *clip, size_t *r_size, int *r_current_frame)
bool ED_space_clip_view_clip_poll(bContext *C)
static uchar * prefetch_read_file_to_memory(MovieClip *clip, int current_frame, short render_size, short render_flag, size_t *r_size)
static void prefetch_task_func(TaskPool *__restrict pool, void *task_data)
static void prefetch_startjob(void *pjv, wmJobWorkerStatus *worker_status)
static void do_prefetch_movie(MovieClip *clip, MovieClip *clip_local, int start_frame, int current_frame, int end_frame, short render_size, short render_flag, bool *stop, bool *do_update, float *progress)
static int prefetch_get_final_frame(const bContext *C)
void ED_space_clip_get_size_fl(const SpaceClip *sc, float r_size[2])
bool ED_space_clip_get_position(const SpaceClip *sc, const ARegion *region, const int mval[2], float r_fpos[2])
bool ED_space_clip_maskedit_mask_poll(bContext *C)
void ED_space_clip_get_aspect(const SpaceClip *sc, float *r_aspx, float *r_aspy)
bool ED_clip_view_selection(const bContext *C, const ARegion *, bool fit)
int ED_space_clip_get_clip_frame_number(const SpaceClip *sc)
static void prefetch_freejob(void *pjv)
bool ED_space_clip_poll(bContext *C)
void ED_clip_view_lock_state_store(const bContext *C, ClipViewLockState *state)
void ED_clip_select_all(const SpaceClip *sc, int action, bool *r_has_selection)
void clip_start_prefetch_job(const bContext *C)
void ED_clip_point_undistorted_pos(const SpaceClip *sc, const float co[2], float r_co[2])
ImBuf * ED_space_clip_get_buffer(const SpaceClip *sc)
bool ED_space_clip_maskedit_mask_visible_splines_poll(bContext *C)
static void start_prefetch_threads(MovieClip *clip, int start_frame, int current_frame, int end_frame, short render_size, short render_flag, bool *stop, bool *do_update, float *progress)
bool ED_space_clip_color_sample(const SpaceClip *sc, const ARegion *region, const int mval[2], float r_col[3])
bool ED_space_clip_tracking_poll(bContext *C)
static int prefetch_find_uncached_frame(MovieClip *clip, int from_frame, int end_frame, short render_size, short render_flag, short direction)
void ED_clip_point_stable_pos__reverse(const SpaceClip *sc, const ARegion *region, const float co[2], float r_co[2])
the reverse of ED_clip_point_stable_pos(), gets the marker region coords. better name here?...
void ED_space_clip_get_aspect_dimension_aware(const SpaceClip *sc, float *r_aspx, float *r_aspy)
ImBuf * ED_space_clip_get_stable_buffer(const SpaceClip *sc, float loc[2], float *scale, float *angle)
BLI_INLINE bool ED_space_clip_marker_is_visible(const SpaceClip *space_clip, const MovieTrackingObject *tracking_object, const MovieTrackingTrack *track, const MovieTrackingMarker *marker)
bool clip_view_calculate_view_selection(const bContext *C, bool fit, float *r_offset_x, float *r_offset_y, float *r_zoom)
nullptr float
#define SELECT
TaskPool * task_pool
uint pos
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
static ulong state[N]
#define G(x, y, z)
std::mutex Mutex
Definition BLI_mutex.hh:47
return ret
Definition DNA_ID.h:414
void * py_instance
Definition DNA_ID.h:518
const ColorSpace * colorspace
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
ListBase wm
Definition BKE_main.hh:307
struct Mask * mask
struct MovieTracking tracking
ColorManagedColorspaceSettings colorspace_settings
MovieTrackingCamera camera
short render_size
MovieClip * clip
short render_flag
MovieClip * clip_local
blender::Mutex mutex
struct RenderData r
struct SpaceClipOverlay overlay
struct MovieClipUser user
float stabmat[4][4]
struct MovieClipScopes scopes
struct MovieClip * clip
MaskSpaceInfo mask_info
ListBase areabase
i
Definition text_draw.cc:230
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
void WM_jobs_timer(wmJob *wm_job, double time_step, uint note, uint endnote)
Definition wm_jobs.cc:376
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition wm_jobs.cc:479
wmJob * WM_jobs_get(wmWindowManager *wm, wmWindow *win, const void *owner, const char *name, const eWM_JobFlag flag, const eWM_JobType job_type)
Definition wm_jobs.cc:211
void WM_jobs_callbacks(wmJob *wm_job, wm_jobs_start_callback startjob, void(*initjob)(void *), void(*update)(void *), void(*endjob)(void *))
Definition wm_jobs.cc:388
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *customdata))
Definition wm_jobs.cc:360
bScreen * WM_window_get_active_screen(const wmWindow *win)
uint8_t flag
Definition wm_window.cc:145