h264rtppacketizer.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /**
  2. * Copyright (c) 2020 Filip Klembara (in2core)
  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 "h264rtppacketizer.hpp"
  10. #include "impl/internals.hpp"
  11. #include <cassert>
  12. #ifdef _WIN32
  13. #include <winsock2.h>
  14. #else
  15. #include <arpa/inet.h>
  16. #endif
  17. namespace rtc {
  18. typedef enum {
  19. NUSM_noMatch,
  20. NUSM_firstZero,
  21. NUSM_secondZero,
  22. NUSM_thirdZero,
  23. NUSM_shortMatch,
  24. NUSM_longMatch
  25. } NalUnitStartSequenceMatch;
  26. NalUnitStartSequenceMatch StartSequenceMatchSucc(NalUnitStartSequenceMatch match, byte _byte,
  27. H264RtpPacketizer::Separator separator) {
  28. assert(separator != H264RtpPacketizer::Separator::Length);
  29. auto byte = (uint8_t)_byte;
  30. auto detectShort = separator == H264RtpPacketizer::Separator::ShortStartSequence ||
  31. separator == H264RtpPacketizer::Separator::StartSequence;
  32. auto detectLong = separator == H264RtpPacketizer::Separator::LongStartSequence ||
  33. separator == H264RtpPacketizer::Separator::StartSequence;
  34. switch (match) {
  35. case NUSM_noMatch:
  36. if (byte == 0x00) {
  37. return NUSM_firstZero;
  38. }
  39. break;
  40. case NUSM_firstZero:
  41. if (byte == 0x00) {
  42. return NUSM_secondZero;
  43. }
  44. break;
  45. case NUSM_secondZero:
  46. if (byte == 0x00 && detectLong) {
  47. return NUSM_thirdZero;
  48. } else if (byte == 0x00 && detectShort) {
  49. return NUSM_secondZero;
  50. } else if (byte == 0x01 && detectShort) {
  51. return NUSM_shortMatch;
  52. }
  53. break;
  54. case NUSM_thirdZero:
  55. if (byte == 0x00 && detectLong) {
  56. return NUSM_thirdZero;
  57. } else if (byte == 0x01 && detectLong) {
  58. return NUSM_longMatch;
  59. }
  60. break;
  61. case NUSM_shortMatch:
  62. return NUSM_shortMatch;
  63. case NUSM_longMatch:
  64. return NUSM_longMatch;
  65. }
  66. return NUSM_noMatch;
  67. }
  68. shared_ptr<NalUnits> H264RtpPacketizer::splitMessage(binary_ptr message) {
  69. auto nalus = std::make_shared<NalUnits>();
  70. if (separator == Separator::Length) {
  71. size_t index = 0;
  72. while (index < message->size()) {
  73. assert(index + 4 < message->size());
  74. if (index + 4 >= message->size()) {
  75. LOG_WARNING << "Invalid NAL Unit data (incomplete length), ignoring!";
  76. break;
  77. }
  78. auto lengthPtr = (uint32_t *)(message->data() + index);
  79. uint32_t length = ntohl(*lengthPtr);
  80. auto naluStartIndex = index + 4;
  81. auto naluEndIndex = naluStartIndex + length;
  82. assert(naluEndIndex <= message->size());
  83. if (naluEndIndex > message->size()) {
  84. LOG_WARNING << "Invalid NAL Unit data (incomplete unit), ignoring!";
  85. break;
  86. }
  87. auto begin = message->begin() + naluStartIndex;
  88. auto end = message->begin() + naluEndIndex;
  89. nalus->push_back(std::make_shared<NalUnit>(begin, end));
  90. index = naluEndIndex;
  91. }
  92. } else {
  93. NalUnitStartSequenceMatch match = NUSM_noMatch;
  94. size_t index = 0;
  95. while (index < message->size()) {
  96. match = StartSequenceMatchSucc(match, (*message)[index++], separator);
  97. if (match == NUSM_longMatch || match == NUSM_shortMatch) {
  98. match = NUSM_noMatch;
  99. break;
  100. }
  101. }
  102. size_t naluStartIndex = index;
  103. while (index < message->size()) {
  104. match = StartSequenceMatchSucc(match, (*message)[index], separator);
  105. if (match == NUSM_longMatch || match == NUSM_shortMatch) {
  106. auto sequenceLength = match == NUSM_longMatch ? 4 : 3;
  107. size_t naluEndIndex = index - sequenceLength;
  108. match = NUSM_noMatch;
  109. auto begin = message->begin() + naluStartIndex;
  110. auto end = message->begin() + naluEndIndex + 1;
  111. nalus->push_back(std::make_shared<NalUnit>(begin, end));
  112. naluStartIndex = index + 1;
  113. }
  114. index++;
  115. }
  116. auto begin = message->begin() + naluStartIndex;
  117. auto end = message->end();
  118. nalus->push_back(std::make_shared<NalUnit>(begin, end));
  119. }
  120. return nalus;
  121. }
  122. H264RtpPacketizer::H264RtpPacketizer(shared_ptr<RtpPacketizationConfig> rtpConfig,
  123. uint16_t maximumFragmentSize)
  124. : RtpPacketizer(rtpConfig), MediaHandlerRootElement(), maximumFragmentSize(maximumFragmentSize),
  125. separator(Separator::Length) {}
  126. H264RtpPacketizer::H264RtpPacketizer(H264RtpPacketizer::Separator separator,
  127. shared_ptr<RtpPacketizationConfig> rtpConfig,
  128. uint16_t maximumFragmentSize)
  129. : RtpPacketizer(rtpConfig), MediaHandlerRootElement(), maximumFragmentSize(maximumFragmentSize),
  130. separator(separator) {}
  131. ChainedOutgoingProduct
  132. H264RtpPacketizer::processOutgoingBinaryMessage(ChainedMessagesProduct messages,
  133. message_ptr control) {
  134. ChainedMessagesProduct packets = std::make_shared<std::vector<binary_ptr>>();
  135. for (auto message : *messages) {
  136. auto nalus = splitMessage(message);
  137. auto fragments = nalus->generateFragments(maximumFragmentSize);
  138. if (fragments.size() == 0) {
  139. return ChainedOutgoingProduct();
  140. }
  141. unsigned i = 0;
  142. for (; i < fragments.size() - 1; i++) {
  143. packets->push_back(packetize(fragments[i], false));
  144. }
  145. packets->push_back(packetize(fragments[i], true));
  146. }
  147. return {packets, control};
  148. }
  149. } // namespace rtc
  150. #endif /* RTC_ENABLE_MEDIA */