2323#define CAPTURE_HEIGHT 480
2424#define OUTPUT_WIDTH 240 // Resize to 240x240
2525#define OUTPUT_HEIGHT 240
26- #define NUM_BUFFERS 5 // Use 2 buffers, as it worked for two captures
26+ #define NUM_BUFFERS 5 // Use 5 buffers, as it achieved 5 captures
2727#define QUEUE_RETRIES 5 // Number of retry attempts for queueing
28- #define QUEUE_RETRY_DELAY_US 100000 // 50ms delay between retries
28+ #define QUEUE_RETRY_DELAY_US 100000 // 100ms delay between retries
2929
3030// Webcam object type
3131typedef struct _webcam_obj_t {
@@ -70,6 +70,48 @@ static void resize_640x480_to_240x240(uint8_t *src, uint8_t *dst) {
7070 }
7171}
7272
73+ // Reset streaming state
74+ static void webcam_reset_streaming (webcam_obj_t * self ) {
75+ if (self -> streaming ) {
76+ enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
77+ WEBCAM_DEBUG_PRINT ("webcam: Stopping video streaming for reset\n" );
78+ if (ioctl (self -> fd , VIDIOC_STREAMOFF , & type ) < 0 ) {
79+ WEBCAM_DEBUG_PRINT ("webcam: Failed to stop video streaming (errno=%d)\n" , errno );
80+ }
81+ self -> streaming = false;
82+ }
83+
84+ // Re-queue all buffers
85+ for (size_t i = 0 ; i < self -> num_buffers ; i ++ ) {
86+ struct v4l2_buffer buf = {0 };
87+ buf .type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
88+ buf .memory = V4L2_MEMORY_MMAP ;
89+ buf .index = i ;
90+
91+ // Query buffer state
92+ WEBCAM_DEBUG_PRINT ("webcam: Querying buffer state during reset (index=%zu)\n" , i );
93+ if (ioctl (self -> fd , VIDIOC_QUERYBUF , & buf ) < 0 ) {
94+ WEBCAM_DEBUG_PRINT ("webcam: Failed to query buffer state (index=%zu, errno=%d)\n" , i , errno );
95+ continue ;
96+ }
97+
98+ // Queue buffer
99+ WEBCAM_DEBUG_PRINT ("webcam: Re-queuing buffer during reset (index=%zu)\n" , i );
100+ if (ioctl (self -> fd , VIDIOC_QBUF , & buf ) < 0 ) {
101+ WEBCAM_DEBUG_PRINT ("webcam: Failed to re-queue buffer during reset (index=%zu, errno=%d)\n" , i , errno );
102+ }
103+ }
104+
105+ // Restart streaming
106+ enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
107+ WEBCAM_DEBUG_PRINT ("webcam: Restarting video streaming\n" );
108+ if (ioctl (self -> fd , VIDIOC_STREAMON , & type ) < 0 ) {
109+ WEBCAM_DEBUG_PRINT ("webcam: Failed to restart video streaming (errno=%d)\n" , errno );
110+ } else {
111+ self -> streaming = true;
112+ }
113+ }
114+
73115// Capture a grayscale image
74116static mp_obj_t webcam_capture_grayscale (mp_obj_t self_in ) {
75117 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) {
84126 buf .memory = V4L2_MEMORY_MMAP ;
85127 buf .index = i ;
86128
129+ // Query buffer state
130+ WEBCAM_DEBUG_PRINT ("webcam: Querying buffer state (index=%zu, attempt=%d)\n" , i , attempt + 1 );
131+ if (ioctl (self -> fd , VIDIOC_QUERYBUF , & buf ) < 0 ) {
132+ WEBCAM_DEBUG_PRINT ("webcam: Failed to query buffer state (index=%zu, errno=%d)\n" , i , errno );
133+ continue ;
134+ }
135+
87136 WEBCAM_DEBUG_PRINT ("webcam: Attempting to queue buffer (index=%zu, attempt=%d)\n" , i , attempt + 1 );
88137 if (ioctl (self -> fd , VIDIOC_QBUF , & buf ) == 0 ) {
89138 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) {
94143 }
95144 if (!queued && attempt < QUEUE_RETRIES - 1 ) {
96145 WEBCAM_DEBUG_PRINT ("webcam: No buffers available, retrying after delay\n" );
97- usleep (QUEUE_RETRY_DELAY_US ); // Wait 50ms before retrying
146+ usleep (QUEUE_RETRY_DELAY_US ); // Wait 100ms
147+ }
148+ }
149+
150+ if (!queued ) {
151+ WEBCAM_DEBUG_PRINT ("webcam: No buffers available after %d retries, resetting streaming\n" , QUEUE_RETRIES );
152+ webcam_reset_streaming (self );
153+ // Retry queuing one more time after reset
154+ for (size_t i = 0 ; i < self -> num_buffers ; i ++ ) {
155+ memset (& buf , 0 , sizeof (buf ));
156+ buf .type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
157+ buf .memory = V4L2_MEMORY_MMAP ;
158+ buf .index = i ;
159+
160+ WEBCAM_DEBUG_PRINT ("webcam: Querying buffer state after reset (index=%zu)\n" , i );
161+ if (ioctl (self -> fd , VIDIOC_QUERYBUF , & buf ) < 0 ) {
162+ WEBCAM_DEBUG_PRINT ("webcam: Failed to query buffer state after reset (index=%zu, errno=%d)\n" , i , errno );
163+ continue ;
164+ }
165+
166+ WEBCAM_DEBUG_PRINT ("webcam: Attempting to queue buffer after reset (index=%zu)\n" , i );
167+ if (ioctl (self -> fd , VIDIOC_QBUF , & buf ) == 0 ) {
168+ WEBCAM_DEBUG_PRINT ("webcam: Successfully queued buffer after reset (index=%zu)\n" , i );
169+ queued = true;
170+ break ;
171+ }
172+ WEBCAM_DEBUG_PRINT ("webcam: Failed to queue buffer after reset (index=%zu, errno=%d)\n" , i , errno );
98173 }
99174 }
100175
101176 if (!queued ) {
102- WEBCAM_DEBUG_PRINT ("webcam: No buffers available after %d retries \n" , QUEUE_RETRIES );
177+ WEBCAM_DEBUG_PRINT ("webcam: No buffers available even after reset \n" );
103178 mp_raise_OSError (EAGAIN );
104179 }
105180
@@ -156,6 +231,10 @@ static mp_obj_t webcam_capture_grayscale(mp_obj_t self_in) {
156231 buf .type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
157232 buf .memory = V4L2_MEMORY_MMAP ;
158233 buf .index = buf_index ;
234+ WEBCAM_DEBUG_PRINT ("webcam: Querying buffer state before re-queue (index=%zu)\n" , buf_index );
235+ if (ioctl (self -> fd , VIDIOC_QUERYBUF , & buf ) < 0 ) {
236+ WEBCAM_DEBUG_PRINT ("webcam: Failed to query buffer state before re-queue (index=%zu, errno=%d)\n" , buf_index , errno );
237+ }
159238 WEBCAM_DEBUG_PRINT ("webcam: Re-queuing buffer (index=%zu)\n" , buf_index );
160239 if (ioctl (self -> fd , VIDIOC_QBUF , & buf ) < 0 ) {
161240 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) {
286365 close (self -> fd );
287366 mp_raise_OSError (errno );
288367 }
368+
369+ // Queue buffer upfront
370+ memset (& buf , 0 , sizeof (buf ));
371+ buf .type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
372+ buf .memory = V4L2_MEMORY_MMAP ;
373+ buf .index = i ;
374+ WEBCAM_DEBUG_PRINT ("webcam: Initial queuing of buffer %zu\n" , i );
375+ if (ioctl (self -> fd , VIDIOC_QBUF , & buf ) < 0 ) {
376+ WEBCAM_DEBUG_PRINT ("webcam: Failed to queue buffer %zu initially (errno=%d)\n" , i , errno );
377+ for (size_t j = 0 ; j <= i ; j ++ ) {
378+ if (self -> buffers [j ].start != NULL ) {
379+ munmap (self -> buffers [j ].start , self -> buffers [j ].length );
380+ }
381+ }
382+ close (self -> fd );
383+ mp_raise_OSError (errno );
384+ }
289385 }
290386
291- // Create a tuple to hold the webcam object and method references
292- mp_obj_t tuple [3 ];
293- tuple [0 ] = MP_OBJ_FROM_PTR (self );
294- tuple [1 ] = MP_OBJ_FROM_PTR (& webcam_capture_grayscale_obj );
295- tuple [2 ] = MP_OBJ_FROM_PTR (& webcam_deinit_obj );
296- return mp_obj_new_tuple (3 , tuple );
387+ 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 )});
297388}
298389MP_DEFINE_CONST_FUN_OBJ_0 (webcam_init_obj , webcam_init );
299390
@@ -302,7 +393,7 @@ static const mp_rom_map_elem_t webcam_module_globals_table[] = {
302393 { MP_ROM_QSTR (MP_QSTR___name__ ), MP_ROM_QSTR (MP_QSTR_webcam ) },
303394 { MP_ROM_QSTR (MP_QSTR_init ), MP_ROM_PTR (& webcam_init_obj ) },
304395 { MP_ROM_QSTR (MP_QSTR_capture_grayscale ), MP_ROM_PTR (& webcam_capture_grayscale_obj ) },
305- { MP_ROM_QSTR (MP_QSTR_deinit ), MP_ROM_PTR ( & webcam_deinit_obj ) },
396+ { MP_ROM_QSTR (MP_QSTR_deinit ), MP_ROM_PTR / & webcam_deinit_obj ) },
306397};
307398static MP_DEFINE_CONST_DICT (webcam_module_globals , webcam_module_globals_table ) ;
308399
0 commit comments