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