[MPlayer-dev-eng] [PATCH] automatic cropping in vf_crop
Alexander Stege
mplayer at legale-software.com
Mon Jun 18 01:24:51 CEST 2007
Hello everyone!
This is a patch that merges the functionalities of the cropdetect and the
crop video filter to enable automatic/interactive cropping of black borders
without having to manually copy&paste and restart mplayer.
To apply the crop parameters that cropdetect has detected, I have connected
the filter to the 'change_rectangle' input.conf directive that belongs to
the rectangle filter. rectangle is just a dummy-crop anyway I guess.
cropdetect is only run on every 50th frame, so no worries about CPU-eating.
have a nice day,
Alex
-------------- next part --------------
Index: libmpcodecs/vf_crop.c
===================================================================
--- libmpcodecs/vf_crop.c (revision 23572)
+++ libmpcodecs/vf_crop.c (working copy)
@@ -13,12 +13,20 @@
#include "m_option.h"
#include "m_struct.h"
+#define AC_NOVAL (-2)
+
static struct vf_priv_s {
int crop_w,crop_h;
int crop_x,crop_y;
+ int x1,y1,x2,y2;
+ int limit;
+ int fno;
} const vf_priv_dflt = {
-1,-1,
- -1,-1
+ -1,-1,
+ -1,-1,-1,-1,
+ AC_NOVAL,
+ 0
};
extern int opt_screen_size_x;
@@ -26,6 +34,28 @@
//===========================================================================//
+static int checkline(unsigned char* src,int stride,int len,int bpp){
+ int total=0;
+ int div=len;
+ switch(bpp){
+ case 1:
+ while(--len>=0){
+ total+=src[0]; src+=stride;
+ }
+ break;
+ case 3:
+ case 4:
+ while(--len>=0){
+ total+=src[0]+src[1]+src[2]; src+=stride;
+ }
+ div*=3;
+ break;
+ }
+ total/=div;
+// printf("total=%d\n",total);
+ return total;
+}
+
static int config(struct vf_instance_s* vf,
int width, int height, int d_width, int d_height,
unsigned int flags, unsigned int outfmt){
@@ -34,6 +64,12 @@
if(vf->priv->crop_h<=0 || vf->priv->crop_h>height) vf->priv->crop_h=height;
if(vf->priv->crop_x<0) vf->priv->crop_x=(width-vf->priv->crop_w)/2;
if(vf->priv->crop_y<0) vf->priv->crop_y=(height-vf->priv->crop_h)/2;
+ // reset cropdetect parameters:
+ vf->priv->x1=width - 1;
+ vf->priv->y1=height - 1;
+ vf->priv->x2=0;
+ vf->priv->y2=0;
+ vf->priv->fno=0;
// rounding:
if(!IMGFMT_IS_RGB(outfmt) && !IMGFMT_IS_BGR(outfmt)){
switch(outfmt){
@@ -43,15 +79,19 @@
break;
case IMGFMT_YVU9:
case IMGFMT_IF09:
+ vf->priv->crop_h += vf->priv->crop_y&3;
vf->priv->crop_y&=~3;
case IMGFMT_411P:
+ vf->priv->crop_w += vf->priv->crop_x&3;
vf->priv->crop_x&=~3;
break;
case IMGFMT_YV12:
case IMGFMT_I420:
case IMGFMT_IYUV:
+ vf->priv->crop_h += vf->priv->crop_y&1;
vf->priv->crop_y&=~1;
default:
+ vf->priv->crop_w += vf->priv->crop_x&1;
vf->priv->crop_x&=~1;
}
}
@@ -68,8 +108,53 @@
return vf_next_config(vf,vf->priv->crop_w,vf->priv->crop_h,d_width,d_height,flags,outfmt);
}
+static int
+control(struct vf_instance_s* vf, int request, void *data)
+{
+ const int *const tmp = data;
+ switch(request){
+ case VFCTRL_CHANGE_RECTANGLE:
+ switch (tmp[0]){
+ case 0:
+ vf->priv->crop_w += tmp[1];
+ return 1;
+ case 1:
+ vf->priv->crop_h += tmp[1];
+ return 1;
+ case 2:
+ vf->priv->crop_x += tmp[1];
+ return 1;
+ case 3:
+ vf->priv->crop_y += tmp[1];
+ return 1;
+ case 4:
+ // change limit for next cropdetect results
+ // -1: disables cropdetect
+ // -2: leave previous limit untouched
+ if (tmp[1] >= -1) vf->priv->limit = tmp[1];
+ // has cropdetect found a non-black frame yet?
+ if (vf->priv->x2 <= vf->priv->x1 ||
+ vf->priv->y2 <= vf->priv->y1) return 1;
+ // get values from cropdetect filter
+ vf->priv->crop_w = vf->priv->x2 - vf->priv->x1 + 1;
+ vf->priv->crop_h = vf->priv->y2 - vf->priv->y1 + 1;
+ vf->priv->crop_x = vf->priv->x1;
+ vf->priv->crop_y = vf->priv->y1;
+ return 1;
+ default:
+ mp_msg(MSGT_VFILTER,MSGL_FATAL,"Unknown param %d \n", tmp[0]);
+ return 0;
+ }
+ }
+ return vf_next_control(vf, request, data);
+ return 0;
+}
+
static int put_image(struct vf_instance_s* vf, mp_image_t *mpi, double pts){
mp_image_t *dmpi;
+ int bpp=mpi->bpp/8;
+ int x, y;
+
if (mpi->flags&MP_IMGFLAG_DRAW_CALLBACK)
return vf_next_put_image(vf,vf->dmpi, pts);
dmpi=vf_get_image(vf->next,mpi->imgfmt,
@@ -92,6 +177,43 @@
}
dmpi->stride[0]=mpi->stride[0];
dmpi->width=mpi->width;
+
+ // cropdetect will run all the time, so we should not waste CPU
+ if (vf->priv->limit>=0 && ++vf->priv->fno>50)
+ {
+ vf->priv->fno = 0;
+
+ for(y=0;y<vf->priv->y1;y++){
+ if(checkline(mpi->planes[0]+mpi->stride[0]*y,bpp,mpi->w,bpp)>vf->priv->limit){
+ vf->priv->y1=y;
+ break;
+ }
+ }
+
+ for(y=mpi->h-1;y>vf->priv->y2;y--){
+ if(checkline(mpi->planes[0]+mpi->stride[0]*y,bpp,mpi->w,bpp)>vf->priv->limit){
+ vf->priv->y2=y;
+ break;
+ }
+ }
+
+ for(y=0;y<vf->priv->x1;y++){
+ if(checkline(mpi->planes[0]+bpp*y,mpi->stride[0],mpi->h,bpp)>vf->priv->limit){
+ vf->priv->x1=y;
+ break;
+ }
+ }
+
+ for(y=mpi->w-1;y>vf->priv->x2;y--){
+ if(checkline(mpi->planes[0]+bpp*y,mpi->stride[0],mpi->h,bpp)>vf->priv->limit){
+ vf->priv->x2=y;
+ break;
+ }
+ }
+ mp_msg(MSGT_VFILTER, MSGL_DBG2, "Cropbox: %d - %d, %d - %d\n",
+ vf->priv->x1, vf->priv->x2, vf->priv->y1, vf->priv->y2);
+ }
+
return vf_next_put_image(vf,dmpi, pts);
}
@@ -140,6 +262,7 @@
static int open(vf_instance_t *vf, char* args){
vf->config=config;
+ vf->control=control;
vf->put_image=put_image;
vf->start_slice=start_slice;
vf->draw_slice=draw_slice;
@@ -151,17 +274,31 @@
vf->priv->crop_y=
vf->priv->crop_w=
vf->priv->crop_h=-1;
+ vf->priv->limit=AC_NOVAL;
} //if(!vf->priv)
- if(args) sscanf(args, "%d:%d:%d:%d",
+ if(args) sscanf(args, "%d:%d:%d:%d:%d",
&vf->priv->crop_w,
&vf->priv->crop_h,
&vf->priv->crop_x,
- &vf->priv->crop_y);
- mp_msg(MSGT_VFILTER, MSGL_INFO, "Crop: %d x %d, %d ; %d\n",
- vf->priv->crop_w,
- vf->priv->crop_h,
- vf->priv->crop_x,
- vf->priv->crop_y);
+ &vf->priv->crop_y,
+ &vf->priv->limit);
+ // enable autocrop if width and height are not explicitly given
+ if(vf->priv->limit<=AC_NOVAL && vf->priv->crop_w<=0 && vf->priv->crop_h<=0)
+ vf->priv->limit=24;
+
+ if(vf->priv->limit>=0)
+ {
+ mp_msg(MSGT_VFILTER, MSGL_INFO, "Autocrop: threshold=%d\n",
+ vf->priv->limit);
+ }
+ else
+ {
+ mp_msg(MSGT_VFILTER, MSGL_INFO, "Crop: %d x %d, %d ; %d\n",
+ vf->priv->crop_w,
+ vf->priv->crop_h,
+ vf->priv->crop_x,
+ vf->priv->crop_y);
+ }
return 1;
}
@@ -171,6 +308,7 @@
{"h", ST_OFF(crop_h), CONF_TYPE_INT, M_OPT_MIN,0 ,0, NULL},
{"x", ST_OFF(crop_x), CONF_TYPE_INT, M_OPT_MIN,-1 ,0, NULL},
{"y", ST_OFF(crop_y), CONF_TYPE_INT, M_OPT_MIN,-1 ,0, NULL},
+ {"limit", ST_OFF(limit), CONF_TYPE_INT, M_OPT_MIN,-1 ,0, NULL},
{ NULL, NULL, 0, 0, 0, 0, NULL }
};
Index: DOCS/tech/slave.txt
===================================================================
--- DOCS/tech/slave.txt (revision 23572)
+++ DOCS/tech/slave.txt (working copy)
@@ -41,13 +41,14 @@
<value> is in the range [-100, 100].
change_rectangle <val1> <val2>
- Change the position of the rectangle filter rectangle.
+ Change the position of the rectangle filter and the crop filter rectangle.
<val1>
Must be one of the following:
0 = width
1 = height
2 = x position
3 = y position
+ 4 = use autocrop values (only for crop filter)
<val2>
If <val1> is 0 or 1:
Integer amount to add/subtract from the width/height.
@@ -57,6 +58,11 @@
Relative integer amount by which to move the upper left
rectangle corner. Positive values move the rectangle
right/down and negative values move the rectangle left/up.
+ If <val1> is 4:
+ New luma threshold for builtin cropdetect filter.
+ Special values:
+ -1: Disable cropdetect
+ -2: Keep previous value
dvb_set_channel <channel_number> <card_number>
Set DVB channel.
Index: DOCS/man/en/mplayer.1
===================================================================
--- DOCS/man/en/mplayer.1 (revision 23572)
+++ DOCS/man/en/mplayer.1 (working copy)
@@ -5098,15 +5098,25 @@
Available filters are:
.
.TP
-.B crop[=w:h:x:y]
+.B crop[=w:h:x:y:limit]
Crops the given part of the image and discards the rest.
Useful to remove black bands from widescreen movies.
+If limit is set to a non-negative value, autocrop is enabled and the video
+is scanned for black borders. The scanned values are applied by the
+input.conf directive 'change_rectangle' that takes two parameters.
+Give the filter a few seconds to detect the optimal crop boundaries
+before triggering the actual cropping with 'change_rectangle'.
.PD 0
.RSs
.IPs <w>,<h>
-Cropped width and height, defaults to original width and height.
+Cropped width and height. If the crop area is not supplied, autocrop
+is enabled with limit=24, except if limit is also explicitly set to a
+negative value, in which case it defaults to the original width and height.
.IPs <x>,<y>
Position of the cropped picture, defaults to center.
+.IPs <limit>
+Luma threshold for builtin cropdetect filter. It is the same as for the
+standalone cropdetect.
.RE
.PD 1
.
Index: command.c
===================================================================
--- command.c (revision 23572)
+++ command.c (working copy)
@@ -2461,6 +2461,7 @@
case MP_CMD_VF_CHANGE_RECTANGLE:
set_rectangle(sh_video, cmd->args[0].v.i, cmd->args[1].v.i);
+ mpcodecs_config_vo(sh_video, sh_video->disp_w, sh_video->disp_h, 0);
break;
case MP_CMD_GET_TIME_LENGTH:{
More information about the MPlayer-dev-eng
mailing list