1 // SPDX-License-Identifier: GPL-2.0-only
3 * A virtual codec example device.
5 * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
7 * This is a virtual codec device driver for testing the codec framework.
8 * It simulates a device that uses memory buffers for both source and
9 * destination and encodes or decodes the data.
12 #include <linux/module.h>
13 #include <linux/delay.h>
15 #include <linux/sched.h>
16 #include <linux/slab.h>
18 #include <linux/platform_device.h>
19 #include <media/v4l2-mem2mem.h>
20 #include <media/v4l2-device.h>
21 #include <media/v4l2-ioctl.h>
22 #include <media/v4l2-ctrls.h>
23 #include <media/v4l2-event.h>
24 #include <media/videobuf2-vmalloc.h>
26 #include "codec-v4l2-fwht.h"
28 MODULE_DESCRIPTION("Virtual codec device");
29 MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com>");
30 MODULE_LICENSE("GPL v2");
32 static bool multiplanar;
33 module_param(multiplanar, bool, 0444);
34 MODULE_PARM_DESC(multiplanar,
35 " use multi-planar API instead of single-planar API");
37 static unsigned int debug;
38 module_param(debug, uint, 0644);
39 MODULE_PARM_DESC(debug, " activates debug info");
41 #define VICODEC_NAME "vicodec"
42 #define MAX_WIDTH 4096U
43 #define MIN_WIDTH 640U
44 #define MAX_HEIGHT 2160U
45 #define MIN_HEIGHT 360U
47 #define dprintk(dev, fmt, arg...) \
48 v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
53 unsigned int bytesperline_mult;
54 unsigned int sizeimage_mult;
55 unsigned int sizeimage_div;
56 unsigned int luma_step;
57 unsigned int chroma_step;
58 /* Chroma plane subsampling */
59 unsigned int width_div;
60 unsigned int height_div;
63 static const struct v4l2_fwht_pixfmt_info pixfmt_fwht = {
64 V4L2_PIX_FMT_FWHT, 0, 3, 1, 1, 1, 1, 1, 0, 1
67 static void vicodec_dev_release(struct device *dev)
71 static struct platform_device vicodec_pdev = {
73 .dev.release = vicodec_dev_release,
76 /* Per-queue, driver-specific private data */
77 struct vicodec_q_data {
78 unsigned int coded_width;
79 unsigned int coded_height;
80 unsigned int visible_width;
81 unsigned int visible_height;
82 unsigned int sizeimage;
83 unsigned int sequence;
84 const struct v4l2_fwht_pixfmt_info *info;
93 struct v4l2_device v4l2_dev;
94 struct video_device enc_vfd;
95 struct video_device dec_vfd;
96 #ifdef CONFIG_MEDIA_CONTROLLER
97 struct media_device mdev;
100 struct mutex enc_mutex;
101 struct mutex dec_mutex;
105 struct v4l2_m2m_dev *enc_dev;
106 struct v4l2_m2m_dev *dec_dev;
111 struct vicodec_dev *dev;
115 struct v4l2_ctrl_handler hdl;
117 struct vb2_v4l2_buffer *last_src_buf;
118 struct vb2_v4l2_buffer *last_dst_buf;
120 /* Source and destination queue data */
121 struct vicodec_q_data q_data[2];
122 struct v4l2_fwht_state state;
130 bool comp_has_next_frame;
131 bool first_source_change_sent;
135 static inline struct vicodec_ctx *file2ctx(struct file *file)
137 return container_of(file->private_data, struct vicodec_ctx, fh);
140 static struct vicodec_q_data *get_q_data(struct vicodec_ctx *ctx,
141 enum v4l2_buf_type type)
144 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
145 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
146 return &ctx->q_data[V4L2_M2M_SRC];
147 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
148 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
149 return &ctx->q_data[V4L2_M2M_DST];
156 static int device_process(struct vicodec_ctx *ctx,
157 struct vb2_v4l2_buffer *src_vb,
158 struct vb2_v4l2_buffer *dst_vb)
160 struct vicodec_dev *dev = ctx->dev;
161 struct vicodec_q_data *q_dst;
162 struct v4l2_fwht_state *state = &ctx->state;
166 q_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
168 p_src = vb2_plane_vaddr(&src_vb->vb2_buf, 0);
170 p_src = state->compressed_frame;
171 p_dst = vb2_plane_vaddr(&dst_vb->vb2_buf, 0);
172 if (!p_src || !p_dst) {
173 v4l2_err(&dev->v4l2_dev,
174 "Acquiring kernel pointers to buffers failed\n");
179 struct vicodec_q_data *q_src;
180 int comp_sz_or_errcode;
182 q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
183 state->info = q_src->info;
184 comp_sz_or_errcode = v4l2_fwht_encode(state, p_src, p_dst);
185 if (comp_sz_or_errcode < 0)
186 return comp_sz_or_errcode;
187 vb2_set_plane_payload(&dst_vb->vb2_buf, 0, comp_sz_or_errcode);
189 unsigned int comp_frame_size = ntohl(ctx->state.header.size);
191 if (comp_frame_size > ctx->comp_max_size)
193 state->info = q_dst->info;
194 ret = v4l2_fwht_decode(state, p_src, p_dst);
197 vb2_set_plane_payload(&dst_vb->vb2_buf, 0, q_dst->sizeimage);
200 dst_vb->sequence = q_dst->sequence++;
201 dst_vb->flags &= ~V4L2_BUF_FLAG_LAST;
202 v4l2_m2m_buf_copy_metadata(src_vb, dst_vb, !ctx->is_enc);
210 static enum vb2_buffer_state get_next_header(struct vicodec_ctx *ctx,
213 static const u8 magic[] = {
214 0x4f, 0x4f, 0x4f, 0x4f, 0xff, 0xff, 0xff, 0xff
218 u8 *header = (u8 *)&ctx->state.header;
220 state = VB2_BUF_STATE_DONE;
222 if (!ctx->header_size) {
223 state = VB2_BUF_STATE_ERROR;
224 for (; p < *pp + sz; p++) {
227 p = memchr(p, magic[ctx->comp_magic_cnt],
230 ctx->comp_magic_cnt = 0;
234 copy = sizeof(magic) - ctx->comp_magic_cnt;
235 if (*pp + sz - p < copy)
238 memcpy(header + ctx->comp_magic_cnt, p, copy);
239 ctx->comp_magic_cnt += copy;
240 if (!memcmp(header, magic, ctx->comp_magic_cnt)) {
242 state = VB2_BUF_STATE_DONE;
245 ctx->comp_magic_cnt = 0;
247 if (ctx->comp_magic_cnt < sizeof(magic)) {
251 ctx->header_size = sizeof(magic);
254 if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
255 u32 copy = sizeof(struct fwht_cframe_hdr) - ctx->header_size;
257 if (*pp + sz - p < copy)
260 memcpy(header + ctx->header_size, p, copy);
262 ctx->header_size += copy;
268 /* device_run() - prepares and starts the device */
269 static void device_run(void *priv)
271 static const struct v4l2_event eos_event = {
272 .type = V4L2_EVENT_EOS
274 struct vicodec_ctx *ctx = priv;
275 struct vicodec_dev *dev = ctx->dev;
276 struct vb2_v4l2_buffer *src_buf, *dst_buf;
277 struct vicodec_q_data *q_src;
280 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
281 dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
282 q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
284 state = VB2_BUF_STATE_DONE;
285 if (device_process(ctx, src_buf, dst_buf))
286 state = VB2_BUF_STATE_ERROR;
287 ctx->last_dst_buf = dst_buf;
289 spin_lock(ctx->lock);
290 if (!ctx->comp_has_next_frame && src_buf == ctx->last_src_buf) {
291 dst_buf->flags |= V4L2_BUF_FLAG_LAST;
292 v4l2_event_queue_fh(&ctx->fh, &eos_event);
295 src_buf->sequence = q_src->sequence++;
296 src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
297 v4l2_m2m_buf_done(src_buf, state);
298 } else if (vb2_get_plane_payload(&src_buf->vb2_buf, 0) == ctx->cur_buf_offset) {
299 src_buf->sequence = q_src->sequence++;
300 src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
301 v4l2_m2m_buf_done(src_buf, state);
302 ctx->cur_buf_offset = 0;
303 ctx->comp_has_next_frame = false;
305 v4l2_m2m_buf_done(dst_buf, state);
307 ctx->header_size = 0;
308 ctx->comp_magic_cnt = 0;
309 ctx->comp_has_frame = false;
310 spin_unlock(ctx->lock);
313 v4l2_m2m_job_finish(dev->enc_dev, ctx->fh.m2m_ctx);
315 v4l2_m2m_job_finish(dev->dec_dev, ctx->fh.m2m_ctx);
318 static void job_remove_src_buf(struct vicodec_ctx *ctx, u32 state)
320 struct vb2_v4l2_buffer *src_buf;
321 struct vicodec_q_data *q_src;
323 q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
324 spin_lock(ctx->lock);
325 src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
326 src_buf->sequence = q_src->sequence++;
327 v4l2_m2m_buf_done(src_buf, state);
328 ctx->cur_buf_offset = 0;
329 spin_unlock(ctx->lock);
332 static const struct v4l2_fwht_pixfmt_info *
333 info_from_header(const struct fwht_cframe_hdr *p_hdr)
335 unsigned int flags = ntohl(p_hdr->flags);
336 unsigned int width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2;
337 unsigned int height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2;
338 unsigned int components_num = 3;
339 unsigned int pixenc = 0;
340 unsigned int version = ntohl(p_hdr->version);
343 components_num = 1 + ((flags & FWHT_FL_COMPONENTS_NUM_MSK) >>
344 FWHT_FL_COMPONENTS_NUM_OFFSET);
345 pixenc = (flags & FWHT_FL_PIXENC_MSK);
347 return v4l2_fwht_default_fmt(width_div, height_div,
348 components_num, pixenc, 0);
351 static bool is_header_valid(const struct fwht_cframe_hdr *p_hdr)
353 const struct v4l2_fwht_pixfmt_info *info;
354 unsigned int w = ntohl(p_hdr->width);
355 unsigned int h = ntohl(p_hdr->height);
356 unsigned int version = ntohl(p_hdr->version);
357 unsigned int flags = ntohl(p_hdr->flags);
359 if (!version || version > FWHT_VERSION)
362 if (w < MIN_WIDTH || w > MAX_WIDTH || h < MIN_HEIGHT || h > MAX_HEIGHT)
366 unsigned int components_num = 1 +
367 ((flags & FWHT_FL_COMPONENTS_NUM_MSK) >>
368 FWHT_FL_COMPONENTS_NUM_OFFSET);
369 unsigned int pixenc = flags & FWHT_FL_PIXENC_MSK;
371 if (components_num == 0 || components_num > 4 || !pixenc)
375 info = info_from_header(p_hdr);
381 static void update_capture_data_from_header(struct vicodec_ctx *ctx)
383 struct vicodec_q_data *q_dst = get_q_data(ctx,
384 V4L2_BUF_TYPE_VIDEO_CAPTURE);
385 const struct fwht_cframe_hdr *p_hdr = &ctx->state.header;
386 const struct v4l2_fwht_pixfmt_info *info = info_from_header(p_hdr);
387 unsigned int flags = ntohl(p_hdr->flags);
388 unsigned int hdr_width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2;
389 unsigned int hdr_height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2;
392 q_dst->visible_width = ntohl(p_hdr->width);
393 q_dst->visible_height = ntohl(p_hdr->height);
394 q_dst->coded_width = vic_round_dim(q_dst->visible_width, hdr_width_div);
395 q_dst->coded_height = vic_round_dim(q_dst->visible_height,
398 q_dst->sizeimage = q_dst->coded_width * q_dst->coded_height *
399 q_dst->info->sizeimage_mult / q_dst->info->sizeimage_div;
400 ctx->state.colorspace = ntohl(p_hdr->colorspace);
402 ctx->state.xfer_func = ntohl(p_hdr->xfer_func);
403 ctx->state.ycbcr_enc = ntohl(p_hdr->ycbcr_enc);
404 ctx->state.quantization = ntohl(p_hdr->quantization);
407 static void set_last_buffer(struct vb2_v4l2_buffer *dst_buf,
408 const struct vb2_v4l2_buffer *src_buf,
409 struct vicodec_ctx *ctx)
411 struct vicodec_q_data *q_dst = get_q_data(ctx,
412 V4L2_BUF_TYPE_VIDEO_CAPTURE);
414 vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
415 dst_buf->sequence = q_dst->sequence++;
417 v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, !ctx->is_enc);
418 dst_buf->flags |= V4L2_BUF_FLAG_LAST;
419 v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
422 static int job_ready(void *priv)
424 static const u8 magic[] = {
425 0x4f, 0x4f, 0x4f, 0x4f, 0xff, 0xff, 0xff, 0xff
427 struct vicodec_ctx *ctx = priv;
428 struct vb2_v4l2_buffer *src_buf;
433 struct vicodec_q_data *q_dst = get_q_data(ctx,
434 V4L2_BUF_TYPE_VIDEO_CAPTURE);
436 unsigned int hdr_width_div;
437 unsigned int hdr_height_div;
438 unsigned int max_to_copy;
439 unsigned int comp_frame_size;
441 if (ctx->source_changed)
443 if (ctx->is_enc || ctx->comp_has_frame)
447 ctx->comp_has_next_frame = false;
448 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
451 p_src = vb2_plane_vaddr(&src_buf->vb2_buf, 0);
452 sz = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
453 p = p_src + ctx->cur_buf_offset;
455 state = VB2_BUF_STATE_DONE;
457 if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
458 state = get_next_header(ctx, &p, p_src + sz - p);
459 if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
460 job_remove_src_buf(ctx, state);
465 comp_frame_size = ntohl(ctx->state.header.size);
468 * The current scanned frame might be the first frame of a new
469 * resolution so its size might be larger than ctx->comp_max_size.
470 * In that case it is copied up to the current buffer capacity and
471 * the copy will continue after allocating new large enough buffer
474 max_to_copy = min(comp_frame_size, ctx->comp_max_size);
476 if (ctx->comp_size < max_to_copy) {
477 u32 copy = max_to_copy - ctx->comp_size;
479 if (copy > p_src + sz - p)
480 copy = p_src + sz - p;
482 memcpy(ctx->state.compressed_frame + ctx->comp_size,
485 ctx->comp_size += copy;
486 if (ctx->comp_size < max_to_copy) {
487 job_remove_src_buf(ctx, state);
491 ctx->cur_buf_offset = p - p_src;
492 if (ctx->comp_size == comp_frame_size)
493 ctx->comp_has_frame = true;
494 ctx->comp_has_next_frame = false;
495 if (ctx->comp_has_frame && sz - ctx->cur_buf_offset >=
496 sizeof(struct fwht_cframe_hdr)) {
497 struct fwht_cframe_hdr *p_hdr = (struct fwht_cframe_hdr *)p;
498 u32 frame_size = ntohl(p_hdr->size);
499 u32 remaining = sz - ctx->cur_buf_offset - sizeof(*p_hdr);
501 if (!memcmp(p, magic, sizeof(magic)))
502 ctx->comp_has_next_frame = remaining >= frame_size;
505 * if the header is invalid the device_run will just drop the frame
508 if (!is_header_valid(&ctx->state.header) && ctx->comp_has_frame)
510 flags = ntohl(ctx->state.header.flags);
511 hdr_width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2;
512 hdr_height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2;
514 if (ntohl(ctx->state.header.width) != q_dst->visible_width ||
515 ntohl(ctx->state.header.height) != q_dst->visible_height ||
517 hdr_width_div != q_dst->info->width_div ||
518 hdr_height_div != q_dst->info->height_div) {
519 static const struct v4l2_event rs_event = {
520 .type = V4L2_EVENT_SOURCE_CHANGE,
521 .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
524 struct vb2_v4l2_buffer *dst_buf =
525 v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
527 update_capture_data_from_header(ctx);
528 ctx->first_source_change_sent = true;
529 v4l2_event_queue_fh(&ctx->fh, &rs_event);
530 set_last_buffer(dst_buf, src_buf, ctx);
531 ctx->source_changed = true;
541 static const struct v4l2_fwht_pixfmt_info *find_fmt(u32 fmt)
543 const struct v4l2_fwht_pixfmt_info *info =
544 v4l2_fwht_find_pixfmt(fmt);
547 info = v4l2_fwht_get_pixfmt(0);
551 static int vidioc_querycap(struct file *file, void *priv,
552 struct v4l2_capability *cap)
554 strncpy(cap->driver, VICODEC_NAME, sizeof(cap->driver) - 1);
555 strncpy(cap->card, VICODEC_NAME, sizeof(cap->card) - 1);
556 snprintf(cap->bus_info, sizeof(cap->bus_info),
557 "platform:%s", VICODEC_NAME);
561 static int enum_fmt(struct v4l2_fmtdesc *f, struct vicodec_ctx *ctx,
564 bool is_uncomp = (ctx->is_enc && is_out) || (!ctx->is_enc && !is_out);
566 if (V4L2_TYPE_IS_MULTIPLANAR(f->type) && !multiplanar)
568 if (!V4L2_TYPE_IS_MULTIPLANAR(f->type) && multiplanar)
572 const struct v4l2_fwht_pixfmt_info *info =
573 get_q_data(ctx, f->type)->info;
575 if (!info || ctx->is_enc)
576 info = v4l2_fwht_get_pixfmt(f->index);
578 info = v4l2_fwht_default_fmt(info->width_div,
580 info->components_num,
585 f->pixelformat = info->id;
589 f->pixelformat = V4L2_PIX_FMT_FWHT;
594 static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
595 struct v4l2_fmtdesc *f)
597 struct vicodec_ctx *ctx = file2ctx(file);
599 return enum_fmt(f, ctx, false);
602 static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
603 struct v4l2_fmtdesc *f)
605 struct vicodec_ctx *ctx = file2ctx(file);
607 return enum_fmt(f, ctx, true);
610 static int vidioc_g_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
612 struct vb2_queue *vq;
613 struct vicodec_q_data *q_data;
614 struct v4l2_pix_format_mplane *pix_mp;
615 struct v4l2_pix_format *pix;
616 const struct v4l2_fwht_pixfmt_info *info;
618 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
622 q_data = get_q_data(ctx, f->type);
626 info = v4l2_fwht_get_pixfmt(0);
629 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
630 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
634 pix->width = q_data->coded_width;
635 pix->height = q_data->coded_height;
636 pix->field = V4L2_FIELD_NONE;
637 pix->pixelformat = info->id;
638 pix->bytesperline = q_data->coded_width *
639 info->bytesperline_mult;
640 pix->sizeimage = q_data->sizeimage;
641 pix->colorspace = ctx->state.colorspace;
642 pix->xfer_func = ctx->state.xfer_func;
643 pix->ycbcr_enc = ctx->state.ycbcr_enc;
644 pix->quantization = ctx->state.quantization;
647 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
648 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
651 pix_mp = &f->fmt.pix_mp;
652 pix_mp->width = q_data->coded_width;
653 pix_mp->height = q_data->coded_height;
654 pix_mp->field = V4L2_FIELD_NONE;
655 pix_mp->pixelformat = info->id;
656 pix_mp->num_planes = 1;
657 pix_mp->plane_fmt[0].bytesperline =
658 q_data->coded_width * info->bytesperline_mult;
659 pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage;
660 pix_mp->colorspace = ctx->state.colorspace;
661 pix_mp->xfer_func = ctx->state.xfer_func;
662 pix_mp->ycbcr_enc = ctx->state.ycbcr_enc;
663 pix_mp->quantization = ctx->state.quantization;
664 memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
665 memset(pix_mp->plane_fmt[0].reserved, 0,
666 sizeof(pix_mp->plane_fmt[0].reserved));
674 static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
675 struct v4l2_format *f)
677 return vidioc_g_fmt(file2ctx(file), f);
680 static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
681 struct v4l2_format *f)
683 return vidioc_g_fmt(file2ctx(file), f);
686 static int vidioc_try_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
688 struct v4l2_pix_format_mplane *pix_mp;
689 struct v4l2_pix_format *pix;
690 struct v4l2_plane_pix_format *plane;
691 const struct v4l2_fwht_pixfmt_info *info = &pixfmt_fwht;
694 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
695 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
697 if (pix->pixelformat != V4L2_PIX_FMT_FWHT)
698 info = find_fmt(pix->pixelformat);
700 pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH);
701 pix->width = vic_round_dim(pix->width, info->width_div);
703 pix->height = clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT);
704 pix->height = vic_round_dim(pix->height, info->height_div);
706 pix->field = V4L2_FIELD_NONE;
708 pix->width * info->bytesperline_mult;
709 pix->sizeimage = pix->width * pix->height *
710 info->sizeimage_mult / info->sizeimage_div;
711 if (pix->pixelformat == V4L2_PIX_FMT_FWHT)
712 pix->sizeimage += sizeof(struct fwht_cframe_hdr);
714 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
715 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
716 pix_mp = &f->fmt.pix_mp;
717 plane = pix_mp->plane_fmt;
718 if (pix_mp->pixelformat != V4L2_PIX_FMT_FWHT)
719 info = find_fmt(pix_mp->pixelformat);
720 pix_mp->num_planes = 1;
722 pix_mp->width = clamp(pix_mp->width, MIN_WIDTH, MAX_WIDTH);
723 pix_mp->width = vic_round_dim(pix_mp->width, info->width_div);
725 pix_mp->height = clamp(pix_mp->height, MIN_HEIGHT, MAX_HEIGHT);
726 pix_mp->height = vic_round_dim(pix_mp->height,
729 pix_mp->field = V4L2_FIELD_NONE;
730 plane->bytesperline =
731 pix_mp->width * info->bytesperline_mult;
732 plane->sizeimage = pix_mp->width * pix_mp->height *
733 info->sizeimage_mult / info->sizeimage_div;
734 if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT)
735 plane->sizeimage += sizeof(struct fwht_cframe_hdr);
736 memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
737 memset(plane->reserved, 0, sizeof(plane->reserved));
746 static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
747 struct v4l2_format *f)
749 struct vicodec_ctx *ctx = file2ctx(file);
750 struct v4l2_pix_format_mplane *pix_mp;
751 struct v4l2_pix_format *pix;
754 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
758 pix->pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT :
759 find_fmt(f->fmt.pix.pixelformat)->id;
760 pix->colorspace = ctx->state.colorspace;
761 pix->xfer_func = ctx->state.xfer_func;
762 pix->ycbcr_enc = ctx->state.ycbcr_enc;
763 pix->quantization = ctx->state.quantization;
765 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
768 pix_mp = &f->fmt.pix_mp;
769 pix_mp->pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT :
770 find_fmt(pix_mp->pixelformat)->id;
771 pix_mp->colorspace = ctx->state.colorspace;
772 pix_mp->xfer_func = ctx->state.xfer_func;
773 pix_mp->ycbcr_enc = ctx->state.ycbcr_enc;
774 pix_mp->quantization = ctx->state.quantization;
780 return vidioc_try_fmt(ctx, f);
783 static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
784 struct v4l2_format *f)
786 struct vicodec_ctx *ctx = file2ctx(file);
787 struct v4l2_pix_format_mplane *pix_mp;
788 struct v4l2_pix_format *pix;
791 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
795 pix->pixelformat = !ctx->is_enc ? V4L2_PIX_FMT_FWHT :
796 find_fmt(pix->pixelformat)->id;
797 if (!pix->colorspace)
798 pix->colorspace = V4L2_COLORSPACE_REC709;
800 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
803 pix_mp = &f->fmt.pix_mp;
804 pix_mp->pixelformat = !ctx->is_enc ? V4L2_PIX_FMT_FWHT :
805 find_fmt(pix_mp->pixelformat)->id;
806 if (!pix_mp->colorspace)
807 pix_mp->colorspace = V4L2_COLORSPACE_REC709;
813 return vidioc_try_fmt(ctx, f);
816 static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
818 struct vicodec_q_data *q_data;
819 struct vb2_queue *vq;
820 bool fmt_changed = true;
821 struct v4l2_pix_format_mplane *pix_mp;
822 struct v4l2_pix_format *pix;
824 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
828 q_data = get_q_data(ctx, f->type);
833 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
834 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
836 if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type))
839 q_data->info->id != pix->pixelformat ||
840 q_data->coded_width != pix->width ||
841 q_data->coded_height != pix->height;
843 if (vb2_is_busy(vq) && fmt_changed)
846 if (pix->pixelformat == V4L2_PIX_FMT_FWHT)
847 q_data->info = &pixfmt_fwht;
849 q_data->info = find_fmt(pix->pixelformat);
850 q_data->coded_width = pix->width;
851 q_data->coded_height = pix->height;
852 q_data->sizeimage = pix->sizeimage;
854 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
855 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
856 pix_mp = &f->fmt.pix_mp;
857 if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type))
860 q_data->info->id != pix_mp->pixelformat ||
861 q_data->coded_width != pix_mp->width ||
862 q_data->coded_height != pix_mp->height;
864 if (vb2_is_busy(vq) && fmt_changed)
867 if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT)
868 q_data->info = &pixfmt_fwht;
870 q_data->info = find_fmt(pix_mp->pixelformat);
871 q_data->coded_width = pix_mp->width;
872 q_data->coded_height = pix_mp->height;
873 q_data->sizeimage = pix_mp->plane_fmt[0].sizeimage;
878 if (q_data->visible_width > q_data->coded_width)
879 q_data->visible_width = q_data->coded_width;
880 if (q_data->visible_height > q_data->coded_height)
881 q_data->visible_height = q_data->coded_height;
885 "Setting format for type %d, coded wxh: %dx%d, visible wxh: %dx%d, fourcc: %08x\n",
886 f->type, q_data->coded_width, q_data->coded_height,
887 q_data->visible_width, q_data->visible_height,
893 static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
894 struct v4l2_format *f)
898 ret = vidioc_try_fmt_vid_cap(file, priv, f);
902 return vidioc_s_fmt(file2ctx(file), f);
905 static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
906 struct v4l2_format *f)
908 struct vicodec_ctx *ctx = file2ctx(file);
909 struct v4l2_pix_format_mplane *pix_mp;
910 struct v4l2_pix_format *pix;
913 ret = vidioc_try_fmt_vid_out(file, priv, f);
917 ret = vidioc_s_fmt(file2ctx(file), f);
920 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
921 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
923 ctx->state.colorspace = pix->colorspace;
924 ctx->state.xfer_func = pix->xfer_func;
925 ctx->state.ycbcr_enc = pix->ycbcr_enc;
926 ctx->state.quantization = pix->quantization;
928 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
929 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
930 pix_mp = &f->fmt.pix_mp;
931 ctx->state.colorspace = pix_mp->colorspace;
932 ctx->state.xfer_func = pix_mp->xfer_func;
933 ctx->state.ycbcr_enc = pix_mp->ycbcr_enc;
934 ctx->state.quantization = pix_mp->quantization;
943 static int vidioc_g_selection(struct file *file, void *priv,
944 struct v4l2_selection *s)
946 struct vicodec_ctx *ctx = file2ctx(file);
947 struct vicodec_q_data *q_data;
949 q_data = get_q_data(ctx, s->type);
953 * encoder supports only cropping on the OUTPUT buffer
954 * decoder supports only composing on the CAPTURE buffer
956 if (ctx->is_enc && s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
958 case V4L2_SEL_TGT_CROP:
961 s->r.width = q_data->visible_width;
962 s->r.height = q_data->visible_height;
964 case V4L2_SEL_TGT_CROP_DEFAULT:
965 case V4L2_SEL_TGT_CROP_BOUNDS:
968 s->r.width = q_data->coded_width;
969 s->r.height = q_data->coded_height;
972 } else if (!ctx->is_enc && s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
974 case V4L2_SEL_TGT_COMPOSE:
977 s->r.width = q_data->visible_width;
978 s->r.height = q_data->visible_height;
980 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
981 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
984 s->r.width = q_data->coded_width;
985 s->r.height = q_data->coded_height;
992 static int vidioc_s_selection(struct file *file, void *priv,
993 struct v4l2_selection *s)
995 struct vicodec_ctx *ctx = file2ctx(file);
996 struct vicodec_q_data *q_data;
998 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
1001 q_data = get_q_data(ctx, s->type);
1005 if (!ctx->is_enc || s->target != V4L2_SEL_TGT_CROP)
1010 q_data->visible_width = clamp(s->r.width, MIN_WIDTH,
1011 q_data->coded_width);
1012 s->r.width = q_data->visible_width;
1013 q_data->visible_height = clamp(s->r.height, MIN_HEIGHT,
1014 q_data->coded_height);
1015 s->r.height = q_data->visible_height;
1019 static void vicodec_mark_last_buf(struct vicodec_ctx *ctx)
1021 static const struct v4l2_event eos_event = {
1022 .type = V4L2_EVENT_EOS
1025 spin_lock(ctx->lock);
1026 ctx->last_src_buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx);
1027 if (!ctx->last_src_buf && ctx->last_dst_buf) {
1028 ctx->last_dst_buf->flags |= V4L2_BUF_FLAG_LAST;
1029 v4l2_event_queue_fh(&ctx->fh, &eos_event);
1031 spin_unlock(ctx->lock);
1034 static int vicodec_try_encoder_cmd(struct file *file, void *fh,
1035 struct v4l2_encoder_cmd *ec)
1037 if (ec->cmd != V4L2_ENC_CMD_STOP)
1040 if (ec->flags & V4L2_ENC_CMD_STOP_AT_GOP_END)
1046 static int vicodec_encoder_cmd(struct file *file, void *fh,
1047 struct v4l2_encoder_cmd *ec)
1049 struct vicodec_ctx *ctx = file2ctx(file);
1052 ret = vicodec_try_encoder_cmd(file, fh, ec);
1056 vicodec_mark_last_buf(ctx);
1060 static int vicodec_try_decoder_cmd(struct file *file, void *fh,
1061 struct v4l2_decoder_cmd *dc)
1063 if (dc->cmd != V4L2_DEC_CMD_STOP)
1066 if (dc->flags & V4L2_DEC_CMD_STOP_TO_BLACK)
1069 if (!(dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) && (dc->stop.pts != 0))
1075 static int vicodec_decoder_cmd(struct file *file, void *fh,
1076 struct v4l2_decoder_cmd *dc)
1078 struct vicodec_ctx *ctx = file2ctx(file);
1081 ret = vicodec_try_decoder_cmd(file, fh, dc);
1085 vicodec_mark_last_buf(ctx);
1089 static int vicodec_enum_framesizes(struct file *file, void *fh,
1090 struct v4l2_frmsizeenum *fsize)
1092 switch (fsize->pixel_format) {
1093 case V4L2_PIX_FMT_FWHT:
1096 if (find_fmt(fsize->pixel_format)->id == fsize->pixel_format)
1104 fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
1106 fsize->stepwise.min_width = MIN_WIDTH;
1107 fsize->stepwise.max_width = MAX_WIDTH;
1108 fsize->stepwise.step_width = 8;
1109 fsize->stepwise.min_height = MIN_HEIGHT;
1110 fsize->stepwise.max_height = MAX_HEIGHT;
1111 fsize->stepwise.step_height = 8;
1116 static int vicodec_subscribe_event(struct v4l2_fh *fh,
1117 const struct v4l2_event_subscription *sub)
1119 struct vicodec_ctx *ctx = container_of(fh, struct vicodec_ctx, fh);
1121 switch (sub->type) {
1122 case V4L2_EVENT_SOURCE_CHANGE:
1126 case V4L2_EVENT_EOS:
1127 return v4l2_event_subscribe(fh, sub, 0, NULL);
1129 return v4l2_ctrl_subscribe_event(fh, sub);
1133 static const struct v4l2_ioctl_ops vicodec_ioctl_ops = {
1134 .vidioc_querycap = vidioc_querycap,
1136 .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
1137 .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
1138 .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
1139 .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
1141 .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap,
1142 .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap,
1143 .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap,
1144 .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap,
1146 .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
1147 .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out,
1148 .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
1149 .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
1151 .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out,
1152 .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out,
1153 .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out,
1154 .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out,
1156 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
1157 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
1158 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
1159 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
1160 .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
1161 .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
1162 .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
1164 .vidioc_streamon = v4l2_m2m_ioctl_streamon,
1165 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
1167 .vidioc_g_selection = vidioc_g_selection,
1168 .vidioc_s_selection = vidioc_s_selection,
1170 .vidioc_try_encoder_cmd = vicodec_try_encoder_cmd,
1171 .vidioc_encoder_cmd = vicodec_encoder_cmd,
1172 .vidioc_try_decoder_cmd = vicodec_try_decoder_cmd,
1173 .vidioc_decoder_cmd = vicodec_decoder_cmd,
1174 .vidioc_enum_framesizes = vicodec_enum_framesizes,
1176 .vidioc_subscribe_event = vicodec_subscribe_event,
1177 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
1185 static int vicodec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
1186 unsigned int *nplanes, unsigned int sizes[],
1187 struct device *alloc_devs[])
1189 struct vicodec_ctx *ctx = vb2_get_drv_priv(vq);
1190 struct vicodec_q_data *q_data = get_q_data(ctx, vq->type);
1191 unsigned int size = q_data->sizeimage;
1194 return sizes[0] < size ? -EINVAL : 0;
1201 static int vicodec_buf_prepare(struct vb2_buffer *vb)
1203 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1204 struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1205 struct vicodec_q_data *q_data;
1207 dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
1209 q_data = get_q_data(ctx, vb->vb2_queue->type);
1210 if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
1211 if (vbuf->field == V4L2_FIELD_ANY)
1212 vbuf->field = V4L2_FIELD_NONE;
1213 if (vbuf->field != V4L2_FIELD_NONE) {
1214 dprintk(ctx->dev, "%s field isn't supported\n",
1220 if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
1222 "%s data will not fit into plane (%lu < %lu)\n",
1223 __func__, vb2_plane_size(vb, 0),
1224 (long)q_data->sizeimage);
1231 static void vicodec_buf_queue(struct vb2_buffer *vb)
1233 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1234 struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1235 unsigned int sz = vb2_get_plane_payload(&vbuf->vb2_buf, 0);
1236 u8 *p_src = vb2_plane_vaddr(&vbuf->vb2_buf, 0);
1238 struct vb2_queue *vq_out = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
1239 V4L2_BUF_TYPE_VIDEO_OUTPUT);
1240 struct vb2_queue *vq_cap = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
1241 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1242 bool header_valid = false;
1243 static const struct v4l2_event rs_event = {
1244 .type = V4L2_EVENT_SOURCE_CHANGE,
1245 .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
1248 /* buf_queue handles only the first source change event */
1249 if (ctx->first_source_change_sent) {
1250 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
1255 * if both queues are streaming, the source change event is
1256 * handled in job_ready
1258 if (vb2_is_streaming(vq_cap) && vb2_is_streaming(vq_out)) {
1259 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
1264 * source change event is relevant only for the decoder
1265 * in the compressed stream
1267 if (ctx->is_enc || !V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
1268 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
1273 enum vb2_buffer_state state =
1274 get_next_header(ctx, &p, p_src + sz - p);
1276 if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
1277 v4l2_m2m_buf_done(vbuf, state);
1280 header_valid = is_header_valid(&ctx->state.header);
1282 * p points right after the end of the header in the
1283 * buffer. If the header is invalid we set p to point
1284 * to the next byte after the start of the header
1286 if (!header_valid) {
1287 p = p - sizeof(struct fwht_cframe_hdr) + 1;
1290 ctx->header_size = 0;
1291 ctx->comp_magic_cnt = 0;
1294 } while (!header_valid);
1296 ctx->cur_buf_offset = p - p_src;
1297 update_capture_data_from_header(ctx);
1298 ctx->first_source_change_sent = true;
1299 v4l2_event_queue_fh(&ctx->fh, &rs_event);
1300 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
1303 static void vicodec_return_bufs(struct vb2_queue *q, u32 state)
1305 struct vicodec_ctx *ctx = vb2_get_drv_priv(q);
1306 struct vb2_v4l2_buffer *vbuf;
1309 if (V4L2_TYPE_IS_OUTPUT(q->type))
1310 vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
1312 vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
1315 spin_lock(ctx->lock);
1316 v4l2_m2m_buf_done(vbuf, state);
1317 spin_unlock(ctx->lock);
1321 static int vicodec_start_streaming(struct vb2_queue *q,
1324 struct vicodec_ctx *ctx = vb2_get_drv_priv(q);
1325 struct vicodec_q_data *q_data = get_q_data(ctx, q->type);
1326 struct v4l2_fwht_state *state = &ctx->state;
1327 const struct v4l2_fwht_pixfmt_info *info = q_data->info;
1328 unsigned int size = q_data->coded_width * q_data->coded_height;
1329 unsigned int chroma_div;
1330 unsigned int total_planes_size;
1336 chroma_div = info->width_div * info->height_div;
1337 q_data->sequence = 0;
1339 if (V4L2_TYPE_IS_OUTPUT(q->type))
1340 ctx->last_src_buf = NULL;
1342 ctx->last_dst_buf = NULL;
1346 if ((V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) ||
1347 (!V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc))
1350 if (info->id == V4L2_PIX_FMT_FWHT) {
1351 vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED);
1354 if (info->components_num == 4)
1355 total_planes_size = 2 * size + 2 * (size / chroma_div);
1356 else if (info->components_num == 3)
1357 total_planes_size = size + 2 * (size / chroma_div);
1359 total_planes_size = size;
1361 state->visible_width = q_data->visible_width;
1362 state->visible_height = q_data->visible_height;
1363 state->coded_width = q_data->coded_width;
1364 state->coded_height = q_data->coded_height;
1365 state->stride = q_data->coded_width *
1366 info->bytesperline_mult;
1368 state->ref_frame.luma = kvmalloc(total_planes_size, GFP_KERNEL);
1369 ctx->comp_max_size = total_planes_size;
1370 new_comp_frame = kvmalloc(ctx->comp_max_size, GFP_KERNEL);
1372 if (!state->ref_frame.luma || !new_comp_frame) {
1373 kvfree(state->ref_frame.luma);
1374 kvfree(new_comp_frame);
1375 vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED);
1379 * if state->compressed_frame was already allocated then
1380 * it contain data of the first frame of the new resolution
1382 if (state->compressed_frame) {
1383 if (ctx->comp_size > ctx->comp_max_size)
1384 ctx->comp_size = ctx->comp_max_size;
1386 memcpy(new_comp_frame,
1387 state->compressed_frame, ctx->comp_size);
1390 kvfree(state->compressed_frame);
1391 state->compressed_frame = new_comp_frame;
1393 if (info->components_num >= 3) {
1394 state->ref_frame.cb = state->ref_frame.luma + size;
1395 state->ref_frame.cr = state->ref_frame.cb + size / chroma_div;
1397 state->ref_frame.cb = NULL;
1398 state->ref_frame.cr = NULL;
1401 if (info->components_num == 4)
1402 state->ref_frame.alpha =
1403 state->ref_frame.cr + size / chroma_div;
1405 state->ref_frame.alpha = NULL;
1409 static void vicodec_stop_streaming(struct vb2_queue *q)
1411 struct vicodec_ctx *ctx = vb2_get_drv_priv(q);
1413 vicodec_return_bufs(q, VB2_BUF_STATE_ERROR);
1415 if ((!V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) ||
1416 (V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc)) {
1417 kvfree(ctx->state.ref_frame.luma);
1418 ctx->comp_max_size = 0;
1419 ctx->source_changed = false;
1421 if (V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) {
1422 ctx->cur_buf_offset = 0;
1424 ctx->header_size = 0;
1425 ctx->comp_magic_cnt = 0;
1426 ctx->comp_has_frame = 0;
1427 ctx->comp_has_next_frame = 0;
1431 static const struct vb2_ops vicodec_qops = {
1432 .queue_setup = vicodec_queue_setup,
1433 .buf_prepare = vicodec_buf_prepare,
1434 .buf_queue = vicodec_buf_queue,
1435 .start_streaming = vicodec_start_streaming,
1436 .stop_streaming = vicodec_stop_streaming,
1437 .wait_prepare = vb2_ops_wait_prepare,
1438 .wait_finish = vb2_ops_wait_finish,
1441 static int queue_init(void *priv, struct vb2_queue *src_vq,
1442 struct vb2_queue *dst_vq)
1444 struct vicodec_ctx *ctx = priv;
1447 src_vq->type = (multiplanar ?
1448 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
1449 V4L2_BUF_TYPE_VIDEO_OUTPUT);
1450 src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
1451 src_vq->drv_priv = ctx;
1452 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1453 src_vq->ops = &vicodec_qops;
1454 src_vq->mem_ops = &vb2_vmalloc_memops;
1455 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1456 src_vq->lock = ctx->is_enc ? &ctx->dev->enc_mutex :
1457 &ctx->dev->dec_mutex;
1459 ret = vb2_queue_init(src_vq);
1463 dst_vq->type = (multiplanar ?
1464 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
1465 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1466 dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
1467 dst_vq->drv_priv = ctx;
1468 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1469 dst_vq->ops = &vicodec_qops;
1470 dst_vq->mem_ops = &vb2_vmalloc_memops;
1471 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1472 dst_vq->lock = src_vq->lock;
1474 return vb2_queue_init(dst_vq);
1477 #define VICODEC_CID_CUSTOM_BASE (V4L2_CID_MPEG_BASE | 0xf000)
1478 #define VICODEC_CID_I_FRAME_QP (VICODEC_CID_CUSTOM_BASE + 0)
1479 #define VICODEC_CID_P_FRAME_QP (VICODEC_CID_CUSTOM_BASE + 1)
1481 static int vicodec_s_ctrl(struct v4l2_ctrl *ctrl)
1483 struct vicodec_ctx *ctx = container_of(ctrl->handler,
1484 struct vicodec_ctx, hdl);
1487 case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
1488 ctx->state.gop_size = ctrl->val;
1490 case VICODEC_CID_I_FRAME_QP:
1491 ctx->state.i_frame_qp = ctrl->val;
1493 case VICODEC_CID_P_FRAME_QP:
1494 ctx->state.p_frame_qp = ctrl->val;
1500 static const struct v4l2_ctrl_ops vicodec_ctrl_ops = {
1501 .s_ctrl = vicodec_s_ctrl,
1504 static const struct v4l2_ctrl_config vicodec_ctrl_i_frame = {
1505 .ops = &vicodec_ctrl_ops,
1506 .id = VICODEC_CID_I_FRAME_QP,
1507 .name = "FWHT I-Frame QP Value",
1508 .type = V4L2_CTRL_TYPE_INTEGER,
1515 static const struct v4l2_ctrl_config vicodec_ctrl_p_frame = {
1516 .ops = &vicodec_ctrl_ops,
1517 .id = VICODEC_CID_P_FRAME_QP,
1518 .name = "FWHT P-Frame QP Value",
1519 .type = V4L2_CTRL_TYPE_INTEGER,
1529 static int vicodec_open(struct file *file)
1531 struct video_device *vfd = video_devdata(file);
1532 struct vicodec_dev *dev = video_drvdata(file);
1533 struct vicodec_ctx *ctx = NULL;
1534 struct v4l2_ctrl_handler *hdl;
1538 if (mutex_lock_interruptible(vfd->lock))
1539 return -ERESTARTSYS;
1540 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
1546 if (vfd == &dev->enc_vfd)
1549 v4l2_fh_init(&ctx->fh, video_devdata(file));
1550 file->private_data = &ctx->fh;
1553 v4l2_ctrl_handler_init(hdl, 4);
1554 v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE,
1556 v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_i_frame, NULL);
1557 v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_p_frame, NULL);
1560 v4l2_ctrl_handler_free(hdl);
1564 ctx->fh.ctrl_handler = hdl;
1565 v4l2_ctrl_handler_setup(hdl);
1567 ctx->q_data[V4L2_M2M_SRC].info =
1568 ctx->is_enc ? v4l2_fwht_get_pixfmt(0) : &pixfmt_fwht;
1569 ctx->q_data[V4L2_M2M_SRC].coded_width = 1280;
1570 ctx->q_data[V4L2_M2M_SRC].coded_height = 720;
1571 ctx->q_data[V4L2_M2M_SRC].visible_width = 1280;
1572 ctx->q_data[V4L2_M2M_SRC].visible_height = 720;
1573 size = 1280 * 720 * ctx->q_data[V4L2_M2M_SRC].info->sizeimage_mult /
1574 ctx->q_data[V4L2_M2M_SRC].info->sizeimage_div;
1576 ctx->q_data[V4L2_M2M_SRC].sizeimage = size;
1578 ctx->q_data[V4L2_M2M_SRC].sizeimage =
1579 size + sizeof(struct fwht_cframe_hdr);
1581 ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC];
1582 ctx->q_data[V4L2_M2M_DST].info = &pixfmt_fwht;
1583 ctx->q_data[V4L2_M2M_DST].sizeimage = 1280 * 720 *
1584 ctx->q_data[V4L2_M2M_DST].info->sizeimage_mult /
1585 ctx->q_data[V4L2_M2M_DST].info->sizeimage_div +
1586 sizeof(struct fwht_cframe_hdr);
1588 ctx->q_data[V4L2_M2M_DST].info = NULL;
1591 ctx->state.colorspace = V4L2_COLORSPACE_REC709;
1594 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->enc_dev, ctx,
1596 ctx->lock = &dev->enc_lock;
1598 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->dec_dev, ctx,
1600 ctx->lock = &dev->dec_lock;
1603 if (IS_ERR(ctx->fh.m2m_ctx)) {
1604 rc = PTR_ERR(ctx->fh.m2m_ctx);
1606 v4l2_ctrl_handler_free(hdl);
1607 v4l2_fh_exit(&ctx->fh);
1612 v4l2_fh_add(&ctx->fh);
1615 mutex_unlock(vfd->lock);
1619 static int vicodec_release(struct file *file)
1621 struct video_device *vfd = video_devdata(file);
1622 struct vicodec_ctx *ctx = file2ctx(file);
1624 mutex_lock(vfd->lock);
1625 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
1626 mutex_unlock(vfd->lock);
1627 v4l2_fh_del(&ctx->fh);
1628 v4l2_fh_exit(&ctx->fh);
1629 v4l2_ctrl_handler_free(&ctx->hdl);
1635 static const struct v4l2_file_operations vicodec_fops = {
1636 .owner = THIS_MODULE,
1637 .open = vicodec_open,
1638 .release = vicodec_release,
1639 .poll = v4l2_m2m_fop_poll,
1640 .unlocked_ioctl = video_ioctl2,
1641 .mmap = v4l2_m2m_fop_mmap,
1644 static const struct video_device vicodec_videodev = {
1645 .name = VICODEC_NAME,
1646 .vfl_dir = VFL_DIR_M2M,
1647 .fops = &vicodec_fops,
1648 .ioctl_ops = &vicodec_ioctl_ops,
1650 .release = video_device_release_empty,
1653 static const struct v4l2_m2m_ops m2m_ops = {
1654 .device_run = device_run,
1655 .job_ready = job_ready,
1658 static int vicodec_probe(struct platform_device *pdev)
1660 struct vicodec_dev *dev;
1661 struct video_device *vfd;
1664 dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
1668 spin_lock_init(&dev->enc_lock);
1669 spin_lock_init(&dev->dec_lock);
1671 ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
1675 #ifdef CONFIG_MEDIA_CONTROLLER
1676 dev->mdev.dev = &pdev->dev;
1677 strscpy(dev->mdev.model, "vicodec", sizeof(dev->mdev.model));
1678 strscpy(dev->mdev.bus_info, "platform:vicodec",
1679 sizeof(dev->mdev.bus_info));
1680 media_device_init(&dev->mdev);
1681 dev->v4l2_dev.mdev = &dev->mdev;
1684 mutex_init(&dev->enc_mutex);
1685 mutex_init(&dev->dec_mutex);
1687 platform_set_drvdata(pdev, dev);
1689 dev->enc_dev = v4l2_m2m_init(&m2m_ops);
1690 if (IS_ERR(dev->enc_dev)) {
1691 v4l2_err(&dev->v4l2_dev, "Failed to init vicodec device\n");
1692 ret = PTR_ERR(dev->enc_dev);
1696 dev->dec_dev = v4l2_m2m_init(&m2m_ops);
1697 if (IS_ERR(dev->dec_dev)) {
1698 v4l2_err(&dev->v4l2_dev, "Failed to init vicodec device\n");
1699 ret = PTR_ERR(dev->dec_dev);
1703 dev->enc_vfd = vicodec_videodev;
1704 vfd = &dev->enc_vfd;
1705 vfd->lock = &dev->enc_mutex;
1706 vfd->v4l2_dev = &dev->v4l2_dev;
1707 strscpy(vfd->name, "vicodec-enc", sizeof(vfd->name));
1708 vfd->device_caps = V4L2_CAP_STREAMING |
1709 (multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M);
1710 v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
1711 v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
1712 video_set_drvdata(vfd, dev);
1714 ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
1716 v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
1719 v4l2_info(&dev->v4l2_dev,
1720 "Device registered as /dev/video%d\n", vfd->num);
1722 dev->dec_vfd = vicodec_videodev;
1723 vfd = &dev->dec_vfd;
1724 vfd->lock = &dev->dec_mutex;
1725 vfd->v4l2_dev = &dev->v4l2_dev;
1726 vfd->device_caps = V4L2_CAP_STREAMING |
1727 (multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M);
1728 strscpy(vfd->name, "vicodec-dec", sizeof(vfd->name));
1729 v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD);
1730 v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
1731 video_set_drvdata(vfd, dev);
1733 ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
1735 v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
1738 v4l2_info(&dev->v4l2_dev,
1739 "Device registered as /dev/video%d\n", vfd->num);
1741 #ifdef CONFIG_MEDIA_CONTROLLER
1742 ret = v4l2_m2m_register_media_controller(dev->enc_dev,
1743 &dev->enc_vfd, MEDIA_ENT_F_PROC_VIDEO_ENCODER);
1745 v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n");
1749 ret = v4l2_m2m_register_media_controller(dev->dec_dev,
1750 &dev->dec_vfd, MEDIA_ENT_F_PROC_VIDEO_DECODER);
1752 v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n");
1753 goto unreg_m2m_enc_mc;
1756 ret = media_device_register(&dev->mdev);
1758 v4l2_err(&dev->v4l2_dev, "Failed to register mem2mem media device\n");
1759 goto unreg_m2m_dec_mc;
1764 #ifdef CONFIG_MEDIA_CONTROLLER
1766 v4l2_m2m_unregister_media_controller(dev->dec_dev);
1768 v4l2_m2m_unregister_media_controller(dev->enc_dev);
1770 video_unregister_device(&dev->dec_vfd);
1773 video_unregister_device(&dev->enc_vfd);
1775 v4l2_m2m_release(dev->dec_dev);
1777 v4l2_m2m_release(dev->enc_dev);
1779 v4l2_device_unregister(&dev->v4l2_dev);
1784 static int vicodec_remove(struct platform_device *pdev)
1786 struct vicodec_dev *dev = platform_get_drvdata(pdev);
1788 v4l2_info(&dev->v4l2_dev, "Removing " VICODEC_NAME);
1790 #ifdef CONFIG_MEDIA_CONTROLLER
1791 media_device_unregister(&dev->mdev);
1792 v4l2_m2m_unregister_media_controller(dev->enc_dev);
1793 v4l2_m2m_unregister_media_controller(dev->dec_dev);
1794 media_device_cleanup(&dev->mdev);
1797 v4l2_m2m_release(dev->enc_dev);
1798 v4l2_m2m_release(dev->dec_dev);
1799 video_unregister_device(&dev->enc_vfd);
1800 video_unregister_device(&dev->dec_vfd);
1801 v4l2_device_unregister(&dev->v4l2_dev);
1806 static struct platform_driver vicodec_pdrv = {
1807 .probe = vicodec_probe,
1808 .remove = vicodec_remove,
1810 .name = VICODEC_NAME,
1814 static void __exit vicodec_exit(void)
1816 platform_driver_unregister(&vicodec_pdrv);
1817 platform_device_unregister(&vicodec_pdev);
1820 static int __init vicodec_init(void)
1824 ret = platform_device_register(&vicodec_pdev);
1828 ret = platform_driver_register(&vicodec_pdrv);
1830 platform_device_unregister(&vicodec_pdev);
1835 module_init(vicodec_init);
1836 module_exit(vicodec_exit);