5

我是 Node.js 的新手,并且已经知道如何利用 child.spawn 启动一个 FFMPEG 实例,该实例用于捕获实时视频并通过 rtmp 将其发送到 Adob​​e Media Server。

我看到的每个将 FFMPEG 与 Node.js 结合使用的示例都带有时间限制的示例,因此一旦 FFMPEG 到达它正在转换的文件的末尾,子进程就会关闭。

在这种情况下,没有“文件结尾”。

如果我实例化:

    var ffmpeg = child.spawn('ffmpeg.exe', [args]);

它创建实时提要。

我尝试使用以下命令立即关闭子进程:

    setTimeout(function() {
        ffmpeg.stdin.resume();
        ffmpeg.stdin.write('insert command to echo q to close FFMPEG');
        ffmpeg.stdin.end();
    });

但是,这似乎不起作用。我继续在我的测试盒上看到我的 rtmp 提要。

有没有办法通过 Node.js 中的标准输入向 FFMPEG 传递关闭命令?

提前致谢!

瑞克

4

4 回答 4

3

以下代码由我的主 app.js 使用 child_process.fork() 方法作为模块加载:

    var spawn = require('child_process').spawn;

    var ffmpeg = spawn('C:\\Program Files (x86)\\ffmpeg\\bin\\ffmpeg.exe', ['-y', '-threads', '-0', '-re', '-rtbufsize', '204800000', '-probesize', '4096', '-vsync', '2', '-async', '30', '-f', 'dshow', '-s', '320x240', '-i', 'video=Integrated Webcam:audio=Microphone Array (IDT High Defi', '-c:a', 'libvo_aacenc', '-ab', '48000', '-ar', '22050', '-ac', '2', '-c:v', 'libx264', '-s', '400x300', '-g', '96', '-x264opts', 'bitrate=1200', '-preset', 'ultrafast', '-profile:v', 'baseline', '-pix_fmt', 'yuv420p', '-aspect', '4:3', '-f', 'flv', 'rtmp://server']);

    setTimeout(function() {
        ffmpeg.stderr.on('data', function() {
            ffmpeg.stdin.setEncoding('utf8');
            ffmpeg.stdin.write('q');
            process.exit();
        });
    }, 10000);

它远没有我做的那么复杂。主 app.js 是一个基本的 HTML 页面,它提供服务并使用 socket.io 接收事件及其相应的数据。在这种情况下,'true' 事件会加载 module.js 文件,该文件会启动 FFMPEG 的实时捕获会话,将其馈送到 RTMP 服务器,并在 10 秒的超时后正常关闭 FFMPEG。

我的下一个任务是通过从 Web 界面触发的事件将其关闭,而不是当前的超时测试方法。

查看 Windows 中的任务管理器,FFMPEG 进程与辅助节点进程一样关闭。

原因是我发现的 node-ffmpeg 模块都不支持通过捕获输入进行实时流式传输。它们似乎主要用于对现有内容进行转码。理想情况下,最终结果将是一个可以启动和停止 FFMPEG 的基于 Web 的界面。我们的用例将替换 Adob​​e Flash Media Live Encoder 作为我们的 Adob​​e Media Server 的源,因为它无法保存标准 mp4 文件。

于 2013-01-10T15:50:20.753 回答
0

您需要在文件完成流式传输到 ffmpeg 后发送 EOF。然后ffmpeg将正确完成并关闭

于 2013-06-01T17:28:20.890 回答
0

下面或多或少是使用 Node.js 启动和关闭实时 FFMPEG 会话问题的最终解决方案:

    var     spawn = require('child_process').spawn
,   fs = require('fs');


    function ffmpeg(cmd, opts, callback) {
    var p;
    //console.log(callback());
    if(p == undefined) {
        var p = spawn(cmd, opts);

        p.stderr.on('data', function(data) {
            /*p.stdin.setEncoding('utf8');
                p.stdin.write('q');
                process.exit()
            */
            fs.readFile(__dirname + '/server-state.json', function(error, data) {
                if(error) {
                        console.log(error); 
                    } else {
                        content = JSON.parse(data);
                        console.log(content['State']);

                        if(content['State'] == 'false') {
                            p.stdin.setEncoding('utf8');
                            p.stdin.write('q');
                            process.exit()
                        }
                    }
            });

        });

        return p;
    }

}

    ffmpeg_var = ffmpeg('C:\\Program Files (x86)\\ffmpeg\\bin\\ffmpeg.exe', ['-y', '-threads', '-0', '-re', '-rtbufsize', '204800000', '-probesize', '4096', '-vsync', '2', '-async', '30', '-f', 'dshow', '-s', '320x240', '-i', 'video=Integrated Webcam:audio=Microphone Array (IDT High Defi', '-c:a', 'libvo_aacenc', '-ab', '48000', '-ar', '22050', '-ac', '2', '-c:v', 'libx264', '-s', '400x300', '-g', '96', '-x264opts', 'bitrate=1200', '-preset', 'ultrafast', '-profile:v', 'baseline', '-pix_fmt', 'yuv420p', '-aspect', '4:3', '-f', 'mp4', __dirname + '/IntegrityTest.mp4'], function() {


    });

此代码封装在“module.js”文件中,该文件通过根 application.js 文件中的 child_process.fork() 实例化。它读取存储“状态”的文本文件。此状态通过根应用程序中的写入/读取方法切换。在 on('data') 事件中,它读取文件,如果检测到状态已更改为 false,然后通过将 'q' 命令写入标准输入来关闭 FFMPEG。

如果我要在更大范围内实现它,除了通过使用数据库来改进它之外,我更愿意接受有关更优雅的编码方式的反馈。

于 2013-01-10T21:56:01.270 回答
0

你可以简单地杀死它。

ffmpeg.kill(SIGHUB)

或您希望的任何其他终止信号,请参阅http://en.wikipedia.org/wiki/Unix_signal


如果我正确理解您的示例,您将节点进程的所有参数传递给 ffmpeg,包括流。为了让您ffmeg.end()工作,您必须直接从您的节点进程中流式传输。我认为 ffmpeg 在连续接收来自您的相机的数据时不会停止。

于 2013-01-07T21:50:00.670 回答