LFStreamingBuffer 源码阅读

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;
}

你可能感兴趣的:(LFStreamingBuffer 源码阅读)