]> git.sesse.net Git - mlt/blob - src/modules/vid.stab/filter_detect.cpp
Added a fourth filter, that combines both detect and transform passes.
[mlt] / src / modules / vid.stab / filter_detect.cpp
1 /*
2  * filter_detect.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 "common.h"
32
33 typedef struct _stab_data
34 {
35         VSMotionDetect md;
36         mlt_animation animation;
37 } StabData;
38
39 char* vectors_serializer(mlt_animation animation, int length)
40 {
41         return mlt_animation_serialize(animation);
42 }
43
44 #include <sstream>
45 char* lm_serializer(LocalMotions *lms, int length)
46 {
47         std::ostringstream oss;
48         int size = vs_vector_size(lms);
49         for (int i = 0; i < size; ++i)
50         {
51                 LocalMotion* lm = (LocalMotion*) vs_vector_get(lms, i);
52                 oss << lm->v.x << ' ';
53                 oss << lm->v.y << ' ';
54                 oss << lm->f.x << ' ';
55                 oss << lm->f.y << ' ';
56                 oss << lm->f.size << ' ';
57                 oss << lm->contrast << ' ';
58                 oss << lm->match << ' ';
59         }
60         return strdup(oss.str().c_str());
61 }
62
63 void lm_destructor(void *lms)
64 {
65         vs_vector_del(static_cast<VSVector*>(lms));
66 }
67
68 static void serialize_localmotions(StabData* data, LocalMotions &vectors, mlt_position pos)
69 {
70         mlt_animation_item_s item;
71
72         // Initialize animation item
73         item.is_key = 1;
74         item.frame = data->md.frameNum;
75         item.keyframe_type = mlt_keyframe_discrete;
76         item.property = mlt_property_init();
77
78         mlt_property_set_data(item.property, &vectors, 1, lm_destructor, (mlt_serialiser) lm_serializer);
79         mlt_animation_insert(data->animation, &item);
80         mlt_property_close(item.property);
81 }
82
83 static StabData* init_detect(mlt_properties properties, mlt_image_format *format, int *width, int *height)
84 {
85         StabData *data = new StabData;
86         memset(data, 0, sizeof(StabData));
87         data->animation = mlt_animation_new();
88
89         VSPixelFormat pf = convertImageFormat(*format);
90         VSFrameInfo fi;
91         vsFrameInfoInit(&fi, *width, *height, pf);
92
93         const char* filterName = mlt_properties_get(properties, "mlt_service");
94
95         VSMotionDetectConfig conf = vsMotionDetectGetDefaultConfig(filterName);
96         conf.shakiness = mlt_properties_get_int(properties, "shakiness");
97         conf.accuracy = mlt_properties_get_int(properties, "accuracy");
98         conf.stepSize = mlt_properties_get_int(properties, "stepsize");
99         conf.algo = mlt_properties_get_int(properties, "algo");
100         conf.contrastThreshold = mlt_properties_get_double(properties, "mincontrast");
101         conf.show = mlt_properties_get_int(properties, "show");
102         conf.virtualTripod = mlt_properties_get_int(properties, "tripod");
103         vsMotionDetectInit(&data->md, &conf, &fi);
104
105         // add vectors to properties
106         mlt_properties_set_data(properties, "vectors", data->animation, 1, (mlt_destructor) mlt_animation_close,
107                                         (mlt_serialiser) vectors_serializer);
108         return data;
109 }
110
111 void destroy_detect(StabData *data)
112 {
113         if (data)
114         {
115                 vsMotionDetectionCleanup(&data->md);
116                 delete data;
117         }
118 }
119
120 int get_image_and_detect(mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable)
121 {
122         mlt_filter filter = (mlt_filter) mlt_frame_pop_service(frame);
123         mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
124
125         *format = mlt_image_yuv420p;
126
127         writable = writable || mlt_properties_get_int(properties, "show") ? 1 : 0;
128
129         int error = mlt_frame_get_image(frame, image, format, width, height, writable);
130         if (!error)
131         {
132                 // Service locks are for concurrency control
133                 mlt_service_lock(MLT_FILTER_SERVICE(filter));
134
135                 StabData *data = static_cast<StabData*>(mlt_properties_get_data(properties, "_stab_data", NULL));
136                 if (!data)
137                 {
138                         data = init_detect(properties, format, width, height);
139                         mlt_properties_set_data(properties, "_stab_data", data, 0, (mlt_destructor) destroy_detect, NULL);
140                 }
141
142                 VSMotionDetect* md = &data->md;
143                 LocalMotions localmotions;
144                 VSFrame vsFrame;
145                 vsFrameFillFromBuffer(&vsFrame, *image, &md->fi);
146
147                 // detect and save motions
148                 vsMotionDetection(md, &localmotions, &vsFrame);
149                 mlt_position pos = mlt_filter_get_position( filter, frame );
150                 serialize_localmotions(data, localmotions, pos);
151
152                 mlt_service_unlock(MLT_FILTER_SERVICE(filter));
153         }
154
155         return error;
156 }
157
158 static mlt_frame process_filter(mlt_filter filter, mlt_frame frame)
159 {
160         mlt_frame_push_service(frame, filter);
161         mlt_frame_push_get_image(frame, get_image_and_detect);
162         return frame;
163 }
164
165 extern "C"
166 {
167
168 mlt_filter filter_detect_init(mlt_profile profile, mlt_service_type type, const char *id, char *arg)
169 {
170         mlt_filter filter = NULL;
171
172         if ((filter = mlt_filter_new()))
173         {
174                 filter->process = process_filter;
175
176                 mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
177
178                 //properties for stabilize
179                 mlt_properties_set(properties, "shakiness", "4");
180                 mlt_properties_set(properties, "accuracy", "4");
181                 mlt_properties_set(properties, "stepsize", "6");
182                 mlt_properties_set(properties, "algo", "1");
183                 mlt_properties_set(properties, "mincontrast", "0.3");
184                 mlt_properties_set(properties, "show", "0");
185                 mlt_properties_set(properties, "tripod", "0");
186
187                 // properties for transform
188                 mlt_properties_set(properties, "smoothing", "15");
189                 mlt_properties_set(properties, "maxshift", "-1");
190                 mlt_properties_set(properties, "maxangle", "-1");
191                 mlt_properties_set(properties, "crop", "0");
192                 mlt_properties_set(properties, "invert", "0");
193                 mlt_properties_set(properties, "relative", "1");
194                 mlt_properties_set(properties, "zoom", "0");
195                 mlt_properties_set(properties, "optzoom", "1");
196                 mlt_properties_set(properties, "zoomspeed", "0.25");
197
198                 mlt_properties_set(properties, "vid.stab.version", LIBVIDSTAB_VERSION);
199
200                 return filter;
201         }
202
203         return NULL;
204 }
205
206 }