staging: bcm2835-codec: switch to multi-planar API

There are two APIs for mem2mem devices, the older single-planar API and
the newer multi-planar one. Without making things overly complex, the
driver can only support one or the other. However the userspace libv4l2
library has a plugin that allows multi-planar API devices to service
single-planar consumers.

Chromium supports the multi-planar API exclusively, though this is
currently limited to ChromiumOS. It would be possible to add support
for generic Linux.

Switching to the multi-planar API would allow usage of both APIs from
userspace.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
This commit is contained in:
Chen-Yu Tsai
2019-07-18 17:07:05 +08:00
committed by popcornmix
parent 3e638cc74e
commit 5e484a3e2a

View File

@@ -504,7 +504,7 @@ static struct bcm2835_codec_fmt *find_format(struct v4l2_format *f,
for (k = 0; k < fmts->num_entries; k++) { for (k = 0; k < fmts->num_entries; k++) {
fmt = &fmts->list[k]; fmt = &fmts->list[k];
if (fmt->fourcc == f->fmt.pix.pixelformat) if (fmt->fourcc == f->fmt.pix_mp.pixelformat)
break; break;
} }
if (k == fmts->num_entries) if (k == fmts->num_entries)
@@ -522,9 +522,9 @@ static struct bcm2835_codec_q_data *get_q_data(struct bcm2835_codec_ctx *ctx,
enum v4l2_buf_type type) enum v4l2_buf_type type)
{ {
switch (type) { switch (type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
return &ctx->q_data[V4L2_M2M_SRC]; 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]; return &ctx->q_data[V4L2_M2M_DST];
default: default:
v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n", v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n",
@@ -541,9 +541,9 @@ static struct vchiq_mmal_port *get_port_data(struct bcm2835_codec_ctx *ctx,
return NULL; return NULL;
switch (type) { switch (type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
return &ctx->component->input[0]; return &ctx->component->input[0];
case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
return &ctx->component->output[0]; return &ctx->component->output[0];
default: default:
v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n", v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n",
@@ -752,7 +752,7 @@ static void handle_fmt_changed(struct bcm2835_codec_ctx *ctx,
format->es.video.crop.width, format->es.video.crop.height, format->es.video.crop.width, format->es.video.crop.height,
format->es.video.color_space); format->es.video.color_space);
q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
q_data->crop_width = format->es.video.crop.width; q_data->crop_width = format->es.video.crop.width;
q_data->crop_height = format->es.video.crop.height; q_data->crop_height = format->es.video.crop.height;
q_data->bytesperline = format->es.video.crop.width; q_data->bytesperline = format->es.video.crop.width;
@@ -945,7 +945,7 @@ static int vidioc_querycap(struct file *file, void *priv,
strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1); strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
MEM2MEM_NAME); MEM2MEM_NAME);
cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0; return 0;
} }
@@ -996,16 +996,20 @@ static int vidioc_g_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f)
q_data = get_q_data(ctx, f->type); q_data = get_q_data(ctx, f->type);
f->fmt.pix.width = q_data->crop_width; f->fmt.pix_mp.width = q_data->crop_width;
f->fmt.pix.height = q_data->height; f->fmt.pix_mp.height = q_data->height;
f->fmt.pix.field = V4L2_FIELD_NONE; f->fmt.pix_mp.pixelformat = q_data->fmt->fourcc;
f->fmt.pix.pixelformat = q_data->fmt->fourcc; f->fmt.pix_mp.field = V4L2_FIELD_NONE;
f->fmt.pix.bytesperline = q_data->bytesperline; f->fmt.pix_mp.colorspace = ctx->colorspace;
f->fmt.pix.sizeimage = q_data->sizeimage; f->fmt.pix_mp.plane_fmt[0].sizeimage = q_data->sizeimage;
f->fmt.pix.colorspace = ctx->colorspace; f->fmt.pix_mp.plane_fmt[0].bytesperline = q_data->bytesperline;
f->fmt.pix.xfer_func = ctx->xfer_func; f->fmt.pix_mp.num_planes = 1;
f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc; f->fmt.pix_mp.ycbcr_enc = ctx->ycbcr_enc;
f->fmt.pix.quantization = ctx->quant; f->fmt.pix_mp.quantization = ctx->quant;
f->fmt.pix_mp.xfer_func = ctx->xfer_func;
memset(f->fmt.pix_mp.plane_fmt[0].reserved, 0,
sizeof(f->fmt.pix_mp.plane_fmt[0].reserved));
return 0; return 0;
} }
@@ -1029,17 +1033,17 @@ static int vidioc_try_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f,
* The V4L2 specification requires the driver to correct the format * The V4L2 specification requires the driver to correct the format
* struct if any of the dimensions is unsupported * struct if any of the dimensions is unsupported
*/ */
if (f->fmt.pix.width > MAX_W) if (f->fmt.pix_mp.width > MAX_W)
f->fmt.pix.width = MAX_W; f->fmt.pix_mp.width = MAX_W;
if (f->fmt.pix.height > MAX_H) if (f->fmt.pix_mp.height > MAX_H)
f->fmt.pix.height = MAX_H; f->fmt.pix_mp.height = MAX_H;
if (!fmt->flags & V4L2_FMT_FLAG_COMPRESSED) { if (!fmt->flags & V4L2_FMT_FLAG_COMPRESSED) {
/* Only clip min w/h on capture. Treat 0x0 as unknown. */ /* Only clip min w/h on capture. Treat 0x0 as unknown. */
if (f->fmt.pix.width < MIN_W) if (f->fmt.pix_mp.width < MIN_W)
f->fmt.pix.width = MIN_W; f->fmt.pix_mp.width = MIN_W;
if (f->fmt.pix.height < MIN_H) if (f->fmt.pix_mp.height < MIN_H)
f->fmt.pix.height = MIN_H; f->fmt.pix_mp.height = MIN_H;
/* /*
* For codecs the buffer must have a vertical alignment of 16 * For codecs the buffer must have a vertical alignment of 16
@@ -1048,16 +1052,18 @@ static int vidioc_try_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f,
* some of the pixels are active. * some of the pixels are active.
*/ */
if (ctx->dev->role != ISP) if (ctx->dev->role != ISP)
f->fmt.pix.height = ALIGN(f->fmt.pix.height, 16); f->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 16);
} }
f->fmt.pix.bytesperline = get_bytesperline(f->fmt.pix.width, f->fmt.pix_mp.num_planes = 1;
fmt); f->fmt.pix_mp.plane_fmt[0].bytesperline =
f->fmt.pix.sizeimage = get_sizeimage(f->fmt.pix.bytesperline, get_bytesperline(f->fmt.pix_mp.width, fmt);
f->fmt.pix.width, f->fmt.pix_mp.plane_fmt[0].sizeimage =
f->fmt.pix.height, get_sizeimage(f->fmt.pix_mp.plane_fmt[0].bytesperline,
fmt); f->fmt.pix_mp.width, f->fmt.pix_mp.height, fmt);
memset(f->fmt.pix_mp.plane_fmt[0].reserved, 0,
sizeof(f->fmt.pix_mp.plane_fmt[0].reserved));
f->fmt.pix.field = V4L2_FIELD_NONE; f->fmt.pix_mp.field = V4L2_FIELD_NONE;
return 0; return 0;
} }
@@ -1070,7 +1076,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
fmt = find_format(f, ctx->dev, true); fmt = find_format(f, ctx->dev, true);
if (!fmt) { if (!fmt) {
f->fmt.pix.pixelformat = get_default_format(ctx->dev, f->fmt.pix_mp.pixelformat = get_default_format(ctx->dev,
true)->fourcc; true)->fourcc;
fmt = find_format(f, ctx->dev, true); fmt = find_format(f, ctx->dev, true);
} }
@@ -1086,13 +1092,13 @@ static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
fmt = find_format(f, ctx->dev, false); fmt = find_format(f, ctx->dev, false);
if (!fmt) { if (!fmt) {
f->fmt.pix.pixelformat = get_default_format(ctx->dev, f->fmt.pix_mp.pixelformat = get_default_format(ctx->dev,
false)->fourcc; false)->fourcc;
fmt = find_format(f, ctx->dev, false); fmt = find_format(f, ctx->dev, false);
} }
if (!f->fmt.pix.colorspace) if (!f->fmt.pix_mp.colorspace)
f->fmt.pix.colorspace = ctx->colorspace; f->fmt.pix_mp.colorspace = ctx->colorspace;
return vidioc_try_fmt(ctx, f, fmt); return vidioc_try_fmt(ctx, f, fmt);
} }
@@ -1107,8 +1113,9 @@ static int vidioc_s_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f,
int ret; int ret;
v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n", v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
f->type, f->fmt.pix.width, f->fmt.pix.height, f->type, f->fmt.pix_mp.width, f->fmt.pix_mp.height,
f->fmt.pix.pixelformat, f->fmt.pix.sizeimage); f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.plane_fmt[0].sizeimage);
vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
if (!vq) if (!vq)
@@ -1124,9 +1131,9 @@ static int vidioc_s_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f,
} }
q_data->fmt = find_format(f, ctx->dev, q_data->fmt = find_format(f, ctx->dev,
f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE); f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
q_data->crop_width = f->fmt.pix.width; q_data->crop_width = f->fmt.pix_mp.width;
q_data->height = f->fmt.pix.height; q_data->height = f->fmt.pix_mp.height;
if (!q_data->selection_set) if (!q_data->selection_set)
q_data->crop_height = requested_height; q_data->crop_height = requested_height;
@@ -1134,21 +1141,21 @@ static int vidioc_s_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f,
* Copying the behaviour of vicodec which retains a single set of * Copying the behaviour of vicodec which retains a single set of
* colorspace parameters for both input and output. * colorspace parameters for both input and output.
*/ */
ctx->colorspace = f->fmt.pix.colorspace; ctx->colorspace = f->fmt.pix_mp.colorspace;
ctx->xfer_func = f->fmt.pix.xfer_func; ctx->xfer_func = f->fmt.pix_mp.xfer_func;
ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc; ctx->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
ctx->quant = f->fmt.pix.quantization; ctx->quant = f->fmt.pix_mp.quantization;
/* All parameters should have been set correctly by try_fmt */ /* All parameters should have been set correctly by try_fmt */
q_data->bytesperline = f->fmt.pix.bytesperline; q_data->bytesperline = f->fmt.pix_mp.plane_fmt[0].bytesperline;
q_data->sizeimage = f->fmt.pix.sizeimage; q_data->sizeimage = f->fmt.pix_mp.plane_fmt[0].sizeimage;
v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Calulated bpl as %u, size %u\n", v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Calulated bpl as %u, size %u\n",
q_data->bytesperline, q_data->sizeimage); q_data->bytesperline, q_data->sizeimage);
if (ctx->dev->role == DECODE && if (ctx->dev->role == DECODE &&
q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED && q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED &&
f->fmt.pix.width && f->fmt.pix.height) { q_data->crop_width && q_data->height) {
/* /*
* On the decoder, if provided with a resolution on the input * On the decoder, if provided with a resolution on the input
* side, then replicate that to the output side. * side, then replicate that to the output side.
@@ -1165,7 +1172,7 @@ static int vidioc_s_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f,
q_data_dst->height = ALIGN(q_data->crop_height, 16); q_data_dst->height = ALIGN(q_data->crop_height, 16);
q_data_dst->bytesperline = q_data_dst->bytesperline =
get_bytesperline(f->fmt.pix.width, q_data_dst->fmt); get_bytesperline(f->fmt.pix_mp.width, q_data_dst->fmt);
q_data_dst->sizeimage = get_sizeimage(q_data_dst->bytesperline, q_data_dst->sizeimage = get_sizeimage(q_data_dst->bytesperline,
q_data_dst->crop_width, q_data_dst->crop_width,
q_data_dst->height, q_data_dst->height,
@@ -1215,7 +1222,7 @@ static int vidioc_s_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f,
static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f) struct v4l2_format *f)
{ {
unsigned int height = f->fmt.pix.height; unsigned int height = f->fmt.pix_mp.height;
int ret; int ret;
ret = vidioc_try_fmt_vid_cap(file, priv, f); ret = vidioc_try_fmt_vid_cap(file, priv, f);
@@ -1228,7 +1235,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
static int vidioc_s_fmt_vid_out(struct file *file, void *priv, static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
struct v4l2_format *f) struct v4l2_format *f)
{ {
unsigned int height = f->fmt.pix.height; unsigned int height = f->fmt.pix_mp.height;
int ret; int ret;
ret = vidioc_try_fmt_vid_out(file, priv, f); ret = vidioc_try_fmt_vid_out(file, priv, f);
@@ -1244,7 +1251,7 @@ static int vidioc_g_selection(struct file *file, void *priv,
{ {
struct bcm2835_codec_ctx *ctx = file2ctx(file); struct bcm2835_codec_ctx *ctx = file2ctx(file);
struct bcm2835_codec_q_data *q_data; struct bcm2835_codec_q_data *q_data;
bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ?
true : false; true : false;
if ((ctx->dev->role == DECODE && !capture_queue) || if ((ctx->dev->role == DECODE && !capture_queue) ||
@@ -1307,7 +1314,7 @@ static int vidioc_s_selection(struct file *file, void *priv,
{ {
struct bcm2835_codec_ctx *ctx = file2ctx(file); struct bcm2835_codec_ctx *ctx = file2ctx(file);
struct bcm2835_codec_q_data *q_data = NULL; struct bcm2835_codec_q_data *q_data = NULL;
bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ?
true : false; true : false;
v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: ctx %p, type %d, q_data %p, target %d, rect x/y %d/%d, w/h %ux%u\n", v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: ctx %p, type %d, q_data %p, target %d, rect x/y %d/%d, w/h %ux%u\n",
@@ -1368,7 +1375,7 @@ static int vidioc_s_parm(struct file *file, void *priv,
{ {
struct bcm2835_codec_ctx *ctx = file2ctx(file); struct bcm2835_codec_ctx *ctx = file2ctx(file);
if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
return -EINVAL; return -EINVAL;
ctx->framerate_num = ctx->framerate_num =
@@ -1738,15 +1745,15 @@ static int vidioc_encoder_cmd(struct file *file, void *priv,
static const struct v4l2_ioctl_ops bcm2835_codec_ioctl_ops = { static const struct v4l2_ioctl_ops bcm2835_codec_ioctl_ops = {
.vidioc_querycap = vidioc_querycap, .vidioc_querycap = vidioc_querycap,
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_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_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out,
.vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out, .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out,
.vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out,
.vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out,
.vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
.vidioc_querybuf = v4l2_m2m_ioctl_querybuf, .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
@@ -2089,7 +2096,7 @@ static int bcm2835_codec_start_streaming(struct vb2_queue *q,
ctx->component_enabled = true; ctx->component_enabled = true;
} }
if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
/* /*
* Create the EOS buffer. * Create the EOS buffer.
* We only need the MMAL part, and want to NOT attach a memory * We only need the MMAL part, and want to NOT attach a memory
@@ -2216,7 +2223,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
struct bcm2835_codec_ctx *ctx = priv; struct bcm2835_codec_ctx *ctx = priv;
int ret; int ret;
src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
src_vq->io_modes = VB2_MMAP | VB2_DMABUF; src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
src_vq->drv_priv = ctx; src_vq->drv_priv = ctx;
src_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer); src_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer);
@@ -2230,7 +2237,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
if (ret) if (ret)
return ret; return ret;
dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
dst_vq->drv_priv = ctx; dst_vq->drv_priv = ctx;
dst_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer); dst_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer);