Add option to configure raw RTP packetization per payload type.

Bug: webrtc:10625
Change-Id: I699f61af29656827eccb3c4ed507b4229dee972a
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/137803
Commit-Queue: Mirta Dvornicic <mirtad@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Reviewed-by: Åsa Persson <asapersson@webrtc.org>
Reviewed-by: Rasmus Brandt <brandtr@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28036}
diff --git a/call/rtp_config.cc b/call/rtp_config.cc
index cce78ad..f11d69c 100644
--- a/call/rtp_config.cc
+++ b/call/rtp_config.cc
@@ -76,6 +76,7 @@
   ss << ", ulpfec: " << ulpfec.ToString();
   ss << ", payload_name: " << payload_name;
   ss << ", payload_type: " << payload_type;
+  ss << ", raw_payload: " << (raw_payload ? "true" : "false");
 
   ss << ", flexfec: {payload_type: " << flexfec.payload_type;
   ss << ", ssrc: " << flexfec.ssrc;
diff --git a/call/rtp_config.h b/call/rtp_config.h
index b6155c0..adffc89 100644
--- a/call/rtp_config.h
+++ b/call/rtp_config.h
@@ -99,6 +99,10 @@
   // images to the right payload type.
   std::string payload_name;
   int payload_type = -1;
+  // Payload should be packetized using raw packetizer (payload header will
+  // not be added, additional meta data is expected to be present in generic
+  // frame descriptor RTP header extension).
+  bool raw_payload = false;
 
   // See NackConfig for description.
   NackConfig nack;
diff --git a/call/rtp_video_sender.cc b/call/rtp_video_sender.cc
index 796575b..332fc95 100644
--- a/call/rtp_video_sender.cc
+++ b/call/rtp_video_sender.cc
@@ -312,7 +312,8 @@
     stream.rtp_rtcp->RegisterSendPayloadFrequency(rtp_config.payload_type,
                                                   kVideoPayloadTypeFrequency);
     stream.sender_video->RegisterPayloadType(rtp_config.payload_type,
-                                             rtp_config.payload_name);
+                                             rtp_config.payload_name,
+                                             rtp_config.raw_payload);
   }
   // Currently, both ULPFEC and FlexFEC use the same FEC rate calculation logic,
   // so enable that logic if either of those FEC schemes are enabled.
diff --git a/call/video_receive_stream.cc b/call/video_receive_stream.cc
index 92787cc..e825956 100644
--- a/call/video_receive_stream.cc
+++ b/call/video_receive_stream.cc
@@ -125,6 +125,11 @@
     ss << kv.first << " (pt) -> " << kv.second << " (apt), ";
   }
   ss << '}';
+  ss << ", raw_payload_types: {";
+  for (const auto& pt : raw_payload_types) {
+    ss << pt << ", ";
+  }
+  ss << '}';
   ss << ", extensions: [";
   for (size_t i = 0; i < extensions.size(); ++i) {
     ss << extensions[i].ToString();
diff --git a/call/video_receive_stream.h b/call/video_receive_stream.h
index a1fa86d..5a819f9 100644
--- a/call/video_receive_stream.h
+++ b/call/video_receive_stream.h
@@ -13,6 +13,7 @@
 
 #include <limits>
 #include <map>
+#include <set>
 #include <string>
 #include <vector>
 
@@ -195,6 +196,12 @@
       // For RTX to be enabled, both an SSRC and this mapping are needed.
       std::map<int, int> rtx_associated_payload_types;
 
+      // Payload types that should be depacketized using raw depacketizer
+      // (payload header will not be parsed and must not be present, additional
+      // meta data is expected to be present in generic frame descriptor
+      // RTP header extension).
+      std::set<int> raw_payload_types;
+
       // RTP header extensions used for the received stream.
       std::vector<RtpExtension> extensions;
     } rtp;
diff --git a/modules/rtp_rtcp/source/nack_rtx_unittest.cc b/modules/rtp_rtcp/source/nack_rtx_unittest.cc
index 2ae324c..f8fd39a 100644
--- a/modules/rtp_rtcp/source/nack_rtx_unittest.cc
+++ b/modules/rtp_rtcp/source/nack_rtx_unittest.cc
@@ -151,7 +151,8 @@
     // single rtp_rtcp module for both send and receive side.
     rtp_rtcp_module_->SetRemoteSSRC(kTestSsrc);
 
-    rtp_sender_video_->RegisterPayloadType(kPayloadType, "video");
+    rtp_sender_video_->RegisterPayloadType(kPayloadType, "video",
+                                           /*raw_payload=*/false);
     rtp_rtcp_module_->SetRtxSendPayloadType(kRtxPayloadType, kPayloadType);
     transport_.SetSendModule(rtp_rtcp_module_.get());
     media_receiver_ = transport_.stream_receiver_controller_.CreateReceiver(
diff --git a/modules/rtp_rtcp/source/rtp_format.cc b/modules/rtp_rtcp/source/rtp_format.cc
index 843cbb8..e870232 100644
--- a/modules/rtp_rtcp/source/rtp_format.cc
+++ b/modules/rtp_rtcp/source/rtp_format.cc
@@ -24,14 +24,19 @@
 namespace webrtc {
 
 std::unique_ptr<RtpPacketizer> RtpPacketizer::Create(
-    VideoCodecType type,
+    absl::optional<VideoCodecType> type,
     rtc::ArrayView<const uint8_t> payload,
     PayloadSizeLimits limits,
     // Codec-specific details.
     const RTPVideoHeader& rtp_video_header,
     VideoFrameType frame_type,
     const RTPFragmentationHeader* fragmentation) {
-  switch (type) {
+  if (!type) {
+    // Use raw packetizer.
+    return absl::make_unique<RtpPacketizerGeneric>(payload, limits);
+  }
+
+  switch (*type) {
     case kVideoCodecH264: {
       RTC_CHECK(fragmentation);
       const auto& h264 =
@@ -133,8 +138,13 @@
   return result;
 }
 
-RtpDepacketizer* RtpDepacketizer::Create(VideoCodecType type) {
-  switch (type) {
+RtpDepacketizer* RtpDepacketizer::Create(absl::optional<VideoCodecType> type) {
+  if (!type) {
+    // Use raw depacketizer.
+    return new RtpDepacketizerGeneric(/*generic_header_enabled=*/false);
+  }
+
+  switch (*type) {
     case kVideoCodecH264:
       return new RtpDepacketizerH264();
     case kVideoCodecVP8:
@@ -145,4 +155,5 @@
       return new RtpDepacketizerGeneric(/*generic_header_enabled=*/true);
   }
 }
+
 }  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_format.h b/modules/rtp_rtcp/source/rtp_format.h
index f9c1e76..b28e9a6 100644
--- a/modules/rtp_rtcp/source/rtp_format.h
+++ b/modules/rtp_rtcp/source/rtp_format.h
@@ -15,6 +15,7 @@
 #include <memory>
 #include <vector>
 
+#include "absl/types/optional.h"
 #include "api/array_view.h"
 #include "modules/include/module_common_types.h"
 #include "modules/rtp_rtcp/source/rtp_video_header.h"
@@ -32,8 +33,10 @@
     // Reduction len for packet that is first & last at the same time.
     int single_packet_reduction_len = 0;
   };
+
+  // If type is not set, returns a raw packetizer.
   static std::unique_ptr<RtpPacketizer> Create(
-      VideoCodecType type,
+      absl::optional<VideoCodecType> type,
       rtc::ArrayView<const uint8_t> payload,
       PayloadSizeLimits limits,
       // Codec-specific details.
@@ -79,7 +82,8 @@
     size_t payload_length;
   };
 
-  static RtpDepacketizer* Create(VideoCodecType type);
+  // If type is not set, returns a raw depacketizer.
+  static RtpDepacketizer* Create(absl::optional<VideoCodecType> type);
 
   virtual ~RtpDepacketizer() {}
 
diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc b/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc
index 28712c5..09f8dbd 100644
--- a/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc
+++ b/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc
@@ -193,7 +193,8 @@
     codec_.plType = 100;
     codec_.width = 320;
     codec_.height = 180;
-    sender_video_->RegisterPayloadType(codec_.plType, "VP8");
+    sender_video_->RegisterPayloadType(codec_.plType, "VP8",
+                                       /*raw_payload=*/false);
 
     // Receive module.
     EXPECT_EQ(0, receiver_.impl_->SetSendingStatus(false));
diff --git a/modules/rtp_rtcp/source/rtp_sender_unittest.cc b/modules/rtp_rtcp/source/rtp_sender_unittest.cc
index 9ac23fc..3d1bed4 100644
--- a/modules/rtp_rtcp/source/rtp_sender_unittest.cc
+++ b/modules/rtp_rtcp/source/rtp_sender_unittest.cc
@@ -521,7 +521,8 @@
   const uint8_t kPayloadType = 127;
   const char payload_name[] = "GENERIC";
 
-  rtp_sender_video.RegisterPayloadType(kPayloadType, payload_name);
+  rtp_sender_video.RegisterPayloadType(kPayloadType, payload_name,
+                                       /*raw_payload=*/false);
 
   const uint32_t kCaptureTimeMsToRtpTimestamp = 90;  // 90 kHz clock
   RTPVideoHeader video_header;
@@ -1099,7 +1100,8 @@
   RTPSenderVideo rtp_sender_video(&fake_clock_, rtp_sender_.get(), nullptr,
                                   &playout_delay_oracle, nullptr, false,
                                   FieldTrialBasedConfig());
-  rtp_sender_video.RegisterPayloadType(payload_type, payload_name);
+  rtp_sender_video.RegisterPayloadType(payload_type, payload_name,
+                                       /*raw_payload=*/false);
   uint8_t payload[] = {47, 11, 32, 93, 89};
 
   // Send keyframe
@@ -1132,6 +1134,29 @@
   EXPECT_THAT(sent_payload.subview(1), ElementsAreArray(payload));
 }
 
+TEST_P(RtpSenderTestWithoutPacer, SendRawVideo) {
+  const char payload_name[] = "VP8";
+  const uint8_t payload_type = 111;
+  const uint8_t payload[] = {11, 22, 33, 44, 55};
+
+  PlayoutDelayOracle playout_delay_oracle;
+  RTPSenderVideo rtp_sender_video(&fake_clock_, rtp_sender_.get(), nullptr,
+                                  &playout_delay_oracle, nullptr, false,
+                                  FieldTrialBasedConfig());
+  rtp_sender_video.RegisterPayloadType(payload_type, payload_name,
+                                       /*raw_payload=*/true);
+
+  // Send a frame.
+  RTPVideoHeader video_header;
+  ASSERT_TRUE(rtp_sender_video.SendVideo(
+      VideoFrameType::kVideoFrameKey, payload_type, 1234, 4321, payload,
+      sizeof(payload), nullptr, &video_header,
+      kDefaultExpectedRetransmissionTimeMs));
+
+  auto sent_payload = transport_.last_sent_packet().payload();
+  EXPECT_THAT(sent_payload, ElementsAreArray(payload));
+}
+
 TEST_P(RtpSenderTest, SendFlexfecPackets) {
   constexpr uint32_t kTimestamp = 1234;
   constexpr int kMediaPayloadType = 127;
@@ -1158,7 +1183,8 @@
   RTPSenderVideo rtp_sender_video(&fake_clock_, rtp_sender_.get(),
                                   &flexfec_sender, &playout_delay_oracle,
                                   nullptr, false, FieldTrialBasedConfig());
-  rtp_sender_video.RegisterPayloadType(kMediaPayloadType, "GENERIC");
+  rtp_sender_video.RegisterPayloadType(kMediaPayloadType, "GENERIC",
+                                       /*raw_payload=*/false);
 
   // Parameters selected to generate a single FEC packet per media packet.
   FecProtectionParams params;
@@ -1234,7 +1260,8 @@
   RTPSenderVideo rtp_sender_video(&fake_clock_, rtp_sender_.get(),
                                   &flexfec_sender, &playout_delay_oracle,
                                   nullptr, false, FieldTrialBasedConfig());
-  rtp_sender_video.RegisterPayloadType(kMediaPayloadType, "GENERIC");
+  rtp_sender_video.RegisterPayloadType(kMediaPayloadType, "GENERIC",
+                                       /*raw_payload=*/false);
 
   // Need extension to be registered for timing frames to be sent.
   ASSERT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
@@ -1335,7 +1362,8 @@
   RTPSenderVideo rtp_sender_video(&fake_clock_, rtp_sender_.get(),
                                   &flexfec_sender, &playout_delay_oracle,
                                   nullptr, false, FieldTrialBasedConfig());
-  rtp_sender_video.RegisterPayloadType(kMediaPayloadType, "GENERIC");
+  rtp_sender_video.RegisterPayloadType(kMediaPayloadType, "GENERIC",
+                                       /*raw_payload=*/false);
 
   // Parameters selected to generate a single FEC packet per media packet.
   FecProtectionParams params;
@@ -1465,7 +1493,8 @@
   RTPSenderVideo rtp_sender_video(&fake_clock_, rtp_sender_.get(),
                                   &flexfec_sender, &playout_delay_oracle,
                                   nullptr, false, FieldTrialBasedConfig());
-  rtp_sender_video.RegisterPayloadType(kMediaPayloadType, "GENERIC");
+  rtp_sender_video.RegisterPayloadType(kMediaPayloadType, "GENERIC",
+                                       /*raw_payload=*/false);
   // Parameters selected to generate a single FEC packet per media packet.
   FecProtectionParams params;
   params.fec_rate = 15;
@@ -1537,7 +1566,8 @@
                                   FieldTrialBasedConfig());
   const char payload_name[] = "GENERIC";
   const uint8_t payload_type = 127;
-  rtp_sender_video.RegisterPayloadType(payload_type, payload_name);
+  rtp_sender_video.RegisterPayloadType(payload_type, payload_name,
+                                       /*raw_payload=*/false);
 
   // Simulate kNumPackets sent with kPacketInterval ms intervals, with the
   // number of packets selected so that we fill (but don't overflow) the one
@@ -1623,7 +1653,8 @@
   RTPSenderVideo rtp_sender_video(&fake_clock_, rtp_sender_.get(), nullptr,
                                   &playout_delay_oracle, nullptr, false,
                                   FieldTrialBasedConfig());
-  rtp_sender_video.RegisterPayloadType(payload_type, payload_name);
+  rtp_sender_video.RegisterPayloadType(payload_type, payload_name,
+                                       /*raw_payload=*/false);
   uint8_t payload[] = {47, 11, 32, 93, 89};
   rtp_sender_->SetStorePacketsStatus(true, 1);
   uint32_t ssrc = rtp_sender_->SSRC();
diff --git a/modules/rtp_rtcp/source/rtp_sender_video.cc b/modules/rtp_rtcp/source/rtp_sender_video.cc
index a71a6e5..8d12ff4 100644
--- a/modules/rtp_rtcp/source/rtp_sender_video.cc
+++ b/modules/rtp_rtcp/source/rtp_sender_video.cc
@@ -24,9 +24,7 @@
 #include "modules/remote_bitrate_estimator/test/bwe_test_logging.h"
 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
 #include "modules/rtp_rtcp/source/byte_io.h"
-#include "modules/rtp_rtcp/source/rtp_format_video_generic.h"
-#include "modules/rtp_rtcp/source/rtp_format_vp8.h"
-#include "modules/rtp_rtcp/source/rtp_format_vp9.h"
+#include "modules/rtp_rtcp/source/rtp_format.h"
 #include "modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.h"
 #include "modules/rtp_rtcp/source/rtp_header_extensions.h"
 #include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
@@ -224,28 +222,28 @@
 RTPSenderVideo::~RTPSenderVideo() {}
 
 void RTPSenderVideo::RegisterPayloadType(int8_t payload_type,
-                                         absl::string_view payload_name) {
-  VideoCodecType video_type;
-
-  if (absl::EqualsIgnoreCase(payload_name, "VP8")) {
-    video_type = kVideoCodecVP8;
-  } else if (absl::EqualsIgnoreCase(payload_name, "VP9")) {
-    video_type = kVideoCodecVP9;
-  } else if (absl::EqualsIgnoreCase(payload_name, "H264")) {
-    video_type = kVideoCodecH264;
-  } else if (absl::EqualsIgnoreCase(payload_name, "I420")) {
-    video_type = kVideoCodecGeneric;
-  } else if (absl::EqualsIgnoreCase(payload_name, "stereo")) {
-    video_type = kVideoCodecGeneric;
-  } else {
-    video_type = kVideoCodecGeneric;
+                                         absl::string_view payload_name,
+                                         bool raw_payload) {
+  absl::optional<VideoCodecType> video_type;
+  if (!raw_payload) {
+    if (absl::EqualsIgnoreCase(payload_name, "VP8")) {
+      video_type = kVideoCodecVP8;
+    } else if (absl::EqualsIgnoreCase(payload_name, "VP9")) {
+      video_type = kVideoCodecVP9;
+    } else if (absl::EqualsIgnoreCase(payload_name, "H264")) {
+      video_type = kVideoCodecH264;
+    } else {
+      video_type = kVideoCodecGeneric;
+    }
   }
 
-  rtc::CritScope cs(&payload_type_crit_);
-  payload_type_map_[payload_type] = video_type;
+  {
+    rtc::CritScope cs(&payload_type_crit_);
+    payload_type_map_[payload_type] = video_type;
+  }
 
   // Backward compatibility for older receivers without temporal layer logic
-  if (video_type == kVideoCodecH264) {
+  if (absl::EqualsIgnoreCase(payload_name, "H264")) {
     rtc::CritScope cs(&crit_);
     retransmission_settings_ = kRetransmitBaseLayer | kRetransmitHigherLayers;
   }
@@ -613,7 +611,7 @@
         << "one is required since require_frame_encryptor is set";
   }
 
-  VideoCodecType video_type;
+  absl::optional<VideoCodecType> type;
   {
     rtc::CritScope cs(&payload_type_crit_);
     const auto it = payload_type_map_.find(payload_type);
@@ -622,10 +620,10 @@
                         << " not registered.";
       return false;
     }
-    video_type = it->second;
+    type = it->second;
   }
   std::unique_ptr<RtpPacketizer> packetizer = RtpPacketizer::Create(
-      video_type, rtc::MakeArrayView(payload_data, payload_size), limits,
+      type, rtc::MakeArrayView(payload_data, payload_size), limits,
       *packetize_video_header, frame_type, fragmentation);
 
   const uint8_t temporal_id = GetTemporalId(*video_header);
diff --git a/modules/rtp_rtcp/source/rtp_sender_video.h b/modules/rtp_rtcp/source/rtp_sender_video.h
index cc7c1fa..bdbe90a 100644
--- a/modules/rtp_rtcp/source/rtp_sender_video.h
+++ b/modules/rtp_rtcp/source/rtp_sender_video.h
@@ -71,7 +71,9 @@
                  const RTPVideoHeader* video_header,
                  int64_t expected_retransmission_time_ms);
 
-  void RegisterPayloadType(int8_t payload_type, absl::string_view payload_name);
+  void RegisterPayloadType(int8_t payload_type,
+                           absl::string_view payload_name,
+                           bool raw_payload);
 
   // Set RED and ULPFEC payload types. A payload type of -1 means that the
   // corresponding feature is turned off. Note that we DO NOT support enabling
@@ -162,7 +164,7 @@
   // Maps payload type to codec type, for packetization.
   // TODO(nisse): Set on construction, to avoid lock.
   rtc::CriticalSection payload_type_crit_;
-  std::map<int8_t, VideoCodecType> payload_type_map_
+  std::map<int8_t, absl::optional<VideoCodecType>> payload_type_map_
       RTC_GUARDED_BY(payload_type_crit_);
 
   // Should never be held when calling out of this class.
diff --git a/modules/rtp_rtcp/source/rtp_sender_video_unittest.cc b/modules/rtp_rtcp/source/rtp_sender_video_unittest.cc
index b54934c..9864ecb 100644
--- a/modules/rtp_rtcp/source/rtp_sender_video_unittest.cc
+++ b/modules/rtp_rtcp/source/rtp_sender_video_unittest.cc
@@ -163,7 +163,8 @@
     rtp_sender_.SetTimestampOffset(0);
     rtp_sender_.SetSSRC(kSsrc);
 
-    rtp_sender_video_.RegisterPayloadType(kPayload, "generic");
+    rtp_sender_video_.RegisterPayloadType(kPayload, "generic",
+                                          /*raw_payload=*/false);
   }
 
   void PopulateGenericFrameDescriptor(int version);
@@ -618,7 +619,7 @@
   vp8.keyIdx = 2;
   RTPVideoHeader::GenericDescriptorInfo& generic = hdr.generic.emplace();
   generic.frame_id = kFrameId;
-  rtp_sender_video_.RegisterPayloadType(kPayload, "vp8");
+  rtp_sender_video_.RegisterPayloadType(kPayload, "vp8", /*raw_payload=*/false);
   rtp_sender_video_.SendVideo(VideoFrameType::kVideoFrameDelta, kPayload,
                               kTimestamp, 0, kFrame, sizeof(kFrame), nullptr,
                               &hdr, kDefaultExpectedRetransmissionTimeMs);
diff --git a/video/rtp_video_stream_receiver.cc b/video/rtp_video_stream_receiver.cc
index edced5d..e12bd5c 100644
--- a/video/rtp_video_stream_receiver.cc
+++ b/video/rtp_video_stream_receiver.cc
@@ -193,8 +193,13 @@
 
 void RtpVideoStreamReceiver::AddReceiveCodec(
     const VideoCodec& video_codec,
-    const std::map<std::string, std::string>& codec_params) {
-  pt_codec_type_.emplace(video_codec.plType, video_codec.codecType);
+    const std::map<std::string, std::string>& codec_params,
+    bool raw_payload) {
+  absl::optional<VideoCodecType> video_type;
+  if (!raw_payload) {
+    video_type = video_codec.codecType;
+  }
+  payload_type_map_.emplace(video_codec.plType, video_type);
   pt_codec_params_.emplace(video_codec.plType, codec_params);
 }
 
@@ -503,12 +508,12 @@
     return;
   }
 
-  const auto codec_type_it = pt_codec_type_.find(packet.PayloadType());
-  if (codec_type_it == pt_codec_type_.end()) {
+  const auto type_it = payload_type_map_.find(packet.PayloadType());
+  if (type_it == payload_type_map_.end()) {
     return;
   }
   auto depacketizer =
-      absl::WrapUnique(RtpDepacketizer::Create(codec_type_it->second));
+      absl::WrapUnique(RtpDepacketizer::Create(type_it->second));
 
   if (!depacketizer) {
     RTC_LOG(LS_ERROR) << "Failed to create depacketizer.";
diff --git a/video/rtp_video_stream_receiver.h b/video/rtp_video_stream_receiver.h
index fdacca9..237a514 100644
--- a/video/rtp_video_stream_receiver.h
+++ b/video/rtp_video_stream_receiver.h
@@ -82,7 +82,8 @@
   ~RtpVideoStreamReceiver() override;
 
   void AddReceiveCodec(const VideoCodec& video_codec,
-                       const std::map<std::string, std::string>& codec_params);
+                       const std::map<std::string, std::string>& codec_params,
+                       bool raw_payload);
 
   void StartReceive();
   void StopReceive();
@@ -214,7 +215,9 @@
       RTC_GUARDED_BY(last_seq_num_cs_);
   video_coding::H264SpsPpsTracker tracker_;
 
-  std::map<uint8_t, VideoCodecType> pt_codec_type_;
+  // Maps payload type to codec type, for packetization.
+  std::map<uint8_t, absl::optional<VideoCodecType>> payload_type_map_;
+
   // TODO(johan): Remove pt_codec_params_ once
   // https://bugs.chromium.org/p/webrtc/issues/detail?id=6883 is resolved.
   // Maps a payload type to a map of out-of-band supplied codec parameters.
diff --git a/video/rtp_video_stream_receiver_unittest.cc b/video/rtp_video_stream_receiver_unittest.cc
index 1133560..d9c1071 100644
--- a/video/rtp_video_stream_receiver_unittest.cc
+++ b/video/rtp_video_stream_receiver_unittest.cc
@@ -278,7 +278,8 @@
   codec.plType = kPayloadType;
   codec.codecType = kVideoCodecVP9;
   std::map<std::string, std::string> codec_params;
-  rtp_video_stream_receiver_->AddReceiveCodec(codec, codec_params);
+  rtp_video_stream_receiver_->AddReceiveCodec(codec, codec_params,
+                                              /*raw_payload=*/false);
 
   // Generate key frame packets.
   received_packet_generator.SetPayload(kKeyFramePayload,
@@ -345,7 +346,7 @@
   const uint8_t kRedPayloadType = 125;
   VideoCodec codec;
   codec.plType = kRedPayloadType;
-  rtp_video_stream_receiver_->AddReceiveCodec(codec, {});
+  rtp_video_stream_receiver_->AddReceiveCodec(codec, {}, /*raw_payload=*/false);
   const std::vector<uint8_t> data({
       0x80,              // RTP version.
       kRedPayloadType,   // Payload type.
@@ -469,7 +470,8 @@
   // .
   codec_params.insert(
       {cricket::kH264FmtpSpropParameterSets, "Z0IACpZTBYmI,aMljiA=="});
-  rtp_video_stream_receiver_->AddReceiveCodec(codec, codec_params);
+  rtp_video_stream_receiver_->AddReceiveCodec(codec, codec_params,
+                                              /*raw_payload=*/false);
   const uint8_t binary_sps[] = {0x67, 0x42, 0x00, 0x0a, 0x96,
                                 0x53, 0x05, 0x89, 0x88};
   mock_on_complete_frame_callback_.AppendExpectedBitstream(
@@ -683,7 +685,7 @@
 
   VideoCodec codec;
   codec.plType = kPayloadType;
-  rtp_video_stream_receiver_->AddReceiveCodec(codec, {});
+  rtp_video_stream_receiver_->AddReceiveCodec(codec, {}, /*raw_payload=*/false);
   rtp_video_stream_receiver_->StartReceive();
 
   RtpHeaderExtensionMap extension_map;
@@ -731,7 +733,7 @@
 
   VideoCodec codec;
   codec.plType = kPayloadType;
-  rtp_video_stream_receiver_->AddReceiveCodec(codec, {});
+  rtp_video_stream_receiver_->AddReceiveCodec(codec, {}, /*raw_payload=*/false);
   rtp_video_stream_receiver_->StartReceive();
 
   RtpHeaderExtensionMap extension_map;
@@ -792,7 +794,7 @@
 
   VideoCodec codec;
   codec.plType = kPayloadType;
-  rtp_video_stream_receiver_->AddReceiveCodec(codec, {});
+  rtp_video_stream_receiver_->AddReceiveCodec(codec, {}, /*raw_payload=*/false);
   rtp_video_stream_receiver_->StartReceive();
 
   RtpHeaderExtensionMap extension_map;
@@ -824,6 +826,41 @@
   rtp_video_stream_receiver_->OnRtpPacket(rtp_packet);
 }
 
+TEST_P(RtpVideoStreamReceiverGenericDescriptorTest,
+       ParseGenericDescriptorRawPayload) {
+  const int version = GetParam();
+
+  const std::vector<uint8_t> data = {0, 1, 2, 3, 4};
+  const int kPayloadType = 123;
+
+  VideoCodec codec;
+  codec.plType = kPayloadType;
+  rtp_video_stream_receiver_->AddReceiveCodec(codec, {}, /*raw_payload=*/true);
+  rtp_video_stream_receiver_->StartReceive();
+
+  RtpHeaderExtensionMap extension_map;
+  RegisterRtpGenericFrameDescriptorExtension(&extension_map, version);
+  RtpPacketReceived rtp_packet(&extension_map);
+
+  RtpGenericFrameDescriptor generic_descriptor;
+  generic_descriptor.SetFirstPacketInSubFrame(true);
+  generic_descriptor.SetLastPacketInSubFrame(true);
+  ASSERT_TRUE(SetExtensionRtpGenericFrameDescriptorExtension(
+      generic_descriptor, &rtp_packet, version));
+
+  uint8_t* payload = rtp_packet.SetPayloadSize(data.size());
+  memcpy(payload, data.data(), data.size());
+  mock_on_complete_frame_callback_.AppendExpectedBitstream(data.data(),
+                                                           data.size());
+
+  rtp_packet.SetMarker(true);
+  rtp_packet.SetPayloadType(kPayloadType);
+  rtp_packet.SetSequenceNumber(1);
+
+  EXPECT_CALL(mock_on_complete_frame_callback_, DoOnCompleteFrame);
+  rtp_video_stream_receiver_->OnRtpPacket(rtp_packet);
+}
+
 #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
 TEST_F(RtpVideoStreamReceiverTest, RepeatedSecondarySinkDisallowed) {
   MockRtpPacketSink secondary_sink;
diff --git a/video/video_receive_stream.cc b/video/video_receive_stream.cc
index 20a1967..176b682 100644
--- a/video/video_receive_stream.cc
+++ b/video/video_receive_stream.cc
@@ -367,8 +367,11 @@
     video_receiver_.RegisterExternalDecoder(video_decoders_.back().get(),
                                             decoder.payload_type);
     VideoCodec codec = CreateDecoderVideoCodec(decoder);
-    rtp_video_stream_receiver_.AddReceiveCodec(codec,
-                                               decoder.video_format.parameters);
+
+    const bool raw_payload =
+        config_.rtp.raw_payload_types.count(codec.plType) > 0;
+    rtp_video_stream_receiver_.AddReceiveCodec(
+        codec, decoder.video_format.parameters, raw_payload);
     RTC_CHECK_EQ(VCM_OK, video_receiver_.RegisterReceiveCodec(
                              &codec, num_cpu_cores_, false));
   }