This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 20ef7d18b9378f6db1f60ca84fc9c095eb1d303b
Author: niyinghao <[email protected]>
AuthorDate: Thu Sep 25 20:07:37 2025 +0800

    v4l2-m2m: support mplanes format
    
    Add multi-plane format support for v4l2-m2m. QUERYBUF reports a
    mem_offset for every plane, QBUF works out the buffer address, and for
    multi-planar formats each plane's address, from the buffer index and the
    buffer size, and DQBUF turns the addresses back into offsets.
    
    QBUF checks the buffer index, the memory type, the MMAP heap and the
    plane array before it takes a container, so a bad request can neither
    point the codec outside its buffers nor lose a container. DQBUF reads
    the plane array only after checking the buffer pointer, and rejects a
    multi-planar buffer that comes without one.
    
    Signed-off-by: niyinghao <[email protected]>
---
 drivers/video/v4l2_m2m.c        | 193 ++++++++++++++++++++++++++++++++++------
 drivers/video/video_framebuff.h |   5 +-
 2 files changed, 170 insertions(+), 28 deletions(-)

diff --git a/drivers/video/v4l2_m2m.c b/drivers/video/v4l2_m2m.c
index 9693ba444fe..29fc0412a46 100644
--- a/drivers/video/v4l2_m2m.c
+++ b/drivers/video/v4l2_m2m.c
@@ -352,8 +352,12 @@ static int codec_querybuf(FAR struct file *filep,
   FAR codec_mng_t *cmng = inode->i_private;
   FAR codec_file_t *cfile = filep->f_priv;
   FAR codec_type_inf_t *type_inf;
+  struct v4l2_format format;
+  uint32_t offset = 0;
+  size_t bufsize;
+  uint8_t i;
 
-  if (buf == NULL || buf->memory != V4L2_MEMORY_MMAP)
+  if (buf == NULL)
     {
       return -EINVAL;
     }
@@ -369,22 +373,57 @@ static int codec_querybuf(FAR struct file *filep,
       return -EINVAL;
     }
 
+  memset(&format, 0, sizeof(format));
   if (V4L2_TYPE_IS_OUTPUT(buf->type))
     {
-      buf->length   = CODEC_OUTPUT_G_BUFSIZE(cmng->codec, cfile->priv);
-      buf->m.offset = buf->length * buf->index;
+      bufsize = CODEC_OUTPUT_G_BUFSIZE(cmng->codec, cfile->priv);
+      CODEC_OUTPUT_G_FMT(cmng->codec, cfile->priv, &format);
     }
   else
     {
-      buf->length   = CODEC_CAPTURE_G_BUFSIZE(cmng->codec, cfile->priv);
-      buf->m.offset = buf->length * buf->index + CAPTURE_BUF_OFFSET;
+      offset  = CAPTURE_BUF_OFFSET;
+      bufsize = CODEC_CAPTURE_G_BUFSIZE(cmng->codec, cfile->priv);
+      CODEC_CAPTURE_G_FMT(cmng->codec, cfile->priv, &format);
     }
 
-  if (buf->length == 0)
+  if (bufsize == 0)
     {
       return -EINVAL;
     }
 
+  if (V4L2_TYPE_IS_MULTIPLANAR(buf->type))
+    {
+      for (i = 0; i < format.fmt.pix_mp.num_planes; i++)
+        {
+          switch (buf->memory)
+            {
+              case V4L2_MEMORY_MMAP:
+                buf->m.planes[i].length =
+                    format.fmt.pix_mp.plane_fmt[i].sizeimage;
+                buf->m.planes[i].m.mem_offset =
+                    offset + bufsize * buf->index;
+                offset += buf->m.planes[i].length;
+                break;
+
+              default:
+                return -EINVAL;
+            }
+        }
+    }
+  else
+    {
+      switch (buf->memory)
+        {
+          case V4L2_MEMORY_MMAP:
+            buf->length   = bufsize;
+            buf->m.offset = offset + bufsize * buf->index;
+            break;
+
+          default:
+            return -EINVAL;
+        }
+    }
+
   return OK;
 }
 
@@ -396,7 +435,8 @@ static int codec_qbuf(FAR struct file *filep,
   FAR codec_file_t *cfile = filep->f_priv;
   FAR codec_type_inf_t *type_inf;
   FAR vbuf_container_t *container;
-  size_t buf_size;
+  struct v4l2_format format;
+  uint8_t i;
 
   if (buf == NULL)
     {
@@ -404,7 +444,26 @@ static int codec_qbuf(FAR struct file *filep,
     }
 
   type_inf = codec_get_type_inf(cfile, buf->type);
-  if (type_inf == NULL)
+  if (type_inf == NULL ||
+      buf->index >= type_inf->bufinf.container_size)
+    {
+      return -EINVAL;
+    }
+
+  switch (buf->memory)
+    {
+      case V4L2_MEMORY_MMAP:
+        if (type_inf->bufheap == NULL)
+          {
+            return -EINVAL;
+          }
+        break;
+
+      default:
+        return -EINVAL;
+    }
+
+  if (V4L2_TYPE_IS_MULTIPLANAR(buf->type) && buf->m.planes == NULL)
     {
       return -EINVAL;
     }
@@ -416,28 +475,59 @@ static int codec_qbuf(FAR struct file *filep,
       return -EAGAIN;
     }
 
+  memset(&format, 0, sizeof(format));
+  if (V4L2_TYPE_IS_OUTPUT(buf->type))
+    {
+      CODEC_OUTPUT_G_FMT(cmng->codec, cfile->priv, &format);
+    }
+  else
+    {
+      CODEC_CAPTURE_G_FMT(cmng->codec, cfile->priv, &format);
+    }
+
   memcpy(&container->buf, buf, sizeof(struct v4l2_buffer));
-  if (buf->memory == V4L2_MEMORY_MMAP)
+
+  if (V4L2_TYPE_IS_MULTIPLANAR(buf->type))
     {
-      /* only use userptr inside the container */
+      size_t bufsize;
+      uint32_t plane_offset = 0;
+
+      bufsize = V4L2_TYPE_IS_OUTPUT(buf->type) ?
+        CODEC_OUTPUT_G_BUFSIZE(cmng->codec, cfile->priv) :
+        CODEC_CAPTURE_G_BUFSIZE(cmng->codec, cfile->priv);
 
-      if (V4L2_TYPE_IS_OUTPUT(buf->type))
+      memcpy(container->planes, buf->m.planes,
+             sizeof(struct v4l2_plane) * format.fmt.pix_mp.num_planes);
+      container->buf.m.planes = container->planes;
+      for (i = 0; i < format.fmt.pix_mp.num_planes; i++)
         {
-          buf_size = CODEC_OUTPUT_G_BUFSIZE(cmng->codec, cfile->priv);
+          switch (container->buf.memory)
+            {
+              case V4L2_MEMORY_MMAP:
+                container->buf.m.planes[i].m.vaddr =
+                    (FAR void *)(type_inf->bufheap +
+                     bufsize * buf->index + plane_offset);
+                plane_offset += format.fmt.pix_mp.plane_fmt[i].sizeimage;
+                break;
+            }
         }
-      else
+    }
+  else
+    {
+      switch (buf->memory)
         {
-          buf_size = CODEC_CAPTURE_G_BUFSIZE(cmng->codec, cfile->priv);
-        }
+          case V4L2_MEMORY_MMAP:
+            {
+              size_t bufsize;
 
-      if (buf_size == 0)
-        {
-          return -EINVAL;
+              bufsize = V4L2_TYPE_IS_OUTPUT(buf->type) ?
+                CODEC_OUTPUT_G_BUFSIZE(cmng->codec, cfile->priv) :
+                CODEC_CAPTURE_G_BUFSIZE(cmng->codec, cfile->priv);
+              container->buf.m.vaddr =
+                  (FAR void *)(type_inf->bufheap + bufsize * buf->index);
+            }
+            break;
         }
-
-      container->buf.length    = buf_size;
-      container->buf.m.vaddr   = type_inf->bufheap +
-                                 container->buf.length * buf->index;
     }
 
   video_framebuff_queue_container(&type_inf->bufinf, container);
@@ -455,15 +545,22 @@ static int codec_qbuf(FAR struct file *filep,
 static int codec_dqbuf(FAR struct file *filep,
                        FAR struct v4l2_buffer *buf)
 {
+  FAR struct inode *inode = filep->f_inode;
+  FAR codec_mng_t *cmng = inode->i_private;
   FAR codec_file_t *cfile = filep->f_priv;
   FAR codec_type_inf_t *type_inf;
   FAR vbuf_container_t *container;
+  FAR struct v4l2_plane *plans;
+  struct v4l2_format format;
+  uint32_t offset = 0;
+  uint8_t i;
 
   if (buf == NULL)
     {
       return -EINVAL;
     }
 
+  plans = buf->m.planes;
   type_inf = codec_get_type_inf(cfile, buf->type);
   if (type_inf == NULL)
     {
@@ -481,15 +578,59 @@ static int codec_dqbuf(FAR struct file *filep,
       return -EAGAIN;
     }
 
+  memset(&format, 0, sizeof(format));
+  if (V4L2_TYPE_IS_OUTPUT(buf->type))
+    {
+      CODEC_OUTPUT_G_FMT(cmng->codec, cfile->priv, &format);
+    }
+  else
+    {
+      offset = CAPTURE_BUF_OFFSET;
+      CODEC_CAPTURE_G_FMT(cmng->codec, cfile->priv, &format);
+    }
+
   memcpy(buf, &container->buf, sizeof(struct v4l2_buffer));
-  video_framebuff_free_container(&type_inf->bufinf, container);
+  if (V4L2_TYPE_IS_MULTIPLANAR(buf->type))
+    {
+      if (plans == NULL)
+        {
+          return -EINVAL;
+        }
 
-  if (buf->memory == V4L2_MEMORY_MMAP)
+      buf->m.planes = plans;
+      memcpy(plans, container->planes,
+             sizeof(struct v4l2_plane) * format.fmt.pix_mp.num_planes);
+      for (i = 0; i < format.fmt.pix_mp.num_planes; i++)
+        {
+          switch (container->buf.memory)
+            {
+              case V4L2_MEMORY_MMAP:
+                buf->m.planes[i].m.mem_offset = (uint32_t)
+                    ((uint8_t *)buf->m.planes[i].m.vaddr -
+                     type_inf->bufheap + offset);
+                break;
+
+              default:
+                return -EINVAL;
+            }
+        }
+    }
+  else
     {
-      buf->m.offset = buf->length * buf->index +
-          (V4L2_TYPE_IS_OUTPUT(buf->type) ? 0 : CAPTURE_BUF_OFFSET);
+      switch (container->buf.memory)
+        {
+          case V4L2_MEMORY_MMAP:
+            buf->m.offset = (uint32_t)((uint8_t *)buf->m.vaddr -
+                            type_inf->bufheap + offset);
+            break;
+
+          default:
+            return -EINVAL;
+        }
     }
 
+  video_framebuff_free_container(&type_inf->bufinf, container);
+
   vinfo("%s dequeue done\n", V4L2_TYPE_IS_OUTPUT(buf->type) ?
                              "output" : "capture");
 
diff --git a/drivers/video/video_framebuff.h b/drivers/video/video_framebuff.h
index 5623cd6acb2..1fd252b99a9 100644
--- a/drivers/video/video_framebuff.h
+++ b/drivers/video/video_framebuff.h
@@ -38,8 +38,9 @@
 
 struct vbuf_container_s
 {
-  struct v4l2_buffer       buf;   /* Buffer information */
-  struct vbuf_container_s *next;  /* Pointer to next buffer */
+  struct v4l2_buffer       buf;                      /* Buffer information */
+  struct v4l2_plane        planes[VIDEO_MAX_PLANES]; /* Buffer planes */
+  struct vbuf_container_s *next;                     /* Pointer to next buffer 
*/
 };
 
 typedef struct vbuf_container_s vbuf_container_t;

Reply via email to