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 |