From ef06b58ed64a92348cb33aced3e35d4df3d19d1f Mon Sep 17 00:00:00 2001 From: Thomas Farstrike Date: Thu, 27 Nov 2025 13:57:57 +0100 Subject: [PATCH] Camera app: more resolutions, less memory use --- c_mpos/src/quirc_decode.c | 26 +++++++++++-- .../assets/camera_app.py | 39 ++++++++++++------- 2 files changed, 49 insertions(+), 16 deletions(-) diff --git a/c_mpos/src/quirc_decode.c b/c_mpos/src/quirc_decode.c index 68bcccb9..69721e69 100644 --- a/c_mpos/src/quirc_decode.c +++ b/c_mpos/src/quirc_decode.c @@ -151,13 +151,33 @@ static mp_obj_t qrdecode_rgb565(mp_uint_t n_args, const mp_obj_t *args) { free(gray_buffer); } else { QRDECODE_DEBUG_PRINT("qrdecode_rgb565: Exception caught, freeing gray_buffer\n"); - free(gray_buffer); + // Cleanup + if (gray_buffer) { + free(gray_buffer); + gray_buffer = NULL; + } + //mp_raise_TypeError(MP_ERROR_TEXT("qrdecode_rgb565: failed to decode QR code")); // Re-raising the exception results in an Unhandled exception in thread started by // which isn't caught, even when catching Exception, so this looks like a bug in MicroPython... - //nlr_pop(); - //nlr_raise(exception_handler.ret_val); + nlr_pop(); + nlr_raise(exception_handler.ret_val); + // Re-raise the original exception with optional additional message + /* + mp_raise_msg_and_obj( + mp_obj_exception_get_type(exception_handler.ret_val), + MP_OBJ_NEW_QSTR(qstr_from_str("qrdecode_rgb565: failed during processing")), + exception_handler.ret_val + ); + */ + // Re-raise as new exception of same type, with message + original as arg + // (embeds original for traceback chaining) + // crashes: + //const mp_obj_type_t *exc_type = mp_obj_get_type(exception_handler.ret_val); + //mp_raise_msg_varg(exc_type, MP_ERROR_TEXT("qrdecode_rgb565: failed during processing: %q"), exception_handler.ret_val); } + //nlr_pop(); maybe it needs to be done after instead of before the re-raise? + return result; } diff --git a/internal_filesystem/apps/com.micropythonos.camera/assets/camera_app.py b/internal_filesystem/apps/com.micropythonos.camera/assets/camera_app.py index a9ccb6a1..920eec12 100644 --- a/internal_filesystem/apps/com.micropythonos.camera/assets/camera_app.py +++ b/internal_filesystem/apps/com.micropythonos.camera/assets/camera_app.py @@ -227,7 +227,7 @@ class CameraApp(Activity): import qrdecode import utime before = utime.ticks_ms() - result = qrdecode.qrdecode_rgb565(self.current_cam_buffer_copy, self.width, self.height) + result = qrdecode.qrdecode_rgb565(self.current_cam_buffer, self.width, self.height) after = utime.ticks_ms() #result = bytearray("INSERT_QR_HERE", "utf-8") if not result: @@ -263,12 +263,12 @@ class CameraApp(Activity): os.mkdir("data/images") except OSError: pass - if self.current_cam_buffer_copy is not None: + if self.current_cam_buffer is not None: filename=f"data/images/camera_capture_{mpos.time.epoch_seconds()}_{self.width}x{self.height}_RGB565.raw" try: with open(filename, 'wb') as f: - f.write(self.current_cam_buffer_copy) - print(f"Successfully wrote current_cam_buffer_copy to {filename}") + f.write(self.current_cam_buffer) + print(f"Successfully wrote current_cam_buffer to {filename}") except OSError as e: print(f"Error writing to file: {e}") @@ -382,25 +382,30 @@ class CameraApp(Activity): try: if self.use_webcam: self.current_cam_buffer = webcam.capture_frame(self.cam, "rgb565") - self.current_cam_buffer_copy = bytes(self.current_cam_buffer) + #self.current_cam_buffer_copy = bytes(self.current_cam_buffer) elif self.cam.frame_available(): + self.cam.free_buffer() self.current_cam_buffer = self.cam.capture() - self.current_cam_buffer_copy = bytes(self.current_cam_buffer) + #self.current_cam_buffer_copy = bytes(self.current_cam_buffer) self.cam.free_buffer() - if self.current_cam_buffer_copy and len(self.current_cam_buffer_copy): + if self.current_cam_buffer and len(self.current_cam_buffer): # Defensive check: verify buffer size matches expected dimensions expected_size = self.width * self.height * 2 # RGB565 = 2 bytes per pixel - actual_size = len(self.current_cam_buffer_copy) + actual_size = len(self.current_cam_buffer) if actual_size == expected_size: - self.image_dsc.data = self.current_cam_buffer_copy + #self.image_dsc.data = self.current_cam_buffer_copy + self.image_dsc.data = self.current_cam_buffer #image.invalidate() # does not work so do this: self.image.set_src(self.image_dsc) if not self.use_webcam: self.cam.free_buffer() # Free the old buffer - if self.keepliveqrdecoding: - self.qrdecode_one() + try: + if self.keepliveqrdecoding: + self.qrdecode_one() + except Exception as qre: + print(f"try_capture: qrdecode_one got exception: {qre}") else: print(f"Warning: Buffer size mismatch! Expected {expected_size} bytes, got {actual_size} bytes") print(f" Resolution: {self.width}x{self.height}, discarding frame") @@ -433,8 +438,12 @@ def init_internal_cam(width, height): (480, 480): FrameSize.R480X480, (640, 480): FrameSize.VGA, (640, 640): FrameSize.R640X640, + (720, 720): FrameSize.R720X720, (800, 600): FrameSize.SVGA, + (800, 800): FrameSize.R800X800, + (960, 960): FrameSize.R960X960, (1024, 768): FrameSize.XGA, + (1024,1024): FrameSize.R1024X1024, (1280, 720): FrameSize.HD, (1280, 1024): FrameSize.SXGA, (1600, 1200): FrameSize.UXGA, @@ -660,9 +669,13 @@ class CameraSettingsActivity(Activity): ("480x480", "480x480"), ("640x480", "640x480"), ("640x640", "640x640"), + ("720x720", "720x720"), ("800x600", "800x600"), - ("1024x768", "1024x768"), - ("1280x720", "1280x720"), # binned 2x2 + ("800x800", "800x800"), + ("960x960", "960x960"), + ("1024x768", "1024x768"), + ("1024x1024","1024x1024"), + ("1280x720", "1280x720"), # binned 2x2 (in default ov5640.c) ("1280x1024", "1280x1024"), ("1600x1200", "1600x1200"), ("1920x1080", "1920x1080"),