Skip to content

Commit 62943cf

Browse files
webcam: 2 captures works
1 parent 53d37e7 commit 62943cf

File tree

1 file changed

+85
-48
lines changed

1 file changed

+85
-48
lines changed

c_mpos/src/webcam.c

Lines changed: 85 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,17 @@
2323
#define CAPTURE_HEIGHT 480
2424
#define OUTPUT_WIDTH 240 // Resize to 240x240
2525
#define OUTPUT_HEIGHT 240
26+
#define NUM_BUFFERS 2 // Use 2 buffers for robust streaming
2627

2728
// Webcam object type
2829
typedef struct _webcam_obj_t {
2930
mp_obj_base_t base;
3031
int fd; // File descriptor for the webcam
31-
void *buffer; // Memory-mapped buffer
32-
size_t buffer_length; // Length of the buffer
32+
struct {
33+
void *start; // Memory-mapped buffer
34+
size_t length; // Buffer length
35+
} buffers[NUM_BUFFERS]; // Array of buffers
36+
size_t num_buffers; // Number of allocated buffers
3337
bool streaming; // Streaming state
3438
} webcam_obj_t;
3539

@@ -72,13 +76,27 @@ static mp_obj_t webcam_capture_grayscale(mp_obj_t self_in) {
7276
struct v4l2_buffer buf = {0};
7377
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
7478
buf.memory = V4L2_MEMORY_MMAP;
75-
buf.index = 0;
7679

77-
// Queue the buffer
78-
WEBCAM_DEBUG_PRINT("webcam: Queuing buffer (index=%d)\n", buf.index);
79-
if (ioctl(self->fd, VIDIOC_QBUF, &buf) < 0) {
80-
WEBCAM_DEBUG_PRINT("webcam: Failed to queue buffer for capture (errno=%d)\n", errno);
81-
mp_raise_OSError(errno);
80+
// Find an available buffer
81+
for (size_t i = 0; i < self->num_buffers; i++) {
82+
buf.index = i;
83+
84+
// Query buffer state to ensure it’s not already queued
85+
WEBCAM_DEBUG_PRINT("webcam: Querying buffer state (index=%zu)\n", i);
86+
if (ioctl(self->fd, VIDIOC_QUERYBUF, &buf) < 0) {
87+
WEBCAM_DEBUG_PRINT("webcam: Failed to query buffer state (index=%zu, errno=%d)\n", i, errno);
88+
mp_raise_OSError(errno);
89+
}
90+
91+
// Queue the buffer
92+
WEBCAM_DEBUG_PRINT("webcam: Queuing buffer (index=%zu)\n", i);
93+
if (ioctl(self->fd, VIDIOC_QBUF, &buf) == 0) {
94+
break; // Successfully queued
95+
}
96+
WEBCAM_DEBUG_PRINT("webcam: Failed to queue buffer (index=%zu, errno=%d)\n", i, errno);
97+
if (i == self->num_buffers - 1) {
98+
mp_raise_OSError(errno); // No buffers available
99+
}
82100
}
83101

84102
// Start streaming if not already started
@@ -92,16 +110,16 @@ static mp_obj_t webcam_capture_grayscale(mp_obj_t self_in) {
92110
self->streaming = true;
93111
}
94112

95-
// Dequeue the buffer (capture frame)
96-
memset(&buf, 0, sizeof(buf)); // Clear buffer for dequeue
113+
// Dequeue a buffer (capture frame)
114+
memset(&buf, 0, sizeof(buf));
97115
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
98116
buf.memory = V4L2_MEMORY_MMAP;
99-
buf.index = 0;
100117
WEBCAM_DEBUG_PRINT("webcam: Dequeuing buffer\n");
101118
if (ioctl(self->fd, VIDIOC_DQBUF, &buf) < 0) {
102119
WEBCAM_DEBUG_PRINT("webcam: Failed to dequeue captured frame (errno=%d)\n", errno);
103120
mp_raise_OSError(errno);
104121
}
122+
size_t buf_index = buf.index;
105123

106124
// Convert YUYV to grayscale (640x480)
107125
size_t capture_size = CAPTURE_WIDTH * CAPTURE_HEIGHT;
@@ -110,7 +128,7 @@ static mp_obj_t webcam_capture_grayscale(mp_obj_t self_in) {
110128
WEBCAM_DEBUG_PRINT("webcam: Failed to allocate memory for grayscale buffer (%zu bytes)\n", capture_size);
111129
mp_raise_OSError(ENOMEM);
112130
}
113-
yuyv_to_grayscale((uint8_t *)self->buffer, grayscale_buf, CAPTURE_WIDTH, CAPTURE_HEIGHT);
131+
yuyv_to_grayscale((uint8_t *)self->buffers[buf_index].start, grayscale_buf, CAPTURE_WIDTH, CAPTURE_HEIGHT);
114132

115133
// Resize to 240x240
116134
size_t output_size = OUTPUT_WIDTH * OUTPUT_HEIGHT;
@@ -129,14 +147,14 @@ static mp_obj_t webcam_capture_grayscale(mp_obj_t self_in) {
129147
// Clean up
130148
free(resized_buf);
131149

132-
// Re-queue the buffer for the next capture
133-
memset(&buf, 0, sizeof(buf)); // Clear buffer for re-queue
150+
// Re-queue the buffer
151+
memset(&buf, 0, sizeof(buf));
134152
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
135153
buf.memory = V4L2_MEMORY_MMAP;
136-
buf.index = 0;
137-
WEBCAM_DEBUG_PRINT("webcam: Re-queuing buffer (index=%d)\n", buf.index);
154+
buf.index = buf_index;
155+
WEBCAM_DEBUG_PRINT("webcam: Re-queuing buffer (index=%zu)\n", buf_index);
138156
if (ioctl(self->fd, VIDIOC_QBUF, &buf) < 0) {
139-
WEBCAM_DEBUG_PRINT("webcam: Failed to re-queue buffer after capture (errno=%d)\n", errno);
157+
WEBCAM_DEBUG_PRINT("webcam: Failed to re-queue buffer after capture (index=%zu, errno=%d)\n", buf_index, errno);
140158
mp_raise_OSError(errno);
141159
}
142160

@@ -159,13 +177,16 @@ static mp_obj_t webcam_deinit(mp_obj_t self_in) {
159177
self->streaming = false;
160178
}
161179

162-
// Unmap buffer
163-
if (self->buffer != NULL && self->buffer != MAP_FAILED) {
164-
WEBCAM_DEBUG_PRINT("webcam: Unmapping buffer\n");
165-
munmap(self->buffer, self->buffer_length);
166-
self->buffer = NULL;
167-
self->buffer_length = 0;
180+
// Unmap buffers
181+
for (size_t i = 0; i < self->num_buffers; i++) {
182+
if (self->buffers[i].start != NULL && self->buffers[i].start != MAP_FAILED) {
183+
WEBCAM_DEBUG_PRINT("webcam: Unmapping buffer %zu\n", i);
184+
munmap(self->buffers[i].start, self->buffers[i].length);
185+
self->buffers[i].start = NULL;
186+
self->buffers[i].length = 0;
187+
}
168188
}
189+
self->num_buffers = 0;
169190

170191
// Close device
171192
if (self->fd >= 0) {
@@ -183,9 +204,12 @@ static mp_obj_t webcam_init(void) {
183204
webcam_obj_t *self = m_new_obj(webcam_obj_t);
184205
self->base.type = &webcam_type;
185206
self->fd = -1;
186-
self->buffer = NULL;
187-
self->buffer_length = 0;
207+
self->num_buffers = 0;
188208
self->streaming = false;
209+
for (size_t i = 0; i < NUM_BUFFERS; i++) {
210+
self->buffers[i].start = NULL;
211+
self->buffers[i].length = 0;
212+
}
189213

190214
// Open the webcam device
191215
WEBCAM_DEBUG_PRINT("webcam: Opening device %s\n", VIDEO_DEVICE);
@@ -209,37 +233,50 @@ static mp_obj_t webcam_init(void) {
209233
mp_raise_OSError(errno);
210234
}
211235

212-
// Request one buffer
236+
// Request buffers
213237
struct v4l2_requestbuffers req = {0};
214-
req.count = 1;
238+
req.count = NUM_BUFFERS;
215239
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
216240
req.memory = V4L2_MEMORY_MMAP;
217-
WEBCAM_DEBUG_PRINT("webcam: Requesting one memory-mapped buffer\n");
241+
WEBCAM_DEBUG_PRINT("webcam: Requesting %d memory-mapped buffers\n", NUM_BUFFERS);
218242
if (ioctl(self->fd, VIDIOC_REQBUFS, &req) < 0) {
219-
WEBCAM_DEBUG_PRINT("webcam: Failed to request memory-mapped buffer (errno=%d)\n", errno);
220-
close(self->fd);
221-
mp_raise_OSError(errno);
222-
}
223-
224-
// Query and map the buffer
225-
struct v4l2_buffer buf = {0};
226-
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
227-
buf.memory = V4L2_MEMORY_MMAP;
228-
buf.index = 0;
229-
WEBCAM_DEBUG_PRINT("webcam: Querying buffer properties\n");
230-
if (ioctl(self->fd, VIDIOC_QUERYBUF, &buf) < 0) {
231-
WEBCAM_DEBUG_PRINT("webcam: Failed to query buffer properties (errno=%d)\n", errno);
243+
WEBCAM_DEBUG_PRINT("webcam: Failed to request memory-mapped buffers (errno=%d)\n", errno);
232244
close(self->fd);
233245
mp_raise_OSError(errno);
234246
}
247+
self->num_buffers = req.count;
248+
249+
// Query and map buffers
250+
for (size_t i = 0; i < self->num_buffers; i++) {
251+
struct v4l2_buffer buf = {0};
252+
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
253+
buf.memory = V4L2_MEMORY_MMAP;
254+
buf.index = i;
255+
WEBCAM_DEBUG_PRINT("webcam: Querying buffer %zu properties\n", i);
256+
if (ioctl(self->fd, VIDIOC_QUERYBUF, &buf) < 0) {
257+
WEBCAM_DEBUG_PRINT("webcam: Failed to query buffer %zu properties (errno=%d)\n", i, errno);
258+
for (size_t j = 0; j < i; j++) {
259+
if (self->buffers[j].start != NULL) {
260+
munmap(self->buffers[j].start, self->buffers[j].length);
261+
}
262+
}
263+
close(self->fd);
264+
mp_raise_OSError(errno);
265+
}
235266

236-
self->buffer_length = buf.length;
237-
WEBCAM_DEBUG_PRINT("webcam: Mapping buffer of length %zu\n", self->buffer_length);
238-
self->buffer = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, self->fd, buf.m.offset);
239-
if (self->buffer == MAP_FAILED) {
240-
WEBCAM_DEBUG_PRINT("webcam: Failed to map buffer memory (errno=%d)\n", errno);
241-
close(self->fd);
242-
mp_raise_OSError(errno);
267+
self->buffers[i].length = buf.length;
268+
WEBCAM_DEBUG_PRINT("webcam: Mapping buffer %zu of length %zu\n", i, buf.length);
269+
self->buffers[i].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, self->fd, buf.m.offset);
270+
if (self->buffers[i].start == MAP_FAILED) {
271+
WEBCAM_DEBUG_PRINT("webcam: Failed to map buffer %zu memory (errno=%d)\n", i, errno);
272+
for (size_t j = 0; j < i; j++) {
273+
if (self->buffers[j].start != NULL) {
274+
munmap(self->buffers[j].start, self->buffers[j].length);
275+
}
276+
}
277+
close(self->fd);
278+
mp_raise_OSError(errno);
279+
}
243280
}
244281

245282
// Create a tuple to hold the webcam object and method references

0 commit comments

Comments
 (0)