You've already forked MicroPythonOS
mirror of
https://github.com/m5stack/MicroPythonOS.git
synced 2026-05-20 11:51:27 -07:00
webcam: add deinit workaround
This commit is contained in:
+102
-11
@@ -23,9 +23,9 @@
|
||||
#define CAPTURE_HEIGHT 480
|
||||
#define OUTPUT_WIDTH 240 // Resize to 240x240
|
||||
#define OUTPUT_HEIGHT 240
|
||||
#define NUM_BUFFERS 5 // Use 2 buffers, as it worked for two captures
|
||||
#define NUM_BUFFERS 5 // Use 5 buffers, as it achieved 5 captures
|
||||
#define QUEUE_RETRIES 5 // Number of retry attempts for queueing
|
||||
#define QUEUE_RETRY_DELAY_US 100000 // 50ms delay between retries
|
||||
#define QUEUE_RETRY_DELAY_US 100000 // 100ms delay between retries
|
||||
|
||||
// Webcam object type
|
||||
typedef struct _webcam_obj_t {
|
||||
@@ -70,6 +70,48 @@ static void resize_640x480_to_240x240(uint8_t *src, uint8_t *dst) {
|
||||
}
|
||||
}
|
||||
|
||||
// Reset streaming state
|
||||
static void webcam_reset_streaming(webcam_obj_t *self) {
|
||||
if (self->streaming) {
|
||||
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
WEBCAM_DEBUG_PRINT("webcam: Stopping video streaming for reset\n");
|
||||
if (ioctl(self->fd, VIDIOC_STREAMOFF, &type) < 0) {
|
||||
WEBCAM_DEBUG_PRINT("webcam: Failed to stop video streaming (errno=%d)\n", errno);
|
||||
}
|
||||
self->streaming = false;
|
||||
}
|
||||
|
||||
// Re-queue all buffers
|
||||
for (size_t i = 0; i < self->num_buffers; i++) {
|
||||
struct v4l2_buffer buf = {0};
|
||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
buf.index = i;
|
||||
|
||||
// Query buffer state
|
||||
WEBCAM_DEBUG_PRINT("webcam: Querying buffer state during reset (index=%zu)\n", i);
|
||||
if (ioctl(self->fd, VIDIOC_QUERYBUF, &buf) < 0) {
|
||||
WEBCAM_DEBUG_PRINT("webcam: Failed to query buffer state (index=%zu, errno=%d)\n", i, errno);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Queue buffer
|
||||
WEBCAM_DEBUG_PRINT("webcam: Re-queuing buffer during reset (index=%zu)\n", i);
|
||||
if (ioctl(self->fd, VIDIOC_QBUF, &buf) < 0) {
|
||||
WEBCAM_DEBUG_PRINT("webcam: Failed to re-queue buffer during reset (index=%zu, errno=%d)\n", i, errno);
|
||||
}
|
||||
}
|
||||
|
||||
// Restart streaming
|
||||
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
WEBCAM_DEBUG_PRINT("webcam: Restarting video streaming\n");
|
||||
if (ioctl(self->fd, VIDIOC_STREAMON, &type) < 0) {
|
||||
WEBCAM_DEBUG_PRINT("webcam: Failed to restart video streaming (errno=%d)\n", errno);
|
||||
} else {
|
||||
self->streaming = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Capture a grayscale image
|
||||
static mp_obj_t webcam_capture_grayscale(mp_obj_t self_in) {
|
||||
webcam_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
@@ -84,6 +126,13 @@ static mp_obj_t webcam_capture_grayscale(mp_obj_t self_in) {
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
buf.index = i;
|
||||
|
||||
// Query buffer state
|
||||
WEBCAM_DEBUG_PRINT("webcam: Querying buffer state (index=%zu, attempt=%d)\n", i, attempt + 1);
|
||||
if (ioctl(self->fd, VIDIOC_QUERYBUF, &buf) < 0) {
|
||||
WEBCAM_DEBUG_PRINT("webcam: Failed to query buffer state (index=%zu, errno=%d)\n", i, errno);
|
||||
continue;
|
||||
}
|
||||
|
||||
WEBCAM_DEBUG_PRINT("webcam: Attempting to queue buffer (index=%zu, attempt=%d)\n", i, attempt + 1);
|
||||
if (ioctl(self->fd, VIDIOC_QBUF, &buf) == 0) {
|
||||
WEBCAM_DEBUG_PRINT("webcam: Successfully queued buffer (index=%zu)\n", i);
|
||||
@@ -94,12 +143,38 @@ static mp_obj_t webcam_capture_grayscale(mp_obj_t self_in) {
|
||||
}
|
||||
if (!queued && attempt < QUEUE_RETRIES - 1) {
|
||||
WEBCAM_DEBUG_PRINT("webcam: No buffers available, retrying after delay\n");
|
||||
usleep(QUEUE_RETRY_DELAY_US); // Wait 50ms before retrying
|
||||
usleep(QUEUE_RETRY_DELAY_US); // Wait 100ms
|
||||
}
|
||||
}
|
||||
|
||||
if (!queued) {
|
||||
WEBCAM_DEBUG_PRINT("webcam: No buffers available after %d retries\n", QUEUE_RETRIES);
|
||||
WEBCAM_DEBUG_PRINT("webcam: No buffers available after %d retries, resetting streaming\n", QUEUE_RETRIES);
|
||||
webcam_reset_streaming(self);
|
||||
// Retry queuing one more time after reset
|
||||
for (size_t i = 0; i < self->num_buffers; i++) {
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
buf.index = i;
|
||||
|
||||
WEBCAM_DEBUG_PRINT("webcam: Querying buffer state after reset (index=%zu)\n", i);
|
||||
if (ioctl(self->fd, VIDIOC_QUERYBUF, &buf) < 0) {
|
||||
WEBCAM_DEBUG_PRINT("webcam: Failed to query buffer state after reset (index=%zu, errno=%d)\n", i, errno);
|
||||
continue;
|
||||
}
|
||||
|
||||
WEBCAM_DEBUG_PRINT("webcam: Attempting to queue buffer after reset (index=%zu)\n", i);
|
||||
if (ioctl(self->fd, VIDIOC_QBUF, &buf) == 0) {
|
||||
WEBCAM_DEBUG_PRINT("webcam: Successfully queued buffer after reset (index=%zu)\n", i);
|
||||
queued = true;
|
||||
break;
|
||||
}
|
||||
WEBCAM_DEBUG_PRINT("webcam: Failed to queue buffer after reset (index=%zu, errno=%d)\n", i, errno);
|
||||
}
|
||||
}
|
||||
|
||||
if (!queued) {
|
||||
WEBCAM_DEBUG_PRINT("webcam: No buffers available even after reset\n");
|
||||
mp_raise_OSError(EAGAIN);
|
||||
}
|
||||
|
||||
@@ -156,6 +231,10 @@ static mp_obj_t webcam_capture_grayscale(mp_obj_t self_in) {
|
||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
buf.index = buf_index;
|
||||
WEBCAM_DEBUG_PRINT("webcam: Querying buffer state before re-queue (index=%zu)\n", buf_index);
|
||||
if (ioctl(self->fd, VIDIOC_QUERYBUF, &buf) < 0) {
|
||||
WEBCAM_DEBUG_PRINT("webcam: Failed to query buffer state before re-queue (index=%zu, errno=%d)\n", buf_index, errno);
|
||||
}
|
||||
WEBCAM_DEBUG_PRINT("webcam: Re-queuing buffer (index=%zu)\n", buf_index);
|
||||
if (ioctl(self->fd, VIDIOC_QBUF, &buf) < 0) {
|
||||
WEBCAM_DEBUG_PRINT("webcam: Failed to re-queue buffer (index=%zu, errno=%d)\n", buf_index, errno);
|
||||
@@ -286,14 +365,26 @@ static mp_obj_t webcam_init(void) {
|
||||
close(self->fd);
|
||||
mp_raise_OSError(errno);
|
||||
}
|
||||
|
||||
// Queue buffer upfront
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
buf.index = i;
|
||||
WEBCAM_DEBUG_PRINT("webcam: Initial queuing of buffer %zu\n", i);
|
||||
if (ioctl(self->fd, VIDIOC_QBUF, &buf) < 0) {
|
||||
WEBCAM_DEBUG_PRINT("webcam: Failed to queue buffer %zu initially (errno=%d)\n", i, errno);
|
||||
for (size_t j = 0; j <= i; j++) {
|
||||
if (self->buffers[j].start != NULL) {
|
||||
munmap(self->buffers[j].start, self->buffers[j].length);
|
||||
}
|
||||
}
|
||||
close(self->fd);
|
||||
mp_raise_OSError(errno);
|
||||
}
|
||||
}
|
||||
|
||||
// Create a tuple to hold the webcam object and method references
|
||||
mp_obj_t tuple[3];
|
||||
tuple[0] = MP_OBJ_FROM_PTR(self);
|
||||
tuple[1] = MP_OBJ_FROM_PTR(&webcam_capture_grayscale_obj);
|
||||
tuple[2] = MP_OBJ_FROM_PTR(&webcam_deinit_obj);
|
||||
return mp_obj_new_tuple(3, tuple);
|
||||
return mp_obj_new_tuple(3, (mp_obj_t[]){MP_OBJ_FROM_PTR(self), MP_OBJ_FROM_PTR(&webcam_capture_grayscale_obj), MP_OBJ_FROM_PTR(&webcam_deinit_obj)});
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(webcam_init_obj, webcam_init);
|
||||
|
||||
@@ -302,7 +393,7 @@ static const mp_rom_map_elem_t webcam_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_webcam) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&webcam_init_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_capture_grayscale), MP_ROM_PTR(&webcam_capture_grayscale_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&webcam_deinit_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR/&webcam_deinit_obj) },
|
||||
};
|
||||
static MP_DEFINE_CONST_DICT(webcam_module_globals, webcam_module_globals_table);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user