如何在 NodeJS 中成功解析 FFMpeg 的输出
How to successfully parse the output of FFMpeg in NodeJS
所以我看到了很多关于 FFMPeg 的主题,它是我今天学到的一个很棒的工具,但是我花了一天时间完善命令,现在有点卡在 NodeJS 部分了。
本质上,该命令执行以下操作:从 Mac OSX 网络摄像头获取输入,然后将其流式传输到网络套接字。现在我查看了很多 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 数组,供我输出到网页。
现在我所做的就是研究实际解析数据的方法,并且我已经查看了很多其他类似问题的答案,但我似乎无法 split/replace/regex 它。除了一长串,我什么也得不到。
这是我使用的代码 (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 return、空格、制表符进行拆分,但我似乎无法获得我可以使用的基本位数组。
另一件需要注意的事情,你会注意到日志通过 stderr 返回吗,我在网上看到过这个,显然很多人都这样做了?所以我不确定这有什么关系?但代码是 sdterr 回调。
非常感谢任何帮助,因为我真的很困惑我做错了什么。
谢谢。
本着不重新发明轮子的精神,您可能想尝试使用 fluent-ffmpeg. It dispatches a progress event 和一些有用的字段
'progress': transcoding progress information
The progress event is emitted every time ffmpeg reports progress
information. It is emitted with an object argument with the following
keys:
- frames: total processed frame count
- currentFps: framerate at which FFmpeg is currently processing
- currentKbps: throughput at which FFmpeg is currently processing
- targetSize: current size of the target file in kilobytes
- timemark: the timestamp of the current frame in seconds
- percent: an estimation of the progress percentage
如果你想知道他们是怎么做到的,你可以阅读来源,starting from here
Ffmpeg 使用 stderr 输出日志信息,因为 stdout 用于将输出通过管道传输到其他进程。 stderr里面的东西其实只是调试信息,并不是进程的实际输出。
奖励回合
我见过一些使用 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。
关于这方面的更新,我在 IRC 频道上与其中一个人一起工作:FreeNode 上的#ffmpeg。答案是通过管道将输出发送到标准输出。
例如,我将以下内容附加到 FFMpeg 命令中:
-progress pipe:1
进度标志用于每秒输出一个关于流的信息,所以这几乎是你每秒从 stderr 流获得的所有内容,但以我可以解析的格式传输到 stdout 流.以下摘自文档。
-progress url (global) Send program-friendly progress information to url. Progress information is written approximately every second and at the end of the encoding process. It is made of "key=value" lines. key consists of only alphanumeric characters. The last key of a sequence of progress information is always "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);
});
感谢所有评论!
所以我看到了很多关于 FFMPeg 的主题,它是我今天学到的一个很棒的工具,但是我花了一天时间完善命令,现在有点卡在 NodeJS 部分了。
本质上,该命令执行以下操作:从 Mac OSX 网络摄像头获取输入,然后将其流式传输到网络套接字。现在我查看了很多 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 数组,供我输出到网页。
现在我所做的就是研究实际解析数据的方法,并且我已经查看了很多其他类似问题的答案,但我似乎无法 split/replace/regex 它。除了一长串,我什么也得不到。
这是我使用的代码 (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 return、空格、制表符进行拆分,但我似乎无法获得我可以使用的基本位数组。
另一件需要注意的事情,你会注意到日志通过 stderr 返回吗,我在网上看到过这个,显然很多人都这样做了?所以我不确定这有什么关系?但代码是 sdterr 回调。
非常感谢任何帮助,因为我真的很困惑我做错了什么。
谢谢。
本着不重新发明轮子的精神,您可能想尝试使用 fluent-ffmpeg. It dispatches a progress event 和一些有用的字段
'progress': transcoding progress information
The progress event is emitted every time ffmpeg reports progress information. It is emitted with an object argument with the following keys:
- frames: total processed frame count
- currentFps: framerate at which FFmpeg is currently processing
- currentKbps: throughput at which FFmpeg is currently processing
- targetSize: current size of the target file in kilobytes
- timemark: the timestamp of the current frame in seconds
- percent: an estimation of the progress percentage
如果你想知道他们是怎么做到的,你可以阅读来源,starting from here
Ffmpeg 使用 stderr 输出日志信息,因为 stdout 用于将输出通过管道传输到其他进程。 stderr里面的东西其实只是调试信息,并不是进程的实际输出。
奖励回合
我见过一些使用 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。
关于这方面的更新,我在 IRC 频道上与其中一个人一起工作:FreeNode 上的#ffmpeg。答案是通过管道将输出发送到标准输出。
例如,我将以下内容附加到 FFMpeg 命令中:
-progress pipe:1
进度标志用于每秒输出一个关于流的信息,所以这几乎是你每秒从 stderr 流获得的所有内容,但以我可以解析的格式传输到 stdout 流.以下摘自文档。
-progress url (global) Send program-friendly progress information to url. Progress information is written approximately every second and at the end of the encoding process. It is made of "key=value" lines. key consists of only alphanumeric characters. The last key of a sequence of progress information is always "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);
});
感谢所有评论!