diff options
author | Philipp Zabel <p.zabel@pengutronix.de> | 2014-07-11 06:36:19 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2014-07-22 11:55:33 -0300 |
commit | 52c41676f8a317724fbd603646d512278cb00653 (patch) | |
tree | dd6d71e10b55a2292bd26a16689cd44dd89cdd19 /drivers/media/platform/coda.c | |
parent | b9736299c427d5b3df7324e4469f9ce46793f943 (diff) |
[media] coda: add selection API support for h.264 decoder
The h.264 decoder produces capture frames that are a multiple of the macroblock
size (16 pixels). To inform userspace about invalid pixel data at the edges,
use the active and padded composing rectangles on the capture queue.
The cropping information is obtained from the h.264 sequence parameter set.
Reviewed-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Kamil Debski <k.debski@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Diffstat (limited to 'drivers/media/platform/coda.c')
-rw-r--r-- | drivers/media/platform/coda.c | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index f1b16dff89d..0c77366284c 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -119,6 +119,7 @@ struct coda_q_data { unsigned int height; unsigned int sizeimage; unsigned int fourcc; + struct v4l2_rect rect; }; struct coda_aux_buf { @@ -733,6 +734,10 @@ static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f) q_data->width = f->fmt.pix.width; q_data->height = f->fmt.pix.height; q_data->sizeimage = f->fmt.pix.sizeimage; + q_data->rect.left = 0; + q_data->rect.top = 0; + q_data->rect.width = f->fmt.pix.width; + q_data->rect.height = f->fmt.pix.height; v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %d\n", @@ -869,6 +874,50 @@ static int coda_streamoff(struct file *file, void *priv, return ret; } +static int coda_g_selection(struct file *file, void *fh, + struct v4l2_selection *s) +{ + struct coda_ctx *ctx = fh_to_ctx(fh); + struct coda_q_data *q_data; + struct v4l2_rect r, *rsel; + + q_data = get_q_data(ctx, s->type); + if (!q_data) + return -EINVAL; + + r.left = 0; + r.top = 0; + r.width = q_data->width; + r.height = q_data->height; + rsel = &q_data->rect; + + switch (s->target) { + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + rsel = &r; + /* fallthrough */ + case V4L2_SEL_TGT_CROP: + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + break; + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + case V4L2_SEL_TGT_COMPOSE_PADDED: + rsel = &r; + /* fallthrough */ + case V4L2_SEL_TGT_COMPOSE: + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + break; + default: + return -EINVAL; + } + + s->r = *rsel; + + return 0; +} + static int coda_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dc) { @@ -947,6 +996,8 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = { .vidioc_streamon = coda_streamon, .vidioc_streamoff = coda_streamoff, + .vidioc_g_selection = coda_g_selection, + .vidioc_try_decoder_cmd = coda_try_decoder_cmd, .vidioc_decoder_cmd = coda_decoder_cmd, @@ -1502,6 +1553,10 @@ static void set_default_params(struct coda_ctx *ctx) ctx->q_data[V4L2_M2M_DST].width = max_w; ctx->q_data[V4L2_M2M_DST].height = max_h; ctx->q_data[V4L2_M2M_DST].sizeimage = CODA_MAX_FRAME_SIZE; + ctx->q_data[V4L2_M2M_SRC].rect.width = max_w; + ctx->q_data[V4L2_M2M_SRC].rect.height = max_h; + ctx->q_data[V4L2_M2M_DST].rect.width = max_w; + ctx->q_data[V4L2_M2M_DST].rect.height = max_h; if (ctx->dev->devtype->product == CODA_960) coda_set_tiled_map_type(ctx, GDI_LINEAR_FRAME_MAP); @@ -2029,6 +2084,21 @@ static int coda_start_decoding(struct coda_ctx *ctx) return -EINVAL; } + if (src_fourcc == V4L2_PIX_FMT_H264) { + u32 left_right; + u32 top_bottom; + + left_right = coda_read(dev, CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT); + top_bottom = coda_read(dev, CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM); + + q_data_dst->rect.left = (left_right >> 10) & 0x3ff; + q_data_dst->rect.top = (top_bottom >> 10) & 0x3ff; + q_data_dst->rect.width = width - q_data_dst->rect.left - + (left_right & 0x3ff); + q_data_dst->rect.height = height - q_data_dst->rect.top - + (top_bottom & 0x3ff); + } + ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc); if (ret < 0) return ret; @@ -2938,6 +3008,30 @@ static void coda_finish_decode(struct coda_ctx *ctx) q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + /* frame crop information */ + if (src_fourcc == V4L2_PIX_FMT_H264) { + u32 left_right; + u32 top_bottom; + + left_right = coda_read(dev, CODA_RET_DEC_PIC_CROP_LEFT_RIGHT); + top_bottom = coda_read(dev, CODA_RET_DEC_PIC_CROP_TOP_BOTTOM); + + if (left_right == 0xffffffff && top_bottom == 0xffffffff) { + /* Keep current crop information */ + } else { + struct v4l2_rect *rect = &q_data_dst->rect; + + rect->left = left_right >> 16 & 0xffff; + rect->top = top_bottom >> 16 & 0xffff; + rect->width = width - rect->left - + (left_right & 0xffff); + rect->height = height - rect->top - + (top_bottom & 0xffff); + } + } else { + /* no cropping */ + } + val = coda_read(dev, CODA_RET_DEC_PIC_ERR_MB); if (val > 0) v4l2_err(&dev->v4l2_dev, |