]> git.sesse.net Git - mlt/blob - src/modules/vid.stab/filter_deshake.cpp
0dd13cc251993cfd4dee1a5f4ae4a731e29b92b0
[mlt] / src / modules / vid.stab / filter_deshake.cpp
1 /*
2  * filter_deshake.cpp
3  * Copyright (C) 2013 Marco Gittler <g.marco@freenet.de>
4  * Copyright (C) 2013 Jakub Ksiezniak <j.ksiezniak@gmail.com>
5  *
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.
10  *
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.
15  *
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.
19  */
20
21 extern "C"
22 {
23 #include <vid.stab/libvidstab.h>
24 }
25
26 #include <framework/mlt.h>
27 #include <string.h>
28 #include <assert.h>
29 #include "common.h"
30
31 #define FILTER_NAME "vid.stab.deshake"
32
33 typedef struct _deshake_data
34 {
35         bool initialized;
36         VSMotionDetect md;
37         VSTransformData td;
38         VSSlidingAvgTrans avg;
39
40         mlt_position lastFrame;
41 } DeshakeData;
42
43 int init_deshake(DeshakeData *data, mlt_properties properties,
44                 mlt_image_format *format, int *width, int *height, char* interps)
45 {
46         VSPixelFormat pf = convertImageFormat(*format);
47         VSFrameInfo fiIn, fiOut;
48         vsFrameInfoInit(&fiIn, *width, *height, pf);
49         vsFrameInfoInit(&fiOut, *width, *height, pf);
50
51         VSMotionDetectConfig conf = vsMotionDetectGetDefaultConfig(FILTER_NAME);
52         conf.shakiness = mlt_properties_get_int(properties, "shakiness");
53         conf.accuracy = mlt_properties_get_int(properties, "accuracy");
54         conf.stepSize = mlt_properties_get_int(properties, "stepsize");
55         conf.algo = mlt_properties_get_int(properties, "algo");
56         conf.contrastThreshold = mlt_properties_get_double(properties, "mincontrast");
57         conf.show = 0;
58
59         vsMotionDetectInit(&data->md, &conf, &fiIn);
60
61         VSTransformConfig tdconf = vsTransformGetDefaultConfig(FILTER_NAME);
62         tdconf.smoothing = mlt_properties_get_int(properties, "smoothing");
63         tdconf.maxShift = mlt_properties_get_int(properties, "maxshift");
64         tdconf.maxAngle = mlt_properties_get_double(properties, "maxangle");
65         tdconf.crop = (VSBorderType) mlt_properties_get_int(properties, "crop");
66         tdconf.zoom = mlt_properties_get_int(properties, "zoom");
67         tdconf.optZoom = mlt_properties_get_int(properties, "optzoom");
68         tdconf.zoomSpeed = mlt_properties_get_double(properties, "zoomspeed");
69         tdconf.relative = 1;
70         tdconf.invert = 0;
71
72         // by default a bilinear interpolation is selected
73         tdconf.interpolType = VS_BiLinear;
74         if (strcmp(interps, "nearest") == 0 || strcmp(interps, "neighbor") == 0)
75                 tdconf.interpolType = VS_Zero;
76         else if (strcmp(interps, "tiles") == 0 || strcmp(interps, "fast_bilinear") == 0)
77                 tdconf.interpolType = VS_Linear;
78
79         vsTransformDataInit(&data->td, &tdconf, &fiIn, &fiOut);
80
81         data->avg.initialized = 0;
82         return 0;
83 }
84
85 void clear_deshake(DeshakeData *data)
86 {
87         if (data->initialized)
88         {
89                 vsMotionDetectionCleanup(&data->md);
90                 vsTransformDataCleanup(&data->td);
91         }
92 }
93
94 static int get_image(mlt_frame frame, uint8_t **image, mlt_image_format *format,
95                 int *width, int *height, int writable)
96 {
97         mlt_filter filter = (mlt_filter) mlt_frame_pop_service(frame);
98         mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
99
100         *format = mlt_image_yuv420p;
101         DeshakeData *data = static_cast<DeshakeData*>(filter->child);
102
103         int error = mlt_frame_get_image(frame, image, format, width, height, 1);
104         if (!error)
105         {
106                 // Service locks are for concurrency control
107                 mlt_service_lock(MLT_FILTER_SERVICE(filter));
108
109                 // Handle signal from app to re-init data
110                 if (mlt_properties_get_int(properties, "refresh"))
111                 {
112                         mlt_properties_set(properties, "refresh", NULL);
113                         clear_deshake(data);
114                         data->initialized = false;
115                 }
116
117                 // clear deshake data, when seeking or dropping frames
118                 mlt_position pos = mlt_filter_get_position(filter, frame);
119                 if(pos != data->lastFrame+1) {
120                         clear_deshake(data);
121                         data->initialized = false;
122                 }
123                 data->lastFrame = pos;
124
125                 if (!data->initialized)
126                 {
127                         char *interps = mlt_properties_get(MLT_FRAME_PROPERTIES(frame), "rescale.interp");
128                         init_deshake(data, properties, format, width, height,
129                                         interps);
130                         data->initialized = true;
131                 }
132
133                 VSMotionDetect* md = &data->md;
134                 VSTransformData* td = &data->td;
135                 LocalMotions localmotions;
136                 VSTransform motion;
137                 VSFrame vsFrame;
138
139                 vsFrameFillFromBuffer(&vsFrame, *image, &md->fi);
140                 vsMotionDetection(md, &localmotions, &vsFrame);
141
142                 motion = vsSimpleMotionsToTransform(md->fi, FILTER_NAME, &localmotions);
143                 vs_vector_del(&localmotions);
144
145                 vsTransformPrepare(td, &vsFrame, &vsFrame);
146
147                 VSTransform t = vsLowPassTransforms(td, &data->avg, &motion);
148 //          mlt_log_warning(filter, "Trans: det: %f %f %f \n\t\t act: %f %f %f %f",
149 //                       motion.x, motion.y, motion.alpha,
150 //                       t.x, t.y, t.alpha, t.zoom);
151                 vsDoTransform(td, t);
152                 vsTransformFinish(td);
153
154                 mlt_service_unlock(MLT_FILTER_SERVICE(filter));
155         }
156
157         return error;
158 }
159
160 static mlt_frame process_filter(mlt_filter filter, mlt_frame frame)
161 {
162         mlt_frame_push_service(frame, filter);
163         mlt_frame_push_get_image(frame, get_image);
164         return frame;
165 }
166
167 static void close_filter(mlt_filter filter)
168 {
169         DeshakeData *data = static_cast<DeshakeData*>(filter->child);
170         if (data)
171         {
172                 clear_deshake(data);
173                 delete data;
174                 filter->child = NULL;
175         }
176 }
177
178 extern "C"
179 {
180
181 mlt_filter filter_deshake_init(mlt_profile profile, mlt_service_type type,
182                 const char *id, char *arg)
183 {
184         mlt_filter filter = NULL;
185
186         DeshakeData *data = new DeshakeData;
187         memset(data, 0, sizeof(DeshakeData));
188
189         if ((filter = mlt_filter_new()))
190         {
191                 filter->process = process_filter;
192                 filter->close = close_filter;
193                 filter->child = data;
194
195                 mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
196                 //properties for stabilize
197                 mlt_properties_set(properties, "shakiness", "4");
198                 mlt_properties_set(properties, "accuracy", "4");
199                 mlt_properties_set(properties, "stepsize", "6");
200                 mlt_properties_set(properties, "algo", "1");
201                 mlt_properties_set(properties, "mincontrast", "0.3");
202
203                 //properties for transform
204                 mlt_properties_set(properties, "smoothing", "15");
205                 mlt_properties_set(properties, "maxshift", "-1");
206                 mlt_properties_set(properties, "maxangle", "-1");
207                 mlt_properties_set(properties, "crop", "0");
208                 mlt_properties_set(properties, "zoom", "0");
209                 mlt_properties_set(properties, "optzoom", "1");
210                 mlt_properties_set(properties, "zoomspeed", "0.25");
211
212                 return filter;
213         }
214
215         delete data;
216         return NULL;
217 }
218
219 }