2 * /brief Crop Detection filter
4 * /author Zachary Drew, Copyright 2005
6 * inspired by mplayer's cropdetect filter
8 * Note: The goemetry generated is zero-indexed and is inclusive of the end values
11 * -filter crop_detect debug=1 // Visualize crop
12 * -filter crop_detect frequency=25 // Detect the crop once a second
13 * -filter crop_detect frequency=0 // Never detect unless the producer changes
14 * -filter crop_detect thresh=100 // Changes the threshold (default = 25)
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software Foundation,
28 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 #define DEFAULT_THRESH 20
34 #include <framework/mlt.h>
41 #define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b))
42 #define ABS(a) ((a) >= 0 ? (a) : (-(a)))
46 static inline int clip(int a
, int amin
, int amax
)
58 * draws an line from (ex, ey) -> (sx, sy).
59 * Credits: modified from ffmpeg project
60 * @param ystride stride/linesize of the image
61 * @param xstride stride/element size of the image
62 * @param color color of the arrow
64 static void draw_line(uint8_t *buf
, int sx
, int sy
, int ex
, int ey
, int w
, int h
, int xstride
, int ystride
, int color
){
67 // buf[sy*ystride + sx*xstride]= color;
68 buf
[sy
*ystride
+ sx
]+= color
;
75 if(ABS(ex
- sx
) > ABS(ey
- sy
)){
80 buf
+= sx
*xstride
+ sy
*ystride
;
83 for(x
= 0; x
<= ex
; x
++){
86 buf
[ y
*ystride
+ x
*xstride
]= (color
*(0x10000-fr
))>>16;
87 buf
[(y
+1)*ystride
+ x
*xstride
]= (color
* fr
)>>16;
94 buf
+= sx
*xstride
+ sy
*ystride
;
96 if(ey
) f
= ((ex
-sx
)<<16)/ey
;
98 for(y
= 0; y
<= ey
; y
++){
101 buf
[y
*ystride
+ x
*xstride
]= (color
*(0x10000-fr
))>>16;;
102 buf
[y
*ystride
+ (x
+1)*xstride
]= (color
* fr
)>>16;;
108 * draws an arrow from (ex, ey) -> (sx, sy).
109 * Credits: modified from ffmpeg project
110 * @param stride stride/linesize of the image
111 * @param color color of the arrow
113 static void draw_arrow(uint8_t *buf
, int sx
, int sy
, int ex
, int ey
, int w
, int h
, int xstride
, int ystride
, int color
){
119 if(dx
*dx
+ dy
*dy
> 3*3){
122 int length
= sqrt((rx
*rx
+ ry
*ry
)<<4);
124 //FIXME subpixel accuracy
125 rx
= ROUNDED_DIV(rx
*3<<4, length
);
126 ry
= ROUNDED_DIV(ry
*3<<4, length
);
128 draw_line(buf
, sx
, sy
, sx
+ rx
, sy
+ ry
, w
, h
, xstride
, ystride
, color
);
129 draw_line(buf
, sx
, sy
, sx
- ry
, sy
+ rx
, w
, h
, xstride
, ystride
, color
);
131 draw_line(buf
, sx
, sy
, ex
, ey
, w
, h
, xstride
, ystride
, color
);
135 // Image stack(able) method
136 static int filter_get_image( mlt_frame
this, uint8_t **image
, mlt_image_format
*format
, int *width
, int *height
, int writable
)
139 // Get the filter object and properties
140 mlt_filter filter
= mlt_frame_pop_service( this );
141 mlt_properties properties
= MLT_FILTER_PROPERTIES( filter
);
144 int error
= mlt_frame_get_image( this, image
, format
, width
, height
, 1 );
147 mlt_properties_debug( MLT_FRAME_PROPERTIES(this), "error after mlt_frame_get_image()", stderr
);
151 // Parameter that describes how often to check for the crop
152 int frequency
= mlt_properties_get_int( properties
, "frequency");
154 // Producers may start with blank footage, by default we will skip, oh, 5 frames unless overridden
155 int skip
= mlt_properties_get_int( properties
, "skip");
158 mlt_geometry_item bounds
= mlt_properties_get_data( properties
, "bounds", NULL
);
160 // Initialize if needed
161 if( bounds
== NULL
) {
162 bounds
= calloc( 1, sizeof( struct mlt_geometry_item_s
) );
165 mlt_properties_set_data( properties
, "bounds", bounds
, sizeof( struct mlt_geometry_item_s
), free
, NULL
);
168 // mlt_properties first = (mlt_properties) mlt_deque_peek_front( MLT_FRAME_SERVICE_STACK(this) );
169 // int current_producer_id = mlt_properties_get_int( first, "_unique_id");
170 // int former_producer_id = mlt_properties_get_int(properties, "_former_unique_id");
171 // mlt_properties_set_int(properties, "_former_unique_id", current_producer_id);
173 // For periodic detection (with offset of 'skip')
174 if( frequency
== 0 || (mlt_frame_get_position(this)+skip
) % frequency
!= 0)
178 mlt_properties_set_data( MLT_FRAME_PROPERTIES(this), "bounds", bounds
, sizeof( struct mlt_geometry_item_s
), NULL
, NULL
);
184 // There is no way to detect a crop for sure, so make up an arbitrary one
185 int thresh
= mlt_properties_get_int( properties
, "thresh" );
187 int xstride
, ystride
;
190 case mlt_image_yuv422
:
192 ystride
= 2 * *width
;
195 fprintf(stderr
, "image format not supported by filter_crop_detect\n");
199 int x
, y
, average_brightness
, deviation
; // Scratch variables
202 for( y
= 0; y
< *height
/2; y
++ ) {
203 average_brightness
= 0;
206 for( x
= 0; x
< *width
; x
++ )
207 average_brightness
+= *(*image
+ y
*ystride
+ x
*xstride
);
209 average_brightness
/= *width
;
211 for( x
= 0; x
< *width
; x
++ )
212 deviation
+= abs(average_brightness
- *(*image
+ y
*ystride
+ x
*xstride
));
214 if( deviation
>= thresh
)
219 for( y
= *height
- 1; y
>= *height
/2; y
-- ) {
220 average_brightness
= 0;
223 for( x
= 0; x
< *width
; x
++ )
224 average_brightness
+= *(*image
+ y
*ystride
+ x
*xstride
);
226 average_brightness
/= *width
;
228 for( x
= 0; x
< *width
; x
++ )
229 deviation
+= abs(average_brightness
- *(*image
+ y
*ystride
+ x
*xstride
));
231 if( deviation
>= thresh
)
236 for( x
= 0; x
< *width
/2; x
++ ) {
237 average_brightness
= 0;
240 for( y
= 0; y
< *height
; y
++ )
241 average_brightness
+= *(*image
+ y
*ystride
+ x
*xstride
);
243 average_brightness
/= *height
;
245 for( y
= 0; y
< *height
; y
++ )
246 deviation
+= abs(average_brightness
- *(*image
+ y
*ystride
+ x
*xstride
));
248 if( deviation
>= thresh
)
253 for( x
= *width
- 1; x
>= *width
/2; x
-- ) {
254 average_brightness
= 0;
257 for( y
= 0; y
< *height
; y
++ )
258 average_brightness
+= *(*image
+ y
*ystride
+ x
*xstride
);
260 average_brightness
/= *height
;
262 for( y
= 0; y
< *height
; y
++ )
263 deviation
+= abs(average_brightness
- *(*image
+ y
*ystride
+ x
*xstride
));
265 if( deviation
>= thresh
)
269 /* Debug: Draw arrows to show crop */
270 if( mlt_properties_get_int( properties
, "debug") == 1 )
272 draw_arrow(*image
, bounds
->x
, *height
/2, bounds
->x
+40, *height
/2, *width
, *height
, xstride
, ystride
, 0xff);
273 draw_arrow(*image
, *width
/2, bounds
->y
, *width
/2, bounds
->y
+40, *width
, *height
, xstride
, ystride
, 0xff);
274 draw_arrow(*image
, bounds
->w
, *height
/2, bounds
->w
-40, *height
/2, *width
, *height
, xstride
, ystride
, 0xff);
275 draw_arrow(*image
, *width
/2, bounds
->h
, *width
/2, bounds
->h
-40, *width
, *height
, xstride
, ystride
, 0xff);
277 fprintf(stderr
, "Top:%f Left:%f Right:%f Bottom:%f\n", bounds
->y
, bounds
->x
, bounds
->w
, bounds
->h
);
280 bounds
->w
-= bounds
->x
;
281 bounds
->h
-= bounds
->y
;
283 /* inject into frame */
284 mlt_properties_set_data( MLT_FRAME_PROPERTIES(this), "bounds", bounds
, sizeof( struct mlt_geometry_item_s
), NULL
, NULL
);
292 /** Filter processing.
295 static mlt_frame
filter_process( mlt_filter
this, mlt_frame frame
)
298 // Put the filter object somewhere we can find it
299 mlt_frame_push_service( frame
, this);
301 // Push the frame filter
302 mlt_frame_push_get_image( frame
, filter_get_image
);
307 /** Constructor for the filter.
309 mlt_filter
filter_crop_detect_init( char *arg
)
311 mlt_filter
this = mlt_filter_new( );
314 this->process
= filter_process
;
317 mlt_properties_set_int( MLT_FILTER_PROPERTIES(this), "frequency", 1);
318 mlt_properties_set_int( MLT_FILTER_PROPERTIES(this), "thresh", 25);
319 mlt_properties_set_int( MLT_FILTER_PROPERTIES(this), "clip", 5);
320 mlt_properties_set_int( MLT_FILTER_PROPERTIES(this), "former_producer_id", -1);
327 /** This source code will self destruct in 5...4...3...