一、直播流程:前端视角的三步走
主播推流 → 服务端处理 → 用户拉流
↑ ↑ ↑
前端不管 前端了解 前端主战场
二、前端直播职责(一句话概括)
前端只管"拉流播放",不管"推流"!
-
推流:是主播端(OBS/手机APP)的工作,前端不涉及
-
拉流:是前端播放器的工作,从服务器获取视频流并播放
三、为什么选择HLS协议?
兼容性好:所有现代浏览器都支持
CDN友好:基于HTTP,易于分发
移动端支持:iOS/Android完美支持
缺点:延迟较高(3-10秒)
四、代码示例
javascript
<template>
<!-- 视频播放器容器 -->
<!-- controls: 显示浏览器自带的播放控制条(播放/暂停/音量/全屏/画中画等) -->
<!-- width="100%": 视频宽度占满父容器 -->
<!-- playsinline: iOS中禁止自动全屏播放,允许内联播放 -->
<!-- webkit-playsinline: iOS旧版兼容属性 -->
<video ref="videoRef" controls width="100%" playsinline webkit-playsinline></video>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const videoRef = ref(null)
// 存储hls.js实例,用于组件销毁时清理资源
let hlsInstance = null
//初始化HLS播放器,这个函数处理非Safari浏览器的HLS播放
const initHlsPlayer = async (videoElement, streamUrl) => {
try {
// 动态导入hls.js库(代码分割,减少初始包大小)
const { default: Hls } = await import('hls.js')
// 检查当前浏览器是否支持hls.js
if (Hls.isSupported()) {
// 创建HLS播放器实例
hlsInstance = new Hls({
enableWorker: true, // 使用Web Worker提升性能
lowLatencyMode: true, // 启用低延迟模式
maxBufferLength: 30 // 最大缓冲长度
})
// 加载直播流地址
hlsInstance.loadSource(streamUrl)
// 将HLS播放器绑定到video元素
hlsInstance.attachMedia(videoElement)
// 添加事件监听(可选)
hlsInstance.on(Hls.Events.MANIFEST_PARSED, async () => {
try {
// 视频资源解析完成后尝试自动播放
await videoElement.play()
} catch (playError) {
console.warn('自动播放被阻止,需要用户交互:', playError)
}
})
// 监听错误事件
hlsInstance.on(Hls.Events.ERROR, (event, data) => {
if (data.fatal) {
// 根据错误类型处理
switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
console.error('网络错误,尝试重新加载...')
hlsInstance.startLoad()
break
case Hls.ErrorTypes.MEDIA_ERROR:
console.error('媒体错误,尝试恢复...')
hlsInstance.recoverMediaError()
break
default:
console.error('无法恢复的错误,销毁实例')
destroyHlsPlayer()
break
}
}
})
console.log('hls.js播放器初始化成功')
return hlsInstance
} else {
console.error('当前浏览器不支持HLS播放')
return null
}
} catch (error) {
console.error('加载hls.js失败:', error)
return null
}
}
//销毁hls.js实例,释放资源
const destroyHlsPlayer = () => {
if (hlsInstance) {
hlsInstance.destroy()
hlsInstance = null
}
}
//初始化播放器,根据浏览器类型选择不同的播放策略
const initPlayer = async () => {
const video = videoRef.value
if (!video) {
return
}
// 直播流地址(HLS协议),可替换成自己的直播流地址,通常由后端提供或接口返回
// const hlsUrl = 'https://你的服务器地址/直播路径/stream.m3u8'
const hlsUrl = 'https://d2zihajmogu5jn.cloudfront.net/bipbop-advanced/bipbop_16x9_variant.m3u8'
// 检测浏览器是否原生支持HLS协议
// video.canPlayType()是用来检测浏览器是否支持特定的视频格式/协议
// 'application/vnd.apple.mpegurl'是标识HLS协议文件的MIME类型
// 该标识一般由后端在HTTP响应头中提供,这里是指苹果的直播协议
if (video.canPlayType('application/vnd.apple.mpegurl')) {
// 直接设置视频源地址
video.src = hlsUrl
// 开始播放
video.play().catch((error) => {
console.warn('Safari自动播放被阻止:', error)
})
return // 结束函数,Safari不需要hls.js
}
// 非Safari浏览器(Chrome、Firefox、Edge等)
await initHlsPlayer(video, hlsUrl)
}
// 组件挂载完成后执行初始化
onMounted(() => {
initPlayer()
})
// 组件销毁前清理资源
onUnmounted(() => {
destroyHlsPlayer()
})
</script>
<style scoped></style>