[VP9] Shift spatial layers on RTP level to always start from 0.
This CL uses |width| and |height| in RTPVideoHeaderVP9 to pass information about enabled layers from encoder to packetizer. Bug: webrtc:11319 Change-Id: Idc1c337f8dfb3f7631506acb784d2a634b41b955 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/167724 Reviewed-by: Danil Chapovalov <danilchap@webrtc.org> Reviewed-by: Niels Moller <nisse@webrtc.org> Commit-Queue: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/master@{#30428}
This commit is contained in:
committed by
Commit Bot
parent
670af2692e
commit
2e73a3d1e9
@ -61,6 +61,7 @@ void PopulateRtpWithCodecSpecifics(const CodecSpecificInfo& info,
|
||||
info.codecSpecific.VP9.inter_layer_predicted;
|
||||
vp9_header.gof_idx = info.codecSpecific.VP9.gof_idx;
|
||||
vp9_header.num_spatial_layers = info.codecSpecific.VP9.num_spatial_layers;
|
||||
vp9_header.first_active_layer = info.codecSpecific.VP9.first_active_layer;
|
||||
if (vp9_header.num_spatial_layers > 1) {
|
||||
vp9_header.spatial_idx = spatial_index.value_or(kNoSpatialIdx);
|
||||
} else {
|
||||
|
||||
@ -280,15 +280,42 @@ bool WriteSsData(const RTPVideoHeaderVP9& vp9, rtc::BitBufferWriter* writer) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO(https://bugs.webrtc.org/11319):
|
||||
// Workaround for switching off spatial layers on the fly.
|
||||
// Sent layers must start from SL0 on RTP layer, but can start from any
|
||||
// spatial layer because WebRTC-SVC api isn't implemented yet and
|
||||
// current API to invoke SVC is not flexible enough.
|
||||
RTPVideoHeaderVP9 RemoveInactiveSpatialLayers(
|
||||
const RTPVideoHeaderVP9& original_header) {
|
||||
RTPVideoHeaderVP9 hdr(original_header);
|
||||
if (original_header.first_active_layer == 0)
|
||||
return hdr;
|
||||
for (size_t i = hdr.first_active_layer; i < hdr.num_spatial_layers; ++i) {
|
||||
hdr.width[i - hdr.first_active_layer] = hdr.width[i];
|
||||
hdr.height[i - hdr.first_active_layer] = hdr.height[i];
|
||||
}
|
||||
for (size_t i = hdr.num_spatial_layers - hdr.first_active_layer;
|
||||
i < hdr.num_spatial_layers; ++i) {
|
||||
hdr.width[i] = 0;
|
||||
hdr.height[i] = 0;
|
||||
}
|
||||
hdr.num_spatial_layers -= hdr.first_active_layer;
|
||||
hdr.spatial_idx -= hdr.first_active_layer;
|
||||
hdr.first_active_layer = 0;
|
||||
return hdr;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
RtpPacketizerVp9::RtpPacketizerVp9(rtc::ArrayView<const uint8_t> payload,
|
||||
PayloadSizeLimits limits,
|
||||
const RTPVideoHeaderVP9& hdr)
|
||||
: hdr_(hdr),
|
||||
: hdr_(RemoveInactiveSpatialLayers(hdr)),
|
||||
header_size_(PayloadDescriptorLengthMinusSsData(hdr_)),
|
||||
first_packet_extra_header_size_(SsDataLength(hdr_)),
|
||||
remaining_payload_(payload) {
|
||||
RTC_DCHECK_EQ(hdr_.first_active_layer, 0);
|
||||
|
||||
limits.max_payload_len -= header_size_;
|
||||
limits.first_packet_reduction_len += first_packet_extra_header_size_;
|
||||
limits.single_packet_reduction_len += first_packet_extra_header_size_;
|
||||
|
||||
@ -169,6 +169,21 @@ class RtpPacketizerVp9Test : public ::testing::Test {
|
||||
expected_.ss_data_available = false;
|
||||
}
|
||||
}
|
||||
|
||||
void CreateParseAndCheckPacketsLayers(size_t num_spatial_layers,
|
||||
size_t expected_layer) {
|
||||
ASSERT_TRUE(packetizer_ != nullptr);
|
||||
for (size_t i = 0; i < num_packets_; ++i) {
|
||||
EXPECT_TRUE(packetizer_->NextPacket(&packet_));
|
||||
RTPVideoHeader video_header;
|
||||
VideoRtpDepacketizerVp9::ParseRtpPayload(packet_.payload(),
|
||||
&video_header);
|
||||
const auto& vp9_header =
|
||||
absl::get<RTPVideoHeaderVP9>(video_header.video_type_header);
|
||||
EXPECT_EQ(vp9_header.spatial_idx, expected_layer);
|
||||
EXPECT_EQ(vp9_header.num_spatial_layers, num_spatial_layers);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(RtpPacketizerVp9Test, TestEqualSizedMode_OnePacket) {
|
||||
@ -546,5 +561,48 @@ TEST_F(RtpPacketizerVp9Test, TestNonRefForInterLayerPred) {
|
||||
CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes);
|
||||
}
|
||||
|
||||
TEST_F(RtpPacketizerVp9Test,
|
||||
ShiftsSpatialLayersTowardZeroWhenFirstLayersAreDisabled) {
|
||||
const size_t kFrameSize = 25;
|
||||
const size_t kPacketSize = 1024;
|
||||
|
||||
expected_.width[0] = 0;
|
||||
expected_.height[0] = 0;
|
||||
expected_.width[1] = 640;
|
||||
expected_.height[1] = 360;
|
||||
expected_.width[2] = 1280;
|
||||
expected_.height[2] = 720;
|
||||
expected_.num_spatial_layers = 3;
|
||||
expected_.first_active_layer = 1;
|
||||
expected_.ss_data_available = true;
|
||||
expected_.spatial_layer_resolution_present = true;
|
||||
expected_.gof.num_frames_in_gof = 3;
|
||||
expected_.gof.temporal_idx[0] = 0;
|
||||
expected_.gof.temporal_idx[1] = 1;
|
||||
expected_.gof.temporal_idx[2] = 2;
|
||||
expected_.gof.temporal_up_switch[0] = true;
|
||||
expected_.gof.temporal_up_switch[1] = true;
|
||||
expected_.gof.temporal_up_switch[2] = false;
|
||||
expected_.gof.num_ref_pics[0] = 0;
|
||||
expected_.gof.num_ref_pics[1] = 3;
|
||||
expected_.gof.num_ref_pics[2] = 2;
|
||||
expected_.gof.pid_diff[1][0] = 5;
|
||||
expected_.gof.pid_diff[1][1] = 6;
|
||||
expected_.gof.pid_diff[1][2] = 7;
|
||||
expected_.gof.pid_diff[2][0] = 8;
|
||||
expected_.gof.pid_diff[2][1] = 9;
|
||||
|
||||
expected_.spatial_idx = 1;
|
||||
Init(kFrameSize, kPacketSize);
|
||||
CreateParseAndCheckPacketsLayers(/*num_spatial_layers=*/2,
|
||||
/*expected_layer=*/0);
|
||||
|
||||
// Now check for SL 2;
|
||||
expected_.spatial_idx = 2;
|
||||
Init(kFrameSize, kPacketSize);
|
||||
CreateParseAndCheckPacketsLayers(/*num_spatial_layers=*/2,
|
||||
/*expected_layer=*/1);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace webrtc
|
||||
|
||||
@ -173,6 +173,7 @@ struct RTPVideoHeaderVP9 {
|
||||
gof_idx = kNoGofIdx;
|
||||
num_ref_pics = 0;
|
||||
num_spatial_layers = 1;
|
||||
first_active_layer = 0;
|
||||
end_of_picture = true;
|
||||
}
|
||||
|
||||
@ -208,6 +209,7 @@ struct RTPVideoHeaderVP9 {
|
||||
|
||||
// SS data.
|
||||
size_t num_spatial_layers; // Always populated.
|
||||
size_t first_active_layer; // Not sent on wire, used to adjust ss data.
|
||||
bool spatial_layer_resolution_present;
|
||||
uint16_t width[kMaxVp9NumberOfSpatialLayers];
|
||||
uint16_t height[kMaxVp9NumberOfSpatialLayers];
|
||||
|
||||
@ -1113,6 +1113,7 @@ void VP9EncoderImpl::PopulateCodecSpecific(CodecSpecificInfo* codec_specific,
|
||||
// Always populate this, so that the packetizer can properly set the marker
|
||||
// bit.
|
||||
vp9_info->num_spatial_layers = num_active_spatial_layers_;
|
||||
vp9_info->first_active_layer = first_active_layer_;
|
||||
|
||||
vp9_info->num_ref_pics = 0;
|
||||
FillReferenceIndices(pkt, pics_since_key_, vp9_info->inter_layer_predicted,
|
||||
|
||||
@ -69,6 +69,7 @@ struct CodecSpecificInfoVP9 {
|
||||
|
||||
// SS data.
|
||||
size_t num_spatial_layers; // Always populated.
|
||||
size_t first_active_layer;
|
||||
bool spatial_layer_resolution_present;
|
||||
uint16_t width[kMaxVp9NumberOfSpatialLayers];
|
||||
uint16_t height[kMaxVp9NumberOfSpatialLayers];
|
||||
|
||||
Reference in New Issue
Block a user