40

I've been fiddling with the hell that is HTML5 video/audio for a couple of weeks now. Usually the reason why something failed popped up after a while, but I've been, unable to find why I get forwarding and rewinding problems in chrome.

Anyhow...

The video or audio tag is being loaded in an extjs panel when a video or audio file is requested. The files are sent as streams and they work fine in IE and firefox (after adding duration to the response header) There's an issue with safari, but it's apparently the fact that the whole site runs in HTTPS (that's being worked on right now).

In chrome (which is my issue and is at the latest version) the video and audio loads just fine, but I'm unable to rewind or forward. When trying to seek videos just go ahead a few seconds until it reaches the end of the stream. the audio also plays just fine but trying to rewind (or forward) multiple times simply breaks the progress bar and stops the audio from playing on.

I'm not entirely sure what's being sent from the server, but I'm wondering if this might be caused by missing data in the response. If it's not that anything else to point me towards a fix is just as welcome. I think I've covered pretty much the whole set up and I've made sure that there's a source tag for each browser.

edit: this is the code generated by the javascript for one of the files:

<video width="1889" height="2" preload="auto" autoplay="1" controls="1" id="videoPlayer" style="width: 1889px; height: 233px; ">
<source src="http://localhost:8080/epaServer/epa/documents/496.ds_webm?sessionId=5616fde4-50af-43d6-a57c-f06540b64fcb" type="video/webm">
<source src="http://localhost:8080/epaServer/epa/documents/496.ds_mp4?sessionId=5616fde4-50af-43d6-a57c-f06540b64fcb" type="video/mp4">
<div>Your browser doesn't support html5 video. <a>Upgrade Chrome</a></div>
</video>

I've also found that I can't seek any of the files even if I open them separately from the application.

I've tried to find more info on my own these are the headers chrome shows in the network tab:

Request URL:https://localhost:8443/epaServer/epa/documents/496.ds_webm?sessionId=5616fde4-50af-43d6-a57c-f06540b64fcb

Request Method:GET

Status Code:200 OK

Request Headers

Accept:/ Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3

Accept-Encoding:identity;q=1, *;q=0

Accept-Language:en-US,en;q=0.8

Connection:keep-alive

Cookie:sessionId=5616fde4-50af-43d6-a57c-f06540b64fcb

Host:localhost:8443

User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.168 Safari/535.19

Query String Parametersview URL encoded

sessionId:5616fde4-50af-43d6-a57c-f06540b64fcb

Response Headers

Cache-Control:private

Content-Length:1588816

Content-Type:video/webm

Date:Mon, 14 May 2012 14:23:02 GMT

Expires:Thu, 01 Jan 1970 01:00:00 CET

Server:Apache-Coyote/1.1

X-Content-Duration:17.31

>

toxkillfraex
  • 718
  • 1
  • 6
  • 10
  • I've added some of the code that's being generated and the headers I'm getting. – toxkillfraex May 14 '12 at 14:29
  • Just to make a note for people like me who are just looking for browser capable of seeking I suggest to try using alternate browser like Mozilla Firefox (ver 29.0 tested capable of seeking). – Arvind Singh May 01 '14 at 06:43

2 Answers2

31

I found the reason why it's not working on this question:

HTML5 video will not loop

Our server doesn't understand partial content right now. As a result chrome is sending requests for content that doesn't get answered which in turn makes our video's and audio unseekable (and unloopable).

Community
  • 1
  • 1
toxkillfraex
  • 718
  • 1
  • 6
  • 10
2

You must handle req.headers['range'] which Chrome will send to your streaming server.

Please refer to my codes below. It worked well on Chrome, Firefox, Edge and IE. I haven't test it on Safari but hopefully it also can work.

I used Sails/Nodejs backend and gridFS/mongodb database for storing Videos files as Chunks.

try {
        let foundMetaFile = await GridFS.findOne({id: fileId});

        if (!foundMetaFile) return res.status(400).json(Res.error(undefined, {message: `invalid ${fileId} file`}));

        let fileLength  = foundMetaFile['length'];
        let contentType = foundMetaFile['contentType'];
        // let chunkSize   = foundMetaFile['chunkSize'];
        if(req.headers['range']) {

            // Range request, partialle stream the file
            console.log('Range Reuqest');
            var parts = req.headers['range'].replace(/bytes=/, "").split("-");
            var partialStart = parts[0];
            var partialEnd = parts[1];

            var start = parseInt(partialStart, 10);
            var end = partialEnd ? parseInt(partialEnd, 10) : fileLength - 1;
            var chunkSize = (end - start) + 1;

            console.log('Range ', start, '-', end);

            res.writeHead(206, {
                'Content-Range': 'bytes ' + start + '-' + end + '/' + fileLength,
                'Accept-Ranges': 'bytes',
                'Content-Length': chunkSize,
                'Content-Type': contentType
            });
        }

        let { mongodbConnection } = global;
        let bucket = new GridFSBucket(mongodbConnection, { bucketName: 'fs' });

        return new Promise ((resolve, reject) => {
            let downloadStream  = bucket.openDownloadStream(fileId);
            downloadStream.on('error', (err) => {
                console.log("Received Error stream")
                res.end();
                reject(err);
            })

            downloadStream.on('end', () => {
                console.log("Received End stream");
                res.end();
                resolve(true);
            })
            console.log("start streaming");
            downloadStream.pipe(res);
        })

    } catch (error) {
        switch (error.name) {
            case 'UsageError':
                return res.status(400).json(Res.error(undefined, {message: 'invalid Input'}));
            case 'AdapterError':
                return res.status(400).json(Res.error(undefined, {message: 'adapter Error'}));
            default:
                return res.serverError(error);
        }
  • Please update the code with " let downloadStream = bucket.openDownloadStream(fileId, {start: start, end: end}); " --> which set options starting and end points of the streaming. – Pham Duc Toan Apr 15 '20 at 13:03