你好 本文是
我的FFmpeg文章(继续
Visual Studio )的延续
。 在这里,我们开始进行全高清RTSP流的硬件解码。 我会事先说,即使是Intel ATOM Z8350也可以轻松地完成此任务。
目标:硬件解码并在RAM中记录多达4帧,以便通过RTSP h.264 IP摄像机进行后续并行处理(四个处理器内核)。 我使用WinAPI函数显示已处理的帧。 结果,我们得到了用于并行模式下RTSP流的计算机处理的高速系统。 接下来,您可以连接
计算机视觉算法来处理
实时帧。
参赛作品
为什么需要硬件解码? 您想使用性能低廉且价格便宜的处理器解码实时视频,或者要尽可能多地卸载处理器,那么该是时候熟悉硬件解码了。
DirectX视频加速 (DXVA)是一种API,用于使用硬件加速来加速GPU的视频处理。 DXVA 2.0允许您将更多操作重定向到GPU,包括视频捕获和视频处理操作。
在写完上一篇文章之后,我被问了很多问题:“为什么使用FFmpeg?” 我将从问题开始。 硬件解码的主要困难是将解码后的帧写入RAM。 对于全高清,这是1920 x 1080 x 3 = 6,220,800字节。 即使考虑到帧是以NV12格式存储的事实,这也是很多1920 x 1080 x 1.5 = 3110400字节。 对于任何处理器而言,每秒覆盖75 MB都是一项艰巨的任务。 为解决此问题,英特尔增加了SSE 4命令,使您无需处理器即可重写数据。 不幸的是,并不是所有的库都实现了这一功能。 我已经测试了以下库:
- ffmpeg
- VLC
- Opencv的
VLC-通过硬件解码(非常低的处理器负载)与IP摄像机配合使用,仅用10行代码即可构建原始的RTSP流播放器,但是在RAM中接收解码的帧会占用过多的处理器时间。
OpenCV -RTSP使用FFmpeg来处理流,因此决定在没有中介的情况下工作,即 使用FFmpeg库。 此外,默认情况下安装的FFmpeg是在OpenCV中内置的,无需硬件解码。
FFmpeg-在我看来,效果很好,运行稳定。 唯一的缺点是无法在Windows中使用X86版的WEB相机(X64似乎允许您工作)来实现。
硬件视频解码很容易
实际上,使用FFmpeg库进行硬件解码并不比软件复杂。 项目设置与软件实施相同,框图保持不变。
您可以显示FFmpeg支持的硬件解码方法的列表。
fprintf(stderr, " %s", av_hwdevice_get_type_name(type));
我们需要做的第一件事是告诉FFmpeg您要使用哪个硬件解码器解码视频。 就我而言,Windows10 + Intel Atom Z8350仅保留DXVA2:
type = av_hwdevice_find_type_by_name("dxva2");
您可以选择CUDA,D3D11VA,QSV或VAAPI(仅Linux)作为硬件解码器。 因此,您应该具有此硬件解决方案,并且应该在其支持下构建FFmpeg。
打开视频流:
avformat_open_input(&input_ctx, filename, NULL, NULL;
我们获得有关视频流的信息:
av_find_best_stream(input_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0);
分配内存:
frame = av_frame_alloc();
此函数覆盖RAM中的解码文件:
av_hwframe_transfer_data(sw_frame, frame, 0);
关于NV12格式的一些知识
因此,我们在sw_frame结构中获得了一个框架。 接收到的帧以NV12格式存储。 此格式由Microsoft发明。 它允许您以12位存储像素信息。 其中8位是强度,4位描述了颜色(或者,立即为4个相邻的2x2像素描述了颜色)。 此外,sw_frame.data [0]-强度被存储,而sw_frame.data [1]-颜色被存储。 要将NV-12转换为RGB,可以使用以下功能:
从NV12到RGB的C ++转换 void SaveFrame(uint8_t * f1, uint8_t * f2, int iFrame) { FILE *pFile; char szFilename[32]; int x, i, j;
尽管使用NV12可以使您加快诸如模糊,Retinex和获取灰度图像的过程(仅通过丢弃颜色)即可。 在我的任务中,我不会将NV12格式转换为RGB,因为这会花费额外的时间。
因此,我们学习了如何在硬件中解码视频文件并将其显示在窗口中。 我们遇到了NV12格式,以及如何将其转换为熟悉的RGB。
DLL硬件解码
FFmpeg在40毫秒后发出帧(每秒25帧)。 通常,处理全高清帧会花费更长的时间。 这需要多线程以最大化所有4个处理器内核的负载。 实际上,我只启动6个线程,不再删除它们,这大大简化了工作并提高了程序的可靠性。 工作方案如图。 1个
图1使用FFmpeg构建多线程程序的方案我将解码器写为
* .dll (FFmpegD.DLL),以便包含在我的项目中。 这使您可以减少项目的代码,从而增加对代码的理解,并将其包括在任何编程语言中,直至汇编语言(已验证:))。 使用它,我们将从IP摄像机编写RTSP流播放器。
要开始使用DLL,您需要将指针传递给int [13]数组,新帧到达事件的HANDLE,开始处理来自相机的新数据包的HANDLE以及相机地址的char数组。
表1给出了数组结构。

呼叫之前,必须重设帧号1-4。
DLL将采取所有必要的步骤来初始化FFmpeg,并将记录指针和帧号。 之后,将事件设置为“新帧到达”。 只需要处理传入的帧并写入0而不是帧号(这意味着该帧已被处理并且不再使用)。
在下面,您将找到带有源代码的示例播放器。 该示例是ShowDib3 Charles Petzold。
→
随项目存档→
FFmpegD.dll存档结果:即使在Intel Atom Z8350上,FFmpeg硬件运动检测器也可通过连接的运动检测器实时解码h264 Full HD,处理器负载高达20%。
英特尔ATOM Z8350上的运动检测器操作示例。 前30秒是背景的计算。 此后,运动检测器通过减去背景的方法工作。PS您还可以解码视频文件(压缩的h.264)!
参考文献:
- 有关FFmpeg的其他有用信息
- 有关使用FFmpeg提供的各种库的信息
- 有关格式和转换为RGB的信息