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}
This commit is contained in:
Mirta Dvornicic 2019-05-16 15:51:15 +02:00 committed by Commit Bot
parent 67c76b214d
commit a24d934ee4
5 changed files with 84 additions and 30 deletions

View File

@ -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

View File

@ -35,6 +35,14 @@ RtpPacketizerGeneric::RtpPacketizerGeneric(
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 @@ 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;

View File

@ -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<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 @@ 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_

View File

@ -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<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 @@ 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<const uint8_t>(parsed_payload.payload,
parsed_payload.payload_length),
ElementsAreArray(kPayload));
}
} // namespace
} // namespace webrtc

View File

@ -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);
}