LFLiveKit框架是一套RTMP推流框架,主要使用OC写的,框架文件十分清晰,并且拓展性非常强,支持动态切换码率功能,支持美颜功能.
LFStreamingBuffer是LFLiveKit中对视频帧执行缓冲和丢帧策略的地方,对LFStreamingBuffer进行阅读,记录下学习的心得.
LFStreamingBuffer这个类提供了一套根据本地缓冲区在规定时间内的量来回调缓冲区buffer是在增加还是在减少。通过状态来对视频码率进行动态修改.
init初始化,主要用来初始化状态量
- (instancetype)init {
if (self = [super init]) {
// 信号量
_lock = dispatch_semaphore_create(1);
// 更新时间间隔,默认频率1s
self.updateInterval = defaultUpdateInterval;
// 回调时间间隔,默认5s
self.callBackInterval = defaultCallBackInterval;
// 最大缓冲帧数量,默认600
self.maxCount = defaultSendBufferMaxCount;
// 上一次丢帧数量
self.lastDropFrames = 0;
// 循环timer开启状态
self.startTimer = NO;
}
return self;
}
- (void)appendObject:(LFFrame *)frame用来处理添加的frame,超出限制后开始选择性丢帧,并将最终要上传的frame存起来
- (void)appendObject:(LFFrame *)frame {
if (!frame) return;
// 是否启动了timer
if (!_startTimer) {
_startTimer = YES;
[self tick];
}
// 处理完一个frame再处理下一个
dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
// sortList:拿来排序用的数组
if (self.sortList.count < defaultSortBufferMaxCount) {
// sortList.count 小于默认值最大限制时,继续拼接frame
[self.sortList addObject:frame];
} else {
///< 根据时间戳,对数组重新排序
[self.sortList addObject:frame];
[self.sortList sortUsingFunction:frameDataCompare context:nil];
/// 丢帧
[self removeExpireFrame];
/// 添加至缓冲区
LFFrame *firstFrame = [self.sortList lfPopFirstObject];
// 将第一个frame放入list中
if (firstFrame) [self.list addObject:firstFrame];
}
dispatch_semaphore_signal(_lock);
}
removeExpireFrame实施丢帧策略的方法
- (void)removeExpireFrame {
// 如果当前缓冲区要上传的额frame在允许范围内,不进行丢帧处理
if (self.list.count < self.maxCount) return;
// 拿到list中从第一个P到下一个I之间的所有frame
NSArray *pFrames = [self expirePFrames];///< 第一个P到第一个I之间的p帧
self.lastDropFrames += [pFrames count];
// 如果非空,移除掉这些非关键帧
if (pFrames && pFrames.count > 0) {
[self.list removeObjectsInArray:pFrames];
return;
}
// 如果pFrames是空的,删除掉一个I帧
NSArray *iFrames = [self expireIFrames];///< 删除一个I帧(但一个I帧可能对应多个nal)
self.lastDropFrames += [iFrames count];
if (iFrames && iFrames.count > 0) {
[self.list removeObjectsInArray:iFrames];
return;
}
[self.list removeAllObjects];
}
- (NSArray *)expirePFrames {
NSMutableArray *pframes = [[NSMutableArray alloc] init];
for (NSInteger index = 0; index < self.list.count; index++) {
LFFrame *frame = [self.list objectAtIndex:index];
if ([frame isKindOfClass:[LFVideoFrame class]]) {
LFVideoFrame *videoFrame = (LFVideoFrame *)frame;
if (videoFrame.isKeyFrame && pframes.count > 0) {
//找到一个I帧,并且数组非空时,跳出循环
break;
} else if (!videoFrame.isKeyFrame) {
[pframes addObject:frame];
}
}
}
return pframes;
}
- (NSArray *)expireIFrames {
NSMutableArray *iframes = [[NSMutableArray alloc] init];
uint64_t timeStamp = 0;
for (NSInteger index = 0; index < self.list.count; index++) {
LFFrame *frame = [self.list objectAtIndex:index];
if ([frame isKindOfClass:[LFVideoFrame class]] && ((LFVideoFrame *)frame).isKeyFrame) {
// 拿到一个I后,当下一个时间戳不同时,跳出循环
if (timeStamp != 0 && timeStamp != frame.timestamp) break;
[iframes addObject:frame];
timeStamp = frame.timestamp;
}
}
return iframes;
}
tick定时器,通过对缓冲区缓冲数量的轮询,以对采样缓冲区数量为依据,对码率进行调整
- (void)tick {
// 记录下时间状态
_currentInterval += self.updateInterval;
// 记录list中待上传frame的数量
dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
[self.thresholdList addObject:@(self.list.count)];
dispatch_semaphore_signal(_lock);
// 在默认参数下,5s进行一次采样,对状态进行判断
if (self.currentInterval >= self.callBackInterval) {
//当前缓冲区状态
LFLiveBuffferState state = [self currentBufferState];
// 根据缓冲区状态,LFLiveSession可以调整码率
if (state == LFLiveBuffferIncrease) {
if (self.delegate && [self.delegate respondsToSelector:@selector(streamingBuffer:bufferState:)]) {
[self.delegate streamingBuffer:self bufferState:LFLiveBuffferIncrease];
}
} else if (state == LFLiveBuffferDecline) {
if (self.delegate && [self.delegate respondsToSelector:@selector(streamingBuffer:bufferState:)]) {
[self.delegate streamingBuffer:self bufferState:LFLiveBuffferDecline];
}
}
//采样间隔和记录数据清空
self.currentInterval = 0;
[self.thresholdList removeAllObjects];
}
// 定时器
__weak typeof(self) _self = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.updateInterval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
__strong typeof(_self) self = _self;
[self tick];
});
}
- (LFLiveBuffferState)currentBufferState {
NSInteger currentCount = 0;
NSInteger increaseCount = 0;
NSInteger decreaseCount = 0;
// 查看list增加和减小的次数(默认self.thresholdList.count为5)
for (NSNumber *number in self.thresholdList) {
if (number.integerValue > currentCount) {
increaseCount++;
} else{
decreaseCount++;
}
currentCount = [number integerValue];
}
// 如果缓冲区一直在递增,缓冲区状态差应该降低码率
if (increaseCount >= self.callBackInterval) {
return LFLiveBuffferIncrease;
}
// 如果缓冲区一直在递减,缓冲区状态好应该提升码率
if (decreaseCount >= self.callBackInterval) {
return LFLiveBuffferDecline;
}
// 否则不需要处理
return LFLiveBuffferUnknown;
}
网友评论