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 d6b6f39d9b93daf632f3cea1ca00ea521b9c9624 Author: zengshuang <[email protected]> AuthorDate: Sat May 9 14:10:28 2026 +0800 system/nxcamera: add file output support for captured frames Add support for writing captured frames to file when the output command specifies a file path instead of a framebuffer device. - Video file mode (e.g. output /host/video.mjpeg): append each frame to the file continuously until stop is called - Image file mode (e.g. output /host/frame.jpg): save one frame then automatically stop streaming - Optional frame count: output /host/video.mjpeg 10 saves exactly 10 frames then stops (0 or omitted = unlimited) - Skip framebuffer open when file output is configured, fixing -ENOTSUP error on systems without /dev/fb0 Signed-off-by: zengshuang <[email protected]> --- include/system/nxcamera.h | 1 + system/nxcamera/nxcamera.c | 83 +++++++++++++++++++++++++++++++++++++---- system/nxcamera/nxcamera_main.c | 30 +++++++++++++-- 3 files changed, 104 insertions(+), 10 deletions(-) diff --git a/include/system/nxcamera.h b/include/system/nxcamera.h index 4d42dfbfe..45f2c46c3 100644 --- a/include/system/nxcamera.h +++ b/include/system/nxcamera.h @@ -62,6 +62,7 @@ struct nxcamera_s struct fb_videoinfo_s display_vinfo; /* Display video controller info */ char videopath[CONFIG_NAME_MAX]; /* Output video file path */ char imagepath[CONFIG_NAME_MAX]; /* Output image file path */ + uint32_t max_frames; /* Max frames to save (0=unlimited) */ int crefs; /* Number of references */ pthread_mutex_t mutex; /* Thread sync mutex */ char mqname[14]; /* Name of display message queue */ diff --git a/system/nxcamera/nxcamera.c b/system/nxcamera/nxcamera.c index bfc108a4c..c47f27d05 100644 --- a/system/nxcamera/nxcamera.c +++ b/system/nxcamera/nxcamera.c @@ -272,7 +272,13 @@ static int nxcamera_opendevice(FAR struct nxcamera_s *pcam) } else { - /* TODO: Add file output */ + /* File output mode: no display device needed */ + + if (pcam->videopath[0] != '\0' || + pcam->imagepath[0] != '\0') + { + return OK; + } return -ENOTSUP; } @@ -325,6 +331,7 @@ static void *nxcamera_loopthread(pthread_addr_t pvarg) ssize_t size; struct video_msg_s msg; bool streaming = true; + int output_fd = -1; int i; int ret; struct v4l2_buffer buf; @@ -373,6 +380,22 @@ static void *nxcamera_loopthread(pthread_addr_t pvarg) * VIDEO_MSG_DEQUEUE message. */ + /* Open output file before the loop (video mode uses append) */ + + if (pcam->videopath[0] != '\0') + { + output_fd = open(pcam->videopath, + O_WRONLY | O_CREAT | O_APPEND, 0644); + } + else if (pcam->imagepath[0] != '\0') + { + output_fd = open(pcam->imagepath, + O_WRONLY | O_CREAT | O_TRUNC, 0644); + } + + vinfo("output_fd=%d videopath=%s imagepath=%s\n", + output_fd, pcam->videopath, pcam->imagepath); + while (streaming) { size = mq_receive(pcam->mq, (FAR char *)&msg, sizeof(msg), &prio); @@ -411,16 +434,55 @@ static void *nxcamera_loopthread(pthread_addr_t pvarg) goto err_out; } - ret = show_image(pcam, &buf); - if (ret < 0) + if (buf.index >= pcam->nbuffers) { - verr("Fail to show image %d\n", -ret); + verr("Invalid buf.index %d\n", buf.index); goto err_out; } - if (pcam->display_pinfo.yres_virtual > pcam->display_vinfo.yres) + /* Write frame to file if output file is configured */ + + if (output_fd >= 0) { - pan_display(pcam->display_fd, &pcam->display_pinfo); + uint32_t frame_size; + + frame_size = buf.bytesused > 0 ? + buf.bytesused : pcam->buf_sizes[buf.index]; + + ret = write(output_fd, pcam->bufs[buf.index], frame_size); + if (ret != frame_size) + { + verr("write failed: ret=%d frame_size=%" PRIu32 + " errno=%d\n", ret, frame_size, errno); + } + + /* Stop after max_frames if specified (0=unlimited) */ + + if (pcam->max_frames > 0) + { + pcam->max_frames--; + if (pcam->max_frames == 0) + { + streaming = false; + continue; + } + } + } + else + { + ret = show_image(pcam, &buf); + if (ret < 0) + { + verr("Fail to show image %d\n", -ret); + goto err_out; + } + + if (pcam->display_pinfo.yres_virtual > + pcam->display_vinfo.yres) + { + pan_display(pcam->display_fd, + &pcam->display_pinfo); + } } ret = ioctl(pcam->capture_fd, VIDIOC_QBUF, (uintptr_t)&buf); @@ -436,6 +498,13 @@ static void *nxcamera_loopthread(pthread_addr_t pvarg) err_out: vinfo("Clean-up and exit\n"); + /* Close output file if open */ + + if (output_fd >= 0) + { + close(output_fd); + } + /* Cleanup */ pthread_mutex_lock(&pcam->mutex); /* Lock the mutex */ @@ -586,7 +655,7 @@ int nxcamera_setfile(FAR struct nxcamera_s *pcam, FAR const char *pfile, /* Try to open the file */ - temp_fd = open(pfile, O_CREAT | O_RDWR, 0666); + temp_fd = open(pfile, O_CREAT | O_RDWR, 0644); if (temp_fd == -1) { /* Error opening the file */ diff --git a/system/nxcamera/nxcamera_main.c b/system/nxcamera/nxcamera_main.c index 8e56694fe..07656115f 100644 --- a/system/nxcamera/nxcamera_main.c +++ b/system/nxcamera/nxcamera_main.c @@ -124,9 +124,9 @@ static const struct nxcamera_cmd_s g_nxcamera_cmds[] = }, { "output", - "fbdev|filename", + "fbdev|filename [nframes]", nxcamera_cmd_output, - NXCAMERA_HELP_TEXT("Specify a display device or filename") + NXCAMERA_HELP_TEXT("Specify output device or file (nframes=0 unlimited)") }, { "set", @@ -310,7 +310,13 @@ static int nxcamera_cmd_input(FAR struct nxcamera_s *pcam, FAR char *parg) /**************************************************************************** * Name: nxcamera_cmd_output * - * nxcamera_cmd_device() sets the output device/file for display/save. + * nxcamera_cmd_output() sets the output device/file for display/save. + * + * Usage: output <path> [nframes] + * + * - /dev/fbN : display to framebuffer (default) + * - file.jpg/.jpeg : image mode, saves 1 frame (nframes ignored) + * - file.mjpeg/.yuv/… : video mode, nframes (0/omitted=unlimited) * ****************************************************************************/ @@ -319,8 +325,19 @@ static int nxcamera_cmd_output(FAR struct nxcamera_s *pcam, FAR char *parg) int ret; char path[PATH_MAX]; FAR char *ext; + FAR char *space; bool isimage = false; + /* Parse optional frame count after the path */ + + pcam->max_frames = 0; + space = strchr(parg, ' '); + if (space) + { + *space = '\0'; + pcam->max_frames = (uint32_t)atoi(space + 1); + } + /* First try to open the device directly */ ret = nxcamera_setfb(pcam, parg); @@ -351,6 +368,13 @@ static int nxcamera_cmd_output(FAR struct nxcamera_s *pcam, FAR char *parg) } ret = nxcamera_setfile(pcam, parg, isimage); + + /* Image files (.jpg/.jpeg) always save exactly 1 frame */ + + if (isimage) + { + pcam->max_frames = 1; + } } if (ret < 0)
