Skip to content

Commit 21dd308

Browse files
JianyuWang0623acassis
authored andcommitted
examples/camera: handle RGB565X (BE) format from 8-bit DVP camera
Some image sensors on 8-bit DVP buses (e.g. GC0308) produce RGB565X (big-endian) pixel data — the high byte is clocked out first and stored first in PSRAM by the ESP32-S3 CAM controller. The V4L2 framework does not negotiate formats automatically, so try RGB565 first and fall back to RGB565X if S_FMT fails. When the sensor reports RGB565X: - Invalidate D-Cache after DQBUF so the CPU reads fresh DMA data - Byte-swap each pixel in place from BE to LE RGB565 for display Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
1 parent 52b36de commit 21dd308

1 file changed

Lines changed: 46 additions & 5 deletions

File tree

examples/camera/camera_main.c

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838

3939
#include <nuttx/video/video.h>
4040
#include <nuttx/video/v4l2_cap.h>
41+
#include <nuttx/cache.h>
4142

4243
#include "camera_fileutil.h"
4344
#include "camera_bkgd.h"
@@ -85,7 +86,8 @@ static int camera_prepare(int fd, enum v4l2_buf_type type,
8586
uint16_t hsize, uint16_t vsize,
8687
FAR struct v_buffer **vbuf,
8788
uint8_t buffernum, int buffersize,
88-
FAR uint32_t *memory);
89+
FAR uint32_t *memory,
90+
FAR uint32_t *actual_fmt);
8991
static void free_buffer(FAR struct v_buffer *buffers, uint8_t bufnum);
9092
static int parse_arguments(int argc, FAR char *argv[],
9193
FAR int *capture_num,
@@ -121,7 +123,8 @@ static int camera_prepare(int fd, enum v4l2_buf_type type,
121123
uint16_t hsize, uint16_t vsize,
122124
FAR struct v_buffer **vbuf,
123125
uint8_t buffernum, int buffersize,
124-
FAR uint32_t *memory)
126+
FAR uint32_t *memory,
127+
FAR uint32_t *actual_fmt)
125128
{
126129
int ret;
127130
int cnt;
@@ -149,12 +152,27 @@ static int camera_prepare(int fd, enum v4l2_buf_type type,
149152
fmt.fmt.pix.pixelformat = pixformat;
150153

151154
ret = ioctl(fd, VIDIOC_S_FMT, (uintptr_t)&fmt);
155+
if (ret < 0 && pixformat == V4L2_PIX_FMT_RGB565)
156+
{
157+
/* Some sensors on 8-bit DVP output big-endian RGB565 (RGB565X).
158+
* Retry with RGB565X if RGB565 is not supported.
159+
*/
160+
161+
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB565X;
162+
ret = ioctl(fd, VIDIOC_S_FMT, (uintptr_t)&fmt);
163+
}
164+
152165
if (ret < 0)
153166
{
154167
printf("Failed to VIDIOC_S_FMT: errno = %d\n", errno);
155168
return ret;
156169
}
157170

171+
if (actual_fmt)
172+
{
173+
*actual_fmt = fmt.fmt.pix.pixelformat;
174+
}
175+
158176
/* VIDIOC_REQBUFS: try MMAP first (driver-managed DMA buffers).
159177
* Fall back to USERPTR if the driver does not support MMAP.
160178
*/
@@ -518,6 +536,7 @@ int main(int argc, FAR char *argv[])
518536
FAR struct v_buffer *buffers_still = NULL;
519537
uint32_t video_memory = V4L2_MEMORY_USERPTR;
520538
uint32_t still_memory = V4L2_MEMORY_USERPTR;
539+
uint32_t video_pixfmt = V4L2_PIX_FMT_RGB565;
521540

522541
/* ===== Parse and Check arguments ===== */
523542

@@ -607,7 +626,7 @@ int main(int argc, FAR char *argv[])
607626
V4L2_BUF_MODE_FIFO, V4L2_PIX_FMT_JPEG,
608627
w, h,
609628
&buffers_still, STILL_BUFNUM, IMAGE_JPG_SIZE,
610-
&still_memory);
629+
&still_memory, NULL);
611630
if (ret != OK)
612631
{
613632
goto exit_this_app;
@@ -632,7 +651,7 @@ int main(int argc, FAR char *argv[])
632651
V4L2_BUF_MODE_RING, V4L2_PIX_FMT_RGB565,
633652
VIDEO_HSIZE_QVGA, VIDEO_VSIZE_QVGA,
634653
&buffers_video, VIDEO_BUFNUM, IMAGE_RGB_SIZE,
635-
&video_memory);
654+
&video_memory, &video_pixfmt);
636655
if (ret != OK)
637656
{
638657
goto exit_this_app;
@@ -704,13 +723,35 @@ int main(int argc, FAR char *argv[])
704723
case APP_STATE_BEFORE_CAPTURE:
705724
case APP_STATE_AFTER_CAPTURE:
706725
ret = get_camimage(v_fd, &v4l2_buf,
707-
V4L2_BUF_TYPE_VIDEO_CAPTURE, video_memory);
726+
V4L2_BUF_TYPE_VIDEO_CAPTURE, video_memory);
708727
if (ret != OK)
709728
{
710729
goto exit_this_app;
711730
}
712731

713732
#ifdef CONFIG_EXAMPLES_CAMERA_OUTPUT_LCD
733+
/* If the sensor outputs RGB565X (big-endian), invalidate
734+
* D-Cache so we read fresh DMA data from PSRAM, then
735+
* byte-swap in place for display and swap back before
736+
* returning the buffer to the driver.
737+
*/
738+
739+
if (video_pixfmt == V4L2_PIX_FMT_RGB565X)
740+
{
741+
FAR uint16_t *p = (FAR uint16_t *)v4l2_buf.m.userptr;
742+
uint32_t npixels = v4l2_buf.bytesused / 2;
743+
uint32_t i;
744+
745+
up_invalidate_dcache((uintptr_t)p,
746+
(uintptr_t)p + v4l2_buf.bytesused);
747+
748+
for (i = 0; i < npixels; i++)
749+
{
750+
uint16_t v = p[i];
751+
p[i] = (v >> 8) | (v << 8);
752+
}
753+
}
754+
714755
nximage_draw((FAR void *)v4l2_buf.m.userptr,
715756
VIDEO_HSIZE_QVGA, VIDEO_VSIZE_QVGA);
716757
#endif

0 commit comments

Comments
 (0)