41

几个星期以来,我一直在摆弄 HTML5 视频/音频的地狱。通常会在一段时间后弹出某些失败的原因,但我一直无法找到为什么我在 chrome 中遇到转发和倒带问题。

无论如何...

请求视频或音频文件时,将在 extjs 面板中加载视频或音频标签。这些文件作为流发送,它们在 IE 和 firefox 中运行良好(在向响应标头添加持续时间后) safari 存在问题,但显然整个站点在 HTTPS 中运行(目前正在处理)。

在 chrome 中(这是我的问题并且是最新版本),视频和音频加载得很好,但我无法倒带或前进。当试图寻找视频时,只需前进几秒钟,直到它到达流的末尾。音频也可以正常播放,但尝试多次倒带(或快进)只会破坏进度条并停止播放音频。

我不完全确定服务器发送了什么,但我想知道这是否可能是由于响应中缺少数据造成的。如果不是其他任何事情都可以让我找到解决办法,那也是同样受欢迎的。我想我已经涵盖了几乎整个设置,并且我确保每个浏览器都有一个源标签。

编辑:这是 javascript 为其中一个文件生成的代码:

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

我还发现,即使我将它们与应用程序分开打开,我也无法查找任何文件。

我试图自己查找更多信息,这些是网络选项卡中显示的标题 chrome:

请求网址:https://localhost:8443/epaServer/epa/documents/496.ds_webm?sessionId=5616fde4-50af-43d6-a57c-f06540​​b64fcb

请求方法:GET

状态码:200 OK

请求标头

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

接受编码:身份;q=1,*;q=0

接受语言:en-US,en;q=0.8

连接:保持活动

Cookie:sessionId=5616fde4-50af-43d6-a57c-f06540​​b64fcb

主机:本地主机:8443

用户代理:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.168 Safari/535.19

查询字符串参数查看 URL 编码

sessionId:5616fde4-50af-43d6-a57c-f06540​​b64fcb

响应标头

缓存控制:私有

内容长度:1588816

内容类型:video/webm

日期:2012 年 5 月 14 日星期一 14:23:02 GMT

过期时间:周四,1970 年 1 月 1 日 01:00:00 CET

服务器:Apache-Coyote/1.1

X 内容持续时间:17.31

>

4

2 回答 2

33

我找到了它不能解决这个问题的原因:

HTML5 视频不会循环播放

我们的服务器现在不理解部分内容。因此,chrome 正在发送对未得到答复的内容的请求,这反过来又使我们的视频和音频无法搜索(并且无法循环)。

于 2012-05-16T13:20:26.140 回答
2

您必须处理 Chrome 将发送到您的流媒体服务器的 req.headers['range'] 。

请参考我下面的代码。它在 Chrome、Firefox、Edge 和 IE 上运行良好。我还没有在 Safari 上测试它,但希望它也可以工作。

我使用 Sails/Nodejs 后端和 gridFS/mongodb 数据库将视频文件存储为块。

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);
        }
于 2020-04-15T12:55:04.387 回答