* [PATCH 00/10] CODA7 JPEG support
@ 2014-09-30 9:57 Philipp Zabel
2014-09-30 9:57 ` [PATCH 01/10] [media] coda: add support for planar YCbCr 4:2:2 (YUV422P) format Philipp Zabel
` (10 more replies)
0 siblings, 11 replies; 17+ messages in thread
From: Philipp Zabel @ 2014-09-30 9:57 UTC (permalink / raw)
To: Kamil Debski
Cc: Mauro Carvalho Chehab, Hans Verkuil, linux-media, kernel,
Philipp Zabel
Hi,
These patches add JPEG encoding and decoding support for CODA7541 (i.MX5).
The encoder video device is split into one video device per codec, so that
each video device can register only the relevant controls. The H.264/MPEG4
decoder is kept as one video device, but the JPEG decoder video device is
separate because it supports more uncompressed formats (currently YUV422P,
in the future grayscale or YUV 4:4:4 support could be added).
regards
Philipp
Philipp Zabel (10):
[media] coda: add support for planar YCbCr 4:2:2 (YUV422P) format
[media] coda: identify platform device earlier
[media] coda: add coda_video_device descriptors
[media] coda: split out encoder control setup to specify controls per
video device
[media] coda: add JPEG register definitions for CODA7541
[media] coda: add CODA7541 JPEG support
[media] coda: store bitstream buffer position with buffer metadata
[media] coda: pad input stream for JPEG decoder
[media] coda: try to only queue a single JPEG into the bitstream
[media] coda: allow userspace to set compressed buffer size in a
certain range
drivers/media/platform/coda/Makefile | 2 +-
drivers/media/platform/coda/coda-bit.c | 204 +++++++---
drivers/media/platform/coda/coda-common.c | 608 +++++++++++++++++++-----------
drivers/media/platform/coda/coda-jpeg.c | 225 +++++++++++
drivers/media/platform/coda/coda.h | 21 +-
drivers/media/platform/coda/coda_regs.h | 7 +
6 files changed, 785 insertions(+), 282 deletions(-)
create mode 100644 drivers/media/platform/coda/coda-jpeg.c
--
2.1.0
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 01/10] [media] coda: add support for planar YCbCr 4:2:2 (YUV422P) format
2014-09-30 9:57 [PATCH 00/10] CODA7 JPEG support Philipp Zabel
@ 2014-09-30 9:57 ` Philipp Zabel
2014-09-30 9:57 ` [PATCH 02/10] [media] coda: identify platform device earlier Philipp Zabel
` (9 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Philipp Zabel @ 2014-09-30 9:57 UTC (permalink / raw)
To: Kamil Debski
Cc: Mauro Carvalho Chehab, Hans Verkuil, linux-media, kernel,
Philipp Zabel
This patch adds support for the three-plane YUV422P format with one luma plane
and two horizontally subsampled chroma planes.
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
---
drivers/media/platform/coda/coda-bit.c | 14 +++++++++++++-
drivers/media/platform/coda/coda-common.c | 13 +++++++++++++
2 files changed, 26 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c
index fde7775..746a615 100644
--- a/drivers/media/platform/coda/coda-bit.c
+++ b/drivers/media/platform/coda/coda-bit.c
@@ -1591,6 +1591,7 @@ static void coda_finish_decode(struct coda_ctx *ctx)
struct coda_q_data *q_data_dst;
struct vb2_buffer *dst_buf;
struct coda_timestamp *ts;
+ unsigned long payload;
int width, height;
int decoded_idx;
int display_idx;
@@ -1776,7 +1777,18 @@ static void coda_finish_decode(struct coda_ctx *ctx)
dst_buf->v4l2_buf.timecode = ts->timecode;
dst_buf->v4l2_buf.timestamp = ts->timestamp;
- vb2_set_plane_payload(dst_buf, 0, width * height * 3 / 2);
+ switch (q_data_dst->fourcc) {
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YVU420:
+ case V4L2_PIX_FMT_NV12:
+ default:
+ payload = width * height * 3 / 2;
+ break;
+ case V4L2_PIX_FMT_YUV422P:
+ payload = width * height * 2;
+ break;
+ }
+ vb2_set_plane_payload(dst_buf, 0, payload);
v4l2_m2m_buf_done(dst_buf, ctx->frame_errors[display_idx] ?
VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c
index 02d47fa..48be973 100644
--- a/drivers/media/platform/coda/coda-common.c
+++ b/drivers/media/platform/coda/coda-common.c
@@ -100,6 +100,9 @@ void coda_write_base(struct coda_ctx *ctx, struct coda_q_data *q_data,
base_cb = base_y + q_data->bytesperline * q_data->height;
base_cr = base_cb + q_data->bytesperline * q_data->height / 4;
break;
+ case V4L2_PIX_FMT_YUV422P:
+ base_cb = base_y + q_data->bytesperline * q_data->height;
+ base_cr = base_cb + q_data->bytesperline * q_data->height / 2;
}
coda_write(ctx->dev, base_y, reg_y);
@@ -124,6 +127,10 @@ static const struct coda_fmt coda_formats[] = {
.fourcc = V4L2_PIX_FMT_NV12,
},
{
+ .name = "YUV 4:2:2 Planar, YCbCr",
+ .fourcc = V4L2_PIX_FMT_YUV422P,
+ },
+ {
.name = "H264 Encoded Stream",
.fourcc = V4L2_PIX_FMT_H264,
},
@@ -168,6 +175,7 @@ static bool coda_format_is_yuv(u32 fourcc)
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_YUV422P:
return true;
default:
return false;
@@ -393,6 +401,11 @@ static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec,
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
f->fmt.pix.height * 3 / 2;
break;
+ case V4L2_PIX_FMT_YUV422P:
+ f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16);
+ f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
+ f->fmt.pix.height * 2;
+ break;
case V4L2_PIX_FMT_H264:
case V4L2_PIX_FMT_MPEG4:
case V4L2_PIX_FMT_JPEG:
--
2.1.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 02/10] [media] coda: identify platform device earlier
2014-09-30 9:57 [PATCH 00/10] CODA7 JPEG support Philipp Zabel
2014-09-30 9:57 ` [PATCH 01/10] [media] coda: add support for planar YCbCr 4:2:2 (YUV422P) format Philipp Zabel
@ 2014-09-30 9:57 ` Philipp Zabel
2014-09-30 9:57 ` [PATCH 03/10] [media] coda: add coda_video_device descriptors Philipp Zabel
` (8 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Philipp Zabel @ 2014-09-30 9:57 UTC (permalink / raw)
To: Kamil Debski
Cc: Mauro Carvalho Chehab, Hans Verkuil, linux-media, kernel,
Philipp Zabel
We'll use this information to decide whether to request the JPEG IRQ later.
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
---
drivers/media/platform/coda/coda-common.c | 20 +++++++++-----------
1 file changed, 9 insertions(+), 11 deletions(-)
diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c
index 48be973..fb83c56 100644
--- a/drivers/media/platform/coda/coda-common.c
+++ b/drivers/media/platform/coda/coda-common.c
@@ -1896,6 +1896,15 @@ static int coda_probe(struct platform_device *pdev)
if (!dev)
return -ENOMEM;
+ pdev_id = of_id ? of_id->data : platform_get_device_id(pdev);
+
+ if (of_id)
+ dev->devtype = of_id->data;
+ else if (pdev_id)
+ dev->devtype = &coda_devdata[pdev_id->driver_data];
+ else
+ return -EINVAL;
+
spin_lock_init(&dev->irqlock);
INIT_LIST_HEAD(&dev->instances);
@@ -1963,17 +1972,6 @@ static int coda_probe(struct platform_device *pdev)
mutex_init(&dev->dev_mutex);
mutex_init(&dev->coda_mutex);
- pdev_id = of_id ? of_id->data : platform_get_device_id(pdev);
-
- if (of_id) {
- dev->devtype = of_id->data;
- } else if (pdev_id) {
- dev->devtype = &coda_devdata[pdev_id->driver_data];
- } else {
- v4l2_device_unregister(&dev->v4l2_dev);
- return -EINVAL;
- }
-
dev->debugfs_root = debugfs_create_dir("coda", NULL);
if (!dev->debugfs_root)
dev_warn(&pdev->dev, "failed to create debugfs root\n");
--
2.1.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 03/10] [media] coda: add coda_video_device descriptors
2014-09-30 9:57 [PATCH 00/10] CODA7 JPEG support Philipp Zabel
2014-09-30 9:57 ` [PATCH 01/10] [media] coda: add support for planar YCbCr 4:2:2 (YUV422P) format Philipp Zabel
2014-09-30 9:57 ` [PATCH 02/10] [media] coda: identify platform device earlier Philipp Zabel
@ 2014-09-30 9:57 ` Philipp Zabel
2014-09-30 9:57 ` [PATCH 04/10] [media] coda: split out encoder control setup to specify controls per video device Philipp Zabel
` (7 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Philipp Zabel @ 2014-09-30 9:57 UTC (permalink / raw)
To: Kamil Debski
Cc: Mauro Carvalho Chehab, Hans Verkuil, linux-media, kernel,
Philipp Zabel
Depending on the devtype, the coda driver will now spawn a number of video
devices, one separate encoder for each format, and one multi-format decoder.
Each video device descriptor determines the name, callback ops, and input and
output formats on the corresponding video device. This also simplifies
coda_enum_fmt and coda_try_fmt a bit.
A separate decoder video device will be created for JPEG decoding later due to
slightly different behavior in the CodaDx6/CODA7542 case and due to a separate
hardware unit on CODA960.
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
---
drivers/media/platform/coda/coda-common.c | 366 +++++++++++++++++-------------
drivers/media/platform/coda/coda.h | 7 +-
2 files changed, 220 insertions(+), 153 deletions(-)
diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c
index fb83c56..df950f2 100644
--- a/drivers/media/platform/coda/coda-common.c
+++ b/drivers/media/platform/coda/coda-common.c
@@ -43,6 +43,7 @@
#define CODA_NAME "coda"
#define CODADX6_MAX_INSTANCES 4
+#define CODA_MAX_FORMATS 4
#define CODA_PARA_BUF_SIZE (10 * 1024)
#define CODA_ISRAM_SIZE (2048 * 2)
@@ -169,6 +170,74 @@ static const struct coda_codec coda9_codecs[] = {
CODA_CODEC(CODA9_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1088),
};
+struct coda_video_device {
+ const char *name;
+ enum coda_inst_type type;
+ const struct coda_context_ops *ops;
+ u32 src_formats[CODA_MAX_FORMATS];
+ u32 dst_formats[CODA_MAX_FORMATS];
+};
+
+static const struct coda_video_device coda_bit_h264_encoder = {
+ .name = "coda-h264-encoder",
+ .type = CODA_INST_ENCODER,
+ .ops = &coda_bit_encode_ops,
+ .src_formats = {
+ V4L2_PIX_FMT_YUV420,
+ V4L2_PIX_FMT_YVU420,
+ V4L2_PIX_FMT_NV12,
+ },
+ .dst_formats = {
+ V4L2_PIX_FMT_H264,
+ },
+};
+
+static const struct coda_video_device coda_bit_mpeg4_encoder = {
+ .name = "coda-mpeg4-encoder",
+ .type = CODA_INST_ENCODER,
+ .ops = &coda_bit_encode_ops,
+ .src_formats = {
+ V4L2_PIX_FMT_YUV420,
+ V4L2_PIX_FMT_YVU420,
+ V4L2_PIX_FMT_NV12,
+ },
+ .dst_formats = {
+ V4L2_PIX_FMT_MPEG4,
+ },
+};
+
+static const struct coda_video_device coda_bit_decoder = {
+ .name = "coda-decoder",
+ .type = CODA_INST_DECODER,
+ .ops = &coda_bit_decode_ops,
+ .src_formats = {
+ V4L2_PIX_FMT_H264,
+ V4L2_PIX_FMT_MPEG4,
+ },
+ .dst_formats = {
+ V4L2_PIX_FMT_YUV420,
+ V4L2_PIX_FMT_YVU420,
+ V4L2_PIX_FMT_NV12,
+ },
+};
+
+static const struct coda_video_device *codadx6_video_devices[] = {
+ &coda_bit_h264_encoder,
+ &coda_bit_mpeg4_encoder,
+};
+
+static const struct coda_video_device *coda7_video_devices[] = {
+ &coda_bit_h264_encoder,
+ &coda_bit_mpeg4_encoder,
+ &coda_bit_decoder,
+};
+
+static const struct coda_video_device *coda9_video_devices[] = {
+ &coda_bit_h264_encoder,
+ &coda_bit_mpeg4_encoder,
+ &coda_bit_decoder,
+};
+
static bool coda_format_is_yuv(u32 fourcc)
{
switch (fourcc) {
@@ -182,6 +251,18 @@ static bool coda_format_is_yuv(u32 fourcc)
}
}
+static const char *coda_format_name(u32 fourcc)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(coda_formats); i++) {
+ if (coda_formats[i].fourcc == fourcc)
+ return coda_formats[i].name;
+ }
+
+ return NULL;
+}
+
/*
* Normalize all supported YUV 4:2:0 formats to the value used in the codec
* tables.
@@ -240,6 +321,17 @@ static void coda_get_max_dimensions(struct coda_dev *dev,
*max_h = h;
}
+const struct coda_video_device *to_coda_video_device(struct video_device *vdev)
+{
+ struct coda_dev *dev = video_get_drvdata(vdev);
+ unsigned int i = vdev - dev->vfd;
+
+ if (i >= dev->devtype->num_vdevs)
+ return NULL;
+
+ return dev->devtype->vdevs[i];
+}
+
const char *coda_product_name(int product)
{
static char buf[9];
@@ -278,58 +370,28 @@ static int coda_querycap(struct file *file, void *priv,
static int coda_enum_fmt(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
- struct coda_ctx *ctx = fh_to_ctx(priv);
- const struct coda_codec *codecs = ctx->dev->devtype->codecs;
- const struct coda_fmt *formats = coda_formats;
- const struct coda_fmt *fmt;
- int num_codecs = ctx->dev->devtype->num_codecs;
- int num_formats = ARRAY_SIZE(coda_formats);
- int i, k, num = 0;
- bool yuv;
-
- if (ctx->inst_type == CODA_INST_ENCODER)
- yuv = (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ struct video_device *vdev = video_devdata(file);
+ const struct coda_video_device *cvd = to_coda_video_device(vdev);
+ const u32 *formats;
+ const char *name;
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ formats = cvd->src_formats;
+ else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ formats = cvd->dst_formats;
else
- yuv = (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE);
-
- for (i = 0; i < num_formats; i++) {
- /* Skip either raw or compressed formats */
- if (yuv != coda_format_is_yuv(formats[i].fourcc))
- continue;
- /* All uncompressed formats are always supported */
- if (yuv) {
- if (num == f->index)
- break;
- ++num;
- continue;
- }
- /* Compressed formats may be supported, check the codec list */
- for (k = 0; k < num_codecs; k++) {
- if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
- formats[i].fourcc == codecs[k].dst_fourcc)
- break;
- if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
- formats[i].fourcc == codecs[k].src_fourcc)
- break;
- }
- if (k < num_codecs) {
- if (num == f->index)
- break;
- ++num;
- }
- }
+ return -EINVAL;
- if (i < num_formats) {
- fmt = &formats[i];
- strlcpy(f->description, fmt->name, sizeof(f->description));
- f->pixelformat = fmt->fourcc;
- if (!yuv)
- f->flags |= V4L2_FMT_FLAG_COMPRESSED;
- return 0;
- }
+ if (f->index >= CODA_MAX_FORMATS || formats[f->index] == 0)
+ return -EINVAL;
- /* Format not found */
- return -EINVAL;
+ name = coda_format_name(formats[f->index]);
+ strlcpy(f->description, name, sizeof(f->description));
+ f->pixelformat = formats[f->index];
+ if (!coda_format_is_yuv(formats[f->index]))
+ f->flags |= V4L2_FMT_FLAG_COMPRESSED;
+
+ return 0;
}
static int coda_g_fmt(struct file *file, void *priv,
@@ -354,11 +416,37 @@ static int coda_g_fmt(struct file *file, void *priv,
return 0;
}
+static int coda_try_pixelformat(struct coda_ctx *ctx, struct v4l2_format *f)
+{
+ struct coda_q_data *q_data;
+ const u32 *formats;
+ int i;
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ formats = ctx->cvd->src_formats;
+ else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ formats = ctx->cvd->dst_formats;
+ else
+ return -EINVAL;
+
+ for (i = 0; i < CODA_MAX_FORMATS; i++) {
+ if (formats[i] == f->fmt.pix.pixelformat) {
+ f->fmt.pix.pixelformat = formats[i];
+ return 0;
+ }
+ }
+
+ /* Fall back to currently set pixelformat */
+ q_data = get_q_data(ctx, f->type);
+ f->fmt.pix.pixelformat = q_data->fourcc;
+
+ return 0;
+}
+
static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec,
struct v4l2_format *f)
{
struct coda_dev *dev = ctx->dev;
- struct coda_q_data *q_data;
unsigned int max_w, max_h;
enum v4l2_field field;
@@ -381,21 +469,6 @@ static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec,
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
case V4L2_PIX_FMT_NV12:
- case V4L2_PIX_FMT_H264:
- case V4L2_PIX_FMT_MPEG4:
- case V4L2_PIX_FMT_JPEG:
- break;
- default:
- q_data = get_q_data(ctx, f->type);
- if (!q_data)
- return -EINVAL;
- f->fmt.pix.pixelformat = q_data->fourcc;
- }
-
- switch (f->fmt.pix.pixelformat) {
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YVU420:
- case V4L2_PIX_FMT_NV12:
/* Frame stride must be multiple of 8, but 16 for h.264 */
f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16);
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
@@ -423,34 +496,35 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct coda_ctx *ctx = fh_to_ctx(priv);
- const struct coda_codec *codec = NULL;
+ const struct coda_q_data *q_data_src;
+ const struct coda_codec *codec;
struct vb2_queue *src_vq;
int ret;
+ ret = coda_try_pixelformat(ctx, f);
+ if (ret < 0)
+ return ret;
+
+ q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+
/*
- * If the source format is already fixed, try to find a codec that
- * converts to the given destination format
+ * If the source format is already fixed, only allow the same output
+ * resolution
*/
src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
if (vb2_is_streaming(src_vq)) {
- struct coda_q_data *q_data_src;
-
- q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
- codec = coda_find_codec(ctx->dev, q_data_src->fourcc,
- f->fmt.pix.pixelformat);
- if (!codec)
- return -EINVAL;
-
f->fmt.pix.width = q_data_src->width;
f->fmt.pix.height = q_data_src->height;
- } else {
- /* Otherwise determine codec by encoded format, if possible */
- codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420,
- f->fmt.pix.pixelformat);
}
f->fmt.pix.colorspace = ctx->colorspace;
+ q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ codec = coda_find_codec(ctx->dev, q_data_src->fourcc,
+ f->fmt.pix.pixelformat);
+ if (!codec)
+ return -EINVAL;
+
ret = coda_try_fmt(ctx, codec, f);
if (ret < 0)
return ret;
@@ -471,22 +545,21 @@ static int coda_try_fmt_vid_out(struct file *file, void *priv,
struct v4l2_format *f)
{
struct coda_ctx *ctx = fh_to_ctx(priv);
- const struct coda_codec *codec = NULL;
+ struct coda_dev *dev = ctx->dev;
+ const struct coda_q_data *q_data_dst;
+ const struct coda_codec *codec;
+ int ret;
- /* Determine codec by encoded format, returns NULL if raw or invalid */
- if (ctx->inst_type == CODA_INST_DECODER) {
- codec = coda_find_codec(ctx->dev, f->fmt.pix.pixelformat,
- V4L2_PIX_FMT_YUV420);
- if (!codec)
- codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_H264,
- V4L2_PIX_FMT_YUV420);
- if (!codec)
- return -EINVAL;
- }
+ ret = coda_try_pixelformat(ctx, f);
+ if (ret < 0)
+ return ret;
if (!f->fmt.pix.colorspace)
f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
+ q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ codec = coda_find_codec(dev, f->fmt.pix.pixelformat, q_data_dst->fourcc);
+
return coda_try_fmt(ctx, codec, f);
}
@@ -907,18 +980,10 @@ 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;
+ int max_w, max_h;
- 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);
+ ctx->codec = coda_find_codec(ctx->dev, ctx->cvd->src_formats[0],
+ ctx->cvd->dst_formats[0]);
max_w = ctx->codec->max_w;
max_h = ctx->codec->max_h;
@@ -1409,10 +1474,14 @@ static int coda_next_free_instance(struct coda_dev *dev)
return idx;
}
-static int coda_open(struct file *file, enum coda_inst_type inst_type,
- const struct coda_context_ops *ctx_ops)
+/*
+ * File operations
+ */
+
+static int coda_open(struct file *file)
{
- struct coda_dev *dev = video_drvdata(file);
+ struct video_device *vdev = video_devdata(file);
+ struct coda_dev *dev = video_get_drvdata(vdev);
struct coda_ctx *ctx = NULL;
char *name;
int ret;
@@ -1433,8 +1502,9 @@ static int coda_open(struct file *file, enum coda_inst_type inst_type,
ctx->debugfs_entry = debugfs_create_dir(name, dev->debugfs_root);
kfree(name);
- ctx->inst_type = inst_type;
- ctx->ops = ctx_ops;
+ ctx->cvd = to_coda_video_device(vdev);
+ ctx->inst_type = ctx->cvd->type;
+ ctx->ops = ctx->cvd->ops;
init_completion(&ctx->completion);
INIT_WORK(&ctx->pic_run_work, coda_pic_run_work);
INIT_WORK(&ctx->seq_end_work, ctx->ops->seq_end_work);
@@ -1542,16 +1612,6 @@ err_coda_max:
return ret;
}
-static int coda_encoder_open(struct file *file)
-{
- return coda_open(file, CODA_INST_ENCODER, &coda_bit_encode_ops);
-}
-
-static int coda_decoder_open(struct file *file)
-{
- return coda_open(file, CODA_INST_DECODER, &coda_bit_decode_ops);
-}
-
static int coda_release(struct file *file)
{
struct coda_dev *dev = video_drvdata(file);
@@ -1595,18 +1655,9 @@ static int coda_release(struct file *file)
return 0;
}
-static const struct v4l2_file_operations coda_encoder_fops = {
+static const struct v4l2_file_operations coda_fops = {
.owner = THIS_MODULE,
- .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,
+ .open = coda_open,
.release = coda_release,
.poll = v4l2_m2m_fop_poll,
.unlocked_ioctl = video_ioctl2,
@@ -1711,8 +1762,16 @@ err_clk_per:
return ret;
}
-static int coda_register_device(struct coda_dev *dev, struct video_device *vfd)
+static int coda_register_device(struct coda_dev *dev, int i)
{
+ struct video_device *vfd = &dev->vfd[i];
+
+ if (i > ARRAY_SIZE(dev->vfd))
+ return -EINVAL;
+
+ snprintf(vfd->name, sizeof(vfd->name), dev->devtype->vdevs[i]->name);
+ vfd->fops = &coda_fops;
+ vfd->ioctl_ops = &coda_ioctl_ops;
vfd->release = video_device_release_empty,
vfd->lock = &dev->dev_mutex;
vfd->v4l2_dev = &dev->v4l2_dev;
@@ -1731,7 +1790,7 @@ static void coda_fw_callback(const struct firmware *fw, void *context)
{
struct coda_dev *dev = context;
struct platform_device *pdev = dev->plat_dev;
- int ret;
+ int i, ret;
if (!fw) {
v4l2_err(&dev->v4l2_dev, "firmware request failed\n");
@@ -1772,33 +1831,25 @@ static void coda_fw_callback(const struct firmware *fw, void *context)
goto rel_ctx;
}
- 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 encoder video device\n");
- goto rel_m2m;
- }
-
- 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;
+ for (i = 0; i < dev->devtype->num_vdevs; i++) {
+ ret = coda_register_device(dev, i);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev,
+ "Failed to register %s video device: %d\n",
+ dev->devtype->vdevs[i]->name, ret);
+ goto rel_vfd;
+ }
}
v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video[%d-%d]\n",
- dev->vfd[0].num, dev->vfd[1].num);
+ dev->vfd[0].num, dev->vfd[i - 1].num);
pm_runtime_put_sync(&pdev->dev);
return;
-rel_m2m:
+rel_vfd:
+ while (--i >= 0)
+ video_unregister_device(&dev->vfd[i]);
v4l2_m2m_release(dev->m2m_dev);
rel_ctx:
vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
@@ -1830,6 +1881,8 @@ static const struct coda_devtype coda_devdata[] = {
.product = CODA_DX6,
.codecs = codadx6_codecs,
.num_codecs = ARRAY_SIZE(codadx6_codecs),
+ .vdevs = codadx6_video_devices,
+ .num_vdevs = ARRAY_SIZE(codadx6_video_devices),
.workbuf_size = 288 * 1024 + FMO_SLICE_SAVE_BUF_SIZE * 8 * 1024,
.iram_size = 0xb000,
},
@@ -1838,6 +1891,8 @@ static const struct coda_devtype coda_devdata[] = {
.product = CODA_7541,
.codecs = coda7_codecs,
.num_codecs = ARRAY_SIZE(coda7_codecs),
+ .vdevs = coda7_video_devices,
+ .num_vdevs = ARRAY_SIZE(coda7_video_devices),
.workbuf_size = 128 * 1024,
.tempbuf_size = 304 * 1024,
.iram_size = 0x14000,
@@ -1847,6 +1902,8 @@ static const struct coda_devtype coda_devdata[] = {
.product = CODA_960,
.codecs = coda9_codecs,
.num_codecs = ARRAY_SIZE(coda9_codecs),
+ .vdevs = coda9_video_devices,
+ .num_vdevs = ARRAY_SIZE(coda9_video_devices),
.workbuf_size = 80 * 1024,
.tempbuf_size = 204 * 1024,
.iram_size = 0x21000,
@@ -1856,6 +1913,8 @@ static const struct coda_devtype coda_devdata[] = {
.product = CODA_960,
.codecs = coda9_codecs,
.num_codecs = ARRAY_SIZE(coda9_codecs),
+ .vdevs = coda9_video_devices,
+ .num_vdevs = ARRAY_SIZE(coda9_video_devices),
.workbuf_size = 80 * 1024,
.tempbuf_size = 204 * 1024,
.iram_size = 0x20000,
@@ -2035,9 +2094,12 @@ static int coda_probe(struct platform_device *pdev)
static int coda_remove(struct platform_device *pdev)
{
struct coda_dev *dev = platform_get_drvdata(pdev);
+ int i;
- video_unregister_device(&dev->vfd[0]);
- video_unregister_device(&dev->vfd[1]);
+ for (i = 0; i < ARRAY_SIZE(dev->vfd); i++) {
+ if (video_get_drvdata(&dev->vfd[i]))
+ video_unregister_device(&dev->vfd[i]);
+ }
if (dev->m2m_dev)
v4l2_m2m_release(dev->m2m_dev);
pm_runtime_disable(&pdev->dev);
diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h
index 76ba83c..07eaf58 100644
--- a/drivers/media/platform/coda/coda.h
+++ b/drivers/media/platform/coda/coda.h
@@ -45,11 +45,15 @@ enum coda_product {
CODA_960 = 0xf020,
};
+struct coda_video_device;
+
struct coda_devtype {
char *firmware;
enum coda_product product;
const struct coda_codec *codecs;
unsigned int num_codecs;
+ const struct coda_video_device **vdevs;
+ unsigned int num_vdevs;
size_t workbuf_size;
size_t tempbuf_size;
size_t iram_size;
@@ -65,7 +69,7 @@ struct coda_aux_buf {
struct coda_dev {
struct v4l2_device v4l2_dev;
- struct video_device vfd[2];
+ struct video_device vfd[3];
struct platform_device *plat_dev;
const struct coda_devtype *devtype;
@@ -183,6 +187,7 @@ struct coda_ctx {
struct work_struct pic_run_work;
struct work_struct seq_end_work;
struct completion completion;
+ const struct coda_video_device *cvd;
const struct coda_context_ops *ops;
int aborting;
int initialized;
--
2.1.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 04/10] [media] coda: split out encoder control setup to specify controls per video device
2014-09-30 9:57 [PATCH 00/10] CODA7 JPEG support Philipp Zabel
` (2 preceding siblings ...)
2014-09-30 9:57 ` [PATCH 03/10] [media] coda: add coda_video_device descriptors Philipp Zabel
@ 2014-09-30 9:57 ` Philipp Zabel
2014-09-30 9:57 ` [PATCH 05/10] [media] coda: add JPEG register definitions for CODA7541 Philipp Zabel
` (6 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Philipp Zabel @ 2014-09-30 9:57 UTC (permalink / raw)
To: Kamil Debski
Cc: Mauro Carvalho Chehab, Hans Verkuil, linux-media, kernel,
Philipp Zabel
This patch splits the H.264/MPEG4 encoder specific controls out of the main
control setup function. This way each video device registers only relevant
controls.
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
---
drivers/media/platform/coda/coda-common.c | 66 ++++++++++++++++++-------------
1 file changed, 39 insertions(+), 27 deletions(-)
diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c
index df950f2..4d627c6 100644
--- a/drivers/media/platform/coda/coda-common.c
+++ b/drivers/media/platform/coda/coda-common.c
@@ -1350,40 +1350,40 @@ static const struct v4l2_ctrl_ops coda_ctrl_ops = {
.s_ctrl = coda_s_ctrl,
};
-static int coda_ctrls_setup(struct coda_ctx *ctx)
+static void coda_encode_ctrls(struct coda_ctx *ctx)
{
- v4l2_ctrl_handler_init(&ctx->ctrls, 9);
-
- v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
- V4L2_CID_HFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
- V4L2_CID_VFLIP, 0, 1, 1, 0);
v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
V4L2_CID_MPEG_VIDEO_BITRATE, 0, 32767000, 1, 0);
v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 60, 1, 16);
- v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
- V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, 0, 51, 1, 25);
- v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
- V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, 0, 51, 1, 25);
- if (ctx->dev->devtype->product != CODA_960) {
+ switch (ctx->cvd->dst_formats[0]) {
+ case V4L2_PIX_FMT_H264:
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, 0, 51, 1, 25);
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, 0, 51, 1, 25);
+ if (ctx->dev->devtype->product != CODA_960) {
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_MIN_QP, 0, 51, 1, 12);
+ }
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_MAX_QP, 0, 51, 1, 51);
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, 0, 15, 1, 0);
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, 0, 15, 1, 0);
+ v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+ V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED, 0x0,
+ V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED);
+ break;
+ case V4L2_PIX_FMT_MPEG4:
v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
- V4L2_CID_MPEG_VIDEO_H264_MIN_QP, 0, 51, 1, 12);
+ V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP, 1, 31, 1, 2);
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP, 1, 31, 1, 2);
+ break;
}
- v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
- V4L2_CID_MPEG_VIDEO_H264_MAX_QP, 0, 51, 1, 51);
- v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
- V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, 0, 15, 1, 0);
- v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
- V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, 0, 15, 1, 0);
- v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
- V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
- V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED, 0x0,
- V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED);
- v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
- V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP, 1, 31, 1, 2);
- v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
- V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP, 1, 31, 1, 2);
v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES, 0x0,
@@ -1401,6 +1401,18 @@ static int coda_ctrls_setup(struct coda_ctx *ctx)
v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, 0,
1920 * 1088 / 256, 1, 0);
+}
+
+static int coda_ctrls_setup(struct coda_ctx *ctx)
+{
+ v4l2_ctrl_handler_init(&ctx->ctrls, 2);
+
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ if (ctx->inst_type == CODA_INST_ENCODER)
+ coda_encode_ctrls(ctx);
if (ctx->ctrls.error) {
v4l2_err(&ctx->dev->v4l2_dev,
--
2.1.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 05/10] [media] coda: add JPEG register definitions for CODA7541
2014-09-30 9:57 [PATCH 00/10] CODA7 JPEG support Philipp Zabel
` (3 preceding siblings ...)
2014-09-30 9:57 ` [PATCH 04/10] [media] coda: split out encoder control setup to specify controls per video device Philipp Zabel
@ 2014-09-30 9:57 ` Philipp Zabel
2014-09-30 9:57 ` [PATCH 06/10] [media] coda: add CODA7541 JPEG support Philipp Zabel
` (5 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Philipp Zabel @ 2014-09-30 9:57 UTC (permalink / raw)
To: Kamil Debski
Cc: Mauro Carvalho Chehab, Hans Verkuil, linux-media, kernel,
Philipp Zabel, Lucas Stach
Add JPEG specific sequence initialization registers and bit definitions.
Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
---
drivers/media/platform/coda/coda_regs.h | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/media/platform/coda/coda_regs.h b/drivers/media/platform/coda/coda_regs.h
index c791275..8e015b8 100644
--- a/drivers/media/platform/coda/coda_regs.h
+++ b/drivers/media/platform/coda/coda_regs.h
@@ -147,6 +147,7 @@
#define CODA_CMD_DEC_SEQ_BB_START 0x180
#define CODA_CMD_DEC_SEQ_BB_SIZE 0x184
#define CODA_CMD_DEC_SEQ_OPTION 0x188
+#define CODA_NO_INT_ENABLE (1 << 10)
#define CODA_REORDER_ENABLE (1 << 1)
#define CODADX6_QP_REPORT (1 << 0)
#define CODA7_MP4_DEBLK_ENABLE (1 << 0)
@@ -332,6 +333,12 @@
#define CODA9_CMD_ENC_SEQ_ME_OPTION 0x1d8
#define CODA_RET_ENC_SEQ_SUCCESS 0x1c0
+#define CODA_CMD_ENC_SEQ_JPG_PARA 0x198
+#define CODA_CMD_ENC_SEQ_JPG_RST_INTERVAL 0x19C
+#define CODA_CMD_ENC_SEQ_JPG_THUMB_EN 0x1a0
+#define CODA_CMD_ENC_SEQ_JPG_THUMB_SIZE 0x1a4
+#define CODA_CMD_ENC_SEQ_JPG_THUMB_OFFSET 0x1a8
+
/* Encoder Picture Run */
#define CODA9_CMD_ENC_PIC_SRC_INDEX 0x180
#define CODA9_CMD_ENC_PIC_SRC_STRIDE 0x184
--
2.1.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 06/10] [media] coda: add CODA7541 JPEG support
2014-09-30 9:57 [PATCH 00/10] CODA7 JPEG support Philipp Zabel
` (4 preceding siblings ...)
2014-09-30 9:57 ` [PATCH 05/10] [media] coda: add JPEG register definitions for CODA7541 Philipp Zabel
@ 2014-09-30 9:57 ` Philipp Zabel
2014-09-30 9:57 ` [PATCH 07/10] [media] coda: store bitstream buffer position with buffer metadata Philipp Zabel
` (4 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Philipp Zabel @ 2014-09-30 9:57 UTC (permalink / raw)
To: Kamil Debski
Cc: Mauro Carvalho Chehab, Hans Verkuil, linux-media, kernel,
Philipp Zabel, Lucas Stach
This patch adds JPEG encoding and decoding support for CODA7541,
using the BIT processor. Separate JPEG encoder and decoder video
devices are created due to different supported pixel formats.
The hardware can not change subsampling on the fly, but encode
and decode 4:2:2 subsampled JPEG images from and into this format.
The CODA7541 JPEG decoder uses the bitstream buffer and thus can run
without new buffers queued if there is a buffer in the bitstream.
Since there is no standard way to store the colorspace used in
JPEGs, and to make v4l2-compliance happy, the JPEG format always
reports V4L2_COLORSPACE_JPEG.
Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
---
drivers/media/platform/coda/Makefile | 2 +-
drivers/media/platform/coda/coda-bit.c | 103 +++++++++-----
drivers/media/platform/coda/coda-common.c | 112 ++++++++++++---
drivers/media/platform/coda/coda-jpeg.c | 225 ++++++++++++++++++++++++++++++
drivers/media/platform/coda/coda.h | 8 +-
5 files changed, 398 insertions(+), 52 deletions(-)
create mode 100644 drivers/media/platform/coda/coda-jpeg.c
diff --git a/drivers/media/platform/coda/Makefile b/drivers/media/platform/coda/Makefile
index 3543291..25ce155 100644
--- a/drivers/media/platform/coda/Makefile
+++ b/drivers/media/platform/coda/Makefile
@@ -1,3 +1,3 @@
-coda-objs := coda-common.o coda-bit.o coda-h264.o
+coda-objs := coda-common.o coda-bit.o coda-h264.o coda-jpeg.o
obj-$(CONFIG_VIDEO_CODA) += coda.o
diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c
index 746a615..931248d 100644
--- a/drivers/media/platform/coda/coda-bit.c
+++ b/drivers/media/platform/coda/coda-bit.c
@@ -691,6 +691,7 @@ static int coda_start_encoding(struct coda_ctx *ctx)
struct vb2_buffer *buf;
int gamma, ret, value;
u32 dst_fourcc;
+ u32 stride;
q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
@@ -710,6 +711,14 @@ static int coda_start_encoding(struct coda_ctx *ctx)
return -EFAULT;
}
+ if (dst_fourcc == V4L2_PIX_FMT_JPEG) {
+ if (!ctx->params.jpeg_qmat_tab[0])
+ ctx->params.jpeg_qmat_tab[0] = kmalloc(64, GFP_KERNEL);
+ if (!ctx->params.jpeg_qmat_tab[1])
+ ctx->params.jpeg_qmat_tab[1] = kmalloc(64, GFP_KERNEL);
+ coda_set_jpeg_compression_quality(ctx, ctx->params.jpeg_quality);
+ }
+
mutex_lock(&dev->coda_mutex);
coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
@@ -765,6 +774,8 @@ static int coda_start_encoding(struct coda_ctx *ctx)
<< CODA_PICHEIGHT_OFFSET;
}
coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE);
+ if (dst_fourcc == V4L2_PIX_FMT_JPEG)
+ ctx->params.framerate = 0;
coda_write(dev, ctx->params.framerate,
CODA_CMD_ENC_SEQ_SRC_F_RATE);
@@ -798,6 +809,16 @@ static int coda_start_encoding(struct coda_ctx *ctx)
}
coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA);
break;
+ case V4L2_PIX_FMT_JPEG:
+ coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_PARA);
+ coda_write(dev, ctx->params.jpeg_restart_interval,
+ CODA_CMD_ENC_SEQ_JPG_RST_INTERVAL);
+ coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_EN);
+ coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_SIZE);
+ coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_OFFSET);
+
+ coda_jpeg_write_tables(ctx);
+ break;
default:
v4l2_err(v4l2_dev,
"dst format (0x%08x) invalid.\n", dst_fourcc);
@@ -805,28 +826,36 @@ static int coda_start_encoding(struct coda_ctx *ctx)
goto out;
}
- switch (ctx->params.slice_mode) {
- case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE:
- value = 0;
- break;
- case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB:
- value = (ctx->params.slice_max_mb & CODA_SLICING_SIZE_MASK)
- << CODA_SLICING_SIZE_OFFSET;
- value |= (1 & CODA_SLICING_UNIT_MASK)
- << CODA_SLICING_UNIT_OFFSET;
- value |= 1 & CODA_SLICING_MODE_MASK;
- break;
- case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES:
- value = (ctx->params.slice_max_bits & CODA_SLICING_SIZE_MASK)
- << CODA_SLICING_SIZE_OFFSET;
- value |= (0 & CODA_SLICING_UNIT_MASK)
- << CODA_SLICING_UNIT_OFFSET;
- value |= 1 & CODA_SLICING_MODE_MASK;
- break;
+ /*
+ * slice mode and GOP size registers are used for thumb size/offset
+ * in JPEG mode
+ */
+ if (dst_fourcc != V4L2_PIX_FMT_JPEG) {
+ switch (ctx->params.slice_mode) {
+ case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE:
+ value = 0;
+ break;
+ case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB:
+ value = (ctx->params.slice_max_mb &
+ CODA_SLICING_SIZE_MASK)
+ << CODA_SLICING_SIZE_OFFSET;
+ value |= (1 & CODA_SLICING_UNIT_MASK)
+ << CODA_SLICING_UNIT_OFFSET;
+ value |= 1 & CODA_SLICING_MODE_MASK;
+ break;
+ case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES:
+ value = (ctx->params.slice_max_bits &
+ CODA_SLICING_SIZE_MASK)
+ << CODA_SLICING_SIZE_OFFSET;
+ value |= (0 & CODA_SLICING_UNIT_MASK)
+ << CODA_SLICING_UNIT_OFFSET;
+ value |= 1 & CODA_SLICING_MODE_MASK;
+ break;
+ }
+ coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE);
+ value = ctx->params.gop_size & CODA_GOP_SIZE_MASK;
+ coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE);
}
- coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE);
- value = ctx->params.gop_size & CODA_GOP_SIZE_MASK;
- coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE);
if (ctx->params.bitrate) {
/* Rate control enabled */
@@ -917,19 +946,24 @@ static int coda_start_encoding(struct coda_ctx *ctx)
goto out;
}
- if (dev->devtype->product == CODA_960)
- ctx->num_internal_frames = 4;
- else
- ctx->num_internal_frames = 2;
- ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc);
- if (ret < 0) {
- v4l2_err(v4l2_dev, "failed to allocate framebuffers\n");
- goto out;
+ if (dst_fourcc != V4L2_PIX_FMT_JPEG) {
+ if (dev->devtype->product == CODA_960)
+ ctx->num_internal_frames = 4;
+ else
+ ctx->num_internal_frames = 2;
+ ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc);
+ if (ret < 0) {
+ v4l2_err(v4l2_dev, "failed to allocate framebuffers\n");
+ goto out;
+ }
+ stride = q_data_src->bytesperline;
+ } else {
+ ctx->num_internal_frames = 0;
+ stride = 0;
}
-
coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM);
- coda_write(dev, q_data_src->bytesperline,
- CODA_CMD_SET_FRAME_BUF_STRIDE);
+ coda_write(dev, stride, CODA_CMD_SET_FRAME_BUF_STRIDE);
+
if (dev->devtype->product == CODA_7541) {
coda_write(dev, q_data_src->bytesperline,
CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE);
@@ -1104,6 +1138,9 @@ static int coda_prepare_encode(struct coda_ctx *ctx)
case V4L2_PIX_FMT_MPEG4:
quant_param = ctx->params.mpeg4_intra_qp;
break;
+ case V4L2_PIX_FMT_JPEG:
+ quant_param = 30;
+ break;
default:
v4l2_warn(&ctx->dev->v4l2_dev,
"cannot set intra qp, fmt not supported\n");
@@ -1315,6 +1352,8 @@ static int __coda_start_decoding(struct coda_ctx *ctx)
if ((dev->devtype->product == CODA_7541) ||
(dev->devtype->product == CODA_960))
val |= CODA_REORDER_ENABLE;
+ if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG)
+ val |= CODA_NO_INT_ENABLE;
coda_write(dev, val, CODA_CMD_DEC_SEQ_OPTION);
ctx->params.codec_mode = ctx->codec->mode;
diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c
index 4d627c6..53304d5 100644
--- a/drivers/media/platform/coda/coda-common.c
+++ b/drivers/media/platform/coda/coda-common.c
@@ -139,6 +139,10 @@ static const struct coda_fmt coda_formats[] = {
.name = "MPEG4 Encoded Stream",
.fourcc = V4L2_PIX_FMT_MPEG4,
},
+ {
+ .name = "JPEG Encoded Images",
+ .fourcc = V4L2_PIX_FMT_JPEG,
+ },
};
#define CODA_CODEC(mode, src_fourcc, dst_fourcc, max_w, max_h) \
@@ -159,8 +163,10 @@ static const struct coda_codec codadx6_codecs[] = {
static const struct coda_codec coda7_codecs[] = {
CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1280, 720),
CODA_CODEC(CODA7_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1280, 720),
+ CODA_CODEC(CODA7_MODE_ENCODE_MJPG, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_JPEG, 8192, 8192),
CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1088),
CODA_CODEC(CODA7_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1088),
+ CODA_CODEC(CODA7_MODE_DECODE_MJPG, V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_YUV420, 8192, 8192),
};
static const struct coda_codec coda9_codecs[] = {
@@ -206,6 +212,21 @@ static const struct coda_video_device coda_bit_mpeg4_encoder = {
},
};
+static const struct coda_video_device coda_bit_jpeg_encoder = {
+ .name = "coda-jpeg-encoder",
+ .type = CODA_INST_ENCODER,
+ .ops = &coda_bit_encode_ops,
+ .src_formats = {
+ V4L2_PIX_FMT_YUV420,
+ V4L2_PIX_FMT_YVU420,
+ V4L2_PIX_FMT_NV12,
+ V4L2_PIX_FMT_YUV422P,
+ },
+ .dst_formats = {
+ V4L2_PIX_FMT_JPEG,
+ },
+};
+
static const struct coda_video_device coda_bit_decoder = {
.name = "coda-decoder",
.type = CODA_INST_DECODER,
@@ -221,12 +242,29 @@ static const struct coda_video_device coda_bit_decoder = {
},
};
+static const struct coda_video_device coda_bit_jpeg_decoder = {
+ .name = "coda-jpeg-decoder",
+ .type = CODA_INST_DECODER,
+ .ops = &coda_bit_decode_ops,
+ .src_formats = {
+ V4L2_PIX_FMT_JPEG,
+ },
+ .dst_formats = {
+ V4L2_PIX_FMT_YUV420,
+ V4L2_PIX_FMT_YVU420,
+ V4L2_PIX_FMT_NV12,
+ V4L2_PIX_FMT_YUV422P,
+ },
+};
+
static const struct coda_video_device *codadx6_video_devices[] = {
&coda_bit_h264_encoder,
&coda_bit_mpeg4_encoder,
};
static const struct coda_video_device *coda7_video_devices[] = {
+ &coda_bit_jpeg_encoder,
+ &coda_bit_jpeg_decoder,
&coda_bit_h264_encoder,
&coda_bit_mpeg4_encoder,
&coda_bit_decoder,
@@ -411,7 +449,10 @@ static int coda_g_fmt(struct file *file, void *priv,
f->fmt.pix.bytesperline = q_data->bytesperline;
f->fmt.pix.sizeimage = q_data->sizeimage;
- f->fmt.pix.colorspace = ctx->colorspace;
+ if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG)
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
+ else
+ f->fmt.pix.colorspace = ctx->colorspace;
return 0;
}
@@ -469,7 +510,10 @@ static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec,
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
case V4L2_PIX_FMT_NV12:
- /* Frame stride must be multiple of 8, but 16 for h.264 */
+ /*
+ * Frame stride must be at least multiple of 8,
+ * but multiple of 16 for h.264 or JPEG 4:2:x
+ */
f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16);
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
f->fmt.pix.height * 3 / 2;
@@ -479,9 +523,11 @@ static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec,
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
f->fmt.pix.height * 2;
break;
+ case V4L2_PIX_FMT_JPEG:
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
+ /* fallthrough */
case V4L2_PIX_FMT_H264:
case V4L2_PIX_FMT_MPEG4:
- case V4L2_PIX_FMT_JPEG:
f->fmt.pix.bytesperline = 0;
f->fmt.pix.sizeimage = CODA_MAX_FRAME_SIZE;
break;
@@ -554,8 +600,12 @@ static int coda_try_fmt_vid_out(struct file *file, void *priv,
if (ret < 0)
return ret;
- if (!f->fmt.pix.colorspace)
- f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
+ if (!f->fmt.pix.colorspace) {
+ if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG)
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
+ else
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
+ }
q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
codec = coda_find_codec(dev, f->fmt.pix.pixelformat, q_data_dst->fourcc);
@@ -899,6 +949,7 @@ static int coda_job_ready(void *m2m_priv)
if (ctx->hold ||
((ctx->inst_type == CODA_INST_DECODER) &&
+ !v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) &&
(coda_get_bitstream_payload(ctx) < 512) &&
!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) {
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
@@ -1073,7 +1124,7 @@ static void coda_buf_queue(struct vb2_buffer *vb)
* In the decoder case, immediately try to copy the buffer into the
* bitstream ringbuffer and mark it as ready to be dequeued.
*/
- if (q_data->fourcc == V4L2_PIX_FMT_H264 &&
+ if (ctx->inst_type == CODA_INST_DECODER &&
vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
/*
* For backwards compatibility, queuing an empty buffer marks
@@ -1136,12 +1187,13 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev;
struct coda_q_data *q_data_src, *q_data_dst;
struct vb2_buffer *buf;
- u32 dst_fourcc;
int ret = 0;
q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
- if (q_data_src->fourcc == V4L2_PIX_FMT_H264) {
+ if (q_data_src->fourcc == V4L2_PIX_FMT_H264 ||
+ (q_data_src->fourcc == V4L2_PIX_FMT_JPEG &&
+ ctx->dev->devtype->product == CODA_7541)) {
/* copy the buffers that where queued before streamon */
mutex_lock(&ctx->bitstream_mutex);
coda_fill_bitstream(ctx);
@@ -1172,13 +1224,12 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
if (!(ctx->streamon_out & ctx->streamon_cap))
return 0;
- /* Allow decoder device_run with no new buffers queued */
+ /* Allow BIT decoder device_run with no new buffers queued */
if (ctx->inst_type == CODA_INST_DECODER)
v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true);
ctx->gopcounter = ctx->params.gop_size - 1;
q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
- dst_fourcc = q_data_dst->fourcc;
ctx->codec = coda_find_codec(ctx->dev, q_data_src->fourcc,
q_data_dst->fourcc);
@@ -1188,6 +1239,10 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
goto err;
}
+ if (q_data_dst->fourcc == V4L2_PIX_FMT_JPEG)
+ ctx->params.gop_size = 1;
+ ctx->gopcounter = ctx->params.gop_size - 1;
+
ret = ctx->ops->start_streaming(ctx);
if (ctx->inst_type == CODA_INST_DECODER) {
if (ret == -EAGAIN)
@@ -1336,6 +1391,12 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
ctx->params.intra_refresh = ctrl->val;
break;
+ case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+ coda_set_jpeg_compression_quality(ctx, ctrl->val);
+ break;
+ case V4L2_CID_JPEG_RESTART_INTERVAL:
+ ctx->params.jpeg_restart_interval = ctrl->val;
+ break;
default:
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
"Invalid control, id=%d, val=%d\n",
@@ -1403,6 +1464,14 @@ static void coda_encode_ctrls(struct coda_ctx *ctx)
1920 * 1088 / 256, 1, 0);
}
+static void coda_jpeg_encode_ctrls(struct coda_ctx *ctx)
+{
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_JPEG_COMPRESSION_QUALITY, 5, 100, 1, 50);
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_JPEG_RESTART_INTERVAL, 0, 100, 1, 0);
+}
+
static int coda_ctrls_setup(struct coda_ctx *ctx)
{
v4l2_ctrl_handler_init(&ctx->ctrls, 2);
@@ -1411,8 +1480,12 @@ static int coda_ctrls_setup(struct coda_ctx *ctx)
V4L2_CID_HFLIP, 0, 1, 1, 0);
v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
V4L2_CID_VFLIP, 0, 1, 1, 0);
- if (ctx->inst_type == CODA_INST_ENCODER)
- coda_encode_ctrls(ctx);
+ if (ctx->inst_type == CODA_INST_ENCODER) {
+ if (ctx->cvd->dst_formats[0] == V4L2_PIX_FMT_JPEG)
+ coda_jpeg_encode_ctrls(ctx);
+ else
+ coda_encode_ctrls(ctx);
+ }
if (ctx->ctrls.error) {
v4l2_err(&ctx->dev->v4l2_dev,
@@ -1570,16 +1643,17 @@ static int coda_open(struct file *file)
ctx->fh.ctrl_handler = &ctx->ctrls;
- ret = coda_alloc_context_buf(ctx, &ctx->parabuf, CODA_PARA_BUF_SIZE,
- "parabuf");
+ ret = coda_alloc_context_buf(ctx, &ctx->parabuf,
+ CODA_PARA_BUF_SIZE, "parabuf");
if (ret < 0) {
v4l2_err(&dev->v4l2_dev, "failed to allocate parabuf");
goto err_dma_alloc;
}
ctx->bitstream.size = CODA_MAX_FRAME_SIZE;
- ctx->bitstream.vaddr = dma_alloc_writecombine(&dev->plat_dev->dev,
- ctx->bitstream.size, &ctx->bitstream.paddr, GFP_KERNEL);
+ ctx->bitstream.vaddr = dma_alloc_writecombine(
+ &dev->plat_dev->dev, ctx->bitstream.size,
+ &ctx->bitstream.paddr, GFP_KERNEL);
if (!ctx->bitstream.vaddr) {
v4l2_err(&dev->v4l2_dev,
"failed to allocate bitstream ringbuffer");
@@ -1647,8 +1721,10 @@ static int coda_release(struct file *file)
list_del(&ctx->list);
coda_unlock(ctx);
- dma_free_writecombine(&dev->plat_dev->dev, ctx->bitstream.size,
- ctx->bitstream.vaddr, ctx->bitstream.paddr);
+ if (ctx->bitstream.vaddr) {
+ dma_free_writecombine(&dev->plat_dev->dev, ctx->bitstream.size,
+ ctx->bitstream.vaddr, ctx->bitstream.paddr);
+ }
if (ctx->dev->devtype->product == CODA_DX6)
coda_free_aux_buf(dev, &ctx->workbuf);
diff --git a/drivers/media/platform/coda/coda-jpeg.c b/drivers/media/platform/coda/coda-jpeg.c
new file mode 100644
index 0000000..967b015
--- /dev/null
+++ b/drivers/media/platform/coda/coda-jpeg.c
@@ -0,0 +1,225 @@
+/*
+ * Coda multi-standard codec IP - JPEG support functions
+ *
+ * Copyright (C) 2014 Philipp Zabel, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/swab.h>
+
+#include "coda.h"
+
+/*
+ * Typical Huffman tables for 8-bit precision luminance and
+ * chrominance from JPEG ITU-T.81 (ISO/IEC 10918-1) Annex K.3
+ */
+
+static const unsigned char luma_dc_bits[16] = {
+ 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const unsigned char luma_dc_value[12] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b,
+};
+
+static const unsigned char chroma_dc_bits[16] = {
+ 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const unsigned char chroma_dc_value[12] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b,
+};
+
+static const unsigned char luma_ac_bits[16] = {
+ 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
+ 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,
+};
+
+static const unsigned char luma_ac_value[162 + 2] = {
+ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+ 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+ 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+ 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa, /* padded to 32-bit */
+};
+
+static const unsigned char chroma_ac_bits[16] = {
+ 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
+ 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77,
+};
+
+static const unsigned char chroma_ac_value[162 + 2] = {
+ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+ 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+ 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+ 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+ 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
+ 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+ 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+ 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+ 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+ 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+ 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa, /* padded to 32-bit */
+};
+
+/*
+ * Quantization tables for luminance and chrominance components in
+ * zig-zag scan order from the Freescale i.MX VPU libaries
+ */
+
+static unsigned char luma_q[64] = {
+ 0x06, 0x04, 0x04, 0x04, 0x05, 0x04, 0x06, 0x05,
+ 0x05, 0x06, 0x09, 0x06, 0x05, 0x06, 0x09, 0x0b,
+ 0x08, 0x06, 0x06, 0x08, 0x0b, 0x0c, 0x0a, 0x0a,
+ 0x0b, 0x0a, 0x0a, 0x0c, 0x10, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x10, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+};
+
+static unsigned char chroma_q[64] = {
+ 0x07, 0x07, 0x07, 0x0d, 0x0c, 0x0d, 0x18, 0x10,
+ 0x10, 0x18, 0x14, 0x0e, 0x0e, 0x0e, 0x14, 0x14,
+ 0x0e, 0x0e, 0x0e, 0x0e, 0x14, 0x11, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x11, 0x11, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x11, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+};
+
+struct coda_memcpy_desc {
+ int offset;
+ const void *src;
+ size_t len;
+};
+
+static void coda_memcpy_parabuf(void *parabuf,
+ const struct coda_memcpy_desc *desc)
+{
+ u32 *dst = parabuf + desc->offset;
+ const u32 *src = desc->src;
+ int len = desc->len / 4;
+ int i;
+
+ for (i = 0; i < len; i += 2) {
+ dst[i + 1] = swab32(src[i]);
+ dst[i] = swab32(src[i + 1]);
+ }
+}
+
+int coda_jpeg_write_tables(struct coda_ctx *ctx)
+{
+ int i;
+ static const struct coda_memcpy_desc huff[8] = {
+ { 0, luma_dc_bits, sizeof(luma_dc_bits) },
+ { 16, luma_dc_value, sizeof(luma_dc_value) },
+ { 32, luma_ac_bits, sizeof(luma_ac_bits) },
+ { 48, luma_ac_value, sizeof(luma_ac_value) },
+ { 216, chroma_dc_bits, sizeof(chroma_dc_bits) },
+ { 232, chroma_dc_value, sizeof(chroma_dc_value) },
+ { 248, chroma_ac_bits, sizeof(chroma_ac_bits) },
+ { 264, chroma_ac_value, sizeof(chroma_ac_value) },
+ };
+ struct coda_memcpy_desc qmat[3] = {
+ { 512, ctx->params.jpeg_qmat_tab[0], 64 },
+ { 576, ctx->params.jpeg_qmat_tab[1], 64 },
+ { 640, ctx->params.jpeg_qmat_tab[1], 64 },
+ };
+
+ /* Write huffman tables to parameter memory */
+ for (i = 0; i < ARRAY_SIZE(huff); i++)
+ coda_memcpy_parabuf(ctx->parabuf.vaddr, huff + i);
+
+ /* Write Q-matrix to parameter memory */
+ for (i = 0; i < ARRAY_SIZE(qmat); i++)
+ coda_memcpy_parabuf(ctx->parabuf.vaddr, qmat + i);
+
+ return 0;
+}
+
+/*
+ * Scale quantization table using nonlinear scaling factor
+ * u8 qtab[64], scale [50,190]
+ */
+static void coda_scale_quant_table(u8 *q_tab, int scale)
+{
+ unsigned int temp;
+ int i;
+
+ for (i = 0; i < 64; i++) {
+ temp = DIV_ROUND_CLOSEST((unsigned int)q_tab[i] * scale, 100);
+ if (temp <= 0)
+ temp = 1;
+ if (temp > 255)
+ temp = 255;
+ q_tab[i] = (unsigned char)temp;
+ }
+}
+
+void coda_set_jpeg_compression_quality(struct coda_ctx *ctx, int quality)
+{
+ unsigned int scale;
+
+ ctx->params.jpeg_quality = quality;
+
+ /* Clip quality setting to [5,100] interval */
+ if (quality > 100)
+ quality = 100;
+ if (quality < 5)
+ quality = 5;
+
+ /*
+ * Non-linear scaling factor:
+ * [5,50] -> [1000..100], [51,100] -> [98..0]
+ */
+ if (quality < 50)
+ scale = 5000 / quality;
+ else
+ scale = 200 - 2 * quality;
+
+ if (ctx->params.jpeg_qmat_tab[0]) {
+ memcpy(ctx->params.jpeg_qmat_tab[0], luma_q, 64);
+ coda_scale_quant_table(ctx->params.jpeg_qmat_tab[0], scale);
+ }
+ if (ctx->params.jpeg_qmat_tab[1]) {
+ memcpy(ctx->params.jpeg_qmat_tab[1], chroma_q, 64);
+ coda_scale_quant_table(ctx->params.jpeg_qmat_tab[1], scale);
+ }
+}
diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h
index 07eaf58..c14dee8 100644
--- a/drivers/media/platform/coda/coda.h
+++ b/drivers/media/platform/coda/coda.h
@@ -69,7 +69,7 @@ struct coda_aux_buf {
struct coda_dev {
struct v4l2_device v4l2_dev;
- struct video_device vfd[3];
+ struct video_device vfd[5];
struct platform_device *plat_dev;
const struct coda_devtype *devtype;
@@ -118,6 +118,9 @@ struct coda_params {
u8 mpeg4_inter_qp;
u8 gop_size;
int intra_refresh;
+ u8 jpeg_quality;
+ u8 jpeg_restart_interval;
+ u8 *jpeg_qmat_tab[3];
int codec_mode;
int codec_mode_aux;
enum v4l2_mpeg_video_multi_slice_mode slice_mode;
@@ -288,6 +291,9 @@ void coda_bit_stream_end_flag(struct coda_ctx *ctx);
int coda_h264_padding(int size, char *p);
+int coda_jpeg_write_tables(struct coda_ctx *ctx);
+void coda_set_jpeg_compression_quality(struct coda_ctx *ctx, int quality);
+
extern const struct coda_context_ops coda_bit_encode_ops;
extern const struct coda_context_ops coda_bit_decode_ops;
--
2.1.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 07/10] [media] coda: store bitstream buffer position with buffer metadata
2014-09-30 9:57 [PATCH 00/10] CODA7 JPEG support Philipp Zabel
` (5 preceding siblings ...)
2014-09-30 9:57 ` [PATCH 06/10] [media] coda: add CODA7541 JPEG support Philipp Zabel
@ 2014-09-30 9:57 ` Philipp Zabel
2014-09-30 9:57 ` [PATCH 08/10] [media] coda: pad input stream for JPEG decoder Philipp Zabel
` (3 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Philipp Zabel @ 2014-09-30 9:57 UTC (permalink / raw)
To: Kamil Debski
Cc: Mauro Carvalho Chehab, Hans Verkuil, linux-media, kernel,
Philipp Zabel
Storing the buffer position in the bitstream with the buffer metadata
allows to later use that information to drop metadata for skipped buffers
and to determine whether bitstream padding has to be applied.
This patch also renames struct coda_timestamp to struct coda_buffer_meta
to make clear that it contains more than only the buffer timestamp.
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
---
drivers/media/platform/coda/coda-bit.c | 53 ++++++++++++++++++-------------
drivers/media/platform/coda/coda-common.c | 14 ++++----
drivers/media/platform/coda/coda.h | 8 +++--
3 files changed, 43 insertions(+), 32 deletions(-)
diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c
index 931248d..d1ecda5 100644
--- a/drivers/media/platform/coda/coda-bit.c
+++ b/drivers/media/platform/coda/coda-bit.c
@@ -217,11 +217,16 @@ static bool coda_bitstream_try_queue(struct coda_ctx *ctx,
void coda_fill_bitstream(struct coda_ctx *ctx)
{
struct vb2_buffer *src_buf;
- struct coda_timestamp *ts;
+ struct coda_buffer_meta *meta;
+ u32 start;
while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) {
src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ /* Buffer start position */
+ start = ctx->bitstream_fifo.kfifo.in &
+ ctx->bitstream_fifo.kfifo.mask;
+
if (coda_bitstream_try_queue(ctx, src_buf)) {
/*
* Source buffer is queued in the bitstream ringbuffer;
@@ -229,12 +234,16 @@ void coda_fill_bitstream(struct coda_ctx *ctx)
*/
src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
- ts = kmalloc(sizeof(*ts), GFP_KERNEL);
- if (ts) {
- ts->sequence = src_buf->v4l2_buf.sequence;
- ts->timecode = src_buf->v4l2_buf.timecode;
- ts->timestamp = src_buf->v4l2_buf.timestamp;
- list_add_tail(&ts->list, &ctx->timestamp_list);
+ meta = kmalloc(sizeof(*meta), GFP_KERNEL);
+ if (meta) {
+ meta->sequence = src_buf->v4l2_buf.sequence;
+ meta->timecode = src_buf->v4l2_buf.timecode;
+ meta->timestamp = src_buf->v4l2_buf.timestamp;
+ meta->start = start;
+ meta->end = ctx->bitstream_fifo.kfifo.in &
+ ctx->bitstream_fifo.kfifo.mask;
+ list_add_tail(&meta->list,
+ &ctx->buffer_meta_list);
}
v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
@@ -1629,7 +1638,7 @@ static void coda_finish_decode(struct coda_ctx *ctx)
struct coda_q_data *q_data_src;
struct coda_q_data *q_data_dst;
struct vb2_buffer *dst_buf;
- struct coda_timestamp *ts;
+ struct coda_buffer_meta *meta;
unsigned long payload;
int width, height;
int decoded_idx;
@@ -1757,23 +1766,23 @@ static void coda_finish_decode(struct coda_ctx *ctx)
val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1;
val -= ctx->sequence_offset;
mutex_lock(&ctx->bitstream_mutex);
- if (!list_empty(&ctx->timestamp_list)) {
- ts = list_first_entry(&ctx->timestamp_list,
- struct coda_timestamp, list);
- list_del(&ts->list);
- if (val != (ts->sequence & 0xffff)) {
+ if (!list_empty(&ctx->buffer_meta_list)) {
+ meta = list_first_entry(&ctx->buffer_meta_list,
+ struct coda_buffer_meta, list);
+ list_del(&meta->list);
+ if (val != (meta->sequence & 0xffff)) {
v4l2_err(&dev->v4l2_dev,
"sequence number mismatch (%d(%d) != %d)\n",
val, ctx->sequence_offset,
- ts->sequence);
+ meta->sequence);
}
- ctx->frame_timestamps[decoded_idx] = *ts;
- kfree(ts);
+ ctx->frame_metas[decoded_idx] = *meta;
+ kfree(meta);
} else {
v4l2_err(&dev->v4l2_dev, "empty timestamp list!\n");
- memset(&ctx->frame_timestamps[decoded_idx], 0,
- sizeof(struct coda_timestamp));
- ctx->frame_timestamps[decoded_idx].sequence = val;
+ memset(&ctx->frame_metas[decoded_idx], 0,
+ sizeof(struct coda_buffer_meta));
+ ctx->frame_metas[decoded_idx].sequence = val;
}
mutex_unlock(&ctx->bitstream_mutex);
@@ -1812,9 +1821,9 @@ static void coda_finish_decode(struct coda_ctx *ctx)
V4L2_BUF_FLAG_PFRAME |
V4L2_BUF_FLAG_BFRAME);
dst_buf->v4l2_buf.flags |= ctx->frame_types[ctx->display_idx];
- ts = &ctx->frame_timestamps[ctx->display_idx];
- dst_buf->v4l2_buf.timecode = ts->timecode;
- dst_buf->v4l2_buf.timestamp = ts->timestamp;
+ meta = &ctx->frame_metas[ctx->display_idx];
+ dst_buf->v4l2_buf.timecode = meta->timecode;
+ dst_buf->v4l2_buf.timestamp = meta->timestamp;
switch (q_data_dst->fourcc) {
case V4L2_PIX_FMT_YUV420:
diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c
index 53304d5..53791d4 100644
--- a/drivers/media/platform/coda/coda-common.c
+++ b/drivers/media/platform/coda/coda-common.c
@@ -1295,14 +1295,14 @@ static void coda_stop_streaming(struct vb2_queue *q)
}
if (!ctx->streamon_out && !ctx->streamon_cap) {
- struct coda_timestamp *ts;
+ struct coda_buffer_meta *meta;
mutex_lock(&ctx->bitstream_mutex);
- while (!list_empty(&ctx->timestamp_list)) {
- ts = list_first_entry(&ctx->timestamp_list,
- struct coda_timestamp, list);
- list_del(&ts->list);
- kfree(ts);
+ while (!list_empty(&ctx->buffer_meta_list)) {
+ meta = list_first_entry(&ctx->buffer_meta_list,
+ struct coda_buffer_meta, list);
+ list_del(&meta->list);
+ kfree(meta);
}
mutex_unlock(&ctx->bitstream_mutex);
kfifo_init(&ctx->bitstream_fifo,
@@ -1664,7 +1664,7 @@ static int coda_open(struct file *file)
ctx->bitstream.vaddr, ctx->bitstream.size);
mutex_init(&ctx->bitstream_mutex);
mutex_init(&ctx->buffer_mutex);
- INIT_LIST_HEAD(&ctx->timestamp_list);
+ INIT_LIST_HEAD(&ctx->buffer_meta_list);
coda_lock(ctx);
list_add(&ctx->list, &dev->instances);
diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h
index c14dee8..8dd81a7 100644
--- a/drivers/media/platform/coda/coda.h
+++ b/drivers/media/platform/coda/coda.h
@@ -130,11 +130,13 @@ struct coda_params {
u32 slice_max_mb;
};
-struct coda_timestamp {
+struct coda_buffer_meta {
struct list_head list;
u32 sequence;
struct v4l2_timecode timecode;
struct timeval timestamp;
+ u32 start;
+ u32 end;
};
/* Per-queue, driver-specific private data */
@@ -220,9 +222,9 @@ struct coda_ctx {
struct coda_aux_buf slicebuf;
struct coda_aux_buf internal_frames[CODA_MAX_FRAMEBUFFERS];
u32 frame_types[CODA_MAX_FRAMEBUFFERS];
- struct coda_timestamp frame_timestamps[CODA_MAX_FRAMEBUFFERS];
+ struct coda_buffer_meta frame_metas[CODA_MAX_FRAMEBUFFERS];
u32 frame_errors[CODA_MAX_FRAMEBUFFERS];
- struct list_head timestamp_list;
+ struct list_head buffer_meta_list;
struct coda_aux_buf workbuf;
int num_internal_frames;
int idx;
--
2.1.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 08/10] [media] coda: pad input stream for JPEG decoder
2014-09-30 9:57 [PATCH 00/10] CODA7 JPEG support Philipp Zabel
` (6 preceding siblings ...)
2014-09-30 9:57 ` [PATCH 07/10] [media] coda: store bitstream buffer position with buffer metadata Philipp Zabel
@ 2014-09-30 9:57 ` Philipp Zabel
2014-09-30 9:57 ` [PATCH 09/10] [media] coda: try to only queue a single JPEG into the bitstream Philipp Zabel
` (2 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Philipp Zabel @ 2014-09-30 9:57 UTC (permalink / raw)
To: Kamil Debski
Cc: Mauro Carvalho Chehab, Hans Verkuil, linux-media, kernel,
Philipp Zabel
Before starting a PIC_RUN, pad the bitstream with 0xff until 256 bytes
past the next multiple of 256 bytes, if the buffer to be decoded is the
last buffer in the bitstream.
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
---
drivers/media/platform/coda/coda-bit.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c
index d1ecda5..27e0764 100644
--- a/drivers/media/platform/coda/coda-bit.c
+++ b/drivers/media/platform/coda/coda-bit.c
@@ -1625,6 +1625,26 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
coda_write(dev, ctx->iram_info.axi_sram_use,
CODA7_REG_BIT_AXI_SRAM_USE);
+ if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) {
+ struct coda_buffer_meta *meta;
+
+ /* If this is the last buffer in the bitstream, add padding */
+ meta = list_first_entry(&ctx->buffer_meta_list,
+ struct coda_buffer_meta, list);
+ if (meta->end == (ctx->bitstream_fifo.kfifo.in &
+ ctx->bitstream_fifo.kfifo.mask)) {
+ static unsigned char buf[512];
+ unsigned int pad;
+
+ /* Pad to multiple of 256 and then add 256 more */
+ pad = ((0 - meta->end) & 0xff) + 256;
+
+ memset(buf, 0xff, sizeof(buf));
+
+ kfifo_in(&ctx->bitstream_fifo, buf, pad);
+ }
+ }
+
coda_kfifo_sync_to_device_full(ctx);
coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
--
2.1.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 09/10] [media] coda: try to only queue a single JPEG into the bitstream
2014-09-30 9:57 [PATCH 00/10] CODA7 JPEG support Philipp Zabel
` (7 preceding siblings ...)
2014-09-30 9:57 ` [PATCH 08/10] [media] coda: pad input stream for JPEG decoder Philipp Zabel
@ 2014-09-30 9:57 ` Philipp Zabel
2014-09-30 9:57 ` [PATCH 10/10] [media] coda: allow userspace to set compressed buffer size in a certain range Philipp Zabel
2014-09-30 13:43 ` [PATCH 00/10] CODA7 JPEG support Hans Verkuil
10 siblings, 0 replies; 17+ messages in thread
From: Philipp Zabel @ 2014-09-30 9:57 UTC (permalink / raw)
To: Kamil Debski
Cc: Mauro Carvalho Chehab, Hans Verkuil, linux-media, kernel,
Philipp Zabel
With bitstream padding, it is possible to decode a single JPEG in the bitstream
immediately. This allows us to only ever queue a single JPEG into the bitstream
buffer, except to increase payload over 512 bytes or to back out of hold state.
This is a measure to decrease JPEG decoder latency.
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
---
drivers/media/platform/coda/coda-bit.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c
index 27e0764..2a6810e 100644
--- a/drivers/media/platform/coda/coda-bit.c
+++ b/drivers/media/platform/coda/coda-bit.c
@@ -221,6 +221,14 @@ void coda_fill_bitstream(struct coda_ctx *ctx)
u32 start;
while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) {
+ /*
+ * Only queue a single JPEG into the bitstream buffer, except
+ * to increase payload over 512 bytes or if in hold state.
+ */
+ if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG &&
+ (coda_get_bitstream_payload(ctx) >= 512) && !ctx->hold)
+ break;
+
src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
/* Buffer start position */
--
2.1.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 10/10] [media] coda: allow userspace to set compressed buffer size in a certain range
2014-09-30 9:57 [PATCH 00/10] CODA7 JPEG support Philipp Zabel
` (8 preceding siblings ...)
2014-09-30 9:57 ` [PATCH 09/10] [media] coda: try to only queue a single JPEG into the bitstream Philipp Zabel
@ 2014-09-30 9:57 ` Philipp Zabel
2014-09-30 13:43 ` [PATCH 00/10] CODA7 JPEG support Hans Verkuil
10 siblings, 0 replies; 17+ messages in thread
From: Philipp Zabel @ 2014-09-30 9:57 UTC (permalink / raw)
To: Kamil Debski
Cc: Mauro Carvalho Chehab, Hans Verkuil, linux-media, kernel,
Philipp Zabel
For small frame sizes, allocating 1 MiB per compressed buffer is a waste of
space. On the other hand, incompressible 1080p data can produce JPEGs larger
than 1 MiB at higher quality settings. Allow userspace to set the compressed
buffer size and clamp the value to a sensible range.
Also set the initial sizeimage to a value inside the range allowed by try_fmt.
While at it, reduce the default image size to a maximum of 1920*1088 (otherwise
JPEG will default to 8k*8k and 96 MiB buffers).
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
---
drivers/media/platform/coda/coda-bit.c | 4 ++--
drivers/media/platform/coda/coda-common.c | 25 +++++++++++++++++--------
2 files changed, 19 insertions(+), 10 deletions(-)
diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c
index 2a6810e..0c67cfd 100644
--- a/drivers/media/platform/coda/coda-bit.c
+++ b/drivers/media/platform/coda/coda-bit.c
@@ -1129,7 +1129,7 @@ static int coda_prepare_encode(struct coda_ctx *ctx)
ctx->vpu_header_size[0] +
ctx->vpu_header_size[1] +
ctx->vpu_header_size[2];
- pic_stream_buffer_size = CODA_MAX_FRAME_SIZE -
+ pic_stream_buffer_size = q_data_dst->sizeimage -
ctx->vpu_header_size[0] -
ctx->vpu_header_size[1] -
ctx->vpu_header_size[2];
@@ -1143,7 +1143,7 @@ static int coda_prepare_encode(struct coda_ctx *ctx)
} else {
pic_stream_buffer_addr =
vb2_dma_contig_plane_dma_addr(dst_buf, 0);
- pic_stream_buffer_size = CODA_MAX_FRAME_SIZE;
+ pic_stream_buffer_size = q_data_dst->sizeimage;
}
if (src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) {
diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c
index 53791d4..5429e85 100644
--- a/drivers/media/platform/coda/coda-common.c
+++ b/drivers/media/platform/coda/coda-common.c
@@ -529,7 +529,15 @@ static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec,
case V4L2_PIX_FMT_H264:
case V4L2_PIX_FMT_MPEG4:
f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage = CODA_MAX_FRAME_SIZE;
+ /*
+ * This is a rough estimate for sensible compressed buffer
+ * sizes (between 1 and 16 bits per pixel). This could be
+ * improved by better format specific worst case estimates.
+ */
+ f->fmt.pix.sizeimage = round_up(clamp(f->fmt.pix.sizeimage,
+ f->fmt.pix.width * f->fmt.pix.height / 8,
+ f->fmt.pix.width * f->fmt.pix.height * 2),
+ PAGE_SIZE);
break;
default:
BUG();
@@ -1031,12 +1039,13 @@ static void coda_set_tiled_map_type(struct coda_ctx *ctx, int tiled_map_type)
static void set_default_params(struct coda_ctx *ctx)
{
- int max_w, max_h;
+ unsigned int max_w, max_h, size;
ctx->codec = coda_find_codec(ctx->dev, ctx->cvd->src_formats[0],
ctx->cvd->dst_formats[0]);
- max_w = ctx->codec->max_w;
- max_h = ctx->codec->max_h;
+ max_w = min(ctx->codec->max_w, 1920U);
+ max_h = min(ctx->codec->max_h, 1088U);
+ size = max_w * max_h * 3 / 2;
ctx->params.codec_mode = ctx->codec->mode;
ctx->colorspace = V4L2_COLORSPACE_REC709;
@@ -1051,14 +1060,14 @@ static void set_default_params(struct coda_ctx *ctx)
ctx->q_data[V4L2_M2M_DST].height = max_h;
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_SRC].sizeimage = size;
ctx->q_data[V4L2_M2M_DST].bytesperline = 0;
- ctx->q_data[V4L2_M2M_DST].sizeimage = CODA_MAX_FRAME_SIZE;
+ ctx->q_data[V4L2_M2M_DST].sizeimage = round_up(size, PAGE_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_SRC].sizeimage = round_up(size, PAGE_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_DST].sizeimage = size;
}
ctx->q_data[V4L2_M2M_SRC].rect.width = max_w;
ctx->q_data[V4L2_M2M_SRC].rect.height = max_h;
--
2.1.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH 00/10] CODA7 JPEG support
2014-09-30 9:57 [PATCH 00/10] CODA7 JPEG support Philipp Zabel
` (9 preceding siblings ...)
2014-09-30 9:57 ` [PATCH 10/10] [media] coda: allow userspace to set compressed buffer size in a certain range Philipp Zabel
@ 2014-09-30 13:43 ` Hans Verkuil
2014-09-30 14:20 ` Philipp Zabel
10 siblings, 1 reply; 17+ messages in thread
From: Hans Verkuil @ 2014-09-30 13:43 UTC (permalink / raw)
To: Philipp Zabel, Kamil Debski
Cc: Mauro Carvalho Chehab, Hans Verkuil, linux-media, kernel
On 09/30/14 11:57, Philipp Zabel wrote:
> Hi,
>
> These patches add JPEG encoding and decoding support for CODA7541 (i.MX5).
> The encoder video device is split into one video device per codec, so that
> each video device can register only the relevant controls. The H.264/MPEG4
> decoder is kept as one video device, but the JPEG decoder video device is
> separate because it supports more uncompressed formats (currently YUV422P,
> in the future grayscale or YUV 4:4:4 support could be added).
Normally device nodes are linked to DMA engines, so the only reason why you
would have e.g. two video nodes is if you can capture from both at the same
time. Is that the case here as well? If not, then it really should be a
single video node. That not all controls are relevant for the currently
chosen codec is not important.
Are there other reasons than the controls to split it up into multiple video
devices?
Regards,
Hans
>
> regards
> Philipp
>
> Philipp Zabel (10):
> [media] coda: add support for planar YCbCr 4:2:2 (YUV422P) format
> [media] coda: identify platform device earlier
> [media] coda: add coda_video_device descriptors
> [media] coda: split out encoder control setup to specify controls per
> video device
> [media] coda: add JPEG register definitions for CODA7541
> [media] coda: add CODA7541 JPEG support
> [media] coda: store bitstream buffer position with buffer metadata
> [media] coda: pad input stream for JPEG decoder
> [media] coda: try to only queue a single JPEG into the bitstream
> [media] coda: allow userspace to set compressed buffer size in a
> certain range
>
> drivers/media/platform/coda/Makefile | 2 +-
> drivers/media/platform/coda/coda-bit.c | 204 +++++++---
> drivers/media/platform/coda/coda-common.c | 608 +++++++++++++++++++-----------
> drivers/media/platform/coda/coda-jpeg.c | 225 +++++++++++
> drivers/media/platform/coda/coda.h | 21 +-
> drivers/media/platform/coda/coda_regs.h | 7 +
> 6 files changed, 785 insertions(+), 282 deletions(-)
> create mode 100644 drivers/media/platform/coda/coda-jpeg.c
>
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 00/10] CODA7 JPEG support
2014-09-30 13:43 ` [PATCH 00/10] CODA7 JPEG support Hans Verkuil
@ 2014-09-30 14:20 ` Philipp Zabel
2014-09-30 14:24 ` Hans Verkuil
0 siblings, 1 reply; 17+ messages in thread
From: Philipp Zabel @ 2014-09-30 14:20 UTC (permalink / raw)
To: Hans Verkuil
Cc: Kamil Debski, Mauro Carvalho Chehab, Hans Verkuil, linux-media,
kernel
Hi Hans,
Am Dienstag, den 30.09.2014, 15:43 +0200 schrieb Hans Verkuil:
> On 09/30/14 11:57, Philipp Zabel wrote:
> > Hi,
> >
> > These patches add JPEG encoding and decoding support for CODA7541 (i.MX5).
> > The encoder video device is split into one video device per codec, so that
> > each video device can register only the relevant controls. The H.264/MPEG4
> > decoder is kept as one video device, but the JPEG decoder video device is
> > separate because it supports more uncompressed formats (currently YUV422P,
> > in the future grayscale or YUV 4:4:4 support could be added).
>
> Normally device nodes are linked to DMA engines, so the only reason why you
> would have e.g. two video nodes is if you can capture from both at the same
> time. Is that the case here as well? If not, then it really should be a
> single video node. That not all controls are relevant for the currently
> chosen codec is not important.
>
> Are there other reasons than the controls to split it up into multiple video
> devices?
I had already split the encoder and decoder parts of this mem2mem device
into two video devices because of the issue of changing available
capture formats depending on the selected output format.
The motivation for splitting the JPEG codecs from the H264/MPEG4 codecs
is the same: to avoid the appearing and disappearing of the YUV422P
format on the uncompressed side whenever the compressed format changes
between JPEG and H264/MPEG4. I could keep the H264 and MPEG4 encoders
combined without running into this issue.
Furthermore, I want to change the output queue for the currently
available decoders to use vb2-vmalloc eventually (because the CPU has to
copy incoming frames into the bitstream buffer), but have to keep using
vb2-dma-contig for the CODA960 JPEG decoder, which will have the
hardware read from the incoming buffers directly.
regards
Philipp
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 00/10] CODA7 JPEG support
2014-09-30 14:20 ` Philipp Zabel
@ 2014-09-30 14:24 ` Hans Verkuil
2014-09-30 14:34 ` Kamil Debski
0 siblings, 1 reply; 17+ messages in thread
From: Hans Verkuil @ 2014-09-30 14:24 UTC (permalink / raw)
To: Philipp Zabel
Cc: Kamil Debski, Mauro Carvalho Chehab, Hans Verkuil, linux-media,
kernel
On 09/30/14 16:20, Philipp Zabel wrote:
> Hi Hans,
>
> Am Dienstag, den 30.09.2014, 15:43 +0200 schrieb Hans Verkuil:
>> On 09/30/14 11:57, Philipp Zabel wrote:
>>> Hi,
>>>
>>> These patches add JPEG encoding and decoding support for CODA7541 (i.MX5).
>>> The encoder video device is split into one video device per codec, so that
>>> each video device can register only the relevant controls. The H.264/MPEG4
>>> decoder is kept as one video device, but the JPEG decoder video device is
>>> separate because it supports more uncompressed formats (currently YUV422P,
>>> in the future grayscale or YUV 4:4:4 support could be added).
>>
>> Normally device nodes are linked to DMA engines, so the only reason why you
>> would have e.g. two video nodes is if you can capture from both at the same
>> time. Is that the case here as well? If not, then it really should be a
>> single video node. That not all controls are relevant for the currently
>> chosen codec is not important.
>>
>> Are there other reasons than the controls to split it up into multiple video
>> devices?
>
> I had already split the encoder and decoder parts of this mem2mem device
> into two video devices because of the issue of changing available
> capture formats depending on the selected output format.
> The motivation for splitting the JPEG codecs from the H264/MPEG4 codecs
> is the same: to avoid the appearing and disappearing of the YUV422P
> format on the uncompressed side whenever the compressed format changes
> between JPEG and H264/MPEG4. I could keep the H264 and MPEG4 encoders
> combined without running into this issue.
>
> Furthermore, I want to change the output queue for the currently
> available decoders to use vb2-vmalloc eventually (because the CPU has to
> copy incoming frames into the bitstream buffer), but have to keep using
> vb2-dma-contig for the CODA960 JPEG decoder, which will have the
> hardware read from the incoming buffers directly.
Based on this description I think it makes sense to split off the JPEG
encoder, but I would keep H264/MPEG4 together. Kamil, what's your opinion
on this?
Regards,
Hans
^ permalink raw reply [flat|nested] 17+ messages in thread
* RE: [PATCH 00/10] CODA7 JPEG support
2014-09-30 14:24 ` Hans Verkuil
@ 2014-09-30 14:34 ` Kamil Debski
2014-10-01 13:33 ` Nicolas Dufresne
0 siblings, 1 reply; 17+ messages in thread
From: Kamil Debski @ 2014-09-30 14:34 UTC (permalink / raw)
To: 'Hans Verkuil', 'Philipp Zabel'
Cc: 'Mauro Carvalho Chehab', 'Hans Verkuil',
linux-media, kernel
Hi,
> From: Hans Verkuil [mailto:hverkuil@xs4all.nl]
> Sent: Tuesday, September 30, 2014 4:25 PM
> To: Philipp Zabel
> Cc: Kamil Debski; Mauro Carvalho Chehab; Hans Verkuil; linux-
> media@vger.kernel.org; kernel@pengutronix.de
> Subject: Re: [PATCH 00/10] CODA7 JPEG support
>
> On 09/30/14 16:20, Philipp Zabel wrote:
> > Hi Hans,
> >
> > Am Dienstag, den 30.09.2014, 15:43 +0200 schrieb Hans Verkuil:
> >> On 09/30/14 11:57, Philipp Zabel wrote:
> >>> Hi,
> >>>
> >>> These patches add JPEG encoding and decoding support for CODA7541
> (i.MX5).
> >>> The encoder video device is split into one video device per codec,
> >>> so that each video device can register only the relevant controls.
> >>> The H.264/MPEG4 decoder is kept as one video device, but the JPEG
> >>> decoder video device is separate because it supports more
> >>> uncompressed formats (currently YUV422P, in the future grayscale or
> YUV 4:4:4 support could be added).
> >>
> >> Normally device nodes are linked to DMA engines, so the only reason
> >> why you would have e.g. two video nodes is if you can capture from
> >> both at the same time. Is that the case here as well? If not, then
> it
> >> really should be a single video node. That not all controls are
> >> relevant for the currently chosen codec is not important.
> >>
> >> Are there other reasons than the controls to split it up into
> >> multiple video devices?
> >
> > I had already split the encoder and decoder parts of this mem2mem
> > device into two video devices because of the issue of changing
> > available capture formats depending on the selected output format.
> > The motivation for splitting the JPEG codecs from the H264/MPEG4
> > codecs is the same: to avoid the appearing and disappearing of the
> > YUV422P format on the uncompressed side whenever the compressed
> format
> > changes between JPEG and H264/MPEG4. I could keep the H264 and MPEG4
> > encoders combined without running into this issue.
> >
> > Furthermore, I want to change the output queue for the currently
> > available decoders to use vb2-vmalloc eventually (because the CPU has
> > to copy incoming frames into the bitstream buffer), but have to keep
> > using vb2-dma-contig for the CODA960 JPEG decoder, which will have
> the
> > hardware read from the incoming buffers directly.
>
> Based on this description I think it makes sense to split off the JPEG
> encoder, but I would keep H264/MPEG4 together. Kamil, what's your
> opinion on this?
I agree with you Hans. MFC has a single encoder node that supports multiple
codecs and I think this design works well.
JPEG should be separated into separate device.
Best wishes,
--
Kamil Debski
Samsung R&D Institute Poland
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 00/10] CODA7 JPEG support
2014-09-30 14:34 ` Kamil Debski
@ 2014-10-01 13:33 ` Nicolas Dufresne
2014-10-01 15:40 ` Philipp Zabel
0 siblings, 1 reply; 17+ messages in thread
From: Nicolas Dufresne @ 2014-10-01 13:33 UTC (permalink / raw)
To: Kamil Debski, 'Hans Verkuil', 'Philipp Zabel'
Cc: 'Mauro Carvalho Chehab', 'Hans Verkuil',
linux-media, kernel
Le 2014-09-30 10:34, Kamil Debski a écrit :
> I agree with you Hans. MFC has a single encoder node that supports multiple
> codecs and I think this design works well.
>
> JPEG should be separated into separate device.
Having combined encoders and combines decoders works well from
application / gstreamer point of view too. It's only combine encoder and
decoder that causes issues with our ability to probe what the HW is
capable (without a need to know about the platform). Exynos has split
JPEG decoder because it's not the same HW backing it.
cheers,
Nicolas
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 00/10] CODA7 JPEG support
2014-10-01 13:33 ` Nicolas Dufresne
@ 2014-10-01 15:40 ` Philipp Zabel
0 siblings, 0 replies; 17+ messages in thread
From: Philipp Zabel @ 2014-10-01 15:40 UTC (permalink / raw)
To: Nicolas Dufresne
Cc: Kamil Debski, 'Hans Verkuil',
'Mauro Carvalho Chehab', 'Hans Verkuil',
linux-media, kernel
Am Mittwoch, den 01.10.2014, 09:33 -0400 schrieb Nicolas Dufresne:
> Le 2014-09-30 10:34, Kamil Debski a écrit :
> > I agree with you Hans. MFC has a single encoder node that supports multiple
> > codecs and I think this design works well.
> >
> > JPEG should be separated into separate device.
> Having combined encoders and combines decoders works well from
> application / gstreamer point of view too. It's only combine encoder and
> decoder that causes issues with our ability to probe what the HW is
> capable (without a need to know about the platform). Exynos has split
> JPEG decoder because it's not the same HW backing it.
Alright, I'll merge the H.264 and MPEG4 encoder devices again and resend
the series tomorrow.
thanks
Philipp
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2014-10-01 15:40 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-09-30 9:57 [PATCH 00/10] CODA7 JPEG support Philipp Zabel
2014-09-30 9:57 ` [PATCH 01/10] [media] coda: add support for planar YCbCr 4:2:2 (YUV422P) format Philipp Zabel
2014-09-30 9:57 ` [PATCH 02/10] [media] coda: identify platform device earlier Philipp Zabel
2014-09-30 9:57 ` [PATCH 03/10] [media] coda: add coda_video_device descriptors Philipp Zabel
2014-09-30 9:57 ` [PATCH 04/10] [media] coda: split out encoder control setup to specify controls per video device Philipp Zabel
2014-09-30 9:57 ` [PATCH 05/10] [media] coda: add JPEG register definitions for CODA7541 Philipp Zabel
2014-09-30 9:57 ` [PATCH 06/10] [media] coda: add CODA7541 JPEG support Philipp Zabel
2014-09-30 9:57 ` [PATCH 07/10] [media] coda: store bitstream buffer position with buffer metadata Philipp Zabel
2014-09-30 9:57 ` [PATCH 08/10] [media] coda: pad input stream for JPEG decoder Philipp Zabel
2014-09-30 9:57 ` [PATCH 09/10] [media] coda: try to only queue a single JPEG into the bitstream Philipp Zabel
2014-09-30 9:57 ` [PATCH 10/10] [media] coda: allow userspace to set compressed buffer size in a certain range Philipp Zabel
2014-09-30 13:43 ` [PATCH 00/10] CODA7 JPEG support Hans Verkuil
2014-09-30 14:20 ` Philipp Zabel
2014-09-30 14:24 ` Hans Verkuil
2014-09-30 14:34 ` Kamil Debski
2014-10-01 13:33 ` Nicolas Dufresne
2014-10-01 15:40 ` Philipp Zabel
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).