]> git.sesse.net Git - mlt/blob - src/modules/videostab/filter_videostab2.c
read filter params correct, set interpol type
[mlt] / src / modules / videostab / filter_videostab2.c
1 /*
2  * filter_imagestab.c -- video stabilization with code from http://vstab.sourceforge.net/
3  * Copyright (c) 2011 Marco Gittler <g.marco@freenet.de>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #include <framework/mlt_filter.h>
21 #include <framework/mlt_frame.h>
22 #include <framework/mlt_log.h>
23 #include <framework/mlt_producer.h>
24 #include <framework/mlt_geometry.h>
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <math.h>
29 #include <sys/stat.h>
30 #include <string.h>
31
32 #include "stabilize.h"
33 #include "transform_image.h"
34
35
36 static void serialize_vectors( StabData* self, mlt_position length )
37 {
38         mlt_geometry g = mlt_geometry_init();
39
40         if ( g )
41         {
42                 struct mlt_geometry_item_s item;
43                 mlt_position i;
44
45                 // Initialize geometry item
46                 item.key = item.f[0] = item.f[1] = 1;
47                 item.f[2] = item.f[3] = item.f[4] = 1;
48
49                 tlist* transform_data =self->transs;
50                 for ( i = 0; i < length; i++ )
51                 {
52                         // Set the geometry item
53                         item.frame = i;
54                         if (transform_data){
55                                 if ( transform_data->data){
56                                         Transform* t=transform_data->data;
57                                         item.x=t->x;
58                                         item.y=t->y;
59                                         item.w=t->alpha;
60                                         item.h=t->zoom;
61                                         transform_data=transform_data->next;
62                                 }
63                         }
64                         // Add the geometry item
65                         mlt_geometry_insert( g, &item );
66                 }
67
68                 // Put the analysis results in a property
69                 mlt_geometry_set_length( g, length );
70                 mlt_properties_set( MLT_FILTER_PROPERTIES( (mlt_filter) self->parent ), "vectors", mlt_geometry_serialise( g ) );
71                 mlt_geometry_close( g );
72         }
73 }
74
75 Transform* deserialize_vectors( char *vectors, mlt_position length )
76 {
77         mlt_geometry g = mlt_geometry_init();
78         Transform* tx=NULL;
79         // Parse the property as a geometry
80         if ( !mlt_geometry_parse( g, vectors, length, -1, -1 ) )
81         {
82                 struct mlt_geometry_item_s item;
83                 int i;
84                 tx=malloc(sizeof(Transform)*length);
85                 memset(tx,sizeof(Transform)*length,0);
86                 // Copy the geometry items to a vc array for interp()
87                 for ( i = 0; i < length; i++ )
88                 {
89                         mlt_geometry_fetch( g, &item, i );
90                         Transform t;
91                         t.x=item.x;
92                         t.y=item.y;
93                         t.alpha=item.w;
94                         t.zoom=item.h;
95                         t.extra=0;
96                         tx[i]=t;
97                 }
98                 
99         }
100         else
101         {
102                 //mlt_log_warning( NULL, "failed to parse vectors\n" );
103         }
104
105         // We are done with this mlt_geometry
106         if ( g ) mlt_geometry_close( g );
107         return tx;
108 }
109
110 static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
111 {
112         mlt_filter filter = mlt_frame_pop_service( frame );
113         //*format = mlt_image_rgb24;
114         *format = mlt_image_yuv420p;
115         int error = mlt_frame_get_image( frame, image, format, width, height, 1 );
116
117         if ( !error && *image )
118         {
119                 StabData* self = filter->child;
120                 mlt_position length = mlt_filter_get_length2( filter, frame );
121                 int h = *height;
122                 int w = *width;
123
124                 // Service locks are for concurrency control
125                 mlt_service_lock( MLT_FILTER_SERVICE( filter ) );
126                 if ( !self->initialized )
127                 {
128                         // Initialize our context
129                         self->initialized = 1;
130                         self->width=w;
131                         self->height=h;
132                         self->framesize=w*h* 3/2;//( mlt_image_format_size ( *format, w,h , 0) ; // 3/2 =1 too small
133                         self->shakiness = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter) , "shakiness" );
134                         self->accuracy = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter) , "accuracy" );
135                         self->stepsize = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter) , "stepsize" );
136                         self->algo = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter) , "algo" );
137                         self->show = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter) , "show" );
138                         self->contrast_threshold = mlt_properties_get_double( MLT_FILTER_PROPERTIES(filter) , "mincontrast" );
139                         stabilize_configure(self);
140                 }
141                 char *vectors = mlt_properties_get( MLT_FILTER_PROPERTIES(filter), "vectors" );
142                 if ( !vectors )
143                 {
144                         // Analyse
145                         mlt_position pos = mlt_filter_get_position( filter, frame );
146                         stabilize_filter_video ( self, *image, *format );
147
148
149                         // On last frame
150                         if ( pos == length - 1 )
151                         {
152                                 serialize_vectors( self, length );
153                         }
154                 }
155                 if ( vectors )
156                 {
157                         // Apply
158                         TransformData* tf=mlt_properties_get_data( MLT_FILTER_PROPERTIES(filter), "_transformdata", NULL);
159                         char *interps = mlt_properties_get( MLT_FRAME_PROPERTIES( frame ), "rescale.interp" );
160
161                         if (!tf){
162                                 tf=mlt_pool_alloc(sizeof(TransformData));
163                                 mlt_properties_set_data( MLT_FILTER_PROPERTIES(filter), "_transformdata", tf, 0, ( mlt_destructor )mlt_pool_release, NULL );
164                         }
165                         if ( self->initialized != 2 )
166                         {
167                                 // Load analysis results from property
168                                 self->initialized = 2;
169
170                                 int interp = 2;
171                                 if ( strcmp( interps, "nearest" ) == 0 || strcmp( interps, "neighbor" ) == 0 )
172                                         interp = 0;
173                                 else if ( strcmp( interps, "tiles" ) == 0 || strcmp( interps, "fast_bilinear" ) == 0 )
174                                         interp = 1;
175                                 else if ( strcmp( interps, "bilinear" ) == 0 )
176                                         interp = 2;
177                                 else if ( strcmp( interps, "bicubic" ) == 0 )
178                                         interp = 3;
179                                 else if ( strcmp( interps, "bicublin" ) == 0 )
180                                         interp = 4;
181                                 tf->interpoltype = interp;
182                                 transform_configure(tf,w,h,*format ,*image, deserialize_vectors(  vectors, length ),length);
183                                 
184                         }
185                         if ( self->initialized == 2 )
186                         {
187                                 // Stabilize
188                                 float pos = mlt_filter_get_position( filter, frame );
189                                 tf->current_trans=pos;
190                                 transform_filter_video(tf, *image, *format );
191                         }
192                 }
193                 mlt_service_unlock( MLT_FILTER_SERVICE( filter ) );
194         }
195         return error;
196 }
197
198 static mlt_frame filter_process( mlt_filter filter, mlt_frame frame )
199 {
200         mlt_frame_push_service( frame, filter );
201         mlt_frame_push_get_image( frame, filter_get_image );
202         return frame;
203 }
204
205 static void filter_close( mlt_filter parent )
206 {
207         StabData* self = parent->child;
208         stabilize_stop(self);
209         free( self );
210         parent->close = NULL;
211         parent->child = NULL;
212 }
213
214 mlt_filter filter_videostab2_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
215 {
216         StabData* self = calloc( 1, sizeof(StabData) );
217         if ( self )
218         {
219                 mlt_filter parent = mlt_filter_new();
220                 parent->child = self;
221                 parent->close = filter_close;
222                 parent->process = filter_process;
223                 self->parent = parent;
224                 mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "shakiness", "4" ); 
225                 mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "accuracy", "4" ); 
226                 mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "stepsize", "6" ); 
227                 mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "algo", "1" ); 
228                 mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "mincontrast", "0.3" ); 
229                 mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "show", "0" ); 
230                 return parent;
231         }
232         return NULL;
233 }