Skip to content

Commit d20843c

Browse files
webcam: try 4/infinite buffers (doesn't work)
1 parent 62943cf commit d20843c

File tree

1 file changed

+33
-40
lines changed

1 file changed

+33
-40
lines changed

c_mpos/src/webcam.c

Lines changed: 33 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <linux/videodev2.h>
77
#include <sys/mman.h>
88
#include <string.h>
9+
#include <poll.h>
910

1011
#include "py/obj.h"
1112
#include "py/runtime.h"
@@ -23,7 +24,7 @@
2324
#define CAPTURE_HEIGHT 480
2425
#define OUTPUT_WIDTH 240 // Resize to 240x240
2526
#define OUTPUT_HEIGHT 240
26-
#define NUM_BUFFERS 2 // Use 2 buffers for robust streaming
27+
#define NUM_BUFFERS 4 // Use 4 buffers for continuous streaming
2728

2829
// Webcam object type
2930
typedef struct _webcam_obj_t {
@@ -72,46 +73,16 @@ static void resize_640x480_to_240x240(uint8_t *src, uint8_t *dst) {
7273
static mp_obj_t webcam_capture_grayscale(mp_obj_t self_in) {
7374
webcam_obj_t *self = MP_OBJ_TO_PTR(self_in);
7475

75-
// Initialize buffer structure
76-
struct v4l2_buffer buf = {0};
77-
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
78-
buf.memory = V4L2_MEMORY_MMAP;
79-
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-
}
100-
}
101-
102-
// Start streaming if not already started
103-
if (!self->streaming) {
104-
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
105-
WEBCAM_DEBUG_PRINT("webcam: Starting video streaming\n");
106-
if (ioctl(self->fd, VIDIOC_STREAMON, &type) < 0) {
107-
WEBCAM_DEBUG_PRINT("webcam: Failed to start video streaming (errno=%d)\n", errno);
108-
mp_raise_OSError(errno);
109-
}
110-
self->streaming = true;
76+
// Poll for available buffer
77+
struct pollfd pfd = { .fd = self->fd, .events = POLLIN };
78+
WEBCAM_DEBUG_PRINT("webcam: Polling for available buffer\n");
79+
if (poll(&pfd, 1, 1000) <= 0) { // 1-second timeout
80+
WEBCAM_DEBUG_PRINT("webcam: Poll timeout or error (errno=%d)\n", errno);
81+
mp_raise_OSError(ETIMEDOUT);
11182
}
11283

11384
// Dequeue a buffer (capture frame)
114-
memset(&buf, 0, sizeof(buf));
85+
struct v4l2_buffer buf = {0};
11586
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
11687
buf.memory = V4L2_MEMORY_MMAP;
11788
WEBCAM_DEBUG_PRINT("webcam: Dequeuing buffer\n");
@@ -154,7 +125,7 @@ static mp_obj_t webcam_capture_grayscale(mp_obj_t self_in) {
154125
buf.index = buf_index;
155126
WEBCAM_DEBUG_PRINT("webcam: Re-queuing buffer (index=%zu)\n", buf_index);
156127
if (ioctl(self->fd, VIDIOC_QBUF, &buf) < 0) {
157-
WEBCAM_DEBUG_PRINT("webcam: Failed to re-queue buffer after capture (index=%zu, errno=%d)\n", buf_index, errno);
128+
WEBCAM_DEBUG_PRINT("webcam: Failed to re-queue buffer (index=%zu, errno=%d)\n", buf_index, errno);
158129
mp_raise_OSError(errno);
159130
}
160131

@@ -213,7 +184,7 @@ static mp_obj_t webcam_init(void) {
213184

214185
// Open the webcam device
215186
WEBCAM_DEBUG_PRINT("webcam: Opening device %s\n", VIDEO_DEVICE);
216-
self->fd = open(VIDEO_DEVICE, O_RDWR);
187+
self->fd = open(VIDEO_DEVICE, O_RDWR | O_NONBLOCK); // Non-blocking for polling
217188
if (self->fd < 0) {
218189
WEBCAM_DEBUG_PRINT("webcam: Failed to open device %s (errno=%d)\n", VIDEO_DEVICE, errno);
219190
mp_raise_OSError(errno);
@@ -245,6 +216,11 @@ static mp_obj_t webcam_init(void) {
245216
mp_raise_OSError(errno);
246217
}
247218
self->num_buffers = req.count;
219+
if (self->num_buffers < 2) {
220+
WEBCAM_DEBUG_PRINT("webcam: Insufficient buffers allocated (%zu)\n", self->num_buffers);
221+
close(self->fd);
222+
mp_raise_OSError(ENOMEM);
223+
}
248224

249225
// Query and map buffers
250226
for (size_t i = 0; i < self->num_buffers; i++) {
@@ -277,6 +253,23 @@ static mp_obj_t webcam_init(void) {
277253
close(self->fd);
278254
mp_raise_OSError(errno);
279255
}
256+
257+
// Queue the buffer upfront
258+
memset(&buf, 0, sizeof(buf));
259+
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
260+
buf.memory = V4L2_MEMORY_MMAP;
261+
buf.index = i;
262+
WEBCAM_DEBUG_PRINT("webcam: Initial queuing of buffer %zu\n", i);
263+
if (ioctl(self->fd, VIDIOC_QBUF, &buf) < 0) {
264+
WEBCAM_DEBUG_PRINT("webcam: Failed to queue buffer %zu initially (errno=%d)\n", i, errno);
265+
for (size_t j = 0; j <= i; j++) {
266+
if (self->buffers[j].start != NULL) {
267+
munmap(self->buffers[j].start, self->buffers[j].length);
268+
}
269+
}
270+
close(self->fd);
271+
mp_raise_OSError(errno);
272+
}
280273
}
281274

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

0 commit comments

Comments
 (0)