Skip to content

Commit

Permalink
[media] omap3isp: preview: Add crop support on the sink pad
Browse files Browse the repository at this point in the history
The crop rectangle takes the preview engine internal cropping
requirements into account. The smallest allowable margins are 14 columns
and 8 rows when reading from memory, and 18 columns and 8 rows when
processing data on the fly from the CCDC.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
  • Loading branch information
Laurent Pinchart authored and Mauro Carvalho Chehab committed Nov 3, 2011
1 parent 059dc1d commit 1f69fd9
Show file tree
Hide file tree
Showing 2 changed files with 198 additions and 66 deletions.
262 changes: 196 additions & 66 deletions drivers/media/video/omap3isp/isppreview.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,42 @@ static struct omap3isp_prev_csc flr_prev_csc = {

#define DEF_DETECT_CORRECT_VAL 0xe

/*
* Margins and image size limits.
*
* The preview engine crops several rows and columns internally depending on
* which filters are enabled. To avoid format changes when the filters are
* enabled or disabled (which would prevent them from being turned on or off
* during streaming), the driver assumes all the filters are enabled when
* computing sink crop and source format limits.
*
* If a filter is disabled, additional cropping is automatically added at the
* preview engine input by the driver to avoid overflow at line and frame end.
* This is completely transparent for applications.
*
* Median filter 4 pixels
* Noise filter,
* Faulty pixels correction 4 pixels, 4 lines
* CFA filter 4 pixels, 4 lines in Bayer mode
* 2 lines in other modes
* Color suppression 2 pixels
* or luma enhancement
* -------------------------------------------------------------
* Maximum total 14 pixels, 8 lines
*
* The color suppression and luma enhancement filters are applied after bayer to
* YUV conversion. They thus can crop one pixel on the left and one pixel on the
* right side of the image without changing the color pattern. When both those
* filters are disabled, the driver must crop the two pixels on the same side of
* the image to avoid changing the bayer pattern. The left margin is thus set to
* 8 pixels and the right margin to 6 pixels.
*/

#define PREV_MARGIN_LEFT 8
#define PREV_MARGIN_RIGHT 6
#define PREV_MARGIN_TOP 4
#define PREV_MARGIN_BOTTOM 4

#define PREV_MIN_IN_WIDTH 64
#define PREV_MIN_IN_HEIGHT 8
#define PREV_MAX_IN_HEIGHT 16384
Expand Down Expand Up @@ -985,52 +1021,36 @@ static void preview_config_averager(struct isp_prev_device *prev, u8 average)
* enabled when reporting source pad formats to userspace. If this assumption is
* not true, rows and columns must be manually cropped at the preview engine
* input to avoid overflows at the end of lines and frames.
*
* See the explanation at the PREV_MARGIN_* definitions for more details.
*/
static void preview_config_input_size(struct isp_prev_device *prev)
{
struct isp_device *isp = to_isp_device(prev);
struct prev_params *params = &prev->params;
struct v4l2_mbus_framefmt *format = &prev->formats[PREV_PAD_SINK];
unsigned int sph = 0;
unsigned int eph = format->width - 1;
unsigned int slv = 0;
unsigned int elv = format->height - 1;

if (prev->input == PREVIEW_INPUT_CCDC) {
sph += 2;
eph -= 2;
}

/*
* Median filter 4 pixels
* Noise filter 4 pixels, 4 lines
* or faulty pixels correction
* CFA filter 4 pixels, 4 lines in Bayer mode
* 2 lines in other modes
* Color suppression 2 pixels
* or luma enhancement
* -------------------------------------------------------------
* Maximum total 14 pixels, 8 lines
*/

if (!(params->features & PREV_CFA)) {
sph += 2;
eph -= 2;
slv += 2;
elv -= 2;
unsigned int sph = prev->crop.left;
unsigned int eph = prev->crop.left + prev->crop.width - 1;
unsigned int slv = prev->crop.top;
unsigned int elv = prev->crop.top + prev->crop.height - 1;

if (params->features & PREV_CFA) {
sph -= 2;
eph += 2;
slv -= 2;
elv += 2;
}
if (!(params->features & (PREV_DEFECT_COR | PREV_NOISE_FILTER))) {
sph += 2;
eph -= 2;
slv += 2;
elv -= 2;
if (params->features & (PREV_DEFECT_COR | PREV_NOISE_FILTER)) {
sph -= 2;
eph += 2;
slv -= 2;
elv += 2;
}
if (!(params->features & PREV_HORZ_MEDIAN_FILTER)) {
sph += 2;
eph -= 2;
if (params->features & PREV_HORZ_MEDIAN_FILTER) {
sph -= 2;
eph += 2;
}
if (!(params->features & (PREV_CHROMA_SUPPRESS | PREV_LUMA_ENHANCE)))
sph += 2;
if (params->features & (PREV_CHROMA_SUPPRESS | PREV_LUMA_ENHANCE))
sph -= 2;

isp_reg_writel(isp, (sph << ISPPRV_HORZ_INFO_SPH_SHIFT) | eph,
OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO);
Expand Down Expand Up @@ -1597,6 +1617,16 @@ __preview_get_format(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh,
return &prev->formats[pad];
}

static struct v4l2_rect *
__preview_get_crop(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
return v4l2_subdev_get_try_crop(fh, PREV_PAD_SINK);
else
return &prev->crop;
}

/* previewer format descriptions */
static const unsigned int preview_input_fmts[] = {
V4L2_MBUS_FMT_SGRBG10_1X10,
Expand All @@ -1611,19 +1641,23 @@ static const unsigned int preview_output_fmts[] = {
};

/*
* preview_try_format - Handle try format by pad subdev method
* @prev: ISP preview device
* @fh : V4L2 subdev file handle
* @pad: pad num
* @fmt: pointer to v4l2 format structure
* preview_try_format - Validate a format
* @prev: ISP preview engine
* @fh: V4L2 subdev file handle
* @pad: pad number
* @fmt: format to be validated
* @which: try/active format selector
*
* Validate and adjust the given format for the given pad based on the preview
* engine limits and the format and crop rectangles on other pads.
*/
static void preview_try_format(struct isp_prev_device *prev,
struct v4l2_subdev_fh *fh, unsigned int pad,
struct v4l2_mbus_framefmt *fmt,
enum v4l2_subdev_format_whence which)
{
struct v4l2_mbus_framefmt *format;
enum v4l2_mbus_pixelcode pixelcode;
struct v4l2_rect *crop;
unsigned int i;

switch (pad) {
Expand Down Expand Up @@ -1659,15 +1693,8 @@ static void preview_try_format(struct isp_prev_device *prev,

case PREV_PAD_SOURCE:
pixelcode = fmt->code;
format = __preview_get_format(prev, fh, PREV_PAD_SINK, which);
memcpy(fmt, format, sizeof(*fmt));
*fmt = *__preview_get_format(prev, fh, PREV_PAD_SINK, which);

/* The preview module output size is configurable through the
* input interface (horizontal and vertical cropping) and the
* averager (horizontal scaling by 1/1, 1/2, 1/4 or 1/8). In
* spite of this, hardcode the output size to the biggest
* possible value for simplicity reasons.
*/
switch (pixelcode) {
case V4L2_MBUS_FMT_YUYV8_1X16:
case V4L2_MBUS_FMT_UYVY8_1X16:
Expand All @@ -1679,20 +1706,14 @@ static void preview_try_format(struct isp_prev_device *prev,
break;
}

/* The TRM states (12.1.4.7.1.2) that 2 pixels must be cropped
* from the left and right sides when the input source is the
* CCDC. This seems not to be needed in practice, investigation
* is required.
*/
if (prev->input == PREVIEW_INPUT_CCDC)
fmt->width -= 4;

/* Assume that all blocks are enabled and crop pixels and lines
* accordingly. See preview_config_input_size() for more
* information.
/* The preview module output size is configurable through the
* averager (horizontal scaling by 1/1, 1/2, 1/4 or 1/8). This
* is not supported yet, hardcode the output size to the crop
* rectangle size.
*/
fmt->width -= 14;
fmt->height -= 8;
crop = __preview_get_crop(prev, fh, which);
fmt->width = crop->width;
fmt->height = crop->height;

fmt->colorspace = V4L2_COLORSPACE_JPEG;
break;
Expand All @@ -1701,6 +1722,49 @@ static void preview_try_format(struct isp_prev_device *prev,
fmt->field = V4L2_FIELD_NONE;
}

/*
* preview_try_crop - Validate a crop rectangle
* @prev: ISP preview engine
* @sink: format on the sink pad
* @crop: crop rectangle to be validated
*
* The preview engine crops lines and columns for its internal operation,
* depending on which filters are enabled. Enforce minimum crop margins to
* handle that transparently for userspace.
*
* See the explanation at the PREV_MARGIN_* definitions for more details.
*/
static void preview_try_crop(struct isp_prev_device *prev,
const struct v4l2_mbus_framefmt *sink,
struct v4l2_rect *crop)
{
unsigned int left = PREV_MARGIN_LEFT;
unsigned int right = sink->width - PREV_MARGIN_RIGHT;
unsigned int top = PREV_MARGIN_TOP;
unsigned int bottom = sink->height - PREV_MARGIN_BOTTOM;

/* When processing data on-the-fly from the CCDC, at least 2 pixels must
* be cropped from the left and right sides of the image. As we don't
* know which filters will be enabled, increase the left and right
* margins by two.
*/
if (prev->input == PREVIEW_INPUT_CCDC) {
left += 2;
right -= 2;
}

/* Restrict left/top to even values to keep the Bayer pattern. */
crop->left &= ~1;
crop->top &= ~1;

crop->left = clamp_t(u32, crop->left, left, right - PREV_MIN_OUT_WIDTH);
crop->top = clamp_t(u32, crop->top, top, bottom - PREV_MIN_OUT_HEIGHT);
crop->width = clamp_t(u32, crop->width, PREV_MIN_OUT_WIDTH,
right - crop->left);
crop->height = clamp_t(u32, crop->height, PREV_MIN_OUT_HEIGHT,
bottom - crop->top);
}

/*
* preview_enum_mbus_code - Handle pixel format enumeration
* @sd : pointer to v4l2 subdev structure
Expand Down Expand Up @@ -1762,6 +1826,60 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd,
return 0;
}

/*
* preview_get_crop - Retrieve the crop rectangle on a pad
* @sd: ISP preview V4L2 subdevice
* @fh: V4L2 subdev file handle
* @crop: crop rectangle
*
* Return 0 on success or a negative error code otherwise.
*/
static int preview_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
struct v4l2_subdev_crop *crop)
{
struct isp_prev_device *prev = v4l2_get_subdevdata(sd);

/* Cropping is only supported on the sink pad. */
if (crop->pad != PREV_PAD_SINK)
return -EINVAL;

crop->rect = *__preview_get_crop(prev, fh, crop->which);
return 0;
}

/*
* preview_set_crop - Retrieve the crop rectangle on a pad
* @sd: ISP preview V4L2 subdevice
* @fh: V4L2 subdev file handle
* @crop: crop rectangle
*
* Return 0 on success or a negative error code otherwise.
*/
static int preview_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
struct v4l2_subdev_crop *crop)
{
struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;

/* Cropping is only supported on the sink pad. */
if (crop->pad != PREV_PAD_SINK)
return -EINVAL;

/* The crop rectangle can't be changed while streaming. */
if (prev->state != ISP_PIPELINE_STREAM_STOPPED)
return -EBUSY;

format = __preview_get_format(prev, fh, PREV_PAD_SINK, crop->which);
preview_try_crop(prev, format, &crop->rect);
*__preview_get_crop(prev, fh, crop->which) = crop->rect;

/* Update the source format. */
format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, crop->which);
preview_try_format(prev, fh, PREV_PAD_SOURCE, format, crop->which);

return 0;
}

/*
* preview_get_format - Handle get format by pads subdev method
* @sd : pointer to v4l2 subdev structure
Expand Down Expand Up @@ -1795,6 +1913,7 @@ static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
{
struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;

format = __preview_get_format(prev, fh, fmt->pad, fmt->which);
if (format == NULL)
Expand All @@ -1805,9 +1924,18 @@ static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,

/* Propagate the format from sink to source */
if (fmt->pad == PREV_PAD_SINK) {
/* Reset the crop rectangle. */
crop = __preview_get_crop(prev, fh, fmt->which);
crop->left = 0;
crop->top = 0;
crop->width = fmt->format.width;
crop->height = fmt->format.height;

preview_try_crop(prev, &fmt->format, crop);

/* Update the source format. */
format = __preview_get_format(prev, fh, PREV_PAD_SOURCE,
fmt->which);
*format = fmt->format;
preview_try_format(prev, fh, PREV_PAD_SOURCE, format,
fmt->which);
}
Expand Down Expand Up @@ -1856,6 +1984,8 @@ static const struct v4l2_subdev_pad_ops preview_v4l2_pad_ops = {
.enum_frame_size = preview_enum_frame_size,
.get_fmt = preview_get_format,
.set_fmt = preview_set_format,
.get_crop = preview_get_crop,
.set_crop = preview_set_crop,
};

/* subdev operations */
Expand Down
2 changes: 2 additions & 0 deletions drivers/media/video/omap3isp/isppreview.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ struct isptables_update {
* @subdev: V4L2 subdevice
* @pads: Media entity pads
* @formats: Active formats at the subdev pad
* @crop: Active crop rectangle
* @input: Module currently connected to the input pad
* @output: Bitmask of the active output
* @video_in: Input video entity
Expand All @@ -170,6 +171,7 @@ struct isp_prev_device {
struct v4l2_subdev subdev;
struct media_pad pads[PREV_PADS_NUM];
struct v4l2_mbus_framefmt formats[PREV_PADS_NUM];
struct v4l2_rect crop;

struct v4l2_ctrl_handler ctrls;

Expand Down

0 comments on commit 1f69fd9

Please sign in to comment.