All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 0/3] Multi-planar video format and buffer support for the V4L2 API
@ 2010-07-30  8:49 Pawel Osciak
  2010-07-30  8:49 ` [PATCH v5 1/3] v4l: Add multi-planar API definitions to " Pawel Osciak
                   ` (3 more replies)
  0 siblings, 4 replies; 11+ messages in thread
From: Pawel Osciak @ 2010-07-30  8:49 UTC (permalink / raw)
  To: linux-media; +Cc: p.osciak, kyungmin.park, m.szyprowski, t.fujak

Hello,

After 9 months since the first proposal, lots of discussion and many changes, 
including an almost full redesign between versions 3 and 4, I present the
patches that add the fifth version of the multi-planar API for V4L2.

I am posting patches first for everyone to be able to take a look early and
would be grateful for some indication of your acceptance.

More documentation (DocBook) is on the way. Documentation in textual form can be
found below.


Changes since v4:
- struct v4l2_pix_format_mplane:
  * does not include a struct v4l2_pix_format anymore, replaced with concrete
    fields
  * new field: num_planes
- renamed fields in struct v4l2_plane (to prevent ambiguity):
  * mem_off -> mem_offset
  * data_off -> data_offset
- renamed field in struct v4l2_format (for consistency):
  * mp_pix -> pix_mp


Contents:
[PATCH v5 1/3] v4l: Add multi-planar API definitions to the V4L2 API
[PATCH v5 2/3] v4l: Add multi-planar ioctl handling code
[PATCH v5 3/3] v4l: Add compat functions for the multi-planar API


===============================================
I. Rationale
===============================================
Some embedded devices (including Samsung S3C/S5P SoC series) require physically
separate memory buffers for placing video components. For example, S5P SoC video
codec uses one buffer for Y and another for interleaved CbCr components. This
cannot be achieved with the current V4L2 API. One of the reasons is that
v4l2_buffer struct can only hold one pointer/offset to a video buffer.

As the proposal evolved, we found more uses for separate planes per buffer,
for non-embedded systems as well. Some examples include:
  - applications may receive (or choose to store) video data of one video
  buffer in separate memory buffers; such data would have to be temporarily
  copied together into one buffer before passing it to a V4L2 device;
  - applications or drivers may want to pass metadata related to a buffer and
  it may not be possible to place it in the same buffer together with video
  data;
Example features to be implemented in the future:
  - allowing video data to be stored in driver-provided memory (MMAP type) while
  metadata in application-provided buffers (USEPTR type) - useful for drivers
  that require coefficient matrices, that take or return header/metadata, etc.
  - allowing variable number of planes passed to each QBUF/DQBUF operations,
  differing between calls.


===============================================
II. Short introduction
===============================================

To establish a consistent nomenclature, for the remainder of this document:
 - "multi-planar" indicates a call/format used with multi-planar API,
   irrespective of the number of planes;
 - "1-plane format", "n-plane formats" indicate the number of planes in a format
   and have nothing to do with the API used; 1-plane formats can be used with
   the multi-planar API;


* The changes are fully backwards-compatible with the current V4L2 API.

* All multi-planar calls and types can be recognized by their utilization of new
buffer type defines (see below).

* Multi-planar API can be used as a superset of both APIs and can replace the
single-planar API; "old" formats can be used as 1-plane multi-planar formats.

* A format translation layer is also introduced, new drivers and applications
do not have to implement both API versions. A driver that only implements the
multi-planar version will still be able to transparently communicate with
applications that only use single-planar calls (but those applications will
only be able to use the driver's 1-plane formats). The other way around is also
possible - a driver that only implements the single-planar API can be used by
a multi-planar-API-only application fully.

* Applications can query for multi-planar capabilities by means of the standard
VIDIOC_QUERYCAP call.

* Affected ioctls are those that operate on either pix formats or buffers, which
are interpreted in a different way when one of the new buffer types is passed
in their corresponding fields:
 - VIDIOC_G_FMT, VIDIOC_S_FMT, VIDIOC_TRY_FMT, VIDIOC_ENUM_FMT;
 - VIDIOC_QBUF, VIDIOC_DQBUF, VIDIOC_QUERYBUF
 - VIDIOC_REQBUF (accepts new buffer types, behavior unchanged)

* Fourcc codes differ across plane counts, e.g. a 1-plane YCbCr fourcc is
different from that of an, otherwise identical, 2-plane YCbCr. On the other
hand, a 1-plane format uses the same fourcc code in both versions of the API.

* Applications do not have to support both APIs, it is enough to just use the
multi-planar version, as it will be transparently converted to single-planar
API for 1-plane-format-only drivers. Of course, it is not possible to set
a format with more than 1-plane for a single-planar-only driver, but
applications should not try this in the first place. They should use formats
returned from ENUM_FMT only and those will be 1-plane only.


===============================================
III. Multi-planar API format description/negotiation
===============================================


1. Maximum number of planes
----------------------------------

It has been agreed that the maximum number of planes per buffer will be 8:

+#define VIDEO_MAX_PLANES               8


2. Capability checks
----------------------------------

If a driver supports multi-planar API, it can set one (or both) of the new
capability flags:

+/* Is a video capture device that supports multiplanar formats */
+#define V4L2_CAP_VIDEO_CAPTURE_MPLANE  0x00001000
+/* Is a video output device that supports multiplanar formats */
+#define V4L2_CAP_VIDEO_OUTPUT_MPLANE   0x00002000

- any combination of those flags is valid;
- any combinations with V4L2_CAP_VIDEO_CAPTURE and V4L2_CAP_VIDEO_OUTPUT flags
  are also valid;
- the new flags indicate that a driver supports the multi-planar API, but it
  does NOT imply that it actually uses formats with more than 1 plane; it is
  perfectly possible and valid to use the new API for 1-plane formats only;
  using the new API for both 1-plane and n-plane formats makes the
  applications simpler, as they do not have to fall back to the old API in the
  former case.


3. Identifying multi-planar calls and structs:
----------------------------------

It is assumed (for now at least) that multi-planar API makes sense for pixel
formats only, so two new buffer types are added, for OUTPUT and CAPTURE:

 enum v4l2_buf_type {
        /* ... */
+       V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE = 17,
+       V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE  = 18,
        /* ... */
 };


4. Describing multi-planar formats
----------------------------------

To describe multi-planar formats, the format struct has to be extended, as some
information has to be specified per plane:

 struct v4l2_format {
        enum v4l2_buf_type type;
        union {
                struct v4l2_pix_format          pix;     /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
+               struct v4l2_pix_format_mplane   pix_mp;  /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
                struct v4l2_window              win;     /* V4L2_BUF_TYPE_VIDEO_OVERLAY */
                struct v4l2_vbi_format          vbi;     /* V4L2_BUF_TYPE_VBI_CAPTURE */
                struct v4l2_sliced_vbi_format   sliced;  /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */
                __u8    raw_data[200];                   /* user-defined */
        } fmt;
 };

For the new buffer types mp_pix member is chosen. For those buffer types,
struct v4l2_pix_format_mplane is used:

/**
 * struct v4l2_pix_format_mplane - multiplanar format definition
 * @width:              image width in pixels
 * @height:             image height in pixels
 * @pixelformat:        little endian four character code (fourcc)
 * @field:              field order (for interlaced video)
 * @colorspace:         supplemental to pixelformat
 * @plane_fmt:          per-plane information
 * @num_planes:         number of planes for this format and number of valid
 *                      elements in plane_fmt array
 */
struct v4l2_pix_format_mplane {
        __u32                           width;
        __u32                           height;
        __u32                           pixelformat;
        enum v4l2_field                 field;
        enum v4l2_colorspace            colorspace;

        struct v4l2_plane_pix_format    plane_fmt[VIDEO_MAX_PLANES];
        __u8                            num_planes;
        __u8                            reserved[11];
} __attribute__ ((packed));

New fourcc values have to be introduced for formats consisting of more than
1 plane.
Note: 1-plane formats retain their single-planar fourccs in multi-planar API, it
is the number of planes that rules this value, not the currently chosen API.


The per-plane format struct is as follows:

/**
 * struct v4l2_plane_pix_format - additional, per-plane format definition
 * @sizeimage:          maximum size in bytes required for data, for which
 *                      this plane will be used
 * @bytesperline:       distance in bytes between the leftmost pixels in two
 *                      adjacent lines
 */
struct v4l2_plane_pix_format {
        __u32           sizeimage;
        __u16           bytesperline;
        __u16           reserved[7];
} __attribute__ ((packed));


Fitting everything into v4l2_format's union (which is 200 bytes long):
v4l2_pix_format shouldn't be larger than 40 bytes.
8 * struct v4l2_plane_pix_format + 3 * 4 + 2 * enum + 12 * 1 = 8 * 20 + 40 = 200


5. Format enumeration
----------------------------------
struct v4l2_fmtdesc, used for format enumeration, does include the v4l2_buf_type
enum as well, so the new types are handled properly here as well.

Calls in the single-planar API should of course return 1-plane formats only.

For drivers supporting the new API, 1-plane formats should be returned for
multi-planar API calls types as well, for consistency. In other words, for
multi-planar API calls, the formats returned are a superset of those returned
when enumerating with the old buffer types.


6. Requesting buffers (buffer allocation)
----------------------------------
VIDIOC_REQBUFS includes v4l2_buf_type as well, so everything works as expected.
Drivers/allocators have to take into account plane requirements for the
currently selected format, such as per-plane alignment, etc.


7. Format conversion
----------------------------------
v4l2 core ioctl handling includes a simple conversion layer that allows
translation - when possible - between multi-planar and single-planar APIs,
transparently to drivers and applications.

The table below summarizes conversion behavior for cases when driver and
application use different API versions:

---------------------------------------------------------------
              | Application MP --> Driver SP --> Application MP
   G_FMT      |            always OK   |   always OK
   S_FMT      |            -EINVAL     |   always OK
 TRY_FMT      |            -EINVAL     |   always OK
---------------------------------------------------------------
              | Application SP --> Driver MP --> Application SP
   G_FMT      |            always OK   |   -EBUSY 
   S_FMT      |            always OK   |   -EBUSY and WARN()
 TRY_FMT      |            always OK   |   -EBUSY and WARN()

Legend:
- SP - single-planar API used (NOT format!)
- MP - multi-planar API used (NOT format!)
- always OK - conversion is always valid irrespective of number of planes
- -EINVAL - if an MP application tries to TRY or SET a format with more
            than 1 plane, EINVAL is returned from the conversion function
            (of course, 1-plane multi-planar formats work and are converted)
- -EBUSY - if an MP driver returns a more than 1-plane format to an SP
           application, the conversion layer returns EBUSY to the application;
           this is useful in cases when the driver is currently set to a more
           than 1-plane format, SP application would not be able to understand
           it)
- -EBUSY and WARN() - there is only one reason for which SET or TRY from an SP
           application would result in a driver returning a more than 1-plane
           format - when the driver adjusts a 1-plane format to a more than
           1-plane format. This should not happen and is a bug in driver, hence
           a WARN_ON(). Application receives EBUSY.


===============================================
IV. Multi-planar buffer and plane descriptors
===============================================

1. Adding plane info to v4l2_buffer
----------------------------------

 struct v4l2_buffer {
        /* ... */ 
        enum v4l2_buf_type      type;
        /* ... */ 
        union {
                __u32           offset;
                unsigned long   userptr;
+               struct v4l2_plane *planes;
        } m;
        __u32                   length;
        /* ... */
 };

Multi-planar buffers are also recognized using the new v4l2_buf_types.

For new buffer types, the "planes" member of the union is used. It should
contain a userspace pointer to an array of structs v4l2_plane. The size of this
array is to be passed in "length", as this field is not relevant for
multi-planar API buffers (plane lengths are specified per-plane in the
v4l2_plane struct instead).

Drivers can expect the planes field to contain a kernel pointer to the array,
it will be copied to kernelspace by ioctl handling code.


2. Plane description struct
----------------------------------

/**
 * struct v4l2_plane - plane info for multi-planar buffers
 * @bytesused:          number of bytes occupied by data in the plane (payload)
 * @mem_offset:         when memory in the associated struct v4l2_buffer is
 *                      V4L2_MEMORY_MMAP, equals the offset from the start of
 *                      the device memory for this plane (or is a "cookie" that
 *                      should be passed to mmap() called on the video node)
 * @userptr:            when memory is V4L2_MEMORY_USERPTR, a userspace pointer
 *                      pointing
 *                      to this plane
 * @length:             size of this plane (NOT the payload) in bytes
 * @data_offset:        offset in plane to the start of data/end of header,
 *                      if relevant
 *
 * Multi-planar buffers consist of one or more planes, e.g. an YCbCr buffer
 * with two planes can have one plane for Y, and another for interleaved CbCr
 * components. Each plane can reside in a separate memory buffer, or even in
 * a completely separate memory node (e.g. in embedded devices).
 */
struct v4l2_plane {
        __u32                   bytesused;
        __u32                   length;
        union {
                __u32           mem_offset;
                unsigned long   userptr;
        } m;
        __u32                   data_offset;
        __u32                   reserved[11];
};

If plane contents include not only data, but also a header, a driver may use
the data_offset member to indicate the offset in bytes to the start of the data.

Union m works in the same way as it does in the single-planar API for
v4l2_buffer. Which of the two to choose is decided by checking the memory field
in struct v4l2_buffer.


===============================================
V. Using ioctl()s and mmap()
===============================================

* Format calls (VIDIOC_S/TRY/G_FMT) are converted transparently across APIs
  by the ioctl handling code, where possible. Conversion from single-planar
  to multi-planar cannot fail, but the other way around is possible only for
  1-plane formats. 
  Possible errors in conversion are described below.

  To use multi-planar calls, pass a new buffer type and use the new pix_mp
  member of the struct.

* VIDIOC_S/TRY_FMT:
  - a single-planar call may fail (returning EBUSY) if a driver adjusts
    a 1-plane format to a more than 1-plane one. Note that this is considered
    a bug in the driver and will result in a kernel warning.
  - multi-planar call to a single-planar-only driver will result in EINVAL
    if a more than 1-plane format is requested

* VIDIOC_G_FMT:
  - a single-planar call may fail (returning EBUSY) if a driver has a more
    than 1-plane format currently set up; this is a normal situation and not
    a bug in the driver. This allows single-plane-only applications to use
    multi-planar drivers with their 1-plane formats.

* VIDIOC_ENUM_FMT:
  - for multi-planar API, should return a list of all formats supported by the
    driver (including 1-plane formats);
  - for single-planar API, will return 1-plane formats only;
  - an application does not have to enumerate formats in both APIs, as formats
    returned by multi-planar version are a superset of those returned by the
    single-planar version;
  - fourccs for the same pixel formats, differing only in number of planes,
    should differ; on the other hand, the same 1-plane format will have the same
    fourcc in both versions of the API;
  - format indexes (index field in struct v4l2_fmtdesc) may differ for the same
    formats between both APIs, so a 1-plane format may be returned with a
    different index across APIs.


* VIDIOC_REQBUFS:
Pass a new buffer type and count of video buffers (not planes) normally.
Expect the driver to return count (of buffers, not planes) as usual or EINVAL
if the multi-planar API is not supported.

The number of planes in a buffer is already known at the time of this call,
since it is specified by the currently chosen format.

* VIDIOC_QUERYBUFS:
Pass a v4l2_buffer struct as normal, setting a multi-planar buffer type and put
a pointer to an array of v4l2_plane structures under "planes". Place the size
of that array in the v4l2_buffer's "length" field. Expect the driver to fill
mem_offset fields in each v4l2_plane struct, analogically to offsets in
single-planar v4l2_buffers.

* VIDIOC_QBUF
As in the case of QUERYBUFS, pass the array of planes and its size in "length".
Fill all the fields required by non-multi-planar versions of this call, although
some of them in the planes' array members.

* VIDIOC_DQBUF
An array of planes does not have to be passed, in such case the "planes" pointer
has to be set to NULL and length should be set to 0.
If the array is passed, it will be filled with data, analogically to the
single-planar version of the API.

* mmap()
In the multi-planar API, not only every v4l2_buffer is a separate buffer in
memory, but every plane is a separate memory buffer as well. Therefore, every
plane has to be mapped separately. This requires num_planes * num_buffers calls
to mmap.

Note that the VIDIOC_QUERYBUF is called num_buffer times only, as each
v4l2_buffer passed to it contains offsets for all planes of a buffer.

Every mmap() call should be given the offsets provided in v4l2_plane structs.
There is no need for those calls to be in any particular order.

A v4l2_buffer changes state to mapped (V4L2_BUF_FLAG_MAPPED flag) only after all
of its planes have been mmapped successfully.

Best regards
--
Pawel Osciak
Linux Platform Group
Samsung Poland R&D Center

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v5 1/3] v4l: Add multi-planar API definitions to the V4L2 API
  2010-07-30  8:49 [PATCH v5 0/3] Multi-planar video format and buffer support for the V4L2 API Pawel Osciak
@ 2010-07-30  8:49 ` Pawel Osciak
  2010-08-01 12:14   ` Hans Verkuil
  2010-07-30  8:49 ` [PATCH v5 2/3] v4l: Add multi-planar ioctl handling code Pawel Osciak
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 11+ messages in thread
From: Pawel Osciak @ 2010-07-30  8:49 UTC (permalink / raw)
  To: linux-media; +Cc: p.osciak, kyungmin.park, m.szyprowski, t.fujak

Multi-planar API is as a backwards-compatible extension of the V4L2 API,
which allows video buffers to consist of one or more planes. Planes are
separate memory buffers; each has its own mapping, backed by usually
separate physical memory buffers.

Many different uses for the multi-planar API are possible, examples
include:
- embedded devices requiring video components to be placed in physically
separate buffers, e.g. for Samsung S3C/S5P SoC series' video codec,
Y and interleaved Cb/Cr components reside in buffers in different
memory banks;
- applications may receive (or choose to store) video data of one video
buffer in separate memory buffers; such data would have to be temporarily
copied together into one buffer before passing it to a V4L2 device;
- applications or drivers may want to pass metadata related to a buffer and
it may not be possible to place it in the same buffer, together with video
data.

Signed-off-by: Pawel Osciak <p.osciak@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Reviewed-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 drivers/media/video/v4l2-ioctl.c |    2 +
 include/linux/videodev2.h        |  126 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 126 insertions(+), 2 deletions(-)

diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index 0eeceae..a830bbd 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -168,6 +168,8 @@ const char *v4l2_type_names[] = {
 	[V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap",
 	[V4L2_BUF_TYPE_SLICED_VBI_OUTPUT]  = "sliced-vbi-out",
 	[V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "vid-out-overlay",
+	[V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE] = "vid-cap-mplane",
+	[V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE] = "vid-out-mplane",
 };
 EXPORT_SYMBOL(v4l2_type_names);
 
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 047f7e6..0379f07 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -70,6 +70,7 @@
  * Moved from videodev.h
  */
 #define VIDEO_MAX_FRAME               32
+#define VIDEO_MAX_PLANES               8
 
 #ifndef __KERNEL__
 
@@ -157,9 +158,23 @@ enum v4l2_buf_type {
 	/* Experimental */
 	V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8,
 #endif
+	V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE = 17,
+	V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE  = 18,
 	V4L2_BUF_TYPE_PRIVATE              = 0x80,
 };
 
+#define V4L2_TYPE_IS_MULTIPLANAR(type)			\
+	((type) == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE	\
+	 || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+
+#define V4L2_TYPE_IS_OUTPUT(type)				\
+	((type) == V4L2_BUF_TYPE_VIDEO_OUTPUT			\
+	 || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE		\
+	 || (type) == V4L2_BUF_TYPE_VIDEO_OVERLAY		\
+	 || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY	\
+	 || (type) == V4L2_BUF_TYPE_VBI_OUTPUT			\
+	 || (type) == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT)
+
 enum v4l2_tuner_type {
 	V4L2_TUNER_RADIO	     = 1,
 	V4L2_TUNER_ANALOG_TV	     = 2,
@@ -245,6 +260,11 @@ struct v4l2_capability {
 #define V4L2_CAP_HW_FREQ_SEEK		0x00000400  /* Can do hardware frequency seek  */
 #define V4L2_CAP_RDS_OUTPUT		0x00000800  /* Is an RDS encoder */
 
+/* Is a video capture device that supports multiplanar formats */
+#define V4L2_CAP_VIDEO_CAPTURE_MPLANE	0x00001000
+/* Is a video output device that supports multiplanar formats */
+#define V4L2_CAP_VIDEO_OUTPUT_MPLANE	0x00002000
+
 #define V4L2_CAP_TUNER			0x00010000  /* has a tuner */
 #define V4L2_CAP_AUDIO			0x00020000  /* has audio support */
 #define V4L2_CAP_RADIO			0x00040000  /* is a radio device */
@@ -514,6 +534,63 @@ struct v4l2_requestbuffers {
 	__u32			reserved[2];
 };
 
+/**
+ * struct v4l2_plane - plane info for multi-planar buffers
+ * @bytesused:		number of bytes occupied by data in the plane (payload)
+ * @mem_offset:		when memory in the associated struct v4l2_buffer is
+ * 			V4L2_MEMORY_MMAP, equals the offset from the start of
+ * 			the device memory for this plane (or is a "cookie" that
+ * 			should be passed to mmap() called on the video node)
+ * @userptr:		when memory is V4L2_MEMORY_USERPTR, a userspace pointer
+ * 			pointing
+ * 			to this plane
+ * @length:		size of this plane (NOT the payload) in bytes
+ * @data_offset:	offset in plane to the start of data/end of header,
+ * 			if relevant
+ *
+ * Multi-planar buffers consist of one or more planes, e.g. an YCbCr buffer
+ * with two planes can have one plane for Y, and another for interleaved CbCr
+ * components. Each plane can reside in a separate memory buffer, or even in
+ * a completely separate memory node (e.g. in embedded devices).
+ */
+struct v4l2_plane {
+	__u32			bytesused;
+	__u32			length;
+	union {
+		__u32		mem_offset;
+		unsigned long	userptr;
+	} m;
+	__u32			data_offset;
+	__u32			reserved[11];
+};
+
+/**
+ * struct v4l2_buffer - video buffer info
+ * @index:	id number of the buffer
+ * @type:	buffer type (type == *_MPLANE for multiplanar buffers)
+ * @bytesused:	number of bytes occupied by data in the buffer (payload);
+ * 		unused (set to 0) for multiplanar buffers
+ * @flags:	buffer informational flags
+ * @field:	field order of the image in the buffer
+ * @timestamp:	frame timestamp
+ * @timecode:	frame timecode
+ * @sequence:	sequence count of this frame
+ * @memory:	the method, in which the actual video data is passed
+ * @offset:	for non-multiplanar buffers with memory == V4L2_MEMORY_MMAP;
+ * 		offset from the start of the device memory for this plane,
+ * 		(or a "cookie" that should be passed to mmap() as offset)
+ * @userptr:	for non-multiplanar buffers with memory == V4L2_MEMORY_USERPTR;
+ * 		a userspace pointer pointing to this buffer
+ * @planes:	for multiplanar buffers; userspace pointer to the array of plane
+ * 		info structs for this buffer
+ * @length:	size in bytes of the buffer (NOT its payload) for single-plane
+ * 		buffers (when type != *_MPLANE); number of planes (and number
+ * 		of elements in the planes array) for multi-plane buffers
+ * @input:	input number from which the video data has has been captured
+ *
+ * Contains data exchanged by application and driver using one of the Streaming
+ * I/O methods.
+ */
 struct v4l2_buffer {
 	__u32			index;
 	enum v4l2_buf_type      type;
@@ -529,6 +606,7 @@ struct v4l2_buffer {
 	union {
 		__u32           offset;
 		unsigned long   userptr;
+		struct v4l2_plane *planes;
 	} m;
 	__u32			length;
 	__u32			input;
@@ -1613,12 +1691,57 @@ struct v4l2_mpeg_vbi_fmt_ivtv {
  *	A G G R E G A T E   S T R U C T U R E S
  */
 
-/*	Stream data format
+/**
+ * struct v4l2_plane_pix_format - additional, per-plane format definition
+ * @sizeimage:		maximum size in bytes required for data, for which
+ * 			this plane will be used
+ * @bytesperline:	distance in bytes between the leftmost pixels in two
+ * 			adjacent lines
+ */
+struct v4l2_plane_pix_format {
+	__u32		sizeimage;
+	__u16		bytesperline;
+	__u16		reserved[7];
+} __attribute__ ((packed));
+
+/**
+ * struct v4l2_pix_format_mplane - multiplanar format definition
+ * @width:		image width in pixels
+ * @height:		image height in pixels
+ * @pixelformat:	little endian four character code (fourcc)
+ * @field:		field order (for interlaced video)
+ * @colorspace:		supplemental to pixelformat
+ * @plane_fmt:		per-plane information
+ * @num_planes:		number of planes for this format and number of valid
+ * 			elements in plane_fmt array
+ */
+struct v4l2_pix_format_mplane {
+	__u32				width;
+	__u32				height;
+	__u32				pixelformat;
+	enum v4l2_field			field;
+	enum v4l2_colorspace		colorspace;
+
+	struct v4l2_plane_pix_format	plane_fmt[VIDEO_MAX_PLANES];
+	__u8				num_planes;
+	__u8				reserved[11];
+} __attribute__ ((packed));
+
+/**
+ * struct v4l2_format - stream data format
+ * @type:	type of the data stream
+ * @pix:	definition of an image format
+ * @pix_mp:	definition of a multiplanar image format
+ * @win:	definition of an overlaid image
+ * @vbi:	raw VBI capture or output parameters
+ * @sliced:	sliced VBI capture or output parameters
+ * @raw_data:	placeholder for future extensions and custom formats
  */
 struct v4l2_format {
 	enum v4l2_buf_type type;
 	union {
 		struct v4l2_pix_format		pix;     /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
+		struct v4l2_pix_format_mplane	pix_mp;  /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
 		struct v4l2_window		win;     /* V4L2_BUF_TYPE_VIDEO_OVERLAY */
 		struct v4l2_vbi_format		vbi;     /* V4L2_BUF_TYPE_VBI_CAPTURE */
 		struct v4l2_sliced_vbi_format	sliced;  /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */
@@ -1626,7 +1749,6 @@ struct v4l2_format {
 	} fmt;
 };
 
-
 /*	Stream type-dependent parameters
  */
 struct v4l2_streamparm {
-- 
1.7.1.569.g6f426


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v5 2/3] v4l: Add multi-planar ioctl handling code
  2010-07-30  8:49 [PATCH v5 0/3] Multi-planar video format and buffer support for the V4L2 API Pawel Osciak
  2010-07-30  8:49 ` [PATCH v5 1/3] v4l: Add multi-planar API definitions to " Pawel Osciak
@ 2010-07-30  8:49 ` Pawel Osciak
  2010-08-01 12:30   ` Hans Verkuil
  2010-07-30  8:49 ` [PATCH v5 3/3] v4l: Add compat functions for the multi-planar API Pawel Osciak
  2010-07-30 14:43 ` [PATCH v5 0/3] Multi-planar video format and buffer support for the V4L2 API Karicheri, Muralidharan
  3 siblings, 1 reply; 11+ messages in thread
From: Pawel Osciak @ 2010-07-30  8:49 UTC (permalink / raw)
  To: linux-media; +Cc: p.osciak, kyungmin.park, m.szyprowski, t.fujak

Add multi-planar API core ioctl handling and conversion functions.

Signed-off-by: Pawel Osciak <p.osciak@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Reviewed-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 drivers/media/video/v4l2-ioctl.c |  418 ++++++++++++++++++++++++++++++++++----
 include/media/v4l2-ioctl.h       |   16 ++
 2 files changed, 390 insertions(+), 44 deletions(-)

diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index a830bbd..3b2880a 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -476,20 +476,33 @@ static void dbgbuf(unsigned int cmd, struct video_device *vfd,
 					struct v4l2_buffer *p)
 {
 	struct v4l2_timecode *tc = &p->timecode;
+	struct v4l2_plane *plane;
+	int i;
 
 	dbgarg(cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, "
-		"bytesused=%d, flags=0x%08d, "
-		"field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx, length=%d\n",
+		"flags=0x%08d, field=%0d, sequence=%d, memory=%s\n",
 			p->timestamp.tv_sec / 3600,
 			(int)(p->timestamp.tv_sec / 60) % 60,
 			(int)(p->timestamp.tv_sec % 60),
 			(long)p->timestamp.tv_usec,
 			p->index,
 			prt_names(p->type, v4l2_type_names),
-			p->bytesused, p->flags,
-			p->field, p->sequence,
-			prt_names(p->memory, v4l2_memory_names),
-			p->m.userptr, p->length);
+			p->flags, p->field, p->sequence,
+			prt_names(p->memory, v4l2_memory_names));
+
+	if (V4L2_TYPE_IS_MULTIPLANAR(p->type) && p->m.planes) {
+		for (i = 0; i < p->length; ++i) {
+			plane = &p->m.planes[i];
+			dbgarg2("plane %d: bytesused=%d, data_offset=0x%08x "
+				"offset/userptr=0x%08lx, length=%d\n",
+				i, plane->bytesused, plane->data_offset,
+				plane->m.userptr, plane->length);
+		}
+	} else {
+		dbgarg2("bytesused=%d, offset/userptr=0x%08lx, length=%d\n",
+			p->bytesused, p->m.userptr, p->length);
+	}
+
 	dbgarg2("timecode=%02d:%02d:%02d type=%d, "
 		"flags=0x%08d, frames=%d, userbits=0x%08x\n",
 			tc->hours, tc->minutes, tc->seconds,
@@ -517,6 +530,27 @@ static inline void v4l_print_pix_fmt(struct video_device *vfd,
 		fmt->bytesperline, fmt->sizeimage, fmt->colorspace);
 };
 
+static inline void v4l_print_pix_fmt_mplane(struct video_device *vfd,
+					    struct v4l2_pix_format_mplane *fmt)
+{
+	int i;
+
+	dbgarg2("width=%d, height=%d, format=%c%c%c%c, field=%s, "
+		"colorspace=%d, num_planes=%d\n",
+		fmt->width, fmt->height,
+		(fmt->pixelformat & 0xff),
+		(fmt->pixelformat >>  8) & 0xff,
+		(fmt->pixelformat >> 16) & 0xff,
+		(fmt->pixelformat >> 24) & 0xff,
+		prt_names(fmt->field, v4l2_field_names),
+		fmt->colorspace, fmt->num_planes);
+
+	for (i = 0; i < fmt->num_planes; ++i)
+		dbgarg2("plane %d: bytesperline=%d sizeimage=%d\n", i,
+			fmt->plane_fmt[i].bytesperline,
+			fmt->plane_fmt[i].sizeimage);
+}
+
 static inline void v4l_print_ext_ctrls(unsigned int cmd,
 	struct video_device *vfd, struct v4l2_ext_controls *c, int show_vals)
 {
@@ -570,7 +604,12 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type)
 
 	switch (type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (ops->vidioc_g_fmt_vid_cap)
+		if (ops->vidioc_g_fmt_vid_cap ||
+				ops->vidioc_g_fmt_vid_cap_mplane)
+			return 0;
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		if (ops->vidioc_g_fmt_vid_cap_mplane)
 			return 0;
 		break;
 	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
@@ -578,7 +617,12 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type)
 			return 0;
 		break;
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-		if (ops->vidioc_g_fmt_vid_out)
+		if (ops->vidioc_g_fmt_vid_out ||
+				ops->vidioc_g_fmt_vid_out_mplane)
+			return 0;
+		break;
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		if (ops->vidioc_g_fmt_vid_out_mplane)
 			return 0;
 		break;
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
@@ -609,12 +653,70 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type)
 	return -EINVAL;
 }
 
+/**
+ * fmt_sp_to_mp() - Convert a single-plane format to its multi-planar 1-plane
+ * equivalent
+ */
+static int fmt_sp_to_mp(const struct v4l2_format *f_sp,
+			struct v4l2_format *f_mp)
+{
+	struct v4l2_pix_format_mplane *pix_mp = &f_mp->fmt.pix_mp;
+	const struct v4l2_pix_format *pix = &f_sp->fmt.pix;
+
+	if (f_sp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		f_mp->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+	else if (f_sp->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		f_mp->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+	else
+		return -EINVAL;
+
+	pix_mp->width = pix->width;
+	pix_mp->height = pix->height;
+	pix_mp->pixelformat = pix->pixelformat;
+	pix_mp->field = pix->field;
+	pix_mp->colorspace = pix->colorspace;
+	pix_mp->num_planes = 1;
+	pix_mp->plane_fmt[0].sizeimage = pix->sizeimage;
+	pix_mp->plane_fmt[0].bytesperline = pix->bytesperline;
+
+	return 0;
+}
+
+/**
+ * fmt_mp_to_sp() - Convert a multi-planar 1-plane format to its single-planar
+ * equivalent
+ */
+static int fmt_mp_to_sp(const struct v4l2_format *f_mp,
+			struct v4l2_format *f_sp)
+{
+	const struct v4l2_pix_format_mplane *pix_mp = &f_mp->fmt.pix_mp;
+	struct v4l2_pix_format *pix = &f_sp->fmt.pix;
+
+	if (f_mp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		f_sp->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	else if (f_mp->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		f_sp->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	else
+		return -EINVAL;
+
+	pix->width = pix_mp->width;
+	pix->height = pix_mp->height;
+	pix->pixelformat = pix_mp->pixelformat;
+	pix->field = pix_mp->field;
+	pix->colorspace = pix_mp->colorspace;
+	pix->sizeimage = pix_mp->plane_fmt[0].sizeimage;
+	pix->bytesperline = pix_mp->plane_fmt[0].bytesperline;
+
+	return 0;
+}
+
 static long __video_do_ioctl(struct file *file,
 		unsigned int cmd, void *arg)
 {
 	struct video_device *vfd = video_devdata(file);
 	const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;
 	void *fh = file->private_data;
+	struct v4l2_format f_copy;
 	long ret = -EINVAL;
 
 	if (ops == NULL) {
@@ -720,6 +822,11 @@ static long __video_do_ioctl(struct file *file,
 			if (ops->vidioc_enum_fmt_vid_cap)
 				ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f);
 			break;
+		case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+			if (ops->vidioc_enum_fmt_vid_cap_mplane)
+				ret = ops->vidioc_enum_fmt_vid_cap_mplane(file,
+									fh, f);
+			break;
 		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
 			if (ops->vidioc_enum_fmt_vid_overlay)
 				ret = ops->vidioc_enum_fmt_vid_overlay(file,
@@ -729,6 +836,11 @@ static long __video_do_ioctl(struct file *file,
 			if (ops->vidioc_enum_fmt_vid_out)
 				ret = ops->vidioc_enum_fmt_vid_out(file, fh, f);
 			break;
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+			if (ops->vidioc_enum_fmt_vid_out_mplane)
+				ret = ops->vidioc_enum_fmt_vid_out_mplane(file,
+									fh, f);
+			break;
 		case V4L2_BUF_TYPE_PRIVATE:
 			if (ops->vidioc_enum_fmt_type_private)
 				ret = ops->vidioc_enum_fmt_type_private(file,
@@ -757,22 +869,79 @@ static long __video_do_ioctl(struct file *file,
 
 		switch (f->type) {
 		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-			if (ops->vidioc_g_fmt_vid_cap)
+			if (ops->vidioc_g_fmt_vid_cap) {
 				ret = ops->vidioc_g_fmt_vid_cap(file, fh, f);
+			} else if (ops->vidioc_g_fmt_vid_cap_mplane) {
+				if (fmt_sp_to_mp(f, &f_copy))
+					break;
+				ret = ops->vidioc_g_fmt_vid_cap_mplane(file, fh,
+									&f_copy);
+				/* Driver is currently in multi-planar format,
+				 * we can't return it in single-planar API*/
+				if (f_copy.fmt.pix_mp.num_planes > 1) {
+					ret = -EBUSY;
+					break;
+				}
+
+				ret = fmt_mp_to_sp(&f_copy, f);
+			}
 			if (!ret)
 				v4l_print_pix_fmt(vfd, &f->fmt.pix);
 			break;
+		case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+			if (ops->vidioc_g_fmt_vid_cap_mplane) {
+				ret = ops->vidioc_g_fmt_vid_cap_mplane(file,
+									fh, f);
+			} else if (ops->vidioc_g_fmt_vid_cap) {
+				if (fmt_mp_to_sp(f, &f_copy))
+					break;
+				ret = ops->vidioc_g_fmt_vid_cap(file,
+								fh, &f_copy);
+				ret = fmt_sp_to_mp(&f_copy, f);
+			}
+			if (!ret)
+				v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp);
+			break;
 		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
 			if (ops->vidioc_g_fmt_vid_overlay)
 				ret = ops->vidioc_g_fmt_vid_overlay(file,
 								    fh, f);
 			break;
 		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-			if (ops->vidioc_g_fmt_vid_out)
+			if (ops->vidioc_g_fmt_vid_out) {
 				ret = ops->vidioc_g_fmt_vid_out(file, fh, f);
+			} else if (ops->vidioc_g_fmt_vid_out_mplane) {
+				if (fmt_sp_to_mp(f, &f_copy))
+					break;
+				ret = ops->vidioc_g_fmt_vid_out_mplane(file, fh,
+									&f_copy);
+				/* Driver is currently in multi-planar format,
+				 * we can't return it in single-planar API*/
+				if (f_copy.fmt.pix_mp.num_planes > 1) {
+					ret = -EBUSY;
+					break;
+				}
+
+				ret = fmt_mp_to_sp(&f_copy, f);
+			}
 			if (!ret)
 				v4l_print_pix_fmt(vfd, &f->fmt.pix);
 			break;
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+			if (ops->vidioc_g_fmt_vid_out_mplane) {
+				ret = ops->vidioc_g_fmt_vid_out_mplane(file,
+									fh, f);
+			} else if (ops->vidioc_g_fmt_vid_out) {
+				if (fmt_mp_to_sp(f, &f_copy))
+					break;
+				ret = ops->vidioc_g_fmt_vid_out(file,
+								fh, &f_copy);
+				ret = fmt_sp_to_mp(&f_copy, f);
+
+			}
+			if (!ret)
+				v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp);
+			break;
 		case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
 			if (ops->vidioc_g_fmt_vid_out_overlay)
 				ret = ops->vidioc_g_fmt_vid_out_overlay(file,
@@ -816,8 +985,38 @@ static long __video_do_ioctl(struct file *file,
 		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 			CLEAR_AFTER_FIELD(f, fmt.pix);
 			v4l_print_pix_fmt(vfd, &f->fmt.pix);
-			if (ops->vidioc_s_fmt_vid_cap)
+			if (ops->vidioc_s_fmt_vid_cap) {
 				ret = ops->vidioc_s_fmt_vid_cap(file, fh, f);
+			} else if (ops->vidioc_s_fmt_vid_cap_mplane) {
+				if (fmt_sp_to_mp(f, &f_copy))
+					break;
+				ret = ops->vidioc_s_fmt_vid_cap_mplane(file, fh,
+									&f_copy);
+				if (f_copy.fmt.pix_mp.num_planes > 1) {
+					/* Drivers shouldn't adjust from 1-plane
+					 * to more than 1-plane formats */
+					ret = -EBUSY;
+					WARN_ON(1);
+					break;
+				}
+
+				ret = fmt_mp_to_sp(&f_copy, f);
+			}
+			break;
+		case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+			CLEAR_AFTER_FIELD(f, fmt.pix_mp);
+			v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp);
+			if (ops->vidioc_s_fmt_vid_cap_mplane) {
+				ret = ops->vidioc_s_fmt_vid_cap_mplane(file,
+									fh, f);
+			} else if (ops->vidioc_s_fmt_vid_cap &&
+					f->fmt.pix_mp.num_planes == 1) {
+				if (fmt_mp_to_sp(f, &f_copy))
+					break;
+				ret = ops->vidioc_s_fmt_vid_cap(file,
+								fh, &f_copy);
+				ret = fmt_sp_to_mp(&f_copy, f);
+			}
 			break;
 		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
 			CLEAR_AFTER_FIELD(f, fmt.win);
@@ -828,8 +1027,38 @@ static long __video_do_ioctl(struct file *file,
 		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
 			CLEAR_AFTER_FIELD(f, fmt.pix);
 			v4l_print_pix_fmt(vfd, &f->fmt.pix);
-			if (ops->vidioc_s_fmt_vid_out)
+			if (ops->vidioc_s_fmt_vid_out) {
 				ret = ops->vidioc_s_fmt_vid_out(file, fh, f);
+			} else if (ops->vidioc_s_fmt_vid_out_mplane) {
+				if (fmt_sp_to_mp(f, &f_copy))
+					break;
+				ret = ops->vidioc_s_fmt_vid_out_mplane(file, fh,
+									&f_copy);
+				if (f_copy.fmt.pix_mp.num_planes > 1) {
+					/* Drivers shouldn't adjust from 1-plane
+					 * to more than 1-plane formats */
+					ret = -EBUSY;
+					WARN_ON(1);
+					break;
+				}
+
+				ret = fmt_mp_to_sp(&f_copy, f);
+			}
+			break;
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+			CLEAR_AFTER_FIELD(f, fmt.pix_mp);
+			v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp);
+			if (ops->vidioc_s_fmt_vid_out_mplane) {
+				ret = ops->vidioc_s_fmt_vid_out_mplane(file,
+									fh, f);
+			} else if (ops->vidioc_s_fmt_vid_out &&
+					f->fmt.pix_mp.num_planes == 1) {
+				if (fmt_mp_to_sp(f, &f_copy))
+					break;
+				ret = ops->vidioc_s_fmt_vid_out(file,
+								fh, &f_copy);
+				ret = fmt_mp_to_sp(&f_copy, f);
+			}
 			break;
 		case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
 			CLEAR_AFTER_FIELD(f, fmt.win);
@@ -878,11 +1107,41 @@ static long __video_do_ioctl(struct file *file,
 		switch (f->type) {
 		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 			CLEAR_AFTER_FIELD(f, fmt.pix);
-			if (ops->vidioc_try_fmt_vid_cap)
+			if (ops->vidioc_try_fmt_vid_cap) {
 				ret = ops->vidioc_try_fmt_vid_cap(file, fh, f);
+			} else if (ops->vidioc_try_fmt_vid_cap_mplane) {
+				if (fmt_sp_to_mp(f, &f_copy))
+					break;
+				ret = ops->vidioc_try_fmt_vid_cap_mplane(file,
+								fh, &f_copy);
+				if (f_copy.fmt.pix_mp.num_planes > 1) {
+					/* Drivers shouldn't adjust from 1-plane
+					 * to more than 1-plane formats */
+					ret = -EBUSY;
+					WARN_ON(1);
+					break;
+				}
+				ret = fmt_mp_to_sp(&f_copy, f);
+			}
 			if (!ret)
 				v4l_print_pix_fmt(vfd, &f->fmt.pix);
 			break;
+		case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+			CLEAR_AFTER_FIELD(f, fmt.pix_mp);
+			if (ops->vidioc_try_fmt_vid_cap_mplane) {
+				ret = ops->vidioc_try_fmt_vid_cap_mplane(file,
+									 fh, f);
+			} else if (ops->vidioc_try_fmt_vid_cap &&
+					f->fmt.pix_mp.num_planes == 1) {
+				if (fmt_mp_to_sp(f, &f_copy))
+					break;
+				ret = ops->vidioc_try_fmt_vid_cap(file,
+								  fh, &f_copy);
+				ret = fmt_sp_to_mp(&f_copy, f);
+			}
+			if (!ret)
+				v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp);
+			break;
 		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
 			CLEAR_AFTER_FIELD(f, fmt.win);
 			if (ops->vidioc_try_fmt_vid_overlay)
@@ -891,11 +1150,41 @@ static long __video_do_ioctl(struct file *file,
 			break;
 		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
 			CLEAR_AFTER_FIELD(f, fmt.pix);
-			if (ops->vidioc_try_fmt_vid_out)
+			if (ops->vidioc_try_fmt_vid_out) {
 				ret = ops->vidioc_try_fmt_vid_out(file, fh, f);
+			} else if (ops->vidioc_try_fmt_vid_out_mplane) {
+				if (fmt_sp_to_mp(f, &f_copy))
+					break;
+				ret = ops->vidioc_try_fmt_vid_out_mplane(file,
+								fh, &f_copy);
+				if (f_copy.fmt.pix_mp.num_planes > 1) {
+					/* Drivers shouldn't adjust from 1-plane
+					 * to more than 1-plane formats */
+					ret = -EBUSY;
+					WARN_ON(1);
+					break;
+				}
+				ret = fmt_mp_to_sp(&f_copy, f);
+			}
 			if (!ret)
 				v4l_print_pix_fmt(vfd, &f->fmt.pix);
 			break;
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+			CLEAR_AFTER_FIELD(f, fmt.pix_mp);
+			if (ops->vidioc_try_fmt_vid_out_mplane) {
+				ret = ops->vidioc_try_fmt_vid_out_mplane(file,
+									 fh, f);
+			} else if (ops->vidioc_try_fmt_vid_out &&
+					f->fmt.pix_mp.num_planes == 1) {
+				if (fmt_mp_to_sp(f, &f_copy))
+					break;
+				ret = ops->vidioc_try_fmt_vid_out(file,
+								  fh, &f_copy);
+				ret = fmt_sp_to_mp(&f_copy, f);
+			}
+			if (!ret)
+				v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp);
+			break;
 		case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
 			CLEAR_AFTER_FIELD(f, fmt.win);
 			if (ops->vidioc_try_fmt_vid_out_overlay)
@@ -2037,7 +2326,7 @@ static unsigned long cmd_input_size(unsigned int cmd)
 	switch (cmd) {
 		CMDINSIZE(ENUM_FMT,		fmtdesc,	type);
 		CMDINSIZE(G_FMT,		format,		type);
-		CMDINSIZE(QUERYBUF,		buffer,		type);
+		CMDINSIZE(QUERYBUF,		buffer,		length);
 		CMDINSIZE(G_PARM,		streamparm,	type);
 		CMDINSIZE(ENUMSTD,		standard,	index);
 		CMDINSIZE(ENUMINPUT,		input,		index);
@@ -2062,6 +2351,49 @@ static unsigned long cmd_input_size(unsigned int cmd)
 	}
 }
 
+static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
+			    void * __user *user_ptr, void ***kernel_ptr)
+{
+	int ret = 0;
+
+	switch(cmd) {
+	case VIDIOC_QUERYBUF:
+	case VIDIOC_QBUF:
+	case VIDIOC_DQBUF: {
+		struct v4l2_buffer *buf = parg;
+
+		if (V4L2_TYPE_IS_MULTIPLANAR(buf->type) && buf->length > 0) {
+			if (buf->length > VIDEO_MAX_PLANES) {
+				ret = -EINVAL;
+				break;
+			}
+			*user_ptr = (void __user *)buf->m.planes;
+			*kernel_ptr = (void **)&buf->m.planes;
+			*array_size = sizeof(struct v4l2_plane) * buf->length;
+			ret = 1;
+		}
+		break;
+	}
+
+	case VIDIOC_S_EXT_CTRLS:
+	case VIDIOC_G_EXT_CTRLS:
+	case VIDIOC_TRY_EXT_CTRLS: {
+		struct v4l2_ext_controls *ctrls = parg;
+
+		if (ctrls->count != 0) {
+			*user_ptr = (void __user *)ctrls->controls;
+			*kernel_ptr = (void **)&ctrls->controls;
+			*array_size = sizeof(struct v4l2_ext_control)
+				    * ctrls->count;
+			ret = 1;
+		}
+		break;
+	}
+	}
+
+	return ret;
+}
+
 long video_ioctl2(struct file *file,
 	       unsigned int cmd, unsigned long arg)
 {
@@ -2069,16 +2401,14 @@ long video_ioctl2(struct file *file,
 	void    *mbuf = NULL;
 	void	*parg = (void *)arg;
 	long	err  = -EINVAL;
-	int     is_ext_ctrl;
-	size_t  ctrls_size = 0;
+	bool	has_array_args;
+	size_t  array_size = 0;
 	void __user *user_ptr = NULL;
+	void	**kernel_ptr = NULL;
 
 #ifdef __OLD_VIDIOC_
 	cmd = video_fix_command(cmd);
 #endif
-	is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
-		       cmd == VIDIOC_TRY_EXT_CTRLS);
-
 	/*  Copy arguments into temp kernel buffer  */
 	if (_IOC_DIR(cmd) != _IOC_NONE) {
 		if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
@@ -2107,43 +2437,43 @@ long video_ioctl2(struct file *file,
 		}
 	}
 
-	if (is_ext_ctrl) {
-		struct v4l2_ext_controls *p = parg;
+	err = check_array_args(cmd, parg, &array_size, &user_ptr, &kernel_ptr);
+	if (err < 0)
+		goto out;
+	has_array_args = err;
 
-		/* In case of an error, tell the caller that it wasn't
-		   a specific control that caused it. */
-		p->error_idx = p->count;
-		user_ptr = (void __user *)p->controls;
-		if (p->count) {
-			ctrls_size = sizeof(struct v4l2_ext_control) * p->count;
-			/* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */
-			mbuf = kmalloc(ctrls_size, GFP_KERNEL);
-			err = -ENOMEM;
-			if (NULL == mbuf)
-				goto out_ext_ctrl;
-			err = -EFAULT;
-			if (copy_from_user(mbuf, user_ptr, ctrls_size))
-				goto out_ext_ctrl;
-			p->controls = mbuf;
-		}
+	if (has_array_args) {
+		/*
+		 * When adding new types of array args, make sure that the
+		 * parent argument to ioctl (which contains the pointer to the
+		 * array) fits into sbuf (so that mbuf will still remain
+		 * unused up to here).
+		 */
+		mbuf = kmalloc(array_size, GFP_KERNEL);
+		err = -ENOMEM;
+		if (NULL == mbuf)
+			goto out_array_args;
+		err = -EFAULT;
+		if (copy_from_user(mbuf, user_ptr, array_size))
+			goto out_array_args;
+		*kernel_ptr = mbuf;
 	}
 
 	/* Handles IOCTL */
 	err = __video_do_ioctl(file, cmd, parg);
 	if (err == -ENOIOCTLCMD)
 		err = -EINVAL;
-	if (is_ext_ctrl) {
-		struct v4l2_ext_controls *p = parg;
 
-		p->controls = (void *)user_ptr;
-		if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
+	if (has_array_args) {
+		*kernel_ptr = user_ptr;
+		if (copy_to_user(user_ptr, mbuf, array_size))
 			err = -EFAULT;
-		goto out_ext_ctrl;
+		goto out_array_args;
 	}
 	if (err < 0)
 		goto out;
 
-out_ext_ctrl:
+out_array_args:
 	/*  Copy results into user buffer  */
 	switch (_IOC_DIR(cmd)) {
 	case _IOC_READ:
diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
index 06daa6e..9ea2b0e 100644
--- a/include/media/v4l2-ioctl.h
+++ b/include/media/v4l2-ioctl.h
@@ -42,6 +42,10 @@ struct v4l2_ioctl_ops {
 					    struct v4l2_fmtdesc *f);
 	int (*vidioc_enum_fmt_vid_out)     (struct file *file, void *fh,
 					    struct v4l2_fmtdesc *f);
+	int (*vidioc_enum_fmt_vid_cap_mplane)(struct file *file, void *fh,
+					      struct v4l2_fmtdesc *f);
+	int (*vidioc_enum_fmt_vid_out_mplane)(struct file *file, void *fh,
+					      struct v4l2_fmtdesc *f);
 	int (*vidioc_enum_fmt_type_private)(struct file *file, void *fh,
 					    struct v4l2_fmtdesc *f);
 
@@ -62,6 +66,10 @@ struct v4l2_ioctl_ops {
 					struct v4l2_format *f);
 	int (*vidioc_g_fmt_sliced_vbi_out)(struct file *file, void *fh,
 					struct v4l2_format *f);
+	int (*vidioc_g_fmt_vid_cap_mplane)(struct file *file, void *fh,
+					   struct v4l2_format *f);
+	int (*vidioc_g_fmt_vid_out_mplane)(struct file *file, void *fh,
+					   struct v4l2_format *f);
 	int (*vidioc_g_fmt_type_private)(struct file *file, void *fh,
 					struct v4l2_format *f);
 
@@ -82,6 +90,10 @@ struct v4l2_ioctl_ops {
 					struct v4l2_format *f);
 	int (*vidioc_s_fmt_sliced_vbi_out)(struct file *file, void *fh,
 					struct v4l2_format *f);
+	int (*vidioc_s_fmt_vid_cap_mplane)(struct file *file, void *fh,
+					   struct v4l2_format *f);
+	int (*vidioc_s_fmt_vid_out_mplane)(struct file *file, void *fh,
+					   struct v4l2_format *f);
 	int (*vidioc_s_fmt_type_private)(struct file *file, void *fh,
 					struct v4l2_format *f);
 
@@ -102,6 +114,10 @@ struct v4l2_ioctl_ops {
 					  struct v4l2_format *f);
 	int (*vidioc_try_fmt_sliced_vbi_out)(struct file *file, void *fh,
 					  struct v4l2_format *f);
+	int (*vidioc_try_fmt_vid_cap_mplane)(struct file *file, void *fh,
+					     struct v4l2_format *f);
+	int (*vidioc_try_fmt_vid_out_mplane)(struct file *file, void *fh,
+					     struct v4l2_format *f);
 	int (*vidioc_try_fmt_type_private)(struct file *file, void *fh,
 					  struct v4l2_format *f);
 
-- 
1.7.1.569.g6f426


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v5 3/3] v4l: Add compat functions for the multi-planar API
  2010-07-30  8:49 [PATCH v5 0/3] Multi-planar video format and buffer support for the V4L2 API Pawel Osciak
  2010-07-30  8:49 ` [PATCH v5 1/3] v4l: Add multi-planar API definitions to " Pawel Osciak
  2010-07-30  8:49 ` [PATCH v5 2/3] v4l: Add multi-planar ioctl handling code Pawel Osciak
@ 2010-07-30  8:49 ` Pawel Osciak
  2010-07-30 14:43 ` [PATCH v5 0/3] Multi-planar video format and buffer support for the V4L2 API Karicheri, Muralidharan
  3 siblings, 0 replies; 11+ messages in thread
From: Pawel Osciak @ 2010-07-30  8:49 UTC (permalink / raw)
  To: linux-media; +Cc: p.osciak, kyungmin.park, m.szyprowski, t.fujak

Add multi-planar ioctl handling to the 32bit compatibility layer.

Signed-off-by: Pawel Osciak <p.osciak@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/media/video/v4l2-compat-ioctl32.c |  221 +++++++++++++++++++++++++----
 1 files changed, 190 insertions(+), 31 deletions(-)

diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
index 9004a5f..90bf865 100644
--- a/drivers/media/video/v4l2-compat-ioctl32.c
+++ b/drivers/media/video/v4l2-compat-ioctl32.c
@@ -303,6 +303,14 @@ static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pi
 	return 0;
 }
 
+static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp,
+				struct v4l2_pix_format_mplane __user *up)
+{
+	if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane)))
+		return -EFAULT;
+	return 0;
+}
+
 static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
 {
 	if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format)))
@@ -310,6 +318,14 @@ static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pi
 	return 0;
 }
 
+static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp,
+				struct v4l2_pix_format_mplane __user *up)
+{
+	if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane)))
+		return -EFAULT;
+	return 0;
+}
+
 static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
 {
 	if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format)))
@@ -342,6 +358,7 @@ struct v4l2_format32 {
 	enum v4l2_buf_type type;
 	union {
 		struct v4l2_pix_format	pix;
+		struct v4l2_pix_format_mplane	pix_mp;
 		struct v4l2_window32	win;
 		struct v4l2_vbi_format	vbi;
 		struct v4l2_sliced_vbi_format	sliced;
@@ -358,6 +375,10 @@ static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
 		return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		return get_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
+						  &up->fmt.pix_mp);
 	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
 		return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
@@ -389,6 +410,10 @@ static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
 		return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		return put_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
+						  &up->fmt.pix_mp);
 	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
 		return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
@@ -442,6 +467,17 @@ static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32
 	return 0;
 }
 
+struct v4l2_plane32 {
+	__u32			bytesused;
+	__u32			length;
+	union {
+		__u32		mem_offset;
+		compat_long_t	userptr;
+	} m;
+	__u32			data_offset;
+	__u32			reserved[11];
+};
+
 struct v4l2_buffer32 {
 	__u32			index;
 	enum v4l2_buf_type      type;
@@ -457,14 +493,64 @@ struct v4l2_buffer32 {
 	union {
 		__u32           offset;
 		compat_long_t   userptr;
+		compat_caddr_t  planes;
 	} m;
 	__u32			length;
 	__u32			input;
 	__u32			reserved;
 };
 
+static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32,
+				enum v4l2_memory memory)
+{
+	void __user *up_pln;
+	compat_long_t p;
+
+	if (copy_in_user(up, up32, 2 * sizeof(__u32)) ||
+		copy_in_user(&up->data_offset, &up32->data_offset,
+				sizeof(__u32)))
+		return -EFAULT;
+
+	if (memory == V4L2_MEMORY_USERPTR) {
+		if (get_user(p, &up32->m.userptr))
+			return -EFAULT;
+		up_pln = compat_ptr(p);
+		if (put_user((unsigned long)up_pln, &up->m.userptr))
+			return -EFAULT;
+	} else {
+		if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset,
+					sizeof(__u32)))
+			return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int put_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32,
+				enum v4l2_memory memory)
+{
+	if (copy_in_user(up32, up, 2 * sizeof(__u32)) ||
+		copy_in_user(&up32->data_offset, &up->data_offset,
+				sizeof(__u32)))
+		return -EFAULT;
+
+	/* For MMAP, driver might've set up the offset, so copy it back.
+	 * USERPTR stays the same (was userspace-provided), so no copying. */
+	if (memory == V4L2_MEMORY_MMAP)
+		if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset,
+					sizeof(__u32)))
+			return -EFAULT;
+
+	return 0;
+}
+
 static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
 {
+	struct v4l2_plane32 __user *uplane32;
+	struct v4l2_plane __user *uplane;
+	compat_caddr_t p;
+	int num_planes;
+	int ret;
 
 	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) ||
 		get_user(kp->index, &up->index) ||
@@ -473,33 +559,84 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
 		get_user(kp->memory, &up->memory) ||
 		get_user(kp->input, &up->input))
 			return -EFAULT;
-	switch (kp->memory) {
-	case V4L2_MEMORY_MMAP:
-		if (get_user(kp->length, &up->length) ||
-			get_user(kp->m.offset, &up->m.offset))
+
+	if (V4L2_TYPE_IS_OUTPUT(kp->type))
+		if (get_user(kp->bytesused, &up->bytesused) ||
+			get_user(kp->field, &up->field) ||
+			get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
+			get_user(kp->timestamp.tv_usec,
+					&up->timestamp.tv_usec))
 			return -EFAULT;
-		break;
-	case V4L2_MEMORY_USERPTR:
-		{
-		compat_long_t tmp;
 
-		if (get_user(kp->length, &up->length) ||
-		    get_user(tmp, &up->m.userptr))
+	if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
+		if (get_user(kp->length, &up->length))
 			return -EFAULT;
 
-		kp->m.userptr = (unsigned long)compat_ptr(tmp);
+		num_planes = kp->length;
+		if (num_planes == 0) {
+			kp->m.planes = NULL;
+			/* num_planes == 0 is legal, e.g. when userspace doesn't
+			 * need planes array on DQBUF*/
+			return 0;
 		}
-		break;
-	case V4L2_MEMORY_OVERLAY:
-		if (get_user(kp->m.offset, &up->m.offset))
+
+		if (get_user(p, &up->m.planes))
 			return -EFAULT;
-		break;
+
+		uplane32 = compat_ptr(p);
+		if (!access_ok(VERIFY_READ, uplane32,
+				num_planes * sizeof(struct v4l2_plane32)))
+			return -EFAULT;
+
+		/* We don't really care if userspace decides to kill itself
+		 * by passing a very big num_planes value */
+		uplane = compat_alloc_user_space(num_planes *
+						sizeof(struct v4l2_plane));
+		kp->m.planes = uplane;
+
+		while (--num_planes >= 0) {
+			ret = get_v4l2_plane32(uplane, uplane32, kp->memory);
+			if (ret)
+				return ret;
+			++uplane;
+			++uplane32;
+		}
+	} else {
+		switch (kp->memory) {
+		case V4L2_MEMORY_MMAP:
+			if (get_user(kp->length, &up->length) ||
+				get_user(kp->m.offset, &up->m.offset))
+				return -EFAULT;
+			break;
+		case V4L2_MEMORY_USERPTR:
+			{
+			compat_long_t tmp;
+
+			if (get_user(kp->length, &up->length) ||
+			    get_user(tmp, &up->m.userptr))
+				return -EFAULT;
+
+			kp->m.userptr = (unsigned long)compat_ptr(tmp);
+			}
+			break;
+		case V4L2_MEMORY_OVERLAY:
+			if (get_user(kp->m.offset, &up->m.offset))
+				return -EFAULT;
+			break;
+		}
 	}
+
 	return 0;
 }
 
 static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
 {
+	struct v4l2_plane32 __user *uplane32;
+	struct v4l2_plane __user *uplane;
+	compat_caddr_t p;
+	int num_planes;
+	int ret;
+
 	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) ||
 		put_user(kp->index, &up->index) ||
 		put_user(kp->type, &up->type) ||
@@ -507,22 +644,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
 		put_user(kp->memory, &up->memory) ||
 		put_user(kp->input, &up->input))
 			return -EFAULT;
-	switch (kp->memory) {
-	case V4L2_MEMORY_MMAP:
-		if (put_user(kp->length, &up->length) ||
-			put_user(kp->m.offset, &up->m.offset))
-			return -EFAULT;
-		break;
-	case V4L2_MEMORY_USERPTR:
-		if (put_user(kp->length, &up->length) ||
-			put_user(kp->m.userptr, &up->m.userptr))
-			return -EFAULT;
-		break;
-	case V4L2_MEMORY_OVERLAY:
-		if (put_user(kp->m.offset, &up->m.offset))
-			return -EFAULT;
-		break;
-	}
+
 	if (put_user(kp->bytesused, &up->bytesused) ||
 		put_user(kp->field, &up->field) ||
 		put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
@@ -531,6 +653,43 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
 		put_user(kp->sequence, &up->sequence) ||
 		put_user(kp->reserved, &up->reserved))
 			return -EFAULT;
+
+	if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
+		num_planes = kp->length;
+		if (num_planes == 0)
+			return 0;
+
+		uplane = kp->m.planes;
+		if (get_user(p, &up->m.planes))
+			return -EFAULT;
+		uplane32 = compat_ptr(p);
+
+		while (--num_planes >= 0) {
+			ret = put_v4l2_plane32(uplane, uplane32, kp->memory);
+			if (ret)
+				return ret;
+			++uplane;
+			++uplane32;
+		}
+	} else {
+		switch (kp->memory) {
+		case V4L2_MEMORY_MMAP:
+			if (put_user(kp->length, &up->length) ||
+				put_user(kp->m.offset, &up->m.offset))
+				return -EFAULT;
+			break;
+		case V4L2_MEMORY_USERPTR:
+			if (put_user(kp->length, &up->length) ||
+				put_user(kp->m.userptr, &up->m.userptr))
+				return -EFAULT;
+			break;
+		case V4L2_MEMORY_OVERLAY:
+			if (put_user(kp->m.offset, &up->m.offset))
+				return -EFAULT;
+			break;
+		}
+	}
+
 	return 0;
 }
 
-- 
1.7.1.569.g6f426


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* RE: [PATCH v5 0/3] Multi-planar video format and buffer support for the V4L2 API
  2010-07-30  8:49 [PATCH v5 0/3] Multi-planar video format and buffer support for the V4L2 API Pawel Osciak
                   ` (2 preceding siblings ...)
  2010-07-30  8:49 ` [PATCH v5 3/3] v4l: Add compat functions for the multi-planar API Pawel Osciak
@ 2010-07-30 14:43 ` Karicheri, Muralidharan
  2010-08-02  8:18   ` Pawel Osciak
  3 siblings, 1 reply; 11+ messages in thread
From: Karicheri, Muralidharan @ 2010-07-30 14:43 UTC (permalink / raw)
  To: Pawel Osciak, linux-media; +Cc: kyungmin.park, m.szyprowski, t.fujak

<Snip>

>
> struct v4l2_format {
>        enum v4l2_buf_type type;
>        union {
>                struct v4l2_pix_format          pix;     /*
>V4L2_BUF_TYPE_VIDEO_CAPTURE */
>+               struct v4l2_pix_format_mplane   pix_mp;  /*
>V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
>                struct v4l2_window              win;     /*
>V4L2_BUF_TYPE_VIDEO_OVERLAY */
>                struct v4l2_vbi_format          vbi;     /*
>V4L2_BUF_TYPE_VBI_CAPTURE */
>                struct v4l2_sliced_vbi_format   sliced;  /*
>V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */
>                __u8    raw_data[200];                   /* user-defined */
>        } fmt;
> };
>
>For the new buffer types mp_pix member is chosen. For those buffer types,
>struct v4l2_pix_format_mplane is used:
>

Typo. replae mp_pix with pix_mp

>/**
> * struct v4l2_pix_format_mplane - multiplanar format definition
> * @width:              image width in pixels
> * @height:             image height in pixels
> * @pixelformat:        little endian four character code (fourcc)
> * @field:              field order (for interlaced video)
> * @colorspace:         supplemental to pixelformat
> * @plane_fmt:          per-plane information
> * @num_planes:         number of planes for this format and number of
>valid

<Snip>

>
>
>7. Format conversion
>----------------------------------
>v4l2 core ioctl handling includes a simple conversion layer that allows
>translation - when possible - between multi-planar and single-planar APIs,
>transparently to drivers and applications.
>
>The table below summarizes conversion behavior for cases when driver and
>application use different API versions:
>
>---------------------------------------------------------------
>              | Application MP --> Driver SP --> Application MP
>   G_FMT      |            always OK   |   always OK
>   S_FMT      |            -EINVAL     |   always OK
> TRY_FMT      |            -EINVAL     |   always OK
>---------------------------------------------------------------
>              | Application SP --> Driver MP --> Application SP
>   G_FMT      |            always OK   |   -EBUSY
>   S_FMT      |            always OK   |   -EBUSY and WARN()
> TRY_FMT      |            always OK   |   -EBUSY and WARN()
>

What is the logic behind using -EBUSY for this? Why not -EINVAL? Also why use WARN()?

>Legend:
>- SP - single-planar API used (NOT format!)
>- MP - multi-planar API used (NOT format!)
>- always OK - conversion is always valid irrespective of number of planes
>- -EINVAL - if an MP application tries to TRY or SET a format with more
>            than 1 plane, EINVAL is returned from the conversion function
>            (of course, 1-plane multi-planar formats work and are
>converted)
>- -EBUSY - if an MP driver returns a more than 1-plane format to an SP
>           application, the conversion layer returns EBUSY to the
>application;
>           this is useful in cases when the driver is currently set to a
>more
>           than 1-plane format, SP application would not be able to
>understand
>           it)
>- -EBUSY and WARN() - there is only one reason for which SET or TRY from an
>SP
>           application would result in a driver returning a more than 1-
>plane
>           format - when the driver adjusts a 1-plane format to a more than
>           1-plane format. This should not happen and is a bug in driver,
>hence
>           a WARN_ON(). Application receives EBUSY.
>
>

Suppose, S_FMT/TRY_FMT is called with UYVY format and driver supports only NV12 (2 plane) only, then for

Application SP --> Driver MP --> Application SP

I guess in this case, new drivers that supports multi-plane format would have to return old NV12 format code (for backward compatibility). Is
this handled by driver or translation layer? 

Application MP --> Driver SP --> Application MP

In this case, new driver would return new NV12 format code and have no issue.
Not sure what translation layer does in this scenario.

<snip>

>
>===============================================
>V. Using ioctl()s and mmap()
>===============================================
>
>* Format calls (VIDIOC_S/TRY/G_FMT) are converted transparently across APIs
>  by the ioctl handling code, where possible. Conversion from single-planar
>  to multi-planar cannot fail, but the other way around is possible only
>for
>  1-plane formats.
>  Possible errors in conversion are described below.
>

Could you explain what you mean by conversion of formats? The idea of the translation layer functionality is not clear to me. An example would help.


Murali


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v5 1/3] v4l: Add multi-planar API definitions to the V4L2 API
  2010-07-30  8:49 ` [PATCH v5 1/3] v4l: Add multi-planar API definitions to " Pawel Osciak
@ 2010-08-01 12:14   ` Hans Verkuil
  2010-08-02  8:37     ` Pawel Osciak
  0 siblings, 1 reply; 11+ messages in thread
From: Hans Verkuil @ 2010-08-01 12:14 UTC (permalink / raw)
  To: Pawel Osciak; +Cc: linux-media, kyungmin.park, m.szyprowski, t.fujak

On Friday 30 July 2010 10:49:41 Pawel Osciak wrote:
> Multi-planar API is as a backwards-compatible extension of the V4L2 API,
> which allows video buffers to consist of one or more planes. Planes are
> separate memory buffers; each has its own mapping, backed by usually
> separate physical memory buffers.
> 
> Many different uses for the multi-planar API are possible, examples
> include:
> - embedded devices requiring video components to be placed in physically
> separate buffers, e.g. for Samsung S3C/S5P SoC series' video codec,
> Y and interleaved Cb/Cr components reside in buffers in different
> memory banks;
> - applications may receive (or choose to store) video data of one video
> buffer in separate memory buffers; such data would have to be temporarily
> copied together into one buffer before passing it to a V4L2 device;
> - applications or drivers may want to pass metadata related to a buffer and
> it may not be possible to place it in the same buffer, together with video
> data.
> 
> Signed-off-by: Pawel Osciak <p.osciak@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> Reviewed-by: Marek Szyprowski <m.szyprowski@samsung.com>
> ---
>  drivers/media/video/v4l2-ioctl.c |    2 +
>  include/linux/videodev2.h        |  126 +++++++++++++++++++++++++++++++++++++-
>  2 files changed, 126 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
> index 0eeceae..a830bbd 100644
> --- a/drivers/media/video/v4l2-ioctl.c
> +++ b/drivers/media/video/v4l2-ioctl.c
> @@ -168,6 +168,8 @@ const char *v4l2_type_names[] = {
>  	[V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap",
>  	[V4L2_BUF_TYPE_SLICED_VBI_OUTPUT]  = "sliced-vbi-out",
>  	[V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "vid-out-overlay",
> +	[V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE] = "vid-cap-mplane",
> +	[V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE] = "vid-out-mplane",
>  };
>  EXPORT_SYMBOL(v4l2_type_names);
>  
> diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
> index 047f7e6..0379f07 100644
> --- a/include/linux/videodev2.h
> +++ b/include/linux/videodev2.h
> @@ -70,6 +70,7 @@
>   * Moved from videodev.h
>   */
>  #define VIDEO_MAX_FRAME               32
> +#define VIDEO_MAX_PLANES               8
>  
>  #ifndef __KERNEL__
>  
> @@ -157,9 +158,23 @@ enum v4l2_buf_type {
>  	/* Experimental */
>  	V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8,
>  #endif
> +	V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE = 17,
> +	V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE  = 18,

Why 17 and 18 instead of 9 and 10?

>  	V4L2_BUF_TYPE_PRIVATE              = 0x80,
>  };
>  
> +#define V4L2_TYPE_IS_MULTIPLANAR(type)			\
> +	((type) == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE	\
> +	 || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
> +
> +#define V4L2_TYPE_IS_OUTPUT(type)				\
> +	((type) == V4L2_BUF_TYPE_VIDEO_OUTPUT			\
> +	 || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE		\
> +	 || (type) == V4L2_BUF_TYPE_VIDEO_OVERLAY		\
> +	 || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY	\
> +	 || (type) == V4L2_BUF_TYPE_VBI_OUTPUT			\
> +	 || (type) == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT)
> +
>  enum v4l2_tuner_type {
>  	V4L2_TUNER_RADIO	     = 1,
>  	V4L2_TUNER_ANALOG_TV	     = 2,
> @@ -245,6 +260,11 @@ struct v4l2_capability {
>  #define V4L2_CAP_HW_FREQ_SEEK		0x00000400  /* Can do hardware frequency seek  */
>  #define V4L2_CAP_RDS_OUTPUT		0x00000800  /* Is an RDS encoder */
>  
> +/* Is a video capture device that supports multiplanar formats */
> +#define V4L2_CAP_VIDEO_CAPTURE_MPLANE	0x00001000
> +/* Is a video output device that supports multiplanar formats */
> +#define V4L2_CAP_VIDEO_OUTPUT_MPLANE	0x00002000
> +
>  #define V4L2_CAP_TUNER			0x00010000  /* has a tuner */
>  #define V4L2_CAP_AUDIO			0x00020000  /* has audio support */
>  #define V4L2_CAP_RADIO			0x00040000  /* is a radio device */
> @@ -514,6 +534,63 @@ struct v4l2_requestbuffers {
>  	__u32			reserved[2];
>  };
>  
> +/**
> + * struct v4l2_plane - plane info for multi-planar buffers
> + * @bytesused:		number of bytes occupied by data in the plane (payload)
> + * @mem_offset:		when memory in the associated struct v4l2_buffer is
> + * 			V4L2_MEMORY_MMAP, equals the offset from the start of
> + * 			the device memory for this plane (or is a "cookie" that
> + * 			should be passed to mmap() called on the video node)
> + * @userptr:		when memory is V4L2_MEMORY_USERPTR, a userspace pointer
> + * 			pointing
> + * 			to this plane

Can be put on one line instead of two.

> + * @length:		size of this plane (NOT the payload) in bytes

Note: mismatch between the order of the fields here and in the actual struct.
@length should be after @bytesused.

> + * @data_offset:	offset in plane to the start of data/end of header,
> + * 			if relevant

I would rephrase this:

offset in the plane to the start of data. Usually this is 0, unless there is
a header in front of the data.


> + *
> + * Multi-planar buffers consist of one or more planes, e.g. an YCbCr buffer
> + * with two planes can have one plane for Y, and another for interleaved CbCr
> + * components. Each plane can reside in a separate memory buffer, or even in
> + * a completely separate memory node (e.g. in embedded devices).
> + */
> +struct v4l2_plane {
> +	__u32			bytesused;
> +	__u32			length;
> +	union {
> +		__u32		mem_offset;
> +		unsigned long	userptr;
> +	} m;
> +	__u32			data_offset;
> +	__u32			reserved[11];
> +};
> +
> +/**
> + * struct v4l2_buffer - video buffer info
> + * @index:	id number of the buffer
> + * @type:	buffer type (type == *_MPLANE for multiplanar buffers)
> + * @bytesused:	number of bytes occupied by data in the buffer (payload);
> + * 		unused (set to 0) for multiplanar buffers
> + * @flags:	buffer informational flags
> + * @field:	field order of the image in the buffer
> + * @timestamp:	frame timestamp
> + * @timecode:	frame timecode
> + * @sequence:	sequence count of this frame
> + * @memory:	the method, in which the actual video data is passed
> + * @offset:	for non-multiplanar buffers with memory == V4L2_MEMORY_MMAP;
> + * 		offset from the start of the device memory for this plane,
> + * 		(or a "cookie" that should be passed to mmap() as offset)
> + * @userptr:	for non-multiplanar buffers with memory == V4L2_MEMORY_USERPTR;
> + * 		a userspace pointer pointing to this buffer
> + * @planes:	for multiplanar buffers; userspace pointer to the array of plane
> + * 		info structs for this buffer
> + * @length:	size in bytes of the buffer (NOT its payload) for single-plane
> + * 		buffers (when type != *_MPLANE); number of planes (and number
> + * 		of elements in the planes array) for multi-plane buffers

This is confusing. Just write "number of elements in the planes array".

> + * @input:	input number from which the video data has has been captured
> + *
> + * Contains data exchanged by application and driver using one of the Streaming
> + * I/O methods.
> + */
>  struct v4l2_buffer {
>  	__u32			index;
>  	enum v4l2_buf_type      type;
> @@ -529,6 +606,7 @@ struct v4l2_buffer {
>  	union {
>  		__u32           offset;
>  		unsigned long   userptr;
> +		struct v4l2_plane *planes;

Should use the __user attribute.

>  	} m;
>  	__u32			length;
>  	__u32			input;
> @@ -1613,12 +1691,57 @@ struct v4l2_mpeg_vbi_fmt_ivtv {
>   *	A G G R E G A T E   S T R U C T U R E S
>   */
>  
> -/*	Stream data format
> +/**
> + * struct v4l2_plane_pix_format - additional, per-plane format definition
> + * @sizeimage:		maximum size in bytes required for data, for which
> + * 			this plane will be used
> + * @bytesperline:	distance in bytes between the leftmost pixels in two
> + * 			adjacent lines
> + */
> +struct v4l2_plane_pix_format {
> +	__u32		sizeimage;
> +	__u16		bytesperline;
> +	__u16		reserved[7];
> +} __attribute__ ((packed));
> +
> +/**
> + * struct v4l2_pix_format_mplane - multiplanar format definition
> + * @width:		image width in pixels
> + * @height:		image height in pixels
> + * @pixelformat:	little endian four character code (fourcc)
> + * @field:		field order (for interlaced video)
> + * @colorspace:		supplemental to pixelformat
> + * @plane_fmt:		per-plane information
> + * @num_planes:		number of planes for this format and number of valid
> + * 			elements in plane_fmt array

Same problem here: just write "number of planes for this format".

> + */
> +struct v4l2_pix_format_mplane {
> +	__u32				width;
> +	__u32				height;
> +	__u32				pixelformat;
> +	enum v4l2_field			field;
> +	enum v4l2_colorspace		colorspace;
> +
> +	struct v4l2_plane_pix_format	plane_fmt[VIDEO_MAX_PLANES];
> +	__u8				num_planes;
> +	__u8				reserved[11];
> +} __attribute__ ((packed));
> +
> +/**
> + * struct v4l2_format - stream data format
> + * @type:	type of the data stream
> + * @pix:	definition of an image format
> + * @pix_mp:	definition of a multiplanar image format
> + * @win:	definition of an overlaid image
> + * @vbi:	raw VBI capture or output parameters
> + * @sliced:	sliced VBI capture or output parameters
> + * @raw_data:	placeholder for future extensions and custom formats
>   */
>  struct v4l2_format {
>  	enum v4l2_buf_type type;
>  	union {
>  		struct v4l2_pix_format		pix;     /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
> +		struct v4l2_pix_format_mplane	pix_mp;  /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
>  		struct v4l2_window		win;     /* V4L2_BUF_TYPE_VIDEO_OVERLAY */
>  		struct v4l2_vbi_format		vbi;     /* V4L2_BUF_TYPE_VBI_CAPTURE */
>  		struct v4l2_sliced_vbi_format	sliced;  /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */
> @@ -1626,7 +1749,6 @@ struct v4l2_format {
>  	} fmt;
>  };
>  
> -
>  /*	Stream type-dependent parameters
>   */
>  struct v4l2_streamparm {
> 

Regards,

	Hans

-- 
Hans Verkuil - video4linux developer - sponsored by TANDBERG, part of Cisco

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v5 2/3] v4l: Add multi-planar ioctl handling code
  2010-07-30  8:49 ` [PATCH v5 2/3] v4l: Add multi-planar ioctl handling code Pawel Osciak
@ 2010-08-01 12:30   ` Hans Verkuil
  2010-08-02  8:40     ` Pawel Osciak
  0 siblings, 1 reply; 11+ messages in thread
From: Hans Verkuil @ 2010-08-01 12:30 UTC (permalink / raw)
  To: Pawel Osciak; +Cc: linux-media, kyungmin.park, m.szyprowski, t.fujak

On Friday 30 July 2010 10:49:42 Pawel Osciak wrote:
> Add multi-planar API core ioctl handling and conversion functions.
> 
> Signed-off-by: Pawel Osciak <p.osciak@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> Reviewed-by: Marek Szyprowski <m.szyprowski@samsung.com>
> ---
>  drivers/media/video/v4l2-ioctl.c |  418 ++++++++++++++++++++++++++++++++++----
>  include/media/v4l2-ioctl.h       |   16 ++
>  2 files changed, 390 insertions(+), 44 deletions(-)
> 
> diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
> index a830bbd..3b2880a 100644
> --- a/drivers/media/video/v4l2-ioctl.c
> +++ b/drivers/media/video/v4l2-ioctl.c
> @@ -476,20 +476,33 @@ static void dbgbuf(unsigned int cmd, struct video_device *vfd,
>  					struct v4l2_buffer *p)
>  {
>  	struct v4l2_timecode *tc = &p->timecode;
> +	struct v4l2_plane *plane;
> +	int i;
>  
>  	dbgarg(cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, "
> -		"bytesused=%d, flags=0x%08d, "
> -		"field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx, length=%d\n",
> +		"flags=0x%08d, field=%0d, sequence=%d, memory=%s\n",
>  			p->timestamp.tv_sec / 3600,
>  			(int)(p->timestamp.tv_sec / 60) % 60,
>  			(int)(p->timestamp.tv_sec % 60),
>  			(long)p->timestamp.tv_usec,
>  			p->index,
>  			prt_names(p->type, v4l2_type_names),
> -			p->bytesused, p->flags,
> -			p->field, p->sequence,
> -			prt_names(p->memory, v4l2_memory_names),
> -			p->m.userptr, p->length);
> +			p->flags, p->field, p->sequence,
> +			prt_names(p->memory, v4l2_memory_names));
> +
> +	if (V4L2_TYPE_IS_MULTIPLANAR(p->type) && p->m.planes) {
> +		for (i = 0; i < p->length; ++i) {
> +			plane = &p->m.planes[i];
> +			dbgarg2("plane %d: bytesused=%d, data_offset=0x%08x "
> +				"offset/userptr=0x%08lx, length=%d\n",
> +				i, plane->bytesused, plane->data_offset,
> +				plane->m.userptr, plane->length);
> +		}
> +	} else {
> +		dbgarg2("bytesused=%d, offset/userptr=0x%08lx, length=%d\n",
> +			p->bytesused, p->m.userptr, p->length);
> +	}
> +
>  	dbgarg2("timecode=%02d:%02d:%02d type=%d, "
>  		"flags=0x%08d, frames=%d, userbits=0x%08x\n",
>  			tc->hours, tc->minutes, tc->seconds,
> @@ -517,6 +530,27 @@ static inline void v4l_print_pix_fmt(struct video_device *vfd,
>  		fmt->bytesperline, fmt->sizeimage, fmt->colorspace);
>  };
>  
> +static inline void v4l_print_pix_fmt_mplane(struct video_device *vfd,
> +					    struct v4l2_pix_format_mplane *fmt)
> +{
> +	int i;
> +
> +	dbgarg2("width=%d, height=%d, format=%c%c%c%c, field=%s, "
> +		"colorspace=%d, num_planes=%d\n",
> +		fmt->width, fmt->height,
> +		(fmt->pixelformat & 0xff),
> +		(fmt->pixelformat >>  8) & 0xff,
> +		(fmt->pixelformat >> 16) & 0xff,
> +		(fmt->pixelformat >> 24) & 0xff,
> +		prt_names(fmt->field, v4l2_field_names),
> +		fmt->colorspace, fmt->num_planes);
> +
> +	for (i = 0; i < fmt->num_planes; ++i)
> +		dbgarg2("plane %d: bytesperline=%d sizeimage=%d\n", i,
> +			fmt->plane_fmt[i].bytesperline,
> +			fmt->plane_fmt[i].sizeimage);
> +}
> +
>  static inline void v4l_print_ext_ctrls(unsigned int cmd,
>  	struct video_device *vfd, struct v4l2_ext_controls *c, int show_vals)
>  {
> @@ -570,7 +604,12 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type)
>  
>  	switch (type) {
>  	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
> -		if (ops->vidioc_g_fmt_vid_cap)
> +		if (ops->vidioc_g_fmt_vid_cap ||
> +				ops->vidioc_g_fmt_vid_cap_mplane)
> +			return 0;
> +		break;
> +	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
> +		if (ops->vidioc_g_fmt_vid_cap_mplane)
>  			return 0;
>  		break;
>  	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
> @@ -578,7 +617,12 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type)
>  			return 0;
>  		break;
>  	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
> -		if (ops->vidioc_g_fmt_vid_out)
> +		if (ops->vidioc_g_fmt_vid_out ||
> +				ops->vidioc_g_fmt_vid_out_mplane)
> +			return 0;
> +		break;
> +	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
> +		if (ops->vidioc_g_fmt_vid_out_mplane)
>  			return 0;
>  		break;
>  	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
> @@ -609,12 +653,70 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type)
>  	return -EINVAL;
>  }
>  
> +/**
> + * fmt_sp_to_mp() - Convert a single-plane format to its multi-planar 1-plane
> + * equivalent
> + */
> +static int fmt_sp_to_mp(const struct v4l2_format *f_sp,
> +			struct v4l2_format *f_mp)
> +{
> +	struct v4l2_pix_format_mplane *pix_mp = &f_mp->fmt.pix_mp;
> +	const struct v4l2_pix_format *pix = &f_sp->fmt.pix;
> +
> +	if (f_sp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
> +		f_mp->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
> +	else if (f_sp->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
> +		f_mp->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
> +	else
> +		return -EINVAL;
> +
> +	pix_mp->width = pix->width;
> +	pix_mp->height = pix->height;
> +	pix_mp->pixelformat = pix->pixelformat;
> +	pix_mp->field = pix->field;
> +	pix_mp->colorspace = pix->colorspace;
> +	pix_mp->num_planes = 1;
> +	pix_mp->plane_fmt[0].sizeimage = pix->sizeimage;
> +	pix_mp->plane_fmt[0].bytesperline = pix->bytesperline;
> +
> +	return 0;
> +}
> +
> +/**
> + * fmt_mp_to_sp() - Convert a multi-planar 1-plane format to its single-planar
> + * equivalent
> + */
> +static int fmt_mp_to_sp(const struct v4l2_format *f_mp,
> +			struct v4l2_format *f_sp)
> +{
> +	const struct v4l2_pix_format_mplane *pix_mp = &f_mp->fmt.pix_mp;
> +	struct v4l2_pix_format *pix = &f_sp->fmt.pix;
> +
> +	if (f_mp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
> +		f_sp->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +	else if (f_mp->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
> +		f_sp->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
> +	else
> +		return -EINVAL;
> +
> +	pix->width = pix_mp->width;
> +	pix->height = pix_mp->height;
> +	pix->pixelformat = pix_mp->pixelformat;
> +	pix->field = pix_mp->field;
> +	pix->colorspace = pix_mp->colorspace;
> +	pix->sizeimage = pix_mp->plane_fmt[0].sizeimage;
> +	pix->bytesperline = pix_mp->plane_fmt[0].bytesperline;
> +
> +	return 0;
> +}
> +
>  static long __video_do_ioctl(struct file *file,
>  		unsigned int cmd, void *arg)
>  {
>  	struct video_device *vfd = video_devdata(file);
>  	const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;
>  	void *fh = file->private_data;
> +	struct v4l2_format f_copy;
>  	long ret = -EINVAL;
>  
>  	if (ops == NULL) {
> @@ -720,6 +822,11 @@ static long __video_do_ioctl(struct file *file,
>  			if (ops->vidioc_enum_fmt_vid_cap)
>  				ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f);
>  			break;
> +		case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
> +			if (ops->vidioc_enum_fmt_vid_cap_mplane)
> +				ret = ops->vidioc_enum_fmt_vid_cap_mplane(file,
> +									fh, f);
> +			break;
>  		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
>  			if (ops->vidioc_enum_fmt_vid_overlay)
>  				ret = ops->vidioc_enum_fmt_vid_overlay(file,
> @@ -729,6 +836,11 @@ static long __video_do_ioctl(struct file *file,
>  			if (ops->vidioc_enum_fmt_vid_out)
>  				ret = ops->vidioc_enum_fmt_vid_out(file, fh, f);
>  			break;
> +		case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
> +			if (ops->vidioc_enum_fmt_vid_out_mplane)
> +				ret = ops->vidioc_enum_fmt_vid_out_mplane(file,
> +									fh, f);
> +			break;
>  		case V4L2_BUF_TYPE_PRIVATE:
>  			if (ops->vidioc_enum_fmt_type_private)
>  				ret = ops->vidioc_enum_fmt_type_private(file,
> @@ -757,22 +869,79 @@ static long __video_do_ioctl(struct file *file,
>  
>  		switch (f->type) {
>  		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
> -			if (ops->vidioc_g_fmt_vid_cap)
> +			if (ops->vidioc_g_fmt_vid_cap) {
>  				ret = ops->vidioc_g_fmt_vid_cap(file, fh, f);
> +			} else if (ops->vidioc_g_fmt_vid_cap_mplane) {
> +				if (fmt_sp_to_mp(f, &f_copy))
> +					break;
> +				ret = ops->vidioc_g_fmt_vid_cap_mplane(file, fh,
> +									&f_copy);
> +				/* Driver is currently in multi-planar format,
> +				 * we can't return it in single-planar API*/
> +				if (f_copy.fmt.pix_mp.num_planes > 1) {

Only do this if ret == 0.

> +					ret = -EBUSY;
> +					break;
> +				}
> +
> +				ret = fmt_mp_to_sp(&f_copy, f);

Ditto: 'ret' is overwritten here.

Same happens elsewhere as well.

<snip>

Regards,

	Hans

-- 
Hans Verkuil - video4linux developer - sponsored by TANDBERG, part of Cisco

^ permalink raw reply	[flat|nested] 11+ messages in thread

* RE: [PATCH v5 0/3] Multi-planar video format and buffer support for the V4L2 API
  2010-07-30 14:43 ` [PATCH v5 0/3] Multi-planar video format and buffer support for the V4L2 API Karicheri, Muralidharan
@ 2010-08-02  8:18   ` Pawel Osciak
  0 siblings, 0 replies; 11+ messages in thread
From: Pawel Osciak @ 2010-08-02  8:18 UTC (permalink / raw)
  To: 'Karicheri, Muralidharan', linux-media
  Cc: kyungmin.park, Marek Szyprowski, Tomasz Fujak

Hi,
thanks for the review.

>Karicheri, Muralidharan <m-karicheri2@ti.com> wrote:
>
>>
>>
>>7. Format conversion
>>----------------------------------
>>v4l2 core ioctl handling includes a simple conversion layer that allows
>>translation - when possible - between multi-planar and single-planar APIs,
>>transparently to drivers and applications.
>>
>>The table below summarizes conversion behavior for cases when driver and
>>application use different API versions:
>>
>>---------------------------------------------------------------
>>              | Application MP --> Driver SP --> Application MP
>>   G_FMT      |            always OK   |   always OK
>>   S_FMT      |            -EINVAL     |   always OK
>> TRY_FMT      |            -EINVAL     |   always OK
>>---------------------------------------------------------------
>>              | Application SP --> Driver MP --> Application SP
>>   G_FMT      |            always OK   |   -EBUSY
>>   S_FMT      |            always OK   |   -EBUSY and WARN()
>> TRY_FMT      |            always OK   |   -EBUSY and WARN()
>>
>
>What is the logic behind using -EBUSY for this? Why not -EINVAL? Also why use
>WARN()?
>

We think that it's better to return EBUSY from a G_FMT call to say:
"Your call is valid, but I cannot tell you the format now, but may be able to
later" (i.e. after I switch back to a single-planar format). EINVAL just says
"Your call is invalid", i.e. no point in retrying. Also, EINVAL doesn't really
make sense for G_FMT.

WARN because, as explained below, we think of it as a bug in driver to adjust
a 1-plane format to a >1-plane format on S/TRY.

>>Legend:
>>- SP - single-planar API used (NOT format!)
>>- MP - multi-planar API used (NOT format!)
>>- always OK - conversion is always valid irrespective of number of planes
>>- -EINVAL - if an MP application tries to TRY or SET a format with more
>>            than 1 plane, EINVAL is returned from the conversion function
>>            (of course, 1-plane multi-planar formats work and are
>>converted)
>>- -EBUSY - if an MP driver returns a more than 1-plane format to an SP
>>           application, the conversion layer returns EBUSY to the
>>application;
>>           this is useful in cases when the driver is currently set to a
>>more
>>           than 1-plane format, SP application would not be able to
>>understand
>>           it)
>>- -EBUSY and WARN() - there is only one reason for which SET or TRY from an
>>SP
>>           application would result in a driver returning a more than 1-
>>plane
>>           format - when the driver adjusts a 1-plane format to a more than
>>           1-plane format. This should not happen and is a bug in driver,
>>hence
>>           a WARN_ON(). Application receives EBUSY.
>>
>>
>
>Suppose, S_FMT/TRY_FMT is called with UYVY format and driver supports only
>NV12 (2 plane) only, then for
>
>Application SP --> Driver MP --> Application SP
>
>I guess in this case, new drivers that supports multi-plane format would have
>to return old NV12 format code (for backward compatibility). Is
>this handled by driver or translation layer?
>

Not really. If a driver supports a 2-plane format only, an SP application
won't be able to use it (unless we copy video data from two separate memory
buffers into one and back on each QBUF/DQBUF in core ioctl handling, I don't
think we want to go that far). The app expects one buffer, not two. So this is
an EINVAL.

>Application MP --> Driver SP --> Application MP
>
>In this case, new driver would return new NV12 format code and have no issue.
>Not sure what translation layer does in this scenario.
>

Again, not really. If an MP application requests a 2-plane format, the driver
cannot support it (it can support 1-plane formats only). So this is also
an EINVAL.

Overall, we do not convert v4l2_buffers, we only convert format structs (not
the actual formats).

><snip>
>
>>
>>===============================================
>>V. Using ioctl()s and mmap()
>>===============================================
>>
>>* Format calls (VIDIOC_S/TRY/G_FMT) are converted transparently across APIs
>>  by the ioctl handling code, where possible. Conversion from single-planar
>>  to multi-planar cannot fail, but the other way around is possible only
>>for
>>  1-plane formats.
>>  Possible errors in conversion are described below.
>>
>
>Could you explain what you mean by conversion of formats? The idea of the
>translation layer functionality is not clear to me. An example would help.
>


I guess this needs to be rephrased:

It doesn't convert the actual formats, it only converts between APIs, i.e.
between different format structs. So it's a conversion between struct
v4l2_pix_format_mplane and struct v4l2_pix_format. It's not a conversion
of formats, the format stays completely identical.

So basically an NV12 format can be passed as well in a v4l2_pix_format
struct as in v4l2_pix_format_mplane. Fourccs and other fields will be
exactly the same. Only the location of those fields will differ,
a v4l2_pix_format_mplane struct will have an array of v4l2_plane_pix_format
of size one. Look at the fmt_sp_to_mp and fmt_mp_to_sp functions in
v4l2-ioctl.c and it should become more clear to you. It just moves some
fields between structs and back.

The reason behind this "conversion" layer is to ease driver development.
Drivers won't have to implement both vidioc_*_fmt_* and
vidioc_*_fmt_*_mplane versions of calls, only mplane ones.


Best regards
--
Pawel Osciak
Linux Platform Group
Samsung Poland R&D Center




^ permalink raw reply	[flat|nested] 11+ messages in thread

* RE: [PATCH v5 1/3] v4l: Add multi-planar API definitions to the V4L2 API
  2010-08-01 12:14   ` Hans Verkuil
@ 2010-08-02  8:37     ` Pawel Osciak
  2010-08-02  9:00       ` Hans Verkuil
  0 siblings, 1 reply; 11+ messages in thread
From: Pawel Osciak @ 2010-08-02  8:37 UTC (permalink / raw)
  To: 'Hans Verkuil'
  Cc: linux-media, kyungmin.park, Marek Szyprowski, Tomasz Fujak

Hi Hans,
thank you for the review.

>Hans Verkuil <hverkuil@xs4all.nl> wrote:
>On Friday 30 July 2010 10:49:41 Pawel Osciak wrote:

<snip>

>> @@ -157,9 +158,23 @@ enum v4l2_buf_type {
>>  	/* Experimental */
>>  	V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8,
>>  #endif
>> +	V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE = 17,
>> +	V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE  = 18,
>
>Why 17 and 18 instead of 9 and 10?
>

To be able to test for "mplane" versions with a bit operation,
(type & 0x10), and to leave some space for future extensions
to "old" formats. I can go back to 9, 10 though if you prefer.


>> + *
>> + * Multi-planar buffers consist of one or more planes, e.g. an YCbCr
>buffer
>> + * with two planes can have one plane for Y, and another for interleaved
>CbCr
>> + * components. Each plane can reside in a separate memory buffer, or even
>in
>> + * a completely separate memory node (e.g. in embedded devices).
>> + */
>> +struct v4l2_plane {
>> +	__u32			bytesused;
>> +	__u32			length;
>> +	union {
>> +		__u32		mem_offset;
>> +		unsigned long	userptr;
>> +	} m;
>> +	__u32			data_offset;
>> +	__u32			reserved[11];
>> +};
>> +
>> +/**
>> + * struct v4l2_buffer - video buffer info
>> + * @index:	id number of the buffer
>> + * @type:	buffer type (type == *_MPLANE for multiplanar buffers)
>> + * @bytesused:	number of bytes occupied by data in the buffer (payload);
>> + * 		unused (set to 0) for multiplanar buffers
>> + * @flags:	buffer informational flags
>> + * @field:	field order of the image in the buffer
>> + * @timestamp:	frame timestamp
>> + * @timecode:	frame timecode
>> + * @sequence:	sequence count of this frame
>> + * @memory:	the method, in which the actual video data is passed
>> + * @offset:	for non-multiplanar buffers with memory ==
>V4L2_MEMORY_MMAP;
>> + * 		offset from the start of the device memory for this plane,
>> + * 		(or a "cookie" that should be passed to mmap() as offset)
>> + * @userptr:	for non-multiplanar buffers with memory ==
>V4L2_MEMORY_USERPTR;
>> + * 		a userspace pointer pointing to this buffer
>> + * @planes:	for multiplanar buffers; userspace pointer to the array
>of plane
>> + * 		info structs for this buffer
>> + * @length:	size in bytes of the buffer (NOT its payload) for single-
>plane
>> + * 		buffers (when type != *_MPLANE); number of planes (and number
>> + * 		of elements in the planes array) for multi-plane buffers
>
>This is confusing. Just write "number of elements in the planes array".
>
>> + * @input:	input number from which the video data has has been captured
>> + *
>> + * Contains data exchanged by application and driver using one of the
>Streaming
>> + * I/O methods.
>> + */
>>  struct v4l2_buffer {
>>  	__u32			index;
>>  	enum v4l2_buf_type      type;
>> @@ -529,6 +606,7 @@ struct v4l2_buffer {
>>  	union {
>>  		__u32           offset;
>>  		unsigned long   userptr;
>> +		struct v4l2_plane *planes;
>
>Should use the __user attribute.
>

We discussed this already, just for others: since we use the "planes" pointer
both as __user and kernel pointer, it's not worth it. We'd have to do some
obscure #ifdef magic and redefine the struct for parts of kernel code.
The same thing goes for controls pointer in v4l2_ext_controls.

Best regards
--
Pawel Osciak
Linux Platform Group
Samsung Poland R&D Center



^ permalink raw reply	[flat|nested] 11+ messages in thread

* RE: [PATCH v5 2/3] v4l: Add multi-planar ioctl handling code
  2010-08-01 12:30   ` Hans Verkuil
@ 2010-08-02  8:40     ` Pawel Osciak
  0 siblings, 0 replies; 11+ messages in thread
From: Pawel Osciak @ 2010-08-02  8:40 UTC (permalink / raw)
  To: 'Hans Verkuil'
  Cc: linux-media, kyungmin.park, Marek Szyprowski, Tomasz Fujak

Hi,

>Hans Verkuil <hverkuil@xs4all.nl> wrote:
>On Friday 30 July 2010 10:49:42 Pawel Osciak wrote:

<snip>

>>  static long __video_do_ioctl(struct file *file,
>>  		unsigned int cmd, void *arg)
>>  {
>>  	struct video_device *vfd = video_devdata(file);
>>  	const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;
>>  	void *fh = file->private_data;
>> +	struct v4l2_format f_copy;
>>  	long ret = -EINVAL;
>>
>>  	if (ops == NULL) {
>> @@ -720,6 +822,11 @@ static long __video_do_ioctl(struct file *file,
>>  			if (ops->vidioc_enum_fmt_vid_cap)
>>  				ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f);
>>  			break;
>> +		case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
>> +			if (ops->vidioc_enum_fmt_vid_cap_mplane)
>> +				ret = ops->vidioc_enum_fmt_vid_cap_mplane(file,
>> +									fh, f);
>> +			break;
>>  		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
>>  			if (ops->vidioc_enum_fmt_vid_overlay)
>>  				ret = ops->vidioc_enum_fmt_vid_overlay(file,
>> @@ -729,6 +836,11 @@ static long __video_do_ioctl(struct file *file,
>>  			if (ops->vidioc_enum_fmt_vid_out)
>>  				ret = ops->vidioc_enum_fmt_vid_out(file, fh, f);
>>  			break;
>> +		case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
>> +			if (ops->vidioc_enum_fmt_vid_out_mplane)
>> +				ret = ops->vidioc_enum_fmt_vid_out_mplane(file,
>> +									fh, f);
>> +			break;
>>  		case V4L2_BUF_TYPE_PRIVATE:
>>  			if (ops->vidioc_enum_fmt_type_private)
>>  				ret = ops->vidioc_enum_fmt_type_private(file,
>> @@ -757,22 +869,79 @@ static long __video_do_ioctl(struct file *file,
>>
>>  		switch (f->type) {
>>  		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
>> -			if (ops->vidioc_g_fmt_vid_cap)
>> +			if (ops->vidioc_g_fmt_vid_cap) {
>>  				ret = ops->vidioc_g_fmt_vid_cap(file, fh, f);
>> +			} else if (ops->vidioc_g_fmt_vid_cap_mplane) {
>> +				if (fmt_sp_to_mp(f, &f_copy))
>> +					break;
>> +				ret = ops->vidioc_g_fmt_vid_cap_mplane(file, fh,
>> +									&f_copy);
>> +				/* Driver is currently in multi-planar format,
>> +				 * we can't return it in single-planar API*/
>> +				if (f_copy.fmt.pix_mp.num_planes > 1) {
>
>Only do this if ret == 0.
>

Good point, thanks. Driver-produced errors should take precedence over EBUSY.


Best regards
--
Pawel Osciak
Linux Platform Group
Samsung Poland R&D Center






^ permalink raw reply	[flat|nested] 11+ messages in thread

* RE: [PATCH v5 1/3] v4l: Add multi-planar API definitions to the V4L2 API
  2010-08-02  8:37     ` Pawel Osciak
@ 2010-08-02  9:00       ` Hans Verkuil
  0 siblings, 0 replies; 11+ messages in thread
From: Hans Verkuil @ 2010-08-02  9:00 UTC (permalink / raw)
  To: Pawel Osciak; +Cc: linux-media, kyungmin.park, Marek Szyprowski, Tomasz Fujak

Hi Pawel!

> Hi Hans,
> thank you for the review.
>
>>Hans Verkuil <hverkuil@xs4all.nl> wrote:
>>On Friday 30 July 2010 10:49:41 Pawel Osciak wrote:
>
> <snip>
>
>>> @@ -157,9 +158,23 @@ enum v4l2_buf_type {
>>>  	/* Experimental */
>>>  	V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8,
>>>  #endif
>>> +	V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE = 17,
>>> +	V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE  = 18,
>>
>>Why 17 and 18 instead of 9 and 10?
>>
>
> To be able to test for "mplane" versions with a bit operation,
> (type & 0x10), and to leave some space for future extensions
> to "old" formats. I can go back to 9, 10 though if you prefer.

I prefer 9, 10. I would agree with you if there was some sort
of numbering scheme already, but it is just an enum with no particular
order.

>
>
>>> + *
>>> + * Multi-planar buffers consist of one or more planes, e.g. an YCbCr
>>buffer
>>> + * with two planes can have one plane for Y, and another for
>>> interleaved
>>CbCr
>>> + * components. Each plane can reside in a separate memory buffer, or
>>> even
>>in
>>> + * a completely separate memory node (e.g. in embedded devices).
>>> + */
>>> +struct v4l2_plane {
>>> +	__u32			bytesused;
>>> +	__u32			length;
>>> +	union {
>>> +		__u32		mem_offset;
>>> +		unsigned long	userptr;
>>> +	} m;
>>> +	__u32			data_offset;
>>> +	__u32			reserved[11];
>>> +};
>>> +
>>> +/**
>>> + * struct v4l2_buffer - video buffer info
>>> + * @index:	id number of the buffer
>>> + * @type:	buffer type (type == *_MPLANE for multiplanar buffers)
>>> + * @bytesused:	number of bytes occupied by data in the buffer
>>> (payload);
>>> + * 		unused (set to 0) for multiplanar buffers
>>> + * @flags:	buffer informational flags
>>> + * @field:	field order of the image in the buffer
>>> + * @timestamp:	frame timestamp
>>> + * @timecode:	frame timecode
>>> + * @sequence:	sequence count of this frame
>>> + * @memory:	the method, in which the actual video data is passed
>>> + * @offset:	for non-multiplanar buffers with memory ==
>>V4L2_MEMORY_MMAP;
>>> + * 		offset from the start of the device memory for this plane,
>>> + * 		(or a "cookie" that should be passed to mmap() as offset)
>>> + * @userptr:	for non-multiplanar buffers with memory ==
>>V4L2_MEMORY_USERPTR;
>>> + * 		a userspace pointer pointing to this buffer
>>> + * @planes:	for multiplanar buffers; userspace pointer to the array
>>of plane
>>> + * 		info structs for this buffer
>>> + * @length:	size in bytes of the buffer (NOT its payload) for single-
>>plane
>>> + * 		buffers (when type != *_MPLANE); number of planes (and number
>>> + * 		of elements in the planes array) for multi-plane buffers
>>
>>This is confusing. Just write "number of elements in the planes array".
>>
>>> + * @input:	input number from which the video data has has been
>>> captured
>>> + *
>>> + * Contains data exchanged by application and driver using one of the
>>Streaming
>>> + * I/O methods.
>>> + */
>>>  struct v4l2_buffer {
>>>  	__u32			index;
>>>  	enum v4l2_buf_type      type;
>>> @@ -529,6 +606,7 @@ struct v4l2_buffer {
>>>  	union {
>>>  		__u32           offset;
>>>  		unsigned long   userptr;
>>> +		struct v4l2_plane *planes;
>>
>>Should use the __user attribute.
>>
>
> We discussed this already, just for others: since we use the "planes"
> pointer
> both as __user and kernel pointer, it's not worth it. We'd have to do some
> obscure #ifdef magic and redefine the struct for parts of kernel code.
> The same thing goes for controls pointer in v4l2_ext_controls.

Indeed. This is also the reason why there is no __user in v4l2_ext_controls.

Regards,

         Hans

-- 
Hans Verkuil - video4linux developer - sponsored by TANDBERG, part of Cisco


^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2010-08-02  9:00 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-07-30  8:49 [PATCH v5 0/3] Multi-planar video format and buffer support for the V4L2 API Pawel Osciak
2010-07-30  8:49 ` [PATCH v5 1/3] v4l: Add multi-planar API definitions to " Pawel Osciak
2010-08-01 12:14   ` Hans Verkuil
2010-08-02  8:37     ` Pawel Osciak
2010-08-02  9:00       ` Hans Verkuil
2010-07-30  8:49 ` [PATCH v5 2/3] v4l: Add multi-planar ioctl handling code Pawel Osciak
2010-08-01 12:30   ` Hans Verkuil
2010-08-02  8:40     ` Pawel Osciak
2010-07-30  8:49 ` [PATCH v5 3/3] v4l: Add compat functions for the multi-planar API Pawel Osciak
2010-07-30 14:43 ` [PATCH v5 0/3] Multi-planar video format and buffer support for the V4L2 API Karicheri, Muralidharan
2010-08-02  8:18   ` Pawel Osciak

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.