Commit c1ff2ed2 authored by Yuri Wiitala's avatar Yuri Wiitala Committed by Commit Bot

'Place-holder' overlay rendering for CrOS window capture.

A minimal FrameSinkVideoCaptureOverlay implementation for browser window
video capture on ChromeOS (i.e., not desktop capture, and not
WebContents capture). The intention is for this code to be a temporary
solution until more work is complete on services/ui/ws (the new Window
Service).

Bug: 810133,806366
Change-Id: I4f929248a9620f96f2a538caaac9761a472cbe09
Reviewed-on: https://chromium-review.googlesource.com/1155985
Commit-Queue: Yuri Wiitala <miu@chromium.org>
Reviewed-by: default avatarXiangjun Zhang <xjz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#579913}
parent 8bd8ecd0
...@@ -1923,6 +1923,8 @@ jumbo_source_set("browser") { ...@@ -1923,6 +1923,8 @@ jumbo_source_set("browser") {
} }
if (is_chromeos) { if (is_chromeos) {
sources += [ sources += [
"media/capture/lame_capture_overlay_chromeos.cc",
"media/capture/lame_capture_overlay_chromeos.h",
"media/capture/lame_window_capturer_chromeos.cc", "media/capture/lame_window_capturer_chromeos.cc",
"media/capture/lame_window_capturer_chromeos.h", "media/capture/lame_window_capturer_chromeos.h",
] ]
......
// Copyright 2018 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 "content/browser/media/capture/lame_capture_overlay_chromeos.h"
#include <algorithm>
#include <cmath>
#include "base/numerics/safe_conversions.h"
#include "content/browser/media/capture/lame_window_capturer_chromeos.h"
#include "media/base/video_frame.h"
#include "skia/ext/image_operations.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
namespace content {
LameCaptureOverlayChromeOS::Owner::~Owner() = default;
LameCaptureOverlayChromeOS::LameCaptureOverlayChromeOS(
Owner* owner,
viz::mojom::FrameSinkVideoCaptureOverlayRequest request)
: binding_(this, std::move(request)) {
if (owner) {
binding_.set_connection_error_handler(base::BindOnce(
&Owner::OnOverlayConnectionLost, base::Unretained(owner), this));
}
}
LameCaptureOverlayChromeOS::~LameCaptureOverlayChromeOS() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
void LameCaptureOverlayChromeOS::SetImageAndBounds(const SkBitmap& image,
const gfx::RectF& bounds) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
image_ = image;
bounds_ = bounds;
cached_scaled_image_.reset();
}
void LameCaptureOverlayChromeOS::SetBounds(const gfx::RectF& bounds) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (bounds != bounds_) {
bounds_ = bounds;
cached_scaled_image_.reset();
}
}
namespace {
// Scales a |relative| rect having coordinates in the range [0.0,1.0) by the
// given |span|, snapping all coordinates to even numbers.
gfx::Rect ToAbsoluteBoundsForI420(const gfx::RectF& relative,
const gfx::Rect& span) {
const float absolute_left = std::fma(relative.x(), span.width(), span.x());
const float absolute_top = std::fma(relative.y(), span.height(), span.y());
const float absolute_right =
std::fma(relative.right(), span.width(), span.x());
const float absolute_bottom =
std::fma(relative.bottom(), span.height(), span.y());
// Compute the largest I420-friendly Rect that is fully-enclosed by the
// absolute rect. Use saturated_cast<> to restrict all extreme results [and
// Inf and NaN] to a safe range of integers.
const int snapped_left =
base::saturated_cast<int16_t>(std::ceil(absolute_left / 2.0f)) * 2;
const int snapped_top =
base::saturated_cast<int16_t>(std::ceil(absolute_top / 2.0f)) * 2;
const int snapped_right =
base::saturated_cast<int16_t>(std::floor(absolute_right / 2.0f)) * 2;
const int snapped_bottom =
base::saturated_cast<int16_t>(std::floor(absolute_bottom / 2.0f)) * 2;
return gfx::Rect(snapped_left, snapped_top,
std::max(0, snapped_right - snapped_left),
std::max(0, snapped_bottom - snapped_top));
}
inline int clip_byte(int x) {
return std::max(0, std::min(x, 255));
}
inline int alpha_blend(int alpha, int src, int dst) {
return (src * alpha + dst * (255 - alpha)) / 255;
}
} // namespace
LameCaptureOverlayChromeOS::OnceRenderer
LameCaptureOverlayChromeOS::MakeRenderer(const gfx::Rect& region_in_frame) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (bounds_.IsEmpty() || image_.drawsNothing()) {
return OnceRenderer();
}
// Determine the bounds of the overlay inside the video frame. The
// calculations here align to the 2x2 pixel-quads to simplify later
// implementation.
const gfx::Rect bounds_in_frame =
ToAbsoluteBoundsForI420(bounds_, region_in_frame);
// Compute the region of the frame to be modified.
gfx::Rect blit_rect = region_in_frame;
blit_rect.Intersect(bounds_in_frame);
// If the two rects didn't intersect at all (i.e., everything has been
// clipped), punt.
if (blit_rect.IsEmpty()) {
return OnceRenderer();
}
if (cached_scaled_image_.drawsNothing() ||
cached_scaled_image_.width() != bounds_in_frame.width() ||
cached_scaled_image_.height() != bounds_in_frame.height()) {
cached_scaled_image_ = skia::ImageOperations::Resize(
image_, skia::ImageOperations::RESIZE_BETTER, bounds_in_frame.width(),
bounds_in_frame.height());
}
// The following binds all state required to render the overlay on a
// VideoFrame at a later time. This callback does not require
// LameCaptureOverlayChromeOS to outlive it.
return base::BindOnce(
[](const SkBitmap& image, const gfx::Point& position,
const gfx::Rect& rect, media::VideoFrame* frame) {
DCHECK(frame);
DCHECK_EQ(frame->format(), media::PIXEL_FORMAT_I420);
DCHECK(frame->visible_rect().Contains(rect));
// Render the overlay in the video frame. This loop also performs a
// simple RGB→YUV color space conversion, with alpha-blended
// compositing.
for (int y = rect.y(); y < rect.bottom(); ++y) {
const int source_row = y - position.y();
uint8_t* const yplane =
frame->visible_data(media::VideoFrame::kYPlane) +
y * frame->stride(media::VideoFrame::kYPlane);
uint8_t* const uplane =
frame->visible_data(media::VideoFrame::kUPlane) +
(y / 2) * frame->stride(media::VideoFrame::kUPlane);
uint8_t* const vplane =
frame->visible_data(media::VideoFrame::kVPlane) +
(y / 2) * frame->stride(media::VideoFrame::kVPlane);
for (int x = rect.x(); x < rect.right(); ++x) {
const int source_col = x - position.x();
const SkColor color = image.getColor(source_col, source_row);
const int alpha = SkColorGetA(color);
const int color_r = SkColorGetR(color);
const int color_g = SkColorGetG(color);
const int color_b = SkColorGetB(color);
const int color_y =
((color_r * 66 + color_g * 129 + color_b * 25 + 128) >> 8) + 16;
yplane[x] = clip_byte(alpha_blend(alpha, color_y, yplane[x]));
// Only sample U and V at even coordinates.
if ((x % 2 == 0) && (y % 2 == 0)) {
const int color_u =
((color_r * -38 + color_g * -74 + color_b * 112 + 128) >> 8) +
128;
const int color_v =
((color_r * 112 + color_g * -94 + color_b * -18 + 128) >> 8) +
128;
uplane[x / 2] =
clip_byte(alpha_blend(alpha, color_u, uplane[x / 2]));
vplane[x / 2] =
clip_byte(alpha_blend(alpha, color_v, vplane[x / 2]));
}
}
}
},
cached_scaled_image_, bounds_in_frame.origin(), blit_rect);
}
} // namespace content
// Copyright 2018 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.
#ifndef CONTENT_BROWSER_MEDIA_CAPTURE_LAME_CAPTURE_OVERLAY_CHROMEOS_H_
#define CONTENT_BROWSER_MEDIA_CAPTURE_LAME_CAPTURE_OVERLAY_CHROMEOS_H_
#include "base/callback.h"
#include "base/macros.h"
#include "base/sequence_checker.h"
#include "content/common/content_export.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "services/viz/privileged/interfaces/compositing/frame_sink_video_capture.mojom.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/geometry/rect_f.h"
namespace media {
class VideoFrame;
}
namespace content {
// A minimal FrameSinkVideoCaptureOverlay implementation for aura::Window video
// capture on ChromeOS (i.e., not desktop capture, and not WebContents capture).
// See class comments for LameWindowCapturerChromeOS for further details on why
// this exists and why this placeholder is needed for now.
//
// The implementation here is a hodgepodge of code borrowed from
// viz::VideoCaptureOverlay and the legacy content::CursorRenderer. Like its
// full-featured VIZ cousin, it will cache the scaled version of the bitmap, and
// re-use it across multiple frames. However, the rest of the rendering impl is
// overly-simplified, sufferring from color accuracy and image sampling issues.
// However, its quality is sufficient for its main use as a mouse cursor
// renderer.
//
// TODO(crbug/806366): The goal is to remove this code by 2019.
class CONTENT_EXPORT LameCaptureOverlayChromeOS
: public viz::mojom::FrameSinkVideoCaptureOverlay {
public:
// Implemented by LameWindowCapturerChromeOS.
class CONTENT_EXPORT Owner {
public:
// Called to notify that the |overlay| has lost its mojo binding. The owner
// will usually delete it during this method call.
virtual void OnOverlayConnectionLost(
LameCaptureOverlayChromeOS* overlay) = 0;
protected:
virtual ~Owner();
};
// A OnceCallback that, when run, renders the overlay on a VideoFrame.
using OnceRenderer = base::OnceCallback<void(media::VideoFrame*)>;
LameCaptureOverlayChromeOS(
Owner* owner,
viz::mojom::FrameSinkVideoCaptureOverlayRequest request);
~LameCaptureOverlayChromeOS() final;
// viz::mojom::FrameSinkVideoCaptureOverlay implementation.
void SetImageAndBounds(const SkBitmap& image, const gfx::RectF& bounds) final;
void SetBounds(const gfx::RectF& bounds) final;
// Returns a OnceCallback that, when run, renders this overlay on an
// I420-format VideoFrame. The overlay's position and size are computed based
// on the given content |region_in_frame|. Returns a null OnceCallback if
// there is nothing to render at this time.
OnceRenderer MakeRenderer(const gfx::Rect& region_in_frame);
private:
SEQUENCE_CHECKER(sequence_checker_);
mojo::Binding<viz::mojom::FrameSinkVideoCaptureOverlay> binding_;
SkBitmap image_;
gfx::RectF bounds_;
// The scaled |image_| used in the last call to MakeRenderer(). This is reset
// and re-generated whenever: a) the |image_| changes, or b) the required
// bitmap size changes.
SkBitmap cached_scaled_image_;
DISALLOW_COPY_AND_ASSIGN(LameCaptureOverlayChromeOS);
};
} // namespace content
#endif // CONTENT_BROWSER_MEDIA_CAPTURE_LAME_CAPTURE_OVERLAY_CHROMEOS_H_
// Copyright 2018 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 "content/browser/media/capture/lame_capture_overlay_chromeos.h"
#include <stdint.h>
#include <memory>
#include <utility>
#include "base/test/scoped_task_environment.h"
#include "base/time/time.h"
#include "media/base/video_frame.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/size.h"
namespace content {
namespace {
constexpr gfx::Size kFrameSize = gfx::Size(320, 200);
constexpr gfx::Rect kContentRegion = gfx::Rect(kFrameSize);
constexpr gfx::RectF kSpanOfEntireFrame = gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f);
class LameCaptureOverlayChromeOSTest : public testing::Test {
public:
void RunUntilIdle() { env_.RunUntilIdle(); }
// Returns a 32x32 bitmap filled with red.
static SkBitmap CreateTestBitmap() {
SkBitmap bitmap;
bitmap.allocN32Pixels(32, 32);
CHECK(!bitmap.isNull());
bitmap.eraseColor(SK_ColorRED);
return bitmap;
}
// Returns true if there are any non-zero pixels in the region |rect| within
// |frame|.
static bool NonZeroPixelsInRegion(const media::VideoFrame* frame,
const gfx::Rect& rect) {
bool y_found = false, u_found = false, v_found = false;
for (int y = rect.y(); y < rect.bottom(); ++y) {
auto* const yplane = frame->visible_data(media::VideoFrame::kYPlane) +
y * frame->stride(media::VideoFrame::kYPlane);
auto* const uplane = frame->visible_data(media::VideoFrame::kUPlane) +
(y / 2) * frame->stride(media::VideoFrame::kUPlane);
auto* const vplane = frame->visible_data(media::VideoFrame::kVPlane) +
(y / 2) * frame->stride(media::VideoFrame::kVPlane);
for (int x = rect.x(); x < rect.right(); ++x) {
if (yplane[x] != 0)
y_found = true;
if (uplane[x / 2])
u_found = true;
if (vplane[x / 2])
v_found = true;
}
}
return (y_found && u_found && v_found);
}
private:
base::test::ScopedTaskEnvironment env_;
};
TEST_F(LameCaptureOverlayChromeOSTest, UnsetImageNotRenderedOnFrame) {
LameCaptureOverlayChromeOS overlay(
nullptr, viz::mojom::FrameSinkVideoCaptureOverlayRequest());
// Bounds set, but no image. → Should not render anything.
overlay.SetBounds(kSpanOfEntireFrame);
EXPECT_FALSE(overlay.MakeRenderer(kContentRegion));
// Both image and bounds set. → Should render something.
overlay.SetImageAndBounds(CreateTestBitmap(), kSpanOfEntireFrame);
EXPECT_TRUE(overlay.MakeRenderer(kContentRegion));
}
TEST_F(LameCaptureOverlayChromeOSTest, HiddenImageNotRenderedOnFrame) {
LameCaptureOverlayChromeOS overlay(
nullptr, viz::mojom::FrameSinkVideoCaptureOverlayRequest());
// Both image and bounds set. → Should render something.
overlay.SetImageAndBounds(CreateTestBitmap(), kSpanOfEntireFrame);
EXPECT_TRUE(overlay.MakeRenderer(kContentRegion));
// Bounds set to empty. → Should render nothing.
overlay.SetBounds(gfx::RectF());
EXPECT_FALSE(overlay.MakeRenderer(kContentRegion));
}
TEST_F(LameCaptureOverlayChromeOSTest, OutOfBoundsOverlayNotRenderedOnFrame) {
LameCaptureOverlayChromeOS overlay(
nullptr, viz::mojom::FrameSinkVideoCaptureOverlayRequest());
// Both image and bounds set. → Should render something.
overlay.SetImageAndBounds(CreateTestBitmap(), kSpanOfEntireFrame);
EXPECT_TRUE(overlay.MakeRenderer(kContentRegion));
// Move overlay to above and left of content area. → Should render nothing.
overlay.SetBounds(gfx::RectF(-0.5f, -0.5f, 0.25f, 0.25f));
EXPECT_FALSE(overlay.MakeRenderer(kContentRegion));
}
TEST_F(LameCaptureOverlayChromeOSTest, ImageRenderedOnFrame) {
LameCaptureOverlayChromeOS overlay(
nullptr, viz::mojom::FrameSinkVideoCaptureOverlayRequest());
// Create blank black frame. No non-zero pixels should be present.
const auto frame = media::VideoFrame::CreateZeroInitializedFrame(
media::PIXEL_FORMAT_I420, kFrameSize, gfx::Rect(kFrameSize), kFrameSize,
base::TimeDelta());
ASSERT_FALSE(NonZeroPixelsInRegion(frame.get(), frame->visible_rect()));
// Set image and bounds to a location in the lower-right quadrant of the
// frame.
const gfx::RectF bounds(0.8f, 0.8f, 0.1f, 0.1f);
overlay.SetImageAndBounds(CreateTestBitmap(), bounds);
// Render the overlay in the VideoFrame.
auto renderer = overlay.MakeRenderer(kContentRegion);
ASSERT_TRUE(renderer);
std::move(renderer).Run(frame.get());
// Check that there are non-zero pixels present in the modified region.
const gfx::Rect mutated_region = gfx::ToEnclosingRect(
gfx::ScaleRect(bounds, kContentRegion.width(), kContentRegion.height()));
EXPECT_TRUE(NonZeroPixelsInRegion(frame.get(), mutated_region));
// Check that there are no non-zero pixels present in the rest of the frame.
const struct BlankRegion {
const char* const description;
gfx::Rect rect;
} regions_around_mutation[] = {
{"above", gfx::Rect(0, 0, kContentRegion.width(), mutated_region.y())},
{"left", gfx::Rect(0, mutated_region.y(), mutated_region.x(),
mutated_region.height())},
{"right", gfx::Rect(mutated_region.right(), mutated_region.y(),
kContentRegion.width() - mutated_region.right(),
mutated_region.height())},
{"below", gfx::Rect(0, mutated_region.bottom(), kContentRegion.width(),
kContentRegion.height() - mutated_region.bottom())},
};
for (const BlankRegion& region : regions_around_mutation) {
SCOPED_TRACE(testing::Message() << region.description);
EXPECT_FALSE(NonZeroPixelsInRegion(frame.get(), region.rect));
}
}
TEST_F(LameCaptureOverlayChromeOSTest, ReportsLostMojoConnection) {
class MockOwner : public LameCaptureOverlayChromeOS::Owner {
public:
~MockOwner() final = default;
MOCK_METHOD1(OnOverlayConnectionLost,
void(LameCaptureOverlayChromeOS* overlay));
} mock_owner;
viz::mojom::FrameSinkVideoCaptureOverlayPtr overlay_ptr;
LameCaptureOverlayChromeOS overlay(&mock_owner,
mojo::MakeRequest(&overlay_ptr));
ASSERT_TRUE(overlay_ptr);
RunUntilIdle(); // Propagate mojo tasks.
EXPECT_CALL(mock_owner, OnOverlayConnectionLost(&overlay));
overlay_ptr.reset();
RunUntilIdle(); // Propagate mojo tasks.
}
} // namespace
} // namespace content
...@@ -143,8 +143,10 @@ void LameWindowCapturerChromeOS::RequestRefreshFrame() { ...@@ -143,8 +143,10 @@ void LameWindowCapturerChromeOS::RequestRefreshFrame() {
void LameWindowCapturerChromeOS::CreateOverlay( void LameWindowCapturerChromeOS::CreateOverlay(
int32_t stacking_index, int32_t stacking_index,
viz::mojom::FrameSinkVideoCaptureOverlayRequest request) { viz::mojom::FrameSinkVideoCaptureOverlayRequest request) {
// TODO(crbug.com/810133): Provide an implementation. // LameWindowCapturerChromeOS only supports one overlay at a time. If one
NOTIMPLEMENTED(); // already exists, the following will cause it to be dropped.
overlay_ =
std::make_unique<LameCaptureOverlayChromeOS>(this, std::move(request));
} }
class LameWindowCapturerChromeOS::InFlightFrame class LameWindowCapturerChromeOS::InFlightFrame
...@@ -171,6 +173,15 @@ class LameWindowCapturerChromeOS::InFlightFrame ...@@ -171,6 +173,15 @@ class LameWindowCapturerChromeOS::InFlightFrame
const gfx::Rect& content_rect() const { return content_rect_; } const gfx::Rect& content_rect() const { return content_rect_; }
void set_content_rect(const gfx::Rect& rect) { content_rect_ = rect; } void set_content_rect(const gfx::Rect& rect) { content_rect_ = rect; }
void set_overlay_renderer(LameCaptureOverlayChromeOS::OnceRenderer renderer) {
overlay_renderer_ = std::move(renderer);
}
void RenderOptionalOverlay() {
if (overlay_renderer_) {
std::move(overlay_renderer_).Run(video_frame_.get());
}
}
void Done() final { void Done() final {
if (auto* capturer = capturer_.get()) { if (auto* capturer = capturer_.get()) {
DCHECK_GT(capturer->in_flight_count_, 0); DCHECK_GT(capturer->in_flight_count_, 0);
...@@ -195,10 +206,18 @@ class LameWindowCapturerChromeOS::InFlightFrame ...@@ -195,10 +206,18 @@ class LameWindowCapturerChromeOS::InFlightFrame
BufferAndSize buffer_; BufferAndSize buffer_;
scoped_refptr<VideoFrame> video_frame_; scoped_refptr<VideoFrame> video_frame_;
gfx::Rect content_rect_; gfx::Rect content_rect_;
LameCaptureOverlayChromeOS::OnceRenderer overlay_renderer_;
DISALLOW_COPY_AND_ASSIGN(InFlightFrame); DISALLOW_COPY_AND_ASSIGN(InFlightFrame);
}; };
void LameWindowCapturerChromeOS::OnOverlayConnectionLost(
LameCaptureOverlayChromeOS* overlay) {
if (overlay_.get() == overlay) {
overlay_.reset();
}
}
void LameWindowCapturerChromeOS::CaptureNextFrame() { void LameWindowCapturerChromeOS::CaptureNextFrame() {
// If the maximum frame in-flight count has been reached, skip this frame. // If the maximum frame in-flight count has been reached, skip this frame.
if (in_flight_count_ >= kMaxFramesInFlight) { if (in_flight_count_ >= kMaxFramesInFlight) {
...@@ -280,6 +299,10 @@ void LameWindowCapturerChromeOS::CaptureNextFrame() { ...@@ -280,6 +299,10 @@ void LameWindowCapturerChromeOS::CaptureNextFrame() {
} }
DCHECK(target_); DCHECK(target_);
if (overlay_) {
in_flight_frame->set_overlay_renderer(overlay_->MakeRenderer(content_rect));
}
// Request a copy of the Layer associated with the |target_| aura::Window. // Request a copy of the Layer associated with the |target_| aura::Window.
auto request = std::make_unique<viz::CopyOutputRequest>( auto request = std::make_unique<viz::CopyOutputRequest>(
// Note: As of this writing, I420_PLANES is not supported external to VIZ. // Note: As of this writing, I420_PLANES is not supported external to VIZ.
...@@ -315,6 +338,8 @@ void LameWindowCapturerChromeOS::DidCopyFrame( ...@@ -315,6 +338,8 @@ void LameWindowCapturerChromeOS::DidCopyFrame(
return; // Copy request failed, punt. return; // Copy request failed, punt.
} }
in_flight_frame->RenderOptionalOverlay();
// The result may be smaller than what was requested, if unforeseen clamping // The result may be smaller than what was requested, if unforeseen clamping
// to the source boundaries occurred by the executor of the copy request. // to the source boundaries occurred by the executor of the copy request.
// However, the result should never contain more than what was requested. // However, the result should never contain more than what was requested.
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "base/time/time.h" #include "base/time/time.h"
#include "base/timer/timer.h" #include "base/timer/timer.h"
#include "base/unguessable_token.h" #include "base/unguessable_token.h"
#include "content/browser/media/capture/lame_capture_overlay_chromeos.h"
#include "media/base/video_frame.h" #include "media/base/video_frame.h"
#include "mojo/public/cpp/system/buffer.h" #include "mojo/public/cpp/system/buffer.h"
#include "services/viz/privileged/interfaces/compositing/frame_sink_video_capture.mojom.h" #include "services/viz/privileged/interfaces/compositing/frame_sink_video_capture.mojom.h"
...@@ -47,6 +48,7 @@ namespace content { ...@@ -47,6 +48,7 @@ namespace content {
// //
// TODO(crbug/806366): The goal is to remove this code by 2019. // TODO(crbug/806366): The goal is to remove this code by 2019.
class LameWindowCapturerChromeOS : public viz::mojom::FrameSinkVideoCapturer, class LameWindowCapturerChromeOS : public viz::mojom::FrameSinkVideoCapturer,
public LameCaptureOverlayChromeOS::Owner,
public aura::WindowObserver { public aura::WindowObserver {
public: public:
explicit LameWindowCapturerChromeOS(aura::Window* target); explicit LameWindowCapturerChromeOS(aura::Window* target);
...@@ -76,6 +78,9 @@ class LameWindowCapturerChromeOS : public viz::mojom::FrameSinkVideoCapturer, ...@@ -76,6 +78,9 @@ class LameWindowCapturerChromeOS : public viz::mojom::FrameSinkVideoCapturer,
// returns the buffer back to the pool. // returns the buffer back to the pool.
class InFlightFrame; class InFlightFrame;
// LameWindowCapturerChromeOS::Owner implementation.
void OnOverlayConnectionLost(LameCaptureOverlayChromeOS* overlay) final;
// Initiates capture of the next frame. This is called periodically by the // Initiates capture of the next frame. This is called periodically by the
// |timer_|. // |timer_|.
void CaptureNextFrame(); void CaptureNextFrame();
...@@ -124,6 +129,9 @@ class LameWindowCapturerChromeOS : public viz::mojom::FrameSinkVideoCapturer, ...@@ -124,6 +129,9 @@ class LameWindowCapturerChromeOS : public viz::mojom::FrameSinkVideoCapturer,
// video capture. // video capture.
const base::UnguessableToken copy_request_source_; const base::UnguessableToken copy_request_source_;
// An optional overlay to be rendered over each captured video frame.
std::unique_ptr<LameCaptureOverlayChromeOS> overlay_;
// Used for cancelling any outstanding activities' results, once Stop() is // Used for cancelling any outstanding activities' results, once Stop() is
// called and there is no longer a consumer to receive another frame. // called and there is no longer a consumer to receive another frame.
base::WeakPtrFactory<LameWindowCapturerChromeOS> weak_factory_; base::WeakPtrFactory<LameWindowCapturerChromeOS> weak_factory_;
......
...@@ -1970,6 +1970,11 @@ test("content_unittests") { ...@@ -1970,6 +1970,11 @@ test("content_unittests") {
if (is_mac) { if (is_mac) {
sources += [ "../browser/media/capture/cursor_renderer_mac_unittest.mm" ] sources += [ "../browser/media/capture/cursor_renderer_mac_unittest.mm" ]
} }
if (is_chromeos) {
sources += [
"../browser/media/capture/lame_capture_overlay_chromeos_unittest.cc",
]
}
} }
if (is_linux) { if (is_linux) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment