实时HTTPstream媒体到HTML5video客户端的最佳途径

我很困惑,试图理解使用node.js实时输出ffmpeg到HTML5客户端的最佳方式,因为在这里有很多variables,我在这个领域没有太多的经验,花了很多时间尝试不同的组合。

我的用例是:

1)IPvideo摄像机RTSP H.264stream由FFMPEG接收,并在节点中使用以下FFMPEG设置重新混合成mp4容器,输出到STDOUT。 这只在初始客户端连接上运行,所以部分内容请求不会再尝试产生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)我使用节点http服务器来捕获STDOUT,并在客户端请求时将数据stream发送回客户端。 当客户端第一次连接时,我产生了上面的FFMPEG命令行,然后pipe道STDOUTstream到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)客户端必须使用HTML5video标签。

我没有任何问题stream媒体播放(使用fs.createReadStream与206 HTTP部分内容)到HTML5客户端以前FFMPEG命令行(但保存到一个文件,而不是STDOUT)录制的video文件,所以我知道FFMPEGstream是正确的,当连接到HTTP节点服务器时,我甚至可以在VLC中正确地看到video直播。

然而,试图通过节点HTTP从FFMPEGstream式传输看起来要困难得多,因为客户端将显示一帧然后停止。 我怀疑问题是我没有设置HTTP连接与HTML5video客户端兼容。 我已经尝试过使用HTTP 206(部分内容)和200响应的各种东西,把数据放入缓冲区,然后stream没有运气,所以我需要回到第一个原则,以确保我设置了正确的办法。

这是我的理解,这应该如何工作,请纠正我,如果我错了:

1)FFMPEG应设置为分段输出,并使用空moov(FFMPEG frag_keyframe和empty_moov mov标志)。 这意味着客户端不会使用moovprimefaces,这通常在文件的结尾是不相关的,当stream(没有文件的结尾),但意味着没有寻求可能这是我的用例罚款。

2)即使我使用MP4片段和空的MOOV,我仍然必须使用HTTP部分内容,因为HTML5播放器将等待,直到整个stream下载之前,播放,直播stream永远不会结束,因此是行不通的。

3)我不明白为什么pipe道的STDOUTstream的HTTP响应不工作时stream媒体直播,但如果我保存到一个文件我可以很容易地stream此文件到HTML5客户端使用类似的代码。 也许这是一个时间问题,因为启动FFMPEG spawn需要一秒钟的时间,连接到IP摄像机并发送块到节点,并且节点数据事件也是不规则的。 然而,字节stream应该与保存到文件完全一样,并且HTTP应该能够迎合延迟。

4)当从照相机stream传输由FFMPEG创build的MP4文件时,从HTTP客户端检查networking日志时,我看到有3个客户端请求:HTTP服务器返回大约40Kb的video的一般GET请求,内容请求的文件的最后10K字节范围,然后最后请求中间的位未加载。 也许HTML5客户端收到第一个响应之后是要求文件的最后部分加载MP4 MOOVprimefaces? 如果是这种情况,它将无法工作stream媒体,因为没有MOOV文件,没有文件的结尾。

5)当试图stream式传输时检查networking日志时,我收到一个中止的初始请求,只收到大约200字节,然后再次请求中止了200字节和第三个请求,只有2K长。 我不明白为什么HTML5客户端会中止请求,因为字节stream与从录制文件stream式传输时可以成功使用的完全相同。 也似乎节点没有发送剩余的FFMPEGstream到客户端,但我可以在.on事件例程中看到FFMPEG数据,因此它正在到达FFMPEG节点HTTP服务器。

6)虽然我认为pipe道STDOUTstream到HTTP响应缓冲区应该工作,我必须build立一个中间缓冲区和stream,将允许HTTP部分内容客户端请求正常工作,就像它((成功)读取文件时? 我认为这是我的问题的主要原因,但我不完全确定在节点如何最好地设置。 我不知道如何处理文件末尾数据的客户端请求,因为没有文件结尾。

7)我是否试图处理206个部分内容请求的错误轨道,并应该与普通的200 HTTP响应? HTTP 200响应对于VLC工作正常,所以我怀疑HTML5video客户端只能处理部分内容请求?

由于我仍然在学习这个东西,所以很难通过这个问题的各个层面(FFMPEG,节点,stream媒体,HTTP,HTML5video),所以任何指针将不胜感激。 我花了数小时研究这个网站和networking,我还没有遇到任何人谁已经能够做节点实时stream,但我不能成为第一,我认为这应该能够工作(以某种方式!)。

编辑3:从IOS 10开始,HLS将支持分段的mp4文件。 现在的答案是创build碎片mp4资产,具有DASH和HLS清单。 >假装闪光,iOS9及以下和IE10及以下不存在。

这条线下面的所有东西都是过时的。 把它留在这里为后代。


编辑2:正如评论中的人们指出的,事情发生了变化。 几乎所有的浏览器都支持AVC / AAC编解码器。 iOS仍然需要HLS。 但通过像hls.js这样的适配器,您可以在MSE中播放HLS。 如果您需要iOS,新的答案是HLS + hls.js。 或者只是碎片化的MP4(即DASH),如果你没有

video,特别是直播video的原因有很多,非常困难。 (请注意,原始问题指定HTML5video是一个要求,但提问者声明Flash可能在评论中,因此,这个问题立即引起误解)

首先我要重申一下: HTML5上没有任何官方的stream量支持 。 有黑客,但你的里程可能会有所不同。

编辑:因为我写这个答案媒体源扩展已经成熟,现在非常接近成为一个可行的select。 它们在大多数主stream浏览器上都受支持。 IOS继续保持。

接下来,您需要了解video点播(VOD)和实况video是非常不同的。 是的,他们都是video,但问题是不同的,因此格式是不同的。 例如,如果您的电脑中的时钟运行速度比应该快1%,您将不会注意到VOD。 借助实时video,您将尝试在video发生之前播放video。 如果您想join正在进行的实时videostream,则需要初始化解码器所需的数据,因此必须在stream中重复,或者在带外发送。 有了VOD,你可以阅读文件的开始,他们寻找你想要的任何点。

现在我们来深入一点。

平台:

  • iOS版
  • 个人计算机
  • 苹果电脑
  • Android的

编解码器:

  • VP8 / 9
  • H.264
  • thora(vp3)

浏览器中实时video的常用传送方法:

  • DASH(HTTP)
  • HLS(HTTP)
  • 闪存(RTMP)
  • 闪存(HDS)

浏览器中VOD的常见传送方式:

  • DASH(HTTPstream)
  • HLS(HTTPstream媒体)
  • 闪存(RTMP)
  • 闪光灯(HTTPstream媒体)
  • MP4(HTTP伪stream媒体)
  • 我不会谈论MKV和OOG,因为我不太了解他们。

html5video标签:

  • MP4
  • WEBM
  • OGG

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

苹果浏览器:

  • HLS(仅适用于iOS和Mac)
  • H.264
  • MP4

火狐

  • DASH(通过MSE,但没有h.264)
  • h.264只能通过Flash!
  • VP9
  • MP4
  • OGG
  • WEBM

IE

  • DASH(仅限MSE IE 11+)
  • H.264
  • MP4

  • DASH(通过MSE)
  • H.264
  • VP9
  • MP4
  • WEBM
  • OGG

MP4不能用于实时video(注:DASH是MP4的超集,所以不要混淆)。 MP4分为两部分:moov和mdat。 mdat包含原始audiovideo数据。 但是没有索引,所以没有moov就没用了。 moov包含mdat中所有数据的索引。 但是由于其格式的原因,在每个帧的时间戳和大小已知之前,它不能被“拼合”。 构build一个可以“帧化”帧大小的moov是可能的,但是这是非常浪费的带宽明智的。

所以,如果你想在任何地方交付,我们需要find最不共同的分母。 没有诉诸闪光的例子,你会看到这里没有LCD:

  • iOS只支持h.264video。 而且它只支持HLS直播。
  • Firefox根本不支持h.264,除非你使用flash
  • Flash在iOS中不起作用

最接近液晶显示器的是使用HLS来让你的iOS用户,并为其他人闪光。 我个人最喜欢的是对HLS进行编码,然后使用闪存为其他人播放HLS。 您可以通过JW播放器6在Flash中播放HLS(或像我一样在AS3中将您自己的HLS编写到FLV中)

很快,最常见的做法是在iOS / Mac上使用HLS,而在其他地方使用MSE使用DASH(这就是Netflix很快将要做的事情)。 但是我们仍然在等待所有人升级他们的浏览器。 你也可能需要一个独立的DASH / VP9 for Firefox(我知道的是open264,它很糟糕,它不能以主stream或者高端的forms来做video,所以现在是没用的)。

感谢大家特别是szatmary,因为这是一个复杂的问题,并有许多层,所有这些都必须工作之前,你可以stream直播video。 为了澄清我的原始问题和HTML5video的使用与Flash – 我的用例对HTML5有着强烈的偏好,因为它是通用的,易于在客户端和未来实现。 Flash是第二好的,所以让我们坚持使用HTML5来解决这个问题。

我通过这个练习学到了很多东西,并且认同实时stream媒体比VOD(它适用于HTML5video)要困难得多。 但是,我确实得到了这个工作令人满意,我的用例和解决scheme的工作很简单,追逐更复杂的选项,如MSE,闪存,精心制作的缓冲scheme在节点。 问题是,FFMPEG破坏了零碎的MP4,我不得不调整FFMPEG参数,并且通过我原来使用的http的标准节点streampipe道redirect是所有需要的。

在MP4中有一个“分段”选项,将mp4分割成更小的片段,这些片段有自己的索引,并使mp4直播选项可行。 但是不能回到stream中(对于我的用例来说OK),FFMPEG的更高版本支持分片。

注意时间可能是一个问题,并与我的解决scheme,我有一个滞后2至6秒由remuxing的组合(有效FFMPEG必须接收实时stream,remux然后发送到节点通过HTTP服务) 。 在这方面没有太多可以做的事情,但是在Chrome浏览器中,video尽可能地赶上,这使得video有点跳跃,但比IE11(我的首选客户端)更加stream行。

而不是解释代码在这篇文章中是如何工作的,用注释(不包括客户端代码,它是一个带有节点http服务器地址的标准HTML5video标签)来检查GIST。 GIST在这里: https : //gist.github.com/deandob/9240090

我一直没有find类似的例子,所以我希望上面的解释和代码能够帮助其他人,特别是我从这个网站学到了很多东西,并且仍然认为自己是初学者!

虽然这是我的具体问题的答案,但我select了最为全面的答案作为公认的答案。

看看JSMPEG项目。 在那里实现了一个好主意 – 在浏览器中使用JavaScript来解码MPEG。 例如,编码器的字节(例如FFMPEG)可以使用WebSocket或Flash传输到浏览器。 如果社区能够赶上,我认为这将是目前最好的HTML5实时videostream媒体解决scheme。

将基于RTSP的networking摄像头直播到HTML5客户端的一种方法(涉及重新编码,因此期望质量损失并需要一些CPU能力):

  • 设置一台icecast服务器(可以在Web服务器所在的同一台机器上,或者在接收来自摄像机的RTSPstream的机器上)
  • 在从相机接收stream的机器上,请勿使用FFMPEG但使用gstreamer。 它能够接收和解码RTSP数据stream,重新编码并将数据stream传输到icecast服务器。 示例stream水线(仅video,无audio):

     gst-launch-1.0 rtspsrc location=rtsp://192.168.1.234:554 user-id=admin user-pw=123456 ! rtph264depay ! avdec_h264 ! vp8enc threads=2 deadline=10000 ! webmmux streamable=true ! shout2send password=pass ip=<IP_OF_ICECAST_SERVER> port=12000 mount=cam.webm 

=>然后,您可以使用<video>标签和icecast-stream的URL( http://127.0.0.1:12000/cam.webm ),它可以在每个支持webm的浏览器和设备

我在百老汇h264编解码器(emscripten)周围写了一个HTML5video播放器,可以在所有浏览器(桌面,iOS,…)上直播(不延迟)h264video。

videostream通过websocket发送到客户端,每帧解码帧并显示在canva(使用webgl加速)

在github上查看https://github.com/131/h264-live-player

看看这个解决scheme 。 据我所知,Flashphoner允许在纯HTML5页面中播放实时audio+videostream。

他们使用MPEG1G.711编解码器进行播放。 黑客正在将解码的video呈现给HTML5 canvas元素,并通过HTML5audio上下文播放解码的audio。

如何使用jpeg解决scheme,让服务器将jpeg逐一分发到浏览器,然后使用canvas元素来绘制这些jpeg? http://thejackalofjavascript.com/rpi-live-streaming/

这是一个很常见的误解。 没有实时的HTML5video支持(iOS和Mac Safari上的HLS除外)。 您可能能够使用webm容器来“破解”它,但我不希望得到普遍支持。 您正在寻找的内容包含在“媒体来源扩展”中,您可以在其中一次将片段提供给浏览器。 但是你将需要写一些客户端的JavaScript。

尝试binaryjs。 它就像socket.io但它唯一的好处是它streamaudiovideo。 Binaryjs谷歌它