Enable CVO by default through webrtc pipeline.
All RTP packets from sender side will carry the rotation info. (will file a bug to track this) On the receiving side, only packets with marker bit set will be examined. Tests completed: 1. android standalone to android standalone 2. android standalone to chrome (with and without this change) 3. android on chrome BUG=4145 R=glaznev@webrtc.org, mflodman@webrtc.org, perkj@webrtc.org, pthatcher@webrtc.org Committed: https://crrev.com/1b1c15cad16de57053bb6aa8a916079e0534bdae Cr-Commit-Position: refs/heads/master@{#8905} Review URL: https://webrtc-codereview.appspot.com/47399004 Cr-Commit-Position: refs/heads/master@{#8917}
This commit is contained in:
@ -34,6 +34,17 @@ void RtpHeaderExtensionMap::Erase() {
|
||||
|
||||
int32_t RtpHeaderExtensionMap::Register(const RTPExtensionType type,
|
||||
const uint8_t id) {
|
||||
return Register(type, id, true);
|
||||
}
|
||||
|
||||
int32_t RtpHeaderExtensionMap::RegisterInactive(const RTPExtensionType type,
|
||||
const uint8_t id) {
|
||||
return Register(type, id, false);
|
||||
}
|
||||
|
||||
int32_t RtpHeaderExtensionMap::Register(const RTPExtensionType type,
|
||||
const uint8_t id,
|
||||
bool active) {
|
||||
if (id < 1 || id > 14) {
|
||||
return -1;
|
||||
}
|
||||
@ -47,12 +58,24 @@ int32_t RtpHeaderExtensionMap::Register(const RTPExtensionType type,
|
||||
}
|
||||
// This extension type is already registered with this id,
|
||||
// so return success.
|
||||
it->second->active = active;
|
||||
return 0;
|
||||
}
|
||||
extensionMap_[id] = new HeaderExtension(type);
|
||||
extensionMap_[id] = new HeaderExtension(type, active);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool RtpHeaderExtensionMap::SetActive(const RTPExtensionType type,
|
||||
bool active) {
|
||||
for (auto& kv : extensionMap_) {
|
||||
if (kv.second->type == type) {
|
||||
kv.second->active = active;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t RtpHeaderExtensionMap::Deregister(const RTPExtensionType type) {
|
||||
uint8_t id;
|
||||
if (GetId(type, &id) != 0) {
|
||||
@ -113,7 +136,9 @@ size_t RtpHeaderExtensionMap::GetTotalLengthInBytes() const {
|
||||
extensionMap_.begin();
|
||||
while (it != extensionMap_.end()) {
|
||||
HeaderExtension* extension = it->second;
|
||||
length += extension->length;
|
||||
if (extension->active) {
|
||||
length += extension->length;
|
||||
}
|
||||
it++;
|
||||
}
|
||||
// Add RTP extension header length.
|
||||
@ -140,8 +165,11 @@ int32_t RtpHeaderExtensionMap::GetLengthUntilBlockStartInBytes(
|
||||
while (it != extensionMap_.end()) {
|
||||
HeaderExtension* extension = it->second;
|
||||
if (extension->type == type) {
|
||||
if (!extension->active) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
} else if (extension->active) {
|
||||
length += extension->length;
|
||||
}
|
||||
it++;
|
||||
@ -150,17 +178,23 @@ int32_t RtpHeaderExtensionMap::GetLengthUntilBlockStartInBytes(
|
||||
}
|
||||
|
||||
int32_t RtpHeaderExtensionMap::Size() const {
|
||||
return extensionMap_.size();
|
||||
int32_t count = 0;
|
||||
for (auto& kv : extensionMap_) {
|
||||
if (kv.second->active) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
RTPExtensionType RtpHeaderExtensionMap::First() const {
|
||||
std::map<uint8_t, HeaderExtension*>::const_iterator it =
|
||||
extensionMap_.begin();
|
||||
if (it == extensionMap_.end()) {
|
||||
return kRtpExtensionNone;
|
||||
for (auto& kv : extensionMap_) {
|
||||
if (kv.second->active) {
|
||||
return kv.second->type;
|
||||
}
|
||||
}
|
||||
HeaderExtension* extension = it->second;
|
||||
return extension->type;
|
||||
|
||||
return kRtpExtensionNone;
|
||||
}
|
||||
|
||||
RTPExtensionType RtpHeaderExtensionMap::Next(RTPExtensionType type) const {
|
||||
@ -170,15 +204,16 @@ RTPExtensionType RtpHeaderExtensionMap::Next(RTPExtensionType type) const {
|
||||
}
|
||||
std::map<uint8_t, HeaderExtension*>::const_iterator it =
|
||||
extensionMap_.find(id);
|
||||
if (it == extensionMap_.end()) {
|
||||
if (it == extensionMap_.end() || !it->second->active) {
|
||||
return kRtpExtensionNone;
|
||||
}
|
||||
it++;
|
||||
if (it == extensionMap_.end()) {
|
||||
return kRtpExtensionNone;
|
||||
while ((++it) != extensionMap_.end()) {
|
||||
if (it->second->active) {
|
||||
return it->second->type;
|
||||
}
|
||||
}
|
||||
HeaderExtension* extension = it->second;
|
||||
return extension->type;
|
||||
|
||||
return kRtpExtensionNone;
|
||||
}
|
||||
|
||||
void RtpHeaderExtensionMap::GetCopy(RtpHeaderExtensionMap* map) const {
|
||||
@ -187,7 +222,7 @@ void RtpHeaderExtensionMap::GetCopy(RtpHeaderExtensionMap* map) const {
|
||||
extensionMap_.begin();
|
||||
while (it != extensionMap_.end()) {
|
||||
HeaderExtension* extension = it->second;
|
||||
map->Register(extension->type, it->first);
|
||||
map->Register(extension->type, it->first, extension->active);
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,8 +29,16 @@ const size_t kTransportSequenceNumberLength = 3;
|
||||
|
||||
struct HeaderExtension {
|
||||
HeaderExtension(RTPExtensionType extension_type)
|
||||
: type(extension_type),
|
||||
length(0) {
|
||||
: type(extension_type), length(0), active(true) {
|
||||
Init();
|
||||
}
|
||||
|
||||
HeaderExtension(RTPExtensionType extension_type, bool active)
|
||||
: type(extension_type), length(0), active(active) {
|
||||
Init();
|
||||
}
|
||||
|
||||
void Init() {
|
||||
// TODO(solenberg): Create handler classes for header extensions so we can
|
||||
// get rid of switches like these as well as handling code spread out all
|
||||
// over.
|
||||
@ -57,6 +65,7 @@ struct HeaderExtension {
|
||||
|
||||
const RTPExtensionType type;
|
||||
uint8_t length;
|
||||
bool active;
|
||||
};
|
||||
|
||||
class RtpHeaderExtensionMap {
|
||||
@ -68,6 +77,13 @@ class RtpHeaderExtensionMap {
|
||||
|
||||
int32_t Register(const RTPExtensionType type, const uint8_t id);
|
||||
|
||||
// Active is a concept for a registered rtp header extension which doesn't
|
||||
// take effect yet until being activated. Inactive RTP header extensions do
|
||||
// not take effect and should not be included in size calculations until they
|
||||
// are activated.
|
||||
int32_t RegisterInactive(const RTPExtensionType type, const uint8_t id);
|
||||
bool SetActive(const RTPExtensionType type, bool active);
|
||||
|
||||
int32_t Deregister(const RTPExtensionType type);
|
||||
|
||||
bool IsRegistered(RTPExtensionType type) const;
|
||||
@ -76,6 +92,10 @@ class RtpHeaderExtensionMap {
|
||||
|
||||
int32_t GetId(const RTPExtensionType type, uint8_t* id) const;
|
||||
|
||||
//
|
||||
// Methods below ignore any inactive rtp header extensions.
|
||||
//
|
||||
|
||||
size_t GetTotalLengthInBytes() const;
|
||||
|
||||
int32_t GetLengthUntilBlockStartInBytes(const RTPExtensionType type) const;
|
||||
@ -89,6 +109,7 @@ class RtpHeaderExtensionMap {
|
||||
RTPExtensionType Next(RTPExtensionType type) const;
|
||||
|
||||
private:
|
||||
int32_t Register(const RTPExtensionType type, const uint8_t id, bool active);
|
||||
std::map<uint8_t, HeaderExtension*> extensionMap_;
|
||||
};
|
||||
}
|
||||
|
||||
@ -35,9 +35,16 @@ const uint8_t RtpHeaderExtensionTest::kId = 3;
|
||||
TEST_F(RtpHeaderExtensionTest, Register) {
|
||||
EXPECT_EQ(0, map_.Size());
|
||||
EXPECT_EQ(0, map_.Register(kRtpExtensionTransmissionTimeOffset, kId));
|
||||
EXPECT_TRUE(map_.IsRegistered(kRtpExtensionTransmissionTimeOffset));
|
||||
EXPECT_EQ(1, map_.Size());
|
||||
EXPECT_EQ(0, map_.Deregister(kRtpExtensionTransmissionTimeOffset));
|
||||
EXPECT_EQ(0, map_.Size());
|
||||
|
||||
EXPECT_EQ(0, map_.RegisterInactive(kRtpExtensionTransmissionTimeOffset, kId));
|
||||
EXPECT_EQ(0, map_.Size());
|
||||
EXPECT_TRUE(map_.IsRegistered(kRtpExtensionTransmissionTimeOffset));
|
||||
EXPECT_TRUE(map_.SetActive(kRtpExtensionTransmissionTimeOffset, true));
|
||||
EXPECT_EQ(1, map_.Size());
|
||||
}
|
||||
|
||||
TEST_F(RtpHeaderExtensionTest, RegisterIllegalArg) {
|
||||
@ -56,10 +63,14 @@ TEST_F(RtpHeaderExtensionTest, Idempotent) {
|
||||
TEST_F(RtpHeaderExtensionTest, NonUniqueId) {
|
||||
EXPECT_EQ(0, map_.Register(kRtpExtensionTransmissionTimeOffset, kId));
|
||||
EXPECT_EQ(-1, map_.Register(kRtpExtensionAudioLevel, kId));
|
||||
EXPECT_EQ(-1, map_.RegisterInactive(kRtpExtensionAudioLevel, kId));
|
||||
}
|
||||
|
||||
TEST_F(RtpHeaderExtensionTest, GetTotalLength) {
|
||||
EXPECT_EQ(0u, map_.GetTotalLengthInBytes());
|
||||
EXPECT_EQ(0, map_.RegisterInactive(kRtpExtensionTransmissionTimeOffset, kId));
|
||||
EXPECT_EQ(0u, map_.GetTotalLengthInBytes());
|
||||
|
||||
EXPECT_EQ(0, map_.Register(kRtpExtensionTransmissionTimeOffset, kId));
|
||||
EXPECT_EQ(kRtpOneByteHeaderLength + kTransmissionTimeOffsetLength,
|
||||
map_.GetTotalLengthInBytes());
|
||||
@ -68,7 +79,11 @@ TEST_F(RtpHeaderExtensionTest, GetTotalLength) {
|
||||
TEST_F(RtpHeaderExtensionTest, GetLengthUntilBlockStart) {
|
||||
EXPECT_EQ(-1, map_.GetLengthUntilBlockStartInBytes(
|
||||
kRtpExtensionTransmissionTimeOffset));
|
||||
EXPECT_EQ(0, map_.Register(kRtpExtensionTransmissionTimeOffset, kId));
|
||||
EXPECT_EQ(0, map_.RegisterInactive(kRtpExtensionTransmissionTimeOffset, kId));
|
||||
EXPECT_EQ(-1, map_.GetLengthUntilBlockStartInBytes(
|
||||
kRtpExtensionTransmissionTimeOffset));
|
||||
|
||||
EXPECT_TRUE(map_.SetActive(kRtpExtensionTransmissionTimeOffset, true));
|
||||
EXPECT_EQ(static_cast<int>(kRtpOneByteHeaderLength),
|
||||
map_.GetLengthUntilBlockStartInBytes(
|
||||
kRtpExtensionTransmissionTimeOffset));
|
||||
@ -96,7 +111,11 @@ TEST_F(RtpHeaderExtensionTest, IterateTypes) {
|
||||
EXPECT_EQ(kRtpExtensionNone, map_.First());
|
||||
EXPECT_EQ(kRtpExtensionNone, map_.Next(kRtpExtensionTransmissionTimeOffset));
|
||||
|
||||
EXPECT_EQ(0, map_.Register(kRtpExtensionTransmissionTimeOffset, kId));
|
||||
EXPECT_EQ(0, map_.RegisterInactive(kRtpExtensionTransmissionTimeOffset, kId));
|
||||
|
||||
EXPECT_EQ(kRtpExtensionNone, map_.First());
|
||||
|
||||
EXPECT_TRUE(map_.SetActive(kRtpExtensionTransmissionTimeOffset, true));
|
||||
|
||||
EXPECT_EQ(kRtpExtensionTransmissionTimeOffset, map_.First());
|
||||
EXPECT_EQ(kRtpExtensionNone, map_.Next(kRtpExtensionTransmissionTimeOffset));
|
||||
|
||||
@ -63,13 +63,6 @@ int32_t RTPReceiverVideo::ParseRtpPacket(WebRtcRTPHeader* rtp_header,
|
||||
const size_t payload_data_length =
|
||||
payload_length - rtp_header->header.paddingLength;
|
||||
|
||||
// Retrieve the video rotation information.
|
||||
rtp_header->type.Video.rotation = kVideoRotation_0;
|
||||
if (rtp_header->header.extension.hasVideoRotation) {
|
||||
rtp_header->type.Video.rotation = ConvertCVOByteToVideoRotation(
|
||||
rtp_header->header.extension.videoRotation);
|
||||
}
|
||||
|
||||
if (payload == NULL || payload_data_length == 0) {
|
||||
return data_callback_->OnReceivedPayloadData(NULL, 0, rtp_header) == 0 ? 0
|
||||
: -1;
|
||||
@ -90,6 +83,14 @@ int32_t RTPReceiverVideo::ParseRtpPacket(WebRtcRTPHeader* rtp_header,
|
||||
|
||||
rtp_header->frameType = parsed_payload.frame_type;
|
||||
rtp_header->type = parsed_payload.type;
|
||||
rtp_header->type.Video.rotation = kVideoRotation_0;
|
||||
|
||||
// Retrieve the video rotation information.
|
||||
if (rtp_header->header.extension.hasVideoRotation) {
|
||||
rtp_header->type.Video.rotation = ConvertCVOByteToVideoRotation(
|
||||
rtp_header->header.extension.videoRotation);
|
||||
}
|
||||
|
||||
return data_callback_->OnReceivedPayloadData(parsed_payload.payload,
|
||||
parsed_payload.payload_length,
|
||||
rtp_header) == 0
|
||||
|
||||
@ -129,6 +129,7 @@ RTPSender::RTPSender(int32_t id,
|
||||
transmission_time_offset_(0),
|
||||
absolute_send_time_(0),
|
||||
rotation_(kVideoRotation_0),
|
||||
cvo_mode_(kCVONone),
|
||||
transport_sequence_number_(0),
|
||||
// NACK.
|
||||
nack_byte_count_times_(),
|
||||
@ -266,6 +267,10 @@ int32_t RTPSender::SetTransportSequenceNumber(uint16_t sequence_number) {
|
||||
int32_t RTPSender::RegisterRtpHeaderExtension(RTPExtensionType type,
|
||||
uint8_t id) {
|
||||
CriticalSectionScoped cs(send_critsect_.get());
|
||||
if (type == kRtpExtensionVideoRotation) {
|
||||
cvo_mode_ = kCVOInactive;
|
||||
return rtp_header_extension_map_.RegisterInactive(type, id);
|
||||
}
|
||||
return rtp_header_extension_map_.Register(type, id);
|
||||
}
|
||||
|
||||
@ -462,6 +467,16 @@ int32_t RTPSender::CheckPayloadType(int8_t payload_type,
|
||||
return 0;
|
||||
}
|
||||
|
||||
RTPSenderInterface::CVOMode RTPSender::ActivateCVORtpHeaderExtension() {
|
||||
if (cvo_mode_ == kCVOInactive) {
|
||||
CriticalSectionScoped cs(send_critsect_.get());
|
||||
if (rtp_header_extension_map_.SetActive(kRtpExtensionVideoRotation, true)) {
|
||||
cvo_mode_ = kCVOActivated;
|
||||
}
|
||||
}
|
||||
return cvo_mode_;
|
||||
}
|
||||
|
||||
int32_t RTPSender::SendOutgoingData(FrameType frame_type,
|
||||
int8_t payload_type,
|
||||
uint32_t capture_timestamp,
|
||||
@ -1201,8 +1216,7 @@ uint16_t RTPSender::BuildRTPHeaderExtension(uint8_t* data_buffer,
|
||||
block_length = BuildAbsoluteSendTimeExtension(extension_data);
|
||||
break;
|
||||
case kRtpExtensionVideoRotation:
|
||||
if (marker_bit)
|
||||
block_length = BuildVideoRotationExtension(extension_data);
|
||||
block_length = BuildVideoRotationExtension(extension_data);
|
||||
break;
|
||||
case kRtpExtensionTransportSequenceNumber:
|
||||
block_length = BuildTransportSequenceNumberExtension(extension_data);
|
||||
|
||||
@ -41,6 +41,14 @@ class RTPSenderInterface {
|
||||
RTPSenderInterface() {}
|
||||
virtual ~RTPSenderInterface() {}
|
||||
|
||||
enum CVOMode {
|
||||
kCVONone,
|
||||
kCVOInactive, // CVO rtp header extension is registered but haven't
|
||||
// received any frame with rotation pending.
|
||||
kCVOActivated, // CVO rtp header extension will be present in the rtp
|
||||
// packets.
|
||||
};
|
||||
|
||||
virtual uint32_t SSRC() const = 0;
|
||||
virtual uint32_t Timestamp() const = 0;
|
||||
|
||||
@ -70,6 +78,7 @@ class RTPSenderInterface {
|
||||
const RTPHeader& rtp_header,
|
||||
VideoRotation rotation) const = 0;
|
||||
virtual bool IsRtpHeaderExtensionRegistered(RTPExtensionType type) = 0;
|
||||
virtual CVOMode ActivateCVORtpHeaderExtension() = 0;
|
||||
};
|
||||
|
||||
class RTPSender : public RTPSenderInterface {
|
||||
@ -285,6 +294,7 @@ class RTPSender : public RTPSenderInterface {
|
||||
RtpState GetRtpState() const;
|
||||
void SetRtxRtpState(const RtpState& rtp_state);
|
||||
RtpState GetRtxRtpState() const;
|
||||
CVOMode ActivateCVORtpHeaderExtension() override;
|
||||
|
||||
protected:
|
||||
int32_t CheckPayloadType(int8_t payload_type, RtpVideoCodecTypes* video_type);
|
||||
@ -378,6 +388,7 @@ class RTPSender : public RTPSenderInterface {
|
||||
int32_t transmission_time_offset_;
|
||||
uint32_t absolute_send_time_;
|
||||
VideoRotation rotation_;
|
||||
CVOMode cvo_mode_;
|
||||
uint16_t transport_sequence_number_;
|
||||
|
||||
// NACK
|
||||
|
||||
@ -186,7 +186,6 @@ class RtpSenderVideoTest : public RtpSenderTest {
|
||||
}
|
||||
ASSERT_TRUE(rtp_parser.Parse(rtp_header, map));
|
||||
ASSERT_FALSE(rtp_parser.RTCP());
|
||||
EXPECT_EQ(expect_cvo, rtp_header.markerBit);
|
||||
EXPECT_EQ(payload_, rtp_header.payloadType);
|
||||
EXPECT_EQ(seq_num, rtp_header.sequenceNumber);
|
||||
EXPECT_EQ(kTimestamp, rtp_header.timestamp);
|
||||
@ -254,6 +253,7 @@ TEST_F(RtpSenderTest, RegisterRtpHeaderExtensions) {
|
||||
rtp_sender_->RtpHeaderExtensionTotalLength());
|
||||
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
|
||||
kRtpExtensionVideoRotation, kVideoRotationExtensionId));
|
||||
EXPECT_TRUE(rtp_sender_->ActivateCVORtpHeaderExtension());
|
||||
EXPECT_EQ(RtpUtility::Word32Align(kRtpOneByteHeaderLength +
|
||||
kTransmissionTimeOffsetLength +
|
||||
kAbsoluteSendTimeLength +
|
||||
@ -286,6 +286,9 @@ TEST_F(RtpSenderTest, RegisterRtpVideoRotationHeaderExtension) {
|
||||
EXPECT_EQ(0u, rtp_sender_->RtpHeaderExtensionTotalLength());
|
||||
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
|
||||
kRtpExtensionVideoRotation, kVideoRotationExtensionId));
|
||||
EXPECT_EQ(0u, rtp_sender_->RtpHeaderExtensionTotalLength());
|
||||
|
||||
EXPECT_TRUE(rtp_sender_->ActivateCVORtpHeaderExtension());
|
||||
EXPECT_EQ(
|
||||
RtpUtility::Word32Align(kRtpOneByteHeaderLength + kVideoRotationLength),
|
||||
rtp_sender_->RtpHeaderExtensionTotalLength());
|
||||
@ -424,6 +427,7 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithVideoRotation_MarkerBit) {
|
||||
rtp_sender_->SetVideoRotation(kRotation);
|
||||
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
|
||||
kRtpExtensionVideoRotation, kVideoRotationExtensionId));
|
||||
EXPECT_TRUE(rtp_sender_->ActivateCVORtpHeaderExtension());
|
||||
|
||||
RtpHeaderExtensionMap map;
|
||||
map.Register(kRtpExtensionVideoRotation, kVideoRotationExtensionId);
|
||||
@ -447,10 +451,11 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithVideoRotation_MarkerBit) {
|
||||
}
|
||||
|
||||
// Test CVO header extension is not set when marker bit is false.
|
||||
TEST_F(RtpSenderTest, BuildRTPPacketWithVideoRotation_NoMarkerBit) {
|
||||
TEST_F(RtpSenderTest, DISABLED_BuildRTPPacketWithVideoRotation_NoMarkerBit) {
|
||||
rtp_sender_->SetVideoRotation(kRotation);
|
||||
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
|
||||
kRtpExtensionVideoRotation, kVideoRotationExtensionId));
|
||||
EXPECT_TRUE(rtp_sender_->ActivateCVORtpHeaderExtension());
|
||||
|
||||
RtpHeaderExtensionMap map;
|
||||
map.Register(kRtpExtensionVideoRotation, kVideoRotationExtensionId);
|
||||
@ -1333,13 +1338,15 @@ TEST_F(RtpSenderTest, BytesReportedCorrectly) {
|
||||
rtx_stats.transmitted.TotalBytes());
|
||||
}
|
||||
|
||||
// Verify that only the last packet of a frame has CVO byte set.
|
||||
// Verify that all packets of a frame have CVO byte set.
|
||||
TEST_F(RtpSenderVideoTest, SendVideoWithCVO) {
|
||||
RTPVideoHeader hdr = {0};
|
||||
hdr.rotation = kVideoRotation_90;
|
||||
|
||||
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
|
||||
kRtpExtensionVideoRotation, kVideoRotationExtensionId));
|
||||
EXPECT_TRUE(rtp_sender_->ActivateCVORtpHeaderExtension());
|
||||
|
||||
EXPECT_EQ(
|
||||
RtpUtility::Word32Align(kRtpOneByteHeaderLength + kVideoRotationLength),
|
||||
rtp_sender_->RtpHeaderExtensionTotalLength());
|
||||
@ -1351,13 +1358,12 @@ TEST_F(RtpSenderVideoTest, SendVideoWithCVO) {
|
||||
RtpHeaderExtensionMap map;
|
||||
map.Register(kRtpExtensionVideoRotation, kVideoRotationExtensionId);
|
||||
|
||||
// Verify that this packet doesn't have CVO byte.
|
||||
// Verify that this packet does have CVO byte.
|
||||
VerifyCVOPacket(
|
||||
reinterpret_cast<uint8_t*>(transport_.sent_packets_[0]->data()),
|
||||
transport_.sent_packets_[0]->size(), false, &map, kSeqNum,
|
||||
kVideoRotation_0);
|
||||
transport_.sent_packets_[0]->length(), true, &map, kSeqNum, hdr.rotation);
|
||||
|
||||
// Verify that this packet doesn't have CVO byte.
|
||||
// Verify that this packet does have CVO byte.
|
||||
VerifyCVOPacket(
|
||||
reinterpret_cast<uint8_t*>(transport_.sent_packets_[1]->data()),
|
||||
transport_.sent_packets_[1]->size(), true, &map, kSeqNum + 1,
|
||||
|
||||
@ -301,6 +301,13 @@ bool RTPSenderVideo::Send(const RtpVideoCodecTypes videoType,
|
||||
const size_t payloadSize,
|
||||
const RTPFragmentationHeader* fragmentation,
|
||||
const RTPVideoHeader* rtpHdr) {
|
||||
// Register CVO rtp header extension at the first time when we receive a frame
|
||||
// with pending rotation.
|
||||
RTPSenderInterface::CVOMode cvo_mode = RTPSenderInterface::kCVONone;
|
||||
if (rtpHdr && rtpHdr->rotation != kVideoRotation_0) {
|
||||
cvo_mode = _rtpSender.ActivateCVORtpHeaderExtension();
|
||||
}
|
||||
|
||||
uint16_t rtp_header_length = _rtpSender.RTPHeaderLength();
|
||||
size_t payload_bytes_to_send = payloadSize;
|
||||
const uint8_t* data = payloadData;
|
||||
@ -341,13 +348,16 @@ bool RTPSenderVideo::Send(const RtpVideoCodecTypes videoType,
|
||||
// packet in each group of packets which make up another type of frame
|
||||
// (e.g. a P-Frame) only if the current value is different from the previous
|
||||
// value sent.
|
||||
// Here we are adding it to the last packet of every frame at this point.
|
||||
// Here we are adding it to every packet of every frame at this point.
|
||||
if (!rtpHdr) {
|
||||
assert(!_rtpSender.IsRtpHeaderExtensionRegistered(
|
||||
kRtpExtensionVideoRotation));
|
||||
} else if (last) {
|
||||
} else if (cvo_mode == RTPSenderInterface::kCVOActivated) {
|
||||
// Checking whether CVO header extension is registered will require taking
|
||||
// a lock. It'll be a no-op if it's not registered.
|
||||
// TODO(guoweis): For now, all packets sent will carry the CVO such that
|
||||
// the RTP header length is consistent, although the receiver side will
|
||||
// only exam the packets with market bit set.
|
||||
size_t packetSize = payloadSize + rtp_header_length;
|
||||
RtpUtility::RtpHeaderParser rtp_parser(dataBuffer, packetSize);
|
||||
RTPHeader rtp_header;
|
||||
|
||||
Reference in New Issue
Block a user