1 /*
2 * Copyright (c) 2024 Charles Dias <charlesdias.cd@outlook.com>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/device.h>
9 #include <zephyr/drivers/display.h>
10 #include <zephyr/drivers/video.h>
11 #include <zephyr/drivers/video-controls.h>
12 #include <lvgl.h>
13
14 #define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_REGISTER(main);
17
18 #define VIDEO_DEV_SW "VIDEO_SW_GENERATOR"
19
main(void)20 int main(void)
21 {
22 struct video_buffer *buffers[2], *vbuf;
23 const struct device *display_dev;
24 struct video_format fmt;
25 struct video_caps caps;
26 const struct device *video_dev;
27 size_t bsize;
28 int i = 0;
29
30 display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));
31 if (!device_is_ready(display_dev)) {
32 LOG_ERR("Device not ready, aborting test");
33 return 0;
34 }
35
36 #if DT_HAS_CHOSEN(zephyr_camera)
37 video_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_camera));
38 if (!device_is_ready(video_dev)) {
39 LOG_ERR("%s device is not ready", video_dev->name);
40 return 0;
41 }
42 #else
43 video_dev = device_get_binding(VIDEO_DEV_SW);
44 if (video_dev == NULL) {
45 LOG_ERR("%s device not found", VIDEO_DEV_SW);
46 return 0;
47 }
48 #endif
49
50 LOG_INF("- Device name: %s", video_dev->name);
51
52 /* Get capabilities */
53 if (video_get_caps(video_dev, VIDEO_EP_OUT, &caps)) {
54 LOG_ERR("Unable to retrieve video capabilities");
55 return 0;
56 }
57
58 LOG_INF("- Capabilities:");
59 while (caps.format_caps[i].pixelformat) {
60 const struct video_format_cap *fcap = &caps.format_caps[i];
61 /* four %c to string */
62 LOG_INF(" %c%c%c%c width [%u; %u; %u] height [%u; %u; %u]",
63 (char)fcap->pixelformat, (char)(fcap->pixelformat >> 8),
64 (char)(fcap->pixelformat >> 16), (char)(fcap->pixelformat >> 24),
65 fcap->width_min, fcap->width_max, fcap->width_step, fcap->height_min,
66 fcap->height_max, fcap->height_step);
67 i++;
68 }
69
70 /* Get default/native format */
71 if (video_get_format(video_dev, VIDEO_EP_OUT, &fmt)) {
72 LOG_ERR("Unable to retrieve video format");
73 return 0;
74 }
75
76 /* Set format */
77 fmt.width = CONFIG_VIDEO_WIDTH;
78 fmt.height = CONFIG_VIDEO_HEIGHT;
79 fmt.pitch = fmt.width * 2;
80 fmt.pixelformat = VIDEO_PIX_FMT_RGB565;
81
82 if (video_set_format(video_dev, VIDEO_EP_OUT, &fmt)) {
83 LOG_ERR("Unable to set up video format");
84 return 0;
85 }
86
87 LOG_INF("- Format: %c%c%c%c %ux%u %u", (char)fmt.pixelformat, (char)(fmt.pixelformat >> 8),
88 (char)(fmt.pixelformat >> 16), (char)(fmt.pixelformat >> 24), fmt.width, fmt.height,
89 fmt.pitch);
90
91 if (caps.min_line_count != LINE_COUNT_HEIGHT) {
92 LOG_ERR("Partial framebuffers not supported by this sample");
93 return 0;
94 }
95 /* Size to allocate for each buffer */
96 bsize = fmt.pitch * fmt.height;
97
98 /* Alloc video buffers and enqueue for capture */
99 for (i = 0; i < ARRAY_SIZE(buffers); i++) {
100 buffers[i] = video_buffer_alloc(bsize, K_FOREVER);
101 if (buffers[i] == NULL) {
102 LOG_ERR("Unable to alloc video buffer");
103 return 0;
104 }
105
106 video_enqueue(video_dev, VIDEO_EP_OUT, buffers[i]);
107 }
108
109 #ifdef CONFIG_VIDEO_HFLIP
110 /* Video flip image horizontally */
111 if (video_set_ctrl(video_dev, VIDEO_CID_HFLIP, (void *)1)) {
112 LOG_ERR("Unable to set video control (HFLIP)");
113 return 0;
114 }
115 #endif
116
117 #ifdef CONFIG_VIDEO_VFLIP
118 /* Video flip image vertically */
119 if (video_set_ctrl(video_dev, VIDEO_CID_VFLIP, (void *)1)) {
120 LOG_ERR("Unable to set video control (VFLIP)");
121 return 0;
122 }
123 #endif
124
125 /* Start video capture */
126 if (video_stream_start(video_dev)) {
127 LOG_ERR("Unable to start capture (interface)");
128 return 0;
129 }
130
131 display_blanking_off(display_dev);
132
133 const lv_img_dsc_t video_img = {
134 .header.w = CONFIG_VIDEO_WIDTH,
135 .header.h = CONFIG_VIDEO_HEIGHT,
136 .data_size = CONFIG_VIDEO_WIDTH * CONFIG_VIDEO_HEIGHT * sizeof(lv_color_t),
137 .header.cf = LV_COLOR_FORMAT_NATIVE,
138 .data = (const uint8_t *)buffers[0]->buffer,
139 };
140
141 lv_obj_t *screen = lv_img_create(lv_scr_act());
142
143 LOG_INF("- Capture started");
144
145 /* Grab video frames */
146 while (1) {
147 int err;
148
149 err = video_dequeue(video_dev, VIDEO_EP_OUT, &vbuf, K_FOREVER);
150 if (err) {
151 LOG_ERR("Unable to dequeue video buf");
152 return 0;
153 }
154
155 lv_img_set_src(screen, &video_img);
156 lv_obj_align(screen, LV_ALIGN_BOTTOM_LEFT, 0, 0);
157
158 lv_task_handler();
159
160 err = video_enqueue(video_dev, VIDEO_EP_OUT, vbuf);
161 if (err) {
162 LOG_ERR("Unable to requeue video buf");
163 return 0;
164 }
165 }
166 }
167