]> git.sesse.net Git - mlt/blob - src/modules/vid.stab/filter_deshake.cpp
Add support for more image formats to vid.stab
[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  * Copyright (C) 2014 Brian Matherly <pez4brian@yahoo.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 "common.h"
26 }
27
28 #include <framework/mlt.h>
29 #include <string.h>
30 #include <assert.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                 VSPixelFormat vs_format, int *width, int *height, char* interps)
46 {
47         VSFrameInfo fiIn, fiOut;
48         vsFrameInfoInit(&fiIn, *width, *height, vs_format);
49         vsFrameInfoInit(&fiOut, *width, *height, vs_format);
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         uint8_t* vs_image = NULL;
100         VSPixelFormat vs_format = PF_NONE;
101
102         // VS only works on progressive frames
103         mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "consumer_deinterlace", 1 );
104
105         *format = validate_format( *format );
106         DeshakeData *data = static_cast<DeshakeData*>(filter->child);
107
108         int error = mlt_frame_get_image(frame, image, format, width, height, 1);
109
110         // Convert the received image to a format vid.stab can handle
111         if ( !error )
112         {
113                 vs_format = mltimage_to_vsimage( *format, *width, *height, *image, &vs_image );
114         }
115
116         if ( vs_image )
117         {
118                 // Service locks are for concurrency control
119                 mlt_service_lock(MLT_FILTER_SERVICE(filter));
120
121                 // Handle signal from app to re-init data
122                 if (mlt_properties_get_int(properties, "refresh"))
123                 {
124                         mlt_properties_set(properties, "refresh", NULL);
125                         clear_deshake(data);
126                         data->initialized = false;
127                 }
128
129                 // clear deshake data, when seeking or dropping frames
130                 mlt_position pos = mlt_filter_get_position(filter, frame);
131                 if(pos != data->lastFrame+1) {
132                         clear_deshake(data);
133                         data->initialized = false;
134                 }
135                 data->lastFrame = pos;
136
137                 if (!data->initialized)
138                 {
139                         char *interps = mlt_properties_get(MLT_FRAME_PROPERTIES(frame), "rescale.interp");
140                         init_deshake(data, properties, vs_format, width, height,
141                                         interps);
142                         data->initialized = true;
143                 }
144
145                 VSMotionDetect* md = &data->md;
146                 VSTransformData* td = &data->td;
147                 LocalMotions localmotions;
148                 VSTransform motion;
149                 VSFrame vsFrame;
150
151                 vsFrameFillFromBuffer(&vsFrame, vs_image, &md->fi);
152                 vsMotionDetection(md, &localmotions, &vsFrame);
153
154                 motion = vsSimpleMotionsToTransform(md->fi, FILTER_NAME, &localmotions);
155                 vs_vector_del(&localmotions);
156
157                 vsTransformPrepare(td, &vsFrame, &vsFrame);
158
159                 VSTransform t = vsLowPassTransforms(td, &data->avg, &motion);
160 //          mlt_log_warning(filter, "Trans: det: %f %f %f \n\t\t act: %f %f %f %f",
161 //                       motion.x, motion.y, motion.alpha,
162 //                       t.x, t.y, t.alpha, t.zoom);
163                 vsDoTransform(td, t);
164                 vsTransformFinish(td);
165
166                 vsimage_to_mltimage( vs_image, *image, *format, *width, *height );
167
168                 mlt_service_unlock(MLT_FILTER_SERVICE(filter));
169
170                 free_vsimage( vs_image, vs_format );
171         }
172
173         return error;
174 }
175
176 static mlt_frame process_filter(mlt_filter filter, mlt_frame frame)
177 {
178         mlt_frame_push_service(frame, filter);
179         mlt_frame_push_get_image(frame, get_image);
180         return frame;
181 }
182
183 static void close_filter(mlt_filter filter)
184 {
185         DeshakeData *data = static_cast<DeshakeData*>(filter->child);
186         if (data)
187         {
188                 clear_deshake(data);
189                 delete data;
190                 filter->child = NULL;
191         }
192 }
193
194 extern "C"
195 {
196
197 mlt_filter filter_deshake_init(mlt_profile profile, mlt_service_type type,
198                 const char *id, char *arg)
199 {
200         mlt_filter filter = NULL;
201
202         DeshakeData *data = new DeshakeData;
203         memset(data, 0, sizeof(DeshakeData));
204
205         if ((filter = mlt_filter_new()))
206         {
207                 filter->process = process_filter;
208                 filter->close = close_filter;
209                 filter->child = data;
210
211                 mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
212                 //properties for stabilize
213                 mlt_properties_set(properties, "shakiness", "4");
214                 mlt_properties_set(properties, "accuracy", "4");
215                 mlt_properties_set(properties, "stepsize", "6");
216                 mlt_properties_set(properties, "algo", "1");
217                 mlt_properties_set(properties, "mincontrast", "0.3");
218
219                 //properties for transform
220                 mlt_properties_set(properties, "smoothing", "15");
221                 mlt_properties_set(properties, "maxshift", "-1");
222                 mlt_properties_set(properties, "maxangle", "-1");
223                 mlt_properties_set(properties, "crop", "0");
224                 mlt_properties_set(properties, "zoom", "0");
225                 mlt_properties_set(properties, "optzoom", "1");
226                 mlt_properties_set(properties, "zoomspeed", "0.25");
227
228                 return filter;
229         }
230
231         delete data;
232         return NULL;
233 }
234
235 }