2011-11-07 12:55:18 +00:00
|
|
|
/*
|
|
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2011 Blender Foundation.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Contributor(s): Blender Foundation,
|
|
|
|
* Sergey Sharybin
|
|
|
|
*
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
*/
|
|
|
|
|
|
|
|
/** \file blender/editors/space_clip/clip_editor.c
|
|
|
|
* \ingroup spclip
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stddef.h>
|
2013-03-20 17:03:20 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
|
|
|
#ifndef WIN32
|
|
|
|
# include <unistd.h>
|
|
|
|
#else
|
|
|
|
# include <io.h>
|
|
|
|
#endif
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-04-30 16:19:12 +00:00
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
2012-06-04 16:42:58 +00:00
|
|
|
#include "DNA_mask_types.h"
|
2011-11-07 12:55:18 +00:00
|
|
|
#include "DNA_object_types.h" /* SELECT */
|
|
|
|
|
|
|
|
#include "BLI_utildefines.h"
|
2013-03-20 17:03:20 +00:00
|
|
|
#include "BLI_fileops.h"
|
2011-11-07 12:55:18 +00:00
|
|
|
#include "BLI_math.h"
|
2012-10-14 07:40:16 +00:00
|
|
|
#include "BLI_string.h"
|
2012-08-20 23:06:17 +00:00
|
|
|
#include "BLI_rect.h"
|
2013-03-20 17:03:20 +00:00
|
|
|
#include "BLI_threads.h"
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2013-03-20 17:03:20 +00:00
|
|
|
#include "BKE_global.h"
|
2013-01-24 21:57:13 +00:00
|
|
|
#include "BKE_main.h"
|
|
|
|
#include "BKE_mask.h"
|
|
|
|
#include "BKE_movieclip.h"
|
|
|
|
#include "BKE_context.h"
|
|
|
|
#include "BKE_tracking.h"
|
|
|
|
#include "BKE_library.h"
|
|
|
|
|
2012-04-30 16:19:12 +00:00
|
|
|
#include "GPU_extensions.h"
|
|
|
|
|
2013-03-29 16:02:27 +00:00
|
|
|
#include "IMB_colormanagement.h"
|
2011-11-07 12:55:18 +00:00
|
|
|
#include "IMB_imbuf_types.h"
|
|
|
|
#include "IMB_imbuf.h"
|
|
|
|
|
|
|
|
#include "ED_screen.h"
|
|
|
|
#include "ED_clip.h"
|
|
|
|
|
|
|
|
#include "WM_api.h"
|
|
|
|
#include "WM_types.h"
|
|
|
|
|
|
|
|
#include "UI_view2d.h"
|
|
|
|
|
|
|
|
#include "clip_intern.h" // own include
|
|
|
|
|
2012-04-29 12:32:26 +00:00
|
|
|
/* ******** operactor poll functions ******** */
|
|
|
|
|
2011-11-07 12:55:18 +00:00
|
|
|
int ED_space_clip_poll(bContext *C)
|
|
|
|
{
|
2012-03-25 23:19:21 +00:00
|
|
|
SpaceClip *sc = CTX_wm_space_clip(C);
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (sc && sc->clip)
|
2012-03-25 23:19:21 +00:00
|
|
|
return TRUE;
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-03-25 23:19:21 +00:00
|
|
|
return FALSE;
|
2011-11-07 12:55:18 +00:00
|
|
|
}
|
|
|
|
|
2012-05-02 17:33:48 +00:00
|
|
|
int ED_space_clip_view_clip_poll(bContext *C)
|
|
|
|
{
|
|
|
|
SpaceClip *sc = CTX_wm_space_clip(C);
|
|
|
|
|
2013-01-06 11:16:49 +00:00
|
|
|
if (sc) {
|
2012-05-02 17:33:48 +00:00
|
|
|
return sc->view == SC_VIEW_CLIP;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2012-04-29 12:32:26 +00:00
|
|
|
int ED_space_clip_tracking_poll(bContext *C)
|
|
|
|
{
|
2012-05-03 23:47:39 +00:00
|
|
|
SpaceClip *sc = CTX_wm_space_clip(C);
|
2012-04-29 12:32:26 +00:00
|
|
|
|
|
|
|
if (sc && sc->clip)
|
2012-06-19 14:26:29 +00:00
|
|
|
return ED_space_clip_check_show_trackedit(sc);
|
2012-04-29 12:32:26 +00:00
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2012-06-04 17:30:54 +00:00
|
|
|
int ED_space_clip_maskedit_poll(bContext *C)
|
2012-06-04 16:42:58 +00:00
|
|
|
{
|
|
|
|
SpaceClip *sc = CTX_wm_space_clip(C);
|
|
|
|
|
|
|
|
if (sc && sc->clip) {
|
2012-06-19 14:26:29 +00:00
|
|
|
return ED_space_clip_check_show_maskedit(sc);
|
2012-06-04 16:42:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2012-06-04 17:30:54 +00:00
|
|
|
int ED_space_clip_maskedit_mask_poll(bContext *C)
|
2012-06-04 16:42:58 +00:00
|
|
|
{
|
2012-06-04 17:30:54 +00:00
|
|
|
if (ED_space_clip_maskedit_poll(C)) {
|
2012-06-04 16:42:58 +00:00
|
|
|
MovieClip *clip = CTX_data_edit_movieclip(C);
|
|
|
|
|
|
|
|
if (clip) {
|
2012-06-15 14:11:23 +00:00
|
|
|
SpaceClip *sc = CTX_wm_space_clip(C);
|
2012-06-04 16:42:58 +00:00
|
|
|
|
2012-07-24 20:33:55 +00:00
|
|
|
return sc->mask_info.mask != NULL;
|
2012-06-04 16:42:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2012-06-20 10:28:51 +00:00
|
|
|
/* ******** common editing functions ******** */
|
2012-04-29 12:32:26 +00:00
|
|
|
|
2012-07-26 22:47:05 +00:00
|
|
|
void ED_space_clip_get_size(SpaceClip *sc, int *width, int *height)
|
2011-11-07 12:55:18 +00:00
|
|
|
{
|
2012-07-25 19:36:59 +00:00
|
|
|
if (sc->clip) {
|
|
|
|
BKE_movieclip_get_size(sc->clip, &sc->user, width, height);
|
2012-03-24 06:38:07 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-07-25 19:36:59 +00:00
|
|
|
*width = *height = IMG_SIZE_FALLBACK;
|
2012-03-24 06:38:07 +00:00
|
|
|
}
|
2011-11-07 12:55:18 +00:00
|
|
|
}
|
|
|
|
|
2012-07-26 22:47:05 +00:00
|
|
|
void ED_space_clip_get_size_fl(SpaceClip *sc, float size[2])
|
2012-07-26 11:47:47 +00:00
|
|
|
{
|
|
|
|
int size_i[2];
|
2012-07-26 22:41:40 +00:00
|
|
|
ED_space_clip_get_size(sc, &size_i[0], &size_i[1]);
|
2012-07-26 11:47:47 +00:00
|
|
|
size[0] = size_i[0];
|
|
|
|
size[1] = size_i[1];
|
|
|
|
}
|
|
|
|
|
2012-07-26 22:47:05 +00:00
|
|
|
void ED_space_clip_get_zoom(SpaceClip *sc, ARegion *ar, float *zoomx, float *zoomy)
|
2012-06-04 16:42:58 +00:00
|
|
|
{
|
2012-06-20 10:28:51 +00:00
|
|
|
int width, height;
|
2012-06-04 16:42:58 +00:00
|
|
|
|
2012-07-26 22:41:40 +00:00
|
|
|
ED_space_clip_get_size(sc, &width, &height);
|
2012-06-04 16:42:58 +00:00
|
|
|
|
2012-09-15 11:48:20 +00:00
|
|
|
*zoomx = (float)(BLI_rcti_size_x(&ar->winrct) + 1) / (BLI_rctf_size_x(&ar->v2d.cur) * width);
|
|
|
|
*zoomy = (float)(BLI_rcti_size_y(&ar->winrct) + 1) / (BLI_rctf_size_y(&ar->v2d.cur) * height);
|
2012-06-04 16:42:58 +00:00
|
|
|
}
|
|
|
|
|
2012-06-20 10:28:51 +00:00
|
|
|
void ED_space_clip_get_aspect(SpaceClip *sc, float *aspx, float *aspy)
|
2012-06-04 16:42:58 +00:00
|
|
|
{
|
2012-06-20 10:28:51 +00:00
|
|
|
MovieClip *clip = ED_space_clip_get_clip(sc);
|
2012-06-04 16:42:58 +00:00
|
|
|
|
2012-06-20 10:28:51 +00:00
|
|
|
if (clip)
|
2012-09-13 05:29:38 +00:00
|
|
|
BKE_movieclip_get_aspect(clip, aspx, aspy);
|
2012-06-20 10:28:51 +00:00
|
|
|
else
|
|
|
|
*aspx = *aspy = 1.0f;
|
2012-06-04 16:42:58 +00:00
|
|
|
|
2012-06-04 20:11:09 +00:00
|
|
|
if (*aspx < *aspy) {
|
2012-06-15 14:11:23 +00:00
|
|
|
*aspy = *aspy / *aspx;
|
|
|
|
*aspx = 1.0f;
|
2012-06-04 16:42:58 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-06-15 14:11:23 +00:00
|
|
|
*aspx = *aspx / *aspy;
|
|
|
|
*aspy = 1.0f;
|
2012-06-04 16:42:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-20 10:28:51 +00:00
|
|
|
void ED_space_clip_get_aspect_dimension_aware(SpaceClip *sc, float *aspx, float *aspy)
|
2012-06-04 16:42:58 +00:00
|
|
|
{
|
|
|
|
int w, h;
|
|
|
|
|
|
|
|
/* most of tools does not require aspect to be returned with dimensions correction
|
|
|
|
* due to they're invariant to this stuff, but some transformation tools like rotation
|
|
|
|
* should be aware of aspect correction caused by different resolution in different
|
|
|
|
* directions.
|
|
|
|
* mainly this is sued for transformation stuff
|
|
|
|
*/
|
|
|
|
|
2012-06-25 19:48:05 +00:00
|
|
|
if (!sc->clip) {
|
|
|
|
*aspx = 1.0f;
|
|
|
|
*aspy = 1.0f;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-06-20 10:28:51 +00:00
|
|
|
ED_space_clip_get_aspect(sc, aspx, aspy);
|
|
|
|
BKE_movieclip_get_size(sc->clip, &sc->user, &w, &h);
|
2012-06-04 16:42:58 +00:00
|
|
|
|
2012-06-20 10:28:51 +00:00
|
|
|
*aspx *= (float) w;
|
|
|
|
*aspy *= (float) h;
|
2012-06-04 16:42:58 +00:00
|
|
|
|
2012-06-04 20:11:09 +00:00
|
|
|
if (*aspx < *aspy) {
|
2012-06-15 14:11:23 +00:00
|
|
|
*aspy = *aspy / *aspx;
|
|
|
|
*aspx = 1.0f;
|
2012-06-04 16:42:58 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-06-15 14:11:23 +00:00
|
|
|
*aspx = *aspx / *aspy;
|
|
|
|
*aspy = 1.0f;
|
2012-06-04 16:42:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-20 10:28:51 +00:00
|
|
|
/* return current frame number in clip space */
|
|
|
|
int ED_space_clip_get_clip_frame_number(SpaceClip *sc)
|
|
|
|
{
|
|
|
|
MovieClip *clip = ED_space_clip_get_clip(sc);
|
|
|
|
|
|
|
|
return BKE_movieclip_remap_scene_to_clip_frame(clip, sc->user.framenr);
|
|
|
|
}
|
|
|
|
|
|
|
|
ImBuf *ED_space_clip_get_buffer(SpaceClip *sc)
|
|
|
|
{
|
|
|
|
if (sc->clip) {
|
|
|
|
ImBuf *ibuf;
|
|
|
|
|
|
|
|
ibuf = BKE_movieclip_get_postprocessed_ibuf(sc->clip, &sc->user, sc->postproc_flag);
|
|
|
|
|
|
|
|
if (ibuf && (ibuf->rect || ibuf->rect_float))
|
|
|
|
return ibuf;
|
|
|
|
|
|
|
|
if (ibuf)
|
|
|
|
IMB_freeImBuf(ibuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ImBuf *ED_space_clip_get_stable_buffer(SpaceClip *sc, float loc[2], float *scale, float *angle)
|
|
|
|
{
|
|
|
|
if (sc->clip) {
|
|
|
|
ImBuf *ibuf;
|
|
|
|
|
|
|
|
ibuf = BKE_movieclip_get_stable_ibuf(sc->clip, &sc->user, loc, scale, angle, sc->postproc_flag);
|
|
|
|
|
|
|
|
if (ibuf && (ibuf->rect || ibuf->rect_float))
|
|
|
|
return ibuf;
|
|
|
|
|
|
|
|
if (ibuf)
|
|
|
|
IMB_freeImBuf(ibuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-08-20 16:56:11 +00:00
|
|
|
/* returns color in SRGB */
|
|
|
|
/* matching ED_space_image_color_sample() */
|
2013-09-05 13:37:53 +00:00
|
|
|
bool ED_space_clip_color_sample(SpaceClip *sc, ARegion *ar, int mval[2], float r_col[3])
|
2012-08-20 16:56:11 +00:00
|
|
|
{
|
|
|
|
ImBuf *ibuf;
|
|
|
|
float fx, fy, co[2];
|
2013-09-05 13:37:53 +00:00
|
|
|
bool ret = false;
|
2012-08-20 16:56:11 +00:00
|
|
|
|
|
|
|
ibuf = ED_space_clip_get_buffer(sc);
|
|
|
|
if (!ibuf) {
|
2013-09-05 13:37:53 +00:00
|
|
|
return false;
|
2012-08-20 16:56:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* map the mouse coords to the backdrop image space */
|
|
|
|
ED_clip_mouse_pos(sc, ar, mval, co);
|
|
|
|
|
|
|
|
fx = co[0];
|
|
|
|
fy = co[1];
|
|
|
|
|
|
|
|
if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
|
|
|
|
float *fp;
|
|
|
|
unsigned char *cp;
|
|
|
|
int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);
|
|
|
|
|
|
|
|
CLAMP(x, 0, ibuf->x - 1);
|
|
|
|
CLAMP(y, 0, ibuf->y - 1);
|
|
|
|
|
|
|
|
if (ibuf->rect_float) {
|
|
|
|
fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
|
Color Management, Stage 2: Switch color pipeline to use OpenColorIO
Replace old color pipeline which was supporting linear/sRGB color spaces
only with OpenColorIO-based pipeline.
This introduces two configurable color spaces:
- Input color space for images and movie clips. This space is used to convert
images/movies from color space in which file is saved to Blender's linear
space (for float images, byte images are not internally converted, only input
space is stored for such images and used later).
This setting could be found in image/clip data block settings.
- Display color space which defines space in which particular display is working.
This settings could be found in scene's Color Management panel.
When render result is being displayed on the screen, apart from converting image
to display space, some additional conversions could happen.
This conversions are:
- View, which defines tone curve applying before display transformation.
These are different ways to view the image on the same display device.
For example it could be used to emulate film view on sRGB display.
- Exposure affects on image exposure before tone map is applied.
- Gamma is post-display gamma correction, could be used to match particular
display gamma.
- RGB curves are user-defined curves which are applying before display
transformation, could be used for different purposes.
All this settings by default are only applying on render result and does not
affect on other images. If some particular image needs to be affected by this
transformation, "View as Render" setting of image data block should be set to
truth. Movie clips are always affected by all display transformations.
This commit also introduces configurable color space in which sequencer is
working. This setting could be found in scene's Color Management panel and
it should be used if such stuff as grading needs to be done in color space
different from sRGB (i.e. when Film view on sRGB display is use, using VD16
space as sequencer's internal space would make grading working in space
which is close to the space using for display).
Some technical notes:
- Image buffer's float buffer is now always in linear space, even if it was
created from 16bit byte images.
- Space of byte buffer is stored in image buffer's rect_colorspace property.
- Profile of image buffer was removed since it's not longer meaningful.
- OpenGL and GLSL is supposed to always work in sRGB space. It is possible
to support other spaces, but it's quite large project which isn't so
much important.
- Legacy Color Management option disabled is emulated by using None display.
It could have some regressions, but there's no clear way to avoid them.
- If OpenColorIO is disabled on build time, it should make blender behaving
in the same way as previous release with color management enabled.
More details could be found at this page (more details would be added soon):
http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.64/Color_Management
--
Thanks to Xavier Thomas, Lukas Toene for initial work on OpenColorIO
integration and to Brecht van Lommel for some further development and code/
usecase review!
2012-09-15 10:05:07 +00:00
|
|
|
linearrgb_to_srgb_v3_v3(r_col, fp);
|
2013-09-05 13:37:53 +00:00
|
|
|
ret = true;
|
2012-08-20 16:56:11 +00:00
|
|
|
}
|
|
|
|
else if (ibuf->rect) {
|
|
|
|
cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
|
|
|
|
rgb_uchar_to_float(r_col, cp);
|
2013-09-05 13:37:53 +00:00
|
|
|
ret = true;
|
2012-08-20 16:56:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-11-07 12:55:18 +00:00
|
|
|
void ED_clip_update_frame(const Main *mainp, int cfra)
|
|
|
|
{
|
|
|
|
wmWindowManager *wm;
|
|
|
|
wmWindow *win;
|
|
|
|
|
|
|
|
/* image window, compo node users */
|
2012-03-25 23:19:21 +00:00
|
|
|
for (wm = mainp->wm.first; wm; wm = wm->id.next) { /* only 1 wm */
|
|
|
|
for (win = wm->windows.first; win; win = win->next) {
|
2011-11-07 12:55:18 +00:00
|
|
|
ScrArea *sa;
|
|
|
|
|
2012-03-25 23:19:21 +00:00
|
|
|
for (sa = win->screen->areabase.first; sa; sa = sa->next) {
|
|
|
|
if (sa->spacetype == SPACE_CLIP) {
|
|
|
|
SpaceClip *sc = sa->spacedata.first;
|
|
|
|
|
|
|
|
sc->scopes.ok = FALSE;
|
2011-11-07 12:55:18 +00:00
|
|
|
|
|
|
|
BKE_movieclip_user_set_frame(&sc->user, cfra);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-05 13:37:53 +00:00
|
|
|
static bool selected_boundbox(SpaceClip *sc, float min[2], float max[2])
|
2011-11-07 12:55:18 +00:00
|
|
|
{
|
2012-06-19 14:26:29 +00:00
|
|
|
MovieClip *clip = ED_space_clip_get_clip(sc);
|
2011-11-07 12:55:18 +00:00
|
|
|
MovieTrackingTrack *track;
|
2013-09-05 13:37:53 +00:00
|
|
|
int width, height;
|
|
|
|
bool ok = false;
|
2012-06-15 11:03:23 +00:00
|
|
|
ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
|
2012-06-20 10:42:41 +00:00
|
|
|
int framenr = ED_space_clip_get_clip_frame_number(sc);
|
2011-11-07 12:55:18 +00:00
|
|
|
|
|
|
|
INIT_MINMAX2(min, max);
|
|
|
|
|
2012-07-26 22:41:40 +00:00
|
|
|
ED_space_clip_get_size(sc, &width, &height);
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-03-25 23:19:21 +00:00
|
|
|
track = tracksbase->first;
|
2012-03-24 06:38:07 +00:00
|
|
|
while (track) {
|
|
|
|
if (TRACK_VIEW_SELECTED(sc, track)) {
|
2012-06-20 10:42:41 +00:00
|
|
|
MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (marker) {
|
2011-11-07 12:55:18 +00:00
|
|
|
float pos[3];
|
|
|
|
|
2012-03-25 23:19:21 +00:00
|
|
|
pos[0] = marker->pos[0] + track->offset[0];
|
|
|
|
pos[1] = marker->pos[1] + track->offset[1];
|
|
|
|
pos[2] = 0.0f;
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2011-11-07 15:32:32 +00:00
|
|
|
/* undistortion happens for normalized coords */
|
2012-03-25 23:19:21 +00:00
|
|
|
if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) {
|
2011-11-07 15:32:32 +00:00
|
|
|
/* undistortion happens for normalized coords */
|
|
|
|
ED_clip_point_undistorted_pos(sc, pos, pos);
|
2012-03-25 23:19:21 +00:00
|
|
|
}
|
2011-11-07 15:32:32 +00:00
|
|
|
|
2012-03-25 23:19:21 +00:00
|
|
|
pos[0] *= width;
|
|
|
|
pos[1] *= height;
|
2011-11-07 15:32:32 +00:00
|
|
|
|
2011-11-07 12:55:18 +00:00
|
|
|
mul_v3_m4v3(pos, sc->stabmat, pos);
|
|
|
|
|
2012-11-15 22:20:18 +00:00
|
|
|
minmax_v2v2_v2(min, max, pos);
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2013-09-05 13:37:53 +00:00
|
|
|
ok = true;
|
2011-11-07 12:55:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-25 23:19:21 +00:00
|
|
|
track = track->next;
|
2011-11-07 12:55:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2013-09-05 13:37:53 +00:00
|
|
|
bool ED_clip_view_selection(const bContext *C, ARegion *ar, bool fit)
|
2011-11-07 12:55:18 +00:00
|
|
|
{
|
2012-06-20 10:28:51 +00:00
|
|
|
SpaceClip *sc = CTX_wm_space_clip(C);
|
2011-11-07 12:55:18 +00:00
|
|
|
int w, h, frame_width, frame_height;
|
|
|
|
float min[2], max[2];
|
|
|
|
|
2012-07-26 22:41:40 +00:00
|
|
|
ED_space_clip_get_size(sc, &frame_width, &frame_height);
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-09-30 10:39:00 +00:00
|
|
|
if ((frame_width == 0) || (frame_height == 0) || (sc->clip == NULL))
|
2013-09-05 13:37:53 +00:00
|
|
|
return false;
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-07-26 22:41:40 +00:00
|
|
|
if (!selected_boundbox(sc, min, max))
|
2013-09-05 13:37:53 +00:00
|
|
|
return false;
|
2011-11-07 12:55:18 +00:00
|
|
|
|
|
|
|
/* center view */
|
2012-07-26 22:41:40 +00:00
|
|
|
clip_view_center_to_point(sc, (max[0] + min[0]) / (2 * frame_width),
|
|
|
|
(max[1] + min[1]) / (2 * frame_height));
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-03-25 23:19:21 +00:00
|
|
|
w = max[0] - min[0];
|
|
|
|
h = max[1] - min[1];
|
2011-11-07 12:55:18 +00:00
|
|
|
|
|
|
|
/* set zoom to see all selection */
|
2012-03-25 23:19:21 +00:00
|
|
|
if (w > 0 && h > 0) {
|
2011-11-07 12:55:18 +00:00
|
|
|
int width, height;
|
|
|
|
float zoomx, zoomy, newzoom, aspx, aspy;
|
|
|
|
|
2012-06-20 10:28:51 +00:00
|
|
|
ED_space_clip_get_aspect(sc, &aspx, &aspy);
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-09-15 11:48:20 +00:00
|
|
|
width = BLI_rcti_size_x(&ar->winrct) + 1;
|
|
|
|
height = BLI_rcti_size_y(&ar->winrct) + 1;
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-03-25 23:19:21 +00:00
|
|
|
zoomx = (float)width / w / aspx;
|
|
|
|
zoomy = (float)height / h / aspy;
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-10-23 13:28:22 +00:00
|
|
|
newzoom = 1.0f / power_of_2(1.0f / min_ff(zoomx, zoomy));
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-05-07 08:53:59 +00:00
|
|
|
if (fit || sc->zoom > newzoom)
|
2012-03-25 23:19:21 +00:00
|
|
|
sc->zoom = newzoom;
|
2011-11-07 12:55:18 +00:00
|
|
|
}
|
|
|
|
|
2013-09-05 13:37:53 +00:00
|
|
|
return true;
|
2011-11-07 12:55:18 +00:00
|
|
|
}
|
|
|
|
|
2012-06-11 20:50:57 +00:00
|
|
|
void ED_clip_point_undistorted_pos(SpaceClip *sc, const float co[2], float r_co[2])
|
2011-11-07 12:55:18 +00:00
|
|
|
{
|
2012-06-11 20:50:57 +00:00
|
|
|
copy_v2_v2(r_co, co);
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-03-25 23:19:21 +00:00
|
|
|
if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) {
|
2012-06-19 14:26:29 +00:00
|
|
|
MovieClip *clip = ED_space_clip_get_clip(sc);
|
2012-03-25 23:19:21 +00:00
|
|
|
float aspy = 1.0f / clip->tracking.camera.pixel_aspect;
|
2011-11-07 12:55:18 +00:00
|
|
|
int width, height;
|
|
|
|
|
2012-06-20 10:28:51 +00:00
|
|
|
BKE_movieclip_get_size(sc->clip, &sc->user, &width, &height);
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-06-11 20:50:57 +00:00
|
|
|
r_co[0] *= width;
|
|
|
|
r_co[1] *= height * aspy;
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-06-15 11:03:23 +00:00
|
|
|
BKE_tracking_undistort_v2(&clip->tracking, r_co, r_co);
|
2012-03-25 23:19:21 +00:00
|
|
|
|
2012-06-11 20:50:57 +00:00
|
|
|
r_co[0] /= width;
|
|
|
|
r_co[1] /= height * aspy;
|
2011-11-07 12:55:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-26 22:47:05 +00:00
|
|
|
void ED_clip_point_stable_pos(SpaceClip *sc, ARegion *ar, float x, float y, float *xr, float *yr)
|
2011-11-07 12:55:18 +00:00
|
|
|
{
|
|
|
|
int sx, sy, width, height;
|
2012-06-11 20:50:57 +00:00
|
|
|
float zoomx, zoomy, pos[3], imat[4][4];
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-07-26 22:41:40 +00:00
|
|
|
ED_space_clip_get_zoom(sc, ar, &zoomx, &zoomy);
|
|
|
|
ED_space_clip_get_size(sc, &width, &height);
|
2011-11-07 12:55:18 +00:00
|
|
|
|
|
|
|
UI_view2d_to_region_no_clip(&ar->v2d, 0.0f, 0.0f, &sx, &sy);
|
|
|
|
|
2012-03-25 23:19:21 +00:00
|
|
|
pos[0] = (x - sx) / zoomx;
|
|
|
|
pos[1] = (y - sy) / zoomy;
|
2012-06-11 20:50:57 +00:00
|
|
|
pos[2] = 0.0f;
|
2011-11-07 12:55:18 +00:00
|
|
|
|
|
|
|
invert_m4_m4(imat, sc->stabmat);
|
|
|
|
mul_v3_m4v3(pos, imat, pos);
|
|
|
|
|
2012-03-25 23:19:21 +00:00
|
|
|
*xr = pos[0] / width;
|
|
|
|
*yr = pos[1] / height;
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-03-25 23:19:21 +00:00
|
|
|
if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) {
|
2012-06-19 14:26:29 +00:00
|
|
|
MovieClip *clip = ED_space_clip_get_clip(sc);
|
2012-03-25 23:19:21 +00:00
|
|
|
MovieTracking *tracking = &clip->tracking;
|
|
|
|
float aspy = 1.0f / tracking->camera.pixel_aspect;
|
|
|
|
float tmp[2] = {*xr * width, *yr * height * aspy};
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-06-15 11:03:23 +00:00
|
|
|
BKE_tracking_distort_v2(tracking, tmp, tmp);
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-03-25 23:19:21 +00:00
|
|
|
*xr = tmp[0] / width;
|
|
|
|
*yr = tmp[1] / (height * aspy);
|
2011-11-07 12:55:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-14 12:04:00 +00:00
|
|
|
/**
|
|
|
|
* \brief the reverse of ED_clip_point_stable_pos(), gets the marker region coords.
|
2012-05-14 12:50:36 +00:00
|
|
|
* better name here? view_to_track / track_to_view or so?
|
2012-05-14 12:04:00 +00:00
|
|
|
*/
|
2012-07-26 22:47:05 +00:00
|
|
|
void ED_clip_point_stable_pos__reverse(SpaceClip *sc, ARegion *ar, const float co[2], float r_co[2])
|
2012-05-14 12:04:00 +00:00
|
|
|
{
|
|
|
|
float zoomx, zoomy;
|
|
|
|
float pos[3];
|
|
|
|
int width, height;
|
|
|
|
int sx, sy;
|
|
|
|
|
|
|
|
UI_view2d_to_region_no_clip(&ar->v2d, 0.0f, 0.0f, &sx, &sy);
|
2012-07-26 22:41:40 +00:00
|
|
|
ED_space_clip_get_size(sc, &width, &height);
|
|
|
|
ED_space_clip_get_zoom(sc, ar, &zoomx, &zoomy);
|
2012-05-14 12:04:00 +00:00
|
|
|
|
|
|
|
ED_clip_point_undistorted_pos(sc, co, pos);
|
2012-06-11 20:50:57 +00:00
|
|
|
pos[2] = 0.0f;
|
2012-05-14 12:04:00 +00:00
|
|
|
|
|
|
|
/* untested */
|
|
|
|
mul_v3_m4v3(pos, sc->stabmat, pos);
|
|
|
|
|
2012-06-11 20:50:57 +00:00
|
|
|
r_co[0] = (pos[0] * width * zoomx) + (float)sx;
|
|
|
|
r_co[1] = (pos[1] * height * zoomy) + (float)sy;
|
2012-05-14 12:04:00 +00:00
|
|
|
}
|
|
|
|
|
2012-07-27 15:15:55 +00:00
|
|
|
/* takes event->mval */
|
|
|
|
void ED_clip_mouse_pos(SpaceClip *sc, ARegion *ar, const int mval[2], float co[2])
|
2011-11-07 12:55:18 +00:00
|
|
|
{
|
2012-07-27 15:15:55 +00:00
|
|
|
ED_clip_point_stable_pos(sc, ar, mval[0], mval[1], &co[0], &co[1]);
|
2011-11-07 12:55:18 +00:00
|
|
|
}
|
2012-04-29 12:32:26 +00:00
|
|
|
|
2013-09-05 13:37:53 +00:00
|
|
|
bool ED_space_clip_check_show_trackedit(SpaceClip *sc)
|
2012-06-20 10:28:51 +00:00
|
|
|
{
|
|
|
|
if (sc) {
|
2014-02-07 20:26:43 +06:00
|
|
|
return sc->mode == SC_MODE_TRACKING;
|
2012-06-20 10:28:51 +00:00
|
|
|
}
|
|
|
|
|
2013-09-05 13:37:53 +00:00
|
|
|
return false;
|
2012-06-20 10:28:51 +00:00
|
|
|
}
|
|
|
|
|
2013-09-05 13:37:53 +00:00
|
|
|
bool ED_space_clip_check_show_maskedit(SpaceClip *sc)
|
2012-06-20 10:28:51 +00:00
|
|
|
{
|
|
|
|
if (sc) {
|
|
|
|
return sc->mode == SC_MODE_MASKEDIT;
|
|
|
|
}
|
|
|
|
|
2013-09-05 13:37:53 +00:00
|
|
|
return false;
|
2012-06-20 10:28:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ******** clip editing functions ******** */
|
|
|
|
|
|
|
|
MovieClip *ED_space_clip_get_clip(SpaceClip *sc)
|
|
|
|
{
|
|
|
|
return sc->clip;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ED_space_clip_set_clip(bContext *C, bScreen *screen, SpaceClip *sc, MovieClip *clip)
|
|
|
|
{
|
|
|
|
MovieClip *old_clip;
|
2013-04-04 09:50:51 +00:00
|
|
|
bool old_clip_visible = false;
|
2012-06-20 10:28:51 +00:00
|
|
|
|
|
|
|
if (!screen && C)
|
|
|
|
screen = CTX_wm_screen(C);
|
|
|
|
|
|
|
|
old_clip = sc->clip;
|
|
|
|
sc->clip = clip;
|
|
|
|
|
2012-12-18 08:41:38 +00:00
|
|
|
id_us_ensure_real((ID *)sc->clip);
|
2012-06-20 10:28:51 +00:00
|
|
|
|
|
|
|
if (screen && sc->view == SC_VIEW_CLIP) {
|
|
|
|
ScrArea *area;
|
|
|
|
SpaceLink *sl;
|
|
|
|
|
|
|
|
for (area = screen->areabase.first; area; area = area->next) {
|
|
|
|
for (sl = area->spacedata.first; sl; sl = sl->next) {
|
|
|
|
if (sl->spacetype == SPACE_CLIP) {
|
|
|
|
SpaceClip *cur_sc = (SpaceClip *) sl;
|
|
|
|
|
2013-04-04 09:50:51 +00:00
|
|
|
if (cur_sc != sc) {
|
|
|
|
if (cur_sc->view == SC_VIEW_CLIP) {
|
|
|
|
if (cur_sc->clip == old_clip)
|
|
|
|
old_clip_visible = true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (cur_sc->clip == old_clip || cur_sc->clip == NULL) {
|
|
|
|
cur_sc->clip = clip;
|
|
|
|
}
|
2012-06-20 10:28:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-04 09:50:51 +00:00
|
|
|
/* If clip is no longer visible on screen, free memory used by it's cache */
|
|
|
|
if (old_clip && old_clip != clip && !old_clip_visible) {
|
|
|
|
BKE_movieclip_clear_cache(old_clip);
|
|
|
|
}
|
|
|
|
|
2012-06-20 10:28:51 +00:00
|
|
|
if (C)
|
|
|
|
WM_event_add_notifier(C, NC_MOVIECLIP | NA_SELECTED, sc->clip);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ******** masking editing functions ******** */
|
|
|
|
|
|
|
|
Mask *ED_space_clip_get_mask(SpaceClip *sc)
|
|
|
|
{
|
2012-07-24 20:33:55 +00:00
|
|
|
return sc->mask_info.mask;
|
2012-06-20 10:28:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ED_space_clip_set_mask(bContext *C, SpaceClip *sc, Mask *mask)
|
|
|
|
{
|
2012-07-24 20:33:55 +00:00
|
|
|
sc->mask_info.mask = mask;
|
2012-06-20 10:28:51 +00:00
|
|
|
|
2012-12-18 08:41:38 +00:00
|
|
|
id_us_ensure_real((ID *)sc->mask_info.mask);
|
2012-06-20 10:28:51 +00:00
|
|
|
|
|
|
|
if (C) {
|
|
|
|
WM_event_add_notifier(C, NC_MASK | NA_SELECTED, mask);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-20 17:03:20 +00:00
|
|
|
/* ******** pre-fetching functions ******** */
|
|
|
|
|
|
|
|
typedef struct PrefetchJob {
|
|
|
|
MovieClip *clip;
|
2013-03-25 15:32:15 +00:00
|
|
|
int start_frame, current_frame, end_frame;
|
2013-03-20 17:03:20 +00:00
|
|
|
short render_size, render_flag;
|
|
|
|
} PrefetchJob;
|
|
|
|
|
|
|
|
typedef struct PrefetchQueue {
|
2013-03-25 15:32:15 +00:00
|
|
|
int initial_frame, current_frame, start_frame, end_frame;
|
2013-03-20 17:03:20 +00:00
|
|
|
short render_size, render_flag;
|
|
|
|
|
2014-01-01 23:23:12 +06:00
|
|
|
/* If true prefecthing goes forward in time,
|
|
|
|
* othwewise it goes backwards in time (starting from current frame).
|
|
|
|
*/
|
|
|
|
bool forward;
|
2013-03-25 15:32:15 +00:00
|
|
|
|
2013-03-20 17:03:20 +00:00
|
|
|
SpinLock spin;
|
|
|
|
|
|
|
|
short *stop;
|
|
|
|
short *do_update;
|
|
|
|
float *progress;
|
|
|
|
} PrefetchQueue;
|
|
|
|
|
|
|
|
typedef struct PrefetchThread {
|
|
|
|
MovieClip *clip;
|
|
|
|
PrefetchQueue *queue;
|
|
|
|
} PrefetchThread;
|
|
|
|
|
|
|
|
/* check whether pre-fetching is allowed */
|
2013-04-04 09:50:38 +00:00
|
|
|
static bool check_prefetch_break(void)
|
2013-03-20 17:03:20 +00:00
|
|
|
{
|
2013-04-04 09:50:38 +00:00
|
|
|
return G.is_break;
|
2013-03-20 17:03:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* read file for specified frame number to the memory */
|
|
|
|
static unsigned char *prefetch_read_file_to_memory(MovieClip *clip, int current_frame, short render_size,
|
2013-03-21 14:46:37 +00:00
|
|
|
short render_flag, size_t *size_r)
|
2013-03-20 17:03:20 +00:00
|
|
|
{
|
|
|
|
MovieClipUser user = {0};
|
|
|
|
char name[FILE_MAX];
|
|
|
|
size_t size;
|
|
|
|
int file;
|
|
|
|
unsigned char *mem;
|
|
|
|
|
|
|
|
user.framenr = current_frame;
|
|
|
|
user.render_size = render_size;
|
|
|
|
user.render_flag = render_flag;
|
|
|
|
|
|
|
|
BKE_movieclip_filename_for_frame(clip, &user, name);
|
|
|
|
|
2013-10-17 12:28:32 +00:00
|
|
|
file = BLI_open(name, O_BINARY | O_RDONLY, 0);
|
2013-03-20 17:03:20 +00:00
|
|
|
if (file < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
size = BLI_file_descriptor_size(file);
|
|
|
|
if (size < 1) {
|
|
|
|
close(file);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
mem = MEM_mallocN(size, "movieclip prefetch memory file");
|
|
|
|
|
|
|
|
if (read(file, mem, size) != size) {
|
|
|
|
close(file);
|
|
|
|
MEM_freeN(mem);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
*size_r = size;
|
|
|
|
|
|
|
|
close(file);
|
|
|
|
|
|
|
|
return mem;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* find first uncached frame within prefetching frame range */
|
|
|
|
static int prefetch_find_uncached_frame(MovieClip *clip, int from_frame, int end_frame,
|
2013-03-25 15:32:15 +00:00
|
|
|
short render_size, short render_flag, short direction)
|
2013-03-20 17:03:20 +00:00
|
|
|
{
|
|
|
|
int current_frame;
|
2013-03-25 15:32:15 +00:00
|
|
|
MovieClipUser user = {0};
|
2013-03-20 17:03:20 +00:00
|
|
|
|
2013-03-25 15:32:15 +00:00
|
|
|
user.render_size = render_size;
|
|
|
|
user.render_flag = render_flag;
|
2013-03-20 17:03:20 +00:00
|
|
|
|
2013-03-25 15:32:15 +00:00
|
|
|
if (direction > 0) {
|
|
|
|
for (current_frame = from_frame; current_frame <= end_frame; current_frame++) {
|
|
|
|
user.framenr = current_frame;
|
2013-03-20 17:03:20 +00:00
|
|
|
|
2013-03-25 15:32:15 +00:00
|
|
|
if (!BKE_movieclip_has_cached_frame(clip, &user))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
for (current_frame = from_frame; current_frame >= end_frame; current_frame--) {
|
|
|
|
user.framenr = current_frame;
|
|
|
|
|
|
|
|
if (!BKE_movieclip_has_cached_frame(clip, &user))
|
|
|
|
break;
|
|
|
|
}
|
2013-03-20 17:03:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return current_frame;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get memory buffer for first uncached frame within prefetch frame range */
|
|
|
|
static unsigned char *prefetch_thread_next_frame(PrefetchQueue *queue, MovieClip *clip,
|
|
|
|
size_t *size_r, int *current_frame_r)
|
|
|
|
{
|
|
|
|
unsigned char *mem = NULL;
|
|
|
|
|
|
|
|
BLI_spin_lock(&queue->spin);
|
2013-04-04 09:50:38 +00:00
|
|
|
if (!*queue->stop && !check_prefetch_break() &&
|
2013-03-25 15:32:15 +00:00
|
|
|
IN_RANGE_INCL(queue->current_frame, queue->start_frame, queue->end_frame))
|
|
|
|
{
|
2013-03-20 17:03:20 +00:00
|
|
|
int current_frame;
|
|
|
|
|
2014-01-01 23:23:12 +06:00
|
|
|
if (queue->forward) {
|
2013-03-25 15:32:15 +00:00
|
|
|
current_frame = prefetch_find_uncached_frame(clip, queue->current_frame + 1, queue->end_frame,
|
|
|
|
queue->render_size, queue->render_flag, 1);
|
2013-10-12 14:47:04 +00:00
|
|
|
/* switch direction if read frames from current up to scene end frames */
|
2013-10-17 09:19:03 +00:00
|
|
|
if (current_frame > queue->end_frame) {
|
2013-10-12 14:47:04 +00:00
|
|
|
queue->current_frame = queue->initial_frame;
|
2014-01-01 23:23:12 +06:00
|
|
|
queue->forward = false;
|
2013-10-12 14:47:04 +00:00
|
|
|
}
|
2013-03-25 15:32:15 +00:00
|
|
|
}
|
2013-10-12 14:47:04 +00:00
|
|
|
|
2014-01-01 23:23:12 +06:00
|
|
|
if (!queue->forward) {
|
2013-03-25 15:32:15 +00:00
|
|
|
current_frame = prefetch_find_uncached_frame(clip, queue->current_frame - 1, queue->start_frame,
|
|
|
|
queue->render_size, queue->render_flag, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IN_RANGE_INCL(current_frame, queue->start_frame, queue->end_frame)) {
|
|
|
|
int frames_processed;
|
|
|
|
|
2013-03-20 17:03:20 +00:00
|
|
|
mem = prefetch_read_file_to_memory(clip, current_frame, queue->render_size,
|
|
|
|
queue->render_flag, size_r);
|
|
|
|
|
|
|
|
*current_frame_r = current_frame;
|
|
|
|
|
|
|
|
queue->current_frame = current_frame;
|
|
|
|
|
2014-01-01 23:23:12 +06:00
|
|
|
if (queue->forward) {
|
2013-03-25 15:32:15 +00:00
|
|
|
frames_processed = queue->current_frame - queue->initial_frame;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
frames_processed = (queue->end_frame - queue->initial_frame) +
|
|
|
|
(queue->initial_frame - queue->current_frame);
|
|
|
|
}
|
|
|
|
|
2013-03-20 17:03:20 +00:00
|
|
|
*queue->do_update = 1;
|
2013-03-25 15:32:15 +00:00
|
|
|
*queue->progress = (float)frames_processed / (queue->end_frame - queue->start_frame);
|
2013-03-20 17:03:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
BLI_spin_unlock(&queue->spin);
|
|
|
|
|
|
|
|
return mem;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *do_prefetch_thread(void *data_v)
|
|
|
|
{
|
|
|
|
PrefetchThread *data = (PrefetchThread *) data_v;
|
2013-10-17 09:44:08 +00:00
|
|
|
MovieClip *clip = data->clip;
|
2013-03-20 17:03:20 +00:00
|
|
|
unsigned char *mem;
|
|
|
|
size_t size;
|
|
|
|
int current_frame;
|
|
|
|
|
|
|
|
while ((mem = prefetch_thread_next_frame(data->queue, data->clip, &size, ¤t_frame))) {
|
|
|
|
ImBuf *ibuf;
|
|
|
|
MovieClipUser user = {0};
|
|
|
|
int flag = IB_rect | IB_alphamode_detect;
|
|
|
|
int result;
|
2014-03-10 16:46:05 +06:00
|
|
|
char *colorspace_name = NULL;
|
2013-03-20 17:03:20 +00:00
|
|
|
|
|
|
|
user.framenr = current_frame;
|
|
|
|
user.render_size = data->queue->render_size;
|
|
|
|
user.render_flag = data->queue->render_flag;
|
|
|
|
|
2014-03-10 16:46:05 +06:00
|
|
|
/* Proxies are stored in the display space. */
|
|
|
|
if (data->queue->render_flag & MCLIP_USE_PROXY) {
|
|
|
|
colorspace_name = clip->colorspace_settings.name;
|
|
|
|
}
|
|
|
|
|
|
|
|
ibuf = IMB_ibImageFromMemory(mem, size, flag, colorspace_name, "prefetch frame");
|
2013-03-20 17:03:20 +00:00
|
|
|
|
|
|
|
result = BKE_movieclip_put_frame_if_possible(data->clip, &user, ibuf);
|
|
|
|
|
|
|
|
IMB_freeImBuf(ibuf);
|
|
|
|
|
|
|
|
MEM_freeN(mem);
|
|
|
|
|
|
|
|
if (!result) {
|
|
|
|
/* no more space in the cache, stop reading frames */
|
|
|
|
*data->queue->stop = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-03-25 15:32:15 +00:00
|
|
|
static void start_prefetch_threads(MovieClip *clip, int start_frame, int current_frame, int end_frame,
|
|
|
|
short render_size, short render_flag, short *stop, short *do_update,
|
|
|
|
float *progress)
|
2013-03-20 17:03:20 +00:00
|
|
|
{
|
|
|
|
ListBase threads;
|
|
|
|
PrefetchQueue queue;
|
|
|
|
PrefetchThread *handles;
|
|
|
|
int tot_thread = BLI_system_thread_count();
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* reserve one thread for the interface */
|
|
|
|
if (tot_thread > 1)
|
|
|
|
tot_thread--;
|
|
|
|
|
|
|
|
/* initialize queue */
|
|
|
|
BLI_spin_init(&queue.spin);
|
|
|
|
|
2013-03-25 15:32:15 +00:00
|
|
|
queue.current_frame = current_frame;
|
|
|
|
queue.initial_frame = current_frame;
|
2013-03-20 17:03:20 +00:00
|
|
|
queue.start_frame = start_frame;
|
|
|
|
queue.end_frame = end_frame;
|
|
|
|
queue.render_size = render_size;
|
|
|
|
queue.render_flag = render_flag;
|
2014-01-01 23:23:12 +06:00
|
|
|
queue.forward = 1;
|
2013-03-20 17:03:20 +00:00
|
|
|
|
|
|
|
queue.stop = stop;
|
|
|
|
queue.do_update = do_update;
|
|
|
|
queue.progress = progress;
|
|
|
|
|
|
|
|
/* fill in thread handles */
|
|
|
|
handles = MEM_callocN(sizeof(PrefetchThread) * tot_thread, "prefetch threaded handles");
|
|
|
|
|
|
|
|
if (tot_thread > 1)
|
|
|
|
BLI_init_threads(&threads, do_prefetch_thread, tot_thread);
|
|
|
|
|
|
|
|
for (i = 0; i < tot_thread; i++) {
|
|
|
|
PrefetchThread *handle = &handles[i];
|
|
|
|
|
|
|
|
handle->clip = clip;
|
|
|
|
handle->queue = &queue;
|
|
|
|
|
|
|
|
if (tot_thread > 1)
|
|
|
|
BLI_insert_thread(&threads, handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* run the threads */
|
|
|
|
if (tot_thread > 1)
|
|
|
|
BLI_end_threads(&threads);
|
|
|
|
else
|
|
|
|
do_prefetch_thread(handles);
|
|
|
|
|
|
|
|
MEM_freeN(handles);
|
|
|
|
}
|
|
|
|
|
2013-03-25 15:32:15 +00:00
|
|
|
static bool prefetch_movie_frame(MovieClip *clip, int frame, short render_size,
|
|
|
|
short render_flag, short *stop)
|
2013-03-20 17:03:20 +00:00
|
|
|
{
|
2013-03-25 15:32:15 +00:00
|
|
|
MovieClipUser user = {0};
|
|
|
|
ImBuf *ibuf;
|
2013-03-20 17:03:20 +00:00
|
|
|
|
2013-04-04 09:50:38 +00:00
|
|
|
if (check_prefetch_break() || *stop)
|
2013-03-25 15:32:15 +00:00
|
|
|
return false;
|
2013-03-20 17:03:20 +00:00
|
|
|
|
2013-03-25 15:32:15 +00:00
|
|
|
user.framenr = frame;
|
|
|
|
user.render_size = render_size;
|
|
|
|
user.render_flag = render_flag;
|
2013-03-20 17:03:20 +00:00
|
|
|
|
2013-03-25 15:32:15 +00:00
|
|
|
if (!BKE_movieclip_has_cached_frame(clip, &user)) {
|
|
|
|
ibuf = BKE_movieclip_anim_ibuf_for_frame(clip, &user);
|
2013-03-20 17:03:20 +00:00
|
|
|
|
2013-03-25 15:32:15 +00:00
|
|
|
if (ibuf) {
|
|
|
|
int result;
|
2013-03-20 17:03:20 +00:00
|
|
|
|
2013-03-25 15:32:15 +00:00
|
|
|
result = BKE_movieclip_put_frame_if_possible(clip, &user, ibuf);
|
2013-03-20 17:03:20 +00:00
|
|
|
|
2013-03-25 15:32:15 +00:00
|
|
|
if (!result) {
|
|
|
|
/* no more space in the cache, we could stop prefetching here */
|
2013-03-20 17:03:20 +00:00
|
|
|
*stop = 1;
|
|
|
|
}
|
2013-03-25 15:32:15 +00:00
|
|
|
|
|
|
|
IMB_freeImBuf(ibuf);
|
2013-03-20 17:03:20 +00:00
|
|
|
}
|
2013-03-25 15:32:15 +00:00
|
|
|
else {
|
|
|
|
/* error reading frame, fair enough stop attempting further reading */
|
|
|
|
*stop = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void do_prefetch_movie(MovieClip *clip, int start_frame, int current_frame, int end_frame,
|
|
|
|
short render_size, short render_flag, short *stop, short *do_update,
|
|
|
|
float *progress)
|
|
|
|
{
|
|
|
|
int frame;
|
|
|
|
int frames_processed = 0;
|
|
|
|
|
|
|
|
/* read frames starting from current frame up to scene end frame */
|
|
|
|
for (frame = current_frame; frame <= end_frame; frame++) {
|
|
|
|
if (!prefetch_movie_frame(clip, frame, render_size, render_flag, stop))
|
|
|
|
return;
|
|
|
|
|
|
|
|
frames_processed++;
|
|
|
|
|
|
|
|
*do_update = 1;
|
|
|
|
*progress = (float) frames_processed / (end_frame - start_frame);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* read frames starting from current frame up to scene start frame */
|
|
|
|
for (frame = current_frame; frame >= start_frame; frame--) {
|
|
|
|
if (!prefetch_movie_frame(clip, frame, render_size, render_flag, stop))
|
|
|
|
return;
|
|
|
|
|
|
|
|
frames_processed++;
|
2013-03-20 17:03:20 +00:00
|
|
|
|
|
|
|
*do_update = 1;
|
2013-03-25 15:32:15 +00:00
|
|
|
*progress = (float) frames_processed / (end_frame - start_frame);
|
2013-03-20 17:03:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void prefetch_startjob(void *pjv, short *stop, short *do_update, float *progress)
|
|
|
|
{
|
|
|
|
PrefetchJob *pj = pjv;
|
|
|
|
|
|
|
|
if (pj->clip->source == MCLIP_SRC_SEQUENCE) {
|
|
|
|
/* read sequence files in multiple threads */
|
2013-03-25 15:32:15 +00:00
|
|
|
start_prefetch_threads(pj->clip, pj->start_frame, pj->current_frame, pj->end_frame,
|
2013-03-20 17:03:20 +00:00
|
|
|
pj->render_size, pj->render_flag,
|
|
|
|
stop, do_update, progress);
|
|
|
|
}
|
|
|
|
else if (pj->clip->source == MCLIP_SRC_MOVIE) {
|
|
|
|
/* read movie in a single thread */
|
2013-03-25 15:32:15 +00:00
|
|
|
do_prefetch_movie(pj->clip, pj->start_frame, pj->current_frame, pj->end_frame,
|
2013-03-20 17:03:20 +00:00
|
|
|
pj->render_size, pj->render_flag,
|
|
|
|
stop, do_update, progress);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BLI_assert(!"Unknown movie clip source when prefetching frames");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void prefetch_freejob(void *pjv)
|
|
|
|
{
|
|
|
|
PrefetchJob *pj = pjv;
|
|
|
|
|
|
|
|
MEM_freeN(pj);
|
|
|
|
}
|
|
|
|
|
2013-03-25 15:32:15 +00:00
|
|
|
static int prefetch_get_start_frame(const bContext *C)
|
|
|
|
{
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
|
|
|
|
return SFRA;
|
|
|
|
}
|
|
|
|
|
2013-03-20 17:03:20 +00:00
|
|
|
static int prefetch_get_final_frame(const bContext *C)
|
|
|
|
{
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
SpaceClip *sc = CTX_wm_space_clip(C);
|
|
|
|
MovieClip *clip = ED_space_clip_get_clip(sc);
|
|
|
|
int end_frame;
|
|
|
|
|
|
|
|
/* check whether all the frames from prefetch range are cached */
|
2013-03-21 07:47:38 +00:00
|
|
|
end_frame = EFRA;
|
2013-03-20 17:03:20 +00:00
|
|
|
|
|
|
|
if (clip->len)
|
|
|
|
end_frame = min_ii(end_frame, clip->len);
|
|
|
|
|
|
|
|
return end_frame;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* returns true if early out is possible */
|
|
|
|
static bool prefetch_check_early_out(const bContext *C)
|
|
|
|
{
|
|
|
|
SpaceClip *sc = CTX_wm_space_clip(C);
|
|
|
|
MovieClip *clip = ED_space_clip_get_clip(sc);
|
|
|
|
int first_uncached_frame, end_frame;
|
|
|
|
int clip_len;
|
|
|
|
|
2014-03-20 12:39:02 +06:00
|
|
|
if (clip == NULL) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-03-20 17:03:20 +00:00
|
|
|
clip_len = BKE_movieclip_get_duration(clip);
|
|
|
|
|
|
|
|
/* check whether all the frames from prefetch range are cached */
|
|
|
|
end_frame = prefetch_get_final_frame(C);
|
|
|
|
|
|
|
|
first_uncached_frame =
|
|
|
|
prefetch_find_uncached_frame(clip, sc->user.framenr, end_frame,
|
2013-03-25 15:32:15 +00:00
|
|
|
sc->user.render_size, sc->user.render_flag, 1);
|
2013-03-20 17:03:20 +00:00
|
|
|
|
2013-03-25 15:32:15 +00:00
|
|
|
if (first_uncached_frame > end_frame || first_uncached_frame == clip_len) {
|
|
|
|
int start_frame = prefetch_get_start_frame(C);
|
|
|
|
|
|
|
|
first_uncached_frame =
|
|
|
|
prefetch_find_uncached_frame(clip, sc->user.framenr, start_frame,
|
|
|
|
sc->user.render_size, sc->user.render_flag, -1);
|
|
|
|
|
|
|
|
if (first_uncached_frame < start_frame)
|
|
|
|
return true;
|
|
|
|
}
|
2013-03-20 17:03:20 +00:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void clip_start_prefetch_job(const bContext *C)
|
|
|
|
{
|
|
|
|
wmJob *wm_job;
|
|
|
|
PrefetchJob *pj;
|
|
|
|
SpaceClip *sc = CTX_wm_space_clip(C);
|
|
|
|
|
|
|
|
if (prefetch_check_early_out(C))
|
|
|
|
return;
|
|
|
|
|
|
|
|
wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), CTX_wm_area(C), "Prefetching",
|
|
|
|
WM_JOB_PROGRESS, WM_JOB_TYPE_CLIP_PREFETCH);
|
|
|
|
|
|
|
|
/* create new job */
|
|
|
|
pj = MEM_callocN(sizeof(PrefetchJob), "prefetch job");
|
|
|
|
pj->clip = ED_space_clip_get_clip(sc);
|
2013-03-25 15:32:15 +00:00
|
|
|
pj->start_frame = prefetch_get_start_frame(C);
|
|
|
|
pj->current_frame = sc->user.framenr;
|
2013-03-20 17:03:20 +00:00
|
|
|
pj->end_frame = prefetch_get_final_frame(C);
|
|
|
|
pj->render_size = sc->user.render_size;
|
|
|
|
pj->render_flag = sc->user.render_flag;
|
|
|
|
|
|
|
|
WM_jobs_customdata_set(wm_job, pj, prefetch_freejob);
|
2013-04-04 09:50:38 +00:00
|
|
|
WM_jobs_timer(wm_job, 0.2, NC_MOVIECLIP | ND_DISPLAY, 0);
|
2013-03-20 17:03:20 +00:00
|
|
|
WM_jobs_callbacks(wm_job, prefetch_startjob, NULL, NULL, NULL);
|
|
|
|
|
2014-03-20 15:52:00 +06:00
|
|
|
G.is_break = false;
|
2013-04-04 09:50:38 +00:00
|
|
|
|
2013-03-20 17:03:20 +00:00
|
|
|
/* and finally start the job */
|
|
|
|
WM_jobs_start(CTX_wm_manager(C), wm_job);
|
|
|
|
}
|