Move usage of QualityScaler to ViEEncoder.

This brings QualityScaler much more in line with OveruseFrameDetector.
The two classes are conceptually similar, and should be used in the
same way. The biggest changes in this CL are:
- Quality scaling is now only done in ViEEncoder and not in each
  encoder implementation separately.
- QualityScaler now checks the average QP asynchronously, instead of
  having to be polled on each frame.
- QualityScaler is no longer responsible for actually scaling the frames,
  but has a callback to ViEEncoder that it uses to express it's desire
  for lower resolution.

BUG=webrtc:6495

Review-Url: https://codereview.webrtc.org/2398963003
Cr-Commit-Position: refs/heads/master@{#15286}
This commit is contained in:
kthelgason
2016-11-29 01:44:11 -08:00
committed by Commit bot
parent 320e45ad87
commit 876222f77d
32 changed files with 736 additions and 907 deletions

View File

@ -46,7 +46,6 @@ class H264VideoToolboxEncoder : public H264Encoder {
int RegisterEncodeCompleteCallback(EncodedImageCallback* callback) override;
void OnDroppedFrame() override;
int SetChannelParameters(uint32_t packet_loss, int64_t rtt) override;
int SetRates(uint32_t new_bitrate_kbit, uint32_t frame_rate) override;
@ -67,6 +66,8 @@ class H264VideoToolboxEncoder : public H264Encoder {
uint32_t timestamp,
VideoRotation rotation);
ScalingSettings GetScalingSettings() const override;
private:
int ResetCompressionSession();
void ConfigureCompressionSession();
@ -85,10 +86,7 @@ class H264VideoToolboxEncoder : public H264Encoder {
int32_t height_;
const CFStringRef profile_;
rtc::CriticalSection quality_scaler_crit_;
QualityScaler quality_scaler_ GUARDED_BY(quality_scaler_crit_);
H264BitstreamParser h264_bitstream_parser_;
bool enable_scaling_;
std::vector<uint8_t> nv12_scale_buffer_;
}; // H264VideoToolboxEncoder

View File

@ -360,18 +360,9 @@ int H264VideoToolboxEncoder::InitEncode(const VideoCodec* codec_settings,
size_t max_payload_size) {
RTC_DCHECK(codec_settings);
RTC_DCHECK_EQ(codec_settings->codecType, kVideoCodecH264);
{
rtc::CritScope lock(&quality_scaler_crit_);
quality_scaler_.Init(internal::kLowH264QpThreshold,
internal::kHighH264QpThreshold,
codec_settings->startBitrate, codec_settings->width,
codec_settings->height, codec_settings->maxFramerate);
QualityScaler::Resolution res = quality_scaler_.GetScaledResolution();
// TODO(tkchin): We may need to enforce width/height dimension restrictions
// to match what the encoder supports.
width_ = res.width;
height_ = res.height;
}
width_ = codec_settings->width;
height_ = codec_settings->height;
// We can only set average bitrate on the HW encoder.
target_bitrate_bps_ = codec_settings->startBitrate;
bitrate_adjuster_.SetTargetBitrateBps(target_bitrate_bps_);
@ -386,6 +377,9 @@ int H264VideoToolboxEncoder::Encode(
const VideoFrame& frame,
const CodecSpecificInfo* codec_specific_info,
const std::vector<FrameType>* frame_types) {
// |input_frame| size should always match codec settings.
RTC_DCHECK_EQ(frame.width(), width_);
RTC_DCHECK_EQ(frame.height(), height_);
RTC_DCHECK(!frame.IsZeroSize());
if (!callback_ || !compression_session_) {
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
@ -399,18 +393,6 @@ int H264VideoToolboxEncoder::Encode(
#endif
bool is_keyframe_required = false;
quality_scaler_.OnEncodeFrame(frame.width(), frame.height());
const QualityScaler::Resolution scaled_res =
quality_scaler_.GetScaledResolution();
if (scaled_res.width != width_ || scaled_res.height != height_) {
width_ = scaled_res.width;
height_ = scaled_res.height;
int ret = ResetCompressionSession();
if (ret < 0)
return ret;
}
// Get a pixel buffer from the pool and copy frame data over.
CVPixelBufferPoolRef pixel_buffer_pool =
VTCompressionSessionGetPixelBufferPool(compression_session_);
@ -457,11 +439,8 @@ int H264VideoToolboxEncoder::Encode(
if (!pixel_buffer) {
return WEBRTC_VIDEO_CODEC_ERROR;
}
// TODO(magjed): Optimize by merging scaling and NV12 pixel buffer
// conversion once libyuv::MergeUVPlanes is available.
rtc::scoped_refptr<VideoFrameBuffer> scaled_i420_buffer =
quality_scaler_.GetScaledBuffer(frame.video_frame_buffer());
if (!internal::CopyVideoFrameToPixelBuffer(scaled_i420_buffer,
RTC_DCHECK(pixel_buffer);
if (!internal::CopyVideoFrameToPixelBuffer(frame.video_frame_buffer(),
pixel_buffer)) {
LOG(LS_ERROR) << "Failed to copy frame data.";
CVBufferRelease(pixel_buffer);
@ -517,11 +496,6 @@ int H264VideoToolboxEncoder::RegisterEncodeCompleteCallback(
return WEBRTC_VIDEO_CODEC_OK;
}
void H264VideoToolboxEncoder::OnDroppedFrame() {
rtc::CritScope lock(&quality_scaler_crit_);
quality_scaler_.ReportDroppedFrame();
}
int H264VideoToolboxEncoder::SetChannelParameters(uint32_t packet_loss,
int64_t rtt) {
// Encoder doesn't know anything about packet loss or rtt so just return.
@ -533,10 +507,6 @@ int H264VideoToolboxEncoder::SetRates(uint32_t new_bitrate_kbit,
target_bitrate_bps_ = 1000 * new_bitrate_kbit;
bitrate_adjuster_.SetTargetBitrateBps(target_bitrate_bps_);
SetBitrateBps(bitrate_adjuster_.GetAdjustedBitrateBps());
rtc::CritScope lock(&quality_scaler_crit_);
quality_scaler_.ReportFramerate(frame_rate);
return WEBRTC_VIDEO_CODEC_OK;
}
@ -709,8 +679,6 @@ void H264VideoToolboxEncoder::OnEncodedFrame(
}
if (info_flags & kVTEncodeInfo_FrameDropped) {
LOG(LS_INFO) << "H264 encode dropped frame.";
rtc::CritScope lock(&quality_scaler_crit_);
quality_scaler_.ReportDroppedFrame();
return;
}
@ -752,20 +720,20 @@ void H264VideoToolboxEncoder::OnEncodedFrame(
frame.rotation_ = rotation;
h264_bitstream_parser_.ParseBitstream(buffer->data(), buffer->size());
int qp;
if (h264_bitstream_parser_.GetLastSliceQp(&qp)) {
rtc::CritScope lock(&quality_scaler_crit_);
quality_scaler_.ReportQP(qp);
frame.qp_ = qp;
}
h264_bitstream_parser_.GetLastSliceQp(&frame.qp_);
EncodedImageCallback::Result result =
EncodedImageCallback::Result res =
callback_->OnEncodedImage(frame, &codec_specific_info, header.get());
if (result.error != EncodedImageCallback::Result::OK) {
LOG(LS_ERROR) << "Encode callback failed: " << result.error;
if (res.error != EncodedImageCallback::Result::OK) {
LOG(LS_ERROR) << "Encode callback failed: " << res.error;
return;
}
bitrate_adjuster_.Update(frame._size);
}
VideoEncoder::ScalingSettings H264VideoToolboxEncoder::GetScalingSettings()
const {
return VideoEncoder::ScalingSettings(true, internal::kLowH264QpThreshold,
internal::kHighH264QpThreshold);
}
} // namespace webrtc