React + Videojs + Sanic 打造简易流播放器

Html5 的 <video /> 只能在整个视频文件加载完成后才能播放,体验极其不好。如果仅是支持基于 Http(s) 的流媒体播放的话,可以直接利用 Http 协议的 Content-Range 头。

所以本文的核心思想是使 Sanic 后端能正确处理 Videojs 发送的 byte-range 请求,并回以带 Content-Range 的文件流响应即可。

安装 Video.js

在 React 项目目录下安装 Video.js 及其主题 UI 库。

1
2
3
npm install video.js

npm install video.js @videojs/themes

React 组件中使用 Video.js

App.js 中,创建 video 对象并将其与 Video.js player 关联:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import './App.css';
import React from 'react';
import videojs from 'video.js';
import "video.js/dist/video-js.css";
import '@videojs/themes/dist/sea/index.css';

export default class App extends React.Component {

componentDidMount() {
// instantiate Video.js
this.player = videojs(this.videoNode, this.props, function onPlayerReady() {
console.log('onPlayerReady', this)
});
}

render() {
return (
<div>
<div data-vjs-player>
<video ref={node => this.videoNode = node} className="video-js vjs-theme-sea"></video>
</div>
</div>
)
}
}

index.js 中,通过 /api/video 接口向后端发送视频请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

const videoJsOptions = {
autoplay: false,
controls: true,
sources: [{
src: '/api/video',
type: 'video/mp4'
}]
}

ReactDOM.render(
<React.StrictMode>
<App {...videoJsOptions}/>
</React.StrictMode>,
document.getElementById('root')
);

Sanic 中处理请求

Sanic 提供文件流响应对象,并提供 api 处理请求中的 byte-range。将两者结合,即可构造出一个带 Content-Range 头的响应。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from sanic import Sanic
from sanic.response import file_stream
from sanic.handlers import ContentRangeHandler
from sanic.compat import stat_async

app = Sanic('player')

app.static('/static', './static')


@app.get('/api/video')
async def api(request):
file_path = './1.mp4'
stats = await stat_async(file_path)
_range = ContentRangeHandler(request, stats)
return await file_stream(file_path, _range=_range)

结论

  1. 基本能达到“秒开”效果。

  2. 需要媒体格式支持才行。比如 MP4,就需要在其文件开头具有 moov atom 信息。

参考

Problems with playback:https://docs.videojs.com/tutorial-troubleshooting.html#problems-with-playback

Problems when hosting media:https://docs.videojs.com/tutorial-troubleshooting.html#problems-when-hosting-media

Video.js and ReactJS integration:https://docs.videojs.com/tutorial-react.html#react-class-component-example

ContentRangeHandler:https://sanic.readthedocs.io/en/stable/sanic/api/core.html#sanic.handlers.ContentRangeHandler

如何优雅地实现网页播放视频:https://www.jianshu.com/p/65af0f01cb97

评论