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