]> git.sesse.net Git - mlt/blob - src/modules/vid.stab/filter_transform.cpp
Mark vid.stab module as GPL
[mlt] / src / modules / vid.stab / filter_transform.cpp
1 /*
2  * filter_transform.cpp
3  * Copyright (C) 2013
4  * Marco Gittler <g.marco@freenet.de>
5  * Jakub Ksiezniak <j.ksiezniak@gmail.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software Foundation,
19  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21
22 extern "C"
23 {
24 #include <vid.stab/libvidstab.h>
25 #include <framework/mlt.h>
26 #include <framework/mlt_animation.h>
27 }
28
29 #include <string.h>
30 #include <assert.h>
31 #include <sstream>
32 #include "common.h"
33
34 #define FILTER_NAME "vid.stab.transform"
35
36 typedef struct
37 {
38         bool initialized;
39         VSTransformData td;
40         VSTransformations trans;
41
42         void *parent;
43 } TransformData;
44
45 int lm_deserialize(LocalMotions *lms, mlt_property property)
46 {
47         std::istringstream iss(mlt_property_get_string(property));
48         vs_vector_init(lms, 0);
49
50         while (iss.good())
51         {
52                 LocalMotion lm;
53                 iss >> lm.v.x >> lm.v.y >> lm.f.x >> lm.f.y >> lm.f.size >> lm.contrast >> lm.match;
54                 if (iss.fail())
55                 {
56                         break;
57                 }
58                 vs_vector_append_dup(lms, &lm, sizeof(lm));
59         }
60         return 0;
61 }
62
63 int vectors_deserialize(mlt_animation anim, VSManyLocalMotions *mlms)
64 {
65         int error = 0;
66         mlt_animation_item_s item;
67         item.property = mlt_property_init();
68
69         vs_vector_init(mlms, 1024); // initial number of frames, but it will be increased
70
71         int length = mlt_animation_get_length(anim);
72         for (int i = 0; i < length; ++i)
73         {
74                 LocalMotions lms;
75
76                 // read lms
77                 mlt_animation_get_item(anim, &item, i + 1);
78                 if ((error = lm_deserialize(&lms, item.property)))
79                 {
80                         break;
81                 }
82
83                 vs_vector_set_dup(mlms, i, &lms, sizeof(LocalMotions));
84         }
85
86         mlt_property_close(item.property);
87         return error;
88 }
89
90 inline int initialize_transforms(TransformData *data, int *width, int *height, mlt_image_format *format,
91                 mlt_properties properties, char* interps)
92 {
93         VSPixelFormat pf = convertImageFormat(*format);
94         VSFrameInfo fi_src, fi_dst;
95         vsFrameInfoInit(&fi_src, *width, *height, pf);
96         vsFrameInfoInit(&fi_dst, *width, *height, pf);
97
98         VSTransformConfig conf = vsTransformGetDefaultConfig(FILTER_NAME);
99         conf.smoothing = mlt_properties_get_int(properties, "smoothing");
100         conf.maxShift = mlt_properties_get_int(properties, "maxshift");
101         conf.maxAngle = mlt_properties_get_double(properties, "maxangle");
102         conf.crop = (VSBorderType) mlt_properties_get_int(properties, "crop");
103         conf.zoom = mlt_properties_get_int(properties, "zoom");
104         conf.optZoom = mlt_properties_get_int(properties, "optzoom");
105         conf.zoomSpeed = mlt_properties_get_double(properties, "zoomspeed");
106         conf.relative = mlt_properties_get_int(properties, "relative");
107         conf.invert = mlt_properties_get_int(properties, "invert");
108         if (mlt_properties_get_int(properties, "tripod") != 0)
109         {
110                 // Virtual tripod mode: relative=False, smoothing=0
111                 conf.relative = 0;
112                 conf.smoothing = 0;
113         }
114
115         // by default a bilinear interpolation is selected
116         conf.interpolType = VS_BiLinear;
117         if (strcmp(interps, "nearest") == 0 || strcmp(interps, "neighbor") == 0)
118                 conf.interpolType = VS_Zero;
119         else if (strcmp(interps, "tiles") == 0 || strcmp(interps, "fast_bilinear") == 0)
120                 conf.interpolType = VS_Linear;
121
122         vsTransformDataInit(&data->td, &conf, &fi_src, &fi_dst);
123
124         vsTransformationsInit(&data->trans);
125
126         // load transformations
127         mlt_animation animation = mlt_animation_new();
128         char* strAnim = mlt_properties_get(properties, "vectors");
129         if (mlt_animation_parse(animation, strAnim, 0, 0, NULL))
130         {
131                 mlt_log_warning(NULL, "parse failed\n");
132                 return 1;
133         }
134
135         VSManyLocalMotions mlms;
136         if (vectors_deserialize(animation, &mlms))
137         {
138                 return 1;
139         }
140
141         mlt_animation_close(animation);
142
143         vsLocalmotions2Transforms(&data->td, &mlms, &data->trans);
144         vsPreprocessTransforms(&data->td, &data->trans);
145         return 0;
146 }
147
148 void clear_transforms(TransformData *data)
149 {
150         if (data->initialized)
151         {
152                 vsTransformDataCleanup(&data->td);
153                 vsTransformationsCleanup(&data->trans);
154         }
155 }
156
157 static int get_image(mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable)
158 {
159         int error = 0;
160         mlt_filter filter = (mlt_filter) mlt_frame_pop_service(frame);
161         mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
162
163         *format = mlt_image_yuv420p;
164         TransformData *data = static_cast<TransformData*>(filter->child);
165
166         error = mlt_frame_get_image(frame, image, format, width, height, 1);
167         if (!error)
168         {
169                 // Service locks are for concurrency control
170                 mlt_service_lock(MLT_FILTER_SERVICE(filter));
171
172                 // Handle signal from app to re-init data
173                 if (mlt_properties_get_int(properties, "refresh"))
174                 {
175                         mlt_properties_set(properties, "refresh", NULL);
176                         clear_transforms(data);
177                         data->initialized = false;
178                 }
179
180                 if (!data->initialized)
181                 {
182                         char *interps = mlt_properties_get(MLT_FRAME_PROPERTIES(frame), "rescale.interp");
183                         initialize_transforms(data, width, height, format, properties, interps);
184                         data->initialized = true;
185                 }
186
187                 VSTransformData* td = &data->td;
188                 VSFrame vsFrame;
189                 vsFrameFillFromBuffer(&vsFrame, *image, vsTransformGetSrcFrameInfo(td));
190
191                 // transform frame
192                 data->trans.current = mlt_filter_get_position(filter, frame);
193                 vsTransformPrepare(td, &vsFrame, &vsFrame);
194                 VSTransform t = vsGetNextTransform(td, &data->trans);
195                 vsDoTransform(td, t);
196                 vsTransformFinish(td);
197
198                 mlt_service_unlock(MLT_FILTER_SERVICE(filter));
199         }
200
201         return error;
202 }
203
204 static mlt_frame process_filter(mlt_filter filter, mlt_frame frame)
205 {
206         mlt_frame_push_service(frame, filter);
207         mlt_frame_push_get_image(frame, get_image);
208         return frame;
209 }
210
211 static void close_filter(mlt_filter filter)
212 {
213         TransformData *data = static_cast<TransformData*>(filter->child);
214         if (data)
215         {
216                 clear_transforms(data);
217                 delete data;
218                 filter->child = NULL;
219         }
220 }
221
222 extern "C"
223 {
224
225 mlt_filter filter_transform_init(mlt_profile profile, mlt_service_type type, const char *id, char *arg)
226 {
227         mlt_filter filter = NULL;
228
229         TransformData *data = new TransformData;
230         memset(data, 0, sizeof(TransformData));
231
232         if ((filter = mlt_filter_new()))
233         {
234                 filter->process = process_filter;
235                 filter->close = close_filter;
236                 filter->child = data;
237
238                 data->parent = filter;
239
240                 mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
241
242                 // properties for transform
243                 mlt_properties_set(properties, "smoothing", "10");
244                 mlt_properties_set(properties, "maxshift", "-1");
245                 mlt_properties_set(properties, "maxangle", "-1");
246                 mlt_properties_set(properties, "crop", "0");
247                 mlt_properties_set(properties, "invert", "0");
248                 mlt_properties_set(properties, "relative", "1");
249                 mlt_properties_set(properties, "zoom", "0");
250                 mlt_properties_set(properties, "optzoom", "1");
251                 mlt_properties_set(properties, "zoomspeed", "0.25");
252
253                 return filter;
254         }
255
256         delete data;
257         return NULL;
258 }
259
260 }