Вопрос или проблема
Я пытаюсь захватить поток и записать его на куски по 30 секунд. Я не знаю, какова будет частота кадров у камер, поэтому мне нужно учитывать, что я хочу захватывать только 15 fps.
Моя проблема в том, что следующий код генерирует куски в 28 секунд вместо 30. Как мне правильно настроить тайминг?
Я не новичок в C++, но немного зашел в ржавчину и никогда не делал ничего подобного раньше (обычно это простые ввод/вывод или в контексте разработки простых игр).
Должно быть, что-то не так с математикой или я делаю что-то, что вызывает задержку в обработке, или просто слишком долго смотрю на это и пропускаю что-то очевидное (вероятно).
Вот что я пробовал до сих пор:
int frame_count = 0;
double frame_duration = 1.0 / currentCameraConfig.fps;
auto start_time = std::chrono::steady_clock::now();
while (true) {
cv::Mat frame;
if (!cap.read(frame)) {
break;
}
frame_count++;
auto now = std::chrono::steady_clock::now();
auto elapsed_time = std::chrono::duration_cast<std::chrono::seconds>(now - start_time).count();
if (elapsed_time < 30) {
video_output.write(frame);
std::cout << "[INFO]: elapsed time " << elapsed_time << std::endl;
std::cout << "[INFO]: Saving video frame " << frame_count << " at " << currentCameraConfig.fps << " fps....cam " << std::endl;
}
if (cv::waitKey(1) == 'q' || elapsed_time >= 30) {
std::cout << "\n [INFO]: Stopping recording..." << std::endl;
break;
}
auto frame_end_time = std::chrono::steady_clock::now();
auto frame_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(frame_end_time - now).count();
int sleep_time = static_cast<int>((frame_duration * 1000) - frame_elapsed);
if (sleep_time > 0) {
std::this_thread::sleep_for(std::chrono::milliseconds(sleep_time));
}
}
cap.release();
video_output.release();
std::cout << "Video saved successfully.!" << std::endl;
Ответ или решение
Чтобы создать точный таймер в цикле записи потокового видео RTSP и разбивать его на 30-секундные фрагменты при частоте кадров в 15 FPS, нужно учитывать различные факторы, которые могут вызвать задержки и некорректное время захвата. Я уточню ваш код и предложу оптимизации, чтобы достичь желаемого поведения.
Оптимизированный код
#include <iostream>
#include <chrono>
#include <thread>
#include <opencv2/opencv.hpp>
void capture_stream(cv::VideoCapture& cap, cv::VideoWriter& video_output, double target_fps) {
int frame_count = 0;
double target_frame_duration = 1.0 / target_fps; // полное время фрейма (в секундах)
auto start_time = std::chrono::steady_clock::now();
while (true) {
cv::Mat frame;
if (!cap.read(frame)) {
std::cerr << "[ERROR]: Не удалось прочитать кадр." << std::endl;
break;
}
frame_count++;
video_output.write(frame);
auto now = std::chrono::steady_clock::now();
auto elapsed_time = std::chrono::duration_cast<std::chrono::seconds>(now - start_time).count();
std::cout << "[INFO]: elasped time: " << elapsed_time << " seconds" << std::endl;
std::cout << "[INFO]: Saving video frame " << frame_count << " at " << target_fps << " fps." << std::endl;
// Проверка времени записи
if (elapsed_time >= 30) {
std::cout << "[INFO]: Достигнуто время записи. Остановка..." << std::endl;
break;
}
// Подсчет времени прошедшего с начала обработки кадра
auto frame_start_time = std::chrono::steady_clock::now();
auto frame_elapsed_time = std::chrono::duration_cast<std::chrono::milliseconds>(frame_start_time - now).count();
// Расчет времени ожидания до следующего кадра
int sleep_time = static_cast<int>((target_frame_duration * 1000) - frame_elapsed_time);
if (sleep_time > 0) {
std::this_thread::sleep_for(std::chrono::milliseconds(sleep_time));
}
}
cap.release();
video_output.release();
std::cout << "[INFO]: Видео успешно сохранено!" << std::endl;
}
int main() {
cv::VideoCapture cap("rtsp://your_camera_stream");
if (!cap.isOpened()) {
std::cerr << "[ERROR]: Не удалось открыть поток." << std::endl;
return -1;
}
cv::VideoWriter video_output("output.avi", cv::VideoWriter::fourcc('M', 'J', 'P', 'G'), 15, cv::Size(640, 480)); // Убедитесь в правильных параметрах вывода
capture_stream(cap, video_output, 15.0);
return 0;
}
Объяснение изменений и оптимизаций:
-
Параллельная обработка времени: Я добавил переменную
frame_start_time
, чтобы точно отслеживать, сколько времени уходит на обработку каждого кадра. Это позволяет более точно вычислить, сколько времени нам еще нужно подождать до следующего кадра. -
Запись видео: Запись фреймов выполняется вне временной проверки, чтобы удостовериться, что мы записываем все захваченные кадры до достижения 30 секунд.
-
Устранение задержек: Убедитесь, что задержка между кадрами учитывает фактическое время обработки, таким образом мы минимизируем неоптимальные временные задержки.
-
Проверка ошибок: Я добавил базовую обработку ошибок для проверки, открывается ли поток и считываются ли кадры.
-
Запись до полной 30-секундной отметки: Мы продолжаем записывать видео до достижения отметки в 30 секунд, а не останавливаем обработку при превышении 30 секунд.
Следуя описанным рекомендациям, вы сможете получить более точное управление временем записи и избежать неожиданной потери кадров.