node.js ffmpeg spawn child_process 意外的数据输出

node.js ffmpeg spawn child_process unexpected data output


我对后端的东西比较陌生,如果我的问题很简单,请原谅。
对于 Intranet 项目,我想在网页中呈现视频元素(React,HLS.js 播放器)。
视频源是作为 udp 多播传送的 mpeg-ts 流。
小型 node.js / express 服务器应该处理 ffmpeg 命令,将多播转码为 hls 以在浏览器中显示它们。

问题是输出:
输出在 stderr 上发出...即使进程按预期工作。
这是我到目前为止为转码编写的相应代码:

const express = require("express");
const { spawn, exec } = require("child_process");
const process = require("process")

let ls;

const app = express();

app.get('/cam/:source', (body) => {
    const cam = body.params.source;
    console.log(cam);

    let source = "udp://239.1.1.1:4444";
    let stream = "/var/www/html/streams/tmp/cam1.m3u8"


    stream = spawn("ffmpeg", ["-re", "-i", source, "-c:v", "libx264", "-crf", "21", "-preset", "veryfast", "-c:a", "aac", "-b:a", "128k", "-ac", "2", "-f", "hls", "-hls_list_size", "5", "-hls_flags", "delete_segments", stream], {detached: true});

    stream.stdout.on("data", data => {
        console.log(`stdout: ${data}`);
    });

    stream.stderr.on("data", data => {
        console.log(`stderr: ${data}`);
    });

    stream.on("error", error => {
        console.log(`error: ${error.message}`);
    });

    stream.on("close", code => {
        console.log(`child process exited with code ${code}`);
    });
})

app.listen(5000, ()=> {
    console.log('Listening');
})

这可能只是化妆品,但它让我想知道。
这是终端输出:

[nodemon] starting `node server.js`
Listening
camera stream reloaded
stderr: ffmpeg version 4.3.2-0+deb11u1ubuntu1 Copyright (c) 2000-2021 the FFmpeg developers
  built with gcc 10 (Ubuntu 10.2.1-20ubuntu1)

  --shortend--


pid:  4206
stderr: frame=    8 fps=0.0 q=0.0 size=N/A time=00:00:00.46 bitrate=N/A speed=0.931x    
pid:  4206
stderr: frame=   21 fps= 21 q=26.0 size=N/A time=00:00:00.96 bitrate=N/A speed=0.95x    
pid:  4206
stderr: frame=   33 fps= 22 q=26.0 size=N/A time=00:00:01.49 bitrate=N/A speed=0.982x    
pid:  4206
stderr: frame=   46 fps= 23 q=26.0 size=N/A time=00:00:02.00 bitrate=N/A speed=0.989x    
pid:  4206
stderr: frame=   58 fps= 23 q=26.0 size=N/A time=00:00:02.49 bitrate=N/A speed=0.986x    
pid:  4206

等等...

任何有用的信息将不胜感激!
非常感谢

如果输出正常,您无需担心。

使用 spawn 您已经围绕特定进程创建了一个包装器,通过 stream.stderr 的输出由继承进程的 warn/error 触发,warn 无需担心,尤其是当您的应用程序运行正常时。

我在下面放了一个关于如何触发 warnerror 的简单演示,这样您就可以更清楚地看到发生了什么:

index.js

const {spawn} = require('child_process');

const output = (label) => (data) => {
    let str = data.toString().split(/(\r\n|\n)+/).filter(i => i.trim().length);
    str.forEach(row => {
        console.log(`[${label}]`, row);
    })
};
let proc = spawn('node', ['proc.js'], {
    shell: true,
    env: {
        ...process.env
    },
})

proc.stdout.on('data', output('data'));
proc.stderr.on('data', output('error'));

proc.js

setInterval(()=>{
    console.log('default log',new Date())
    console.info('info log', new Date())
    console.error('error log', new Date());
    console.warn('warn log', new Date());
}, 1000);

/** Output: 
[data] default log 2021-09-05T10:03:22.283Z
[error] error log 2021-09-05T10:03:22.287Z
[error] warn log 2021-09-05T10:03:22.287Z
[data] info log 2021-09-05T10:03:22.287Z
[data] default log 2021-09-05T10:03:23.292Z
[error] error log 2021-09-05T10:03:23.293Z
[error] warn log 2021-09-05T10:03:23.293Z
[data] info log 2021-09-05T10:03:23.293Z
[data] default log 2021-09-05T10:03:24.299Z
[error] error log 2021-09-05T10:03:24.299Z
[error] warn log 2021-09-05T10:03:24.299Z
[data] info log 2021-09-05T10:03:24.299Z

我已经 运行 ffmpeg -version,日志:

[data] ffmpeg version git-2020-06-17-0b3bd00 Copyright (c) 2000-2020 the FFmpeg developers
[data] built with gcc 9.3.1 (GCC) 20200523
[data] configuration: --enable-gpl --enable-version3 --enable-sdl2 --enable-fontconfig --enable-gnutls --enable-iconv --enable-libass --enable-libdav1d --enable-libbluray --enable-libfreetype --enable-libmp3lame --enable-libopencore
-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libsrt --enable-libtheora --enable-libtwolame --enable-libvpx --enable-libwavpack --enable-libweb
p --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libzimg --enable-lzma --enable-zlib --enable-gmp --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvo-amrwbenc --enable-libmysofa --enable-libspeex --en
able-libxvid --enable-libaom --disable-w32threads --enable-libmfx --enable-ffnvcodec --enable-cuda-llvm --enable-cuvid --enable-d3d11va --enable-nvenc --enable-nvdec --enable-dxva2 --enable-avisynth --enable-libopenmpt --enable-amf
[data] libavutil      56. 55.100 / 56. 55.100
[data] libavcodec     58. 92.100 / 58. 92.100
[data] libavformat    58. 46.101 / 58. 46.101
[data] libavdevice    58. 11.100 / 58. 11.100
[data] libavfilter     7. 86.100 /  7. 86.100
[data] libswscale      5.  8.100 /  5.  8.100
[data] libswresample   3.  8.100 /  3.  8.100
[data] libpostproc    55.  8.100 / 55.  8.100

我也运行一个ffmpeg转换过程,文件没问题,这是日志:

[error] ffmpeg version git-2020-06-17-0b3bd00 Copyright (c) 2000-2020 the FFmpeg developers
[error]   built with gcc 9.3.1 (GCC) 20200523
[error]   configuration: --enable-gpl --enable-version3 --enable-sdl2 --enable-fontconfig --enable-gnutls --enable-iconv --enable-libass --enable-libdav1d --enable-libbluray --enable-libfreetype --enable-libmp3lame --enable-libopenc
ore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libsrt --enable-libtheora --enable-libtwolame --enable-libvpx --enable-libwavpack --enable-lib
webp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libzimg --enable-lzma --enable-zlib --enable-gmp --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvo-amrwbenc --enable-libmysofa --enable-libspeex -
-enable-libxvid --enable-libaom --disable-w32threads --enable-libmfx --enable-ffnvcodec --enable-cuda-llvm --enable-cuvid --enable-d3d11va --enable-nvenc --enable-nvdec --enable-dxva2 --enable-avisynth --enable-libopenmpt --enable-a
mf
[error]   libavutil      56. 55.100 / 56. 55.100
[error]   libavcodec     58. 92.100 / 58. 92.100
[error]   libavformat    58. 46.101 / 58. 46.101
[error]   libavdevice    58. 11.100 / 58. 11.100
[error]   libavfilter     7. 86.100 /  7. 86.100
[error]   libswscale      5.  8.100 /  5.  8.100
[error]   libswresample   3.  8.100 /  3.  8.100
[error]   libpostproc    55.  8.100 / 55.  8.100
[error] Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '2020-11-23_18-47-52.mp4':
[error]   Metadata:
[error]     major_brand     : isom
[error]     minor_version   : 512
[error]     compatible_brands: isomiso2avc1mp41
[error]     encoder         : Lavf58.29.100
[error]   Duration: 00:00:03.17, start: 0.000000, bitrate: 30039 kb/s
[error]     Stream #0:0(und)
[error] : Video: h264 (High) (avc1 / 0x31637661), yuvj420p(pc, bt709), 1920x1080 [SAR 1:1 DAR 16:9], 30026 kb/s, 60 fps, 60 tbr, 15360 tbn, 120 tbc (default)
[error]     Metadata:
[error]       handler_name    : VideoHandler
[error]     Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 2 kb/s (default)
[error]     Metadata:
[error]       handler_name    : SoundHandler
[error] Stream mapping:
[error]   Stream #0:0 -> #0:0 (h264 (native) -> hevc (libx265))
[error]   Stream #0:1 -> #0:1 (aac (native) -> aac (native))
[error] Press [q] to stop, [?] for help
[error] [swscaler @ 000002cddcf89d40] deprecated pixel format used, make sure you did set range correctly
[error] x265 [info]: HEVC encoder version 3.3+29-1e3dbf09ee4f
[error] x265 [info]: build info [Windows][GCC 9.3.1][64 bit] 8bit+10bit
[error] x265 [info]: using cpu capabilities: MMX2 SSE2Fast LZCNT SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2
[error] x265 [info]: Main profile, Level-4.1 (Main tier)
[error] x265 [info]: Thread pool created using 12 threads
[error] x265 [info]: Slices                              : 1
[error] x265 [info]: frame threads / pool features       : 3 / wpp(30 rows)
[error] x265 [warning]: VBV maxrate unspecified, assuming CBR
[error] x265 [info]: Coding QT: max CU size, min CU size : 64 / 8
[error] x265 [info]: Residual QT: max TU size, max depth : 32 / 1 inter / 1 intra
[error] x265 [info]: ME / range / subpel / merge         : hex / 57 / 1 / 2
[error] x265 [info]: Keyframe min / max / scenecut / bias  : 25 / 250 / 40 / 5.00
[error] x265 [info]: Lookahead / bframes / badapt        : 15 / 4 / 0
[error] x265 [info]: b-pyramid / weightp / weightb       : 1 / 1 / 0
[error] x265 [info]: References / ref-limit  cu / depth  : 2 / on / on
[error] x265 [info]: AQ: mode / str / qg-size / cu-tree  : 2 / 1.0 / 32 / 1
[error] x265 [info]: Rate Control / qCompress            : ABR-800 kbps / 0.60
[error] x265 [info]: VBV/HRD buffer / max-rate / init    : 1200 / 800 / 0.750
[error] x265 [info]: tools: rd=2 psy-rd=2.00 early-skip rskip mode=1 signhide tmvp
[error] x265 [info]: tools: fast-intra strong-intra-smoothing lslices=8 deblock sao
[error] Output #0, mp4, to 'outputXZ.mp4':
[error]   Metadata:
[error]     major_brand     : isom
[error]     minor_version   : 512
[error]     compatible_brands: isomiso2avc1mp41
[error]     encoder         : Lavf58.46.101
[error]     Stream #0:0(und): Video: hevc (libx265) (hvc1 / 0x31637668), yuv420p, 1080x1920 [SAR 256:81 DAR 16:9], q=-1--1, 800 kb/s, 60 fps, 15360 tbn, 60 tbc (default)
[error]     Metadata:
[error]       handler_name    : VideoHandler
[error]       encoder         : Lavc58.92.100 libx265
[error]     Side data:
[error]       cpb: bitrate max/min/avg: 0/0/800000 buffer size: 1200000 vbv_delay: N/A
[error]     Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 128 kb/s (default)
[error]     Metadata:
[error]       handler_name    : SoundHandler
[error]       encoder         : Lavc58.92.100 aac
[error] frame=   47 fps=0.0 q=39.0 size=       0kB time=00:00:00.95 bitrate=   0.4kbits/s speed=1.89x
[error] frame=  110 fps=109 q=11.0 size=       0kB time=00:00:01.97 bitrate=   0.2kbits/s speed=1.96x
[error] frame=  172 fps=114 q=5.0 size=       0kB time=00:00:03.04 bitrate=   0.1kbits/s speed=2.01x
[error] frame=  190 fps=106 q=6.0 Lsize=      36kB time=00:00:03.15 bitrate=  94.2kbits/s speed=1.76x
[error] video:27kB audio:1kB subtitle:0kB other streams:0kB global headers:2kB muxing overhead: 31.662476%
[error] x265 [info]: frame I:      1, Avg QP:50.77  kb/s: 296.16
[error] x265 [info]: frame P:     38, Avg QP:22.16  kb/s: 67.17
[error] x265 [info]: frame B:    151, Avg QP:17.18  kb/s: 65.79
[error] x265 [info]: Weighted P-Frames: Y:0.0% UV:0.0%
[error] x265 [info]: consecutive B-frames: 2.6% 0.0% 0.0% 2.6% 94.9%
[error] encoded 190 frames in 1.75s (108.45 fps), 67.28 kb/s, Avg QP:18.35
[error] [aac @ 000002cddd6d0a80] Qavg: 65536.000

不幸的是,您无法控制更改输出的过程,您只需要按原样使用它。只是不要完全相信应用程序的输出,它就在那里,因此您可以查看是否正常。

但是,您可以控制捕获的输出,您可以修改您认为合适的方式,就像我在 output 函数中所做的那样。

PS: 任何以不同于 0 的 exitCode 退出的进程都被视为失败。有时程序员可以在不知道这一点的情况下对行为正确的进程强制执行 process.exit(1),当然如果其他人正在使用该进程,他们的 error events/conditions 将触发。