Vue 中使用 Video.js 播放 RTMP 视频

香港卫视有直播的 RTMP 流,本文简述了使用 Vue 技术播放 RTMP 流媒体的方法。

在网页上播放视频或者直播流,比较常用的视频流有很多。可以分为几类技术:

  • HTTP 系列。直播采用的是 ogg 格式的流媒体;
  • Apple 系列。直播采用的是 HLS 格式的流媒体;
  • Flash 系列。直播采用的是 RTMP 格式的流媒体。

Video.js 库已经将常见的视频流进行了封装,并扩展了 HTML 的视频控件的能力。 因此我们主要使用 Video.js 作为基础进行开发。

Vue-Video-Player 的改造

在 Vue 中使用 Video.js 库的时候,常用的库就是 Vue-Video-Player 这个库。 这个库将 Video.js 封装为 Vue 组件,在 Vue 项目中直接引用即可。 但是这个库在播放 RTMP 格式视频流的时候,会出现问题!我们需要对其进行改造。

其实这个库最核心的源码就是一个名为 player.vue 的组件。其他文件不过是作为 Vue 插件的必要代码。 因此,我们可以直接将这个组件复制到我们的工程中,以普通组件的方式引入即可。 然后对其进行改造。改造方法如下

1
2
3
import _videojs from 'video.js'
const videojs = window.videojs || _videojs
+ import "videojs-flash"

这个库无法播放 RTMP 的根本原因尚不清楚,不过从这个改造方法来看,可能是由于作用域的问题, 导致在外部引入的 videojs-flash 模块无法在这个组件中加载,因此需要将这个模块在组件中引入。 然后运行即可。

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<template>
<div>
<h1>RTMP Video</h1>
<video-player :options="playerOptions" :playsinline="true" @statechanged="playerStateChanged($event)"></video-player>
</div>
</template>

<script>
import VideoPlayer from "./player.vue"
export default {
components: {
"video-player": VideoPlayer
},
data () {
return {
playerOptions: {
sources: [{
type: "rtmp/flv",
src: "rtmp://live.hkstv.hk.lxdns.com/live/hks2"
}],
techOrder: ['flash'],
autoplay: true,
controls: true,
flash: {
swf: "static/video-js.swf"
},
height: "320"
}
}
},
methods: {
playerStateChanged (state) {
console.log(state)
}
},
mounted() {

}
}
</script>

在 Electron 中播放

在 Electron 中播放,需要加载 Flash。加载的方法也很简单,将下面代码加入创建窗口之前

1
2
3
4
5
let flashPath = app.getPath('pepperFlashSystemPlugin');
console.log(flashPath);

app.commandLine.appendSwitch("ppapi-flash-path", flashPath);
app.commandLine.appendSwitch('ppapi-flash-version', '29.0.0.013'); // 可以不要

然后打开 Electron 插件的功能

1
2
3
4
5
6
7
mainWindow = new BrowserWindow({
height: 563,
useContentSize: true,
+ webPreferences: {
+ plugins: true
+ },
})

然后把 videojs-flash 中提供的 video-js.swf 文件放到 statics 文件夹下即可。 这是我们在 Electron 中使用的效果。

打包模式下的问题

上述 Electron 应用在打包后,就无法播放 RTMP 视频了。为什么呢?

Electron 应用一旦打包,所有资源的加载都是以 file:// 协议进行加载的,这时 Flash 被禁用了。

这是官方的解释。但是其实我试过,直接用 embed 标签从 static 文件夹中加载 swf 文件是可以的。 但是为什么 video-js.swf 就加载不出来,原因就不得而知了。 如果想要加载视频,可以采取将 Electron 编译好的 HTML 文件放到服务器上,如 nginx 。 通过服务器加载 Electron 应用内的页面。

官方给出的解决方案是,使用 nw-flash-trust 库,信任 Flash 。 但是我至今也没有试出来到底怎么使用这个库。

经过测试,我实验出了一种打包方法,可以摆脱单独的服务器。原理是采用内置服务器,最简单的方法是用 Express。 在应用程序的主进程中创建一个 Express 服务器,只需要设置静态文件中间件,即可通过服务器加载页面。 在主进程的 index.js 文件中添加如下函数

1
2
3
4
5
function localServer() {
let server = express();
server.use(express.static(__dirname));
server.listen(8888);
}

然后做如下修改:

1
2
3
4
5
6
import express from "express"
let mainWindow
const winURL = process.env.NODE_ENV === 'development'
? `http://localhost:9082`
- : `file://${__dirname}/index.html`
+ : `http://localhost:8888/index.html`
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
26
function createWindow () {
/**
* Initial window options
*/
mainWindow = new BrowserWindow({
height: 563,
useContentSize: true,
width: 1000,
frame: true,
webPreferences: {
plugins: true
}
})

mainWindow.loadURL(winURL)

mainWindow.webContents.openDevTools()

mainWindow.on('closed', () => {
mainWindow = null
})

+ if (process.env.NODE_ENV === "production") {
+ localServer();
+ }
}

然后就可以愉快地在本地播放 RTMP 视频啦。

这是本地播放视频的效果。 (没想到香港卫视晚上竟然在播《虹猫蓝兔七侠传》系列,童年心痛的回忆啊,央视播了一半被举报然后停播了)

在网页中播放

由于现在主流浏览器都抛弃了 Flash ,默认关闭 Flash 。而 Video.js 是不会去请求 Flash 权限的。 因此我们需要一个 embed 标签加载一个 swf 文件,通过点击这个标签获取 Flash 权限。 当然,在实际生产中,后续如何处理,就看大家怎么搞了。

这是我们在网页上获取 Flash 权限之前的效果:

点击 flash 文件,获取权限,效果如下:

感谢您的阅读,本文由 HPDell 的个人博客 版权所有。如若转载,请注明出处:HPDell 的个人博客(http://hpdell.github.io/编程/vue-vidoejs-rtmp/
武汉大学《硕士英语》课视听文件字幕
《逃避虽可耻但有用》观后感