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 |