为什么 FFMpeg 输出错误的 NAL 单元类型? (javascript h264 直播)
Why is FFMpeg outputting wrong NAL unit types? (javascript h264 livestream)
我正在尝试使用 h264 编码在浏览器中设置直播,其中 javascript 解码 h264 帧并将其绘制在 Canvas-element 上(或使用 WebGL)。
Broadway 和 Prism 都实现了对类型 1、5、7 和 8 的 NAL 单元的解码。
我目前的设置如下:
- FFMpeg 输出带有 h264 数据的 MPEG-TS 流
- 流通过管道传输到侦听端口 8084 的 netcat
- NodeJS 中的 websocket 服务器通过管道将数据从端口 8084 传输到 8085 上的客户端
- jsmpeg 库将 MPEG-TS 解码为单独的 NAL 单元
- 单独的 NAL 单元由输出到 canvas
的 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 单元之一的 header,在 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 中字符和字节之间的 encoding/decoding 问题。我已经为可能想要做类似事情的其他人设置了 working code on github。
关于 NAL 单元,事实证明,FFMpeg 输出的原始视频包含只有几个字节的类型 6,然后是具有帧数据的类型 1。类型 6 可以丢弃。感谢评论和接受的答案,以便深入了解这一点。
"jsmpeg library decodes MPEG-TS into separate NAL units"中有一个误解,因为它真的将传输流解码为PES数据包。 PES 数据包可以包含 多个 NAL 单元。
删除访问单元定界符很容易,因为它们实际上只有一个字节长。所以你可以跳过 0x0000000109f0(从你的第一个转储)并处理偏移量 6 处的下一个 NAL 单元。
那个是6型,意思是补充增强信息。它也需要被跳过,因为你的解码器不支持它(它不是解码所必需的)。 SEI NAL 单元通常也很短,大约 10-50 字节。所以只要寻找下一个起始码 0x00000001...
我正在尝试使用 h264 编码在浏览器中设置直播,其中 javascript 解码 h264 帧并将其绘制在 Canvas-element 上(或使用 WebGL)。
Broadway 和 Prism 都实现了对类型 1、5、7 和 8 的 NAL 单元的解码。
我目前的设置如下:
- FFMpeg 输出带有 h264 数据的 MPEG-TS 流
- 流通过管道传输到侦听端口 8084 的 netcat
- NodeJS 中的 websocket 服务器通过管道将数据从端口 8084 传输到 8085 上的客户端
- jsmpeg 库将 MPEG-TS 解码为单独的 NAL 单元
- 单独的 NAL 单元由输出到 canvas 的 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 单元之一的 header,在 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 中字符和字节之间的 encoding/decoding 问题。我已经为可能想要做类似事情的其他人设置了 working code on github。
关于 NAL 单元,事实证明,FFMpeg 输出的原始视频包含只有几个字节的类型 6,然后是具有帧数据的类型 1。类型 6 可以丢弃。感谢评论和接受的答案,以便深入了解这一点。
"jsmpeg library decodes MPEG-TS into separate NAL units"中有一个误解,因为它真的将传输流解码为PES数据包。 PES 数据包可以包含 多个 NAL 单元。
删除访问单元定界符很容易,因为它们实际上只有一个字节长。所以你可以跳过 0x0000000109f0(从你的第一个转储)并处理偏移量 6 处的下一个 NAL 单元。
那个是6型,意思是补充增强信息。它也需要被跳过,因为你的解码器不支持它(它不是解码所必需的)。 SEI NAL 单元通常也很短,大约 10-50 字节。所以只要寻找下一个起始码 0x00000001...