管道中未处理的流错误:在 Node.js 中编写 EPIPE

Mic*_*nko 5 streaming ffmpeg rtsp node.js

这个想法是使用 Express.js 服务器提供 RTSP 视频流的屏幕截图。在流动模式下有一个连续运行的衍生 openRTSP 进程(它的标准输出被另一个 ffmpeg 进程消耗):

function spawnProcesses (camera) {
  var openRTSP = spawn('openRTSP', ['-c', '-v', '-t', camera.rtsp_url]),
      encoder = spawn('ffmpeg', ['-i', 'pipe:', '-an', '-vcodec', 'libvpx', '-r', 10, '-f', 'webm', 'pipe:1']);

  openRTSP.stdout.pipe(encoder.stdin);

  openRTSP.on('close', function (code) {
    if (code !== 0) {
      console.log('Encoder process exited with code ' + code);
    }
  });

  encoder.on('close', function (code) {
    if (code !== 0) {
      console.log('Encoder process exited with code ' + code);
    }
  });

  return { rtsp: openRTSP, encoder: encoder };
}

...

camera.proc = spawnProcesses(camera);
Run Code Online (Sandbox Code Playgroud)

有一个单一路由的 Express 服务器:

app.get('/cameras/:id.jpg', function(req, res){
  var camera = _.find(cameras, {id: parseInt(req.params.id, 10)});
  if (camera) {
    res.set({'Content-Type': 'image/jpeg'});
    var ffmpeg = spawn('ffmpeg', ['-i', 'pipe:', '-an', '-vframes', '1', '-s', '800x600', '-f', 'image2', 'pipe:1']);
    camera.proc.rtsp.stdout.pipe(ffmpeg.stdin);
    ffmpeg.stdout.pipe(res);
  } else {
    res.status(404).send('Not found');
  }
});

app.listen(3333);
Run Code Online (Sandbox Code Playgroud)

当我请求http://localhost:3333/cameras/1.jpg我获得所需的图像时,但有时应用程序会因错误而中断:

stream.js:94
  throw er; // Unhandled stream error in pipe.
        ^
Error: write EPIPE
    at errnoException (net.js:901:11)
    at Object.afterWrite (net.js:718:19)
Run Code Online (Sandbox Code Playgroud)

奇怪的是,有时它成功地将图像res流式传输并关闭子进程而没有任何错误,但是,有时,流式传输图像并掉下来。

我尝试on('error', ...)在每个可能的流上创建事件处理程序,尝试更改pipe(...)on('data',...)构造的调用,但未能成功。

我的环境:node v0.10.22,OSX Mavericks 10.9。

更新:

spawn('ffmpeg',...用 try-catch包裹了块:

app.get('/cameras/:id.jpg', function(req, res){
....
    try {
      var ffmpeg = spawn('ffmpeg', ['-i', 'pipe:', '-an', '-vframes', '1', '-s', '800x600', '-f', 'image2', 'pipe:1']);
      camera.proc.rtsp.stdout.pipe(ffmpeg.stdin);
      ffmpeg.stdout.pipe(res);
    } catch (e) {
      console.log("Gotcha!", e);
    }
....
});
Run Code Online (Sandbox Code Playgroud)

...这个错误消失了,但日志是静默的,它没有发现任何错误。怎么了?

小智 1

EPIPE :对管道、套接字或 FIFO 的写入,没有进程读取数据

尝试添加错误处理程序,然后在调用 .pipe() 之前放置 .on('error', function(e) { ... }) 或更改程序以在管道关闭的情况下成功退出

尝试 :

process.stdout.on('error', function( err ) {
  if (err.code == "EPIPE") {
    process.exit(0);
  }
});
Run Code Online (Sandbox Code Playgroud)