From 3557914356ebcb5f489b470de4f762682d3e02bd Mon Sep 17 00:00:00 2001 From: julian Date: Wed, 11 Dec 2024 17:42:47 -0600 Subject: [PATCH 1/2] fix: free memory after use --- lib/camera_linux.dart | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/lib/camera_linux.dart b/lib/camera_linux.dart index 55bf9a5..da3a919 100644 --- a/lib/camera_linux.dart +++ b/lib/camera_linux.dart @@ -2,9 +2,11 @@ import 'dart:async'; import 'dart:convert'; import 'dart:ffi'; import 'dart:typed_data'; -import 'camera_linux_bindings_generated.dart'; + import 'package:ffi/ffi.dart'; +import 'camera_linux_bindings_generated.dart'; + class CameraLinux { late CameraLinuxBindings _bindings; @@ -24,7 +26,7 @@ class CameraLinux { } // Convert Frame Into Base64 - String uint8ListToBase64Url(Uint8List data) { + String _uint8ListToBase64Url(Uint8List data) { String base64String = base64Encode(data); String base64Url = base64String @@ -39,14 +41,24 @@ class CameraLinux { // Capture The Frame Future captureImage() async { final lengthPtr = calloc(); - Pointer framePointer = _bindings.getLatestFrameBytes(lengthPtr); - final latestFrame = getLatestFrameData(framePointer, lengthPtr.value); - final base64Image = uint8ListToBase64Url(latestFrame); - return base64Image; + Pointer? latestFramePtr; + try { + latestFramePtr = _bindings.getLatestFrameBytes(lengthPtr); + final latestFrame = _getLatestFrameData(latestFramePtr, lengthPtr.value); + final base64Image = _uint8ListToBase64Url(latestFrame); + return base64Image; + } catch (_) { + rethrow; + } finally { + calloc.free(lengthPtr); + if (latestFramePtr != null) { + calloc.free(latestFramePtr); + } + } } // Get The Latest Frame - Uint8List getLatestFrameData(Pointer framePointer, frameSize) { + Uint8List _getLatestFrameData(Pointer framePointer, frameSize) { List frameList = framePointer.asTypedList(frameSize); return Uint8List.fromList(frameList); } From ecb412474c5d240347b04ac1eb9f019802ff7034 Mon Sep 17 00:00:00 2001 From: julian Date: Wed, 11 Dec 2024 18:11:22 -0600 Subject: [PATCH 2/2] feat: clear last frame on read --- src/opencv_wrapper.cpp | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/opencv_wrapper.cpp b/src/opencv_wrapper.cpp index 2b71d80..78ce43b 100644 --- a/src/opencv_wrapper.cpp +++ b/src/opencv_wrapper.cpp @@ -2,12 +2,14 @@ #include #include #include +#include using namespace std; using namespace cv; std::thread videoThread; std::atomic stopFlag(false); +std::mutex frameMutex; Mat latestFrame; // Extern C block to expose the function to C @@ -22,15 +24,20 @@ extern "C" { } while (!stopFlag.load()) { - cap >> latestFrame; - if (latestFrame.empty()) { + Mat frame; + cap >> frame; + if (frame.empty()) { printf("Frame is Empty"); break; } + { + lock_guard lock(frameMutex); + frame.copyTo(latestFrame); + } std::this_thread::sleep_for(std::chrono::milliseconds(500)); } - cap.release(); + cap.release(); } @@ -55,16 +62,23 @@ extern "C" { } *length = 0; // Initialize length to 0 - - - if (latestFrame.empty()) { - printf("Frame Empty"); - return nullptr; + + Mat frameCopy; + { + std::lock_guard lock(frameMutex); + + if (latestFrame.empty()) { + printf("Frame Empty\n"); + return nullptr; + } + + frameCopy = latestFrame.clone(); // Clone the frame to avoid race conditions + latestFrame.release(); // Clear the frame after it has been fetched } // Encode the frame as JPEG vector buf; - bool encodeSuccess = imencode(".jpg", latestFrame, buf); + bool encodeSuccess = imencode(".jpg", frameCopy, buf); // Check if encoding was successful if (!encodeSuccess || buf.empty()) {