OpenCV结合Intel Quick Sync的4K实时视频编码优化咨询
问题背景
计划开发一款从4K摄像头采集帧数据并同步编码的软件,目前已实现帧采集、压缩生成.h264文件的基础功能,但存在明显性能瓶颈:目标输出视频帧率为10FPS,实际编码过程中无法采集全部帧,整体处理帧率仅为3-5FPS。
经代码排查,编码模块性能符合预期,耗时过高的环节为BGR->YUV色彩空间转换:单帧BGR转YUV耗时约0.20s(对应约5FPS处理能力),编码环节单帧仅耗时0.045s(对应约20FPS处理能力)。当前软件运行在专用设备上,硬件配置为:
- GPU: Intel(R) UHD Graphics 620
- CPU: Intel Core i5-8350U 1.70GHz(8逻辑核心)
设备仅搭载Intel集成显卡,无法使用基于NVIDIA GPU的FFmpeg加速方案,需要可行的性能提速方案。
现有实现代码
主函数代码
int main() { Mat frame; VideoCapture vcap(0); vcap.set(3, 3840); vcap.set(4, 2160); if (!vcap.isOpened()) { std::cout << "Error opening video stream or file" << std::endl; return -1; } int frame_width = vcap.get(3); int frame_height = vcap.get(4); VideoWriter video; std::cout << video.open("out.h264", CAP_INTEL_MFX, VideoWriter::fourcc('H', '2', '6', '4'), 10, Size(frame_width, frame_height), true); for (;;) { vcap >> frame; video.write(frame); } return -1; }
性能瓶颈定位
经定位,OpenCV中每帧调用的VideoWriter_IntelMFX::write_one()函数负责帧格式转换与编码,其中cvtBGRtoTwoPlaneYUV()函数执行BGR->YUV转换,单帧耗时达200ms,该函数实现代码如下:
bool VideoWriter_IntelMFX::write_one(cv::InputArray bgr) { mfxStatus res; mfxFrameSurface1 *workSurface = 0; mfxSyncPoint sync; clock_t start1 = clock(); if (!bgr.empty() && (bgr.dims() != 2 || bgr.type() != CV_8UC3 || bgr.size() != frameSize)) { MSG(cerr << "MFX: invalid frame passed to encoder: " << "dims/depth/cn=" << bgr.dims() << "/" << bgr.depth() << "/" << bgr.channels() << ", size=" << bgr.size() << endl); return false; } if (!bgr.empty()) { workSurface = pool->getFreeSurface(); if (!workSurface) { // not enough surfaces MSG(cerr << "MFX: Failed to get free surface" << endl); return false; } Mat src = bgr.getMat(); hal::cvtBGRtoTwoPlaneYUV(src.data, src.step, workSurface->Data.Y, workSurface->Data.UV, workSurface->Data.Pitch, workSurface->Info.CropW, workSurface->Info.CropH, 3, false, 1); } clock_t end1 = clock(); clock_t start = clock(); while (true) { outSurface = 0; DBG(cout << "Calling with surface: " << workSurface << endl); res = encoder->EncodeFrameAsync(NULL, workSurface, &bs->stream, &sync); if (res == MFX_ERR_NONE) { res = session->SyncOperation(sync, getWriterTimeoutMS()); if (res == MFX_ERR_NONE) { if (!bs->write()) { MSG(cerr << "MFX: Failed to write bitstream" << endl); return false; } else { DBG(cout << "Write bitstream" << endl); clock_t end = clock(); frame_info[0] += (double(end - start) / CLOCKS_PER_SEC); frame_info[2] += (double(end1 - start1) / CLOCKS_PER_SEC); frame_info[1]++; return true; } } else { MSG(cerr << "MFX: Sync error: " << res << endl); return false; } } else if (res == MFX_ERR_MORE_DATA) { DBG(cout << "ERR_MORE_DATA" << endl); return false; } else if (res == MFX_WRN_DEVICE_BUSY) { DBG(cout << "Waiting for device" << endl); sleep_ms(1000); continue; } else { MSG(cerr << "MFX: Bad status: " << res << endl); return false; } } }
可行性能优化方案
- 优先从采集端规避格式转换开销:检查摄像头驱动是否支持直接输出NV12/YUV420格式帧,直接输出的帧可以送入MFX编码器,完全跳过BGR转YUV的CPU计算环节,这是收益最高的优化方向。
- 替换色彩空间转换实现:现有OpenCV自带的
hal::cvtBGRtoTwoPlaneYUV是未做指令集优化的单线程CPU实现,可替换为Intel IPP库、或者编译OpenCV时开启IPP/AVX2优化的cvtColor实现,针对i5-8350U的AVX2指令集优化后,单帧4K BGR转NV12的耗时可以降到30ms以内。 - 硬件加速色彩转换:利用UHD620核显的Quick Sync视频处理模块做BGR到NV12的格式转换,转换后的显存表面直接送入MFX编码器,不需要在CPU和GPU之间做帧数据拷贝,端到端单帧转换+拷贝耗时可以降到10ms以内。
- 流水线并行处理:拆分为三个独立线程:采集线程负责拉取摄像头帧存入帧队列,转换线程从队列取帧做BGR转YUV存入编码队列,编码线程从编码队列取帧送硬件编码,避免串行流程下转换阻塞采集和编码环节,8逻辑核心的CPU可以充分利用多核资源。
- 编译选项优化:编译代码时开启
-O3优化、启用AVX2指令集支持,关闭不必要的调试宏,默认Debug编译下的色彩转换性能会比Release版本低60%以上。
现有代码里遇到
MFX_WRN_DEVICE_BUSY时直接sleep 1s的逻辑会严重拉低编码帧率,正常核显繁忙等待只需要sleep 1-5ms重试即可,1s的等待会直接导致期间丢10帧以上。
内容的提问来源于stack exchange,提问作者Batuhan Zorlu
相关产品推荐
相关产品推荐

