Skip to content

Commit edd2421

Browse files
committed
Camera: Viewport and Snapshot
Note: this all uses the Zephyr updates from my PR zephyrproject-rtos/zephyr#93797 Which I added to the STM dcmi driver the ability to have the camera work in snapshot mode instead of in continuous video mode. This allows for example that we start the camera it grabs a frame and stops, we then take the buffer and process it, and repeat this. This helps minimize how much the SDRAM gets used concurrently. In addition, I added to the VIDEO_STM32_DCMI and GC2145 the ability to use some of the new set_selection and get_selection code that was added for the DCMIPP. In particular the DCMI simply forwards these messages to the camera if it defined thise apis... And with this it allows you to setup a viewport into the frame. For example: You can setup the frame on the GC2145 to be 800x600 and then define a view port to be 480x320 to fill an ST7796/ILI9486 tft display or you could do it 400x240 to half fill the GIGA display. You can also move that view port around within the frame (pan) I have examples that do this on Portenta H7 on the ST7796 display and another one that does this on the GIGA display shield. Still WIP as we probably need to refine the APIS and the like Updated with first set of CR changes on the Zephyr side
1 parent cb3531e commit edd2421

File tree

3 files changed

+188
-13
lines changed

3 files changed

+188
-13
lines changed

libraries/Camera/src/camera.cpp

Lines changed: 112 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,21 +31,30 @@ uint32_t FrameBuffer::getBufferSize() {
3131
if (this->vbuf) {
3232
return this->vbuf->bytesused;
3333
}
34+
return 0;
3435
}
3536

3637
uint8_t *FrameBuffer::getBuffer() {
3738
if (this->vbuf) {
3839
return this->vbuf->buffer;
3940
}
41+
return nullptr;
4042
}
4143

42-
Camera::Camera() : vdev(NULL), byte_swap(false), yuv_to_gray(false) {
44+
Camera::Camera()
45+
: vdev(NULL), byte_swap(false), yuv_to_gray(false),
46+
snapshot_mode(CONFIG_VIDEO_BUFFER_POOL_NUM_MAX <= 1) {
4347
for (size_t i = 0; i < ARRAY_SIZE(this->vbuf); i++) {
4448
this->vbuf[i] = NULL;
4549
}
4650
}
4751

4852
bool Camera::begin(uint32_t width, uint32_t height, uint32_t pixformat, bool byte_swap) {
53+
return begin(width, height, width, height, pixformat, byte_swap);
54+
}
55+
56+
bool Camera::begin(uint32_t width, uint32_t height, uint32_t crop_width, uint32_t crop_height,
57+
uint32_t pixformat, bool byte_swap) {
4958
#if DT_HAS_CHOSEN(zephyr_camera)
5059
this->vdev = DEVICE_DT_GET(DT_CHOSEN(zephyr_camera));
5160
#endif
@@ -74,20 +83,21 @@ bool Camera::begin(uint32_t width, uint32_t height, uint32_t pixformat, bool byt
7483
return false;
7584
}
7685

77-
for (size_t i = 0; caps.format_caps[i].pixelformat != NULL; i++) {
86+
for (size_t i = 0; caps.format_caps[i].pixelformat != 0; i++) {
7887
const struct video_format_cap *fcap = &caps.format_caps[i];
79-
if (fcap->width_min == width && fcap->height_min == height &&
80-
fcap->pixelformat == pixformat) {
88+
if (fcap->width_min <= width && fcap->width_max >= width && fcap->height_min <= height &&
89+
fcap->height_max >= height && fcap->pixelformat == pixformat) {
8190
break;
8291
}
83-
if (caps.format_caps[i + 1].pixelformat == NULL) {
92+
if (caps.format_caps[i + 1].pixelformat == 0) {
8493
Serial.println("The specified format is not supported");
8594
return false;
8695
}
8796
}
8897

8998
// Set format.
9099
static struct video_format fmt = {
100+
.type = VIDEO_BUF_TYPE_OUTPUT,
91101
.pixelformat = pixformat,
92102
.width = width,
93103
.height = height,
@@ -99,6 +109,34 @@ bool Camera::begin(uint32_t width, uint32_t height, uint32_t pixformat, bool byt
99109
return false;
100110
}
101111

112+
// optionally set the crop values
113+
if (width != crop_width || height != crop_height) {
114+
struct video_selection vselCrop;
115+
vselCrop.type = VIDEO_BUF_TYPE_OUTPUT;
116+
vselCrop.target = VIDEO_SEL_TGT_CROP;
117+
vselCrop.rect.left = (width - crop_width) / 2;
118+
vselCrop.rect.top = (height - crop_height) / 2;
119+
vselCrop.rect.width = crop_width;
120+
vselCrop.rect.height = crop_height;
121+
;
122+
123+
int ret;
124+
if ((ret = setSelection(&vselCrop)) != 0) {
125+
printk("ERROR: %d\n", ret);
126+
}
127+
}
128+
// this should compute the sizes needed.
129+
video_get_format(this->vdev, &fmt);
130+
131+
// If we are in snapshot mode, try starting the video stream with no buffers
132+
// to tell it that we want snapshot...
133+
if (snapshot_mode) {
134+
if (video_stream_start(this->vdev, VIDEO_BUF_TYPE_OUTPUT)) {
135+
Serial.println("Snapshot mode Failed to start capture");
136+
// return false;
137+
}
138+
}
139+
102140
// Allocate video buffers.
103141
for (size_t i = 0; i < ARRAY_SIZE(this->vbuf); i++) {
104142
this->vbuf[i] = video_buffer_aligned_alloc(fmt.pitch * fmt.height,
@@ -111,23 +149,24 @@ bool Camera::begin(uint32_t width, uint32_t height, uint32_t pixformat, bool byt
111149
}
112150

113151
// Start video capture
114-
if (video_stream_start(this->vdev, VIDEO_BUF_TYPE_OUTPUT)) {
115-
Serial.println("Failed to start capture");
116-
return false;
152+
if (!snapshot_mode) {
153+
if (video_stream_start(this->vdev, VIDEO_BUF_TYPE_OUTPUT)) {
154+
Serial.println("Failed to start capture");
155+
return false;
156+
}
117157
}
118-
119158
return true;
120159
}
121160

122161
bool Camera::grabFrame(FrameBuffer &fb, uint32_t timeout) {
123162
if (this->vdev == NULL) {
124163
return false;
125164
}
126-
165+
// printk("Camera::grabFrame called\n");
127166
if (video_dequeue(this->vdev, &fb.vbuf, K_MSEC(timeout))) {
128167
return false;
129168
}
130-
169+
// printk("video_dequeue returned :%p\n", fb.vbuf->buffer);
131170
if (this->byte_swap) {
132171
uint16_t *pixels = (uint16_t *)fb.vbuf->buffer;
133172
for (size_t i = 0; i < fb.vbuf->bytesused / 2; i++) {
@@ -151,6 +190,13 @@ bool Camera::releaseFrame(FrameBuffer &fb) {
151190
return false;
152191
}
153192

193+
int ret;
194+
// printk("Camera::ReleaseFrame called\n");
195+
if ((ret = video_enqueue(this->vdev, fb.vbuf)) != 0) {
196+
printk("Failed to enqueue buffer %d\n", ret);
197+
return false;
198+
}
199+
154200
if (video_enqueue(this->vdev, fb.vbuf)) {
155201
return false;
156202
}
@@ -167,3 +213,58 @@ bool Camera::setHorizontalMirror(bool mirror_enable) {
167213
struct video_control ctrl = {.id = VIDEO_CID_HFLIP, .val = mirror_enable};
168214
return video_set_ctrl(this->vdev, &ctrl) == 0;
169215
}
216+
217+
int Camera::setSelection(struct video_selection *sel) {
218+
return video_set_selection(vdev, sel);
219+
}
220+
221+
/**
222+
* @brief Get video selection (crop/compose).
223+
*
224+
* Retrieve the current settings related to the crop and compose of the video device.
225+
* This can also be used to read the native size of the input stream of the video
226+
* device.
227+
* This function can be used to read crop / compose capabilities of the device prior
228+
* to performing configuration via the @ref video_set_selection api.
229+
*
230+
* @param sel Pointer to a video selection structure, @c type and @c target set by the caller
231+
*
232+
* @retval 0 Is successful.
233+
* @retval -EINVAL If parameters are invalid.
234+
* @retval -ENOTSUP If format is not supported.
235+
* @retval -EIO General input / output error.
236+
*/
237+
int Camera::getSelection(struct video_selection *sel) {
238+
return video_get_selection(vdev, sel);
239+
}
240+
241+
/**
242+
* @brief returns if snapshot mode is turned on or off.
243+
*
244+
* @param snapshot_mode pointer to Turn Snaphsot mode on or off..
245+
*/
246+
bool Camera::getSnapshotMode() {
247+
return snapshot_mode;
248+
}
249+
250+
/**
251+
* @brief returns if snapshot mode is turned on or off.
252+
*
253+
* Must be called before begin to take effect.
254+
*
255+
* @param snap_shot mode if true.
256+
*
257+
* @retval 0 is successful.
258+
*/
259+
int Camera::setSnapshotMode(bool snap_shot) {
260+
if (snap_shot) {
261+
snapshot_mode = snap_shot;
262+
return 0;
263+
} else {
264+
#if CONFIG_VIDEO_BUFFER_POOL_NUM_MAX <= 1
265+
return -EINVAL;
266+
#endif
267+
snapshot_mode = snap_shot;
268+
return 0;
269+
}
270+
}

libraries/Camera/src/camera.h

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ class FrameBuffer {
6363
friend class Camera;
6464
};
6565

66+
// bugbug temporary
67+
#include <zephyr/drivers/video.h>
68+
6669
/**
6770
* @class Camera
6871
* @brief The main class for controlling a camera.
@@ -92,6 +95,20 @@ class Camera {
9295
bool begin(uint32_t width, uint32_t height, uint32_t pixformat = CAMERA_RGB565,
9396
bool byte_swap = false);
9497

98+
/**
99+
* @brief Initialize the camera.
100+
*
101+
* @param width Frame width in pixels.
102+
* @param height Frame height in pixels.
103+
* @param crop_width crop width in pixels.
104+
* @param crop_height crop height in pixels.
105+
* @param pixformat Initial pixel format (default: CAMERA_RGB565).
106+
* @param byte_swap Enable byte swapping (default: false).
107+
* @return true if the camera is successfully initialized, otherwise false.
108+
*/
109+
bool begin(uint32_t width, uint32_t height, uint32_t crop_width, uint32_t crop_height,
110+
uint32_t pixformat = CAMERA_RGB565, bool byte_swap = false);
111+
95112
/**
96113
* @brief Capture a frame.
97114
*
@@ -124,6 +141,62 @@ class Camera {
124141
* @return true on success, false on failure.
125142
*/
126143
bool setHorizontalMirror(bool mirror_enable);
144+
145+
/* Experiments to be able to set crop and the like */
146+
/**
147+
* @brief Set video selection (crop/compose).
148+
*
149+
* Configure the optional crop and compose feature of a video device.
150+
* Crop is first applied on the input frame, and the result of that crop is applied
151+
* to the compose. The result of the compose (width/height) is equal to the format
152+
* width/height given to the @ref video_set_format function.
153+
*
154+
* Some targets are inter-dependents. For instance, setting a @ref VIDEO_SEL_TGT_CROP will
155+
* reset @ref VIDEO_SEL_TGT_COMPOSE to the same size.
156+
*
157+
* @param sel Pointer to a video selection structure
158+
*
159+
* @retval 0 Is successful.
160+
* @retval -EINVAL If parameters are invalid.
161+
* @retval -ENOTSUP If format is not supported.
162+
* @retval -EIO General input / output error.
163+
*/
164+
int setSelection(struct video_selection *sel);
165+
/**
166+
* @brief Get video selection (crop/compose).
167+
*
168+
* Retrieve the current settings related to the crop and compose of the video device.
169+
* This can also be used to read the native size of the input stream of the video
170+
* device.
171+
* This function can be used to read crop / compose capabilities of the device prior
172+
* to performing configuration via the @ref video_set_selection api.
173+
*
174+
* @param sel Pointer to a video selection structure, @c type and @c target set by the caller
175+
*
176+
* @retval 0 Is successful.
177+
* @retval -EINVAL If parameters are invalid.
178+
* @retval -ENOTSUP If format is not supported.
179+
* @retval -EIO General input / output error.
180+
*/
181+
int getSelection(struct video_selection *sel);
182+
183+
/**
184+
* @brief returns if snapshot mode is turned on or off.
185+
*
186+
* @retval true if in snapshot mode false otherwise.
187+
*/
188+
bool getSnapshotMode();
189+
190+
/**
191+
* @brief returns if snapshot mode is turned on or off.
192+
*
193+
* Must be called before begin to take effect.
194+
*
195+
* @param snap_shot mode if true.
196+
*
197+
* @retval 0 is successful.
198+
*/
199+
int setSnapshotMode(bool snap_shot);
127200
};
128201

129202
#endif // __CAMERA_H__

variants/arduino_giga_r1_stm32h747xx_m7/arduino_giga_r1_stm32h747xx_m7.conf

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ CONFIG_ENTROPY_GENERATOR=y
3636
CONFIG_TEST_RANDOM_GENERATOR=y
3737

3838
CONFIG_VIDEO=y
39-
CONFIG_VIDEO_LOG_LEVEL_DBG=y
39+
CONFIG_VIDEO_LOG_LEVEL_DBG=n
4040
CONFIG_VIDEO_STM32_DCMI=y
41-
CONFIG_VIDEO_BUFFER_POOL_NUM_MAX=3
41+
CONFIG_VIDEO_BUFFER_POOL_NUM_MAX=1
4242
CONFIG_VIDEO_BUFFER_POOL_SZ_MAX=614400
4343
CONFIG_VIDEO_BUFFER_POOL_ALIGN=32
4444
CONFIG_VIDEO_BUFFER_USE_SHARED_MULTI_HEAP=y
@@ -63,6 +63,7 @@ CONFIG_BT_CTLR_ADV_EXT=y
6363
CONFIG_BT_CTLR_ADV_PERIODIC=y
6464
CONFIG_BT_CTLR_DTM_HCI=y
6565
CONFIG_CYW4343W_MURATA_1DX=y
66+
CONFIG_BT_HCI_DRIVER_LOG_LEVEL_DBG=n
6667
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
6768
CONFIG_BT_RX_STACK_SIZE=4096
6869
CONFIG_BT_HCI_TX_STACK_SIZE=4096

0 commit comments

Comments
 (0)