iOS推流一般是用aac+h264封裝成flv后,推流rtmp協(xié)議
大致的流程圖我簡單畫了下
在使用過程中發(fā)現(xiàn)雨涛,如果主播推流網(wǎng)絡(luò)卡了M分鐘(很常見)枢舶,這時候編碼后的數(shù)據(jù)如果不丟的話懦胞,還會把老的(編碼后的)數(shù)據(jù)陸陸續(xù)續(xù)推上去(可能要N分鐘才能推完),這時候播放器有丟包處理祟辟,X分鐘后恢復(fù)正常医瘫,但是體驗其實不算太好侣肄,因為推流端沒丟包旧困,本來不該推上去的老數(shù)據(jù),還是推上去了稼锅,這樣播放器即使丟包了吼具,還是會看到老數(shù)據(jù),會造成幾個不好的結(jié)果:
- 播放器過了很久才恢復(fù)到實時矩距。
- 無謂的帶寬浪費了拗盒。
- 在那段恢復(fù)的時間內(nèi),延遲大锥债。
所以陡蝇,要丟包,編碼出來的包哮肚,如果隊列很大登夫,說明推不上去,那這時候允趟,應(yīng)該丟掉一部分恼策。
我的思路是: 根據(jù)包的隊列或者buffer, 換算成時間單位s潮剪, 如果>3s, 就丟掉一半涣楷,或者丟的只剩3s。
根據(jù)pts為閥值來判斷抗碰,丟掉某個pts之前的數(shù)據(jù)狮斗。
丟包的時候,視頻包要注意一下弧蝇,很老的I幀包可以丟情龄,但是臨近閥值的時候,就不能丟捍壤,丟到I幀前一幀骤视。
如果不能按照pts丟,那就只能用size大小來丟幀鹃觉。
這個策略和播放的丟包其實是一樣的专酗。
Size大小丟幀:
//當前幀的size追加到m_bufferSize
increaseBuffer(size);
//如果超過了最大緩沖buf,且又是視頻I幀盗扇,置一下標志位
if(m_bufferSize > kMaxSendbufferSize && isKeyframe) {
m_clearing = true;
//Todo 記錄丟幀次數(shù)祷肯,滿足條件就重連
}
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
消息回調(diào)的函數(shù)中,把重連的消息拋上去
setClientState(kClientStateBlock);