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