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