【问题标题】:Why is FFMpeg outputting wrong NAL unit types? (javascript h264 livestream)为什么 FFMpeg 输出错误的 NAL 单元类型? (javascript h264 直播)
【发布时间】:2018-12-18 16:57:20
【问题描述】:

我正在尝试使用 h264 编码在浏览器中设置直播,其中 javascript 解码 h264 帧并将其绘制在 Canvas 元素(或使用 WebGL)上。

Broadway 和 Prism 都实现了解码类型 1、5、7 和 8 的 NAL 单元。

我目前的设置如下:

  • FFMpeg 输出带有 h264 数据的 MPEG-TS 流
  • 流通过管道传送到侦听端口 8084 的 netcat
  • NodeJS 中的 websocket 服务器将数据从端口 8084 管道传输到 8085 上的客户端
  • jsmpeg 库将 MPEG-TS 解码为单独的 NAL 单元
  • 独立的 NAL 单元由 Broadway 或 Prism 解码,输出到画布

我正在使用这个 FFMpeg 命令:

ffmpeg -f v4l2 -i /dev/video0 -r 15 -c:v h264_nvenc -pix_fmt yuv420p -b:v 500k -profile:v baseline -tune zerolatency -f mpegts - | nc -l -p 8084 127.0.0.1

问题是我得到的 NAL 单元是类型 9(或者可能是 6?),这是 javascript 正在接收的 NAL 单元之一的标头,采用 Base64 和二进制格式:

echo "AAAAAQnwAAAAAQYBBAAECBCAAAAAAWHg" | base64 -d | xxd -b
00000000: 00000000 00000000 00000000 00000001 00001001 11110000  ......
00000006: 00000000 00000000 00000000 00000001 00000110 00000001  ......
0000000c: 00000100 00000000 00000100 00001000 00010000 10000000  ......
00000012: 00000000 00000000 00000000 00000001 01100001 11100000  ....a.

Broadway 和 Prism 都不支持这些 NAL 单元类型。如何将 FFMpeg 配置为仅输出类型 1、5、7 和 8 的 NAL 单元?


编辑:我也尝试了以下命令:

ffmpeg -f v4l2 -i /dev/video0 -r 15 -c:v h264_nvenc -pix_fmt yuv420p \
    -b:v 500k -profile:v baseline -tune zerolatency \
    -movflags frag_keyframe+empty_moov -g 52 -f mp4 - \
    | nc -l -p 8084 127.0.0.1

它编码为 mp4,然后我尝试从三个零字节开始解析 NAL 单元。这些行看起来都类似于以下内容:

echo "AAAACAYBBABOCBCAAAARemHk4f8df1Su" | base64 -d | xxd -b
00000000: 00000000 00000000 00000000 00001000 00000110 00000001  ......
00000006: 00000100 00000000 01001110 00001000 00010000 10000000  ..N...
0000000c: 00000000 00000000 00010001 01111010 01100001 11100100  ...za.
00000012: 11100001 11111111 00011101 01111111 01010100 10101110  ....T.

即类型 6(第 5 个字节中的 00110),仍然不是所需的 NAL 单元类型。


更新:它对我不起作用的原因是 Javascript 中字符和字节之间的编码/解码问题。我已将working code on github 提供给其他可能想做类似事情的人。

关于 NAL 单元,事实证明 FFMpeg 输出的原始视频包含只有几个字节的类型 6,然后是具有帧数据的类型 1。类型 6 可以丢弃。感谢 cmets 并接受了对此的洞察力。

【问题讨论】:

  • 这些是 MPEG-TS 所需的访问单元分隔符 NALU。由于您的解码器不支持它们,因此您需要将它们去掉。
  • 或输出并使用原始 H264 比特流。
  • @Gyan 这些是流中唯一的数据包,没有其他类型。但是,我确实注意到,在标头 6 个字节之后,标头似乎又开始了,作为类型 6?我对这个了解不够。如果它们都是 9 型或 6 型,我该如何进行剥离?
  • @Gyan 我已经尝试在没有 MPEG-TS 解复用器的情况下使用 ... -f h264 - | nc ... 使用原始 264 流,但是,这也不是开箱即用的,因此它可能不包含正确的类型(我可能需要仔细检查)。它应该适用于-f mp4,但不适用于流式传输。
  • 您可以使用-movflags +empty_moov流式传输mp4

标签: ffmpeg video-streaming h.264


【解决方案1】:

“jsmpeg 库将 MPEG-TS 解码为单独的 NAL 单元”存在误解,因为它确实将传输流解码为 PES 数据包。 PES 数据包可以包含几个 NAL 单元。

删除访问单元分隔符很容易,因为它们实际上只有一个字节长。所以你可以跳过 0x0000000109f0(从你的第一个转储)并在偏移量 6 处处理下一个 NAL 单元。

那个是类型 6,意思是 补充增强信息。它也需要跳过,因为您的解码器不支持它(解码不需要它)。 SEI NAL 单元通常也很短,大约 10-50 个字节。所以只要寻找下一个起始码0x00000001...

【讨论】:

    猜你喜欢
    • 2020-08-25
    • 2022-12-04
    • 2015-08-07
    • 2018-03-18
    • 2014-06-24
    • 1970-01-01
    • 2011-08-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多