int bytesperline_align;
u32 flags;
u32 mmal_fmt;
- bool decode_only;
- bool encode_only;
int size_multiplier_x2;
};
-/* Supported raw pixel formats. Those supported for both encode and decode
- * must come first, with those only supported for decode coming after (there
- * are no formats supported for encode only).
- */
-static struct bcm2835_codec_fmt raw_formats[] = {
+static const struct bcm2835_codec_fmt supported_formats[] = {
{
+ /* YUV formats */
.fourcc = V4L2_PIX_FMT_YUV420,
.depth = 8,
.bytesperline_align = 32,
.bytesperline_align = 32,
.flags = 0,
.mmal_fmt = MMAL_ENCODING_YUYV,
- .encode_only = true,
.size_multiplier_x2 = 2,
}, {
.fourcc = V4L2_PIX_FMT_UYVY,
.bytesperline_align = 32,
.flags = 0,
.mmal_fmt = MMAL_ENCODING_UYVY,
- .encode_only = true,
.size_multiplier_x2 = 2,
}, {
.fourcc = V4L2_PIX_FMT_YVYU,
.bytesperline_align = 32,
.flags = 0,
.mmal_fmt = MMAL_ENCODING_YVYU,
- .encode_only = true,
.size_multiplier_x2 = 2,
}, {
.fourcc = V4L2_PIX_FMT_VYUY,
.bytesperline_align = 32,
.flags = 0,
.mmal_fmt = MMAL_ENCODING_VYUY,
- .encode_only = true,
.size_multiplier_x2 = 2,
}, {
+ /* RGB formats */
.fourcc = V4L2_PIX_FMT_RGB24,
.depth = 24,
.bytesperline_align = 32,
.flags = 0,
.mmal_fmt = MMAL_ENCODING_RGB24,
- .encode_only = true,
.size_multiplier_x2 = 2,
}, {
.fourcc = V4L2_PIX_FMT_BGR24,
.bytesperline_align = 32,
.flags = 0,
.mmal_fmt = MMAL_ENCODING_BGR24,
- .encode_only = true,
.size_multiplier_x2 = 2,
}, {
.fourcc = V4L2_PIX_FMT_BGR32,
.bytesperline_align = 32,
.flags = 0,
.mmal_fmt = MMAL_ENCODING_BGRA,
- .encode_only = true,
.size_multiplier_x2 = 2,
- },
-};
-
-/* Supported encoded formats. Those supported for both encode and decode
- * must come first, with those only supported for decode coming after (there
- * are no formats supported for encode only).
- */
-static struct bcm2835_codec_fmt encoded_formats[] = {
- {
+ }, {
+ /* Bayer formats */
+ /* 8 bit */
+ .fourcc = V4L2_PIX_FMT_SRGGB8,
+ .depth = 8,
+ .bytesperline_align = 32,
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB8,
+ .size_multiplier_x2 = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SBGGR8,
+ .depth = 8,
+ .bytesperline_align = 32,
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR8,
+ .size_multiplier_x2 = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGRBG8,
+ .depth = 8,
+ .bytesperline_align = 32,
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG8,
+ .size_multiplier_x2 = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGBRG8,
+ .depth = 8,
+ .bytesperline_align = 32,
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG8,
+ .size_multiplier_x2 = 2,
+ }, {
+ /* 10 bit */
+ .fourcc = V4L2_PIX_FMT_SRGGB10P,
+ .depth = 10,
+ .bytesperline_align = 32,
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB10P,
+ .size_multiplier_x2 = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SBGGR10P,
+ .depth = 10,
+ .bytesperline_align = 32,
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR10P,
+ .size_multiplier_x2 = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGRBG10P,
+ .depth = 10,
+ .bytesperline_align = 32,
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG10P,
+ .size_multiplier_x2 = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGBRG10P,
+ .depth = 10,
+ .bytesperline_align = 32,
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG10P,
+ .size_multiplier_x2 = 2,
+ }, {
+ /* 12 bit */
+ .fourcc = V4L2_PIX_FMT_SRGGB12P,
+ .depth = 12,
+ .bytesperline_align = 32,
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB12P,
+ .size_multiplier_x2 = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SBGGR12P,
+ .depth = 12,
+ .bytesperline_align = 32,
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR12P,
+ .size_multiplier_x2 = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGRBG12P,
+ .depth = 12,
+ .bytesperline_align = 32,
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG12P,
+ .size_multiplier_x2 = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGBRG12P,
+ .depth = 12,
+ .bytesperline_align = 32,
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG12P,
+ .size_multiplier_x2 = 2,
+ }, {
+ /* 16 bit */
+ .fourcc = V4L2_PIX_FMT_SRGGB16,
+ .depth = 16,
+ .bytesperline_align = 32,
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB16,
+ .size_multiplier_x2 = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SBGGR16,
+ .depth = 16,
+ .bytesperline_align = 32,
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR16,
+ .size_multiplier_x2 = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGRBG16,
+ .depth = 16,
+ .bytesperline_align = 32,
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG16,
+ .size_multiplier_x2 = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGBRG16,
+ .depth = 16,
+ .bytesperline_align = 32,
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG16,
+ .size_multiplier_x2 = 2,
+ }, {
+ /* Compressed formats */
.fourcc = V4L2_PIX_FMT_H264,
.depth = 0,
.flags = V4L2_FMT_FLAG_COMPRESSED,
.depth = 0,
.flags = V4L2_FMT_FLAG_COMPRESSED,
.mmal_fmt = MMAL_ENCODING_MP4V,
- .decode_only = true,
}, {
.fourcc = V4L2_PIX_FMT_H263,
.depth = 0,
.flags = V4L2_FMT_FLAG_COMPRESSED,
.mmal_fmt = MMAL_ENCODING_H263,
- .decode_only = true,
}, {
.fourcc = V4L2_PIX_FMT_MPEG2,
.depth = 0,
.flags = V4L2_FMT_FLAG_COMPRESSED,
.mmal_fmt = MMAL_ENCODING_MP2V,
- .decode_only = true,
}, {
.fourcc = V4L2_PIX_FMT_VP8,
.depth = 0,
.flags = V4L2_FMT_FLAG_COMPRESSED,
.mmal_fmt = MMAL_ENCODING_VP8,
- .decode_only = true,
},
- /*
- * This list couold include VP6 and Theorafor decode, but V4L2 doesn't
- * support them.
- */
};
struct bcm2835_codec_fmt_list {
unsigned int num_entries;
};
-#define RAW_LIST 0
-#define ENCODED_LIST 1
-
-struct bcm2835_codec_fmt_list formats[] = {
- {
- .list = raw_formats,
- .num_entries = ARRAY_SIZE(raw_formats),
- }, {
- .list = encoded_formats,
- .num_entries = ARRAY_SIZE(encoded_formats),
- },
-};
-
struct m2m_mmal_buffer {
struct v4l2_m2m_buffer m2m;
struct mmal_buffer mmal;
bool eos_buffer_in_use; /* debug only */
};
-enum {
- V4L2_M2M_SRC = 0,
- V4L2_M2M_DST = 1,
-};
-
-static inline struct bcm2835_codec_fmt_list *get_format_list(bool decode,
- bool capture)
-{
- return decode ^ capture ? &formats[ENCODED_LIST] : &formats[RAW_LIST];
-}
-
-static struct bcm2835_codec_fmt *get_default_format(bool decode, bool capture)
-{
- return &get_format_list(decode, capture)->list[0];
-}
-
-static struct bcm2835_codec_fmt *find_format(struct v4l2_format *f, bool decode,
- bool capture)
-{
- struct bcm2835_codec_fmt *fmt;
- unsigned int k;
- struct bcm2835_codec_fmt_list *fmts = get_format_list(decode, capture);
-
- for (k = 0; k < fmts->num_entries; k++) {
- fmt = &fmts->list[k];
- if (fmt->fourcc == f->fmt.pix.pixelformat)
- break;
- }
-
- /*
- * Some compressed formats are only supported for decoding, not
- * encoding.
- */
- if (!decode && fmts->list[k].decode_only)
- return NULL;
-
- /* Some pixel formats are only supported for encoding, not decoding. */
- if (decode && fmts->list[k].encode_only)
- return NULL;
-
- if (k == fmts->num_entries)
- return NULL;
-
- return &fmts->list[k];
-}
-
struct bcm2835_codec_dev {
struct platform_device *pdev;
/* allocated mmal instance and components */
bool decode; /* Is this instance a decoder? */
+ /* The list of formats supported on input and output queues. */
+ struct bcm2835_codec_fmt_list supported_fmts[2];
+
struct vchiq_mmal_instance *instance;
struct v4l2_m2m_dev *m2m_dev;
struct bcm2835_codec_driver {
struct bcm2835_codec_dev *encode;
struct bcm2835_codec_dev *decode;
+ struct bcm2835_codec_dev *isp;
+};
+
+enum {
+ V4L2_M2M_SRC = 0,
+ V4L2_M2M_DST = 1,
};
+static const struct bcm2835_codec_fmt *get_fmt(u32 mmal_fmt)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(supported_formats); i++) {
+ if (supported_formats[i].mmal_fmt == mmal_fmt)
+ return &supported_formats[i];
+ }
+ return NULL;
+}
+
+static inline
+struct bcm2835_codec_fmt_list *get_format_list(struct bcm2835_codec_dev *dev,
+ bool capture)
+{
+ return &dev->supported_fmts[capture ? 1 : 0];
+}
+
+static
+struct bcm2835_codec_fmt *get_default_format(struct bcm2835_codec_dev *dev,
+ bool capture)
+{
+ return &dev->supported_fmts[capture ? 1 : 0].list[0];
+}
+
+static struct bcm2835_codec_fmt *find_format(struct v4l2_format *f,
+ struct bcm2835_codec_dev *dev,
+ bool capture)
+{
+ struct bcm2835_codec_fmt *fmt;
+ unsigned int k;
+ struct bcm2835_codec_fmt_list *fmts =
+ &dev->supported_fmts[capture ? 1 : 0];
+
+ for (k = 0; k < fmts->num_entries; k++) {
+ fmt = &fmts->list[k];
+ if (fmt->fourcc == f->fmt.pix.pixelformat)
+ break;
+ }
+ if (k == fmts->num_entries)
+ return NULL;
+
+ return &fmts->list[k];
+}
+
static inline struct bcm2835_codec_ctx *file2ctx(struct file *file)
{
return container_of(file->private_data, struct bcm2835_codec_ctx, fh);
}
static void setup_mmal_port_format(struct bcm2835_codec_ctx *ctx,
- bool decode,
struct bcm2835_codec_q_data *q_data,
struct vchiq_mmal_port *port)
{
port->es.video.frame_rate.den = 1;
} else {
/* Compressed format - leave resolution as 0 for decode */
- if (decode) {
+ if (ctx->dev->decode) {
port->es.video.width = 0;
port->es.video.height = 0;
port->es.video.crop.width = 0;
return 0;
}
-static int enum_fmt(struct v4l2_fmtdesc *f, bool decode, bool capture)
+static int enum_fmt(struct v4l2_fmtdesc *f, struct bcm2835_codec_ctx *ctx,
+ bool capture)
{
struct bcm2835_codec_fmt *fmt;
- struct bcm2835_codec_fmt_list *fmts = get_format_list(decode, capture);
+ struct bcm2835_codec_fmt_list *fmts =
+ get_format_list(ctx->dev, capture);
if (f->index < fmts->num_entries) {
/* Format found */
- /* Check format isn't a decode only format when encoding */
- if (!decode &&
- fmts->list[f->index].decode_only)
- return -EINVAL;
- /* Check format isn't a decode only format when encoding */
- if (decode &&
- fmts->list[f->index].encode_only)
- return -EINVAL;
-
fmt = &fmts->list[f->index];
f->pixelformat = fmt->fourcc;
f->flags = fmt->flags;
{
struct bcm2835_codec_ctx *ctx = file2ctx(file);
- return enum_fmt(f, ctx->dev->decode, true);
+ return enum_fmt(f, ctx, true);
}
static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
{
struct bcm2835_codec_ctx *ctx = file2ctx(file);
- return enum_fmt(f, ctx->dev->decode, false);
+ return enum_fmt(f, ctx, false);
}
static int vidioc_g_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f)
struct bcm2835_codec_fmt *fmt;
struct bcm2835_codec_ctx *ctx = file2ctx(file);
- fmt = find_format(f, ctx->dev->decode, true);
+ fmt = find_format(f, ctx->dev, true);
if (!fmt) {
- f->fmt.pix.pixelformat = get_default_format(ctx->dev->decode,
+ f->fmt.pix.pixelformat = get_default_format(ctx->dev,
true)->fourcc;
- fmt = find_format(f, ctx->dev->decode, true);
+ fmt = find_format(f, ctx->dev, true);
}
return vidioc_try_fmt(f, fmt);
struct bcm2835_codec_fmt *fmt;
struct bcm2835_codec_ctx *ctx = file2ctx(file);
- fmt = find_format(f, ctx->dev->decode, false);
+ fmt = find_format(f, ctx->dev, false);
if (!fmt) {
- f->fmt.pix.pixelformat = get_default_format(ctx->dev->decode,
+ f->fmt.pix.pixelformat = get_default_format(ctx->dev,
false)->fourcc;
- fmt = find_format(f, ctx->dev->decode, false);
+ fmt = find_format(f, ctx->dev, false);
}
if (!f->fmt.pix.colorspace)
return -EBUSY;
}
- q_data->fmt = find_format(f, ctx->dev->decode,
+ q_data->fmt = find_format(f, ctx->dev,
f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE);
q_data->crop_width = f->fmt.pix.width;
q_data->height = f->fmt.pix.height;
if (!port)
return 0;
- setup_mmal_port_format(ctx, ctx->dev->decode, q_data, port);
+ setup_mmal_port_format(ctx, q_data, port);
ret = vchiq_mmal_port_set_format(ctx->dev->instance, port);
if (ret) {
v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed vchiq_mmal_port_set_format on port, ret %d\n",
struct bcm2835_codec_q_data *q_data_dst =
&ctx->q_data[V4L2_M2M_DST];
- setup_mmal_port_format(ctx, ctx->dev->decode, q_data_dst,
- port_dst);
+ setup_mmal_port_format(ctx, q_data_dst, port_dst);
ret = vchiq_mmal_port_set_format(ctx->dev->instance, port_dst);
if (ret) {
v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed vchiq_mmal_port_set_format on output port, ret %d\n",
MMAL_PARAMETER_ZERO_COPY, &enable,
sizeof(enable));
- setup_mmal_port_format(ctx, dev->decode, &ctx->q_data[V4L2_M2M_SRC],
+ setup_mmal_port_format(ctx, &ctx->q_data[V4L2_M2M_SRC],
&ctx->component->input[0]);
- setup_mmal_port_format(ctx, dev->decode, &ctx->q_data[V4L2_M2M_DST],
+ setup_mmal_port_format(ctx, &ctx->q_data[V4L2_M2M_DST],
&ctx->component->output[0]);
ret = vchiq_mmal_port_set_format(dev->instance,
goto open_unlock;
}
- ctx->q_data[V4L2_M2M_SRC].fmt = get_default_format(dev->decode, false);
- ctx->q_data[V4L2_M2M_DST].fmt = get_default_format(dev->decode, true);
+ ctx->q_data[V4L2_M2M_SRC].fmt = get_default_format(dev, false);
+ ctx->q_data[V4L2_M2M_DST].fmt = get_default_format(dev, true);
if (dev->decode) {
/*
* Input width and height are irrelevant as they will be defined
.job_abort = job_abort,
};
+/* Size of the array to provide to the VPU when asking for the list of supported
+ * formats.
+ * The ISP component currently advertises 33 input formats, so add a small
+ * overhead on that.
+ */
+#define MAX_SUPPORTED_ENCODINGS 40
+
+/* Populate dev->supported_fmts with the formats supported by those ports. */
+static int bcm2835_codec_get_supported_fmts(struct bcm2835_codec_dev *dev)
+{
+ struct bcm2835_codec_fmt *list;
+ struct vchiq_mmal_component *component;
+ u32 fourccs[MAX_SUPPORTED_ENCODINGS];
+ u32 param_size = sizeof(fourccs);
+ unsigned int i, j, num_encodings;
+ int ret;
+
+ ret = vchiq_mmal_component_init(dev->instance,
+ dev->decode ?
+ "ril.video_decode" :
+ "ril.video_encode",
+ &component);
+ if (ret < 0) {
+ v4l2_err(&dev->v4l2_dev, "%s: failed to create component\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ ret = vchiq_mmal_port_parameter_get(dev->instance,
+ &component->input[0],
+ MMAL_PARAMETER_SUPPORTED_ENCODINGS,
+ &fourccs,
+ ¶m_size);
+
+ if (ret) {
+ if (ret == MMAL_MSG_STATUS_ENOSPC) {
+ v4l2_err(&dev->v4l2_dev, "%s: port has more encoding than we provided space for. Some are dropped.\n",
+ __func__);
+ num_encodings = MAX_SUPPORTED_ENCODINGS;
+ } else {
+ v4l2_err(&dev->v4l2_dev, "%s: get_param ret %u.\n",
+ __func__, ret);
+ ret = -EINVAL;
+ goto destroy_component;
+ }
+ } else {
+ num_encodings = param_size / sizeof(u32);
+ }
+
+ /* Assume at this stage that all encodings will be supported in V4L2.
+ * Any that aren't supported will waste a very small amount of memory.
+ */
+ list = devm_kzalloc(&dev->pdev->dev,
+ sizeof(struct bcm2835_codec_fmt) * num_encodings,
+ GFP_KERNEL);
+ if (!list) {
+ ret = -ENOMEM;
+ goto destroy_component;
+ }
+ dev->supported_fmts[0].list = list;
+
+ for (i = 0, j = 0; i < num_encodings; i++) {
+ const struct bcm2835_codec_fmt *fmt = get_fmt(fourccs[i]);
+
+ if (fmt) {
+ list[j] = *fmt;
+ j++;
+ }
+ }
+ dev->supported_fmts[0].num_entries = j;
+
+ param_size = sizeof(fourccs);
+ ret = vchiq_mmal_port_parameter_get(dev->instance,
+ &component->output[0],
+ MMAL_PARAMETER_SUPPORTED_ENCODINGS,
+ &fourccs,
+ ¶m_size);
+
+ if (ret) {
+ if (ret == MMAL_MSG_STATUS_ENOSPC) {
+ v4l2_err(&dev->v4l2_dev, "%s: port has more encoding than we provided space for. Some are dropped.\n",
+ __func__);
+ num_encodings = MAX_SUPPORTED_ENCODINGS;
+ } else {
+ ret = -EINVAL;
+ goto destroy_component;
+ }
+ } else {
+ num_encodings = param_size / sizeof(u32);
+ }
+ /* Assume at this stage that all encodings will be supported in V4L2. */
+ list = devm_kzalloc(&dev->pdev->dev,
+ sizeof(struct bcm2835_codec_fmt) * num_encodings,
+ GFP_KERNEL);
+ if (!list) {
+ ret = -ENOMEM;
+ goto destroy_component;
+ }
+ dev->supported_fmts[1].list = list;
+
+ for (i = 0, j = 0; i < num_encodings; i++) {
+ const struct bcm2835_codec_fmt *fmt = get_fmt(fourccs[i]);
+
+ if (fmt) {
+ list[j] = *fmt;
+ j++;
+ }
+ }
+ dev->supported_fmts[1].num_entries = j;
+
+ ret = 0;
+
+destroy_component:
+ vchiq_mmal_component_finalise(dev->instance, component);
+
+ return ret;
+}
+
static int bcm2835_codec_create(struct platform_device *pdev,
struct bcm2835_codec_dev **new_dev,
bool decode)
{
struct bcm2835_codec_dev *dev;
struct video_device *vfd;
- struct vchiq_mmal_instance *instance = NULL;
int video_nr;
int ret;
dev->decode = decode;
- ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+ ret = vchiq_mmal_init(&dev->instance);
if (ret)
return ret;
+ ret = bcm2835_codec_get_supported_fmts(dev);
+ if (ret)
+ goto vchiq_finalise;
+
+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+ if (ret)
+ goto vchiq_finalise;
+
atomic_set(&dev->num_inst, 0);
mutex_init(&dev->dev_mutex);
goto err_m2m;
}
- ret = vchiq_mmal_init(&instance);
- if (ret < 0)
- goto err_m2m;
- dev->instance = instance;
-
- v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s codec\n",
+ v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s\n",
dev->decode ? "decode" : "encode");
return 0;
video_unregister_device(&dev->vfd);
unreg_dev:
v4l2_device_unregister(&dev->v4l2_dev);
-
+vchiq_finalise:
+ vchiq_mmal_finalise(dev->instance);
return ret;
}
v4l2_m2m_release(dev->m2m_dev);
video_unregister_device(&dev->vfd);
v4l2_device_unregister(&dev->v4l2_dev);
+ vchiq_mmal_finalise(dev->instance);
return 0;
}