我真的很难理解使用Node.js将ffmpeg的实时输出流到HTML5客户端的最佳方法,因为有很多变量在起作用,而我在这方面没有太多经验,我花了很多时间尝试不同的组合。
我的用例是:
1)IP视频摄像机RTSP H.264流由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并在客户端请求时将其流回客户端。当客户端第一次连接时,我生成上面的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视频标签。
我对流式回放(使用带有206 HTTP部分内容的fs.createReadStream)到HTML5客户端一个以前用上面的FFMPEG命令行录制的视频文件(但保存到一个文件而不是STDOUT)没有任何问题,所以我知道FFMPEG流是正确的,我甚至可以在连接到HTTP节点服务器时正确地看到VLC中的视频直播流。
然而,试图通过节点HTTP从FFMPEG实时流似乎要困难得多,因为客户端将显示一个帧,然后停止。我怀疑问题是我没有将HTTP连接设置为与HTML5视频客户端兼容。我尝试了很多方法,比如使用HTTP206(部分内容)和200响应,将数据放入缓冲区,然后流式传输,但没有运气,所以我需要回到第一原则,以确保我的设置是正确的。
以下是我对这应该如何工作的理解,如果我错了请纠正我:
1)FFMPEG应该设置为分割输出并使用空moov(FFMPEG frag_keyframe和empty_moov mov标志)。这意味着客户端不使用moov原子,该原子通常位于文件末尾,在流式传输时不相关(没有文件末尾),但意味着不可能查找,这对我的用例很好。
2)即使我使用MP4片段和空的MOOV,我仍然必须使用HTTP部分内容,因为HTML5播放器会等到整个流下载完后再播放,这对于一个直播流来说是永远不会结束的,所以是不可行的。
3)我不明白为什么管道STDOUT流到HTTP响应在流式传输时不起作用,如果我保存到一个文件,我可以使用类似的代码轻松地将该文件流式传输到HTML5客户端。也许这是一个定时问题,因为FFMPEG产卵启动、连接到IP摄像机并发送块到节点需要一秒钟,并且节点数据事件也是不规则的。然而,字节流应该与保存到一个文件完全相同,并且HTTP应该能够满足延迟。
4)当从HTTP客户端检查网络日志时,当从摄像机传输由FFMPEG创建的MP4文件时,我看到有3个客户端请求:对视频的一般GET请求,HTTP服务器返回大约40KB,然后是对文件最后10K的字节范围的部分内容请求,然后是对中间未加载的位的最终请求。也许HTML5客户端一旦收到第一个响应,就会请求文件的最后一部分来加载MP4 MOOV Atom?如果是这种情况,它将无法用于流,因为没有MOOV文件,也没有文件结尾。
5)当尝试流式传输时,当检查网络日志时,我得到一个中断的初始请求,只接收到大约200字节,然后一个重请求再次中断,只接收到200字节,第三个请求只有2K长。我不明白为什么HTML5客户端会中止请求,因为字流与我从记录文件流式传输时可以成功使用的字流完全相同。node似乎没有将FFMPEG流的其余部分发送到客户端,但我可以在.on event例程中看到FFMPEG数据,因此它正在到达FFMPEG node HTTP服务器。
6)虽然我认为将STDOUT流管道化到HTTP响应缓冲区应该可以工作,但我是否必须构建一个中间缓冲区和流,以允许HTTP部分内容客户端请求像它(成功地)读取文件时那样正常工作?我认为这是我的问题的主要原因,但我不确定在节点中如何最好地设置。而且我不知道如何处理客户端请求文件末尾的数据,因为没有文件末尾。
7)我在尝试处理206个部分内容请求时是不是走错了路,这应该与正常的200个HTTP响应一起工作吗?HTTP 200响应对VLC很好,所以我怀疑HTML5视频客户端将只与部分内容请求一起工作?
由于我还在学习这些东西,它很难通过这个问题的各个层次(FFMPEG、节点、流、HTTP、HTML5视频)工作,所以任何指针都将非常感谢。我花了几个小时的时间在这个网站和网络上研究,我没有遇到过任何人能够在node中做实时流,但我不可能是第一个,我认为这应该能够工作(不知怎么的!)。
感谢大家,特别是szatmary,因为这是一个复杂的问题,有很多层,所有这些都必须在你可以流媒体直播视频之前工作。为了澄清我最初的问题和HTML5视频使用vs flash--我的用例对HTML5有强烈的偏好,因为它是通用的,易于在客户端和未来实现。Flash是一个遥远的第二好,所以让我们继续用HTML5来解决这个问题。
通过这个练习,我学到了很多东西,我也同意直播流比视频点播(与HTML5视频配合得很好)要难得多。但我确实让这个方法在我的用例中得到了令人满意的效果,并且解决方案非常简单,在使用了更复杂的选项之后,比如MSE、flash、Node中精心设计的缓冲方案。问题是FFMPEG破坏了碎片化的MP4,我不得不调优FFMPEG参数,而我最初使用的http上的标准节点流管道重定向就是所需的全部。
在MP4中有一个“碎片化”选项,将MP4分解成更小的碎片,它有自己的索引,使MP4直播流选项可行。但不可能返回到流中(对我的用例来说是可以的),并且FFMPEG的更高版本支持碎片化。
注定时可能是一个问题,在我的解决方案中,由于重新复用的组合(实际上FFMPEG必须接收实时流,重新复用它,然后将它发送到通过HTTP提供服务的节点),导致了2到6秒之间的延迟。在这方面做不到太多,但在Chrome的视频确实尽力赶上它所能做到的,这使得视频有点跳跃,但比IE11(我的首选客户端)更有时代感。
在这篇文章中,不是解释代码是如何工作的,而是通过注释查看要点(客户端代码不包括在内,它是一个标准的HTML5视频标记,带有节点http服务器地址)。要点在这里:https://GIST.github.com/deandob/9240090
我还没有找到这个用例的类似例子,所以我希望上面的解释和代码能帮助其他人,特别是因为我已经从这个站点学到了这么多,但仍然认为自己是一个初学者!
虽然这是对我的具体问题的回答,但我还是选择了Szatmary的回答作为被接受的,因为它是最全面的。
编辑3:从IOS 10开始,HLS将支持碎片化的mp4文件。现在的答案是创建碎片化的mp4资产,带有破折号和HLS清单。>假装flash,iOS9及以下版本和IE10及以下版本不存在。
编辑2:正如评论中的人所指出的,事情发生了变化。几乎所有的浏览器都将支持AVC/AAC编解码器。iOS仍然需要HLS。但是通过像HLS.js这样的适配器,您可以在MSE中播放HLS。新的答案是hls+hls.js如果你需要iOS的话。如果你不喜欢的话,也可以使用碎片MP4(如破折号)
视频,特别是视频直播非常困难的原因有很多。(请注意,最初的问题指定HTML5视频是一个要求,但提问者在评论中表示Flash是可以的。所以立即,这个问题是误导)
首先,我要重申:官方没有对HTML5上的直播流的支持。有黑客,但您的里程可能会有所不同。
编辑:自从我写这个答案,媒体源扩展已经成熟,现在非常接近成为一个可行的选择。它们在大多数主要浏览器上都得到支持。IOS仍然是一个顽固的问题。
接下来,您需要理解视频点播(VOD)和视频直播是非常不同的。是的,它们都是视频,但问题不同,因此格式也不同。例如,如果你的计算机中的时钟运行比它应该的快1%,你将不会注意到一个视频点播。使用现场视频,您将尝试在视频发生之前播放视频。如果您想加入一个正在进行的实时视频流,您需要初始化解码器所必需的数据,因此它必须在流中重复,或在带外发送。通过视频点播,您可以读到他们寻求的文件的开头,直到您希望的任何一点。
现在让我们深入一点。
平台:
编解码器:
浏览器中视频直播常见的传递方式:
浏览器中视频点播常用的传递方式:
html5视频标记:
让我们来看看哪些浏览器支持什么格式
狩猎:
火狐
即
铬
MP4不能用于视频直播(注意:DASH是MP4的超集,所以不要与之混淆)。MP4被分成两块:moov和MDAT。mdat包含原始音频视频数据。但是它没有索引,所以没有moov,它是没用的。moov包含MDAT中所有数据的索引。但由于它的格式,它不能‘平坦’直到每个帧的时间戳和大小已知。它可以构造一个moov来‘扭曲’帧大小,但这是非常浪费带宽。
所以如果你想要到处递送,我们需要找到最小的公分母。如果不使用flash示例,您将看到这里没有LCD:
与LCD最接近的是使用HLS获得iOS用户,并为其他用户提供flash。我个人最喜欢的是对HLS进行编码,然后用flash为其他人播放HLS。你可以通过JW Player6在flash中播放HLS(或者像我一样在AS3中将自己的HLS写入FLV)
很快,最常见的方法将是iOS/Mac上的HLS和其他任何地方通过MSE的DASH(这也是Netflix即将要做的)。但我们还在等待大家升级自己的浏览器。你可能还需要一个单独的DASH/VP9用于Firefox(我知道Open264;它太烂了。它不能做主视频或高姿态视频。所以目前它是没用的)。
问题内容: 我真的很想了解使用node.js将ffmpeg实时输出流到HTML5客户端的最佳方法,因为有很多变量在起作用,而且我在这个领域没有很多经验,花了很多小时尝试不同的组合。 我的用例是: 1)IP摄像机RTSP H.264流由FFMPEG采集,并使用节点中的以下FFMPEG设置重新混合到mp4容器中,并输出到STDOUT。这仅在初始客户端连接上运行,因此部分内容请求不会尝试再次产生FFMP
我很难理解使用Node.js将ffmpeg的实时输出流到HTML5客户机的最佳方法,因为有许多变量在起作用,而且我在这方面没有太多经验,已经花了很多时间尝试不同的组合。 我的用例是: 1)IP视频摄像机RTSP H.264流由FFMPEG拾取,并使用node中的以下FFMPEG设置重新组合到mp4容器中,输出到stdout。这只在初始客户端连接上运行,这样部分内容请求就不会再次尝试生成FFMPEG
我有一个现有的应用程序,通过RTMP将实时音频从Flash客户端流到Wowza zerver。。。我能够将Flash客户端连接到该设备,并获得实时、低延迟的音频。 我想在PC、Android和iOS中连接一些基于HTML5的客户端,而不在客户端使用任何Flash。。。RTMP URI通常为“rtmp://myserver/live/mystream“我尝试从HTML5页面连接视频和音频标签,但没有
问题内容: 我有第三方WSDL,我需要用Java编写代码以使Web服务客户端调用第三方WSDL中的操作。现在,我已经使用Axis的WSDL2JAVA工具生成了客户端存根,并使用XMLbeans进行了数据绑定。 进行此JAVA的最佳方法是什么? 我阅读了有关SAAJ的文章,看起来这种方法会更细化吗? 除了使用WSDL2Java工具之外,还有什么其他方法可以生成代码。也许wsimport还有其他选择。
问题内容: 这是我正在从事的项目的一部分。我有两个桌面Java应用程序,一个运行在服务器上(具有真实IP),另一个运行在客户端上。我只想从连接到服务器应用程序的网络摄像头流式传输实时视频,然后在客户端应用程序上播放它。我想从多个摄像机进行流式传输。 我一直在寻找Xuggler,JMF,Red5,VLCj之间的日子。我只是不知道应该从哪里开始,因为我刚接触编程中的媒体。 我从哪里开始有什么想法? 提
我有一个blob数组(实际上是二进制数据--我可以表达它是最有效的。我现在使用Blobs,但可能或其他更好的方法)。每个Blob包含1秒的音频/视频数据。每秒都会生成一个新的Blob并将其追加到我的数组中。因此代码大致如下所示: 我的目标是将此音频/视频数据流式传输到HTML5元素。我知道Blob URL可以像下面这样生成和播放: