提交 d5797cf6 编写于 作者: V Vandana BN 提交者: Mauro Carvalho Chehab

media: vivid: Add metadata capture support

This patch adds meatadata capture support in vivid driver.
Adds new files for metadata capture.
Adds vivid controls to generate PTS and SCR for metadata stream.
also fixes v4l2-compliance issues seen on metadata device.
Signed-off-by: NVandana BN <bnvandana@gmail.com>
Signed-off-by: NHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: NMauro Carvalho Chehab <mchehab+samsung@kernel.org>
上级 8669d847
...@@ -3,7 +3,7 @@ vivid-objs := vivid-core.o vivid-ctrls.o vivid-vid-common.o vivid-vbi-gen.o \ ...@@ -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-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-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-rds-gen.o vivid-sdr-cap.o vivid-vbi-cap.o vivid-vbi-out.o \
vivid-osd.o vivid-osd.o vivid-meta-cap.o
ifeq ($(CONFIG_VIDEO_VIVID_CEC),y) ifeq ($(CONFIG_VIDEO_VIVID_CEC),y)
vivid-objs += vivid-cec.o vivid-objs += vivid-cec.o
endif endif
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "vivid-osd.h" #include "vivid-osd.h"
#include "vivid-cec.h" #include "vivid-cec.h"
#include "vivid-ctrls.h" #include "vivid-ctrls.h"
#include "vivid-meta-cap.h"
#define VIVID_MODULE_NAME "vivid" #define VIVID_MODULE_NAME "vivid"
...@@ -79,6 +80,10 @@ static int radio_tx_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; ...@@ -79,6 +80,10 @@ static int radio_tx_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
module_param_array(radio_tx_nr, int, NULL, 0444); module_param_array(radio_tx_nr, int, NULL, 0444);
MODULE_PARM_DESC(radio_tx_nr, " radioX start number, -1 is autodetect"); MODULE_PARM_DESC(radio_tx_nr, " radioX start number, -1 is autodetect");
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 ccs_cap_mode[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; static int ccs_cap_mode[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
module_param_array(ccs_cap_mode, int, NULL, 0444); module_param_array(ccs_cap_mode, int, NULL, 0444);
MODULE_PARM_DESC(ccs_cap_mode, " capture crop/compose/scale mode:\n" MODULE_PARM_DESC(ccs_cap_mode, " capture crop/compose/scale mode:\n"
...@@ -95,10 +100,15 @@ static unsigned multiplanar[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 1 ...@@ -95,10 +100,15 @@ static unsigned multiplanar[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 1
module_param_array(multiplanar, uint, NULL, 0444); module_param_array(multiplanar, uint, NULL, 0444);
MODULE_PARM_DESC(multiplanar, " 1 (default) creates a single planar device, 2 creates a multiplanar device."); MODULE_PARM_DESC(multiplanar, " 1 (default) creates a single planar device, 2 creates a multiplanar device.");
/* Default: video + vbi-cap (raw and sliced) + radio rx + radio tx + sdr + vbi-out + vid-out */ /*
static unsigned node_types[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 0x1d3d }; * Default: video + vbi-cap (raw and sliced) + radio rx + radio tx + sdr +
* vbi-out + vid-out + meta-cap
*/
static unsigned int node_types[VIVID_MAX_DEVS] = {
[0 ... (VIVID_MAX_DEVS - 1)] = 0x21d3d
};
module_param_array(node_types, uint, NULL, 0444); module_param_array(node_types, uint, NULL, 0444);
MODULE_PARM_DESC(node_types, " node types, default is 0x1d3d. Bitmask with the following meaning:\n" MODULE_PARM_DESC(node_types, " node types, default is 0x21d3d. Bitmask with the following meaning:\n"
"\t\t bit 0: Video Capture node\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 2-3: VBI Capture node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both\n"
"\t\t bit 4: Radio Receiver node\n" "\t\t bit 4: Radio Receiver node\n"
...@@ -106,7 +116,8 @@ MODULE_PARM_DESC(node_types, " node types, default is 0x1d3d. Bitmask with the f ...@@ -106,7 +116,8 @@ MODULE_PARM_DESC(node_types, " node types, default is 0x1d3d. Bitmask with the f
"\t\t bit 8: Video Output node\n" "\t\t bit 8: Video Output node\n"
"\t\t bit 10-11: VBI Output node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both\n" "\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 12: Radio Transmitter node\n"
"\t\t bit 16: Framebuffer for testing overlays"); "\t\t bit 16: Framebuffer for testing overlays\n"
"\t\t bit 17: Metadata Capture node\n");
/* Default: 4 inputs */ /* Default: 4 inputs */
static unsigned num_inputs[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 4 }; static unsigned num_inputs[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 4 };
...@@ -205,7 +216,7 @@ static int vidioc_querycap(struct file *file, void *priv, ...@@ -205,7 +216,7 @@ static int vidioc_querycap(struct file *file, void *priv,
cap->capabilities = dev->vid_cap_caps | dev->vid_out_caps | cap->capabilities = dev->vid_cap_caps | dev->vid_out_caps |
dev->vbi_cap_caps | dev->vbi_out_caps | dev->vbi_cap_caps | dev->vbi_out_caps |
dev->radio_rx_caps | dev->radio_tx_caps | dev->radio_rx_caps | dev->radio_tx_caps |
dev->sdr_cap_caps | V4L2_CAP_DEVICE_CAPS; dev->sdr_cap_caps | dev->meta_cap_caps | V4L2_CAP_DEVICE_CAPS;
return 0; return 0;
} }
...@@ -433,7 +444,8 @@ static bool vivid_is_last_user(struct vivid_dev *dev) ...@@ -433,7 +444,8 @@ static bool vivid_is_last_user(struct vivid_dev *dev)
vivid_is_in_use(&dev->vbi_out_dev) + vivid_is_in_use(&dev->vbi_out_dev) +
vivid_is_in_use(&dev->sdr_cap_dev) + vivid_is_in_use(&dev->sdr_cap_dev) +
vivid_is_in_use(&dev->radio_rx_dev) + vivid_is_in_use(&dev->radio_rx_dev) +
vivid_is_in_use(&dev->radio_tx_dev); vivid_is_in_use(&dev->radio_tx_dev) +
vivid_is_in_use(&dev->meta_cap_dev);
return uses == 1; return uses == 1;
} }
...@@ -459,6 +471,7 @@ static int vivid_fop_release(struct file *file) ...@@ -459,6 +471,7 @@ static int vivid_fop_release(struct file *file)
set_bit(V4L2_FL_REGISTERED, &dev->sdr_cap_dev.flags); set_bit(V4L2_FL_REGISTERED, &dev->sdr_cap_dev.flags);
set_bit(V4L2_FL_REGISTERED, &dev->radio_rx_dev.flags); 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->radio_tx_dev.flags);
set_bit(V4L2_FL_REGISTERED, &dev->meta_cap_dev.flags);
} }
mutex_unlock(&dev->mutex); mutex_unlock(&dev->mutex);
if (file->private_data == dev->overlay_cap_owner) if (file->private_data == dev->overlay_cap_owner)
...@@ -604,6 +617,11 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = { ...@@ -604,6 +617,11 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
.vidioc_log_status = vidioc_log_status, .vidioc_log_status = vidioc_log_status,
.vidioc_subscribe_event = vidioc_subscribe_event, .vidioc_subscribe_event = vidioc_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe, .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
.vidioc_enum_fmt_meta_cap = vidioc_enum_fmt_meta_cap,
.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,
}; };
/* ----------------------------------------------------------------- /* -----------------------------------------------------------------
...@@ -818,6 +836,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) ...@@ -818,6 +836,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->has_scaler_out ? 'Y' : 'N'); dev->has_scaler_out ? 'Y' : 'N');
} }
/* do we create a meta capture device */
dev->has_meta_cap = node_type & 0x20000;
/* end detecting feature set */ /* end detecting feature set */
if (dev->has_vid_cap) { if (dev->has_vid_cap) {
...@@ -875,6 +896,16 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) ...@@ -875,6 +896,16 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->radio_tx_caps = V4L2_CAP_RDS_OUTPUT | V4L2_CAP_MODULATOR | dev->radio_tx_caps = V4L2_CAP_RDS_OUTPUT | V4L2_CAP_MODULATOR |
V4L2_CAP_READWRITE; V4L2_CAP_READWRITE;
/* set up the capabilities of meta capture device */
if (dev->has_meta_cap) {
dev->meta_cap_caps = V4L2_CAP_META_CAPTURE |
V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
if (dev->has_audio_inputs)
dev->meta_cap_caps |= V4L2_CAP_AUDIO;
if (in_type_counter[TV])
dev->meta_cap_caps |= V4L2_CAP_TUNER;
}
ret = -ENOMEM; ret = -ENOMEM;
/* initialize the test pattern generator */ /* initialize the test pattern generator */
tpg_init(&dev->tpg, 640, 360); tpg_init(&dev->tpg, 640, 360);
...@@ -934,6 +965,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) ...@@ -934,6 +965,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_AUDIO); v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_AUDIO);
v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_AUDIO); v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_AUDIO);
v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_ENUMAUDIO); v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_ENUMAUDIO);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_AUDIO);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_G_AUDIO);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_ENUMAUDIO);
} }
if (!dev->has_audio_outputs) { if (!dev->has_audio_outputs) {
v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_AUDOUT); v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_AUDOUT);
...@@ -959,12 +993,16 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) ...@@ -959,12 +993,16 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_FREQUENCY); v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_FREQUENCY);
v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_FREQUENCY); v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_FREQUENCY);
v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_FREQUENCY); v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_FREQUENCY);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_FREQUENCY);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_G_FREQUENCY);
} }
if (!has_tuner) { if (!has_tuner) {
v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_TUNER); v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_TUNER);
v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_TUNER); v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_TUNER);
v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_TUNER); v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_TUNER);
v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_TUNER); v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_TUNER);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_TUNER);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_G_TUNER);
} }
if (in_type_counter[HDMI] == 0) { if (in_type_counter[HDMI] == 0) {
v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_EDID); v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_EDID);
...@@ -990,6 +1028,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) ...@@ -990,6 +1028,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_HW_FREQ_SEEK); v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_HW_FREQ_SEEK); v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
v4l2_disable_ioctl(&dev->sdr_cap_dev, VIDIOC_S_HW_FREQ_SEEK); v4l2_disable_ioctl(&dev->sdr_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_FREQUENCY); v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_FREQUENCY);
v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_FREQUENCY); v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_FREQUENCY);
v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_FRAMESIZES); v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_FRAMESIZES);
...@@ -1078,6 +1117,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) ...@@ -1078,6 +1117,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
INIT_LIST_HEAD(&dev->vbi_cap_active); INIT_LIST_HEAD(&dev->vbi_cap_active);
INIT_LIST_HEAD(&dev->vbi_out_active); INIT_LIST_HEAD(&dev->vbi_out_active);
INIT_LIST_HEAD(&dev->sdr_cap_active); INIT_LIST_HEAD(&dev->sdr_cap_active);
INIT_LIST_HEAD(&dev->meta_cap_active);
INIT_LIST_HEAD(&dev->cec_work_list); INIT_LIST_HEAD(&dev->cec_work_list);
spin_lock_init(&dev->cec_slock); spin_lock_init(&dev->cec_slock);
...@@ -1225,6 +1265,27 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) ...@@ -1225,6 +1265,27 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->fb_info.node); dev->fb_info.node);
} }
if (dev->has_meta_cap) {
/* initialize meta_cap queue */
q = &dev->vb_meta_cap_q;
q->type = V4L2_BUF_TYPE_META_CAPTURE;
q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
if (!allocator)
q->io_modes |= VB2_USERPTR;
q->drv_priv = dev;
q->buf_struct_size = sizeof(struct vivid_buffer);
q->ops = &vivid_meta_cap_qops;
q->mem_ops = vivid_mem_ops[allocator];
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->min_buffers_needed = 2;
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 #ifdef CONFIG_VIDEO_VIVID_CEC
if (dev->has_vid_cap && in_type_counter[HDMI]) { if (dev->has_vid_cap && in_type_counter[HDMI]) {
struct cec_adapter *adap; struct cec_adapter *adap;
...@@ -1265,6 +1326,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) ...@@ -1265,6 +1326,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_rx); v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_rx);
v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_tx); 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_sdr_cap);
v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_cap);
/* finally start creating the device nodes */ /* finally start creating the device nodes */
if (dev->has_vid_cap) { if (dev->has_vid_cap) {
...@@ -1492,6 +1554,35 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) ...@@ -1492,6 +1554,35 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
video_device_node_name(vfd)); video_device_node_name(vfd));
} }
if (dev->has_meta_cap) {
vfd = &dev->meta_cap_dev;
snprintf(vfd->name, sizeof(vfd->name),
"vivid-%03d-meta-cap", inst);
vfd->fops = &vivid_fops;
vfd->ioctl_ops = &vivid_ioctl_ops;
vfd->device_caps = dev->meta_cap_caps;
vfd->release = video_device_release_empty;
vfd->v4l2_dev = &dev->v4l2_dev;
vfd->queue = &dev->vb_meta_cap_q;
vfd->lock = &dev->mutex;
vfd->tvnorms = tvnorms_cap;
video_set_drvdata(vfd, dev);
#ifdef CONFIG_MEDIA_CONTROLLER
dev->meta_cap_pad.flags = MEDIA_PAD_FL_SINK;
ret = media_entity_pads_init(&vfd->entity, 1,
&dev->meta_cap_pad);
if (ret)
goto unreg_dev;
#endif
ret = video_register_device(vfd, VFL_TYPE_GRABBER,
meta_cap_nr[inst]);
if (ret < 0)
goto unreg_dev;
v4l2_info(&dev->v4l2_dev,
"V4L2 metadata capture device registered as %s\n",
video_device_node_name(vfd));
}
#ifdef CONFIG_MEDIA_CONTROLLER #ifdef CONFIG_MEDIA_CONTROLLER
/* Register the media device */ /* Register the media device */
ret = media_device_register(&dev->mdev); ret = media_device_register(&dev->mdev);
...@@ -1508,6 +1599,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) ...@@ -1508,6 +1599,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
return 0; return 0;
unreg_dev: unreg_dev:
video_unregister_device(&dev->meta_cap_dev);
video_unregister_device(&dev->radio_tx_dev); video_unregister_device(&dev->radio_tx_dev);
video_unregister_device(&dev->radio_rx_dev); video_unregister_device(&dev->radio_rx_dev);
video_unregister_device(&dev->sdr_cap_dev); video_unregister_device(&dev->sdr_cap_dev);
...@@ -1624,6 +1716,11 @@ static int vivid_remove(struct platform_device *pdev) ...@@ -1624,6 +1716,11 @@ static int vivid_remove(struct platform_device *pdev)
unregister_framebuffer(&dev->fb_info); unregister_framebuffer(&dev->fb_info);
vivid_fb_release_buffers(dev); vivid_fb_release_buffers(dev);
} }
if (dev->has_meta_cap) {
v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
video_device_node_name(&dev->meta_cap_dev));
video_unregister_device(&dev->meta_cap_dev);
}
cec_unregister_adapter(dev->cec_rx_adap); cec_unregister_adapter(dev->cec_rx_adap);
for (j = 0; j < MAX_OUTPUTS; j++) for (j = 0; j < MAX_OUTPUTS; j++)
cec_unregister_adapter(dev->cec_tx_adap[j]); cec_unregister_adapter(dev->cec_tx_adap[j]);
......
...@@ -131,6 +131,7 @@ struct vivid_dev { ...@@ -131,6 +131,7 @@ struct vivid_dev {
struct media_pad vbi_cap_pad; struct media_pad vbi_cap_pad;
struct media_pad vbi_out_pad; struct media_pad vbi_out_pad;
struct media_pad sdr_cap_pad; struct media_pad sdr_cap_pad;
struct media_pad meta_cap_pad;
#endif #endif
struct v4l2_ctrl_handler ctrl_hdl_user_gen; struct v4l2_ctrl_handler ctrl_hdl_user_gen;
struct v4l2_ctrl_handler ctrl_hdl_user_vid; struct v4l2_ctrl_handler ctrl_hdl_user_vid;
...@@ -153,6 +154,9 @@ struct vivid_dev { ...@@ -153,6 +154,9 @@ struct vivid_dev {
struct v4l2_ctrl_handler ctrl_hdl_radio_tx; struct v4l2_ctrl_handler ctrl_hdl_radio_tx;
struct video_device sdr_cap_dev; struct video_device sdr_cap_dev;
struct v4l2_ctrl_handler ctrl_hdl_sdr_cap; struct v4l2_ctrl_handler ctrl_hdl_sdr_cap;
struct video_device meta_cap_dev;
struct v4l2_ctrl_handler ctrl_hdl_meta_cap;
spinlock_t slock; spinlock_t slock;
struct mutex mutex; struct mutex mutex;
...@@ -164,6 +168,7 @@ struct vivid_dev { ...@@ -164,6 +168,7 @@ struct vivid_dev {
u32 sdr_cap_caps; u32 sdr_cap_caps;
u32 radio_rx_caps; u32 radio_rx_caps;
u32 radio_tx_caps; u32 radio_tx_caps;
u32 meta_cap_caps;
/* supported features */ /* supported features */
bool multiplanar; bool multiplanar;
...@@ -189,6 +194,7 @@ struct vivid_dev { ...@@ -189,6 +194,7 @@ struct vivid_dev {
bool has_radio_tx; bool has_radio_tx;
bool has_sdr_cap; bool has_sdr_cap;
bool has_fb; bool has_fb;
bool has_meta_cap;
bool can_loop_video; bool can_loop_video;
...@@ -390,6 +396,8 @@ struct vivid_dev { ...@@ -390,6 +396,8 @@ struct vivid_dev {
struct list_head vid_cap_active; struct list_head vid_cap_active;
struct vb2_queue vb_vbi_cap_q; struct vb2_queue vb_vbi_cap_q;
struct list_head vbi_cap_active; struct list_head vbi_cap_active;
struct vb2_queue vb_meta_cap_q;
struct list_head meta_cap_active;
/* thread for generating video capture stream */ /* thread for generating video capture stream */
struct task_struct *kthread_vid_cap; struct task_struct *kthread_vid_cap;
...@@ -407,6 +415,9 @@ struct vivid_dev { ...@@ -407,6 +415,9 @@ struct vivid_dev {
u32 vbi_cap_seq_count; u32 vbi_cap_seq_count;
bool vbi_cap_streaming; bool vbi_cap_streaming;
bool stream_sliced_vbi_cap; bool stream_sliced_vbi_cap;
u32 meta_cap_seq_start;
u32 meta_cap_seq_count;
bool meta_cap_streaming;
/* video output */ /* video output */
const struct vivid_fmt *fmt_out; const struct vivid_fmt *fmt_out;
...@@ -527,6 +538,9 @@ struct vivid_dev { ...@@ -527,6 +538,9 @@ struct vivid_dev {
/* CEC OSD String */ /* CEC OSD String */
char osd[14]; char osd[14];
unsigned long osd_jiffies; unsigned long osd_jiffies;
bool meta_pts;
bool meta_scr;
}; };
static inline bool vivid_is_webcam(const struct vivid_dev *dev) static inline bool vivid_is_webcam(const struct vivid_dev *dev)
......
...@@ -94,6 +94,9 @@ ...@@ -94,6 +94,9 @@
#define VIVID_CID_SDR_CAP_FM_DEVIATION (VIVID_CID_VIVID_BASE + 110) #define VIVID_CID_SDR_CAP_FM_DEVIATION (VIVID_CID_VIVID_BASE + 110)
#define VIVID_CID_META_CAP_GENERATE_PTS (VIVID_CID_VIVID_BASE + 111)
#define VIVID_CID_META_CAP_GENERATE_SCR (VIVID_CID_VIVID_BASE + 112)
/* General User Controls */ /* General User Controls */
static int vivid_user_gen_s_ctrl(struct v4l2_ctrl *ctrl) static int vivid_user_gen_s_ctrl(struct v4l2_ctrl *ctrl)
...@@ -110,6 +113,7 @@ static int vivid_user_gen_s_ctrl(struct v4l2_ctrl *ctrl) ...@@ -110,6 +113,7 @@ static int vivid_user_gen_s_ctrl(struct v4l2_ctrl *ctrl)
clear_bit(V4L2_FL_REGISTERED, &dev->sdr_cap_dev.flags); clear_bit(V4L2_FL_REGISTERED, &dev->sdr_cap_dev.flags);
clear_bit(V4L2_FL_REGISTERED, &dev->radio_rx_dev.flags); clear_bit(V4L2_FL_REGISTERED, &dev->radio_rx_dev.flags);
clear_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags); clear_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags);
clear_bit(V4L2_FL_REGISTERED, &dev->meta_cap_dev.flags);
break; break;
case VIVID_CID_BUTTON: case VIVID_CID_BUTTON:
dev->button_pressed = 30; dev->button_pressed = 30;
...@@ -1421,6 +1425,47 @@ static const struct v4l2_ctrl_config vivid_ctrl_sdr_cap_fm_deviation = { ...@@ -1421,6 +1425,47 @@ static const struct v4l2_ctrl_config vivid_ctrl_sdr_cap_fm_deviation = {
.step = 1, .step = 1,
}; };
/* Metadata Capture Control */
static int vivid_meta_cap_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev,
ctrl_hdl_meta_cap);
switch (ctrl->id) {
case VIVID_CID_META_CAP_GENERATE_PTS:
dev->meta_pts = ctrl->val;
break;
case VIVID_CID_META_CAP_GENERATE_SCR:
dev->meta_scr = ctrl->val;
break;
}
return 0;
}
static const struct v4l2_ctrl_ops vivid_meta_cap_ctrl_ops = {
.s_ctrl = vivid_meta_cap_s_ctrl,
};
static const struct v4l2_ctrl_config vivid_ctrl_meta_has_pts = {
.ops = &vivid_meta_cap_ctrl_ops,
.id = VIVID_CID_META_CAP_GENERATE_PTS,
.name = "Generate PTS",
.type = V4L2_CTRL_TYPE_BOOLEAN,
.max = 1,
.def = 1,
.step = 1,
};
static const struct v4l2_ctrl_config vivid_ctrl_meta_has_src_clk = {
.ops = &vivid_meta_cap_ctrl_ops,
.id = VIVID_CID_META_CAP_GENERATE_SCR,
.name = "Generate SCR",
.type = V4L2_CTRL_TYPE_BOOLEAN,
.max = 1,
.def = 1,
.step = 1,
};
static const struct v4l2_ctrl_config vivid_ctrl_class = { static const struct v4l2_ctrl_config vivid_ctrl_class = {
.ops = &vivid_user_gen_ctrl_ops, .ops = &vivid_user_gen_ctrl_ops,
...@@ -1448,6 +1493,8 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, ...@@ -1448,6 +1493,8 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
struct v4l2_ctrl_handler *hdl_radio_rx = &dev->ctrl_hdl_radio_rx; struct v4l2_ctrl_handler *hdl_radio_rx = &dev->ctrl_hdl_radio_rx;
struct v4l2_ctrl_handler *hdl_radio_tx = &dev->ctrl_hdl_radio_tx; 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_sdr_cap = &dev->ctrl_hdl_sdr_cap;
struct v4l2_ctrl_handler *hdl_meta_cap = &dev->ctrl_hdl_meta_cap;
struct v4l2_ctrl_config vivid_ctrl_dv_timings = { struct v4l2_ctrl_config vivid_ctrl_dv_timings = {
.ops = &vivid_vid_cap_ctrl_ops, .ops = &vivid_vid_cap_ctrl_ops,
.id = VIVID_CID_DV_TIMINGS, .id = VIVID_CID_DV_TIMINGS,
...@@ -1486,6 +1533,8 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, ...@@ -1486,6 +1533,8 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
v4l2_ctrl_new_custom(hdl_radio_tx, &vivid_ctrl_class, NULL); v4l2_ctrl_new_custom(hdl_radio_tx, &vivid_ctrl_class, NULL);
v4l2_ctrl_handler_init(hdl_sdr_cap, 19); v4l2_ctrl_handler_init(hdl_sdr_cap, 19);
v4l2_ctrl_new_custom(hdl_sdr_cap, &vivid_ctrl_class, NULL); 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);
/* User Controls */ /* User Controls */
dev->volume = v4l2_ctrl_new_std(hdl_user_aud, NULL, dev->volume = v4l2_ctrl_new_std(hdl_user_aud, NULL,
...@@ -1743,6 +1792,13 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, ...@@ -1743,6 +1792,13 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
v4l2_ctrl_new_custom(hdl_sdr_cap, v4l2_ctrl_new_custom(hdl_sdr_cap,
&vivid_ctrl_sdr_cap_fm_deviation, NULL); &vivid_ctrl_sdr_cap_fm_deviation, NULL);
} }
if (dev->has_meta_cap) {
v4l2_ctrl_new_custom(hdl_meta_cap,
&vivid_ctrl_meta_has_pts, NULL);
v4l2_ctrl_new_custom(hdl_meta_cap,
&vivid_ctrl_meta_has_src_clk, NULL);
}
if (hdl_user_gen->error) if (hdl_user_gen->error)
return hdl_user_gen->error; return hdl_user_gen->error;
if (hdl_user_vid->error) if (hdl_user_vid->error)
...@@ -1817,6 +1873,14 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, ...@@ -1817,6 +1873,14 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
return hdl_sdr_cap->error; return hdl_sdr_cap->error;
dev->sdr_cap_dev.ctrl_handler = hdl_sdr_cap; dev->sdr_cap_dev.ctrl_handler = hdl_sdr_cap;
} }
if (dev->has_meta_cap) {
v4l2_ctrl_add_handler(hdl_meta_cap, hdl_user_gen, NULL, false);
v4l2_ctrl_add_handler(hdl_meta_cap, hdl_streaming, NULL, false);
if (hdl_meta_cap->error)
return hdl_meta_cap->error;
dev->meta_cap_dev.ctrl_handler = hdl_meta_cap;
}
return 0; return 0;
} }
...@@ -1836,4 +1900,5 @@ void vivid_free_controls(struct vivid_dev *dev) ...@@ -1836,4 +1900,5 @@ void vivid_free_controls(struct vivid_dev *dev)
v4l2_ctrl_handler_free(&dev->ctrl_hdl_sdtv_cap); v4l2_ctrl_handler_free(&dev->ctrl_hdl_sdtv_cap);
v4l2_ctrl_handler_free(&dev->ctrl_hdl_loop_cap); v4l2_ctrl_handler_free(&dev->ctrl_hdl_loop_cap);
v4l2_ctrl_handler_free(&dev->ctrl_hdl_fb); v4l2_ctrl_handler_free(&dev->ctrl_hdl_fb);
v4l2_ctrl_handler_free(&dev->ctrl_hdl_meta_cap);
} }
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include "vivid-osd.h" #include "vivid-osd.h"
#include "vivid-ctrls.h" #include "vivid-ctrls.h"
#include "vivid-kthread-cap.h" #include "vivid-kthread-cap.h"
#include "vivid-meta-cap.h"
static inline v4l2_std_id vivid_get_std_cap(const struct vivid_dev *dev) static inline v4l2_std_id vivid_get_std_cap(const struct vivid_dev *dev)
{ {
...@@ -677,6 +678,7 @@ static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev, ...@@ -677,6 +678,7 @@ static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev,
{ {
struct vivid_buffer *vid_cap_buf = NULL; struct vivid_buffer *vid_cap_buf = NULL;
struct vivid_buffer *vbi_cap_buf = NULL; struct vivid_buffer *vbi_cap_buf = NULL;
struct vivid_buffer *meta_cap_buf = NULL;
u64 f_time = 0; u64 f_time = 0;
dprintk(dev, 1, "Video Capture Thread Tick\n"); dprintk(dev, 1, "Video Capture Thread Tick\n");
...@@ -704,15 +706,19 @@ static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev, ...@@ -704,15 +706,19 @@ static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev,
list_del(&vbi_cap_buf->list); list_del(&vbi_cap_buf->list);
} }
} }
if (!list_empty(&dev->meta_cap_active)) {
meta_cap_buf = list_entry(dev->meta_cap_active.next,
struct vivid_buffer, list);
list_del(&meta_cap_buf->list);
}
spin_unlock(&dev->slock); spin_unlock(&dev->slock);
if (!vid_cap_buf && !vbi_cap_buf) if (!vid_cap_buf && !vbi_cap_buf && !meta_cap_buf)
goto update_mv; goto update_mv;
f_time = dev->cap_frame_period * dev->vid_cap_seq_count + f_time = dev->cap_frame_period * dev->vid_cap_seq_count +
dev->cap_stream_start + dev->time_wrap_offset; dev->cap_stream_start + dev->time_wrap_offset;
if (!dev->tstamp_src_is_soe)
f_time += dev->cap_frame_eof_offset;
if (vid_cap_buf) { if (vid_cap_buf) {
v4l2_ctrl_request_setup(vid_cap_buf->vb.vb2_buf.req_obj.req, v4l2_ctrl_request_setup(vid_cap_buf->vb.vb2_buf.req_obj.req,
...@@ -735,6 +741,8 @@ static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev, ...@@ -735,6 +741,8 @@ static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev,
vid_cap_buf->vb.vb2_buf.index); vid_cap_buf->vb.vb2_buf.index);
vid_cap_buf->vb.vb2_buf.timestamp = f_time; vid_cap_buf->vb.vb2_buf.timestamp = f_time;
if (!dev->tstamp_src_is_soe)
vid_cap_buf->vb.vb2_buf.timestamp += dev->cap_frame_eof_offset;
} }
if (vbi_cap_buf) { if (vbi_cap_buf) {
...@@ -756,8 +764,22 @@ static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev, ...@@ -756,8 +764,22 @@ static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev,
/* If capturing a VBI, offset by 0.05 */ /* If capturing a VBI, offset by 0.05 */
vbi_period = dev->cap_frame_period * 5; vbi_period = dev->cap_frame_period * 5;
do_div(vbi_period, 100); do_div(vbi_period, 100);
vbi_cap_buf->vb.vb2_buf.timestamp = f_time + vbi_period; vbi_cap_buf->vb.vb2_buf.timestamp = f_time + dev->cap_frame_eof_offset + vbi_period;
}
if (meta_cap_buf) {
v4l2_ctrl_request_setup(meta_cap_buf->vb.vb2_buf.req_obj.req,
&dev->ctrl_hdl_meta_cap);
vivid_meta_cap_fillbuff(dev, meta_cap_buf, f_time);
v4l2_ctrl_request_complete(meta_cap_buf->vb.vb2_buf.req_obj.req,
&dev->ctrl_hdl_meta_cap);
vb2_buffer_done(&meta_cap_buf->vb.vb2_buf, dev->dqbuf_error ?
VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
dprintk(dev, 2, "meta_cap %d done\n",
meta_cap_buf->vb.vb2_buf.index);
meta_cap_buf->vb.vb2_buf.timestamp = f_time + dev->cap_frame_eof_offset;
} }
dev->dqbuf_error = false; dev->dqbuf_error = false;
update_mv: update_mv:
...@@ -835,6 +857,7 @@ static int vivid_thread_vid_cap(void *data) ...@@ -835,6 +857,7 @@ static int vivid_thread_vid_cap(void *data)
dev->cap_seq_count = buffers_since_start + dev->cap_seq_offset; dev->cap_seq_count = buffers_since_start + dev->cap_seq_offset;
dev->vid_cap_seq_count = dev->cap_seq_count - dev->vid_cap_seq_start; dev->vid_cap_seq_count = dev->cap_seq_count - dev->vid_cap_seq_start;
dev->vbi_cap_seq_count = dev->cap_seq_count - dev->vbi_cap_seq_start; dev->vbi_cap_seq_count = dev->cap_seq_count - dev->vbi_cap_seq_start;
dev->meta_cap_seq_count = dev->cap_seq_count - dev->meta_cap_seq_start;
vivid_thread_vid_cap_tick(dev, dropped_bufs); vivid_thread_vid_cap_tick(dev, dropped_bufs);
...@@ -883,8 +906,10 @@ int vivid_start_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming) ...@@ -883,8 +906,10 @@ int vivid_start_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming)
if (pstreaming == &dev->vid_cap_streaming) if (pstreaming == &dev->vid_cap_streaming)
dev->vid_cap_seq_start = seq_count; dev->vid_cap_seq_start = seq_count;
else else if (pstreaming == &dev->vbi_cap_streaming)
dev->vbi_cap_seq_start = seq_count; dev->vbi_cap_seq_start = seq_count;
else
dev->meta_cap_seq_start = seq_count;
*pstreaming = true; *pstreaming = true;
return 0; return 0;
} }
...@@ -894,6 +919,7 @@ int vivid_start_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming) ...@@ -894,6 +919,7 @@ int vivid_start_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming)
dev->vid_cap_seq_start = dev->seq_wrap * 128; dev->vid_cap_seq_start = dev->seq_wrap * 128;
dev->vbi_cap_seq_start = dev->seq_wrap * 128; dev->vbi_cap_seq_start = dev->seq_wrap * 128;
dev->meta_cap_seq_start = dev->seq_wrap * 128;
dev->kthread_vid_cap = kthread_run(vivid_thread_vid_cap, dev, dev->kthread_vid_cap = kthread_run(vivid_thread_vid_cap, dev,
"%s-vid-cap", dev->v4l2_dev.name); "%s-vid-cap", dev->v4l2_dev.name);
...@@ -951,7 +977,23 @@ void vivid_stop_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming) ...@@ -951,7 +977,23 @@ void vivid_stop_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming)
} }
} }
if (dev->vid_cap_streaming || dev->vbi_cap_streaming) if (pstreaming == &dev->meta_cap_streaming) {
while (!list_empty(&dev->meta_cap_active)) {
struct vivid_buffer *buf;
buf = list_entry(dev->meta_cap_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_cap);
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
dprintk(dev, 2, "meta_cap buffer %d done\n",
buf->vb.vb2_buf.index);
}
}
if (dev->vid_cap_streaming || dev->vbi_cap_streaming ||
dev->meta_cap_streaming)
return; return;
/* shutdown control thread */ /* shutdown control thread */
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* vivid-meta-cap.c - meta capture support functions.
*/
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <linux/usb/video.h>
#include "vivid-core.h"
#include "vivid-kthread-cap.h"
#include "vivid-meta-cap.h"
static int meta_cap_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
unsigned int *nplanes, unsigned int sizes[],
struct device *alloc_devs[])
{
struct vivid_dev *dev = vb2_get_drv_priv(vq);
unsigned int size = sizeof(struct vivid_uvc_meta_buf);
if (!vivid_is_webcam(dev))
return -EINVAL;
if (*nplanes) {
if (sizes[0] < size)
return -EINVAL;
} else {
sizes[0] = size;
}
if (vq->num_buffers + *nbuffers < 2)
*nbuffers = 2 - vq->num_buffers;
*nplanes = 1;
return 0;
}
static int meta_cap_buf_prepare(struct vb2_buffer *vb)
{
struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
unsigned int size = sizeof(struct vivid_uvc_meta_buf);
dprintk(dev, 1, "%s\n", __func__);
if (dev->buf_prepare_error) {
/*
* Error injection: test what happens if buf_prepare() returns
* an error.
*/
dev->buf_prepare_error = false;
return -EINVAL;
}
if (vb2_plane_size(vb, 0) < size) {
dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n",
__func__, vb2_plane_size(vb, 0), size);
return -EINVAL;
}
vb2_set_plane_payload(vb, 0, size);
return 0;
}
static void meta_cap_buf_queue(struct vb2_buffer *vb)
{
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb);
dprintk(dev, 1, "%s\n", __func__);
spin_lock(&dev->slock);
list_add_tail(&buf->list, &dev->meta_cap_active);
spin_unlock(&dev->slock);
}
static int meta_cap_start_streaming(struct vb2_queue *vq, unsigned int count)
{
struct vivid_dev *dev = vb2_get_drv_priv(vq);
int err;
dprintk(dev, 1, "%s\n", __func__);
dev->meta_cap_seq_count = 0;
if (dev->start_streaming_error) {
dev->start_streaming_error = false;
err = -EINVAL;
} else {
err = vivid_start_generating_vid_cap(dev,
&dev->meta_cap_streaming);
}
if (err) {
struct vivid_buffer *buf, *tmp;
list_for_each_entry_safe(buf, tmp,
&dev->meta_cap_active, list) {
list_del(&buf->list);
vb2_buffer_done(&buf->vb.vb2_buf,
VB2_BUF_STATE_QUEUED);
}
}
return err;
}
/* abort streaming and wait for last buffer */
static void meta_cap_stop_streaming(struct vb2_queue *vq)
{
struct vivid_dev *dev = vb2_get_drv_priv(vq);
dprintk(dev, 1, "%s\n", __func__);
vivid_stop_generating_vid_cap(dev, &dev->meta_cap_streaming);
}
static void meta_cap_buf_request_complete(struct vb2_buffer *vb)
{
struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_meta_cap);
}
const struct vb2_ops vivid_meta_cap_qops = {
.queue_setup = meta_cap_queue_setup,
.buf_prepare = meta_cap_buf_prepare,
.buf_queue = meta_cap_buf_queue,
.start_streaming = meta_cap_start_streaming,
.stop_streaming = meta_cap_stop_streaming,
.buf_request_complete = meta_cap_buf_request_complete,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
};
int vidioc_enum_fmt_meta_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
struct vivid_dev *dev = video_drvdata(file);
if (!vivid_is_webcam(dev))
return -EINVAL;
if (f->index > 0)
return -EINVAL;
f->type = V4L2_BUF_TYPE_META_CAPTURE;
f->pixelformat = V4L2_META_FMT_UVC;
return 0;
}
int vidioc_g_fmt_meta_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct vivid_dev *dev = video_drvdata(file);
struct v4l2_meta_format *meta = &f->fmt.meta;
if (!vivid_is_webcam(dev) || !dev->has_meta_cap)
return -EINVAL;
meta->dataformat = V4L2_META_FMT_UVC;
meta->buffersize = sizeof(struct vivid_uvc_meta_buf);
return 0;
}
void vivid_meta_cap_fillbuff(struct vivid_dev *dev,
struct vivid_buffer *buf, u64 soe)
{
struct vivid_uvc_meta_buf *meta = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
int buf_off = 0;
buf->vb.sequence = dev->meta_cap_seq_count;
if (dev->field_cap == V4L2_FIELD_ALTERNATE)
buf->vb.sequence /= 2;
memset(meta, 1, vb2_plane_size(&buf->vb.vb2_buf, 0));
meta->ns = ktime_get_ns();
meta->sof = buf->vb.sequence * 30;
meta->length = sizeof(*meta) - offsetof(struct vivid_uvc_meta_buf, length);
meta->flags = UVC_STREAM_EOH | UVC_STREAM_EOF;
if ((buf->vb.sequence % 2) == 0)
meta->flags |= UVC_STREAM_FID;
dprintk(dev, 2, "%s ns:%llu sof:%4d len:%u flags: 0x%02x",
__func__, meta->ns, meta->sof, meta->length, meta->flags);
if (dev->meta_pts) {
meta->flags |= UVC_STREAM_PTS;
meta->buf[0] = div_u64(soe, VIVID_META_CLOCK_UNIT);
buf_off = 4;
dprintk(dev, 2, " pts: %u\n", *(__u32 *)(meta->buf));
}
if (dev->meta_scr) {
meta->flags |= UVC_STREAM_SCR;
meta->buf[buf_off] = div_u64((soe + dev->cap_frame_eof_offset),
VIVID_META_CLOCK_UNIT);
meta->buf[buf_off + 4] = (buf->vb.sequence * 30) % 1000;
dprintk(dev, 2, " stc: %u, sof counter: %u\n",
*(__u32 *)(meta->buf + buf_off),
*(__u16 *)(meta->buf + buf_off + 4));
}
dprintk(dev, 2, "\n");
}
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* vivid-meta-cap.h - meta capture support functions.
*/
#ifndef _VIVID_META_CAP_H_
#define _VIVID_META_CAP_H_
#define VIVID_META_CLOCK_UNIT 10 /* 100 MHz */
struct vivid_uvc_meta_buf {
__u64 ns;
__u16 sof;
__u8 length;
__u8 flags;
__u8 buf[10]; /* PTS(4)+STC(4)+SOF(2) */
} __packed;
void vivid_meta_cap_fillbuff(struct vivid_dev *dev,
struct vivid_buffer *buf, u64 soe);
int vidioc_enum_fmt_meta_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f);
int vidioc_g_fmt_meta_cap(struct file *file, void *priv,
struct v4l2_format *f);
extern const struct vb2_ops vivid_meta_cap_qops;
#endif
...@@ -1356,7 +1356,9 @@ int vidioc_s_input(struct file *file, void *priv, unsigned i) ...@@ -1356,7 +1356,9 @@ int vidioc_s_input(struct file *file, void *priv, unsigned i)
if (i == dev->input) if (i == dev->input)
return 0; return 0;
if (vb2_is_busy(&dev->vb_vid_cap_q) || vb2_is_busy(&dev->vb_vbi_cap_q)) if (vb2_is_busy(&dev->vb_vid_cap_q) ||
vb2_is_busy(&dev->vb_vbi_cap_q) ||
vb2_is_busy(&dev->vb_meta_cap_q))
return -EBUSY; return -EBUSY;
dev->input = i; dev->input = i;
...@@ -1366,6 +1368,7 @@ int vidioc_s_input(struct file *file, void *priv, unsigned i) ...@@ -1366,6 +1368,7 @@ int vidioc_s_input(struct file *file, void *priv, unsigned i)
dev->vid_cap_dev.tvnorms = V4L2_STD_ALL; dev->vid_cap_dev.tvnorms = V4L2_STD_ALL;
} }
dev->vbi_cap_dev.tvnorms = dev->vid_cap_dev.tvnorms; dev->vbi_cap_dev.tvnorms = dev->vid_cap_dev.tvnorms;
dev->meta_cap_dev.tvnorms = dev->vid_cap_dev.tvnorms;
vivid_update_format_cap(dev, false); vivid_update_format_cap(dev, false);
if (dev->colorspace) { if (dev->colorspace) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册