4 * Copyright (C) Georg Martius - June 2007
5 * georg dot martius at web dot de
7 * This file is part of transcode, a video stream processing tool
9 * transcode is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2, or (at your option)
14 * transcode is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with GNU Make; see the file COPYING. If not, write to
21 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24 * transcode -J transform -i inp.mpeg -y xdiv,tcaud inp_stab.avi
26 #include "transform_image.h"
29 #include <framework/mlt_log.h>
31 #define MAX (a,b) (((a)>(b)?(a):(b)))
32 #define MIN (a,b) (((a)<(b)?(a):(b)))
33 #define CLAMP(a,x,y) MIN( MAX( (a),(x) ,y))
35 #define TC_MAX(a, b) (((a) > (b)) ?(a) :(b))
36 #define TC_MIN(a, b) (((a) < (b)) ?(a) :(b))
37 /* clamp x between a and b */
38 #define TC_CLAMP(x, a, b) TC_MIN(TC_MAX((a), (x)), (b))
41 static const char* interpoltypes[5] = {"No (0)", "Linear (1)", "Bi-Linear (2)",
42 "Quadratic (3)", "Bi-Cubic (4)"};
44 void (*interpolate)(unsigned char *rv, float x, float y,
45 unsigned char* img, int width, int height,
46 unsigned char def,unsigned char N, unsigned char channel) = 0;
48 /** interpolateBiLinBorder: bi-linear interpolation function that also works at the border.
49 This is used by many other interpolation methods at and outsize the border, see interpolate */
50 void interpolateBiLinBorder(unsigned char *rv, float x, float y,
51 unsigned char* img, int width, int height,
52 unsigned char def,unsigned char N, unsigned char channel)
58 short v1 = PIXELN(img, x_c, y_c, width, height, N, channel, def);
59 short v2 = PIXELN(img, x_c, y_f, width, height, N, channel, def);
60 short v3 = PIXELN(img, x_f, y_c, width, height, N, channel, def);
61 short v4 = PIXELN(img, x_f, y_f, width, height, N, channel, def);
62 float s = (v1*(x - x_f)+v3*(x_c - x))*(y - y_f) +
63 (v2*(x - x_f) + v4*(x_c - x))*(y_c - y);
64 *rv = (unsigned char)s;
67 /* taken from http://en.wikipedia.org/wiki/Bicubic_interpolation for alpha=-0.5
69 a0-a3 are the neigthboring points where the target point is between a1 and a2
70 t is the point of interpolation (position between a1 and a2) value between 0 and 1
73 (1,t,t^2,t^3) | 2,-5, 4,-1 | |a2|
76 static short bicub_kernel(float t, short a0, short a1, short a2, short a3){
77 return (2*a1 + t*((-a0+a2) + t*((2*a0-5*a1+4*a2-a3) + t*(-a0+3*a1-3*a2+a3) )) ) / 2;
80 /** interpolateBiCub: bi-cubic interpolation function using 4x4 pixel, see interpolate */
81 void interpolateBiCub(unsigned char *rv, float x, float y,
82 unsigned char* img, int width, int height, unsigned char def,unsigned char N, unsigned char channel)
84 // do a simple linear interpolation at the border
85 if (x < 1 || x >= width-2 || y < 1 || y >= height - 2) {
86 interpolateBiLinBorder(rv, x,y,img,width,height,def,N,channel);
91 short v1 = bicub_kernel(tx,
92 PIXN(img, x_f-1, y_f-1, width, height, N, channel),
93 PIXN(img, x_f, y_f-1, width, height, N, channel),
94 PIXN(img, x_f+1, y_f-1, width, height, N, channel),
95 PIXN(img, x_f+2, y_f-1, width, height, N, channel));
96 short v2 = bicub_kernel(tx,
97 PIXN(img, x_f-1, y_f, width, height, N, channel),
98 PIXN(img, x_f, y_f, width, height, N, channel),
99 PIXN(img, x_f+1, y_f, width, height, N, channel),
100 PIXN(img, x_f+2, y_f, width, height, N, channel));
101 short v3 = bicub_kernel(tx,
102 PIXN(img, x_f-1, y_f+1, width, height, N, channel),
103 PIXN(img, x_f, y_f+1, width, height, N, channel),
104 PIXN(img, x_f+1, y_f+1, width, height, N, channel),
105 PIXN(img, x_f+2, y_f+1, width, height, N, channel));
106 short v4 = bicub_kernel(tx,
107 PIXN(img, x_f-1, y_f+2, width, height, N, channel),
108 PIXN(img, x_f, y_f+2, width, height, N, channel),
109 PIXN(img, x_f+1, y_f+2, width, height, N, channel),
110 PIXN(img, x_f+2, y_f+2, width, height, N, channel));
111 *rv = (unsigned char)bicub_kernel(y-y_f, v1, v2, v3, v4);
115 /** interpolateSqr: bi-quatratic interpolation function, see interpolate */
116 void interpolateSqr(unsigned char *rv, float x, float y,
117 unsigned char* img, int width, int height, unsigned char def,unsigned char N, unsigned char channel)
119 if (x < 0 || x >= width-1 || y < 0 || y >= height-1) {
120 interpolateBiLinBorder(rv, x, y, img, width, height, def,N,channel);
122 int x_f = myfloor(x);
124 int y_f = myfloor(y);
126 short v1 = PIXN(img, x_c, y_c, width, height, N, channel);
127 short v2 = PIXN(img, x_c, y_f, width, height, N, channel);
128 short v3 = PIXN(img, x_f, y_c, width, height, N, channel);
129 short v4 = PIXN(img, x_f, y_f, width, height, N, channel);
130 float f1 = 1 - sqrt((x_c - x) * (y_c - y));
131 float f2 = 1 - sqrt((x_c - x) * (y - y_f));
132 float f3 = 1 - sqrt((x - x_f) * (y_c - y));
133 float f4 = 1 - sqrt((x - x_f) * (y - y_f));
134 float s = (v1*f1 + v2*f2 + v3*f3+ v4*f4)/(f1 + f2 + f3 + f4);
135 *rv = (unsigned char)s;
139 /** interpolateBiLin: bi-linear interpolation function, see interpolate */
140 void interpolateBiLin(unsigned char *rv, float x, float y,
141 unsigned char* img, int width, int height,
142 unsigned char def,unsigned char N, unsigned char channel)
144 if (x < 0 || x >= width-1 || y < 0 || y >= height - 1) {
145 interpolateBiLinBorder(rv, x, y, img, width, height, def,N,channel);
147 int x_f = myfloor(x);
149 int y_f = myfloor(y);
151 short v1 = PIXN(img, x_c, y_c, width, height, N, channel);
152 short v2 = PIXN(img, x_c, y_f, width, height, N, channel);
153 short v3 = PIXN(img, x_f, y_c, width, height, N, channel);
154 short v4 = PIXN(img, x_f, y_f, width, height, N, channel);
155 float s = (v1*(x - x_f)+v3*(x_c - x))*(y - y_f) +
156 (v2*(x - x_f) + v4*(x_c - x))*(y_c - y);
157 *rv = (unsigned char)s;
162 /** interpolateLin: linear (only x) interpolation function, see interpolate */
163 void interpolateLin(unsigned char *rv, float x, float y,
164 unsigned char* img, int width, int height,
165 unsigned char def,unsigned char N, unsigned char channel)
167 int x_f = myfloor(x);
169 int y_n = myround(y);
170 float v1 = PIXELN(img, x_c, y_n, width, height, N, channel,def);
171 float v2 = PIXELN(img, x_f, y_n, width, height, N, channel,def);
172 float s = v1*(x - x_f) + v2*(x_c - x);
173 *rv = (unsigned char)s;
176 /** interpolateZero: nearest neighbor interpolation function, see interpolate */
177 void interpolateZero(unsigned char *rv, float x, float y,
178 unsigned char* img, int width, int height, unsigned char def,unsigned char N, unsigned char channel)
180 int x_n = myround(x);
181 int y_n = myround(y);
182 *rv = (unsigned char) PIXELN(img, x_n, y_n, width, height, N,channel,def);
187 * interpolateN: Bi-linear interpolation function for N channel image.
190 * rv: destination pixel (call by reference)
191 * x,y: the source coordinates in the image img. Note this
192 * are real-value coordinates, that's why we interpolate
194 * width,height: dimension of image
195 * N: number of channels
196 * channel: channel number (0..N-1)
197 * def: default value if coordinates are out of range
200 void interpolateN(unsigned char *rv, float x, float y,
201 unsigned char* img, int width, int height,
202 unsigned char N, unsigned char channel,
205 if (x < - 1 || x > width || y < -1 || y > height) {
208 int x_f = myfloor(x);
210 int y_f = myfloor(y);
212 short v1 = PIXELN(img, x_c, y_c, width, height, N, channel, def);
213 short v2 = PIXELN(img, x_c, y_f, width, height, N, channel, def);
214 short v3 = PIXELN(img, x_f, y_c, width, height, N, channel, def);
215 short v4 = PIXELN(img, x_f, y_f, width, height, N, channel, def);
216 float s = (v1*(x - x_f)+v3*(x_c - x))*(y - y_f) +
217 (v2*(x - x_f) + v4*(x_c - x))*(y_c - y);
218 *rv = (unsigned char)s;
224 * transformRGB: applies current transformation to frame
226 * td: private data structure of this filter
228 * 0 for failture, 1 for success
230 * The frame must be in RGB format
232 int transformRGB(TransformData* td)
235 int x = 0, y = 0, z = 0;
236 unsigned char *D_1, *D_2;
237 t = td->trans[td->current_trans];
241 float zm = 1.0-t.zoom/100;
242 float zcos_a = zm*cos(-t.alpha); // scaled cos
243 float zsin_a = zm*sin(-t.alpha); // scaled sin
244 float c_s_x = td->width_src/2.0;
245 float c_s_y = td->height_src/2.0;
246 float c_d_x = td->width_dest/2.0;
247 float c_d_y = td->height_dest/2.0;
249 /* for each pixel in the destination image we calc the source
250 * coordinate and make an interpolation:
251 * p_d = c_d + M(p_s - c_s) + t
252 * where p are the points, c the center coordinate,
253 * _s source and _d destination,
254 * t the translation, and M the rotation matrix
255 * p_s = M^{-1}(p_d - c_d - t) + c_s
258 if (fabs(t.alpha) > td->rotation_threshhold || t.zoom != 0) {
259 for (x = 0; x < td->width_dest; x++) {
260 for (y = 0; y < td->height_dest; y++) {
261 float x_d1 = (x - c_d_x);
262 float y_d1 = (y - c_d_y);
263 float x_s = zcos_a * x_d1
264 + zsin_a * y_d1 + c_s_x -t.x;
265 float y_s = -zsin_a * x_d1
266 + zcos_a * y_d1 + c_s_y -t.y;
267 for (z = 0; z < 3; z++) { // iterate over colors
268 unsigned char* dest = &D_2[(x + y * td->width_dest)*3+z];
269 interpolate(dest, x_s, y_s, D_1,
270 td->width_src, td->height_src,
271 td->crop ? 16 : *dest,3,z);
276 /* no rotation, just translation
277 *(also no interpolation, since no size change (so far)
279 int round_tx = myround(t.x);
280 int round_ty = myround(t.y);
281 for (x = 0; x < td->width_dest; x++) {
282 for (y = 0; y < td->height_dest; y++) {
283 for (z = 0; z < 3; z++) { // iterate over colors
284 short p = PIXELN(D_1, x - round_tx, y - round_ty,
285 td->width_src, td->height_src, 3, z, -1);
288 D_2[(x + y * td->width_dest)*3+z] = 16;
290 D_2[(x + y * td->width_dest)*3+z] = (unsigned char)p;
300 * transformYUV: applies current transformation to frame
303 * td: private data structure of this filter
305 * 0 for failture, 1 for success
307 * The frame must be in YUV format
309 int transformYUV(TransformData* td)
313 unsigned char *Y_1, *Y_2, *Cb_1, *Cb_2, *Cr_1, *Cr_2;
314 t = td->trans[td->current_trans];
318 Cb_1 = td->src + td->width_src * td->height_src;
319 Cb_2 = td->dest + td->width_dest * td->height_dest;
320 Cr_1 = td->src + 5*td->width_src * td->height_src/4;
321 Cr_2 = td->dest + 5*td->width_dest * td->height_dest/4;
322 float c_s_x = td->width_src/2.0;
323 float c_s_y = td->height_src/2.0;
324 float c_d_x = td->width_dest/2.0;
325 float c_d_y = td->height_dest/2.0;
327 float z = 1.0-t.zoom/100;
328 float zcos_a = z*cos(-t.alpha); // scaled cos
329 float zsin_a = z*sin(-t.alpha); // scaled sin
331 /* for each pixel in the destination image we calc the source
332 * coordinate and make an interpolation:
333 * p_d = c_d + M(p_s - c_s) + t
334 * where p are the points, c the center coordinate,
335 * _s source and _d destination,
336 * t the translation, and M the rotation and scaling matrix
337 * p_s = M^{-1}(p_d - c_d - t) + c_s
339 /* Luminance channel */
340 if (fabs(t.alpha) > td->rotation_threshhold || t.zoom != 0) {
341 for (x = 0; x < td->width_dest; x++) {
342 for (y = 0; y < td->height_dest; y++) {
343 float x_d1 = (x - c_d_x);
344 float y_d1 = (y - c_d_y);
345 float x_s = zcos_a * x_d1
346 + zsin_a * y_d1 + c_s_x -t.x;
347 float y_s = -zsin_a * x_d1
348 + zcos_a * y_d1 + c_s_y -t.y;
349 unsigned char* dest = &Y_2[x + y * td->width_dest];
350 interpolate(dest, x_s, y_s, Y_1,
351 td->width_src, td->height_src,
352 td->crop ? 16 : *dest,1,0);
356 /* no rotation, no zooming, just translation
357 *(also no interpolation, since no size change)
359 int round_tx = myround(t.x);
360 int round_ty = myround(t.y);
361 for (x = 0; x < td->width_dest; x++) {
362 for (y = 0; y < td->height_dest; y++) {
363 short p = PIXEL(Y_1, x - round_tx, y - round_ty,
364 td->width_src, td->height_src, -1);
367 Y_2[x + y * td->width_dest] = 16;
369 Y_2[x + y * td->width_dest] = (unsigned char)p;
376 int ws2 = td->width_src/2;
377 int wd2 = td->width_dest/2;
378 int hs2 = td->height_src/2;
379 int hd2 = td->height_dest/2;
380 if (fabs(t.alpha) > td->rotation_threshhold || t.zoom != 0) {
381 for (x = 0; x < wd2; x++) {
382 for (y = 0; y < hd2; y++) {
383 float x_d1 = x - (c_d_x)/2;
384 float y_d1 = y - (c_d_y)/2;
385 float x_s = zcos_a * x_d1
386 + zsin_a * y_d1 + (c_s_x -t.x)/2;
387 float y_s = -zsin_a * x_d1
388 + zcos_a * y_d1 + (c_s_y -t.y)/2;
389 unsigned char* dest = &Cr_2[x + y * wd2];
390 interpolate(dest, x_s, y_s, Cr_1, ws2, hs2,
391 td->crop ? 128 : *dest,1,0);
392 dest = &Cb_2[x + y * wd2];
393 interpolate(dest, x_s, y_s, Cb_1, ws2, hs2,
394 td->crop ? 128 : *dest,1,0);
397 } else { // no rotation, no zoom, no interpolation, just translation
398 int round_tx2 = myround(t.x/2.0);
399 int round_ty2 = myround(t.y/2.0);
400 for (x = 0; x < wd2; x++) {
401 for (y = 0; y < hd2; y++) {
402 short cr = PIXEL(Cr_1, x - round_tx2, y - round_ty2,
404 short cb = PIXEL(Cb_1, x - round_tx2, y - round_ty2,
408 Cr_2[x + y * wd2] = 128;
409 Cb_2[x + y * wd2] = 128;
412 Cr_2[x + y * wd2] = (unsigned char)cr;
413 Cb_2[x + y * wd2] = (unsigned char)cb;
423 * preprocess_transforms: does smoothing, relative to absolute conversion,
424 * and cropping of too large transforms.
425 * This is actually the core algorithm for canceling the jiggle in the
426 * movie. We perform a low-pass filter in terms of transformation size.
427 * This enables still camera movement, but in a smooth fasion.
430 * td: tranform private data structure
432 * 1 for success and 0 for failture
436 * td->trans will be modified
438 int preprocess_transforms(TransformData* td)
440 Transform* ts = td->trans;
443 if (td->trans_len < 1)
446 mlt_log_debug(NULL,"Preprocess transforms:");
448 if (td->smoothing>0) {
450 Transform* ts2 = malloc(sizeof(Transform) * td->trans_len);
451 memcpy(ts2, ts, sizeof(Transform) * td->trans_len);
453 /* we will do a sliding average with minimal update
454 * \hat x_{n/2} = x_1+x_2 + .. + x_n
455 * \hat x_{n/2+1} = x_2+x_3 + .. + x_{n+1} = x_{n/2} - x_1 + x_{n+1}
458 int s = td->smoothing * 2 + 1;
459 Transform null = null_transform();
460 /* avg is the average over [-smoothing, smoothing] transforms
461 around the current point */
463 /* avg2 is a sliding average over the filtered signal! (only to past)
464 * with smoothing * 10 horizont to kill offsets */
465 Transform avg2 = null_transform();
466 double tau = 1.0/(3 * s);
467 /* initialise sliding sum with hypothetic sum centered around
468 * -1st element. We have two choices:
469 * a) assume the camera is not moving at the beginning
470 * b) assume that the camera moves and we use the first transforms
472 Transform s_sum = null;
473 for (i = 0; i < td->smoothing; i++){
474 s_sum = add_transforms(&s_sum, i < td->trans_len ? &ts2[i]:&null);
476 mult_transform(&s_sum, 2); // choice b (comment out for choice a)
478 for (i = 0; i < td->trans_len; i++) {
479 Transform* old = ((i - td->smoothing - 1) < 0)
480 ? &null : &ts2[(i - td->smoothing - 1)];
481 Transform* new = ((i + td->smoothing) >= td->trans_len)
482 ? &null : &ts2[(i + td->smoothing)];
483 s_sum = sub_transforms(&s_sum, old);
484 s_sum = add_transforms(&s_sum, new);
486 avg = mult_transform(&s_sum, 1.0/s);
489 * meaning high frequency must be transformed away
491 ts[i] = sub_transforms(&ts2[i], &avg);
492 /* kill accumulating offset in the filtered signal*/
493 avg2 = add_transforms_(mult_transform(&avg2, 1 - tau),
494 mult_transform(&ts[i], tau));
495 ts[i] = sub_transforms(&ts[i], &avg2);
497 if (0 /*verbose*/ ) {
498 mlt_log_warning(NULL,"s_sum: %5lf %5lf %5lf, ts: %5lf, %5lf, %5lf\n",
499 s_sum.x, s_sum.y, s_sum.alpha,
500 ts[i].x, ts[i].y, ts[i].alpha);
501 mlt_log_warning(NULL,
502 " avg: %5lf, %5lf, %5lf avg2: %5lf, %5lf, %5lf",
503 avg.x, avg.y, avg.alpha,
504 avg2.x, avg2.y, avg2.alpha);
513 for (i = 0; i < td->trans_len; i++) {
514 ts[i] = mult_transform(&ts[i], -1);
518 /* relative to absolute */
521 for (i = 1; i < td->trans_len; i++) {
523 mlt_log_warning(NULL, "shift: %5lf %5lf %lf \n",
524 t.x, t.y, t.alpha *180/M_PI);
526 ts[i] = add_transforms(&ts[i], &t);
530 /* crop at maximal shift */
531 if (td->maxshift != -1)
532 for (i = 0; i < td->trans_len; i++) {
533 ts[i].x = TC_CLAMP(ts[i].x, -td->maxshift, td->maxshift);
534 ts[i].y = TC_CLAMP(ts[i].y, -td->maxshift, td->maxshift);
536 if (td->maxangle != - 1.0)
537 for (i = 0; i < td->trans_len; i++)
538 ts[i].alpha = TC_CLAMP(ts[i].alpha, -td->maxangle, td->maxangle);
541 * cheap algo is to only consider transformations
542 * uses cleaned max and min
544 if (td->optzoom != 0 && td->trans_len > 1){
545 Transform min_t, max_t;
546 cleanmaxmin_xy_transform(ts, td->trans_len, 10, &min_t, &max_t);
547 // the zoom value only for x
548 double zx = 2*TC_MAX(max_t.x,fabs(min_t.x))/td->width_src;
549 // the zoom value only for y
550 double zy = 2*TC_MAX(max_t.y,fabs(min_t.y))/td->height_src;
551 td->zoom += 100* TC_MAX(zx,zy); // use maximum
552 mlt_log_debug(NULL,"Final zoom: %lf\n", td->zoom);
555 /* apply global zoom */
557 for (i = 0; i < td->trans_len; i++)
558 ts[i].zoom += td->zoom;
565 * transform_init: Initialize this instance of the module. See
566 * tcmodule-data.h for function details.
571 static int transform_init(TCModuleInstance *self, uint32_t features)
574 TransformData* td = NULL;
575 TC_MODULE_SELF_CHECK(self, "init");
576 TC_MODULE_INIT_CHECK(self, MOD_FEATURES, features);
578 td = tc_zalloc(sizeof(TransformData));
580 tc_log_error(MOD_NAME, "init: out of memory!");
585 tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP);
593 * transform_configure: Configure this instance of the module. See
594 * tcmodule-data.h for function details.
596 int transform_configure(TransformData *self,int width,int height, mlt_image_format pixelformat, unsigned char* image ,Transform* tx,int trans_len)
598 TransformData *td = self;
600 /**** Initialise private data structure */
602 /* td->framesize = td->vob->im_v_width *
603 * MAX_PLANES * sizeof(char) * 2 * td->vob->im_v_height * 2;
605 // rgb24 = w*h*3 , yuv420p = w* h* 3/2
606 td->framesize_src = width*height*(pixelformat==mlt_image_rgb24 ? 3 : (3.0/2.0));
607 td->src = malloc(td->framesize_src); /* FIXME */
608 if (td->src == NULL) {
609 mlt_log_error(NULL,"tc_malloc failed\n");
613 td->width_src = width;
614 td->height_src = height;
616 /* Todo: in case we can scale the images, calc new size later */
617 td->width_dest = width;
618 td->height_dest = height;
619 td->framesize_dest = td->framesize_src;
623 td->trans_len = trans_len;
624 td->current_trans = 0;
625 td->warned_transform_end = 0;
628 // set from filter td->maxshift = -1;
629 // set from filter td->maxangle = -1;
632 // set from filter td->crop = 0;
633 // set from filter td->relative = 1;
634 // set from filter td->invert = 0;
635 // set from filter td->smoothing = 10;
637 td->rotation_threshhold = 0.25/(180/M_PI);
639 // set from filter td->zoom = 0;
640 // set from filter td->optzoom = 1;
641 // set from filter td->interpoltype = 2; // bi-linear
642 // set from filter td->sharpen = 0.8;
644 td->interpoltype = TC_MIN(td->interpoltype,4);
646 mlt_log_debug(NULL, "Image Transformation/Stabilization Settings:\n");
647 mlt_log_debug(NULL, " smoothing = %d\n", td->smoothing);
648 mlt_log_debug(NULL, " maxshift = %d\n", td->maxshift);
649 mlt_log_debug(NULL, " maxangle = %f\n", td->maxangle);
650 mlt_log_debug(NULL, " crop = %s\n",
651 td->crop ? "Black" : "Keep");
652 mlt_log_debug(NULL, " relative = %s\n",
653 td->relative ? "True": "False");
654 mlt_log_debug(NULL, " invert = %s\n",
655 td->invert ? "True" : "False");
656 mlt_log_debug(NULL, " zoom = %f\n", td->zoom);
657 mlt_log_debug(NULL, " optzoom = %s\n",
658 td->optzoom ? "On" : "Off");
659 mlt_log_debug(NULL, " interpol = %s\n",
660 interpoltypes[td->interpoltype]);
661 mlt_log_debug(NULL, " sharpen = %f\n", td->sharpen);
664 if (td->maxshift > td->width_dest/2
665 ) td->maxshift = td->width_dest/2;
666 if (td->maxshift > td->height_dest/2)
667 td->maxshift = td->height_dest/2;
669 if (!preprocess_transforms(td)) {
670 mlt_log_error(NULL,"error while preprocessing transforms!");
674 switch(td->interpoltype){
675 case 0: interpolate = &interpolateZero; break;
676 case 1: interpolate = &interpolateLin; break;
677 case 2: interpolate = &interpolateBiLin; break;
678 case 3: interpolate = &interpolateSqr; break;
679 case 4: interpolate = &interpolateBiCub; break;
680 default: interpolate = &interpolateBiLin;
688 * transform_filter_video: performs the transformation of frames
689 * See tcmodule-data.h for function details.
691 int transform_filter_video(TransformData *self,
692 unsigned char *frame,mlt_image_format pixelformat)
694 TransformData *td = self;
698 memcpy(td->src, frame, td->framesize_src);
699 if (td->current_trans >= td->trans_len) {
700 td->current_trans = td->trans_len-1;
701 if(!td->warned_transform_end)
702 mlt_log_warning(NULL,"not enough transforms found, use last transformation!\n");
703 td->warned_transform_end = 1;
706 if (pixelformat == mlt_image_rgb24 ) {
708 } else if (pixelformat == mlt_image_yuv420p) {
711 mlt_log_error(NULL,"unsupported Codec: %i\n", pixelformat);