]> git.sesse.net Git - mlt/blob - src/modules/vid.stab/filter_transform.cpp
3b23372417142f7cab15a46cc533125ba21de992
[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.relative = mlt_properties_get_int(properties, "relative");
106         conf.invert = mlt_properties_get_int(properties, "invert");
107         if (mlt_properties_get_int(properties, "tripod") != 0)
108         {
109                 // Virtual tripod mode: relative=False, smoothing=0
110                 conf.relative = 0;
111                 conf.smoothing = 0;
112         }
113
114         // by default a bilinear interpolation is selected
115         conf.interpolType = VS_BiLinear;
116         if (strcmp(interps, "nearest") == 0 || strcmp(interps, "neighbor") == 0)
117                 conf.interpolType = VS_Zero;
118         else if (strcmp(interps, "tiles") == 0 || strcmp(interps, "fast_bilinear") == 0)
119                 conf.interpolType = VS_Linear;
120
121         vsTransformDataInit(&data->td, &conf, &fi_src, &fi_dst);
122
123         vsTransformationsInit(&data->trans);
124
125         // load transformations
126         mlt_animation animation = mlt_animation_new();
127         char* strAnim = mlt_properties_get(properties, "vectors");
128         if (mlt_animation_parse(animation, strAnim, 0, 0, NULL))
129         {
130                 mlt_log_warning(NULL, "parse failed\n");
131                 return 1;
132         }
133
134         VSManyLocalMotions mlms;
135         if (vectors_deserialize(animation, &mlms))
136         {
137                 return 1;
138         }
139
140         mlt_animation_close(animation);
141
142         vsLocalmotions2Transforms(&data->td, &mlms, &data->trans);
143         vsPreprocessTransforms(&data->td, &data->trans);
144         return 0;
145 }
146
147 void clear_transforms(TransformData *data)
148 {
149         if (data->initialized)
150         {
151                 vsTransformDataCleanup(&data->td);
152                 vsTransformationsCleanup(&data->trans);
153         }
154 }
155
156 static int get_image(mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable)
157 {
158         int error = 0;
159         mlt_filter filter = (mlt_filter) mlt_frame_pop_service(frame);
160         mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
161
162         *format = mlt_image_yuv420p;
163         TransformData *data = static_cast<TransformData*>(filter->child);
164
165         error = mlt_frame_get_image(frame, image, format, width, height, 1);
166         if (!error)
167         {
168                 // Service locks are for concurrency control
169                 mlt_service_lock(MLT_FILTER_SERVICE(filter));
170
171                 // Handle signal from app to re-init data
172                 if (mlt_properties_get_int(properties, "refresh"))
173                 {
174                         mlt_properties_set(properties, "refresh", NULL);
175                         clear_transforms(data);
176                         data->initialized = false;
177                 }
178
179                 if (!data->initialized)
180                 {
181                         char *interps = mlt_properties_get(MLT_FRAME_PROPERTIES(frame), "rescale.interp");
182                         initialize_transforms(data, width, height, format, properties, interps);
183                         data->initialized = true;
184                 }
185
186                 VSTransformData* td = &data->td;
187                 VSFrame vsFrame;
188                 vsFrameFillFromBuffer(&vsFrame, *image, vsTransformGetSrcFrameInfo(td));
189
190                 // transform frame
191                 data->trans.current = mlt_filter_get_position(filter, frame);
192                 vsTransformPrepare(td, &vsFrame, &vsFrame);
193                 VSTransform t = vsGetNextTransform(td, &data->trans);
194                 vsDoTransform(td, t);
195                 vsTransformFinish(td);
196
197                 mlt_service_unlock(MLT_FILTER_SERVICE(filter));
198         }
199
200         return error;
201 }
202
203 static mlt_frame process_filter(mlt_filter filter, mlt_frame frame)
204 {
205         mlt_frame_push_service(frame, filter);
206         mlt_frame_push_get_image(frame, get_image);
207         return frame;
208 }
209
210 static void close_filter(mlt_filter filter)
211 {
212         TransformData *data = static_cast<TransformData*>(filter->child);
213         if (data)
214         {
215                 clear_transforms(data);
216                 delete data;
217                 filter->child = NULL;
218         }
219 }
220
221 extern "C"
222 {
223
224 mlt_filter filter_transform_init(mlt_profile profile, mlt_service_type type, const char *id, char *arg)
225 {
226         mlt_filter filter = NULL;
227
228         TransformData *data = new TransformData;
229         memset(data, 0, sizeof(TransformData));
230
231         if ((filter = mlt_filter_new()))
232         {
233                 filter->process = process_filter;
234                 filter->close = close_filter;
235                 filter->child = data;
236
237                 data->parent = filter;
238
239                 mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
240
241                 // properties for transform
242                 mlt_properties_set(properties, "smoothing", "10");
243                 mlt_properties_set(properties, "maxshift", "-1");
244                 mlt_properties_set(properties, "maxangle", "-1");
245                 mlt_properties_set(properties, "crop", "0");
246                 mlt_properties_set(properties, "invert", "0");
247                 mlt_properties_set(properties, "relative", "1");
248                 mlt_properties_set(properties, "zoom", "0");
249                 mlt_properties_set(properties, "optzoom", "1");
250
251                 return filter;
252         }
253
254         delete data;
255         return NULL;
256 }
257
258 }