Chromium Code Reviews| 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 |