iOS直播推流丢包处理方案

2016-12-12  本文已影响384人  南风无影

iOS推流一般是用aac+h264封装成flv后,推流rtmp协议
大致的流程图我简单画了下

iOS推流.png

在使用过程中发现,如果主播推流网络卡了M分钟(很常见),这时候编码后的数据如果不丢的话,还会把老的(编码后的)数据陆陆续续推上去(可能要N分钟才能推完),这时候播放器有丢包处理,X分钟后恢复正常,但是体验其实不算太好,因为推流端没丢包,本来不该推上去的老数据,还是推上去了,这样播放器即使丢包了,还是会看到老数据,会造成几个不好的结果:

  1. 播放器过了很久才恢复到实时。
  2. 无谓的带宽浪费了。
  3. 在那段恢复的时间内,延迟大。

所以,要丢包,编码出来的包,如果队列很大,说明推不上去,那这时候,应该丢掉一部分。


我的思路是: 根据包的队列或者buffer, 换算成时间单位s, 如果>3s, 就丢掉一半,或者丢的只剩3s。
根据pts为阀值来判断,丢掉某个pts之前的数据。
丢包的时候,视频包要注意一下,很老的I帧包可以丢,但是临近阀值的时候,就不能丢,丢到I帧前一帧。
如果不能按照pts丢,那就只能用size大小来丢帧。
这个策略和播放的丢包其实是一样的。

Size大小丢帧:

           //当前帧的size追加到m_bufferSize
            increaseBuffer(size);
           //如果超过了最大缓冲buf,且又是视频I帧,置一下标志位
           if(m_bufferSize > kMaxSendbufferSize && isKeyframe) {
                m_clearing = true;
                //Todo 记录丢帧次数,满足条件就重连
            }
            m_networkQueue.enqueue([=]() {
                size_t tosend = size;
                uint8_t* p ;
                buf->read(&p, size);
                //如果没到max_buf,则视频I/P帧,音频I帧都输出,如果超过max_buf,只写视频I帧
                while(tosend > 0 && !this->m_ending && (!this->m_clearing || this->m_sentKeyframe == packetTime)) {
                    this->m_clearing = false;
                    size_t sent = m_streamSession->write(p, tosend);
                    p += sent;
                    tosend -= sent;
                    this->m_throughputSession.addSentBytesSample(sent);
                    if( sent == 0 ) {
                        dispatch_semaphore_wait(m_networkWaitSemaphore, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)));
                    }
                }

              this->increaseBuffer(-int64_t(size)); //m_bufferSize -= size

消息回调的函数中,把重连的消息抛上去

      setClientState(kClientStateBlock);
上一篇下一篇

猜你喜欢

热点阅读