Files
tkAiPage/src/composables/useStreams.js
2025-08-22 16:35:32 +08:00

83 lines
2.4 KiB
JavaScript

// composables/useStreams.js
import { nextTick } from 'vue'
export function useStreams({ instanceList, videoElement, wslist, openStr, VideoConverter }) {
// 用 Map 做延迟队列,避免固定 8 个的限制
const feedState = new Map()
function ensureState(index) {
if (!feedState.has(index)) {
feedState.set(index, { processing: false, pending: null })
}
return feedState.get(index)
}
function pushFrame(index, buf) {
const st = ensureState(index)
if (st.processing) {
// 覆盖旧的等待帧,保留最新
st.pending = buf
return
}
st.processing = true
try {
instanceList[index].converter.appendRawData(new Uint8Array(buf))
} finally {
st.processing = false
if (st.pending) {
const next = st.pending
st.pending = null
queueMicrotask(() => pushFrame(index, next))
}
}
}
function resetFeedState(index) {
const st = feedState.get(index)
if (!st) return
st.processing = false
st.pending = null
}
async function waitForVideoEl(udid, tries = 20, delay = 16) {
for (let i = 0; i < tries; i++) {
const el = videoElement.value?.[udid]
if (el) return el
await nextTick()
await new Promise(r => setTimeout(r, delay))
}
return null
}
function refreshStream(index, hard = true) {
const devices = Object.keys(videoElement.value || {})
const udid = devices[index]
const video = videoElement.value?.[udid]
if (!video || !instanceList[index]) return
resetFeedState(index)
try { instanceList[index].converter?.destroy?.() } catch { }
instanceList[index].converter = null
if (hard) {
try { video.pause?.() } catch { }
try { video.removeAttribute?.('src') } catch { }
try { video.load?.() } catch { }
}
// 重新挂新的 converter
instanceList[index].converter = new VideoConverter(video, 60, 1)
// 让后端尽快推关键帧
try { wslist[index]?.send?.(openStr) } catch { }
}
return {
feedState,
pushFrame,
resetFeedState,
waitForVideoEl,
refreshStream,
}
}