当前位置: 首页 > article >正文

解决GB28181对接RTSP倍速播放导致FFmpeg缓冲区满导致花屏问题

在GB28181协议对接RTSP流时,倍速播放会导致FFmpeg缓冲区溢出,进而造成花屏问题。这是由于倍速播放增加了数据流的处理速度,而FFmpeg的缓冲区未能及时处理这些增量数据,导致视频帧丢失或渲染错误。为解决此问题,可能需要优化数据缓存策略或调整流的处理速率,确保FFmpeg能够稳定地处理高吞吐量的视频流。

下面是我在网上找到的一些思路及方法:
大华、海康和华为等NVR录像机gb28181平台倍速播放原理 - 阿风小子 - 博客园

基本原理如下:
因为这些平台都不会牵扯到编解码,所以只能在编码后的数据进行处理,原始的编码数据来源于相机(大部分),所以对于安防,编码的源头在相机端,这是一个大致前提。

平台收到相机编码后的数据后,如果要进行倍速播放,那怎么发送数据呢?策略如下:
1、4倍以下,按照全帧率4倍码流发送数据,即1s发送100帧(假设25fps),注意这里对dts和pts不做任何修改。
2、4倍以上,只发送I帧数据。这里也不修改dits和pts.

我们收到数据后直接播放会出现什么问题呢?
1、如果我们收到的100fps,但是此时dts和pts却没有改变,播放器播放的时候会出现跳秒和花屏现象。为什么呢?
这是因为dts和pts没有修改,播放器还是按照正常dts和pts速率来解码播放,导致缓存长满,这时候播放器一般会丢包处理,丢包后刚好这一段数据中包含I帧,那么就会出现花屏现象。
2、如果按照只接受I帧来收数据,如果不修改dts和pts就会出现非常严重的卡顿,因为还是按照原来的dts和pts来解码播放。
所以这时候就必须修改dts和pts,同时将编码端的gop调整到25左右,不然,如果gop是50那么2s才会发一帧数据,假设8倍速率,也就是4帧每秒,这可不行,最好设置为gop25,那么8倍就是8帧,16倍就是16帧,凑合着可以看呢。

如果你要对接NVR28181平台的倍速播放功能,就是拉流后对dts和pts进行修改,因为只有P帧(假设相机编码没有B帧),dts=pts。

对于rtsp,如果让服务器发送倍速码流,增加scale头域就可以了。

为了解决在倍速播放RTSP流时,FFmpeg缓冲区满导致花屏的问题,我采用了重新计算时间戳的方法。倍速播放会加速视频帧的处理和播放速度,导致FFmpeg缓冲区在短时间内接收大量数据,超出了其处理能力,最终引发花屏现象。为了避免这一问题,我通过调整每一帧的时间戳,使其与倍速播放的速率相匹配。具体来说,在接收到每一帧数据时,重新计算该帧的显示时间,确保帧与帧之间的时间间隔按照倍速播放的设定进行压缩或扩展,从而实现流畅的播放效果。

此外,我还优化了缓冲区管理策略,在播放过程中适时清空已处理的帧,并控制缓冲区的最大填充量,避免过多的帧数据堆积造成溢出。这种方式有效避免了由于帧积压而导致的渲染问题,使得倍速播放时FFmpeg能够顺利地处理高吞吐量的数据流,减少了花屏和卡顿现象,确保了视频播放的稳定性和流畅性。

经测试,随着倍速提升,缓冲区打满的速度会更快,同样的通过ffplay来播放RTSP的倍速流,ffplay未进行丢包或计算时间戳,而是全部缓存,导致倍速播放并不生效,VLC是通过重新计算时间戳来达到倍速播放。

下面是代码:

//speed_multiplier:当前播放倍速
void adjust_timestamps(AVPacket *packet, double speed_multiplier) {
    // 检查速度倍数是否合法
    if (speed_multiplier <= 0) return;

    // 修改 PTS 和 DTS
    if (packet->pts != AV_NOPTS_VALUE) {
        packet->pts = (int64_t)(packet->pts / speed_multiplier);
    }

    if (packet->dts != AV_NOPTS_VALUE) {
        packet->dts = (int64_t)(packet->dts / speed_multiplier);
    }

    // 确保 PTS >= DTS
    if (packet->pts < packet->dts) {
        packet->pts = packet->dts;
    }
}


http://www.kler.cn/a/512899.html

相关文章:

  • freecad1.0的编译
  • 游戏引擎学习第80天
  • Windows电脑安装USB Redirector并实现内外网跨网USB共享通信访问
  • Python绘制数据地图-MovingPandas
  • 《Linux服务与安全管理》| 邮件服务器安装和配置
  • PHP教育系统小程序
  • LangGraph:基于图结构的智能系统开发与实践
  • Java 大视界 -- 深入剖析 Java 在大数据内存管理中的优化策略(49)
  • 数据结构 链表1
  • 力扣hot100之螺旋矩阵
  • 深度学习篇---AnacondaLabelImg
  • Spring 6 第4章——原理:手写IoC
  • 《开源与合作:驱动鸿蒙Next系统中人工智能技术创新发展的双引擎》
  • STM32单片机学习记录(1.17)
  • Failed to load API definition
  • vue 如何判断每次进入都会刷新页面
  • 【WPF】WPF设置自定义皮肤主题
  • 数据结构初 - 链表
  • 第01章 11 分别使用DCMTK和gdcm库,解析DICOM文件系列的dicom标准数据信息
  • SpringBoot 搭建 SSE
  • Numpy基础01(Jupyter基本用法/Ndarray创建与基本操作)
  • vue.draggable 拖拽
  • 2025年国产化推进.NET跨平台应用框架推荐
  • MyBatis操作数据库(入门)
  • 【Java实现导出Excel使用EasyExcel快速实现数据下载到Excel功能】
  • Qt之QDjango-db的简单使用