WebRTC:编码器实现中的 RTPFragmentationHeader 是什么?

SMU*_*hah 3 video video-streaming h.264 webrtc openh264

我已修改h264_encoder_impl为使用基于 nvidia 网格的硬件编码器。这是通过用 Nvidia API 调用替换 OpenH264 特定调用来完成的。编码流可以成功写入文件,但写入_buffer_sizeencoded_image_还不够,RTPFragmentationHeader还需要填充。

// RtpFragmentize(EncodedImage* encoded_image,
//                       std::unique_ptr<uint8_t[]>* encoded_image_buffer,
//                       const VideoFrameBuffer& frame_buffer,
//                       SFrameBSInfo* info,
//                      RTPFragmentationHeader* frag_header)

// encode
openh264_->Encode(input, &info /*out*/);

// fragmentize ?
RtpFragmentize(&encoded_image_ /*out*/, &encoded_image_buffer_, *frame_buffer, 
               &info, &frag_header /*out*/); 

// ...

// send 
encoded_image_callback_->OnEncodedImage(encoded_image_, &codec_specific, &frag_header);
Run Code Online (Sandbox Code Playgroud)

当前Openh264根据实施填充frag_headerRTPFragmentize()和VP8不同填充它。我可以看到 NAL 单元和层也计算的东西,encoded_image->_length但我不知道如何。

我在任何地方都找不到关于它的任何文档。我只有 VP8 和 OpenH264 实现。

那么什么是RTPFragmentationHeader?它有什么作用?什么是encoded_image->_length?使用自定义H264编码器时如何正确填充?我可以找到 startcode 但接下来呢?如何填满它的所有成员?

SMU*_*hah 6

通过后会RTPFragmentize()h264_encoder_impl我已经想通了。

在一个编码帧中有多个 NALU。有不同的 NALU,包括 AUD、SPS (67)、PPS (68) 和 IDR。每个 NALU 由 4 字节起始代码分隔,即00 00 00 01.

对于 OpenH264,第一帧的标题看起来像这样

[ 00 00 00 01 67 42 c0 20 8c 8d 40 20 03 09 00 f0  
 88 46 a0 00 00 00 01 68 ce 3c 80] 00 00 00 01 .. 

您可以看到粗体的起始代码。只有方括号之间的字节属于报头,最后的起始码用于帧数据。

RTPFragmentationHeader 对于以上:

frag_header->fragmentationVectorSize = 3     // 2 fragments for header
                                             // 3rd fragment for frame buffer

frag_header->fragmentationOffset[0]  = 4     
frag_header->fragmentationLength[0]  = 15

frag_header->fragmentationOffset[1]  = 23    // 4 + 15 + sizeof(startcode)
frag_header->fragmentationLength[1]  = 4    

frag_header->fragmentationOffset[2]  = 31   
frag_header->fragmentationLength[2]  = 43218 // last fragment is frame buffer
Run Code Online (Sandbox Code Playgroud)

下一帧总是只有一个片段,如下所示

00 00 00 01 67 b8 .. .. ..
Run Code Online (Sandbox Code Playgroud)

encoded_image->_length是实际编码帧缓冲区的
encoded_image->_size大小,是编码帧缓冲区的最大大小。

OpenH264 API 提供编码帧中的 NALU 数量,用于计算片段,而我使用的 API 仅提供标头及其大小,无论标头是否实际与帧一起添加。仅针对标头大小搜索帧字节允许正确计算碎片。

这样做最终发送了编码数据,并在客户端浏览器上正确解码。

更新:本质上,我不得不RTPFragmentize()完全跳过,因为它是专门为 OpenH264 制作的,并frag_header根据上述观察结果计算自己。