Browse Source

feat: play HLS in LivePlayer via hls.js

main
xiaosi 2 weeks ago
parent
commit
3bba5e8d87
  1. 74
      src/components/LivePlayer.vue

74
src/components/LivePlayer.vue

@ -10,8 +10,6 @@
controls
autoplay
playsinline
:src="playUrl"
@error="$emit('error')"
/>
<div v-else class="camera-scene">
<div class="horizon" />
@ -37,7 +35,7 @@
</template>
<script setup>
import { computed, ref } from 'vue'
import { computed, onBeforeUnmount, ref, watch } from 'vue'
const props = defineProps({
playUrl: { type: String, default: '' },
@ -46,10 +44,12 @@ const props = defineProps({
cameraLabel: { type: String, default: '机巢摄像头' },
})
defineEmits(['toggle', 'error'])
const emit = defineEmits(['toggle', 'error'])
const frameEl = ref(null)
const videoEl = ref(null)
let hls = null
let attachSeq = 0
const playable = computed(() => props.playUrl && !props.playUrl.startsWith('fake://'))
const isLiveShell = computed(() => props.active && !playable.value)
@ -71,6 +71,72 @@ const statusMessage = computed(() => {
return ''
})
function destroyPlayer() {
if (hls) {
hls.destroy()
hls = null
}
const video = videoEl.value
if (video) {
video.removeAttribute('src')
video.load()
}
}
async function attachPlayer(url) {
const seq = ++attachSeq
destroyPlayer()
if (!url || url.startsWith('fake://')) return
await Promise.resolve()
const video = videoEl.value
if (!video || seq !== attachSeq) return
video.addEventListener('error', () => {
if (seq !== attachSeq) return
emit('error')
}, { once: true })
if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = url
try { await video.play() } catch (_) {}
return
}
const { default: Hls } = await import('hls.js')
if (seq !== attachSeq) return
if (!Hls.isSupported()) {
emit('error')
return
}
hls = new Hls({ enableWorker: true, lowLatencyMode: true })
hls.on(Hls.Events.ERROR, (_event, data) => {
if (seq !== attachSeq) return
if (data?.fatal) emit('error')
})
hls.loadSource(url)
hls.attachMedia(video)
hls.on(Hls.Events.MANIFEST_PARSED, () => {
if (seq !== attachSeq) return
video.play().catch(() => {})
})
}
watch(
() => props.playUrl,
(url) => {
if (playable.value) attachPlayer(url)
else destroyPlayer()
},
{ immediate: true }
)
onBeforeUnmount(() => {
attachSeq += 1
destroyPlayer()
})
function requestFullscreen() {
const el = playable.value ? videoEl.value : frameEl.value
if (!el?.requestFullscreen) return false

Loading…
Cancel
Save