如何通过videojs/video-contrib-hls查看HLS播放的rendition与分段信息
嘿,我来帮你搞定这两个Video.js + video-contrib-hls的HLS播放问题——这俩需求在做自适应码率调试或者用户体验分析的时候确实挺常用的:
video-contrib-hls给我们提供了直接访问当前播放码率层的API,有两种常用方式:
实时获取当前Rendition
你可以直接通过播放器的tech对象拿到当前活跃的rendition,它包含了分辨率、码率等关键信息:// 获取当前播放的rendition const currentRendition = player.tech().hls.currentRendition; if (currentRendition) { console.log(`当前播放版本:${currentRendition.height}px,码率:${currentRendition.bitrate}bps`); }你可以把这段代码绑定到按钮点击,或者定时执行,来实时查看当前的播放版本。
监听Rendition切换事件
如果需要实时感知码率切换的时机,可以监听hlsLevelSwitch事件,每次码率切换时都会触发:player.on('hlsLevelSwitch', (event, data) => { const newRendition = player.tech().hls.playlists.level; console.log(`切换到新的播放版本:${newRendition.height}px`); });这个事件能帮你精准捕捉到码率切换的时间点和对应的版本信息。
这个需求要结合HLS的分段结构和缓冲机制来处理,毕竟video-contrib-hls会提前加载分段,我们需要区分“当前播放的分段”和“已缓冲的分段”:
核心思路
每个Rendition(码率层)都维护了自己的分段列表,每个分段包含startTime(起始时间)和duration(时长)属性。同时,我们可以通过事件监听来跟踪已缓冲的分段及其所属的Rendition。
方法一:查询指定时间段对应的分段及Rendition
首先,你需要先获取所有可用的Rendition,然后遍历每个Rendition的分段,匹配目标时间段:
function getSegmentByTime(targetTime) { const hls = player.tech().hls; // 获取所有码率版本 const renditions = hls.playlists.master.renditions; // 先找到当前时间点对应的Rendition(考虑码率切换历史) let currentRendition = hls.currentRendition; // 在当前Rendition的分段中查找匹配的时间段 const targetSegment = currentRendition.segments.find(segment => { const segmentEnd = segment.startTime + segment.duration; return targetTime >= segment.startTime && targetTime < segmentEnd; }); if (targetSegment) { return { timeRange: `${targetSegment.startTime}-${targetSegment.startTime + targetSegment.duration}秒`, rendition: `${currentRendition.height}px`, segment: targetSegment }; } return null; } // 示例:查询第5秒对应的分段 console.log(getSegmentByTime(5));
方法二:跟踪已缓冲的分段(含预加载场景)
要处理“播放到3秒但已缓冲6-12秒”的情况,你可以监听hlsSegmentLoaded事件,这个事件会在每个分段加载完成时触发,能直接拿到该分段的时间范围和所属Rendition:
// 维护一个已缓冲分段的记录数组 const bufferedSegments = []; player.on('hlsSegmentLoaded', (event, data) => { const hls = player.tech().hls; const loadedRendition = hls.playlists.level; // 该分段所属的码率版本 const segmentInfo = { startTime: data.start, endTime: data.start + data.duration, rendition: `${loadedRendition.height}px`, bitrate: loadedRendition.bitrate }; bufferedSegments.push(segmentInfo); console.log(`已缓冲分段:${segmentInfo.startTime}-${segmentInfo.endTime}秒,版本:${segmentInfo.rendition}`); });
处理码率切换的历史分段
如果播放过程中切换过码率,不同时间段可能对应不同的Rendition,你可以维护一个码率切换历史来精准匹配:
const renditionSwitchHistory = [{ startTime: 0, rendition: player.tech().hls.currentRendition }]; player.on('hlsLevelSwitch', (event, data) => { const switchTime = player.currentTime(); const newRendition = player.tech().hls.playlists.level; renditionSwitchHistory.push({ startTime: switchTime, rendition: newRendition }); }); // 查询任意时间点对应的Rendition function getRenditionByTime(targetTime) { for (let i = renditionSwitchHistory.length - 1; i >= 0; i--) { if (targetTime >= renditionSwitchHistory[i].startTime) { return renditionSwitchHistory[i].rendition; } } return null; }
结合这个函数,你就能准确知道某个时间段对应的Rendition,再去该Rendition的分段列表中找到对应的分段即可。
内容的提问来源于stack exchange,提问作者Shobhit_Geek

