fix(camera): capture a fresh UVC snapshot

This commit is contained in:
linbo 2026-08-12 09:25:27 +08:00
parent b0efc341a9
commit 8c2ed13f80
2 changed files with 30 additions and 9 deletions

View File

@ -5,6 +5,8 @@
#ifndef CMVR_ES_UVC_CAMERA_H #ifndef CMVR_ES_UVC_CAMERA_H
#define CMVR_ES_UVC_CAMERA_H #define CMVR_ES_UVC_CAMERA_H
#include <condition_variable>
#include "common/base/ring_buffer.h" #include "common/base/ring_buffer.h"
#include "camera/abstract_camera.h" #include "camera/abstract_camera.h"
#include "devices/camera/common/include/camera_stream_encoder.h" #include "devices/camera/common/include/camera_stream_encoder.h"
@ -68,8 +70,10 @@ namespace cmvr::device {
std::shared_ptr<std::thread> recording_thread_; std::shared_ptr<std::thread> recording_thread_;
cv::Mat latest_frame_; // 存储最新帧 cv::Mat latest_frame_;
std::mutex frame_mutex_; // 保护最新帧的访问 std::mutex frame_mutex_;
std::condition_variable frame_condition_;
uint64_t latest_frame_sequence_{0};
std::string output_path_; std::string output_path_;
bool is_recording_ = false; bool is_recording_ = false;

View File

@ -71,6 +71,7 @@ bool UVCCamera::init() {
{ {
std::lock_guard frame_lock(frame_mutex_); std::lock_guard frame_lock(frame_mutex_);
latest_frame_.release(); latest_frame_.release();
latest_frame_sequence_ = 0;
} }
stream_frame_buffer_ = std::make_shared<SPMCRingBuffer<StreamFrameData>>(buffer_size_); stream_frame_buffer_ = std::make_shared<SPMCRingBuffer<StreamFrameData>>(buffer_size_);
@ -144,6 +145,7 @@ bool UVCCamera::start() {
{ {
std::lock_guard frame_lock(frame_mutex_); std::lock_guard frame_lock(frame_mutex_);
latest_frame_.release(); latest_frame_.release();
latest_frame_sequence_ = 0;
} }
cap_.open(serial_, cv::CAP_V4L2); cap_.open(serial_, cv::CAP_V4L2);
@ -212,6 +214,7 @@ bool UVCCamera::stop() {
{ {
std::lock_guard frame_lock(frame_mutex_); std::lock_guard frame_lock(frame_mutex_);
latest_frame_.release(); latest_frame_.release();
latest_frame_sequence_ = 0;
} }
state_.is_opened = false; state_.is_opened = false;
return true; return true;
@ -228,6 +231,7 @@ void UVCCamera::getRGBImage(cv::Mat& color, Rs2Intrinsics& intrinsics)
{ {
std::lock_guard lock(ctrl_mtx_); std::lock_guard lock(ctrl_mtx_);
clear_error_(); clear_error_();
color.release();
if (mode_ == PHOTO_MODE) { if (mode_ == PHOTO_MODE) {
if (!state_.is_opened) { if (!state_.is_opened) {
state_.is_error = true; state_.is_error = true;
@ -254,15 +258,24 @@ void UVCCamera::getRGBImage(cv::Mat& color, Rs2Intrinsics& intrinsics)
return; return;
} }
{ const bool capture_worker_requested = state_.is_streaming || state_.is_recording;
std::lock_guard frame_lock(frame_mutex_); bool snapshot_timed_out = false;
if (!latest_frame_.empty()) { 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); latest_frame_.copyTo(color);
} }
snapshot_timed_out = !received_new_frame;
} }
else {
const bool capture_worker_requested = state_.is_streaming || state_.is_recording;
if (color.empty() && !capture_worker_requested) {
if (stream_thread_) { if (stream_thread_) {
if (stream_thread_->joinable()) { if (stream_thread_->joinable()) {
stream_thread_->join(); stream_thread_->join();
@ -282,7 +295,9 @@ void UVCCamera::getRGBImage(cv::Mat& color, Rs2Intrinsics& intrinsics)
if (color.empty()) { if (color.empty()) {
state_.is_error = true; 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; CMVR_LOG(ERROR) << "[UVCCamera] (getRGBImage): " << state_.error_message;
return; return;
} }
@ -563,7 +578,9 @@ void UVCCamera::streaming_worker_() {
{ {
std::lock_guard frame_lock(frame_mutex_); std::lock_guard frame_lock(frame_mutex_);
frame.copyTo(latest_frame_); frame.copyTo(latest_frame_);
++latest_frame_sequence_;
} }
frame_condition_.notify_all();
// 以下为编码部分,用于流模式 // 以下为编码部分,用于流模式
StreamFrameData frame_data; StreamFrameData frame_data;