summaryrefslogtreecommitdiff
path: root/chromium/media/capabilities/webrtc_video_stats_db.cc
blob: eaf25c63d6a629d251623547e108309c2309de74 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
// Copyright 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/capabilities/webrtc_video_stats_db.h"

#include "base/check_op.h"
#include "base/format_macros.h"
#include "base/metrics/field_trial_params.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "media/base/media_switches.h"
#include "media/capabilities/bucket_utility.h"

namespace media {

namespace {
// Default value for maximum number of days until a stats entry is considered
// expired.
constexpr int kMaxDaysToKeepStatsDefault = 30;
// Default value for maximum number of stats entries per config.
constexpr int kMaxEntriesPerConfigDefault = 10;
// Field trial parameter names.
constexpr char kMaxDaysToKeepStatsParamName[] = "db_days_to_keep_stats";
constexpr char kMaxEntriesPerConfigParamName[] = "db_max_entries_per_cpnfig";

// Group similar codec profiles to the same entry. Returns
// VIDEO_CODEC_PROFILE_UNKNOWN if `codec_profile` is outside the valid range or
// not tracked. The reason to not track all codec profiles is to limit the
// fingerprinting surface.
VideoCodecProfile GetWebrtcCodecProfileBucket(VideoCodecProfile codec_profile) {
  if (codec_profile >= H264PROFILE_MIN && codec_profile <= H264PROFILE_MAX) {
    return H264PROFILE_MIN;
  }
  if (codec_profile >= VP8PROFILE_MIN && codec_profile <= VP8PROFILE_MAX) {
    return VP8PROFILE_MIN;
  }
  if (codec_profile == VP9PROFILE_PROFILE0) {
    return VP9PROFILE_PROFILE0;
  }
  if (codec_profile == VP9PROFILE_PROFILE2) {
    return VP9PROFILE_PROFILE2;
  }
  if (codec_profile >= AV1PROFILE_MIN && codec_profile <= AV1PROFILE_MAX) {
    return AV1PROFILE_MIN;
  }
  return VIDEO_CODEC_PROFILE_UNKNOWN;
}

}  // namespace

// static
WebrtcVideoStatsDB::VideoDescKey
WebrtcVideoStatsDB::VideoDescKey::MakeBucketedKey(
    bool is_decode_stats,
    VideoCodecProfile codec_profile,
    bool hardware_accelerated,
    int pixels) {
  // Bucket pixel size to prevent an explosion of one-off values in the
  // database and add basic guards against fingerprinting.
  return VideoDescKey(is_decode_stats,
                      GetWebrtcCodecProfileBucket(codec_profile),
                      hardware_accelerated, GetWebrtcPixelsBucket(pixels));
}

WebrtcVideoStatsDB::VideoDescKey::VideoDescKey(bool is_decode_stats,
                                               VideoCodecProfile codec_profile,
                                               bool hardware_accelerated,
                                               int pixels)
    : is_decode_stats(is_decode_stats),
      codec_profile(codec_profile),
      hardware_accelerated(hardware_accelerated),
      pixels(pixels) {}

std::string WebrtcVideoStatsDB::VideoDescKey::Serialize() const {
  std::string video_part = base::StringPrintf("%d|%d|%d|%d", is_decode_stats,
                                              static_cast<int>(codec_profile),
                                              hardware_accelerated, pixels);

  return video_part;
}

std::string WebrtcVideoStatsDB::VideoDescKey::SerializeWithoutPixels() const {
  std::string video_part =
      base::StringPrintf("%d|%d|%d|", is_decode_stats,
                         static_cast<int>(codec_profile), hardware_accelerated);

  return video_part;
}

std::string WebrtcVideoStatsDB::VideoDescKey::ToLogStringForDebug() const {
  return "Key {" + Serialize() + "}";
}

// static
absl::optional<int> WebrtcVideoStatsDB::VideoDescKey::ParsePixelsFromKey(
    std::string key) {
  constexpr size_t kMinimumIndexOfLastSeparator = 5;
  size_t last_separator_index = key.rfind("|");
  if (last_separator_index != std::string::npos &&
      last_separator_index >= kMinimumIndexOfLastSeparator &&
      (last_separator_index + 1) < key.size()) {
    int parsed_pixels;
    if (base::StringToInt(&key.c_str()[last_separator_index + 1],
                          &parsed_pixels))
      return parsed_pixels;
  }
  return absl::nullopt;
}

WebrtcVideoStatsDB::VideoStats::VideoStats(double timestamp,
                                           uint32_t frames_processed,
                                           uint32_t key_frames_processed,
                                           float p99_processing_time_ms)
    : timestamp(timestamp),
      frames_processed(frames_processed),
      key_frames_processed(key_frames_processed),
      p99_processing_time_ms(p99_processing_time_ms) {
  DCHECK_GE(frames_processed, 0u);
  DCHECK_GE(key_frames_processed, 0u);
  DCHECK_GE(p99_processing_time_ms, 0);
}

WebrtcVideoStatsDB::VideoStats::VideoStats(uint32_t frames_processed,
                                           uint32_t key_frames_processed,
                                           float p99_processing_time_ms)
    : VideoStats(/*timestamp=*/0.0,
                 frames_processed,
                 key_frames_processed,
                 p99_processing_time_ms) {}

WebrtcVideoStatsDB::VideoStats::VideoStats(const VideoStats& entry) = default;

WebrtcVideoStatsDB::VideoStats& WebrtcVideoStatsDB::VideoStats::operator=(
    const VideoStats& entry) = default;

std::string WebrtcVideoStatsDB::VideoStats::ToLogString() const {
  return base::StringPrintf(
      "VideoStats {Frames processed:%u, key frames processed:%u, p99 "
      "processing time:%.2f}",
      frames_processed, key_frames_processed, p99_processing_time_ms);
}

bool operator==(const WebrtcVideoStatsDB::VideoDescKey& x,
                const WebrtcVideoStatsDB::VideoDescKey& y) {
  return x.is_decode_stats == y.is_decode_stats &&
         x.codec_profile == y.codec_profile &&
         x.hardware_accelerated == y.hardware_accelerated &&
         x.pixels == y.pixels;
}
bool operator!=(const WebrtcVideoStatsDB::VideoDescKey& x,
                const WebrtcVideoStatsDB::VideoDescKey& y) {
  return !(x == y);
}

bool operator==(const WebrtcVideoStatsDB::VideoStats& x,
                const WebrtcVideoStatsDB::VideoStats& y) {
  return x.timestamp == y.timestamp &&
         x.frames_processed == y.frames_processed &&
         x.key_frames_processed == y.key_frames_processed &&
         x.p99_processing_time_ms == y.p99_processing_time_ms;
}
bool operator!=(const WebrtcVideoStatsDB::VideoStats& x,
                const WebrtcVideoStatsDB::VideoStats& y) {
  return !(x == y);
}

// static
base::TimeDelta WebrtcVideoStatsDB::GetMaxTimeToKeepStats() {
  return base::Days(base::GetFieldTrialParamByFeatureAsInt(
      kWebrtcMediaCapabilitiesParameters, kMaxDaysToKeepStatsParamName,
      kMaxDaysToKeepStatsDefault));
}

// static
int WebrtcVideoStatsDB::GetMaxEntriesPerConfig() {
  return base::GetFieldTrialParamByFeatureAsInt(
      kWebrtcMediaCapabilitiesParameters, kMaxEntriesPerConfigParamName,
      kMaxEntriesPerConfigDefault);
}

}  // namespace media