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

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

Issue 2775993002: Crash Fix (Cast Streaming): Render overlay on copy of source frame. (Closed)
Patch Set: Created 3 years, 9 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
« no previous file with comments | « media/cast/sender/performance_metrics_overlay.h ('k') | media/cast/sender/video_sender.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/cast/sender/performance_metrics_overlay.h" 5 #include "media/cast/sender/performance_metrics_overlay.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 #include <stdint.h> 8 #include <stdint.h>
9 9
10 #include <algorithm> 10 #include <algorithm>
11 #include <string> 11 #include <string>
12 12
13 #include "base/bind.h"
13 #include "base/logging.h" 14 #include "base/logging.h"
14 #include "base/numerics/safe_conversions.h" 15 #include "base/numerics/safe_conversions.h"
15 #include "base/strings/stringprintf.h" 16 #include "base/strings/stringprintf.h"
16 #include "media/base/video_frame.h" 17 #include "media/base/video_frame.h"
17 18
18 namespace media { 19 namespace media {
19 namespace cast { 20 namespace cast {
20 21
21 namespace { 22 namespace {
22 23
23 const int kScale = 4; // Physical pixels per one logical pixel. 24 constexpr int kScale = 4; // Physical pixels per one logical pixel.
24 const int kCharacterWidth = 3; // Logical pixel width of one character. 25 constexpr int kCharacterWidth = 3; // Logical pixel width of one character.
25 const int kCharacterHeight = 5; // Logical pixel height of one character. 26 constexpr int kCharacterHeight = 5; // Logical pixel height of one character.
26 const int kCharacterSpacing = 1; // Logical pixels between each character. 27 constexpr int kCharacterSpacing = 1; // Logical pixels between each character.
27 const int kLineSpacing = 2; // Logical pixels between each line of characters. 28 constexpr int kLineSpacing = 2; // Logical pixels between each line of chars.
28 const int kPlane = 0; // Y-plane in YUV formats. 29 constexpr int kPlane = 0; // Y-plane in YUV formats.
29 30
30 // For each pixel in the |rect| (logical coordinates), either decrease the 31 // For each pixel in the |rect| (logical coordinates), either decrease the
31 // intensity or increase it so that the resulting pixel has a perceivably 32 // intensity or increase it so that the resulting pixel has a perceivably
32 // different value than it did before. |p_ul| is a pointer to the pixel at 33 // different value than it did before. |p_ul| is a pointer to the pixel at
33 // coordinate (0,0) in a single-channel 8bpp bitmap. |stride| is the number of 34 // coordinate (0,0) in a single-channel 8bpp bitmap. |stride| is the number of
34 // bytes per row in the output bitmap. 35 // bytes per row in the output bitmap.
35 void DivergePixels(const gfx::Rect& rect, uint8_t* p_ul, int stride) { 36 void DivergePixels(const gfx::Rect& rect, uint8_t* p_ul, int stride) {
36 DCHECK(p_ul); 37 DCHECK(p_ul);
37 DCHECK_GT(stride, 0); 38 DCHECK_GT(stride, 0);
38 39
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after
207 break; 208 break;
208 case ' ': 209 case ' ':
209 default: 210 default:
210 break; 211 break;
211 } 212 }
212 } 213 }
213 } 214 }
214 215
215 } // namespace 216 } // namespace
216 217
217 void MaybeRenderPerformanceMetricsOverlay(base::TimeDelta target_playout_delay, 218 scoped_refptr<VideoFrame> MaybeRenderPerformanceMetricsOverlay(
218 bool in_low_latency_mode, 219 base::TimeDelta target_playout_delay,
219 int target_bitrate, 220 bool in_low_latency_mode,
220 int frames_ago, 221 int target_bitrate,
221 double encoder_utilization, 222 int frames_ago,
222 double lossy_utilization, 223 double encoder_utilization,
223 VideoFrame* frame) { 224 double lossy_utilization,
224 if (VideoFrame::PlaneHorizontalBitsPerPixel(frame->format(), kPlane) != 8) { 225 scoped_refptr<VideoFrame> source) {
226 if (!VLOG_IS_ON(1))
227 return source;
228
229 if (VideoFrame::PlaneHorizontalBitsPerPixel(source->format(), kPlane) != 8) {
225 DLOG(WARNING) << "Cannot render overlay: Plane " << kPlane << " not 8bpp."; 230 DLOG(WARNING) << "Cannot render overlay: Plane " << kPlane << " not 8bpp.";
226 return; 231 return source;
227 } 232 }
228 233
229 // Can't render to unmappable memory (DmaBuf, CVPixelBuffer). 234 // Can't read from unmappable memory (DmaBuf, CVPixelBuffer).
230 if (!frame->IsMappable()) { 235 if (!source->IsMappable()) {
231 DVLOG(2) << "Cannot render overlay: frame uses unmappable memory."; 236 DVLOG(2) << "Cannot render overlay: frame uses unmappable memory.";
232 return; 237 return source;
233 } 238 }
234 239
235 // Compute the physical pixel top row for the bottom-most line of text. 240 // Compute the physical pixel top row for the bottom-most line of text.
236 const int line_height = (kCharacterHeight + kLineSpacing) * kScale; 241 const int line_height = (kCharacterHeight + kLineSpacing) * kScale;
237 int top = frame->visible_rect().height() - line_height; 242 int top = source->visible_rect().height() - line_height;
238 if (top < 0 || !VLOG_IS_ON(1)) 243 if (top < 0)
239 return; 244 return source; // No pixels would change: Return source frame.
245
246 // Allocate a new frame, identical in configuration to |source| and copy over
247 // all data and metadata.
248 const scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame(
249 source->format(), source->coded_size(), source->visible_rect(),
250 source->natural_size(), source->timestamp());
251 if (!frame)
252 return source; // Allocation failure: Return source frame.
253 for (size_t plane = 0, num_planes = VideoFrame::NumPlanes(source->format());
254 plane < num_planes; ++plane) {
255 memcpy(frame->data(plane), source->data(plane),
256 source->stride(plane) * source->rows(plane));
257 }
258 frame->metadata()->MergeMetadataFrom(source->metadata());
259 // Important: After all consumers are done with the frame, copy-back the
260 // changed/new metadata to the source frame, as it contains feedback signals
261 // that need to propagate back up the video stack. The destruction callback
262 // for the |frame| holds a ref-counted reference to the source frame to ensure
263 // the source frame has the right metadata before its destruction observers
264 // are invoked.
265 frame->AddDestructionObserver(base::Bind(
266 [](const VideoFrameMetadata* sent_frame_metadata,
267 const scoped_refptr<VideoFrame>& source_frame) {
268 source_frame->metadata()->Clear();
269 source_frame->metadata()->MergeMetadataFrom(sent_frame_metadata);
270 },
271 frame->metadata(), std::move(source)));
240 272
241 // Line 3: Frame duration, resolution, and timestamp. 273 // Line 3: Frame duration, resolution, and timestamp.
242 int frame_duration_ms = 0; 274 int frame_duration_ms = 0;
243 int frame_duration_ms_frac = 0; 275 int frame_duration_ms_frac = 0;
244 base::TimeDelta frame_duration; 276 base::TimeDelta frame_duration;
245 if (frame->metadata()->GetTimeDelta(VideoFrameMetadata::FRAME_DURATION, 277 if (frame->metadata()->GetTimeDelta(VideoFrameMetadata::FRAME_DURATION,
246 &frame_duration)) { 278 &frame_duration)) {
247 const int decimilliseconds = base::saturated_cast<int>( 279 const int decimilliseconds = base::saturated_cast<int>(
248 frame_duration.InMicroseconds() / 100.0 + 0.5); 280 frame_duration.InMicroseconds() / 100.0 + 0.5);
249 frame_duration_ms = decimilliseconds / 10; 281 frame_duration_ms = decimilliseconds / 10;
250 frame_duration_ms_frac = decimilliseconds % 10; 282 frame_duration_ms_frac = decimilliseconds % 10;
251 } 283 }
252 base::TimeDelta rem = frame->timestamp(); 284 base::TimeDelta rem = frame->timestamp();
253 const int minutes = rem.InMinutes(); 285 const int minutes = rem.InMinutes();
254 rem -= base::TimeDelta::FromMinutes(minutes); 286 rem -= base::TimeDelta::FromMinutes(minutes);
255 const int seconds = static_cast<int>(rem.InSeconds()); 287 const int seconds = static_cast<int>(rem.InSeconds());
256 rem -= base::TimeDelta::FromSeconds(seconds); 288 rem -= base::TimeDelta::FromSeconds(seconds);
257 const int hundredth_seconds = static_cast<int>(rem.InMilliseconds() / 10); 289 const int hundredth_seconds = static_cast<int>(rem.InMilliseconds() / 10);
258 RenderLineOfText(base::StringPrintf("%d.%01d %dx%d %d:%02d.%02d", 290 RenderLineOfText(
259 frame_duration_ms, 291 base::StringPrintf("%d.%01d %dx%d %d:%02d.%02d", frame_duration_ms,
260 frame_duration_ms_frac, 292 frame_duration_ms_frac, frame->visible_rect().width(),
261 frame->visible_rect().width(), 293 frame->visible_rect().height(), minutes, seconds,
262 frame->visible_rect().height(), 294 hundredth_seconds),
263 minutes, 295 top, frame.get());
264 seconds,
265 hundredth_seconds),
266 top,
267 frame);
268 296
269 // Move up one line's worth of pixels. 297 // Move up one line's worth of pixels.
270 top -= line_height; 298 top -= line_height;
271 if (top < 0 || !VLOG_IS_ON(2)) 299 if (top < 0 || !VLOG_IS_ON(2))
272 return; 300 return frame;
273 301
274 // Line 2: Capture duration, target playout delay, low-latency mode, and 302 // Line 2: Capture duration, target playout delay, low-latency mode, and
275 // target bitrate. 303 // target bitrate.
276 int capture_duration_ms = 0; 304 int capture_duration_ms = 0;
277 base::TimeTicks capture_begin_time, capture_end_time; 305 base::TimeTicks capture_begin_time, capture_end_time;
278 if (frame->metadata()->GetTimeTicks(VideoFrameMetadata::CAPTURE_BEGIN_TIME, 306 if (frame->metadata()->GetTimeTicks(VideoFrameMetadata::CAPTURE_BEGIN_TIME,
279 &capture_begin_time) && 307 &capture_begin_time) &&
280 frame->metadata()->GetTimeTicks(VideoFrameMetadata::CAPTURE_END_TIME, 308 frame->metadata()->GetTimeTicks(VideoFrameMetadata::CAPTURE_END_TIME,
281 &capture_end_time)) { 309 &capture_end_time)) {
282 capture_duration_ms = base::saturated_cast<int>( 310 capture_duration_ms = base::saturated_cast<int>(
283 (capture_end_time - capture_begin_time).InMillisecondsF() + 0.5); 311 (capture_end_time - capture_begin_time).InMillisecondsF() + 0.5);
284 } 312 }
285 const int target_playout_delay_ms = 313 const int target_playout_delay_ms =
286 static_cast<int>(target_playout_delay.InMillisecondsF() + 0.5); 314 static_cast<int>(target_playout_delay.InMillisecondsF() + 0.5);
287 const int target_kbits = target_bitrate / 1000; 315 const int target_kbits = target_bitrate / 1000;
288 RenderLineOfText(base::StringPrintf("%d %4.1d%c %4.1d", 316 RenderLineOfText(
289 capture_duration_ms, 317 base::StringPrintf("%d %4.1d%c %4.1d", capture_duration_ms,
290 target_playout_delay_ms, 318 target_playout_delay_ms,
291 in_low_latency_mode ? '!' : '.', 319 in_low_latency_mode ? '!' : '.', target_kbits),
292 target_kbits), 320 top, frame.get());
293 top,
294 frame);
295 321
296 // Move up one line's worth of pixels. 322 // Move up one line's worth of pixels.
297 top -= line_height; 323 top -= line_height;
298 if (top < 0 || !VLOG_IS_ON(3)) 324 if (top < 0 || !VLOG_IS_ON(3))
299 return; 325 return frame;
300 326
301 // Line 1: Recent utilization metrics. 327 // Line 1: Recent utilization metrics.
302 const int encoder_pct = 328 const int encoder_pct =
303 base::saturated_cast<int>(encoder_utilization * 100.0 + 0.5); 329 base::saturated_cast<int>(encoder_utilization * 100.0 + 0.5);
304 const int lossy_pct = 330 const int lossy_pct =
305 base::saturated_cast<int>(lossy_utilization * 100.0 + 0.5); 331 base::saturated_cast<int>(lossy_utilization * 100.0 + 0.5);
306 RenderLineOfText(base::StringPrintf("%d %3.1d%% %3.1d%%", frames_ago, 332 RenderLineOfText(base::StringPrintf("%d %3.1d%% %3.1d%%", frames_ago,
307 encoder_pct, lossy_pct), 333 encoder_pct, lossy_pct),
308 top, frame); 334 top, frame.get());
335
336 return frame;
309 } 337 }
310 338
311 } // namespace cast 339 } // namespace cast
312 } // namespace media 340 } // namespace media
OLDNEW
« no previous file with comments | « media/cast/sender/performance_metrics_overlay.h ('k') | media/cast/sender/video_sender.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698