diff --git a/cmvr-es/devices/camera/uvc_camera/include/uvc_camera.h b/cmvr-es/devices/camera/uvc_camera/include/uvc_camera.h index 4560cd10..4b5a76a4 100644 --- a/cmvr-es/devices/camera/uvc_camera/include/uvc_camera.h +++ b/cmvr-es/devices/camera/uvc_camera/include/uvc_camera.h @@ -5,6 +5,8 @@ #ifndef CMVR_ES_UVC_CAMERA_H #define CMVR_ES_UVC_CAMERA_H +#include + #include "common/base/ring_buffer.h" #include "camera/abstract_camera.h" #include "devices/camera/common/include/camera_stream_encoder.h" @@ -68,8 +70,10 @@ namespace cmvr::device { std::shared_ptr recording_thread_; - cv::Mat latest_frame_; // 存储最新帧 - std::mutex frame_mutex_; // 保护最新帧的访问 + cv::Mat latest_frame_; + std::mutex frame_mutex_; + std::condition_variable frame_condition_; + uint64_t latest_frame_sequence_{0}; std::string output_path_; bool is_recording_ = false; diff --git a/cmvr-es/devices/camera/uvc_camera/src/uvc_camera.cpp b/cmvr-es/devices/camera/uvc_camera/src/uvc_camera.cpp index 4372b791..2d417dae 100644 --- a/cmvr-es/devices/camera/uvc_camera/src/uvc_camera.cpp +++ b/cmvr-es/devices/camera/uvc_camera/src/uvc_camera.cpp @@ -71,6 +71,7 @@ bool UVCCamera::init() { { std::lock_guard frame_lock(frame_mutex_); latest_frame_.release(); + latest_frame_sequence_ = 0; } stream_frame_buffer_ = std::make_shared>(buffer_size_); @@ -144,6 +145,7 @@ bool UVCCamera::start() { { std::lock_guard frame_lock(frame_mutex_); latest_frame_.release(); + latest_frame_sequence_ = 0; } cap_.open(serial_, cv::CAP_V4L2); @@ -212,6 +214,7 @@ bool UVCCamera::stop() { { std::lock_guard frame_lock(frame_mutex_); latest_frame_.release(); + latest_frame_sequence_ = 0; } state_.is_opened = false; return true; @@ -228,6 +231,7 @@ void UVCCamera::getRGBImage(cv::Mat& color, Rs2Intrinsics& intrinsics) { std::lock_guard lock(ctrl_mtx_); clear_error_(); + color.release(); if (mode_ == PHOTO_MODE) { if (!state_.is_opened) { state_.is_error = true; @@ -254,15 +258,24 @@ void UVCCamera::getRGBImage(cv::Mat& color, Rs2Intrinsics& intrinsics) return; } - { - std::lock_guard frame_lock(frame_mutex_); - if (!latest_frame_.empty()) { + const bool capture_worker_requested = state_.is_streaming || state_.is_recording; + bool snapshot_timed_out = false; + if (capture_worker_requested) { + std::unique_lock frame_lock(frame_mutex_); + const uint64_t requested_after_sequence = latest_frame_sequence_; + const bool received_new_frame = frame_condition_.wait_for( + frame_lock, + std::chrono::seconds(2), + [this, requested_after_sequence]() { + return latest_frame_sequence_ != requested_after_sequence; + }); + + if (received_new_frame && !latest_frame_.empty()) { latest_frame_.copyTo(color); } + snapshot_timed_out = !received_new_frame; } - - const bool capture_worker_requested = state_.is_streaming || state_.is_recording; - if (color.empty() && !capture_worker_requested) { + else { if (stream_thread_) { if (stream_thread_->joinable()) { stream_thread_->join(); @@ -282,7 +295,9 @@ void UVCCamera::getRGBImage(cv::Mat& color, Rs2Intrinsics& intrinsics) if (color.empty()) { state_.is_error = true; - state_.error_message = "no video frame available"; + state_.error_message = snapshot_timed_out + ? "timed out waiting for a new video frame" + : "no video frame available"; CMVR_LOG(ERROR) << "[UVCCamera] (getRGBImage): " << state_.error_message; return; } @@ -563,7 +578,9 @@ void UVCCamera::streaming_worker_() { { std::lock_guard frame_lock(frame_mutex_); frame.copyTo(latest_frame_); + ++latest_frame_sequence_; } + frame_condition_.notify_all(); // 以下为编码部分,用于流模式 StreamFrameData frame_data;