云课堂中,直播功能非常重要,可以很大程度上弥补单纯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,这个方法需要大量的功能改进,例如获得摄像头名称并直播摄像头、电脑音频和麦克风音频选择、桌面推流来源选择等。