| Index: media/cast/sender/performance_metrics_overlay.cc
 | 
| diff --git a/media/cast/sender/performance_metrics_overlay.cc b/media/cast/sender/performance_metrics_overlay.cc
 | 
| index 389b6f37cd8c387a423e0f963f19700f04ad084a..d132db059db7cce0962695651b48799998caf2ed 100644
 | 
| --- a/media/cast/sender/performance_metrics_overlay.cc
 | 
| +++ b/media/cast/sender/performance_metrics_overlay.cc
 | 
| @@ -10,6 +10,7 @@
 | 
|  #include <algorithm>
 | 
|  #include <string>
 | 
|  
 | 
| +#include "base/bind.h"
 | 
|  #include "base/logging.h"
 | 
|  #include "base/numerics/safe_conversions.h"
 | 
|  #include "base/strings/stringprintf.h"
 | 
| @@ -20,12 +21,12 @@ namespace cast {
 | 
|  
 | 
|  namespace {
 | 
|  
 | 
| -const int kScale = 4;  // Physical pixels per one logical pixel.
 | 
| -const int kCharacterWidth = 3;  // Logical pixel width of one character.
 | 
| -const int kCharacterHeight = 5;  // Logical pixel height of one character.
 | 
| -const int kCharacterSpacing = 1;  // Logical pixels between each character.
 | 
| -const int kLineSpacing = 2;  // Logical pixels between each line of characters.
 | 
| -const int kPlane = 0;  // Y-plane in YUV formats.
 | 
| +constexpr int kScale = 4;             // Physical pixels per one logical pixel.
 | 
| +constexpr int kCharacterWidth = 3;    // Logical pixel width of one character.
 | 
| +constexpr int kCharacterHeight = 5;   // Logical pixel height of one character.
 | 
| +constexpr int kCharacterSpacing = 1;  // Logical pixels between each character.
 | 
| +constexpr int kLineSpacing = 2;  // Logical pixels between each line of chars.
 | 
| +constexpr int kPlane = 0;        // Y-plane in YUV formats.
 | 
|  
 | 
|  // For each pixel in the |rect| (logical coordinates), either decrease the
 | 
|  // intensity or increase it so that the resulting pixel has a perceivably
 | 
| @@ -214,29 +215,60 @@ void RenderLineOfText(const std::string& line, int top, VideoFrame* frame) {
 | 
|  
 | 
|  }  // namespace
 | 
|  
 | 
| -void MaybeRenderPerformanceMetricsOverlay(base::TimeDelta target_playout_delay,
 | 
| -                                          bool in_low_latency_mode,
 | 
| -                                          int target_bitrate,
 | 
| -                                          int frames_ago,
 | 
| -                                          double encoder_utilization,
 | 
| -                                          double lossy_utilization,
 | 
| -                                          VideoFrame* frame) {
 | 
| -  if (VideoFrame::PlaneHorizontalBitsPerPixel(frame->format(), kPlane) != 8) {
 | 
| +scoped_refptr<VideoFrame> MaybeRenderPerformanceMetricsOverlay(
 | 
| +    base::TimeDelta target_playout_delay,
 | 
| +    bool in_low_latency_mode,
 | 
| +    int target_bitrate,
 | 
| +    int frames_ago,
 | 
| +    double encoder_utilization,
 | 
| +    double lossy_utilization,
 | 
| +    scoped_refptr<VideoFrame> source) {
 | 
| +  if (!VLOG_IS_ON(1))
 | 
| +    return source;
 | 
| +
 | 
| +  if (VideoFrame::PlaneHorizontalBitsPerPixel(source->format(), kPlane) != 8) {
 | 
|      DLOG(WARNING) << "Cannot render overlay: Plane " << kPlane << " not 8bpp.";
 | 
| -    return;
 | 
| +    return source;
 | 
|    }
 | 
|  
 | 
| -  // Can't render to unmappable memory (DmaBuf, CVPixelBuffer).
 | 
| -  if (!frame->IsMappable()) {
 | 
| +  // Can't read from unmappable memory (DmaBuf, CVPixelBuffer).
 | 
| +  if (!source->IsMappable()) {
 | 
|      DVLOG(2) << "Cannot render overlay: frame uses unmappable memory.";
 | 
| -    return;
 | 
| +    return source;
 | 
|    }
 | 
|  
 | 
|    // Compute the physical pixel top row for the bottom-most line of text.
 | 
|    const int line_height = (kCharacterHeight + kLineSpacing) * kScale;
 | 
| -  int top = frame->visible_rect().height() - line_height;
 | 
| -  if (top < 0 || !VLOG_IS_ON(1))
 | 
| -    return;
 | 
| +  int top = source->visible_rect().height() - line_height;
 | 
| +  if (top < 0)
 | 
| +    return source;  // No pixels would change: Return source frame.
 | 
| +
 | 
| +  // Allocate a new frame, identical in configuration to |source| and copy over
 | 
| +  // all data and metadata.
 | 
| +  const scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame(
 | 
| +      source->format(), source->coded_size(), source->visible_rect(),
 | 
| +      source->natural_size(), source->timestamp());
 | 
| +  if (!frame)
 | 
| +    return source;  // Allocation failure: Return source frame.
 | 
| +  for (size_t plane = 0, num_planes = VideoFrame::NumPlanes(source->format());
 | 
| +       plane < num_planes; ++plane) {
 | 
| +    memcpy(frame->data(plane), source->data(plane),
 | 
| +           source->stride(plane) * source->rows(plane));
 | 
| +  }
 | 
| +  frame->metadata()->MergeMetadataFrom(source->metadata());
 | 
| +  // Important: After all consumers are done with the frame, copy-back the
 | 
| +  // changed/new metadata to the source frame, as it contains feedback signals
 | 
| +  // that need to propagate back up the video stack. The destruction callback
 | 
| +  // for the |frame| holds a ref-counted reference to the source frame to ensure
 | 
| +  // the source frame has the right metadata before its destruction observers
 | 
| +  // are invoked.
 | 
| +  frame->AddDestructionObserver(base::Bind(
 | 
| +      [](const VideoFrameMetadata* sent_frame_metadata,
 | 
| +         const scoped_refptr<VideoFrame>& source_frame) {
 | 
| +        source_frame->metadata()->Clear();
 | 
| +        source_frame->metadata()->MergeMetadataFrom(sent_frame_metadata);
 | 
| +      },
 | 
| +      frame->metadata(), std::move(source)));
 | 
|  
 | 
|    // Line 3: Frame duration, resolution, and timestamp.
 | 
|    int frame_duration_ms = 0;
 | 
| @@ -255,21 +287,17 @@ void MaybeRenderPerformanceMetricsOverlay(base::TimeDelta target_playout_delay,
 | 
|    const int seconds = static_cast<int>(rem.InSeconds());
 | 
|    rem -= base::TimeDelta::FromSeconds(seconds);
 | 
|    const int hundredth_seconds = static_cast<int>(rem.InMilliseconds() / 10);
 | 
| -  RenderLineOfText(base::StringPrintf("%d.%01d %dx%d %d:%02d.%02d",
 | 
| -                                      frame_duration_ms,
 | 
| -                                      frame_duration_ms_frac,
 | 
| -                                      frame->visible_rect().width(),
 | 
| -                                      frame->visible_rect().height(),
 | 
| -                                      minutes,
 | 
| -                                      seconds,
 | 
| -                                      hundredth_seconds),
 | 
| -                   top,
 | 
| -                   frame);
 | 
| +  RenderLineOfText(
 | 
| +      base::StringPrintf("%d.%01d %dx%d %d:%02d.%02d", frame_duration_ms,
 | 
| +                         frame_duration_ms_frac, frame->visible_rect().width(),
 | 
| +                         frame->visible_rect().height(), minutes, seconds,
 | 
| +                         hundredth_seconds),
 | 
| +      top, frame.get());
 | 
|  
 | 
|    // Move up one line's worth of pixels.
 | 
|    top -= line_height;
 | 
|    if (top < 0 || !VLOG_IS_ON(2))
 | 
| -    return;
 | 
| +    return frame;
 | 
|  
 | 
|    // Line 2: Capture duration, target playout delay, low-latency mode, and
 | 
|    // target bitrate.
 | 
| @@ -285,18 +313,16 @@ void MaybeRenderPerformanceMetricsOverlay(base::TimeDelta target_playout_delay,
 | 
|    const int target_playout_delay_ms =
 | 
|        static_cast<int>(target_playout_delay.InMillisecondsF() + 0.5);
 | 
|    const int target_kbits = target_bitrate / 1000;
 | 
| -  RenderLineOfText(base::StringPrintf("%d %4.1d%c %4.1d",
 | 
| -                                      capture_duration_ms,
 | 
| -                                      target_playout_delay_ms,
 | 
| -                                      in_low_latency_mode ? '!' : '.',
 | 
| -                                      target_kbits),
 | 
| -                   top,
 | 
| -                   frame);
 | 
| +  RenderLineOfText(
 | 
| +      base::StringPrintf("%d %4.1d%c %4.1d", capture_duration_ms,
 | 
| +                         target_playout_delay_ms,
 | 
| +                         in_low_latency_mode ? '!' : '.', target_kbits),
 | 
| +      top, frame.get());
 | 
|  
 | 
|    // Move up one line's worth of pixels.
 | 
|    top -= line_height;
 | 
|    if (top < 0 || !VLOG_IS_ON(3))
 | 
| -    return;
 | 
| +    return frame;
 | 
|  
 | 
|    // Line 1: Recent utilization metrics.
 | 
|    const int encoder_pct =
 | 
| @@ -305,7 +331,9 @@ void MaybeRenderPerformanceMetricsOverlay(base::TimeDelta target_playout_delay,
 | 
|        base::saturated_cast<int>(lossy_utilization * 100.0 + 0.5);
 | 
|    RenderLineOfText(base::StringPrintf("%d %3.1d%% %3.1d%%", frames_ago,
 | 
|                                        encoder_pct, lossy_pct),
 | 
| -                   top, frame);
 | 
| +                   top, frame.get());
 | 
| +
 | 
| +  return frame;
 | 
|  }
 | 
|  
 | 
|  }  // namespace cast
 | 
| 
 |