[RFC PATCH] media: v4l: implement virtual channels

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



With experimental support for multiple streams per pad being added, the
pieces are in place to support a virtual channel id per stream.

This is necessary because stream ids cannot be directly mapped to a virtual
channel id, since the same virtual channel id can be assigned to multiple
streams of data, each with a different data type.

To implement this, the following steps have been taken.

Add subdev ioctls for getting and setting the virtual channel for a
specific pad and stream.

Add pad .get_vc() and .set_vc() ops.

Add the virtual channel to the stream config in V4L2 subdev central state.

Add a default .get_vc() implementation that retrieves the virtual channel
from the central state, or, if that is not supported, default to virtual
channel 0.

Signed-off-by: Cosmin Tanislav <demonsingur@xxxxxxxxx>
---
 drivers/media/v4l2-core/v4l2-subdev.c | 57 +++++++++++++++++++++++++++
 include/media/v4l2-subdev.h           | 39 ++++++++++++++++++
 include/uapi/linux/v4l2-subdev.h      | 18 +++++++++
 3 files changed, 114 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index be86b906c985..8945bfd0fe12 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -535,6 +535,9 @@ subdev_ioctl_get_state(struct v4l2_subdev *sd, struct v4l2_subdev_fh *subdev_fh,
 	case VIDIOC_SUBDEV_S_ROUTING:
 		which = ((struct v4l2_subdev_routing *)arg)->which;
 		break;
+	case VIDIOC_SUBDEV_G_VC:
+	case VIDIOC_SUBDEV_S_VC:
+		which = ((struct v4l2_subdev_vc *)arg)->which;
 	}
 
 	return which == V4L2_SUBDEV_FORMAT_TRY ?
@@ -969,6 +972,26 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
 					routing->which, &krouting);
 	}
 
+	case VIDIOC_SUBDEV_G_VC: {
+		struct v4l2_subdev_vc *vc = arg;
+
+		if (!client_supports_streams)
+			vc->stream = 0;
+
+		memset(vc->reserved, 0, sizeof(vc->reserved));
+		return v4l2_subdev_call(sd, pad, get_vc, state, vc);
+	}
+
+	case VIDIOC_SUBDEV_S_VC: {
+		struct v4l2_subdev_vc *vc = arg;
+
+		if (!client_supports_streams)
+			vc->stream = 0;
+
+		memset(vc->reserved, 0, sizeof(vc->reserved));
+		return v4l2_subdev_call(sd, pad, set_vc, state, vc);
+	}
+
 	case VIDIOC_SUBDEV_G_CLIENT_CAP: {
 		struct v4l2_subdev_client_capability *client_cap = arg;
 
@@ -1602,6 +1625,20 @@ int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state,
 }
 EXPORT_SYMBOL_GPL(v4l2_subdev_get_fmt);
 
+int v4l2_subdev_get_vc(struct v4l2_subdev *sd, struct v4l2_subdev_state *state,
+		       struct v4l2_subdev_vc *vc)
+{
+	u32 vc_id = 0;
+
+	if (sd->flags & V4L2_SUBDEV_FL_STREAMS)
+		vc_id = v4l2_subdev_state_get_stream_vc(state, vc->pad, vc->stream);
+
+	vc->vc = vc_id;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_get_vc);
+
 int v4l2_subdev_set_routing(struct v4l2_subdev *sd,
 			    struct v4l2_subdev_state *state,
 			    const struct v4l2_subdev_krouting *routing)
@@ -1745,6 +1782,26 @@ v4l2_subdev_state_get_stream_compose(struct v4l2_subdev_state *state,
 }
 EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_stream_compose);
 
+u32 v4l2_subdev_state_get_stream_vc(struct v4l2_subdev_state *state,
+				    unsigned int pad, u32 stream)
+{
+	struct v4l2_subdev_stream_configs *stream_configs;
+	unsigned int i;
+
+	lockdep_assert_held(state->lock);
+
+	stream_configs = &state->stream_configs;
+
+	for (i = 0; i < stream_configs->num_configs; ++i) {
+		if (stream_configs->configs[i].pad == pad &&
+		    stream_configs->configs[i].stream == stream)
+			return stream_configs->configs[i].vc;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_stream_vc);
+
 int v4l2_subdev_routing_find_opposite_end(const struct v4l2_subdev_krouting *routing,
 					  u32 pad, u32 stream, u32 *other_pad,
 					  u32 *other_stream)
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index c1f90c1223a7..ed1fdd79c2bb 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -722,6 +722,7 @@ struct v4l2_subdev_stream_config {
 	u32 stream;
 	bool enabled;
 
+	u32 vc;
 	struct v4l2_mbus_framefmt fmt;
 	struct v4l2_rect crop;
 	struct v4l2_rect compose;
@@ -858,6 +859,12 @@ struct v4l2_subdev_pad_ops {
 	int (*set_fmt)(struct v4l2_subdev *sd,
 		       struct v4l2_subdev_state *state,
 		       struct v4l2_subdev_format *format);
+	int (*get_vc)(struct v4l2_subdev *sd,
+		      struct v4l2_subdev_state *state,
+		      struct v4l2_subdev_vc *vc);
+	int (*set_vc)(struct v4l2_subdev *sd,
+		      struct v4l2_subdev_state *state,
+		      struct v4l2_subdev_vc *vc);
 	int (*get_selection)(struct v4l2_subdev *sd,
 			     struct v4l2_subdev_state *state,
 			     struct v4l2_subdev_selection *sel);
@@ -1494,6 +1501,23 @@ v4l2_subdev_lock_and_get_active_state(struct v4l2_subdev *sd)
 int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state,
 			struct v4l2_subdev_format *format);
 
+/**
+ * v4l2_subdev_get_vc() - Fill virtual channel based on state
+ * @sd: subdevice
+ * @state: subdevice state
+ * @vc: pointer to &struct v4l2_subdev_vc
+ *
+ * Fill @vc->vc field based on the information in the @vc struct.
+ *
+ * This function can be used by the subdev drivers which support active state to
+ * implement v4l2_subdev_pad_ops.get_vc if the subdev driver does not need to
+ * do anything special in their get_vc op.
+ *
+ * Returns 0 on success, error value otherwise.
+ */
+int v4l2_subdev_get_vc(struct v4l2_subdev *sd, struct v4l2_subdev_state *state,
+		       struct v4l2_subdev_vc *vc);
+
 /**
  * v4l2_subdev_set_routing() - Set given routing to subdev state
  * @sd: The subdevice
@@ -1585,6 +1609,21 @@ struct v4l2_rect *
 v4l2_subdev_state_get_stream_compose(struct v4l2_subdev_state *state,
 				     unsigned int pad, u32 stream);
 
+/**
+ * v4l2_subdev_state_get_stream_vc() - Get the virtual channel of a stream
+ * @state: subdevice state
+ * @pad: pad id
+ * @stream: stream id
+ *
+ * This returns the virtual channel for the given pad + stream in the
+ * subdev state.
+ *
+ * If the state does not contain the given pad + stream, 0 is returned.
+ */
+u32
+v4l2_subdev_state_get_stream_vc(struct v4l2_subdev_state *state,
+				unsigned int pad, u32 stream);
+
 /**
  * v4l2_subdev_routing_find_opposite_end() - Find the opposite stream
  * @routing: routing used to find the opposite side
diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
index b383c2fe0cf3..8e90405bb1e6 100644
--- a/include/uapi/linux/v4l2-subdev.h
+++ b/include/uapi/linux/v4l2-subdev.h
@@ -187,6 +187,22 @@ struct v4l2_subdev_capability {
 	__u32 reserved[14];
 };
 
+/**
+ * struct v4l2_subdev_vc - Pad-level virtual channel settings
+ * @which: format type (from enum v4l2_subdev_format_whence)
+ * @pad: pad number, as reported by the media API
+ * @vc: virtual channel
+ * @stream: stream number, defined in subdev routing
+ * @reserved: drivers and applications must zero this array
+ */
+struct v4l2_subdev_vc {
+	__u32 which;
+	__u32 pad;
+	__u32 vc;
+	__u32 stream;
+	__u32 reserved[7];
+};
+
 /* The v4l2 sub-device video device node is registered in read-only mode. */
 #define V4L2_SUBDEV_CAP_RO_SUBDEV		0x00000001
 
@@ -268,6 +284,8 @@ struct v4l2_subdev_client_capability {
 #define VIDIOC_SUBDEV_S_SELECTION		_IOWR('V', 62, struct v4l2_subdev_selection)
 #define VIDIOC_SUBDEV_G_ROUTING			_IOWR('V', 38, struct v4l2_subdev_routing)
 #define VIDIOC_SUBDEV_S_ROUTING			_IOWR('V', 39, struct v4l2_subdev_routing)
+#define VIDIOC_SUBDEV_G_VC			_IOWR('V', 40, struct v4l2_subdev_vc)
+#define VIDIOC_SUBDEV_S_VC			_IOWR('V', 41, struct v4l2_subdev_vc)
 #define VIDIOC_SUBDEV_G_CLIENT_CAP		_IOR('V',  101, struct v4l2_subdev_client_capability)
 #define VIDIOC_SUBDEV_S_CLIENT_CAP		_IOWR('V',  102, struct v4l2_subdev_client_capability)
 
-- 
2.43.0





[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux