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 6d213a4d2ac718ede157d2e57bc0703157be1685
Author: yaojingwei <[email protected]>
AuthorDate: Wed Apr 29 20:47:44 2026 +0800

    video/v4l2_m2m: add DMA-BUF import support
    
    Add V4L2_MEMORY_DMABUF support to the V4L2 M2M codec framework,
    enabling zero-copy buffer sharing between codec and other devices
    (camera, display) via DMA-BUF file descriptors.
    
    QBUF checks the index of a DMA-BUF buffer against the import slots
    before it takes a container, and gives the container back when the
    import fails.
    
    Signed-off-by: yaojingwei <[email protected]>
---
 drivers/video/v4l2_m2m.c       | 193 +++++++++++++++++++++++++++++++++++++++++
 include/nuttx/video/v4l2_m2m.h |   8 +-
 2 files changed, 197 insertions(+), 4 deletions(-)

diff --git a/drivers/video/v4l2_m2m.c b/drivers/video/v4l2_m2m.c
index 42359a98cde..426fb6f476a 100644
--- a/drivers/video/v4l2_m2m.c
+++ b/drivers/video/v4l2_m2m.c
@@ -38,6 +38,10 @@
 #include <nuttx/video/video.h>
 #include <sys/param.h>
 
+#ifdef CONFIG_DMA_SHARED_BUFFER
+#  include <nuttx/dma-buf.h>
+#endif
+
 #include "video_framebuff.h"
 
 /****************************************************************************
@@ -64,11 +68,23 @@ struct codec_event_s
 
 typedef struct codec_event_s codec_event_t;
 
+#ifdef CONFIG_DMA_SHARED_BUFFER
+struct codec_dmabuf_s
+{
+  FAR struct dma_buf            *dmabuf;
+  FAR struct dma_buf_attachment *attachment;
+  uintptr_t                     dmaaddr;
+};
+#endif
+
 struct codec_type_inf_s
 {
   video_framebuff_t bufinf;
   FAR uint8_t       *bufheap;   /* for V4L2_MEMORY_MMAP buffers */
   bool              buflast;
+#ifdef CONFIG_DMA_SHARED_BUFFER
+  struct codec_dmabuf_s dmabufinf[V4L2_REQBUFS_COUNT_MAX];
+#endif
 };
 
 typedef struct codec_type_inf_s codec_type_inf_t;
@@ -159,6 +175,13 @@ static int codec_decoder_cmd(FAR struct file *filep,
                              FAR struct v4l2_decoder_cmd *cmd);
 static int codec_encoder_cmd(FAR struct file *filep,
                              FAR struct v4l2_encoder_cmd *cmd);
+#ifdef CONFIG_DMA_SHARED_BUFFER
+static void codec_release_dmabuf(FAR codec_type_inf_t *type_inf,
+                                 uint32_t index);
+static int codec_import_dmabuf(FAR codec_type_inf_t *type_inf,
+                               uint32_t index, int fd);
+static void codec_cleanup_dmabuf(FAR codec_type_inf_t *type_inf);
+#endif
 
 /****************************************************************************
  * Private Data
@@ -237,6 +260,73 @@ codec_get_type_inf(FAR struct codec_file_s *cfile, int 
type)
     }
 }
 
+#ifdef CONFIG_DMA_SHARED_BUFFER
+static void codec_release_dmabuf(FAR codec_type_inf_t *type_inf,
+                                 uint32_t index)
+{
+  if (type_inf->dmabufinf[index].attachment != NULL)
+    {
+      dma_buf_unmap_attachment(type_inf->dmabufinf[index].attachment,
+                              type_inf->dmabufinf[index].dmaaddr,
+                              DMA_BIDIRECTIONAL);
+      dma_buf_detach(type_inf->dmabufinf[index].dmabuf,
+                     type_inf->dmabufinf[index].attachment);
+      dma_buf_put(type_inf->dmabufinf[index].dmabuf);
+      type_inf->dmabufinf[index].dmabuf = NULL;
+      type_inf->dmabufinf[index].attachment = NULL;
+      type_inf->dmabufinf[index].dmaaddr = 0;
+    }
+}
+
+static int codec_import_dmabuf(FAR codec_type_inf_t *type_inf,
+                               uint32_t index, int fd)
+{
+  FAR struct dma_buf *dbuf;
+  FAR struct dma_buf_attachment *attach;
+  uintptr_t dmaaddr;
+
+  codec_release_dmabuf(type_inf, index);
+
+  dbuf = dma_buf_get(fd);
+  if (dbuf == NULL)
+    {
+      return -EINVAL;
+    }
+
+  attach = dma_buf_attach(dbuf);
+  if (attach == NULL)
+    {
+      dma_buf_put(dbuf);
+      return -ENOMEM;
+    }
+
+  dmaaddr = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+  if (dmaaddr == 0)
+    {
+      dma_buf_detach(dbuf, attach);
+      dma_buf_put(dbuf);
+      return -EFAULT;
+    }
+
+  type_inf->dmabufinf[index].dmabuf = dbuf;
+  type_inf->dmabufinf[index].attachment = attach;
+  type_inf->dmabufinf[index].dmaaddr = dmaaddr;
+
+  return OK;
+}
+
+static void codec_cleanup_dmabuf(FAR codec_type_inf_t *type_inf)
+{
+  int i;
+
+  for (i = 0; i < V4L2_REQBUFS_COUNT_MAX; i++)
+    {
+      codec_release_dmabuf(type_inf, i);
+    }
+}
+
+#endif /* CONFIG_DMA_SHARED_BUFFER */
+
 static int codec_querycap(FAR struct file *filep,
                           FAR struct v4l2_capability *cap)
 {
@@ -322,6 +412,30 @@ static int codec_reqbufs(FAR struct file *filep,
   video_framebuff_change_mode(&type_inf->bufinf, reqbufs->mode);
   ret = video_framebuff_realloc_container(&type_inf->bufinf,
                                           reqbufs->count);
+
+#ifdef CONFIG_DMA_SHARED_BUFFER
+  if (ret == 0 && reqbufs->memory == V4L2_MEMORY_DMABUF)
+    {
+      /* DMABUF mode: only allocate containers, no bufheap needed.
+       * Free existing bufheap if present.
+       */
+
+      if (type_inf->bufheap != NULL)
+        {
+          if (cmng->codec->ops->free_buf)
+            {
+              cmng->codec->ops->free_buf(cfile->priv, type_inf->bufheap);
+            }
+          else
+            {
+              kumm_free(type_inf->bufheap);
+            }
+
+          type_inf->bufheap = NULL;
+        }
+    }
+  else
+#endif
   if (ret == 0 && reqbufs->memory == V4L2_MEMORY_MMAP)
     {
       if (cmng->codec->ops->free_buf)
@@ -474,6 +588,15 @@ static int codec_qbuf(FAR struct file *filep,
       case V4L2_MEMORY_USERPTR:
         break;
 
+#ifdef CONFIG_DMA_SHARED_BUFFER
+      case V4L2_MEMORY_DMABUF:
+        if (buf->index >= V4L2_REQBUFS_COUNT_MAX)
+          {
+            return -EINVAL;
+          }
+        break;
+#endif
+
       default:
         return -EINVAL;
     }
@@ -529,6 +652,29 @@ static int codec_qbuf(FAR struct file *filep,
                 container->buf.m.planes[i].m.vaddr =
                     (FAR void *)buf->m.planes[i].m.userptr;
                 break;
+
+#ifdef CONFIG_DMA_SHARED_BUFFER
+              case V4L2_MEMORY_DMABUF:
+                {
+                  int ret;
+
+                  ret = codec_import_dmabuf(type_inf,
+                            buf->index, buf->m.planes[i].m.fd);
+                  if (ret < 0)
+                    {
+                      video_framebuff_free_container(&type_inf->bufinf,
+                                                     container);
+                      return ret;
+                    }
+
+                  container->buf.m.planes[i].m.fd =
+                      buf->m.planes[i].m.fd;
+                  container->buf.m.planes[i].m.vaddr =
+                      (FAR void *)type_inf->dmabufinf[
+                          buf->index].dmaaddr;
+                }
+                break;
+#endif
             }
         }
     }
@@ -551,6 +697,28 @@ static int codec_qbuf(FAR struct file *filep,
           case V4L2_MEMORY_USERPTR:
             container->buf.m.vaddr = (FAR void *)buf->m.userptr;
             break;
+
+#ifdef CONFIG_DMA_SHARED_BUFFER
+          case V4L2_MEMORY_DMABUF:
+            {
+              int ret;
+
+              ret = codec_import_dmabuf(type_inf,
+                        buf->index, buf->m.fd);
+              if (ret < 0)
+                {
+                  video_framebuff_free_container(&type_inf->bufinf,
+                                                 container);
+                  return ret;
+                }
+
+              container->buf.m.fd = buf->m.fd;
+              container->buf.m.vaddr =
+                  (FAR void *)type_inf->dmabufinf[
+                      buf->index].dmaaddr;
+            }
+            break;
+#endif
         }
     }
 
@@ -639,6 +807,15 @@ static int codec_dqbuf(FAR struct file *filep,
                     buf->m.planes[i].m.vaddr;
                 break;
 
+#ifdef CONFIG_DMA_SHARED_BUFFER
+              case V4L2_MEMORY_DMABUF:
+                buf->m.planes[i].m.fd =
+                    container->buf.m.planes[i].m.fd;
+                codec_release_dmabuf(type_inf,
+                    container->buf.index);
+                break;
+#endif
+
               default:
                 return -EINVAL;
             }
@@ -657,6 +834,13 @@ static int codec_dqbuf(FAR struct file *filep,
             buf->m.userptr = (unsigned long)buf->m.vaddr;
             break;
 
+#ifdef CONFIG_DMA_SHARED_BUFFER
+          case V4L2_MEMORY_DMABUF:
+            buf->m.fd = container->buf.m.fd;
+            codec_release_dmabuf(type_inf, container->buf.index);
+            break;
+#endif
+
           default:
             return -EINVAL;
         }
@@ -904,6 +1088,10 @@ static int codec_streamoff(FAR struct file *filep,
       return -EINVAL;
     }
 
+#ifdef CONFIG_DMA_SHARED_BUFFER
+  codec_cleanup_dmabuf(type_inf);
+#endif
+
   if (V4L2_TYPE_IS_OUTPUT(*type))
     {
       return CODEC_OUTPUT_STREAMOFF(cmng->codec, cfile->priv);
@@ -1058,6 +1246,11 @@ static int codec_close(FAR struct file *filep)
 
   CODEC_CLOSE(cmng->codec, cfile->priv);
 
+#ifdef CONFIG_DMA_SHARED_BUFFER
+  codec_cleanup_dmabuf(&cfile->capture_inf);
+  codec_cleanup_dmabuf(&cfile->output_inf);
+#endif
+
   video_framebuff_uninit(&cfile->capture_inf.bufinf);
   video_framebuff_uninit(&cfile->output_inf.bufinf);
   if (cmng->codec->ops->free_buf)
diff --git a/include/nuttx/video/v4l2_m2m.h b/include/nuttx/video/v4l2_m2m.h
index 4110c6fea0c..708f4ec31d6 100644
--- a/include/nuttx/video/v4l2_m2m.h
+++ b/include/nuttx/video/v4l2_m2m.h
@@ -185,14 +185,14 @@
 #define CODEC_CAPTURE_TRY_MEMORY(codec, priv, mem) \
   ((codec)->ops->capture_try_memory ? \
    (codec)->ops->capture_try_memory(priv, mem) : \
-   ((mem == V4L2_MEMORY_MMAP || mem == V4L2_MEMORY_USERPTR) ? \
-    0 : -ENOTTY))
+   ((mem == V4L2_MEMORY_MMAP || mem == V4L2_MEMORY_USERPTR || \
+     mem == V4L2_MEMORY_DMABUF) ? 0 : -ENOTTY))
 
 #define CODEC_OUTPUT_TRY_MEMORY(codec, priv, mem) \
   ((codec)->ops->output_try_memory ? \
    (codec)->ops->output_try_memory(priv, mem) : \
-   ((mem == V4L2_MEMORY_MMAP || mem == V4L2_MEMORY_USERPTR) ? \
-    0 : -ENOTTY))
+   ((mem == V4L2_MEMORY_MMAP || mem == V4L2_MEMORY_USERPTR || \
+     mem == V4L2_MEMORY_DMABUF) ? 0 : -ENOTTY))
 
 /****************************************************************************
  * Public Types

Reply via email to