#include "fps_counter.h" #include "video_saver.h" #include "virtual_device.h" #include "framebuffer.h" #include "hdmi_in.h" #include "kaylordut/log/logger.h" #include #include #include #include // 为了使用系统函数 #include // 为了使用 access 函数 int main(int argc, char **argv) { // 执行 framebuffer 设置命令 int result = system("sudo fbset -xres 1280 -yres 720"); if (result != 0) { KAYLORDUT_LOG_ERROR("Failed to set framebuffer resolution"); return -1; } std::string virtual_device = "/dev/video10"; // 检查虚拟设备是否存在 if (access(virtual_device.c_str(), F_OK) == -1) { // 如果不存在,创建虚拟设备 result = system("sudo modprobe v4l2loopback video_nr=10 card_label=\"HDMI_Capture\" exclusive_caps=1"); if (result != 0) { KAYLORDUT_LOG_ERROR("Failed to load v4l2loopback module"); return -1; } } std::stringstream ss; for (int i = 0; i < argc; ++i) { ss << argv[i] << " "; } KAYLORDUT_LOG_ERROR("Command: {}", ss.str()); std::string device = "/dev/video0"; HdmiIn hdmi_in(device); std::string fb = "/dev/fb0"; FrameBuffer frame_buffer(fb); int vd_fd = init_virtual_device(virtual_device, 1280, 720); if (vd_fd == -1) { KAYLORDUT_LOG_ERROR("Failed to initialize virtual device"); return -1; } cv::Mat frame; FPSCounter fps_counter; const std::chrono::milliseconds frame_duration(1000 / 25); auto next_frame_time = std::chrono::steady_clock::now(); frame = hdmi_in.get_next_frame(); if (frame.empty()) { KAYLORDUT_LOG_ERROR("Failed to get initial frame to determine video size"); return -1; } VideoSaver video_saver(25, frame.cols, frame.rows); std::thread writer_thread(virtual_device_writer, vd_fd); std::thread deleter_thread(VideoSaver::file_deleter); while (true) { auto start_time = std::chrono::steady_clock::now(); frame = hdmi_in.get_next_frame(); if (!frame.empty()) { double current_fps = fps_counter.update(); std::string fps_text = cv::format("FPS: %.1f", current_fps); cv::putText(frame, fps_text, cv::Point(20, 40), cv::FONT_HERSHEY_SIMPLEX, 1.2, CV_RGB(0, 255, 0), 2); frame_buffer.WriteFrameBuffer(frame); video_saver.write_frame(frame); { std::lock_guard lock(queue_mutex); frame_queue.push(frame.clone()); queue_cv.notify_one(); } } auto process_time = std::chrono::steady_clock::now() - start_time; next_frame_time += frame_duration; std::this_thread::sleep_until(next_frame_time); if (process_time > frame_duration) { // KAYLORDUT_LOG_ERROR("Frame processing took too long: {}ms", std::chrono::duration_cast(process_time).count()); } } { std::lock_guard lock(queue_mutex); stop_thread = true; queue_cv.notify_one(); } writer_thread.join(); VideoSaver::stop_file_deleter(); deleter_thread.join(); if (vd_fd != -1) { close(vd_fd); } return 0; }