Blender V4.3
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
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_rect.h"
28#include "BLI_task.h"
29#include "BLI_utildefines.h"
30
31#include "BKE_context.hh"
32#include "BKE_global.hh"
33#include "BKE_lib_id.hh"
34#include "BKE_main.hh"
35#include "BKE_movieclip.h"
36#include "BKE_tracking.h"
37
39#include "IMB_imbuf.hh"
40#include "IMB_imbuf_types.hh"
41
42#include "ED_clip.hh"
43#include "ED_select_utils.hh"
44
45#include "WM_api.hh"
46#include "WM_types.hh"
47
48#include "UI_view2d.hh"
49
50#include "clip_intern.hh" /* own include */
51
52/* -------------------------------------------------------------------- */
57{
59
60 if (sc && sc->clip) {
61 return true;
62 }
63
64 return false;
65}
66
68{
70
71 if (sc) {
72 return sc->view == SC_VIEW_CLIP;
73 }
74
75 return false;
76}
77
79{
81
82 if (sc && sc->clip) {
84 }
85
86 return false;
87}
88
90{
92
93 if (sc && sc->clip) {
95 }
96
97 return false;
98}
99
101{
103 return false;
104 }
105
106 const SpaceClip *space_clip = CTX_wm_space_clip(C);
107 return space_clip->mask_info.draw_flag & MASK_DRAWFLAG_SPLINE;
108}
109
111{
114
115 if (clip) {
117
118 return sc->mask_info.mask != nullptr;
119 }
120 }
121
122 return false;
123}
124
126{
128 return false;
129 }
130
131 const SpaceClip *space_clip = CTX_wm_space_clip(C);
132 return space_clip->mask_info.draw_flag & MASK_DRAWFLAG_SPLINE;
133}
134
137/* -------------------------------------------------------------------- */
141void ED_space_clip_get_size(const SpaceClip *sc, int *r_width, int *r_height)
142{
143 if (sc->clip) {
144 BKE_movieclip_get_size(sc->clip, &sc->user, r_width, r_height);
145 }
146 else {
147 *r_width = *r_height = IMG_SIZE_FALLBACK;
148 }
149}
150
151void ED_space_clip_get_size_fl(const SpaceClip *sc, float r_size[2])
152{
153 int size_i[2];
154 ED_space_clip_get_size(sc, &size_i[0], &size_i[1]);
155 r_size[0] = size_i[0];
156 r_size[1] = size_i[1];
157}
158
160 const ARegion *region,
161 float *r_zoomx,
162 float *r_zoomy)
163{
164 int width, height;
165
166 ED_space_clip_get_size(sc, &width, &height);
167
168 *r_zoomx = float(BLI_rcti_size_x(&region->winrct) + 1) /
169 (BLI_rctf_size_x(&region->v2d.cur) * width);
170 *r_zoomy = float(BLI_rcti_size_y(&region->winrct) + 1) /
171 (BLI_rctf_size_y(&region->v2d.cur) * height);
172}
173
174void ED_space_clip_get_aspect(const SpaceClip *sc, float *r_aspx, float *r_aspy)
175{
177
178 if (clip) {
179 BKE_movieclip_get_aspect(clip, r_aspx, r_aspy);
180 }
181 else {
182 *r_aspx = *r_aspy = 1.0f;
183 }
184
185 if (*r_aspx < *r_aspy) {
186 *r_aspy = *r_aspy / *r_aspx;
187 *r_aspx = 1.0f;
188 }
189 else {
190 *r_aspx = *r_aspx / *r_aspy;
191 *r_aspy = 1.0f;
192 }
193}
194
195void ED_space_clip_get_aspect_dimension_aware(const SpaceClip *sc, float *r_aspx, float *r_aspy)
196{
197 int w, h;
198
199 /* most of tools does not require aspect to be returned with dimensions correction
200 * due to they're invariant to this stuff, but some transformation tools like rotation
201 * should be aware of aspect correction caused by different resolution in different
202 * directions.
203 * mainly this is used for transformation stuff
204 */
205
206 if (!sc->clip) {
207 *r_aspx = 1.0f;
208 *r_aspy = 1.0f;
209
210 return;
211 }
212
213 ED_space_clip_get_aspect(sc, r_aspx, r_aspy);
214 BKE_movieclip_get_size(sc->clip, &sc->user, &w, &h);
215
216 *r_aspx *= float(w);
217 *r_aspy *= float(h);
218
219 if (*r_aspx < *r_aspy) {
220 *r_aspy = *r_aspy / *r_aspx;
221 *r_aspx = 1.0f;
222 }
223 else {
224 *r_aspx = *r_aspx / *r_aspy;
225 *r_aspy = 1.0f;
226 }
227}
228
230{
232
233 /* Caller must ensure space does have a valid clip, otherwise it will crash, see #45017. */
235}
236
238{
239 if (sc->clip) {
240 ImBuf *ibuf;
241
243
244 if (ibuf && (ibuf->byte_buffer.data || ibuf->float_buffer.data)) {
245 return ibuf;
246 }
247
248 if (ibuf) {
249 IMB_freeImBuf(ibuf);
250 }
251 }
252
253 return nullptr;
254}
255
257 float loc[2],
258 float *scale,
259 float *angle)
260{
261 if (sc->clip) {
262 ImBuf *ibuf;
263
265 sc->clip, &sc->user, sc->postproc_flag, loc, scale, angle);
266
267 if (ibuf && (ibuf->byte_buffer.data || ibuf->float_buffer.data)) {
268 return ibuf;
269 }
270
271 if (ibuf) {
272 IMB_freeImBuf(ibuf);
273 }
274 }
275
276 return nullptr;
277}
278
280 const ARegion *region,
281 const int mval[2],
282 float r_fpos[2])
283{
285 if (!ibuf) {
286 return false;
287 }
288
289 /* map the mouse coords to the backdrop image space */
290 ED_clip_mouse_pos(sc, region, mval, r_fpos);
291
292 IMB_freeImBuf(ibuf);
293 return true;
294}
295
297 const ARegion *region,
298 const int mval[2],
299 float r_col[3])
300{
301 ImBuf *ibuf;
302 float fx, fy, co[2];
303 bool ret = false;
304
305 ibuf = ED_space_clip_get_buffer(sc);
306 if (!ibuf) {
307 return false;
308 }
309
310 /* map the mouse coords to the backdrop image space */
311 ED_clip_mouse_pos(sc, region, mval, co);
312
313 fx = co[0];
314 fy = co[1];
315
316 if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
317 const float *fp;
318 uchar *cp;
319 int x = int(fx * ibuf->x), y = int(fy * ibuf->y);
320
321 CLAMP(x, 0, ibuf->x - 1);
322 CLAMP(y, 0, ibuf->y - 1);
323
324 if (ibuf->float_buffer.data) {
325 fp = (ibuf->float_buffer.data + (ibuf->channels) * (y * ibuf->x + x));
326 copy_v3_v3(r_col, fp);
327 ret = true;
328 }
329 else if (ibuf->byte_buffer.data) {
330 cp = ibuf->byte_buffer.data + 4 * (y * ibuf->x + x);
331 rgb_uchar_to_float(r_col, cp);
333 ret = true;
334 }
335 }
336
337 IMB_freeImBuf(ibuf);
338
339 return ret;
340}
341
342void ED_clip_update_frame(const Main *mainp, int cfra)
343{
344 /* image window, compo node users */
345 LISTBASE_FOREACH (wmWindowManager *, wm, &mainp->wm) {
346 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
348
349 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
350 if (area->spacetype == SPACE_CLIP) {
351 SpaceClip *sc = static_cast<SpaceClip *>(area->spacedata.first);
352
353 sc->scopes.ok = false;
354
356 }
357 }
358 }
359 }
360}
361
362bool ED_clip_view_selection(const bContext *C, const ARegion * /*region*/, bool fit)
363{
364 float offset_x, offset_y;
365 float zoom;
366 if (!clip_view_calculate_view_selection(C, fit, &offset_x, &offset_y, &zoom)) {
367 return false;
368 }
369
371 sc->xof = offset_x;
372 sc->yof = offset_y;
373 sc->zoom = zoom;
374
375 return true;
376}
377
378void ED_clip_select_all(const SpaceClip *sc, int action, bool *r_has_selection)
379{
381 const MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(&clip->tracking);
382 const int framenr = ED_space_clip_get_clip_frame_number(sc);
383 bool has_selection = false;
384
385 if (action == SEL_TOGGLE) {
386 action = SEL_SELECT;
387
388 LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
389 if (!TRACK_VIEW_SELECTED(sc, track)) {
390 continue;
391 }
392
393 const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
394
395 if (ED_space_clip_marker_is_visible(sc, tracking_object, track, marker)) {
396 action = SEL_DESELECT;
397 break;
398 }
399 }
400
401 LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, &tracking_object->plane_tracks) {
402 if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
403 action = SEL_DESELECT;
404 break;
405 }
406 }
407 }
408
409 LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
410 if (track->flag & TRACK_HIDDEN) {
411 continue;
412 }
413
414 const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
415
416 if (ED_space_clip_marker_is_visible(sc, tracking_object, track, marker)) {
417 switch (action) {
418 case SEL_SELECT:
419 track->flag |= SELECT;
420 track->pat_flag |= SELECT;
421 track->search_flag |= SELECT;
422 break;
423 case SEL_DESELECT:
424 track->flag &= ~SELECT;
425 track->pat_flag &= ~SELECT;
426 track->search_flag &= ~SELECT;
427 break;
428 case SEL_INVERT:
429 track->flag ^= SELECT;
430 track->pat_flag ^= SELECT;
431 track->search_flag ^= SELECT;
432 break;
433 }
434 }
435
436 if (TRACK_VIEW_SELECTED(sc, track)) {
437 has_selection = true;
438 }
439 }
440
441 LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, &tracking_object->plane_tracks) {
442 if (plane_track->flag & PLANE_TRACK_HIDDEN) {
443 continue;
444 }
445
446 switch (action) {
447 case SEL_SELECT:
448 plane_track->flag |= SELECT;
449 break;
450 case SEL_DESELECT:
451 plane_track->flag &= ~SELECT;
452 break;
453 case SEL_INVERT:
454 plane_track->flag ^= SELECT;
455 break;
456 }
457 if (plane_track->flag & SELECT) {
458 has_selection = true;
459 }
460 }
461
462 if (r_has_selection) {
463 *r_has_selection = has_selection;
464 }
465}
466
467void ED_clip_point_undistorted_pos(const SpaceClip *sc, const float co[2], float r_co[2])
468{
469 copy_v2_v2(r_co, co);
470
473 float aspy = 1.0f / clip->tracking.camera.pixel_aspect;
474 int width, height;
475
476 BKE_movieclip_get_size(sc->clip, &sc->user, &width, &height);
477
478 r_co[0] *= width;
479 r_co[1] *= height * aspy;
480
481 BKE_tracking_undistort_v2(&clip->tracking, width, height, r_co, r_co);
482
483 r_co[0] /= width;
484 r_co[1] /= height * aspy;
485 }
486}
487
489 const SpaceClip *sc, const ARegion *region, float x, float y, float *xr, float *yr)
490{
491 int sx, sy, width, height;
492 float zoomx, zoomy, pos[3], imat[4][4];
493
494 ED_space_clip_get_zoom(sc, region, &zoomx, &zoomy);
495 ED_space_clip_get_size(sc, &width, &height);
496
497 UI_view2d_view_to_region(&region->v2d, 0.0f, 0.0f, &sx, &sy);
498
499 pos[0] = (x - sx) / zoomx;
500 pos[1] = (y - sy) / zoomy;
501 pos[2] = 0.0f;
502
503 invert_m4_m4(imat, sc->stabmat);
504 mul_v3_m4v3(pos, imat, pos);
505
506 *xr = pos[0] / width;
507 *yr = pos[1] / height;
508
511 if (clip != nullptr) {
512 MovieTracking *tracking = &clip->tracking;
513 float aspy = 1.0f / tracking->camera.pixel_aspect;
514 float tmp[2] = {*xr * width, *yr * height * aspy};
515
516 BKE_tracking_distort_v2(tracking, width, height, tmp, tmp);
517
518 *xr = tmp[0] / width;
519 *yr = tmp[1] / (height * aspy);
520 }
521 }
522}
523
525 const ARegion *region,
526 const float co[2],
527 float r_co[2])
528{
529 float zoomx, zoomy;
530 float pos[3];
531 int width, height;
532 int sx, sy;
533
534 UI_view2d_view_to_region(&region->v2d, 0.0f, 0.0f, &sx, &sy);
535 ED_space_clip_get_size(sc, &width, &height);
536 ED_space_clip_get_zoom(sc, region, &zoomx, &zoomy);
537
539 pos[2] = 0.0f;
540
541 /* untested */
542 mul_v3_m4v3(pos, sc->stabmat, pos);
543
544 r_co[0] = (pos[0] * width * zoomx) + float(sx);
545 r_co[1] = (pos[1] * height * zoomy) + float(sy);
546}
547
549 const ARegion *region,
550 const int mval[2],
551 float r_co[2])
552{
553 ED_clip_point_stable_pos(sc, region, mval[0], mval[1], &r_co[0], &r_co[1]);
554}
555
557{
558 if (sc) {
559 return sc->mode == SC_MODE_TRACKING;
560 }
561
562 return false;
563}
564
566{
567 if (sc) {
568 return sc->mode == SC_MODE_MASKEDIT;
569 }
570
571 return false;
572}
573
576/* -------------------------------------------------------------------- */
581{
582 return sc->clip;
583}
584
586{
587 MovieClip *old_clip;
588 bool old_clip_visible = false;
589
590 if (!screen && C) {
591 screen = CTX_wm_screen(C);
592 }
593
594 old_clip = sc->clip;
595 sc->clip = clip;
596
597 id_us_ensure_real((ID *)sc->clip);
598
599 if (screen && sc->view == SC_VIEW_CLIP) {
600 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
601 LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
602 if (sl->spacetype == SPACE_CLIP) {
603 SpaceClip *cur_sc = (SpaceClip *)sl;
604
605 if (cur_sc != sc) {
606 if (cur_sc->view == SC_VIEW_CLIP) {
607 if (cur_sc->clip == old_clip) {
608 old_clip_visible = true;
609 }
610 }
611 else {
612 if (ELEM(cur_sc->clip, old_clip, nullptr)) {
613 cur_sc->clip = clip;
614 }
615 }
616 }
617 }
618 }
619 }
620 }
621
622 /* If clip is no longer visible on screen, free memory used by its cache */
623 if (old_clip && old_clip != clip && !old_clip_visible) {
625 }
626
627 if (C) {
629 }
630}
631
634/* -------------------------------------------------------------------- */
639{
640 return sc->mask_info.mask;
641}
642
644{
645 sc->mask_info.mask = mask;
646
648
649 if (C) {
651 }
652}
653
656/* -------------------------------------------------------------------- */
663
664 /* Local copy of the clip which is used to decouple reading in a way which does not require
665 * threading lock which might "conflict" with the main thread,
666 *
667 * Used, for example, for animation prefetching (`clip->anim` can not be used from multiple
668 * threads and main thread might need it). */
670
673};
674
678
679 /* If true pre-fetching goes forward in time,
680 * otherwise it goes backwards in time (starting from current frame).
681 */
683
685
686 bool *stop;
688 float *progress;
689};
690
691/* check whether pre-fetching is allowed */
693{
694 return G.is_break;
695}
696
697/* read file for specified frame number to the memory */
699 MovieClip *clip, int current_frame, short render_size, short render_flag, size_t *r_size)
700{
702 user.framenr = current_frame;
703 user.render_size = render_size;
704 user.render_flag = render_flag;
705
706 char filepath[FILE_MAX];
707 BKE_movieclip_filepath_for_frame(clip, &user, filepath);
708
709 int file = BLI_open(filepath, O_BINARY | O_RDONLY, 0);
710 if (file == -1) {
711 return nullptr;
712 }
713
714 const size_t size = BLI_file_descriptor_size(file);
715 if (UNLIKELY(ELEM(size, 0, size_t(-1)))) {
716 close(file);
717 return nullptr;
718 }
719
720 uchar *mem = MEM_cnew_array<uchar>(size, "movieclip prefetch memory file");
721 if (mem == nullptr) {
722 close(file);
723 return nullptr;
724 }
725
726 if (BLI_read(file, mem, size) != size) {
727 close(file);
728 MEM_freeN(mem);
729 return nullptr;
730 }
731
732 *r_size = size;
733
734 close(file);
735
736 return mem;
737}
738
739/* find first uncached frame within prefetching frame range */
741 int from_frame,
742 int end_frame,
743 short render_size,
744 short render_flag,
745 short direction)
746{
747 int current_frame;
749
750 user.render_size = render_size;
751 user.render_flag = render_flag;
752
753 if (direction > 0) {
754 for (current_frame = from_frame; current_frame <= end_frame; current_frame++) {
755 user.framenr = current_frame;
756
757 if (!BKE_movieclip_has_cached_frame(clip, &user)) {
758 break;
759 }
760 }
761 }
762 else {
763 for (current_frame = from_frame; current_frame >= end_frame; current_frame--) {
764 user.framenr = current_frame;
765
766 if (!BKE_movieclip_has_cached_frame(clip, &user)) {
767 break;
768 }
769 }
770 }
771
772 return current_frame;
773}
774
775/* get memory buffer for first uncached frame within prefetch frame range */
777 MovieClip *clip,
778 size_t *r_size,
779 int *r_current_frame)
780{
781 uchar *mem = nullptr;
782
783 BLI_spin_lock(&queue->spin);
784 if (!*queue->stop && !check_prefetch_break() &&
785 IN_RANGE_INCL(queue->current_frame, queue->start_frame, queue->end_frame))
786 {
787 int current_frame;
788
789 if (queue->forward) {
790 current_frame = prefetch_find_uncached_frame(clip,
791 queue->current_frame + 1,
792 queue->end_frame,
793 queue->render_size,
794 queue->render_flag,
795 1);
796 /* switch direction if read frames from current up to scene end frames */
797 if (current_frame > queue->end_frame) {
798 queue->current_frame = queue->initial_frame;
799 queue->forward = false;
800 }
801 }
802
803 if (!queue->forward) {
804 current_frame = prefetch_find_uncached_frame(clip,
805 queue->current_frame - 1,
806 queue->start_frame,
807 queue->render_size,
808 queue->render_flag,
809 -1);
810 }
811
812 if (IN_RANGE_INCL(current_frame, queue->start_frame, queue->end_frame)) {
813 int frames_processed;
814
816 clip, current_frame, queue->render_size, queue->render_flag, r_size);
817
818 *r_current_frame = current_frame;
819
820 queue->current_frame = current_frame;
821
822 if (queue->forward) {
823 frames_processed = queue->current_frame - queue->initial_frame;
824 }
825 else {
826 frames_processed = (queue->end_frame - queue->initial_frame) +
827 (queue->initial_frame - queue->current_frame);
828 }
829
830 *queue->do_update = true;
831 *queue->progress = float(frames_processed) / (queue->end_frame - queue->start_frame);
832 }
833 }
834 BLI_spin_unlock(&queue->spin);
835
836 return mem;
837}
838
839static void prefetch_task_func(TaskPool *__restrict pool, void *task_data)
840{
842 MovieClip *clip = (MovieClip *)task_data;
843 uchar *mem;
844 size_t size;
845 int current_frame;
846
847 while ((mem = prefetch_thread_next_frame(queue, clip, &size, &current_frame))) {
848 ImBuf *ibuf;
851 int result;
852 char *colorspace_name = nullptr;
853 const bool use_proxy = (clip->flag & MCLIP_USE_PROXY) &&
854 (queue->render_size != MCLIP_PROXY_RENDER_SIZE_FULL);
855
856 user.framenr = current_frame;
857 user.render_size = queue->render_size;
858 user.render_flag = queue->render_flag;
859
860 /* Proxies are stored in the display space. */
861 if (!use_proxy) {
862 colorspace_name = clip->colorspace_settings.name;
863 }
864
865 ibuf = IMB_ibImageFromMemory(mem, size, flag, colorspace_name, "prefetch frame");
866 if (ibuf == nullptr) {
867 continue;
868 }
870
871 result = BKE_movieclip_put_frame_if_possible(clip, &user, ibuf);
872
873 IMB_freeImBuf(ibuf);
874
875 MEM_freeN(mem);
876
877 if (!result) {
878 /* no more space in the cache, stop reading frames */
879 *queue->stop = true;
880 break;
881 }
882 }
883}
884
886 int start_frame,
887 int current_frame,
888 int end_frame,
889 short render_size,
890 short render_flag,
891 bool *stop,
892 bool *do_update,
893 float *progress)
894{
895 int tot_thread = BLI_task_scheduler_num_threads();
896
897 /* initialize queue */
898 PrefetchQueue queue;
899 BLI_spin_init(&queue.spin);
900
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 BLI_spin_end(&queue.spin);
921}
922
923/* NOTE: Reading happens from `clip_local` into `clip->cache`. */
925 MovieClip *clip_local,
926 int frame,
927 short render_size,
928 short render_flag,
929 bool *stop)
930{
932
933 if (check_prefetch_break() || *stop) {
934 return false;
935 }
936
937 user.framenr = frame;
938 user.render_size = render_size;
939 user.render_flag = render_flag;
940
941 if (!BKE_movieclip_has_cached_frame(clip, &user)) {
942 ImBuf *ibuf = BKE_movieclip_anim_ibuf_for_frame_no_lock(clip_local, &user);
943
944 if (ibuf) {
945 int result;
946
947 result = BKE_movieclip_put_frame_if_possible(clip, &user, ibuf);
948
949 if (!result) {
950 /* no more space in the cache, we could stop prefetching here */
951 *stop = true;
952 }
953
954 IMB_freeImBuf(ibuf);
955 }
956 else {
957 /* error reading frame, fair enough stop attempting further reading */
958 *stop = true;
959 }
960 }
961
962 return true;
963}
964
965static void do_prefetch_movie(MovieClip *clip,
966 MovieClip *clip_local,
967 int start_frame,
968 int current_frame,
969 int end_frame,
970 short render_size,
971 short render_flag,
972 bool *stop,
973 bool *do_update,
974 float *progress)
975{
976 int frame;
977 int frames_processed = 0;
978
979 /* read frames starting from current frame up to scene end frame */
980 for (frame = current_frame; frame <= end_frame; frame++) {
981 if (!prefetch_movie_frame(clip, clip_local, frame, render_size, render_flag, stop)) {
982 return;
983 }
984
985 frames_processed++;
986
987 *do_update = true;
988 *progress = float(frames_processed) / (end_frame - start_frame);
989 }
990
991 /* read frames starting from current frame up to scene start frame */
992 for (frame = current_frame; frame >= start_frame; frame--) {
993 if (!prefetch_movie_frame(clip, clip_local, frame, render_size, render_flag, stop)) {
994 return;
995 }
996
997 frames_processed++;
998
999 *do_update = true;
1000 *progress = float(frames_processed) / (end_frame - start_frame);
1001 }
1002}
1003
1004static void prefetch_startjob(void *pjv, wmJobWorkerStatus *worker_status)
1005{
1006 PrefetchJob *pj = static_cast<PrefetchJob *>(pjv);
1007
1008 if (pj->clip->source == MCLIP_SRC_SEQUENCE) {
1009 /* read sequence files in multiple threads */
1011 pj->start_frame,
1012 pj->current_frame,
1013 pj->end_frame,
1014 pj->render_size,
1015 pj->render_flag,
1016 &worker_status->stop,
1017 &worker_status->do_update,
1018 &worker_status->progress);
1019 }
1020 else if (pj->clip->source == MCLIP_SRC_MOVIE) {
1021 /* read movie in a single thread */
1023 pj->clip_local,
1024 pj->start_frame,
1025 pj->current_frame,
1026 pj->end_frame,
1027 pj->render_size,
1028 pj->render_flag,
1029 &worker_status->stop,
1030 &worker_status->do_update,
1031 &worker_status->progress);
1032 }
1033 else {
1034 BLI_assert_msg(0, "Unknown movie clip source when prefetching frames");
1035 }
1036}
1037
1038static void prefetch_freejob(void *pjv)
1039{
1040 PrefetchJob *pj = static_cast<PrefetchJob *>(pjv);
1041
1042 MovieClip *clip_local = pj->clip_local;
1043 if (clip_local != nullptr) {
1044 BKE_libblock_free_datablock(&clip_local->id, 0);
1045 BKE_libblock_free_data(&clip_local->id, false);
1046 BLI_assert(!clip_local->id.py_instance); /* Or call #BKE_libblock_free_data_py. */
1047 MEM_freeN(clip_local);
1048 }
1049
1050 MEM_freeN(pj);
1051}
1052
1054{
1055 Scene *scene = CTX_data_scene(C);
1056
1057 return scene->r.sfra;
1058}
1059
1061{
1062 Scene *scene = CTX_data_scene(C);
1065 int end_frame;
1066
1067 /* check whether all the frames from prefetch range are cached */
1068 end_frame = scene->r.efra;
1069
1070 if (clip->len) {
1071 end_frame = min_ii(end_frame, scene->r.sfra + clip->len - 1);
1072 }
1073
1074 return end_frame;
1075}
1076
1077/* returns true if early out is possible */
1079{
1082 int first_uncached_frame, end_frame;
1083 int clip_len;
1084
1085 if (clip == nullptr) {
1086 return true;
1087 }
1088
1089 clip_len = BKE_movieclip_get_duration(clip);
1090
1091 /* check whether all the frames from prefetch range are cached */
1092 end_frame = prefetch_get_final_frame(C);
1093
1094 first_uncached_frame = prefetch_find_uncached_frame(
1095 clip, sc->user.framenr, end_frame, sc->user.render_size, sc->user.render_flag, 1);
1096
1097 if (first_uncached_frame > end_frame || first_uncached_frame == clip_len) {
1098 int start_frame = prefetch_get_start_frame(C);
1099
1100 first_uncached_frame = prefetch_find_uncached_frame(
1101 clip, sc->user.framenr, start_frame, sc->user.render_size, sc->user.render_flag, -1);
1102
1103 if (first_uncached_frame < start_frame) {
1104 return true;
1105 }
1106 }
1107
1108 return false;
1109}
1110
1112{
1113 wmJob *wm_job;
1114 PrefetchJob *pj;
1116
1117 if (prefetch_check_early_out(C)) {
1118 return;
1119 }
1120
1121 wm_job = WM_jobs_get(CTX_wm_manager(C),
1122 CTX_wm_window(C),
1123 CTX_data_scene(C),
1124 "Prefetching",
1127
1128 /* create new job */
1129 pj = MEM_cnew<PrefetchJob>("prefetch job");
1130 pj->clip = ED_space_clip_get_clip(sc);
1132 pj->current_frame = sc->user.framenr;
1134 pj->render_size = sc->user.render_size;
1135 pj->render_flag = sc->user.render_flag;
1136
1137 /* Create a local copy of the clip, so that video file (clip->anim) access can happen without
1138 * acquiring the lock which will interfere with the main thread. */
1139 if (pj->clip->source == MCLIP_SRC_MOVIE) {
1140 BKE_id_copy_ex(nullptr, (ID *)&pj->clip->id, (ID **)&pj->clip_local, LIB_ID_COPY_LOCALIZE);
1141 }
1142
1144 WM_jobs_timer(wm_job, 0.2, NC_MOVIECLIP | ND_DISPLAY, 0);
1145 WM_jobs_callbacks(wm_job, prefetch_startjob, nullptr, nullptr, nullptr);
1146
1147 G.is_break = false;
1148
1149 /* and finally start the job */
1150 WM_jobs_start(CTX_wm_manager(C), wm_job);
1151}
1152
1154{
1155 SpaceClip *space_clip = CTX_wm_space_clip(C);
1156 BLI_assert(space_clip != nullptr);
1157
1158 state->offset_x = space_clip->xof;
1159 state->offset_y = space_clip->yof;
1160 state->zoom = space_clip->zoom;
1161
1162 state->lock_offset_x = 0.0f;
1163 state->lock_offset_y = 0.0f;
1164
1165 if ((space_clip->flag & SC_LOCK_SELECTION) == 0) {
1166 return;
1167 }
1168
1170 C, false, &state->offset_x, &state->offset_y, &state->zoom))
1171 {
1172 return;
1173 }
1174
1175 state->lock_offset_x = space_clip->xlockof;
1176 state->lock_offset_y = space_clip->ylockof;
1177}
1178
1180{
1181 SpaceClip *space_clip = CTX_wm_space_clip(C);
1182 BLI_assert(space_clip != nullptr);
1183
1184 if ((space_clip->flag & SC_LOCK_SELECTION) == 0) {
1185 return;
1186 }
1187
1188 float offset_x, offset_y;
1189 float zoom;
1190 if (!clip_view_calculate_view_selection(C, false, &offset_x, &offset_y, &zoom)) {
1191 return;
1192 }
1193
1194 space_clip->xlockof = state->offset_x + state->lock_offset_x - offset_x;
1195 space_clip->ylockof = state->offset_y + state->lock_offset_y - offset_y;
1196}
1197
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()
@ LIB_ID_COPY_LOCALIZE
void BKE_libblock_free_data(ID *id, bool do_id_user) ATTR_NONNULL()
void id_us_ensure_real(ID *id)
Definition lib_id.cc:306
ID * BKE_id_copy_ex(Main *bmain, const ID *id, ID **new_id_p, int flag)
Definition lib_id.cc:760
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:505
#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:2421
#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:2448
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
File and directory operations.
#define O_BINARY
size_t BLI_file_descriptor_size(int file) ATTR_WARN_UNUSED_RESULT
Definition storage.cc:206
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)
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:193
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:189
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:197
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition BLI_rect.h:201
unsigned char uchar
int BLI_task_scheduler_num_threads(void)
@ TASK_PRIORITY_LOW
Definition BLI_task.h:56
void * BLI_task_pool_user_data(TaskPool *pool)
Definition task_pool.cc:516
void BLI_task_pool_work_and_wait(TaskPool *pool)
Definition task_pool.cc:471
TaskPool * BLI_task_pool_create(void *userdata, eTaskPriority priority)
Definition task_pool.cc:394
void BLI_task_pool_free(TaskPool *pool)
Definition task_pool.cc:431
void BLI_task_pool_push(TaskPool *pool, TaskRunFunction run, void *taskdata, bool free_taskdata, TaskFreeFunction freedata)
Definition task_pool.cc:450
pthread_spinlock_t SpinLock
void BLI_spin_init(SpinLock *spin)
Definition threads.cc:391
void BLI_spin_unlock(SpinLock *spin)
Definition threads.cc:430
void BLI_spin_lock(SpinLock *spin)
Definition threads.cc:405
void BLI_spin_end(SpinLock *spin)
Definition threads.cc:445
#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_PROXY_RENDER_SIZE_FULL
@ MCLIP_SRC_SEQUENCE
@ MCLIP_SRC_MOVIE
@ MCLIP_PROXY_RENDER_UNDISTORT
@ MCLIP_USE_PROXY
@ SPACE_CLIP
@ SC_VIEW_CLIP
@ 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
void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], ColorSpace *colorspace)
Contains defines and structs used throughout the imbuf module.
@ IB_metadata
@ IB_multilayer
@ IB_alphamode_detect
@ IB_rect
Read Guarded memory(de)allocation.
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:1718
@ WM_JOB_TYPE_CLIP_PREFETCH
Definition WM_api.hh:1591
@ WM_JOB_PROGRESS
Definition WM_api.hh:1566
#define ND_DISPLAY
Definition WM_types.hh:458
#define NC_MOVIECLIP
Definition WM_types.hh:364
#define NC_MASK
Definition WM_types.hh:365
#define NA_SELECTED
Definition WM_types.hh:555
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)
#define SELECT
TaskPool * task_pool
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
struct ImBuf * IMB_ibImageFromMemory(const unsigned char *, size_t, int, char[IM_MAX_SPACE], const char *)
void IMB_freeImBuf(ImBuf *)
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
ccl_device_inline float4 mask(const int4 mask, const float4 a)
static ulong state[N]
#define G(x, y, z)
return ret
static bool use_proxy(Editing *ed, Sequence *seq)
Definition DNA_ID.h:413
void * py_instance
Definition DNA_ID.h:482
ColorSpace * colorspace
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
ListBase wm
Definition BKE_main.hh:239
struct Mask * mask
MovieTrackingCamera camera
short render_size
MovieClip * clip
short render_flag
MovieClip * clip_local
struct MovieClipUser user
float stabmat[4][4]
struct MovieClipScopes scopes
struct MovieClip * clip
MaskSpaceInfo mask_info
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:352
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition wm_jobs.cc:455
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:189
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:364
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *customdata))
Definition wm_jobs.cc:336
bScreen * WM_window_get_active_screen(const wmWindow *win)
uint8_t flag
Definition wm_window.cc:138