1 /*****************************************************************************
2 * crop.c : Crop video plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2002, 2003 the VideoLAN team
7 * Authors: Samuel Hocevar <sam@zoy.org>
8 * mod by Cedric Cocquebert <Cedric.Cocquebert@supelec.fr>
9 * based of DScaler idea (M. Samblanet)
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
26 /*****************************************************************************
28 *****************************************************************************/
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
37 #include <vlc_dialog.h>
39 #define BEST_AUTOCROP 1
41 #define RATIO_MAX 15000 // 10*4/3 for a 360
44 /*****************************************************************************
46 *****************************************************************************/
47 static int Create ( vlc_object_t
* );
48 static void Destroy ( vlc_object_t
* );
50 static int Init ( vout_thread_t
* );
51 static void End ( vout_thread_t
* );
52 static int Manage ( vout_thread_t
* );
53 static void Render ( vout_thread_t
*, picture_t
* );
55 static void UpdateStats ( vout_thread_t
*, picture_t
* );
57 static int MouseEvent( vlc_object_t
*, char const *,
58 vlc_value_t
, vlc_value_t
, void * );
61 /*****************************************************************************
63 *****************************************************************************/
64 static int FilterCallback ( vlc_object_t
*, char const *,
65 vlc_value_t
, vlc_value_t
, void * );
68 /*****************************************************************************
70 *****************************************************************************/
71 #define GEOMETRY_TEXT N_("Crop geometry (pixels)")
72 #define GEOMETRY_LONGTEXT N_("Set the geometry of the zone to crop. This is set as <width> x <height> + <left offset> + <top offset>.")
74 #define AUTOCROP_TEXT N_("Automatic cropping")
75 #define AUTOCROP_LONGTEXT N_("Automatically detect black borders and crop them.")
77 #define CROP_HELP N_("Remove borders of the video and replace them by black borders")
80 #define RATIOMAX_TEXT N_("Ratio max (x 1000)")
81 #define RATIOMAX_LONGTEXT N_("Maximum image ratio. The crop plugin will never automatically crop to a higher ratio (ie, to a more \"flat\" image). The value is x1000: 1333 means 4/3.")
83 #define RATIO_TEXT N_("Manual ratio")
84 #define RATIO_LONGTEXT N_("Force a ratio (0 for automatic). Value is x1000: 1333 means 4/3.")
86 #define TIME_TEXT N_("Number of images for change")
87 #define TIME_LONGTEXT N_("The number of consecutive images with the same detected ratio (different from the previously detected ratio) to consider that ratio changed and trigger recrop.")
89 #define DIFF_TEXT N_("Number of lines for change")
90 #define DIFF_LONGTEXT N_("The minimum difference in the number of detected black lines to consider that ratio changed and trigger recrop.")
92 #define NBP_TEXT N_("Number of non black pixels ")
93 #define NBP_LONGTEXT N_("The maximum of non-black pixels in a line to consider"\
94 " that the line is black.")
96 #define SKIP_TEXT N_("Skip percentage (%)")
97 #define SKIP_LONGTEXT N_("Percentage of the line to consider while checking for black lines. This allows skipping logos in black borders and crop them anyway.")
99 #define LUM_TEXT N_("Luminance threshold ")
100 #define LUM_LONGTEXT N_("Maximum luminance to consider a pixel as black (0-255).")
104 set_description( N_("Crop video filter") )
105 set_shortname( N_("Crop" ))
107 set_category( CAT_VIDEO
)
108 set_subcategory( SUBCAT_VIDEO_VFILTER
)
109 set_capability( "video filter", 0 )
111 add_string( "crop-geometry", NULL
, GEOMETRY_TEXT
,
112 GEOMETRY_LONGTEXT
, false )
113 add_bool( "autocrop", false, AUTOCROP_TEXT
,
114 AUTOCROP_LONGTEXT
, false )
117 add_integer_with_range( "autocrop-ratio-max", 2405, 0, RATIO_MAX
,
118 RATIOMAX_TEXT
, RATIOMAX_LONGTEXT
, true )
120 add_integer_with_range( "crop-ratio", 0, 0, RATIO_MAX
, RATIO_TEXT
,
121 RATIO_LONGTEXT
, false )
122 add_integer( "autocrop-time", 25, TIME_TEXT
,
123 TIME_LONGTEXT
, true )
124 add_integer( "autocrop-diff", 16, DIFF_TEXT
,
125 DIFF_LONGTEXT
, true )
127 add_integer( "autocrop-non-black-pixels", 3,
128 NBP_TEXT
, NBP_LONGTEXT
, true )
130 add_integer_with_range( "autocrop-skip-percent", 17, 0, 100,
131 SKIP_TEXT
, SKIP_LONGTEXT
, true )
133 add_integer_with_range( "autocrop-luminance-threshold", 40, 0, 128,
134 LUM_TEXT
, LUM_LONGTEXT
, true )
135 #endif //BEST_AUTOCROP
137 add_shortcut( "crop" )
138 set_callbacks( Create
, Destroy
)
141 /*****************************************************************************
142 * vout_sys_t: Crop video output method descriptor
143 *****************************************************************************
144 * This structure is part of the video output thread descriptor.
145 * It describes the Crop specific properties of an output thread.
146 *****************************************************************************/
150 vout_thread_t
*p_vout
;
152 unsigned int i_x
, i_y
;
153 unsigned int i_width
, i_height
, i_aspect
;
157 /* Autocrop specific variables */
158 unsigned int i_lastchange
;
161 unsigned int i_ratio_max
;
162 unsigned int i_threshold
, i_skipPercent
, i_nonBlackPixel
, i_diff
, i_time
;
163 unsigned int i_ratio
;
168 /*****************************************************************************
169 * Control: control facility for the vout (forwards to child vout)
170 *****************************************************************************/
171 static int Control( vout_thread_t
*p_vout
, int i_query
, va_list args
)
173 return vout_vaControl( p_vout
->p_sys
->p_vout
, i_query
, args
);
176 /*****************************************************************************
177 * Create: allocates Crop video thread output method
178 *****************************************************************************
179 * This function allocates and initializes a Crop vout method.
180 *****************************************************************************/
181 static int Create( vlc_object_t
*p_this
)
183 vout_thread_t
*p_vout
= (vout_thread_t
*)p_this
;
185 /* Allocate structure */
186 p_vout
->p_sys
= malloc( sizeof( vout_sys_t
) );
187 if( p_vout
->p_sys
== NULL
)
190 p_vout
->pf_init
= Init
;
191 p_vout
->pf_end
= End
;
192 p_vout
->pf_manage
= Manage
;
193 p_vout
->pf_render
= Render
;
194 p_vout
->pf_display
= NULL
;
195 p_vout
->pf_control
= Control
;
200 /*****************************************************************************
201 * Init: initialize Crop video thread output method
202 *****************************************************************************/
203 static int Init( vout_thread_t
*p_vout
)
208 I_OUTPUTPICTURES
= 0;
209 memset( &fmt
, 0, sizeof(video_format_t
) );
211 p_vout
->p_sys
->i_lastchange
= 0;
212 p_vout
->p_sys
->b_changed
= false;
214 /* Initialize the output structure */
215 p_vout
->output
.i_chroma
= p_vout
->render
.i_chroma
;
216 p_vout
->output
.i_width
= p_vout
->render
.i_width
;
217 p_vout
->output
.i_height
= p_vout
->render
.i_height
;
218 p_vout
->output
.i_aspect
= p_vout
->render
.i_aspect
;
219 p_vout
->fmt_out
= p_vout
->fmt_in
;
221 /* Shall we use autocrop ? */
222 p_vout
->p_sys
->b_autocrop
= var_InheritBool( p_vout
, "autocrop" );
224 p_vout
->p_sys
->i_ratio_max
=
225 var_InheritInteger( p_vout
, "autocrop-ratio-max" );
226 p_vout
->p_sys
->i_threshold
=
227 var_InheritInteger( p_vout
, "autocrop-luminance-threshold" );
228 p_vout
->p_sys
->i_skipPercent
=
229 var_InheritInteger( p_vout
, "autocrop-skip-percent" );
230 p_vout
->p_sys
->i_nonBlackPixel
=
231 var_InheritInteger( p_vout
, "autocrop-non-black-pixels" );
232 p_vout
->p_sys
->i_diff
=
233 var_InheritInteger( p_vout
, "autocrop-diff" );
234 p_vout
->p_sys
->i_time
=
235 var_InheritInteger( p_vout
, "autocrop-time" );
236 var_SetString( p_vout
, "ratio-crop", "0" );
238 if (p_vout
->p_sys
->b_autocrop
)
239 p_vout
->p_sys
->i_ratio
= 0;
242 p_vout
->p_sys
->i_ratio
= var_InheritInteger( p_vout
, "crop-ratio" );
243 // ratio < width / height => ratio = 0 (unchange ratio)
244 if (p_vout
->p_sys
->i_ratio
< (p_vout
->output
.i_width
* 1000) / p_vout
->output
.i_height
)
245 p_vout
->p_sys
->i_ratio
= 0;
250 /* Get geometry value from the user */
251 psz_var
= var_InheritString( p_vout
, "crop-geometry" );
254 char *psz_parser
, *psz_tmp
;
256 psz_parser
= psz_tmp
= psz_var
;
257 while( *psz_tmp
&& *psz_tmp
!= 'x' ) psz_tmp
++;
262 p_vout
->p_sys
->i_width
= atoi( psz_parser
);
264 psz_parser
= ++psz_tmp
;
265 while( *psz_tmp
&& *psz_tmp
!= '+' ) psz_tmp
++;
270 p_vout
->p_sys
->i_height
= atoi( psz_parser
);
272 psz_parser
= ++psz_tmp
;
273 while( *psz_tmp
&& *psz_tmp
!= '+' ) psz_tmp
++;
278 p_vout
->p_sys
->i_x
= atoi( psz_parser
);
279 p_vout
->p_sys
->i_y
= atoi( ++psz_tmp
);
283 p_vout
->p_sys
->i_x
= atoi( psz_parser
);
285 ( p_vout
->output
.i_height
- p_vout
->p_sys
->i_height
) / 2;
290 p_vout
->p_sys
->i_height
= atoi( psz_parser
);
292 ( p_vout
->output
.i_width
- p_vout
->p_sys
->i_width
) / 2;
294 ( p_vout
->output
.i_height
- p_vout
->p_sys
->i_height
) / 2;
299 p_vout
->p_sys
->i_width
= atoi( psz_parser
);
300 p_vout
->p_sys
->i_height
= p_vout
->output
.i_height
;
302 ( p_vout
->output
.i_width
- p_vout
->p_sys
->i_width
) / 2;
304 ( p_vout
->output
.i_height
- p_vout
->p_sys
->i_height
) / 2;
307 /* Check for validity */
308 if( p_vout
->p_sys
->i_x
+ p_vout
->p_sys
->i_width
309 > p_vout
->output
.i_width
)
311 p_vout
->p_sys
->i_x
= 0;
312 if( p_vout
->p_sys
->i_width
> p_vout
->output
.i_width
)
314 p_vout
->p_sys
->i_width
= p_vout
->output
.i_width
;
318 if( p_vout
->p_sys
->i_y
+ p_vout
->p_sys
->i_height
319 > p_vout
->output
.i_height
)
321 p_vout
->p_sys
->i_y
= 0;
322 if( p_vout
->p_sys
->i_height
> p_vout
->output
.i_height
)
324 p_vout
->p_sys
->i_height
= p_vout
->output
.i_height
;
332 if (p_vout
->p_sys
->i_ratio
)
334 p_vout
->p_sys
->i_aspect
= p_vout
->p_sys
->i_ratio
* 432;
335 p_vout
->p_sys
->i_width
= p_vout
->fmt_out
.i_visible_width
;
336 p_vout
->p_sys
->i_height
= p_vout
->output
.i_aspect
337 * p_vout
->output
.i_height
/ p_vout
->p_sys
->i_aspect
338 * p_vout
->p_sys
->i_width
/ p_vout
->output
.i_width
;
339 p_vout
->p_sys
->i_height
+= p_vout
->p_sys
->i_height
% 2;
340 p_vout
->p_sys
->i_x
= p_vout
->fmt_out
.i_x_offset
;
341 p_vout
->p_sys
->i_y
= (p_vout
->output
.i_height
- p_vout
->p_sys
->i_height
) / 2;
346 p_vout
->p_sys
->i_width
= p_vout
->fmt_out
.i_visible_width
;
347 p_vout
->p_sys
->i_height
= p_vout
->fmt_out
.i_visible_height
;
348 p_vout
->p_sys
->i_x
= p_vout
->fmt_out
.i_x_offset
;
349 p_vout
->p_sys
->i_y
= p_vout
->fmt_out
.i_y_offset
;
352 /* Pheeew. Parsing done. */
353 msg_Dbg( p_vout
, "cropping at %ix%i+%i+%i, %sautocropping",
354 p_vout
->p_sys
->i_width
, p_vout
->p_sys
->i_height
,
355 p_vout
->p_sys
->i_x
, p_vout
->p_sys
->i_y
,
356 p_vout
->p_sys
->b_autocrop
? "" : "not " );
357 /* Set current output image properties */
358 p_vout
->p_sys
->i_aspect
= (int64_t)VOUT_ASPECT_FACTOR
*
359 p_vout
->fmt_out
.i_sar_num
* p_vout
->p_sys
->i_width
/
360 (p_vout
->fmt_out
.i_sar_den
* p_vout
->p_sys
->i_height
);
363 msg_Info( p_vout
, "ratio %d", p_vout
->p_sys
->i_aspect
/ 432);
365 fmt
.i_width
= fmt
.i_visible_width
= p_vout
->p_sys
->i_width
;
366 fmt
.i_height
= fmt
.i_visible_height
= p_vout
->p_sys
->i_height
;
367 fmt
.i_x_offset
= fmt
.i_y_offset
= 0;
368 fmt
.i_chroma
= p_vout
->render
.i_chroma
;
369 fmt
.i_sar_num
= p_vout
->p_sys
->i_aspect
* fmt
.i_height
;
370 fmt
.i_sar_den
= VOUT_ASPECT_FACTOR
* fmt
.i_width
;
372 /* Try to open the real video output */
373 p_vout
->p_sys
->p_vout
= vout_Create( p_vout
, &fmt
);
374 if( p_vout
->p_sys
->p_vout
== NULL
)
376 msg_Err( p_vout
, "failed to create vout" );
377 dialog_Fatal( p_vout
, _("Cropping failed"), "%s",
378 _("VLC could not open the video output module.") );
382 vlc_mutex_init( &p_vout
->p_sys
->lock
);
384 var_AddCallback( p_vout
, "ratio-crop", FilterCallback
, NULL
);
387 vout_filter_AllocateDirectBuffers( p_vout
, VOUT_MAX_PICTURES
);
389 vout_filter_AddChild( p_vout
, p_vout
->p_sys
->p_vout
, MouseEvent
);
394 /*****************************************************************************
395 * End: terminate Crop video thread output method
396 *****************************************************************************/
397 static void End( vout_thread_t
*p_vout
)
399 vout_sys_t
*p_sys
= p_vout
->p_sys
;
403 vout_filter_DelChild( p_vout
, p_sys
->p_vout
, MouseEvent
);
404 vout_CloseAndRelease( p_sys
->p_vout
);
407 vout_filter_ReleaseDirectBuffers( p_vout
);
408 var_DelCallback( p_vout
, "ratio-crop", FilterCallback
, NULL
);
409 vlc_mutex_destroy( &p_sys
->lock
);
412 /*****************************************************************************
413 * Destroy: destroy Crop video thread output method
414 *****************************************************************************
415 * Terminate an output method created by CropCreateOutputMethod
416 *****************************************************************************/
417 static void Destroy( vlc_object_t
*p_this
)
419 vout_thread_t
*p_vout
= (vout_thread_t
*)p_this
;
421 free( p_vout
->p_sys
);
424 /*****************************************************************************
425 * Manage: handle Crop events
426 *****************************************************************************
427 * This function should be called regularly by video output thread. It manages
428 * console events. It returns a non null value on error.
429 *****************************************************************************/
430 static int Manage( vout_thread_t
*p_vout
)
434 if( !p_vout
->p_sys
->b_changed
)
439 memset( &fmt
, 0, sizeof(video_format_t
) );
442 /* XXX: not thread-safe with FilterCallback */
443 msg_Dbg( p_vout
, "cropping at %ix%i+%i+%i, %sautocropping",
444 p_vout
->p_sys
->i_width
, p_vout
->p_sys
->i_height
,
445 p_vout
->p_sys
->i_x
, p_vout
->p_sys
->i_y
,
446 p_vout
->p_sys
->b_autocrop
? "" : "not " );
448 msg_Info( p_vout
, "ratio %d", p_vout
->p_sys
->i_aspect
/ 432);
451 if( p_vout
->p_sys
->p_vout
)
453 vout_filter_DelChild( p_vout
, p_vout
->p_sys
->p_vout
, MouseEvent
);
454 vout_CloseAndRelease( p_vout
->p_sys
->p_vout
);
457 fmt
.i_width
= fmt
.i_visible_width
= p_vout
->p_sys
->i_width
;
458 fmt
.i_height
= fmt
.i_visible_height
= p_vout
->p_sys
->i_height
;
459 fmt
.i_x_offset
= fmt
.i_y_offset
= 0;
460 fmt
.i_chroma
= p_vout
->render
.i_chroma
;
461 fmt
.i_sar_num
= p_vout
->p_sys
->i_aspect
* fmt
.i_height
/ fmt
.i_width
;
462 fmt
.i_sar_den
= VOUT_ASPECT_FACTOR
;
464 p_vout
->p_sys
->p_vout
= vout_Create( p_vout
, &fmt
);
465 if( p_vout
->p_sys
->p_vout
== NULL
)
467 msg_Err( p_vout
, "failed to create vout" );
468 dialog_Fatal( p_vout
, _("Cropping failed"), "%s",
469 _("VLC could not open the video output module.") );
472 vout_filter_AddChild( p_vout
, p_vout
->p_sys
->p_vout
, MouseEvent
);
474 p_vout
->p_sys
->b_changed
= false;
475 vlc_mutex_lock( &p_vout
->p_sys
->lock
);
476 p_vout
->p_sys
->i_lastchange
= 0;
477 vlc_mutex_unlock( &p_vout
->p_sys
->lock
);
482 /*****************************************************************************
483 * Render: display previously rendered output
484 *****************************************************************************
485 * This function sends the currently rendered image to Crop image, waits
486 * until it is displayed and switches the two rendering buffers, preparing next
488 *****************************************************************************/
489 static void Render( vout_thread_t
*p_vout
, picture_t
*p_pic
)
491 picture_t
*p_outpic
= NULL
;
494 if( p_vout
->p_sys
->b_changed
)
500 vout_CreatePicture( p_vout
->p_sys
->p_vout
, 0, 0, 0 )
503 if( !vlc_object_alive (p_vout
) || p_vout
->b_error
)
505 vout_DestroyPicture( p_vout
->p_sys
->p_vout
, p_outpic
);
509 msleep( VOUT_OUTMEM_SLEEP
);
512 p_outpic
->date
= p_pic
->date
;
513 vout_LinkPicture( p_vout
->p_sys
->p_vout
, p_outpic
);
515 for( i_plane
= 0 ; i_plane
< p_pic
->i_planes
; i_plane
++ )
517 uint8_t *p_in
, *p_out
, *p_out_end
;
518 int i_in_pitch
= p_pic
->p
[i_plane
].i_pitch
;
519 const int i_out_pitch
= p_outpic
->p
[i_plane
].i_pitch
;
520 const int i_copy_pitch
= p_outpic
->p
[i_plane
].i_visible_pitch
;
522 p_in
= p_pic
->p
[i_plane
].p_pixels
523 /* Skip the right amount of lines */
524 + i_in_pitch
* ( p_pic
->p
[i_plane
].i_visible_lines
*
525 p_vout
->p_sys
->i_y
/ p_vout
->output
.i_height
)
526 /* Skip the right amount of columns */
527 + i_in_pitch
* p_vout
->p_sys
->i_x
/ p_vout
->output
.i_width
;
529 p_out
= p_outpic
->p
[i_plane
].p_pixels
;
530 p_out_end
= p_out
+ i_out_pitch
* p_outpic
->p
[i_plane
].i_visible_lines
;
532 while( p_out
< p_out_end
)
534 vlc_memcpy( p_out
, p_in
, i_copy_pitch
);
536 p_out
+= i_out_pitch
;
540 vout_UnlinkPicture( p_vout
->p_sys
->p_vout
, p_outpic
);
541 vout_DisplayPicture( p_vout
->p_sys
->p_vout
, p_outpic
);
543 /* The source image may still be in the cache ... parse it! */
544 vlc_mutex_lock( &p_vout
->p_sys
->lock
);
545 if( p_vout
->p_sys
->b_autocrop
)
546 UpdateStats( p_vout
, p_pic
);
547 vlc_mutex_unlock( &p_vout
->p_sys
->lock
);
551 static bool NonBlackLine(uint8_t *p_in
, int i_line
, int i_pitch
,
552 int i_visible_pitch
, int i_lines
,
553 int i_lumThreshold
, int i_skipCountPercent
,
554 int i_nonBlackPixel
, int i_chroma
)
556 const int i_col
= i_line
* i_pitch
/ i_lines
;
557 int i_index
, i_count
= 0;
570 i_skipCount
= (i_pitch
* i_skipCountPercent
) / 100;
571 for (i_index
= i_col
/2 + i_skipCount
/2;
572 i_index
<= i_visible_pitch
/2 + i_col
/2 - i_skipCount
/2;
575 i_count
+= (p_in
[i_index
] > i_lumThreshold
);
576 if (i_count
> i_nonBlackPixel
) break;
580 case VLC_CODEC_RGB8
: // packed by 1
581 i_skipCount
= (i_pitch
* i_skipCountPercent
) / 100;
582 for (i_index
= i_col
/2 + i_skipCount
/2;
583 i_index
<= i_visible_pitch
/2 + i_col
/2 - i_skipCount
/2;
586 i_count
+= (p_in
[i_index
] > i_lumThreshold
);
587 if (i_count
> i_nonBlackPixel
) break;
590 case VLC_CODEC_RGB15
: // packed by 2
591 case VLC_CODEC_RGB16
: // packed by 2
592 i_skipCount
= (i_pitch
* i_skipCountPercent
) / 100;
593 for (i_index
= i_col
/2 + i_skipCount
/2 -
594 (i_col
/2 + i_skipCount
/2) % 2;
595 i_index
<= i_visible_pitch
/2 + i_col
/2 - i_skipCount
/2;
598 i_count
+= (p_in
[i_index
] > i_lumThreshold
) &&
599 (p_in
[i_index
+ 1] > i_lumThreshold
);
600 if (i_count
> i_nonBlackPixel
) break;
603 case VLC_CODEC_RGB24
: // packed by 3
604 i_skipCount
= (i_pitch
* i_skipCountPercent
) / 100;
605 for (i_index
= i_col
/2 + i_skipCount
/2 - (i_col
/2 + i_skipCount
/2) % 3; i_index
<= i_visible_pitch
/2 + i_col
/2 - i_skipCount
/2; i_index
+=3)
607 i_count
+= (p_in
[i_index
] > i_lumThreshold
) &&
608 (p_in
[i_index
+ 1] > i_lumThreshold
) &&
609 (p_in
[i_index
+ 2] > i_lumThreshold
);
610 if (i_count
> i_nonBlackPixel
) break;
613 case VLC_CODEC_RGB32
: // packed by 4
614 i_skipCount
= (i_pitch
* i_skipCountPercent
) / 100;
615 for (i_index
= i_col
/2 + i_skipCount
/2 - (i_col
/2 + i_skipCount
/2) % 4; i_index
<= i_visible_pitch
/2 + i_col
/2 - i_skipCount
/2; i_index
+=4)
617 i_count
+= (uint32_t)(*(p_in
+ i_index
)) > (uint32_t)i_lumThreshold
;
618 if (i_count
> i_nonBlackPixel
) break;
622 case VLC_CODEC_YUYV
: // packed by 2
623 case VLC_CODEC_UYVY
: // packed by 2
624 i_skipCount
= (i_pitch
* i_skipCountPercent
) / 100;
625 for (i_index
= (i_col
/2 + i_skipCount
/2) -
626 (i_col
/2 + i_skipCount
/2) % 2;
627 i_index
<= i_visible_pitch
/2 + i_col
/2 - i_skipCount
/2;
630 i_count
+= (p_in
[i_index
] > i_lumThreshold
);
631 if (i_count
> i_nonBlackPixel
) break;
637 return (i_count
> i_nonBlackPixel
);
641 static void UpdateStats( vout_thread_t
*p_vout
, picture_t
*p_pic
)
643 uint8_t *p_in
= p_pic
->p
[0].p_pixels
;
644 int i_pitch
= p_pic
->p
[0].i_pitch
;
645 int i_visible_pitch
= p_pic
->p
[0].i_visible_pitch
;
646 int i_lines
= p_pic
->p
[0].i_visible_lines
;
647 int i_firstwhite
= -1, i_lastwhite
= -1, i
;
649 int i_time
= p_vout
->p_sys
->i_time
;
650 int i_diff
= p_vout
->p_sys
->i_diff
;
652 if (!p_vout
->p_sys
->i_ratio
)
654 /* Determine where black borders are */
655 for( i
= 0 ; i
< i_lines
; i
++)
657 if (NonBlackLine(p_in
, i
, i_pitch
, i_visible_pitch
, i_lines
,
658 p_vout
->p_sys
->i_threshold
,
659 p_vout
->p_sys
->i_skipPercent
,
660 p_vout
->p_sys
->i_nonBlackPixel
,
661 p_vout
->output
.i_chroma
))
664 i_lastwhite
= i_lines
- i
;
670 /* Decide whether it's worth changing the size */
671 if( i_lastwhite
== -1 )
673 p_vout
->p_sys
->i_lastchange
= 0;
677 if( (i_lastwhite
- i_firstwhite
) < (int) (p_vout
->p_sys
->i_height
/ 2) )
679 p_vout
->p_sys
->i_lastchange
= 0;
683 if (p_vout
->output
.i_aspect
684 * p_vout
->output
.i_height
/
685 (i_lastwhite
- i_firstwhite
+ 1)
686 * p_vout
->p_sys
->i_width
/
687 p_vout
->output
.i_width
>
688 p_vout
->p_sys
->i_ratio_max
* 432)
690 int i_height
= ((p_vout
->output
.i_aspect
/ 432) *
691 p_vout
->output
.i_height
* p_vout
->p_sys
->i_width
) /
692 (p_vout
->output
.i_width
* p_vout
->p_sys
->i_ratio_max
);
693 i_firstwhite
= (p_vout
->output
.i_height
- i_height
) / 2;
694 i_lastwhite
= p_vout
->output
.i_height
- i_firstwhite
;
696 p_vout->p_sys->i_lastchange = 0;
701 if( (i_lastwhite
- i_firstwhite
) <
702 (int) (p_vout
->p_sys
->i_height
+ i_diff
)
703 && (i_lastwhite
- i_firstwhite
+ i_diff
) >
704 (int) p_vout
->p_sys
->i_height
)
706 p_vout
->p_sys
->i_lastchange
= 0;
710 /* We need at least 'i_time' images to make up our mind */
711 p_vout
->p_sys
->i_lastchange
++;
712 if( p_vout
->p_sys
->i_lastchange
< (unsigned int)i_time
)
719 if ( p_vout
->p_sys
->i_lastchange
>= (unsigned int)i_time
)
721 p_vout
->p_sys
->i_aspect
= p_vout
->p_sys
->i_ratio
* 432;
722 int i_height
= p_vout
->output
.i_aspect
723 * p_vout
->output
.i_height
/
724 p_vout
->p_sys
->i_aspect
725 * p_vout
->p_sys
->i_width
/
726 p_vout
->output
.i_width
;
727 i_firstwhite
= (p_vout
->output
.i_height
- i_height
) / 2;
728 i_lastwhite
= p_vout
->output
.i_height
- i_firstwhite
;
737 /* Determine where black borders are */
738 switch( p_vout
->output
.i_chroma
)
741 /* XXX: Do not laugh ! I know this is very naive. But it's just a
742 * proof of concept code snippet... */
743 for( i
= i_lines
; i
-- ; )
745 const int i_col
= i
* i_pitch
/ i_lines
;
747 if( p_in
[i_col
/2] > 40
748 && p_in
[i_visible_pitch
/2] > 40
749 && p_in
[i_visible_pitch
/2 + i_col
/2] > 40 )
751 if( i_lastwhite
== -1 )
765 /* Decide whether it's worth changing the size */
766 if( i_lastwhite
== -1 )
768 p_vout
->p_sys
->i_lastchange
= 0;
772 if( (unsigned int)(i_lastwhite
- i_firstwhite
)
773 < p_vout
->p_sys
->i_height
/ 2 )
775 p_vout
->p_sys
->i_lastchange
= 0;
779 if( (unsigned int)(i_lastwhite
- i_firstwhite
)
780 < p_vout
->p_sys
->i_height
+ 16
781 && (unsigned int)(i_lastwhite
- i_firstwhite
+ 16)
782 > p_vout
->p_sys
->i_height
)
784 p_vout
->p_sys
->i_lastchange
= 0;
788 /* We need at least 25 images to make up our mind */
789 p_vout
->p_sys
->i_lastchange
++;
790 if( p_vout
->p_sys
->i_lastchange
< 25 )
794 #endif //BEST_AUTOCROP
796 /* Tune a few values */
797 if( i_firstwhite
& 1 )
802 if( !(i_lastwhite
& 1) )
808 p_vout
->p_sys
->i_y
= i_firstwhite
;
809 p_vout
->p_sys
->i_height
= i_lastwhite
- i_firstwhite
+ 1;
811 // check p_vout->p_sys->i_height <= p_vout->output.i_height
812 if (p_vout
->p_sys
->i_height
> p_vout
->output
.i_height
)
813 p_vout
->p_sys
->i_height
= p_vout
->output
.i_height
;
816 p_vout
->p_sys
->i_aspect
= p_vout
->output
.i_aspect
817 * p_vout
->output
.i_height
/ p_vout
->p_sys
->i_height
818 * p_vout
->p_sys
->i_width
/ p_vout
->output
.i_width
;
820 p_vout
->p_sys
->b_changed
= true;
824 * Forward mouse event with proper conversion.
826 static int MouseEvent( vlc_object_t
*p_this
, char const *psz_var
,
827 vlc_value_t oldval
, vlc_value_t newval
, void *p_data
)
829 vout_thread_t
*p_vout
= p_data
;
830 VLC_UNUSED(p_this
); VLC_UNUSED(oldval
);
832 if( !strcmp( psz_var
, "mouse-button-down" ) )
833 return var_SetChecked( p_vout
, psz_var
, VLC_VAR_INTEGER
, newval
);
835 /* Translate the mouse coordinates
836 * FIXME missing lock */
837 newval
.coords
.x
+= p_vout
->p_sys
->i_x
;
838 newval
.coords
.y
+= p_vout
->p_sys
->i_y
;
839 return var_SetChecked( p_vout
, psz_var
, VLC_VAR_COORDS
, newval
);
843 /*****************************************************************************
844 * FilterCallback: called when changing the ratio on the fly.
845 *****************************************************************************/
846 static int FilterCallback( vlc_object_t
*p_this
, char const *psz_var
,
847 vlc_value_t oldval
, vlc_value_t newval
,
850 VLC_UNUSED(p_data
); VLC_UNUSED(oldval
);
851 vout_thread_t
* p_vout
= (vout_thread_t
*)p_this
;
853 if( !strcmp( psz_var
, "ratio-crop" ) )
855 vlc_mutex_lock( &p_vout
->p_sys
->lock
);
856 if ( !strcmp( newval
.psz_string
, "Auto" ) )
857 p_vout
->p_sys
->i_ratio
= 0;
860 p_vout
->p_sys
->i_ratio
= (unsigned int)atoi(newval
.psz_string
);
861 p_vout
->p_sys
->i_lastchange
= p_vout
->p_sys
->i_time
;
862 p_vout
->p_sys
->b_autocrop
= true;
864 if (p_vout
->p_sys
->i_ratio
)
866 if (p_vout
->p_sys
->i_ratio
< (p_vout
->output
.i_width
* 1000) /
867 p_vout
->output
.i_height
)
868 p_vout
->p_sys
->i_ratio
= (p_vout
->output
.i_width
* 1000) /
869 p_vout
->output
.i_height
;
870 if (p_vout
->p_sys
->i_ratio
< p_vout
->output
.i_aspect
/ 432)
871 p_vout
->p_sys
->i_ratio
= p_vout
->output
.i_aspect
/ 432;
873 vlc_mutex_unlock( &p_vout
->p_sys
->lock
);