nodejs ffmpeg 在特定时间播放视频并将其流式传输到客户端

nodejs ffmpeg play video at specific time and stream it to client

我正在尝试使用 nodeJS 和 ffmpeg 制作一个基本的在线视频编辑器。

为此,我需要 2 个步骤:

  1. 设置客户端视频进出时间,需要客户端在特定时间观看视频,切换视频位置。这意味着,如果将单个视频用作输入,并将其分成更小的部分,则需要从下一个编辑片段的开始时间开始重播,如果这样的话。

  2. 将输入输出数据发送到nodejs,用ffmpeg导出为成品视频

一开始我想做1.纯客户端,然后把源视频上传到nodeJS,用ffmpeg生成一样的结果,再传回。

但是目前HTML客户端的视频处理可能存在问题,所以现在我改变了计划:在nodeJS服务器上完成所有处理,包括视频正在播放。

这是我现在卡住的部分。我知道 ffmpeg 可以与 nodeJS 以多种不同的方式使用,但是 我还没有找到一种方法来使用 ffmpeg 在特定的时间戳实时播放 .mp4 webm 视频,并发送流媒体视频(同样,在某个时间戳)到客户端。

我看过 ffmpeg 的 pipe:1 属性,但我找不到任何教程来让它与 mp4 webm 视频一起工作,也找不到用 nodejs 以某种方式解析 stdout 数据并将其发送到客户端。即使我能让那部分工作,我仍然不知道在某个时间戳实时播放视频。

我也看过ffplay,但据我所知那只是为了测试;我还没有看到任何使用 nodejs 实时从中获取视频数据的方法。

所以:

如何在特定时间(最好使用ffmpeg)在nodeJS中播放视频,并将其实时发送回客户端?

我已经看到的:

Live streaming using FFMPEG to web audio api

ffmpeg: Render webm from stdin using NodeJS

node.js live streaming ffmpeg stdout to res

Realtime video conversion using nodejs and ffmpeg

Pipe output of ffmpeg using nodejs stdout

can't re-stream using FFMPEG to MP4 HTML5 video

http://www.mobiuso.com/blog/2018/04/18/video-processing-with-node-ffmpeg-and-gearman/

stream mp4 video with node fluent-ffmpeg

Server node.js for livestreaming

HLS Streaming using node JS

Stream part of the video to the client

Video streaming with HTML 5 via node.js

Streaming a video file to an html5 video player with Node.js so that the video controls continue to work?

How to (pseudo) stream H.264 video - in a cross browser and html5 way?

Pseudo Streaming an MP4 file

How do I convert an h.264 stream to MP4 using ffmpeg and pipe the result to the client?

https://medium.com/@brianshaler/on-the-fly-video-rendering-with-node-js-and-ffmpeg-165590314f2

node.js live streaming ffmpeg stdout to res

Can Node.js edit video files?

这个问题有点宽泛,但我已经构建了类似的东西,并会尝试为您逐一回答:

  1. set the in-and-out times of the videos from the client, which requires the client to view the video at specific times, and switch the position of the video. Meaning, if a single video is used as an input, and split it into smaller parts, it needs to replay from the starting time of the next edited segment, if that makes sense.

客户端,当你播放时,你可以简单地使用引用相同的多个 HTMLVideoElement 实例 URL。

对于时间,您可以使用 .currentTime 属性 自行管理。但是,您会发现您的 JavaScript 时机并不完美。如果你在实例化时知道你的 start/end 点数,你可以使用 Media Fragment URIs:

video.src = 'https://example.com/video.webm#t=5.5,30';

在此示例中,视频从 5.5 秒开始,到 30 秒停止。您可以使用 ended event 来知道何时开始播放下一个剪辑。这不能保证完全精确到帧,但对于实时预览之类的东西来说非常好。

But there are may problems with video processing on the client side in HTML at the moment, so now I have a change of plans: to do all of the processing on the nodeJS server,...

不错的计划,如果一致性很重要的话。

... including the video playing.

就控制该视频的延迟和预览质量而言,您在这里做出了严重的权衡。我建议采用混合方法,在客户端完成编辑,但最终 bounce/compositing/whatever 在服务器端完成。

无论如何,这与桌面视频编辑软件的工作方式没什么不同。

This is the part I am stuck at now. I'm aware that ffmpeg can be used in many different ways from nodeJS, but I have not found a way to play a .mp4 webm video in realtime with ffmpeg, at a specific timestamp, and send the streaming video (again, at a certain timestamp) to the client.

是MP4还是WebM?这是两种不同的容器格式。 WebM 很容易流式传输,直接从 FFmpeg 中传输出来。 MP4 需要使用 MOOV 原子 (-movflags faststart),这可能有点麻烦。

无论如何,听起来您只需要在输入上设置时间戳:

ffmpeg -ss 00:01:23 -i video.mp4 -to 00:04:56 -f webm -

I've seen the pipe:1 attribute from ffmpeg, but I couldn't find any tutorials to get it working with an mp4 webm video, and to parse the stdout data somehow with nodejs and send it to the client.

只需使用连字符 - 作为输出文件名,FFmpeg 将输出到 STDOUT。然后,您无需在 Node.js 应用程序中执行任何其他操作...直接输出到客户端的管道。未经测试,但假设是典型的 Express 应用程序,您正在寻找这样的东西:

app.get('/stream', (req, res, next) => {
  const ffmpeg = child_process.spawn('ffmpeg', [
    '-i', 'video.mp4',
    '-f', 'webm',
    '-'
  ]);

  res.set('Content-Type', 'video/webm'); // TODO: Might want to set your codecs here also

  ffmpeg.stdout.pipe(res);
});

And even if I could get that part to work, I still have no idea to play the video, in realtime, at a certain timestamp.

好吧,为此,您只是在播放一个流,所以您可以这样做:

<video src="https://your-nodejs-server.example.com/stream" preload="none" />

preload="none"部分很重要,要保留"live"。

所有这些的替代方法是设置一个 GStreamer 管道,并可能利用其内置的 WebRTC 堆栈。这不是微不足道的,但具有潜在较低延迟和自动处理 "catching up" 到来自服务器的实时视频的优势。如果您使用普通视频标签,则必须通过监控缓冲数据和管理播放速度自行处理。

I've also seen ffplay...

FFplay 与您的项目无关。

希望这一堆笔记能给你一些思考和观察的东西。