Imported Debian version 1.0~trusty
[deb_vid.stab.git] / transcode / filter_deshake.c
1 /*
2 * filter_deshake.c
3 *
4 * Copyright (C) Georg Martius - November 2011
5 * georg dot martius at web dot de
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
19 * Free Software Foundation, Inc.,
20 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 *
22 */
23
24 /* Typical call:
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
28 */
29
30 #include "libvidstab.h"
31
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"
38
39
40 #define MOD_FEATURES \
41 TC_MODULE_FEATURE_FILTER|TC_MODULE_FEATURE_VIDEO
42 #define MOD_FLAGS \
43 TC_MODULE_FLAG_RECONFIGURABLE | TC_MODULE_FLAG_DELAY
44
45 #define DEFAULT_TRANS_FILE_NAME "transforms.dat"
46
47
48 #include <math.h>
49 #include <libgen.h>
50
51 #include "transcode.h"
52 #include "filter.h"
53 #include "libtc/libtc.h"
54 #include "libtc/optstr.h"
55 #include "libtc/tccodecs.h"
56 #include "libtc/tcmodule-plugin.h"
57
58 #include "transcode_specifics.h"
59
60 /* private date structure of this filter*/
61 typedef struct _deshake_data {
62 VSMotionDetect md;
63 VSTransformData td;
64 VSSlidingAvgTrans avg;
65
66 double sharpen; // amount of sharpening
67 vob_t* vob; // pointer to information structure
68 char* result;
69 FILE* f;
70
71 char conf_str[TC_BUF_MIN];
72 } DeshakeData;
73
74
75 static const char deshake_help[] = ""
76 "Overview:\n"
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."
81 "Options\n"
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"
103 " 3: bi-cubic\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";
107
108 /*************************************************************************/
109
110 /* Module interface routines and data. */
111
112 /*************************************************************************/
113
114 /**
115 * deshake_init: Initialize this instance of the module. See
116 * tcmodule-data.h for function details.
117 */
118
119 static int deshake_init(TCModuleInstance *self, uint32_t features)
120 {
121 DeshakeData* sd = NULL;
122 TC_MODULE_SELF_CHECK(self, "init");
123 TC_MODULE_INIT_CHECK(self, MOD_FEATURES, features);
124
125 setLogFunctions();
126
127 sd = tc_zalloc(sizeof(DeshakeData)); // allocation with zero values
128 if (!sd) {
129 if (verbose > TC_INFO)
130 tc_log_error(MOD_NAME, "init: out of memory!");
131 return TC_ERROR;
132 }
133
134 sd->vob = tc_get_vob();
135 if (!sd->vob)
136 return TC_ERROR;
137
138 /**** Initialise private data structure */
139
140 self->userdata = sd;
141 if (verbose & TC_INFO){
142 tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP);
143 }
144
145 return TC_OK;
146 }
147
148
149 /*
150 * deshake_fini: Clean up after this instance of the module. See
151 * tcmodule-data.h for function details.
152 */
153 static int deshake_fini(TCModuleInstance *self)
154 {
155 DeshakeData *sd = NULL;
156 TC_MODULE_SELF_CHECK(self, "fini");
157 sd = self->userdata;
158
159 tc_free(sd);
160 self->userdata = NULL;
161 return TC_OK;
162 }
163
164 /*
165 * deshake_configure: Configure this instance of the module. See
166 * tcmodule-data.h for function details.
167 */
168 static int deshake_configure(TCModuleInstance *self,
169 const char *options, vob_t *vob)
170 {
171 DeshakeData *sd = NULL;
172 TC_MODULE_SELF_CHECK(self, "configure");
173 char* filenamecopy, *filebasename;
174
175 sd = self->userdata;
176
177 /* sd->framesize = sd->vob->im_v_width * MAX_PLANES *
178 sizeof(char) * 2 * sd->vob->im_v_height * 2; */
179
180 VSMotionDetect* md = &(sd->md);
181 VSTransformData* td = &(sd->td);
182
183 // init VSMotionDetect part
184 VSFrameInfo fi;
185 vsFrameInfoInit(&fi, sd->vob->ex_v_width, sd->vob->ex_v_height,
186 transcode2ourPF(sd->vob->im_v_codec));
187
188 VSMotionDetectConfig mdconf = vsMotionDetectGetDefaultConfig(MOD_NAME);
189 VSTransformConfig tdconf = vsTransformGetDefaultConfig(MOD_NAME);
190 tdconf.verbose=verbose;
191
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);
197 } else {
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);
201 }
202
203 // init trasform part
204 VSFrameInfo fi_dest;
205 vsFrameInfoInit(&fi_dest, sd->vob->ex_v_width, sd->vob->ex_v_height,
206 transcode2ourPF(sd->vob->im_v_codec));
207
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);
214 }
215
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);
222 mdconf.show = 0;
223
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);
232 tdconf.relative=1;
233 tdconf.invert=0;
234 }
235
236 if(vsMotionDetectInit(md, &mdconf, &fi) != VS_OK){
237 tc_log_error(MOD_NAME, "initialization of Motion Detection failed");
238 return TC_ERROR;
239 }
240 vsMotionDetectGetConfig(&mdconf,md);
241
242 if(vsTransformDataInit(td, &tdconf, &fi, &fi_dest) != VS_OK){
243 tc_log_error(MOD_NAME, "initialization of VSTransformData failed");
244 return TC_ERROR;
245 }
246 vsTransformGetConfig(&tdconf, td);
247
248 if (verbose) {
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);
268
269 }
270
271 sd->avg.initialized=0;
272
273 sd->f = fopen(sd->result, "w");
274 if (sd->f == NULL) {
275 tc_log_error(MOD_NAME, "cannot open result file %s!\n", sd->result);
276 return TC_ERROR;
277 }
278
279 return TC_OK;
280 }
281
282
283 /**
284 * deshake_filter_video: performs the analysis of subsequent frames
285 * See tcmodule-data.h for function details.
286 */
287
288 static int deshake_filter_video(TCModuleInstance *self,
289 vframe_list_t *frame)
290 {
291 DeshakeData *sd = NULL;
292
293 TC_MODULE_SELF_CHECK(self, "filter_video");
294 TC_MODULE_SELF_CHECK(frame, "filter_video");
295
296 sd = self->userdata;
297 VSMotionDetect* md = &(sd->md);
298 VSTransformData* td = &(sd->td);
299 LocalMotions localmotions;
300 VSTransform motion;
301 VSFrame vsFrame;
302 vsFrameFillFromBuffer(&vsFrame,frame->video_buf, &md->fi);
303
304 if(vsMotionDetection(md, &localmotions, &vsFrame)!= VS_OK){
305 tc_log_error(MOD_NAME, "motion detection failed");
306 return TC_ERROR;
307 }
308
309 if(vsWriteToFile(md, sd->f, &localmotions) != VS_OK){
310 tc_log_error(MOD_NAME, "cannot write to file!");
311 return TC_ERROR;
312 }
313 motion = vsSimpleMotionsToTransform(td->fiSrc, td->conf.modName, &localmotions);
314 vs_vector_del(&localmotions);
315
316 vsTransformPrepare(td, &vsFrame, &vsFrame);
317
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); */
322
323 vsDoTransform(td, t);
324
325 vsTransformFinish(td);
326 return TC_OK;
327 }
328
329 /**
330 * deshake_stop: Reset this instance of the module. See tcmodule-data.h
331 * for function details.
332 */
333
334 static int deshake_stop(TCModuleInstance *self)
335 {
336 DeshakeData *sd = NULL;
337 TC_MODULE_SELF_CHECK(self, "stop");
338 sd = self->userdata;
339 // print transs
340 if (sd->f) {
341 fclose(sd->f);
342 sd->f = NULL;
343 }
344
345 vsMotionDetectionCleanup(&sd->md);
346 if (sd->result) {
347 tc_free(sd->result);
348 sd->result = NULL;
349 }
350
351 vsTransformDataCleanup(&sd->td);
352
353 return TC_OK;
354 }
355
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; \
362 }
363
364 /**
365 * deshake_inspect: Return the value of an option in this instance of
366 * the module. See tcmodule-data.h for function details.
367 */
368
369 static int deshake_inspect(TCModuleInstance *self,
370 const char *param, const char **value)
371 {
372 DeshakeData *sd = NULL;
373
374 TC_MODULE_SELF_CHECK(self, "inspect");
375 TC_MODULE_SELF_CHECK(param, "inspect");
376 TC_MODULE_SELF_CHECK(value, "inspect");
377 sd = self->userdata;
378
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;
385 }
386
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);
399
400 return TC_OK;
401 }
402
403 static const TCCodecID deshake_codecs_in[] = {
404 TC_CODEC_YUV420P, TC_CODEC_YUV422P, TC_CODEC_RGB, TC_CODEC_ERROR
405 };
406 static const TCCodecID deshake_codecs_out[] = {
407 TC_CODEC_YUV420P, TC_CODEC_YUV422P, TC_CODEC_RGB, TC_CODEC_ERROR
408 };
409 TC_MODULE_FILTER_FORMATS(deshake);
410
411 TC_MODULE_INFO(deshake);
412
413 static const TCModuleClass deshake_class = {
414 TC_MODULE_CLASS_HEAD(deshake),
415
416 .init = deshake_init,
417 .fini = deshake_fini,
418 .configure = deshake_configure,
419 .stop = deshake_stop,
420 .inspect = deshake_inspect,
421
422 .filter_video = deshake_filter_video,
423 };
424
425 TC_MODULE_ENTRY_POINT(deshake)
426
427 /*************************************************************************/
428
429 static int deshake_get_config(TCModuleInstance *self, char *options)
430 {
431 TC_MODULE_SELF_CHECK(self, "get_config");
432
433 optstr_filter_desc(options, MOD_NAME, MOD_CAP, MOD_VERSION,
434 MOD_AUTHOR, "VRY4", "1");
435
436 return TC_OK;
437 }
438
439 static int deshake_process(TCModuleInstance *self, frame_list_t *frame)
440 {
441 TC_MODULE_SELF_CHECK(self, "process");
442
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);
446 }
447 return TC_OK;
448 }
449
450 /*************************************************************************/
451
452 TC_FILTER_OLDINTERFACE(deshake)
453
454 /*************************************************************************/
455
456 /*
457 * Local variables:
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
462 * End:
463 *
464 * vim: expandtab shiftwidth=2:
465 */