前言
Yam TV 支持通过本地 HTTP 代理过滤 HLS 流中的广告分段。广告检测算法使用启发式方法分析分段时长和重复模式。但在实际运营中发现,这条启发式会把普通视频内容误判为广告(假阳性),导致播放时正片被错误删除。
问题场景
以下是控制台输出的诊断日志:
块 3 | 重复次数: 1 | 时长: 32.2s | 占比: 4.78% | 判定: 【广告】
块 4 | 重复次数: 1 | 时长: 30.0s | 占比: 4.46% | 判定: 【广告】
...(共 22 个连续块全部被标记)
准备删除 440 个相关行
块 3 到块 24,每个块 28-32 秒,连续 22 个块总时长 672 秒——这显然是正片内容,不是广告。但启发式算法将其全部标记为广告。
启发式算法分析
原有判定逻辑:
if (repeatTimes >= 3) -> 广告
else if (repeatTimes == 2) -> 广告(时长 < 180s)
else {
// repeatTimes == 1,唯一出现
if (segs.length < 2) -> 不是广告
if (ratio < 15% && duration < 90s) -> 广告
}
每个块在 672 秒视频中占比约 4.5%(小于 15% 阈值),时长约 30 秒(小于 90 秒阈值),且出现次数为 1(不重复)。三个条件全命中 → 判定为广告。
但这是正常的连续视频内容——每段 30 秒、不重复、连续排列。算法将连续视频中的每一段独立看待,用「占比小 + 时长短 + 不重复」三合一误判为广告。
根因:比例检查的误用
问题在于对唯一出现(repeatTimes == 1)的块使用「时长占比」和「绝对时长」作为判定标准。30 秒的正片分段在长视频中占比必然小,而这个比例对于唯一出现的块没有意义——它不去判断「这个块是不是广告」,而是误判了「这个块占比很小所以可能是广告」。
正确的标准应该是唯一出现的短块(< 15 秒)才可能是广告,正常内容的分段时长通常至少在 15-60 秒范围。
修复方案
去除 repeatTimes == 1 的比例检查和短块时长检查,改为简单的短时间检查:
// 修复后
if (repeatTimes >= 3) -> 广告
else if (repeatTimes == 2) -> 广告(时长 < 180s)
else {
// 唯一出现:只有极短的块(< 15s)才可能是广告
heuristicAd = b.totalDurationSec < 15.0;
}
同时添加了「规则命中后跳过启发式」的保护。原则是:一个视频流不应该同时被规则引擎和启发式判定为广告。如果管理员配置的规则已经命中了一些分段,说明这个流确实有广告模式,不需要启发式再补充诊断:
// 如果 Block 规则已经命中了任何分段,直接跳过启发式
if (hasMatchingBlockRule) {
skipHeuristic = true;
}
两种修复同时生效
- 无规则环境:启发式运行,30 秒正片块因 > 15 秒不会被误判;真正的广告块(通常 5-10 秒)仍能被捕获
- 有规则环境:规则命中后启发式被跳过,完全由管理员配置的规则决定
总结
启发式算法的核心假设是「异常片段 ≈ 广告」。但 HLS 流中正常的 30 秒分段也会在长视频中表现出「异常」特性(占比小、不重复)。修复的关键是认识到不同模式需要不同的判定标准——重复多次的块可能是广告,但唯一出现的块只有在极短的情况下才可能是广告。
讨论
还没有留言,来留下第一条评论吧!