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

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

commit 9312a740043d79d35ee1162ca4a82eeff227e5a3
Author: yangsen5 <[email protected]>
AuthorDate: Tue Mar 5 20:45:08 2024 +0800

    add m2m decoder/encoder test
    
    Signed-off-by: yangsen5 <[email protected]>
---
 system/nxcodec/Kconfig           |  30 +++
 system/nxcodec/Make.defs         |  23 +++
 system/nxcodec/Makefile          |  36 ++++
 system/nxcodec/nxcodec.c         | 259 ++++++++++++++++++++++++++
 system/nxcodec/nxcodec.h         |  51 ++++++
 system/nxcodec/nxcodec_context.c | 383 +++++++++++++++++++++++++++++++++++++++
 system/nxcodec/nxcodec_context.h |  65 +++++++
 system/nxcodec/nxcodec_main.c    | 206 +++++++++++++++++++++
 8 files changed, 1053 insertions(+)

diff --git a/system/nxcodec/Kconfig b/system/nxcodec/Kconfig
new file mode 100644
index 000000000..f7850dccf
--- /dev/null
+++ b/system/nxcodec/Kconfig
@@ -0,0 +1,30 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+config SYSTEM_NXCODEC
+       bool "NxCodec test application"
+       default n
+       ---help---
+               Enable support for the NxCodec test application and optional
+               command line interface.
+
+if SYSTEM_NXCODEC
+
+config SYSTEM_NXCODEC_PROGNAME
+       string "Program name"
+       default "nxcodec"
+       ---help---
+               This is the name of the program that will be used when the NSH 
ELF
+               program is installed.
+
+config SYSTEM_NXCODEC_PRIORITY
+       int "nxcodec task priority"
+       default 100
+
+config SYSTEM_NXCODEC_STACKSIZE
+       int "nxcodec stack size"
+       default DEFAULT_TASK_STACKSIZE
+
+endif # SYSTEM_NXCODEC
diff --git a/system/nxcodec/Make.defs b/system/nxcodec/Make.defs
new file mode 100644
index 000000000..ba0768549
--- /dev/null
+++ b/system/nxcodec/Make.defs
@@ -0,0 +1,23 @@
+############################################################################
+# apps/system/nxcodec/Make.defs
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################
+
+ifneq ($(CONFIG_SYSTEM_NXCODEC),)
+CONFIGURED_APPS += $(APPDIR)/system/nxcodec
+endif
diff --git a/system/nxcodec/Makefile b/system/nxcodec/Makefile
new file mode 100644
index 000000000..220e4f82c
--- /dev/null
+++ b/system/nxcodec/Makefile
@@ -0,0 +1,36 @@
+############################################################################
+# apps/system/nxcodec/Makefile
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################
+
+include $(APPDIR)/Make.defs
+
+CSRCS = nxcodec.c nxcodec_context.c
+
+# nxcodec test built-in application info
+
+PROGNAME = $(CONFIG_SYSTEM_NXCODEC_PROGNAME)
+PRIORITY = $(CONFIG_SYSTEM_NXCODEC_PRIORITY)
+STACKSIZE = $(CONFIG_SYSTEM_NXCODEC_STACKSIZE)
+MODULE = $(CONFIG_SYSTEM_NXCODEC)
+
+# nxcodec test
+
+MAINSRC = nxcodec_main.c
+
+include $(APPDIR)/Application.mk
diff --git a/system/nxcodec/nxcodec.c b/system/nxcodec/nxcodec.c
new file mode 100644
index 000000000..d6a99e4de
--- /dev/null
+++ b/system/nxcodec/nxcodec.c
@@ -0,0 +1,259 @@
+/****************************************************************************
+ * apps/system/nxcodec/nxcodec.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "nxcodec.h"
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static inline bool nxcodec_splane_video(FAR struct v4l2_capability *cap)
+{
+  return (cap->capabilities & V4L2_CAP_VIDEO_M2M) ||
+         ((cap->capabilities & V4L2_CAP_STREAMING) &&
+         (cap->capabilities & (V4L2_CAP_VIDEO_OUTPUT |
+                               V4L2_CAP_VIDEO_CAPTURE)));
+}
+
+static inline bool nxcodec_mplane_video(FAR struct v4l2_capability *cap)
+{
+  return (cap->capabilities & V4L2_CAP_VIDEO_M2M_MPLANE) ||
+         ((cap->capabilities & V4L2_CAP_STREAMING) &&
+         (cap->capabilities & (V4L2_CAP_VIDEO_OUTPUT_MPLANE |
+                               V4L2_CAP_VIDEO_CAPTURE_MPLANE)));
+}
+
+static int nxcodec_prepare_contexts(FAR nxcodec_t *codec)
+{
+  struct v4l2_capability cap;
+  int ret;
+
+  memset(&cap, 0, sizeof(cap));
+  ret = ioctl(codec->fd, VIDIOC_QUERYCAP, &cap);
+  if (ret < 0)
+    {
+      return -errno;
+    }
+
+  if (nxcodec_mplane_video(&cap))
+    {
+      codec->capture.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+      codec->output.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+      return 0;
+    }
+
+  if (nxcodec_splane_video(&cap))
+    {
+      codec->capture.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+      codec->output.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+      return 0;
+    }
+
+  return -EINVAL;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int nxcodec_init(FAR nxcodec_t *codec)
+{
+  int ret;
+
+  codec->fd = open(codec->devname, O_RDWR | O_NONBLOCK);
+  if (codec->fd < 0)
+    {
+      return -errno;
+    }
+
+  ret = nxcodec_prepare_contexts(codec);
+  if (ret < 0)
+    {
+      goto err0;
+    }
+
+  ret = nxcodec_context_get_format(&codec->output);
+  if (ret < 0)
+    {
+      printf("v4l2 output format not supported\n");
+      goto err0;
+    }
+
+  ret = nxcodec_context_get_format(&codec->capture);
+  if (ret < 0)
+    {
+      printf("v4l2 capture format not supported\n");
+      goto err0;
+    }
+
+  if (codec->output.fdesc.pixelformat !=
+      codec->output.format.fmt.pix.pixelformat)
+    {
+      ret = -EINVAL;
+      goto err0;
+    }
+
+  codec->output.format.type = codec->output.type;
+
+  ret = nxcodec_context_set_format(&codec->output);
+  if (ret < 0)
+    {
+      printf("can't set v4l2 output format\n");
+      goto err0;
+    }
+
+  codec->output.fd = open(codec->output.filename, O_RDONLY);
+  if (codec->output.fd < 0)
+    {
+      printf("Failed to open input file %s \n", codec->output.filename);
+      ret = -errno;
+      goto err0;
+    }
+
+  if (codec->capture.fdesc.pixelformat !=
+      codec->capture.format.fmt.pix.pixelformat)
+    {
+      ret = -EINVAL;
+      goto err1;
+    }
+
+  codec->capture.format.type = codec->capture.type;
+
+  ret = nxcodec_context_set_format(&codec->capture);
+  if (ret < 0)
+    {
+      printf("can't to set v4l2 capture format\n");
+      goto err1;
+    }
+
+  codec->capture.fd = open(codec->capture.filename,
+                           O_WRONLY | O_CREAT, 0644);
+  if (codec->capture.fd < 0)
+    {
+      printf("Failed to open input file %s \n", codec->capture.filename);
+      ret = -errno;
+      goto err1;
+    }
+
+  return 0;
+
+err1:
+  close(codec->output.fd);
+err0:
+  close(codec->fd);
+  return ret;
+}
+
+int nxcodec_start(FAR nxcodec_t *codec)
+{
+  int ret;
+
+  ret = nxcodec_context_init(&codec->output);
+  if (ret < 0)
+    {
+      printf("can't request output buffers\n");
+      return ret;
+    }
+
+  ret = nxcodec_context_set_status(&codec->output, VIDIOC_STREAMON);
+  if (ret < 0)
+    {
+      printf("set output VIDIOC_STREAMON failed\n");
+      goto err0;
+    }
+
+  ret = nxcodec_context_init(&codec->capture);
+  if (ret < 0)
+    {
+      printf("can't request capture buffers\n");
+      goto err0;
+    }
+
+  ret = nxcodec_context_set_status(&codec->capture, VIDIOC_STREAMON);
+  if (ret < 0)
+    {
+      printf("set capture VIDIOC_STREAMON failed\n");
+      goto err1;
+    }
+
+  ret = nxcodec_context_enqueue_frame(&codec->output);
+  if (ret < 0 && ret != -EAGAIN)
+    {
+      goto err1;
+    }
+
+  return 0;
+
+err1:
+  nxcodec_context_uninit(&codec->capture);
+err0:
+  nxcodec_context_uninit(&codec->output);
+  return ret;
+}
+
+int nxcodec_stop(FAR nxcodec_t *codec)
+{
+  int ret;
+
+  if (!codec)
+    {
+      return 0;
+    }
+
+  nxcodec_context_uninit(&codec->output);
+
+  ret = nxcodec_context_set_status(&codec->output, VIDIOC_STREAMOFF);
+  if (ret < 0)
+    {
+      printf("set output VIDIOC_STREAMOFF failed\n");
+      return ret;
+    }
+
+  nxcodec_context_uninit(&codec->capture);
+
+  ret = nxcodec_context_set_status(&codec->capture, VIDIOC_STREAMOFF);
+  if (ret < 0)
+    {
+      printf("set capture VIDIOC_STREAMOFF failed\n");
+      return ret;
+    }
+
+  return 0;
+}
+
+int nxcodec_uninit(FAR nxcodec_t *codec)
+{
+  close(codec->capture.fd);
+  close(codec->output.fd);
+  close(codec->fd);
+
+  return 0;
+}
diff --git a/system/nxcodec/nxcodec.h b/system/nxcodec/nxcodec.h
new file mode 100644
index 000000000..a3e89217b
--- /dev/null
+++ b/system/nxcodec/nxcodec.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+ * apps/system/nxcodec/nxcodec.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_SYSTEM_NXCODEC_NXCODEC_H
+#define __APPS_SYSTEM_NXCODEC_NXCODEC_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include "nxcodec_context.h"
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+typedef struct nxcodec_s
+{
+  char              devname[PATH_MAX];
+  int               fd;
+  nxcodec_context_t capture;
+  nxcodec_context_t output;
+} nxcodec_t;
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+int nxcodec_init(FAR nxcodec_t *codec);
+int nxcodec_start(FAR nxcodec_t *codec);
+int nxcodec_stop(FAR nxcodec_t *codec);
+int nxcodec_uninit(FAR nxcodec_t *codec);
+
+#endif /* __APPS_SYSTEM_NXCODEC_NXCODEC_H */
diff --git a/system/nxcodec/nxcodec_context.c b/system/nxcodec/nxcodec_context.c
new file mode 100644
index 000000000..16514d94a
--- /dev/null
+++ b/system/nxcodec/nxcodec_context.c
@@ -0,0 +1,383 @@
+/****************************************************************************
+ * apps/system/nxcodec/nxcodec_context.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <nuttx/nuttx.h>
+
+#include "nxcodec_context.h"
+#include "nxcodec.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define NXCODEC_CONTEXT_BUFNUMBER 3
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static inline FAR nxcodec_t *
+nxcodec_context_to_nxcodec(FAR nxcodec_context_t *ctx)
+{
+  return V4L2_TYPE_IS_OUTPUT(ctx->type) ?
+         container_of(ctx, nxcodec_t, output) :
+         container_of(ctx, nxcodec_t, capture);
+}
+
+static FAR nxcodec_context_buf_t *
+nxcodec_context_dequeue_buf(FAR nxcodec_context_t *ctx)
+{
+  FAR nxcodec_t *codec = nxcodec_context_to_nxcodec(ctx);
+  struct v4l2_buffer buf;
+  int ret;
+
+  memset(&buf, 0, sizeof(buf));
+  buf.memory = V4L2_MEMORY_MMAP;
+  buf.type = ctx->type;
+
+  ret = ioctl(codec->fd, VIDIOC_DQBUF, &buf);
+  if (ret < 0)
+    {
+      printf("type: %d VIDIOC_DQBUF, err: %s\n", ctx->type, strerror(errno));
+      return NULL;
+    }
+
+  ctx->buf[buf.index].free = true;
+  ctx->buf[buf.index].buf = buf;
+
+  return &ctx->buf[buf.index];
+}
+
+static FAR nxcodec_context_buf_t *
+nxcodec_context_get_freebuf(FAR nxcodec_context_t *ctx)
+{
+  int i;
+
+  if (V4L2_TYPE_IS_OUTPUT(ctx->type))
+    {
+      while (nxcodec_context_dequeue_buf(ctx));
+    }
+
+  for (i = 0; i < ctx->nbuffers; i++)
+    {
+      if (ctx->buf[i].free)
+        {
+          return &ctx->buf[i];
+        }
+    }
+
+  return NULL;
+}
+
+static int nxcodec_context_write_data(FAR nxcodec_context_t *ctx,
+                                      FAR const char *buf, int size)
+{
+  return write(ctx->fd, buf, size) < 0 ? -errno : 0;
+}
+
+static int nxcodec_context_read_yuv_data(FAR nxcodec_context_t *ctx,
+                                         FAR char *buf,
+                                         FAR uint32_t *bytesused)
+{
+  size_t buflen = ctx->format.fmt.pix.width *
+                  ctx->format.fmt.pix.height * 3 / 2;
+  ssize_t ret;
+
+  ret = read(ctx->fd, buf, buflen);
+  if (ret <= 0)
+    {
+      return -errno;
+    }
+
+  *bytesused = ret;
+  return 0;
+}
+
+static int nxcodec_context_read_h264_data(FAR nxcodec_context_t *ctx,
+                                          FAR char *buf,
+                                          FAR uint32_t *bytesused)
+{
+  char start_code[4];
+  ssize_t ret;
+  int size;
+
+  memset(start_code, 0, 4);
+
+  ret = read(ctx->fd, buf, 4);
+  if (ret <= 0)
+    {
+      return -errno;
+    }
+
+  if (buf[0] == 0x00 && buf[1] == 0x00 &&
+      buf[2] == 0x00 && buf[3] == 0x01)
+    {
+      size = 4;
+      while (1)
+        {
+          ret = read(ctx->fd, buf + size, 1);
+          if (ret < 0)
+            {
+              return -errno;
+            }
+          else if (ret == 0)
+            {
+              break;
+            }
+
+          start_code[0] = start_code[1];
+          start_code[1] = start_code[2];
+          start_code[2] = start_code[3];
+          start_code[3] = *(buf + size);
+          size++;
+
+          if (start_code[0] == 0x00 && start_code[1] == 0x00 &&
+              start_code[2] == 0x00 && start_code[3] == 0x01)
+            {
+              size -= 4;
+              lseek(ctx->fd, -4, SEEK_CUR);
+              break;
+            }
+        }
+    }
+  else
+    {
+      return -EINVAL;
+    }
+
+  *bytesused = size;
+
+  return 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int nxcodec_context_set_status(FAR nxcodec_context_t *ctx, uint32_t cmd)
+{
+  FAR nxcodec_t *codec = nxcodec_context_to_nxcodec(ctx);
+
+  return ioctl(codec->fd, cmd, &ctx->type) < 0 ? -errno : 0;
+}
+
+int nxcodec_context_enqueue_frame(FAR nxcodec_context_t *ctx)
+{
+  FAR nxcodec_t *codec = nxcodec_context_to_nxcodec(ctx);
+  FAR nxcodec_context_buf_t *buf;
+  int ret;
+
+  buf = nxcodec_context_get_freebuf(ctx);
+  if (!buf)
+    {
+      return -EAGAIN;
+    }
+
+  if (ctx->format.fmt.pix.pixelformat == V4L2_PIX_FMT_H264)
+    {
+      ret = nxcodec_context_read_h264_data(ctx,
+                                           buf->addr,
+                                           &buf->buf.bytesused);
+      if (ret < 0)
+        {
+          return ret;
+        }
+    }
+  else if (ctx->format.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
+    {
+      ret = nxcodec_context_read_yuv_data(ctx,
+                                          buf->addr,
+                                          &buf->buf.bytesused);
+      if (ret < 0)
+        {
+          return ret;
+        }
+    }
+
+  ret = ioctl(codec->fd, VIDIOC_QBUF, &buf->buf);
+  if (ret < 0)
+    {
+      return -errno;
+    }
+
+  buf->free = false;
+  return 0;
+}
+
+int nxcodec_context_dequeue_frame(FAR nxcodec_context_t *ctx)
+{
+  FAR nxcodec_t *codec = nxcodec_context_to_nxcodec(ctx);
+  FAR nxcodec_context_buf_t *buf;
+  int ret;
+
+  buf = nxcodec_context_dequeue_buf(ctx);
+  if (!buf)
+    {
+      return -EAGAIN;
+    }
+
+  if (buf->buf.length > 0)
+    {
+      nxcodec_context_write_data(ctx, buf->addr, buf->buf.bytesused);
+    }
+
+  ret = ioctl(codec->fd, VIDIOC_QBUF, &buf->buf);
+  if (ret < 0)
+    {
+      return -errno;
+    }
+
+  buf->free = false;
+  return 0;
+}
+
+int nxcodec_context_get_format(FAR nxcodec_context_t *ctx)
+{
+  FAR nxcodec_t *codec = nxcodec_context_to_nxcodec(ctx);
+
+  memset(&ctx->fdesc, 0, sizeof(ctx->fdesc));
+  ctx->fdesc.type = ctx->type;
+
+  return ioctl(codec->fd, VIDIOC_ENUM_FMT, &ctx->fdesc) < 0 ? -errno : 0;
+}
+
+int nxcodec_context_set_format(FAR nxcodec_context_t *ctx)
+{
+  FAR nxcodec_t *codec = nxcodec_context_to_nxcodec(ctx);
+
+  return ioctl(codec->fd, VIDIOC_S_FMT, &ctx->format) < 0 ? -errno : 0;
+}
+
+int nxcodec_context_init(FAR nxcodec_context_t *ctx)
+{
+  FAR nxcodec_t *codec = nxcodec_context_to_nxcodec(ctx);
+  struct v4l2_requestbuffers req;
+  int ret;
+  int i;
+
+  memset(&req, 0, sizeof(req));
+  req.count = NXCODEC_CONTEXT_BUFNUMBER;
+  req.memory = V4L2_MEMORY_MMAP;
+  req.type = ctx->type;
+
+  ret = ioctl(codec->fd, VIDIOC_REQBUFS, &req);
+  if (ret < 0)
+    {
+      printf("type: %d VIDIOC_REQBUFS failed: %s\n",
+              ctx->type, strerror(errno));
+      return -errno;
+    }
+
+  ctx->nbuffers = req.count;
+  ctx->buf = calloc(ctx->nbuffers, sizeof(nxcodec_context_buf_t));
+  if (!ctx->buf)
+    {
+      printf("type: %d malloc enomem\n", ctx->type);
+      return -ENOMEM;
+    }
+
+  for (i = 0; i < ctx->nbuffers; i++)
+    {
+      FAR nxcodec_context_buf_t *buf = &ctx->buf[i];
+
+      buf->buf.memory = V4L2_MEMORY_MMAP;
+      buf->buf.type = ctx->type;
+      buf->buf.index = i;
+
+      ret = ioctl(codec->fd, VIDIOC_QUERYBUF, &buf->buf);
+      if (ret < 0)
+        {
+          goto error;
+        }
+
+      buf->length = buf->buf.length;
+      buf->addr = mmap(NULL,
+                       buf->buf.length,
+                       PROT_READ | PROT_WRITE,
+                       MAP_SHARED,
+                       codec->fd,
+                       buf->buf.m.offset);
+
+      if (buf->addr == MAP_FAILED)
+        {
+          goto error;
+        }
+
+      buf->free = true;
+
+      if (V4L2_TYPE_IS_OUTPUT(ctx->type))
+        {
+          continue;
+        }
+
+      ret = ioctl(codec->fd, VIDIOC_QBUF, &buf->buf);
+      if (ret < 0)
+        {
+          munmap(buf->addr, buf->length);
+          goto error;
+        }
+
+      buf->free = false;
+    }
+
+  return 0;
+
+error:
+  free(ctx->buf);
+  return -errno;
+}
+
+void nxcodec_context_uninit(FAR nxcodec_context_t *ctx)
+{
+  int i;
+
+  if (!ctx->buf)
+    {
+      return;
+    }
+
+  for (i = 0; i < ctx->nbuffers; i++)
+    {
+      FAR nxcodec_context_buf_t *buf = &ctx->buf[i];
+
+      if (buf->addr && buf->length)
+        {
+          if (munmap(buf->addr, buf->length) < 0)
+            {
+              printf("type: %d unmap plane (%s))\n",
+                      ctx->type, strerror(errno));
+            }
+        }
+    }
+
+  free(ctx->buf);
+}
diff --git a/system/nxcodec/nxcodec_context.h b/system/nxcodec/nxcodec_context.h
new file mode 100644
index 000000000..09319e6ff
--- /dev/null
+++ b/system/nxcodec/nxcodec_context.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+ * apps/system/nxcodec/nxcodec_context.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __APP_SYSTEM_NXCODEC_NXCODEC_CONTEXT_H
+#define __APP_SYSTEM_NXCODEC_NXCODEC_CONTEXT_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <sys/videoio.h>
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+typedef struct nxcodec_context_buf_s
+{
+  FAR void           *addr;
+  size_t             length;
+  struct v4l2_buffer buf;
+  bool               free;
+} nxcodec_context_buf_t;
+
+typedef struct nxcodec_context_s
+{
+  char                      filename[PATH_MAX];
+  int                       fd;
+  enum v4l2_buf_type        type;
+  struct v4l2_format        format;
+  struct v4l2_fmtdesc       fdesc;
+  FAR nxcodec_context_buf_t *buf;
+  int                       nbuffers;
+} nxcodec_context_t;
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+int nxcodec_context_init(FAR nxcodec_context_t *ctx);
+int nxcodec_context_set_status(FAR nxcodec_context_t *ctx, uint32_t cmd);
+int nxcodec_context_enqueue_frame(FAR nxcodec_context_t *ctx);
+int nxcodec_context_dequeue_frame(FAR nxcodec_context_t *ctx);
+int nxcodec_context_get_format(FAR nxcodec_context_t *ctx);
+int nxcodec_context_set_format(FAR nxcodec_context_t *ctx);
+void nxcodec_context_uninit(FAR nxcodec_context_t *ctx);
+
+#endif /* __APP_SYSTEM_NXCODEC_NXCODEC_CONTEXT_H */
diff --git a/system/nxcodec/nxcodec_main.c b/system/nxcodec/nxcodec_main.c
new file mode 100644
index 000000000..d25f57180
--- /dev/null
+++ b/system/nxcodec/nxcodec_main.c
@@ -0,0 +1,206 @@
+/****************************************************************************
+ * apps/system/nxcodec/nxcodec_main.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <poll.h>
+#include <getopt.h>
+#include <errno.h>
+
+#include "nxcodec.h"
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const char g_short_options[] = "d:s:hf:i:o:";
+
+static const struct option g_long_options[] =
+{
+  { "device",  required_argument, NULL, 'd' },
+  { "size",    required_argument, NULL, 's' },
+  { "help",    no_argument,       NULL, 'h' },
+  { "format",  required_argument, NULL, 'f' },
+  { "infile",  required_argument, NULL, 'i' },
+  { "outfile", required_argument, NULL, 'o' },
+  { NULL,      0,                 NULL, 0   }
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static void usage(FAR const char *progname)
+{
+  printf("Usage: %s [options]\n\n"
+         "Version 1.3\n"
+         "Options:\n"
+         "-d | --device  Video device name\n"
+         "-s | --size    Size of stream\n"
+         "-h | --help    Print this message\n"
+         "-f | --format  Format of stream\n"
+         "-i | --infile  Input filename for M2M devices\n"
+         "-o | --outfile Outputs stream to filename\n\n"
+         "eg: nxcodec -d /dev/video1 -s 256x144 \
+              -f H264 -i input.h264 -f YU12 -o output.yuv\n",
+         progname);
+
+  exit(EXIT_SUCCESS);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * nxcodec_main
+ ****************************************************************************/
+
+int main(int argc, FAR char **argv)
+{
+  nxcodec_t codec;
+  int ret;
+  char cc[5] =
+    {
+      0
+    };
+
+  memset(&codec, 0, sizeof(codec));
+
+  while (1)
+    {
+      int idx;
+      int c;
+
+      c = getopt_long(argc, argv, g_short_options, g_long_options, &idx);
+      if (-1 == c)
+        {
+          break;
+        }
+
+      switch (c)
+        {
+          case 0: /* getopt_long() flag */
+            break;
+
+          case 'd':
+            memset(codec.devname, 0, sizeof(codec.devname));
+            snprintf(codec.devname, sizeof(codec.devname), "%s", optarg);
+            break;
+
+          case 's' :
+            sscanf(optarg, "%"SCNu32"x%"SCNu32"",
+                   &codec.capture.format.fmt.pix.width,
+                   &codec.capture.format.fmt.pix.height);
+
+            codec.output.format.fmt.pix.width =
+                                codec.capture.format.fmt.pix.width;
+            codec.output.format.fmt.pix.height =
+                                codec.capture.format.fmt.pix.height;
+            break;
+
+          case 'h':
+            usage(argv[0]);
+
+          case 'f':
+            memset(cc, 0, 5);
+            snprintf(cc, sizeof(cc), "%s", optarg);
+            break;
+
+          case 'i':
+            memset(codec.output.filename, 0, sizeof(codec.output.filename));
+            snprintf(codec.output.filename,
+                     sizeof(codec.output.filename), "%s", optarg);
+
+            codec.output.format.fmt.pix.pixelformat =
+                                    v4l2_fourcc(cc[0], cc[1], cc[2], cc[3]);
+            break;
+
+          case 'o':
+            memset(codec.capture.filename, 0,
+                   sizeof(codec.capture.filename));
+            snprintf(codec.capture.filename,
+                     sizeof(codec.capture.filename), "%s", optarg);
+
+            codec.capture.format.fmt.pix.pixelformat =
+                                     v4l2_fourcc(cc[0], cc[1], cc[2], cc[3]);
+            break;
+
+          default:
+            usage(argv[0]);
+            break;
+        }
+    }
+
+  if (argc != optind)
+    {
+      printf("Too few input parameter!\n\n");
+      usage(argv[0]);
+    }
+
+  ret = nxcodec_init(&codec);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = nxcodec_start(&codec);
+  if (ret < 0)
+    {
+      goto end0;
+    }
+
+  while (1)
+    {
+      struct pollfd pfd =
+      {
+        .events =  POLLIN | POLLOUT,
+        .fd = codec.fd,
+      };
+
+      poll(&pfd, 1, -1);
+
+      if (pfd.revents & POLLIN)
+        {
+          if (nxcodec_context_dequeue_frame(&codec.capture) < 0)
+            {
+              break;
+            }
+        }
+
+      if (pfd.revents & POLLOUT)
+        {
+          if (nxcodec_context_enqueue_frame(&codec.output) < 0)
+            {
+              break;
+            }
+        }
+    }
+
+  nxcodec_stop(&codec);
+
+end0:
+  nxcodec_uninit(&codec);
+  return ret;
+}

Reply via email to