为什么FFMpeg输出错误的NAL单元类型?(javascript h264 livestream)

为什么FFMpeg输出错误的NAL单元类型?(javascript h264 livestream),ffmpeg,video-streaming,h.264,Ffmpeg,Video Streaming,H.264,我正在尝试使用h264编码在浏览器中设置livestream,其中javascript解码h264帧并将其绘制在画布元素上(或使用WebGL) 百老汇和Prism均实现1、5、7和8型解码NAL单元 我当前的设置如下: FFMpeg输出带有h264数据的MPEG-TS流 该流通过管道传输到netcat,netcat在端口8084上侦听 NodeJS中的websocket服务器将数据从端口8084传输到8085上的客户端 jsmpeg库将MPEG-TS解码为单独的NAL单元 单独的NAL单元由输

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

百老汇和Prism均实现1、5、7和8型解码NAL单元

我当前的设置如下:

  • FFMpeg输出带有h264数据的MPEG-TS流
  • 该流通过管道传输到netcat,netcat在端口8084上侦听
  • 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
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
问题是我得到的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.
百老汇和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 -f mpegts - | nc -l -p 8084 127.0.0.1
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中字符和字节之间的编码/解码问题。我已经为其他可能想做类似事情的人提出了建议


关于NAL单元,FFMpeg输出的原始视频包含只有几个字节的类型6,然后是包含帧数据的类型1。类型6可以丢弃。多亏了这些评论和公认的答案,才能深入了解这一点。

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

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


这是第6类,这意味着补充增强信息。也需要跳过它,因为解码器不支持它(解码不需要它)。SEI NAL单位通常也很短,约10-50字节。因此,只需查找下一个开始代码0x00000001…

这些是MPEG-TS所需的访问单元分隔符NALU。由于您的解码器不支持它们,您需要将它们去掉。或者输出并使用原始H264位流。@Gyan这些是流中唯一的数据包,没有其他类型。但是,我确实注意到,在头中插入6个字节后,头似乎再次启动,如类型6?我对这件事了解得还不够。如果它们都是9型或6型,我该如何进行剥离呢?@Gyan我已经尝试使用
使用原始264流-f h264-| nc…
没有MPEG-TS解复用器,但是,这也不能开箱即用,因此它可能也不包含正确的类型(我可能需要再次检查)。它应该适用于
-f mp4
,但不适用于流媒体。您可以使用
-movflags+empty\u moov