|
6 | 6 | #include <linux/videodev2.h> |
7 | 7 | #include <sys/mman.h> |
8 | 8 | #include <string.h> |
9 | | -#include <poll.h> |
10 | 9 |
|
11 | 10 | #include "py/obj.h" |
12 | 11 | #include "py/runtime.h" |
|
24 | 23 | #define CAPTURE_HEIGHT 480 |
25 | 24 | #define OUTPUT_WIDTH 240 // Resize to 240x240 |
26 | 25 | #define OUTPUT_HEIGHT 240 |
27 | | -#define NUM_BUFFERS 4 // Use 4 buffers for continuous streaming |
| 26 | +#define NUM_BUFFERS 2 // Use 2 buffers, as it worked for two captures |
28 | 27 |
|
29 | 28 | // Webcam object type |
30 | 29 | typedef struct _webcam_obj_t { |
@@ -73,16 +72,42 @@ static void resize_640x480_to_240x240(uint8_t *src, uint8_t *dst) { |
73 | 72 | static mp_obj_t webcam_capture_grayscale(mp_obj_t self_in) { |
74 | 73 | webcam_obj_t *self = MP_OBJ_TO_PTR(self_in); |
75 | 74 |
|
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); |
| 75 | + // Try to queue a buffer |
| 76 | + struct v4l2_buffer buf = {0}; |
| 77 | + bool queued = false; |
| 78 | + for (size_t i = 0; i < self->num_buffers; i++) { |
| 79 | + memset(&buf, 0, sizeof(buf)); |
| 80 | + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 81 | + buf.memory = V4L2_MEMORY_MMAP; |
| 82 | + buf.index = i; |
| 83 | + |
| 84 | + WEBCAM_DEBUG_PRINT("webcam: Attempting to queue buffer (index=%zu)\n", i); |
| 85 | + if (ioctl(self->fd, VIDIOC_QBUF, &buf) == 0) { |
| 86 | + WEBCAM_DEBUG_PRINT("webcam: Successfully queued buffer (index=%zu)\n", i); |
| 87 | + queued = true; |
| 88 | + break; |
| 89 | + } |
| 90 | + WEBCAM_DEBUG_PRINT("webcam: Failed to queue buffer (index=%zu, errno=%d)\n", i, errno); |
| 91 | + } |
| 92 | + |
| 93 | + if (!queued) { |
| 94 | + WEBCAM_DEBUG_PRINT("webcam: No buffers available for queuing\n"); |
| 95 | + mp_raise_OSError(EAGAIN); // Try again later |
| 96 | + } |
| 97 | + |
| 98 | + // Start streaming if not already started |
| 99 | + if (!self->streaming) { |
| 100 | + enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 101 | + WEBCAM_DEBUG_PRINT("webcam: Starting video streaming\n"); |
| 102 | + if (ioctl(self->fd, VIDIOC_STREAMON, &type) < 0) { |
| 103 | + WEBCAM_DEBUG_PRINT("webcam: Failed to start video streaming (errno=%d)\n", errno); |
| 104 | + mp_raise_OSError(errno); |
| 105 | + } |
| 106 | + self->streaming = true; |
82 | 107 | } |
83 | 108 |
|
84 | 109 | // Dequeue a buffer (capture frame) |
85 | | - struct v4l2_buffer buf = {0}; |
| 110 | + memset(&buf, 0, sizeof(buf)); |
86 | 111 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
87 | 112 | buf.memory = V4L2_MEMORY_MMAP; |
88 | 113 | WEBCAM_DEBUG_PRINT("webcam: Dequeuing buffer\n"); |
@@ -184,7 +209,7 @@ static mp_obj_t webcam_init(void) { |
184 | 209 |
|
185 | 210 | // Open the webcam device |
186 | 211 | WEBCAM_DEBUG_PRINT("webcam: Opening device %s\n", VIDEO_DEVICE); |
187 | | - self->fd = open(VIDEO_DEVICE, O_RDWR | O_NONBLOCK); // Non-blocking for polling |
| 212 | + self->fd = open(VIDEO_DEVICE, O_RDWR); |
188 | 213 | if (self->fd < 0) { |
189 | 214 | WEBCAM_DEBUG_PRINT("webcam: Failed to open device %s (errno=%d)\n", VIDEO_DEVICE, errno); |
190 | 215 | mp_raise_OSError(errno); |
@@ -216,7 +241,7 @@ static mp_obj_t webcam_init(void) { |
216 | 241 | mp_raise_OSError(errno); |
217 | 242 | } |
218 | 243 | self->num_buffers = req.count; |
219 | | - if (self->num_buffers < 2) { |
| 244 | + if (self->num_buffers < NUM_BUFFERS) { |
220 | 245 | WEBCAM_DEBUG_PRINT("webcam: Insufficient buffers allocated (%zu)\n", self->num_buffers); |
221 | 246 | close(self->fd); |
222 | 247 | mp_raise_OSError(ENOMEM); |
@@ -253,23 +278,6 @@ static mp_obj_t webcam_init(void) { |
253 | 278 | close(self->fd); |
254 | 279 | mp_raise_OSError(errno); |
255 | 280 | } |
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 | | - } |
273 | 281 | } |
274 | 282 |
|
275 | 283 | // Create a tuple to hold the webcam object and method references |
|
0 commit comments