- 2018.10.31 更新
更新日志: 此次更新增加了metadata的判斷憔杨,更新原因:
metadata什么時候會發(fā)送北戏? 2種情況:
- 剛連接的時候
- metadata發(fā)送變化的時候
那么在長時間的跑機中,時間戳的調(diào)整上會出現(xiàn)問題环葵,equeue進來的時候如果沒有對metadata的類型加以判斷调窍,則會丟失metadata,從而導(dǎo)致客戶端無法解碼播放
所以张遭,需要增加metadata的判斷
- 2018.10.25 更新
更新日志: 從0開始檢查邓萨,避免當(dāng)0為參數(shù)集的時候清理掉,從而導(dǎo)致丟失 - 現(xiàn)象
推流端切換分辨率菊卷,結(jié)果播放端花屏了缔恳,之所以花屏,查看了下rtmp幀洁闰,少了參數(shù)集歉甚。
那么等到下一個參數(shù)集到來的時候,就立即好了扑眉,這個好理解 - 原因
問題是纸泄,丟失的參數(shù)集為什么會丟失呢赖钞?
一般情況下, 參數(shù)集都是在I幀前的聘裁,后面的I幀沒有丟雪营,反倒是前面的參數(shù)集丟失了
來看下面這段代碼:
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);
}
在這里面有清掉幀數(shù)據(jù)的操作,并且是從1開始的衡便,也就是說卓缰,不管數(shù)據(jù)0的類型是什么,萬一這個0恰好就是參數(shù)集砰诵,那就清理掉了
- 修復(fù)方法
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
部分征唬,需要去掉循環(huán),否則有可能會一直在這里循環(huán)導(dǎo)致cpu飆升
if (av_end_time - av_start_time > queue_size_ms) {
shrink();
}
這里從0開始茁彭,就是為了避免當(dāng)0為參數(shù)集的時候也清理掉
- 一個沒查到的問題
什么時候會調(diào)用這個shrink呢总寒?如下代碼
while (av_end_time - av_start_time > queue_size_ms) {
shrink();
}
經(jīng)過測試,當(dāng)av_start_time=0的時候理肺,會進入這段代碼摄闸,但是在av_start_time能夠賦值的地方都看過了,實在是沒有找到為0的時候妹萨,到現(xiàn)在依然沒有查出來
哪位朋友知道答案年枕,望不吝賜教