云课堂中,直播功能非常重要,可以很大程度上弥补单纯web端功能的不足,尤其是串流电脑屏幕时,可以将使用任何教学软件的过程串流给客户端,效果拔群。
推流方式选择
一、Web端推流
Web端推流在现在使用得很少,一般基于rtmp-streamer模块进行,同时需要swf插件。并且现在各大浏览器正在陆续抛弃FlashPlayer,因此不采用这种方式进行推流。
二、利用ffmpeg推流
ffmpeg是非常常用的开源的视频音频处理程序,在很多软件中有使用。如果在js使用,可以利用封装了ffmpeg命令行调用的fluent-ffmpeg模块进行调用。然而ffmpeg在多个平台需要不同的本地客户端,并且配置环境变量,或者临时写入路径,因此主要有两个方法:
随网站载入,下载ffmpeg执行文件,临时存储。但由于平台多样、ffmpeg程序体积大的问题并不合适。 在网站上预先提供ffmpeg下载和安装,但由于更新版本、构建等问题,加以该云课堂需要脱离外部网络运行,这个方法的使用也有缺陷。
在章节最后一节,尝试了将ffmpeg打包成用户界面更舒适的应用,用于显示器推流。
另外,直播推流对系统性能的开销很大,出于对优化和实际应用场景等方面考虑,既然需要本地预先安装推流客户端,不如选择更加成熟的软件。
三、利用OBS(Open Broadcaster Software)推流
OBS是一个免费、开源的视频录制、推流软件,其优化力度大、对系统性能占用小、支持复杂灵活的场景,并且具有直接推流至某一服务器的完善功能,因此使用OBS对课堂直播进行推流。
OBS的使用
obs的使用非常灵活,可以捕捉各种各样的来源,包括屏幕捕获、窗口捕获、媒体源、浏览器、图片、文字等,并且可以实时查看当前的捕获情况。
obs的推流需要一个服务器地址,将视频流发送至服务端,因此服务端需要一个服务来提供地址获取视频
服务端监听:node-media-server模块
首先安装模块
sudo npm install node-media-server –save
然后创建一个调用模块的脚本
// myscripts\stream.js
const NodeMediaServer = require('node-media-server');
const config = {
rtmp: {
port: 1935,
chunk_size: 60000,
gop_cache: true,
ping: 60,
ping_timeout: 30
},
http: {
port: 8000,
allow_origin: '*'
}
};
function run() {
console.log('开始监听推流');
var nms = new NodeMediaServer(config);
nms.run();
}
module.exports.run = run;
因为框架中运行服务器的是www文件,因此把启动对串流的监听也放在www中
// bin\www
// 启动推流监听
var stream = require('../myscripts/stream').run;
stream();
客户端拉流:flv.js
flv.js是一个开源的脚本,可以不借助flash在H5的video标签中播放flv。
<head>
<script src="https://cdn.bootcss.com/flv.js/1.4.0/flv.min.js"></script>
<!-- ...... -->
</head>
<body>
<video id="videoElement" width="1280px" controls></video>
</body>
紧接着对这个vedio添加来源
// stream.js
$(document).ready(() => {
if (flvjs.isSupported()) {
var url = 'http://' + document.domain + ':8000/live/test.flv';
var videoElement = document.getElementById('videoElement');
var flvPlayer = flvjs.createPlayer({
type: 'flv',
url: url
});
flvPlayer.attachMediaElement(videoElement);
flvPlayer.load();
flvPlayer.play();
}
});
注意url中的“test”便是直播名,同时在串流时作为串流的秘钥使用
启动直播功能
启动express框架,便能看见后台的消息:
开始监听推流
2020-6-20 0:05:50 13172 [INFO] Node Media Server v2.1.9
2020-6-20 0:05:50 13172 [INFO] Node Media Rtmp Server started on port: 1935
2020-6-20 0:05:50 13172 [INFO] Node Media Http Server started on port: 8000
2020-6-20 0:05:50 13172 [INFO] Node Media WebSocket Server started on port: 8000
对于OBS串流,这个时候需要在obs里填写串流信息。此时在本机上进行测试,域名填写localhost。
服务器:rtmp://localhost/live
串流秘钥:test
在obs中开始串流,便能在网站上查看到直播了。
优化开播设置
直接在课程界面添加服务器和串流秘钥即可
$(document).ready(() => {
//请求所有需要的数据
$.get("/users/process_getdata", (data) => {
var name = data.username;
var classname = data.classname;
//修改称呼
let text = $("#welcome").text();
$("#welcome").text(text + name);
let key = "stream-key-" + classname;
$('#stream-url').val('rtmp://' + document.domain + '/live');
// 串流服务器url
$('#stream-key').val(key);
// 串流秘钥
}, "json");
})
非常简约
附:利用ffmpeg推流
ffmpeg功能非常强大,同时只需要命令行就可以进行推流。为了提高用户体验,我们将操作打包成一个nodejs应用。
首先为了使用ffmpeg推流,需要一个如下的指令启动ffmpeg,并且将屏幕流推送到服务器:
ffmpeg -f gdigrab -i desktop -vcodec libx264 -preset:v ultrafast -tune:v zerolatency -f flv rtmp://127.0.0.1/live/stream-key-0.flv
当然可以使用js直接执行这个命令。当然也可以使用fluent-ffmpeg模块,它将ffmpeg命令行以js形式转译,便于执行命令,调用ffmpeg的方式如下:
const ffmpeg = require('fluent-ffmpeg');
const ffmpegPath = __dirname+"\\..\\libs\\ffmpeg.exe";
var command = null;
function run(outputPath) {
command = ffmpeg()
.setFfmpegPath(ffmpegPath)
.input('desktop')
.inputFormat('gdigrab')
.addOptions([
'-vcodec libx264',
'-preset ultrafast',
'-acodec libmp3lame',
'-pix_fmt yuv422p'
])
.format('flv')
.output(outputPath, {
end: true
})
.on('start', function (commandLine) {
console.log('[' + new Date() + '] Vedio is Pushing !');
console.log('commandLine: ' + commandLine);
})
.on('error', function (err, stdout, stderr) {
console.log('error: ' + err.message);
})
.on('end', function () {
console.log('[' + new Date() + '] Vedio Pushing is Finished !');
});
command.run();
}
function stop() {
command.kill();
}
直接运行脚本里的run函数,是可以成功推流的。然后编写一个简单的html页面:
为了将node程序打包,这里需要使用electron和打包工具asar,并初始化项目
cnpm install electron -g cnpm install electron-prebuilt -g cnpm install electron-packager -g cnpm install electron-builder -g cnpm install asar -g npm init
初始化完项目后,只需要在index.html中编写主窗体,然后在js中加上对fluent-ffmpeg的引用,并且可以直接在本地访问ffmpeg.exe。引入非原生模块需要重新构建模块:
cnpm install electron-rebuild –save-dev .\node_modules.bin\electron-rebuild.cmd
在页面脚本中使用vue,并且调用run和stop两个函数
$(document).ready(() => {
var data = {
isStreaming: false,
btnMessage: '开始串流',
url: '',
key: ''
}
var buttonApp = new Vue({
el: "#btn",
data: data
})
var inputApp = new Vue({
el: "#inputs",
data: data
})
$('#btn').on('click', () => {
if (data.isStreaming == false) {
if (!data.url) {
alert('请输入服务器!');
} else if (!data.key) {
alert('请输入串流秘钥!');
} else {
data.isStreaming = true;
var path;
if (data.url[data.url.length - 1] != "/") {
path = data.url + "/" + data.key + '.flv';
} else {
path = data.url + data.key + '.flv';
}
data.btnMessage = "串流中:" + path;
const ipc = require('electron').ipcRenderer;
run(path);
}
} else {
data.isStreaming = false;
data.btnMessage = "开始串流";
stop();
}
})
})
由于构件electron需要的部分github资源由于网络原因无法下载,这里使用wpf,用类似的逻辑,命令行启动ffmpeg并推流。
可以看见使用ffmpeg也可以正常地推流桌面,但是同样需要下载客户端,相比较于使用obs,这个方法需要大量的功能改进,例如获得摄像头名称并直播摄像头、电脑音频和麦克风音频选择、桌面推流来源选择等。