美文网首页服务器开发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