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}
diff --git a/modules/video_coding/BUILD.gn b/modules/video_coding/BUILD.gn
index ffd58a2..fb67178 100644
--- a/modules/video_coding/BUILD.gn
+++ b/modules/video_coding/BUILD.gn
@@ -185,6 +185,7 @@
rtc_source_set("video_codec_interface") {
visibility = [ "*" ]
sources = [
+ "include/video_codec_interface.cc",
"include/video_codec_interface.h",
"include/video_coding_defines.h",
"include/video_error_codes.h",
@@ -196,6 +197,7 @@
"../../api/video:video_frame",
"../../api/video_codecs:video_codecs_api",
"../../common_video:common_video",
+ "../../common_video/generic_frame_descriptor:generic_frame_descriptor",
"//third_party/abseil-cpp/absl/types:optional",
]
}
diff --git a/modules/video_coding/codecs/vp8/default_temporal_layers.cc b/modules/video_coding/codecs/vp8/default_temporal_layers.cc
index 47b1bef..61dca09 100644
--- a/modules/video_coding/codecs/vp8/default_temporal_layers.cc
+++ b/modules/video_coding/codecs/vp8/default_temporal_layers.cc
@@ -444,7 +444,7 @@
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 @@
}
#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 @@
}
} 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 @@
}
}
+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(
diff --git a/modules/video_coding/codecs/vp8/default_temporal_layers.h b/modules/video_coding/codecs/vp8/default_temporal_layers.h
index d04e4f4..8deeb40 100644
--- a/modules/video_coding/codecs/vp8/default_temporal_layers.h
+++ b/modules/video_coding/codecs/vp8/default_temporal_layers.h
@@ -49,7 +49,7 @@
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 @@
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.
diff --git a/modules/video_coding/codecs/vp8/default_temporal_layers_unittest.cc b/modules/video_coding/codecs/vp8/default_temporal_layers_unittest.cc
index ae72ec9..37e6620 100644
--- a/modules/video_coding/codecs/vp8/default_temporal_layers_unittest.cc
+++ b/modules/video_coding/codecs/vp8/default_temporal_layers_unittest.cc
@@ -107,9 +107,9 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
// 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 @@
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 @@
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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
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 @@
// 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 @@
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 @@
// 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 @@
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 @@
}
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 @@
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);
diff --git a/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc b/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc
index 1dc0837..e8a6d25 100644
--- a/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc
+++ b/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc
@@ -850,15 +850,16 @@
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) {
diff --git a/modules/video_coding/codecs/vp8/screenshare_layers.cc b/modules/video_coding/codecs/vp8/screenshare_layers.cc
index d3f4d42..17b1aed 100644
--- a/modules/video_coding/codecs/vp8/screenshare_layers.cc
+++ b/modules/video_coding/codecs/vp8/screenshare_layers.cc
@@ -265,7 +265,7 @@
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 @@
}
}
+ 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 @@
}
}
+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);
diff --git a/modules/video_coding/codecs/vp8/screenshare_layers.h b/modules/video_coding/codecs/vp8/screenshare_layers.h
index b1dbde8..1c96796 100644
--- a/modules/video_coding/codecs/vp8/screenshare_layers.h
+++ b/modules/video_coding/codecs/vp8/screenshare_layers.h
@@ -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 @@
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 @@
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 @@
} layers_[kMaxNumTemporalLayers];
void UpdateHistograms();
+ TemplateStructure GetTemplateStructure(int num_layers) const;
+
// Data for histogram statistics.
struct Stats {
int64_t first_frame_time_ms_ = -1;
diff --git a/modules/video_coding/codecs/vp8/screenshare_layers_unittest.cc b/modules/video_coding/codecs/vp8/screenshare_layers_unittest.cc
index 5f4f9af..16e4d46 100644
--- a/modules/video_coding/codecs/vp8/screenshare_layers_unittest.cc
+++ b/modules/video_coding/codecs/vp8/screenshare_layers_unittest.cc
@@ -80,8 +80,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
} 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 @@
} 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 @@
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 @@
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 @@
// 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 @@
// 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 @@
// Frame encoded.
layers_->OnEncodeDone(timestamp_, frame_size_, false, max_qp_,
- IgnoredCodecSpecificInfoVp8());
+ IgnoredCodecSpecificInfo());
// A fourth frame, max qp should be restored.
layers_->OnRatesUpdated(kDefault2TlBitratesBpsAlt, kFrameRate);
diff --git a/modules/video_coding/include/video_codec_interface.cc b/modules/video_coding/include/video_codec_interface.cc
new file mode 100644
index 0000000..bd033b6
--- /dev/null
+++ b/modules/video_coding/include/video_codec_interface.cc
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#include "modules/video_coding/include/video_codec_interface.h"
+
+namespace webrtc {
+CodecSpecificInfo::CodecSpecificInfo() : codecType(kVideoCodecGeneric) {
+ memset(&codecSpecific, 0, sizeof(codecSpecific));
+}
+
+CodecSpecificInfo::CodecSpecificInfo(const CodecSpecificInfo&) = default;
+CodecSpecificInfo::~CodecSpecificInfo() = default;
+
+} // namespace webrtc
diff --git a/modules/video_coding/include/video_codec_interface.h b/modules/video_coding/include/video_codec_interface.h
index cde5512..fb440be 100644
--- a/modules/video_coding/include/video_codec_interface.h
+++ b/modules/video_coding/include/video_codec_interface.h
@@ -13,10 +13,12 @@
#include <vector>
+#include "absl/types/optional.h"
#include "api/video/video_frame.h"
#include "api/video_codecs/video_decoder.h"
#include "api/video_codecs/video_encoder.h"
#include "common_types.h" // NOLINT(build/include)
+#include "common_video/generic_frame_descriptor/generic_frame_info.h"
#include "modules/include/module_common_types.h"
#include "modules/video_coding/include/video_error_codes.h"
@@ -96,16 +98,18 @@
};
static_assert(std::is_pod<CodecSpecificInfoUnion>::value, "");
-// Note: If any pointers are added to this struct or its sub-structs, it
+// Note: if any pointers are added to this struct or its sub-structs, it
// must be fitted with a copy-constructor. This is because it is copied
// in the copy-constructor of VCMEncodedFrame.
struct CodecSpecificInfo {
- CodecSpecificInfo() : codecType(kVideoCodecGeneric) {
- memset(&codecSpecific, 0, sizeof(codecSpecific));
- }
+ CodecSpecificInfo();
+ CodecSpecificInfo(const CodecSpecificInfo&);
+ ~CodecSpecificInfo();
VideoCodecType codecType;
CodecSpecificInfoUnion codecSpecific;
+ absl::optional<GenericFrameInfo> generic_frame_info;
+ absl::optional<TemplateStructure> template_structure;
};
} // namespace webrtc
diff --git a/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc b/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc
index 690c3fa..4744e38 100644
--- a/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc
+++ b/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc
@@ -41,7 +41,7 @@
MOCK_METHOD2(OnRatesUpdated, void(const std::vector<uint32_t>&, int));
MOCK_METHOD1(UpdateConfiguration, bool(Vp8EncoderConfig*));
MOCK_METHOD5(OnEncodeDone,
- void(uint32_t, size_t, bool, int, CodecSpecificInfoVP8*));
+ void(uint32_t, size_t, bool, int, CodecSpecificInfo*));
MOCK_METHOD3(FrameEncoded, void(uint32_t, size_t, int));
MOCK_CONST_METHOD0(Tl0PicIdx, uint8_t());
MOCK_CONST_METHOD1(GetTemporalLayerId, int(const Vp8FrameConfig&));