2
0

h264rtppacketizer.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /**
  2. * Copyright (c) 2020 Filip Klembara (in2core)
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. #if RTC_ENABLE_MEDIA
  19. #include "h264rtppacketizer.hpp"
  20. #include "impl/internals.hpp"
  21. #include <cassert>
  22. #ifdef _WIN32
  23. #include <winsock2.h>
  24. #else
  25. #include <arpa/inet.h>
  26. #endif
  27. namespace rtc {
  28. typedef enum {
  29. NUSM_noMatch,
  30. NUSM_firstZero,
  31. NUSM_secondZero,
  32. NUSM_thirdZero,
  33. NUSM_shortMatch,
  34. NUSM_longMatch
  35. } NalUnitStartSequenceMatch;
  36. NalUnitStartSequenceMatch StartSequenceMatchSucc(NalUnitStartSequenceMatch match, byte _byte,
  37. H264RtpPacketizer::Separator separator) {
  38. assert(separator != H264RtpPacketizer::Separator::Length);
  39. auto byte = (uint8_t)_byte;
  40. auto detectShort = separator == H264RtpPacketizer::Separator::ShortStartSequence ||
  41. separator == H264RtpPacketizer::Separator::StartSequence;
  42. auto detectLong = separator == H264RtpPacketizer::Separator::LongStartSequence ||
  43. separator == H264RtpPacketizer::Separator::StartSequence;
  44. switch (match) {
  45. case NUSM_noMatch:
  46. if (byte == 0x00) {
  47. return NUSM_firstZero;
  48. }
  49. break;
  50. case NUSM_firstZero:
  51. if (byte == 0x00) {
  52. return NUSM_secondZero;
  53. }
  54. break;
  55. case NUSM_secondZero:
  56. if (byte == 0x00 && detectLong) {
  57. return NUSM_thirdZero;
  58. } else if (byte == 0x01 && detectShort) {
  59. return NUSM_shortMatch;
  60. }
  61. break;
  62. case NUSM_thirdZero:
  63. if (byte == 0x01 && detectLong) {
  64. return NUSM_longMatch;
  65. }
  66. break;
  67. case NUSM_shortMatch:
  68. return NUSM_shortMatch;
  69. case NUSM_longMatch:
  70. return NUSM_longMatch;
  71. }
  72. return NUSM_noMatch;
  73. }
  74. shared_ptr<NalUnits> H264RtpPacketizer::splitMessage(binary_ptr message) {
  75. auto nalus = std::make_shared<NalUnits>();
  76. if (separator == Separator::Length) {
  77. size_t index = 0;
  78. while (index < message->size()) {
  79. assert(index + 4 < message->size());
  80. if (index + 4 >= message->size()) {
  81. LOG_WARNING << "Invalid NAL Unit data (incomplete length), ignoring!";
  82. break;
  83. }
  84. auto lengthPtr = (uint32_t *)(message->data() + index);
  85. uint32_t length = ntohl(*lengthPtr);
  86. auto naluStartIndex = index + 4;
  87. auto naluEndIndex = naluStartIndex + length;
  88. assert(naluEndIndex <= message->size());
  89. if (naluEndIndex > message->size()) {
  90. LOG_WARNING << "Invalid NAL Unit data (incomplete unit), ignoring!";
  91. break;
  92. }
  93. auto begin = message->begin() + naluStartIndex;
  94. auto end = message->begin() + naluEndIndex;
  95. nalus->push_back(std::make_shared<NalUnit>(begin, end));
  96. index = naluEndIndex;
  97. }
  98. } else {
  99. NalUnitStartSequenceMatch match = NUSM_noMatch;
  100. size_t index = 0;
  101. while (index < message->size()) {
  102. match = StartSequenceMatchSucc(match, (*message)[index++], separator);
  103. if (match == NUSM_longMatch || match == NUSM_shortMatch) {
  104. match = NUSM_noMatch;
  105. break;
  106. }
  107. }
  108. size_t naluStartIndex = index;
  109. while (index < message->size()) {
  110. match = StartSequenceMatchSucc(match, (*message)[index], separator);
  111. if (match == NUSM_longMatch || match == NUSM_shortMatch) {
  112. auto sequenceLength = match == NUSM_longMatch ? 4 : 3;
  113. size_t naluEndIndex = index - sequenceLength;
  114. match = NUSM_noMatch;
  115. auto begin = message->begin() + naluStartIndex;
  116. auto end = message->begin() + naluEndIndex + 1;
  117. nalus->push_back(std::make_shared<NalUnit>(begin, end));
  118. naluStartIndex = index + 1;
  119. }
  120. index++;
  121. }
  122. auto begin = message->begin() + naluStartIndex;
  123. auto end = message->end();
  124. nalus->push_back(std::make_shared<NalUnit>(begin, end));
  125. }
  126. return nalus;
  127. }
  128. H264RtpPacketizer::H264RtpPacketizer(shared_ptr<RtpPacketizationConfig> rtpConfig,
  129. uint16_t maximumFragmentSize)
  130. : RtpPacketizer(rtpConfig), MediaHandlerRootElement(), maximumFragmentSize(maximumFragmentSize),
  131. separator(Separator::Length) {}
  132. H264RtpPacketizer::H264RtpPacketizer(H264RtpPacketizer::Separator separator,
  133. shared_ptr<RtpPacketizationConfig> rtpConfig,
  134. uint16_t maximumFragmentSize)
  135. : RtpPacketizer(rtpConfig), MediaHandlerRootElement(), maximumFragmentSize(maximumFragmentSize),
  136. separator(separator) {}
  137. ChainedOutgoingProduct
  138. H264RtpPacketizer::processOutgoingBinaryMessage(ChainedMessagesProduct messages,
  139. message_ptr control) {
  140. ChainedMessagesProduct packets = std::make_shared<std::vector<binary_ptr>>();
  141. for (auto message : *messages) {
  142. auto nalus = splitMessage(message);
  143. auto fragments = nalus->generateFragments(maximumFragmentSize);
  144. if (fragments.size() == 0) {
  145. return ChainedOutgoingProduct();
  146. }
  147. unsigned i = 0;
  148. for (; i < fragments.size() - 1; i++) {
  149. packets->push_back(packetize(fragments[i], false));
  150. }
  151. packets->push_back(packetize(fragments[i], true));
  152. }
  153. return {packets, control};
  154. }
  155. } // namespace rtc
  156. #endif /* RTC_ENABLE_MEDIA */