【问题标题】:FFmpeg outputs corrupted NAL unitsFFmpeg 输出损坏的 NAL 单元
【发布时间】:2020-08-25 09:25:10
【问题描述】:

我需要将 Windows PC 的屏幕流式传输到 Android。我打算使用 FFmpeg 捕获屏幕并使用 H.264 编解码器进行编码,通过 RTP 发送流,最后使用MediaCodec 解码视频并将其显示在 SurfaceView 上。

我尝试了以下 FFmpeg 命令:

ffmpeg -f gdigrab -i desktop -an -video_size 1920x1080 -f rtp rtp://192.168.0.12:23000

但是,生成的所有 NAL 单元似乎都已损坏,因为:

  1. NAL单元头的forbidden_​​zero_bit(最高有效位)为1。例如下图所示的NAL单元头(0x00 0x00 0x01之后的字节)为0xB6,那么显然最高有效位是等于 1。

  2. NAL 单元中的很多字节等于 0xFF。我真的不知道他们是否应该是这样的,他们对我来说似乎很奇怪。

这是 FFmpeg 输出的 NAL 单元之一的开头,使用 Wireshark 捕获:

0000   00 00 01 b6 56 5a bc 7c fd de ea e7 72 ff ff ff
0010   ff ff ff ef 7d d7 ff bd 6f 5f ff ee d7 ba bf ff
0020   fd df bd 7b a5 ff ff ff ff ff fd d7 78 bf fd e2
0030   ff ff ff ff ff ff 7b fe eb ff ff ff ff ff ff ff
0040   fe f5 ff ff ff ff fd b4 c6 17 45 ba 7e f4 e9 fb
0050   d7 ef 7f de ff ff ff ff fd d7 ff 79 ff bc ff ff
0060   ff ff ff ff ff ba ff ff ff ff ff ff ff 7b ff f7
0070   27 ff ff ff de ff ff ff ff ff ff ff fe ef fd c7
0080   de ef 6f 7b db dd db 74 de dd 37 bd ef ff ff ff
0090   ff ff ff ff 77 bb ff 75 ee ee bf ff ff fb dd df
00a0   ee d7 79 5e 5f ff ff ff fb 9b ff fb d7 ff ff ff
00b0   de bf ff ff ff ff ff ff ff ff fb 9d ef bd df 00
00c0   00 8f 03 ef ff ff ff ff ff ff ff 7b f7 03 1f fd
00d0   ed e5 ba ef 5d d5 cc 5f ff ff ff ff ff ff ff ff
00e0   ff ff ff ee 06 37 be f4 f6 eb ff ff ff ff ff ff
00f0   ff ff ff ff ff ff ff ba 5f f7 af ff ff ff ff ff
0100   ff ff ff ff ff ff ff ff fd d3 fb c2 ef 1b dd ed
...
...
...

Screenshot from Wireshark (same NAL unit)

我还尝试在 FFmpeg 中明确指定视频编解码器,如下所示:

ffmpeg -f gdigrab -i desktop -an -vcodec libx264 -f rtp rtp://192.168.0.12:23000

在这种情况下,我没有得到附件 B 样式的 NAL 单元,而是 AVCC 样式的单元(没有 0x00 0x00 0x01 分隔符,但前面有它们的长度,如 here 所述)。

对于 AVCC NAL 单元,我真的不明白一个结束和另一个开始的地方,以及上面链接的问题中提到的“额外数据”在哪里。

综上,我想知道的如下:

  1. 为什么第一个命令输出的 NAL 单元损坏了?

  2. 据我了解 (from here),您必须将单独的 NAL 单元提供给 MediaCodec 以进行解码。那么,如何将 AVCC 格式的 NAL 单元彼此分开?

  3. 在将视频编解码器指定为 libx264 时,我能否以某种方式强制 FFmpeg 输出附件 B 样式的 NAL 单元而不是 AVCC 单元?

  4. 是否有更直接的方法在 Windows 上捕获屏幕、编码、将流发送到 Android 设备并在我的应用程序中显示视频? (可能是我没有注意到的库或 API)

【问题讨论】:

  • 你成功了吗?我目前正在打完全相同的战斗。当我输入全帧数据时,我确实得到了输出,但 MediaCodec 在输出到表面之前缓冲了大约 15 帧,这意味着我得到了巨大的延迟。在我剪切帧数据并在 0x00 0x00 0x01 序列之间输入数据后输入 NAL 单元时,输出损坏。
  • @Hey'Youssef 还没有。明天我会回来的。您是否也在使用 ffmpeg 来捕获 Windows 机器的屏幕?如果是这样,您能否分享您使用的确切命令?

标签: android ffmpeg h.264


【解决方案1】:

1) 为什么第一个命令输出的 NAL 单元损坏了?

那里没有损坏。除了原始 h264 数据之外,RTP 数据包中还有其他信息。该信息可能包含字节序列00 00 01,并且不表示后面有 NALU。

2)据我了解(从这里),您必须提供单独的 NAL 单元到 MediaCodec 进行解码。那么,我如何在 AVCC 格式相互转换?

你解析流,包括协议开销

3) 我能以某种方式强制 FFmpeg 输出附件 B 样式的 NAL 单元吗 将视频编解码器指定为 libx264 而不是 AVCC?

这不符合 RTP 规范。如果您使用 RTP,您将获得 AVCC 起始长度大小值。

4) 是否有更直接的方法来捕获屏幕 Windows,编码,将流发送到 Android 设备和 在我的应用中显示视频? (也许是一个库或 API 逃避我的注意)

这是一个相当自以为是的问题。 RTP 非常简单。但也可能有其他选择,各有利弊。

【讨论】:

  • 实际上,仿真预防字节用于确保 00 00 01 只能在 NAL 单元之前找到(在附件 B 样式单元中)。而且它们肯定会损坏,因为正如我在问题中解释的那样,如果 disabled_zero_bit 等于 1,则意味着 NAL 单元已引入错误。可以在这里找到一个非常好的解释:https://yumichan.net/video-processing/video-compression/introduction-to-h264-nal-unit/
  • You parse the stream, including the protocol overhead 你的意思是我应该将 RTP 数据包(包括它们的标头)直接传递给 MediaCodec?
猜你喜欢
  • 2022-12-04
  • 2021-09-07
  • 2021-12-14
  • 2011-08-29
  • 2018-12-18
  • 2021-07-20
  • 1970-01-01
  • 2019-03-14
  • 2016-02-06
相关资源
最近更新 更多