如何从RTMP流(avc1编码)中提取SPS和PPS?

时间:2018-12-11 17:08:18

标签: node.js video mp4 h.264 rtmp

我正在对Node Media Server进行扩展,以将传入流作为MP4保存到磁盘。对于这种向MP4的转换,我主要依靠Apple QuickTime Movie SpecificationThe ISO/IEC 14496-14 Specification(我在Rust-MP4 GitHub存储库中免费发现)和The HLS.js Source Code

我目前正在测试一个视频。一旦成功,我将开始尝试其他视频。对于我的用例,我只需要支持H.264视频和AAC音频。

当前,当建立RTMP连接时,我收到的前3个数据包是一致的:

  • 1个AMF metadata数据包(RTMP cid = 6),其中包含诸如视频宽度,视频高度,比特率,音频采样率等信息。
  • 1个audio数据包(RMTP cid = 4),其中包含7个字节的数据。我认为这是AAC配置数据包
  • 1个video数据包(RTMP cid = 5),其中包含46个字节的数据。我认为这是AVC配置数据包

编写MP4 moov原子时,有两个地方需要利用AMF元数据(可能位于这两个配置数据包中)以外的其他信息:

  • esds原子中,The HLS.js source附加了“ config”数据。我假设我只是将音频配置数据包中的整个7字节有效负载附加到此处
  • avcC原子中,The HLS.js source附加“ sps”和“ pps”数据。这是我问题的根源

关于这46个字节的解析,我在Node Media ServerHLS.js中发现了似乎解析相同数据的代码。这两段代码之间的区别在于,Node Media Server在数据包的开头期望额外的13个字节的数据。我收到的数据包似乎包含这13个字节,因此我仅遵循它们的先后顺序来提取widthheightprofilecompatlevel信息。特别是46个字节是:

[0x17, 0x00, 0x00, 0x00, 0x00, 0x01, 0x42, 0xc0, 0x1f, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x42, 0xc0, 0x1f, 0xa6, 0x11, 0x02, 0x80, 0xbf, 0xe5, 0x84, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x03, 0x00, 0xc2, 0x3c, 0x60, 0xc8, 0x46, 0x01, 0x00, 0x05, 0x68, 0xc8, 0x42, 0x32, 0xc8]

将此分解为我可以 容易 解析的字节(在使用指数哥伦布编码之前):

[
    0x17, // "frame type", specifies H.264 or HVEC
    0x00, 0x00, 0x00, 0x00, 0x01, // ignored. Reserved?
    0x42, // profile
    0xc0, // compat
    0x1f, // level
    0xff, // "info.nalu" (per Node Media Server source)
    0xe1, // "info.nb_sps" (per Node Media Server source)
    0x00, 0x19, // "nal size"
    // Above here are the bits exclusively seen by Node Media Server (specific to RTMP?)
    // Below here are the bits passed to HLS.js as "unit.data" (common to all AVC1 streams?):
    0x67, // "nal type"
    0x42, // profile (again?)
    0xc0, // compat (again?)
    0x1f, // level (again?)
    // Below here, data is not necessarily byte-aligned as Exponential Golomb encoding is used
    // ...
]

现在我遇到的问题是在创建moov原子(特别是avcC原子期间),我需要同时了解sps和{{ 1}}个字节。 From the HLS.js source似乎pps可能只是这个视频配置数据包减去前13个字节。但是,如何找到spspps实际上是此数据包的最后几个字节,我应该将其拆分到某个地方吗?会以其他小包的形式发送吗?如果需要两个视频数据包,我是否可以通过某种方式对其进行区分,以便知道哪个是pps,哪个是sps

如果我能弄清楚这最后一点,那么我应该完全写完pps数据包(此后,我只需要找出moov数据包的正确格式即可,应该有工作代码)

更新:为了进行记录,我只是检查了正在传递的第四个数据包,以查看其中是否包含mdat数据。重新连接到流约20次后,第四个数据包始终是pps数据包(RTMP cid = 5),但是数据包的大小在16000字节到21000字节之间。我怀疑这是合法的视频数据。

第二次更新::刚解析完SPS时,我刚刚检查了视频配置数据包中的偏移量,并且我位于字节23(video)上。因此,很可能PPS 实际上是在此字节数组的末尾,但是我不确定分隔符/标头有多少个字节(NAL类型,NAL长度等)以及多少个字节是实际的PPS。

0 个答案:

没有答案