- 2018.10.31 更新
更新日志: 此次更新增加了metadata的判斷,更新原因:
metadata什么時候會發送? 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的時候,到現在依然沒有查出來
哪位朋友知道答案,望不吝賜教