Generic Frame Descriptor (GFD) VP8 templates.

In this CL:
 - Updated Vp8TemporalLayers::OnEncodeDone to take a CodecSpecificInfo
   instead of a CodecSpecificInfoVP8, so that both the VP8 specific and
   generic information can be populated.
 - Added structs to represent the GFD template structure.
 - Added code to generate templates for video/screensharing.

Bug: webrtc:10342
Change-Id: I978f9d708597a6f86bbdc494e62acf7a7b400db3
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/123422
Commit-Queue: Philip Eliasson <philipel@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Reviewed-by: Stefan Holmer <stefan@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26987}
This commit is contained in:
philipel
2019-03-04 16:37:50 +01:00
committed by Commit Bot
parent 8fb1a6ad27
commit 9df335374a
17 changed files with 441 additions and 150 deletions

View File

@ -444,7 +444,7 @@ void DefaultTemporalLayers::OnEncodeDone(uint32_t rtp_timestamp,
size_t size_bytes,
bool is_keyframe,
int qp,
CodecSpecificInfoVP8* vp8_info) {
CodecSpecificInfo* info) {
RTC_DCHECK_GT(num_layers_, 0);
auto pending_frame = pending_frames_.find(rtp_timestamp);
@ -463,15 +463,16 @@ void DefaultTemporalLayers::OnEncodeDone(uint32_t rtp_timestamp,
}
#endif
CodecSpecificInfoVP8& vp8_info = info->codecSpecific.VP8;
if (num_layers_ == 1) {
vp8_info->temporalIdx = kNoTemporalIdx;
vp8_info->layerSync = false;
vp8_info.temporalIdx = kNoTemporalIdx;
vp8_info.layerSync = false;
} else {
if (is_keyframe) {
// Restart the temporal pattern on keyframes.
pattern_idx_ = 0;
vp8_info->temporalIdx = 0;
vp8_info->layerSync = true; // Keyframes are always sync frames.
vp8_info.temporalIdx = 0;
vp8_info.layerSync = true; // Keyframes are always sync frames.
for (Vp8BufferReference buffer : kAllBuffers) {
if (kf_buffers_.find(buffer) != kf_buffers_.end()) {
@ -486,29 +487,35 @@ void DefaultTemporalLayers::OnEncodeDone(uint32_t rtp_timestamp,
}
} else {
// Delta frame, update codec specifics with temporal id and sync flag.
vp8_info->temporalIdx = frame.frame_config.packetizer_temporal_idx;
vp8_info->layerSync = frame.frame_config.layer_sync;
vp8_info.temporalIdx = frame.frame_config.packetizer_temporal_idx;
vp8_info.layerSync = frame.frame_config.layer_sync;
}
}
vp8_info->useExplicitDependencies = true;
RTC_DCHECK_EQ(vp8_info->referencedBuffersCount, 0u);
RTC_DCHECK_EQ(vp8_info->updatedBuffersCount, 0u);
vp8_info.useExplicitDependencies = true;
RTC_DCHECK_EQ(vp8_info.referencedBuffersCount, 0u);
RTC_DCHECK_EQ(vp8_info.updatedBuffersCount, 0u);
for (int i = 0; i < static_cast<int>(Buffer::kCount); ++i) {
if (!is_keyframe && frame.frame_config.References(static_cast<Buffer>(i))) {
RTC_DCHECK_LT(vp8_info->referencedBuffersCount,
RTC_DCHECK_LT(vp8_info.referencedBuffersCount,
arraysize(CodecSpecificInfoVP8::referencedBuffers));
vp8_info->referencedBuffers[vp8_info->referencedBuffersCount++] = i;
vp8_info.referencedBuffers[vp8_info.referencedBuffersCount++] = i;
}
if (is_keyframe || frame.frame_config.Updates(static_cast<Buffer>(i))) {
RTC_DCHECK_LT(vp8_info->updatedBuffersCount,
RTC_DCHECK_LT(vp8_info.updatedBuffersCount,
arraysize(CodecSpecificInfoVP8::updatedBuffers));
vp8_info->updatedBuffers[vp8_info->updatedBuffersCount++] = i;
vp8_info.updatedBuffers[vp8_info.updatedBuffersCount++] = i;
}
}
// The templates are always present on keyframes, and then refered to by
// subsequent frames.
if (is_keyframe) {
info->template_structure = GetTemplateStructure(num_layers_);
}
if (!frame.expired) {
for (Vp8BufferReference buffer : kAllBuffers) {
if (frame.updated_buffer_mask & static_cast<uint8_t>(buffer)) {
@ -518,6 +525,65 @@ void DefaultTemporalLayers::OnEncodeDone(uint32_t rtp_timestamp,
}
}
TemplateStructure DefaultTemporalLayers::GetTemplateStructure(
int num_layers) const {
RTC_CHECK_LT(num_layers, 5);
RTC_CHECK_GT(num_layers, 0);
TemplateStructure template_structure;
template_structure.num_operating_points = num_layers;
using Builder = GenericFrameInfo::Builder;
switch (num_layers) {
case 1: {
template_structure.templates = {
Builder().T(0).Dtis("S").Build(),
Builder().T(0).Dtis("S").Fdiffs({1}).Build(),
};
return template_structure;
}
case 2: {
template_structure.templates = {
Builder().T(0).Dtis("SS").Build(),
Builder().T(0).Dtis("SS").Fdiffs({2}).Build(),
Builder().T(0).Dtis("SR").Fdiffs({2}).Build(),
Builder().T(1).Dtis("-S").Fdiffs({1}).Build(),
Builder().T(1).Dtis("-D").Fdiffs({1, 2}).Build(),
};
return template_structure;
}
case 3: {
template_structure.templates = {
Builder().T(0).Dtis("SSS").Build(),
Builder().T(0).Dtis("SSS").Fdiffs({4}).Build(),
Builder().T(0).Dtis("SRR").Fdiffs({4}).Build(),
Builder().T(1).Dtis("-SR").Fdiffs({2}).Build(),
Builder().T(1).Dtis("-DR").Fdiffs({2, 4}).Build(),
Builder().T(2).Dtis("--D").Fdiffs({1}).Build(),
Builder().T(2).Dtis("--D").Fdiffs({1, 3}).Build(),
};
return template_structure;
}
case 4: {
template_structure.templates = {
Builder().T(0).Dtis("SSSS").Build(),
Builder().T(0).Dtis("SSSS").Fdiffs({8}).Build(),
Builder().T(1).Dtis("-SRR").Fdiffs({4}).Build(),
Builder().T(1).Dtis("-SRR").Fdiffs({4, 8}).Build(),
Builder().T(2).Dtis("--SR").Fdiffs({2}).Build(),
Builder().T(2).Dtis("--SR").Fdiffs({2, 4}).Build(),
Builder().T(3).Dtis("---D").Fdiffs({1}).Build(),
Builder().T(3).Dtis("---D").Fdiffs({1, 3}).Build(),
};
return template_structure;
}
default:
RTC_NOTREACHED();
// To make the compiler happy!
return template_structure;
}
}
// Returns list of temporal dependencies for each frame in the temporal pattern.
// Values are lists of indecies in the pattern.
std::vector<std::set<uint8_t>> GetTemporalDependencies(

View File

@ -49,7 +49,7 @@ class DefaultTemporalLayers : public Vp8TemporalLayers {
size_t size_bytes,
bool is_keyframe,
int qp,
CodecSpecificInfoVP8* vp8_info) override;
CodecSpecificInfo* info) override;
private:
static constexpr size_t kKeyframeBuffer = std::numeric_limits<size_t>::max();
@ -64,6 +64,7 @@ class DefaultTemporalLayers : public Vp8TemporalLayers {
const std::vector<Vp8FrameConfig> temporal_pattern_;
// Set of buffers that are never updated except by keyframes.
const std::set<Vp8FrameConfig::Vp8BufferReference> kf_buffers_;
TemplateStructure GetTemplateStructure(int num_layers) const;
uint8_t pattern_idx_;
// Updated cumulative bitrates, per temporal layer.

View File

@ -107,9 +107,9 @@ class TemporalLayersTest : public ::testing::Test {
public:
~TemporalLayersTest() override = default;
CodecSpecificInfoVP8* IgnoredCodecSpecificInfoVp8() {
CodecSpecificInfo* IgnoredCodecSpecificInfo() {
codec_specific_info_ = absl::make_unique<CodecSpecificInfo>();
return &codec_specific_info_->codecSpecific.VP8;
return codec_specific_info_.get();
}
private:
@ -142,17 +142,17 @@ TEST_F(TemporalLayersTest, 2Layers) {
for (size_t i = 0; i < kPatternSize * kRepetitions; ++i) {
const size_t ind = i % kPatternSize;
CodecSpecificInfo info;
CodecSpecificInfoVP8& vp8_info = info.codecSpecific.VP8;
Vp8FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
EXPECT_EQ(expected_flags[ind], LibvpxVp8Encoder::EncodeFlags(tl_config))
<< i;
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, i == 0, kDefaultQp,
&vp8_info);
&info);
EXPECT_TRUE(checker.CheckTemporalConfig(i == 0, tl_config));
EXPECT_EQ(expected_temporal_idx[ind], vp8_info.temporalIdx);
EXPECT_EQ(expected_temporal_idx[ind], info.codecSpecific.VP8.temporalIdx);
EXPECT_EQ(expected_temporal_idx[ind], tl_config.packetizer_temporal_idx);
EXPECT_EQ(expected_temporal_idx[ind], tl_config.encoder_layer_id);
EXPECT_EQ(i == 0 || expected_layer_sync[ind], vp8_info.layerSync);
EXPECT_EQ(i == 0 || expected_layer_sync[ind],
info.codecSpecific.VP8.layerSync);
EXPECT_EQ(expected_layer_sync[ind], tl_config.layer_sync);
timestamp += 3000;
}
@ -196,16 +196,16 @@ TEST_F(TemporalLayersTest, 3Layers) {
unsigned int timestamp = 0;
for (int i = 0; i < 16; ++i) {
CodecSpecificInfo info;
CodecSpecificInfoVP8& vp8_info = info.codecSpecific.VP8;
Vp8FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
EXPECT_EQ(expected_flags[i], LibvpxVp8Encoder::EncodeFlags(tl_config)) << i;
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, i == 0, kDefaultQp,
&vp8_info);
&info);
EXPECT_TRUE(checker.CheckTemporalConfig(i == 0, tl_config));
EXPECT_EQ(expected_temporal_idx[i], vp8_info.temporalIdx);
EXPECT_EQ(expected_temporal_idx[i], info.codecSpecific.VP8.temporalIdx);
EXPECT_EQ(expected_temporal_idx[i], tl_config.packetizer_temporal_idx);
EXPECT_EQ(expected_temporal_idx[i], tl_config.encoder_layer_id);
EXPECT_EQ(i == 0 || expected_layer_sync[i], vp8_info.layerSync);
EXPECT_EQ(i == 0 || expected_layer_sync[i],
info.codecSpecific.VP8.layerSync);
EXPECT_EQ(expected_layer_sync[i], tl_config.layer_sync);
timestamp += 3000;
}
@ -238,16 +238,16 @@ TEST_F(TemporalLayersTest, Alternative3Layers) {
unsigned int timestamp = 0;
for (int i = 0; i < 8; ++i) {
CodecSpecificInfo info;
CodecSpecificInfoVP8& vp8_info = info.codecSpecific.VP8;
Vp8FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
EXPECT_EQ(expected_flags[i], LibvpxVp8Encoder::EncodeFlags(tl_config)) << i;
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, i == 0, kDefaultQp,
&vp8_info);
&info);
EXPECT_TRUE(checker.CheckTemporalConfig(i == 0, tl_config));
EXPECT_EQ(expected_temporal_idx[i], vp8_info.temporalIdx);
EXPECT_EQ(expected_temporal_idx[i], info.codecSpecific.VP8.temporalIdx);
EXPECT_EQ(expected_temporal_idx[i], tl_config.packetizer_temporal_idx);
EXPECT_EQ(expected_temporal_idx[i], tl_config.encoder_layer_id);
EXPECT_EQ(i == 0 || expected_layer_sync[i], vp8_info.layerSync);
EXPECT_EQ(i == 0 || expected_layer_sync[i],
info.codecSpecific.VP8.layerSync);
EXPECT_EQ(expected_layer_sync[i], tl_config.layer_sync);
timestamp += 3000;
}
@ -271,19 +271,19 @@ TEST_F(TemporalLayersTest, SearchOrder) {
uint32_t timestamp = 0;
Vp8FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, true, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
// TL2 frame. First one only references TL0. Updates altref.
tl_config = tl.UpdateLayerConfig(++timestamp);
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
EXPECT_EQ(tl_config.first_reference, Vp8BufferReference::kLast);
EXPECT_EQ(tl_config.second_reference, Vp8BufferReference::kNone);
// TL1 frame. Can only reference TL0. Updated golden.
tl_config = tl.UpdateLayerConfig(++timestamp);
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
EXPECT_EQ(tl_config.first_reference, Vp8BufferReference::kLast);
EXPECT_EQ(tl_config.second_reference, Vp8BufferReference::kNone);
@ -291,7 +291,7 @@ TEST_F(TemporalLayersTest, SearchOrder) {
// updated, the next to last was altref.
tl_config = tl.UpdateLayerConfig(++timestamp);
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
EXPECT_EQ(tl_config.first_reference, Vp8BufferReference::kGolden);
EXPECT_EQ(tl_config.second_reference, Vp8BufferReference::kAltref);
}
@ -314,12 +314,12 @@ TEST_F(TemporalLayersTest, SearchOrderWithDrop) {
uint32_t timestamp = 0;
Vp8FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, true, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
// TL2 frame. First one only references TL0. Updates altref.
tl_config = tl.UpdateLayerConfig(++timestamp);
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
EXPECT_EQ(tl_config.first_reference, Vp8BufferReference::kLast);
EXPECT_EQ(tl_config.second_reference, Vp8BufferReference::kNone);
@ -331,7 +331,7 @@ TEST_F(TemporalLayersTest, SearchOrderWithDrop) {
// been populated this cycle. Altref was last to be updated, before that last.
tl_config = tl.UpdateLayerConfig(++timestamp);
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
EXPECT_EQ(tl_config.first_reference, Vp8BufferReference::kAltref);
EXPECT_EQ(tl_config.second_reference, Vp8BufferReference::kLast);
}
@ -373,16 +373,16 @@ TEST_F(TemporalLayersTest, 4Layers) {
uint32_t timestamp = 0;
for (int i = 0; i < 16; ++i) {
CodecSpecificInfo info;
CodecSpecificInfoVP8& vp8_info = info.codecSpecific.VP8;
Vp8FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
EXPECT_EQ(expected_flags[i], LibvpxVp8Encoder::EncodeFlags(tl_config)) << i;
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, i == 0, kDefaultQp,
&vp8_info);
&info);
EXPECT_TRUE(checker.CheckTemporalConfig(i == 0, tl_config));
EXPECT_EQ(expected_temporal_idx[i], vp8_info.temporalIdx);
EXPECT_EQ(expected_temporal_idx[i], info.codecSpecific.VP8.temporalIdx);
EXPECT_EQ(expected_temporal_idx[i], tl_config.packetizer_temporal_idx);
EXPECT_EQ(expected_temporal_idx[i], tl_config.encoder_layer_id);
EXPECT_EQ(i == 0 || expected_layer_sync[i], vp8_info.layerSync);
EXPECT_EQ(i == 0 || expected_layer_sync[i],
info.codecSpecific.VP8.layerSync);
EXPECT_EQ(expected_layer_sync[i], tl_config.layer_sync);
timestamp += 3000;
}
@ -405,7 +405,7 @@ TEST_F(TemporalLayersTest, DoesNotReferenceDroppedFrames) {
uint32_t timestamp = 0;
Vp8FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, true, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
// Dropped TL2 frame.
tl_config = tl.UpdateLayerConfig(++timestamp);
@ -419,7 +419,7 @@ TEST_F(TemporalLayersTest, DoesNotReferenceDroppedFrames) {
// both contain the last keyframe.
tl_config = tl.UpdateLayerConfig(++timestamp);
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
EXPECT_TRUE(tl_config.last_buffer_flags & BufferFlags::kReference);
EXPECT_TRUE(tl_config.golden_buffer_flags & BufferFlags::kReference);
EXPECT_TRUE(tl_config.arf_buffer_flags & BufferFlags::kReference);
@ -429,23 +429,23 @@ TEST_F(TemporalLayersTest, DoesNotReferenceDroppedFrames) {
// TL0 base layer frame, updating and referencing last.
tl_config = tl.UpdateLayerConfig(++timestamp);
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
// TL2 frame, updating altref.
tl_config = tl.UpdateLayerConfig(++timestamp);
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
// TL1 frame, updating golden.
tl_config = tl.UpdateLayerConfig(++timestamp);
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
// TL2 frame. Can still reference all buffer since they have been update this
// cycle.
tl_config = tl.UpdateLayerConfig(++timestamp);
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
EXPECT_TRUE(tl_config.last_buffer_flags & BufferFlags::kReference);
EXPECT_TRUE(tl_config.golden_buffer_flags & BufferFlags::kReference);
EXPECT_TRUE(tl_config.arf_buffer_flags & BufferFlags::kReference);
@ -455,7 +455,7 @@ TEST_F(TemporalLayersTest, DoesNotReferenceDroppedFrames) {
// TL0 base layer frame, updating and referencing last.
tl_config = tl.UpdateLayerConfig(++timestamp);
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
// Dropped TL2 frame.
tl_config = tl.UpdateLayerConfig(++timestamp);
@ -469,7 +469,7 @@ TEST_F(TemporalLayersTest, DoesNotReferenceDroppedFrames) {
// and cannot be referenced.
tl_config = tl.UpdateLayerConfig(++timestamp);
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
EXPECT_TRUE(tl_config.last_buffer_flags & BufferFlags::kReference);
EXPECT_FALSE(tl_config.golden_buffer_flags & BufferFlags::kReference);
EXPECT_FALSE(tl_config.arf_buffer_flags & BufferFlags::kReference);
@ -491,24 +491,24 @@ TEST_F(TemporalLayersTest, DoesNotReferenceUnlessGuaranteedToExist) {
uint32_t timestamp = 0;
Vp8FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, true, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
// Do a full cycle of the pattern.
for (int i = 0; i < 7; ++i) {
tl_config = tl.UpdateLayerConfig(++timestamp);
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
}
// TL0 base layer frame, starting the cycle over.
tl_config = tl.UpdateLayerConfig(++timestamp);
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
// TL2 frame.
tl_config = tl.UpdateLayerConfig(++timestamp);
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
// Encoder has a hiccup and builds a queue, so frame encoding is delayed.
// TL1 frame, updating golden.
@ -528,13 +528,13 @@ TEST_F(TemporalLayersTest, DoesNotReferenceUnlessGuaranteedToExist) {
// buffers are now OK to reference.
// Enqueued TL1 frame ready.
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
// Enqueued TL2 frame.
tl.OnEncodeDone(++timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
// Enqueued TL0 frame.
tl.OnEncodeDone(++timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
// TL2 frame, all buffers are now in a known good state, OK to reference.
tl_config = tl.UpdateLayerConfig(++timestamp + 1);
@ -560,24 +560,24 @@ TEST_F(TemporalLayersTest, DoesNotReferenceUnlessGuaranteedToExistLongDelay) {
uint32_t timestamp = 0;
Vp8FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, true, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
// Do a full cycle of the pattern.
for (int i = 0; i < 3; ++i) {
tl_config = tl.UpdateLayerConfig(++timestamp);
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
}
// TL0 base layer frame, starting the cycle over.
tl_config = tl.UpdateLayerConfig(++timestamp);
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
// TL2 frame.
tl_config = tl.UpdateLayerConfig(++timestamp);
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
// Encoder has a hiccup and builds a queue, so frame encoding is delayed.
// Encoded, but delayed frames in TL 1, 2.
@ -592,10 +592,10 @@ TEST_F(TemporalLayersTest, DoesNotReferenceUnlessGuaranteedToExistLongDelay) {
// TL1 frame from last cycle is ready.
tl.OnEncodeDone(timestamp + 1, kDefaultBytesPerFrame, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
// TL2 frame from last cycle is ready.
tl.OnEncodeDone(timestamp + 2, kDefaultBytesPerFrame, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
// TL2 frame, that should be referencing all buffers, but altref and golden
// haven not been updated this cycle. (Don't be fooled by the late frames from
@ -641,7 +641,7 @@ TEST_F(TemporalLayersTest, KeyFrame) {
EXPECT_EQ(expected_flags[j], LibvpxVp8Encoder::EncodeFlags(tl_config))
<< j;
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
EXPECT_TRUE(checker.CheckTemporalConfig(false, tl_config));
EXPECT_EQ(expected_temporal_idx[j], tl_config.packetizer_temporal_idx);
EXPECT_EQ(expected_temporal_idx[j], tl_config.encoder_layer_id);
@ -650,12 +650,11 @@ TEST_F(TemporalLayersTest, KeyFrame) {
}
CodecSpecificInfo info;
CodecSpecificInfoVP8& vp8_info = info.codecSpecific.VP8;
Vp8FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, true, kDefaultQp,
&vp8_info);
EXPECT_TRUE(vp8_info.layerSync) << "Key frame should be marked layer sync.";
EXPECT_EQ(0, vp8_info.temporalIdx)
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, true, kDefaultQp, &info);
EXPECT_TRUE(info.codecSpecific.VP8.layerSync)
<< "Key frame should be marked layer sync.";
EXPECT_EQ(0, info.codecSpecific.VP8.temporalIdx)
<< "Key frame should always be packetized as layer 0";
EXPECT_TRUE(checker.CheckTemporalConfig(true, tl_config));
}
@ -741,7 +740,7 @@ TEST_P(TemporalLayersReferenceTest, ValidFrameConfigs) {
for (int i = 0; i < kMaxPatternLength; ++i) {
Vp8FrameConfig tl_config = tl.UpdateLayerConfig(timestamp_);
tl.OnEncodeDone(timestamp_, kDefaultBytesPerFrame, i == 0, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
++timestamp_;
EXPECT_FALSE(tl_config.drop_frame);
tl_configs.push_back(tl_config);

View File

@ -850,15 +850,16 @@ void LibvpxVp8Encoder::PopulateCodecSpecific(CodecSpecificInfo* codec_specific,
uint32_t timestamp) {
assert(codec_specific != NULL);
codec_specific->codecType = kVideoCodecVP8;
CodecSpecificInfoVP8* vp8Info = &(codec_specific->codecSpecific.VP8);
vp8Info->keyIdx = kNoKeyIdx; // TODO(hlundin) populate this
vp8Info->nonReference = (pkt.data.frame.flags & VPX_FRAME_IS_DROPPABLE) != 0;
codec_specific->codecSpecific.VP8.keyIdx =
kNoKeyIdx; // TODO(hlundin) populate this
codec_specific->codecSpecific.VP8.nonReference =
(pkt.data.frame.flags & VPX_FRAME_IS_DROPPABLE) != 0;
int qp = 0;
vpx_codec_control(&encoders_[encoder_idx], VP8E_GET_LAST_QUANTIZER_64, &qp);
temporal_layers_[stream_idx]->OnEncodeDone(
timestamp, encoded_images_[encoder_idx].size(),
(pkt.data.frame.flags & VPX_FRAME_IS_KEY) != 0, qp, vp8Info);
(pkt.data.frame.flags & VPX_FRAME_IS_KEY) != 0, qp, codec_specific);
}
int LibvpxVp8Encoder::GetEncodedPartitions(const VideoFrame& input_image) {

View File

@ -265,7 +265,7 @@ void ScreenshareLayers::OnEncodeDone(uint32_t rtp_timestamp,
size_t size_bytes,
bool is_keyframe,
int qp,
CodecSpecificInfoVP8* vp8_info) {
CodecSpecificInfo* info) {
if (size_bytes == 0) {
layers_[active_layer_].state = TemporalLayer::State::kDropped;
++stats_.num_overshoots_;
@ -283,44 +283,47 @@ void ScreenshareLayers::OnEncodeDone(uint32_t rtp_timestamp,
}
}
CodecSpecificInfoVP8& vp8_info = info->codecSpecific.VP8;
if (number_of_temporal_layers_ == 1) {
vp8_info->temporalIdx = kNoTemporalIdx;
vp8_info->layerSync = false;
vp8_info.temporalIdx = kNoTemporalIdx;
vp8_info.layerSync = false;
} else {
int64_t unwrapped_timestamp = time_wrap_handler_.Unwrap(rtp_timestamp);
if (frame_config) {
vp8_info->temporalIdx = frame_config->packetizer_temporal_idx;
vp8_info->layerSync = frame_config->layer_sync;
vp8_info.temporalIdx = frame_config->packetizer_temporal_idx;
vp8_info.layerSync = frame_config->layer_sync;
} else {
RTC_DCHECK(is_keyframe);
}
if (is_keyframe) {
vp8_info->temporalIdx = 0;
vp8_info.temporalIdx = 0;
last_sync_timestamp_ = unwrapped_timestamp;
vp8_info->layerSync = true;
vp8_info.layerSync = true;
layers_[0].state = TemporalLayer::State::kKeyFrame;
layers_[1].state = TemporalLayer::State::kKeyFrame;
active_layer_ = 1;
info->template_structure =
GetTemplateStructure(number_of_temporal_layers_);
}
vp8_info->useExplicitDependencies = true;
RTC_DCHECK_EQ(vp8_info->referencedBuffersCount, 0u);
RTC_DCHECK_EQ(vp8_info->updatedBuffersCount, 0u);
vp8_info.useExplicitDependencies = true;
RTC_DCHECK_EQ(vp8_info.referencedBuffersCount, 0u);
RTC_DCHECK_EQ(vp8_info.updatedBuffersCount, 0u);
// Note that |frame_config| is not derefernced if |is_keyframe|,
// meaning it's never dereferenced if the optional may be unset.
for (int i = 0; i < static_cast<int>(Buffer::kCount); ++i) {
if (!is_keyframe && frame_config->References(static_cast<Buffer>(i))) {
RTC_DCHECK_LT(vp8_info->referencedBuffersCount,
RTC_DCHECK_LT(vp8_info.referencedBuffersCount,
arraysize(CodecSpecificInfoVP8::referencedBuffers));
vp8_info->referencedBuffers[vp8_info->referencedBuffersCount++] = i;
vp8_info.referencedBuffers[vp8_info.referencedBuffersCount++] = i;
}
if (is_keyframe || frame_config->Updates(static_cast<Buffer>(i))) {
RTC_DCHECK_LT(vp8_info->updatedBuffersCount,
RTC_DCHECK_LT(vp8_info.updatedBuffersCount,
arraysize(CodecSpecificInfoVP8::updatedBuffers));
vp8_info->updatedBuffers[vp8_info->updatedBuffersCount++] = i;
vp8_info.updatedBuffers[vp8_info.updatedBuffersCount++] = i;
}
}
}
@ -352,6 +355,38 @@ void ScreenshareLayers::OnEncodeDone(uint32_t rtp_timestamp,
}
}
TemplateStructure ScreenshareLayers::GetTemplateStructure(
int num_layers) const {
RTC_CHECK_LT(num_layers, 3);
RTC_CHECK_GT(num_layers, 0);
TemplateStructure template_structure;
template_structure.num_operating_points = num_layers;
using Builder = GenericFrameInfo::Builder;
switch (num_layers) {
case 1: {
template_structure.templates = {
Builder().T(0).Dtis("S").Build(),
Builder().T(0).Dtis("S").Fdiffs({1}).Build(),
};
return template_structure;
}
case 2: {
template_structure.templates = {
Builder().T(0).Dtis("SS").Build(),
Builder().T(0).Dtis("SS").Fdiffs({1}).Build(),
Builder().T(1).Dtis("-S").Fdiffs({1}).Build(),
};
return template_structure;
}
default:
RTC_NOTREACHED();
// To make the compiler happy!
return template_structure;
}
}
bool ScreenshareLayers::TimeToSync(int64_t timestamp) const {
RTC_DCHECK_EQ(1, active_layer_);
RTC_DCHECK_NE(-1, layers_[0].last_qp);

View File

@ -16,6 +16,7 @@
#include "api/video_codecs/vp8_frame_config.h"
#include "api/video_codecs/vp8_temporal_layers.h"
#include "modules/video_coding/codecs/vp8/include/temporal_layers_checker.h"
#include "modules/video_coding/include/video_codec_interface.h"
#include "modules/video_coding/utility/frame_dropper.h"
#include "rtc_base/rate_statistics.h"
#include "rtc_base/time_utils.h"
@ -52,7 +53,7 @@ class ScreenshareLayers : public Vp8TemporalLayers {
size_t size_bytes,
bool is_keyframe,
int qp,
CodecSpecificInfoVP8* vp8_info) override;
CodecSpecificInfo* info) override;
private:
enum class TemporalLayerState : int { kDrop, kTl0, kTl1, kTl1Sync };
@ -77,6 +78,7 @@ class ScreenshareLayers : public Vp8TemporalLayers {
absl::optional<uint32_t> target_framerate_;
// Incoming framerate from capturer.
absl::optional<uint32_t> capture_framerate_;
// Tracks what framerate we actually encode, and drops frames on overshoot.
RateStatistics encode_framerate_;
bool bitrate_updated_;
@ -107,6 +109,8 @@ class ScreenshareLayers : public Vp8TemporalLayers {
} layers_[kMaxNumTemporalLayers];
void UpdateHistograms();
TemplateStructure GetTemplateStructure(int num_layers) const;
// Data for histogram statistics.
struct Stats {
int64_t first_frame_time_ms_ = -1;

View File

@ -80,8 +80,7 @@ class ScreenshareLayerTest : public ::testing::Test {
int flags = ConfigureFrame(base_sync);
if (flags != -1)
layers_->OnEncodeDone(timestamp_, frame_size_, base_sync, kDefaultQp,
&info->codecSpecific.VP8);
info);
return flags;
}
@ -133,10 +132,9 @@ class ScreenshareLayerTest : public ::testing::Test {
bool got_tl1 = false;
for (int i = 0; i < 10; ++i) {
CodecSpecificInfo info;
const CodecSpecificInfoVP8& vp8_info = info.codecSpecific.VP8;
EXPECT_NE(-1, EncodeFrame(false, &info));
timestamp_ += kTimestampDelta5Fps;
if (vp8_info.temporalIdx == 0) {
if (info.codecSpecific.VP8.temporalIdx == 0) {
got_tl0 = true;
} else {
got_tl1 = true;
@ -164,9 +162,8 @@ class ScreenshareLayerTest : public ::testing::Test {
if (tl_config_.packetizer_temporal_idx != layer ||
(sync && *sync != tl_config_.layer_sync)) {
CodecSpecificInfo info;
CodecSpecificInfoVP8* vp8_info = &info.codecSpecific.VP8;
layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp,
vp8_info);
&info);
timestamp_ += kTimestampDelta5Fps;
} else {
// Found frame from sought after layer.
@ -188,9 +185,9 @@ class ScreenshareLayerTest : public ::testing::Test {
Vp8EncoderConfig cfg_;
bool config_updated_;
CodecSpecificInfoVP8* IgnoredCodecSpecificInfoVp8() {
CodecSpecificInfo* IgnoredCodecSpecificInfo() {
ignored_codec_specific_info_ = absl::make_unique<CodecSpecificInfo>();
return &ignored_codec_specific_info_->codecSpecific.VP8;
return ignored_codec_specific_info_.get();
}
private:
@ -223,10 +220,10 @@ TEST_F(ScreenshareLayerTest, 2LayersPeriodicSync) {
const int kNumFrames = kSyncPeriodSeconds * kFrameRate * 2 - 1;
for (int i = 0; i < kNumFrames; ++i) {
CodecSpecificInfo info;
const CodecSpecificInfoVP8& vp8_info = info.codecSpecific.VP8;
EncodeFrame(false, &info);
timestamp_ += kTimestampDelta5Fps;
if (vp8_info.temporalIdx == 1 && vp8_info.layerSync) {
if (info.codecSpecific.VP8.temporalIdx == 1 &&
info.codecSpecific.VP8.layerSync) {
sync_times.push_back(timestamp_);
}
}
@ -240,21 +237,20 @@ TEST_F(ScreenshareLayerTest, 2LayersSyncAfterTimeout) {
const int kNumFrames = kMaxSyncPeriodSeconds * kFrameRate * 2 - 1;
for (int i = 0; i < kNumFrames; ++i) {
CodecSpecificInfo info;
CodecSpecificInfoVP8* vp8_info = &info.codecSpecific.VP8;
tl_config_ = UpdateLayerConfig(timestamp_);
config_updated_ = layers_->UpdateConfiguration(&cfg_);
// Simulate TL1 being at least 8 qp steps better.
if (tl_config_.packetizer_temporal_idx == 0) {
layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp,
vp8_info);
layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp, &info);
} else {
layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp - 8,
vp8_info);
&info);
}
if (vp8_info->temporalIdx == 1 && vp8_info->layerSync)
if (info.codecSpecific.VP8.temporalIdx == 1 &&
info.codecSpecific.VP8.layerSync)
sync_times.push_back(timestamp_);
timestamp_ += kTimestampDelta5Fps;
@ -272,20 +268,19 @@ TEST_F(ScreenshareLayerTest, 2LayersSyncAfterSimilarQP) {
kFrameRate;
for (int i = 0; i < kNumFrames; ++i) {
CodecSpecificInfo info;
CodecSpecificInfoVP8* vp8_info = &info.codecSpecific.VP8;
ConfigureFrame(false);
// Simulate TL1 being at least 8 qp steps better.
if (tl_config_.packetizer_temporal_idx == 0) {
layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp,
vp8_info);
layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp, &info);
} else {
layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp - 8,
vp8_info);
&info);
}
if (vp8_info->temporalIdx == 1 && vp8_info->layerSync)
if (info.codecSpecific.VP8.temporalIdx == 1 &&
info.codecSpecific.VP8.layerSync)
sync_times.push_back(timestamp_);
timestamp_ += kTimestampDelta5Fps;
@ -296,17 +291,16 @@ TEST_F(ScreenshareLayerTest, 2LayersSyncAfterSimilarQP) {
bool bumped_tl0_quality = false;
for (int i = 0; i < 3; ++i) {
CodecSpecificInfo info;
CodecSpecificInfoVP8* vp8_info = &info.codecSpecific.VP8;
int flags = ConfigureFrame(false);
layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp - 8,
vp8_info);
if (vp8_info->temporalIdx == 0) {
&info);
if (info.codecSpecific.VP8.temporalIdx == 0) {
// Bump TL0 to same quality as TL1.
bumped_tl0_quality = true;
} else {
if (bumped_tl0_quality) {
EXPECT_TRUE(vp8_info->layerSync);
EXPECT_TRUE(info.codecSpecific.VP8.layerSync);
EXPECT_EQ(kTl1SyncFlags, flags);
return;
}
@ -324,10 +318,9 @@ TEST_F(ScreenshareLayerTest, 2LayersToggling) {
int tl1_frames = 0;
for (int i = 0; i < 50; ++i) {
CodecSpecificInfo info;
const CodecSpecificInfoVP8& vp8_info = info.codecSpecific.VP8;
EncodeFrame(false, &info);
timestamp_ += kTimestampDelta5Fps;
switch (vp8_info.temporalIdx) {
switch (info.codecSpecific.VP8.temporalIdx) {
case 0:
++tl0_frames;
break;
@ -348,11 +341,10 @@ TEST_F(ScreenshareLayerTest, AllFitsLayer0) {
// Insert 50 frames, small enough that all fits in TL0.
for (int i = 0; i < 50; ++i) {
CodecSpecificInfo info;
const CodecSpecificInfoVP8& vp8_info = info.codecSpecific.VP8;
int flags = EncodeFrame(false, &info);
timestamp_ += kTimestampDelta5Fps;
EXPECT_EQ(kTl0Flags, flags);
EXPECT_EQ(0, vp8_info.temporalIdx);
EXPECT_EQ(0, info.codecSpecific.VP8.temporalIdx);
}
}
@ -365,13 +357,12 @@ TEST_F(ScreenshareLayerTest, TooHighBitrate) {
int dropped_frames = 0;
for (int i = 0; i < 100; ++i) {
CodecSpecificInfo info;
const CodecSpecificInfoVP8& vp8_info = info.codecSpecific.VP8;
int flags = EncodeFrame(false, &info);
timestamp_ += kTimestampDelta5Fps;
if (flags == -1) {
++dropped_frames;
} else {
switch (vp8_info.temporalIdx) {
switch (info.codecSpecific.VP8.temporalIdx) {
case 0:
++tl0_frames;
break;
@ -428,7 +419,7 @@ TEST_F(ScreenshareLayerTest, EncoderDrop) {
SkipUntilTl(0);
// Size 0 indicates dropped frame.
layers_->OnEncodeDone(timestamp_, 0, false, 0, IgnoredCodecSpecificInfoVp8());
layers_->OnEncodeDone(timestamp_, 0, false, 0, IgnoredCodecSpecificInfo());
// Re-encode frame (so don't advance timestamp).
int flags = EncodeFrame(false);
@ -441,19 +432,19 @@ TEST_F(ScreenshareLayerTest, EncoderDrop) {
EXPECT_TRUE(config_updated_);
EXPECT_LT(cfg_.rc_max_quantizer, static_cast<unsigned int>(kDefaultQp));
layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
timestamp_ += kTimestampDelta5Fps;
// ...then back to standard setup.
SkipUntilTl(0);
layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
timestamp_ += kTimestampDelta5Fps;
EXPECT_EQ(cfg_.rc_max_quantizer, static_cast<unsigned int>(kDefaultQp));
// Next drop in TL1.
SkipUntilTl(1);
layers_->OnEncodeDone(timestamp_, 0, false, 0, IgnoredCodecSpecificInfoVp8());
layers_->OnEncodeDone(timestamp_, 0, false, 0, IgnoredCodecSpecificInfo());
// Re-encode frame (so don't advance timestamp).
flags = EncodeFrame(false);
@ -466,14 +457,14 @@ TEST_F(ScreenshareLayerTest, EncoderDrop) {
EXPECT_TRUE(config_updated_);
EXPECT_LT(cfg_.rc_max_quantizer, static_cast<unsigned int>(kDefaultQp));
layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
timestamp_ += kTimestampDelta5Fps;
// ...and back to normal.
SkipUntilTl(1);
EXPECT_EQ(cfg_.rc_max_quantizer, static_cast<unsigned int>(kDefaultQp));
layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
timestamp_ += kTimestampDelta5Fps;
}
@ -489,7 +480,7 @@ TEST_F(ScreenshareLayerTest, RespectsMaxIntervalBetweenFrames) {
EXPECT_EQ(kTl0Flags,
LibvpxVp8Encoder::EncodeFlags(UpdateLayerConfig(kStartTimestamp)));
layers_->OnEncodeDone(kStartTimestamp, kLargeFrameSizeBytes, false,
kDefaultQp, IgnoredCodecSpecificInfoVp8());
kDefaultQp, IgnoredCodecSpecificInfo());
const uint32_t kTwoSecondsLater =
kStartTimestamp + (ScreenshareLayers::kMaxFrameIntervalMs * 90);
@ -539,15 +530,15 @@ TEST_F(ScreenshareLayerTest, UpdatesHistograms) {
if (timestamp >= kTimestampDelta5Fps * 20 && !trigger_drop) {
// Simulate a too large frame, to cause frame drop.
layers_->OnEncodeDone(timestamp, frame_size_ * 10, false, kTl0Qp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
trigger_drop = true;
} else {
layers_->OnEncodeDone(timestamp, frame_size_, false, kTl0Qp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
}
} else if (flags == kTl1Flags || flags == kTl1SyncFlags) {
layers_->OnEncodeDone(timestamp, frame_size_, false, kTl1Qp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
} else if (flags == -1) {
dropped_frame = true;
} else {
@ -614,7 +605,7 @@ TEST_F(ScreenshareLayerTest, RespectsConfiguredFramerate) {
} else {
size_t frame_size_bytes = kDefaultTl0BitrateKbps * kFrameIntervalsMs / 8;
layers_->OnEncodeDone(timestamp, frame_size_bytes, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
}
timestamp += kFrameIntervalsMs * 90;
clock_.AdvanceTime(TimeDelta::ms(kFrameIntervalsMs));
@ -632,7 +623,7 @@ TEST_F(ScreenshareLayerTest, RespectsConfiguredFramerate) {
} else {
size_t frame_size_bytes = kDefaultTl0BitrateKbps * kFrameIntervalsMs / 8;
layers_->OnEncodeDone(timestamp, frame_size_bytes, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
}
timestamp += kFrameIntervalsMs * 90 / 2;
clock_.AdvanceTime(TimeDelta::ms(kFrameIntervalsMs));
@ -657,10 +648,9 @@ TEST_F(ScreenshareLayerTest, 2LayersSyncAtOvershootDrop) {
config_updated_ = layers_->UpdateConfiguration(&cfg_);
EXPECT_EQ(kTl1SyncFlags, LibvpxVp8Encoder::EncodeFlags(tl_config_));
CodecSpecificInfo info;
CodecSpecificInfoVP8* vp8_info = &info.codecSpecific.VP8;
layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp, vp8_info);
EXPECT_TRUE(vp8_info->layerSync);
CodecSpecificInfo new_info;
layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp, &new_info);
EXPECT_TRUE(new_info.codecSpecific.VP8.layerSync);
}
TEST_F(ScreenshareLayerTest, DropOnTooShortFrameInterval) {
@ -671,7 +661,7 @@ TEST_F(ScreenshareLayerTest, DropOnTooShortFrameInterval) {
timestamp_ += kTimestampDelta5Fps * 3;
EXPECT_FALSE(UpdateLayerConfig(timestamp_).drop_frame);
layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
// Frame interval below 90% if desired time is not allowed, try inserting
// frame just before this limit.
@ -735,7 +725,7 @@ TEST_F(ScreenshareLayerTest, DISABLED_MaxQpRestoredAfterDoubleDrop) {
// Simulate re-encoded frame.
layers_->OnEncodeDone(timestamp_, 1, false, max_qp_,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
// Next frame, expect boosted quality.
// Slightly alter bitrate between each frame.
@ -752,7 +742,7 @@ TEST_F(ScreenshareLayerTest, DISABLED_MaxQpRestoredAfterDoubleDrop) {
// Simulate re-encoded frame.
layers_->OnEncodeDone(timestamp_, frame_size_, false, max_qp_,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
// A third frame, expect boosted quality.
layers_->OnRatesUpdated(kDefault2TlBitratesBps, kFrameRate);
@ -763,7 +753,7 @@ TEST_F(ScreenshareLayerTest, DISABLED_MaxQpRestoredAfterDoubleDrop) {
// Frame encoded.
layers_->OnEncodeDone(timestamp_, frame_size_, false, max_qp_,
IgnoredCodecSpecificInfoVp8());
IgnoredCodecSpecificInfo());
// A fourth frame, max qp should be restored.
layers_->OnRatesUpdated(kDefault2TlBitratesBpsAlt, kFrameRate);