Add the option to use raw RTP packetization without the generic header.

Bug: webrtc:10625
Change-Id: I198031154dbb706ae1e7c15bd34a3bdf93d1a51a
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/136923
Reviewed-by: Stefan Holmer <stefan@webrtc.org>
Reviewed-by: Rasmus Brandt <brandtr@webrtc.org>
Reviewed-by: Philip Eliasson <philipel@webrtc.org>
Commit-Queue: Mirta Dvornicic <mirtad@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27964}
diff --git a/modules/rtp_rtcp/source/rtp_format.cc b/modules/rtp_rtcp/source/rtp_format.cc
index 7375a63..843cbb8 100644
--- a/modules/rtp_rtcp/source/rtp_format.cc
+++ b/modules/rtp_rtcp/source/rtp_format.cc
@@ -142,7 +142,7 @@
     case kVideoCodecVP9:
       return new RtpDepacketizerVp9();
     default:
-      return new RtpDepacketizerGeneric();
+      return new RtpDepacketizerGeneric(/*generic_header_enabled=*/true);
   }
 }
 }  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_format_video_generic.cc b/modules/rtp_rtcp/source/rtp_format_video_generic.cc
index 171c5ff..a45597d 100644
--- a/modules/rtp_rtcp/source/rtp_format_video_generic.cc
+++ b/modules/rtp_rtcp/source/rtp_format_video_generic.cc
@@ -35,6 +35,14 @@
   current_packet_ = payload_sizes_.begin();
 }
 
+RtpPacketizerGeneric::RtpPacketizerGeneric(
+    rtc::ArrayView<const uint8_t> payload,
+    PayloadSizeLimits limits)
+    : header_size_(0), remaining_payload_(payload) {
+  payload_sizes_ = SplitAboutEqually(payload.size(), limits);
+  current_packet_ = payload_sizes_.begin();
+}
+
 RtpPacketizerGeneric::~RtpPacketizerGeneric() = default;
 
 size_t RtpPacketizerGeneric::NumPackets() const {
@@ -52,13 +60,15 @@
       packet->AllocatePayload(header_size_ + next_packet_payload_len);
   RTC_CHECK(out_ptr);
 
-  memcpy(out_ptr, header_, header_size_);
+  if (header_size_ > 0) {
+    memcpy(out_ptr, header_, header_size_);
+    // Remove first-packet bit, following packets are intermediate.
+    header_[0] &= ~RtpFormatVideoGeneric::kFirstPacketBit;
+  }
+
   memcpy(out_ptr + header_size_, remaining_payload_.data(),
          next_packet_payload_len);
 
-  // Remove first-packet bit, following packets are intermediate.
-  header_[0] &= ~RtpFormatVideoGeneric::kFirstPacketBit;
-
   remaining_payload_ = remaining_payload_.subview(next_packet_payload_len);
 
   ++current_packet_;
@@ -79,7 +89,7 @@
     header_[0] |= RtpFormatVideoGeneric::kKeyFrameBit;
   }
   if (rtp_video_header.generic.has_value()) {
-    // Store bottom 15 bits of the the picture id. Only 15 bits are used for
+    // Store bottom 15 bits of the picture id. Only 15 bits are used for
     // compatibility with other packetizer implemenetations.
     uint16_t picture_id = rtp_video_header.generic->frame_id & 0x7FFF;
     header_[0] |= RtpFormatVideoGeneric::kExtendedHeaderBit;
@@ -89,6 +99,9 @@
   }
 }
 
+RtpDepacketizerGeneric::RtpDepacketizerGeneric(bool generic_header_enabled)
+    : generic_header_enabled_(generic_header_enabled) {}
+
 RtpDepacketizerGeneric::~RtpDepacketizerGeneric() = default;
 
 bool RtpDepacketizerGeneric::Parse(ParsedPayload* parsed_payload,
@@ -100,29 +113,31 @@
     return false;
   }
 
-  uint8_t generic_header = *payload_data++;
-  --payload_data_length;
+  if (generic_header_enabled_) {
+    uint8_t generic_header = *payload_data++;
+    --payload_data_length;
 
-  parsed_payload->video_header().frame_type =
-      ((generic_header & RtpFormatVideoGeneric::kKeyFrameBit) != 0)
-          ? VideoFrameType::kVideoFrameKey
-          : VideoFrameType::kVideoFrameDelta;
-  parsed_payload->video_header().is_first_packet_in_frame =
-      (generic_header & RtpFormatVideoGeneric::kFirstPacketBit) != 0;
-  parsed_payload->video_header().codec = kVideoCodecGeneric;
-  parsed_payload->video_header().width = 0;
-  parsed_payload->video_header().height = 0;
+    parsed_payload->video_header().frame_type =
+        ((generic_header & RtpFormatVideoGeneric::kKeyFrameBit) != 0)
+            ? VideoFrameType::kVideoFrameKey
+            : VideoFrameType::kVideoFrameDelta;
+    parsed_payload->video_header().is_first_packet_in_frame =
+        (generic_header & RtpFormatVideoGeneric::kFirstPacketBit) != 0;
+    parsed_payload->video_header().codec = kVideoCodecGeneric;
+    parsed_payload->video_header().width = 0;
+    parsed_payload->video_header().height = 0;
 
-  if (generic_header & RtpFormatVideoGeneric::kExtendedHeaderBit) {
-    if (payload_data_length < kExtendedHeaderLength) {
-      RTC_LOG(LS_WARNING) << "Too short payload for generic header.";
-      return false;
+    if (generic_header & RtpFormatVideoGeneric::kExtendedHeaderBit) {
+      if (payload_data_length < kExtendedHeaderLength) {
+        RTC_LOG(LS_WARNING) << "Too short payload for generic header.";
+        return false;
+      }
+      parsed_payload->video_header().generic.emplace();
+      parsed_payload->video_header().generic->frame_id =
+          ((payload_data[0] & 0x7F) << 8) | payload_data[1];
+      payload_data += kExtendedHeaderLength;
+      payload_data_length -= kExtendedHeaderLength;
     }
-    parsed_payload->video_header().generic.emplace();
-    parsed_payload->video_header().generic->frame_id =
-        ((payload_data[0] & 0x7F) << 8) | payload_data[1];
-    payload_data += kExtendedHeaderLength;
-    payload_data_length -= kExtendedHeaderLength;
   }
 
   parsed_payload->payload = payload_data;
diff --git a/modules/rtp_rtcp/source/rtp_format_video_generic.h b/modules/rtp_rtcp/source/rtp_format_video_generic.h
index 6406b74..4e21c96 100644
--- a/modules/rtp_rtcp/source/rtp_format_video_generic.h
+++ b/modules/rtp_rtcp/source/rtp_format_video_generic.h
@@ -34,16 +34,23 @@
  public:
   // Initialize with payload from encoder.
   // The payload_data must be exactly one encoded generic frame.
+  // Packets returned by |NextPacket| will contain the generic payload header.
   RtpPacketizerGeneric(rtc::ArrayView<const uint8_t> payload,
                        PayloadSizeLimits limits,
                        const RTPVideoHeader& rtp_video_header,
                        VideoFrameType frametype);
+  // Initialize with payload from encoder.
+  // The payload_data must be exactly one encoded generic frame.
+  // Packets returned by |NextPacket| will contain raw payload without the
+  // generic payload header.
+  RtpPacketizerGeneric(rtc::ArrayView<const uint8_t> payload,
+                       PayloadSizeLimits limits);
 
   ~RtpPacketizerGeneric() override;
 
   size_t NumPackets() const override;
 
-  // Get the next payload with generic payload header.
+  // Get the next payload.
   // Write payload and set marker bit of the |packet|.
   // Returns true on success, false otherwise.
   bool NextPacket(RtpPacketToSend* packet) override;
@@ -65,11 +72,17 @@
 // Depacketizer for generic codec.
 class RtpDepacketizerGeneric : public RtpDepacketizer {
  public:
+  // Parses the generic payload header if |generic_header_enabled| is true,
+  // returns raw payload otherwise.
+  explicit RtpDepacketizerGeneric(bool generic_header_enabled);
   ~RtpDepacketizerGeneric() override;
 
   bool Parse(ParsedPayload* parsed_payload,
              const uint8_t* payload_data,
              size_t payload_data_length) override;
+
+ private:
+  bool generic_header_enabled_;
 };
 }  // namespace webrtc
 #endif  // MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VIDEO_GENERIC_H_
diff --git a/modules/rtp_rtcp/source/rtp_format_video_generic_unittest.cc b/modules/rtp_rtcp/source/rtp_format_video_generic_unittest.cc
index fa274dd..d43af77 100644
--- a/modules/rtp_rtcp/source/rtp_format_video_generic_unittest.cc
+++ b/modules/rtp_rtcp/source/rtp_format_video_generic_unittest.cc
@@ -158,11 +158,23 @@
   EXPECT_FALSE(payload[0] & 0x04);
 }
 
+TEST(RtpPacketizerVideoGeneric, DoesNotWriteHeaderForRawPayload) {
+  const uint8_t kPayload[] = {0x05, 0x25, 0x52};
+
+  RtpPacketizerGeneric packetizer(kPayload, kNoSizeLimits);
+
+  RtpPacketToSend packet(nullptr);
+  ASSERT_TRUE(packetizer.NextPacket(&packet));
+
+  rtc::ArrayView<const uint8_t> payload = packet.payload();
+  EXPECT_THAT(payload, ElementsAreArray(kPayload));
+}
+
 TEST(RtpDepacketizerVideoGeneric, NonExtendedHeaderNoFrameId) {
   const size_t kPayloadLen = 1;
   uint8_t payload[kPayloadLen] = {0x01};
 
-  RtpDepacketizerGeneric depacketizer;
+  RtpDepacketizerGeneric depacketizer(/*generic_header_enabled=*/true);
   RtpDepacketizer::ParsedPayload parsed_payload;
   depacketizer.Parse(&parsed_payload, payload, kPayloadLen);
 
@@ -173,7 +185,7 @@
   const size_t kPayloadLen = 3;
   uint8_t payload[kPayloadLen] = {0x05, 0x13, 0x37};
 
-  RtpDepacketizerGeneric depacketizer;
+  RtpDepacketizerGeneric depacketizer(/*generic_header_enabled=*/true);
   RtpDepacketizer::ParsedPayload parsed_payload;
   depacketizer.Parse(&parsed_payload, payload, kPayloadLen);
 
@@ -181,5 +193,19 @@
   EXPECT_EQ(0x1337, parsed_payload.video_header().generic->frame_id);
 }
 
+TEST(RtpDepacketizerVideoGeneric, DoesNotParseHeaderForRawPayload) {
+  const uint8_t kPayload[] = {0x05, 0x25, 0x52};
+  const size_t kPayloadLen = sizeof(kPayload);
+
+  RtpDepacketizerGeneric depacketizer(/*generic_header_enabled=*/false);
+  RtpDepacketizer::ParsedPayload parsed_payload;
+  depacketizer.Parse(&parsed_payload, kPayload, kPayloadLen);
+
+  EXPECT_FALSE(parsed_payload.video_header().generic);
+  EXPECT_THAT(rtc::MakeArrayView<const uint8_t>(parsed_payload.payload,
+                                                parsed_payload.payload_length),
+              ElementsAreArray(kPayload));
+}
+
 }  // namespace
 }  // namespace webrtc
diff --git a/test/fuzzers/generic_depacketizer_fuzzer.cc b/test/fuzzers/generic_depacketizer_fuzzer.cc
index 4775501..6b98b41 100644
--- a/test/fuzzers/generic_depacketizer_fuzzer.cc
+++ b/test/fuzzers/generic_depacketizer_fuzzer.cc
@@ -14,7 +14,7 @@
 namespace webrtc {
 
 void FuzzOneInput(const uint8_t* data, size_t size) {
-  RtpDepacketizerGeneric depacketizer;
+  RtpDepacketizerGeneric depacketizer(/*generic_header_enabled=*/true);
   RtpDepacketizer::ParsedPayload parsed_payload;
   depacketizer.Parse(&parsed_payload, data, size);
 }