Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(32)

Side by Side Diff: media/cast/sender/performance_metrics_overlay.cc

Issue 1148233002: [Cast] Compute utilization metrics and add performance overlay. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/cast/sender/performance_metrics_overlay.h"
6
7 #include <algorithm>
8 #include <string>
9
10 #include "base/logging.h"
11 #include "base/numerics/safe_conversions.h"
12 #include "base/strings/stringprintf.h"
13 #include "media/base/video_frame.h"
14
15 namespace media {
16 namespace cast {
17
18 namespace {
19
20 const int kScale = 4; // Physical pixels per one logical pixel.
21 const int kCharacterWidth = 3; // Logical pixel width of one character.
22 const int kCharacterHeight = 5; // Logical pixel height of one character.
23 const int kCharacterSpacing = 1; // Logical pixels between each character.
24 const int kLineSpacing = 2; // Logical pixels between each line of characters.
25 const int kPlane = 0; // Y-plane in YUV formats.
26
27 // For each pixel in the |rect| (logical coordinates), either decrease the
28 // intensity or increase it so that the resulting pixel has a perceivably
29 // different value than it did before. |p_ul| is a pointer to the pixel at
30 // coordinate (0,0) in a single-channel 8bpp bitmap. |stride| is the number of
31 // bytes per row in the output bitmap.
32 void DivergePixels(const gfx::Rect& rect, uint8* p_ul, int stride) {
33 DCHECK(p_ul);
34 DCHECK_GT(stride, 0);
35
36 const int kDivergeDownThreshold = 32;
hubbe 2015/05/20 21:32:18 Why not make sure that kDivergeDownThreshold is >=
miu 2015/05/20 23:44:00 Yeah, all this was the result of experimenting wit
37 const int kDivergeDownAmount = 48;
38 const int kDivergeUpAmount = 32;
39 const int kMinIntensity = 16;
40
41 const int top = rect.y() * kScale;
42 const int bottom = rect.bottom() * kScale;
43 const int left = rect.x() * kScale;
44 const int right = rect.right() * kScale;
45 for (int y = top; y < bottom; ++y) {
46 uint8* const p_l = p_ul + y * stride;
47 for (int x = left; x < right; ++x) {
48 int intensity = p_l[x];
49 if (intensity >= kDivergeDownThreshold)
50 intensity = std::max(kMinIntensity, intensity - kDivergeDownAmount);
51 else
52 intensity += kDivergeUpAmount;
53 p_l[x] = static_cast<uint8>(intensity);
54 }
55 }
56 }
57
58 // Render |line| into |frame| at physical pixel row |top| and aligned to the
59 // right edge. Only number digits and a smattering of punctuation characters
60 // will be rendered.
61 void RenderLineOfText(const std::string& line, int top, VideoFrame* frame) {
62 // Compute number of physical pixels wide the rendered |line| would be,
63 // including padding.
64 const int line_width =
65 (((kCharacterWidth + kCharacterSpacing) * static_cast<int>(line.size())) +
66 kCharacterSpacing) * kScale;
67
68 // Determine if any characters would render past the left edge of the frame,
69 // and compute the index of the first character to be rendered.
70 const int pixels_per_char = (kCharacterWidth + kCharacterSpacing) * kScale;
71 const size_t first_idx = (line_width < frame->visible_rect().width()) ? 0u :
72 static_cast<size_t>(
73 ((line_width - frame->visible_rect().width()) / pixels_per_char) + 1);
74
75 // Compute the pointer to the pixel at the upper-left corner of the first
76 // character to be rendered.
77 const int stride = frame->stride(kPlane);
78 uint8* p_ul =
79 // Start at the pixel after the end of the first row...
80 frame->visible_data(kPlane) + (stride * (top + 1)) -
81 // ...now move left to where line[0] would be rendered...
hubbe 2015/05/20 21:32:18 This seems to assume that the actual image is righ
miu 2015/05/20 23:44:00 Good catch! Fixed.
82 line_width +
83 // ...now move right to where line[first_idx] would be rendered.
84 first_idx * pixels_per_char;
85
86 // Render each character.
hubbe 2015/05/20 21:32:18 Did you explore using ttf fonts or something here?
miu 2015/05/20 23:44:00 There were too many unknowns when looking at what'
87 for (size_t i = first_idx; i < line.size(); ++i, p_ul += pixels_per_char) {
88 switch (line[i]) {
89 case '0':
90 DivergePixels(gfx::Rect(0, 0, 3, 1), p_ul, stride);
91 DivergePixels(gfx::Rect(0, 1, 1, 3), p_ul, stride);
92 DivergePixels(gfx::Rect(2, 1, 1, 3), p_ul, stride);
93 DivergePixels(gfx::Rect(0, 4, 3, 1), p_ul, stride);
94 break;
95 case '1':
96 DivergePixels(gfx::Rect(1, 0, 1, 5), p_ul, stride);
97 break;
98 case '2':
99 DivergePixels(gfx::Rect(0, 0, 3, 1), p_ul, stride);
100 DivergePixels(gfx::Rect(2, 1, 1, 1), p_ul, stride);
101 DivergePixels(gfx::Rect(0, 2, 3, 1), p_ul, stride);
102 DivergePixels(gfx::Rect(0, 3, 1, 1), p_ul, stride);
103 DivergePixels(gfx::Rect(0, 4, 3, 1), p_ul, stride);
104 break;
105 case '3':
106 DivergePixels(gfx::Rect(0, 0, 3, 1), p_ul, stride);
107 DivergePixels(gfx::Rect(2, 1, 1, 1), p_ul, stride);
108 DivergePixels(gfx::Rect(0, 2, 3, 1), p_ul, stride);
109 DivergePixels(gfx::Rect(2, 3, 1, 1), p_ul, stride);
110 DivergePixels(gfx::Rect(0, 4, 3, 1), p_ul, stride);
111 break;
112 case '4':
113 DivergePixels(gfx::Rect(0, 0, 1, 2), p_ul, stride);
114 DivergePixels(gfx::Rect(2, 0, 1, 5), p_ul, stride);
115 DivergePixels(gfx::Rect(0, 2, 2, 1), p_ul, stride);
116 break;
117 case '5':
118 DivergePixels(gfx::Rect(0, 0, 3, 1), p_ul, stride);
119 DivergePixels(gfx::Rect(0, 1, 1, 1), p_ul, stride);
120 DivergePixels(gfx::Rect(0, 2, 3, 1), p_ul, stride);
121 DivergePixels(gfx::Rect(2, 3, 1, 1), p_ul, stride);
122 DivergePixels(gfx::Rect(0, 4, 3, 1), p_ul, stride);
123 break;
124 case '6':
125 DivergePixels(gfx::Rect(1, 0, 2, 1), p_ul, stride);
126 DivergePixels(gfx::Rect(0, 1, 1, 1), p_ul, stride);
127 DivergePixels(gfx::Rect(0, 2, 3, 1), p_ul, stride);
128 DivergePixels(gfx::Rect(0, 3, 1, 1), p_ul, stride);
129 DivergePixels(gfx::Rect(2, 3, 1, 1), p_ul, stride);
130 DivergePixels(gfx::Rect(0, 4, 3, 1), p_ul, stride);
131 break;
132 case '7':
133 DivergePixels(gfx::Rect(0, 0, 3, 1), p_ul, stride);
134 DivergePixels(gfx::Rect(2, 1, 1, 2), p_ul, stride);
135 DivergePixels(gfx::Rect(1, 3, 1, 2), p_ul, stride);
136 break;
137 case '8':
138 DivergePixels(gfx::Rect(0, 0, 3, 1), p_ul, stride);
139 DivergePixels(gfx::Rect(0, 1, 1, 1), p_ul, stride);
140 DivergePixels(gfx::Rect(2, 1, 1, 1), p_ul, stride);
141 DivergePixels(gfx::Rect(0, 2, 3, 1), p_ul, stride);
142 DivergePixels(gfx::Rect(0, 3, 1, 1), p_ul, stride);
143 DivergePixels(gfx::Rect(2, 3, 1, 1), p_ul, stride);
144 DivergePixels(gfx::Rect(0, 4, 3, 1), p_ul, stride);
145 break;
146 case '9':
147 DivergePixels(gfx::Rect(0, 0, 3, 1), p_ul, stride);
148 DivergePixels(gfx::Rect(0, 1, 1, 1), p_ul, stride);
149 DivergePixels(gfx::Rect(2, 1, 1, 1), p_ul, stride);
150 DivergePixels(gfx::Rect(0, 2, 3, 1), p_ul, stride);
151 DivergePixels(gfx::Rect(2, 3, 1, 1), p_ul, stride);
152 DivergePixels(gfx::Rect(0, 4, 2, 1), p_ul, stride);
153 break;
154 case 'e':
155 case 'E':
156 DivergePixels(gfx::Rect(0, 0, 3, 1), p_ul, stride);
157 DivergePixels(gfx::Rect(0, 1, 1, 1), p_ul, stride);
158 DivergePixels(gfx::Rect(0, 2, 2, 1), p_ul, stride);
159 DivergePixels(gfx::Rect(0, 3, 1, 1), p_ul, stride);
160 DivergePixels(gfx::Rect(0, 4, 3, 1), p_ul, stride);
161 break;
162 case '.':
163 DivergePixels(gfx::Rect(1, 4, 1, 1), p_ul, stride);
164 break;
165 case '+':
166 DivergePixels(gfx::Rect(1, 1, 1, 1), p_ul, stride);
167 DivergePixels(gfx::Rect(1, 3, 1, 1), p_ul, stride);
168 // ...follow through...
hubbe 2015/05/20 21:32:19 s/follow/fall/
169 case '-':
170 DivergePixels(gfx::Rect(0, 2, 3, 1), p_ul, stride);
171 break;
172 case 'x':
173 DivergePixels(gfx::Rect(0, 1, 1, 1), p_ul, stride);
174 DivergePixels(gfx::Rect(2, 1, 1, 1), p_ul, stride);
175 DivergePixels(gfx::Rect(1, 2, 1, 1), p_ul, stride);
176 DivergePixels(gfx::Rect(0, 3, 1, 1), p_ul, stride);
177 DivergePixels(gfx::Rect(2, 3, 1, 1), p_ul, stride);
178 break;
179 case ':':
180 DivergePixels(gfx::Rect(1, 1, 1, 1), p_ul, stride);
181 DivergePixels(gfx::Rect(1, 3, 1, 1), p_ul, stride);
182 break;
183 case '%':
184 DivergePixels(gfx::Rect(0, 0, 1, 1), p_ul, stride);
185 DivergePixels(gfx::Rect(2, 1, 1, 1), p_ul, stride);
186 DivergePixels(gfx::Rect(1, 2, 1, 1), p_ul, stride);
187 DivergePixels(gfx::Rect(0, 3, 1, 1), p_ul, stride);
188 DivergePixels(gfx::Rect(2, 4, 1, 1), p_ul, stride);
189 break;
190 case ' ':
191 default:
192 break;
193 }
194 }
195 }
196
197 } // namespace
198
199 void MaybeRenderPerformanceMetricsOverlay(int target_bitrate,
200 int frames_ago,
201 double deadline_utilization,
202 double lossy_utilization,
203 VideoFrame* frame) {
204 if (VideoFrame::PlaneHorizontalBitsPerPixel(frame->format(), kPlane) != 8) {
205 DLOG(WARNING) << "Cannot render overlay: Plane " << kPlane << " not 8bpp.";
206 return;
207 }
208
209 // Compute the physical pixel top row for the bottom-most line of text.
210 const int line_height = (kCharacterHeight + kLineSpacing) * kScale;
211 int top = frame->visible_rect().height() - line_height;
212 if (top < 0 || !VLOG_IS_ON(1))
213 return;
214
215 // Line 3: Frame resolution and timestamp.
216 base::TimeDelta rem = frame->timestamp();
217 const int minutes = rem.InMinutes();
218 rem -= base::TimeDelta::FromMinutes(minutes);
219 const int seconds = static_cast<int>(rem.InSeconds());
220 rem -= base::TimeDelta::FromSeconds(seconds);
221 const int hundredth_seconds = static_cast<int>(rem.InMilliseconds() / 10);
222 RenderLineOfText(base::StringPrintf("%dx%d %d:%02d.%02d",
223 frame->visible_rect().width(),
224 frame->visible_rect().height(),
225 minutes,
226 seconds,
227 hundredth_seconds),
228 top,
229 frame);
230
231 // Move up one line's worth of pixels.
232 top -= line_height;
233 if (top < 0 || !VLOG_IS_ON(2))
234 return;
235
236 // Line 2: Capture/frame duration and target bitrate.
237 int capture_duration_ms = 0;
238 base::TimeTicks capture_begin_time, capture_end_time;
239 if (frame->metadata()->GetTimeTicks(VideoFrameMetadata::CAPTURE_BEGIN_TIME,
240 &capture_begin_time) &&
241 frame->metadata()->GetTimeTicks(VideoFrameMetadata::CAPTURE_END_TIME,
242 &capture_end_time)) {
243 capture_duration_ms = base::saturated_cast<int>(
244 (capture_end_time - capture_begin_time).InMillisecondsF() + 0.5);
245 }
246 int frame_duration_ms = 0;
247 int frame_duration_ms_frac = 0;
248 base::TimeDelta frame_duration;
249 if (frame->metadata()->GetTimeDelta(VideoFrameMetadata::FRAME_DURATION,
250 &frame_duration)) {
251 const int decimilliseconds = base::saturated_cast<int>(
252 frame_duration.InMicroseconds() / 100.0 + 0.5);
253 frame_duration_ms = decimilliseconds / 10;
254 frame_duration_ms_frac = decimilliseconds % 10;
255 }
256 const int target_kbits = target_bitrate / 1000;
257 RenderLineOfText(base::StringPrintf("%3.1d %3.1d.%01d %4.1d",
258 capture_duration_ms,
259 frame_duration_ms,
260 frame_duration_ms_frac,
261 target_kbits),
262 top,
263 frame);
264
265 // Move up one line's worth of pixels.
266 top -= line_height;
267 if (top < 0 || !VLOG_IS_ON(3))
268 return;
269
270 // Line 1: Recent utilization metrics.
271 const int deadline_pct =
272 base::saturated_cast<int>(deadline_utilization * 100.0 + 0.5);
273 const int lossy_pct =
274 base::saturated_cast<int>(lossy_utilization * 100.0 + 0.5);
275 RenderLineOfText(base::StringPrintf("%d %3.1d%% %3.1d%%",
276 frames_ago,
277 deadline_pct,
278 lossy_pct),
279 top,
280 frame);
281 }
282
283 } // namespace cast
284 } // namespace media
OLDNEW
« no previous file with comments | « media/cast/sender/performance_metrics_overlay.h ('k') | media/cast/sender/sender_encoded_frame.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698