美文网首页
iOS h264直播遇到的问题

iOS h264直播遇到的问题

作者: 哥只是个菜鸟 | 来源:发表于2020-07-18 17:25 被阅读0次

花屏问题

  • 丢失参考帧导致的

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

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

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

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

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

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

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

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

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

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

基于 ffmpeg 的播放器,如何判断关键帧,可以参考文章:《FFMPEG Tips (3) 如何读取每一帧的信息》

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

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

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

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

  • 如何判断是音频帧还是视频帧

int video_stream_idx = av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);

int audio_stream_idx = av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);

每一个 AVPacket 都有一个成员变量:stream_index,由该成员变量即可判断这个 Packet 到底是音频还是视频了:

if (avpkt.stream_index == video_stream_idx) {
    LOGD("read a video frame");
} else if (avpkt.stream_index == audio_stream_idx) {
    LOGD("read audio frame);
}
  • 如何判断是否为关键帧

if (avpkt.flags & AV_PKT_FLAG_KEY) {
    LOGD("read a key frame");
}
  • 如何获取帧的数据和大小

帧的数据和大小直接定义在 AVPacket 结构体中,对应的成员变量如下:

// 压缩编码的数据,一帧音频/视频
uint8_t *data;

// 数据的大小
int size;
  • 如何获取帧的时间戳信息

每一个帧都可能携带有 2 个时间戳信息,一个是解码时间戳 dts,一个是显示时间戳 pts,解码时间戳告诉我们什么时候需要解码,显示时间戳告诉我们什么时候需要显示,只有在码流中存在 B 帧的情况下,这两个时间戳才会不一致。

这些时间戳信息不一定存在于码流中(取决于生产端),如果不存在,则其值为:AV_NOPTS_VALUE

一定要选择正确地方式打印时间戳,时间戳是使用 long long 来表示的,即 int64_t,因此打印的时候,需要使用 “%lld” 来打印,例如:

while (!interrupt) {
    int ret = av_read_frame(player->ic, &avpkt);
    if (ret < 0) {
        break;
    }
    if (avpkt.stream_index == video_stream_idx) {
        LOGD("read video frame, timestamp = %lld \n”, avpkt.pts);
    } else if (avpkt.stream_index == audio_stream_idx) {
        LOGD("read audio frame, timestamp = %lld \n”, avpkt.pts);
    }
}

由此,我们就可以通过这些 log 信息调试一下某一段音视频流的时间戳是否正确,比如是否出现了时间戳的回滚和错乱,则必然会导致播放端出现音视频不同步或者显示异常等情况。

相关文章

网友评论

      本文标题:iOS h264直播遇到的问题

      本文链接:https://www.haomeiwen.com/subject/oetjhktx.html