播放器的缓冲区管理一般在demxuer模块,VLC也不例外,缓冲逻辑的对外接口文件是
vlc/modules/demux/adaptive/logic/BufferingLogic.hpp
这里先看下对外(demuxer)透出的能力:
const vlc_tick_t AbstractBufferingLogic::BUFFERING_LOWEST_LIMIT = VLC_TICK_FROM_SEC(2);
const vlc_tick_t AbstractBufferingLogic::DEFAULT_MIN_BUFFERING = VLC_TICK_FROM_SEC(6);
const vlc_tick_t AbstractBufferingLogic::DEFAULT_MAX_BUFFERING = VLC_TICK_FROM_SEC(30);
const vlc_tick_t AbstractBufferingLogic::DEFAULT_LIVE_BUFFERING = VLC_TICK_FROM_SEC(15);
class AbstractBufferingLogic
{
public:
AbstractBufferingLogic();
virtual ~AbstractBufferingLogic() {}
virtual uint64_t getStartSegmentNumber(BaseRepresentation *) const = 0;
virtual vlc_tick_t getMinBuffering(const BasePlaylist *) const = 0;
virtual vlc_tick_t getMaxBuffering(const BasePlaylist *) const = 0;
virtual vlc_tick_t getLiveDelay(const BasePlaylist *) const = 0;
virtual vlc_tick_t getStableBuffering(const BasePlaylist *) const = 0;
void setUserMinBuffering(vlc_tick_t);
void setUserMaxBuffering(vlc_tick_t);
void setUserLiveDelay(vlc_tick_t);
void setLowDelay(bool);
static const vlc_tick_t BUFFERING_LOWEST_LIMIT;
static const vlc_tick_t DEFAULT_MIN_BUFFERING;
static const vlc_tick_t DEFAULT_MAX_BUFFERING;
static const vlc_tick_t DEFAULT_LIVE_BUFFERING;
protected:
vlc_tick_t userMinBuffering;
vlc_tick_t userMaxBuffering;
vlc_tick_t userLiveDelay;
Undef<bool> userLowLatency;
};
从接口看提供的逻辑很简单,设置/获取最小/大的缓冲区,是否开启低延时等接口。这里简单梳理一下调用关系
本文福利, 免费领取C++音视频学习资料包、技术视频/代码,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,编解码,推拉流,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓
附上关键线程代码:
void PlaylistManager::Run()
{
mutex_locker locker {lock};
// 这里获取前面createLogic时的配置值,这里会影响后面返回的缓冲状态
const vlc_tick_t i_min_buffering = bufferingLogic->getMinBuffering(playlist);
const vlc_tick_t i_max_buffering = bufferingLogic->getMaxBuffering(playlist);
const vlc_tick_t i_target_buffering = bufferingLogic->getStableBuffering(playlist);
while(1)
{
while(!b_buffering && !b_canceled)
waitcond.wait(lock);
if (b_canceled)
break;
if(needsUpdate())
{
if(updatePlaylist())
scheduleNextUpdate();
else
failedupdates++;
}
vlc_mutex_lock(&demux.lock);
vlc_tick_t i_nzpcr = demux.i_nzpcr;
vlc_mutex_unlock(&demux.lock);
// 主要是在这里,这里会返回缓冲区状态
AbstractStream::BufferingStatus i_return = bufferize(i_nzpcr, i_min_buffering,
i_max_buffering, i_target_buffering);
// 缓存只要不是特别少还是要进里面的逻辑
if(i_return != AbstractStream::BufferingStatus::Lessthanmin)
{
// 说白了不同的状态只是wait的时间不同
vlc_tick_t i_deadline = vlc_tick_now();
if(i_return == AbstractStream::BufferingStatus::Ongoing)
i_deadline += VLC_TICK_FROM_MS(10);
else if(i_return == AbstractStream::BufferingStatus::Full)
i_deadline += VLC_TICK_FROM_MS(100);
else if(i_return == AbstractStream::BufferingStatus::End)
i_deadline += VLC_TICK_FROM_SEC(1);
else /*if(i_return == AbstractStream::BufferingStatus::suspended)*/
i_deadline += VLC_TICK_FROM_MS(250);
// TODO: The current function doesn't seem to modify shared
// state under demux lock.
vlc_cond_signal(&demux.cond);
while(b_buffering &&
waitcond.timedwait(lock, i_deadline) == 0 &&
i_deadline > vlc_tick_now() &&
!b_canceled);
if (b_canceled)
break;
}
}
}
这里在讲一下上面提到的缓冲状态,源码没有注释,看起来也是晦涩难懂,附到代码注释中,如果有理解不到位的地方欢迎指正:
enum class BufferingStatus {
End = 0, /* prioritized */ // 结束的状态,类似EOF
Suspended, // 起播时候还在fakeEsOut或者直播超过最新的playlist的时候的状态
Full, // 缓冲区满了
Ongoing, // 介于满和Lessthanmin之间的状态,最常见的状态
Lessthanmin, // 缓冲数据量小于最小阈值i_min_buffering
};