美文网首页
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