Skip to content

Commit 54fdda5

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 1821cb9 commit 54fdda5

File tree

3 files changed

+188
-16
lines changed

3 files changed

+188
-16
lines changed

libraries/Camera/src/camera.cpp

Lines changed: 109 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,21 +32,29 @@ uint32_t FrameBuffer::getBufferSize() {
3232
if (this->vbuf) {
3333
return this->vbuf->bytesused;
3434
}
35+
return 0;
3536
}
3637

3738
uint8_t* FrameBuffer::getBuffer() {
3839
if (this->vbuf) {
3940
return this->vbuf->buffer;
4041
}
42+
return nullptr;
4143
}
4244

43-
Camera::Camera() : vdev(NULL), byte_swap(false), yuv_to_gray(false) {
45+
Camera::Camera() : vdev(NULL), byte_swap(false), yuv_to_gray(false),
46+
snapshot_mode(CONFIG_VIDEO_BUFFER_POOL_NUM_MAX <= 1) {
4447
for (size_t i = 0; i < ARRAY_SIZE(this->vbuf); i++) {
4548
this->vbuf[i] = NULL;
4649
}
4750
}
4851

52+
4953
bool Camera::begin(uint32_t width, uint32_t height, uint32_t pixformat, bool byte_swap) {
54+
return begin(width, height, width, height, pixformat, byte_swap);
55+
}
56+
57+
bool Camera::begin(uint32_t width, uint32_t height, uint32_t crop_width, uint32_t crop_height, uint32_t pixformat, bool byte_swap) {
5058
#if DT_HAS_CHOSEN(zephyr_camera)
5159
this->vdev = DEVICE_DT_GET(DT_CHOSEN(zephyr_camera));
5260
#endif
@@ -75,21 +83,22 @@ bool Camera::begin(uint32_t width, uint32_t height, uint32_t pixformat, bool byt
7583
return false;
7684
}
7785

78-
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++) {
7987
const struct video_format_cap *fcap = &caps.format_caps[i];
80-
if (fcap->width_min == width &&
81-
fcap->height_min == height &&
88+
if (fcap->width_min <= width && fcap->width_max >= width &&
89+
fcap->height_min <= height && fcap->height_max >= height &&
8290
fcap->pixelformat == pixformat) {
8391
break;
8492
}
85-
if (caps.format_caps[i+1].pixelformat == NULL) {
93+
if (caps.format_caps[i+1].pixelformat == 0) {
8694
Serial.println("The specified format is not supported");
8795
return false;
8896
}
8997
}
9098

9199
// Set format.
92100
static struct video_format fmt = {
101+
.type = VIDEO_BUF_TYPE_OUTPUT,
93102
.pixelformat = pixformat,
94103
.width = width,
95104
.height = height,
@@ -101,6 +110,34 @@ bool Camera::begin(uint32_t width, uint32_t height, uint32_t pixformat, bool byt
101110
return false;
102111
}
103112

113+
// optionally set the crop values
114+
if (width != crop_width || height != crop_height) {
115+
struct video_selection vselCrop;
116+
vselCrop.type = VIDEO_BUF_TYPE_OUTPUT;
117+
vselCrop.target = VIDEO_SEL_TGT_CROP;
118+
vselCrop.rect.left = (width - crop_width) / 2;
119+
vselCrop.rect.top = (height - crop_height) / 2;
120+
vselCrop.rect.width = crop_width;
121+
vselCrop.rect.height = crop_height;;
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+
132+
// If we are in snapshot mode, try starting the video stream with no buffers
133+
// to tell it that we want snapshot...
134+
if (snapshot_mode) {
135+
if (video_stream_start(this->vdev, VIDEO_BUF_TYPE_OUTPUT)) {
136+
Serial.println("Snapshot mode Failed to start capture");
137+
//return false;
138+
}
139+
}
140+
104141
// Allocate video buffers.
105142
for (size_t i = 0; i < ARRAY_SIZE(this->vbuf); i++) {
106143
this->vbuf[i] = video_buffer_aligned_alloc(fmt.pitch * fmt.height,
@@ -114,23 +151,24 @@ bool Camera::begin(uint32_t width, uint32_t height, uint32_t pixformat, bool byt
114151
}
115152

116153
// Start video capture
117-
if (video_stream_start(this->vdev, VIDEO_BUF_TYPE_OUTPUT)) {
118-
Serial.println("Failed to start capture");
119-
return false;
120-
}
121-
154+
if (!snapshot_mode) {
155+
if (video_stream_start(this->vdev, VIDEO_BUF_TYPE_OUTPUT)) {
156+
Serial.println("Failed to start capture");
157+
return false;
158+
}
159+
}
122160
return true;
123161
}
124162

125163
bool Camera::grabFrame(FrameBuffer &fb, uint32_t timeout) {
126164
if (this->vdev == NULL) {
127165
return false;
128166
}
129-
167+
//printk("Camera::grabFrame called\n");
130168
if (video_dequeue(this->vdev, &fb.vbuf, K_MSEC(timeout))) {
131169
return false;
132170
}
133-
171+
//printk("video_dequeue returned :%p\n", fb.vbuf->buffer);
134172
if (this->byte_swap) {
135173
uint16_t *pixels = (uint16_t *) fb.vbuf->buffer;
136174
for (size_t i=0; i<fb.vbuf->bytesused / 2; i++) {
@@ -154,7 +192,10 @@ bool Camera::releaseFrame(FrameBuffer &fb) {
154192
return false;
155193
}
156194

157-
if (video_enqueue(this->vdev, fb.vbuf)) {
195+
int ret;
196+
//printk("Camera::ReleaseFrame called\n");
197+
if ((ret = video_enqueue(this->vdev, fb.vbuf)) != 0) {
198+
printk("Failed to enqueue buffer %d\n", ret);
158199
return false;
159200
}
160201

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

libraries/Camera/src/camera.h

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,20 @@ class FrameBuffer {
6262
friend class Camera;
6363
};
6464

65+
66+
// bugbug temporary
67+
#include <zephyr/drivers/video.h>
68+
6569
/**
6670
* @class Camera
6771
* @brief The main class for controlling a camera.
6872
*/
6973
class Camera {
7074
private:
75+
const struct device *vdev;
7176
bool byte_swap;
7277
bool yuv_to_gray;
73-
const struct device *vdev;
78+
bool snapshot_mode;
7479
struct video_buffer *vbuf[CONFIG_VIDEO_BUFFER_POOL_NUM_MAX];
7580

7681
public:
@@ -90,6 +95,19 @@ class Camera {
9095
*/
9196
bool begin(uint32_t width, uint32_t height, uint32_t pixformat = CAMERA_RGB565, bool byte_swap = false);
9297

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, uint32_t pixformat = CAMERA_RGB565, bool byte_swap = false);
110+
93111
/**
94112
* @brief Capture a frame.
95113
*
@@ -122,6 +140,63 @@ class Camera {
122140
* @return true on success, false on failure.
123141
*/
124142
bool setHorizontalMirror(bool mirror_enable);
143+
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);
125200
};
126201

127202
#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
@@ -35,9 +35,9 @@ CONFIG_ENTROPY_GENERATOR=y
3535
CONFIG_TEST_RANDOM_GENERATOR=y
3636

3737
CONFIG_VIDEO=y
38-
CONFIG_VIDEO_LOG_LEVEL_DBG=y
38+
CONFIG_VIDEO_LOG_LEVEL_DBG=n
3939
CONFIG_VIDEO_STM32_DCMI=y
40-
CONFIG_VIDEO_BUFFER_POOL_NUM_MAX=3
40+
CONFIG_VIDEO_BUFFER_POOL_NUM_MAX=1
4141
CONFIG_VIDEO_BUFFER_POOL_SZ_MAX=614400
4242
CONFIG_VIDEO_BUFFER_POOL_ALIGN=32
4343
CONFIG_VIDEO_BUFFER_USE_SHARED_MULTI_HEAP=y
@@ -61,6 +61,7 @@ CONFIG_BT_CTLR_ADV_EXT=y
6161
CONFIG_BT_CTLR_ADV_PERIODIC=y
6262
CONFIG_BT_CTLR_DTM_HCI=y
6363
CONFIG_CYW4343W_MURATA_1DX=y
64+
CONFIG_BT_HCI_DRIVER_LOG_LEVEL_DBG=n
6465
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
6566
CONFIG_BT_RX_STACK_SIZE=4096
6667
CONFIG_BT_HCI_TX_STACK_SIZE=4096

0 commit comments

Comments
 (0)