2828#include "modcamera.h"
2929#include "esp_err.h"
3030#include "esp_log.h"
31+ #include "img_converters.h"
3132
3233#define TAG "ESP32_MPY_CAMERA"
3334
4243#endif
4344
4445// Supporting functions
45- void raise_micropython_error_from_esp_err (esp_err_t err ) {
46+ static void raise_micropython_error_from_esp_err (esp_err_t err ) {
4647 switch (err ) {
4748 case ESP_OK :
4849 return ;
@@ -72,8 +73,8 @@ void raise_micropython_error_from_esp_err(esp_err_t err) {
7273 break ;
7374
7475 default :
75- mp_raise_msg_varg (& mp_type_RuntimeError , MP_ERROR_TEXT ("Unknown error 0x%04x" ), err );
76- // mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("Unknown error"));
76+ // mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("Unknown error 0x%04x"), err);
77+ mp_raise_msg_varg (& mp_type_RuntimeError , MP_ERROR_TEXT ("Unknown error" ));
7778 break ;
7879 }
7980}
@@ -85,7 +86,7 @@ static int map(int value, int fromLow, int fromHigh, int toLow, int toHigh) {
8586 return (int )((int32_t )(value - fromLow ) * (toHigh - toLow ) / (fromHigh - fromLow ) + toLow );
8687}
8788
88- static int get_mapped_jpeg_quality (int8_t quality ) {
89+ static inline int get_mapped_jpeg_quality (int8_t quality ) {
8990 return map (quality , 0 , 100 , 63 , 0 );
9091}
9192
@@ -246,37 +247,90 @@ void mp_camera_hal_reconfigure(mp_camera_obj_t *self, mp_camera_framesize_t fram
246247 }
247248}
248249
249- mp_obj_t mp_camera_hal_capture (mp_camera_obj_t * self , int timeout_ms ) {
250- // Timeout not used at the moment
250+ mp_obj_t mp_camera_hal_capture (mp_camera_obj_t * self , int8_t out_format ) {
251251 if (!self -> initialized ) {
252252 mp_raise_msg (& mp_type_OSError , MP_ERROR_TEXT ("Failed to capture image: Camera not initialized" ));
253253 }
254254 if (self -> captured_buffer ) {
255255 esp_camera_fb_return (self -> captured_buffer );
256256 self -> captured_buffer = NULL ;
257257 }
258+
259+ static size_t out_len = 0 ;
260+ static uint8_t * out_buf = NULL ;
261+ if (out_len > 0 || out_buf ) {
262+ free (out_buf );
263+ out_len = 0 ;
264+ out_buf = NULL ;
265+ }
266+
258267 ESP_LOGI (TAG , "Capturing image" );
259268 self -> captured_buffer = esp_camera_fb_get ();
260- if (self -> captured_buffer ) {
261- if (self -> camera_config .pixel_format == PIXFORMAT_JPEG ) {
262- ESP_LOGI (TAG , "Captured image in JPEG format" );
263- return mp_obj_new_memoryview ('b' , self -> captured_buffer -> len , self -> captured_buffer -> buf );
264- } else {
265- ESP_LOGI (TAG , "Captured image in raw format" );
266- return mp_obj_new_memoryview ('b' , self -> captured_buffer -> len , self -> captured_buffer -> buf );
267- // TODO: Stub at the moment in order to return raw data, but it sould be implemented to return a Bitmap, see following circuitpython example:
268- //
269- // int width = common_hal_espcamera_camera_get_width(self);
270- // int height = common_hal_espcamera_camera_get_height(self);
271- // displayio_bitmap_t *bitmap = m_new_obj(displayio_bitmap_t);
272- // bitmap->base.type = &displayio_bitmap_type;
273- // common_hal_displayio_bitmap_construct_from_buffer(bitmap, width, height, (format == PIXFORMAT_RGB565) ? 16 : 8, (uint32_t *)(void *)result->buf, true);
274- // return bitmap;
269+ if (!self -> captured_buffer ) {
270+ ESP_LOGE (TAG , "Failed to capture image" );
271+ return mp_const_none ;
272+ }
273+
274+ if (out_format >= 0 && (mp_camera_pixformat_t )out_format != self -> camera_config .pixel_format ) {
275+ switch (out_format ) {
276+ case PIXFORMAT_JPEG :
277+ if (frame2jpg (self -> captured_buffer , self -> camera_config .jpeg_quality , & out_buf , & out_len )) {
278+ esp_camera_fb_return (self -> captured_buffer );
279+ mp_obj_t result = mp_obj_new_memoryview ('b' , out_len , out_buf );
280+ return result ;
281+ } else {
282+ return mp_const_none ;
283+ }
284+
285+ case PIXFORMAT_RGB888 :
286+ out_len = self -> captured_buffer -> width * self -> captured_buffer -> height * 3 ;
287+ out_buf = (uint8_t * )malloc (out_len );
288+ if (!out_buf ) {
289+ ESP_LOGE (TAG , "out_buf malloc failed" );
290+ return mp_const_none ;
291+ }
292+ if (fmt2rgb888 (self -> captured_buffer -> buf , self -> captured_buffer -> len , self -> captured_buffer -> format , out_buf )) {
293+ esp_camera_fb_return (self -> captured_buffer );
294+ mp_obj_t result = mp_obj_new_memoryview ('b' , out_len , out_buf );
295+ return result ;
296+ } else {
297+ return mp_const_none ;
298+ }
299+
300+ case PIXFORMAT_RGB565 :
301+ if (self -> camera_config .pixel_format == PIXFORMAT_JPEG ){
302+ if (jpg2rgb565 (self -> captured_buffer -> buf , self -> captured_buffer -> len , out_buf , JPG_SCALE_NONE )) {
303+ esp_camera_fb_return (self -> captured_buffer );
304+ mp_obj_t result = mp_obj_new_memoryview ('b' , out_len , out_buf );
305+ return result ;
306+ } else {
307+ return mp_const_none ;
308+ }
309+ } else {
310+ mp_raise_msg (& mp_type_OSError , MP_ERROR_TEXT ("Can only convert JPEG to RGB565" ));
311+ return mp_const_none ;
312+ }
313+
314+ default :
315+ mp_raise_msg (& mp_type_OSError , MP_ERROR_TEXT ("Unsupported pixel format for conversion" ));
316+ return mp_const_none ;
317+
275318 }
319+ }
320+
321+ if (self -> bmp_out == false) {
322+ ESP_LOGI (TAG , "Returning imgae without conversion" );
323+ return mp_obj_new_memoryview ('b' , self -> captured_buffer -> len , self -> captured_buffer -> buf );
276324 } else {
277- esp_camera_fb_return (self -> captured_buffer );
278- self -> captured_buffer = NULL ;
279- return mp_const_none ;
325+ ESP_LOGI (TAG , "Returning image as bitmap" );
326+ if (frame2bmp (self -> captured_buffer , & out_buf , & out_len )) {
327+ esp_camera_fb_return (self -> captured_buffer );
328+ mp_obj_t result = mp_obj_new_memoryview ('b' , out_len , out_buf );
329+ return result ;
330+ } else {
331+ mp_raise_msg (& mp_type_OSError , MP_ERROR_TEXT ("Failed to convert image to BMP" ));
332+ return mp_const_none ;
333+ }
280334 }
281335}
282336
@@ -289,6 +343,7 @@ const mp_rom_map_elem_t mp_camera_hal_pixel_format_table[] = {
289343 { MP_ROM_QSTR (MP_QSTR_YUV422 ), MP_ROM_INT (PIXFORMAT_YUV422 ) },
290344 { MP_ROM_QSTR (MP_QSTR_GRAYSCALE ), MP_ROM_INT (PIXFORMAT_GRAYSCALE ) },
291345 { MP_ROM_QSTR (MP_QSTR_RGB565 ), MP_ROM_INT (PIXFORMAT_RGB565 ) },
346+ { MP_ROM_QSTR (MP_QSTR_RGB888 ), MP_ROM_INT (PIXFORMAT_RGB888 ) },
292347};
293348
294349const mp_rom_map_elem_t mp_camera_hal_frame_size_table [] = {
@@ -418,16 +473,24 @@ void mp_camera_hal_set_frame_size(mp_camera_obj_t * self, framesize_t value) {
418473 if (!self -> initialized ) {
419474 mp_raise_ValueError (MP_ERROR_TEXT ("Camera not initialized" ));
420475 }
476+
421477 sensor_t * sensor = esp_camera_sensor_get ();
422478 if (!sensor -> set_framesize ) {
423479 mp_raise_ValueError (MP_ERROR_TEXT ("No attribute frame_size" ));
424480 }
481+
482+ if (self -> captured_buffer ) {
483+ esp_camera_return_all ();
484+ self -> captured_buffer = NULL ;
485+ }
486+
425487 if (sensor -> set_framesize (sensor , value ) < 0 ) {
426488 mp_raise_ValueError (MP_ERROR_TEXT ("Invalid setting for frame_size" ));
427489 } else {
428490 self -> camera_config .frame_size = value ;
429491 }
430492}
493+
431494int mp_camera_hal_get_quality (mp_camera_obj_t * self ) {
432495 if (!self -> initialized ) {
433496 mp_raise_ValueError (MP_ERROR_TEXT ("Camera not initialized" ));
0 commit comments