Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1657)

Unified Diff: webrtc/video/video_encoder_hardware.cc

Issue 1660963002: Bitrate controller for VideoToolbox encoder. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Rebase Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « webrtc/video/BUILD.gn ('k') | webrtc/video/webrtc_video.gypi » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: webrtc/video/video_encoder_hardware.cc
diff --git a/webrtc/video/video_encoder_hardware.cc b/webrtc/video/video_encoder_hardware.cc
new file mode 100644
index 0000000000000000000000000000000000000000..3b8a3edb574da8d394786b8fe47d099c03ee4c42
--- /dev/null
+++ b/webrtc/video/video_encoder_hardware.cc
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2016 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 <cmath>
+
+#include "webrtc/base/checks.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/timeutils.h"
+#include "webrtc/video_encoder.h"
+
+namespace internal {
+
+class HardwareEncodedImageCallbackWrapper
+ : public webrtc::EncodedImageCallback {
+ public:
+ HardwareEncodedImageCallbackWrapper(
+ webrtc::HardwareVideoEncoderWrapper* encoder)
+ : encoder_(encoder) {
+ RTC_CHECK(encoder_);
+ }
+
+ virtual ~HardwareEncodedImageCallbackWrapper() { encoder_ = nullptr; }
+
+ virtual int32_t Encoded(const webrtc::EncodedImage& encoded_image,
+ const webrtc::CodecSpecificInfo* codec_specific_info,
+ const webrtc::RTPFragmentationHeader* fragmentation) {
+ return encoder_->OnFrameEncoded(encoded_image, codec_specific_info,
+ fragmentation);
+ }
+
+ private:
+ webrtc::HardwareVideoEncoderWrapper* encoder_;
+};
+
+} // namespace internal
+
+namespace webrtc {
+
+HardwareVideoEncoderWrapper::HardwareVideoEncoderWrapper(
+ webrtc::VideoEncoder* encoder)
+ : encoder_(encoder),
+ bitrate_tracker_(30 * 20),
+ original_bitrate_(0),
+ original_frame_rate_(0),
+ adjusted_bitrate_(0),
+ last_bitrate_update_time_ms_(0),
+ last_frame_time_ms_(0) {
+ RTC_DCHECK(encoder->IsHardwareEncoder());
+ wrapped_callback_.reset(
+ new internal::HardwareEncodedImageCallbackWrapper(this));
+}
+
+int32_t HardwareVideoEncoderWrapper::InitEncode(
+ const VideoCodec* codec_settings,
+ int32_t number_of_cores,
+ size_t max_payload_size) {
+ return encoder_->InitEncode(codec_settings, number_of_cores,
+ max_payload_size);
+}
+
+int32_t HardwareVideoEncoderWrapper::RegisterEncodeCompleteCallback(
+ EncodedImageCallback* callback) {
+ callback_ = callback;
+ return encoder_->RegisterEncodeCompleteCallback(wrapped_callback_.get());
+}
+
+int32_t HardwareVideoEncoderWrapper::Release() {
+ return encoder_->Release();
+}
+
+int32_t HardwareVideoEncoderWrapper::Encode(
+ const VideoFrame& frame,
+ const CodecSpecificInfo* codec_specific_info,
+ const std::vector<FrameType>* frame_types) {
+ return encoder_->Encode(frame, codec_specific_info, frame_types);
+}
+
+int32_t HardwareVideoEncoderWrapper::SetChannelParameters(uint32_t packet_loss,
+ int64_t rtt) {
+ return encoder_->SetChannelParameters(packet_loss, rtt);
+}
+
+int32_t HardwareVideoEncoderWrapper::SetRates(uint32_t bitrate,
pbos-webrtc 2016/02/03 15:52:22 This one is permitted to be called often so you sh
+ uint32_t framerate) {
+ original_bitrate_ = bitrate * 1000;
+ adjusted_bitrate_ = original_bitrate_;
+ original_frame_rate_ = framerate;
+ bitrate_tracker_.Reset();
+ return encoder_->SetRates(bitrate, framerate);
+}
+
+void HardwareVideoEncoderWrapper::OnDroppedFrame() {
+ encoder_->OnDroppedFrame();
+}
+
+int HardwareVideoEncoderWrapper::GetTargetFramerate() {
+ return encoder_->GetTargetFramerate();
+}
+
+bool HardwareVideoEncoderWrapper::SupportsNativeHandle() const {
+ return encoder_->SupportsNativeHandle();
+}
+
+bool HardwareVideoEncoderWrapper::IsHardwareEncoder() const {
+ return encoder_->IsHardwareEncoder();
+}
+
+const char* HardwareVideoEncoderWrapper::ImplementationName() const {
+ return encoder_->ImplementationName();
+}
+
+int32_t HardwareVideoEncoderWrapper::OnFrameEncoded(
+ const EncodedImage& encoded_image,
+ const CodecSpecificInfo* codec_specific_info,
+ const RTPFragmentationHeader* fragmentation) {
+ uint32_t current_time_ms = rtc::Time();
+ UpdateBitrate(current_time_ms);
+ UpdateBitrateTracker(encoded_image._size, current_time_ms);
+ return callback_->Encoded(encoded_image, codec_specific_info, fragmentation);
+}
+
+void HardwareVideoEncoderWrapper::UpdateBitrateTracker(
+ size_t frame_size,
+ uint32_t current_time_ms) {
+ if (last_frame_time_ms_) {
+ RTC_DCHECK_LT(last_frame_time_ms_, current_time_ms);
+ float bitrate_sample =
+ static_cast<float>(frame_size * 8 * 1000) /
+ static_cast<float>(current_time_ms - last_frame_time_ms_);
+ bitrate_tracker_.AddSample(bitrate_sample);
+ }
+ last_frame_time_ms_ = current_time_ms;
+}
+
+void HardwareVideoEncoderWrapper::UpdateBitrate(uint32_t current_time_ms) {
+ if (current_time_ms - last_bitrate_update_time_ms_ <
+ kBitrateUpdateIntervalMs) {
+ return;
+ }
+ if (bitrate_tracker_.count() < 30) {
+ // Wait for some samples before doing anything. Roughly 1s of samples
+ // at 30fps.
+ return;
+ }
+ // Compute exponentially weighted average of bitrate samples.
+ float bitrate = bitrate_tracker_.ComputeWeightedMean(0.17);
+ float error = original_bitrate_ - bitrate;
+
+ // Adjust if we've overshot by any amount or if we've undershot too much.
+ if (bitrate > original_bitrate_ ||
+ error * 100 > kBitrateTolerancePct * original_bitrate_) {
+ // Adjust the bitrate by a fraction of the error.
+ float adjustment = .5 * error;
+ float adjusted_bitrate = original_bitrate_ + adjustment;
+
+ // Clamp the adjustment.
+ float min_bitrate =
+ static_cast<float>(kBitrateTolerancePct * original_bitrate_) / 100.;
+ float max_bitrate =
+ static_cast<float>((100 - kBitrateTolerancePct) * original_bitrate_) /
+ 100.;
+ adjusted_bitrate = std::max(adjusted_bitrate, min_bitrate);
+ adjusted_bitrate = std::min(adjusted_bitrate, max_bitrate);
+
+ // Set the adjustment if it's not already set.
+ if (adjusted_bitrate_ != adjusted_bitrate) {
+ encoder_->SetRates(adjusted_bitrate * 1e-3, original_frame_rate_);
+ LOG(LS_INFO) << "Adjusting encoder bitrate:"
+ << "\n target_bitrate:" << original_bitrate_
+ << "\n actual_bitrate:" << bitrate
+ << "\n previous_bitrate:" << adjusted_bitrate_
+ << "\n adjusted_bitrate:" << (uint32_t)adjusted_bitrate;
+ adjusted_bitrate_ = adjusted_bitrate;
+ }
+ }
+ last_bitrate_update_time_ms_ = current_time_ms;
+}
+
+} // namespace webrtc
« no previous file with comments | « webrtc/video/BUILD.gn ('k') | webrtc/video/webrtc_video.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698