Roshan Maind
Roshan Maind

Reputation: 21

Error event fires on SourceBuffer object after appendBuffer() call with a Uint8Array() chunk of an mp4 file

I am trying to create a video player in which I want to download segments/chunks of an MP4 file using the Range header from a server (I have a proxy server in between the client React.js app and the actual resource server for my application specific security reasons).

I am receiving the chunk of the mp4 file in buffer properly, I tried printing the data out on console. But as soon as the appendBuffer() method is called the first time with the first chunk of the file, the SourceBuffer throws an error event.

Here is the code:

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)
            })
        }
        
    }

As the code shows, I am converting the API response to an ArrayBuffer, then converting that to a Uint8Array which is passed to the appendBuffer() method on the SourceBuffer object.

These are my SourceBuffer's updateend & MediaSource's sourceopen event handlers:


    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()
    }

And finally, in my render() JSX, I have mounted the video tag like so

<video loop="loop" id="video" height="320px" width="640px" controls="1" onError={(e) => {console.log(e)}}/>

These are the logs I get

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, eventPhase: 2, …}
Services.js:373 SyntheticEvent {dispatchConfig: {…}, _targetInst: FiberNode, _dispatchInstances: FiberNode, nativeEvent: Event, _dispatchListeners: ƒ, …}
index.js:1 video tag error  Event {isTrusted: true, type: "error", target: video#video, currentTarget: video#video, eventPhase: 2, …}

The SourceBuffer is firing error event and right after that the updateend event is fired. I am not able to understand what the actual issue is with this code. What could I be doing wrong?

Upvotes: 2

Views: 756

Answers (0)

Related Questions