Blender V4.5
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->mask_info.draw_flag & MASK_DRAWFLAG_SPLINE;
109}
110
112{
115
116 if (clip) {
118
119 return sc->mask_info.mask != nullptr;
120 }
121 }
122
123 return false;
124}
125
127{
129 return false;
130 }
131
132 const SpaceClip *space_clip = CTX_wm_space_clip(C);
133 return space_clip->mask_info.draw_flag & MASK_DRAWFLAG_SPLINE;
134}
135
137
138/* -------------------------------------------------------------------- */
141
142void ED_space_clip_get_size(const SpaceClip *sc, int *r_width, int *r_height)
143{
144 if (sc->clip) {
145 BKE_movieclip_get_size(sc->clip, &sc->user, r_width, r_height);
146 }
147 else {
148 *r_width = *r_height = IMG_SIZE_FALLBACK;
149 }
150}
151
152void ED_space_clip_get_size_fl(const SpaceClip *sc, float r_size[2])
153{
154 int size_i[2];
155 ED_space_clip_get_size(sc, &size_i[0], &size_i[1]);
156 r_size[0] = size_i[0];
157 r_size[1] = size_i[1];
158}
159
161 const ARegion *region,
162 float *r_zoomx,
163 float *r_zoomy)
164{
165 int width, height;
166
167 ED_space_clip_get_size(sc, &width, &height);
168
169 *r_zoomx = float(BLI_rcti_size_x(&region->winrct) + 1) /
170 (BLI_rctf_size_x(&region->v2d.cur) * width);
171 *r_zoomy = float(BLI_rcti_size_y(&region->winrct) + 1) /
172 (BLI_rctf_size_y(&region->v2d.cur) * height);
173}
174
175void ED_space_clip_get_aspect(const SpaceClip *sc, float *r_aspx, float *r_aspy)
176{
178
179 if (clip) {
180 BKE_movieclip_get_aspect(clip, r_aspx, r_aspy);
181 }
182 else {
183 *r_aspx = *r_aspy = 1.0f;
184 }
185
186 if (*r_aspx < *r_aspy) {
187 *r_aspy = *r_aspy / *r_aspx;
188 *r_aspx = 1.0f;
189 }
190 else {
191 *r_aspx = *r_aspx / *r_aspy;
192 *r_aspy = 1.0f;
193 }
194}
195
196void ED_space_clip_get_aspect_dimension_aware(const SpaceClip *sc, float *r_aspx, float *r_aspy)
197{
198 int w, h;
199
200 /* most of tools does not require aspect to be returned with dimensions correction
201 * due to they're invariant to this stuff, but some transformation tools like rotation
202 * should be aware of aspect correction caused by different resolution in different
203 * directions.
204 * mainly this is used for transformation stuff
205 */
206
207 if (!sc->clip) {
208 *r_aspx = 1.0f;
209 *r_aspy = 1.0f;
210
211 return;
212 }
213
214 ED_space_clip_get_aspect(sc, r_aspx, r_aspy);
215 BKE_movieclip_get_size(sc->clip, &sc->user, &w, &h);
216
217 *r_aspx *= float(w);
218 *r_aspy *= float(h);
219
220 if (*r_aspx < *r_aspy) {
221 *r_aspy = *r_aspy / *r_aspx;
222 *r_aspx = 1.0f;
223 }
224 else {
225 *r_aspx = *r_aspx / *r_aspy;
226 *r_aspy = 1.0f;
227 }
228}
229
231{
233
234 /* Caller must ensure space does have a valid clip, otherwise it will crash, see #45017. */
236}
237
239{
240 if (sc->clip) {
241 ImBuf *ibuf;
242
244
245 if (ibuf && (ibuf->byte_buffer.data || ibuf->float_buffer.data)) {
246 return ibuf;
247 }
248
249 if (ibuf) {
250 IMB_freeImBuf(ibuf);
251 }
252 }
253
254 return nullptr;
255}
256
258 float loc[2],
259 float *scale,
260 float *angle)
261{
262 if (sc->clip) {
263 ImBuf *ibuf;
264
266 sc->clip, &sc->user, sc->postproc_flag, loc, scale, angle);
267
268 if (ibuf && (ibuf->byte_buffer.data || ibuf->float_buffer.data)) {
269 return ibuf;
270 }
271
272 if (ibuf) {
273 IMB_freeImBuf(ibuf);
274 }
275 }
276
277 return nullptr;
278}
279
281 const ARegion *region,
282 const int mval[2],
283 float r_fpos[2])
284{
286 if (!ibuf) {
287 return false;
288 }
289
290 /* map the mouse coords to the backdrop image space */
291 ED_clip_mouse_pos(sc, region, mval, r_fpos);
292
293 IMB_freeImBuf(ibuf);
294 return true;
295}
296
298 const ARegion *region,
299 const int mval[2],
300 float r_col[3])
301{
302 ImBuf *ibuf;
303 float fx, fy, co[2];
304 bool ret = false;
305
306 ibuf = ED_space_clip_get_buffer(sc);
307 if (!ibuf) {
308 return false;
309 }
310
311 /* map the mouse coords to the backdrop image space */
312 ED_clip_mouse_pos(sc, region, mval, co);
313
314 fx = co[0];
315 fy = co[1];
316
317 if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
318 const float *fp;
319 uchar *cp;
320 int x = int(fx * ibuf->x), y = int(fy * ibuf->y);
321
322 CLAMP(x, 0, ibuf->x - 1);
323 CLAMP(y, 0, ibuf->y - 1);
324
325 if (ibuf->float_buffer.data) {
326 fp = (ibuf->float_buffer.data + (ibuf->channels) * (y * ibuf->x + x));
327 copy_v3_v3(r_col, fp);
328 ret = true;
329 }
330 else if (ibuf->byte_buffer.data) {
331 cp = ibuf->byte_buffer.data + 4 * (y * ibuf->x + x);
332 rgb_uchar_to_float(r_col, cp);
334 ret = true;
335 }
336 }
337
338 IMB_freeImBuf(ibuf);
339
340 return ret;
341}
342
343void ED_clip_update_frame(const Main *mainp, int cfra)
344{
345 /* image window, compo node users */
346 LISTBASE_FOREACH (wmWindowManager *, wm, &mainp->wm) {
347 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
349
350 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
351 if (area->spacetype == SPACE_CLIP) {
352 SpaceClip *sc = static_cast<SpaceClip *>(area->spacedata.first);
353
354 sc->scopes.ok = false;
355
357 }
358 }
359 }
360 }
361}
362
363bool ED_clip_view_selection(const bContext *C, const ARegion * /*region*/, bool fit)
364{
365 float offset_x, offset_y;
366 float zoom;
367 if (!clip_view_calculate_view_selection(C, fit, &offset_x, &offset_y, &zoom)) {
368 return false;
369 }
370
372 sc->xof = offset_x;
373 sc->yof = offset_y;
374 sc->zoom = zoom;
375
376 return true;
377}
378
379void ED_clip_select_all(const SpaceClip *sc, int action, bool *r_has_selection)
380{
382 const MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(&clip->tracking);
383 const int framenr = ED_space_clip_get_clip_frame_number(sc);
384 bool has_selection = false;
385
386 if (action == SEL_TOGGLE) {
387 action = SEL_SELECT;
388
389 LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
390 if (!TRACK_VIEW_SELECTED(sc, track)) {
391 continue;
392 }
393
394 const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
395
396 if (ED_space_clip_marker_is_visible(sc, tracking_object, track, marker)) {
397 action = SEL_DESELECT;
398 break;
399 }
400 }
401
402 LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, &tracking_object->plane_tracks) {
403 if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
404 action = SEL_DESELECT;
405 break;
406 }
407 }
408 }
409
410 LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
411 if (track->flag & TRACK_HIDDEN) {
412 continue;
413 }
414
415 const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
416
417 if (ED_space_clip_marker_is_visible(sc, tracking_object, track, marker)) {
418 switch (action) {
419 case SEL_SELECT:
420 track->flag |= SELECT;
421 track->pat_flag |= SELECT;
422 track->search_flag |= SELECT;
423 break;
424 case SEL_DESELECT:
425 track->flag &= ~SELECT;
426 track->pat_flag &= ~SELECT;
427 track->search_flag &= ~SELECT;
428 break;
429 case SEL_INVERT:
430 track->flag ^= SELECT;
431 track->pat_flag ^= SELECT;
432 track->search_flag ^= SELECT;
433 break;
434 }
435 }
436
437 if (TRACK_VIEW_SELECTED(sc, track)) {
438 has_selection = true;
439 }
440 }
441
442 LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, &tracking_object->plane_tracks) {
443 if (plane_track->flag & PLANE_TRACK_HIDDEN) {
444 continue;
445 }
446
447 switch (action) {
448 case SEL_SELECT:
449 plane_track->flag |= SELECT;
450 break;
451 case SEL_DESELECT:
452 plane_track->flag &= ~SELECT;
453 break;
454 case SEL_INVERT:
455 plane_track->flag ^= SELECT;
456 break;
457 }
458 if (plane_track->flag & SELECT) {
459 has_selection = true;
460 }
461 }
462
463 if (r_has_selection) {
464 *r_has_selection = has_selection;
465 }
466}
467
468void ED_clip_point_undistorted_pos(const SpaceClip *sc, const float co[2], float r_co[2])
469{
470 copy_v2_v2(r_co, co);
471
474 float aspy = 1.0f / clip->tracking.camera.pixel_aspect;
475 int width, height;
476
477 BKE_movieclip_get_size(sc->clip, &sc->user, &width, &height);
478
479 r_co[0] *= width;
480 r_co[1] *= height * aspy;
481
482 BKE_tracking_undistort_v2(&clip->tracking, width, height, r_co, r_co);
483
484 r_co[0] /= width;
485 r_co[1] /= height * aspy;
486 }
487}
488
490 const SpaceClip *sc, const ARegion *region, float x, float y, float *xr, float *yr)
491{
492 int sx, sy, width, height;
493 float zoomx, zoomy, pos[3], imat[4][4];
494
495 ED_space_clip_get_zoom(sc, region, &zoomx, &zoomy);
496 ED_space_clip_get_size(sc, &width, &height);
497
498 UI_view2d_view_to_region(&region->v2d, 0.0f, 0.0f, &sx, &sy);
499
500 pos[0] = (x - sx) / zoomx;
501 pos[1] = (y - sy) / zoomy;
502 pos[2] = 0.0f;
503
504 invert_m4_m4(imat, sc->stabmat);
505 mul_v3_m4v3(pos, imat, pos);
506
507 *xr = pos[0] / width;
508 *yr = pos[1] / height;
509
512 if (clip != nullptr) {
513 MovieTracking *tracking = &clip->tracking;
514 float aspy = 1.0f / tracking->camera.pixel_aspect;
515 float tmp[2] = {*xr * width, *yr * height * aspy};
516
517 BKE_tracking_distort_v2(tracking, width, height, tmp, tmp);
518
519 *xr = tmp[0] / width;
520 *yr = tmp[1] / (height * aspy);
521 }
522 }
523}
524
526 const ARegion *region,
527 const float co[2],
528 float r_co[2])
529{
530 float zoomx, zoomy;
531 float pos[3];
532 int width, height;
533 int sx, sy;
534
535 UI_view2d_view_to_region(&region->v2d, 0.0f, 0.0f, &sx, &sy);
536 ED_space_clip_get_size(sc, &width, &height);
537 ED_space_clip_get_zoom(sc, region, &zoomx, &zoomy);
538
540 pos[2] = 0.0f;
541
542 /* untested */
543 mul_v3_m4v3(pos, sc->stabmat, pos);
544
545 r_co[0] = (pos[0] * width * zoomx) + float(sx);
546 r_co[1] = (pos[1] * height * zoomy) + float(sy);
547}
548
550 const ARegion *region,
551 const int mval[2],
552 float r_co[2])
553{
554 ED_clip_point_stable_pos(sc, region, mval[0], mval[1], &r_co[0], &r_co[1]);
555}
556
558{
559 if (sc) {
560 return sc->mode == SC_MODE_TRACKING;
561 }
562
563 return false;
564}
565
567{
568 if (sc) {
569 return sc->mode == SC_MODE_MASKEDIT;
570 }
571
572 return false;
573}
574
576
577/* -------------------------------------------------------------------- */
580
582{
583 return sc->clip;
584}
585
587{
588 MovieClip *old_clip;
589 bool old_clip_visible = false;
590
591 if (!screen && C) {
592 screen = CTX_wm_screen(C);
593 }
594
595 old_clip = sc->clip;
596 sc->clip = clip;
597
598 id_us_ensure_real((ID *)sc->clip);
599
600 if (screen && sc->view == SC_VIEW_CLIP) {
601 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
602 LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
603 if (sl->spacetype == SPACE_CLIP) {
604 SpaceClip *cur_sc = (SpaceClip *)sl;
605
606 if (cur_sc != sc) {
607 if (cur_sc->view == SC_VIEW_CLIP) {
608 if (cur_sc->clip == old_clip) {
609 old_clip_visible = true;
610 }
611 }
612 else {
613 if (ELEM(cur_sc->clip, old_clip, nullptr)) {
614 cur_sc->clip = clip;
615 }
616 }
617 }
618 }
619 }
620 }
621 }
622
623 /* If clip is no longer visible on screen, free memory used by its cache */
624 if (old_clip && old_clip != clip && !old_clip_visible) {
626 }
627
628 if (C) {
630 }
631}
632
634
635/* -------------------------------------------------------------------- */
638
640{
641 return sc->mask_info.mask;
642}
643
645{
646 sc->mask_info.mask = mask;
647
649
650 if (C) {
652 }
653}
654
656
657/* -------------------------------------------------------------------- */
660
664
665 /* Local copy of the clip which is used to decouple reading in a way which does not require
666 * threading lock which might "conflict" with the main thread,
667 *
668 * Used, for example, for animation prefetching (`clip->anim` can not be used from multiple
669 * threads and main thread might need it). */
671
674};
675
679
680 /* If true pre-fetching goes forward in time,
681 * otherwise it goes backwards in time (starting from current frame).
682 */
684
686
687 bool *stop;
689 float *progress;
690};
691
692/* check whether pre-fetching is allowed */
694{
695 return G.is_break;
696}
697
698/* read file for specified frame number to the memory */
700 MovieClip *clip, int current_frame, short render_size, short render_flag, size_t *r_size)
701{
703 user.framenr = current_frame;
704 user.render_size = render_size;
705 user.render_flag = render_flag;
706
707 char filepath[FILE_MAX];
708 BKE_movieclip_filepath_for_frame(clip, &user, filepath);
709
710 int file = BLI_open(filepath, O_BINARY | O_RDONLY, 0);
711 if (file == -1) {
712 return nullptr;
713 }
714
715 const size_t size = BLI_file_descriptor_size(file);
716 if (UNLIKELY(ELEM(size, 0, size_t(-1)))) {
717 close(file);
718 return nullptr;
719 }
720
721 uchar *mem = MEM_calloc_arrayN<uchar>(size, "movieclip prefetch memory file");
722 if (mem == nullptr) {
723 close(file);
724 return nullptr;
725 }
726
727 if (BLI_read(file, mem, size) != size) {
728 close(file);
729 MEM_freeN(mem);
730 return nullptr;
731 }
732
733 *r_size = size;
734
735 close(file);
736
737 return mem;
738}
739
740/* find first uncached frame within prefetching frame range */
742 int from_frame,
743 int end_frame,
744 short render_size,
745 short render_flag,
746 short direction)
747{
748 int current_frame;
750
751 user.render_size = render_size;
752 user.render_flag = render_flag;
753
754 if (direction > 0) {
755 for (current_frame = from_frame; current_frame <= end_frame; current_frame++) {
756 user.framenr = current_frame;
757
758 if (!BKE_movieclip_has_cached_frame(clip, &user)) {
759 break;
760 }
761 }
762 }
763 else {
764 for (current_frame = from_frame; current_frame >= end_frame; current_frame--) {
765 user.framenr = current_frame;
766
767 if (!BKE_movieclip_has_cached_frame(clip, &user)) {
768 break;
769 }
770 }
771 }
772
773 return current_frame;
774}
775
776/* get memory buffer for first uncached frame within prefetch frame range */
778 MovieClip *clip,
779 size_t *r_size,
780 int *r_current_frame)
781{
782 uchar *mem = nullptr;
783
784 std::lock_guard lock(queue->mutex);
785 if (!*queue->stop && !check_prefetch_break() &&
786 IN_RANGE_INCL(queue->current_frame, queue->start_frame, queue->end_frame))
787 {
788 int current_frame;
789
790 if (queue->forward) {
791 current_frame = prefetch_find_uncached_frame(clip,
792 queue->current_frame + 1,
793 queue->end_frame,
794 queue->render_size,
795 queue->render_flag,
796 1);
797 /* switch direction if read frames from current up to scene end frames */
798 if (current_frame > queue->end_frame) {
799 queue->current_frame = queue->initial_frame;
800 queue->forward = false;
801 }
802 }
803
804 if (!queue->forward) {
805 current_frame = prefetch_find_uncached_frame(clip,
806 queue->current_frame - 1,
807 queue->start_frame,
808 queue->render_size,
809 queue->render_flag,
810 -1);
811 }
812
813 if (IN_RANGE_INCL(current_frame, queue->start_frame, queue->end_frame)) {
814 int frames_processed;
815
817 clip, current_frame, queue->render_size, queue->render_flag, r_size);
818
819 *r_current_frame = current_frame;
820
821 queue->current_frame = current_frame;
822
823 if (queue->forward) {
824 frames_processed = queue->current_frame - queue->initial_frame;
825 }
826 else {
827 frames_processed = (queue->end_frame - queue->initial_frame) +
828 (queue->initial_frame - queue->current_frame);
829 }
830
831 *queue->do_update = true;
832 *queue->progress = float(frames_processed) / (queue->end_frame - queue->start_frame);
833 }
834 }
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) &&
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_load_image_from_memory(mem, size, flag, "prefetch frame", nullptr, colorspace_name);
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 queue.current_frame = current_frame;
900 queue.initial_frame = current_frame;
901 queue.start_frame = start_frame;
902 queue.end_frame = end_frame;
903 queue.render_size = render_size;
904 queue.render_flag = render_flag;
905 queue.forward = true;
906
907 queue.stop = stop;
908 queue.do_update = do_update;
909 queue.progress = progress;
910
912 for (int i = 0; i < tot_thread; i++) {
913 BLI_task_pool_push(task_pool, prefetch_task_func, clip, false, nullptr);
914 }
917}
918
919/* NOTE: Reading happens from `clip_local` into `clip->cache`. */
921 MovieClip *clip_local,
922 int frame,
923 short render_size,
924 short render_flag,
925 bool *stop)
926{
928
929 if (check_prefetch_break() || *stop) {
930 return false;
931 }
932
933 user.framenr = frame;
934 user.render_size = render_size;
935 user.render_flag = render_flag;
936
937 if (!BKE_movieclip_has_cached_frame(clip, &user)) {
938 ImBuf *ibuf = BKE_movieclip_anim_ibuf_for_frame_no_lock(clip_local, &user);
939
940 if (ibuf) {
941 int result;
942
943 result = BKE_movieclip_put_frame_if_possible(clip, &user, ibuf);
944
945 if (!result) {
946 /* no more space in the cache, we could stop prefetching here */
947 *stop = true;
948 }
949
950 IMB_freeImBuf(ibuf);
951 }
952 else {
953 /* error reading frame, fair enough stop attempting further reading */
954 *stop = true;
955 }
956 }
957
958 return true;
959}
960
961static void do_prefetch_movie(MovieClip *clip,
962 MovieClip *clip_local,
963 int start_frame,
964 int current_frame,
965 int end_frame,
966 short render_size,
967 short render_flag,
968 bool *stop,
969 bool *do_update,
970 float *progress)
971{
972 int frame;
973 int frames_processed = 0;
974
975 /* read frames starting from current frame up to scene end frame */
976 for (frame = current_frame; frame <= end_frame; frame++) {
977 if (!prefetch_movie_frame(clip, clip_local, frame, render_size, render_flag, stop)) {
978 return;
979 }
980
981 frames_processed++;
982
983 *do_update = true;
984 *progress = float(frames_processed) / (end_frame - start_frame);
985 }
986
987 /* read frames starting from current frame up to scene start frame */
988 for (frame = current_frame; frame >= start_frame; frame--) {
989 if (!prefetch_movie_frame(clip, clip_local, frame, render_size, render_flag, stop)) {
990 return;
991 }
992
993 frames_processed++;
994
995 *do_update = true;
996 *progress = float(frames_processed) / (end_frame - start_frame);
997 }
998}
999
1000static void prefetch_startjob(void *pjv, wmJobWorkerStatus *worker_status)
1001{
1002 PrefetchJob *pj = static_cast<PrefetchJob *>(pjv);
1003
1004 if (pj->clip->source == MCLIP_SRC_SEQUENCE) {
1005 /* read sequence files in multiple threads */
1007 pj->start_frame,
1008 pj->current_frame,
1009 pj->end_frame,
1010 pj->render_size,
1011 pj->render_flag,
1012 &worker_status->stop,
1013 &worker_status->do_update,
1014 &worker_status->progress);
1015 }
1016 else if (pj->clip->source == MCLIP_SRC_MOVIE) {
1017 /* read movie in a single thread */
1019 pj->clip_local,
1020 pj->start_frame,
1021 pj->current_frame,
1022 pj->end_frame,
1023 pj->render_size,
1024 pj->render_flag,
1025 &worker_status->stop,
1026 &worker_status->do_update,
1027 &worker_status->progress);
1028 }
1029 else {
1030 BLI_assert_msg(0, "Unknown movie clip source when prefetching frames");
1031 }
1032}
1033
1034static void prefetch_freejob(void *pjv)
1035{
1036 PrefetchJob *pj = static_cast<PrefetchJob *>(pjv);
1037
1038 MovieClip *clip_local = pj->clip_local;
1039 if (clip_local != nullptr) {
1040 BKE_libblock_free_datablock(&clip_local->id, 0);
1041 BKE_libblock_free_data(&clip_local->id, false);
1042 BLI_assert(!clip_local->id.py_instance); /* Or call #BKE_libblock_free_data_py. */
1043 MEM_freeN(clip_local);
1044 }
1045
1046 MEM_freeN(pj);
1047}
1048
1050{
1051 Scene *scene = CTX_data_scene(C);
1052
1053 return scene->r.sfra;
1054}
1055
1057{
1058 Scene *scene = CTX_data_scene(C);
1061 int end_frame;
1062
1063 /* check whether all the frames from prefetch range are cached */
1064 end_frame = scene->r.efra;
1065
1066 if (clip->len) {
1067 end_frame = min_ii(end_frame, scene->r.sfra + clip->len - 1);
1068 }
1069
1070 return end_frame;
1071}
1072
1073/* returns true if early out is possible */
1075{
1078 int first_uncached_frame, end_frame;
1079 int clip_len;
1080
1081 if (clip == nullptr) {
1082 return true;
1083 }
1084
1085 clip_len = BKE_movieclip_get_duration(clip);
1086
1087 /* check whether all the frames from prefetch range are cached */
1088 end_frame = prefetch_get_final_frame(C);
1089
1090 first_uncached_frame = prefetch_find_uncached_frame(
1091 clip, sc->user.framenr, end_frame, sc->user.render_size, sc->user.render_flag, 1);
1092
1093 if (first_uncached_frame > end_frame || first_uncached_frame == clip_len) {
1094 int start_frame = prefetch_get_start_frame(C);
1095
1096 first_uncached_frame = prefetch_find_uncached_frame(
1097 clip, sc->user.framenr, start_frame, sc->user.render_size, sc->user.render_flag, -1);
1098
1099 if (first_uncached_frame < start_frame) {
1100 return true;
1101 }
1102 }
1103
1104 return false;
1105}
1106
1108{
1109 wmJob *wm_job;
1110 PrefetchJob *pj;
1112
1114 return;
1115 }
1116
1117 wm_job = WM_jobs_get(CTX_wm_manager(C),
1120 "Prefetching",
1123
1124 /* create new job */
1125 pj = MEM_callocN<PrefetchJob>("prefetch job");
1126 pj->clip = ED_space_clip_get_clip(sc);
1128 pj->current_frame = sc->user.framenr;
1130 pj->render_size = sc->user.render_size;
1131 pj->render_flag = sc->user.render_flag;
1132
1133 /* Create a local copy of the clip, so that video file (clip->anim) access can happen without
1134 * acquiring the lock which will interfere with the main thread. */
1135 if (pj->clip->source == MCLIP_SRC_MOVIE) {
1136 BKE_id_copy_ex(nullptr, (&pj->clip->id), (ID **)&pj->clip_local, LIB_ID_COPY_LOCALIZE);
1137 }
1138
1140 WM_jobs_timer(wm_job, 0.2, NC_MOVIECLIP | ND_DISPLAY, 0);
1141 WM_jobs_callbacks(wm_job, prefetch_startjob, nullptr, nullptr, nullptr);
1142
1143 G.is_break = false;
1144
1145 /* and finally start the job */
1146 WM_jobs_start(CTX_wm_manager(C), wm_job);
1147}
1148
1150{
1151 SpaceClip *space_clip = CTX_wm_space_clip(C);
1152 BLI_assert(space_clip != nullptr);
1153
1154 state->offset_x = space_clip->xof;
1155 state->offset_y = space_clip->yof;
1156 state->zoom = space_clip->zoom;
1157
1158 state->lock_offset_x = 0.0f;
1159 state->lock_offset_y = 0.0f;
1160
1161 if ((space_clip->flag & SC_LOCK_SELECTION) == 0) {
1162 return;
1163 }
1164
1166 C, false, &state->offset_x, &state->offset_y, &state->zoom))
1167 {
1168 return;
1169 }
1170
1171 state->lock_offset_x = space_clip->xlockof;
1172 state->lock_offset_y = space_clip->ylockof;
1173}
1174
1176{
1177 SpaceClip *space_clip = CTX_wm_space_clip(C);
1178 BLI_assert(space_clip != nullptr);
1179
1180 if ((space_clip->flag & SC_LOCK_SELECTION) == 0) {
1181 return;
1182 }
1183
1184 float offset_x, offset_y;
1185 float zoom;
1186 if (!clip_view_calculate_view_selection(C, false, &offset_x, &offset_y, &zoom)) {
1187 return;
1188 }
1189
1190 space_clip->xlockof = state->offset_x + state->lock_offset_x - offset_x;
1191 space_clip->ylockof = state->offset_y + state->lock_offset_y - offset_y;
1192}
1193
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:308
ID * BKE_id_copy_ex(Main *bmain, const ID *id, ID **new_id_p, int flag)
Definition lib_id.cc:767
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:516
#define PLANE_TRACK_VIEW_SELECTED(plane_track)
struct MovieTrackingMarker * BKE_tracking_marker_get(struct MovieTrackingTrack *track, int framenr)
Definition tracking.cc:1357
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:2414
#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:2441
#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:230
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: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:546
void BLI_task_pool_work_and_wait(TaskPool *pool)
Definition task_pool.cc:531
TaskPool * BLI_task_pool_create(void *userdata, eTaskPriority priority)
Definition task_pool.cc:480
void BLI_task_pool_free(TaskPool *pool)
Definition task_pool.cc:517
void BLI_task_pool_push(TaskPool *pool, TaskRunFunction run, void *taskdata, bool free_taskdata, TaskFreeFunction freedata)
Definition task_pool.cc:522
#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
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:116
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:1722
@ WM_JOB_TYPE_CLIP_PREFETCH
Definition WM_api.hh:1741
@ WM_JOB_PROGRESS
Definition WM_api.hh:1716
#define ND_DISPLAY
Definition WM_types.hh:488
#define NC_MOVIECLIP
Definition WM_types.hh:394
bool stop
Definition WM_types.hh:1016
bool do_update
Definition WM_types.hh:1008
#define NC_MASK
Definition WM_types.hh:395
float progress
Definition WM_types.hh:1019
#define NA_SELECTED
Definition WM_types.hh:586
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)
#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:404
void * py_instance
Definition DNA_ID.h:483
const ColorSpace * colorspace
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
ListBase wm
Definition BKE_main.hh:276
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 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:353
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition wm_jobs.cc:456
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:190
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:365
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *customdata))
Definition wm_jobs.cc:337
bScreen * WM_window_get_active_screen(const wmWindow *win)
uint8_t flag
Definition wm_window.cc:139