@@ -31,6 +31,25 @@ typedef struct _webcam_obj_t {
3131 int height ; // Resolution height
3232} webcam_obj_t ;
3333
34+ // Helper function to convert single YUV pixel to RGB565
35+ static inline uint16_t yuv_to_rgb565 (int y_val , int u , int v ) {
36+ int c = y_val - 16 ;
37+ int d = u - 128 ;
38+ int e = v - 128 ;
39+
40+ int r = (298 * c + 409 * e + 128 ) >> 8 ;
41+ int g = (298 * c - 100 * d - 208 * e + 128 ) >> 8 ;
42+ int b = (298 * c + 516 * d + 128 ) >> 8 ;
43+
44+ // Clamp to valid range
45+ r = r < 0 ? 0 : (r > 255 ? 255 : r );
46+ g = g < 0 ? 0 : (g > 255 ? 255 : g );
47+ b = b < 0 ? 0 : (b > 255 ? 255 : b );
48+
49+ // Convert to RGB565
50+ return ((r >> 3 ) << 11 ) | ((g >> 2 ) << 5 ) | (b >> 3 );
51+ }
52+
3453static void yuyv_to_rgb565 (unsigned char * yuyv , uint16_t * rgb565 , int width , int height ) {
3554 // Convert YUYV to RGB565 without scaling
3655 // YUYV format: Y0 U Y1 V (4 bytes for 2 pixels, chroma shared)
@@ -45,43 +64,9 @@ static void yuyv_to_rgb565(unsigned char *yuyv, uint16_t *rgb565, int width, int
4564 int y1 = yuyv [base_index + 2 ];
4665 int v = yuyv [base_index + 3 ];
4766
48- // YUV to RGB conversion (ITU-R BT.601) for first pixel
49- int c = y0 - 16 ;
50- int d = u - 128 ;
51- int e = v - 128 ;
52-
53- int r = (298 * c + 409 * e + 128 ) >> 8 ;
54- int g = (298 * c - 100 * d - 208 * e + 128 ) >> 8 ;
55- int b = (298 * c + 516 * d + 128 ) >> 8 ;
56-
57- // Clamp to valid range
58- r = r < 0 ? 0 : (r > 255 ? 255 : r );
59- g = g < 0 ? 0 : (g > 255 ? 255 : g );
60- b = b < 0 ? 0 : (b > 255 ? 255 : b );
61-
62- // Convert to RGB565
63- uint16_t r5 = (r >> 3 ) & 0x1F ;
64- uint16_t g6 = (g >> 2 ) & 0x3F ;
65- uint16_t b5 = (b >> 3 ) & 0x1F ;
66-
67- rgb565 [y * width + x ] = (r5 << 11 ) | (g6 << 5 ) | b5 ;
68-
69- // Second pixel (shares U/V with first)
70- c = y1 - 16 ;
71-
72- r = (298 * c + 409 * e + 128 ) >> 8 ;
73- g = (298 * c - 100 * d - 208 * e + 128 ) >> 8 ;
74- b = (298 * c + 516 * d + 128 ) >> 8 ;
75-
76- r = r < 0 ? 0 : (r > 255 ? 255 : r );
77- g = g < 0 ? 0 : (g > 255 ? 255 : g );
78- b = b < 0 ? 0 : (b > 255 ? 255 : b );
79-
80- r5 = (r >> 3 ) & 0x1F ;
81- g6 = (g >> 2 ) & 0x3F ;
82- b5 = (b >> 3 ) & 0x1F ;
83-
84- rgb565 [y * width + x + 1 ] = (r5 << 11 ) | (g6 << 5 ) | b5 ;
67+ // Convert both pixels (sharing U/V chroma)
68+ rgb565 [y * width + x ] = yuv_to_rgb565 (y0 , u , v );
69+ rgb565 [y * width + x + 1 ] = yuv_to_rgb565 (y1 , u , v );
8570 }
8671 }
8772}
@@ -98,23 +83,13 @@ static void yuyv_to_grayscale(unsigned char *yuyv, unsigned char *gray, int widt
9883 }
9984}
10085
101- static void save_raw (const char * filename , unsigned char * data , int width , int height ) {
86+ static void save_raw_generic (const char * filename , void * data , size_t elem_size , int width , int height ) {
10287 FILE * fp = fopen (filename , "wb" );
10388 if (!fp ) {
10489 WEBCAM_DEBUG_PRINT ("Cannot open file %s: %s\n" , filename , strerror (errno ));
10590 return ;
10691 }
107- fwrite (data , 1 , width * height , fp );
108- fclose (fp );
109- }
110-
111- static void save_raw_rgb565 (const char * filename , uint16_t * data , int width , int height ) {
112- FILE * fp = fopen (filename , "wb" );
113- if (!fp ) {
114- WEBCAM_DEBUG_PRINT ("Cannot open file %s: %s\n" , filename , strerror (errno ));
115- return ;
116- }
117- fwrite (data , sizeof (uint16_t ), width * height , fp );
92+ fwrite (data , elem_size , width * height , fp );
11893 fclose (fp );
11994}
12095
@@ -162,13 +137,21 @@ static int init_webcam(webcam_obj_t *self, const char *device, int width, int he
162137 buf .index = i ;
163138 if (ioctl (self -> fd , VIDIOC_QUERYBUF , & buf ) < 0 ) {
164139 WEBCAM_DEBUG_PRINT ("Cannot query buffer: %s\n" , strerror (errno ));
140+ // Unmap any already-mapped buffers
141+ for (int j = 0 ; j < i ; j ++ ) {
142+ munmap (self -> buffers [j ], self -> buffer_length );
143+ }
165144 close (self -> fd );
166145 return - errno ;
167146 }
168147 self -> buffer_length = buf .length ;
169148 self -> buffers [i ] = mmap (NULL , buf .length , PROT_READ | PROT_WRITE , MAP_SHARED , self -> fd , buf .m .offset );
170149 if (self -> buffers [i ] == MAP_FAILED ) {
171150 WEBCAM_DEBUG_PRINT ("Cannot map buffer: %s\n" , strerror (errno ));
151+ // Unmap any already-mapped buffers
152+ for (int j = 0 ; j < i ; j ++ ) {
153+ munmap (self -> buffers [j ], self -> buffer_length );
154+ }
172155 close (self -> fd );
173156 return - errno ;
174157 }
@@ -301,10 +284,6 @@ static mp_obj_t webcam_init(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k
301284 webcam_obj_t * self = m_new_obj (webcam_obj_t );
302285 self -> base .type = & webcam_type ;
303286 self -> fd = -1 ;
304- self -> gray_buffer = NULL ;
305- self -> rgb565_buffer = NULL ;
306- self -> width = 0 ; // Will be set from V4L2 format in init_webcam
307- self -> height = 0 ; // Will be set from V4L2 format in init_webcam
308287
309288 int res = init_webcam (self , device , width , height );
310289 if (res < 0 ) {
@@ -380,13 +359,10 @@ static mp_obj_t webcam_reconfigure(size_t n_args, const mp_obj_t *pos_args, mp_m
380359 WEBCAM_DEBUG_PRINT ("Reconfiguring webcam: %dx%d -> %dx%d\n" ,
381360 self -> width , self -> height , new_width , new_height );
382361
383- // Remember device path before deinit (which closes fd)
384- char device [64 ];
385- strncpy (device , self -> device , sizeof (device ));
386-
387362 // Clean shutdown and reinitialize with new resolution
363+ // Note: deinit_webcam doesn't touch self->device, so it's safe to use directly
388364 deinit_webcam (self );
389- int res = init_webcam (self , device , new_width , new_height );
365+ int res = init_webcam (self , self -> device , new_width , new_height );
390366
391367 if (res < 0 ) {
392368 mp_raise_OSError (- res );
0 commit comments