Support multi-planar APIs in the virtual codec driver. Multi-planar APIs are enabled by the module parameter 'multiplanar'. Signed-off-by: Keiichi Watanabe <keiichiw@xxxxxxxxxxxx> --- drivers/media/platform/vicodec/vicodec-core.c | 219 ++++++++++++++---- 1 file changed, 171 insertions(+), 48 deletions(-) diff --git a/drivers/media/platform/vicodec/vicodec-core.c b/drivers/media/platform/vicodec/vicodec-core.c index 12c12cb0c1c0..1717f44e1743 100644 --- a/drivers/media/platform/vicodec/vicodec-core.c +++ b/drivers/media/platform/vicodec/vicodec-core.c @@ -29,6 +29,11 @@ MODULE_DESCRIPTION("Virtual codec device"); MODULE_AUTHOR("Hans Verkuil <hans.verkuil@xxxxxxxxx>"); MODULE_LICENSE("GPL v2"); +static bool multiplanar; +module_param(multiplanar, bool, 0444); +MODULE_PARM_DESC(multiplanar, + " use multi-planar API instead of single-planar API"); + static unsigned int debug; module_param(debug, uint, 0644); MODULE_PARM_DESC(debug, "activates debug info"); @@ -135,8 +140,10 @@ static struct vicodec_q_data *get_q_data(struct vicodec_ctx *ctx, { switch (type) { case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: return &ctx->q_data[V4L2_M2M_SRC]; case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: return &ctx->q_data[V4L2_M2M_DST]; default: WARN_ON(1); @@ -530,7 +537,10 @@ static int vidioc_querycap(struct file *file, void *priv, strncpy(cap->card, VICODEC_NAME, sizeof(cap->card) - 1); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", VICODEC_NAME); - cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; + cap->device_caps = V4L2_CAP_STREAMING | + (multiplanar ? + V4L2_CAP_VIDEO_M2M_MPLANE : + V4L2_CAP_VIDEO_M2M); cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -576,20 +586,44 @@ static int vidioc_g_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) q_data = get_q_data(ctx, f->type); - f->fmt.pix.width = q_data->width; - f->fmt.pix.height = q_data->height; - f->fmt.pix.field = V4L2_FIELD_NONE; - f->fmt.pix.pixelformat = q_data->fourcc; - if (q_data->fourcc == V4L2_PIX_FMT_FWHT) - f->fmt.pix.bytesperline = 0; - else - f->fmt.pix.bytesperline = q_data->width; - f->fmt.pix.sizeimage = q_data->sizeimage; - f->fmt.pix.colorspace = ctx->colorspace; - f->fmt.pix.xfer_func = ctx->xfer_func; - f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc; - f->fmt.pix.quantization = ctx->quantization; + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + f->fmt.pix.width = q_data->width; + f->fmt.pix.height = q_data->height; + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.pixelformat = q_data->fourcc; + if (q_data->fourcc == V4L2_PIX_FMT_FWHT) + f->fmt.pix.bytesperline = 0; + else + f->fmt.pix.bytesperline = q_data->width; + f->fmt.pix.sizeimage = q_data->sizeimage; + f->fmt.pix.colorspace = ctx->colorspace; + f->fmt.pix.xfer_func = ctx->xfer_func; + f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc; + f->fmt.pix.quantization = ctx->quantization; + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + f->fmt.pix_mp.width = q_data->width; + f->fmt.pix_mp.height = q_data->height; + f->fmt.pix_mp.field = V4L2_FIELD_NONE; + f->fmt.pix_mp.pixelformat = q_data->fourcc; + f->fmt.pix_mp.num_planes = 1; + if (q_data->fourcc == V4L2_PIX_FMT_FWHT) + f->fmt.pix_mp.plane_fmt[0].bytesperline = 0; + else + f->fmt.pix_mp.plane_fmt[0].bytesperline = q_data->width; + f->fmt.pix_mp.plane_fmt[0].sizeimage = q_data->sizeimage; + f->fmt.pix_mp.colorspace = ctx->colorspace; + f->fmt.pix_mp.xfer_func = ctx->xfer_func; + f->fmt.pix_mp.ycbcr_enc = ctx->ycbcr_enc; + f->fmt.pix_mp.quantization = ctx->quantization; + break; + default: + return -EINVAL; + } return 0; } @@ -607,16 +641,41 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, static int vidioc_try_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) { - struct v4l2_pix_format *pix = &f->fmt.pix; - - pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH) & ~7; - pix->height = clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT) & ~7; - pix->bytesperline = pix->width; - pix->sizeimage = pix->width * pix->height * 3 / 2; - pix->field = V4L2_FIELD_NONE; - if (pix->pixelformat == V4L2_PIX_FMT_FWHT) { - pix->bytesperline = 0; - pix->sizeimage += sizeof(struct cframe_hdr); + struct v4l2_pix_format *pix; + struct v4l2_pix_format_mplane *pix_mp; + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + pix = &f->fmt.pix; + pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH) & ~7; + pix->height = clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT) & ~7; + pix->bytesperline = pix->width; + pix->sizeimage = pix->width * pix->height * 3 / 2; + pix->field = V4L2_FIELD_NONE; + if (pix->pixelformat == V4L2_PIX_FMT_FWHT) { + pix->bytesperline = 0; + pix->sizeimage += sizeof(struct cframe_hdr); + } + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + pix_mp = &f->fmt.pix_mp; + pix_mp->width = clamp(pix_mp->width, MIN_WIDTH, MAX_WIDTH) & ~7; + pix_mp->height = + clamp(pix_mp->height, MIN_HEIGHT, MAX_HEIGHT) & ~7; + pix_mp->plane_fmt[0].bytesperline = pix_mp->width; + pix_mp->plane_fmt[0].sizeimage = + pix_mp->width * pix_mp->height * 3 / 2; + pix_mp->field = V4L2_FIELD_NONE; + if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT) { + pix_mp->plane_fmt[0].bytesperline = 0; + pix_mp->plane_fmt[0].sizeimage += + sizeof(struct cframe_hdr); + } + break; + default: + return -EINVAL; } return 0; @@ -627,12 +686,26 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, { struct vicodec_ctx *ctx = file2ctx(file); - f->fmt.pix.pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT : - find_fmt(f->fmt.pix.pixelformat); - f->fmt.pix.colorspace = ctx->colorspace; - f->fmt.pix.xfer_func = ctx->xfer_func; - f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc; - f->fmt.pix.quantization = ctx->quantization; + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + f->fmt.pix.pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT : + find_fmt(f->fmt.pix.pixelformat); + f->fmt.pix.colorspace = ctx->colorspace; + f->fmt.pix.xfer_func = ctx->xfer_func; + f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc; + f->fmt.pix.quantization = ctx->quantization; + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + f->fmt.pix_mp.pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT : + find_fmt(f->fmt.pix_mp.pixelformat); + f->fmt.pix_mp.colorspace = ctx->colorspace; + f->fmt.pix_mp.xfer_func = ctx->xfer_func; + f->fmt.pix_mp.ycbcr_enc = ctx->ycbcr_enc; + f->fmt.pix_mp.quantization = ctx->quantization; + break; + default: + return -EINVAL; + } return vidioc_try_fmt(ctx, f); } @@ -642,10 +715,22 @@ static int vidioc_try_fmt_vid_out(struct file *file, void *priv, { struct vicodec_ctx *ctx = file2ctx(file); - f->fmt.pix.pixelformat = !ctx->is_enc ? V4L2_PIX_FMT_FWHT : - find_fmt(f->fmt.pix.pixelformat); - if (!f->fmt.pix.colorspace) - f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709; + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + f->fmt.pix.pixelformat = !ctx->is_enc ? V4L2_PIX_FMT_FWHT : + find_fmt(f->fmt.pix.pixelformat); + if (!f->fmt.pix.colorspace) + f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709; + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + f->fmt.pix_mp.pixelformat = !ctx->is_enc ? V4L2_PIX_FMT_FWHT : + find_fmt(f->fmt.pix_mp.pixelformat); + if (!f->fmt.pix_mp.colorspace) + f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709; + break; + default: + return -EINVAL; + } return vidioc_try_fmt(ctx, f); } @@ -664,18 +749,42 @@ static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) if (!q_data) return -EINVAL; - if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type)) - fmt_changed = q_data->fourcc != f->fmt.pix.pixelformat || - q_data->width != f->fmt.pix.width || - q_data->height != f->fmt.pix.height; - - if (vb2_is_busy(vq) && fmt_changed) - return -EBUSY; - - q_data->fourcc = f->fmt.pix.pixelformat; - q_data->width = f->fmt.pix.width; - q_data->height = f->fmt.pix.height; - q_data->sizeimage = f->fmt.pix.sizeimage; + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type)) + fmt_changed = + q_data->fourcc != f->fmt.pix.pixelformat || + q_data->width != f->fmt.pix.width || + q_data->height != f->fmt.pix.height; + + if (vb2_is_busy(vq) && fmt_changed) + return -EBUSY; + + q_data->fourcc = f->fmt.pix.pixelformat; + q_data->width = f->fmt.pix.width; + q_data->height = f->fmt.pix.height; + q_data->sizeimage = f->fmt.pix.sizeimage; + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type)) + fmt_changed = + q_data->fourcc != f->fmt.pix_mp.pixelformat || + q_data->width != f->fmt.pix_mp.width || + q_data->height != f->fmt.pix_mp.height; + + if (vb2_is_busy(vq) && fmt_changed) + return -EBUSY; + + q_data->fourcc = f->fmt.pix_mp.pixelformat; + q_data->width = f->fmt.pix_mp.width; + q_data->height = f->fmt.pix_mp.height; + q_data->sizeimage = f->fmt.pix_mp.plane_fmt[0].sizeimage; + break; + default: + return -EINVAL; + } dprintk(ctx->dev, "Setting format for type %d, wxh: %dx%d, fourcc: %08x\n", @@ -832,11 +941,21 @@ static const struct v4l2_ioctl_ops vicodec_ioctl_ops = { .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap, + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out, .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, + .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out, + .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out, + .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out, + .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out, + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, @@ -1002,7 +1121,9 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vicodec_ctx *ctx = priv; int ret; - src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + src_vq->type = (multiplanar ? + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : + V4L2_BUF_TYPE_VIDEO_OUTPUT); src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; src_vq->drv_priv = ctx; src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); @@ -1016,7 +1137,9 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, if (ret) return ret; - dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + dst_vq->type = (multiplanar ? + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : + V4L2_BUF_TYPE_VIDEO_CAPTURE); dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; dst_vq->drv_priv = ctx; dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); -- 2.18.0.233.g985f88cf7e-goog This is an additional patch to Hans's patch series of the new vicodec driver. This patch adds multi-planar API support. I confirmed that v4l2-ctl uses multi-planar APIs to decode a FWHT format video when vicodec module is loaded with module parameter 'multiplanar'.