Commit 31d6d17e authored by hshi@chromium.org's avatar hshi@chromium.org

Fix screen capture slowness in Chrome OS feedback report.

The webkitGetUserMedia maxWidth/maxHeight parameters only define the maximum
frame sizes. The actual capture resolution should not exceed that or the
actual desktop resolution. In other words it should only downscale the desktop
but not upscale it.

BUG=324923
TEST=trybot, Chrome OS feedback screen captures in native resolution

Review URL: https://codereview.chromium.org/100313002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@238359 0039d316-1c4b-4281-b951-d872f2087c98
parent d43280fb
......@@ -16,6 +16,9 @@ per-file web_contents*=hclam@chromium.org
per-file web_contents*=justinlin@chromium.org
per-file web_contents*=miu@chromium.org
per-file web_contents*=nick@chromium.org
per-file video_capture_device_impl*=hclam@chromium.org
per-file video_capture_device_impl*=miu@chromium.org
per-file video_capture_device_impl*=nick@chromium.org
per-file video_capture_oracle*=hclam@chromium.org
per-file video_capture_oracle*=justinlin@chromium.org
per-file video_capture_oracle*=miu@chromium.org
......
......@@ -41,6 +41,9 @@ class DesktopVideoCaptureMachine
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.
......@@ -60,6 +63,9 @@ class DesktopVideoCaptureMachine
// |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,
......@@ -117,6 +123,9 @@ bool DesktopVideoCaptureMachine::Start(
DCHECK(oracle_proxy.get());
oracle_proxy_ = oracle_proxy;
// Update capture size.
UpdateCaptureSize();
// Start observing window events.
desktop_window_->AddObserver(this);
......@@ -156,6 +165,14 @@ void DesktopVideoCaptureMachine::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()));
}
}
void DesktopVideoCaptureMachine::Capture(bool dirty) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
......@@ -248,6 +265,17 @@ void DesktopVideoCaptureMachine::DidCopyOutput(
base::Passed(&release_callback)));
}
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;
......
......@@ -23,6 +23,7 @@
#include "content/public/browser/browser_thread.h"
#include "media/base/bind_to_loop.h"
#include "media/base/video_frame.h"
#include "media/base/video_util.h"
#include "media/video/capture/video_capture_types.h"
#include "ui/gfx/rect.h"
......@@ -44,12 +45,18 @@ void DeleteCaptureMachineOnUIThread(
ThreadSafeCaptureOracle::ThreadSafeCaptureOracle(
scoped_ptr<media::VideoCaptureDevice::Client> client,
scoped_ptr<VideoCaptureOracle> oracle,
const gfx::Size& capture_size,
int frame_rate)
const media::VideoCaptureParams& params)
: client_(client.Pass()),
oracle_(oracle.Pass()),
capture_size_(capture_size),
frame_rate_(frame_rate) {}
params_(params),
capture_size_updated_(false) {
// Frame dimensions must each be an even integer since the client wants (or
// will convert to) YUV420.
capture_size_ = gfx::Size(
MakeEven(params.requested_format.frame_size.width()),
MakeEven(params.requested_format.frame_size.height()));
frame_rate_ = params.requested_format.frame_rate;
}
ThreadSafeCaptureOracle::~ThreadSafeCaptureOracle() {}
......@@ -122,6 +129,23 @@ bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture(
return true;
}
void ThreadSafeCaptureOracle::UpdateCaptureSize(const gfx::Size& source_size) {
base::AutoLock guard(lock_);
// If this is the first call to UpdateCaptureSize(), or the receiver supports
// variable resolution, then determine the capture size by treating the
// requested width and height as maxima.
if (!capture_size_updated_ || params_.allow_resolution_change) {
// The capture resolution should not exceed the source frame size.
// In other words it should downscale the image but not upscale it.
gfx::Rect capture_rect = media::ComputeLetterboxRegion(
gfx::Rect(params_.requested_format.frame_size), source_size);
capture_size_ = gfx::Size(MakeEven(capture_rect.width()),
MakeEven(capture_rect.height()));
capture_size_updated_ = true;
}
}
void ThreadSafeCaptureOracle::Stop() {
base::AutoLock guard(lock_);
client_.reset();
......@@ -173,13 +197,10 @@ void VideoCaptureDeviceImpl::AllocateAndStart(
return;
}
// Frame dimensions must each be a positive, even integer, since the client
// wants (or will convert to) YUV420.
gfx::Size frame_size(MakeEven(params.requested_format.frame_size.width()),
MakeEven(params.requested_format.frame_size.height()));
if (frame_size.width() < kMinFrameWidth ||
frame_size.height() < kMinFrameHeight) {
DVLOG(1) << "invalid frame size: " << frame_size.ToString();
if (params.requested_format.frame_size.width() < kMinFrameWidth ||
params.requested_format.frame_size.height() < kMinFrameHeight) {
DVLOG(1) << "invalid frame size: "
<< params.requested_format.frame_size.ToString();
client->OnError();
return;
}
......@@ -191,10 +212,7 @@ void VideoCaptureDeviceImpl::AllocateAndStart(
new VideoCaptureOracle(capture_period,
kAcceleratedSubscriberIsSupported));
oracle_proxy_ =
new ThreadSafeCaptureOracle(client.Pass(),
oracle.Pass(),
frame_size,
params.requested_format.frame_rate);
new ThreadSafeCaptureOracle(client.Pass(), oracle.Pass(), params);
// Starts the capture machine asynchronously.
BrowserThread::PostTaskAndReplyWithResult(
......
......@@ -45,8 +45,7 @@ class ThreadSafeCaptureOracle
public:
ThreadSafeCaptureOracle(scoped_ptr<media::VideoCaptureDevice::Client> client,
scoped_ptr<VideoCaptureOracle> oracle,
const gfx::Size& capture_size,
int frame_rate);
const media::VideoCaptureParams& params);
// Called when a captured frame is available or an error has occurred.
// If |success| is true then the frame provided is valid and |timestamp|
......@@ -64,6 +63,10 @@ class ThreadSafeCaptureOracle
return oracle_->capture_period();
}
// Updates capture resolution based on the supplied source size and the
// maximum frame size.
void UpdateCaptureSize(const gfx::Size& source_size);
// Stop new captures from happening (but doesn't forget the client).
void Stop();
......@@ -89,9 +92,15 @@ class ThreadSafeCaptureOracle
// Makes the decision to capture a frame.
const scoped_ptr<VideoCaptureOracle> oracle_;
// The video capture parameters used to construct the oracle proxy.
const media::VideoCaptureParams params_;
// Indicates if capture size has been updated after construction.
bool capture_size_updated_;
// The current capturing resolution and frame rate.
const gfx::Size capture_size_;
const int frame_rate_;
gfx::Size capture_size_;
int frame_rate_;
};
// Keeps track of the video capture source frames and executes copying on the
......
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