Index: webrtc/test/fake_encoder.cc |
diff --git a/webrtc/test/fake_encoder.cc b/webrtc/test/fake_encoder.cc |
index 962cd657a11df2a01c6191ce1e547fb5add45f36..fce12c61a804c8af841435b001779374b912066c 100644 |
--- a/webrtc/test/fake_encoder.cc |
+++ b/webrtc/test/fake_encoder.cc |
@@ -24,15 +24,11 @@ |
namespace webrtc { |
namespace test { |
-const int kKeyframeSizeFactor = 10; |
- |
FakeEncoder::FakeEncoder(Clock* clock) |
: clock_(clock), |
callback_(nullptr), |
- configured_input_framerate_(-1), |
max_target_bitrate_kbps_(-1), |
- pending_keyframe_(true), |
- debt_bytes_(0) { |
+ last_encode_time_ms_(0) { |
// Generate some arbitrary not-all-zero data |
for (size_t i = 0; i < sizeof(encoded_buffer_); ++i) { |
encoded_buffer_[i] = static_cast<uint8_t>(i); |
@@ -51,8 +47,6 @@ |
rtc::CritScope cs(&crit_sect_); |
config_ = *config; |
target_bitrate_.SetBitrate(0, 0, config_.startBitrate * 1000); |
- configured_input_framerate_ = config_.maxFramerate; |
- pending_keyframe_ = true; |
return 0; |
} |
@@ -65,10 +59,9 @@ |
EncodedImageCallback* callback; |
uint32_t target_bitrate_sum_kbps; |
int max_target_bitrate_kbps; |
+ int64_t last_encode_time_ms; |
size_t num_encoded_bytes; |
- int framerate; |
VideoCodecMode mode; |
- bool keyframe; |
{ |
rtc::CritScope cs(&crit_sect_); |
max_framerate = config_.maxFramerate; |
@@ -79,33 +72,42 @@ |
callback = callback_; |
target_bitrate_sum_kbps = target_bitrate_.get_sum_kbps(); |
max_target_bitrate_kbps = max_target_bitrate_kbps_; |
+ last_encode_time_ms = last_encode_time_ms_; |
num_encoded_bytes = sizeof(encoded_buffer_); |
mode = config_.mode; |
- if (configured_input_framerate_ > 0) { |
- framerate = configured_input_framerate_; |
- } else { |
- framerate = max_framerate; |
- } |
- keyframe = pending_keyframe_; |
- pending_keyframe_ = false; |
- } |
- |
- for (FrameType frame_type : *frame_types) { |
- if (frame_type == kVideoFrameKey) { |
- keyframe = true; |
- break; |
- } |
- } |
- |
+ } |
+ |
+ int64_t time_now_ms = clock_->TimeInMilliseconds(); |
+ const bool first_encode = (last_encode_time_ms == 0); |
RTC_DCHECK_GT(max_framerate, 0); |
- |
- size_t bitrate = target_bitrate_sum_kbps; |
- bitrate = |
- std::max(bitrate, static_cast<size_t>(simulcast_streams[0].minBitrate)); |
- if (max_target_bitrate_kbps > 0) |
- bitrate = std::min(bitrate, static_cast<size_t>(max_target_bitrate_kbps)); |
- |
- size_t bits_available = target_bitrate_sum_kbps * 1000 / framerate; |
+ int64_t time_since_last_encode_ms = 1000 / max_framerate; |
+ if (!first_encode) { |
+ // For all frames but the first we can estimate the display time by looking |
+ // at the display time of the previous frame. |
+ time_since_last_encode_ms = time_now_ms - last_encode_time_ms; |
+ } |
+ if (time_since_last_encode_ms > 3 * 1000 / max_framerate) { |
+ // Rudimentary check to make sure we don't widely overshoot bitrate target |
+ // when resuming encoding after a suspension. |
+ time_since_last_encode_ms = 3 * 1000 / max_framerate; |
+ } |
+ |
+ size_t bits_available = |
+ static_cast<size_t>(target_bitrate_sum_kbps * time_since_last_encode_ms); |
+ size_t min_bits = static_cast<size_t>(simulcast_streams[0].minBitrate * |
+ time_since_last_encode_ms); |
+ |
+ if (bits_available < min_bits) |
+ bits_available = min_bits; |
+ size_t max_bits = |
+ static_cast<size_t>(max_target_bitrate_kbps * time_since_last_encode_ms); |
+ if (max_bits > 0 && max_bits < bits_available) |
+ bits_available = max_bits; |
+ |
+ { |
+ rtc::CritScope cs(&crit_sect_); |
+ last_encode_time_ms_ = time_now_ms; |
+ } |
RTC_DCHECK_GT(num_simulcast_streams, 0); |
for (unsigned char i = 0; i < num_simulcast_streams; ++i) { |
@@ -114,27 +116,18 @@ |
specifics.codecType = kVideoCodecGeneric; |
specifics.codecSpecific.generic.simulcast_idx = i; |
size_t min_stream_bits = static_cast<size_t>( |
- (simulcast_streams[i].minBitrate * 1000) / framerate); |
+ simulcast_streams[i].minBitrate * time_since_last_encode_ms); |
size_t max_stream_bits = static_cast<size_t>( |
- (simulcast_streams[i].maxBitrate * 1000) / framerate); |
+ simulcast_streams[i].maxBitrate * time_since_last_encode_ms); |
size_t stream_bits = (bits_available > max_stream_bits) ? max_stream_bits : |
bits_available; |
size_t stream_bytes = (stream_bits + 7) / 8; |
- if (keyframe) { |
+ if (first_encode) { |
// The first frame is a key frame and should be larger. |
- // Store the overshoot bytes and distribute them over the coming frames, |
- // so that we on average meet the bitrate target. |
- debt_bytes_ += (kKeyframeSizeFactor - 1) * stream_bytes; |
- stream_bytes *= kKeyframeSizeFactor; |
- } else { |
- if (debt_bytes_ > 0) { |
- // Pay at most half of the frame size for old debts. |
- size_t payment_size = std::min(stream_bytes / 2, debt_bytes_); |
- debt_bytes_ -= payment_size; |
- stream_bytes -= payment_size; |
- } |
+ // TODO(holmer): The FakeEncoder should store the bits_available between |
+ // encodes so that it can compensate for oversized frames. |
+ stream_bytes *= 10; |
} |
- |
if (stream_bytes > num_encoded_bytes) |
stream_bytes = num_encoded_bytes; |
@@ -182,18 +175,12 @@ |
uint32_t framerate) { |
rtc::CritScope cs(&crit_sect_); |
target_bitrate_ = rate_allocation; |
- configured_input_framerate_ = framerate; |
return 0; |
} |
const char* FakeEncoder::kImplementationName = "fake_encoder"; |
const char* FakeEncoder::ImplementationName() const { |
return kImplementationName; |
-} |
- |
-int FakeEncoder::GetConfiguredInputFramerate() const { |
- rtc::CritScope cs(&crit_sect_); |
- return configured_input_framerate_; |
} |
FakeH264Encoder::FakeH264Encoder(Clock* clock) |