fix(camera): prevent double free in UVC recording
This commit is contained in:
parent
e94db8b66c
commit
5f4e3897ac
@ -45,6 +45,7 @@ namespace cmvr::device {
|
||||
private:
|
||||
void streaming_worker_();
|
||||
void recording_worker_();
|
||||
void cleanup_recording_resources_();
|
||||
|
||||
int fps_;
|
||||
int width_;
|
||||
|
||||
@ -181,7 +181,7 @@ bool UVCCamera::start() {
|
||||
|
||||
bool UVCCamera::stop() {
|
||||
//先停止录制再关闭摄像头
|
||||
if (state_.is_recording) {
|
||||
if (state_.is_recording || recording_thread_ || packet_ || format_context_ || stream_) {
|
||||
stopRecording();
|
||||
}
|
||||
std::lock_guard lock(ctrl_mtx_);
|
||||
@ -278,6 +278,22 @@ void UVCCamera::getRGBDImages(cv::Mat &color, cv::Mat &depth, Rs2Intrinsics& int
|
||||
depth.release();
|
||||
}
|
||||
|
||||
void UVCCamera::cleanup_recording_resources_() {
|
||||
if (packet_) {
|
||||
av_packet_free(&packet_);
|
||||
}
|
||||
|
||||
if (format_context_) {
|
||||
if (!(format_context_->oformat->flags & AVFMT_NOFILE) && format_context_->pb) {
|
||||
avio_closep(&format_context_->pb);
|
||||
}
|
||||
avformat_free_context(format_context_);
|
||||
format_context_ = nullptr;
|
||||
}
|
||||
|
||||
stream_ = nullptr;
|
||||
}
|
||||
|
||||
void UVCCamera::startRecording(const std::string &video_path) {
|
||||
std::lock_guard lock(ctrl_mtx_);
|
||||
clear_error_();
|
||||
@ -300,18 +316,6 @@ void UVCCamera::startRecording(const std::string &video_path) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto cleanup_recording_resources = [this]() {
|
||||
if (packet_) av_packet_free(&packet_);
|
||||
if (stream_ && stream_->codecpar->extradata) av_free(stream_->codecpar->extradata);
|
||||
if (format_context_) {
|
||||
if (!(format_context_->oformat->flags & AVFMT_NOFILE) && format_context_->pb) avio_closep(&format_context_->pb);
|
||||
avformat_free_context(format_context_);
|
||||
}
|
||||
stream_ = nullptr;
|
||||
format_context_ = nullptr;
|
||||
state_.is_recording = false;
|
||||
};
|
||||
|
||||
try {
|
||||
current_video_path_ = video_path;
|
||||
std::string temp_path = current_video_path_ + ".temp"; // 临时文件
|
||||
@ -348,7 +352,7 @@ void UVCCamera::startRecording(const std::string &video_path) {
|
||||
state_.is_error = true;
|
||||
state_.error_message = "failed to create video stream";
|
||||
CMVR_LOG(ERROR) << "[UVCCamera] (startRecording): " << state_.error_message;
|
||||
cleanup_recording_resources();
|
||||
cleanup_recording_resources_();
|
||||
return;
|
||||
}
|
||||
stream_ = stream;
|
||||
@ -366,7 +370,7 @@ void UVCCamera::startRecording(const std::string &video_path) {
|
||||
state_.is_error = true;
|
||||
state_.error_message = "failed to allocate extradata";
|
||||
CMVR_LOG(ERROR) << "[UVCCamera] (startRecording): " << state_.error_message;
|
||||
cleanup_recording_resources();
|
||||
cleanup_recording_resources_();
|
||||
return;
|
||||
}
|
||||
memcpy(codecpar->extradata, rgbEncoder_->codec_context->extradata, rgbEncoder_->codec_context->extradata_size);
|
||||
@ -379,7 +383,7 @@ void UVCCamera::startRecording(const std::string &video_path) {
|
||||
state_.is_error = true;
|
||||
state_.error_message = "failed to open output file: " + temp_path;
|
||||
CMVR_LOG(ERROR) << "[UVCCamera] (startRecording): " << state_.error_message;
|
||||
cleanup_recording_resources();
|
||||
cleanup_recording_resources_();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -389,7 +393,7 @@ void UVCCamera::startRecording(const std::string &video_path) {
|
||||
state_.is_error = true;
|
||||
state_.error_message = "failed to write file header";
|
||||
CMVR_LOG(ERROR) << "[UVCCamera] (startRecording): " << state_.error_message;
|
||||
cleanup_recording_resources();
|
||||
cleanup_recording_resources_();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -399,7 +403,7 @@ void UVCCamera::startRecording(const std::string &video_path) {
|
||||
state_.is_error = true;
|
||||
state_.error_message = "failed to allocate AVPacket";
|
||||
CMVR_LOG(ERROR) << "[UVCCamera] (startRecording): " << state_.error_message;
|
||||
cleanup_recording_resources();
|
||||
cleanup_recording_resources_();
|
||||
return;
|
||||
}
|
||||
//不在录像也不在流传输,但是采集线程没有退出时。
|
||||
@ -432,7 +436,8 @@ void UVCCamera::startRecording(const std::string &video_path) {
|
||||
recording_thread_ = make_shared<thread>(&UVCCamera::recording_worker_, this);
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
cleanup_recording_resources();
|
||||
cleanup_recording_resources_();
|
||||
state_.is_recording = false;
|
||||
state_.is_error = true;
|
||||
state_.error_message = "[UVCCamera] (startRecording): " + std::string(e.what());
|
||||
CMVR_LOG(ERROR) << state_.error_message;
|
||||
@ -448,36 +453,24 @@ void UVCCamera::stopRecording() {
|
||||
CMVR_LOG(ERROR) << "[UVCCamera] (stopRecording): " << state_.error_message;
|
||||
return;
|
||||
}
|
||||
if (!state_.is_recording) {
|
||||
const bool has_recording_resources =
|
||||
recording_thread_ || packet_ || format_context_ || stream_;
|
||||
if (!state_.is_recording && !has_recording_resources) {
|
||||
CMVR_LOG(WARNING) << "[UVCCamera] (stopRecording): not recording";
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. 停止录像线程
|
||||
state_.is_recording = false;
|
||||
if (recording_thread_ && recording_thread_->joinable()) {
|
||||
recording_thread_->join();
|
||||
if (recording_thread_) {
|
||||
if (recording_thread_->joinable()) {
|
||||
recording_thread_->join();
|
||||
}
|
||||
recording_thread_.reset();
|
||||
}
|
||||
|
||||
// 2. 清理FFmpeg资源
|
||||
if (packet_) {
|
||||
av_packet_free(&packet_);
|
||||
packet_ = nullptr;
|
||||
}
|
||||
if (stream_ && stream_->codecpar->extradata) {
|
||||
av_free(stream_->codecpar->extradata);
|
||||
stream_->codecpar->extradata = nullptr;
|
||||
stream_->codecpar->extradata_size = 0;
|
||||
}
|
||||
if (format_context_) {
|
||||
if (!(format_context_->oformat->flags & AVFMT_NOFILE) && format_context_->pb) {
|
||||
avio_closep(&format_context_->pb); // 关闭文件
|
||||
}
|
||||
avformat_free_context(format_context_); // 释放格式上下文
|
||||
format_context_ = nullptr;
|
||||
}
|
||||
stream_ = nullptr;
|
||||
cleanup_recording_resources_();
|
||||
|
||||
// 3. 重命名临时文件为目标文件
|
||||
std::string temp_path = current_video_path_ + ".temp";
|
||||
|
||||
Loading…
Reference in New Issue
Block a user