WebRTC: Что такое RTPFragmentationHeader в реализации кодировщика?
Я модифицировал h264_encoder_impl
использовать аппаратный кодировщик nvidia grid. Это делается путем замены определенных вызовов OpenH264 вызовами API Nvidia. Закодированный поток может быть успешно записан в файл, но запись _buffer
а также _size
из encoded_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);
Текущая реализация на основе Openh264 заполняет frag_header
в RTPFragmentize()
и VP8 заполняет это по-другому. Я могу увидеть что-то с NAL Untis и слоев, который также рассчитывает encoded_image->_length
но я понятия не имею как.
Я не могу найти какую-либо документацию по нему нигде. Реализации VP8 и OpenH264 - это все, что у меня есть.
Так что же RTPFragmentationHeader
? Что это делает? Что такое encoded_image->_length
? Как правильно его заполнить при использовании нестандартного кодера H264? Я могу найти стартовый код, но что дальше? Как заполнить всех своих членов?
1 ответ
После прохождения 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
Следующие кадры всегда имели только один фрагмент, который выглядел следующим образом
00 00 00 01 67 b8 .. .. ..
encoded_image->_length
размер фактического закодированного кадра буфера иencoded_image->_size
максимальный размер буфера закодированного кадра.
OpenH264 API дает количество NALU в кодированном фрейме, которое используется для вычисления фрагментов, в то время как API, который я использовал, предоставлял только заголовок и его размер, независимо от того, был ли заголовок фактически добавлен с фреймом или нет. Поиск байтов кадра только по размеру заголовка позволил правильно рассчитать фрагментацию.
После этого, наконец, были отправлены закодированные данные, и они были правильно декодированы в браузере клиента.
Обновление: по сути, мне пришлось пропустить RTPFragmentize()
целиком, потому что это сделано специально для OpenH264, и рассчитать frag_header
сам на основе вышеуказанных наблюдений.