4 * Copyright (C) Georg Martius - November 2011
5 * georg dot martius at web dot de
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.
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.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the
19 * Free Software Foundation, Inc.,
20 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 * transcode -V -J deshake=shakiness=5:smoothing=10
26 * -i inp.mpeg -y xvid,tc_aud -o out.avi
27 * all parameters are optional
30 #include "libvidstab.h"
32 #define MOD_NAME "filter_deshake.so"
33 #define MOD_VERSION LIBVIDSTAB_VERSION
34 #define MOD_CAP "deshakes a video clip by extracting relative transformations\n\
35 of subsequent frames and transforms the high-frequency away\n\
36 This is a single pass verion of stabilize and transform plugin"
37 #define MOD_AUTHOR "Georg Martius"
40 #define MOD_FEATURES \
41 TC_MODULE_FEATURE_FILTER|TC_MODULE_FEATURE_VIDEO
43 TC_MODULE_FLAG_RECONFIGURABLE | TC_MODULE_FLAG_DELAY
45 #define DEFAULT_TRANS_FILE_NAME "transforms.dat"
51 #include "transcode.h"
53 #include "libtc/libtc.h"
54 #include "libtc/optstr.h"
55 #include "libtc/tccodecs.h"
56 #include "libtc/tcmodule-plugin.h"
58 #include "transcode_specifics.h"
60 /* private date structure of this filter*/
61 typedef struct _deshake_data
{
64 VSSlidingAvgTrans avg
;
66 double sharpen
; // amount of sharpening
67 vob_t
* vob
; // pointer to information structure
71 char conf_str
[TC_BUF_MIN
];
75 static const char deshake_help
[] = ""
77 " Deshakes a video clip. It only uses past information, such that it is less\n"
78 " powerful than the filters stabilize and transform. \n"
79 " It also generates a file with relative transform information\n"
80 " to be used by the transform filter separately."
82 " 'smoothing' number of frames*2 + 1 used for lowpass filtering \n"
83 " used for stabilizing (def: 10)\n"
84 " 'shakiness' how shaky is the video and how quick is the camera?\n"
85 " 1: little (fast) 10: very strong/quick (slow) (def: 4)\n"
86 " 'accuracy' accuracy of detection process (>=shakiness)\n"
87 " 1: low (fast) 15: high (slow) (def: 4)\n"
88 " 'stepsize' stepsize of search process, region around minimum \n"
89 " is scanned with 1 pixel resolution (def: 6)\n"
90 " 'algo' 0: brute force (translation only);\n"
91 " 1: small measurement fields (def)\n"
92 " 'mincontrast' below this contrast a field is discarded (0-1) (def: 0.3)\n"
93 " 'result' path to the file used to write the transforms\n"
94 " (def:inputfile.stab)\n"
95 " 'maxshift' maximal number of pixels to translate image\n"
96 " (def: -1 no limit)\n"
97 " 'maxangle' maximal angle in rad to rotate image (def: -1 no limit)\n"
98 " 'crop' 0: keep border (def), 1: black background\n"
99 " 'zoom' percentage to zoom >0: zoom in, <0 zoom out (def: 2)\n"
100 " 'optzoom' 0: nothing, 1: determine optimal zoom (def)\n"
101 " 'interpol' type of interpolation: 0: no interpolation, \n"
102 " 1: linear (horizontal), 2: bi-linear (def), \n"
104 " 'sharpen' amount of sharpening: 0: no sharpening (def: 0.8)\n"
105 " uses filter unsharp with 5x5 matrix\n"
106 " 'help' print this help message\n";
108 /*************************************************************************/
110 /* Module interface routines and data. */
112 /*************************************************************************/
115 * deshake_init: Initialize this instance of the module. See
116 * tcmodule-data.h for function details.
119 static int deshake_init(TCModuleInstance
*self
, uint32_t features
)
121 DeshakeData
* sd
= NULL
;
122 TC_MODULE_SELF_CHECK(self
, "init");
123 TC_MODULE_INIT_CHECK(self
, MOD_FEATURES
, features
);
127 sd
= tc_zalloc(sizeof(DeshakeData
)); // allocation with zero values
129 if (verbose
> TC_INFO
)
130 tc_log_error(MOD_NAME
, "init: out of memory!");
134 sd
->vob
= tc_get_vob();
138 /**** Initialise private data structure */
141 if (verbose
& TC_INFO
){
142 tc_log_info(MOD_NAME
, "%s %s", MOD_VERSION
, MOD_CAP
);
150 * deshake_fini: Clean up after this instance of the module. See
151 * tcmodule-data.h for function details.
153 static int deshake_fini(TCModuleInstance
*self
)
155 DeshakeData
*sd
= NULL
;
156 TC_MODULE_SELF_CHECK(self
, "fini");
160 self
->userdata
= NULL
;
165 * deshake_configure: Configure this instance of the module. See
166 * tcmodule-data.h for function details.
168 static int deshake_configure(TCModuleInstance
*self
,
169 const char *options
, vob_t
*vob
)
171 DeshakeData
*sd
= NULL
;
172 TC_MODULE_SELF_CHECK(self
, "configure");
173 char* filenamecopy
, *filebasename
;
177 /* sd->framesize = sd->vob->im_v_width * MAX_PLANES *
178 sizeof(char) * 2 * sd->vob->im_v_height * 2; */
180 VSMotionDetect
* md
= &(sd
->md
);
181 VSTransformData
* td
= &(sd
->td
);
183 // init VSMotionDetect part
185 vsFrameInfoInit(&fi
, sd
->vob
->ex_v_width
, sd
->vob
->ex_v_height
,
186 transcode2ourPF(sd
->vob
->im_v_codec
));
188 VSMotionDetectConfig mdconf
= vsMotionDetectGetDefaultConfig(MOD_NAME
);
189 VSTransformConfig tdconf
= vsTransformGetDefaultConfig(MOD_NAME
);
190 tdconf
.verbose
=verbose
;
192 sd
->result
= tc_malloc(TC_BUF_LINE
);
193 filenamecopy
= tc_strdup(sd
->vob
->video_in_file
);
194 filebasename
= basename(filenamecopy
);
195 if (strlen(filebasename
) < TC_BUF_LINE
- 4) {
196 tc_snprintf(sd
->result
, TC_BUF_LINE
, "%s.trf", filebasename
);
198 tc_log_warn(MOD_NAME
, "input name too long, using default `%s'",
199 DEFAULT_TRANS_FILE_NAME
);
200 tc_snprintf(sd
->result
, TC_BUF_LINE
, DEFAULT_TRANS_FILE_NAME
);
203 // init trasform part
205 vsFrameInfoInit(&fi_dest
, sd
->vob
->ex_v_width
, sd
->vob
->ex_v_height
,
206 transcode2ourPF(sd
->vob
->im_v_codec
));
208 if (options
!= NULL
) {
209 // for some reason this plugin is called in the old fashion
210 // (not with inspect). Anyway we support both ways of getting help.
211 if(optstr_lookup(options
, "help")) {
212 tc_log_info(MOD_NAME
,deshake_help
);
213 return(TC_IMPORT_ERROR
);
216 optstr_get(options
, "result", "%[^:]", sd
->result
);
217 optstr_get(options
, "shakiness", "%d", &mdconf
.shakiness
);
218 optstr_get(options
, "accuracy", "%d", &mdconf
.accuracy
);
219 optstr_get(options
, "stepsize", "%d", &mdconf
.stepSize
);
220 optstr_get(options
, "algo", "%d", &mdconf
.algo
);
221 optstr_get(options
, "mincontrast","%lf",&mdconf
.contrastThreshold
);
224 optstr_get(options
, "maxshift", "%d", &tdconf
.maxShift
);
225 optstr_get(options
, "maxangle", "%lf",&tdconf
.maxAngle
);
226 optstr_get(options
, "smoothing", "%d", &tdconf
.smoothing
);
227 optstr_get(options
, "crop" , "%d", (int*)&tdconf
.crop
);
228 optstr_get(options
, "zoom" , "%lf",&tdconf
.zoom
);
229 optstr_get(options
, "optzoom" , "%d", &tdconf
.optZoom
);
230 optstr_get(options
, "interpol" , "%d", (int*)(&tdconf
.interpolType
));
231 optstr_get(options
, "sharpen" , "%lf",&sd
->sharpen
);
236 if(vsMotionDetectInit(md
, &mdconf
, &fi
) != VS_OK
){
237 tc_log_error(MOD_NAME
, "initialization of Motion Detection failed");
240 vsMotionDetectGetConfig(&mdconf
,md
);
242 if(vsTransformDataInit(td
, &tdconf
, &fi
, &fi_dest
) != VS_OK
){
243 tc_log_error(MOD_NAME
, "initialization of VSTransformData failed");
246 vsTransformGetConfig(&tdconf
, td
);
249 tc_log_info(MOD_NAME
, "Video Deshake Settings:");
250 tc_log_info(MOD_NAME
, " smoothing = %d", tdconf
.smoothing
);
251 tc_log_info(MOD_NAME
, " shakiness = %d", mdconf
.shakiness
);
252 tc_log_info(MOD_NAME
, " accuracy = %d", mdconf
.accuracy
);
253 tc_log_info(MOD_NAME
, " stepsize = %d", mdconf
.stepSize
);
254 tc_log_info(MOD_NAME
, " algo = %d", mdconf
.algo
);
255 tc_log_info(MOD_NAME
, " mincontrast = %f", mdconf
.contrastThreshold
);
256 tc_log_info(MOD_NAME
, " show = %d", mdconf
.show
);
257 tc_log_info(MOD_NAME
, " result = %s", sd
->result
);
258 tc_log_info(MOD_NAME
, " maxshift = %d", tdconf
.maxShift
);
259 tc_log_info(MOD_NAME
, " maxangle = %f", tdconf
.maxAngle
);
260 tc_log_info(MOD_NAME
, " crop = %s",
261 tdconf
.crop
? "Black" : "Keep");
262 tc_log_info(MOD_NAME
, " zoom = %f", tdconf
.zoom
);
263 tc_log_info(MOD_NAME
, " optzoom = %s",
264 tdconf
.optZoom
? "On" : "Off");
265 tc_log_info(MOD_NAME
, " interpol = %s",
266 getInterpolationTypeName(tdconf
.interpolType
));
267 tc_log_info(MOD_NAME
, " sharpen = %f", sd
->sharpen
);
271 sd
->avg
.initialized
=0;
273 sd
->f
= fopen(sd
->result
, "w");
275 tc_log_error(MOD_NAME
, "cannot open result file %s!\n", sd
->result
);
284 * deshake_filter_video: performs the analysis of subsequent frames
285 * See tcmodule-data.h for function details.
288 static int deshake_filter_video(TCModuleInstance
*self
,
289 vframe_list_t
*frame
)
291 DeshakeData
*sd
= NULL
;
293 TC_MODULE_SELF_CHECK(self
, "filter_video");
294 TC_MODULE_SELF_CHECK(frame
, "filter_video");
297 VSMotionDetect
* md
= &(sd
->md
);
298 VSTransformData
* td
= &(sd
->td
);
299 LocalMotions localmotions
;
302 vsFrameFillFromBuffer(&vsFrame
,frame
->video_buf
, &md
->fi
);
304 if(vsMotionDetection(md
, &localmotions
, &vsFrame
)!= VS_OK
){
305 tc_log_error(MOD_NAME
, "motion detection failed");
309 if(vsWriteToFile(md
, sd
->f
, &localmotions
) != VS_OK
){
310 tc_log_error(MOD_NAME
, "cannot write to file!");
313 motion
= vsSimpleMotionsToTransform(td
->fiSrc
, td
->conf
.modName
, &localmotions
);
314 vs_vector_del(&localmotions
);
316 vsTransformPrepare(td
, &vsFrame
, &vsFrame
);
318 VSTransform t
= vsLowPassTransforms(td
, &sd
->avg
, &motion
);
319 /* tc_log_info(MOD_NAME, "Trans: det: %f %f %f \n\t\t act: %f %f %f %f", */
320 /* motion.x, motion.y, motion.alpha, */
321 /* t.x, t.y, t.alpha, t.zoom); */
323 vsDoTransform(td
, t
);
325 vsTransformFinish(td
);
330 * deshake_stop: Reset this instance of the module. See tcmodule-data.h
331 * for function details.
334 static int deshake_stop(TCModuleInstance
*self
)
336 DeshakeData
*sd
= NULL
;
337 TC_MODULE_SELF_CHECK(self
, "stop");
345 vsMotionDetectionCleanup(&sd
->md
);
351 vsTransformDataCleanup(&sd
->td
);
356 /* checks for parameter in function _inspect */
357 #define CHECKPARAM(paramname, formatstring, variable) \
358 if (optstr_lookup(param, paramname)) { \
359 tc_snprintf(sd->conf_str, sizeof(sd->conf_str), \
360 formatstring, variable); \
361 *value = sd->conf_str; \
365 * deshake_inspect: Return the value of an option in this instance of
366 * the module. See tcmodule-data.h for function details.
369 static int deshake_inspect(TCModuleInstance
*self
,
370 const char *param
, const char **value
)
372 DeshakeData
*sd
= NULL
;
374 TC_MODULE_SELF_CHECK(self
, "inspect");
375 TC_MODULE_SELF_CHECK(param
, "inspect");
376 TC_MODULE_SELF_CHECK(value
, "inspect");
379 VSMotionDetectConfig mdconf
;
380 vsMotionDetectGetConfig(&mdconf
,&(sd
->md
));
381 VSTransformConfig tdconf
;
382 vsTransformGetConfig(&tdconf
,&sd
->td
);
383 if (optstr_lookup(param
, "help")) {
384 *value
= deshake_help
;
387 CHECKPARAM("shakiness","shakiness=%d", mdconf
.shakiness
);
388 CHECKPARAM("accuracy", "accuracy=%d", mdconf
.accuracy
);
389 CHECKPARAM("stepsize", "stepsize=%d", mdconf
.stepSize
);
390 CHECKPARAM("algo", "algo=%d", mdconf
.algo
);
391 CHECKPARAM("result", "result=%s", sd
->result
);
392 CHECKPARAM("maxshift", "maxshift=%d", tdconf
.maxShift
);
393 CHECKPARAM("maxangle", "maxangle=%f", tdconf
.maxAngle
);
394 CHECKPARAM("smoothing","smoothing=%d", tdconf
.smoothing
);
395 CHECKPARAM("crop", "crop=%d", tdconf
.crop
);
396 CHECKPARAM("optzoom", "optzoom=%i", tdconf
.optZoom
);
397 CHECKPARAM("zoom", "zoom=%f", tdconf
.zoom
);
398 CHECKPARAM("sharpen", "sharpen=%f", sd
->sharpen
);
403 static const TCCodecID deshake_codecs_in
[] = {
404 TC_CODEC_YUV420P
, TC_CODEC_YUV422P
, TC_CODEC_RGB
, TC_CODEC_ERROR
406 static const TCCodecID deshake_codecs_out
[] = {
407 TC_CODEC_YUV420P
, TC_CODEC_YUV422P
, TC_CODEC_RGB
, TC_CODEC_ERROR
409 TC_MODULE_FILTER_FORMATS(deshake
);
411 TC_MODULE_INFO(deshake
);
413 static const TCModuleClass deshake_class
= {
414 TC_MODULE_CLASS_HEAD(deshake
),
416 .init
= deshake_init
,
417 .fini
= deshake_fini
,
418 .configure
= deshake_configure
,
419 .stop
= deshake_stop
,
420 .inspect
= deshake_inspect
,
422 .filter_video
= deshake_filter_video
,
425 TC_MODULE_ENTRY_POINT(deshake
)
427 /*************************************************************************/
429 static int deshake_get_config(TCModuleInstance
*self
, char *options
)
431 TC_MODULE_SELF_CHECK(self
, "get_config");
433 optstr_filter_desc(options
, MOD_NAME
, MOD_CAP
, MOD_VERSION
,
434 MOD_AUTHOR
, "VRY4", "1");
439 static int deshake_process(TCModuleInstance
*self
, frame_list_t
*frame
)
441 TC_MODULE_SELF_CHECK(self
, "process");
443 // if (frame->tag & TC_PRE_S_PROCESS && frame->tag & TC_VIDEO) {
444 if (frame
->tag
& TC_POST_S_PROCESS
&& frame
->tag
& TC_VIDEO
) {
445 return deshake_filter_video(self
, (vframe_list_t
*)frame
);
450 /*************************************************************************/
452 TC_FILTER_OLDINTERFACE(deshake
)
454 /*************************************************************************/
458 * c-file-style: "stroustrup"
459 * c-file-offsets: ((case-label . *) (statement-case-intro . *))
460 * indent-tabs-mode: nil
461 * c-basic-offset: 2 t
464 * vim: expandtab shiftwidth=2: