1 From 2758fab4321519446fe5444769b6257dd18e794b Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.org>
3 Date: Tue, 25 Sep 2018 14:53:49 +0100
4 Subject: [PATCH] staging: vc04_services: Add a V4L2 M2M codec driver
6 This adds a V4L2 memory to memory device that wraps the MMAL
7 video decode and video_encode components for H264 and MJPEG encode
8 and decode, MPEG4, H263, and VP8 decode (and MPEG2 decode
9 if the appropriate licence has been purchased).
11 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
13 drivers/staging/vc04_services/Kconfig | 1 +
14 drivers/staging/vc04_services/Makefile | 9 +-
15 .../vc04_services/bcm2835-codec/Kconfig | 11 +
16 .../vc04_services/bcm2835-codec/Makefile | 8 +
17 .../staging/vc04_services/bcm2835-codec/TODO | 24 +
18 .../bcm2835-codec/bcm2835-v4l2-codec.c | 2359 +++++++++++++++++
19 6 files changed, 2408 insertions(+), 4 deletions(-)
20 create mode 100644 drivers/staging/vc04_services/bcm2835-codec/Kconfig
21 create mode 100644 drivers/staging/vc04_services/bcm2835-codec/Makefile
22 create mode 100644 drivers/staging/vc04_services/bcm2835-codec/TODO
23 create mode 100644 drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
25 --- a/drivers/staging/vc04_services/Kconfig
26 +++ b/drivers/staging/vc04_services/Kconfig
27 @@ -23,6 +23,7 @@ source "drivers/staging/vc04_services/bc
28 source "drivers/staging/vc04_services/bcm2835-camera/Kconfig"
29 source "drivers/staging/vc04_services/vchiq-mmal/Kconfig"
30 source "drivers/staging/vc04_services/vc-sm-cma/Kconfig"
31 +source "drivers/staging/vc04_services/bcm2835-codec/Kconfig"
35 --- a/drivers/staging/vc04_services/Makefile
36 +++ b/drivers/staging/vc04_services/Makefile
37 @@ -10,10 +10,11 @@ vchiq-objs := \
38 interface/vchiq_arm/vchiq_util.o \
39 interface/vchiq_arm/vchiq_connected.o \
41 -obj-$(CONFIG_SND_BCM2835) += bcm2835-audio/
42 -obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-camera/
43 -obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += vchiq-mmal/
44 -obj-$(CONFIG_BCM_VC_SM_CMA) += vc-sm-cma/
45 +obj-$(CONFIG_SND_BCM2835) += bcm2835-audio/
46 +obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-camera/
47 +obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += vchiq-mmal/
48 +obj-$(CONFIG_BCM_VC_SM_CMA) += vc-sm-cma/
49 +obj-$(CONFIG_VIDEO_CODEC_BCM2835) += bcm2835-codec/
51 ccflags-y += -Idrivers/staging/vc04_services -D__VCCOREVER__=0x04000000
54 +++ b/drivers/staging/vc04_services/bcm2835-codec/Kconfig
56 +config VIDEO_CODEC_BCM2835
57 + tristate "BCM2835 Video codec support"
58 + depends on MEDIA_SUPPORT
59 + depends on VIDEO_V4L2 && (ARCH_BCM2835 || COMPILE_TEST)
60 + select BCM2835_VCHIQ_MMAL
61 + select VIDEOBUF2_DMA_CONTIG
62 + select V4L2_MEM2MEM_DEV
64 + Say Y here to enable the V4L2 video codecs for
65 + Broadcom BCM2835 SoC. This operates over the VCHIQ interface
66 + to a service running on VideoCore.
68 +++ b/drivers/staging/vc04_services/bcm2835-codec/Makefile
70 +# SPDX-License-Identifier: GPL-2.0
71 +bcm2835-codec-objs := bcm2835-v4l2-codec.o
73 +obj-$(CONFIG_VIDEO_CODEC_BCM2835) += bcm2835-codec.o
76 + -Idrivers/staging/vc04_services \
77 + -D__VCCOREVER__=0x04000000
79 +++ b/drivers/staging/vc04_services/bcm2835-codec/TODO
81 +1) Convert to be a platform driver.
83 +Right now when the module probes, it tries to initialize VCHI and
84 +errors out if it wasn't ready yet. If bcm2835-v4l2 was built in, then
85 +VCHI generally isn't ready because it depends on both the firmware and
86 +mailbox drivers having already loaded.
88 +We should have VCHI create a platform device once it's initialized,
89 +and have this driver bind to it, so that we automatically load the
90 +v4l2 module after VCHI loads.
92 +2) Support SELECTION API to define crop region on the image for encode.
94 +Particularly for resolutions that aren't a multiple of the macroblock
95 +size, the codec will report a resolution that is a multiple of the macroblock
96 +size (it has to have the memory to decode into), and then a different crop
97 +region within that buffer.
98 +The most common example is 1080P, where the buffer will be 1920x1088 with a
99 +crop region of 1920x1080.
101 +3) Refactor so that the component creation is only on queue_setup, not open.
103 +Fixes v4l2-compliance failure on trying to open 100 instances of the
105 \ No newline at end of file
107 +++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
109 +// SPDX-License-Identifier: GPL-2.0
112 + * A v4l2-mem2mem device that wraps the video codec MMAL component.
114 + * Copyright 2018 Raspberry Pi (Trading) Ltd.
115 + * Author: Dave Stevenson (dave.stevenson@raspberrypi.org)
117 + * Loosely based on the vim2m virtual driver by Pawel Osciak
118 + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
119 + * Pawel Osciak, <pawel@osciak.com>
120 + * Marek Szyprowski, <m.szyprowski@samsung.com>
122 + * Whilst this driver uses the v4l2_mem2mem framework, it does not need the
123 + * scheduling aspects, so will always take the buffers, pass them to the VPU,
124 + * and then signal the job as complete.
126 + * This program is free software; you can redistribute it and/or modify
127 + * it under the terms of the GNU General Public License as published by the
128 + * Free Software Foundation; either version 2 of the
129 + * License, or (at your option) any later version
131 +#include <linux/module.h>
132 +#include <linux/delay.h>
133 +#include <linux/fs.h>
134 +#include <linux/timer.h>
135 +#include <linux/sched.h>
136 +#include <linux/slab.h>
137 +#include <linux/platform_device.h>
138 +#include <linux/syscalls.h>
140 +#include <media/v4l2-mem2mem.h>
141 +#include <media/v4l2-device.h>
142 +#include <media/v4l2-ioctl.h>
143 +#include <media/v4l2-ctrls.h>
144 +#include <media/v4l2-event.h>
145 +#include <media/videobuf2-dma-contig.h>
147 +#include "vchiq-mmal/mmal-encodings.h"
148 +#include "vchiq-mmal/mmal-msg.h"
149 +#include "vchiq-mmal/mmal-parameters.h"
150 +#include "vchiq-mmal/mmal-vchiq.h"
153 + * Default /dev/videoN node numbers for decode and encode.
154 + * Deliberately avoid the very low numbers as these are often taken by webcams
155 + * etc, and simple apps tend to only go for /dev/video0.
157 +static int decode_video_nr = 10;
158 +module_param(decode_video_nr, int, 0644);
159 +MODULE_PARM_DESC(decode_video_nr, "decoder video device number");
161 +static int encode_video_nr = 11;
162 +module_param(encode_video_nr, int, 0644);
163 +MODULE_PARM_DESC(encode_video_nr, "encoder video device number");
165 +static unsigned int debug;
166 +module_param(debug, uint, 0644);
167 +MODULE_PARM_DESC(debug, "activates debug info (0-3)");
173 +#define BPL_ALIGN 32
174 +#define DEFAULT_WIDTH 640
175 +#define DEFAULT_HEIGHT 480
177 + * The unanswered question - what is the maximum size of a compressed frame?
178 + * V4L2 mandates that the encoded frame must fit in a single buffer. Sizing
179 + * that buffer is a compromise between wasting memory and risking not fitting.
180 + * The 1080P version of Big Buck Bunny has some frames that exceed 512kB.
181 + * Adopt a moderately arbitrary split at 720P for switching between 512 and
184 +#define DEF_COMP_BUF_SIZE_GREATER_720P (768 << 10)
185 +#define DEF_COMP_BUF_SIZE_720P_OR_LESS (512 << 10)
187 +/* Flags that indicate a format can be used for capture/output */
188 +#define MEM2MEM_CAPTURE BIT(0)
189 +#define MEM2MEM_OUTPUT BIT(1)
191 +#define MEM2MEM_NAME "bcm2835-codec"
193 +struct bcm2835_codec_fmt {
196 + int bytesperline_align;
201 + int size_multiplier_x2;
204 +/* Supported raw pixel formats. Those supported for both encode and decode
205 + * must come first, with those only supported for decode coming after (there
206 + * are no formats supported for encode only).
208 +static struct bcm2835_codec_fmt raw_formats[] = {
210 + .fourcc = V4L2_PIX_FMT_YUV420,
212 + .bytesperline_align = 32,
214 + .mmal_fmt = MMAL_ENCODING_I420,
215 + .size_multiplier_x2 = 3,
217 + .fourcc = V4L2_PIX_FMT_YVU420,
219 + .bytesperline_align = 32,
221 + .mmal_fmt = MMAL_ENCODING_YV12,
222 + .size_multiplier_x2 = 3,
224 + .fourcc = V4L2_PIX_FMT_NV12,
226 + .bytesperline_align = 32,
228 + .mmal_fmt = MMAL_ENCODING_NV12,
229 + .size_multiplier_x2 = 3,
231 + .fourcc = V4L2_PIX_FMT_NV21,
233 + .bytesperline_align = 32,
235 + .mmal_fmt = MMAL_ENCODING_NV21,
236 + .size_multiplier_x2 = 3,
238 + .fourcc = V4L2_PIX_FMT_RGB565,
240 + .bytesperline_align = 32,
242 + .mmal_fmt = MMAL_ENCODING_RGB16,
243 + .size_multiplier_x2 = 2,
245 + .fourcc = V4L2_PIX_FMT_YUYV,
247 + .bytesperline_align = 32,
249 + .mmal_fmt = MMAL_ENCODING_YUYV,
250 + .encode_only = true,
251 + .size_multiplier_x2 = 2,
253 + .fourcc = V4L2_PIX_FMT_UYVY,
255 + .bytesperline_align = 32,
257 + .mmal_fmt = MMAL_ENCODING_UYVY,
258 + .encode_only = true,
259 + .size_multiplier_x2 = 2,
261 + .fourcc = V4L2_PIX_FMT_YVYU,
263 + .bytesperline_align = 32,
265 + .mmal_fmt = MMAL_ENCODING_YVYU,
266 + .encode_only = true,
267 + .size_multiplier_x2 = 2,
269 + .fourcc = V4L2_PIX_FMT_VYUY,
271 + .bytesperline_align = 32,
273 + .mmal_fmt = MMAL_ENCODING_VYUY,
274 + .encode_only = true,
275 + .size_multiplier_x2 = 2,
277 + .fourcc = V4L2_PIX_FMT_RGB24,
279 + .bytesperline_align = 32,
281 + .mmal_fmt = MMAL_ENCODING_RGB24,
282 + .encode_only = true,
283 + .size_multiplier_x2 = 2,
285 + .fourcc = V4L2_PIX_FMT_BGR24,
287 + .bytesperline_align = 32,
289 + .mmal_fmt = MMAL_ENCODING_BGR24,
290 + .encode_only = true,
291 + .size_multiplier_x2 = 2,
293 + .fourcc = V4L2_PIX_FMT_BGR32,
295 + .bytesperline_align = 32,
297 + .mmal_fmt = MMAL_ENCODING_BGRA,
298 + .encode_only = true,
299 + .size_multiplier_x2 = 2,
303 +/* Supported encoded formats. Those supported for both encode and decode
304 + * must come first, with those only supported for decode coming after (there
305 + * are no formats supported for encode only).
307 +static struct bcm2835_codec_fmt encoded_formats[] = {
309 + .fourcc = V4L2_PIX_FMT_H264,
311 + .flags = V4L2_FMT_FLAG_COMPRESSED,
312 + .mmal_fmt = MMAL_ENCODING_H264,
314 + .fourcc = V4L2_PIX_FMT_MJPEG,
316 + .flags = V4L2_FMT_FLAG_COMPRESSED,
317 + .mmal_fmt = MMAL_ENCODING_MJPEG,
319 + .fourcc = V4L2_PIX_FMT_MPEG4,
321 + .flags = V4L2_FMT_FLAG_COMPRESSED,
322 + .mmal_fmt = MMAL_ENCODING_MP4V,
323 + .decode_only = true,
325 + .fourcc = V4L2_PIX_FMT_H263,
327 + .flags = V4L2_FMT_FLAG_COMPRESSED,
328 + .mmal_fmt = MMAL_ENCODING_H263,
329 + .decode_only = true,
331 + .fourcc = V4L2_PIX_FMT_MPEG2,
333 + .flags = V4L2_FMT_FLAG_COMPRESSED,
334 + .mmal_fmt = MMAL_ENCODING_MP2V,
335 + .decode_only = true,
337 + .fourcc = V4L2_PIX_FMT_VP8,
339 + .flags = V4L2_FMT_FLAG_COMPRESSED,
340 + .mmal_fmt = MMAL_ENCODING_VP8,
341 + .decode_only = true,
344 + * This list couold include VP6 and Theorafor decode, but V4L2 doesn't
349 +struct bcm2835_codec_fmt_list {
350 + struct bcm2835_codec_fmt *list;
351 + unsigned int num_entries;
355 +#define ENCODED_LIST 1
357 +struct bcm2835_codec_fmt_list formats[] = {
359 + .list = raw_formats,
360 + .num_entries = ARRAY_SIZE(raw_formats),
362 + .list = encoded_formats,
363 + .num_entries = ARRAY_SIZE(encoded_formats),
367 +struct m2m_mmal_buffer {
368 + struct v4l2_m2m_buffer m2m;
369 + struct mmal_buffer mmal;
372 +/* Per-queue, driver-specific private data */
373 +struct bcm2835_codec_q_data {
375 + * These parameters should be treated as gospel, with everything else
376 + * being determined from them.
378 + /* Buffer width/height */
379 + unsigned int bytesperline;
380 + unsigned int height;
381 + /* Crop size used for selection handling */
382 + unsigned int crop_width;
383 + unsigned int crop_height;
384 + bool selection_set;
386 + unsigned int sizeimage;
387 + unsigned int sequence;
388 + struct bcm2835_codec_fmt *fmt;
390 + /* One extra buffer header so we can send an EOS. */
391 + struct m2m_mmal_buffer eos_buffer;
392 + bool eos_buffer_in_use; /* debug only */
400 +static inline struct bcm2835_codec_fmt_list *get_format_list(bool decode,
403 + return decode ^ capture ? &formats[ENCODED_LIST] : &formats[RAW_LIST];
406 +static struct bcm2835_codec_fmt *get_default_format(bool decode, bool capture)
408 + return &get_format_list(decode, capture)->list[0];
411 +static struct bcm2835_codec_fmt *find_format(struct v4l2_format *f, bool decode,
414 + struct bcm2835_codec_fmt *fmt;
416 + struct bcm2835_codec_fmt_list *fmts = get_format_list(decode, capture);
418 + for (k = 0; k < fmts->num_entries; k++) {
419 + fmt = &fmts->list[k];
420 + if (fmt->fourcc == f->fmt.pix.pixelformat)
425 + * Some compressed formats are only supported for decoding, not
428 + if (!decode && fmts->list[k].decode_only)
431 + /* Some pixel formats are only supported for encoding, not decoding. */
432 + if (decode && fmts->list[k].encode_only)
435 + if (k == fmts->num_entries)
438 + return &fmts->list[k];
441 +struct bcm2835_codec_dev {
442 + struct platform_device *pdev;
445 + struct v4l2_device v4l2_dev;
446 + struct video_device vfd;
447 + /* mutex for the v4l2 device */
448 + struct mutex dev_mutex;
451 + /* allocated mmal instance and components */
452 + bool decode; /* Is this instance a decoder? */
453 + struct vchiq_mmal_instance *instance;
455 + struct v4l2_m2m_dev *m2m_dev;
458 +struct bcm2835_codec_ctx {
460 + struct bcm2835_codec_dev *dev;
462 + struct v4l2_ctrl_handler hdl;
464 + struct vchiq_mmal_component *component;
465 + bool component_enabled;
467 + enum v4l2_colorspace colorspace;
468 + enum v4l2_ycbcr_encoding ycbcr_enc;
469 + enum v4l2_xfer_func xfer_func;
470 + enum v4l2_quantization quant;
472 + /* Source and destination queue data */
473 + struct bcm2835_codec_q_data q_data[2];
477 + int num_ip_buffers;
478 + int num_op_buffers;
479 + struct completion frame_cmplt;
482 +struct bcm2835_codec_driver {
483 + struct bcm2835_codec_dev *encode;
484 + struct bcm2835_codec_dev *decode;
487 +static inline struct bcm2835_codec_ctx *file2ctx(struct file *file)
489 + return container_of(file->private_data, struct bcm2835_codec_ctx, fh);
492 +static struct bcm2835_codec_q_data *get_q_data(struct bcm2835_codec_ctx *ctx,
493 + enum v4l2_buf_type type)
496 + case V4L2_BUF_TYPE_VIDEO_OUTPUT:
497 + return &ctx->q_data[V4L2_M2M_SRC];
498 + case V4L2_BUF_TYPE_VIDEO_CAPTURE:
499 + return &ctx->q_data[V4L2_M2M_DST];
501 + v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n",
508 +static struct vchiq_mmal_port *get_port_data(struct bcm2835_codec_ctx *ctx,
509 + enum v4l2_buf_type type)
511 + if (!ctx->component)
515 + case V4L2_BUF_TYPE_VIDEO_OUTPUT:
516 + return &ctx->component->input[0];
517 + case V4L2_BUF_TYPE_VIDEO_CAPTURE:
518 + return &ctx->component->output[0];
520 + v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n",
528 + * mem2mem callbacks
532 + * job_ready() - check whether an instance is ready to be scheduled to run
534 +static int job_ready(void *priv)
536 + struct bcm2835_codec_ctx *ctx = priv;
538 + if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) &&
539 + !v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx))
545 +static void job_abort(void *priv)
547 + struct bcm2835_codec_ctx *ctx = priv;
549 + v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s\n", __func__);
550 + /* Will cancel the transaction in the next interrupt handler */
554 +static inline unsigned int get_sizeimage(int bpl, int height,
555 + struct bcm2835_codec_fmt *fmt)
557 + return (bpl * height * fmt->size_multiplier_x2) >> 1;
560 +static inline unsigned int get_bytesperline(int width,
561 + struct bcm2835_codec_fmt *fmt)
563 + return ALIGN((width * fmt->depth) >> 3, fmt->bytesperline_align);
566 +static void setup_mmal_port_format(struct bcm2835_codec_ctx *ctx,
568 + struct bcm2835_codec_q_data *q_data,
569 + struct vchiq_mmal_port *port)
571 + port->format.encoding = q_data->fmt->mmal_fmt;
573 + if (!(q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED)) {
574 + /* Raw image format - set width/height */
575 + port->es.video.width = q_data->bytesperline /
576 + (q_data->fmt->depth >> 3);
577 + port->es.video.height = q_data->height;
578 + port->es.video.crop.width = q_data->crop_width;
579 + port->es.video.crop.height = q_data->crop_height;
580 + port->es.video.frame_rate.num = 0;
581 + port->es.video.frame_rate.den = 1;
583 + /* Compressed format - leave resolution as 0 for decode */
585 + port->es.video.width = 0;
586 + port->es.video.height = 0;
587 + port->es.video.crop.width = 0;
588 + port->es.video.crop.height = 0;
590 + port->es.video.width = q_data->crop_width;
591 + port->es.video.height = q_data->height;
592 + port->es.video.crop.width = q_data->crop_width;
593 + port->es.video.crop.height = q_data->crop_height;
594 + port->format.bitrate = ctx->bitrate;
596 + port->es.video.frame_rate.num = 0;
597 + port->es.video.frame_rate.den = 1;
599 + port->es.video.crop.x = 0;
600 + port->es.video.crop.y = 0;
602 + port->current_buffer.size = q_data->sizeimage;
605 +static void ip_buffer_cb(struct vchiq_mmal_instance *instance,
606 + struct vchiq_mmal_port *port, int status,
607 + struct mmal_buffer *mmal_buf)
609 + struct bcm2835_codec_ctx *ctx = port->cb_ctx/*, *curr_ctx*/;
610 + struct m2m_mmal_buffer *buf =
611 + container_of(mmal_buf, struct m2m_mmal_buffer, mmal);
613 + v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: port %p buf %p length %lu, flags %x\n",
614 + __func__, port, mmal_buf, mmal_buf->length,
615 + mmal_buf->mmal_flags);
617 + if (buf == &ctx->q_data[V4L2_M2M_SRC].eos_buffer) {
618 + /* Do we need to add lcoking to prevent multiple submission of
619 + * the EOS, and therefore handle mutliple return here?
621 + v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: eos buffer returned.\n",
623 + ctx->q_data[V4L2_M2M_SRC].eos_buffer_in_use = false;
628 + /* error in transfer */
630 + /* there was a buffer with the error so return it */
631 + vb2_buffer_done(&buf->m2m.vb.vb2_buf,
632 + VB2_BUF_STATE_ERROR);
635 + if (mmal_buf->cmd) {
636 + v4l2_err(&ctx->dev->v4l2_dev, "%s: Not expecting cmd msgs on ip callback - %08x\n",
637 + __func__, mmal_buf->cmd);
639 + * CHECKME: Should we return here. The buffer shouldn't have a
640 + * message context or vb2 buf associated.
644 + v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: no error. Return buffer %p\n",
645 + __func__, &buf->m2m.vb.vb2_buf);
646 + vb2_buffer_done(&buf->m2m.vb.vb2_buf, VB2_BUF_STATE_DONE);
648 + ctx->num_ip_buffers++;
649 + v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: done %d input buffers\n",
650 + __func__, ctx->num_ip_buffers);
652 + if (!port->enabled)
653 + complete(&ctx->frame_cmplt);
656 +static void queue_res_chg_event(struct bcm2835_codec_ctx *ctx)
658 + static const struct v4l2_event ev_src_ch = {
659 + .type = V4L2_EVENT_SOURCE_CHANGE,
660 + .u.src_change.changes =
661 + V4L2_EVENT_SRC_CH_RESOLUTION,
664 + v4l2_event_queue_fh(&ctx->fh, &ev_src_ch);
667 +static void send_eos_event(struct bcm2835_codec_ctx *ctx)
669 + static const struct v4l2_event ev = {
670 + .type = V4L2_EVENT_EOS,
673 + v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Sending EOS event\n");
675 + v4l2_event_queue_fh(&ctx->fh, &ev);
678 +static void color_mmal2v4l(struct bcm2835_codec_ctx *ctx, u32 mmal_color_space)
680 + switch (mmal_color_space) {
681 + case MMAL_COLOR_SPACE_ITUR_BT601:
682 + ctx->colorspace = V4L2_COLORSPACE_REC709;
683 + ctx->xfer_func = V4L2_XFER_FUNC_709;
684 + ctx->ycbcr_enc = V4L2_YCBCR_ENC_601;
685 + ctx->quant = V4L2_QUANTIZATION_LIM_RANGE;
688 + case MMAL_COLOR_SPACE_ITUR_BT709:
689 + ctx->colorspace = V4L2_COLORSPACE_REC709;
690 + ctx->xfer_func = V4L2_XFER_FUNC_709;
691 + ctx->ycbcr_enc = V4L2_YCBCR_ENC_709;
692 + ctx->quant = V4L2_QUANTIZATION_LIM_RANGE;
697 +static void handle_fmt_changed(struct bcm2835_codec_ctx *ctx,
698 + struct mmal_buffer *mmal_buf)
700 + struct bcm2835_codec_q_data *q_data;
701 + struct mmal_msg_event_format_changed *format =
702 + (struct mmal_msg_event_format_changed *)mmal_buf->buffer;
703 + v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Format changed: buff size min %u, rec %u, buff num min %u, rec %u\n",
705 + format->buffer_size_min,
706 + format->buffer_size_recommended,
707 + format->buffer_num_min,
708 + format->buffer_num_recommended
710 + if (format->format.type != MMAL_ES_TYPE_VIDEO) {
711 + v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Format changed but not video %u\n",
712 + __func__, format->format.type);
715 + v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Format changed to %ux%u, crop %ux%u, colourspace %08X\n",
716 + __func__, format->es.video.width, format->es.video.height,
717 + format->es.video.crop.width, format->es.video.crop.height,
718 + format->es.video.color_space);
720 + q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
721 + q_data->crop_width = format->es.video.crop.width;
722 + q_data->crop_height = format->es.video.crop.height;
723 + q_data->bytesperline = format->es.video.crop.width;
724 + q_data->height = format->es.video.height;
725 + q_data->sizeimage = format->buffer_size_min;
726 + if (format->es.video.color_space)
727 + color_mmal2v4l(ctx, format->es.video.color_space);
729 + queue_res_chg_event(ctx);
732 +static void op_buffer_cb(struct vchiq_mmal_instance *instance,
733 + struct vchiq_mmal_port *port, int status,
734 + struct mmal_buffer *mmal_buf)
736 + struct bcm2835_codec_ctx *ctx = port->cb_ctx;
737 + struct m2m_mmal_buffer *buf;
738 + struct vb2_v4l2_buffer *vb2;
740 + v4l2_dbg(2, debug, &ctx->dev->v4l2_dev,
741 + "%s: status:%d, buf:%p, length:%lu, flags %u, pts %lld\n",
742 + __func__, status, mmal_buf, mmal_buf->length,
743 + mmal_buf->mmal_flags, mmal_buf->pts);
746 + /* error in transfer */
748 + /* there was a buffer with the error so return it */
749 + vb2_buffer_done(&vb2->vb2_buf, VB2_BUF_STATE_ERROR);
754 + if (mmal_buf->cmd) {
755 + switch (mmal_buf->cmd) {
756 + case MMAL_EVENT_FORMAT_CHANGED:
758 + handle_fmt_changed(ctx, mmal_buf);
762 + v4l2_err(&ctx->dev->v4l2_dev, "%s: Unexpected event on output callback - %08x\n",
763 + __func__, mmal_buf->cmd);
769 + buf = container_of(mmal_buf, struct m2m_mmal_buffer, mmal);
770 + vb2 = &buf->m2m.vb;
772 + v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: length %lu, flags %x, idx %u\n",
773 + __func__, mmal_buf->length, mmal_buf->mmal_flags,
774 + vb2->vb2_buf.index);
776 + if (mmal_buf->length == 0) {
777 + /* stream ended, or buffer being returned during disable. */
778 + v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: Empty buffer - flags %04x",
779 + __func__, mmal_buf->mmal_flags);
780 + if (!mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS) {
781 + vb2_buffer_done(&vb2->vb2_buf, VB2_BUF_STATE_ERROR);
782 + if (!port->enabled)
783 + complete(&ctx->frame_cmplt);
787 + if (mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS) {
788 + /* EOS packet from the VPU */
789 + send_eos_event(ctx);
790 + vb2->flags |= V4L2_BUF_FLAG_LAST;
793 + vb2->vb2_buf.timestamp = mmal_buf->pts;
795 + vb2_set_plane_payload(&vb2->vb2_buf, 0, mmal_buf->length);
796 + if (mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
797 + vb2->flags |= V4L2_BUF_FLAG_KEYFRAME;
799 + vb2_buffer_done(&vb2->vb2_buf, VB2_BUF_STATE_DONE);
800 + ctx->num_op_buffers++;
802 + v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: done %d output buffers\n",
803 + __func__, ctx->num_op_buffers);
805 + if (!port->enabled)
806 + complete(&ctx->frame_cmplt);
809 +/* vb2_to_mmal_buffer() - converts vb2 buffer header to MMAL
811 + * Copies all the required fields from a VB2 buffer to the MMAL buffer header,
812 + * ready for sending to the VPU.
814 +static void vb2_to_mmal_buffer(struct m2m_mmal_buffer *buf,
815 + struct vb2_v4l2_buffer *vb2)
817 + buf->mmal.mmal_flags = 0;
818 + if (vb2->flags & V4L2_BUF_FLAG_KEYFRAME)
819 + buf->mmal.mmal_flags |= MMAL_BUFFER_HEADER_FLAG_KEYFRAME;
822 + * Adding this means that the data must be framed correctly as one frame
823 + * per buffer. The underlying decoder has no such requirement, but it
824 + * will reduce latency as the bistream parser will be kicked immediately
825 + * to parse the frame, rather than relying on its own heuristics for
828 + buf->mmal.mmal_flags |= MMAL_BUFFER_HEADER_FLAG_FRAME_END;
830 + buf->mmal.length = vb2->vb2_buf.planes[0].bytesused;
832 + * Minor ambiguity in the V4L2 spec as to whether passing in a 0 length
833 + * buffer, or one with V4L2_BUF_FLAG_LAST set denotes end of stream.
836 + if (!buf->mmal.length || vb2->flags & V4L2_BUF_FLAG_LAST)
837 + buf->mmal.mmal_flags |= MMAL_BUFFER_HEADER_FLAG_EOS;
839 + buf->mmal.pts = vb2->vb2_buf.timestamp;
840 + buf->mmal.dts = MMAL_TIME_UNKNOWN;
843 +/* device_run() - prepares and starts the device
845 + * This simulates all the immediate preparations required before starting
846 + * a device. This will be called by the framework when it decides to schedule
847 + * a particular instance.
849 +static void device_run(void *priv)
851 + struct bcm2835_codec_ctx *ctx = priv;
852 + struct bcm2835_codec_dev *dev = ctx->dev;
853 + struct vb2_v4l2_buffer *src_buf, *dst_buf;
854 + struct m2m_mmal_buffer *src_m2m_buf, *dst_m2m_buf;
855 + struct v4l2_m2m_buffer *m2m;
858 + v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: off we go\n", __func__);
860 + src_buf = v4l2_m2m_buf_remove(&ctx->fh.m2m_ctx->out_q_ctx);
862 + m2m = container_of(src_buf, struct v4l2_m2m_buffer, vb);
863 + src_m2m_buf = container_of(m2m, struct m2m_mmal_buffer, m2m);
864 + vb2_to_mmal_buffer(src_m2m_buf, src_buf);
866 + ret = vchiq_mmal_submit_buffer(dev->instance,
867 + &ctx->component->input[0],
868 + &src_m2m_buf->mmal);
869 + v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: Submitted ip buffer len %lu, pts %llu, flags %04x\n",
870 + __func__, src_m2m_buf->mmal.length,
871 + src_m2m_buf->mmal.pts, src_m2m_buf->mmal.mmal_flags);
873 + v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed submitting ip buffer\n",
877 + dst_buf = v4l2_m2m_buf_remove(&ctx->fh.m2m_ctx->cap_q_ctx);
879 + m2m = container_of(dst_buf, struct v4l2_m2m_buffer, vb);
880 + dst_m2m_buf = container_of(m2m, struct m2m_mmal_buffer, m2m);
881 + vb2_to_mmal_buffer(dst_m2m_buf, dst_buf);
883 + ret = vchiq_mmal_submit_buffer(dev->instance,
884 + &ctx->component->output[0],
885 + &dst_m2m_buf->mmal);
887 + v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed submitting op buffer\n",
891 + v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: Submitted src %p, dst %p\n",
892 + __func__, src_m2m_buf, dst_m2m_buf);
894 + /* Complete the job here. */
895 + v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
901 +static int vidioc_querycap(struct file *file, void *priv,
902 + struct v4l2_capability *cap)
904 + strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1);
905 + strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
906 + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
908 + cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
909 + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
913 +static int enum_fmt(struct v4l2_fmtdesc *f, bool decode, bool capture)
915 + struct bcm2835_codec_fmt *fmt;
916 + struct bcm2835_codec_fmt_list *fmts = get_format_list(decode, capture);
918 + if (f->index < fmts->num_entries) {
920 + /* Check format isn't a decode only format when encoding */
922 + fmts->list[f->index].decode_only)
924 + /* Check format isn't a decode only format when encoding */
926 + fmts->list[f->index].encode_only)
929 + fmt = &fmts->list[f->index];
930 + f->pixelformat = fmt->fourcc;
931 + f->flags = fmt->flags;
935 + /* Format not found */
939 +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
940 + struct v4l2_fmtdesc *f)
942 + struct bcm2835_codec_ctx *ctx = file2ctx(file);
944 + return enum_fmt(f, ctx->dev->decode, true);
947 +static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
948 + struct v4l2_fmtdesc *f)
950 + struct bcm2835_codec_ctx *ctx = file2ctx(file);
952 + return enum_fmt(f, ctx->dev->decode, false);
955 +static int vidioc_g_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f)
957 + struct vb2_queue *vq;
958 + struct bcm2835_codec_q_data *q_data;
960 + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
964 + q_data = get_q_data(ctx, f->type);
966 + f->fmt.pix.width = q_data->crop_width;
967 + f->fmt.pix.height = q_data->height;
968 + f->fmt.pix.field = V4L2_FIELD_NONE;
969 + f->fmt.pix.pixelformat = q_data->fmt->fourcc;
970 + f->fmt.pix.bytesperline = q_data->bytesperline;
971 + f->fmt.pix.sizeimage = q_data->sizeimage;
972 + f->fmt.pix.colorspace = ctx->colorspace;
973 + f->fmt.pix.xfer_func = ctx->xfer_func;
974 + f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc;
975 + f->fmt.pix.quantization = ctx->quant;
980 +static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
981 + struct v4l2_format *f)
983 + return vidioc_g_fmt(file2ctx(file), f);
986 +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
987 + struct v4l2_format *f)
989 + return vidioc_g_fmt(file2ctx(file), f);
992 +static int vidioc_try_fmt(struct v4l2_format *f, struct bcm2835_codec_fmt *fmt)
995 + * The V4L2 specification requires the driver to correct the format
996 + * struct if any of the dimensions is unsupported
998 + if (f->fmt.pix.width > MAX_W)
999 + f->fmt.pix.width = MAX_W;
1000 + if (f->fmt.pix.height > MAX_H)
1001 + f->fmt.pix.height = MAX_H;
1003 + if (!fmt->flags & V4L2_FMT_FLAG_COMPRESSED) {
1004 + /* Only clip min w/h on capture. Treat 0x0 as unknown. */
1005 + if (f->fmt.pix.width < MIN_W)
1006 + f->fmt.pix.width = MIN_W;
1007 + if (f->fmt.pix.height < MIN_H)
1008 + f->fmt.pix.height = MIN_H;
1011 + * Buffer must have a vertical alignment of 16 lines.
1012 + * The selection will reflect any cropping rectangle when only
1013 + * some of the pixels are active.
1015 + f->fmt.pix.height = ALIGN(f->fmt.pix.height, 16);
1017 + f->fmt.pix.bytesperline = get_bytesperline(f->fmt.pix.width,
1019 + f->fmt.pix.sizeimage = get_sizeimage(f->fmt.pix.bytesperline,
1020 + f->fmt.pix.height,
1023 + u32 min_size = f->fmt.pix.width > 1280 ||
1024 + f->fmt.pix.height > 720 ?
1025 + DEF_COMP_BUF_SIZE_GREATER_720P :
1026 + DEF_COMP_BUF_SIZE_720P_OR_LESS;
1028 + f->fmt.pix.bytesperline = 0;
1029 + if (f->fmt.pix.sizeimage < min_size)
1030 + f->fmt.pix.sizeimage = min_size;
1033 + f->fmt.pix.field = V4L2_FIELD_NONE;
1038 +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
1039 + struct v4l2_format *f)
1041 + struct bcm2835_codec_fmt *fmt;
1042 + struct bcm2835_codec_ctx *ctx = file2ctx(file);
1044 + fmt = find_format(f, ctx->dev->decode, true);
1046 + f->fmt.pix.pixelformat = get_default_format(ctx->dev->decode,
1048 + fmt = find_format(f, ctx->dev->decode, true);
1051 + return vidioc_try_fmt(f, fmt);
1054 +static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
1055 + struct v4l2_format *f)
1057 + struct bcm2835_codec_fmt *fmt;
1058 + struct bcm2835_codec_ctx *ctx = file2ctx(file);
1060 + fmt = find_format(f, ctx->dev->decode, false);
1062 + f->fmt.pix.pixelformat = get_default_format(ctx->dev->decode,
1064 + fmt = find_format(f, ctx->dev->decode, false);
1067 + if (!f->fmt.pix.colorspace)
1068 + f->fmt.pix.colorspace = ctx->colorspace;
1070 + return vidioc_try_fmt(f, fmt);
1073 +static int vidioc_s_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f,
1074 + unsigned int requested_height)
1076 + struct bcm2835_codec_q_data *q_data;
1077 + struct vb2_queue *vq;
1078 + struct vchiq_mmal_port *port;
1079 + bool update_capture_port = false;
1082 + v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
1083 + f->type, f->fmt.pix.width, f->fmt.pix.height,
1084 + f->fmt.pix.pixelformat, f->fmt.pix.sizeimage);
1086 + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
1090 + q_data = get_q_data(ctx, f->type);
1094 + if (vb2_is_busy(vq)) {
1095 + v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
1099 + q_data->fmt = find_format(f, ctx->dev->decode,
1100 + f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE);
1101 + q_data->crop_width = f->fmt.pix.width;
1102 + q_data->height = f->fmt.pix.height;
1103 + if (!q_data->selection_set)
1104 + q_data->crop_height = requested_height;
1107 + * Copying the behaviour of vicodec which retains a single set of
1108 + * colorspace parameters for both input and output.
1110 + ctx->colorspace = f->fmt.pix.colorspace;
1111 + ctx->xfer_func = f->fmt.pix.xfer_func;
1112 + ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc;
1113 + ctx->quant = f->fmt.pix.quantization;
1115 + /* All parameters should have been set correctly by try_fmt */
1116 + q_data->bytesperline = f->fmt.pix.bytesperline;
1117 + q_data->sizeimage = f->fmt.pix.sizeimage;
1119 + v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Calulated bpl as %u, size %u\n",
1120 + q_data->bytesperline, q_data->sizeimage);
1122 + if (ctx->dev->decode && q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED &&
1123 + f->fmt.pix.width && f->fmt.pix.height) {
1125 + * On the decoder, if provided with a resolution on the input
1126 + * side, then replicate that to the output side.
1127 + * GStreamer appears not to support V4L2_EVENT_SOURCE_CHANGE,
1128 + * nor set up a resolution on the output side, therefore
1129 + * we can't decode anything at a resolution other than the
1132 + struct bcm2835_codec_q_data *q_data_dst =
1133 + &ctx->q_data[V4L2_M2M_DST];
1135 + q_data_dst->crop_width = q_data->crop_width;
1136 + q_data_dst->crop_height = q_data->crop_height;
1137 + q_data_dst->height = ALIGN(q_data->crop_height, 16);
1139 + q_data_dst->bytesperline =
1140 + get_bytesperline(f->fmt.pix.width, q_data_dst->fmt);
1141 + q_data_dst->sizeimage = get_sizeimage(q_data_dst->bytesperline,
1142 + q_data_dst->height,
1144 + update_capture_port = true;
1147 + /* If we have a component then setup the port as well */
1148 + port = get_port_data(ctx, vq->type);
1152 + setup_mmal_port_format(ctx, ctx->dev->decode, q_data, port);
1153 + ret = vchiq_mmal_port_set_format(ctx->dev->instance, port);
1155 + v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed vchiq_mmal_port_set_format on port, ret %d\n",
1160 + if (q_data->sizeimage < port->minimum_buffer.size) {
1161 + v4l2_err(&ctx->dev->v4l2_dev, "%s: Current buffer size of %u < min buf size %u - driver mismatch to MMAL\n",
1162 + __func__, q_data->sizeimage,
1163 + port->minimum_buffer.size);
1166 + v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Set format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
1167 + f->type, q_data->crop_width, q_data->height,
1168 + q_data->fmt->fourcc, q_data->sizeimage);
1170 + if (update_capture_port) {
1171 + struct vchiq_mmal_port *port_dst = &ctx->component->output[0];
1172 + struct bcm2835_codec_q_data *q_data_dst =
1173 + &ctx->q_data[V4L2_M2M_DST];
1175 + setup_mmal_port_format(ctx, ctx->dev->decode, q_data_dst,
1177 + ret = vchiq_mmal_port_set_format(ctx->dev->instance, port_dst);
1179 + v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed vchiq_mmal_port_set_format on output port, ret %d\n",
1187 +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
1188 + struct v4l2_format *f)
1190 + unsigned int height = f->fmt.pix.height;
1193 + ret = vidioc_try_fmt_vid_cap(file, priv, f);
1197 + return vidioc_s_fmt(file2ctx(file), f, height);
1200 +static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
1201 + struct v4l2_format *f)
1203 + unsigned int height = f->fmt.pix.height;
1206 + ret = vidioc_try_fmt_vid_out(file, priv, f);
1210 + ret = vidioc_s_fmt(file2ctx(file), f, height);
1214 +static int vidioc_g_selection(struct file *file, void *priv,
1215 + struct v4l2_selection *s)
1217 + struct bcm2835_codec_ctx *ctx = file2ctx(file);
1218 + struct bcm2835_codec_q_data *q_data;
1219 + bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
1222 + if (capture_queue ^ ctx->dev->decode)
1223 + /* OUTPUT on decoder and CAPTURE on encoder are not valid. */
1226 + q_data = get_q_data(ctx, s->type);
1230 + if (ctx->dev->decode) {
1231 + switch (s->target) {
1232 + case V4L2_SEL_TGT_COMPOSE_DEFAULT:
1233 + case V4L2_SEL_TGT_COMPOSE:
1236 + s->r.width = q_data->crop_width;
1237 + s->r.height = q_data->crop_height;
1239 + case V4L2_SEL_TGT_COMPOSE_BOUNDS:
1242 + s->r.width = q_data->crop_width;
1243 + s->r.height = q_data->crop_height;
1249 + switch (s->target) {
1250 + case V4L2_SEL_TGT_CROP_DEFAULT:
1251 + case V4L2_SEL_TGT_CROP_BOUNDS:
1254 + s->r.width = q_data->bytesperline;
1255 + s->r.height = q_data->height;
1257 + case V4L2_SEL_TGT_CROP:
1260 + s->r.width = q_data->crop_width;
1261 + s->r.height = q_data->crop_height;
1271 +static int vidioc_s_selection(struct file *file, void *priv,
1272 + struct v4l2_selection *s)
1274 + struct bcm2835_codec_ctx *ctx = file2ctx(file);
1275 + struct bcm2835_codec_q_data *q_data = NULL;
1276 + bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
1279 + v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: ctx %p, type %d, q_data %p, target %d, rect x/y %d/%d, w/h %ux%u\n",
1280 + __func__, ctx, s->type, q_data, s->target, s->r.left, s->r.top,
1281 + s->r.width, s->r.height);
1283 + if (capture_queue ^ ctx->dev->decode)
1284 + /* OUTPUT on decoder and CAPTURE on encoder are not valid. */
1287 + q_data = get_q_data(ctx, s->type);
1291 + if (ctx->dev->decode) {
1292 + switch (s->target) {
1293 + case V4L2_SEL_TGT_COMPOSE:
1294 + /* Accept cropped image */
1297 + s->r.width = min(s->r.width, q_data->crop_width);
1298 + s->r.height = min(s->r.height, q_data->height);
1299 + q_data->crop_width = s->r.width;
1300 + q_data->crop_height = s->r.height;
1301 + q_data->selection_set = true;
1307 + switch (s->target) {
1308 + case V4L2_SEL_TGT_CROP:
1309 + /* Only support crop from (0,0) */
1312 + s->r.width = min(s->r.width, q_data->crop_width);
1313 + s->r.height = min(s->r.height, q_data->crop_height);
1314 + q_data->crop_width = s->r.width;
1315 + q_data->crop_height = s->r.height;
1316 + q_data->selection_set = true;
1326 +static int vidioc_subscribe_evt(struct v4l2_fh *fh,
1327 + const struct v4l2_event_subscription *sub)
1329 + switch (sub->type) {
1330 + case V4L2_EVENT_EOS:
1331 + return v4l2_event_subscribe(fh, sub, 2, NULL);
1332 + case V4L2_EVENT_SOURCE_CHANGE:
1333 + return v4l2_src_change_event_subscribe(fh, sub);
1335 + return v4l2_ctrl_subscribe_event(fh, sub);
1339 +static int bcm2835_codec_set_level_profile(struct bcm2835_codec_ctx *ctx,
1340 + struct v4l2_ctrl *ctrl)
1342 + struct mmal_parameter_video_profile param;
1343 + int param_size = sizeof(param);
1347 + * Level and Profile are set via the same MMAL parameter.
1348 + * Retrieve the current settings and amend the one that has changed.
1350 + ret = vchiq_mmal_port_parameter_get(ctx->dev->instance,
1351 + &ctx->component->output[0],
1352 + MMAL_PARAMETER_PROFILE,
1358 + switch (ctrl->id) {
1359 + case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
1360 + switch (ctrl->val) {
1361 + case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
1362 + param.profile = MMAL_VIDEO_PROFILE_H264_BASELINE;
1364 + case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
1366 + MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE;
1368 + case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
1369 + param.profile = MMAL_VIDEO_PROFILE_H264_MAIN;
1371 + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
1372 + param.profile = MMAL_VIDEO_PROFILE_H264_HIGH;
1375 + /* Should never get here */
1380 + case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
1381 + switch (ctrl->val) {
1382 + case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
1383 + param.level = MMAL_VIDEO_LEVEL_H264_1;
1385 + case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
1386 + param.level = MMAL_VIDEO_LEVEL_H264_1b;
1388 + case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
1389 + param.level = MMAL_VIDEO_LEVEL_H264_11;
1391 + case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
1392 + param.level = MMAL_VIDEO_LEVEL_H264_12;
1394 + case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
1395 + param.level = MMAL_VIDEO_LEVEL_H264_13;
1397 + case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
1398 + param.level = MMAL_VIDEO_LEVEL_H264_2;
1400 + case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
1401 + param.level = MMAL_VIDEO_LEVEL_H264_21;
1403 + case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
1404 + param.level = MMAL_VIDEO_LEVEL_H264_22;
1406 + case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
1407 + param.level = MMAL_VIDEO_LEVEL_H264_3;
1409 + case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
1410 + param.level = MMAL_VIDEO_LEVEL_H264_31;
1412 + case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
1413 + param.level = MMAL_VIDEO_LEVEL_H264_32;
1415 + case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
1416 + param.level = MMAL_VIDEO_LEVEL_H264_4;
1419 + /* Should never get here */
1423 + ret = vchiq_mmal_port_parameter_set(ctx->dev->instance,
1424 + &ctx->component->output[0],
1425 + MMAL_PARAMETER_PROFILE,
1432 +static int bcm2835_codec_s_ctrl(struct v4l2_ctrl *ctrl)
1434 + struct bcm2835_codec_ctx *ctx =
1435 + container_of(ctrl->handler, struct bcm2835_codec_ctx, hdl);
1438 + switch (ctrl->id) {
1439 + case V4L2_CID_MPEG_VIDEO_BITRATE:
1440 + ctx->bitrate = ctrl->val;
1441 + if (!ctx->component)
1444 + ret = vchiq_mmal_port_parameter_set(ctx->dev->instance,
1445 + &ctx->component->output[0],
1446 + MMAL_PARAMETER_VIDEO_BIT_RATE,
1448 + sizeof(ctrl->val));
1451 + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: {
1454 + if (!ctx->component)
1457 + switch (ctrl->val) {
1459 + case V4L2_MPEG_VIDEO_BITRATE_MODE_VBR:
1460 + bitrate_mode = MMAL_VIDEO_RATECONTROL_VARIABLE;
1462 + case V4L2_MPEG_VIDEO_BITRATE_MODE_CBR:
1463 + bitrate_mode = MMAL_VIDEO_RATECONTROL_CONSTANT;
1467 + ret = vchiq_mmal_port_parameter_set(ctx->dev->instance,
1468 + &ctx->component->output[0],
1469 + MMAL_PARAMETER_RATECONTROL,
1471 + sizeof(bitrate_mode));
1474 + case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER:
1475 + if (!ctx->component)
1478 + ret = vchiq_mmal_port_parameter_set(ctx->dev->instance,
1479 + &ctx->component->output[0],
1480 + MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER,
1482 + sizeof(ctrl->val));
1485 + case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:
1486 + if (!ctx->component)
1489 + ret = vchiq_mmal_port_parameter_set(ctx->dev->instance,
1490 + &ctx->component->output[0],
1491 + MMAL_PARAMETER_INTRAPERIOD,
1493 + sizeof(ctrl->val));
1496 + case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
1497 + case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
1498 + if (!ctx->component)
1501 + ret = bcm2835_codec_set_level_profile(ctx, ctrl);
1505 + v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
1510 + v4l2_err(&ctx->dev->v4l2_dev, "Failed setting ctrl %08x, ret %d\n",
1512 + return ret ? -EINVAL : 0;
1515 +static const struct v4l2_ctrl_ops bcm2835_codec_ctrl_ops = {
1516 + .s_ctrl = bcm2835_codec_s_ctrl,
1519 +static int vidioc_try_decoder_cmd(struct file *file, void *priv,
1520 + struct v4l2_decoder_cmd *cmd)
1522 + struct bcm2835_codec_ctx *ctx = file2ctx(file);
1524 + if (!ctx->dev->decode)
1527 + switch (cmd->cmd) {
1528 + case V4L2_DEC_CMD_STOP:
1529 + if (cmd->flags & V4L2_DEC_CMD_STOP_TO_BLACK) {
1530 + v4l2_err(&ctx->dev->v4l2_dev, "%s: DEC cmd->flags=%u stop to black not supported",
1531 + __func__, cmd->flags);
1535 + case V4L2_DEC_CMD_START:
1543 +static int vidioc_decoder_cmd(struct file *file, void *priv,
1544 + struct v4l2_decoder_cmd *cmd)
1546 + struct bcm2835_codec_ctx *ctx = file2ctx(file);
1547 + struct bcm2835_codec_q_data *q_data = &ctx->q_data[V4L2_M2M_SRC];
1550 + v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s, cmd %u", __func__,
1552 + ret = vidioc_try_decoder_cmd(file, priv, cmd);
1556 + switch (cmd->cmd) {
1557 + case V4L2_DEC_CMD_STOP:
1558 + if (q_data->eos_buffer_in_use)
1559 + v4l2_err(&ctx->dev->v4l2_dev, "EOS buffers already in use\n");
1560 + q_data->eos_buffer_in_use = true;
1562 + q_data->eos_buffer.mmal.buffer_size = 0;
1563 + q_data->eos_buffer.mmal.length = 0;
1564 + q_data->eos_buffer.mmal.mmal_flags =
1565 + MMAL_BUFFER_HEADER_FLAG_EOS;
1566 + q_data->eos_buffer.mmal.pts = 0;
1567 + q_data->eos_buffer.mmal.dts = 0;
1569 + if (!ctx->component)
1572 + ret = vchiq_mmal_submit_buffer(ctx->dev->instance,
1573 + &ctx->component->input[0],
1574 + &q_data->eos_buffer.mmal);
1576 + v4l2_err(&ctx->dev->v4l2_dev,
1577 + "%s: EOS buffer submit failed %d\n",
1582 + case V4L2_DEC_CMD_START:
1583 + /* Do we need to do anything here? */
1593 +static int vidioc_try_encoder_cmd(struct file *file, void *priv,
1594 + struct v4l2_encoder_cmd *cmd)
1596 + struct bcm2835_codec_ctx *ctx = file2ctx(file);
1598 + if (ctx->dev->decode)
1601 + switch (cmd->cmd) {
1602 + case V4L2_ENC_CMD_STOP:
1605 + case V4L2_ENC_CMD_START:
1606 + /* Do we need to do anything here? */
1614 +static int vidioc_encoder_cmd(struct file *file, void *priv,
1615 + struct v4l2_encoder_cmd *cmd)
1617 + struct bcm2835_codec_ctx *ctx = file2ctx(file);
1618 + struct bcm2835_codec_q_data *q_data = &ctx->q_data[V4L2_M2M_SRC];
1621 + v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s, cmd %u", __func__,
1623 + ret = vidioc_try_encoder_cmd(file, priv, cmd);
1627 + switch (cmd->cmd) {
1628 + case V4L2_ENC_CMD_STOP:
1629 + if (q_data->eos_buffer_in_use)
1630 + v4l2_err(&ctx->dev->v4l2_dev, "EOS buffers already in use\n");
1631 + q_data->eos_buffer_in_use = true;
1633 + q_data->eos_buffer.mmal.buffer_size = 0;
1634 + q_data->eos_buffer.mmal.length = 0;
1635 + q_data->eos_buffer.mmal.mmal_flags =
1636 + MMAL_BUFFER_HEADER_FLAG_EOS;
1637 + q_data->eos_buffer.mmal.pts = 0;
1638 + q_data->eos_buffer.mmal.dts = 0;
1640 + if (!ctx->component)
1643 + ret = vchiq_mmal_submit_buffer(ctx->dev->instance,
1644 + &ctx->component->input[0],
1645 + &q_data->eos_buffer.mmal);
1647 + v4l2_err(&ctx->dev->v4l2_dev,
1648 + "%s: EOS buffer submit failed %d\n",
1652 + case V4L2_ENC_CMD_START:
1653 + /* Do we need to do anything here? */
1663 +static const struct v4l2_ioctl_ops bcm2835_codec_ioctl_ops = {
1664 + .vidioc_querycap = vidioc_querycap,
1666 + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
1667 + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
1668 + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
1669 + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
1671 + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
1672 + .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out,
1673 + .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
1674 + .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
1676 + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
1677 + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
1678 + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
1679 + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
1680 + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
1681 + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
1682 + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
1684 + .vidioc_streamon = v4l2_m2m_ioctl_streamon,
1685 + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
1687 + .vidioc_g_selection = vidioc_g_selection,
1688 + .vidioc_s_selection = vidioc_s_selection,
1690 + .vidioc_subscribe_event = vidioc_subscribe_evt,
1691 + .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
1693 + .vidioc_decoder_cmd = vidioc_decoder_cmd,
1694 + .vidioc_try_decoder_cmd = vidioc_try_decoder_cmd,
1695 + .vidioc_encoder_cmd = vidioc_encoder_cmd,
1696 + .vidioc_try_encoder_cmd = vidioc_try_encoder_cmd,
1699 +static int bcm2835_codec_set_ctrls(struct bcm2835_codec_ctx *ctx)
1702 + * Query the control handler for the value of the various controls and
1705 + const u32 control_ids[] = {
1706 + V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
1707 + V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER,
1708 + V4L2_CID_MPEG_VIDEO_H264_I_PERIOD,
1709 + V4L2_CID_MPEG_VIDEO_H264_LEVEL,
1710 + V4L2_CID_MPEG_VIDEO_H264_PROFILE,
1714 + for (i = 0; i < ARRAY_SIZE(control_ids); i++) {
1715 + struct v4l2_ctrl *ctrl;
1717 + ctrl = v4l2_ctrl_find(&ctx->hdl, control_ids[i]);
1719 + bcm2835_codec_s_ctrl(ctrl);
1725 +static int bcm2835_codec_create_component(struct bcm2835_codec_ctx *ctx)
1727 + struct bcm2835_codec_dev *dev = ctx->dev;
1728 + unsigned int enable = 1;
1731 + ret = vchiq_mmal_component_init(dev->instance, dev->decode ?
1732 + "ril.video_decode" : "ril.video_encode",
1735 + v4l2_err(&dev->v4l2_dev, "%s: failed to create component for %s\n",
1736 + __func__, dev->decode ? "decode" : "encode");
1740 + vchiq_mmal_port_parameter_set(dev->instance, &ctx->component->input[0],
1741 + MMAL_PARAMETER_ZERO_COPY, &enable,
1743 + vchiq_mmal_port_parameter_set(dev->instance, &ctx->component->output[0],
1744 + MMAL_PARAMETER_ZERO_COPY, &enable,
1747 + setup_mmal_port_format(ctx, dev->decode, &ctx->q_data[V4L2_M2M_SRC],
1748 + &ctx->component->input[0]);
1750 + setup_mmal_port_format(ctx, dev->decode, &ctx->q_data[V4L2_M2M_DST],
1751 + &ctx->component->output[0]);
1753 + ret = vchiq_mmal_port_set_format(dev->instance,
1754 + &ctx->component->input[0]);
1756 + goto destroy_component;
1758 + ret = vchiq_mmal_port_set_format(dev->instance,
1759 + &ctx->component->output[0]);
1761 + goto destroy_component;
1763 + if (dev->decode) {
1764 + if (ctx->q_data[V4L2_M2M_DST].sizeimage <
1765 + ctx->component->output[0].minimum_buffer.size)
1766 + v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n",
1767 + ctx->q_data[V4L2_M2M_DST].sizeimage,
1768 + ctx->component->output[0].minimum_buffer.size);
1770 + if (ctx->q_data[V4L2_M2M_SRC].sizeimage <
1771 + ctx->component->output[0].minimum_buffer.size)
1772 + v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n",
1773 + ctx->q_data[V4L2_M2M_SRC].sizeimage,
1774 + ctx->component->output[0].minimum_buffer.size);
1776 + /* Now we have a component we can set all the ctrls */
1777 + bcm2835_codec_set_ctrls(ctx);
1783 + vchiq_mmal_component_finalise(ctx->dev->instance, ctx->component);
1789 + * Queue operations
1792 +static int bcm2835_codec_queue_setup(struct vb2_queue *vq,
1793 + unsigned int *nbuffers,
1794 + unsigned int *nplanes,
1795 + unsigned int sizes[],
1796 + struct device *alloc_devs[])
1798 + struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vq);
1799 + struct bcm2835_codec_q_data *q_data;
1800 + struct vchiq_mmal_port *port;
1801 + unsigned int size;
1803 + q_data = get_q_data(ctx, vq->type);
1807 + if (!ctx->component)
1808 + if (bcm2835_codec_create_component(ctx))
1811 + port = get_port_data(ctx, vq->type);
1813 + size = q_data->sizeimage;
1816 + return sizes[0] < size ? -EINVAL : 0;
1821 + port->current_buffer.size = size;
1823 + if (*nbuffers < port->minimum_buffer.num)
1824 + *nbuffers = port->minimum_buffer.num;
1825 + /* Add one buffer to take an EOS */
1826 + port->current_buffer.num = *nbuffers + 1;
1831 +static int bcm2835_codec_buf_init(struct vb2_buffer *vb)
1833 + struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1834 + struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb);
1835 + struct v4l2_m2m_buffer *m2m = container_of(vb2, struct v4l2_m2m_buffer,
1837 + struct m2m_mmal_buffer *buf = container_of(m2m, struct m2m_mmal_buffer,
1840 + v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: ctx:%p, vb %p\n",
1841 + __func__, ctx, vb);
1842 + buf->mmal.buffer = vb2_plane_vaddr(&buf->m2m.vb.vb2_buf, 0);
1843 + buf->mmal.buffer_size = vb2_plane_size(&buf->m2m.vb.vb2_buf, 0);
1845 + mmal_vchi_buffer_init(ctx->dev->instance, &buf->mmal);
1850 +static int bcm2835_codec_buf_prepare(struct vb2_buffer *vb)
1852 + struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1853 + struct bcm2835_codec_q_data *q_data;
1854 + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1855 + struct v4l2_m2m_buffer *m2m = container_of(vbuf, struct v4l2_m2m_buffer,
1857 + struct m2m_mmal_buffer *buf = container_of(m2m, struct m2m_mmal_buffer,
1861 + v4l2_dbg(4, debug, &ctx->dev->v4l2_dev, "%s: type: %d ptr %p\n",
1862 + __func__, vb->vb2_queue->type, vb);
1864 + q_data = get_q_data(ctx, vb->vb2_queue->type);
1865 + if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
1866 + if (vbuf->field == V4L2_FIELD_ANY)
1867 + vbuf->field = V4L2_FIELD_NONE;
1868 + if (vbuf->field != V4L2_FIELD_NONE) {
1869 + v4l2_err(&ctx->dev->v4l2_dev, "%s field isn't supported\n",
1875 + if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
1876 + v4l2_err(&ctx->dev->v4l2_dev, "%s data will not fit into plane (%lu < %lu)\n",
1877 + __func__, vb2_plane_size(vb, 0),
1878 + (long)q_data->sizeimage);
1882 + if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type))
1883 + vb2_set_plane_payload(vb, 0, q_data->sizeimage);
1886 + * We want to do this at init, but vb2_core_expbuf checks that the
1887 + * index < q->num_buffers, and q->num_buffers only gets updated once
1888 + * all the buffers are allocated.
1890 + if (!buf->mmal.dma_buf) {
1891 + ret = vb2_core_expbuf_dmabuf(vb->vb2_queue,
1892 + vb->vb2_queue->type, vb->index, 0,
1893 + O_CLOEXEC, &buf->mmal.dma_buf);
1895 + v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed to expbuf idx %d, ret %d\n",
1896 + __func__, vb->index, ret);
1904 +static void bcm2835_codec_buf_queue(struct vb2_buffer *vb)
1906 + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1907 + struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1909 + v4l2_dbg(4, debug, &ctx->dev->v4l2_dev, "%s: type: %d ptr %p vbuf->flags %u, seq %u, bytesused %u\n",
1910 + __func__, vb->vb2_queue->type, vb, vbuf->flags, vbuf->sequence,
1911 + vb->planes[0].bytesused);
1912 + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
1915 +static void bcm2835_codec_buffer_cleanup(struct vb2_buffer *vb)
1917 + struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1918 + struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb);
1919 + struct v4l2_m2m_buffer *m2m = container_of(vb2, struct v4l2_m2m_buffer,
1921 + struct m2m_mmal_buffer *buf = container_of(m2m, struct m2m_mmal_buffer,
1924 + v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: ctx:%p, vb %p\n",
1925 + __func__, ctx, vb);
1927 + mmal_vchi_buffer_cleanup(&buf->mmal);
1929 + if (buf->mmal.dma_buf) {
1930 + dma_buf_put(buf->mmal.dma_buf);
1931 + buf->mmal.dma_buf = NULL;
1935 +static int bcm2835_codec_start_streaming(struct vb2_queue *q,
1936 + unsigned int count)
1938 + struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(q);
1939 + struct bcm2835_codec_dev *dev = ctx->dev;
1940 + struct bcm2835_codec_q_data *q_data = get_q_data(ctx, q->type);
1943 + v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: type: %d count %d\n",
1944 + __func__, q->type, count);
1945 + q_data->sequence = 0;
1947 + if (!ctx->component_enabled) {
1948 + ret = vchiq_mmal_component_enable(dev->instance,
1951 + v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling component, ret %d\n",
1953 + ctx->component_enabled = true;
1956 + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
1958 + * Create the EOS buffer.
1959 + * We only need the MMAL part, and want to NOT attach a memory
1960 + * buffer to it as it should only take flags.
1962 + memset(&q_data->eos_buffer, 0, sizeof(q_data->eos_buffer));
1963 + mmal_vchi_buffer_init(dev->instance,
1964 + &q_data->eos_buffer.mmal);
1965 + q_data->eos_buffer_in_use = false;
1967 + ctx->component->input[0].cb_ctx = ctx;
1968 + ret = vchiq_mmal_port_enable(dev->instance,
1969 + &ctx->component->input[0],
1972 + v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling i/p port, ret %d\n",
1975 + ctx->component->output[0].cb_ctx = ctx;
1976 + ret = vchiq_mmal_port_enable(dev->instance,
1977 + &ctx->component->output[0],
1980 + v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling o/p port, ret %d\n",
1986 +static void bcm2835_codec_stop_streaming(struct vb2_queue *q)
1988 + struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(q);
1989 + struct bcm2835_codec_dev *dev = ctx->dev;
1990 + struct bcm2835_codec_q_data *q_data = get_q_data(ctx, q->type);
1991 + struct vchiq_mmal_port *port = get_port_data(ctx, q->type);
1992 + struct vb2_v4l2_buffer *vbuf;
1993 + struct vb2_v4l2_buffer *vb2;
1994 + struct v4l2_m2m_buffer *m2m;
1995 + struct m2m_mmal_buffer *buf;
1998 + v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: type: %d - return buffers\n",
1999 + __func__, q->type);
2001 + init_completion(&ctx->frame_cmplt);
2003 + /* Clear out all buffers held by m2m framework */
2005 + if (V4L2_TYPE_IS_OUTPUT(q->type))
2006 + vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
2008 + vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
2011 + v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: return buffer %p\n",
2014 + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
2017 + /* Disable MMAL port - this will flush buffers back */
2018 + ret = vchiq_mmal_port_disable(dev->instance, port);
2020 + v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed disabling %s port, ret %d\n",
2021 + __func__, V4L2_TYPE_IS_OUTPUT(q->type) ? "i/p" : "o/p",
2024 + while (atomic_read(&port->buffers_with_vpu)) {
2025 + v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Waiting for buffers to be returned - %d outstanding\n",
2026 + __func__, atomic_read(&port->buffers_with_vpu));
2027 + ret = wait_for_completion_timeout(&ctx->frame_cmplt, HZ);
2029 + v4l2_err(&ctx->dev->v4l2_dev, "%s: Timeout waiting for buffers to be returned - %d outstanding\n",
2031 + atomic_read(&port->buffers_with_vpu));
2037 + * Release the VCSM handle here as otherwise REQBUFS(0) aborts because
2038 + * someone is using the dmabuf before giving the driver a chance to do
2039 + * anything about it.
2041 + for (i = 0; i < q->num_buffers; i++) {
2042 + vb2 = to_vb2_v4l2_buffer(q->bufs[i]);
2043 + m2m = container_of(vb2, struct v4l2_m2m_buffer, vb);
2044 + buf = container_of(m2m, struct m2m_mmal_buffer, m2m);
2046 + mmal_vchi_buffer_cleanup(&buf->mmal);
2047 + if (buf->mmal.dma_buf) {
2048 + dma_buf_put(buf->mmal.dma_buf);
2049 + buf->mmal.dma_buf = NULL;
2053 + /* If both ports disabled, then disable the component */
2054 + if (!ctx->component->input[0].enabled &&
2055 + !ctx->component->output[0].enabled) {
2056 + ret = vchiq_mmal_component_disable(dev->instance,
2059 + v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling component, ret %d\n",
2063 + if (V4L2_TYPE_IS_OUTPUT(q->type))
2064 + mmal_vchi_buffer_cleanup(&q_data->eos_buffer.mmal);
2066 + v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: done\n", __func__);
2069 +static const struct vb2_ops bcm2835_codec_qops = {
2070 + .queue_setup = bcm2835_codec_queue_setup,
2071 + .buf_init = bcm2835_codec_buf_init,
2072 + .buf_prepare = bcm2835_codec_buf_prepare,
2073 + .buf_queue = bcm2835_codec_buf_queue,
2074 + .buf_cleanup = bcm2835_codec_buffer_cleanup,
2075 + .start_streaming = bcm2835_codec_start_streaming,
2076 + .stop_streaming = bcm2835_codec_stop_streaming,
2077 + .wait_prepare = vb2_ops_wait_prepare,
2078 + .wait_finish = vb2_ops_wait_finish,
2081 +static int queue_init(void *priv, struct vb2_queue *src_vq,
2082 + struct vb2_queue *dst_vq)
2084 + struct bcm2835_codec_ctx *ctx = priv;
2087 + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
2088 + src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
2089 + src_vq->drv_priv = ctx;
2090 + src_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer);
2091 + src_vq->ops = &bcm2835_codec_qops;
2092 + src_vq->mem_ops = &vb2_dma_contig_memops;
2093 + src_vq->dev = &ctx->dev->pdev->dev;
2094 + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
2095 + src_vq->lock = &ctx->dev->dev_mutex;
2097 + ret = vb2_queue_init(src_vq);
2101 + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2102 + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
2103 + dst_vq->drv_priv = ctx;
2104 + dst_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer);
2105 + dst_vq->ops = &bcm2835_codec_qops;
2106 + dst_vq->mem_ops = &vb2_dma_contig_memops;
2107 + dst_vq->dev = &ctx->dev->pdev->dev;
2108 + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
2109 + dst_vq->lock = &ctx->dev->dev_mutex;
2111 + return vb2_queue_init(dst_vq);
2117 +static int bcm2835_codec_open(struct file *file)
2119 + struct bcm2835_codec_dev *dev = video_drvdata(file);
2120 + struct bcm2835_codec_ctx *ctx = NULL;
2121 + struct v4l2_ctrl_handler *hdl;
2124 + v4l2_dbg(1, debug, &dev->v4l2_dev, "Creating instance for %s\n",
2125 + dev->decode ? "decode" : "encode");
2126 + if (mutex_lock_interruptible(&dev->dev_mutex)) {
2127 + v4l2_err(&dev->v4l2_dev, "Mutex fail\n");
2128 + return -ERESTARTSYS;
2130 + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
2136 + ctx->q_data[V4L2_M2M_SRC].fmt = get_default_format(dev->decode, false);
2137 + ctx->q_data[V4L2_M2M_DST].fmt = get_default_format(dev->decode, true);
2138 + if (dev->decode) {
2140 + * Input width and height are irrelevant as they will be defined
2141 + * by the bitstream not the format. Required by V4L2 though.
2143 + ctx->q_data[V4L2_M2M_SRC].crop_width = DEFAULT_WIDTH;
2144 + ctx->q_data[V4L2_M2M_SRC].crop_height = DEFAULT_HEIGHT;
2145 + ctx->q_data[V4L2_M2M_SRC].height = DEFAULT_HEIGHT;
2146 + ctx->q_data[V4L2_M2M_SRC].bytesperline = 0;
2147 + ctx->q_data[V4L2_M2M_SRC].sizeimage =
2148 + DEF_COMP_BUF_SIZE_720P_OR_LESS;
2150 + ctx->q_data[V4L2_M2M_DST].crop_width = DEFAULT_WIDTH;
2151 + ctx->q_data[V4L2_M2M_DST].crop_height = DEFAULT_HEIGHT;
2152 + ctx->q_data[V4L2_M2M_DST].height = DEFAULT_HEIGHT;
2153 + ctx->q_data[V4L2_M2M_DST].bytesperline =
2154 + get_bytesperline(DEFAULT_WIDTH,
2155 + ctx->q_data[V4L2_M2M_DST].fmt);
2156 + ctx->q_data[V4L2_M2M_DST].sizeimage =
2157 + get_sizeimage(ctx->q_data[V4L2_M2M_DST].bytesperline,
2158 + ctx->q_data[V4L2_M2M_DST].height,
2159 + ctx->q_data[V4L2_M2M_DST].fmt);
2161 + ctx->q_data[V4L2_M2M_SRC].crop_width = DEFAULT_WIDTH;
2162 + ctx->q_data[V4L2_M2M_SRC].crop_height = DEFAULT_HEIGHT;
2163 + ctx->q_data[V4L2_M2M_SRC].height = DEFAULT_HEIGHT;
2164 + ctx->q_data[V4L2_M2M_SRC].bytesperline =
2165 + get_bytesperline(DEFAULT_WIDTH,
2166 + ctx->q_data[V4L2_M2M_SRC].fmt);
2167 + ctx->q_data[V4L2_M2M_SRC].sizeimage =
2168 + get_sizeimage(ctx->q_data[V4L2_M2M_SRC].bytesperline,
2169 + ctx->q_data[V4L2_M2M_SRC].height,
2170 + ctx->q_data[V4L2_M2M_SRC].fmt);
2172 + ctx->q_data[V4L2_M2M_DST].crop_width = DEFAULT_WIDTH;
2173 + ctx->q_data[V4L2_M2M_DST].crop_height = DEFAULT_HEIGHT;
2174 + ctx->q_data[V4L2_M2M_DST].bytesperline = 0;
2175 + ctx->q_data[V4L2_M2M_DST].height = DEFAULT_HEIGHT;
2176 + ctx->q_data[V4L2_M2M_DST].sizeimage =
2177 + DEF_COMP_BUF_SIZE_720P_OR_LESS;
2180 + ctx->colorspace = V4L2_COLORSPACE_REC709;
2181 + ctx->bitrate = 10 * 1000 * 1000;
2183 + /* Initialise V4L2 contexts */
2184 + v4l2_fh_init(&ctx->fh, video_devdata(file));
2185 + file->private_data = &ctx->fh;
2188 + if (!dev->decode) {
2189 + /* Encode controls */
2190 + v4l2_ctrl_handler_init(hdl, 6);
2192 + v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops,
2193 + V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
2194 + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0,
2195 + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
2196 + v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops,
2197 + V4L2_CID_MPEG_VIDEO_BITRATE,
2198 + 25 * 1000, 25 * 1000 * 1000,
2199 + 25 * 1000, 10 * 1000 * 1000);
2200 + v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops,
2201 + V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER,
2204 + v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops,
2205 + V4L2_CID_MPEG_VIDEO_H264_I_PERIOD,
2208 + v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops,
2209 + V4L2_CID_MPEG_VIDEO_H264_LEVEL,
2210 + V4L2_MPEG_VIDEO_H264_LEVEL_4_2,
2211 + ~(BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
2212 + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) |
2213 + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) |
2214 + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) |
2215 + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) |
2216 + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
2217 + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) |
2218 + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) |
2219 + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
2220 + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
2221 + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
2222 + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) |
2223 + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) |
2224 + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2)),
2225 + V4L2_MPEG_VIDEO_H264_LEVEL_4_0);
2226 + v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops,
2227 + V4L2_CID_MPEG_VIDEO_H264_PROFILE,
2228 + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
2229 + ~(BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
2230 + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) |
2231 + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
2232 + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)),
2233 + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH);
2236 + goto free_ctrl_handler;
2238 + ctx->fh.ctrl_handler = hdl;
2239 + v4l2_ctrl_handler_setup(hdl);
2242 + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
2244 + if (IS_ERR(ctx->fh.m2m_ctx)) {
2245 + rc = PTR_ERR(ctx->fh.m2m_ctx);
2247 + goto free_ctrl_handler;
2250 + /* Set both queues as buffered as we have buffering in the VPU. That
2251 + * means that we will be scheduled whenever either an input or output
2252 + * buffer is available (otherwise one of each are required).
2254 + v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true);
2255 + v4l2_m2m_set_dst_buffered(ctx->fh.m2m_ctx, true);
2257 + v4l2_fh_add(&ctx->fh);
2258 + atomic_inc(&dev->num_inst);
2260 + mutex_unlock(&dev->dev_mutex);
2264 + v4l2_ctrl_handler_free(hdl);
2267 + mutex_unlock(&dev->dev_mutex);
2271 +static int bcm2835_codec_release(struct file *file)
2273 + struct bcm2835_codec_dev *dev = video_drvdata(file);
2274 + struct bcm2835_codec_ctx *ctx = file2ctx(file);
2276 + v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: Releasing instance %p\n",
2279 + v4l2_fh_del(&ctx->fh);
2280 + v4l2_fh_exit(&ctx->fh);
2281 + v4l2_ctrl_handler_free(&ctx->hdl);
2282 + mutex_lock(&dev->dev_mutex);
2283 + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
2285 + if (ctx->component)
2286 + vchiq_mmal_component_finalise(dev->instance, ctx->component);
2288 + mutex_unlock(&dev->dev_mutex);
2291 + atomic_dec(&dev->num_inst);
2296 +static const struct v4l2_file_operations bcm2835_codec_fops = {
2297 + .owner = THIS_MODULE,
2298 + .open = bcm2835_codec_open,
2299 + .release = bcm2835_codec_release,
2300 + .poll = v4l2_m2m_fop_poll,
2301 + .unlocked_ioctl = video_ioctl2,
2302 + .mmap = v4l2_m2m_fop_mmap,
2305 +static const struct video_device bcm2835_codec_videodev = {
2306 + .name = MEM2MEM_NAME,
2307 + .vfl_dir = VFL_DIR_M2M,
2308 + .fops = &bcm2835_codec_fops,
2309 + .ioctl_ops = &bcm2835_codec_ioctl_ops,
2311 + .release = video_device_release_empty,
2314 +static const struct v4l2_m2m_ops m2m_ops = {
2315 + .device_run = device_run,
2316 + .job_ready = job_ready,
2317 + .job_abort = job_abort,
2320 +static int bcm2835_codec_create(struct platform_device *pdev,
2321 + struct bcm2835_codec_dev **new_dev,
2324 + struct bcm2835_codec_dev *dev;
2325 + struct video_device *vfd;
2326 + struct vchiq_mmal_instance *instance = NULL;
2330 + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
2336 + dev->decode = decode;
2338 + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
2342 + atomic_set(&dev->num_inst, 0);
2343 + mutex_init(&dev->dev_mutex);
2345 + dev->vfd = bcm2835_codec_videodev;
2347 + vfd->lock = &dev->dev_mutex;
2348 + vfd->v4l2_dev = &dev->v4l2_dev;
2350 + if (dev->decode) {
2351 + v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD);
2352 + v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
2353 + video_nr = decode_video_nr;
2355 + v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
2356 + v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
2357 + video_nr = encode_video_nr;
2360 + ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
2362 + v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
2366 + video_set_drvdata(vfd, dev);
2367 + snprintf(vfd->name, sizeof(vfd->name), "%s",
2368 + bcm2835_codec_videodev.name);
2369 + v4l2_info(&dev->v4l2_dev, "Device registered as /dev/video%d\n",
2374 + dev->m2m_dev = v4l2_m2m_init(&m2m_ops);
2375 + if (IS_ERR(dev->m2m_dev)) {
2376 + v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
2377 + ret = PTR_ERR(dev->m2m_dev);
2381 + ret = vchiq_mmal_init(&instance);
2384 + dev->instance = instance;
2386 + v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s codec\n",
2387 + dev->decode ? "decode" : "encode");
2391 + v4l2_m2m_release(dev->m2m_dev);
2392 + video_unregister_device(&dev->vfd);
2394 + v4l2_device_unregister(&dev->v4l2_dev);
2399 +static int bcm2835_codec_destroy(struct bcm2835_codec_dev *dev)
2404 + v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME);
2405 + v4l2_m2m_release(dev->m2m_dev);
2406 + video_unregister_device(&dev->vfd);
2407 + v4l2_device_unregister(&dev->v4l2_dev);
2412 +static int bcm2835_codec_probe(struct platform_device *pdev)
2414 + struct bcm2835_codec_driver *drv;
2417 + drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
2421 + ret = bcm2835_codec_create(pdev, &drv->encode, false);
2425 + ret = bcm2835_codec_create(pdev, &drv->decode, true);
2429 + platform_set_drvdata(pdev, drv);
2434 + if (drv->encode) {
2435 + bcm2835_codec_destroy(drv->encode);
2436 + drv->encode = NULL;
2441 +static int bcm2835_codec_remove(struct platform_device *pdev)
2443 + struct bcm2835_codec_driver *drv = platform_get_drvdata(pdev);
2445 + bcm2835_codec_destroy(drv->encode);
2447 + bcm2835_codec_destroy(drv->decode);
2452 +static struct platform_driver bcm2835_v4l2_codec_driver = {
2453 + .probe = bcm2835_codec_probe,
2454 + .remove = bcm2835_codec_remove,
2456 + .name = "bcm2835-codec",
2457 + .owner = THIS_MODULE,
2461 +module_platform_driver(bcm2835_v4l2_codec_driver);
2463 +MODULE_DESCRIPTION("BCM2835 codec V4L2 driver");
2464 +MODULE_AUTHOR("Dave Stevenson, <dave.stevenson@raspberrypi.org>");
2465 +MODULE_LICENSE("GPL");
2466 +MODULE_VERSION("0.0.1");
2467 +MODULE_ALIAS("platform:bcm2835-codec");