Commit e784bfb9 authored by vdb128@picaros.org's avatar vdb128@picaros.org Committed by Mauro Carvalho Chehab

V4L/DVB (8896): pvrusb2: Implement crop support

Implement pvrusb2 driver plumbing to support cropping.  Submitted by a
pvrusb2 user.
Signed-off-by: default avatarMike Isely <isely@pobox.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent fe15f136
...@@ -319,6 +319,7 @@ struct pvr2_hdw { ...@@ -319,6 +319,7 @@ struct pvr2_hdw {
struct pvr2_ctl_info std_info_cur; struct pvr2_ctl_info std_info_cur;
struct v4l2_standard *std_defs; struct v4l2_standard *std_defs;
const char **std_enum_names; const char **std_enum_names;
struct v4l2_cropcap cropcap;
// Generated string names, one per actual V4L2 standard // Generated string names, one per actual V4L2 standard
const char *std_mask_ptrs[32]; const char *std_mask_ptrs[32];
...@@ -367,6 +368,10 @@ struct pvr2_hdw { ...@@ -367,6 +368,10 @@ struct pvr2_hdw {
VCREATE_DATA(bass); VCREATE_DATA(bass);
VCREATE_DATA(treble); VCREATE_DATA(treble);
VCREATE_DATA(mute); VCREATE_DATA(mute);
VCREATE_DATA(cropl);
VCREATE_DATA(cropt);
VCREATE_DATA(cropw);
VCREATE_DATA(croph);
VCREATE_DATA(input); VCREATE_DATA(input);
VCREATE_DATA(audiomode); VCREATE_DATA(audiomode);
VCREATE_DATA(res_hor); VCREATE_DATA(res_hor);
......
...@@ -402,6 +402,52 @@ static int ctrl_freq_set(struct pvr2_ctrl *cptr,int m,int v) ...@@ -402,6 +402,52 @@ static int ctrl_freq_set(struct pvr2_ctrl *cptr,int m,int v)
return 0; return 0;
} }
static int ctrl_cropl_min_get(struct pvr2_ctrl *cptr, int *left)
{
struct v4l2_cropcap *cap = &cptr->hdw->cropcap;
if (cap->bounds.width > 0) {
/* This statement is present purely to shut up
checkpatch.pl */
*left = cap->bounds.left - cap->defrect.left;
} else {
/* This statement is present purely to shut up
checkpatch.pl */
*left = -119;
}
return 0;
}
static int ctrl_cropl_max_get(struct pvr2_ctrl *cptr, int *left)
{
struct v4l2_cropcap *cap = &cptr->hdw->cropcap;
if (cap->bounds.width > 0) {
*left = cap->bounds.left + cap->bounds.width
- cap->defrect.left;
*left += 3;
*left -= cptr->hdw->cropw_val;
} else {
/* This statement is present purely to shut up
checkpatch.pl */
*left = 340;
}
return 0;
}
static int ctrl_cropt_min_get(struct pvr2_ctrl *cptr, int *top)
{
struct v4l2_cropcap *cap = &cptr->hdw->cropcap;
if (cap->bounds.height > 0) {
/* This statement is present purely to shut up
checkpatch.pl */
*top = cap->bounds.top - cap->defrect.top;
} else {
/* This statement is present purely to shut up
checkpatch.pl */
*top = -19;
}
return 0;
}
static int ctrl_vres_max_get(struct pvr2_ctrl *cptr,int *vp) static int ctrl_vres_max_get(struct pvr2_ctrl *cptr,int *vp)
{ {
/* Actual maximum depends on the video standard in effect. */ /* Actual maximum depends on the video standard in effect. */
...@@ -413,6 +459,19 @@ static int ctrl_vres_max_get(struct pvr2_ctrl *cptr,int *vp) ...@@ -413,6 +459,19 @@ static int ctrl_vres_max_get(struct pvr2_ctrl *cptr,int *vp)
return 0; return 0;
} }
static int ctrl_cropt_max_get(struct pvr2_ctrl *cptr, int *top)
{
struct v4l2_cropcap *cap = &cptr->hdw->cropcap;
if (cap->bounds.height > 0) {
*top = cap->bounds.top + cap->bounds.height - cap->defrect.top;
*top -= cptr->hdw->croph_val;
} else {
ctrl_vres_max_get(cptr, top);
*top -= 32;
}
return 0;
}
static int ctrl_vres_min_get(struct pvr2_ctrl *cptr,int *vp) static int ctrl_vres_min_get(struct pvr2_ctrl *cptr,int *vp)
{ {
/* Actual minimum depends on device digitizer type. */ /* Actual minimum depends on device digitizer type. */
...@@ -779,6 +838,10 @@ VCREATE_FUNCS(balance) ...@@ -779,6 +838,10 @@ VCREATE_FUNCS(balance)
VCREATE_FUNCS(bass) VCREATE_FUNCS(bass)
VCREATE_FUNCS(treble) VCREATE_FUNCS(treble)
VCREATE_FUNCS(mute) VCREATE_FUNCS(mute)
VCREATE_FUNCS(cropl)
VCREATE_FUNCS(cropt)
VCREATE_FUNCS(cropw)
VCREATE_FUNCS(croph)
VCREATE_FUNCS(audiomode) VCREATE_FUNCS(audiomode)
VCREATE_FUNCS(res_hor) VCREATE_FUNCS(res_hor)
VCREATE_FUNCS(res_ver) VCREATE_FUNCS(res_ver)
...@@ -849,6 +912,39 @@ static const struct pvr2_ctl_info control_defs[] = { ...@@ -849,6 +912,39 @@ static const struct pvr2_ctl_info control_defs[] = {
.default_value = 0, .default_value = 0,
DEFREF(mute), DEFREF(mute),
DEFBOOL, DEFBOOL,
}, {
.desc = "Capture left margin",
.name = "crop_left",
.internal_id = PVR2_CID_CROPL,
.default_value = 0,
DEFREF(cropl),
DEFINT(-129, 340),
.get_min_value = ctrl_cropl_min_get,
.get_max_value = ctrl_cropl_max_get,
}, {
.desc = "Capture top margin",
.name = "crop_top",
.internal_id = PVR2_CID_CROPT,
.default_value = 0,
DEFREF(cropt),
DEFINT(-35, 544),
.get_min_value = ctrl_cropt_min_get,
.get_max_value = ctrl_cropt_max_get,
}, {
.desc = "Capture width",
.name = "crop_width",
.internal_id = PVR2_CID_CROPW,
.default_value = 720,
DEFREF(cropw),
DEFINT(388, 849), /* determined empirically, any res_hor>=64 */
}, {
.desc = "Capture height",
.name = "crop_height",
.internal_id = PVR2_CID_CROPH,
.default_value = 480,
DEFREF(croph),
DEFINT(32, 576),
.get_max_value = ctrl_vres_max_get,
},{ },{
.desc = "Video Source", .desc = "Video Source",
.name = "input", .name = "input",
...@@ -2092,6 +2188,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, ...@@ -2092,6 +2188,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
valid_std_mask; valid_std_mask;
} }
memset(&hdw->cropcap, 0, sizeof hdw->cropcap);
hdw->eeprom_addr = -1; hdw->eeprom_addr = -1;
hdw->unit_number = -1; hdw->unit_number = -1;
hdw->v4l_minor_number_video = -1; hdw->v4l_minor_number_video = -1;
...@@ -2528,6 +2625,28 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw) ...@@ -2528,6 +2625,28 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
/* Can't commit anything until pathway is ok. */ /* Can't commit anything until pathway is ok. */
return 0; return 0;
} }
/* The broadcast decoder can only scale down, so if
* res_*_dirty && crop window < output format ==> enlarge crop.
*
* The mpeg encoder receives fields of res_hor_val dots and
* res_ver_val halflines. Limits: hor<=720, ver<=576.
*/
if (hdw->res_hor_dirty && hdw->cropw_val < hdw->res_hor_val) {
hdw->cropw_val = hdw->res_hor_val;
hdw->cropw_dirty = !0;
} else if (hdw->cropw_dirty) {
hdw->res_hor_dirty = !0; /* must rescale */
hdw->res_hor_val = min(720, hdw->cropw_val);
}
if (hdw->res_ver_dirty && hdw->croph_val < hdw->res_ver_val) {
hdw->croph_val = hdw->res_ver_val;
hdw->croph_dirty = !0;
} else if (hdw->croph_dirty) {
int nvres = hdw->std_mask_cur & V4L2_STD_525_60 ? 480 : 576;
hdw->res_ver_dirty = !0;
hdw->res_ver_val = min(nvres, hdw->croph_val);
}
/* If any of the below has changed, then we can't do the update /* If any of the below has changed, then we can't do the update
while the pipeline is running. Pipeline must be paused first while the pipeline is running. Pipeline must be paused first
and decoder -> encoder connection be made quiescent before we and decoder -> encoder connection be made quiescent before we
......
...@@ -36,6 +36,10 @@ ...@@ -36,6 +36,10 @@
#define PVR2_CID_FREQUENCY 6 #define PVR2_CID_FREQUENCY 6
#define PVR2_CID_HRES 7 #define PVR2_CID_HRES 7
#define PVR2_CID_VRES 8 #define PVR2_CID_VRES 8
#define PVR2_CID_CROPL 9
#define PVR2_CID_CROPT 10
#define PVR2_CID_CROPW 11
#define PVR2_CID_CROPH 12
/* Legal values for the INPUT state variable */ /* Legal values for the INPUT state variable */
#define PVR2_CVAL_INPUT_TV 0 #define PVR2_CVAL_INPUT_TV 0
......
...@@ -37,8 +37,9 @@ ...@@ -37,8 +37,9 @@
#define OP_VOLUME 3 #define OP_VOLUME 3
#define OP_FREQ 4 #define OP_FREQ 4
#define OP_AUDIORATE 5 #define OP_AUDIORATE 5
#define OP_SIZE 6 #define OP_CROP 6
#define OP_LOG 7 #define OP_SIZE 7
#define OP_LOG 8
static const struct pvr2_i2c_op * const ops[] = { static const struct pvr2_i2c_op * const ops[] = {
[OP_STANDARD] = &pvr2_i2c_op_v4l2_standard, [OP_STANDARD] = &pvr2_i2c_op_v4l2_standard,
...@@ -46,6 +47,7 @@ static const struct pvr2_i2c_op * const ops[] = { ...@@ -46,6 +47,7 @@ static const struct pvr2_i2c_op * const ops[] = {
[OP_BCSH] = &pvr2_i2c_op_v4l2_bcsh, [OP_BCSH] = &pvr2_i2c_op_v4l2_bcsh,
[OP_VOLUME] = &pvr2_i2c_op_v4l2_volume, [OP_VOLUME] = &pvr2_i2c_op_v4l2_volume,
[OP_FREQ] = &pvr2_i2c_op_v4l2_frequency, [OP_FREQ] = &pvr2_i2c_op_v4l2_frequency,
[OP_CROP] = &pvr2_i2c_op_v4l2_crop,
[OP_SIZE] = &pvr2_i2c_op_v4l2_size, [OP_SIZE] = &pvr2_i2c_op_v4l2_size,
[OP_LOG] = &pvr2_i2c_op_v4l2_log, [OP_LOG] = &pvr2_i2c_op_v4l2_log,
}; };
...@@ -59,6 +61,7 @@ void pvr2_i2c_probe(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp) ...@@ -59,6 +61,7 @@ void pvr2_i2c_probe(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
(1 << OP_BCSH) | (1 << OP_BCSH) |
(1 << OP_VOLUME) | (1 << OP_VOLUME) |
(1 << OP_FREQ) | (1 << OP_FREQ) |
(1 << OP_CROP) |
(1 << OP_SIZE) | (1 << OP_SIZE) |
(1 << OP_LOG)); (1 << OP_LOG));
cp->status_poll = pvr2_v4l2_cmd_status_poll; cp->status_poll = pvr2_v4l2_cmd_status_poll;
......
...@@ -233,6 +233,55 @@ const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size = { ...@@ -233,6 +233,55 @@ const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size = {
}; };
static void set_crop(struct pvr2_hdw *hdw)
{
struct v4l2_cropcap cap;
struct v4l2_crop crop;
int stat;
memset(&cap, 0, sizeof cap);
cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
stat = pvr2_i2c_core_cmd(hdw, VIDIOC_CROPCAP, &cap);
hdw->cropcap = cap;
memset(&crop, 0, sizeof crop);
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
crop.c = cap.defrect;
crop.c.left += hdw->cropl_val;
crop.c.top += hdw->cropt_val;
crop.c.height = hdw->croph_val;
crop.c.width = hdw->cropw_val;
pvr2_trace(PVR2_TRACE_CHIPS,
"i2c v4l2 set_crop stat=%d cap=%d:%d:%d:%d"
" crop=%d:%d:%d:%d", stat, cap.bounds.width,
cap.bounds.height, cap.bounds.left, cap.bounds.top,
crop.c.width, crop.c.height, crop.c.left, crop.c.top);
if (stat >= 0) {
/* This comment is present purely to keep
checkpatch.pl quiet */
pvr2_i2c_core_cmd(hdw, VIDIOC_S_CROP, &crop);
}
}
static int check_crop(struct pvr2_hdw *hdw)
{
/* The "0 +" stupidity is present only to get checkpatch.pl to
shut up. I _want_ those parantheses present so that the
two lines automatically line up in my editor. I despise
checkpatch.pl. */
return 0 + (hdw->cropl_dirty || hdw->cropt_dirty ||
hdw->cropw_dirty || hdw->croph_dirty);
}
const struct pvr2_i2c_op pvr2_i2c_op_v4l2_crop = {
.check = check_crop,
.update = set_crop,
.name = "v4l2_crop",
};
static void do_log(struct pvr2_hdw *hdw) static void do_log(struct pvr2_hdw *hdw)
{ {
pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 do_log()"); pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 do_log()");
......
...@@ -29,6 +29,7 @@ extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_radio; ...@@ -29,6 +29,7 @@ extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_radio;
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_bcsh; extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_bcsh;
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume; extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume;
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_frequency; extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_frequency;
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_crop;
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size; extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size;
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_audiomode; extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_audiomode;
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log; extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment