Commit 121cacf4 authored by Philipp Zabel's avatar Philipp Zabel Committed by Mauro Carvalho Chehab

[media] coda: split userspace interface into encoder and decoder device

Userspace has a hard time making sense of format enumerations on V4L2
mem2mem devices if there are restrictions on which input and output
formats can be used together. Alleviate the problem by splitting the
video4linux device into separate encoder and decoder devices which list
only raw formats on one side and only encoded formats on the other side.
With this patch, the instance type (encoder or decoder) is already
determined by the open file operation.
Acked-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarPhilipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: default avatarKamil Debski <k.debski@samsung.com>
Signed-off-by: default avatarMauro Carvalho Chehab <m.chehab@samsung.com>
parent 91b5841e
......@@ -129,7 +129,7 @@ struct coda_aux_buf {
struct coda_dev {
struct v4l2_device v4l2_dev;
struct video_device vfd;
struct video_device vfd[2];
struct platform_device *plat_dev;
const struct coda_devtype *devtype;
......@@ -1578,14 +1578,22 @@ static void coda_set_tiled_map_type(struct coda_ctx *ctx, int tiled_map_type)
static void set_default_params(struct coda_ctx *ctx)
{
u32 src_fourcc, dst_fourcc;
int max_w;
int max_h;
ctx->codec = &ctx->dev->devtype->codecs[0];
if (ctx->inst_type == CODA_INST_ENCODER) {
src_fourcc = V4L2_PIX_FMT_YUV420;
dst_fourcc = V4L2_PIX_FMT_H264;
} else {
src_fourcc = V4L2_PIX_FMT_H264;
dst_fourcc = V4L2_PIX_FMT_YUV420;
}
ctx->codec = coda_find_codec(ctx->dev, src_fourcc, dst_fourcc);
max_w = ctx->codec->max_w;
max_h = ctx->codec->max_h;
ctx->params.codec_mode = CODA_MODE_INVALID;
ctx->params.codec_mode = ctx->codec->mode;
ctx->colorspace = V4L2_COLORSPACE_REC709;
ctx->params.framerate = 30;
ctx->aborting = 0;
......@@ -1595,12 +1603,19 @@ static void set_default_params(struct coda_ctx *ctx)
ctx->q_data[V4L2_M2M_DST].fourcc = ctx->codec->dst_fourcc;
ctx->q_data[V4L2_M2M_SRC].width = max_w;
ctx->q_data[V4L2_M2M_SRC].height = max_h;
ctx->q_data[V4L2_M2M_SRC].bytesperline = max_w;
ctx->q_data[V4L2_M2M_SRC].sizeimage = (max_w * max_h * 3) / 2;
ctx->q_data[V4L2_M2M_DST].width = max_w;
ctx->q_data[V4L2_M2M_DST].height = max_h;
ctx->q_data[V4L2_M2M_DST].bytesperline = 0;
ctx->q_data[V4L2_M2M_DST].sizeimage = CODA_MAX_FRAME_SIZE;
if (ctx->codec->src_fourcc == V4L2_PIX_FMT_YUV420) {
ctx->q_data[V4L2_M2M_SRC].bytesperline = max_w;
ctx->q_data[V4L2_M2M_SRC].sizeimage = (max_w * max_h * 3) / 2;
ctx->q_data[V4L2_M2M_DST].bytesperline = 0;
ctx->q_data[V4L2_M2M_DST].sizeimage = CODA_MAX_FRAME_SIZE;
} else {
ctx->q_data[V4L2_M2M_SRC].bytesperline = 0;
ctx->q_data[V4L2_M2M_SRC].sizeimage = CODA_MAX_FRAME_SIZE;
ctx->q_data[V4L2_M2M_DST].bytesperline = max_w;
ctx->q_data[V4L2_M2M_DST].sizeimage = (max_w * max_h * 3) / 2;
}
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;
......@@ -2287,11 +2302,6 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
}
ctx->streamon_out = 1;
if (coda_format_is_yuv(q_data_src->fourcc))
ctx->inst_type = CODA_INST_ENCODER;
else
ctx->inst_type = CODA_INST_DECODER;
} else {
if (count < 1)
return -EINVAL;
......@@ -2713,7 +2723,7 @@ static void coda_stop_streaming(struct vb2_queue *q)
}
}
static struct vb2_ops coda_qops = {
static const struct vb2_ops coda_qops = {
.queue_setup = coda_queue_setup,
.buf_prepare = coda_buf_prepare,
.buf_queue = coda_buf_queue,
......@@ -2865,35 +2875,55 @@ static int coda_ctrls_setup(struct coda_ctx *ctx)
return v4l2_ctrl_handler_setup(&ctx->ctrls);
}
static int coda_queue_init(void *priv, struct vb2_queue *src_vq,
struct vb2_queue *dst_vq)
static int coda_queue_init(struct coda_ctx *ctx, struct vb2_queue *vq)
{
vq->drv_priv = ctx;
vq->ops = &coda_qops;
vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
vq->lock = &ctx->dev->dev_mutex;
return vb2_queue_init(vq);
}
static int coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq,
struct vb2_queue *dst_vq)
{
struct coda_ctx *ctx = priv;
int ret;
src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
src_vq->io_modes = VB2_DMABUF | VB2_MMAP;
src_vq->drv_priv = ctx;
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
src_vq->ops = &coda_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
src_vq->lock = &ctx->dev->dev_mutex;
ret = vb2_queue_init(src_vq);
ret = coda_queue_init(priv, src_vq);
if (ret)
return ret;
dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
dst_vq->io_modes = VB2_DMABUF | VB2_MMAP;
dst_vq->drv_priv = ctx;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->ops = &coda_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
dst_vq->lock = &ctx->dev->dev_mutex;
return vb2_queue_init(dst_vq);
return coda_queue_init(priv, dst_vq);
}
static int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq,
struct vb2_queue *dst_vq)
{
int ret;
src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
src_vq->io_modes = VB2_DMABUF | VB2_MMAP;
src_vq->mem_ops = &vb2_dma_contig_memops;
ret = coda_queue_init(priv, src_vq);
if (ret)
return ret;
dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
dst_vq->io_modes = VB2_DMABUF | VB2_MMAP;
dst_vq->mem_ops = &vb2_dma_contig_memops;
return coda_queue_init(priv, dst_vq);
}
static int coda_next_free_instance(struct coda_dev *dev)
......@@ -2907,8 +2937,10 @@ static int coda_next_free_instance(struct coda_dev *dev)
return idx;
}
static int coda_open(struct file *file)
static int coda_open(struct file *file, enum coda_inst_type inst_type)
{
int (*queue_init)(void *priv, struct vb2_queue *src_vq,
struct vb2_queue *dst_vq);
struct coda_dev *dev = video_drvdata(file);
struct coda_ctx *ctx = NULL;
char *name;
......@@ -2930,6 +2962,7 @@ static int coda_open(struct file *file)
ctx->debugfs_entry = debugfs_create_dir(name, dev->debugfs_root);
kfree(name);
ctx->inst_type = inst_type;
init_completion(&ctx->completion);
INIT_WORK(&ctx->pic_run_work, coda_pic_run_work);
INIT_WORK(&ctx->seq_end_work, coda_seq_end_work);
......@@ -2963,8 +2996,11 @@ static int coda_open(struct file *file)
goto err_clk_ahb;
set_default_params(ctx);
ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
&coda_queue_init);
if (inst_type == CODA_INST_ENCODER)
queue_init = coda_encoder_queue_init;
else
queue_init = coda_decoder_queue_init;
ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, queue_init);
if (IS_ERR(ctx->fh.m2m_ctx)) {
ret = PTR_ERR(ctx->fh.m2m_ctx);
......@@ -3035,6 +3071,16 @@ static int coda_open(struct file *file)
return ret;
}
static int coda_encoder_open(struct file *file)
{
return coda_open(file, CODA_INST_ENCODER);
}
static int coda_decoder_open(struct file *file)
{
return coda_open(file, CODA_INST_DECODER);
}
static int coda_release(struct file *file)
{
struct coda_dev *dev = video_drvdata(file);
......@@ -3079,9 +3125,18 @@ static int coda_release(struct file *file)
return 0;
}
static const struct v4l2_file_operations coda_fops = {
static const struct v4l2_file_operations coda_encoder_fops = {
.owner = THIS_MODULE,
.open = coda_open,
.open = coda_encoder_open,
.release = coda_release,
.poll = v4l2_m2m_fop_poll,
.unlocked_ioctl = video_ioctl2,
.mmap = v4l2_m2m_fop_mmap,
};
static const struct v4l2_file_operations coda_decoder_fops = {
.owner = THIS_MODULE,
.open = coda_decoder_open,
.release = coda_release,
.poll = v4l2_m2m_fop_poll,
.unlocked_ioctl = video_ioctl2,
......@@ -3564,6 +3619,17 @@ static int coda_check_firmware(struct coda_dev *dev)
return ret;
}
static int coda_register_device(struct coda_dev *dev, struct video_device *vfd)
{
vfd->release = video_device_release_empty,
vfd->lock = &dev->dev_mutex;
vfd->v4l2_dev = &dev->v4l2_dev;
vfd->vfl_dir = VFL_DIR_M2M;
video_set_drvdata(vfd, dev);
return video_register_device(vfd, VFL_TYPE_GRABBER, 0);
}
static void coda_fw_callback(const struct firmware *fw, void *context)
{
struct coda_dev *dev = context;
......@@ -3620,15 +3686,6 @@ static void coda_fw_callback(const struct firmware *fw, void *context)
return;
}
dev->vfd.fops = &coda_fops,
dev->vfd.ioctl_ops = &coda_ioctl_ops;
dev->vfd.release = video_device_release_empty,
dev->vfd.lock = &dev->dev_mutex;
dev->vfd.v4l2_dev = &dev->v4l2_dev;
dev->vfd.vfl_dir = VFL_DIR_M2M;
snprintf(dev->vfd.name, sizeof(dev->vfd.name), "%s", CODA_NAME);
video_set_drvdata(&dev->vfd, dev);
dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
if (IS_ERR(dev->alloc_ctx)) {
v4l2_err(&dev->v4l2_dev, "Failed to alloc vb2 context\n");
......@@ -3641,13 +3698,28 @@ static void coda_fw_callback(const struct firmware *fw, void *context)
goto rel_ctx;
}
ret = video_register_device(&dev->vfd, VFL_TYPE_GRABBER, 0);
dev->vfd[0].fops = &coda_encoder_fops,
dev->vfd[0].ioctl_ops = &coda_ioctl_ops;
snprintf(dev->vfd[0].name, sizeof(dev->vfd[0].name), "coda-encoder");
ret = coda_register_device(dev, &dev->vfd[0]);
if (ret) {
v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
v4l2_err(&dev->v4l2_dev,
"Failed to register encoder video device\n");
goto rel_m2m;
}
v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video%d\n",
dev->vfd.num);
dev->vfd[1].fops = &coda_decoder_fops,
dev->vfd[1].ioctl_ops = &coda_ioctl_ops;
snprintf(dev->vfd[1].name, sizeof(dev->vfd[1].name), "coda-decoder");
ret = coda_register_device(dev, &dev->vfd[1]);
if (ret) {
v4l2_err(&dev->v4l2_dev,
"Failed to register decoder video device\n");
goto rel_m2m;
}
v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video[%d-%d]\n",
dev->vfd[0].num, dev->vfd[1].num);
return;
......@@ -3882,7 +3954,8 @@ static int coda_remove(struct platform_device *pdev)
{
struct coda_dev *dev = platform_get_drvdata(pdev);
video_unregister_device(&dev->vfd);
video_unregister_device(&dev->vfd[0]);
video_unregister_device(&dev->vfd[1]);
if (dev->m2m_dev)
v4l2_m2m_release(dev->m2m_dev);
pm_runtime_disable(&pdev->dev);
......
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