Java教程

直播相关讲解 -- 直播常见问题(转载)

本文主要是介绍直播相关讲解 -- 直播常见问题(转载),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

转载:ttps://blog.csdn.net/qq_18998145/article/details/106570385 

播放卡顿

从代码层面来看,什么是卡顿?其实是指播放器渲染的帧率太低,比如:1s 显示 3~5 帧,或者渲染完一帧后,过很久才渲染下一帧。

因此,我们需要排查,是什么原因导致了播放器无法流畅地渲染数据,通常可能有如下几大类:

 

网络带宽不足

一个完整的直播应用,简单来说数据流是这样的:主播 -> CDN -> 观众

因此,直播出现卡顿,三个端都可能是问题的源头:

1. 主播端的网络不好,导致推流上行不稳定

2. 服务端的线路质量不好,导致分发不稳定

3. 观众端的网络不好,导致拉流下行不稳定

网络性能测试工具:ping, iperf

播放设备性能不足

越高清的码率,对解码的要求也越高,很多手机性能不足以支撑 720P 甚至 1080P 的视频解码,特别是很多低端的 Android 手机,因此导致实际解码播放的帧率远小于视频码流的实际帧率,从而产生卡顿。

解决这个问题的思路主要有如下几个方面:

1. 尽可能选择使用硬解,充分利用 GPU 加速

2. 如果有多种码流,尽可能在低端机上选择非高清码流

3. 增大缓冲区,有助于缓解解码不稳定带来的卡顿

视频流时间戳问题

播放器一般是严格根据码流中的音视频的时间戳来做音画同步的,因此,如果码流中的音视频时间戳出现错误,
肯定会影响到播放画面的渲染时机。

例如,一个流的时间戳信息如下:

 可以看到,它的视频时间戳出现了「回退」,而播放器一般 master 主时钟是单调递增的,当后来的视频帧小于了当前的主时钟,播放器就会做丢帧处理,从而导致播放的视频帧率远低于实际码流中的视频帧率,从而产生卡顿现象。

首开慢


首开慢的表现:点击播放后,需要好几秒才能显示播放画面。

点击播放后才从服务器取播放地址


播放视频,第一件事就是要拿到播放地址,大多数直播 App,主播的播放地址是由 App 向服务端发 HTTP GET 请求才能拿到的,因此,什么时候去「拿」 这个播放地址,显得至关重要,常见的做法有如下两种:

  • App 拉取正在视频列表的时候
  • 用户点击某个视频,跳转到播放界面之后

显然,后者的用户体验明显会比前者差,因为通过 HTTP GET 请求播放地址的过程,无形增加了首开时间,特别是在弱网下,会更慢。

DNS 解析慢


不同的播放域名,DNS 解析有快有慢,再加上 DNS 解析服务的缓存策略,在本地没有该域名缓存的情况下,会逐级向更高级的域名服务器查询域名,因此,播放域名解析的耗时,会对首开产生不小的影响。

为了有效降低 DNS 解析对首开的影响,我们可以提前完成播放域名->IP 地址的解析,并缓存起来,播放的时候,直接传入带 IP 地址的播放地址,从而省去了 DNS 解析的耗时。

播放策略原因


播放首开时间的定义,就是从点击播放到第一帧画面显示出来的耗时,因此,我们需要尽一切可能加快播放进度。

很多侧重点播的播放器,为了减少卡顿,会有一些缓冲策略,当缓冲足够多的数据之后 ,再送入解码播放。

而为了加快首开效果,需要对播放的缓冲策略做一些调整,如果第一帧还没有渲染出来的情况下,不要做任何缓冲,直接送入解码器解码播放,这样就可以保证没有任何因为「主动」缓冲带来的首开延时。

播放参数配置


所有基于 ffmpeg 的播放器,都会遇到 avformat_find_stream_info 这个函数耗时比较久,从而增大了首开时间,该函数主要作用是通过读取一定字节的码流数据,来分析码流的基本信息,如编码信息、时长、码率、帧率等等,它由两个参数来控制其读取的数据量大小和时长,一个是 probesize,一个是 analyzeduration。

减少 probesize 和 analyzeduration 可以有效地减少 avformat_find_stream_info 的函数耗时,从而加快首开,但是需要注意的是,设置地太小可能会导致读取的数据量不足,从而无法解析出码流信息,导致播放失败,或者出现只有音频没有视频,只有视频没有音频的问题。

服务端原因


当播放端的优化做到极限后,剩下的首开快慢的决定性因素就是服务端了,服务端主要有哪些方面会影响首开呢?

冷热流


当你去附近的边缘服务器节点拉取某个流的时候,如果最近没有任何人从该服务器拉过这个流,那么这台服务器就需要逐级向源头拉流,而且该服务器还需要进行 GOP 缓存,从而产生比较大的首开延时。

边缘节点的距离


同等大小的数据,客户端距离服务器越近,那么传输也就越快,首开也会越快。

服务器的响应速度


影响服务器响应速度的因素,一个是跟服务器的协议层优化有关,另一个就是服务端的负载和性能了,服务器当前负载越大,响应自然越慢。

延时高
延时高问题分析


我们看看可能产生延时的模块有哪些:

  1. 图像处理延时,比如画面剪裁、美颜、特效处理
  2. 视频编码/解码延时
  3. 网络传输的延时
  4. 业务代码中的缓冲区

一般图像处理、数据拷贝、编解码带来的延时,都是 ms 级别的,真正会产生比较大延时的地方,一个是互联网上的网络传输延时,另一个就是业务代码中的缓冲区了。

编码延时


很多人可能不知道 H.264 的解码器正常情况下会在显示之前缓存一定的视频帧,对于 QCIF 分辨率大小的视频(176 × 144)一般会缓存 16 帧,对于 720P 的视频则缓存 5 帧。对于第一帧的读取来说,这是一个很大的延迟。视频中 B 帧的解码依赖于前后的视频帧,会增加延迟。Codec 一般都会有低延迟优化的开关,对于 H.264 来说其效果尤其明显。

如果使用了 FFmpeg,降低「-probesize 」和「 -analyze duration」参数的值,这两个值用于视频帧信息监测和用于监测的时长,这两个值越大对编码延迟的影响越大。

网络传输延时


数据在网络上传输,从一个节点经过多级服务器转发到达另一个节点,是不可避免有物理延时的,下面这个表格给出了理论上数据在光纤中的网络传输的时间(实际场景中的延时往往比这个要大很多,因为涉及到带宽、网络抖动等干扰):

在这里插入图片描述
业务代码中的缓冲区


业务代码中的缓冲区,主要是推流端的缓冲区和播放端的缓冲区,一个 30 fps 的视频流,缓冲区每滞留 30 帧,延时就会增大 1s,那么,它们是怎么产生缓冲数据的呢 ?

  • 推流端的数据怎么积累起来的呢 ?

        采集 -> 编码 -> 数据发送 -> 服务器

        当网络产生抖动的时候,数据发送会因此减慢,产生一定的阻塞,从而导致这些数据会被积累在了推流端的发送缓冲区中。

  • 播放端的数据怎么积累起来的呢 ?

        服务器-> 数据接收 -> 解码 -> 渲染

        当网络产生抖动的时候,服务器的数据无法及时地传输到播放端,而由于 TCP 协议的可靠性,所有的数据都会被服务端积累起来,在网络恢复良好的时候,会快速传输到播放端,这些数据会被动地积累在接收缓冲区中。

  • 怎么消除业务缓冲区的累计延时呢 ?

        推流端的发送缓冲区,可以在网络恢复良好的时候,快送发送出去,从而消除掉这个累计延时。

        播放端的接收缓冲区,可以通过丢帧或者加速播放的方式快速消费掉缓冲区中的数据,从而消除累计延时。

协议延时


通常标准的直播协议有 RTMP,HLV,HLS 三种,一般 RTMP/HLV 协议的延时在 1~3s,HLS 协议的直播延时则会更大,注重延时的直播应用,大都会选择 RTMP/HLV 协议,这些协议均是基于 tcp 的协议,tcp 协议的多个特性导致其延时明显要高于基于 udp 的私有协议,主要有如下方面:

• 建立连接的三次握手

• ACK 机制

• 丢包重传

因此,如果想从本质上解决直播延时问题,还是要换成基于 udp 的私有协议来传输数据。

音画不同步


对于播放器而言,它判断一帧视频和一帧音频是否要在同一个时间渲染和播放,依靠的完全是该数据携带的时间戳信息。

如果内容的生产端给音视频数据打的时间戳本身就有问题的话,播放器也往往无能为力了,因此,音画不同步问题,更多的时候,应该从生产端去排查原因。

采集源距离太远


如果音频源离麦克风距离太远,那么,摄像头采集到画面后给出的时间戳,肯定要远小于麦克风采集到同一时刻音频给出的时间戳,因此会产生音画不同步问题。

解决方案:音频源尽可能离麦克风设备近一点。

采集设备内部问题


摄像头和麦克风采集音视频,在硬件上都会经过一些信号处理模块,如果处理延时不稳定,则会导致输出数据的时间不稳定,从而导致应用层获取时间戳的时候产生误差,带来音画不同步问题。

解决方案:极少数硬件/机型才会有,需要根据采集参数(如采样率)做一些 Jitter 抖动的矫正。

未使用采集的时间戳


如果在后续的某个环节修改了采集的时间戳,则非常大概率地会出现音视频不同步问题。

• 音视频算法处理模块

比如:视频经过美颜、编码后,重新更新为了处理后的的时间戳。

• 缓冲区导致的不同步

多线程程序中,往往会在不同线程之间共享一些帧缓冲区,缓冲区会导致音视频对应关系发生变化,如果从缓冲区取数据后,抛弃掉了原有的时间戳,重新使用新的当前时间,那么,肯定会出现问题。

• 网络传输导致的不同步

由于网络的传输的延时、丢包等原因,同一时刻的音视频包不会正好同时准确到达,如果在接收到了数据后再打上当前的时间戳,肯定也会出现不同步问题。

时间戳出现回退或者紊乱


如果时间戳出现了回退,这样的流,会导致播放器出现卡顿,因为播放器的 master 主时钟一般是单调递增的,当出现小于主时钟的视频帧后,一般会做丢弃处理,画面不更新但是音频还是在继续播放,从而导致看起来声音和画面并没有匹配上的问题。

解决方案:排查推流端时间戳是否单调线性递增,或者排查服务端是否有对流的时间戳有过修改导致回退。

播放端性能问题


比如低端机型软解 1080P 的高清码流,会存在解码不够及时的问题,导致部分视频解码完成后,已经远慢于当前的音频时钟,只能丢弃,从而导致画面更新不及时,与正在播放的音频无法匹配上,从而产生音画不同步的现象。

解决方案:使用硬解,选择较低清的码流,增大播放缓冲,等等。

马赛克严重


马赛克主要是指画面中出现多处类似小方块的图像,导致画面的局部或者整体看不清楚的情况。

视频编码参数配置原因


视频的画质,是由它的编码质量决定的,压缩得越厉害,画质损失就越严重,马赛克就越多。

编码器最重要的五个参数:画质级别、码率、帧率、GOP 大小、码控方式。

画质级别:H.264 有四种画质级别,Baseline profile,Extended profile,Main profile,High profile。级别越高,压缩的效果越好,但算法复杂度更高,导致功耗也更高。

码率:决定了视频被压缩的程度,码率越低,丢失的信息也就越多,画质也就越差。但是,带来的好处是占用的网络带宽会比较小,容易在互联网上传输,不容易出现卡顿。

帧率:决定了视频的流畅性,帧率越高,视频越流畅,但每秒钟编码器要处理的数据量也就越大,同等码率下压缩出来的视频质量就越差。

GOP 大小:决定了视频的延时,GOP 越小,延时就越小,但 GOP 小带来的问题是关键帧数量多,数据量变大,因此,同等码率下压缩出来的视频质量就会越差。

码控方式:一般编码器都有固定码率(CBR) 和 动态码率(VBR) 两种码控方式,前者是指码率优先,为了保证码率尽可能稳定,会主动降低画质,因此容易出现马赛克,后者是指画质优先,会优先保证画质,减少马赛克,但码率会浮动很大。

当然,还有一个重要的因素,就是编码器本身的实现质量,软编一般可以保证在不同手机上效果一致,而硬编则完全依赖手机所使用的硬件平台了。

推荐的编码器参数配置


一般直播场景中,考虑到手机性能和功耗,一般画质级别采用的是 Baseline profile,GOP 通常设置为 1~3s,帧率一般在 15~24 帧,而码率的配置,则需要根据推流的分辨率来决定,推荐的分辨率和码率配置关系如下图所示:

**加粗样式**

 

总之,关于视频编码与马赛克的关系,我们只需要记住一个原则:送入编码器的数据量越大,编码压缩得越厉害,丢失的图像信息也就越多,数据解码后的产生马赛克也就越厉害。

图像尺寸原因


一般摄像头采集的图像分辨率,跟最终推流的尺寸不一定完全匹配,当摄像头采集的分辨率大于推流尺寸的时候,需要先对画面进行剪裁处理,而当摄像头采集的分辨率小于推流尺寸的时候,则需要先对画面进行拉伸处理,然后再送入编码器中编码压缩。在这里插入图片描述

 

例如:小尺寸的画面(比如:640 x 480),拉伸到大的尺寸(比如:1280 x 720),则很容易会产生模糊和马赛克,这样的画面再送入编码器中编码,无论怎样配置都无法再改善已经产生的马赛克了。

所以,为了降低马赛克,我们必须要保证,摄像头采集的分辨率,一定要大于最终推流的分辨率。

客观条件原因


如果主播在光线非常暗的环境下,本身送入编码器的图像质量也不会特别好,因此,同等条件下马赛克也会相对严重些。

同样,如果拍摄的是剧烈晃动的画面,剧烈变化的画面信息量也要大很多,因此,编码的复杂度会明显增大,如果要保证码率不会浮动太大,就必然要降低输出的图像质量,从而产生马赛克现象。

如果直播应用是主打这种光线暗的场景或者剧烈运动的画面场景的话,为了降低马赛克,可以考虑适当将编码参数配置得高 一点(比如:码率高一点,帧率低一点等等),以抵抗环境因素带来的影响。

关键帧丢失


还有一种马赛克现象,是由于视频流中丢失了关键帧,导致播放器解码后花屏,从现象来看有点像马赛克,但实际上跟上面讨论的不是同一个问题。

黑屏、花屏、闪屏


黑屏、花屏、闪屏等问题,可能是推流端的问题,也可能是播放器的问题,遇到这些现象,我们要第一时间用别的播放器(如 VLC,ffplay)试试,如果都出现同样的问题,那么多半是流本身的问题了,反之,则很可能是播放器的问题。

播放黑屏


现象:画面是黑的,没有图像,但是有声音。

主播端摄像头权限问题


无论 Android 还是 iOS,App 使用摄像头都是需要申请授权的,特别是 Android 6.0 以后,如果 App 层面不做专门的处理的话,很可能出现摄像头权限被禁用的情况。

如果 App 没有获取到摄像头权限,视频就无法采集成功,从而导致推出来的流只有音频数据。

解决方案:App 层面肯定要小心处理权限问题,检测到未获取相应权限则禁止开播,或者反复提示主播授予权限。另外,可以询问出现问题的主播是否有摄像头预览画面,如果 App 没有获得权限的话,是没有预览画面的。

主播端编码失败


视频数据采集到后,下一步就是经过编码器,由于参数配置或者某些机型的硬编兼容性问题,很可能数据送入编码器后,编码失败,并无输出,从而导致没有视频数据送入到推流模块。

解决方案:一般推流 SDK 都会统计推流的实时视频帧率,CDN 服务端也会有一些帧率监控,因此,如果发现这些统计得到的推流帧率为 0,同时又确定不是没有采集到数据,那么多半是编码器的原因,可以想办法查看下该机型的日志看看具体的报错信息。

视频解码失败


当播放器遇到不支持的视频格式,或者数据内容/格式异常,则会解码失败,从而导致无解码视频输出。

针对不支持的格式:

• 要提前了解播放器本身支持哪些音视频格式,如 H.264,mp4v,aac 等等,避免播放不支持的格式

• 播放器本身遇到的硬解或者软解失败,应该有日志报错,或者抛出异常给应用层提示用户

针对视频数据内容错误,需要分析码流文件本身,常见的数据内容错误导致的解码失败有如下几种:

• 送入解码器的帧数据不完整

• H.264 的视频码流,缺失了 SPS,PPS 等必要的信息头

• iOS 的 VideoToolbox 解码,只支持 avcc 方式打包的 H.264 数据

• 部分 Android 机型硬编出来的数据有额外的 naul 头

• 其他等等

码流的前半段只有音频没有视频

这种情况,多半出自 HLS 切片产生的码流,当主播用同一个地址推流,前半段只推了音频(可能是摄像头权限被禁用,也可能是选择了纯音频推流等等),然后接着又同时推了音视频流,那么,服务端 HLS 切片产生的文件,就会出现这样的情况。

基于 ffmpeg 的播放器,会在解析完视频头后初始化解码器,因此,对于这种码流,往往会出现仅有音频或者仅有视频播放的情况。

解决方案:从 App 端尽可能避免出现这种使用姿势,修改播放器的代码,对这种码流进行兼容处理。

播放花屏/绿屏

现象:播放画面出现图像紊乱,大面积的异常颜色的方块图,或者绿屏现象

丢失参考帧导致的
一般 H.264 码流有 I、B、P 三种帧类型,I 帧是关键帧,B 帧是双向预测内插编码帧,P 帧是前向预测编码帧。

I 帧由于是帧内压缩,因此可以独立解码播放,而 B 帧,一旦丢失了 I 帧或者后面的 P 帧,则会解码失败,而 P 帧一旦丢失了前面的 I/B/P 帧,也会导致解码失败。

对于丢失了参考帧而导致的解码失败,一般就会出现花屏的现象,花屏的严重程度依赖于丢失的参考帧对即将解码的帧的重要程度。

那么,什么情况下会丢失参考帧呢 ?

首先,推流/播放的代码层面,需要注意,不要丢弃编码后、解码前的视频帧数据,不过实际场景中,遇到下面的情况,难免还是会产生丢帧:

• 网络不好,编码后的数据发不出去

• 系统低内存,队列里面无法承受更多的帧数据

因此,在这些极端的情况下,不得不丢帧的话,最合理的策略就应该是一次丢一整个 GOP,即:一旦开始丢了一个 I 帧,那么在遇到下一个 I 帧之前的所有视频帧,均丢弃掉,这样即可有效避免播放器端产生解码花屏。

播放器没有从关键帧开始解码

原理依然如上面所述,如果不从关键帧开始解码,则必然会由于丢失了参考信息而导致解码花屏。

因此,播放器,无论是首播,还是断网重连后,都应该判断第一帧视频是否是关键帧,如果不是,则应该等到第一个关键帧到达之后再送入解码器。

码流中视频尺寸发生变化

很多直播 App,横屏直播和竖屏直播,使用的是不同的推流尺寸 ,当主播由竖屏推流改为横屏推流,同时又不改变推流地址的话,观众端拉到的流就会出现中间发生了视频尺寸的变化,比如:从 848 x 480 变成了 1280 x 720 等等。

播放器需要实时检测,如果发现视频尺寸发生了变化,则需要重置解码器以及相关逻辑,否则容易出现解码花屏或者出现内存越界等异常。

硬编硬解的兼容性问题

当然,如果使用的是 Android 硬编硬解,则难免会遇到一些比较坑爹的手机,硬编硬解没有失败报错,但是输出的图像确实异常的情况。

Android 硬编硬解的兼容性问题,代码上小心仔细,充分考虑机型的兼容性,不轻易写死任何参数,剩下能做的就是靠白名单/黑名单了。

推流端图像尺寸和格式处理不当

图像的格式和尺寸,都是非常重要的参数,一定要严格配置正确。

比如:如果采集到的视频是 NV21 ,编码器只支持 I420,那么编码出来的图像自然会出现颜色问题。

比如:在一些场景切换的过程中,前后摄像头切换,视频的尺寸可能发生了变化,但是剪裁、处理、编码模块没有相应的修改尺寸,那么,也会出现各种视频错乱的现象。

播放闪屏

闪屏问题,从根源来看,就是播放的过程中,出现了两种不同的画面来回切换,从而看起来 闪屏,比如,黑白两张图片交替渲染。

播放器缓冲机制原因

网络不好的时候,播放器会频繁缓冲,曾遇到过一种案例,就是某直播 App 应用,在缓冲的时候,使用了一张广告图片,在某种极端弱网情况下,由于频繁缓冲,导致真实的播放画面和广告图片来回快速切换,导致闪屏现象。

这个情况是完全可以从播放器的缓冲策略上避免的,每次缓冲后,不要收到一帧后就立即渲染,而是适当地多缓冲一些数据,再发送缓冲结束的消息,从而可以频繁 ms 级别的缓冲切换产生的闪屏。

推流端的原因

推流端产生闪屏的流,往往发生在有画面合成的代码模块,比如:叠加水印、摄像头/图片切换推流、连麦合流等等。

画面的合成,一定要铭记一点,任何情况下,都要避免出现,有合成/没有合成两种画面的交替。

播放杂音、噪音、回声

相比于视频而言,音频要敏感得多,视频画面有噪点、马赛克都还是可以勉强被接受,而声音一旦有任何瑕疵,人耳都会特别容易感觉到,而且难以忍受。

常见的音频问题现象描述如下:
• 电流音,爆音,滋滋声或者嘟嘟声
• 声音断断续续,听不清楚
• 回声,能听到自己说话的声音

参数配置问题

音频是一个特别敏感的东西,涉及到许多参数配置,一旦配置不太匹配,就会导致声音听起来非常诡异(比如:采样率是 32000Hz 的音频,给播放器配置为 8000Hz 或者 44100Hz,就明显会出现音频慢放或者快放的效果)。

我们只需要注意的是,无论是采集和播放,都要给系统的 API 以及第三方的库配置正确的参数,如:采样率、位宽、声道数等等。

代码层面的原因

常见的代码层面的问题有如下几种:

• 音频 buffer 大小不匹配,一段 1024 bytes 的音频,放到了 2048 bytes 的数组,导致尾部有随机数

• 音频 resample 重采样的算法问题,导致采样出来的数据出了问题

• Android 的 ByteBuffer 取出数组,是不能直接用 .array() 方法的,而需要用 .get() 方法

• iOS 系统,其他 app 通过系统 API 更改了 AudioSession 采样率的配置

网络波动

视频是一帧一帧连续的图像构成的,在播放过程中,如果无法按时渲染,则会出现卡顿的效果;如果丢失几帧画面,则会出现快进效果。

而音频是流式的,虽然也被切分为了一个个音频帧,但如果无法按时播放或者连续丢失较多的音频帧,则会明显听到断断续续的声音出现。特别是在弱网、丢包率高等不稳定网络环境下,很容易出现这种情况。

回声消除

回声一般出现在同时有音频的采集和播放的场景,比如:连麦互动、混音返听等等,采集到的音频通过扬声器又播放出来了,同时又被采集了进去,从而产生了回声或者啸叫声。

这样的场景下,一般需要通过系统的回声消除 API,或者第三方回声消除库(如:speexdsp,webrtc 等)进行处理。

注意:很多 Android 机型硬件自带的回声消除效果并不是很好。

混音越界

音频的 PCM 数据,通常用 short 数组来存放,当我们做一些多路音频的混音功能的时候,如果不注意处理 short 类型的大小越界,则往往带来爆音的问题。下面是一段参考 webrtc 的混音代码,专门针对混音越界做了简单处理,可以参考参考:

在这里插入图片描述

 

拖动不准

现象:播放过程中,拖动进度条后,实际播放的位置跟松开拖动时的位置相差很远。

由于直播流是实时产生和传输的,是不能拖动的,因此该问题主要出现在点播或者本地文件 的播放。

基本概念
首先,我们要了解播放器拖动的基本原理:

视频是由一系列图像帧组成的,每一个帧都有对应的时间戳。拖动,就是告诉播放一个时间戳,由它直接跳转到指定的这一帧开始播放。

拖动到的时间点 = (进度条的 progress / 进度条最大值 100 )x 视频总时长

关键帧间隔太大

由于解码器必须从 I 帧开始解码,才不会出现花屏现象,因此,播放器通常会寻找离 seekTo 视频帧最近的一个关键帧,从该关键帧开始解码播放。

假设关键帧间隔(GOP)是 3s,那么关键帧的时间点排列如下:

0s, 3s, 6s, 9s

如果拖动到 4s 的位置,那么播放器就跳转到第 3s 的关键帧开始解码播放,因此,会产生一定的误差。

关键帧的间隔越大,那么这个误差也就越大。因此,为了更准确地支持拖动,建议不要把关键帧间隔设置得太大。

直播丢帧

丢帧的情况多发生在直播场景,由于主播端的网络抖动或者内存不足,导致不得不被迫丢掉一些视频帧,而为了保证客户端解码后不出现花屏,丢帧往往伴随着一整个 GOP 的丢弃。

当 GOP 丢失后,部分关键帧的间隔时间点就会变得更大了,从而导致拖动不准。

为了避免这种情况,建议推流端开启动态码率,在网络不好的时候,主动降低码率,快速发送掉缓冲区中累积的视频帧,从而减少丢帧的情况发生。

发热

导致机器功耗高,发热严重的根本因素,无外乎就是一点:CPU/GPU 占用率高,所以,我们首先要分析下,哪些因素会导致 CPU/GPU 占用率高。

数据量太大

直播主要由:视频采集 -> 视频处理(剪裁、美颜、滤镜) -> 编码 -> 推流 这些环节组成。

在这整个流程中,决定数据量大小的因素有哪些呢 ?

视频的尺寸(例如:1280 x 720 的图像,明显要比 320 x 240 的图像处理起来费劲)

视频的帧率(例如:每秒 30 帧,明显要比每秒 15 帧,处理起来费劲)

因此,在不影响业务体验的情况下,适当减少视频的尺寸和帧率,是可以明显降低后续环节 CPU/GPU 的负荷的,从而显著降低功耗。

大量的格式转换

不同的模块对数据格式的要求,往往有差异,比如 Android 摄像头出来的数据大多是 NV21 的,而编码器一般要求 I420 格式的数据;再比如 ffmpeg 解码的视频往往是 YUV 格式,而渲染显示往往需要 RGB 格式,等等。

我们要尽可能减少不同格式之间的数据转换,或者尽可能利用 GPU 来处理一些复杂的格式转换,比如利用 OpenGL 直接渲染 YUV 格式的数据,而不是用 CPU 做一次 YUV -> RGB 的转换,就是一个不错的选择。

对图像进行放大操作

前面文章有提到,非常不推荐把一个小尺寸的图片 -> 放大 -> 大尺寸图片,这样很容易出现马赛克。

其实,这样的设计,不仅仅是容易出现马赛克,而且在图像放大的过程中,由于涉及到复杂的插值运算,也会非常消耗 CPU。

同理,图像的缩小或者剪裁,同样也会消耗一定的 CPU,只不过相比于图片放大要好点。

因此,最好的办法,就是小心选择摄像头的预览分辨率以及推流的尺寸,尽可能让两者保持一致,这样,才能最大化地节省 CPU 的消耗。

软编/软解

这个原因或许大家都懂,软编/软解靠的是 CPU,非常耗性能,而硬编/硬解是使用专门的硬件编解码器模块,会显著降低 CPU 的负担,相对而言,会省电很多。

只不过需要小心各种 Android 机型兼容性问题,对于某些奇葩设备,还是加入硬编/硬解黑名单的好。

其他方面

当然,导致功耗高的因素还有很多,这里就不一一展开说明了,列举如下:

人脸识别/美颜/滤镜,对 CPU/GPU 消耗很大

代码逻辑中过多的 memory copy 操作

后台线程频繁唤醒手机访问网络或者读写 SDCard

App 的一些动画特效

其他等等
————————————————
版权声明:本文为CSDN博主「LIEYz」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_18998145/article/details/106570385

这篇关于直播相关讲解 -- 直播常见问题(转载)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!