diff --git a/CMakeLists.txt b/CMakeLists.txt index c2949d2..086aa6d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,30 @@ find_package(OpenCV REQUIRED) pkg_check_modules(LIBDRM REQUIRED libdrm) pkg_check_modules(LIBCAMERA REQUIRED libcamera) -add_executable(libcamera_meme main.cpp concurrent_blocking_queue.h camera_grabber.cpp dma_buf_alloc.cpp gl_hsv_thresholder.cpp libcamera_opengl_utility.cpp) -target_include_directories(libcamera_meme PUBLIC ${OPENGL_INCLUDE_DIRS} ${LIBDRM_INCLUDE_DIRS} ${LIBCAMERA_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS}) +find_package(JNI) +if (JNI_FOUND) + # Fixes odd AWT dependency + set (JNI_INCLUDE_DIRS ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2}) + message (STATUS "JNI_INCLUDE_DIRS=${JNI_INCLUDE_DIRS}") +endif() + +add_executable(libcamera_meme + main.cpp + concurrent_blocking_queue.h + camera_grabber.cpp + dma_buf_alloc.cpp + gl_hsv_thresholder.cpp + libcamera_opengl_utility.cpp + libcamera_jni.hpp + libcamera_jni.cpp +) + + target_include_directories(libcamera_meme PUBLIC + ${OPENGL_INCLUDE_DIRS} + ${LIBDRM_INCLUDE_DIRS} + ${LIBCAMERA_INCLUDE_DIRS} + ${OpenCV_INCLUDE_DIRS} + ${JNI_INCLUDE_DIRS} +) + target_link_libraries(libcamera_meme PUBLIC OpenGL::GL OpenGL::EGL Threads::Threads ${LIBCAMERA_LINK_LIBRARIES} ${OpenCV_LIBS}) diff --git a/LibCameraJNI.java b/LibCameraJNI.java new file mode 100644 index 0000000..fb240fa --- /dev/null +++ b/LibCameraJNI.java @@ -0,0 +1,24 @@ +public class LibCameraJNI { + public static native String getSensorModelRaw(); + public static native boolean isSupported(); + // Get a pointer to a new runner + public static native long createCamera(int width, int height); + public static native boolean destroyCamera(long ptr); + + // Set thresholds on [0..1] + public static native boolean setThresholds(long ptr, + double hl, double sl, double vl, + double hu, double su, double vu); + + // Exposure time, in microseconds + public static native boolean setExposure(long ptr, int exposureUs); + public static native boolean setBrightness(long ptr, double brightness); + public static native boolean setAwbGain(long ptr, float red, float blue); + public static native boolean setAnalogGain(long ptr, double analog); + public static native boolean setDigitalGain(long ptr, double digital); + public static native boolean setShouldGreyscale(long ptr, boolean shouldGreyscale); + + public static native boolean awaitNewFrame(long ptr); + public static native long getColorFrame(long ptr); + public static native long getGPUoutput(long ptr); +} diff --git a/camera_grabber.cpp b/camera_grabber.cpp index 99f824e..2f5e0ee 100644 --- a/camera_grabber.cpp +++ b/camera_grabber.cpp @@ -72,12 +72,33 @@ void CameraGrabber::requestComplete(libcamera::Request *request) { } void CameraGrabber::requeueRequest(libcamera::Request *request) { + // This resets all our controls + // https://github.com/kbingham/libcamera/blob/master/src/libcamera/request.cpp#L397 request->reuse(libcamera::Request::ReuseFlag::ReuseBuffers); + + setControls(request); + if (m_camera->queueRequest(request) < 0) { throw std::runtime_error("failed to queue request"); } } +void CameraGrabber::setControls(libcamera::Request *request) { + auto &controls = request->controls(); + controls.set(libcamera::controls::AeEnable, false); // Auto exposure disabled + controls.set(libcamera::controls::AwbEnable, false); // AWB disabled + controls.set(libcamera::controls::ExposureTime, m_settings.exposureTimeUs); // in microseconds + controls.set(libcamera::controls::AnalogueGain, m_settings.analogGain); // Analog gain, min 1 max big number? + controls.set(libcamera::controls::DigitalGain, m_settings.digitalGain); // Digital gain, unknown range + controls.set(libcamera::controls::ColourGains, {m_settings.awbRedGain, m_settings.awbBlueGain}); // AWB gains, red and blue, unknown range + controls.set(libcamera::controls::Brightness, m_settings.brightness); // -1 to 1, 0 means unchanged + controls.set(libcamera::controls::Contrast, m_settings.contrast); // Nominal 1 + controls.set(libcamera::controls::Saturation, m_settings.saturation); // Nominal 1, 0 would be greyscale + controls.set(libcamera::controls::FrameDurationLimits, {static_cast(0), static_cast(0)}); // Set default to zero, we have specificed the exposure time + + // Additionally, we can set crop regions and stuff +} + void CameraGrabber::startAndQueue() { if (m_camera->start()) { throw std::runtime_error("failed to start camera"); @@ -85,6 +106,7 @@ void CameraGrabber::startAndQueue() { // TODO: HANDLE THIS BETTER for (auto &request: m_requests) { + setControls(request); if (m_camera->queueRequest(request.get()) < 0) { throw std::runtime_error("failed to queue request"); } diff --git a/camera_grabber.h b/camera_grabber.h index 319f9d9..5a89a87 100644 --- a/camera_grabber.h +++ b/camera_grabber.h @@ -8,6 +8,17 @@ #include #include +struct CameraSettings { + int32_t exposureTimeUs; + float analogGain; + float digitalGain + float brightness; + float contrast; + float awbRedGain; + float awbBlueGain; + float saturation; +} + class CameraGrabber { public: explicit CameraGrabber(std::shared_ptr camera, int width, int height); @@ -18,11 +29,17 @@ class CameraGrabber { void startAndQueue(); void requeueRequest(libcamera::Request *request); + CameraSettings& GetCameraSettings() { return m_settings; } + private: + void setControls(std::function request); + std::vector> m_requests; std::map m_mapped; void requestComplete(libcamera::Request *request); + std::vector> m_controlUpdatesToApply; + CameraSettings m_settings; std::shared_ptr m_camera; std::unique_ptr m_config; libcamera::FrameBufferAllocator m_buf_allocator; diff --git a/camera_manager.cpp b/camera_manager.cpp new file mode 100644 index 0000000..88fbeeb --- /dev/null +++ b/camera_manager.cpp @@ -0,0 +1,123 @@ +#include "camera_manager.h" + +CameraRunner::CameraRunner(int width, int height, const std::string& id) { + auto cameras = camera_manager_->cameras(); + auto *camera = std::find_if(cameras.begin(), cameras.end(), [](auto &cam) { return cam->id() == id; }) + + auto allocer = DmaBufAlloc("/dev/dma_heap/linux,cma"); + + auto grabber = CameraGrabber(std::move(camera), width, height); + unsigned int stride = grabber.streamConfiguration().stride; + + auto camera_queue = ConcurrentBlockingQueue(); + grabber.setOnData([&](libcamera::Request *request) { + camera_queue.push(request); + }); + + std::vector fds { + allocer.alloc_buf(width * height * 4), + allocer.alloc_buf(width * height * 4), + allocer.alloc_buf(width * height * 4) + }; + + + m_threshold ([&]() { + auto colorspace = grabber.streamConfiguration().colorSpace.value(); + auto thresholder = GlHsvThresholder(width, height, fds); + + auto gpu_queue = ConcurrentBlockingQueue(); + thresholder.setOnComplete([&](int fd) { + gpu_queue.push(fd); + }); + + + std::thread display([&]() { + std::unordered_map mmaped; + + for (auto fd: fds) { + auto mmap_ptr = mmap(nullptr, width * height * 4, PROT_READ, MAP_SHARED, fd, 0); + if (mmap_ptr == MAP_FAILED) { + throw std::runtime_error("failed to mmap pointer"); + } + mmaped.emplace(fd, static_cast(mmap_ptr)); + } + + cv::Mat threshold_mat(height, width, CV_8UC1); + unsigned char *threshold_out_buf = threshold_mat.data; + cv::Mat color_mat(height, width, CV_8UC3); + unsigned char *color_out_buf = color_mat.data; + + while (display_thread_run) { + auto fd = gpu_queue.pop(); + if (fd == -1) { + break; + } + + auto input_ptr = mmaped.at(fd); + int bound = width * height; + + for (int i = 0; i < bound; i++) { + std::memcpy(color_out_buf + i * 3, input_ptr + i * 4, 3); + threshold_out_buf[i] = input_ptr[i * 4 + 3]; + } + + // pls don't optimize these writes out compiler + std::cout << reinterpret_cast(threshold_out_buf) << " " << reinterpret_cast(color_out_buf) << std::endl; + + thresholder.returnBuffer(fd); + // cv::imshow("cam", mat); + // cv::waitKey(3); + } + }); + + while (threshold_thread_run) { + auto request = camera_queue.pop(); + + if (!request) { + break; + } + + // in Nanoseconds, from the Linux CLOCK_BOOTTIME + auto sensorTimestamp = request->controls()->get(libcamera::controls::SensorTimestamp); + + auto planes = request->buffers().at(grabber.streamConfiguration().stream())->planes(); + + std::array yuv_data {{ + {planes[0].fd.get(), + static_cast(planes[0].offset), + static_cast(stride)}, + {planes[1].fd.get(), + static_cast(planes[1].offset), + static_cast(stride / 2)}, + {planes[2].fd.get(), + static_cast(planes[2].offset), + static_cast(stride / 2)}, + }}; + + thresholder.testFrame(yuv_data, encodingFromColorspace(colorspace), rangeFromColorspace(colorspace)); + grabber.requeueRequest(request); + } + + // need to stop above thread too + display_thread_run = false; + display.join(); + }); + + std::this_thread::sleep_for(std::chrono::seconds(2)); + + grabber.startAndQueue(); +} + +void CameraRunner::Stop() { + threshold_thread_run = false; + m_threshold.join(); +} + +static std::vector GetAllCameraIDs() { + static libcamera::CameraManager* camera_manager; + if(!camera_manager) { + camera_manager = std::make_unique(); + camera_manager->start(); + } + return camera_manager->cameras(); +} \ No newline at end of file diff --git a/camera_manager.h b/camera_manager.h new file mode 100644 index 0000000..3927b0d --- /dev/null +++ b/camera_manager.h @@ -0,0 +1,34 @@ +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "dma_buf_alloc.h" +#include "gl_hsv_thresholder.h" +#include "camera_grabber.h" +#include "libcamera_opengl_utility.h" +#include "concurrent_blocking_queue.h" + +class CameraRunner { +public: + CameraRunner(int width, int height, int fps, const std::string &id); + + CameraGrabber GetCameraGrabber(); + + void Stop(); + +private: + std::thread m_threshold; + + bool threshold_thread_run = true; + bool display_thread_run = true; +} + +static std::vector GetAllCameraIDs(); \ No newline at end of file diff --git a/gl_hsv_thresholder.cpp b/gl_hsv_thresholder.cpp index 7b44265..53a2380 100644 --- a/gl_hsv_thresholder.cpp +++ b/gl_hsv_thresholder.cpp @@ -369,12 +369,13 @@ void GlHsvThresholder::testFrame(const std::array& yuv_plane_data, EGLint encoding, EGLint range); + + /** + * @brief Set the Hsv Thresholds range, on [0..1] + * + * @param hl Lower hue + * @param sl Sat lower + * @param vl Value lower + * @param hu Upper hue + * @param su Sat Upper + * @param vu Value Upper + */ + void setHsvThresholds(double hl, double sl, double vl, double hu, double su, double vu); + private: int m_width; int m_height; @@ -42,6 +55,9 @@ class GlHsvThresholder { GLuint m_quad_vbo; GLuint m_program; + + double m_hsvLower[3] = {0}; // Hue, sat, value, in [0,1] + double m_hsvUpper[3] = {0}; // Hue, sat, value, in [0,1] }; #endif //LIBCAMERA_MEME_GL_HSV_THRESHOLDER_H diff --git a/libcamera_jni.cpp b/libcamera_jni.cpp new file mode 100644 index 0000000..94dc1c0 --- /dev/null +++ b/libcamera_jni.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2022 Photon Vision. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "libcamera_jni.hpp" // Generated + +#include "camera_manager.h" +#include + +extern "C" { + +#include + +// We use jlongs like pointers, so they better be large enough +static_assert(sizeof(void *) <= sizeof(jlong)); + +JNIEXPORT jstring +Java_org_photonvision_raspi_LibCameraJNI_getSensorModelRaw(JNIEnv *env, jclass) { + return env->NewStringUTF("foobar"); +} + +JNIEXPORT jboolean +Java_org_photonvision_raspi_LibCameraJNI_isSupported(JNIEnv *env jclass) { + return true; +} + +JNIEXPORT jlong JNICALL Java_org_photonvision_raspi_LibCameraJNI_createCamera( + JNIEnv *env jclass, jint width, jint height) { + + auto& cameras = GetAllCameraIDs(); + + // Yeet all USB cameras (I hope) + auto rem = std::remove_if(cameras.begin(), cameras.end(), + [](auto &cam) { return cam->id().find("/usb") != std::string::npos; }); + cameras.erase(rem, cameras.end()); + + if (cameras.size() == 0) return 0; + + // Otherwise, just create the first camera left + return (jlong) new CameraRunner(width, height, cameras[0]->id()); +} + +JNIEXPORT jboolean JNICALL +Java_org_photonvision_raspi_LibCameraJNI_destroyCamera(JNIEnv *env jclass, jlong runnerPtr) { + CameraRunner *runner = (CameraRunner*)runnerPtr; + delete runner; +} + +JNIEXPORT jboolean JNICALL Java_org_photonvision_raspi_LibCameraJNI_setThresholds( + JNIEnv *env jclass, jlong runnerPtr, jdouble hl, jdouble sl, jdouble vl, jdouble hu, + jdouble su, jdouble vu) { + CameraRunner *runner = (CameraRunner*)runnerPtr; + runner->GetCameraGrabber().GetHsvThresholder().setHsvThresholds(hl, sl, vl, hu, su, vu); + return true; +} + +JNIEXPORT jboolean JNICALL Java_org_photonvision_raspi_LibCameraJNI_setExposure( + JNIEnv *env jclass, jlong runnerPtr, jint exposure) { + CameraRunner *runner = (CameraRunner*)runnerPtr; + runner->GetCameraGrabber().GetCameraSettings().exposureTimeUs = exposure; + return true; +} + +JNIEXPORT jboolean JNICALL Java_org_photonvision_raspi_LibCameraJNI_setBrightness( + JNIEnv *env jclass, jlong runnerPtr, jdouble brightness) { + CameraRunner *runner = (CameraRunner*)runnerPtr; + runner->GetCameraGrabber().GetCameraSettings().brightness = brightness; + return true; +} + +JNIEXPORT jboolean JNICALL Java_org_photonvision_raspi_LibCameraJNI_setAwbGain( + JNIEnv *env jclass, jlong runnerPtr, jdouble red, jdouble blue) { + CameraRunner *runner = (CameraRunner*)runnerPtr; + runner->GetCameraGrabber().GetCameraSettings().awbRedGain = red; + runner->GetCameraGrabber().GetCameraSettings().awbBlueGain = blue; + return true; +} + +JNIEXPORT jboolean JNICALL +Java_org_photonvision_raspi_LibCameraJNI_setAnalogGain(JNIEnv *env jclass, jlong runnerPrt, jdouble analog) { + CameraRunner *runner = (CameraRunner*)runnerPtr; + runner->GetCameraGrabber().GetCameraSettings().analogGain = analog; + return true; +} + +JNIEXPORT jboolean JNICALL +Java_org_photonvision_raspi_LibCameraJNI_setDigitalGain(JNIEnv *env jclass, jlong runnerPrt, jdouble digital) { + CameraRunner *runner = (CameraRunner*)runnerPtr; + runner->GetCameraGrabber().GetCameraSettings().digitalGain = digital; + return true; +} + +JNIEXPORT jboolean JNICALL Java_org_photonvision_raspi_LibCameraJNI_setRotation( + JNIEnv *env jclass, jint rotationOrdinal) { + int rotation = (rotationOrdinal + 3) * 90; // Degrees + // TODO + return true; +} + +JNIEXPORT jlong JNICALL +Java_org_photonvision_raspi_LibCameraJNI_getFrameLatency(JNIEnv *env jclass) { + return 0; +} + +JNIEXPORT jboolean JNICALL +Java_org_photonvision_raspi_LibCameraJNI_awaitNewFrame(JNIEnv *env, jclass, jlong runnerPtr) { + // TODO + return true; +} + +JNIEXPORT jlong JNICALL +Java_org_photonvision_raspi_LibCameraJNI_getColorFrame(JNIEnv *env jclass, jlong runnerPtr) { + CameraRunner *runner = (CameraRunner*)runnerPtr; + return 0; +} + +JNIEXPORT jlong JNICALL +Java_org_photonvision_raspi_LibCameraJNI_getGPUoutput(JNIEnv *env jclass, jlong runnerPtr) { + CameraRunner *runner = (CameraRunner*)runnerPtr; + return 0; +} + +JNIEXPORT jboolean JNICALL +Java_org_photonvision_raspi_LibCameraJNI_setShouldGreyscale(JNIEnv *env jclass, jlong runnerPtr, jboolean) { + CameraRunner *runner = (CameraRunner*)runnerPtr; + return 0; +} + +} // extern "C" diff --git a/libcamera_jni.hpp b/libcamera_jni.hpp new file mode 100644 index 0000000..7cb2c4b --- /dev/null +++ b/libcamera_jni.hpp @@ -0,0 +1,117 @@ + +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class org_photonvision_raspi_LibCameraJNI */ + +#ifndef _Included_org_photonvision_raspi_LibCameraJNI +#define _Included_org_photonvision_raspi_LibCameraJNI +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_photonvision_raspi_LibCameraJNI + * Method: getSensorModelRaw + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL +Java_org_photonvision_raspi_LibCameraJNI_getSensorModelRaw(JNIEnv *, jclass); + +/* + * Class: org_photonvision_raspi_LibCameraJNI + * Method: isVCSMSupported + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL +Java_org_photonvision_raspi_LibCameraJNI_isSupported(JNIEnv *, jclass); + +/* + * Class: org_photonvision_raspi_LibCameraJNI + * Method: createCamera + * Signature: (III)Z + */ +JNIEXPORT jlong JNICALL Java_org_photonvision_raspi_LibCameraJNI_createCamera( + JNIEnv *, jclass, jint, jint); + +/* + * Class: org_photonvision_raspi_LibCameraJNI + * Method: destroyCamera + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL +Java_org_photonvision_raspi_LibCameraJNI_destroyCamera(JNIEnv *, jclass, jlong); + +/* + * Class: org_photonvision_raspi_LibCameraJNI + * Method: setThresholds + * Signature: (DDDDDD)V + */ +JNIEXPORT jboolean JNICALL Java_org_photonvision_raspi_LibCameraJNI_setThresholds( + JNIEnv *, jclass, jlong, jdouble, jdouble, jdouble, jdouble, jdouble, jdouble); + +/* + * Class: org_photonvision_raspi_LibCameraJNI + * Method: setExposure + * Signature: (I)Z + */ +JNIEXPORT jboolean JNICALL +Java_org_photonvision_raspi_LibCameraJNI_setExposure(JNIEnv *, jclass, jlong, jint); + +/* + * Class: org_photonvision_raspi_LibCameraJNI + * Method: setBrightness + * Signature: (I)Z + */ +JNIEXPORT jboolean JNICALL +Java_org_photonvision_raspi_LibCameraJNI_setBrightness(JNIEnv *, jclass, jlong, jdouble); + +/* + * Class: org_photonvision_raspi_LibCameraJNI + * Method: setGain + * Signature: (I)Z + */ +JNIEXPORT jboolean JNICALL +Java_org_photonvision_raspi_LibCameraJNI_setAnalogGain(JNIEnv *, jclass, jlong, jdouble); +JNIEXPORT jboolean JNICALL +Java_org_photonvision_raspi_LibCameraJNI_setDigitalGain(JNIEnv *, jclass, jlong, jdouble); + +JNIEXPORT jboolean JNICALL Java_org_photonvision_raspi_LibCameraJNI_setAwbGain( + JNIEnv *, jclass, jlong, jdouble red, jdouble blue); + +/* + * Class: org_photonvision_raspi_LibCameraJNI + * Method: setRotation + * Signature: (I)Z + */ +JNIEXPORT jboolean JNICALL +Java_org_photonvision_raspi_LibCameraJNI_setRotation(JNIEnv *, jclass, jlong, jint); + +/* + * Class: org_photonvision_raspi_LibCameraJNI + * Method: getFrameLatency + * Signature: ()J + */ +JNIEXPORT jlong JNICALL +Java_org_photonvision_raspi_LibCameraJNI_getFrameLatency(JNIEnv *, jclass); + +/* + * Class: org_photonvision_raspi_LibCameraJNI + * Method: grabFrame + * Signature: (Z)J + */ +JNIEXPORT jboolean JNICALL +Java_org_photonvision_raspi_LibCameraJNI_awaitNewFrame(JNIEnv *, jclass, jlong); + +JNIEXPORT jlong JNICALL +Java_org_photonvision_raspi_LibCameraJNI_getColorFrame(JNIEnv *, jclass, jlong); + +JNIEXPORT jlong JNICALL +Java_org_photonvision_raspi_LibCameraJNI_getGPUoutput(JNIEnv *, jclass, jlong); + +// True if greyscale, else binary threshold output +JNIEXPORT jboolean JNICALL +Java_org_photonvision_raspi_LibCameraJNI_setShouldGreyscale(JNIEnv *, jclass, jlong, jboolean); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/main.cpp b/main.cpp index 331a3bc..97d92d2 100644 --- a/main.cpp +++ b/main.cpp @@ -1,130 +1,19 @@ -#include -#include - -#include -#include +#include "camera_manager.h" #include -#include - -#include -#include -#include - -#include "dma_buf_alloc.h" -#include "gl_hsv_thresholder.h" -#include "camera_grabber.h" -#include "libcamera_opengl_utility.h" -#include "concurrent_blocking_queue.h" int main() { constexpr int width = 1920, height = 1080; - auto allocer = DmaBufAlloc("/dev/dma_heap/linux,cma"); - - auto camera_manager = std::make_unique(); - camera_manager->start(); - - auto cameras = camera_manager->cameras(); - if (cameras.size() != 1) { - throw std::runtime_error("code expects only one camera present"); - } - - auto camera = cameras[0]; - auto grabber = CameraGrabber(std::move(camera), width, height); - unsigned int stride = grabber.streamConfiguration().stride; - - auto camera_queue = ConcurrentBlockingQueue(); - grabber.setOnData([&](libcamera::Request *request) { - camera_queue.push(request); - }); - - std::vector fds { - allocer.alloc_buf(width * height * 4), - allocer.alloc_buf(width * height * 4), - allocer.alloc_buf(width * height * 4) - }; - - std::thread threshold([&]() { - auto colorspace = grabber.streamConfiguration().colorSpace.value(); - auto thresholder = GlHsvThresholder(width, height, fds); - - auto gpu_queue = ConcurrentBlockingQueue(); - thresholder.setOnComplete([&](int fd) { - gpu_queue.push(fd); - }); - - std::thread display([&]() { - std::unordered_map mmaped; - - for (auto fd: fds) { - auto mmap_ptr = mmap(nullptr, width * height * 4, PROT_READ, MAP_SHARED, fd, 0); - if (mmap_ptr == MAP_FAILED) { - throw std::runtime_error("failed to mmap pointer"); - } - mmaped.emplace(fd, static_cast(mmap_ptr)); - } - cv::Mat threshold_mat(height, width, CV_8UC1); - unsigned char *threshold_out_buf = threshold_mat.data; - cv::Mat color_mat(height, width, CV_8UC3); - unsigned char *color_out_buf = color_mat.data; + std::cout << "Num cameras: " << GetAllCameraIDs().size() << std::endl; - while (true) { - auto fd = gpu_queue.pop(); - if (fd == -1) { - break; - } - - auto input_ptr = mmaped.at(fd); - int bound = width * height; - - for (int i = 0; i < bound; i++) { - std::memcpy(color_out_buf + i * 3, input_ptr + i * 4, 3); - threshold_out_buf[i] = input_ptr[i * 4 + 3]; - } - - // pls don't optimize these writes out compiler - std::cout << reinterpret_cast(threshold_out_buf) << " " << reinterpret_cast(color_out_buf) << std::endl; - - thresholder.returnBuffer(fd); - // cv::imshow("cam", mat); - // cv::waitKey(3); - } - }); - - while (true) { - auto request = camera_queue.pop(); - - if (!request) { - break; - } - - auto planes = request->buffers().at(grabber.streamConfiguration().stream())->planes(); - - std::array yuv_data {{ - {planes[0].fd.get(), - static_cast(planes[0].offset), - static_cast(stride)}, - {planes[1].fd.get(), - static_cast(planes[1].offset), - static_cast(stride / 2)}, - {planes[2].fd.get(), - static_cast(planes[2].offset), - static_cast(stride / 2)}, - }}; - - thresholder.testFrame(yuv_data, encodingFromColorspace(colorspace), rangeFromColorspace(colorspace)); - grabber.requeueRequest(request); - } - }); - - std::this_thread::sleep_for(std::chrono::seconds(2)); - - grabber.startAndQueue(); + CameraRunner runner{640, 480, GetAllCameraIDs[0]}; for (int i = 0; i < 10; i++) { std::cout << "Waiting for 1 second" << std::endl; std::this_thread::sleep_for(std::chrono::seconds(1)); } + runner.Stop(); + return 0; }