111 lines
3.5 KiB
C++
111 lines
3.5 KiB
C++
![]() |
#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 <opencv2/opencv.hpp>
|
||
|
#include <thread>
|
||
|
#include <unistd.h>
|
||
|
#include <cstdlib> // 为了使用系统函数
|
||
|
#include <sys/stat.h> // 为了使用 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<std::mutex> 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<std::chrono::milliseconds>(process_time).count());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
{
|
||
|
std::lock_guard<std::mutex> 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;
|
||
|
}
|