前提,公司要求在app端播放HLS协议的视频流,流有h.264、h.265(HEVC)两种,并且要实现秒开播放。第一想法就是使用uniapp实现的原生video标签,官网介绍了它在APP平台是完全支持该流的播放,我确实也这么用了(省事就完了)。先说明一点,官方video播放真的很流畅,很香!!
但是问题来了,首次加载超长延迟(平均5s或以上),远远达不到秒开的要求,就被打回了 /(ㄒoㄒ)/~~ ,降低了要求控制在3s内打开。其实在这之前,PC端是有通过hls.js做过播放的,确实是秒开的,所以优化的第一个想法就是在uniapp端使用hls.js,先说怎么做吧,再说在uniapp端使用它存在的问题.
webview的方式(当然也可以使用renderjs,这个的话就不存在webview层级太高的问题),废话不说实现如下:
// 本地html文件中
<div class="controls">
<input type="text" id="videoUrl" placeholder="输入HLS视频URL" style="flex: 1;">
<button onclick="loadVideo()">加载视频</button>
<button onclick="playVideo()">播放</button>
<button onclick="destroyVideo()">销毁</button>
</div>
<video class="video-player" id="videoPlayer" muted></video>
<div class="status">
<strong>状态:</strong> <span id="statusText">等待加载视频...</span>
</div>
//npm i hls 将hls.js放到hybrid下的静态文件夹下(不知道如何加载本地html可以去官网看),uni.web-view.js 必须要放的,跟webview通信关键文件
<script type="text/javascript" src="./js/uni.web-view.js"></script>
<script type="text/javascript" src="./js/hls.js"></script>
<script type="text/javascript">
// 全局变量
let videoPlayer = null;
let hls = null;
let algorithmList = [];
let alarmList = [];
let fallbackImageUrl = './assets/default.png';
// 获取DOM元素
const videoElement = document.getElementById('videoPlayer');
const videoUrlInput = document.getElementById('videoUrl');
// 更新状态显示
function updateStatus(status) {
statusTextElement.textContent = status;
}
// 初始化HLS播放器
function initHlsPlayer() {
if (!Hls.isSupported()) {
updateStatus('HLS.js不支持当前浏览器');
return false;
}
hls = new Hls({
debug: true,
enableWorker: true,
liveSyncDurationCount: 8,
liveMaxLatencyDurationCount: 10
});
// 监听HLS事件
hls.on(Hls.Events.MANIFEST_LOADED, function(event, data) {
updateStatus('MANIFEST_LOADED');
});
hls.on(Hls.Events.FRAG_CHANGED, function(event, data) {
updateStatus('FRAG_CHANGED');
});
hls.on(Hls.Events.ERROR, function(event, data) {
console.log('ERROR:', data);
updateStatus('ERROR');
showErrorImage();
});
hls.on(Hls.Events.FRAG_LOADED, function(event, data) {
updateStatus('FRAG_LOADED');
});
hls.on(Hls.Events.FRAG_PARSED, function(event, data) {
updateStatus('FRAG_PARSED');
});
hls.on(Hls.Events.FRAG_LOAD_EMERGENCY_ABORTED, function(event, data) {
updateStatus('FRAG_LOAD_EMERGENCY_ABORTED');
});
hls.on(Hls.Events.MEDIA_ATTACHED, function() {
updateStatus('MEDIA_ATTACHED');
});
hls.attachMedia(videoElement);
return true;
}
// 加载视频
function loadVideo() {
const videoUrl = videoUrlInput.value.trim();
if (!videoUrl) {
alert('请输入视频URL');
return;
}
if (hls) {
destroyVideo();
}
if (initHlsPlayer()) {
hls.loadSource(videoUrl);
updateStatus('正在加载视频...');
}
}
// 播放视频
function playVideo() {
if (videoElement && hls) {
videoElement.play().catch(error => {
console.error('播放失败:', error);
updateStatus('播放失败: ' + error.message);
});
} else {
alert('请先加载视频');
}
}
// 销毁播放器
function destroyVideo() {
if (hls) {
hls.destroy();
hls = null;
}
}
// 页面可见性变化处理
document.addEventListener('visibilitychange', function() {
if (document.visibilityState === 'hidden') {
if (hls) {
destroyVideo();
}
} else if (document.visibilityState === 'visible') {
// 可以在这里添加重新加载的逻辑
}
});
// 页面加载完成后初始化
window.addEventListener('load', function() {
updateStatus('就绪');
});
</script>
//vue文件中 使用
<web-view src="/hybrid/html/hls-video.html" @message="handleMessage" id='webview' :style="{width:'400px',height:'300rpx'}"></web-view>
在h5端确实秒开了(本来就应该是秒开哈哈),但是在真机运行报错了!!!(对于小白来说人麻了)
Failed to execute 'addSourceBuffer'on 'MediaSource': The type provided ('video/mp4;codeecs=hvc1.1.6.L153.B0') is unsupported why?why?why?
大大的疑问:我手机不支持h.265解码能力?我手机这么low?不对,安卓12支持啊 详情请看
webview的问题?不确定去看看,
Android System Webview ?
再看看, 安卓5.0以上 且 Chromium 143 版本支持
看看我手机的Android System Webview版本,原来如此!!!!!手机太low 🥲(版本太低的话也可以更新,但是是非必要,因为不可能去让用户主动更新)
但其实搜索相关文章会发现 大约在
Android 5-6x WebView:Chromium 105 之后就开始支持 h.265了,发现这一问题后找了其他同事的手机(142的版本)尝试 ,确实Android System Webview版本高的是可以播放的,不会报错,而且秒开无卡顿。这期间其实还试了使用 腾讯X5浏览器内核 打自定义基座包尝试也是报错,后来发现X5内核的免费版可能基于较旧的Chromium版本(如89),同样不支持H265,所以很遗憾hls的方案就没有继续了
第三种,尝试了muiplayer.js,这个使用了renderjs的方式尝试的,h5端秒开,可以播放h265,但是APP端报错(忘记截图了),大概的报错就是不让使用hls,因为使用的时候需要用到hls.js,找了半天原因,才发现APP端需要购买他们的插件才能用 😂 (¥59,但是我没买,因为还想找找其他方案,而且不确定买了之后能不能播放h265,应该需要问客服)
其实我还想尝试一下使用 jessibuca.js, 感觉它更强大一点,也支持软解码硬解码,不过想播放h.265也需要付费 , 但奈何时间不够,就三天左右的时间,想了想还是自己有时间尝试尝试吧~
到后面真的有点没招,决定去插件市场看看,找了两个感觉还可以的,结果发现还是播不了H265, 太绝望了!!
最后找了我们的负责流转发服务的同事讨论了下,结果发现他也可以提供FLV的流,决定直接拿原生video尝试一下,毕竟flv的延迟就是要比hls的低,抱着这个希望试了一下,结果是2s左右就可以播放出画面! 真的失去了所有的力气和手段,兜兜转转还是回到了原点....