4 * Marco Gittler <g.marco@freenet.de>
5 * Jakub Ksiezniak <j.ksiezniak@gmail.com>
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.
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.
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.
24 #include <vid.stab/libvidstab.h>
25 #include <framework/mlt.h>
26 #include <framework/mlt_animation.h>
35 typedef struct _stab_data
38 mlt_animation animation;
44 VSTransformations trans;
48 char* vectors_serializer(mlt_animation animation, int length)
50 return mlt_animation_serialize(animation);
53 char* lm_serializer(LocalMotions *lms, int length)
55 std::ostringstream oss;
56 int size = vs_vector_size(lms);
57 for (int i = 0; i < size; ++i)
59 LocalMotion* lm = (LocalMotion*) vs_vector_get(lms, i);
60 oss << lm->v.x << ' ';
61 oss << lm->v.y << ' ';
62 oss << lm->f.x << ' ';
63 oss << lm->f.y << ' ';
64 oss << lm->f.size << ' ';
65 oss << lm->contrast << ' ';
66 oss << lm->match << ' ';
68 return strdup(oss.str().c_str());
71 int lm_deserialize(LocalMotions *lms, mlt_property property)
73 std::istringstream iss(mlt_property_get_string(property));
74 vs_vector_init(lms, 0);
79 iss >> lm.v.x >> lm.v.y >> lm.f.x >> lm.f.y >> lm.f.size >> lm.contrast >> lm.match;
84 vs_vector_append_dup(lms, &lm, sizeof(lm));
89 void lm_destructor(void *lms)
91 vs_vector_del(static_cast<VSVector*>(lms));
94 static void serialize_localmotions(StabData* data, LocalMotions &vectors, mlt_position pos)
96 mlt_animation_item_s item;
98 // Initialize animation item
100 item.frame = data->md.frameNum;
101 item.keyframe_type = mlt_keyframe_discrete;
102 item.property = mlt_property_init();
104 mlt_property_set_data(item.property, &vectors, 1, lm_destructor, (mlt_serialiser) lm_serializer);
105 mlt_animation_insert(data->animation, &item);
106 mlt_property_close(item.property);
109 int vectors_deserialize(mlt_animation anim, VSManyLocalMotions *mlms)
112 mlt_animation_item_s item;
113 item.property = mlt_property_init();
115 vs_vector_init(mlms, 1024); // initial number of frames, but it will be increased
117 int length = mlt_animation_get_length(anim);
118 for (int i = 0; i < length; ++i)
123 mlt_animation_get_item(anim, &item, i + 1);
124 if ((error = lm_deserialize(&lms, item.property)))
129 vs_vector_set_dup(mlms, i, &lms, sizeof(LocalMotions));
132 mlt_property_close(item.property);
136 void destroy_transforms(TransformData *data)
140 vsTransformDataCleanup(&data->td);
141 vsTransformationsCleanup(&data->trans);
146 TransformData* initialize_transforms(int *width, int *height, mlt_image_format *format,
147 mlt_properties properties, const char* interps)
149 TransformData *data = new TransformData;
150 memset(data, 0, sizeof(TransformData));
152 VSPixelFormat pf = convertImageFormat(*format);
153 VSFrameInfo fi_src, fi_dst;
154 vsFrameInfoInit(&fi_src, *width, *height, pf);
155 vsFrameInfoInit(&fi_dst, *width, *height, pf);
157 const char* filterName = mlt_properties_get(properties, "mlt_service");
159 VSTransformConfig conf = vsTransformGetDefaultConfig(filterName);
160 conf.smoothing = mlt_properties_get_int(properties, "smoothing");
161 conf.maxShift = mlt_properties_get_int(properties, "maxshift");
162 conf.maxAngle = mlt_properties_get_double(properties, "maxangle");
163 conf.crop = (VSBorderType) mlt_properties_get_int(properties, "crop");
164 conf.zoom = mlt_properties_get_int(properties, "zoom");
165 conf.optZoom = mlt_properties_get_int(properties, "optzoom");
166 conf.zoomSpeed = mlt_properties_get_double(properties, "zoomspeed");
167 conf.relative = mlt_properties_get_int(properties, "relative");
168 conf.invert = mlt_properties_get_int(properties, "invert");
169 if (mlt_properties_get_int(properties, "tripod") != 0)
171 // Virtual tripod mode: relative=False, smoothing=0
176 // by default a bilinear interpolation is selected
177 conf.interpolType = VS_BiLinear;
178 if (strcmp(interps, "nearest") == 0 || strcmp(interps, "neighbor") == 0)
179 conf.interpolType = VS_Zero;
180 else if (strcmp(interps, "tiles") == 0 || strcmp(interps, "fast_bilinear") == 0)
181 conf.interpolType = VS_Linear;
183 vsTransformDataInit(&data->td, &conf, &fi_src, &fi_dst);
184 vsTransformationsInit(&data->trans);
186 // load transformations
187 mlt_animation animation = mlt_animation_new();
188 char* strAnim = mlt_properties_get(properties, "vectors");
189 if (mlt_animation_parse(animation, strAnim, 0, 0, NULL))
191 mlt_log_warning(NULL, "parse failed\n");
192 mlt_animation_close(animation);
193 destroy_transforms(data);
197 VSManyLocalMotions mlms;
198 if (vectors_deserialize(animation, &mlms))
200 mlt_animation_close(animation);
201 destroy_transforms(data);
205 mlt_animation_close(animation);
207 vsLocalmotions2Transforms(&data->td, &mlms, &data->trans);
208 vsPreprocessTransforms(&data->td, &data->trans);
212 int get_image_and_transform(mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable)
215 mlt_filter filter = (mlt_filter) mlt_frame_pop_service(frame);
216 mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
218 *format = mlt_image_yuv420p;
220 error = mlt_frame_get_image(frame, image, format, width, height, 1);
223 // Service locks are for concurrency control
224 mlt_service_lock(MLT_FILTER_SERVICE(filter));
226 TransformData *data = static_cast<TransformData*>(mlt_properties_get_data(properties, "_transform_data", NULL));
228 // Handle signal from app to re-init data
229 if (mlt_properties_get_int(properties, "refresh"))
231 mlt_properties_set(properties, "refresh", NULL);
232 destroy_transforms(data);
238 const char *interps = mlt_properties_get(MLT_FRAME_PROPERTIES(frame), "rescale.interp");
239 data = initialize_transforms(width, height, format, properties, interps);
241 mlt_service_unlock(MLT_FILTER_SERVICE(filter));
242 return 1; // return error code
244 mlt_properties_set_data(properties, "_transform_data", data, 0, (mlt_destructor) destroy_transforms, NULL);
247 VSTransformData* td = &data->td;
249 vsFrameFillFromBuffer(&vsFrame, *image, vsTransformGetSrcFrameInfo(td));
252 data->trans.current = mlt_filter_get_position(filter, frame);
253 vsTransformPrepare(td, &vsFrame, &vsFrame);
254 VSTransform t = vsGetNextTransform(td, &data->trans);
255 vsDoTransform(td, t);
256 vsTransformFinish(td);
258 mlt_service_unlock(MLT_FILTER_SERVICE(filter));
264 static StabData* init_detect(mlt_properties properties, mlt_image_format *format, int *width, int *height)
266 StabData *data = new StabData;
267 memset(data, 0, sizeof(StabData));
268 data->animation = mlt_animation_new();
270 VSPixelFormat pf = convertImageFormat(*format);
272 vsFrameInfoInit(&fi, *width, *height, pf);
274 const char* filterName = mlt_properties_get(properties, "mlt_service");
276 VSMotionDetectConfig conf = vsMotionDetectGetDefaultConfig(filterName);
277 conf.shakiness = mlt_properties_get_int(properties, "shakiness");
278 conf.accuracy = mlt_properties_get_int(properties, "accuracy");
279 conf.stepSize = mlt_properties_get_int(properties, "stepsize");
280 conf.algo = mlt_properties_get_int(properties, "algo");
281 conf.contrastThreshold = mlt_properties_get_double(properties, "mincontrast");
282 conf.show = mlt_properties_get_int(properties, "show");
283 conf.virtualTripod = mlt_properties_get_int(properties, "tripod");
284 vsMotionDetectInit(&data->md, &conf, &fi);
286 // add vectors to properties
287 mlt_properties_set_data(properties, "vectors", data->animation, 1, (mlt_destructor) mlt_animation_close,
288 (mlt_serialiser) vectors_serializer);
292 void destroy_detect(StabData *data)
296 vsMotionDetectionCleanup(&data->md);
301 int get_image_and_detect(mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable)
303 mlt_filter filter = (mlt_filter) mlt_frame_pop_service(frame);
304 mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
306 *format = mlt_image_yuv420p;
308 writable = writable || mlt_properties_get_int(properties, "show") ? 1 : 0;
310 int error = mlt_frame_get_image(frame, image, format, width, height, writable);
313 // Service locks are for concurrency control
314 mlt_service_lock(MLT_FILTER_SERVICE(filter));
316 StabData *data = static_cast<StabData*>(mlt_properties_get_data(properties, "_stab_data", NULL));
319 data = init_detect(properties, format, width, height);
320 mlt_properties_set_data(properties, "_stab_data", data, 0, (mlt_destructor) destroy_detect, NULL);
323 VSMotionDetect* md = &data->md;
324 LocalMotions localmotions;
326 vsFrameFillFromBuffer(&vsFrame, *image, &md->fi);
328 // detect and save motions
329 vsMotionDetection(md, &localmotions, &vsFrame);
330 mlt_position pos = mlt_filter_get_position( filter, frame );
331 serialize_localmotions(data, localmotions, pos);
333 mlt_service_unlock(MLT_FILTER_SERVICE(filter));
339 static mlt_frame process_filter(mlt_filter filter, mlt_frame frame)
341 mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
342 mlt_get_image vidstab_get_image = (mlt_get_image) mlt_properties_get_data( properties, "_vidstab_get_image", NULL );
345 mlt_position pos = mlt_filter_get_position(filter, frame);
346 mlt_position length = mlt_filter_get_length2(filter, frame) - 1;
349 mlt_properties_set_data(properties, "_vidstab_get_image", NULL, 0, NULL, NULL);
353 if(vidstab_get_image == NULL)
355 if(mlt_properties_get(properties, "vectors") == NULL)
357 // vectors are NULL, so use a detect filter
358 vidstab_get_image = get_image_and_detect;
360 // found vectors, so use a transform filter
361 vidstab_get_image = get_image_and_transform;
364 mlt_properties_set_data( properties, "_vidstab_get_image", (void*)vidstab_get_image, 0, NULL, NULL );
367 mlt_frame_push_service(frame, filter);
368 mlt_frame_push_get_image(frame, vidstab_get_image);
375 mlt_filter filter_vidstab_init(mlt_profile profile, mlt_service_type type,
376 const char *id, char *arg)
378 mlt_filter filter = mlt_filter_new();
382 filter->process = process_filter;
384 mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
386 //properties for stabilize
387 mlt_properties_set(properties, "shakiness", "4");
388 mlt_properties_set(properties, "accuracy", "4");
389 mlt_properties_set(properties, "stepsize", "6");
390 mlt_properties_set(properties, "algo", "1");
391 mlt_properties_set(properties, "mincontrast", "0.3");
392 mlt_properties_set(properties, "show", "0");
393 mlt_properties_set(properties, "tripod", "0");
395 // properties for transform
396 mlt_properties_set(properties, "smoothing", "15");
397 mlt_properties_set(properties, "maxshift", "-1");
398 mlt_properties_set(properties, "maxangle", "-1");
399 mlt_properties_set(properties, "crop", "0");
400 mlt_properties_set(properties, "invert", "0");
401 mlt_properties_set(properties, "relative", "1");
402 mlt_properties_set(properties, "zoom", "0");
403 mlt_properties_set(properties, "optzoom", "1");
404 mlt_properties_set(properties, "zoomspeed", "0.25");
406 mlt_properties_set(properties, "vid.stab.version", LIBVIDSTAB_VERSION);