av1rtppacketizer.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  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 "av1rtppacketizer.hpp"
  10. #include "impl/internals.hpp"
  11. namespace rtc {
  12. const auto payloadHeaderSize = 1;
  13. const auto zMask = byte(0b10000000);
  14. const auto yMask = byte(0b01000000);
  15. const auto nMask = byte(0b00001000);
  16. const auto wBitshift = 4;
  17. const auto obuFrameTypeMask = byte(0b01111000);
  18. const auto obuFrameTypeBitshift = 3;
  19. const auto obuHeaderSize = 1;
  20. const auto obuHasExtensionMask = byte(0b00000100);
  21. const auto obuHasSizeMask = byte(0b00000010);
  22. const auto obuFrameTypeSequenceHeader = byte(1);
  23. const auto obuTemporalUnitDelimiter = std::vector<byte>{byte(0x12), byte(0x00)};
  24. const auto oneByteLeb128Size = 1;
  25. const uint8_t sevenLsbBitmask = 0b01111111;
  26. const uint8_t msbBitmask = 0b10000000;
  27. std::vector<binary_ptr> extractTemporalUnitObus(binary_ptr message) {
  28. std::vector<shared_ptr<binary>> obus{};
  29. if (message->size() <= 2 || (message->at(0) != obuTemporalUnitDelimiter.at(0)) ||
  30. (message->at(1) != obuTemporalUnitDelimiter.at(1))) {
  31. return obus;
  32. }
  33. size_t messageIndex = 2;
  34. while (messageIndex < message->size()) {
  35. if ((message->at(messageIndex) & obuHasSizeMask) == byte(0)) {
  36. return obus;
  37. }
  38. if ((message->at(messageIndex) & obuHasExtensionMask) != byte(0)) {
  39. messageIndex++;
  40. }
  41. // https://aomediacodec.github.io/av1-spec/#leb128
  42. uint32_t obuLength = 0;
  43. uint8_t leb128Size = 0;
  44. while (leb128Size < 8) {
  45. auto leb128Index = messageIndex + leb128Size + obuHeaderSize;
  46. if (message->size() < leb128Index) {
  47. break;
  48. }
  49. auto leb128_byte = uint8_t(message->at(leb128Index));
  50. obuLength |= ((leb128_byte & sevenLsbBitmask) << (leb128Size * 7));
  51. leb128Size++;
  52. if (!(leb128_byte & msbBitmask)) {
  53. break;
  54. }
  55. }
  56. obus.push_back(std::make_shared<binary>(message->begin() + messageIndex,
  57. message->begin() + messageIndex + obuHeaderSize +
  58. leb128Size + obuLength));
  59. messageIndex += obuHeaderSize + leb128Size + obuLength;
  60. }
  61. return obus;
  62. }
  63. /*
  64. * 0 1 2 3 4 5 6 7
  65. * +-+-+-+-+-+-+-+-+
  66. * |Z|Y| W |N|-|-|-|
  67. * +-+-+-+-+-+-+-+-+
  68. *
  69. * Z: MUST be set to 1 if the first OBU element is an
  70. * OBU fragment that is a continuation of an OBU fragment
  71. * from the previous packet, and MUST be set to 0 otherwise.
  72. *
  73. * Y: MUST be set to 1 if the last OBU element is an OBU fragment
  74. * that will continue in the next packet, and MUST be set to 0 otherwise.
  75. *
  76. * W: two bit field that describes the number of OBU elements in the packet.
  77. * This field MUST be set equal to 0 or equal to the number of OBU elements
  78. * contained in the packet. If set to 0, each OBU element MUST be preceded by
  79. * a length field. If not set to 0 (i.e., W = 1, 2 or 3) the last OBU element
  80. * MUST NOT be preceded by a length field. Instead, the length of the last OBU
  81. * element contained in the packet can be calculated as follows:
  82. * Length of the last OBU element =
  83. * length of the RTP payload
  84. * - length of aggregation header
  85. * - length of previous OBU elements including length fields
  86. *
  87. * N: MUST be set to 1 if the packet is the first packet of a coded video sequence, and MUST be set
  88. * to 0 otherwise.
  89. *
  90. * https://aomediacodec.github.io/av1-rtp-spec/#44-av1-aggregation-header
  91. *
  92. **/
  93. std::vector<binary_ptr> AV1RtpPacketizer::packetizeObu(binary_ptr message,
  94. uint16_t maximumFragmentSize) {
  95. std::vector<shared_ptr<binary>> payloads{};
  96. size_t messageIndex = 0;
  97. if (message->size() < 1) {
  98. return payloads;
  99. }
  100. // Cache sequence header and packetize with next OBU
  101. auto frameType = (message->at(0) & obuFrameTypeMask) >> obuFrameTypeBitshift;
  102. if (frameType == obuFrameTypeSequenceHeader) {
  103. sequenceHeader = std::make_shared<binary>(message->begin(), message->end());
  104. return payloads;
  105. }
  106. size_t messageRemaining = message->size();
  107. while (messageRemaining > 0) {
  108. auto obuCount = 1;
  109. auto metadataSize = payloadHeaderSize;
  110. if (sequenceHeader != nullptr) {
  111. obuCount++;
  112. metadataSize += /* 1 byte leb128 */ 1 + int(sequenceHeader->size());
  113. }
  114. auto payload = std::make_shared<binary>(
  115. std::min(size_t(maximumFragmentSize), messageRemaining + metadataSize));
  116. auto payloadOffset = payloadHeaderSize;
  117. payload->at(0) = byte(obuCount) << wBitshift;
  118. // Packetize cached SequenceHeader
  119. if (obuCount == 2) {
  120. payload->at(0) ^= nMask;
  121. payload->at(1) = byte(sequenceHeader->size() & sevenLsbBitmask);
  122. payloadOffset += oneByteLeb128Size;
  123. std::memcpy(payload->data() + payloadOffset, sequenceHeader->data(),
  124. sequenceHeader->size());
  125. payloadOffset += int(sequenceHeader->size());
  126. sequenceHeader = nullptr;
  127. }
  128. // Copy as much of OBU as possible into Payload
  129. auto payloadRemaining = payload->size() - payloadOffset;
  130. std::memcpy(payload->data() + payloadOffset, message->data() + messageIndex,
  131. payloadRemaining);
  132. messageRemaining -= payloadRemaining;
  133. messageIndex += payloadRemaining;
  134. // Does this Fragment contain an OBU that started in a previous payload
  135. if (payloads.size() > 0) {
  136. payload->at(0) ^= zMask;
  137. }
  138. // This OBU will be continued in next Payload
  139. if (messageIndex < message->size()) {
  140. payload->at(0) ^= yMask;
  141. }
  142. payloads.push_back(payload);
  143. }
  144. return payloads;
  145. }
  146. AV1RtpPacketizer::AV1RtpPacketizer(AV1RtpPacketizer::Packetization packetization,
  147. shared_ptr<RtpPacketizationConfig> rtpConfig,
  148. uint16_t maximumFragmentSize)
  149. : RtpPacketizer(rtpConfig), maximumFragmentSize(maximumFragmentSize),
  150. packetization(packetization) {}
  151. void AV1RtpPacketizer::outgoing(message_vector &messages,
  152. [[maybe_unused]] const message_callback &send) {
  153. message_vector result;
  154. for (const auto &message : messages) {
  155. std::vector<binary_ptr> obus;
  156. if (packetization == AV1RtpPacketizer::Packetization::TemporalUnit) {
  157. obus = extractTemporalUnitObus(message);
  158. } else {
  159. obus.push_back(message);
  160. }
  161. std::vector<binary_ptr> fragments;
  162. for (auto obu : obus) {
  163. auto p = packetizeObu(obu, maximumFragmentSize);
  164. fragments.insert(fragments.end(), p.begin(), p.end());
  165. }
  166. if (fragments.size() == 0)
  167. continue;
  168. for (size_t i = 0; i < fragments.size() - 1; i++)
  169. result.push_back(packetize(fragments[i], false));
  170. result.push_back(packetize(fragments[fragments.size() - 1], true));
  171. }
  172. messages.swap(result);
  173. }
  174. } // namespace rtc
  175. #endif /* RTC_ENABLE_MEDIA */