gpt4 book ai didi

android - 如何将Android MediaCodec编码的H264打包成RTP包

转载 作者:行者123 更新时间:2023-11-30 00:57:29 24 4
gpt4 key购买 nike

如何正确地将 H264 字节流打包到 RTP 数据包中,以便我可以使用 FFMPEG 接收帧?

当我启动 FFMPEG 接收器时,它会输出大量如下错误:

Invalid UE golomb code
[h264 @ 0xd63060] pps_id 3199971767 out of range
[h264 @ 0xd63060] slice type 32 too large at -1
[h264 @ 0xd63060] decode_slice_header error
[h264 @ 0xd63060] non-existing PPS 0 referenced
[h264 @ 0xd63060] decode_slice_header error
[h264 @ 0xd63060] no frame!
[h264 @ 0xd63060] decode_slice_header error
[h264 @ 0xd63060] Unknown NAL code: 0 (0 bits)
[h264 @ 0xd63060] no frame!
[h264 @ 0xd63060] non-existing PPS 0 referenced

这是我使用的 SDP 文件:

c=IN IP4 192.168.2.30
t=0 0
m=video 51372 RTP/AVP 96
a=rtpmap:96 H264/90000
a=recv only

pps_id 错误很奇怪,它好像在寻找下一个 PPS,但找不到它,尽管我尝试将 PPS 嵌入到每个 NALU 中。

我一直在阅读 RFC 6184并试图理解它。但是我觉得我还是不太明白H264和RTP是如何交互的。目前我正在尝试对来自相机的像素进行编码,并通过 RTP 在网络上传输 1920x1080 H264 编码帧,然后由 FFMPEG 接收并解码。我正在用 Java 组装 RTP 和 FU-A header ,并在它们对于 MTU 来说太大时对 NALU 进行分段。

我一直在 Wireshark 中密切关注流,这是我的第一个数据包的输出:

Real-Time Transport Protocol
10.. .... = Version: RFC 1889 Version (2)
..0. .... = Padding: False
...0 .... = Extension: False
.... 0000 = Contributing source identifiers count: 0
1... .... = Marker: True
Payload type: DynamicRTP-Type-96 (96)
Sequence number: 0
Timestamp: 2727179012
Synchronization Source identifier: 0x00000000 (0)
H.264
NAL unit header or first byte of the payload
0... .... = F bit: No bit errors or other syntax violations
.00. .... = Nal_ref_idc (NRI): 0
...0 0000 = Type: Undefined (0)
H264 NAL Unit Payload

我不明白为什么第一个有效负载的 NALU 类型为 0。不过,这是我的第二个数据包:

Real-Time Transport Protocol
10.. .... = Version: RFC 1889 Version (2)
..0. .... = Padding: False
...0 .... = Extension: False
.... 0000 = Contributing source identifiers count: 0
0... .... = Marker: False
Payload type: DynamicRTP-Type-96 (96)
Sequence number: 1
Timestamp: 2727179019
Synchronization Source identifier: 0x00000000 (0)
H.264
FU identifier
0... .... = F bit: No bit errors or other syntax violations
.11. .... = Nal_ref_idc (NRI): 3
...1 1100 = Type: Fragmentation unit A (FU-A) (28)
FU Header
1... .... = Start bit: the first packet of FU-A picture
.0.. .... = End bit: Not the last packet of FU-A picture
..0. .... = Forbidden bit: 0
...0 0101 = Nal_unit_type: Coded slice of an IDR picture (5)
H264 NAL Unit Payload
0000 0000 0000 0000 0000 0000 0000 0001 0110 0101 1011 1000 0000 0100 0000 010. = first_mb_in_slice: 3000762881
.... ...1 = slice_type: P (P slice) (0)
0011 1... = pic_parameter_set_id: 6

所以我认为最后一个数据包是一个 I 帧?这是开始 fragment 和结束 fragment 之间的 fragment :

Real-Time Transport Protocol
10.. .... = Version: RFC 1889 Version (2)
..0. .... = Padding: False
...0 .... = Extension: False
.... 0000 = Contributing source identifiers count: 0
0... .... = Marker: False
Payload type: DynamicRTP-Type-96 (96)
Sequence number: 1
Timestamp: 2727179019
Synchronization Source identifier: 0x00000000 (0)
H.264
FU identifier
0... .... = F bit: No bit errors or other syntax violations
.11. .... = Nal_ref_idc (NRI): 3
...1 1100 = Type: Fragmentation unit A (FU-A) (28)
FU Header
0... .... = Start bit: Not the first packet of FU-A picture
.0.. .... = End bit: Not the last packet of FU-A picture
..0. .... = Forbidden bit: 0
...0 0101 = Nal_unit_type: Coded slice of an IDR picture (5)

当然这里是假定的 I-Frame 的最后一个数据包:

Real-Time Transport Protocol
10.. .... = Version: RFC 1889 Version (2)
..0. .... = Padding: False
...0 .... = Extension: False
.... 0000 = Contributing source identifiers count: 0
1... .... = Marker: True
Payload type: DynamicRTP-Type-96 (96)
Sequence number: 1
Timestamp: 2727179019
Synchronization Source identifier: 0x00000000 (0)
H.264
FU identifier
0... .... = F bit: No bit errors or other syntax violations
.11. .... = Nal_ref_idc (NRI): 3
...1 1100 = Type: Fragmentation unit A (FU-A) (28)
FU Header
0... .... = Start bit: Not the first packet of FU-A picture
.1.. .... = End bit: the last packet of FU-A picture
..0. .... = Forbidden bit: 0
...0 0101 = Nal_unit_type: Coded slice of an IDR picture (5)

现在这是编码器给我的下一个字节的数据包:

Real-Time Transport Protocol
10.. .... = Version: RFC 1889 Version (2)
..0. .... = Padding: False
...0 .... = Extension: False
.... 0000 = Contributing source identifiers count: 0
0... .... = Marker: False
Payload type: DynamicRTP-Type-96 (96)
Sequence number: 2
Timestamp: 2727179089
Synchronization Source identifier: 0x00000000 (0)
H.264
FU identifier
0... .... = F bit: No bit errors or other syntax violations
.11. .... = Nal_ref_idc (NRI): 3
...1 1100 = Type: Fragmentation unit A (FU-A) (28)
FU Header
1... .... = Start bit: the first packet of FU-A picture
.0.. .... = End bit: Not the last packet of FU-A picture
..0. .... = Forbidden bit: 0
...0 0001 = Nal_unit_type: Coded slice of a non-IDR picture (1)
H264 NAL Unit Payload
0000 0000 0000 0000 0000 0000 0000 0001 0110 0001 1110 0000 0010 0000 0001 100. = first_mb_in_slice: 2968522763
.... ...0 0111 .... = slice_type: B (B slice) (6)
.... 0001 110. .... = pic_parameter_set_id: 13

这部分让我感到困惑,当相机静止时,编码器给我越来越小的 NALU 和未定义的类型,我不完全确定为什么下面的数据包会作为一个完整的 NALU 发送到 FFMPEG。

Real-Time Transport Protocol
10.. .... = Version: RFC 1889 Version (2)
..0. .... = Padding: False
...0 .... = Extension: False
.... 0000 = Contributing source identifiers count: 0
1... .... = Marker: True
Payload type: DynamicRTP-Type-96 (96)
Sequence number: 36
Timestamp: 2727180258
Synchronization Source identifier: 0x00000000 (0)
H.264
NAL unit header or first byte of the payload
0... .... = F bit: No bit errors or other syntax violations
.00. .... = Nal_ref_idc (NRI): 0
...0 0000 = Type: Undefined (0)
H264 NAL Unit Payload

我正在使用 Android MediaCodec 编码器,这里是我配置编码器的一些代码:

mediaCodec = MediaCodec.createByCodecName("OMX.Nvidia.h264.encoder");
mediaFormat = MediaFormat.createVideoFormat("video/avc", 1920, 1080);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 125000);
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 0);
mediaFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 1920 * 1080);

编码器是给我整个访问单元还是只给我 NALU?

这是我的逻辑:

  • 如果帧大小大于 MTU,则帧将被分段。
  • 当我发送起始 FU-A header 时,我将起始位设置为 1。
  • 当我发送帧的最后一个分段字节时,我将 RTP header 中的标记位设置为 1,并将 FU-A header 中的结束分段位设置为 1。
  • 开始和结束 fragment 之间的 FU-A header 将开始和结束位设置为 0。
  • 除最后一个数据包外,标记始终设置为 0。
  • 如果 NALU 可以容纳在 MTU 中,则发送整个帧。
  • 对于每个发送的 NALU,我都会迭代 RTP header 的序列号。
  • 随着每个 NALU 的发送,我都会为 RTP header 获得一个新的时间戳。
  • 在对 NALU 进行分段之前,我保存了 NALU 类型并将其插入到 FU-A header 中

我觉得我很接近,但它显然不适用于任何 RTP 接收器。我很欣赏关于此事的任何想法或想法。

谢谢,

最佳答案

我终于设法解决了,我的数据包配置不正确。

  • 我必须迭代每个数据包的序列号。
  • 我必须为每个 NALU 而不是每个数据包设置时间戳。
  • 我必须去除 00 00 01 的 NALU 前缀 ** 在索引 4 之后发送字节。
  • 我的 header 中的按位运算不正确。

我什至可以在流的中间启动 FFmpeg,它可以工作!

关于android - 如何将Android MediaCodec编码的H264打包成RTP包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39928847/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com