1f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org/*
2f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
3f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org *
4f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org *  Use of this source code is governed by a BSD-style license
5f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org *  that can be found in the LICENSE file in the root of the source
6f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org *  tree. An additional intellectual property rights grant can be found
7f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org *  in the file PATENTS.  All contributing project authors may
8f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
9f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org */
10f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org
11f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org#include "webrtc/modules/video_coding/utility/quality_scaler.h"
12f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org
13f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.orgnamespace webrtc {
14f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org
15f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.orgstatic const int kMinFps = 10;
16f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.orgstatic const int kMeasureSeconds = 5;
17f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.orgstatic const int kFramedropPercentThreshold = 60;
18f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.orgstatic const int kLowQpThresholdDenominator = 3;
19f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org
20f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.orgQualityScaler::QualityScaler()
21f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org    : num_samples_(0), low_qp_threshold_(-1), downscale_shift_(0) {
22f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org}
23f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org
24f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.orgvoid QualityScaler::Init(int max_qp) {
25f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  ClearSamples();
26f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  downscale_shift_ = 0;
27f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  low_qp_threshold_ = max_qp / kLowQpThresholdDenominator ;
28f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org}
29f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org
30f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.orgvoid QualityScaler::ReportFramerate(int framerate) {
31f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  num_samples_ = static_cast<size_t>(
32f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org      kMeasureSeconds * (framerate < kMinFps ? kMinFps : framerate));
33f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org}
34f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org
35f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.orgvoid QualityScaler::ReportEncodedFrame(int qp) {
36f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  average_qp_.AddSample(qp);
37f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  framedrop_percent_.AddSample(0);
38f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org}
39f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org
40f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.orgvoid QualityScaler::ReportDroppedFrame() {
41f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  framedrop_percent_.AddSample(100);
42f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org}
43f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org
44f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.orgQualityScaler::Resolution QualityScaler::GetScaledResolution(
45f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org    const I420VideoFrame& frame) {
46f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  // Both of these should be set through InitEncode -> Should be set by now.
47f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  assert(low_qp_threshold_ >= 0);
48f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  assert(num_samples_ > 0);
49f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  // Update scale factor.
50f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  int avg;
51f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  if (framedrop_percent_.GetAverage(num_samples_, &avg) &&
52f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org      avg >= kFramedropPercentThreshold) {
53f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org    AdjustScale(false);
54f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  } else if (average_qp_.GetAverage(num_samples_, &avg) &&
55f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org             avg <= low_qp_threshold_) {
56f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org    AdjustScale(true);
57f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  }
58f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org
59f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  Resolution res;
60f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  res.width = frame.width();
61f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  res.height = frame.height();
62f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org
63f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  assert(downscale_shift_ >= 0);
64f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  for (int shift = downscale_shift_;
65f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org       shift > 0 && res.width > 1 && res.height > 1;
66f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org       --shift) {
67f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org    res.width >>= 1;
68f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org    res.height >>= 1;
69f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  }
70f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org
71f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  return res;
72f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org}
73f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org
74f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.orgconst I420VideoFrame& QualityScaler::GetScaledFrame(
75f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org    const I420VideoFrame& frame) {
76f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  Resolution res = GetScaledResolution(frame);
77f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  if (res.width == frame.width())
78f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org    return frame;
79f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org
80f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  scaler_.Set(frame.width(),
81f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org              frame.height(),
82f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org              res.width,
83f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org              res.height,
84f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org              kI420,
85f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org              kI420,
86f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org              kScaleBox);
87f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  if (scaler_.Scale(frame, &scaled_frame_) != 0)
88f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org    return frame;
89f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org
90f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  scaled_frame_.set_ntp_time_ms(frame.ntp_time_ms());
91f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  scaled_frame_.set_timestamp(frame.timestamp());
92f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  scaled_frame_.set_render_time_ms(frame.render_time_ms());
93f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org
94f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  return scaled_frame_;
95f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org}
96f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org
97f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.orgQualityScaler::MovingAverage::MovingAverage() : sum_(0) {
98f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org}
99f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org
100f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.orgvoid QualityScaler::MovingAverage::AddSample(int sample) {
101f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  samples_.push_back(sample);
102f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  sum_ += sample;
103f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org}
104f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org
105f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.orgbool QualityScaler::MovingAverage::GetAverage(size_t num_samples, int* avg) {
106f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  assert(num_samples > 0);
107f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  if (num_samples > samples_.size())
108f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org    return false;
109f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org
110f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  // Remove old samples.
111f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  while (num_samples < samples_.size()) {
112f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org    sum_ -= samples_.front();
113f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org    samples_.pop_front();
114f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  }
115f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org
116f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  *avg = sum_ / static_cast<int>(num_samples);
117f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  return true;
118f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org}
119f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org
120f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.orgvoid QualityScaler::MovingAverage::Reset() {
121f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  sum_ = 0;
122f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  samples_.clear();
123f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org}
124f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org
125f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.orgvoid QualityScaler::ClearSamples() {
126f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  average_qp_.Reset();
127f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  framedrop_percent_.Reset();
128f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org}
129f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org
130f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.orgvoid QualityScaler::AdjustScale(bool up) {
131f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  downscale_shift_ += up ? -1 : 1;
132f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  if (downscale_shift_ < 0)
133f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org    downscale_shift_ = 0;
134f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org  ClearSamples();
135f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org}
136f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org
137f51f68666c2da07ec231cba7bd44d91fff34da1dpbos@webrtc.org}  // namespace webrtc
138