fix(camera): preserve UVC recording timing
This commit is contained in:
parent
5f4e3897ac
commit
bb6c627fad
@ -3,6 +3,8 @@
|
||||
// Created by xtkuang on 2025/5/30.
|
||||
//
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "../include/uvc_camera.h"
|
||||
|
||||
using namespace std;
|
||||
@ -361,7 +363,9 @@ void UVCCamera::startRecording(const std::string &video_path) {
|
||||
codecpar->codec_id = codec_id;
|
||||
codecpar->width = width_;
|
||||
codecpar->height = height_;
|
||||
stream->time_base = {1, fps_}; // 时间基:1/fps(每帧间隔1个时间单位)
|
||||
// Use a fine-grained time base because the actual UVC frame rate can
|
||||
// differ significantly from the configured frame rate.
|
||||
stream->time_base = {1, 1'000'000};
|
||||
|
||||
// 4. 复制编码器的extradata(如H.264的SPS/PPS,确保播放器能解析)
|
||||
if (rgbEncoder_ && rgbEncoder_->codec_context && rgbEncoder_->codec_context->extradata) {
|
||||
@ -665,6 +669,8 @@ void UVCCamera::recording_worker_() {
|
||||
is_recording_running = true;
|
||||
const int frame_interval = 1000 / fps_;
|
||||
bool is_first_key = false;
|
||||
int64_t first_capture_monotonic_ns = 0;
|
||||
int64_t last_packet_pts = AV_NOPTS_VALUE;
|
||||
try {
|
||||
//保证当前采集线程正常运行
|
||||
while (state_.is_recording && is_streaming_running) {
|
||||
@ -707,25 +713,33 @@ void UVCCamera::recording_worker_() {
|
||||
packet_->size = static_cast<int>(frame_data.rgbFrame.size());
|
||||
packet_->stream_index = stream_->index; // 指定流索引
|
||||
|
||||
// 设置时间戳(递增)
|
||||
packet_->pts = frame_count_++;
|
||||
packet_->dts = packet_->pts;
|
||||
packet_->duration = 1; // 每帧持续1个时间单位(根据time_base)
|
||||
// Preserve real capture time so dropped/late frames do not speed up playback.
|
||||
if (first_capture_monotonic_ns == 0) {
|
||||
first_capture_monotonic_ns = frame_data.capture_monotonic_ns;
|
||||
}
|
||||
const int64_t elapsed_ns = std::max<int64_t>(
|
||||
0, frame_data.capture_monotonic_ns - first_capture_monotonic_ns);
|
||||
int64_t packet_pts = av_rescale_q(
|
||||
elapsed_ns, AVRational{1, 1'000'000'000}, stream_->time_base);
|
||||
if (last_packet_pts != AV_NOPTS_VALUE && packet_pts <= last_packet_pts) {
|
||||
packet_pts = last_packet_pts + 1;
|
||||
}
|
||||
packet_->pts = packet_pts;
|
||||
packet_->dts = packet_pts;
|
||||
packet_->duration = av_rescale_q(
|
||||
1, AVRational{1, fps_}, stream_->time_base);
|
||||
last_packet_pts = packet_pts;
|
||||
++frame_count_;
|
||||
|
||||
// 标记关键帧
|
||||
if (frame_data.bKey) {
|
||||
packet_->flags |= AV_PKT_FLAG_KEY;
|
||||
}
|
||||
|
||||
// 转换时间基
|
||||
av_packet_rescale_ts(packet_, {1, fps_}, stream_->time_base);
|
||||
|
||||
// 写入帧
|
||||
if (av_interleaved_write_frame(format_context_, packet_) < 0) {
|
||||
CMVR_LOG(ERROR) << "写入第" << frame_count_ << "帧失败";
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(33));
|
||||
}
|
||||
|
||||
// 7. 写入文件尾(完成封装)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user