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; } }
