diff --git a/modules/rtp_rtcp/source/rtp_format.cc b/modules/rtp_rtcp/source/rtp_format.cc index 7375a63d50..843cbb85fa 100644 --- a/modules/rtp_rtcp/source/rtp_format.cc +++ b/modules/rtp_rtcp/source/rtp_format.cc @@ -142,7 +142,7 @@ RtpDepacketizer* RtpDepacketizer::Create(VideoCodecType type) { 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 171c5ff018..a45597de44 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 @@ RtpPacketizerGeneric::RtpPacketizerGeneric( current_packet_ = payload_sizes_.begin(); } +RtpPacketizerGeneric::RtpPacketizerGeneric( + rtc::ArrayView 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 @@ bool RtpPacketizerGeneric::NextPacket(RtpPacketToSend* packet) { 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 @@ void RtpPacketizerGeneric::BuildHeader(const RTPVideoHeader& rtp_video_header, 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 @@ void RtpPacketizerGeneric::BuildHeader(const RTPVideoHeader& rtp_video_header, } } +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 @@ bool RtpDepacketizerGeneric::Parse(ParsedPayload* parsed_payload, 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 6406b74a9c..4e21c96fea 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 @@ class RtpPacketizerGeneric : public RtpPacketizer { 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 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 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 @@ class RtpPacketizerGeneric : public RtpPacketizer { // 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 fa274dd6cc..d43af778e3 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 @@ TEST(RtpPacketizerVideoGeneric, NoFrameIdDoesNotWriteExtendedHeader) { 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 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 @@ TEST(RtpDepacketizerVideoGeneric, ExtendedHeaderParsesFrameId) { 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 @@ TEST(RtpDepacketizerVideoGeneric, ExtendedHeaderParsesFrameId) { 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(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 4775501b36..6b98b411f4 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); }