finanl
This commit is contained in:
Binary file not shown.
@@ -14,49 +14,68 @@ using namespace std;
|
|||||||
using namespace cv;
|
using namespace cv;
|
||||||
using namespace chrono_literals;
|
using namespace chrono_literals;
|
||||||
|
|
||||||
|
// 全局变量
|
||||||
|
VideoCapture cap(0);
|
||||||
|
|
||||||
|
// 函数声明
|
||||||
|
//摄像头管道初始化
|
||||||
|
bool videoInit(VideoCapture &cap);
|
||||||
|
//ffmpeg管道初始化
|
||||||
|
FILE* pipeInit();
|
||||||
|
//对单个帧进行处理
|
||||||
|
bool processFrame(VideoCapture &cap, FILE* pipe, Mat &frame, int64 &count, chrono::steady_clock::time_point &t0);
|
||||||
|
//资源清理
|
||||||
|
void cleanup(FILE* pipe, VideoCapture &cap);
|
||||||
|
//主循环
|
||||||
|
void mainLoop(VideoCapture &cap, FILE* pipe);
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
VideoCapture cap(0);
|
// 初始化摄像头
|
||||||
// 直接传 MJPEG(本身就是全 I 帧)
|
if (!videoInit(cap))
|
||||||
// FILE *pipe = popen(
|
{
|
||||||
// "ffmpeg "
|
return -1;
|
||||||
// "-f rawvideo -pixel_format bgr24 -video_size 640x480 -framerate 30 "
|
}
|
||||||
// "-i - "
|
|
||||||
// "-c:v h264_rkmpp "
|
|
||||||
// "-rc_mode 2 " // CQP 模式
|
|
||||||
// "-qp_init 30 "
|
|
||||||
// "-profile baseline "
|
|
||||||
// "-g 1 " // 全 I 帧
|
|
||||||
// "-bf 0 "
|
|
||||||
// "-coder cavlc "
|
|
||||||
// "-8x8dct false "
|
|
||||||
// "-fflags nobuffer "
|
|
||||||
// "-flags low_delay "
|
|
||||||
// "-max_delay 0 "
|
|
||||||
// "-f rtsp -muxdelay 0.001 -rtsp_transport udp "
|
|
||||||
// "rtsp://192.168.12.1:8554/rtsp/test", "w");
|
|
||||||
|
|
||||||
// FILE *pipe = popen(
|
// 初始化FFmpeg管道
|
||||||
// "ffmpeg "
|
FILE *pipe = pipeInit();
|
||||||
// "-f rawvideo -pixel_format bgr24 -video_size 640x480 -framerate 30 "
|
if (!pipe)
|
||||||
// "-i - "
|
{
|
||||||
// "-c:v h264_rkmpp "
|
return -1;
|
||||||
// "-rc_mode 2 " // CQP 模式(最低延迟)
|
}
|
||||||
// "-qp_init 32 " // 初始 QP
|
|
||||||
// "-profile baseline " // baseline profile
|
|
||||||
// "-coder cavlc " // CAVLC 编码
|
|
||||||
// "-8x8dct false " // 禁用 8x8 DCT
|
|
||||||
// "-g 1 " // GOP=1(全 I 帧)
|
|
||||||
// "-bf 0 " // 无 B 帧
|
|
||||||
// "-fflags nobuffer " // 无缓冲
|
|
||||||
// "-flags low_delay " // 低延迟标志
|
|
||||||
// "-max_delay 0 " // 零延迟
|
|
||||||
// "-f rtsp -rtsp_transport udp "
|
|
||||||
// "rtsp://192.168.12.1:8554/rtsp/test",
|
|
||||||
// "w");
|
|
||||||
|
|
||||||
|
// 主处理循环
|
||||||
|
mainLoop(cap, pipe);
|
||||||
|
|
||||||
// UDP传输
|
// 清理资源
|
||||||
|
cleanup(pipe, cap);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 摄像头初始化
|
||||||
|
bool videoInit(VideoCapture &cap)
|
||||||
|
{
|
||||||
|
if (!cap.isOpened())
|
||||||
|
{
|
||||||
|
cerr << "摄像头打开失败,请重试" << endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 降低分辨率,固定MJPG编码
|
||||||
|
cap.set(CAP_PROP_FOURCC, VideoWriter::fourcc('M', 'J', 'P', 'G'));
|
||||||
|
cap.set(CAP_PROP_FRAME_WIDTH, 640);
|
||||||
|
cap.set(CAP_PROP_FRAME_HEIGHT, 480);
|
||||||
|
cap.set(CAP_PROP_FPS, 30);
|
||||||
|
cap.set(CAP_PROP_BUFFERSIZE, 1);
|
||||||
|
|
||||||
|
cout << "摄像头初始化成功" << endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FFmpeg管道初始化
|
||||||
|
FILE* pipeInit()
|
||||||
|
{
|
||||||
FILE *pipe = popen(
|
FILE *pipe = popen(
|
||||||
"ffmpeg "
|
"ffmpeg "
|
||||||
"-f rawvideo -pixel_format bgr24 -video_size 640x480 -framerate 30 "
|
"-f rawvideo -pixel_format bgr24 -video_size 640x480 -framerate 30 "
|
||||||
@@ -66,72 +85,97 @@ int main()
|
|||||||
"-profile baseline -coder cavlc "
|
"-profile baseline -coder cavlc "
|
||||||
"-g 1 -bf 0 "
|
"-g 1 -bf 0 "
|
||||||
"-fflags nobuffer -flags low_delay "
|
"-fflags nobuffer -flags low_delay "
|
||||||
"-f h264 udp://192.168.12.1:8888?pkt_size=1316", "w");
|
"-f h264 udp://192.168.12.1:8888?pkt_size=1316",
|
||||||
|
"w");
|
||||||
|
|
||||||
if (pipe)
|
|
||||||
{
|
|
||||||
setvbuf(pipe, NULL, _IONBF, 0); // 添加无缓冲模式
|
|
||||||
}
|
|
||||||
if (!pipe)
|
if (!pipe)
|
||||||
{
|
{
|
||||||
cerr << "popen faild\n";
|
cerr << "FFmpeg管道打开失败" << endl;
|
||||||
return -1;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cap.isOpened() == false)
|
// 设置无缓冲模式
|
||||||
|
setvbuf(pipe, NULL, _IONBF, 0);
|
||||||
|
cout << "FFmpeg管道初始化成功" << endl;
|
||||||
|
|
||||||
|
return pipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理单帧
|
||||||
|
bool processFrame(VideoCapture &cap, FILE* pipe, Mat &frame, int64 &count, chrono::steady_clock::time_point &t0)
|
||||||
|
{
|
||||||
|
// 读取帧
|
||||||
|
cap.read(frame);
|
||||||
|
if (frame.empty())
|
||||||
{
|
{
|
||||||
cerr << "摄像头打开失败,请重试" << endl;
|
cerr << "读取帧失败" << endl;
|
||||||
return -1;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 降低分辨率,固定MJPG编码
|
// 添加提示文本
|
||||||
cap.set(CAP_PROP_FOURCC, VideoWriter::fourcc('M', 'J', 'P', 'G'));
|
putText(frame, "press 'q' to quit", Point(0, 20),
|
||||||
cap.set(CAP_PROP_FRAME_WIDTH, 640);
|
FONT_HERSHEY_SIMPLEX, 1.0, Scalar(0, 255, 0), 2, LINE_8);
|
||||||
cap.set(CAP_PROP_FRAME_HEIGHT, 480);
|
|
||||||
cap.set(CAP_PROP_FPS, 30);
|
|
||||||
|
|
||||||
cap.set(CAP_PROP_BUFFERSIZE, 1);
|
// FPS计算与显示
|
||||||
|
++count;
|
||||||
|
auto now = chrono::steady_clock::now();
|
||||||
|
if (chrono::duration_cast<chrono::milliseconds>(now - t0).count() / 1000.0 > 1.0)
|
||||||
|
{
|
||||||
|
string fps = "FPS:" + to_string(count);
|
||||||
|
count = 0;
|
||||||
|
t0 = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 写入管道
|
||||||
|
fwrite(frame.data, 1, frame.total() * frame.elemSize(), pipe);
|
||||||
|
fflush(pipe);
|
||||||
|
|
||||||
|
// 可选:显示窗口
|
||||||
|
// imshow("测试画面", frame);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 主处理循环
|
||||||
|
void mainLoop(VideoCapture &cap, FILE* pipe)
|
||||||
|
{
|
||||||
int64 count = 0;
|
int64 count = 0;
|
||||||
auto t0 = chrono::steady_clock::now();
|
auto t0 = chrono::steady_clock::now();
|
||||||
|
|
||||||
Mat frame;
|
Mat frame;
|
||||||
|
|
||||||
|
cout << "开始视频处理循环..." << endl;
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
cap.read(frame);
|
if (!processFrame(cap, pipe, frame, count, t0))
|
||||||
if (frame.empty())
|
|
||||||
{
|
{
|
||||||
cerr << "读取帧失败" << endl;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
putText(frame, "press 'q' to quit", Point(0, 20), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(0, 255, 0), 2, LINE_8);
|
// 检测退出键
|
||||||
|
|
||||||
++count;
|
|
||||||
auto now = chrono::steady_clock::now();
|
|
||||||
string fps;
|
|
||||||
if (chrono::duration_cast<chrono::milliseconds>(now - t0).count() / 1000.0 > 1.0)
|
|
||||||
{
|
|
||||||
fps = "FPS:" + to_string(count);
|
|
||||||
setWindowTitle("测试画面", fps);
|
|
||||||
count = 0;
|
|
||||||
t0 = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
fwrite(frame.data, 1, frame.total() * frame.elemSize(), pipe);
|
|
||||||
fflush(pipe); // 立即刷新
|
|
||||||
// imshow("测试画面", frame);
|
|
||||||
|
|
||||||
// 按下 'q' 键退出
|
|
||||||
if (cv::waitKey(1) == 'q')
|
if (cv::waitKey(1) == 'q')
|
||||||
{
|
{
|
||||||
|
cout << "用户请求退出" << endl;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// 释放资源
|
|
||||||
pclose(pipe);
|
// 资源清理
|
||||||
cap.release();
|
void cleanup(FILE* pipe, VideoCapture &cap)
|
||||||
destroyAllWindows();
|
{
|
||||||
return 0;
|
if (pipe)
|
||||||
|
{
|
||||||
|
pclose(pipe);
|
||||||
|
cout << "FFmpeg管道已关闭" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cap.isOpened())
|
||||||
|
{
|
||||||
|
cap.release();
|
||||||
|
cout << "摄像头已释放" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
destroyAllWindows();
|
||||||
|
cout << "所有资源已清理完毕" << endl;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user