H264音视频流在部分华为浏览器上出现冻屏问题排查经过

1,511 阅读8分钟

问题简述

最近项目开发过程中,测试同学反馈了一个华为手机在WebRTC连接建立的h264音视频流会卡住无法恢复问题。具体的现象是音视频连接可以连接上去一会,但是过一会之后就会无法继续播放。整个画面卡住不动,浏览器没有报错,WebRTC的指标参数可以看到还在继续收包,但是pliCount在持续增加,说明一直在丢帧。然后做了比较多的排查,接下来说下各个排查项

排查经历

码率调整

我这边的产品默认使用的高分辨率1080p的一个产品,初始码率会在8M,出问题那几台手机都是华为的hisi编解码器,所以有所怀疑是不是hisi编解码器在编解码能力上是不是有所欠缺,然后缓慢调小码率,6M,4M都会出现问题,后面就没有在调了,(在这里埋了坑),然后接着排查其他的问题

分辨率调整

由于之前使用与手机不同的分辨率比例的音视频画面的时候会出现sdp设置失败的问题,所以怀疑分辨率有所影响,将画面降至720p的时候,发现画面可以保持播放的时间变长了,但是还是会卡住,降至540p之后发现可以长时间保持播放不卡顿了。可是究竟是什么问题呢?如果想保持高分辨画面需要怎么处理呢?

帧率调整

有所怀疑是不是60fps的h264流是不是太高了,调整至30帧之后发现该问题依旧出现,排查该因素

控制变量

我们排查问题,往往需要具体是什么变量引起的问题。说下我们的问题机器环境:

  • HarmonyOS: 4.0.0
  • 华为浏览器版本号: 14.0.3.340
  • Huawei WebView: 14.0.0.331
  • WebRTC H264 音视频连接
  • 分辨率 1080P
  • 最大码率 8M
  • 画面帧率 60fps

这边借用了不少台机器,发现这个问题存在于华为Mate30和Mate40机器中,并且发现在同台机器中的X5内核浏览器并无该问题。这样的话我们可以稍微判断一下这个问题会跟我们的浏览器内核相关,也就是会和我们的WebView相关。那我们需要怎么继续深入问题?

排查日志

因为浏览器没有任何报错,然后变量又出现在了WebViews层,那我们排查问题就没办法从浏览器层入手了,得通过抓包和排查系统日志入手了。虽然是鸿蒙4.0的机器,但是抓取系统日志和android的差不多,我们装一个adb工具,抓取系统日志

adb logcat -c // 清除日志,排查干扰
adb logcat *:W // 打印WARN级别以上的日志

我一般喜欢打印警告以上的日志,如果只需要打印报错日志可以使用 adb logcat *:E,然后在冻屏的时候可以看到系统确实打印了错误日志,贴一下关键点

11-30 15:33:33.722 31795 32495 W CAWARENESS_32425_ThreadPool: thread pool CompatibleFenceTrigger(1) is busy label:null add to queue 1/1/2
11-30 15:33:34.255  8112  8388 E HWBR-O-1023|hwbr_engine_mainprocess-11362: [ERROR:media_codec_bridge_impl.cc(713)] Input buffer size 240162 exceeds MediaCodec input buffer capacity: 230400
11-30 15:33:34.257  8112 22809 W hwbr_engine_MediaCodecBridge: Releasing: OMX.hisi.video.decoder.avc
11-30 15:33:34.268  8112 32449 E Surface : freeAllBuffers: 6 buffers were freed while being dequeued!
11-30 15:33:34.269  8112 32450 W ACodec  : forcing OMX state to Idle when received shutdown in ExecutingState
11-30 15:33:34.278  8112 22809 W hwbr_engine_MediaCodecBridge: Codec released
11-30 15:33:34.302  1316  1521 E ScreemCommon: perf_db# perf db has been closed
11-30 15:33:34.322  1573  1671 E system_server: Cannot read thread CPU times for PID 1573

可以看到指标参数出现一个关键问题,

Input buffer size 240162 exceeds MediaCodec input buffer capacity: 230400

提示输入的buffer size超过了限定的大小230400(225k),继而做出判断,应该是输入的I帧超过了webview 设置的的限定大小,这样就大概知道了什么问题,应该是webview层限制了I帧的输入大小,不能超过2M的带宽(之前都没想到会限制这么低的码率)。这样我们就知道大概问题了,虽然不知道为什么会存在这种问题,怎么解决这个问题呢?直接改webview是不现实的,限制码率?限制分辨率?,限制帧率?应该都是有用的,只要目标视频码率不超过2M就不会出这个问题了,但是否有办法放开这个限制,这个就比较麻烦了,给华为提了工单,但是没有回应,后续问题就暂时限定了鸿蒙手机的输出码率和分辨率,不是一个很好的方案,希望有大佬看到能给个建议。

太久没回来更新了,这个问题已经解决了

华为反馈

分析结果:

花瓣浏览器会根据 I 帧的大小, 去增加 MediaCodec 的 buffer 的大小。

但是你给的视频流里出现了 B/P 帧的大小超过了 I 帧大小的情况。

这样会导致 这个超大的 B/P 帧不能解码,进而导致视频播放失败。

建议:视频编码时,尽量保证每一个 GOP 里, I 帧是最大的, B/P 帧小于 I 帧的大小。

这个是华为测人员根据h264片源反馈过来的结果,在华为测如何控制编解码器是这样描述的 。。。

调整MediaCodec的buffer的大小:

实际上,浏览器是释放MediaCodec , 然后根据视频的分辨率,再重新创建一个 MediaCodec 。

创建和释放 MediaCodec 比较耗时, 浏览器会尽量的避免这样的操作。

对于视频流里的每个 I 帧, 浏览器都会去判断, 这个 I 帧的大小有没有超过 MediaCodec 的 buffer 大小。

如果超过了, 浏览器再去判断,需不需要重新创建一个新的 MediaCodec 。

如果没有超, 浏览器就不会重新创建 MediaCodec 。

解决方案

....

知道了问题的原因,那我们也大概能知道问题需要怎么解决,我们发现如果是由于I帧比B帧小的问题,那么这个现象并不常见,找了一下大佬排查了一下发现是来自原平均码率的现象带来的这个问题,发现问题来自于AMR的码流控制模式引起的,然后我们改成了平均码率模式或者调整gopSize的大小之后都可以解决该问题。

贴一下超哥的排查结果: 在视频编码中,I帧(Intra-coded frames)是独立编码的帧,不依赖于其他帧。而P帧(Predictive-coded frames)则是基于前面的I帧或P帧进行预测编码的帧。通常情况下,由于P帧采用了预测编码,它们的大小通常会比I帧小。

然而,在某些情况下,P帧可能会出现比I帧更大的情况。这可能是由于以下原因:

  1. 场景变化:当视频场景发生剧烈变化时,P帧需要编码更多的信息以适应新的场景。这可能导致P帧的大小增加,甚至超过I帧。

  2. 编码参数:编码参数的设置也可能影响P帧的大小。例如,如果编码器的量化参数(Quantization Parameter, QP)设置得较低,将会保留更多的细节信息,从而可能导致P帧的大小增加。

  3. 预测误差:P帧是基于前面的帧进行预测的,如果预测不准确,将导致预测误差增大。为了减小预测误差,编码器可能需要编码更多的信息,从而导致P帧的大小增加。

在ABR(Adaptive Bit Rate)码率控制下,编码器会根据网络带宽和缓冲区状态动态调整编码参数,以实现码率的自适应调整。在这个过程中,如果网络带宽充足且缓冲区状态良好,编码器可能会选择较低的QP值以保留更多的细节信息,这可能导致P帧的大小增加。同时,如果场景发生变化或者预测不准确,也可能导致P帧的大小增加。

因此,在ABR码率控制下,P帧出现比I帧大的情况是有可能的。

更改华为浏览器的流控模式为平均 码率 模式基本可以解决了