Move TemporalLayers to api/video_codecs.
Also renaming it Vp8TemporalLayers to show that it is codec specific. Bug: webrtc:9012 Change-Id: I18187538b8142cdd7538f1a4ed1bada09d040f1f Reviewed-on: https://webrtc-review.googlesource.com/c/104643 Commit-Queue: Erik Språng <sprang@webrtc.org> Reviewed-by: Per Kjellander <perkj@webrtc.org> Reviewed-by: Sebastian Jansson <srte@webrtc.org> Reviewed-by: Niels Moller <nisse@webrtc.org> Cr-Commit-Position: refs/heads/master@{#25137}
This commit is contained in:
@ -7,8 +7,6 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "modules/video_coding/codecs/vp8/default_temporal_layers.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -20,6 +18,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "modules/include/module_common_types.h"
|
||||
#include "modules/video_coding/codecs/vp8/default_temporal_layers.h"
|
||||
#include "modules/video_coding/include/video_codec_interface.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
@ -27,27 +26,30 @@
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
TemporalLayers::FrameConfig::FrameConfig()
|
||||
Vp8TemporalLayers::FrameConfig::FrameConfig()
|
||||
: FrameConfig(kNone, kNone, kNone, false) {}
|
||||
|
||||
TemporalLayers::FrameConfig::FrameConfig(TemporalLayers::BufferFlags last,
|
||||
TemporalLayers::BufferFlags golden,
|
||||
TemporalLayers::BufferFlags arf)
|
||||
Vp8TemporalLayers::FrameConfig::FrameConfig(
|
||||
Vp8TemporalLayers::BufferFlags last,
|
||||
Vp8TemporalLayers::BufferFlags golden,
|
||||
Vp8TemporalLayers::BufferFlags arf)
|
||||
: FrameConfig(last, golden, arf, false) {}
|
||||
|
||||
TemporalLayers::FrameConfig::FrameConfig(TemporalLayers::BufferFlags last,
|
||||
TemporalLayers::BufferFlags golden,
|
||||
TemporalLayers::BufferFlags arf,
|
||||
FreezeEntropy)
|
||||
Vp8TemporalLayers::FrameConfig::FrameConfig(
|
||||
Vp8TemporalLayers::BufferFlags last,
|
||||
Vp8TemporalLayers::BufferFlags golden,
|
||||
Vp8TemporalLayers::BufferFlags arf,
|
||||
FreezeEntropy)
|
||||
: FrameConfig(last, golden, arf, true) {}
|
||||
|
||||
TemporalLayers::FrameConfig::FrameConfig(TemporalLayers::BufferFlags last,
|
||||
TemporalLayers::BufferFlags golden,
|
||||
TemporalLayers::BufferFlags arf,
|
||||
bool freeze_entropy)
|
||||
: drop_frame(last == TemporalLayers::kNone &&
|
||||
golden == TemporalLayers::kNone &&
|
||||
arf == TemporalLayers::kNone),
|
||||
Vp8TemporalLayers::FrameConfig::FrameConfig(
|
||||
Vp8TemporalLayers::BufferFlags last,
|
||||
Vp8TemporalLayers::BufferFlags golden,
|
||||
Vp8TemporalLayers::BufferFlags arf,
|
||||
bool freeze_entropy)
|
||||
: drop_frame(last == Vp8TemporalLayers::kNone &&
|
||||
golden == Vp8TemporalLayers::kNone &&
|
||||
arf == Vp8TemporalLayers::kNone),
|
||||
last_buffer_flags(last),
|
||||
golden_buffer_flags(golden),
|
||||
arf_buffer_flags(arf),
|
||||
@ -106,15 +108,15 @@ std::vector<unsigned int> GetTemporalIds(size_t num_layers) {
|
||||
return {0};
|
||||
}
|
||||
|
||||
uint8_t GetUpdatedBuffers(const TemporalLayers::FrameConfig& config) {
|
||||
uint8_t GetUpdatedBuffers(const Vp8TemporalLayers::FrameConfig& config) {
|
||||
uint8_t flags = 0;
|
||||
if (config.last_buffer_flags & TemporalLayers::BufferFlags::kUpdate) {
|
||||
if (config.last_buffer_flags & Vp8TemporalLayers::BufferFlags::kUpdate) {
|
||||
flags |= static_cast<uint8_t>(Vp8BufferReference::kLast);
|
||||
}
|
||||
if (config.golden_buffer_flags & TemporalLayers::BufferFlags::kUpdate) {
|
||||
if (config.golden_buffer_flags & Vp8TemporalLayers::BufferFlags::kUpdate) {
|
||||
flags |= static_cast<uint8_t>(Vp8BufferReference::kGolden);
|
||||
}
|
||||
if (config.arf_buffer_flags & TemporalLayers::BufferFlags::kUpdate) {
|
||||
if (config.arf_buffer_flags & Vp8TemporalLayers::BufferFlags::kUpdate) {
|
||||
flags |= static_cast<uint8_t>(Vp8BufferReference::kAltref);
|
||||
}
|
||||
return flags;
|
||||
@ -122,10 +124,10 @@ uint8_t GetUpdatedBuffers(const TemporalLayers::FrameConfig& config) {
|
||||
|
||||
// Find the set of buffers that are never updated by the given pattern.
|
||||
std::set<Vp8BufferReference> FindKfBuffers(
|
||||
const std::vector<TemporalLayers::FrameConfig>& frame_configs) {
|
||||
const std::vector<Vp8TemporalLayers::FrameConfig>& frame_configs) {
|
||||
std::set<Vp8BufferReference> kf_buffers(kAllBuffers.begin(),
|
||||
kAllBuffers.end());
|
||||
for (TemporalLayers::FrameConfig config : frame_configs) {
|
||||
for (Vp8TemporalLayers::FrameConfig config : frame_configs) {
|
||||
// Get bit-masked set of update buffers for this frame config.
|
||||
uint8_t updated_buffers = GetUpdatedBuffers(config);
|
||||
for (Vp8BufferReference buffer : kAllBuffers) {
|
||||
@ -138,7 +140,7 @@ std::set<Vp8BufferReference> FindKfBuffers(
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::vector<TemporalLayers::FrameConfig>
|
||||
std::vector<Vp8TemporalLayers::FrameConfig>
|
||||
DefaultTemporalLayers::GetTemporalPattern(size_t num_layers) {
|
||||
// For indexing in the patterns described below (which temporal layers they
|
||||
// belong to), see the diagram above.
|
||||
@ -262,7 +264,7 @@ DefaultTemporalLayers::DefaultTemporalLayers(int number_of_temporal_layers)
|
||||
kf_buffers_(FindKfBuffers(temporal_pattern_)),
|
||||
pattern_idx_(kUninitializedPatternIndex),
|
||||
checker_(TemporalLayersChecker::CreateTemporalLayersChecker(
|
||||
TemporalLayersType::kFixedPattern,
|
||||
Vp8TemporalLayersType::kFixedPattern,
|
||||
number_of_temporal_layers)) {
|
||||
RTC_CHECK_GE(kMaxTemporalStreams, number_of_temporal_layers);
|
||||
RTC_CHECK_GE(number_of_temporal_layers, 0);
|
||||
@ -278,6 +280,8 @@ DefaultTemporalLayers::DefaultTemporalLayers(int number_of_temporal_layers)
|
||||
}
|
||||
}
|
||||
|
||||
DefaultTemporalLayers::~DefaultTemporalLayers() = default;
|
||||
|
||||
bool DefaultTemporalLayers::SupportsEncoderFrameDropping() const {
|
||||
// This class allows the encoder drop frames as it sees fit.
|
||||
return true;
|
||||
@ -346,13 +350,13 @@ bool DefaultTemporalLayers::IsSyncFrame(const FrameConfig& config) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
TemporalLayers::FrameConfig DefaultTemporalLayers::UpdateLayerConfig(
|
||||
Vp8TemporalLayers::FrameConfig DefaultTemporalLayers::UpdateLayerConfig(
|
||||
uint32_t timestamp) {
|
||||
RTC_DCHECK_GT(num_layers_, 0);
|
||||
RTC_DCHECK_LT(0, temporal_pattern_.size());
|
||||
|
||||
pattern_idx_ = (pattern_idx_ + 1) % temporal_pattern_.size();
|
||||
TemporalLayers::FrameConfig tl_config = temporal_pattern_[pattern_idx_];
|
||||
Vp8TemporalLayers::FrameConfig tl_config = temporal_pattern_[pattern_idx_];
|
||||
tl_config.encoder_layer_id = tl_config.packetizer_temporal_idx =
|
||||
temporal_ids_[pattern_idx_ % temporal_ids_.size()];
|
||||
|
||||
@ -560,9 +564,11 @@ DefaultTemporalLayersChecker::DefaultTemporalLayersChecker(
|
||||
}
|
||||
}
|
||||
|
||||
DefaultTemporalLayersChecker::~DefaultTemporalLayersChecker() = default;
|
||||
|
||||
bool DefaultTemporalLayersChecker::CheckTemporalConfig(
|
||||
bool frame_is_keyframe,
|
||||
const TemporalLayers::FrameConfig& frame_config) {
|
||||
const Vp8TemporalLayers::FrameConfig& frame_config) {
|
||||
if (!TemporalLayersChecker::CheckTemporalConfig(frame_is_keyframe,
|
||||
frame_config)) {
|
||||
return false;
|
||||
@ -613,7 +619,7 @@ bool DefaultTemporalLayersChecker::CheckTemporalConfig(
|
||||
std::vector<int> dependencies;
|
||||
|
||||
if (frame_config.last_buffer_flags &
|
||||
TemporalLayers::BufferFlags::kReference) {
|
||||
Vp8TemporalLayers::BufferFlags::kReference) {
|
||||
uint8_t referenced_layer = temporal_ids_[last_.pattern_idx];
|
||||
if (referenced_layer > 0) {
|
||||
need_sync = false;
|
||||
@ -628,7 +634,8 @@ bool DefaultTemporalLayersChecker::CheckTemporalConfig(
|
||||
return false;
|
||||
}
|
||||
|
||||
if (frame_config.arf_buffer_flags & TemporalLayers::BufferFlags::kReference) {
|
||||
if (frame_config.arf_buffer_flags &
|
||||
Vp8TemporalLayers::BufferFlags::kReference) {
|
||||
uint8_t referenced_layer = temporal_ids_[arf_.pattern_idx];
|
||||
if (referenced_layer > 0) {
|
||||
need_sync = false;
|
||||
@ -644,7 +651,7 @@ bool DefaultTemporalLayersChecker::CheckTemporalConfig(
|
||||
}
|
||||
|
||||
if (frame_config.golden_buffer_flags &
|
||||
TemporalLayers::BufferFlags::kReference) {
|
||||
Vp8TemporalLayers::BufferFlags::kReference) {
|
||||
uint8_t referenced_layer = temporal_ids_[golden_.pattern_idx];
|
||||
if (referenced_layer > 0) {
|
||||
need_sync = false;
|
||||
@ -680,17 +687,19 @@ bool DefaultTemporalLayersChecker::CheckTemporalConfig(
|
||||
}
|
||||
}
|
||||
|
||||
if (frame_config.last_buffer_flags & TemporalLayers::BufferFlags::kUpdate) {
|
||||
if (frame_config.last_buffer_flags &
|
||||
Vp8TemporalLayers::BufferFlags::kUpdate) {
|
||||
last_.is_updated_this_cycle = true;
|
||||
last_.pattern_idx = pattern_idx_;
|
||||
last_.is_keyframe = false;
|
||||
}
|
||||
if (frame_config.arf_buffer_flags & TemporalLayers::BufferFlags::kUpdate) {
|
||||
if (frame_config.arf_buffer_flags & Vp8TemporalLayers::BufferFlags::kUpdate) {
|
||||
arf_.is_updated_this_cycle = true;
|
||||
arf_.pattern_idx = pattern_idx_;
|
||||
arf_.is_keyframe = false;
|
||||
}
|
||||
if (frame_config.golden_buffer_flags & TemporalLayers::BufferFlags::kUpdate) {
|
||||
if (frame_config.golden_buffer_flags &
|
||||
Vp8TemporalLayers::BufferFlags::kUpdate) {
|
||||
golden_.is_updated_this_cycle = true;
|
||||
golden_.pattern_idx = pattern_idx_;
|
||||
golden_.is_keyframe = false;
|
||||
|
||||
@ -18,23 +18,23 @@
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "modules/video_coding/codecs/vp8/include/temporal_layers_checker.h"
|
||||
#include "modules/video_coding/codecs/vp8/include/vp8_temporal_layers.h"
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
|
||||
#include "api/video_codecs/vp8_temporal_layers.h"
|
||||
#include "modules/video_coding/codecs/vp8/include/temporal_layers_checker.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class DefaultTemporalLayers : public TemporalLayers {
|
||||
class DefaultTemporalLayers : public Vp8TemporalLayers {
|
||||
public:
|
||||
explicit DefaultTemporalLayers(int number_of_temporal_layers);
|
||||
virtual ~DefaultTemporalLayers() {}
|
||||
~DefaultTemporalLayers() override;
|
||||
|
||||
bool SupportsEncoderFrameDropping() const override;
|
||||
|
||||
// Returns the recommended VP8 encode flags needed. May refresh the decoder
|
||||
// and/or update the reference buffers.
|
||||
TemporalLayers::FrameConfig UpdateLayerConfig(uint32_t timestamp) override;
|
||||
Vp8TemporalLayers::FrameConfig UpdateLayerConfig(uint32_t timestamp) override;
|
||||
|
||||
// New target bitrate, per temporal layer.
|
||||
void OnRatesUpdated(const std::vector<uint32_t>& bitrates_bps,
|
||||
@ -50,7 +50,7 @@ class DefaultTemporalLayers : public TemporalLayers {
|
||||
|
||||
private:
|
||||
static constexpr size_t kKeyframeBuffer = std::numeric_limits<size_t>::max();
|
||||
static std::vector<TemporalLayers::FrameConfig> GetTemporalPattern(
|
||||
static std::vector<Vp8TemporalLayers::FrameConfig> GetTemporalPattern(
|
||||
size_t num_layers);
|
||||
bool IsSyncFrame(const FrameConfig& config) const;
|
||||
void ValidateReferences(BufferFlags* flags, Vp8BufferReference ref) const;
|
||||
@ -58,7 +58,7 @@ class DefaultTemporalLayers : public TemporalLayers {
|
||||
|
||||
const size_t num_layers_;
|
||||
const std::vector<unsigned int> temporal_ids_;
|
||||
const std::vector<TemporalLayers::FrameConfig> temporal_pattern_;
|
||||
const std::vector<Vp8TemporalLayers::FrameConfig> temporal_pattern_;
|
||||
// Set of buffers that are never updated except by keyframes.
|
||||
const std::set<Vp8BufferReference> kf_buffers_;
|
||||
|
||||
@ -95,9 +95,11 @@ class DefaultTemporalLayers : public TemporalLayers {
|
||||
class DefaultTemporalLayersChecker : public TemporalLayersChecker {
|
||||
public:
|
||||
explicit DefaultTemporalLayersChecker(int number_of_temporal_layers);
|
||||
~DefaultTemporalLayersChecker() override;
|
||||
|
||||
bool CheckTemporalConfig(
|
||||
bool frame_is_keyframe,
|
||||
const TemporalLayers::FrameConfig& frame_config) override;
|
||||
const Vp8TemporalLayers::FrameConfig& frame_config) override;
|
||||
|
||||
private:
|
||||
struct BufferState {
|
||||
|
||||
@ -74,7 +74,7 @@ constexpr int kDefaultBytesPerFrame =
|
||||
constexpr int kDefaultQp = 2;
|
||||
} // namespace
|
||||
|
||||
using BufferFlags = TemporalLayers::BufferFlags;
|
||||
using BufferFlags = Vp8TemporalLayers::BufferFlags;
|
||||
|
||||
TEST(TemporalLayersTest, 2Layers) {
|
||||
constexpr int kNumLayers = 2;
|
||||
@ -114,7 +114,7 @@ TEST(TemporalLayersTest, 2Layers) {
|
||||
|
||||
uint32_t timestamp = 0;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
TemporalLayers::FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
|
||||
Vp8TemporalLayers::FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
|
||||
EXPECT_EQ(expected_flags[i], LibvpxVp8Encoder::EncodeFlags(tl_config)) << i;
|
||||
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, i == 0, kDefaultQp,
|
||||
&vp8_info);
|
||||
@ -166,7 +166,7 @@ TEST(TemporalLayersTest, 3Layers) {
|
||||
|
||||
unsigned int timestamp = 0;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
TemporalLayers::FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
|
||||
Vp8TemporalLayers::FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
|
||||
EXPECT_EQ(expected_flags[i], LibvpxVp8Encoder::EncodeFlags(tl_config)) << i;
|
||||
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, i == 0, kDefaultQp,
|
||||
&vp8_info);
|
||||
@ -207,7 +207,7 @@ TEST(TemporalLayersTest, Alternative3Layers) {
|
||||
|
||||
unsigned int timestamp = 0;
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
TemporalLayers::FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
|
||||
Vp8TemporalLayers::FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
|
||||
EXPECT_EQ(expected_flags[i], LibvpxVp8Encoder::EncodeFlags(tl_config)) << i;
|
||||
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, i == 0, kDefaultQp,
|
||||
&vp8_info);
|
||||
@ -238,7 +238,7 @@ TEST(TemporalLayersTest, SearchOrder) {
|
||||
|
||||
// Start with a key-frame. tl_config flags can be ignored.
|
||||
uint32_t timestamp = 0;
|
||||
TemporalLayers::FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
|
||||
Vp8TemporalLayers::FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
|
||||
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, true, kDefaultQp,
|
||||
&vp8_info);
|
||||
|
||||
@ -282,7 +282,7 @@ TEST(TemporalLayersTest, SearchOrderWithDrop) {
|
||||
|
||||
// Start with a key-frame. tl_config flags can be ignored.
|
||||
uint32_t timestamp = 0;
|
||||
TemporalLayers::FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
|
||||
Vp8TemporalLayers::FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
|
||||
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, true, kDefaultQp,
|
||||
&vp8_info);
|
||||
|
||||
@ -343,7 +343,7 @@ TEST(TemporalLayersTest, 4Layers) {
|
||||
|
||||
uint32_t timestamp = 0;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
TemporalLayers::FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
|
||||
Vp8TemporalLayers::FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
|
||||
EXPECT_EQ(expected_flags[i], LibvpxVp8Encoder::EncodeFlags(tl_config)) << i;
|
||||
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, i == 0, kDefaultQp,
|
||||
&vp8_info);
|
||||
@ -373,7 +373,7 @@ TEST(TemporalLayersTest, DoesNotReferenceDroppedFrames) {
|
||||
|
||||
// Start with a keyframe.
|
||||
uint32_t timestamp = 0;
|
||||
TemporalLayers::FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
|
||||
Vp8TemporalLayers::FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
|
||||
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, true, kDefaultQp,
|
||||
&vp8_info);
|
||||
|
||||
@ -460,7 +460,7 @@ TEST(TemporalLayersTest, DoesNotReferenceUnlessGuaranteedToExist) {
|
||||
|
||||
// Start with a keyframe.
|
||||
uint32_t timestamp = 0;
|
||||
TemporalLayers::FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
|
||||
Vp8TemporalLayers::FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
|
||||
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, true, kDefaultQp,
|
||||
&vp8_info);
|
||||
|
||||
@ -530,7 +530,7 @@ TEST(TemporalLayersTest, DoesNotReferenceUnlessGuaranteedToExistLongDelay) {
|
||||
|
||||
// Start with a keyframe.
|
||||
uint32_t timestamp = 0;
|
||||
TemporalLayers::FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
|
||||
Vp8TemporalLayers::FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
|
||||
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, true, kDefaultQp,
|
||||
&vp8_info);
|
||||
|
||||
@ -610,7 +610,8 @@ TEST(TemporalLayersTest, KeyFrame) {
|
||||
for (int j = 1; j <= i; ++j) {
|
||||
// Since last frame was always a keyframe and thus index 0 in the pattern,
|
||||
// this loop starts at index 1.
|
||||
TemporalLayers::FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
|
||||
Vp8TemporalLayers::FrameConfig tl_config =
|
||||
tl.UpdateLayerConfig(timestamp);
|
||||
EXPECT_EQ(expected_flags[j], LibvpxVp8Encoder::EncodeFlags(tl_config))
|
||||
<< j;
|
||||
tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
|
||||
@ -622,7 +623,7 @@ TEST(TemporalLayersTest, KeyFrame) {
|
||||
timestamp += 3000;
|
||||
}
|
||||
|
||||
TemporalLayers::FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
|
||||
Vp8TemporalLayers::FrameConfig 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.";
|
||||
@ -652,9 +653,9 @@ class TemporalLayersReferenceTest : public ::testing::TestWithParam<int> {
|
||||
bool sync;
|
||||
};
|
||||
|
||||
bool UpdateSyncRefState(const TemporalLayers::BufferFlags& flags,
|
||||
bool UpdateSyncRefState(const Vp8TemporalLayers::BufferFlags& flags,
|
||||
BufferState* buffer_state) {
|
||||
if (flags & TemporalLayers::kReference) {
|
||||
if (flags & Vp8TemporalLayers::kReference) {
|
||||
if (buffer_state->temporal_idx == -1)
|
||||
return true; // References key-frame.
|
||||
if (buffer_state->temporal_idx == 0) {
|
||||
@ -668,10 +669,10 @@ class TemporalLayersReferenceTest : public ::testing::TestWithParam<int> {
|
||||
return true; // No reference, does not affect sync frame status.
|
||||
}
|
||||
|
||||
void ValidateReference(const TemporalLayers::BufferFlags& flags,
|
||||
void ValidateReference(const Vp8TemporalLayers::BufferFlags& flags,
|
||||
const BufferState& buffer_state,
|
||||
int temporal_layer) {
|
||||
if (flags & TemporalLayers::kReference) {
|
||||
if (flags & Vp8TemporalLayers::kReference) {
|
||||
if (temporal_layer > 0 && buffer_state.timestamp > 0) {
|
||||
// Check that high layer reference does not go past last sync frame.
|
||||
EXPECT_GE(buffer_state.timestamp, last_sync_timestamp_);
|
||||
@ -709,9 +710,9 @@ TEST_P(TemporalLayersReferenceTest, ValidFrameConfigs) {
|
||||
// (any). If a given buffer is never updated, it is legal to reference it
|
||||
// even for sync frames. In order to be general, don't assume TL0 always
|
||||
// updates |last|.
|
||||
std::vector<TemporalLayers::FrameConfig> tl_configs(kMaxPatternLength);
|
||||
std::vector<Vp8TemporalLayers::FrameConfig> tl_configs(kMaxPatternLength);
|
||||
for (int i = 0; i < kMaxPatternLength; ++i) {
|
||||
TemporalLayers::FrameConfig tl_config = tl.UpdateLayerConfig(timestamp_);
|
||||
Vp8TemporalLayers::FrameConfig tl_config = tl.UpdateLayerConfig(timestamp_);
|
||||
tl.OnEncodeDone(timestamp_, kDefaultBytesPerFrame, i == 0, kDefaultQp,
|
||||
&vp8_specifics);
|
||||
++timestamp_;
|
||||
@ -752,11 +753,11 @@ TEST_P(TemporalLayersReferenceTest, ValidFrameConfigs) {
|
||||
|
||||
// Update the current layer state.
|
||||
BufferState state = {temporal_idx, timestamp_, is_sync_frame};
|
||||
if (tl_config.last_buffer_flags & TemporalLayers::kUpdate)
|
||||
if (tl_config.last_buffer_flags & Vp8TemporalLayers::kUpdate)
|
||||
last_state = state;
|
||||
if (tl_config.golden_buffer_flags & TemporalLayers::kUpdate)
|
||||
if (tl_config.golden_buffer_flags & Vp8TemporalLayers::kUpdate)
|
||||
golden_state = state;
|
||||
if (tl_config.arf_buffer_flags & TemporalLayers::kUpdate)
|
||||
if (tl_config.arf_buffer_flags & Vp8TemporalLayers::kUpdate)
|
||||
altref_state = state;
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "modules/video_coding/codecs/vp8/include/vp8_temporal_layers.h"
|
||||
#include "api/video_codecs/vp8_temporal_layers.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@ -29,10 +29,10 @@ class TemporalLayersChecker {
|
||||
|
||||
virtual bool CheckTemporalConfig(
|
||||
bool frame_is_keyframe,
|
||||
const TemporalLayers::FrameConfig& frame_config);
|
||||
const Vp8TemporalLayers::FrameConfig& frame_config);
|
||||
|
||||
static std::unique_ptr<TemporalLayersChecker> CreateTemporalLayersChecker(
|
||||
TemporalLayersType type,
|
||||
Vp8TemporalLayersType type,
|
||||
int num_temporal_layers);
|
||||
|
||||
private:
|
||||
@ -46,7 +46,7 @@ class TemporalLayersChecker {
|
||||
bool* need_sync,
|
||||
bool frame_is_keyframe,
|
||||
uint8_t temporal_layer,
|
||||
webrtc::TemporalLayers::BufferFlags flags,
|
||||
webrtc::Vp8TemporalLayers::BufferFlags flags,
|
||||
uint32_t sequence_number,
|
||||
uint32_t* lowest_sequence_referenced);
|
||||
BufferState last_;
|
||||
|
||||
@ -1,198 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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.
|
||||
*/
|
||||
|
||||
#ifndef MODULES_VIDEO_CODING_CODECS_VP8_INCLUDE_VP8_TEMPORAL_LAYERS_H_
|
||||
#define MODULES_VIDEO_CODING_CODECS_VP8_INCLUDE_VP8_TEMPORAL_LAYERS_H_
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Some notes on the prerequisites of the TemporalLayers interface.
|
||||
// * Implementations of TemporalLayers may not contain internal synchronization
|
||||
// so caller must make sure doing so thread safe.
|
||||
// * The encoder is assumed to encode all frames in order, and callbacks to
|
||||
// PopulateCodecSpecific() / FrameEncoded() must happen in the same order.
|
||||
//
|
||||
// This means that in the case of pipelining encoders, it is OK to have a chain
|
||||
// of calls such as this:
|
||||
// - UpdateLayerConfig(timestampA)
|
||||
// - UpdateLayerConfig(timestampB)
|
||||
// - PopulateCodecSpecific(timestampA, ...)
|
||||
// - UpdateLayerConfig(timestampC)
|
||||
// - OnEncodeDone(timestampA, 1234, ...)
|
||||
// - UpdateLayerConfig(timestampC)
|
||||
// - OnEncodeDone(timestampB, 0, ...)
|
||||
// - OnEncodeDone(timestampC, 1234, ...)
|
||||
// Note that UpdateLayerConfig() for a new frame can happen before
|
||||
// FrameEncoded() for a previous one, but calls themselves must be both
|
||||
// synchronized (e.g. run on a task queue) and in order (per type).
|
||||
|
||||
enum class TemporalLayersType { kFixedPattern, kBitrateDynamic };
|
||||
|
||||
struct CodecSpecificInfoVP8;
|
||||
enum class Vp8BufferReference : uint8_t {
|
||||
kNone = 0,
|
||||
kLast = 1,
|
||||
kGolden = 2,
|
||||
kAltref = 4
|
||||
};
|
||||
|
||||
struct Vp8EncoderConfig {
|
||||
static constexpr size_t kMaxPeriodicity = 16;
|
||||
static constexpr size_t kMaxLayers = 5;
|
||||
|
||||
// Number of active temporal layers. Set to 0 if not used.
|
||||
uint32_t ts_number_layers;
|
||||
// Arrays of length |ts_number_layers|, indicating (cumulative) target bitrate
|
||||
// and rate decimator (e.g. 4 if every 4th frame is in the given layer) for
|
||||
// each active temporal layer, starting with temporal id 0.
|
||||
uint32_t ts_target_bitrate[kMaxLayers];
|
||||
uint32_t ts_rate_decimator[kMaxLayers];
|
||||
|
||||
// The periodicity of the temporal pattern. Set to 0 if not used.
|
||||
uint32_t ts_periodicity;
|
||||
// Array of length |ts_periodicity| indicating the sequence of temporal id's
|
||||
// to assign to incoming frames.
|
||||
uint32_t ts_layer_id[kMaxPeriodicity];
|
||||
|
||||
// Target bitrate, in bps.
|
||||
uint32_t rc_target_bitrate;
|
||||
|
||||
// Clamp QP to min/max. Use 0 to disable clamping.
|
||||
uint32_t rc_min_quantizer;
|
||||
uint32_t rc_max_quantizer;
|
||||
};
|
||||
|
||||
// This interface defines a way of getting the encoder settings needed to
|
||||
// realize a temporal layer structure of predefined size.
|
||||
class TemporalLayers {
|
||||
public:
|
||||
enum BufferFlags : int {
|
||||
kNone = 0,
|
||||
kReference = 1,
|
||||
kUpdate = 2,
|
||||
kReferenceAndUpdate = kReference | kUpdate,
|
||||
};
|
||||
enum FreezeEntropy { kFreezeEntropy };
|
||||
|
||||
struct FrameConfig {
|
||||
FrameConfig();
|
||||
|
||||
FrameConfig(BufferFlags last, BufferFlags golden, BufferFlags arf);
|
||||
FrameConfig(BufferFlags last,
|
||||
BufferFlags golden,
|
||||
BufferFlags arf,
|
||||
FreezeEntropy);
|
||||
|
||||
bool drop_frame;
|
||||
BufferFlags last_buffer_flags;
|
||||
BufferFlags golden_buffer_flags;
|
||||
BufferFlags arf_buffer_flags;
|
||||
|
||||
// The encoder layer ID is used to utilize the correct bitrate allocator
|
||||
// inside the encoder. It does not control references nor determine which
|
||||
// "actual" temporal layer this is. The packetizer temporal index determines
|
||||
// which layer the encoded frame should be packetized into.
|
||||
// Normally these are the same, but current temporal-layer strategies for
|
||||
// screenshare use one bitrate allocator for all layers, but attempt to
|
||||
// packetize / utilize references to split a stream into multiple layers,
|
||||
// with different quantizer settings, to hit target bitrate.
|
||||
// TODO(pbos): Screenshare layers are being reconsidered at the time of
|
||||
// writing, we might be able to remove this distinction, and have a temporal
|
||||
// layer imply both (the normal case).
|
||||
int encoder_layer_id;
|
||||
int packetizer_temporal_idx;
|
||||
|
||||
bool layer_sync;
|
||||
|
||||
bool freeze_entropy;
|
||||
|
||||
// Indicates in which order the encoder should search the reference buffers
|
||||
// when doing motion prediction. Set to kNone to use unspecified order. Any
|
||||
// buffer indicated here must not have the corresponding no_ref bit set.
|
||||
// If all three buffers can be reference, the one not listed here should be
|
||||
// searched last.
|
||||
Vp8BufferReference first_reference;
|
||||
Vp8BufferReference second_reference;
|
||||
|
||||
bool operator==(const FrameConfig& o) const;
|
||||
bool operator!=(const FrameConfig& o) const { return !(*this == o); }
|
||||
|
||||
private:
|
||||
FrameConfig(BufferFlags last,
|
||||
BufferFlags golden,
|
||||
BufferFlags arf,
|
||||
bool freeze_entropy);
|
||||
};
|
||||
|
||||
// Factory for TemporalLayer strategy. Default behavior is a fixed pattern
|
||||
// of temporal layers. See default_temporal_layers.cc
|
||||
static std::unique_ptr<TemporalLayers> CreateTemporalLayers(
|
||||
TemporalLayersType type,
|
||||
int num_temporal_layers);
|
||||
|
||||
virtual ~TemporalLayers() = default;
|
||||
|
||||
// If this method returns true, the encoder is free to drop frames for
|
||||
// instance in an effort to uphold encoding bitrate.
|
||||
// If this return false, the encoder must not drop any frames unless:
|
||||
// 1. Requested to do so via FrameConfig.drop_frame
|
||||
// 2. The frame to be encoded is requested to be a keyframe
|
||||
// 3. The encoded detected a large overshoot and decided to drop and then
|
||||
// re-encode the image at a low bitrate. In this case the encoder should
|
||||
// call OnEncodeDone() once with size = 0 to indicate drop, and then call
|
||||
// OnEncodeDone() again when the frame has actually been encoded.
|
||||
virtual bool SupportsEncoderFrameDropping() const = 0;
|
||||
|
||||
// New target bitrate, per temporal layer.
|
||||
virtual void OnRatesUpdated(const std::vector<uint32_t>& bitrates_bps,
|
||||
int framerate_fps) = 0;
|
||||
|
||||
// Called by the encoder before encoding a frame. |cfg| contains the current
|
||||
// configuration. If the TemporalLayers instance wishes any part of that
|
||||
// to be changed before the encode step, |cfg| should be changed and then
|
||||
// return true. If false is returned, the encoder will proceed without
|
||||
// updating the configuration.
|
||||
virtual bool UpdateConfiguration(Vp8EncoderConfig* cfg) = 0;
|
||||
|
||||
// Returns the recommended VP8 encode flags needed, and moves the temporal
|
||||
// pattern to the next frame.
|
||||
// The timestamp may be used as both a time and a unique identifier, and so
|
||||
// the caller must make sure no two frames use the same timestamp.
|
||||
// The timestamp uses a 90kHz RTP clock.
|
||||
// After calling this method, first call the actual encoder with the provided
|
||||
// frame configuration, and then OnEncodeDone() below.
|
||||
virtual FrameConfig UpdateLayerConfig(uint32_t rtp_timestamp) = 0;
|
||||
|
||||
// Called after the encode step is done. |rtp_timestamp| must match the
|
||||
// parameter use in the UpdateLayerConfig() call.
|
||||
// |is_keyframe| must be true iff the encoder decided to encode this frame as
|
||||
// a keyframe.
|
||||
// If the encoder decided to drop this frame, |size_bytes| must be set to 0,
|
||||
// otherwise it should indicate the size in bytes of the encoded frame.
|
||||
// If |size_bytes| > 0, and |vp8_info| is not null, the TemporalLayers
|
||||
// instance my update |vp8_info| with codec specific data such as temporal id.
|
||||
// Some fields of this struct may have already been populated by the encoder,
|
||||
// check before overwriting.
|
||||
// If |size_bytes| > 0, |qp| should indicate the frame-level QP this frame was
|
||||
// encoded at. If the encoder does not support extracting this, |qp| should be
|
||||
// set to 0.
|
||||
virtual void OnEncodeDone(uint32_t rtp_timestamp,
|
||||
size_t size_bytes,
|
||||
bool is_keyframe,
|
||||
int qp,
|
||||
CodecSpecificInfoVP8* vp8_info) = 0;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MODULES_VIDEO_CODING_CODECS_VP8_INCLUDE_VP8_TEMPORAL_LAYERS_H_
|
||||
@ -14,6 +14,8 @@
|
||||
#include <vector>
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
#include "api/video_codecs/create_vp8_temporal_layers.h"
|
||||
#include "api/video_codecs/vp8_temporal_layers.h"
|
||||
#include "common_video/libyuv/include/webrtc_libyuv.h"
|
||||
#include "modules/video_coding/codecs/vp8/libvpx_vp8_encoder.h"
|
||||
#include "modules/video_coding/utility/simulcast_rate_allocator.h"
|
||||
@ -113,7 +115,7 @@ static void FillInEncoderConfig(vpx_codec_enc_cfg* vpx_config,
|
||||
vpx_config->rc_max_quantizer = config.rc_max_quantizer;
|
||||
}
|
||||
|
||||
bool UpdateVpxConfiguration(TemporalLayers* temporal_layers,
|
||||
bool UpdateVpxConfiguration(Vp8TemporalLayers* temporal_layers,
|
||||
vpx_codec_enc_cfg_t* cfg) {
|
||||
Vp8EncoderConfig config = GetEncoderConfig(cfg);
|
||||
const bool res = temporal_layers->UpdateConfiguration(&config);
|
||||
@ -129,22 +131,22 @@ std::unique_ptr<VideoEncoder> VP8Encoder::Create() {
|
||||
}
|
||||
|
||||
vpx_enc_frame_flags_t LibvpxVp8Encoder::EncodeFlags(
|
||||
const TemporalLayers::FrameConfig& references) {
|
||||
const Vp8TemporalLayers::FrameConfig& references) {
|
||||
RTC_DCHECK(!references.drop_frame);
|
||||
|
||||
vpx_enc_frame_flags_t flags = 0;
|
||||
|
||||
if ((references.last_buffer_flags & TemporalLayers::kReference) == 0)
|
||||
if ((references.last_buffer_flags & Vp8TemporalLayers::kReference) == 0)
|
||||
flags |= VP8_EFLAG_NO_REF_LAST;
|
||||
if ((references.last_buffer_flags & TemporalLayers::kUpdate) == 0)
|
||||
if ((references.last_buffer_flags & Vp8TemporalLayers::kUpdate) == 0)
|
||||
flags |= VP8_EFLAG_NO_UPD_LAST;
|
||||
if ((references.golden_buffer_flags & TemporalLayers::kReference) == 0)
|
||||
if ((references.golden_buffer_flags & Vp8TemporalLayers::kReference) == 0)
|
||||
flags |= VP8_EFLAG_NO_REF_GF;
|
||||
if ((references.golden_buffer_flags & TemporalLayers::kUpdate) == 0)
|
||||
if ((references.golden_buffer_flags & Vp8TemporalLayers::kUpdate) == 0)
|
||||
flags |= VP8_EFLAG_NO_UPD_GF;
|
||||
if ((references.arf_buffer_flags & TemporalLayers::kReference) == 0)
|
||||
if ((references.arf_buffer_flags & Vp8TemporalLayers::kReference) == 0)
|
||||
flags |= VP8_EFLAG_NO_REF_ARF;
|
||||
if ((references.arf_buffer_flags & TemporalLayers::kUpdate) == 0)
|
||||
if ((references.arf_buffer_flags & Vp8TemporalLayers::kUpdate) == 0)
|
||||
flags |= VP8_EFLAG_NO_UPD_ARF;
|
||||
if (references.freeze_entropy)
|
||||
flags |= VP8_EFLAG_NO_UPD_ENTROPY;
|
||||
@ -167,7 +169,6 @@ LibvpxVp8Encoder::LibvpxVp8Encoder(std::unique_ptr<LibvpxInterface> interface)
|
||||
rc_max_intra_target_(0),
|
||||
key_frame_request_(kMaxSimulcastStreams, false) {
|
||||
temporal_layers_.reserve(kMaxSimulcastStreams);
|
||||
temporal_layers_checkers_.reserve(kMaxSimulcastStreams);
|
||||
raw_images_.reserve(kMaxSimulcastStreams);
|
||||
encoded_images_.reserve(kMaxSimulcastStreams);
|
||||
send_stream_.reserve(kMaxSimulcastStreams);
|
||||
@ -206,7 +207,6 @@ int LibvpxVp8Encoder::Release() {
|
||||
raw_images_.pop_back();
|
||||
}
|
||||
temporal_layers_.clear();
|
||||
temporal_layers_checkers_.clear();
|
||||
inited_ = false;
|
||||
return ret_val;
|
||||
}
|
||||
@ -294,21 +294,18 @@ void LibvpxVp8Encoder::SetupTemporalLayers(const VideoCodec& codec) {
|
||||
RTC_DCHECK(temporal_layers_.empty());
|
||||
int num_streams = SimulcastUtility::NumberOfSimulcastStreams(codec);
|
||||
for (int i = 0; i < num_streams; ++i) {
|
||||
TemporalLayersType type;
|
||||
Vp8TemporalLayersType type;
|
||||
int num_temporal_layers =
|
||||
SimulcastUtility::NumberOfTemporalLayers(codec, i);
|
||||
if (SimulcastUtility::IsConferenceModeScreenshare(codec) && i == 0) {
|
||||
type = TemporalLayersType::kBitrateDynamic;
|
||||
type = Vp8TemporalLayersType::kBitrateDynamic;
|
||||
// Legacy screenshare layers supports max 2 layers.
|
||||
num_temporal_layers = std::max<int>(2, num_temporal_layers);
|
||||
} else {
|
||||
type = TemporalLayersType::kFixedPattern;
|
||||
type = Vp8TemporalLayersType::kFixedPattern;
|
||||
}
|
||||
temporal_layers_.emplace_back(
|
||||
TemporalLayers::CreateTemporalLayers(type, num_temporal_layers));
|
||||
temporal_layers_checkers_.emplace_back(
|
||||
TemporalLayersChecker::CreateTemporalLayersChecker(
|
||||
type, num_temporal_layers));
|
||||
CreateVp8TemporalLayers(type, num_temporal_layers));
|
||||
}
|
||||
}
|
||||
|
||||
@ -750,7 +747,7 @@ int LibvpxVp8Encoder::Encode(const VideoFrame& frame,
|
||||
}
|
||||
}
|
||||
vpx_enc_frame_flags_t flags[kMaxSimulcastStreams];
|
||||
TemporalLayers::FrameConfig tl_configs[kMaxSimulcastStreams];
|
||||
Vp8TemporalLayers::FrameConfig tl_configs[kMaxSimulcastStreams];
|
||||
for (size_t i = 0; i < encoders_.size(); ++i) {
|
||||
tl_configs[i] = temporal_layers_[i]->UpdateLayerConfig(frame.timestamp());
|
||||
if (tl_configs[i].drop_frame) {
|
||||
|
||||
@ -17,10 +17,9 @@
|
||||
#include "api/video/encoded_image.h"
|
||||
#include "api/video/video_frame.h"
|
||||
#include "api/video_codecs/video_encoder.h"
|
||||
#include "api/video_codecs/vp8_temporal_layers.h"
|
||||
#include "common_types.h" // NOLINT(build/include)
|
||||
#include "modules/video_coding/codecs/vp8/include/temporal_layers_checker.h"
|
||||
#include "modules/video_coding/codecs/vp8/include/vp8.h"
|
||||
#include "modules/video_coding/codecs/vp8/include/vp8_temporal_layers.h"
|
||||
#include "modules/video_coding/codecs/vp8/libvpx_interface.h"
|
||||
#include "modules/video_coding/include/video_codec_interface.h"
|
||||
|
||||
@ -57,7 +56,7 @@ class LibvpxVp8Encoder : public VideoEncoder {
|
||||
const char* ImplementationName() const override;
|
||||
|
||||
static vpx_enc_frame_flags_t EncodeFlags(
|
||||
const TemporalLayers::FrameConfig& references);
|
||||
const Vp8TemporalLayers::FrameConfig& references);
|
||||
|
||||
private:
|
||||
void SetupTemporalLayers(const VideoCodec& codec);
|
||||
@ -97,8 +96,7 @@ class LibvpxVp8Encoder : public VideoEncoder {
|
||||
int cpu_speed_default_;
|
||||
int number_of_cores_;
|
||||
uint32_t rc_max_intra_target_;
|
||||
std::vector<std::unique_ptr<TemporalLayers>> temporal_layers_;
|
||||
std::vector<std::unique_ptr<TemporalLayersChecker>> temporal_layers_checkers_;
|
||||
std::vector<std::unique_ptr<Vp8TemporalLayers>> temporal_layers_;
|
||||
std::vector<bool> key_frame_request_;
|
||||
std::vector<bool> send_stream_;
|
||||
std::vector<int> cpu_speed_;
|
||||
|
||||
@ -53,7 +53,7 @@ ScreenshareLayers::ScreenshareLayers(int num_temporal_layers, Clock* clock)
|
||||
encode_framerate_(1000.0f, 1000.0f), // 1 second window, second scale.
|
||||
bitrate_updated_(false),
|
||||
checker_(TemporalLayersChecker::CreateTemporalLayersChecker(
|
||||
TemporalLayersType::kBitrateDynamic,
|
||||
Vp8TemporalLayersType::kBitrateDynamic,
|
||||
num_temporal_layers)) {
|
||||
RTC_CHECK_GT(number_of_temporal_layers_, 0);
|
||||
RTC_CHECK_LE(number_of_temporal_layers_, kMaxNumTemporalLayers);
|
||||
@ -68,7 +68,7 @@ bool ScreenshareLayers::SupportsEncoderFrameDropping() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
TemporalLayers::FrameConfig ScreenshareLayers::UpdateLayerConfig(
|
||||
Vp8TemporalLayers::FrameConfig ScreenshareLayers::UpdateLayerConfig(
|
||||
uint32_t timestamp) {
|
||||
auto it = pending_frame_configs_.find(timestamp);
|
||||
if (it != pending_frame_configs_.end()) {
|
||||
@ -79,7 +79,7 @@ TemporalLayers::FrameConfig ScreenshareLayers::UpdateLayerConfig(
|
||||
if (number_of_temporal_layers_ <= 1) {
|
||||
// No flags needed for 1 layer screenshare.
|
||||
// TODO(pbos): Consider updating only last, and not all buffers.
|
||||
TemporalLayers::FrameConfig tl_config(
|
||||
Vp8TemporalLayers::FrameConfig tl_config(
|
||||
kReferenceAndUpdate, kReferenceAndUpdate, kReferenceAndUpdate);
|
||||
pending_frame_configs_[timestamp] = tl_config;
|
||||
return tl_config;
|
||||
@ -100,7 +100,7 @@ TemporalLayers::FrameConfig ScreenshareLayers::UpdateLayerConfig(
|
||||
// averaging window, or if frame interval is below 90% of desired value,
|
||||
// drop frame.
|
||||
if (encode_framerate_.Rate(now_ms).value_or(0) > *target_framerate_)
|
||||
return TemporalLayers::FrameConfig(kNone, kNone, kNone);
|
||||
return Vp8TemporalLayers::FrameConfig(kNone, kNone, kNone);
|
||||
|
||||
// Primarily check if frame interval is too short using frame timestamps,
|
||||
// as if they are correct they won't be affected by queuing in webrtc.
|
||||
@ -108,7 +108,7 @@ TemporalLayers::FrameConfig ScreenshareLayers::UpdateLayerConfig(
|
||||
kOneSecond90Khz / *target_framerate_;
|
||||
if (last_timestamp_ != -1 && ts_diff > 0) {
|
||||
if (ts_diff < 85 * expected_frame_interval_90khz / 100) {
|
||||
return TemporalLayers::FrameConfig(kNone, kNone, kNone);
|
||||
return Vp8TemporalLayers::FrameConfig(kNone, kNone, kNone);
|
||||
}
|
||||
} else {
|
||||
// Timestamps looks off, use realtime clock here instead.
|
||||
@ -116,7 +116,7 @@ TemporalLayers::FrameConfig ScreenshareLayers::UpdateLayerConfig(
|
||||
if (last_frame_time_ms_ != -1 &&
|
||||
now_ms - last_frame_time_ms_ <
|
||||
(85 * expected_frame_interval_ms) / 100) {
|
||||
return TemporalLayers::FrameConfig(kNone, kNone, kNone);
|
||||
return Vp8TemporalLayers::FrameConfig(kNone, kNone, kNone);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -182,30 +182,30 @@ TemporalLayers::FrameConfig ScreenshareLayers::UpdateLayerConfig(
|
||||
RTC_NOTREACHED();
|
||||
}
|
||||
|
||||
TemporalLayers::FrameConfig tl_config;
|
||||
Vp8TemporalLayers::FrameConfig tl_config;
|
||||
// TODO(pbos): Consider referencing but not updating the 'alt' buffer for all
|
||||
// layers.
|
||||
switch (layer_state) {
|
||||
case TemporalLayerState::kDrop:
|
||||
tl_config = TemporalLayers::FrameConfig(kNone, kNone, kNone);
|
||||
tl_config = Vp8TemporalLayers::FrameConfig(kNone, kNone, kNone);
|
||||
break;
|
||||
case TemporalLayerState::kTl0:
|
||||
// TL0 only references and updates 'last'.
|
||||
tl_config =
|
||||
TemporalLayers::FrameConfig(kReferenceAndUpdate, kNone, kNone);
|
||||
Vp8TemporalLayers::FrameConfig(kReferenceAndUpdate, kNone, kNone);
|
||||
tl_config.packetizer_temporal_idx = 0;
|
||||
break;
|
||||
case TemporalLayerState::kTl1:
|
||||
// TL1 references both 'last' and 'golden' but only updates 'golden'.
|
||||
tl_config =
|
||||
TemporalLayers::FrameConfig(kReference, kReferenceAndUpdate, kNone);
|
||||
tl_config = Vp8TemporalLayers::FrameConfig(kReference,
|
||||
kReferenceAndUpdate, kNone);
|
||||
tl_config.packetizer_temporal_idx = 1;
|
||||
break;
|
||||
case TemporalLayerState::kTl1Sync:
|
||||
// Predict from only TL0 to allow participants to switch to the high
|
||||
// bitrate stream. Updates 'golden' so that TL1 can continue to refer to
|
||||
// and update 'golden' from this point on.
|
||||
tl_config = TemporalLayers::FrameConfig(kReference, kUpdate, kNone);
|
||||
tl_config = Vp8TemporalLayers::FrameConfig(kReference, kUpdate, kNone);
|
||||
tl_config.packetizer_temporal_idx = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -13,8 +13,8 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "api/video_codecs/vp8_temporal_layers.h"
|
||||
#include "modules/video_coding/codecs/vp8/include/temporal_layers_checker.h"
|
||||
#include "modules/video_coding/codecs/vp8/include/vp8_temporal_layers.h"
|
||||
#include "modules/video_coding/utility/frame_dropper.h"
|
||||
#include "rtc_base/rate_statistics.h"
|
||||
#include "rtc_base/timeutils.h"
|
||||
@ -24,7 +24,7 @@ namespace webrtc {
|
||||
struct CodecSpecificInfoVP8;
|
||||
class Clock;
|
||||
|
||||
class ScreenshareLayers : public TemporalLayers {
|
||||
class ScreenshareLayers : public Vp8TemporalLayers {
|
||||
public:
|
||||
static const double kMaxTL0FpsReduction;
|
||||
static const double kAcceptableTargetOvershoot;
|
||||
@ -38,7 +38,7 @@ class ScreenshareLayers : public TemporalLayers {
|
||||
|
||||
// Returns the recommended VP8 encode flags needed. May refresh the decoder
|
||||
// and/or update the reference buffers.
|
||||
TemporalLayers::FrameConfig UpdateLayerConfig(
|
||||
Vp8TemporalLayers::FrameConfig UpdateLayerConfig(
|
||||
uint32_t rtp_timestamp) override;
|
||||
|
||||
// New target bitrate, per temporal layer.
|
||||
@ -74,7 +74,7 @@ class ScreenshareLayers : public TemporalLayers {
|
||||
int max_qp_;
|
||||
uint32_t max_debt_bytes_;
|
||||
|
||||
std::map<uint32_t, TemporalLayers::FrameConfig> pending_frame_configs_;
|
||||
std::map<uint32_t, Vp8TemporalLayers::FrameConfig> pending_frame_configs_;
|
||||
|
||||
// Configured max framerate.
|
||||
absl::optional<uint32_t> target_framerate_;
|
||||
|
||||
@ -87,7 +87,7 @@ class ScreenshareLayerTest : public ::testing::Test {
|
||||
return flags;
|
||||
}
|
||||
|
||||
TemporalLayers::FrameConfig UpdateLayerConfig(uint32_t timestamp) {
|
||||
Vp8TemporalLayers::FrameConfig UpdateLayerConfig(uint32_t timestamp) {
|
||||
int64_t timestamp_ms = timestamp / 90;
|
||||
clock_.AdvanceTimeMilliseconds(timestamp_ms - clock_.TimeInMilliseconds());
|
||||
return layers_->UpdateLayerConfig(timestamp);
|
||||
@ -167,7 +167,7 @@ class ScreenshareLayerTest : public ::testing::Test {
|
||||
std::unique_ptr<ScreenshareLayers> layers_;
|
||||
|
||||
uint32_t timestamp_;
|
||||
TemporalLayers::FrameConfig tl_config_;
|
||||
Vp8TemporalLayers::FrameConfig tl_config_;
|
||||
Vp8EncoderConfig cfg_;
|
||||
bool config_updated_;
|
||||
CodecSpecificInfoVP8 vp8_info_;
|
||||
|
||||
@ -12,6 +12,6 @@
|
||||
#define MODULES_VIDEO_CODING_CODECS_VP8_TEMPORAL_LAYERS_H_
|
||||
|
||||
// TODO(webrtc:9012) Remove this file when downstream projects have updated.
|
||||
#include "modules/video_coding/codecs/vp8/include/vp8_temporal_layers.h"
|
||||
#include "api/video_codecs/vp8_temporal_layers.h"
|
||||
|
||||
#endif // MODULES_VIDEO_CODING_CODECS_VP8_TEMPORAL_LAYERS_H_
|
||||
|
||||
@ -17,13 +17,13 @@
|
||||
namespace webrtc {
|
||||
|
||||
std::unique_ptr<TemporalLayersChecker>
|
||||
TemporalLayersChecker::CreateTemporalLayersChecker(TemporalLayersType type,
|
||||
TemporalLayersChecker::CreateTemporalLayersChecker(Vp8TemporalLayersType type,
|
||||
int num_temporal_layers) {
|
||||
switch (type) {
|
||||
case TemporalLayersType::kFixedPattern:
|
||||
case Vp8TemporalLayersType::kFixedPattern:
|
||||
return absl::make_unique<DefaultTemporalLayersChecker>(
|
||||
num_temporal_layers);
|
||||
case TemporalLayersType::kBitrateDynamic:
|
||||
case Vp8TemporalLayersType::kBitrateDynamic:
|
||||
// Conference mode temporal layering for screen content in base stream.
|
||||
return absl::make_unique<TemporalLayersChecker>(num_temporal_layers);
|
||||
}
|
||||
@ -40,10 +40,10 @@ bool TemporalLayersChecker::CheckAndUpdateBufferState(
|
||||
bool* need_sync,
|
||||
bool frame_is_keyframe,
|
||||
uint8_t temporal_layer,
|
||||
webrtc::TemporalLayers::BufferFlags flags,
|
||||
webrtc::Vp8TemporalLayers::BufferFlags flags,
|
||||
uint32_t sequence_number,
|
||||
uint32_t* lowest_sequence_referenced) {
|
||||
if (flags & TemporalLayers::BufferFlags::kReference) {
|
||||
if (flags & Vp8TemporalLayers::BufferFlags::kReference) {
|
||||
if (state->temporal_layer > 0 && !state->is_keyframe) {
|
||||
*need_sync = false;
|
||||
}
|
||||
@ -57,7 +57,7 @@ bool TemporalLayersChecker::CheckAndUpdateBufferState(
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ((flags & TemporalLayers::BufferFlags::kUpdate)) {
|
||||
if ((flags & Vp8TemporalLayers::BufferFlags::kUpdate)) {
|
||||
state->temporal_layer = temporal_layer;
|
||||
state->sequence_number = sequence_number;
|
||||
state->is_keyframe = frame_is_keyframe;
|
||||
@ -69,7 +69,7 @@ bool TemporalLayersChecker::CheckAndUpdateBufferState(
|
||||
|
||||
bool TemporalLayersChecker::CheckTemporalConfig(
|
||||
bool frame_is_keyframe,
|
||||
const TemporalLayers::FrameConfig& frame_config) {
|
||||
const Vp8TemporalLayers::FrameConfig& frame_config) {
|
||||
if (frame_config.drop_frame ||
|
||||
frame_config.packetizer_temporal_idx == kNoTemporalIdx) {
|
||||
return true;
|
||||
|
||||
@ -12,10 +12,10 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/video_codecs/vp8_temporal_layers.h"
|
||||
#include "common_video/libyuv/include/webrtc_libyuv.h"
|
||||
#include "modules/video_coding/codecs/test/video_codec_unittest.h"
|
||||
#include "modules/video_coding/codecs/vp8/include/vp8.h"
|
||||
#include "modules/video_coding/codecs/vp8/include/vp8_temporal_layers.h"
|
||||
#include "modules/video_coding/codecs/vp8/libvpx_vp8_encoder.h"
|
||||
#include "modules/video_coding/codecs/vp8/test/mock_libvpx_interface.h"
|
||||
#include "modules/video_coding/include/mock/mock_video_codec_interface.h"
|
||||
|
||||
@ -1,42 +0,0 @@
|
||||
/* Copyright (c) 2017 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/codecs/vp8/include/vp8_temporal_layers.h"
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
#include "modules/video_coding/codecs/vp8/default_temporal_layers.h"
|
||||
#include "modules/video_coding/codecs/vp8/screenshare_layers.h"
|
||||
#include "system_wrappers/include/clock.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
bool TemporalLayers::FrameConfig::operator==(const FrameConfig& o) const {
|
||||
return drop_frame == o.drop_frame &&
|
||||
last_buffer_flags == o.last_buffer_flags &&
|
||||
golden_buffer_flags == o.golden_buffer_flags &&
|
||||
arf_buffer_flags == o.arf_buffer_flags && layer_sync == o.layer_sync &&
|
||||
freeze_entropy == o.freeze_entropy &&
|
||||
encoder_layer_id == o.encoder_layer_id &&
|
||||
packetizer_temporal_idx == o.packetizer_temporal_idx;
|
||||
}
|
||||
|
||||
std::unique_ptr<TemporalLayers> TemporalLayers::CreateTemporalLayers(
|
||||
TemporalLayersType type,
|
||||
int num_temporal_layers) {
|
||||
switch (type) {
|
||||
case TemporalLayersType::kFixedPattern:
|
||||
return absl::make_unique<DefaultTemporalLayers>(num_temporal_layers);
|
||||
case TemporalLayersType::kBitrateDynamic:
|
||||
// Conference mode temporal layering for screen content in base stream.
|
||||
return absl::make_unique<ScreenshareLayers>(num_temporal_layers,
|
||||
Clock::GetRealTimeClock());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
Reference in New Issue
Block a user