我真的很难理解使用node.js将ffmpeg的实时输出流式传输到HTML5客户机的最佳方式,因为有很多变量在起作用,而且我在这个领域没有太多经验,因为我花了很多时间try 不同的组合.

我的用例是:

1) IP摄像机RTSP H.264流由FFMPEG拾取,并使用 node 中的以下FFMPEG设置重新插入mp4容器,输出到STDOUT.这只在初始客户端连接上运行,因此部分内容请求不会再次try 生成FFMPEG.

liveFFMPEG = child_process.spawn("ffmpeg", [
                "-i", "rtsp://admin:12345@192.168.1.234:554" , "-vcodec", "copy", "-f",
                "mp4", "-reset_timestamps", "1", "-movflags", "frag_keyframe+empty_moov", 
                "-"   // output to stdout
                ],  {detached: false});

2)我使用 node http服务器捕获STDOUT,并在客户端请求时将其流回客户端.当客户端第一次连接时,我生成上面的FFMPEG命令行,然后通过管道将STDOUT流传输到HTTP响应.

liveFFMPEG.stdout.pipe(resp);

我还使用了stream事件将FFMPEG数据写入HTTP响应,但没有任何区别

xliveFFMPEG.stdout.on("data",function(data) {
        resp.write(data);
}

我使用以下HTTP标头(在流式传输预先录制的文件时也会使用并运行该标头)

var total = 999999999         // fake a large file
var partialstart = 0
var partialend = total - 1

if (range !== undefined) {
    var parts = range.replace(/bytes=/, "").split("-"); 
    var partialstart = parts[0]; 
    var partialend = parts[1];
} 

var start = parseInt(partialstart, 10); 
var end = partialend ? parseInt(partialend, 10) : total;   // fake a large file if no range reques 

var chunksize = (end-start)+1; 

resp.writeHead(206, {
                  'Transfer-Encoding': 'chunked'
                 , 'Content-Type': 'video/mp4'
                 , 'Content-Length': chunksize // large size to fake a file
                 , 'Accept-Ranges': 'bytes ' + start + "-" + end + "/" + total
});

3) 客户端必须使用HTML5视频标签.

向HTML5客户端流式播放(使用带有206 HTTP部分内容的fs.createReadStream)之前使用上述FFMPEG命令行录制的视频文件(但保存为文件而不是STDOUT)没有问题,因此我知道FFMPEG流是正确的,甚至可以在连接到HTTP node 服务器时在VLC中正确地看到视频直播.

然而,试图通过 node HTTP从FFMPEG实时流媒体似乎要困难得多,因为客户端将显示一帧,然后停止.我怀疑问题在于我没有将HTTP连接设置为与HTML5视频客户端兼容.我try 过很多方法,比如使用HTTP 206(部分内容)和200个响应,将数据放入缓冲区,然后进行流式处理,但运气不佳,所以我需要回到第一原则,以确保我的设置正确.

这是我对此的理解,如果我错了,请纠正我:

1) FFMPEG应设置为对输出进行分段,并使用空moov(FFMPEG frag_关键帧和空moov mov标志).这意味着客户端不使用moov-atom,它通常位于文件的末尾,在流媒体传输时不相关(文件没有结尾),但这意味着不可能寻找适合我的用例的对象.

2) 尽管我使用MP4片段和空MOOV,但我仍然必须使用HTTP部分内容,因为HTML5播放器将等待整个流下载后再播放,而使用实时流永远不会结束,因此不可行.

3) 我不明白为什么在流媒体直播时,将STDOUT流传输到HTTP响应的管道还不起作用.如果我保存到一个文件中,我可以使用类似的代码轻松地将该文件流传输到HTML5客户端.也许这是一个时间问题,因为FFMPEG生成需要一秒钟的时间才能启动,连接到IP摄像头并将块发送到 node ,而且 node 数据事件也不规则.然而,字节流应该与保存到文件完全相同,HTTP应该能够应对延迟.

4)当从摄像机流式传输由FFMPEG创建的MP4文件时,当从HTTP客户端判断网络日志(log)时,我看到有3个客户端请求:对视频的通用GET请求(HTTP服务器返回约40KB),然后是文件最后10K的字节范围的部分内容请求,然后是对中间位的最终请求未加载.也许HTML5客户端在收到第一个响应后会请求文件的最后一部分来加载MP4MOOV原子?如果是这种情况,它将不适用于流,因为没有MOOV文件,也没有文件结尾.

5)在try 实时流式传输时判断网络日志(log)时,我收到一个仅收到约200字节的中止的初始请求,然后重新请求再次中止,收到的200字节和第三个请求的长度仅为2K.我不明白为什么HTML5客户端会中止请求,因为字节流与我从录制的文件流式传输时可以成功使用的字节流完全相同. node 似乎也没有将ffmpeg流的睡觉发送到客户机,但是我可以在.on事件 routine 中看到ffmpeg数据,所以它会到达ffmpeg node HTTP服务器.

6) 虽然我认为将标准输出流传输到HTTP响应缓冲区应该可以工作,但我是否必须构建一个中间缓冲区和流,以允许HTTP部分内容客户端请求像(成功)读取文件时那样正常工作?我认为这是我的问题的主要原因,但是我不确定如何最好地设置它.我不知道如何处理客户端对文件末尾数据的请求,因为没有文件结尾.

7) 我在try 处理206个部分内容请求时,是不是走错了方向,这是否应该适用于正常的200个HTTP响应?HTTP 200响应对VLC很好,所以我怀疑HTML5视频客户端只能处理部分内容请求?

由于我仍在学习这方面的知识,很难解决这个问题的各个层面(FFMPEG、 node 、流媒体、HTTP、HTML5视频),所以任何指点都会非常感激.我花了数小时研究这个网站和网络,我还没有遇到任何人能够在node中进行实时流媒体,但我不能是第一个,我认为这应该能够工作(不知怎么回事!).

推荐答案

EDIT 3: As of IOS 10, HLS will support fragmented mp4 files. The answer now, is to create fragmented mp4 assets, with a DASH and HLS manifest. > Pretend flash, 网间网操作系统9 and below and IE 10 and below don't exist.

这条线以下的东西都过时了.把它留给子孙后代.


编辑2:正如人们在 comments 中指出的那样,事情发生了变化. 几乎所有浏览器都支持AVC/AAC编解码器. IOS仍然需要HLS.但是通过像hls.js这样的适配器,你可以玩 HLS在MSE.如果您需要网间网操作系统,新的答案是hls+hls.js.或者只是 如果您不这样做,则会出现零碎的MP4(即破折号)

视频,尤其是直播视频非常困难的原因有很多.(请注意,最初的问题规定HTML5视频是一项要求,但提问者在 comments 中表示闪光灯是可能的.因此,这个问题立即具有误导性)

首先我要重申:THERE IS NO OFFICIAL SUPPORT FOR LIVE STREAMING OVER HTML5.有黑客攻击,但你的里程可能会有所不同.

编辑:自从我写了这个答案以来,媒体源扩展已经成熟,

接下来,你需要了解视频点播(VOD)和直播视频是非常不同的.是的,它们都是视频,但问题不同,因此格式不同.例如,如果计算机中的时钟运行速度比实际速度快1%,您将不会注意到视频点播.使用实时视频,您将try 在视频发生之前播放视频.如果要加入正在进行的实时视频流,则需要初始化解码器所需的数据,因此必须在流中重复,或在带外发送.有了VOD,你可以阅读文件的开头,让他们找到你想要的任何地方.

现在让我们深入了解一下.

平台:

  • 网间网操作系统
  • 个人计算机
  • 雨衣
  • 安卓系统

编解码器:

  • vp8/9
  • h、 264
  • Thora(VP3)

浏览器中实时视频的常见交付方法:

  • 破折号(HTTP)
  • HLS(HTTP)
  • 闪光(RTMP)
  • 闪存(HDS)

浏览器中常见的点播投递方式:

  • DASH(HTTP流)
  • HLS(HTTP流媒体)
  • 闪光(RTMP)
  • flash(HTTP流媒体)
  • MP4(HTTP伪流)
  • 我不打算谈论MKV和Oog,因为我对他们不是很了解.

html5视频标签:

  • MP4
  • WebM
  • Ogg

让我们看看哪些浏览器支持什么格式

游猎:

  • HLS (网间网操作系统 and mac only)
  • h、 264
  • MP4

firefox

  • DASH (via MSE but no h、 264)
  • h、 264 via 闪光灯 only!
  • VP9
  • MP4
  • OGG
  • Webm

IE

  • 闪光灯
  • 短跑(仅通过MSE IE 11+实现)
  • h、 264
  • MP4

chromium 合金

  • 闪光灯
  • 短跑(通过MSE)
  • h、 264
  • VP9
  • MP4
  • WebM
  • Ogg

MP4不能用于实时视频(注意:DASH是MP4的超集,所以不要对此感到困惑).MP4分为两部分:moov和mdat.mdat包含原始音频视频数据.但它没有索引,因此没有moov,它是无用的.moov包含mdat中所有数据的索引.但由于其格式,在知道每一帧的时间戳和大小之前,它不能被"展平".也许可以构造一个"fib"帧大小的moov,但这是非常浪费带宽的.

因此,如果你想在任何地方交付,我们需要找到最小的共同点.如果不使用flash,你会看到这里没有LCD

  • 网间网操作系统 only supports h、 264 video. and it only supports HLS for live.
  • firefox does not support h、 264 at all, unless you use flash
  • 闪光灯 does not work in 网间网操作系统

最接近LCD的是使用HLS来吸引网间网操作系统用户,并为其他所有人提供闪存. 我个人最喜欢的是对HLS进行编码,然后用flash为其他人播放HLS.您可以通过JW Player 6在flash中播放HLS(或者像我一样在AS3中编写您自己的HLS到FLV)

Soon, the most common way to do this will be HLS on 网间网操作系统/雨衣 and DASH via MSE everywhere else (This is what Netflix will be doing soon). But we are still waiting for everyone to upgrade their browsers. You will also likely need a separate DASH/VP9 for firefox (I know about open264; it sucks. It can't do video in main or high profile. So it is currently useless).

Html相关问答推荐

如何实现弯曲的梯形导航栏?

浏览器是在调整大小还是在全屏上交换视频源?

动态FormControl值在Angular 上绑定错误的问题

获得一个css框,以便在页面太小时不再粘在页面的角落.

带有多种 colored颜色 的HTML按钮

邮箱追踪器-有效,但在Gmail客户端中是否可以显示问号图标以外的其他内容?

在<;style&>中列出的三种字体中,只有两种显示

轨道上的居中范围滑块拇指(Webkit)

获取标准的Python脚本,以便使用FASK对网站进行Flask

当div位于flexbox中时,如何使div的宽度与高度相同

四开:如何右对齐 PDF *和* HTML 中的文本

在HTML请求中添加源URL

当作为常规图片输入时,Cloudfront分布式图像可显示,但作为背景图像不显示

具有 css 高度的输入元素:100% 溢出父 div

在带有换行文本的工具提示中显示溢出文本

将图像的高度限制为固定的纵横比,并在超过时使用 object-fit

按钮显示:内联不换行

将 HTML 元素粘贴到容器底部,而不剪裁其顶部

如何将图像移动到父容器的右侧?

html元素可以被css跳过吗?