Skip to content

Commit

Permalink
media: vivid: Add metadata output support
Browse files Browse the repository at this point in the history
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: Vandana BN <bnvandana@gmail.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
  • Loading branch information
Vandana BN authored and Mauro Carvalho Chehab committed Oct 24, 2019
1 parent 78892b6 commit 746facd
Show file tree
Hide file tree
Showing 8 changed files with 364 additions and 11 deletions.
2 changes: 1 addition & 1 deletion drivers/media/platform/vivid/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
98 changes: 93 additions & 5 deletions drivers/media/platform/vivid/vivid-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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"
Expand All @@ -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"
Expand All @@ -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 };
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}
Expand All @@ -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)
Expand Down Expand Up @@ -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,
};

/* -----------------------------------------------------------------
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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]);
Expand Down
10 changes: 10 additions & 0 deletions drivers/media/platform/vivid/vivid-core.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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 */

Expand Down Expand Up @@ -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;
Expand Down
12 changes: 11 additions & 1 deletion drivers/media/platform/vivid/vivid-ctrls.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
}

Expand All @@ -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);
}
Loading

0 comments on commit 746facd

Please sign in to comment.