问题描述
我正在尝试创建一个视频播放器,我想在其中使用服务器的 Range 标头下载 MP4 文件的片段/块(我在客户端 React.js 应用程序和实际资源服务器之间有一个代理服务器出于我的应用程序特定的安全原因)。
我正在缓冲区中正确接收 mp4 文件的块,我尝试在控制台上打印数据。但是只要第一次使用文件的第一个块调用 appendBuffer() 方法,SourceBuffer 就会抛出一个错误事件。
代码如下:
loadSegment = async () => {
if (!this.state.videoEnded) {
fetch(`http://localhost:5008/video?id=${this.state.sessionID}&byteCursor=${this.state.byte}&tok=${this.state.token}`,{
method: "GET"
}).then((res) => {
res.arrayBuffer().then(buf => {
console.log('buf',buf)
let status = res.status
console.log('status',status)
let newTime = this.state.time + (buf.byteLength / (this.state.contentLength / this.state.videoDuration))
let newByte = this.state.byte + buf.byteLength
this.setState({
time: newTime,byte: newByte
},() => {
videoSourceBuffer.appendBuffer(new Uint8Array(buf));
console.log('buffer appended')
if (status == 200) {
console.log('end of stream')
this.setState({
videoEnded: true
})
} else if (status == 206) {
let video = document.getElementById("video")
if (video.paused) {
// start playing after first chunk is appended
video.play();
console.log('video was paused; played')
}
console.log("this.state.token before incr",this.state.token)
this.setState({
token: parseInt(this.state.token) + 1,time: newTime
},() => {
console.log('token incremented; loadSegment called again')
console.log("this.state.token after incr",this.state.token)
})
}
})
}).catch(e => {
console.log(e)
})
}).catch(e => {
console.log(e)
})
}
}
如代码所示,我将 API 响应转换为 ArrayBuffer,然后将其转换为 Uint8Array,然后将其传递给 SourceBuffer 对象上的 appendBuffer() 方法。
这些是我的 SourceBuffer 的 updateend 和 MediaSource 的 sourceopen 事件处理程序:
mediaSourceOpenEventListener = () => {
console.log("media source open")
if (MediaSource.isTypeSupported('video/mp4; codecs="avc1.42E01E,mp4a.40.2"')) {
console.log("mp4 codec supported");
} else {
console.log("mp4 codec not supported");
}
videoSourceBuffer =
ms.addSourceBuffer('video/mp4; codecs="avc1.64001E"');
videoSourceBuffer.mode = 'sequence';
console.log("created source buffer")
videoSourceBuffer.addEventListener('updateend',this.videoSourceBufferUpdateEndListener);
videoSourceBuffer.addEventListener('error',(e) => {
console.log("Video Source Error: ",e)
});
ms.addEventListener('sourceended',(e) => {
console.log("MS sourceended event: ",e)
});
ms.addEventListener('sourceclose',(e) => {
console.log("MS sourceclose event: ",e)
});
this.loadSegment()
}
videoSourceBufferUpdateEndListener = () => {
if (this.state.videoEnded) {
videoSourceBuffer.onupdateend = null
ms.onsourceopen = null
videoSourceBuffer.abort()
}
// videoSourceBuffer.timestampOffset = this.state.time
console.log('Finished updating buffer');
this.loadSegment()
}
最后,在我的 render() JSX 中,我像这样安装了视频标签
<video loop="loop" id="video" height="320px" width="640px" controls="1" onError={(e) => {console.log(e)}}/>
这些是我得到的日志
Services.js:78 Create ms object
Services.js:80 Create ms url object
Services.js:82 got video tag
Services.js:84 src assigned to video tag
Services.js:100 media source open
Services.js:102 mp4 codec supported
Services.js:109 created source buffer
Services.js:140 buf ArrayBuffer(256001) {}
Services.js:142 status 206
Services.js:150 buffer appended
Services.js:161 video was paused; played
Services.js:163 this.state.token before incr 213843
Services.js:169 token incremented; loadSegment called again
Services.js:170 this.state.token after incr 213844
Services.js:112 Video Source Error: Event {isTrusted: true,type: "error",target: SourceBuffer,currentTarget: SourceBuffer,eventPhase: 2, …}
Services.js:130 Finished updating buffer
Services.js:115 MS sourceended event: Event {isTrusted: true,type: "sourceended",target: MediaSource,currentTarget: MediaSource, …}
Services.js:373 SyntheticEvent {dispatchConfig: {…},_targetInst: FiberNode,_dispatchInstances: FiberNode,nativeEvent: Event,_dispatchListeners: ƒ, …}
index.js:1 video tag error Event {isTrusted: true,target: video#video,currentTarget: video#video, …}
SourceBuffer 正在触发 error 事件,紧接着 updateend 事件被触发。我无法理解这段代码的实际问题是什么。我可能做错了什么?
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)