所以我在FFMPeg上看到了很多主题,它是我今天学到的一个很好的工具,但我花了一天时间来完善命令,现在我对NodeJS部分感到困惑。
本质上,该命令执行以下操作:从Mac OSX网络摄像头获取输入,然后将其传输到Web套接字。现在我查看了很多NodeJS库,但我找不到能满足我需求的库;或者不明白怎么做。以下是我正在使用的命令示例:
ffmpeg -f avfoundation -framerate 30 -video_size 640x480 -pix_fmt uyvy422 -i "0:1" -f mpegts -codec:v mpeg1video -s 640x480 -b:v 1000k -bf 0 http://localhost:8081/stream
这为流媒体方面提供了所需的一切,但我希望通过NodeJS调用它,然后能够监视日志,并解析返回的数据,例如:
frame= 4852 fps= 30 q=6.8 size= 30506kB time=00:02:41.74 bitrate=1545.1kbits/s speed= 1x \r
并使用它来获取JSON数组,以便我输出到网页。
现在我正在做的就是研究实际解析数据的方法,我已经看过很多其他类似的答案,但我似乎无法分割/替换/正则表达它。我不能得到任何东西,只能从中得到一条长串。
以下是我正在使用的代码(NodeJS):
var ffmpeg = require('child_process').spawn('/usr/local/Cellar/ffmpeg/3.3.1/bin/ffmpeg', ['-f', 'avfoundation', '-framerate', '30', '-video_size', '640x480', '-pix_fmt', 'uyvy422', '-i', '0:1', '-f', 'mpegts', '-codec:v', 'mpeg1video', '-s', '640x480', '-b:v', '1000k', '-bf', '0', 'http://localhost:8081/test']);
ffmpeg.on('error', function (err) {
console.log(err);
});
ffmpeg.on('close', function (code) {
console.log('ffmpeg exited with code ' + code);
});
ffmpeg.stderr.on('data', function (data) {
// console.log('stderr: ' + data);
var tData = data.toString('utf8');
// var a = tData.split('[\\s\\xA0]+');
var a = tData.split('\n');
console.log(a);
});
ffmpeg.stdout.on('data', function (data) {
var frame = new Buffer(data).toString('base64');
// console.log(frame);
});
我尝试过拆分新行,carridge返回,空格,制表符,但我似乎无法获得基本的数组,我可以使用它。
另外需要注意的是,你会注意到日志是通过stderr返回的,我在网上看过这个,很明显它是为很多人做的吗?所以我不确定这笔交易是什么?但代码是sdterr回调。
任何帮助都非常感激,因为我对我做错了什么感到很困惑。
感谢。
答案 0 :(得分:2)
对此的更新,我与IRC频道的其中一个人合作:FreeNode上的#ffmpeg。答案是通过管道将输出发送到stdout。
例如,我将以下内容附加到FFMpeg命令:
-progress pipe:1
进度标志用于每秒提供一个输出,其中包含有关流的信息,因此这几乎是您每秒从stderr流中获得的所有内容,但是以我可以解析的格式通过管道传输到stdout流。以下内容摘自文档。
-progress url(global)将程序友好的进度信息发送到url。大约每秒和编码过程结束时写入进度信息。它由" key = value"组成。线。 key仅包含字母数字字符。一系列进度信息的最后一个键始终是" progress"。
以下是我用来解析流信息的代码示例:
ffmpeg.stdout.on('data', function (data) {
var tLines = data.toString().split('\n');
var progress = {};
for (var i = 0; i < tLines.length; i++) {
var key = tLines[i].split('=');
if (typeof key[0] != 'undefined' && typeof key[1] != 'undefined') {
progress[key[0]] = key[1];
}
}
// The 'progress' variable contains a key value array of the data
console.log(progress);
});
感谢所有评论!
答案 1 :(得分:1)
本着不重新发明轮子的精神,您可能想尝试使用fluent-ffmpeg。它会发送一个progress event,其中包含许多有用的字段
'进度':转码进度信息
每次ffmpeg报告进度时都会发出progress事件 信息。它使用以下对象参数发出 键:
- frames:已处理的总帧数
- currentFps:FFmpeg当前正在处理的帧率
- currentKbps:FFmpeg当前正在处理的吞吐量
- targetSize:目标文件的当前大小,以千字节为单位
- timemark:当前帧的时间戳,以秒为单位
- 百分比:对进度百分比的估计
如果您对他们如何做到这一点感到好奇,您可以阅读来源,starting from here
Ffmpeg使用stderr输出日志信息,因为stdout用于将输出传递给其他进程。 stderr中的东西实际上只是调试信息,而不是过程的实际输出。
BONUS ROUND
我见过一些使用websockets来传输视频的hacky视频播放器,但这种方法存在很多问题。我不打算讨论这些问题,但我会解释为什么我认为你应该使用hls.js。
支持非常好;基本上除了老IE之外到处都有。它使用MSE升级标准视频元素,因此您无需为构建自定义播放器而努力。
的文档以下是我用于从IPTV盒流式传输到网页的一些代码。
this.ffmpeg = new FFFmpeg()
this.ffmpeg.input(request(this.http_stream))
.videoCodec('copy')
.audioCodec('copy')
.outputOptions([
'-f hls',
'-hls_list_size 6',
'-hls_flags delete_segments'
])
.output( path.join(this.out_dir, 'video.m3u8') )
.run()
它会生成.m3u8清单文件以及分段的mpeg-ts视频文件。你需要做的就是将m3u8文件加载到hls.js播放器中,你就有了直播!
如果您要重新编码流,您可能会看到一些低fps和毛刺。我很幸运,因为我的源流已经编码为mpeg-ts。