美文网首页服务器开发Srs
srs流媒体服务器丢失参数集以及metadata的解决办法

srs流媒体服务器丢失参数集以及metadata的解决办法

作者: 爱吃花栗鼠的猫 | 来源:发表于2016-12-12 12:11 被阅读808次
    • 2018.10.31 更新
      更新日志: 此次更新增加了metadata的判断,更新原因:
      metadata什么时候会发送? 2种情况:
    1. 刚连接的时候
    2. metadata发送变化的时候
      那么在长时间的跑机中,时间戳的调整上会出现问题,equeue进来的时候如果没有对metadata的类型加以判断,则会丢失metadata,从而导致客户端无法解码播放
      所以,需要增加metadata的判断
    • 2018.10.25 更新
      更新日志: 从0开始检查,避免当0为参数集的时候清理掉,从而导致丢失
    • 现象
      推流端切换分辨率,结果播放端花屏了,之所以花屏,查看了下rtmp帧,少了参数集。
      那么等到下一个参数集到来的时候,就立即好了,这个好理解
    • 原因
      问题是,丢失的参数集为什么会丢失呢?
      一般情况下, 参数集都是在I帧前的,后面的I帧没有丢,反倒是前面的参数集丢失了
      来看下面这段代码:
    void SrsMessageQueue::shrink()
    {
        int iframe_index = -1;
        
        // issue the first iframe.
        // skip the first frame, whatever the type of it,
        // for when we shrinked, the first is the iframe,
        // we will directly remove the gop next time.
        for (int i = 1; i < (int)msgs.size(); i++) {
            SrsSharedPtrMessage* msg = msgs[i];
    
           if (msg->header.is_amf0_data() || msg->header.is_amf3_data()) {
                // the max frame index to remove.
                iframe_index = i;
                break;
            }        
    
            if (msg->header.is_video()) {
                if (SrsFlvCodec::video_h264_is_spspps(msg->payload, msg->size) ||
                        SrsFlvCodec::video_h265_is_sequence_header(msg->payload, msg->size)) {
                    // the max frame index to remove.
                    iframe_index = i;
                    
                    // set the start time, we will remove until this frame.
                    av_start_time = msg->header.timestamp;
                    
                    break;
                }
            }
        }
       
        // no iframe, for audio, clear the queue.
        // it is ok to clear for audio, for the shrink tell us the queue is full.
        // for video, we clear util the I-Frame, for the decoding must start from I-frame,
        // for audio, it's ok to clear any data, also we can clear the whole queue.
        // @see: https://github.com/winlinvip/simple-rtmp-server/issues/134
        if (iframe_index < 0) {
            clear();
            return;
        }
        
        srs_trace("video_h264_is_sequence_header: shrink the cache queue, size=%d, removed=%d, max=%.2f",
            (int)msgs.size(), iframe_index, queue_size_ms / 1000.0);
        
        // remove the first gop from the front
        for (int i = 0; i < iframe_index; i++) {
            SrsSharedPtrMessage* msg = msgs[i];
            srs_freep(msg);
        }
        msgs.erase(msgs.begin(), msgs.begin() + iframe_index);
    }
    

    在这里面有清掉帧数据的操作,并且是从1开始的,也就是说,不管数据0的类型是什么,万一这个0恰好就是参数集,那就清理掉了

    • 修复方法
    for (int i = 0; i < (int)msgs.size(); i++) {
            SrsSharedPtrMessage* msg = msgs[i];
            
            if (msg->header.is_video()) {
                if (SrsFlvCodec::video_h264_is_spspps(msg->payload, msg->size) ||
                        SrsFlvCodec::video_h265_is_sequence_header(msg->payload, msg->size)) {
                    // the max frame index to remove.
                    iframe_index = i;
                    
                    // set the start time, we will remove until this frame.
                    av_start_time = msg->header.timestamp;
                    
                    break;
                }
            }
        }
    
     if (0 == iframe_index) {
            return;
        }
    

    shrink 部分,需要去掉循环,否则有可能会一直在这里循环导致cpu飙升

    if (av_end_time - av_start_time > queue_size_ms) {
            shrink();
        }
    

    这里从0开始,就是为了避免当0为参数集的时候也清理掉

    • 一个没查到的问题
      什么时候会调用这个shrink呢?如下代码
    while (av_end_time - av_start_time > queue_size_ms) {
            shrink();
        }
    

    经过测试,当av_start_time=0的时候,会进入这段代码,但是在av_start_time能够赋值的地方都看过了,实在是没有找到为0的时候,到现在依然没有查出来

    哪位朋友知道答案,望不吝赐教

    相关文章

      网友评论

        本文标题:srs流媒体服务器丢失参数集以及metadata的解决办法

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