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

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

commit 802e7710a138a3f322cb306042ee8c1f57320288
Author: yaojingwei <[email protected]>
AuthorDate: Thu Jul 23 10:18:52 2026 +0800

    nxcodec: add JPEG/MJPEG single-frame decode support
    
    Add JPEG/MJPEG input format handling to nxcodec for V4L2 M2M JPEG
    decoder verification. Read entire JPEG file as one frame with SOI
    validation, and exit poll loop after first decoded frame.
    
    Signed-off-by: yaojingwei <[email protected]>
---
 system/nxcodec/nxcodec_context.c | 54 ++++++++++++++++++++++++++++++
 system/nxcodec/nxcodec_main.c    | 72 ++++++++++++++++++++++++++++++++++++----
 2 files changed, 120 insertions(+), 6 deletions(-)

diff --git a/system/nxcodec/nxcodec_context.c b/system/nxcodec/nxcodec_context.c
index 77f3c09fc..601dc3b22 100644
--- a/system/nxcodec/nxcodec_context.c
+++ b/system/nxcodec/nxcodec_context.c
@@ -130,6 +130,44 @@ static int nxcodec_context_read_yuv_data(FAR 
nxcodec_context_t *ctx,
   return 0;
 }
 
+static int nxcodec_context_read_jpeg_data(FAR nxcodec_context_t *ctx,
+                                          FAR char *buf,
+                                          FAR uint32_t *bytesused)
+{
+  ssize_t total = 0;
+  ssize_t ret;
+
+  /* Read as much as available from the JPEG file.  For a single-image
+   * JPEG file the entire content is one frame.  We read until EOF or
+   * until the buffer is full.
+   */
+
+  for (; ; )
+    {
+      ret = read(ctx->fd, buf + total,
+                 ctx->format.fmt.pix.sizeimage - total);
+      if (ret < 0)
+        {
+          return -errno;
+        }
+
+      if (ret == 0)
+        {
+          break;
+        }
+
+      total += ret;
+    }
+
+  if (total == 0)
+    {
+      return -ENODATA;
+    }
+
+  *bytesused = total;
+  return 0;
+}
+
 static int nxcodec_context_read_h264_data(FAR nxcodec_context_t *ctx,
                                           FAR char *buf,
                                           FAR uint32_t *bytesused)
@@ -220,6 +258,17 @@ int nxcodec_context_enqueue_frame(FAR nxcodec_context_t 
*ctx)
           return ret;
         }
     }
+  else if (ctx->format.fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG ||
+           ctx->format.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG)
+    {
+      ret = nxcodec_context_read_jpeg_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,
@@ -230,6 +279,10 @@ int nxcodec_context_enqueue_frame(FAR nxcodec_context_t 
*ctx)
           return ret;
         }
     }
+  else
+    {
+      return -EINVAL;
+    }
 
   ret = ioctl(codec->fd, VIDIOC_QBUF, &buf->buf);
   if (ret < 0)
@@ -274,6 +327,7 @@ int nxcodec_context_get_format(FAR nxcodec_context_t *ctx)
   struct v4l2_fmtdesc fdesc;
   int ret;
 
+  memset(&fdesc, 0, sizeof(fdesc));
   fdesc.type = ctx->type;
   while (true)
     {
diff --git a/system/nxcodec/nxcodec_main.c b/system/nxcodec/nxcodec_main.c
index b4aab3131..06407efe8 100644
--- a/system/nxcodec/nxcodec_main.c
+++ b/system/nxcodec/nxcodec_main.c
@@ -27,6 +27,7 @@
 #include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <poll.h>
 #include <getopt.h>
 #include <errno.h>
@@ -46,7 +47,7 @@
  * Private Data
  ****************************************************************************/
 
-static const char g_short_options[] = "d:s:hf:i:o:";
+static const char g_short_options[] = "d:s:hf:i:o:t:";
 
 static const struct option g_long_options[] =
 {
@@ -56,6 +57,7 @@ static const struct option g_long_options[] =
   { "format",  required_argument, NULL, 'f' },
   { "infile",  required_argument, NULL, 'i' },
   { "outfile", required_argument, NULL, 'o' },
+  { "timeout", required_argument, NULL, 't' },
   { NULL,      0,                 NULL, 0   }
 };
 
@@ -67,7 +69,7 @@ static void usage(FAR const char *progname)
 {
   printf("NxCodec Version: "NXCODEC_VER"\n"
          "Usage: %s -d devname -s [wxh] -f [informt] "
-         "-i infile -f [outformat] -o outfile\n"
+         "-i infile -f [outformat] -o outfile [-t timeout_ms]\n"
          "Default settings for decoder parameters\n\n"
          "Options:\n"
          "-d | --device  Video device name\n"
@@ -75,12 +77,41 @@ static void usage(FAR const char *progname)
          "-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",
+         "-o | --outfile Outputs stream to filename\n"
+         "-t | --timeout Decode timeout in ms (default: infinite)\n",
          progname);
 
   exit(EXIT_SUCCESS);
 }
 
+static inline bool nxcodec_is_jpeg(FAR nxcodec_t *codec)
+{
+  uint32_t fmt = codec->output.format.fmt.pix.pixelformat;
+
+  return fmt == V4L2_PIX_FMT_JPEG || fmt == V4L2_PIX_FMT_MJPEG;
+}
+
+static int nxcodec_jpeg_wait_decode(FAR nxcodec_t *codec, int timeout_ms)
+{
+  struct pollfd cpfd =
+  {
+    .events = POLLIN,
+    .fd = codec->fd,
+  };
+
+  /* Wait for the final decoded frame.  A timeout guards against the
+   * decoder hanging on a single-frame JPEG when the lower layer fails.
+   */
+
+  poll(&cpfd, 1, timeout_ms);
+  if (cpfd.revents & POLLIN)
+    {
+      return nxcodec_context_dequeue_frame(&codec->capture);
+    }
+
+  return -ETIMEDOUT;
+}
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -92,6 +123,7 @@ static void usage(FAR const char *progname)
 int main(int argc, FAR char **argv)
 {
   nxcodec_t codec;
+  int timeout_ms = -1;
   int ret;
   char cc[5] =
     {
@@ -193,6 +225,10 @@ int main(int argc, FAR char **argv)
 
             break;
 
+          case 't':
+            timeout_ms = atoi(optarg);
+            break;
+
           default:
             usage(argv[0]);
             break;
@@ -229,18 +265,42 @@ int main(int argc, FAR char **argv)
 
       if (pfd.revents & POLLIN)
         {
-          if (nxcodec_context_dequeue_frame(&codec.capture) < 0)
+          ret = nxcodec_context_dequeue_frame(&codec.capture);
+          if (ret < 0 && ret != -EAGAIN)
             {
               printf("nxcodec dequeue frame failed: %s\n", strerror(errno));
               break;
             }
+
+          /* For single-frame formats (JPEG/MJPEG), one decoded frame
+           * is all we need.  Exit the loop after successfully
+           * dequeuing the output.
+           */
+
+          if (ret == 0 && nxcodec_is_jpeg(&codec))
+            {
+              break;
+            }
         }
 
       if (pfd.revents & POLLOUT)
         {
-          if (nxcodec_context_enqueue_frame(&codec.output) < 0)
+          ret = nxcodec_context_enqueue_frame(&codec.output);
+          if (ret < 0 && ret != -EAGAIN)
             {
-              printf("nxcodec enqueue frame failed: %s\n", strerror(errno));
+              /* For JPEG, reaching EOF after the first frame is
+               * expected.  Don't treat it as a fatal error — just
+               * stop feeding and wait for the decoder to finish.
+               */
+
+              if (nxcodec_is_jpeg(&codec))
+                {
+                  nxcodec_jpeg_wait_decode(&codec, timeout_ms);
+                  break;
+                }
+
+              printf("nxcodec enqueue frame failed: %s\n",
+                     strerror(errno));
               break;
             }
         }

Reply via email to