summaryrefslogtreecommitdiffstats
path: root/chromium/content/browser/renderer_host/media/desktop_capture_device_aura.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/content/browser/renderer_host/media/desktop_capture_device_aura.cc')
-rw-r--r--chromium/content/browser/renderer_host/media/desktop_capture_device_aura.cc442
1 files changed, 0 insertions, 442 deletions
diff --git a/chromium/content/browser/renderer_host/media/desktop_capture_device_aura.cc b/chromium/content/browser/renderer_host/media/desktop_capture_device_aura.cc
deleted file mode 100644
index a36d26b8b5f..00000000000
--- a/chromium/content/browser/renderer_host/media/desktop_capture_device_aura.cc
+++ /dev/null
@@ -1,442 +0,0 @@
-// Copyright 2013 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/renderer_host/media/desktop_capture_device_aura.h"
-
-#include "base/logging.h"
-#include "base/timer/timer.h"
-#include "cc/output/copy_output_request.h"
-#include "cc/output/copy_output_result.h"
-#include "content/browser/aura/image_transport_factory.h"
-#include "content/browser/renderer_host/media/video_capture_device_impl.h"
-#include "content/common/gpu/client/gl_helper.h"
-#include "content/public/browser/browser_thread.h"
-#include "media/base/video_util.h"
-#include "media/video/capture/video_capture_types.h"
-#include "skia/ext/image_operations.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/aura/env.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/window.h"
-#include "ui/aura/window_observer.h"
-#include "ui/base/cursor/cursors_aura.h"
-#include "ui/compositor/compositor.h"
-#include "ui/compositor/dip_util.h"
-#include "ui/compositor/layer.h"
-#include "ui/gfx/screen.h"
-
-namespace content {
-
-namespace {
-
-int clip_byte(int x) {
- return std::max(0, std::min(x, 255));
-}
-
-int alpha_blend(int alpha, int src, int dst) {
- return (src * alpha + dst * (255 - alpha)) / 255;
-}
-
-// Helper function to composite a cursor bitmap on a YUV420 video frame.
-void RenderCursorOnVideoFrame(
- const scoped_refptr<media::VideoFrame>& target,
- const SkBitmap& cursor_bitmap,
- const gfx::Point& cursor_position) {
- DCHECK(target);
- DCHECK(!cursor_bitmap.isNull());
-
- gfx::Rect rect = gfx::IntersectRects(
- gfx::Rect(cursor_bitmap.width(), cursor_bitmap.height()) +
- gfx::Vector2d(cursor_position.x(), cursor_position.y()),
- target->visible_rect());
-
- cursor_bitmap.lockPixels();
- for (int y = rect.y(); y < rect.bottom(); ++y) {
- int cursor_y = y - cursor_position.y();
- uint8* yplane = target->data(media::VideoFrame::kYPlane) +
- y * target->row_bytes(media::VideoFrame::kYPlane);
- uint8* uplane = target->data(media::VideoFrame::kUPlane) +
- (y / 2) * target->row_bytes(media::VideoFrame::kUPlane);
- uint8* vplane = target->data(media::VideoFrame::kVPlane) +
- (y / 2) * target->row_bytes(media::VideoFrame::kVPlane);
- for (int x = rect.x(); x < rect.right(); ++x) {
- int cursor_x = x - cursor_position.x();
- SkColor color = cursor_bitmap.getColor(cursor_x, cursor_y);
- int alpha = SkColorGetA(color);
- int color_r = SkColorGetR(color);
- int color_g = SkColorGetG(color);
- int color_b = SkColorGetB(color);
- int color_y = clip_byte(((color_r * 66 + color_g * 129 + color_b * 25 +
- 128) >> 8) + 16);
- yplane[x] = alpha_blend(alpha, color_y, yplane[x]);
-
- // Only sample U and V at even coordinates.
- if ((x % 2 == 0) && (y % 2 == 0)) {
- int color_u = clip_byte(((color_r * -38 + color_g * -74 +
- color_b * 112 + 128) >> 8) + 128);
- int color_v = clip_byte(((color_r * 112 + color_g * -94 +
- color_b * -18 + 128) >> 8) + 128);
- uplane[x / 2] = alpha_blend(alpha, color_u, uplane[x / 2]);
- vplane[x / 2] = alpha_blend(alpha, color_v, vplane[x / 2]);
- }
- }
- }
- cursor_bitmap.unlockPixels();
-}
-
-class DesktopVideoCaptureMachine
- : public VideoCaptureMachine,
- public aura::WindowObserver,
- public ui::CompositorObserver,
- public base::SupportsWeakPtr<DesktopVideoCaptureMachine> {
- public:
- DesktopVideoCaptureMachine(const DesktopMediaID& source);
- virtual ~DesktopVideoCaptureMachine();
-
- // VideoCaptureFrameSource overrides.
- virtual bool Start(
- const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy) OVERRIDE;
- virtual void Stop() OVERRIDE;
-
- // Implements aura::WindowObserver.
- virtual void OnWindowBoundsChanged(aura::Window* window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) OVERRIDE;
- virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
-
- // Implements ui::CompositorObserver.
- virtual void OnCompositingDidCommit(ui::Compositor* compositor) OVERRIDE {}
- virtual void OnCompositingStarted(ui::Compositor* compositor,
- base::TimeTicks start_time) OVERRIDE {}
- virtual void OnCompositingEnded(ui::Compositor* compositor) OVERRIDE;
- virtual void OnCompositingAborted(ui::Compositor* compositor) OVERRIDE {}
- virtual void OnCompositingLockStateChanged(
- ui::Compositor* compositor) OVERRIDE {}
- virtual void OnUpdateVSyncParameters(ui::Compositor* compositor,
- base::TimeTicks timebase,
- base::TimeDelta interval) OVERRIDE {}
-
- private:
- // Captures a frame.
- // |dirty| is false for timer polls and true for compositor updates.
- void Capture(bool dirty);
-
- // Update capture size. Must be called on the UI thread.
- void UpdateCaptureSize();
-
- // Response callback for cc::Layer::RequestCopyOfOutput().
- void DidCopyOutput(
- scoped_refptr<media::VideoFrame> video_frame,
- base::Time start_time,
- const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb,
- scoped_ptr<cc::CopyOutputResult> result);
-
- // Helper function to update cursor state.
- // |region_in_frame| defines the desktop bound in the captured frame.
- // Returns the current cursor position in captured frame.
- gfx::Point UpdateCursorState(const gfx::Rect& region_in_frame);
-
- // Clears cursor state.
- void ClearCursorState();
-
- // The window associated with the desktop.
- aura::Window* desktop_window_;
-
- // The layer associated with the desktop.
- ui::Layer* desktop_layer_;
-
- // The timer that kicks off period captures.
- base::Timer timer_;
-
- // The id of the window being captured.
- DesktopMediaID window_id_;
-
- // Makes all the decisions about which frames to copy, and how.
- scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_;
-
- // YUV readback pipeline.
- scoped_ptr<content::ReadbackYUVInterface> yuv_readback_pipeline_;
-
- // Cursor state.
- ui::Cursor last_cursor_;
- gfx::Point cursor_hot_point_;
- SkBitmap scaled_cursor_bitmap_;
-
- DISALLOW_COPY_AND_ASSIGN(DesktopVideoCaptureMachine);
-};
-
-DesktopVideoCaptureMachine::DesktopVideoCaptureMachine(
- const DesktopMediaID& source)
- : desktop_window_(NULL),
- desktop_layer_(NULL),
- timer_(true, true),
- window_id_(source) {}
-
-DesktopVideoCaptureMachine::~DesktopVideoCaptureMachine() {}
-
-bool DesktopVideoCaptureMachine::Start(
- const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- desktop_window_ = content::DesktopMediaID::GetAuraWindowById(window_id_);
- if (!desktop_window_)
- return false;
-
- // If the desktop layer is already destroyed then return failure.
- desktop_layer_ = desktop_window_->layer();
- if (!desktop_layer_)
- return false;
-
- DCHECK(oracle_proxy.get());
- oracle_proxy_ = oracle_proxy;
-
- // Update capture size.
- UpdateCaptureSize();
-
- // Start observing window events.
- desktop_window_->AddObserver(this);
-
- // Start observing compositor updates.
- ui::Compositor* compositor = desktop_layer_->GetCompositor();
- if (!compositor)
- return false;
-
- compositor->AddObserver(this);
-
- // Starts timer.
- timer_.Start(FROM_HERE, oracle_proxy_->capture_period(),
- base::Bind(&DesktopVideoCaptureMachine::Capture, AsWeakPtr(),
- false));
-
- started_ = true;
- return true;
-}
-
-void DesktopVideoCaptureMachine::Stop() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // Stop observing window events.
- if (desktop_window_)
- desktop_window_->RemoveObserver(this);
-
- // Stop observing compositor updates.
- if (desktop_layer_) {
- ui::Compositor* compositor = desktop_layer_->GetCompositor();
- if (compositor)
- compositor->RemoveObserver(this);
- }
-
- // Stop timer.
- timer_.Stop();
-
- started_ = false;
-}
-
-void DesktopVideoCaptureMachine::UpdateCaptureSize() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (oracle_proxy_ && desktop_layer_) {
- oracle_proxy_->UpdateCaptureSize(ui::ConvertSizeToPixel(
- desktop_layer_, desktop_layer_->bounds().size()));
- }
- ClearCursorState();
-}
-
-void DesktopVideoCaptureMachine::Capture(bool dirty) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // Do not capture if the desktop layer is already destroyed.
- if (!desktop_layer_)
- return;
-
- scoped_refptr<media::VideoFrame> frame;
- ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb;
-
- const base::Time start_time = base::Time::Now();
- const VideoCaptureOracle::Event event =
- dirty ? VideoCaptureOracle::kCompositorUpdate
- : VideoCaptureOracle::kTimerPoll;
- if (oracle_proxy_->ObserveEventAndDecideCapture(
- event, start_time, &frame, &capture_frame_cb)) {
- scoped_ptr<cc::CopyOutputRequest> request =
- cc::CopyOutputRequest::CreateRequest(
- base::Bind(&DesktopVideoCaptureMachine::DidCopyOutput,
- AsWeakPtr(), frame, start_time, capture_frame_cb));
- gfx::Rect window_rect =
- ui::ConvertRectToPixel(desktop_window_->layer(),
- gfx::Rect(desktop_window_->bounds().width(),
- desktop_window_->bounds().height()));
- request->set_area(window_rect);
- desktop_layer_->RequestCopyOfOutput(request.Pass());
- }
-}
-
-void CopyOutputFinishedForVideo(
- base::Time start_time,
- const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb,
- const scoped_refptr<media::VideoFrame>& target,
- const SkBitmap& cursor_bitmap,
- const gfx::Point& cursor_position,
- scoped_ptr<cc::SingleReleaseCallback> release_callback,
- bool result) {
- if (!cursor_bitmap.isNull())
- RenderCursorOnVideoFrame(target, cursor_bitmap, cursor_position);
- release_callback->Run(0, false);
- capture_frame_cb.Run(start_time, result);
-}
-
-void DesktopVideoCaptureMachine::DidCopyOutput(
- scoped_refptr<media::VideoFrame> video_frame,
- base::Time start_time,
- const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb,
- scoped_ptr<cc::CopyOutputResult> result) {
- if (result->IsEmpty() || result->size().IsEmpty())
- return;
-
- // Compute the dest size we want after the letterboxing resize. Make the
- // coordinates and sizes even because we letterbox in YUV space
- // (see CopyRGBToVideoFrame). They need to be even for the UV samples to
- // line up correctly.
- // The video frame's coded_size() and the result's size() are both physical
- // pixels.
- gfx::Rect region_in_frame =
- media::ComputeLetterboxRegion(gfx::Rect(video_frame->coded_size()),
- result->size());
- region_in_frame = gfx::Rect(region_in_frame.x() & ~1,
- region_in_frame.y() & ~1,
- region_in_frame.width() & ~1,
- region_in_frame.height() & ~1);
- if (region_in_frame.IsEmpty())
- return;
-
- ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
- GLHelper* gl_helper = factory->GetGLHelper();
- if (!gl_helper)
- return;
-
- cc::TextureMailbox texture_mailbox;
- scoped_ptr<cc::SingleReleaseCallback> release_callback;
- result->TakeTexture(&texture_mailbox, &release_callback);
- DCHECK(texture_mailbox.IsTexture());
- if (!texture_mailbox.IsTexture())
- return;
-
- gfx::Rect result_rect(result->size());
- if (!yuv_readback_pipeline_ ||
- yuv_readback_pipeline_->scaler()->SrcSize() != result_rect.size() ||
- yuv_readback_pipeline_->scaler()->SrcSubrect() != result_rect ||
- yuv_readback_pipeline_->scaler()->DstSize() != region_in_frame.size()) {
- yuv_readback_pipeline_.reset(
- gl_helper->CreateReadbackPipelineYUV(GLHelper::SCALER_QUALITY_FAST,
- result_rect.size(),
- result_rect,
- video_frame->coded_size(),
- region_in_frame,
- true,
- true));
- }
-
- gfx::Point cursor_position_in_frame = UpdateCursorState(region_in_frame);
- yuv_readback_pipeline_->ReadbackYUV(
- texture_mailbox.name(), texture_mailbox.sync_point(), video_frame.get(),
- base::Bind(&CopyOutputFinishedForVideo, start_time, capture_frame_cb,
- video_frame, scaled_cursor_bitmap_, cursor_position_in_frame,
- base::Passed(&release_callback)));
-}
-
-gfx::Point DesktopVideoCaptureMachine::UpdateCursorState(
- const gfx::Rect& region_in_frame) {
- const gfx::Rect desktop_bounds = desktop_layer_->bounds();
- gfx::NativeCursor cursor = desktop_window_->GetDispatcher()->last_cursor();
- if (last_cursor_ != cursor) {
- SkBitmap cursor_bitmap;
- if (ui::GetCursorBitmap(cursor, &cursor_bitmap, &cursor_hot_point_)) {
- scaled_cursor_bitmap_ = skia::ImageOperations::Resize(
- cursor_bitmap,
- skia::ImageOperations::RESIZE_BEST,
- cursor_bitmap.width() * region_in_frame.width() /
- desktop_bounds.width(),
- cursor_bitmap.height() * region_in_frame.height() /
- desktop_bounds.height());
- last_cursor_ = cursor;
- } else {
- // Clear cursor state if ui::GetCursorBitmap failed so that we do not
- // render cursor on the captured frame.
- ClearCursorState();
- }
- }
-
- gfx::Point cursor_position = aura::Env::GetInstance()->last_mouse_location();
- const gfx::Point hot_point_in_dip = ui::ConvertPointToDIP(
- desktop_layer_, cursor_hot_point_);
- cursor_position.Offset(-desktop_bounds.x() - hot_point_in_dip.x(),
- -desktop_bounds.y() - hot_point_in_dip.y());
- return gfx::Point(
- region_in_frame.x() + cursor_position.x() * region_in_frame.width() /
- desktop_bounds.width(),
- region_in_frame.y() + cursor_position.y() * region_in_frame.height() /
- desktop_bounds.height());
-}
-
-void DesktopVideoCaptureMachine::ClearCursorState() {
- last_cursor_ = ui::Cursor();
- cursor_hot_point_ = gfx::Point();
- scaled_cursor_bitmap_.reset();
-}
-
-void DesktopVideoCaptureMachine::OnWindowBoundsChanged(
- aura::Window* window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) {
- DCHECK(desktop_window_ && window == desktop_window_);
-
- // Post task to update capture size on UI thread.
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
- &DesktopVideoCaptureMachine::UpdateCaptureSize, AsWeakPtr()));
-}
-
-void DesktopVideoCaptureMachine::OnWindowDestroyed(aura::Window* window) {
- DCHECK(desktop_window_ && window == desktop_window_);
- desktop_window_ = NULL;
- desktop_layer_ = NULL;
-
- // Post task to stop capture on UI thread.
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
- &DesktopVideoCaptureMachine::Stop, AsWeakPtr()));
-}
-
-void DesktopVideoCaptureMachine::OnCompositingEnded(
- ui::Compositor* compositor) {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
- &DesktopVideoCaptureMachine::Capture, AsWeakPtr(), true));
-}
-
-} // namespace
-
-DesktopCaptureDeviceAura::DesktopCaptureDeviceAura(
- const DesktopMediaID& source)
- : impl_(new VideoCaptureDeviceImpl(scoped_ptr<VideoCaptureMachine>(
- new DesktopVideoCaptureMachine(source)))) {}
-
-DesktopCaptureDeviceAura::~DesktopCaptureDeviceAura() {
- DVLOG(2) << "DesktopCaptureDeviceAura@" << this << " destroying.";
-}
-
-// static
-media::VideoCaptureDevice* DesktopCaptureDeviceAura::Create(
- const DesktopMediaID& source) {
- return new DesktopCaptureDeviceAura(source);
-}
-
-void DesktopCaptureDeviceAura::AllocateAndStart(
- const media::VideoCaptureParams& params,
- scoped_ptr<Client> client) {
- DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString();
- impl_->AllocateAndStart(params, client.Pass());
-}
-
-void DesktopCaptureDeviceAura::StopAndDeAllocate() {
- impl_->StopAndDeAllocate();
-}
-
-} // namespace content