Index: webrtc/test/fake_encoder.cc |
diff --git a/webrtc/test/fake_encoder.cc b/webrtc/test/fake_encoder.cc |
index fce12c61a804c8af841435b001779374b912066c..8de59a1d0b8ec57b9aa52a46f8cedf70f233aeae 100644 |
--- a/webrtc/test/fake_encoder.cc |
+++ b/webrtc/test/fake_encoder.cc |
@@ -27,8 +27,9 @@ namespace test { |
FakeEncoder::FakeEncoder(Clock* clock) |
: clock_(clock), |
callback_(nullptr), |
+ configured_input_framerate_(-1), |
max_target_bitrate_kbps_(-1), |
- last_encode_time_ms_(0) { |
+ pending_keyframe_(true) { |
// 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); |
@@ -47,6 +48,8 @@ int32_t FakeEncoder::InitEncode(const VideoCodec* config, |
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; |
} |
@@ -59,9 +62,10 @@ int32_t FakeEncoder::Encode(const VideoFrame& input_image, |
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; |
@@ -72,42 +76,33 @@ int32_t FakeEncoder::Encode(const VideoFrame& input_image, |
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; |
} |
- int64_t time_now_ms = clock_->TimeInMilliseconds(); |
- const bool first_encode = (last_encode_time_ms == 0); |
- RTC_DCHECK_GT(max_framerate, 0); |
- 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; |
+ for (FrameType frame_type : *frame_types) { |
+ if (frame_type == kVideoFrameKey) { |
+ keyframe = true; |
+ break; |
+ } |
} |
- 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); |
+ RTC_DCHECK_GT(max_framerate, 0); |
- 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; |
+ 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)); |
- { |
- rtc::CritScope cs(&crit_sect_); |
- last_encode_time_ms_ = time_now_ms; |
- } |
+ size_t bits_available = target_bitrate_sum_kbps * 1000 / framerate; |
RTC_DCHECK_GT(num_simulcast_streams, 0); |
for (unsigned char i = 0; i < num_simulcast_streams; ++i) { |
@@ -116,18 +111,38 @@ int32_t FakeEncoder::Encode(const VideoFrame& input_image, |
specifics.codecType = kVideoCodecGeneric; |
specifics.codecSpecific.generic.simulcast_idx = i; |
size_t min_stream_bits = static_cast<size_t>( |
- simulcast_streams[i].minBitrate * time_since_last_encode_ms); |
+ (simulcast_streams[i].minBitrate * 1000) / framerate); |
size_t max_stream_bits = static_cast<size_t>( |
- simulcast_streams[i].maxBitrate * time_since_last_encode_ms); |
+ (simulcast_streams[i].maxBitrate * 1000) / framerate); |
size_t stream_bits = (bits_available > max_stream_bits) ? max_stream_bits : |
bits_available; |
size_t stream_bytes = (stream_bits + 7) / 8; |
- if (first_encode) { |
+ if (keyframe) { |
// The first frame is a key frame and should be larger. |
- // TODO(holmer): The FakeEncoder should store the bits_available between |
- // encodes so that it can compensate for oversized frames. |
- stream_bytes *= 10; |
+ // Store the overshoot bytes and distribute them over the coming frames, |
+ // so that we on average meet the bitrate target. |
+ const int kKeyframeSizeFactor = 10; |
+ // Pay 1/2 of a frame debt factor every frame. |
+ const int kNumDebtPayments = (kKeyframeSizeFactor - 1) * 2; |
+ debt_bytes_.resize(kNumDebtPayments); |
+ size_t total_debt_bytes = (kKeyframeSizeFactor - 1) * stream_bytes; |
+ for (int i = 0; i < kNumDebtPayments; ++i) |
+ debt_bytes_[i] += total_debt_bytes / kNumDebtPayments; |
stefan-webrtc
2017/05/23 17:03:20
An option is to just keep track of a total debt an
sprang_webrtc
2017/05/24 09:07:07
Maybe, but then paying of the whole debt will take
holmer
2017/06/02 11:38:05
You could have a total_debt and a payed_debt and t
|
+ stream_bytes *= kKeyframeSizeFactor; |
+ } else { |
+ if (!debt_bytes_.empty()) { |
+ size_t debt_bytes = std::min(stream_bytes, debt_bytes_[0]); |
+ debt_bytes_.pop_front(); |
+ if (debt_bytes >= stream_bytes) { |
stefan-webrtc
2017/05/23 17:03:20
This can only be true if == right? What is it that
sprang_webrtc
2017/05/24 09:07:07
Oops, the std::min above shouldn't be there.
I'll
|
+ if (debt_bytes_.empty()) |
+ debt_bytes_.resize(1); |
+ debt_bytes_[0] += debt_bytes - stream_bytes + 1; |
+ debt_bytes = stream_bytes - 1; |
+ } |
+ stream_bytes -= debt_bytes; |
+ } |
} |
+ |
if (stream_bytes > num_encoded_bytes) |
stream_bytes = num_encoded_bytes; |
@@ -175,6 +190,7 @@ int32_t FakeEncoder::SetRateAllocation(const BitrateAllocation& rate_allocation, |
uint32_t framerate) { |
rtc::CritScope cs(&crit_sect_); |
target_bitrate_ = rate_allocation; |
+ configured_input_framerate_ = framerate; |
return 0; |
} |
@@ -183,6 +199,11 @@ const char* FakeEncoder::ImplementationName() const { |
return kImplementationName; |
} |
+int FakeEncoder::GetConfiguredInputFramerate() { |
+ rtc::CritScope cs(&crit_sect_); |
+ return configured_input_framerate_; |
+} |
+ |
FakeH264Encoder::FakeH264Encoder(Clock* clock) |
: FakeEncoder(clock), callback_(nullptr), idr_counter_(0) { |
FakeEncoder::RegisterEncodeCompleteCallback(this); |