Imported Debian version 1.0~trusty
[deb_vid.stab.git] / transcode / filter_transform.c
CommitLineData
80f575fc
DM
1/*
2 * filter_transform.c
3 *
4 * Copyright (C) Georg Martius - June 2007
5 * georg dot martius at web dot de
6 *
7 * This file is part of transcode, a video stream processing tool
8 *
9 * transcode is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2, or (at your option)
12 * any later version.
13 *
14 * transcode is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with GNU Make; see the file COPYING. If not, write to
21 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 * Typical call:
24 * transcode -J transform -i inp.mpeg -y xdiv,tcaud inp_stab.avi
25*/
26
27#include "libvidstab.h"
28
29#define MOD_NAME "filter_transform.so"
30#define MOD_VERSION LIBVIDSTAB_VERSION
31#define MOD_CAP "transforms each frame according to transformations\n\
32 given in an input file (e.g. translation, rotate) see also filter stabilize"
33#define MOD_AUTHOR "Georg Martius"
34#define MOD_FEATURES \
35 TC_MODULE_FEATURE_FILTER|TC_MODULE_FEATURE_VIDEO
36#define MOD_FLAGS \
37 TC_MODULE_FLAG_RECONFIGURABLE
38
39#include "transcode.h"
40#include "filter.h"
41
42#include "libtc/libtc.h"
43#include "libtc/optstr.h"
44#include "libtc/tccodecs.h"
45#include "libtc/tcmodule-plugin.h"
46
47#include "transcode_specifics.h"
48
49#define DEFAULT_TRANS_FILE_NAME "transforms.dat"
50
51typedef struct {
52 VSTransformData td;
53 vob_t* vob; // pointer to information structure
54
55 VSTransformations trans; // transformations
56
57
58 double sharpen; // amount of sharpening
59 char input[TC_BUF_LINE];
60 char conf_str[TC_BUF_MIN];
61} FilterData;
62
63/**
64 * transform_init: Initialize this instance of the module. See
65 * tcmodule-data.h for function details.
66 */
67static int transform_init(TCModuleInstance *self, uint32_t features)
68{
69 FilterData* fd = NULL;
70 TC_MODULE_SELF_CHECK(self, "init");
71 TC_MODULE_INIT_CHECK(self, MOD_FEATURES, features);
72
73 setLogFunctions();
74
75 fd = tc_zalloc(sizeof(FilterData));
76 if (fd == NULL) {
77 tc_log_error(MOD_NAME, "init: out of memory!");
78 return TC_ERROR;
79 }
80 self->userdata = fd;
81 if (verbose) {
82 tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP);
83 }
84
85 return TC_OK;
86}
87
88
89/**
90 * transform_configure: Configure this instance of the module. See
91 * tcmodule-data.h for function details.
92 */
93static int transform_configure(TCModuleInstance *self,
94 const char *options, vob_t *vob)
95{
96 FilterData *fd = NULL;
97 char* filenamecopy, *filebasename;
98 FILE* f;
99 TC_MODULE_SELF_CHECK(self, "configure");
100
101 fd = self->userdata;
102 VSTransformData* td = &(fd->td);
103
104 fd->vob = vob;
105 if (!fd->vob)
106 return TC_ERROR; /* cannot happen */
107
108 /**** Initialise private data structure */
109
110 VSFrameInfo fi_src;
111 VSFrameInfo fi_dest;
112 vsFrameInfoInit(&fi_src, fd->vob->ex_v_width, fd->vob->ex_v_height,
113 transcode2ourPF(fd->vob->im_v_codec));
114 vsFrameInfoInit(&fi_dest, fd->vob->ex_v_width, fd->vob->ex_v_height,
115 transcode2ourPF(fd->vob->im_v_codec));
116
117 VSTransformConfig conf = vsTransformGetDefaultConfig(MOD_NAME);
118 conf.verbose = verbose;
119 fd->sharpen = 0.8;
120
121
122 vsTransformationsInit(&fd->trans);
123
124 filenamecopy = tc_strdup(fd->vob->video_in_file);
125 filebasename = basename(filenamecopy);
126 if (strlen(filebasename) < TC_BUF_LINE - 4) {
127 tc_snprintf(fd->input, TC_BUF_LINE, "%s.trf", filebasename);
128 } else {
129 tc_log_warn(MOD_NAME, "input name too long, using default `%s'",
130 DEFAULT_TRANS_FILE_NAME);
131 tc_snprintf(fd->input, TC_BUF_LINE, DEFAULT_TRANS_FILE_NAME);
132 }
133
134
135
136 /* process remaining options */
137 if (options != NULL) {
138 // We support also the help option.
139 if(optstr_lookup(options, "help")) {
140 tc_log_info(MOD_NAME,vs_transform_help);
141 return(TC_IMPORT_ERROR);
142 }
143 optstr_get(options, "input", "%[^:]", (char*)&fd->input);
144 optstr_get(options, "maxshift", "%d", &conf.maxShift);
145 optstr_get(options, "maxangle", "%lf", &conf.maxAngle);
146 optstr_get(options, "smoothing", "%d", &conf.smoothing);
147 optstr_get(options, "invert" , "%d", &conf.invert);
148 optstr_get(options, "relative" , "%d", &conf.relative);
149 optstr_get(options, "zoom" ,"%lf", &conf.zoom);
150 optstr_get(options, "optzoom" , "%d", &conf.optZoom);
151 optstr_get(options, "zoomspeed", "%lf",&conf.zoomSpeed);
152 optstr_get(options, "interpol" , "%d", (int*)(&conf.interpolType));
153 optstr_get(options, "sharpen" ,"%lf", &fd->sharpen);
154 if(optstr_lookup(options, "tripod")){
155 tc_log_info(MOD_NAME,"Virtual tripod mode: relative=False, smoothing=0");
156 conf.relative=0;
157 conf.smoothing=0;
158 }
159 }
160
161 if(vsTransformDataInit(td, &conf, &fi_src, &fi_dest) != VS_OK){
162 tc_log_error(MOD_NAME, "initialization of VSTransformData failed");
163 return TC_ERROR;
164 }
165 vsTransformGetConfig(&conf,td);
166
167 if (verbose) {
168 tc_log_info(MOD_NAME, "Image Transformation/Stabilization Settings:");
169 tc_log_info(MOD_NAME, " input = %s", fd->input);
170 tc_log_info(MOD_NAME, " smoothing = %d", conf.smoothing);
171 tc_log_info(MOD_NAME, " maxshift = %d", conf.maxShift);
172 tc_log_info(MOD_NAME, " maxangle = %f", conf.maxAngle);
173 tc_log_info(MOD_NAME, " crop = %s",
174 conf.crop ? "Black" : "Keep");
175 tc_log_info(MOD_NAME, " relative = %s",
176 conf.relative ? "True": "False");
177 tc_log_info(MOD_NAME, " invert = %s",
178 conf.invert ? "True" : "False");
179 tc_log_info(MOD_NAME, " zoom = %f", conf.zoom);
180 tc_log_info(MOD_NAME, " optzoom = %d", conf.optZoom);
181 if(conf.optZoom==2){
182 tc_log_info(MOD_NAME, " zoomspeed = %f", conf.zoomSpeed);
183 }
184 tc_log_info(MOD_NAME, " interpol = %s",
185 getInterpolationTypeName(conf.interpolType));
186 tc_log_info(MOD_NAME, " sharpen = %f", fd->sharpen);
187 }
188
189 f = fopen(fd->input, "r");
190 if (f == NULL) {
191 tc_log_error(MOD_NAME, "cannot open input file %s!\n", fd->input);
192 /* return (-1); when called using tcmodinfo this will fail */
193 } else {
194 VSManyLocalMotions mlms;
195 if(vsReadLocalMotionsFile(f,&mlms)==VS_OK){
196 // calculate the actual transforms from the localmotions
197 if(vsLocalmotions2Transforms(td, &mlms,&fd->trans)!=VS_OK)
198 tc_log_error(MOD_NAME, "calculating transformations failed!\n");
199 }else{ // try to read old format
200 if (!vsReadOldTransforms(td, f, &fd->trans)) { /* read input file */
201 tc_log_error(MOD_NAME, "error parsing input file %s!\n", fd->input);
202 }
203 }
204 }
205 fclose(f);
206
207 if (vsPreprocessTransforms(td, &fd->trans)!= VS_OK ) {
208 tc_log_error(MOD_NAME, "error while preprocessing transforms!");
209 return TC_ERROR;
210 }
211
212 // sharpen is still in transcode...
213 /* Is this the right point to add the filter? Seems to be the case.*/
214 if(fd->sharpen>0){
215 /* load unsharp filter */
216 char unsharp_param[256];
217 sprintf(unsharp_param,"luma=%f:%s:chroma=%f:%s",
218 fd->sharpen, "luma_matrix=5x5",
219 fd->sharpen/2, "chroma_matrix=5x5");
220 if (!tc_filter_add("unsharp", unsharp_param)) {
221 tc_log_warn(MOD_NAME, "cannot load unsharp filter!");
222 }
223 }
224
225 return TC_OK;
226}
227
228
229/**
230 * transform_filter_video: performs the transformation of frames
231 * See tcmodule-data.h for function details.
232 */
233static int transform_filter_video(TCModuleInstance *self,
234 vframe_list_t *frame)
235{
236 FilterData *fd = NULL;
237
238 TC_MODULE_SELF_CHECK(self, "filter_video");
239 TC_MODULE_SELF_CHECK(frame, "filter_video");
240
241 fd = self->userdata;
242 VSFrame vsFrame;
243 vsFrameFillFromBuffer(&vsFrame,frame->video_buf, vsTransformGetSrcFrameInfo(&fd->td));
244
245 vsTransformPrepare(&fd->td, &vsFrame, &vsFrame);
246
247 VSTransform t = vsGetNextTransform(&fd->td, &fd->trans);
248
249 vsDoTransform(&fd->td, t);
250
251 vsTransformFinish(&fd->td);
252 return TC_OK;
253}
254
255
256/**
257 * transform_fini: Clean up after this instance of the module. See
258 * tcmodule-data.h for function details.
259 */
260static int transform_fini(TCModuleInstance *self)
261{
262 FilterData *fd = NULL;
263 TC_MODULE_SELF_CHECK(self, "fini");
264 fd = self->userdata;
265 tc_free(fd);
266 self->userdata = NULL;
267 return TC_OK;
268}
269
270
271/**
272 * transform_stop: Reset this instance of the module. See tcmodule-data.h
273 * for function details.
274 */
275static int transform_stop(TCModuleInstance *self)
276{
277 FilterData *fd = NULL;
278 TC_MODULE_SELF_CHECK(self, "stop");
279 fd = self->userdata;
280 vsTransformDataCleanup(&fd->td);
281
282 vsTransformationsCleanup(&fd->trans);
283 return TC_OK;
284}
285
286/* checks for parameter in function _inspect */
287#define CHECKPARAM(paramname, formatstring, variable) \
288 if (optstr_lookup(param, paramname)) { \
289 tc_snprintf(fd->conf_str, sizeof(fd->conf_str), \
290 formatstring, variable); \
291 *value = fd->conf_str; \
292 }
293
294/**
295 * stabilize_inspect: Return the value of an option in this instance of
296 * the module. See tcmodule-data.h for function details.
297 */
298static int transform_inspect(TCModuleInstance *self,
299 const char *param, const char **value)
300{
301 FilterData *fd = NULL;
302 TC_MODULE_SELF_CHECK(self, "inspect");
303 TC_MODULE_SELF_CHECK(param, "inspect");
304 TC_MODULE_SELF_CHECK(value, "inspect");
305
306 fd = self->userdata;
307
308 if (optstr_lookup(param, "help")) {
309 *value = vs_transform_help;
310 }
311 VSTransformConfig conf;
312 vsTransformGetConfig(&conf,&fd->td);
313 CHECKPARAM("maxshift", "maxshift=%d", conf.maxShift);
314 CHECKPARAM("maxangle", "maxangle=%f", conf.maxAngle);
315 CHECKPARAM("smoothing","smoothing=%d", conf.smoothing);
316 CHECKPARAM("crop", "crop=%d", conf.crop);
317 CHECKPARAM("relative", "relative=%d", conf.relative);
318 CHECKPARAM("invert", "invert=%i", conf.invert);
319 CHECKPARAM("input", "input=%s", fd->input);
320 CHECKPARAM("optzoom", "optzoom=%i", conf.optZoom);
321 CHECKPARAM("zoom", "zoom=%f", conf.zoom);
322 CHECKPARAM("sharpen", "sharpen=%f", fd->sharpen);
323
324 return TC_OK;
325};
326
327
328static const TCCodecID transform_codecs_in[] = {
329 TC_CODEC_YUV420P, TC_CODEC_YUV422P, TC_CODEC_RGB, TC_CODEC_ERROR
330};
331static const TCCodecID transform_codecs_out[] = {
332 TC_CODEC_YUV420P, TC_CODEC_YUV422P, TC_CODEC_RGB, TC_CODEC_ERROR
333};
334TC_MODULE_FILTER_FORMATS(transform);
335
336TC_MODULE_INFO(transform);
337
338static const TCModuleClass transform_class = {
339 TC_MODULE_CLASS_HEAD(transform),
340
341 .init = transform_init,
342 .fini = transform_fini,
343 .configure = transform_configure,
344 .stop = transform_stop,
345 .inspect = transform_inspect,
346
347 .filter_video = transform_filter_video,
348};
349
350TC_MODULE_ENTRY_POINT(transform)
351
352/*************************************************************************/
353
354static int transform_get_config(TCModuleInstance *self, char *options)
355{
356 TC_MODULE_SELF_CHECK(self, "get_config");
357
358 optstr_filter_desc(options, MOD_NAME, MOD_CAP, MOD_VERSION,
359 MOD_AUTHOR, "VRY4", "1");
360
361 return TC_OK;
362}
363
364static int transform_process(TCModuleInstance *self, frame_list_t *frame)
365{
366 TC_MODULE_SELF_CHECK(self, "process");
367
368 if (frame->tag & TC_PRE_S_PROCESS && frame->tag & TC_VIDEO) {
369 return transform_filter_video(self, (vframe_list_t *)frame);
370 }
371 return TC_OK;
372}
373
374/*************************************************************************/
375
376TC_FILTER_OLDINTERFACE(transform)
377
378/*************************************************************************/
379
380/*
381 * Local variables:
382 * c-file-style: "stroustrup"
383 * c-file-offsets: ((case-label . *) (statement-case-intro . *))
384 * indent-tabs-mode: nil
385 * c-basic-offset: 4 t
386 * End:
387 *
388 * vim: expandtab shiftwidth=4:
389 */