如何使用websocket进行h264实时流传输?

4

我看到的大多数websocket示例使用mp4或wbem容器数据。这里是一些示例javascript客户端代码:

var ms = new MediaSource();
...
var buf = ms.addSourceBuffer('video/mp4; codecs="avc1.64001E"');

在我的情况下,我的服务器发送原始的h264数据(仅视频,没有音频)。由于没有mp4 / avc容器来存储我的数据,我想知道为addSourceBuffer()定义参数的正确方式是什么。我是否应该像以下这样简单省略video/mp4标签?谢谢。

var buf = ms.addSourceBuffer('codecs="avc1.64001E"');

据我所知,为此必须预处理流。请阅读webtorrent.io源代码以找到执行此操作的组件... - Stepan Yakovenko
你是否曾经找到过解决方案? - Guru Prasad
1个回答

12

几个月前,我基于MediaSource开发了一个h264播放器。我没想到原来的回答之后这么久还会有人看到,所以我觉得应该编辑一下这篇文章,让它更有帮助性。顺便说一句,我不是专业人士,这篇文章只是基于我使用MediaSource API 的经验。欢迎评论指正我的错误。谢谢!

var buf = ms.addSourceBuffer('video/mp4; codecs="avc1.64001E"');

创建buf之后,我认为每次调用SourceBuffer.appendBuffer时,buf都期望接收一个分段的MP4数据块。

然而,您将RAW H264数据传递给它,我认为浏览器应该给出异常。

在我的情况下,我使用了ffmpeg从RTSP流中读取数据,将数据转换为fMP4格式(不进行编码),并将输出发送到stdout,然后让其他应用程序将数据发送到浏览器。(实际上,我使用了WebSocket。)

以下是参数:

ffmpeg -i rtsp://example.com/ -an -c:v copy -f mp4 \
       -movflags +frag_keyframe+empty_moov+default_base_moof pipe:1

我还想分享一件事。我不确定ffmpeg是如何工作的,但每次从stdout读取时它不会输出一个完整的片段。因此在我的后端程序中,我首先缓存了数据。下面是Java的伪代码:

byte[] oldbuf;
byte[] buffer = ReadDataFromFfmpegStdout();
if (buffer[4] == 'm' && buffer[5] == 'o' && buffer[6] == 'o' && buffer[7] == 'f') {
    send(oldbuf);            // the old buffer is a completed fragment now
    oldbuf = buffer;
} else {
    append(oldbuf, buffer);  // append data to the old buffer
}
你可以在GitHub上查看这个项目131/h264-live-player,它基于JavaScript H.264解码器mbebenita/Broadwaynode server-static.js的示例通过WebSocket流传输原始h264视频,客户端代码将其渲染在画布中。克隆该库,按照安装说明操作,在samples文件夹中放置您的h264文件,在server-static.js#L28中修改video_path为您的视频文件,执行node server-static.js即可在浏览器中播放视频。
请注意,Broadway仅支持基本配置的H.264编码格式。

3
「Broadway 只能使用基础配置文件。」这使得该库相当无用。 - Michael IV
@GuruPrasad 不,从 ffmpeg 的标准输出读取的字节数并不固定。但是可以通过查看开头来判断是否为新片段,这就是为什么我检查是否找到了 moof 的原因。(哦,我在写 if 块时犯了一个错误,写成了 moov,请查看 fMP4 的解释 https://dev59.com/rFsW5IYBdhLWcg3wSFfW#35180327)。实际上,我不知道应该初始化多少字节,这就是为什么我没有在伪代码中编写它的原因。在我的项目中,我假设每次从 ffmpeg 读取的字节数都小于5MB。 - IronBlood
为什么不直接将所有内容发送,让mediasource缓存它,而不是手动检测moov? - Ivan Kara
@IvanKara 很好的问题,事实上那是我最初的设计,但并没有像我记得的那样成功。我没有深入挖掘事情的运作方式,这个解决方案基于其他在线讨论和我的实践。 - IronBlood
@IvanKara 这是一个问题,所以在我的解决方案中,每个播放请求都需要一个ffmpeg实例。我没有达到1对多的目标,因为这种方法在我工作的公司被放弃了,被其他黑客替代了。其中一个IPC供应商使用C/S方式,浏览器通过Websockets向本地服务发送请求,然后该服务获取流数据并无边框地呈现视频,就像视频是浏览器的一部分,而浏览器根本不解码,也不是浏览器插件。回到您的搜索结果,我猜每个新客户端都需要一些常见的头文件。 - IronBlood
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接