3 * Copyright (C) 2013 Marco Gittler <g.marco@freenet.de>
4 * Copyright (C) 2013 Jakub Ksiezniak <j.ksiezniak@gmail.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 #include <vid.stab/libvidstab.h>
24 #include <framework/mlt.h>
25 #include <framework/mlt_animation.h>
34 typedef struct _stab_data
37 mlt_animation animation;
43 VSTransformations trans;
47 char* vectors_serializer(mlt_animation animation, int length)
49 return mlt_animation_serialize(animation);
52 char* lm_serializer(LocalMotions *lms, int length)
54 std::ostringstream oss;
55 int size = vs_vector_size(lms);
56 for (int i = 0; i < size; ++i)
58 LocalMotion* lm = (LocalMotion*) vs_vector_get(lms, i);
59 oss << lm->v.x << ' ';
60 oss << lm->v.y << ' ';
61 oss << lm->f.x << ' ';
62 oss << lm->f.y << ' ';
63 oss << lm->f.size << ' ';
64 oss << lm->contrast << ' ';
65 oss << lm->match << ' ';
67 return strdup(oss.str().c_str());
70 int lm_deserialize(LocalMotions *lms, mlt_property property)
72 std::istringstream iss(mlt_property_get_string(property));
73 vs_vector_init(lms, 0);
78 iss >> lm.v.x >> lm.v.y >> lm.f.x >> lm.f.y >> lm.f.size >> lm.contrast >> lm.match;
83 vs_vector_append_dup(lms, &lm, sizeof(lm));
88 void lm_destructor(void *lms)
90 vs_vector_del(static_cast<VSVector*>(lms));
93 static void serialize_localmotions(StabData* data, LocalMotions &vectors, mlt_position pos)
95 mlt_animation_item_s item;
97 // Initialize animation item
99 item.frame = data->md.frameNum;
100 item.keyframe_type = mlt_keyframe_discrete;
101 item.property = mlt_property_init();
103 mlt_property_set_data(item.property, &vectors, 1, lm_destructor, (mlt_serialiser) lm_serializer);
104 mlt_animation_insert(data->animation, &item);
105 mlt_property_close(item.property);
108 int vectors_deserialize(mlt_animation anim, VSManyLocalMotions *mlms)
111 mlt_animation_item_s item;
112 item.property = mlt_property_init();
114 vs_vector_init(mlms, 1024); // initial number of frames, but it will be increased
116 int length = mlt_animation_get_length(anim);
117 for (int i = 0; i < length; ++i)
122 mlt_animation_get_item(anim, &item, i + 1);
123 if ((error = lm_deserialize(&lms, item.property)))
128 vs_vector_set_dup(mlms, i, &lms, sizeof(LocalMotions));
131 mlt_property_close(item.property);
135 void destroy_transforms(TransformData *data)
139 vsTransformDataCleanup(&data->td);
140 vsTransformationsCleanup(&data->trans);
145 TransformData* initialize_transforms(int *width, int *height, mlt_image_format *format,
146 mlt_properties properties, const char* interps)
148 TransformData *data = new TransformData;
149 memset(data, 0, sizeof(TransformData));
151 VSPixelFormat pf = convertImageFormat(*format);
152 VSFrameInfo fi_src, fi_dst;
153 vsFrameInfoInit(&fi_src, *width, *height, pf);
154 vsFrameInfoInit(&fi_dst, *width, *height, pf);
156 const char* filterName = mlt_properties_get(properties, "mlt_service");
158 VSTransformConfig conf = vsTransformGetDefaultConfig(filterName);
159 conf.smoothing = mlt_properties_get_int(properties, "smoothing");
160 conf.maxShift = mlt_properties_get_int(properties, "maxshift");
161 conf.maxAngle = mlt_properties_get_double(properties, "maxangle");
162 conf.crop = (VSBorderType) mlt_properties_get_int(properties, "crop");
163 conf.zoom = mlt_properties_get_int(properties, "zoom");
164 conf.optZoom = mlt_properties_get_int(properties, "optzoom");
165 conf.zoomSpeed = mlt_properties_get_double(properties, "zoomspeed");
166 conf.relative = mlt_properties_get_int(properties, "relative");
167 conf.invert = mlt_properties_get_int(properties, "invert");
168 if (mlt_properties_get_int(properties, "tripod") != 0)
170 // Virtual tripod mode: relative=False, smoothing=0
175 // by default a bilinear interpolation is selected
176 conf.interpolType = VS_BiLinear;
177 if (strcmp(interps, "nearest") == 0 || strcmp(interps, "neighbor") == 0)
178 conf.interpolType = VS_Zero;
179 else if (strcmp(interps, "tiles") == 0 || strcmp(interps, "fast_bilinear") == 0)
180 conf.interpolType = VS_Linear;
182 vsTransformDataInit(&data->td, &conf, &fi_src, &fi_dst);
183 vsTransformationsInit(&data->trans);
185 // load transformations
186 mlt_animation animation = mlt_animation_new();
187 char* strAnim = mlt_properties_get(properties, "vectors");
188 if (mlt_animation_parse(animation, strAnim, 0, 0, NULL))
190 mlt_log_warning(NULL, "parse failed\n");
191 mlt_animation_close(animation);
192 destroy_transforms(data);
196 VSManyLocalMotions mlms;
197 if (vectors_deserialize(animation, &mlms))
199 mlt_animation_close(animation);
200 destroy_transforms(data);
204 mlt_animation_close(animation);
206 vsLocalmotions2Transforms(&data->td, &mlms, &data->trans);
207 vsPreprocessTransforms(&data->td, &data->trans);
211 int get_image_and_transform(mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable)
214 mlt_filter filter = (mlt_filter) mlt_frame_pop_service(frame);
215 mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
217 *format = mlt_image_yuv420p;
219 error = mlt_frame_get_image(frame, image, format, width, height, 1);
222 // Service locks are for concurrency control
223 mlt_service_lock(MLT_FILTER_SERVICE(filter));
225 TransformData *data = static_cast<TransformData*>(mlt_properties_get_data(properties, "_transform_data", NULL));
227 // Handle signal from app to re-init data
228 if (mlt_properties_get_int(properties, "refresh"))
230 mlt_properties_set(properties, "refresh", NULL);
231 destroy_transforms(data);
237 const char *interps = mlt_properties_get(MLT_FRAME_PROPERTIES(frame), "rescale.interp");
238 data = initialize_transforms(width, height, format, properties, interps);
240 mlt_service_unlock(MLT_FILTER_SERVICE(filter));
241 return 1; // return error code
243 mlt_properties_set_data(properties, "_transform_data", data, 0, (mlt_destructor) destroy_transforms, NULL);
246 VSTransformData* td = &data->td;
248 vsFrameFillFromBuffer(&vsFrame, *image, vsTransformGetSrcFrameInfo(td));
251 data->trans.current = mlt_filter_get_position(filter, frame);
252 vsTransformPrepare(td, &vsFrame, &vsFrame);
253 VSTransform t = vsGetNextTransform(td, &data->trans);
254 vsDoTransform(td, t);
255 vsTransformFinish(td);
257 mlt_service_unlock(MLT_FILTER_SERVICE(filter));
263 static StabData* init_detect(mlt_properties properties, mlt_image_format *format, int *width, int *height)
265 StabData *data = new StabData;
266 memset(data, 0, sizeof(StabData));
267 data->animation = mlt_animation_new();
269 VSPixelFormat pf = convertImageFormat(*format);
271 vsFrameInfoInit(&fi, *width, *height, pf);
273 const char* filterName = mlt_properties_get(properties, "mlt_service");
275 VSMotionDetectConfig conf = vsMotionDetectGetDefaultConfig(filterName);
276 conf.shakiness = mlt_properties_get_int(properties, "shakiness");
277 conf.accuracy = mlt_properties_get_int(properties, "accuracy");
278 conf.stepSize = mlt_properties_get_int(properties, "stepsize");
279 conf.algo = mlt_properties_get_int(properties, "algo");
280 conf.contrastThreshold = mlt_properties_get_double(properties, "mincontrast");
281 conf.show = mlt_properties_get_int(properties, "show");
282 conf.virtualTripod = mlt_properties_get_int(properties, "tripod");
283 vsMotionDetectInit(&data->md, &conf, &fi);
285 // add vectors to properties
286 mlt_properties_set_data(properties, "vectors", data->animation, 1, (mlt_destructor) mlt_animation_close,
287 (mlt_serialiser) vectors_serializer);
291 void destroy_detect(StabData *data)
295 vsMotionDetectionCleanup(&data->md);
300 int get_image_and_detect(mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable)
302 mlt_filter filter = (mlt_filter) mlt_frame_pop_service(frame);
303 mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
305 *format = mlt_image_yuv420p;
307 writable = writable || mlt_properties_get_int(properties, "show") ? 1 : 0;
309 int error = mlt_frame_get_image(frame, image, format, width, height, writable);
312 // Service locks are for concurrency control
313 mlt_service_lock(MLT_FILTER_SERVICE(filter));
315 StabData *data = static_cast<StabData*>(mlt_properties_get_data(properties, "_stab_data", NULL));
318 data = init_detect(properties, format, width, height);
319 mlt_properties_set_data(properties, "_stab_data", data, 0, (mlt_destructor) destroy_detect, NULL);
322 VSMotionDetect* md = &data->md;
323 LocalMotions localmotions;
325 vsFrameFillFromBuffer(&vsFrame, *image, &md->fi);
327 // detect and save motions
328 vsMotionDetection(md, &localmotions, &vsFrame);
329 mlt_position pos = mlt_filter_get_position( filter, frame );
330 serialize_localmotions(data, localmotions, pos);
332 mlt_service_unlock(MLT_FILTER_SERVICE(filter));
338 static mlt_frame process_filter(mlt_filter filter, mlt_frame frame)
340 mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
341 mlt_get_image vidstab_get_image = (mlt_get_image) mlt_properties_get_data( properties, "_vidstab_get_image", NULL );
344 mlt_position pos = mlt_filter_get_position(filter, frame);
345 mlt_position length = mlt_filter_get_length2(filter, frame) - 1;
348 mlt_properties_set_data(properties, "_vidstab_get_image", NULL, 0, NULL, NULL);
352 if(vidstab_get_image == NULL)
354 if(mlt_properties_get(properties, "vectors") == NULL)
356 // vectors are NULL, so use a detect filter
357 vidstab_get_image = get_image_and_detect;
359 // found vectors, so use a transform filter
360 vidstab_get_image = get_image_and_transform;
363 mlt_properties_set_data( properties, "_vidstab_get_image", (void*)vidstab_get_image, 0, NULL, NULL );
366 mlt_frame_push_service(frame, filter);
367 mlt_frame_push_get_image(frame, vidstab_get_image);
374 mlt_filter filter_vidstab_init(mlt_profile profile, mlt_service_type type,
375 const char *id, char *arg)
377 mlt_filter filter = mlt_filter_new();
381 filter->process = process_filter;
383 mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
385 //properties for stabilize
386 mlt_properties_set(properties, "shakiness", "4");
387 mlt_properties_set(properties, "accuracy", "4");
388 mlt_properties_set(properties, "stepsize", "6");
389 mlt_properties_set(properties, "algo", "1");
390 mlt_properties_set(properties, "mincontrast", "0.3");
391 mlt_properties_set(properties, "show", "0");
392 mlt_properties_set(properties, "tripod", "0");
394 // properties for transform
395 mlt_properties_set(properties, "smoothing", "15");
396 mlt_properties_set(properties, "maxshift", "-1");
397 mlt_properties_set(properties, "maxangle", "-1");
398 mlt_properties_set(properties, "crop", "0");
399 mlt_properties_set(properties, "invert", "0");
400 mlt_properties_set(properties, "relative", "1");
401 mlt_properties_set(properties, "zoom", "0");
402 mlt_properties_set(properties, "optzoom", "1");
403 mlt_properties_set(properties, "zoomspeed", "0.25");
405 mlt_properties_set(properties, "vid.stab.version", LIBVIDSTAB_VERSION);