如何在JavaScript中使用ffmpeg将H.264帧解码为RGB帧

时间:2018-09-17 21:43:12

标签: node.js ffmpeg h.264 emscripten fluent-ffmpeg

我正在尝试将ffmpeg编译为javascript,以便可以使用node解码H.264视频流。流是打包到RTP NALU中的H.264帧,因此任何解决方案都必须能够接受H.264帧,而不是整个文件名。这些帧不能放在MP4或AVI之类的容器中,因为解复用器需要在发生解复用之前需要每个帧的时间戳,但是我正在处理实时流,没有容器。

通过RTP流式传输H.264

下面是我用来在udp套接字上监听的基本代码。在“消息”回调内部,数据包是RTP数据报。数据报的数据部分是H.264帧(P帧和I帧)。

var PORT = 33333;
var HOST = '127.0.0.1';

var dgram = require('dgram');
var server = dgram.createSocket('udp4');

server.on('listening', function () {
    var address = server.address();
    console.log('UDP Server listening on ' + address.address + ":" + address.port);
});

server.on('message', function (message, remote) {
    console.log(remote.address + ':' + remote.port +' - ' + message);
    frame = parse_rtp(message);

    rgb_frame = some_library.decode_h264(frame); // This is what I need.

});

server.bind(PORT, HOST);  

我找到了Broadway.js库,但是我无法使其正常运行,并且它无法处理我需要的P帧。我还发现了ffmpeg.js,但可以使它正常工作,并且需要一个完整的文件而不是一个流。同样,fluent-ffmpeg似乎不支持文件流。所有示例都显示了将文件名传递给构造函数的信息。因此,我决定编写自己的API。

我当前的解决方案尝试

我已经能够将ffmpeg编译成一个大的js文件,但是我不能那样使用它。我想围绕ffmpeg编写一个API,然后将这些函数公开给JS。因此在我看来,我需要执行以下操作:

  1. 将ffmpeg组件(avcodec,avutil等)编译为llvm位代码。
  2. 编写一个C包装程序,该程序公开解码功能并使用EMSCRIPTEN_KEEPALIVE。
  3. 使用emcc编译包装程序并将其链接到在步骤1中创建的位代码。

我找到了WASM+ffmpeg,但是它是中文的,其中一些步骤尚不清楚。特别是有以下步骤:

emcc web.c process.c ../lib/libavformat.bc ../lib/libavcodec.bc ../lib/libswscale.bc ../lib/libswresample.bc ../lib/libavutil.bc \

:((我以为我被卡住了

我不明白所有ffmpeg组件如何被编译成单独的* .bc文件。我遵循了该文章中的emmake命令,最后得到了一个大的.bc文件。

2个问题

1。 有人知道使用emscripten编译ffmpeg的步骤,以便我可以向javascript公开一些API吗?
  2。 是否有更好的方法(带有不错的文档/示例)来使用节点解码h264视频流?

2 个答案:

答案 0 :(得分:1)

问题1: 只需遵循官方doc

  

考虑通常使用以下命令进行构建的情况   命令:

./configure
make
     

要使用Emscripten进行构建,请改用以下命令   命令:

# Run emconfigure with the normal configure command as an argument.
./emconfigure ./configure

# Run emmake with the normal make to generate linked LLVM bitcode.
./emmake make

# Compile the linked bitcode generated by make (project.bc) to JavaScript.
# 'project.bc' should be replaced with the make output for your project (e.g. 'yourproject.so')
#  [-Ox] represents build optimisations (discussed in the next section).
./emcc [-Ox] project.bc -o project.js

问题2:可以在节点环境中调用c / c ++库。您可以编写一些c / c ++粘合代码或使用诸如node-ffi之类的代理节点模块。

使用node-ffi调用现有库可能更容易。 可以帮忙:)

答案 1 :(得分:0)

最简单的方法(特别是如果需要在Web浏览器中运行它)是利用Media Source Extension。我在短短三天内就做到了。此外,它会自动使用GPU硬件(Cuda,Intel Qsv,...)加速,直至支持浏览器内置。如果它在真实世界的应用程序中运行,则很重要。我昨天进行了测试,只有5%的旧i7机器CPU可以解码4K(是1080p的4倍)IP摄像机H.264最终原始实时流。我不确定像nodejs这样的服务器端js,但是我希望结果是相似的。如果您需要更多信息,请与我联系。关于H.265 / HEVC,您需要类似地用ffmpeg或x265或OpenH265对其进行部分脚本化,且其bc大小必须最小(取决于配置,小于1,2,3 M)。祝你好运...