- 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的时候,到现在依然没有查出来
哪位朋友知道答案,望不吝赐教
网友评论