void MovieClipAttributeOperation::executePixelSampled(float output[4],
                                                      float /*x*/, float /*y*/,
                                                      PixelSampler /*sampler*/)
{
	if (!this->m_valueSet) {
		float loc[2], scale, angle;
		loc[0] = 0.0f;
		loc[1] = 0.0f;
		scale = 1.0f;
		angle = 0.0f;
		if (this->m_clip) {
			int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_clip, this->m_framenumber);
			BKE_tracking_stabilization_data_get(&this->m_clip->tracking, clip_framenr, getWidth(), getHeight(), loc, &scale, &angle);
		}
		switch (this->m_attribute) {
			case MCA_SCALE:
				this->m_value = scale;
				break;
			case MCA_ANGLE:
				this->m_value = angle;
				break;
			case MCA_X:
				this->m_value = loc[0];
				break;
			case MCA_Y:
				this->m_value = loc[1];
				break;
		}
		this->m_valueSet = true;
	}
	output[0] = this->m_value;
}
Example #2
0
static ImBuf *get_stable_cached_frame(MovieClip *clip, MovieClipUser *user, ImBuf *reference_ibuf,
                                      int framenr, int postprocess_flag)
{
	MovieClipCache *cache = clip->cache;
	MovieTracking *tracking = &clip->tracking;
	ImBuf *stableibuf;
	float tloc[2], tscale, tangle;
	short proxy = IMB_PROXY_NONE;
	int render_flag = 0;
	int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, framenr);

	if (clip->flag & MCLIP_USE_PROXY) {
		proxy = rendersize_to_proxy(user, clip->flag);
		render_flag = user->render_flag;
	}

	/* there's no cached frame or it was calculated for another frame */
	if (!cache->stabilized.ibuf || cache->stabilized.framenr != framenr)
		return NULL;

	if (cache->stabilized.reference_ibuf != reference_ibuf)
		return NULL;

	/* cached ibuf used different proxy settings */
	if (cache->stabilized.render_flag != render_flag || cache->stabilized.proxy != proxy)
		return NULL;

	if (cache->stabilized.postprocess_flag != postprocess_flag)
		return NULL;

	/* stabilization also depends on pixel aspect ratio */
	if (cache->stabilized.aspect != tracking->camera.pixel_aspect)
		return NULL;

	if (cache->stabilized.filter != tracking->stabilization.filter)
		return NULL;

	stableibuf = cache->stabilized.ibuf;

	BKE_tracking_stabilization_data_get(&clip->tracking, clip_framenr, stableibuf->x, stableibuf->y, tloc, &tscale, &tangle);

	/* check for stabilization parameters */
	if (tscale != cache->stabilized.scale ||
	    tangle != cache->stabilized.angle ||
	    !equals_v2v2(tloc, cache->stabilized.loc))
	{
		return NULL;
	}

	IMB_refImBuf(stableibuf);

	return stableibuf;
}
static void node_composit_exec_movieclip(void *data, bNode *node, bNodeStack **UNUSED(in), bNodeStack **out)
{
	if (node->id) {
		RenderData *rd = data;
		MovieClip *clip = (MovieClip *)node->id;
		MovieClipUser *user = (MovieClipUser *)node->storage;
		CompBuf *stackbuf = NULL;

		BKE_movieclip_user_set_frame(user, rd->cfra);

		stackbuf = node_composit_get_movieclip(rd, clip, user);

		if (stackbuf) {
			MovieTrackingStabilization *stab = &clip->tracking.stabilization;

			/* put image on stack */
			out[0]->data = stackbuf;

			if (stab->flag & TRACKING_2D_STABILIZATION) {
				float loc[2], scale, angle;
				int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, rd->cfra);

				BKE_tracking_stabilization_data_get(&clip->tracking, clip_framenr, stackbuf->x, stackbuf->y,
							loc, &scale, &angle);

				out[1]->vec[0] = loc[0];
				out[2]->vec[0] = loc[1];

				out[3]->vec[0] = scale;
				out[4]->vec[0] = angle;
			}

			/* generate preview */
			generate_preview(data, node, stackbuf);
		}
	}
}
void MovieClipAttributeOperation::initExecution()
{
	float loc[2], scale, angle;
	loc[0] = 0.0f;
	loc[1] = 0.0f;
	scale = 1.0f;
	angle = 0.0f;
	int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(
	        this->m_clip, this->m_framenumber);
	BKE_tracking_stabilization_data_get(this->m_clip,
	                                    clip_framenr,
	                                    getWidth(), getHeight(),
	                                    loc, &scale, &angle);
	switch (this->m_attribute) {
		case MCA_SCALE:
			this->m_value = scale;
			break;
		case MCA_ANGLE:
			this->m_value = angle;
			break;
		case MCA_X:
			this->m_value = loc[0];
			break;
		case MCA_Y:
			this->m_value = loc[1];
			break;
	}
	if (this->m_invert) {
		if (this->m_attribute != MCA_SCALE) {
			this->m_value = -this->m_value;
		}
		else {
			this->m_value = 1.0f / this->m_value;
		}
	}
}
void MovieClipNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
{
    NodeOutput *outputMovieClip = this->getOutputSocket(0);
    NodeOutput *alphaMovieClip = this->getOutputSocket(1);
    NodeOutput *offsetXMovieClip = this->getOutputSocket(2);
    NodeOutput *offsetYMovieClip = this->getOutputSocket(3);
    NodeOutput *scaleMovieClip = this->getOutputSocket(4);
    NodeOutput *angleMovieClip = this->getOutputSocket(5);

    bNode *editorNode = this->getbNode();
    MovieClip *movieClip = (MovieClip *)editorNode->id;
    MovieClipUser *movieClipUser = (MovieClipUser *)editorNode->storage;
    bool cacheFrame = !context.isRendering();

    ImBuf *ibuf = NULL;
    if (movieClip) {
        if (cacheFrame)
            ibuf = BKE_movieclip_get_ibuf(movieClip, movieClipUser);
        else
            ibuf = BKE_movieclip_get_ibuf_flag(movieClip, movieClipUser, movieClip->flag, MOVIECLIP_CACHE_SKIP);
    }

    // always connect the output image
    MovieClipOperation *operation = new MovieClipOperation();
    operation->setMovieClip(movieClip);
    operation->setMovieClipUser(movieClipUser);
    operation->setFramenumber(context.getFramenumber());
    operation->setCacheFrame(cacheFrame);

    converter.addOperation(operation);
    converter.mapOutputSocket(outputMovieClip, operation->getOutputSocket());
    converter.addPreview(operation->getOutputSocket());

    MovieClipAlphaOperation *alphaOperation = new MovieClipAlphaOperation();
    alphaOperation->setMovieClip(movieClip);
    alphaOperation->setMovieClipUser(movieClipUser);
    alphaOperation->setFramenumber(context.getFramenumber());
    alphaOperation->setCacheFrame(cacheFrame);

    converter.addOperation(alphaOperation);
    converter.mapOutputSocket(alphaMovieClip, alphaOperation->getOutputSocket());

    MovieTrackingStabilization *stab = &movieClip->tracking.stabilization;
    float loc[2], scale, angle;
    loc[0] = 0.0f;
    loc[1] = 0.0f;
    scale = 1.0f;
    angle = 0.0f;

    if (ibuf) {
        if (stab->flag & TRACKING_2D_STABILIZATION) {
            int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(movieClip, context.getFramenumber());

            BKE_tracking_stabilization_data_get(&movieClip->tracking, clip_framenr, ibuf->x, ibuf->y, loc, &scale, &angle);
        }
    }

    converter.addOutputValue(offsetXMovieClip, loc[0]);
    converter.addOutputValue(offsetYMovieClip, loc[1]);
    converter.addOutputValue(scaleMovieClip, scale);
    converter.addOutputValue(angleMovieClip, angle);

    if (ibuf) {
        IMB_freeImBuf(ibuf);
    }
}
/* Stabilize given image buffer using stabilization data for
 * a specified frame number.
 *
 * NOTE: frame number should be in clip space, not scene space
 */
ImBuf *BKE_tracking_stabilize_frame(MovieTracking *tracking, int framenr, ImBuf *ibuf,
                                    float translation[2], float *scale, float *angle)
{
	float tloc[2], tscale, tangle;
	MovieTrackingStabilization *stab = &tracking->stabilization;
	ImBuf *tmpibuf;
	int width = ibuf->x, height = ibuf->y;
	float aspect = tracking->camera.pixel_aspect;
	float mat[4][4];
	int j, filter = tracking->stabilization.filter;
	void (*interpolation)(struct ImBuf *, struct ImBuf *, float, float, int, int) = NULL;
	int ibuf_flags;

	if (translation)
		copy_v2_v2(tloc, translation);

	if (scale)
		tscale = *scale;

	/* Perform early output if no stabilization is used. */
	if ((stab->flag & TRACKING_2D_STABILIZATION) == 0) {
		if (translation)
			zero_v2(translation);

		if (scale)
			*scale = 1.0f;

		if (angle)
			*angle = 0.0f;

		return ibuf;
	}

	/* Allocate frame for stabilization result. */
	ibuf_flags = 0;
	if (ibuf->rect)
		ibuf_flags |= IB_rect;
	if (ibuf->rect_float)
		ibuf_flags |= IB_rectfloat;

	tmpibuf = IMB_allocImBuf(ibuf->x, ibuf->y, ibuf->planes, ibuf_flags);

	/* Calculate stabilization matrix. */
	BKE_tracking_stabilization_data_get(tracking, framenr, width, height, tloc, &tscale, &tangle);
	BKE_tracking_stabilization_data_to_mat4(ibuf->x, ibuf->y, aspect, tloc, tscale, tangle, mat);
	invert_m4(mat);

	if (filter == TRACKING_FILTER_NEAREST)
		interpolation = nearest_interpolation;
	else if (filter == TRACKING_FILTER_BILINEAR)
		interpolation = bilinear_interpolation;
	else if (filter == TRACKING_FILTER_BICUBIC)
		interpolation = bicubic_interpolation;
	else
		/* fallback to default interpolation method */
		interpolation = nearest_interpolation;

	/* This function is only used for display in clip editor and
	 * sequencer only, which would only benefit of using threads
	 * here.
	 *
	 * But need to keep an eye on this if the function will be
	 * used in other cases.
	 */
#pragma omp parallel for if (tmpibuf->y > 128)
	for (j = 0; j < tmpibuf->y; j++) {
		int i;
		for (i = 0; i < tmpibuf->x; i++) {
			float vec[3] = {i, j, 0.0f};

			mul_v3_m4v3(vec, mat, vec);

			interpolation(ibuf, tmpibuf, vec[0], vec[1], i, j);
		}
	}

	if (tmpibuf->rect_float)
		tmpibuf->userflags |= IB_RECT_INVALID;

	if (translation)
		copy_v2_v2(translation, tloc);

	if (scale)
		*scale = tscale;

	if (angle)
		*angle = tangle;

	return tmpibuf;
}