Commit 746facd3 authored by Vandana BN's avatar Vandana BN Committed by Mauro Carvalho Chehab
Browse files

media: vivid: Add metadata output support



Support metadata output in vivid driver.
Metadata output is used to set brightness, contrast, saturation
and hue.
Adds new files for metadata output.

Signed-off-by: default avatarVandana BN <bnvandana@gmail.com>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent 78892b6b
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -3,7 +3,7 @@ vivid-objs := vivid-core.o vivid-ctrls.o vivid-vid-common.o vivid-vbi-gen.o \
		vivid-vid-cap.o vivid-vid-out.o vivid-kthread-cap.o vivid-kthread-out.o \
		vivid-radio-rx.o vivid-radio-tx.o vivid-radio-common.o \
		vivid-rds-gen.o vivid-sdr-cap.o vivid-vbi-cap.o vivid-vbi-out.o \
		vivid-osd.o vivid-meta-cap.o
		vivid-osd.o vivid-meta-cap.o vivid-meta-out.o
ifeq ($(CONFIG_VIDEO_VIVID_CEC),y)
  vivid-objs += vivid-cec.o
endif
+93 −5
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@
#include "vivid-cec.h"
#include "vivid-ctrls.h"
#include "vivid-meta-cap.h"
#include "vivid-meta-out.h"

#define VIVID_MODULE_NAME "vivid"

@@ -84,6 +85,10 @@ static int meta_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
module_param_array(meta_cap_nr, int, NULL, 0444);
MODULE_PARM_DESC(meta_cap_nr, " videoX start number, -1 is autodetect");

static int meta_out_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
module_param_array(meta_out_nr, int, NULL, 0444);
MODULE_PARM_DESC(meta_out_nr, " videoX start number, -1 is autodetect");

static int ccs_cap_mode[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
module_param_array(ccs_cap_mode, int, NULL, 0444);
MODULE_PARM_DESC(ccs_cap_mode, " capture crop/compose/scale mode:\n"
@@ -105,10 +110,10 @@ MODULE_PARM_DESC(multiplanar, " 1 (default) creates a single planar device, 2 cr
 * vbi-out + vid-out + meta-cap
 */
static unsigned int node_types[VIVID_MAX_DEVS] = {
	[0 ... (VIVID_MAX_DEVS - 1)] = 0x21d3d
	[0 ... (VIVID_MAX_DEVS - 1)] = 0x61d3d
};
module_param_array(node_types, uint, NULL, 0444);
MODULE_PARM_DESC(node_types, " node types, default is 0x21d3d. Bitmask with the following meaning:\n"
MODULE_PARM_DESC(node_types, " node types, default is 0x61d3d. Bitmask with the following meaning:\n"
			     "\t\t    bit 0: Video Capture node\n"
			     "\t\t    bit 2-3: VBI Capture node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both\n"
			     "\t\t    bit 4: Radio Receiver node\n"
@@ -117,7 +122,8 @@ MODULE_PARM_DESC(node_types, " node types, default is 0x21d3d. Bitmask with the
			     "\t\t    bit 10-11: VBI Output node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both\n"
			     "\t\t    bit 12: Radio Transmitter node\n"
			     "\t\t    bit 16: Framebuffer for testing overlays\n"
			     "\t\t    bit 17: Metadata Capture node\n");
			     "\t\t    bit 17: Metadata Capture node\n"
			     "\t\t    bit 18: Metadata Output node\n");

/* Default: 4 inputs */
static unsigned num_inputs[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 4 };
@@ -216,7 +222,8 @@ static int vidioc_querycap(struct file *file, void *priv,
	cap->capabilities = dev->vid_cap_caps | dev->vid_out_caps |
		dev->vbi_cap_caps | dev->vbi_out_caps |
		dev->radio_rx_caps | dev->radio_tx_caps |
		dev->sdr_cap_caps | dev->meta_cap_caps | V4L2_CAP_DEVICE_CAPS;
		dev->sdr_cap_caps | dev->meta_cap_caps |
		dev->meta_out_caps | V4L2_CAP_DEVICE_CAPS;
	return 0;
}

@@ -445,7 +452,8 @@ static bool vivid_is_last_user(struct vivid_dev *dev)
			vivid_is_in_use(&dev->sdr_cap_dev) +
			vivid_is_in_use(&dev->radio_rx_dev) +
			vivid_is_in_use(&dev->radio_tx_dev) +
			vivid_is_in_use(&dev->meta_cap_dev);
			vivid_is_in_use(&dev->meta_cap_dev) +
			vivid_is_in_use(&dev->meta_out_dev);

	return uses == 1;
}
@@ -472,6 +480,7 @@ static int vivid_fop_release(struct file *file)
		set_bit(V4L2_FL_REGISTERED, &dev->radio_rx_dev.flags);
		set_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags);
		set_bit(V4L2_FL_REGISTERED, &dev->meta_cap_dev.flags);
		set_bit(V4L2_FL_REGISTERED, &dev->meta_out_dev.flags);
	}
	mutex_unlock(&dev->mutex);
	if (file->private_data == dev->overlay_cap_owner)
@@ -622,6 +631,11 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
	.vidioc_g_fmt_meta_cap		= vidioc_g_fmt_meta_cap,
	.vidioc_s_fmt_meta_cap		= vidioc_g_fmt_meta_cap,
	.vidioc_try_fmt_meta_cap	= vidioc_g_fmt_meta_cap,

	.vidioc_enum_fmt_meta_out       = vidioc_enum_fmt_meta_out,
	.vidioc_g_fmt_meta_out          = vidioc_g_fmt_meta_out,
	.vidioc_s_fmt_meta_out          = vidioc_g_fmt_meta_out,
	.vidioc_try_fmt_meta_out        = vidioc_g_fmt_meta_out,
};

/* -----------------------------------------------------------------
@@ -839,6 +853,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
	/* do we create a meta capture device */
	dev->has_meta_cap = node_type & 0x20000;

	/* do we create a metadata output device */
	dev->has_meta_out = node_type & 0x40000;

	/* end detecting feature set */

	if (dev->has_vid_cap) {
@@ -905,6 +922,13 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
		if (in_type_counter[TV])
			dev->meta_cap_caps |= V4L2_CAP_TUNER;
	}
	/* set up the capabilities of meta output device */
	if (dev->has_meta_out) {
		dev->meta_out_caps = V4L2_CAP_META_OUTPUT |
				     V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
		if (dev->has_audio_outputs)
			dev->meta_out_caps |= V4L2_CAP_AUDIO;
	}

	ret = -ENOMEM;
	/* initialize the test pattern generator */
@@ -976,6 +1000,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
		v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_S_AUDOUT);
		v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_G_AUDOUT);
		v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_ENUMAUDOUT);
		v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_S_AUDOUT);
		v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_G_AUDOUT);
		v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_ENUMAUDOUT);
	}
	if (!in_type_counter[TV] && !in_type_counter[SVID]) {
		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_STD);
@@ -1035,6 +1062,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
	v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_FRAMEINTERVALS);
	v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_S_FREQUENCY);
	v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_G_FREQUENCY);
	v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_S_FREQUENCY);
	v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_G_FREQUENCY);

	/* configure internal data */
	dev->fmt_cap = &vivid_formats[0];
@@ -1118,6 +1147,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
	INIT_LIST_HEAD(&dev->vbi_out_active);
	INIT_LIST_HEAD(&dev->sdr_cap_active);
	INIT_LIST_HEAD(&dev->meta_cap_active);
	INIT_LIST_HEAD(&dev->meta_out_active);

	INIT_LIST_HEAD(&dev->cec_work_list);
	spin_lock_init(&dev->cec_slock);
@@ -1286,6 +1316,27 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
			goto unreg_dev;
	}

	if (dev->has_meta_out) {
		/* initialize meta_out queue */
		q = &dev->vb_meta_out_q;
		q->type = V4L2_BUF_TYPE_META_OUTPUT;
		q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_WRITE;
		if (!allocator)
			q->io_modes |= VB2_USERPTR;
		q->drv_priv = dev;
		q->buf_struct_size = sizeof(struct vivid_buffer);
		q->ops = &vivid_meta_out_qops;
		q->mem_ops = vivid_mem_ops[allocator];
		q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
		q->min_buffers_needed = 1;
		q->lock = &dev->mutex;
		q->dev = dev->v4l2_dev.dev;
		q->supports_requests = true;
		ret = vb2_queue_init(q);
		if (ret)
			goto unreg_dev;
	}

#ifdef CONFIG_VIDEO_VIVID_CEC
	if (dev->has_vid_cap && in_type_counter[HDMI]) {
		struct cec_adapter *adap;
@@ -1327,6 +1378,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
	v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_tx);
	v4l2_ctrl_handler_setup(&dev->ctrl_hdl_sdr_cap);
	v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_cap);
	v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_out);

	/* finally start creating the device nodes */
	if (dev->has_vid_cap) {
@@ -1583,6 +1635,36 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
			  video_device_node_name(vfd));
	}

	if (dev->has_meta_out) {
		vfd = &dev->meta_out_dev;
		snprintf(vfd->name, sizeof(vfd->name),
			 "vivid-%03d-meta-out", inst);
		vfd->vfl_dir = VFL_DIR_TX;
		vfd->fops = &vivid_fops;
		vfd->ioctl_ops = &vivid_ioctl_ops;
		vfd->device_caps = dev->meta_out_caps;
		vfd->release = video_device_release_empty;
		vfd->v4l2_dev = &dev->v4l2_dev;
		vfd->queue = &dev->vb_meta_out_q;
		vfd->lock = &dev->mutex;
		vfd->tvnorms = tvnorms_out;
		video_set_drvdata(vfd, dev);
#ifdef CONFIG_MEDIA_CONTROLLER
		dev->meta_out_pad.flags = MEDIA_PAD_FL_SOURCE;
		ret = media_entity_pads_init(&vfd->entity, 1,
					     &dev->meta_out_pad);
		if (ret)
			goto unreg_dev;
#endif
		ret = video_register_device(vfd, VFL_TYPE_GRABBER,
					    meta_out_nr[inst]);
		if (ret < 0)
			goto unreg_dev;
		v4l2_info(&dev->v4l2_dev,
			  "V4L2 metadata output device registered as %s\n",
			  video_device_node_name(vfd));
	}

#ifdef CONFIG_MEDIA_CONTROLLER
	/* Register the media device */
	ret = media_device_register(&dev->mdev);
@@ -1599,6 +1681,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
	return 0;

unreg_dev:
	video_unregister_device(&dev->meta_out_dev);
	video_unregister_device(&dev->meta_cap_dev);
	video_unregister_device(&dev->radio_tx_dev);
	video_unregister_device(&dev->radio_rx_dev);
@@ -1721,6 +1804,11 @@ static int vivid_remove(struct platform_device *pdev)
				  video_device_node_name(&dev->meta_cap_dev));
			video_unregister_device(&dev->meta_cap_dev);
		}
		if (dev->has_meta_out) {
			v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
				  video_device_node_name(&dev->meta_out_dev));
			video_unregister_device(&dev->meta_out_dev);
		}
		cec_unregister_adapter(dev->cec_rx_adap);
		for (j = 0; j < MAX_OUTPUTS; j++)
			cec_unregister_adapter(dev->cec_tx_adap[j]);
+10 −0
Original line number Diff line number Diff line
@@ -132,6 +132,7 @@ struct vivid_dev {
	struct media_pad		vbi_out_pad;
	struct media_pad		sdr_cap_pad;
	struct media_pad		meta_cap_pad;
	struct media_pad		meta_out_pad;
#endif
	struct v4l2_ctrl_handler	ctrl_hdl_user_gen;
	struct v4l2_ctrl_handler	ctrl_hdl_user_vid;
@@ -156,6 +157,8 @@ struct vivid_dev {
	struct v4l2_ctrl_handler	ctrl_hdl_sdr_cap;
	struct video_device		meta_cap_dev;
	struct v4l2_ctrl_handler	ctrl_hdl_meta_cap;
	struct video_device		meta_out_dev;
	struct v4l2_ctrl_handler	ctrl_hdl_meta_out;

	spinlock_t			slock;
	struct mutex			mutex;
@@ -169,6 +172,7 @@ struct vivid_dev {
	u32				radio_rx_caps;
	u32				radio_tx_caps;
	u32				meta_cap_caps;
	u32				meta_out_caps;

	/* supported features */
	bool				multiplanar;
@@ -195,6 +199,7 @@ struct vivid_dev {
	bool				has_sdr_cap;
	bool				has_fb;
	bool				has_meta_cap;
	bool				has_meta_out;

	bool				can_loop_video;

@@ -432,6 +437,8 @@ struct vivid_dev {
	struct list_head		vid_out_active;
	struct vb2_queue		vb_vbi_out_q;
	struct list_head		vbi_out_active;
	struct vb2_queue		vb_meta_out_q;
	struct list_head		meta_out_active;

	/* video loop precalculated rectangles */

@@ -472,6 +479,9 @@ struct vivid_dev {
	u32				vbi_out_seq_count;
	bool				vbi_out_streaming;
	bool				stream_sliced_vbi_out;
	u32				meta_out_seq_start;
	u32				meta_out_seq_count;
	bool				meta_out_streaming;

	/* SDR capture */
	struct vb2_queue		vb_sdr_cap_q;
+11 −1
Original line number Diff line number Diff line
@@ -1494,6 +1494,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
	struct v4l2_ctrl_handler *hdl_radio_tx = &dev->ctrl_hdl_radio_tx;
	struct v4l2_ctrl_handler *hdl_sdr_cap = &dev->ctrl_hdl_sdr_cap;
	struct v4l2_ctrl_handler *hdl_meta_cap = &dev->ctrl_hdl_meta_cap;
	struct v4l2_ctrl_handler *hdl_meta_out = &dev->ctrl_hdl_meta_out;

	struct v4l2_ctrl_config vivid_ctrl_dv_timings = {
		.ops = &vivid_vid_cap_ctrl_ops,
@@ -1535,6 +1536,8 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
	v4l2_ctrl_new_custom(hdl_sdr_cap, &vivid_ctrl_class, NULL);
	v4l2_ctrl_handler_init(hdl_meta_cap, 2);
	v4l2_ctrl_new_custom(hdl_meta_cap, &vivid_ctrl_class, NULL);
	v4l2_ctrl_handler_init(hdl_meta_out, 2);
	v4l2_ctrl_new_custom(hdl_meta_out, &vivid_ctrl_class, NULL);

	/* User Controls */
	dev->volume = v4l2_ctrl_new_std(hdl_user_aud, NULL,
@@ -1880,7 +1883,13 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
			return hdl_meta_cap->error;
		dev->meta_cap_dev.ctrl_handler = hdl_meta_cap;
	}

	if (dev->has_meta_out) {
		v4l2_ctrl_add_handler(hdl_meta_out, hdl_user_gen, NULL, false);
		v4l2_ctrl_add_handler(hdl_meta_out, hdl_streaming, NULL, false);
		if (hdl_meta_out->error)
			return hdl_meta_out->error;
		dev->meta_out_dev.ctrl_handler = hdl_meta_out;
	}
	return 0;
}

@@ -1901,4 +1910,5 @@ void vivid_free_controls(struct vivid_dev *dev)
	v4l2_ctrl_handler_free(&dev->ctrl_hdl_loop_cap);
	v4l2_ctrl_handler_free(&dev->ctrl_hdl_fb);
	v4l2_ctrl_handler_free(&dev->ctrl_hdl_meta_cap);
	v4l2_ctrl_handler_free(&dev->ctrl_hdl_meta_out);
}
+46 −3
Original line number Diff line number Diff line
@@ -38,11 +38,13 @@
#include "vivid-osd.h"
#include "vivid-ctrls.h"
#include "vivid-kthread-out.h"
#include "vivid-meta-out.h"

static void vivid_thread_vid_out_tick(struct vivid_dev *dev)
{
	struct vivid_buffer *vid_out_buf = NULL;
	struct vivid_buffer *vbi_out_buf = NULL;
	struct vivid_buffer *meta_out_buf = NULL;

	dprintk(dev, 1, "Video Output Thread Tick\n");

@@ -69,9 +71,14 @@ static void vivid_thread_vid_out_tick(struct vivid_dev *dev)
					 struct vivid_buffer, list);
		list_del(&vbi_out_buf->list);
	}
	if (!list_empty(&dev->meta_out_active)) {
		meta_out_buf = list_entry(dev->meta_out_active.next,
					  struct vivid_buffer, list);
		list_del(&meta_out_buf->list);
	}
	spin_unlock(&dev->slock);

	if (!vid_out_buf && !vbi_out_buf)
	if (!vid_out_buf && !vbi_out_buf && !meta_out_buf)
		return;

	if (vid_out_buf) {
@@ -111,6 +118,21 @@ static void vivid_thread_vid_out_tick(struct vivid_dev *dev)
		dprintk(dev, 2, "vbi_out buffer %d done\n",
			vbi_out_buf->vb.vb2_buf.index);
	}
	if (meta_out_buf) {
		v4l2_ctrl_request_setup(meta_out_buf->vb.vb2_buf.req_obj.req,
					&dev->ctrl_hdl_meta_out);
		v4l2_ctrl_request_complete(meta_out_buf->vb.vb2_buf.req_obj.req,
					   &dev->ctrl_hdl_meta_out);
		vivid_meta_out_process(dev, meta_out_buf);
		meta_out_buf->vb.sequence = dev->meta_out_seq_count;
		meta_out_buf->vb.vb2_buf.timestamp =
			ktime_get_ns() + dev->time_wrap_offset;
		vb2_buffer_done(&meta_out_buf->vb.vb2_buf, dev->dqbuf_error ?
				VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
		dprintk(dev, 2, "meta_out buffer %d done\n",
			meta_out_buf->vb.vb2_buf.index);
	}

	dev->dqbuf_error = false;
}

@@ -136,6 +158,7 @@ static int vivid_thread_vid_out(void *data)
		dev->out_seq_count = 0xffffff80U;
	dev->jiffies_vid_out = jiffies;
	dev->vid_out_seq_start = dev->vbi_out_seq_start = 0;
	dev->meta_out_seq_start = 0;
	dev->out_seq_resync = false;

	for (;;) {
@@ -178,6 +201,7 @@ static int vivid_thread_vid_out(void *data)
		dev->out_seq_count = buffers_since_start + dev->out_seq_offset;
		dev->vid_out_seq_count = dev->out_seq_count - dev->vid_out_seq_start;
		dev->vbi_out_seq_count = dev->out_seq_count - dev->vbi_out_seq_start;
		dev->meta_out_seq_count = dev->out_seq_count - dev->meta_out_seq_start;

		vivid_thread_vid_out_tick(dev);
		mutex_unlock(&dev->mutex);
@@ -229,8 +253,10 @@ int vivid_start_generating_vid_out(struct vivid_dev *dev, bool *pstreaming)

		if (pstreaming == &dev->vid_out_streaming)
			dev->vid_out_seq_start = seq_count;
		else
		else if (pstreaming == &dev->vbi_out_streaming)
			dev->vbi_out_seq_start = seq_count;
		else
			dev->meta_out_seq_start = seq_count;
		*pstreaming = true;
		return 0;
	}
@@ -239,6 +265,7 @@ int vivid_start_generating_vid_out(struct vivid_dev *dev, bool *pstreaming)
	dev->jiffies_vid_out = jiffies;
	dev->vid_out_seq_start = dev->seq_wrap * 128;
	dev->vbi_out_seq_start = dev->seq_wrap * 128;
	dev->meta_out_seq_start = dev->seq_wrap * 128;

	dev->kthread_vid_out = kthread_run(vivid_thread_vid_out, dev,
			"%s-vid-out", dev->v4l2_dev.name);
@@ -296,7 +323,23 @@ void vivid_stop_generating_vid_out(struct vivid_dev *dev, bool *pstreaming)
		}
	}

	if (dev->vid_out_streaming || dev->vbi_out_streaming)
	if (pstreaming == &dev->meta_out_streaming) {
		while (!list_empty(&dev->meta_out_active)) {
			struct vivid_buffer *buf;

			buf = list_entry(dev->meta_out_active.next,
					 struct vivid_buffer, list);
			list_del(&buf->list);
			v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req,
						   &dev->ctrl_hdl_meta_out);
			vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
			dprintk(dev, 2, "meta_out buffer %d done\n",
				buf->vb.vb2_buf.index);
		}
	}

	if (dev->vid_out_streaming || dev->vbi_out_streaming ||
	    dev->meta_out_streaming)
		return;

	/* shutdown control thread */
Loading