av1rtppacketizer.cpp 5.9 KB

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