OBJS = factory.o
CPPOBJS = filter_deshake.o
-CPPOBJS += filter_detect.o
-CPPOBJS += filter_transform.o
CPPOBJS += filter_vidstab.o
CXXFLAGS += -Wno-deprecated $(CFLAGS)
}
}
-int get_image_and_detect(mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable);
-int get_image_and_transform(mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable);
-
#endif /* VIDSTAB_COMMON_H_ */
#include <framework/mlt.h>
extern mlt_filter filter_deshake_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
-extern mlt_filter filter_detect_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
-extern mlt_filter filter_transform_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
extern mlt_filter filter_vidstab_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
static mlt_properties metadata( mlt_service_type type, const char *id, void *data )
MLT_REPOSITORY
{
- MLT_REGISTER( filter_type, "vid.stab.deshake", filter_deshake_init );
- MLT_REGISTER( filter_type, "vid.stab.detect", filter_detect_init );
- MLT_REGISTER( filter_type, "vid.stab.transform", filter_transform_init );
- MLT_REGISTER( filter_type, "vid.stab", filter_vidstab_init );
+ MLT_REGISTER( filter_type, "deshake", filter_deshake_init );
+ MLT_REGISTER( filter_type, "vidstab", filter_vidstab_init );
- MLT_REGISTER_METADATA( filter_type, "vid.stab.deshake", metadata, "filter_deshake.yml" );
- MLT_REGISTER_METADATA( filter_type, "vid.stab.detect", metadata, "filter_detect.yml" );
- MLT_REGISTER_METADATA( filter_type, "vid.stab.transform", metadata, "filter_transform.yml" );
- MLT_REGISTER_METADATA( filter_type, "vid.stab", metadata, "filter_vidstab.yml" );
+ MLT_REGISTER_METADATA( filter_type, "deshake", metadata, "filter_deshake.yml" );
+ MLT_REGISTER_METADATA( filter_type, "vidstab", metadata, "filter_vidstab.yml" );
}
+++ /dev/null
-/*
- * filter_detect.cpp
- * Copyright (C) 2013
- * Marco Gittler <g.marco@freenet.de>
- * Jakub Ksiezniak <j.ksiezniak@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-extern "C"
-{
-#include <vid.stab/libvidstab.h>
-#include <framework/mlt.h>
-#include <framework/mlt_animation.h>
-}
-
-#include <string.h>
-#include <assert.h>
-#include "common.h"
-
-typedef struct _stab_data
-{
- VSMotionDetect md;
- mlt_animation animation;
-} StabData;
-
-char* vectors_serializer(mlt_animation animation, int length)
-{
- return mlt_animation_serialize(animation);
-}
-
-#include <sstream>
-char* lm_serializer(LocalMotions *lms, int length)
-{
- std::ostringstream oss;
- int size = vs_vector_size(lms);
- for (int i = 0; i < size; ++i)
- {
- LocalMotion* lm = (LocalMotion*) vs_vector_get(lms, i);
- oss << lm->v.x << ' ';
- oss << lm->v.y << ' ';
- oss << lm->f.x << ' ';
- oss << lm->f.y << ' ';
- oss << lm->f.size << ' ';
- oss << lm->contrast << ' ';
- oss << lm->match << ' ';
- }
- return strdup(oss.str().c_str());
-}
-
-void lm_destructor(void *lms)
-{
- vs_vector_del(static_cast<VSVector*>(lms));
-}
-
-static void serialize_localmotions(StabData* data, LocalMotions &vectors, mlt_position pos)
-{
- mlt_animation_item_s item;
-
- // Initialize animation item
- item.is_key = 1;
- item.frame = data->md.frameNum;
- item.keyframe_type = mlt_keyframe_discrete;
- item.property = mlt_property_init();
-
- mlt_property_set_data(item.property, &vectors, 1, lm_destructor, (mlt_serialiser) lm_serializer);
- mlt_animation_insert(data->animation, &item);
- mlt_property_close(item.property);
-}
-
-static StabData* init_detect(mlt_properties properties, mlt_image_format *format, int *width, int *height)
-{
- StabData *data = new StabData;
- memset(data, 0, sizeof(StabData));
- data->animation = mlt_animation_new();
-
- VSPixelFormat pf = convertImageFormat(*format);
- VSFrameInfo fi;
- vsFrameInfoInit(&fi, *width, *height, pf);
-
- const char* filterName = mlt_properties_get(properties, "mlt_service");
-
- VSMotionDetectConfig conf = vsMotionDetectGetDefaultConfig(filterName);
- conf.shakiness = mlt_properties_get_int(properties, "shakiness");
- conf.accuracy = mlt_properties_get_int(properties, "accuracy");
- conf.stepSize = mlt_properties_get_int(properties, "stepsize");
- conf.algo = mlt_properties_get_int(properties, "algo");
- conf.contrastThreshold = mlt_properties_get_double(properties, "mincontrast");
- conf.show = mlt_properties_get_int(properties, "show");
- conf.virtualTripod = mlt_properties_get_int(properties, "tripod");
- vsMotionDetectInit(&data->md, &conf, &fi);
-
- // add vectors to properties
- mlt_properties_set_data(properties, "vectors", data->animation, 1, (mlt_destructor) mlt_animation_close,
- (mlt_serialiser) vectors_serializer);
- return data;
-}
-
-void destroy_detect(StabData *data)
-{
- if (data)
- {
- vsMotionDetectionCleanup(&data->md);
- delete data;
- }
-}
-
-int get_image_and_detect(mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable)
-{
- mlt_filter filter = (mlt_filter) mlt_frame_pop_service(frame);
- mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
-
- *format = mlt_image_yuv420p;
-
- writable = writable || mlt_properties_get_int(properties, "show") ? 1 : 0;
-
- int error = mlt_frame_get_image(frame, image, format, width, height, writable);
- if (!error)
- {
- // Service locks are for concurrency control
- mlt_service_lock(MLT_FILTER_SERVICE(filter));
-
- StabData *data = static_cast<StabData*>(mlt_properties_get_data(properties, "_stab_data", NULL));
- if (!data)
- {
- data = init_detect(properties, format, width, height);
- mlt_properties_set_data(properties, "_stab_data", data, 0, (mlt_destructor) destroy_detect, NULL);
- }
-
- VSMotionDetect* md = &data->md;
- LocalMotions localmotions;
- VSFrame vsFrame;
- vsFrameFillFromBuffer(&vsFrame, *image, &md->fi);
-
- // detect and save motions
- vsMotionDetection(md, &localmotions, &vsFrame);
- mlt_position pos = mlt_filter_get_position( filter, frame );
- serialize_localmotions(data, localmotions, pos);
-
- mlt_service_unlock(MLT_FILTER_SERVICE(filter));
- }
-
- return error;
-}
-
-static mlt_frame process_filter(mlt_filter filter, mlt_frame frame)
-{
- mlt_frame_push_service(frame, filter);
- mlt_frame_push_get_image(frame, get_image_and_detect);
- return frame;
-}
-
-extern "C"
-{
-
-mlt_filter filter_detect_init(mlt_profile profile, mlt_service_type type, const char *id, char *arg)
-{
- mlt_filter filter = NULL;
-
- if ((filter = mlt_filter_new()))
- {
- filter->process = process_filter;
-
- mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
-
- //properties for stabilize
- mlt_properties_set(properties, "shakiness", "4");
- mlt_properties_set(properties, "accuracy", "4");
- mlt_properties_set(properties, "stepsize", "6");
- mlt_properties_set(properties, "algo", "1");
- mlt_properties_set(properties, "mincontrast", "0.3");
- mlt_properties_set(properties, "show", "0");
- mlt_properties_set(properties, "tripod", "0");
-
- // properties for transform
- mlt_properties_set(properties, "smoothing", "15");
- mlt_properties_set(properties, "maxshift", "-1");
- mlt_properties_set(properties, "maxangle", "-1");
- mlt_properties_set(properties, "crop", "0");
- mlt_properties_set(properties, "invert", "0");
- mlt_properties_set(properties, "relative", "1");
- mlt_properties_set(properties, "zoom", "0");
- mlt_properties_set(properties, "optzoom", "1");
- mlt_properties_set(properties, "zoomspeed", "0.25");
-
- mlt_properties_set(properties, "vid.stab.version", LIBVIDSTAB_VERSION);
-
- return filter;
- }
-
- return NULL;
-}
-
-}
+++ /dev/null
-schema_version: 0.1
-type: filter
-identifier: vid.stab.detect
-title: Vid.Stab Detect
-copyright: Jakub Ksiezniak
-creator: Marco Gittler <g.marco@freenet.de>
-version: 1
-license: GPL
-language: en
-url: http://public.hronopik.de/vid.stab/
-tags:
- - Video
-description: Stabilize Video (for wiggly/rolling video)
-notes: >
- This filter requires two passes. The first pass performs analysis and stores
- the result in the vectors property. The second pass applies the vectors to
- the image.
- To use with melt, use 'melt ... -consumer xml:output.mlt all=1' for the
- first pass. For the second pass, use output.mlt as the input.
-
-parameters:
- - identifier: vectors (transform)
- title: Vectors
- type: geometry
- description: >
- A set of X/Y coordinates by which to adjust the image.
- When this is not supplied, the filter computes the vectors and stores
- them in this property when the last frame has been processed.
-
- - identifier: shakiness
- title: Shakiness
- type: integer
- description: How shaky is the video (analysis)
- readonly: no
- required: no
- minimum: 1
- maximum: 10
- default: 4
- mutable: yes
- widget: spinner
-
- - identifier: accuracy
- title: Accuracy
- type: integer
- description: Accuracy of shakiness detection (analysis)
- readonly: no
- required: no
- minimum: 1
- maximum: 15
- default: 4
- mutable: yes
- widget: spinner
-
- - identifier: stepsize
- title: Stepsize
- type: integer
- description: Step size of search process (analysis)
- readonly: no
- required: no
- minimum: 0
- maximum: 100
- default: 6
- mutable: yes
- widget: spinner
-
- - identifier: algo
- title: Algorithm
- type: integer
- description: 0 = brute force (translation only), 1 = small measurement fields (analysis)
- readonly: no
- required: no
- minimum: 0
- maximum: 1
- default: 1
- mutable: yes
- widget: spinner
-
- - identifier: mincontrast
- title: Minimum Contrast
- type: float
- description: Below this contrast, a field is discarded (analysis)
- readonly: no
- required: no
- minimum: 0
- maximum: 1
- default: 0.3
- mutable: yes
- widget: spinner
-
- - identifier: show
- title: Show
- type: integer
- description: 0 = draw nothing, 1 or 2 = show fields and transforms (analysis)
- readonly: no
- required: no
- minimum: 0
- maximum: 2
- default: 0
- mutable: yes
- widget: spinner
-
- - identifier: tripod
- title: Tripod
- type: integer
- description: virtual tripod mode (if >0): motion is compared to a reference frame (frame N is the value)
- readonly: no
- required: no
- minimum: 0
- maximum: 100000
- default: 0
- mutable: yes
- widget: spinner
-
- - identifier: smoothing
- title: Smoothing
- type: integer
- description: number of frames for lowpass filtering (2N + 1 frames) (transform)
- readonly: no
- required: no
- minimum: 0
- maximum: 100
- default: 15
- mutable: yes
- widget: spinner
-
- - identifier: maxshift
- title: Maxshift
- type: integer
- description: maximum translation, -1 = no limit (transform)
- unit: pixels
- readonly: no
- required: no
- minimum: -1
- maximum: 1000
- default: -1
- mutable: yes
- widget: spinner
-
- - identifier: maxangle
- title: Maxangle
- type: float
- description: max angle to rotate, -1 = no limit (transform)
- unit: radians
- readonly: no
- required: no
- minimum: -1
- maximum: 3.142
- default: -1
- mutable: yes
- widget: spinner
-
- - identifier: crop
- title: Crop
- type: integer
- description: 0 = keep border, 1 = black background (transform)
- readonly: no
- required: no
- minimum: 0
- maximum: 1
- default: 0
- mutable: yes
- widget: spinner
-
- - identifier: invert
- title: Invert
- type: integer
- description: Invert transforms (transform)
- readonly: no
- required: no
- minimum: 0
- maximum: 1
- default: 0
- mutable: yes
- widget: spinner
-
- - identifier: relative
- title: Relative Transform
- type: integer
- description: 0 = absolute, 1 = relative (transform)
- readonly: no
- required: no
- minimum: 0
- maximum: 1
- default: 1
- mutable: yes
- widget: spinner
-
- - identifier: zoom
- title: Zoom
- type: integer
- description: additional zoom amount (transform)
- unit: percent
- readonly: no
- required: no
- minimum: -500
- maximum: 500
- default: 0
- mutable: yes
- widget: spinner
-
- - identifier: optzoom
- title: Optimal Zoom
- type: integer
- description: automatically determine optimal zoom. 1 - static zoom, 2 - adaptive zoom (transform)
- readonly: no
- required: no
- minimum: 0
- maximum: 2
- default: 1
- mutable: yes
- widget: spinner
-
- - identifier: zoomspeed
- title: Optimal Zoom Speed
- type: float
- description: zoom per frame in percent, (used when optzoom = 2) (transform)
- readonly: no
- required: no
- minimum: 0
- maximum: 1
- default: 0.25
- mutable: yes
- widget: spinner
-
- - identifier: refresh
- description: >
- Applications should set this when it updates a transform parameter.
- type: integer
- minimum: 0
- maximum: 1
+++ /dev/null
-/*
- * filter_transform.cpp
- * Copyright (C) 2013
- * Marco Gittler <g.marco@freenet.de>
- * Jakub Ksiezniak <j.ksiezniak@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-extern "C"
-{
-#include <vid.stab/libvidstab.h>
-#include <framework/mlt.h>
-#include <framework/mlt_animation.h>
-}
-
-#include <string.h>
-#include <assert.h>
-#include <sstream>
-#include "common.h"
-
-typedef struct
-{
- VSTransformData td;
- VSTransformations trans;
-} TransformData;
-
-int lm_deserialize(LocalMotions *lms, mlt_property property)
-{
- std::istringstream iss(mlt_property_get_string(property));
- vs_vector_init(lms, 0);
-
- while (iss.good())
- {
- LocalMotion lm;
- iss >> lm.v.x >> lm.v.y >> lm.f.x >> lm.f.y >> lm.f.size >> lm.contrast >> lm.match;
- if (iss.fail())
- {
- break;
- }
- vs_vector_append_dup(lms, &lm, sizeof(lm));
- }
- return 0;
-}
-
-int vectors_deserialize(mlt_animation anim, VSManyLocalMotions *mlms)
-{
- int error = 0;
- mlt_animation_item_s item;
- item.property = mlt_property_init();
-
- vs_vector_init(mlms, 1024); // initial number of frames, but it will be increased
-
- int length = mlt_animation_get_length(anim);
- for (int i = 0; i < length; ++i)
- {
- LocalMotions lms;
-
- // read lms
- mlt_animation_get_item(anim, &item, i + 1);
- if ((error = lm_deserialize(&lms, item.property)))
- {
- break;
- }
-
- vs_vector_set_dup(mlms, i, &lms, sizeof(LocalMotions));
- }
-
- mlt_property_close(item.property);
- return error;
-}
-
-void destroy_transforms(TransformData *data)
-{
- if (data)
- {
- vsTransformDataCleanup(&data->td);
- vsTransformationsCleanup(&data->trans);
- delete data;
- }
-}
-
-TransformData* initialize_transforms(int *width, int *height, mlt_image_format *format,
- mlt_properties properties, const char* interps)
-{
- TransformData *data = new TransformData;
- memset(data, 0, sizeof(TransformData));
-
- VSPixelFormat pf = convertImageFormat(*format);
- VSFrameInfo fi_src, fi_dst;
- vsFrameInfoInit(&fi_src, *width, *height, pf);
- vsFrameInfoInit(&fi_dst, *width, *height, pf);
-
- const char* filterName = mlt_properties_get(properties, "mlt_service");
-
- VSTransformConfig conf = vsTransformGetDefaultConfig(filterName);
- conf.smoothing = mlt_properties_get_int(properties, "smoothing");
- conf.maxShift = mlt_properties_get_int(properties, "maxshift");
- conf.maxAngle = mlt_properties_get_double(properties, "maxangle");
- conf.crop = (VSBorderType) mlt_properties_get_int(properties, "crop");
- conf.zoom = mlt_properties_get_int(properties, "zoom");
- conf.optZoom = mlt_properties_get_int(properties, "optzoom");
- conf.zoomSpeed = mlt_properties_get_double(properties, "zoomspeed");
- conf.relative = mlt_properties_get_int(properties, "relative");
- conf.invert = mlt_properties_get_int(properties, "invert");
- if (mlt_properties_get_int(properties, "tripod") != 0)
- {
- // Virtual tripod mode: relative=False, smoothing=0
- conf.relative = 0;
- conf.smoothing = 0;
- }
-
- // by default a bilinear interpolation is selected
- conf.interpolType = VS_BiLinear;
- if (strcmp(interps, "nearest") == 0 || strcmp(interps, "neighbor") == 0)
- conf.interpolType = VS_Zero;
- else if (strcmp(interps, "tiles") == 0 || strcmp(interps, "fast_bilinear") == 0)
- conf.interpolType = VS_Linear;
-
- vsTransformDataInit(&data->td, &conf, &fi_src, &fi_dst);
- vsTransformationsInit(&data->trans);
-
- // load transformations
- mlt_animation animation = mlt_animation_new();
- char* strAnim = mlt_properties_get(properties, "vectors");
- if (mlt_animation_parse(animation, strAnim, 0, 0, NULL))
- {
- mlt_log_warning(NULL, "parse failed\n");
- mlt_animation_close(animation);
- destroy_transforms(data);
- return NULL;
- }
-
- VSManyLocalMotions mlms;
- if (vectors_deserialize(animation, &mlms))
- {
- mlt_animation_close(animation);
- destroy_transforms(data);
- return NULL;
- }
-
- mlt_animation_close(animation);
-
- vsLocalmotions2Transforms(&data->td, &mlms, &data->trans);
- vsPreprocessTransforms(&data->td, &data->trans);
- return data;
-}
-
-int get_image_and_transform(mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable)
-{
- int error = 0;
- mlt_filter filter = (mlt_filter) mlt_frame_pop_service(frame);
- mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
-
- *format = mlt_image_yuv420p;
-
- error = mlt_frame_get_image(frame, image, format, width, height, 1);
- if (!error)
- {
- // Service locks are for concurrency control
- mlt_service_lock(MLT_FILTER_SERVICE(filter));
-
- TransformData *data = static_cast<TransformData*>(mlt_properties_get_data(properties, "_transform_data", NULL));
-
- // Handle signal from app to re-init data
- if (mlt_properties_get_int(properties, "refresh"))
- {
- mlt_properties_set(properties, "refresh", NULL);
- destroy_transforms(data);
- data = NULL;
- }
-
- if (!data)
- {
- const char *interps = mlt_properties_get(MLT_FRAME_PROPERTIES(frame), "rescale.interp");
- data = initialize_transforms(width, height, format, properties, interps);
- if(!data) {
- mlt_service_unlock(MLT_FILTER_SERVICE(filter));
- return 1; // return error code
- }
- mlt_properties_set_data(properties, "_transform_data", data, 0, (mlt_destructor) destroy_transforms, NULL);
- }
-
- VSTransformData* td = &data->td;
- VSFrame vsFrame;
- vsFrameFillFromBuffer(&vsFrame, *image, vsTransformGetSrcFrameInfo(td));
-
- // transform frame
- data->trans.current = mlt_filter_get_position(filter, frame);
- vsTransformPrepare(td, &vsFrame, &vsFrame);
- VSTransform t = vsGetNextTransform(td, &data->trans);
- vsDoTransform(td, t);
- vsTransformFinish(td);
-
- mlt_service_unlock(MLT_FILTER_SERVICE(filter));
- }
-
- return error;
-}
-
-static mlt_frame process_filter(mlt_filter filter, mlt_frame frame)
-{
- mlt_frame_push_service(frame, filter);
- mlt_frame_push_get_image(frame, get_image_and_transform);
- return frame;
-}
-
-extern "C"
-{
-
-mlt_filter filter_transform_init(mlt_profile profile, mlt_service_type type, const char *id, char *arg)
-{
- mlt_filter filter = NULL;
-
- if ((filter = mlt_filter_new()))
- {
- filter->process = process_filter;
-
- mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
-
- // properties for transform
- mlt_properties_set(properties, "smoothing", "10");
- mlt_properties_set(properties, "maxshift", "-1");
- mlt_properties_set(properties, "maxangle", "-1");
- mlt_properties_set(properties, "crop", "0");
- mlt_properties_set(properties, "invert", "0");
- mlt_properties_set(properties, "relative", "1");
- mlt_properties_set(properties, "zoom", "0");
- mlt_properties_set(properties, "optzoom", "1");
- mlt_properties_set(properties, "zoomspeed", "0.25");
-
- return filter;
- }
-
- return NULL;
-}
-
-}
+++ /dev/null
-schema_version: 0.1
-type: filter
-identifier: videostab2
-title: Videostab2
-copyright: Copyright (C) 2011 Marco Gittler
-creator: Marco Gittler <g.marco@freenet.de>
-version: 0.1
-license: GPL
-language: en
-url: http://public.hronopik.de/vid.stab/
-tags:
- - Video
-description: Stabilize Video (for wiggly/rolling video)
-notes: >
- This filter requires two passes. The first pass performs analysis and stores
- the result in the vectors property. The second pass applies the vectors to
- the image.
- To use with melt, use 'melt ... -consumer xml:output.mlt all=1' for the
- first pass. For the second pass, use output.mlt as the input.
-
-parameters:
- - identifier: vectors (transform)
- title: Vectors
- type: geometry
- description: >
- A set of X/Y coordinates by which to adjust the image.
- When this is not supplied, the filter computes the vectors and stores
- them in this property when the last frame has been processed.
-
- - identifier: shakiness
- title: Shakiness
- type: integer
- description: How shaky is the video (analysis)
- readonly: no
- required: no
- minimum: 1
- maximum: 10
- default: 4
- mutable: yes
- widget: spinner
-
- - identifier: accuracy
- title: Accuracy
- type: integer
- description: Accuracy of shakiness detection (analysis)
- readonly: no
- required: no
- minimum: 1
- maximum: 15
- default: 4
- mutable: yes
- widget: spinner
-
- - identifier: stepsize
- title: Stepsize
- type: integer
- description: Step size of search process (analysis)
- readonly: no
- required: no
- minimum: 0
- maximum: 100
- default: 6
- mutable: yes
- widget: spinner
-
- - identifier: algo
- title: Algorithm
- type: integer
- description: 0 = brute force (translation only), 1 = small measurement fields (analysis)
- readonly: no
- required: no
- minimum: 0
- maximum: 1
- default: 1
- mutable: yes
- widget: spinner
-
- - identifier: mincontrast
- title: Minimum Contrast
- type: float
- description: Below this contrast, a field is discarded (analysis)
- readonly: no
- required: no
- minimum: 0
- maximum: 1
- default: 0.3
- mutable: yes
- widget: spinner
-
- - identifier: show
- title: Show
- type: integer
- description: 0 = draw nothing, 1 or 2 = show fields and transforms (analysis)
- readonly: no
- required: no
- minimum: 0
- maximum: 2
- default: 0
- mutable: yes
- widget: spinner
-
- - identifier: smoothing
- title: Smoothing
- type: integer
- description: number of frames for lowpass filtering (2N + 1 frames) (transform)
- readonly: no
- required: no
- minimum: 0
- maximum: 100
- default: 15
- mutable: yes
- widget: spinner
-
- - identifier: maxshift
- title: Maxshift
- type: integer
- description: maximum translation, -1 = no limit (transform)
- unit: pixels
- readonly: no
- required: no
- minimum: -1
- maximum: 1000
- default: -1
- mutable: yes
- widget: spinner
-
- - identifier: maxangle
- title: Maxangle
- type: float
- description: max angle to rotate, -1 = no limit (transform)
- unit: radians
- readonly: no
- required: no
- minimum: -1
- maximum: 3.142
- default: -1
- mutable: yes
- widget: spinner
-
- - identifier: crop
- title: Crop
- type: integer
- description: 0 = keep border, 1 = black background (transform)
- readonly: no
- required: no
- minimum: 0
- maximum: 1
- default: 0
- mutable: yes
- widget: spinner
-
- - identifier: invert
- title: Invert
- type: integer
- description: Invert transforms (transform)
- readonly: no
- required: no
- minimum: 0
- maximum: 1
- default: 0
- mutable: yes
- widget: spinner
-
- - identifier: relative
- title: Relative Transform
- type: integer
- description: 0 = absolute, 1 = relative (transform)
- readonly: no
- required: no
- minimum: 0
- maximum: 1
- default: 1
- mutable: yes
- widget: spinner
-
- - identifier: zoom
- title: Zoom
- type: integer
- description: additional zoom amount (transform)
- unit: percent
- readonly: no
- required: no
- minimum: -500
- maximum: 500
- default: 0
- mutable: yes
- widget: spinner
-
- - identifier: optzoom
- title: Optimal Zoom
- type: integer
- description: automatically determine optimal zoom. 1 - static zoom, 2 - adaptive zoom (transform)
- readonly: no
- required: no
- minimum: 0
- maximum: 2
- default: 1
- mutable: yes
- widget: spinner
-
- - identifier: zoomspeed
- title: Optimal Zoom Speed
- type: float
- description: zoom per frame in percent, (used when optzoom = 2) (transform)
- readonly: no
- required: no
- minimum: 0
- maximum: 1
- default: 0.25
- mutable: yes
- widget: spinner
-
- - identifier: refresh
- description: >
- Applications should set this when it updates a transform parameter.
- type: integer
- minimum: 0
- maximum: 1
/*
- * filter_deshake.cpp
+ * filter_vidstab.cpp
* Copyright (C) 2013
* Marco Gittler <g.marco@freenet.de>
* Jakub Ksiezniak <j.ksiezniak@gmail.com>
{
#include <vid.stab/libvidstab.h>
#include <framework/mlt.h>
+#include <framework/mlt_animation.h>
}
+#include <sstream>
#include <string.h>
#include <assert.h>
#include "common.h"
+
+typedef struct _stab_data
+{
+ VSMotionDetect md;
+ mlt_animation animation;
+} StabData;
+
+typedef struct
+{
+ VSTransformData td;
+ VSTransformations trans;
+} TransformData;
+
+
+char* vectors_serializer(mlt_animation animation, int length)
+{
+ return mlt_animation_serialize(animation);
+}
+
+char* lm_serializer(LocalMotions *lms, int length)
+{
+ std::ostringstream oss;
+ int size = vs_vector_size(lms);
+ for (int i = 0; i < size; ++i)
+ {
+ LocalMotion* lm = (LocalMotion*) vs_vector_get(lms, i);
+ oss << lm->v.x << ' ';
+ oss << lm->v.y << ' ';
+ oss << lm->f.x << ' ';
+ oss << lm->f.y << ' ';
+ oss << lm->f.size << ' ';
+ oss << lm->contrast << ' ';
+ oss << lm->match << ' ';
+ }
+ return strdup(oss.str().c_str());
+}
+
+int lm_deserialize(LocalMotions *lms, mlt_property property)
+{
+ std::istringstream iss(mlt_property_get_string(property));
+ vs_vector_init(lms, 0);
+
+ while (iss.good())
+ {
+ LocalMotion lm;
+ iss >> lm.v.x >> lm.v.y >> lm.f.x >> lm.f.y >> lm.f.size >> lm.contrast >> lm.match;
+ if (iss.fail())
+ {
+ break;
+ }
+ vs_vector_append_dup(lms, &lm, sizeof(lm));
+ }
+ return 0;
+}
+
+void lm_destructor(void *lms)
+{
+ vs_vector_del(static_cast<VSVector*>(lms));
+}
+
+static void serialize_localmotions(StabData* data, LocalMotions &vectors, mlt_position pos)
+{
+ mlt_animation_item_s item;
+
+ // Initialize animation item
+ item.is_key = 1;
+ item.frame = data->md.frameNum;
+ item.keyframe_type = mlt_keyframe_discrete;
+ item.property = mlt_property_init();
+
+ mlt_property_set_data(item.property, &vectors, 1, lm_destructor, (mlt_serialiser) lm_serializer);
+ mlt_animation_insert(data->animation, &item);
+ mlt_property_close(item.property);
+}
+
+int vectors_deserialize(mlt_animation anim, VSManyLocalMotions *mlms)
+{
+ int error = 0;
+ mlt_animation_item_s item;
+ item.property = mlt_property_init();
+
+ vs_vector_init(mlms, 1024); // initial number of frames, but it will be increased
+
+ int length = mlt_animation_get_length(anim);
+ for (int i = 0; i < length; ++i)
+ {
+ LocalMotions lms;
+
+ // read lms
+ mlt_animation_get_item(anim, &item, i + 1);
+ if ((error = lm_deserialize(&lms, item.property)))
+ {
+ break;
+ }
+
+ vs_vector_set_dup(mlms, i, &lms, sizeof(LocalMotions));
+ }
+
+ mlt_property_close(item.property);
+ return error;
+}
+
+void destroy_transforms(TransformData *data)
+{
+ if (data)
+ {
+ vsTransformDataCleanup(&data->td);
+ vsTransformationsCleanup(&data->trans);
+ delete data;
+ }
+}
+
+TransformData* initialize_transforms(int *width, int *height, mlt_image_format *format,
+ mlt_properties properties, const char* interps)
+{
+ TransformData *data = new TransformData;
+ memset(data, 0, sizeof(TransformData));
+
+ VSPixelFormat pf = convertImageFormat(*format);
+ VSFrameInfo fi_src, fi_dst;
+ vsFrameInfoInit(&fi_src, *width, *height, pf);
+ vsFrameInfoInit(&fi_dst, *width, *height, pf);
+
+ const char* filterName = mlt_properties_get(properties, "mlt_service");
+
+ VSTransformConfig conf = vsTransformGetDefaultConfig(filterName);
+ conf.smoothing = mlt_properties_get_int(properties, "smoothing");
+ conf.maxShift = mlt_properties_get_int(properties, "maxshift");
+ conf.maxAngle = mlt_properties_get_double(properties, "maxangle");
+ conf.crop = (VSBorderType) mlt_properties_get_int(properties, "crop");
+ conf.zoom = mlt_properties_get_int(properties, "zoom");
+ conf.optZoom = mlt_properties_get_int(properties, "optzoom");
+ conf.zoomSpeed = mlt_properties_get_double(properties, "zoomspeed");
+ conf.relative = mlt_properties_get_int(properties, "relative");
+ conf.invert = mlt_properties_get_int(properties, "invert");
+ if (mlt_properties_get_int(properties, "tripod") != 0)
+ {
+ // Virtual tripod mode: relative=False, smoothing=0
+ conf.relative = 0;
+ conf.smoothing = 0;
+ }
+
+ // by default a bilinear interpolation is selected
+ conf.interpolType = VS_BiLinear;
+ if (strcmp(interps, "nearest") == 0 || strcmp(interps, "neighbor") == 0)
+ conf.interpolType = VS_Zero;
+ else if (strcmp(interps, "tiles") == 0 || strcmp(interps, "fast_bilinear") == 0)
+ conf.interpolType = VS_Linear;
+
+ vsTransformDataInit(&data->td, &conf, &fi_src, &fi_dst);
+ vsTransformationsInit(&data->trans);
+
+ // load transformations
+ mlt_animation animation = mlt_animation_new();
+ char* strAnim = mlt_properties_get(properties, "vectors");
+ if (mlt_animation_parse(animation, strAnim, 0, 0, NULL))
+ {
+ mlt_log_warning(NULL, "parse failed\n");
+ mlt_animation_close(animation);
+ destroy_transforms(data);
+ return NULL;
+ }
+
+ VSManyLocalMotions mlms;
+ if (vectors_deserialize(animation, &mlms))
+ {
+ mlt_animation_close(animation);
+ destroy_transforms(data);
+ return NULL;
+ }
+
+ mlt_animation_close(animation);
+
+ vsLocalmotions2Transforms(&data->td, &mlms, &data->trans);
+ vsPreprocessTransforms(&data->td, &data->trans);
+ return data;
+}
+
+int get_image_and_transform(mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable)
+{
+ int error = 0;
+ mlt_filter filter = (mlt_filter) mlt_frame_pop_service(frame);
+ mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
+
+ *format = mlt_image_yuv420p;
+
+ error = mlt_frame_get_image(frame, image, format, width, height, 1);
+ if (!error)
+ {
+ // Service locks are for concurrency control
+ mlt_service_lock(MLT_FILTER_SERVICE(filter));
+
+ TransformData *data = static_cast<TransformData*>(mlt_properties_get_data(properties, "_transform_data", NULL));
+
+ // Handle signal from app to re-init data
+ if (mlt_properties_get_int(properties, "refresh"))
+ {
+ mlt_properties_set(properties, "refresh", NULL);
+ destroy_transforms(data);
+ data = NULL;
+ }
+
+ if (!data)
+ {
+ const char *interps = mlt_properties_get(MLT_FRAME_PROPERTIES(frame), "rescale.interp");
+ data = initialize_transforms(width, height, format, properties, interps);
+ if(!data) {
+ mlt_service_unlock(MLT_FILTER_SERVICE(filter));
+ return 1; // return error code
+ }
+ mlt_properties_set_data(properties, "_transform_data", data, 0, (mlt_destructor) destroy_transforms, NULL);
+ }
+
+ VSTransformData* td = &data->td;
+ VSFrame vsFrame;
+ vsFrameFillFromBuffer(&vsFrame, *image, vsTransformGetSrcFrameInfo(td));
+
+ // transform frame
+ data->trans.current = mlt_filter_get_position(filter, frame);
+ vsTransformPrepare(td, &vsFrame, &vsFrame);
+ VSTransform t = vsGetNextTransform(td, &data->trans);
+ vsDoTransform(td, t);
+ vsTransformFinish(td);
+
+ mlt_service_unlock(MLT_FILTER_SERVICE(filter));
+ }
+
+ return error;
+}
+
+static StabData* init_detect(mlt_properties properties, mlt_image_format *format, int *width, int *height)
+{
+ StabData *data = new StabData;
+ memset(data, 0, sizeof(StabData));
+ data->animation = mlt_animation_new();
+
+ VSPixelFormat pf = convertImageFormat(*format);
+ VSFrameInfo fi;
+ vsFrameInfoInit(&fi, *width, *height, pf);
+
+ const char* filterName = mlt_properties_get(properties, "mlt_service");
+
+ VSMotionDetectConfig conf = vsMotionDetectGetDefaultConfig(filterName);
+ conf.shakiness = mlt_properties_get_int(properties, "shakiness");
+ conf.accuracy = mlt_properties_get_int(properties, "accuracy");
+ conf.stepSize = mlt_properties_get_int(properties, "stepsize");
+ conf.algo = mlt_properties_get_int(properties, "algo");
+ conf.contrastThreshold = mlt_properties_get_double(properties, "mincontrast");
+ conf.show = mlt_properties_get_int(properties, "show");
+ conf.virtualTripod = mlt_properties_get_int(properties, "tripod");
+ vsMotionDetectInit(&data->md, &conf, &fi);
+
+ // add vectors to properties
+ mlt_properties_set_data(properties, "vectors", data->animation, 1, (mlt_destructor) mlt_animation_close,
+ (mlt_serialiser) vectors_serializer);
+ return data;
+}
+
+void destroy_detect(StabData *data)
+{
+ if (data)
+ {
+ vsMotionDetectionCleanup(&data->md);
+ delete data;
+ }
+}
+
+int get_image_and_detect(mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable)
+{
+ mlt_filter filter = (mlt_filter) mlt_frame_pop_service(frame);
+ mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
+
+ *format = mlt_image_yuv420p;
+
+ writable = writable || mlt_properties_get_int(properties, "show") ? 1 : 0;
+
+ int error = mlt_frame_get_image(frame, image, format, width, height, writable);
+ if (!error)
+ {
+ // Service locks are for concurrency control
+ mlt_service_lock(MLT_FILTER_SERVICE(filter));
+
+ StabData *data = static_cast<StabData*>(mlt_properties_get_data(properties, "_stab_data", NULL));
+ if (!data)
+ {
+ data = init_detect(properties, format, width, height);
+ mlt_properties_set_data(properties, "_stab_data", data, 0, (mlt_destructor) destroy_detect, NULL);
+ }
+
+ VSMotionDetect* md = &data->md;
+ LocalMotions localmotions;
+ VSFrame vsFrame;
+ vsFrameFillFromBuffer(&vsFrame, *image, &md->fi);
+
+ // detect and save motions
+ vsMotionDetection(md, &localmotions, &vsFrame);
+ mlt_position pos = mlt_filter_get_position( filter, frame );
+ serialize_localmotions(data, localmotions, pos);
+
+ mlt_service_unlock(MLT_FILTER_SERVICE(filter));
+ }
+
+ return error;
+}
+
static mlt_frame process_filter(mlt_filter filter, mlt_frame frame)
{
mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
mlt_filter filter_vidstab_init(mlt_profile profile, mlt_service_type type,
const char *id, char *arg)
{
- mlt_filter filter = NULL;
+ mlt_filter filter = mlt_filter_new();
- if ((filter = mlt_filter_new()))
+ if( filter )
{
filter->process = process_filter;
mlt_properties_set(properties, "zoomspeed", "0.25");
mlt_properties_set(properties, "vid.stab.version", LIBVIDSTAB_VERSION);
-
- return filter;
}
- return NULL;
+ return filter;
}
}
schema_version: 0.1
type: filter
-identifier: vid.stab
+identifier: vidstab
title: Vid.Stab Detect and Transform
copyright: Jakub Ksiezniak
creator: Marco Gittler <g.marco@freenet.de>