h264rtpdepacketizer.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /**
  2. * Copyright (c) 2023 Paul-Louis Ageneau
  3. *
  4. * This Source Code Form is subject to the terms of the Mozilla Public
  5. * License, v. 2.0. If a copy of the MPL was not distributed with this
  6. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
  7. */
  8. #if RTC_ENABLE_MEDIA
  9. #include "h264rtpdepacketizer.hpp"
  10. #include "nalunit.hpp"
  11. #include "impl/internals.hpp"
  12. #include <algorithm>
  13. #include <cassert>
  14. #include <chrono>
  15. namespace rtc {
  16. const binary naluLongStartCode = {byte{0}, byte{0}, byte{0}, byte{1}};
  17. const binary naluShortStartCode = {byte{0}, byte{0}, byte{1}};
  18. const uint8_t naluTypeSTAPA = 24;
  19. const uint8_t naluTypeFUA = 28;
  20. H264RtpDepacketizer::H264RtpDepacketizer(Separator separator) : mSeparator(separator) {
  21. if (separator != Separator::StartSequence && separator != Separator::LongStartSequence &&
  22. separator != Separator::ShortStartSequence) {
  23. throw std::invalid_argument("Unimplemented H264 separator");
  24. }
  25. }
  26. H264RtpDepacketizer::~H264RtpDepacketizer() {}
  27. message_ptr H264RtpDepacketizer::reassemble(message_buffer &buffer) {
  28. if (buffer.empty())
  29. return nullptr;
  30. auto first = *buffer.begin();
  31. auto firstRtpHeader = reinterpret_cast<const RtpHeader *>(first->data());
  32. uint8_t payloadType = firstRtpHeader->payloadType();
  33. uint32_t timestamp = firstRtpHeader->timestamp();
  34. uint16_t nextSeqNumber = firstRtpHeader->seqNumber();
  35. binary frame;
  36. bool continuousFragments = false;
  37. for (const auto &packet : buffer) {
  38. auto rtpHeader = reinterpret_cast<const rtc::RtpHeader *>(packet->data());
  39. if (rtpHeader->seqNumber() < nextSeqNumber) {
  40. // Skip
  41. continue;
  42. }
  43. if (rtpHeader->seqNumber() > nextSeqNumber) {
  44. // Missing packet(s)
  45. continuousFragments = false;
  46. }
  47. nextSeqNumber = rtpHeader->seqNumber() + 1;
  48. auto rtpHeaderSize = rtpHeader->getSize() + rtpHeader->getExtensionHeaderSize();
  49. auto paddingSize = 0;
  50. if (rtpHeader->padding())
  51. paddingSize = std::to_integer<uint8_t>(packet->back());
  52. if (packet->size() <= rtpHeaderSize + paddingSize)
  53. continue; // Empty payload
  54. auto nalUnitHeader = NalUnitHeader{std::to_integer<uint8_t>(packet->at(rtpHeaderSize))};
  55. if (nalUnitHeader.unitType() == naluTypeFUA) {
  56. if (packet->size() <= rtpHeaderSize + paddingSize + 1)
  57. continue; // Empty FU-A
  58. auto nalUnitFragmentHeader =
  59. NalUnitFragmentHeader{std::to_integer<uint8_t>(packet->at(rtpHeaderSize + 1))};
  60. // RFC 6184: When set to one, the Start bit indicates the start of a fragmented NAL
  61. // unit. When the following FU payload is not the start of a fragmented NAL unit
  62. // payload, the Start bit is set to zero.
  63. if (nalUnitFragmentHeader.isStart()) {
  64. addSeparator(frame);
  65. frame.emplace_back(byte(nalUnitHeader.idc() | nalUnitFragmentHeader.unitType()));
  66. continuousFragments = true;
  67. }
  68. // RFC 6184: If a fragmentation unit is lost, the receiver SHOULD discard all following
  69. // fragmentation units in transmission order corresponding to the same fragmented NAL
  70. // unit.
  71. if (continuousFragments) {
  72. frame.insert(frame.end(), packet->begin() + rtpHeaderSize + 2,
  73. packet->end() - paddingSize);
  74. }
  75. // RFC 6184: When set to one, the End bit indicates the end of a fragmented NAL unit,
  76. // i.e., the last byte of the payload is also the last byte of the fragmented NAL unit.
  77. // When the following FU payload is not the last fragment of a fragmented NAL unit, the
  78. // End bit is set to zero.
  79. if (nalUnitFragmentHeader.isEnd())
  80. continuousFragments = false;
  81. } else {
  82. continuousFragments = false;
  83. if (nalUnitHeader.unitType() == naluTypeSTAPA) {
  84. auto offset = rtpHeaderSize + 1;
  85. while (offset + 2 < packet->size() - paddingSize) {
  86. auto naluSize = std::to_integer<uint16_t>(packet->at(offset)) << 8 |
  87. std::to_integer<uint16_t>(packet->at(offset + 1));
  88. offset += 2;
  89. if (offset + naluSize > packet->size() - paddingSize)
  90. throw std::runtime_error("H264 STAP-A size is larger than payload");
  91. addSeparator(frame);
  92. frame.insert(frame.end(), packet->begin() + offset,
  93. packet->begin() + offset + naluSize);
  94. offset += naluSize;
  95. }
  96. } else if (nalUnitHeader.unitType() > 0 && nalUnitHeader.unitType() < 24) {
  97. addSeparator(frame);
  98. frame.insert(frame.end(), packet->begin() + rtpHeaderSize,
  99. packet->end() - paddingSize);
  100. } else {
  101. throw std::runtime_error("Unknown H264 RTP Packetization");
  102. }
  103. }
  104. }
  105. return make_message(std::move(frame), createFrameInfo(timestamp, payloadType));
  106. }
  107. void H264RtpDepacketizer::addSeparator(binary &frame) {
  108. switch (mSeparator) {
  109. case Separator::StartSequence:
  110. [[fallthrough]];
  111. case Separator::LongStartSequence:
  112. frame.insert(frame.end(), naluLongStartCode.begin(), naluLongStartCode.end());
  113. break;
  114. case Separator::ShortStartSequence:
  115. frame.insert(frame.end(), naluShortStartCode.begin(), naluShortStartCode.end());
  116. break;
  117. default:
  118. throw std::invalid_argument("Invalid separator");
  119. }
  120. }
  121. } // namespace rtc
  122. #endif // RTC_ENABLE_MEDIA