FFmpeg RTSP推流fwrite优化:批量写入效率提升方案问询
问题描述
我已经搭建了FFmpeg流水线将视频帧推流至RTSP服务器,初始化代码如下:
FILE* openPipeLine = _popen("ffmpeg -f rawvideo -r 10 -video_size 1280x720 -pixel_format bgr24 -i pipe: -vcodec libx264 -crf 25 -pix_fmt yuv420p -f rtsp rtsp://localHost:8554/mystream", "wb");
随后通过循环处理视频帧,得到存储720x1280图像的Mat变量,使用fwrite逐帧写入管道的代码如下:
string filename = "file.mp4"; VideoCapture capture(filename); Mat frame; for( ; ; ) { capture >> frame; if(frame.empty()) break; fwrite(frame.data, 1, 1280 * 720 * 3, openPipeLine); }
目前运行正常,但单次fwrite耗时约0.1秒,需大幅提升效率。能否通过缓存多帧批量写入替代逐帧调用fwrite?或修改fwrite第二个参数实现优化?
优化方案
1. 多帧缓存批量写入
这是提升写入效率的核心有效方法,通过减少IO调用次数降低系统开销。具体实现思路:
- 预先分配一块足够大的内存缓冲区,比如一次性缓存8帧、16帧(可根据可用内存调整)
- 循环读取视频帧,将每帧数据复制到缓冲区的对应位置
- 当缓冲区存满设定的帧数,或者视频读取到末尾时,调用一次fwrite将整个缓冲区数据写入管道
- 写完后重置缓冲区计数,继续循环处理剩余帧
示例代码片段:
const int BATCH_FRAMES = 8; // 批量写入的帧数 const int FRAME_SIZE = 1280 * 720 * 3; vector<uchar> buffer(BATCH_FRAMES * FRAME_SIZE); int frame_count = 0; string filename = "file.mp4"; VideoCapture capture(filename); Mat frame; for( ; ; ) { capture >> frame; if(frame.empty()) break; // 将当前帧数据复制到缓冲区 memcpy(buffer.data() + frame_count * FRAME_SIZE, frame.data, FRAME_SIZE); frame_count++; // 缓冲区满则批量写入 if(frame_count == BATCH_FRAMES) { fwrite(buffer.data(), 1, BATCH_FRAMES * FRAME_SIZE, openPipeLine); frame_count = 0; } } // 写入剩余的不足一整批的帧 if(frame_count > 0) { fwrite(buffer.data(), 1, frame_count * FRAME_SIZE, openPipeLine); }
2. 调整fwrite参数的实际作用
fwrite的参数格式是fwrite(ptr, size, count, stream),总写入字节数为size*count。你当前的调用是按1字节为单位写入FRAME_SIZE个元素,若修改为fwrite(frame.data, FRAME_SIZE, 1, openPipeLine),只是参数组合方式不同,总写入字节数完全一致,底层IO逻辑没有本质变化,对性能提升几乎可以忽略,不是核心优化手段。
3. 额外优化建议
- 关闭用户态缓冲:调用
setvbuf(openPipeLine, NULL, _IONBF, 0)关闭FILE*的用户态缓冲,避免额外内存拷贝,让数据直接写入内核态管道(批量写入场景下收益会被弱化,但仍有帮助) - 替换底层IO函数:如果批量写入后效率仍不满足,可以考虑用
WriteFile(Windows)或write(Linux)替代fwrite,减少标准库封装开销,但要注意跨平台兼容性 - 优化FFmpeg编码参数:给FFmpeg添加
-preset ultrafast参数,让x264编码更快,避免编码端阻塞管道间接影响写入速度
内容的提问来源于stack exchange,提问作者user20623229
相关产品推荐
相关产品推荐

