6
6
7
7
#include <zephyr/device.h>
8
8
#include <zephyr/drivers/video.h>
9
+ #include <zephyr/drivers/video-controls.h>
9
10
#include <zephyr/kernel.h>
10
11
#include <zephyr/logging/log.h>
11
12
#include <zephyr/net/socket.h>
@@ -36,11 +37,22 @@ int main(void)
36
37
socklen_t client_addr_len = sizeof (client_addr );
37
38
struct video_buffer * buffers [2 ];
38
39
struct video_buffer * vbuf = & (struct video_buffer ){};
39
- int i , ret , sock , client ;
40
+ int ret , sock , client ;
40
41
struct video_format fmt ;
41
42
struct video_caps caps ;
43
+ struct video_frmival frmival ;
44
+ struct video_frmival_enum fie ;
42
45
enum video_buf_type type = VIDEO_BUF_TYPE_OUTPUT ;
43
46
const struct device * video_dev ;
47
+ #if (CONFIG_VIDEO_SOURCE_CROP_WIDTH && CONFIG_VIDEO_SOURCE_CROP_HEIGHT ) || \
48
+ CONFIG_VIDEO_FRAME_HEIGHT || CONFIG_VIDEO_FRAME_WIDTH
49
+ struct video_selection sel = {
50
+ .type = VIDEO_BUF_TYPE_OUTPUT ,
51
+ };
52
+ #endif
53
+ size_t bsize ;
54
+ int i = 0 ;
55
+ int err ;
44
56
45
57
video_dev = DEVICE_DT_GET (DT_CHOSEN (zephyr_camera ));
46
58
if (!device_is_ready (video_dev )) {
@@ -80,6 +92,17 @@ int main(void)
80
92
return 0 ;
81
93
}
82
94
95
+ LOG_INF ("- Capabilities:" );
96
+ while (caps .format_caps [i ].pixelformat ) {
97
+ const struct video_format_cap * fcap = & caps .format_caps [i ];
98
+ /* fourcc to string */
99
+ LOG_INF (" %s width [%u; %u; %u] height [%u; %u; %u]" ,
100
+ VIDEO_FOURCC_TO_STR (fcap -> pixelformat ),
101
+ fcap -> width_min , fcap -> width_max , fcap -> width_step ,
102
+ fcap -> height_min , fcap -> height_max , fcap -> height_step );
103
+ i ++ ;
104
+ }
105
+
83
106
/* Get default/native format */
84
107
fmt .type = type ;
85
108
if (video_get_format (video_dev , & fmt )) {
@@ -95,9 +118,134 @@ int main(void)
95
118
return 0 ;
96
119
}
97
120
121
+ /* Set the crop setting if necessary */
122
+ #if CONFIG_VIDEO_SOURCE_CROP_WIDTH && CONFIG_VIDEO_SOURCE_CROP_HEIGHT
123
+ sel .target = VIDEO_SEL_TGT_CROP ;
124
+ sel .rect .left = CONFIG_VIDEO_SOURCE_CROP_LEFT ;
125
+ sel .rect .top = CONFIG_VIDEO_SOURCE_CROP_TOP ;
126
+ sel .rect .width = CONFIG_VIDEO_SOURCE_CROP_WIDTH ;
127
+ sel .rect .height = CONFIG_VIDEO_SOURCE_CROP_HEIGHT ;
128
+ if (video_set_selection (video_dev , & sel )) {
129
+ LOG_ERR ("Unable to set selection crop" );
130
+ return 0 ;
131
+ }
132
+ LOG_INF ("Selection crop set to (%u,%u)/%ux%u" ,
133
+ sel .rect .left , sel .rect .top , sel .rect .width , sel .rect .height );
134
+ #endif
135
+
136
+ #if CONFIG_VIDEO_FRAME_HEIGHT || CONFIG_VIDEO_FRAME_WIDTH
137
+ #if CONFIG_VIDEO_FRAME_HEIGHT
138
+ fmt .height = CONFIG_VIDEO_FRAME_HEIGHT ;
139
+ #endif
140
+
141
+ #if CONFIG_VIDEO_FRAME_WIDTH
142
+ fmt .width = CONFIG_VIDEO_FRAME_WIDTH ;
143
+ #endif
144
+
145
+ /*
146
+ * Check (if possible) if targeted size is same as crop
147
+ * and if compose is necessary
148
+ */
149
+ sel .target = VIDEO_SEL_TGT_CROP ;
150
+ err = video_get_selection (video_dev , & sel );
151
+ if (err < 0 && err != - ENOSYS ) {
152
+ LOG_ERR ("Unable to get selection crop" );
153
+ return 0 ;
154
+ }
155
+
156
+ if (err == 0 && (sel .rect .width != fmt .width || sel .rect .height != fmt .height )) {
157
+ sel .target = VIDEO_SEL_TGT_COMPOSE ;
158
+ sel .rect .left = 0 ;
159
+ sel .rect .top = 0 ;
160
+ sel .rect .width = fmt .width ;
161
+ sel .rect .height = fmt .height ;
162
+ err = video_set_selection (video_dev , & sel );
163
+ if (err < 0 && err != - ENOSYS ) {
164
+ LOG_ERR ("Unable to set selection compose" );
165
+ return 0 ;
166
+ }
167
+ }
168
+ #endif
169
+
170
+ if (strcmp (CONFIG_VIDEO_PIXEL_FORMAT , "" )) {
171
+ fmt .pixelformat = VIDEO_FOURCC_FROM_STR (CONFIG_VIDEO_PIXEL_FORMAT );
172
+ }
173
+
174
+ LOG_INF ("- Video format: %s %ux%u" ,
175
+ VIDEO_FOURCC_TO_STR (fmt .pixelformat ), fmt .width , fmt .height );
176
+
177
+ if (video_set_format (video_dev , & fmt )) {
178
+ LOG_ERR ("Unable to set format" );
179
+ return 0 ;
180
+ }
181
+
182
+ if (!video_get_frmival (video_dev , & frmival )) {
183
+ LOG_INF ("- Default frame rate : %f fps" ,
184
+ 1.0 * frmival .denominator / frmival .numerator );
185
+ }
186
+
187
+ LOG_INF ("- Supported frame intervals for the default format:" );
188
+ memset (& fie , 0 , sizeof (fie ));
189
+ fie .format = & fmt ;
190
+ while (video_enum_frmival (video_dev , & fie ) == 0 ) {
191
+ if (fie .type == VIDEO_FRMIVAL_TYPE_DISCRETE ) {
192
+ LOG_INF (" %u/%u" , fie .discrete .numerator , fie .discrete .denominator );
193
+ } else {
194
+ LOG_INF (" [min = %u/%u; max = %u/%u; step = %u/%u]" ,
195
+ fie .stepwise .min .numerator , fie .stepwise .min .denominator ,
196
+ fie .stepwise .max .numerator , fie .stepwise .max .denominator ,
197
+ fie .stepwise .step .numerator , fie .stepwise .step .denominator );
198
+ }
199
+ fie .index ++ ;
200
+ }
201
+
202
+ /* Get supported controls */
203
+ LOG_INF ("- Supported controls:" );
204
+ const struct device * last_dev = NULL ;
205
+ struct video_ctrl_query cq = {.dev = video_dev , .id = VIDEO_CTRL_FLAG_NEXT_CTRL };
206
+
207
+ while (!video_query_ctrl (& cq )) {
208
+ if (cq .dev != last_dev ) {
209
+ last_dev = cq .dev ;
210
+ LOG_INF ("\t\tdevice: %s" , cq .dev -> name );
211
+ }
212
+ video_print_ctrl (& cq );
213
+ cq .id |= VIDEO_CTRL_FLAG_NEXT_CTRL ;
214
+ }
215
+
216
+ /* Set controls */
217
+ struct video_control ctrl = {.id = VIDEO_CID_HFLIP , .val = 1 };
218
+ int tp_set_ret = - ENOTSUP ;
219
+
220
+ if (IS_ENABLED (CONFIG_VIDEO_CTRL_HFLIP )) {
221
+ video_set_ctrl (video_dev , & ctrl );
222
+ }
223
+
224
+ if (IS_ENABLED (CONFIG_VIDEO_CTRL_VFLIP )) {
225
+ ctrl .id = VIDEO_CID_VFLIP ;
226
+ video_set_ctrl (video_dev , & ctrl );
227
+ }
228
+
229
+ if (IS_ENABLED (CONFIG_TEST )) {
230
+ ctrl .id = VIDEO_CID_TEST_PATTERN ;
231
+ tp_set_ret = video_set_ctrl (video_dev , & ctrl );
232
+ }
233
+
234
+ /* Size to allocate for each buffer */
235
+ if (caps .min_line_count == LINE_COUNT_HEIGHT ) {
236
+ bsize = fmt .pitch * fmt .height ;
237
+ } else {
238
+ bsize = fmt .pitch * caps .min_line_count ;
239
+ }
240
+
98
241
/* Alloc Buffers */
99
242
for (i = 0 ; i < ARRAY_SIZE (buffers ); i ++ ) {
100
- buffers [i ] = video_buffer_alloc (fmt .pitch * fmt .height , K_FOREVER );
243
+ /*
244
+ * For some hardwares, such as the PxP used on i.MX RT1170 to do image rotation,
245
+ * buffer alignment is needed in order to achieve the best performance
246
+ */
247
+ buffers [i ] = video_buffer_aligned_alloc (bsize , CONFIG_VIDEO_BUFFER_POOL_ALIGN ,
248
+ K_FOREVER );
101
249
if (buffers [i ] == NULL ) {
102
250
LOG_ERR ("Unable to alloc video buffer" );
103
251
return 0 ;
0 commit comments