summaryrefslogtreecommitdiffstats
path: root/remoting
diff options
context:
space:
mode:
authorsimonmorris@chromium.org <simonmorris@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-03 16:42:13 +0000
committersimonmorris@chromium.org <simonmorris@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-03 16:42:13 +0000
commit804443aef39615edd5b731aa5bfb3c611aeae697 (patch)
treec999531d0dff5352a1f88fa25e5df50a2996ed70 /remoting
parente05eb1d621ca0a26e0b33c650d4dbf456dba6863 (diff)
downloadchromium_src-804443aef39615edd5b731aa5bfb3c611aeae697.zip
chromium_src-804443aef39615edd5b731aa5bfb3c611aeae697.tar.gz
chromium_src-804443aef39615edd5b731aa5bfb3c611aeae697.tar.bz2
Let the host change resolution.
The screen size flows through the video pipeline, instead of being set statically when that pipeline is constructed. Only the Windows host actually detects when the screen size has changed. BUG=72469 TEST=none Review URL: http://codereview.chromium.org/6573005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@76747 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting')
-rw-r--r--remoting/base/capture_data.h4
-rw-r--r--remoting/base/encoder_row_based.cc11
-rw-r--r--remoting/base/encoder_row_based.h4
-rw-r--r--remoting/base/encoder_vp8.cc64
-rw-r--r--remoting/base/encoder_vp8.h4
-rw-r--r--remoting/client/appengine/static_files/chromoting_session.js1
-rw-r--r--remoting/client/plugin/chromoting_instance.cc5
-rw-r--r--remoting/client/plugin/chromoting_instance.h2
-rw-r--r--remoting/client/plugin/chromoting_scriptable_object.cc21
-rw-r--r--remoting/client/plugin/chromoting_scriptable_object.h3
-rw-r--r--remoting/client/plugin/pepper_view.cc10
-rw-r--r--remoting/client/plugin/pepper_view.h3
-rw-r--r--remoting/client/rectangle_update_decoder.cc114
-rw-r--r--remoting/client/rectangle_update_decoder.h15
-rw-r--r--remoting/client/x11_client.cc7
-rw-r--r--remoting/client/x11_view.h2
-rw-r--r--remoting/host/capturer.cc36
-rw-r--r--remoting/host/capturer.h27
-rw-r--r--remoting/host/capturer_fake.cc5
-rw-r--r--remoting/host/capturer_fake.h3
-rw-r--r--remoting/host/capturer_fake_ascii.cc2
-rw-r--r--remoting/host/capturer_fake_ascii.h5
-rw-r--r--remoting/host/capturer_gdi.cc144
-rw-r--r--remoting/host/capturer_gdi.h38
-rw-r--r--remoting/host/capturer_linux.cc25
-rw-r--r--remoting/host/capturer_mac.cc23
-rw-r--r--remoting/host/capturer_mac.h7
-rw-r--r--remoting/host/chromoting_host.cc5
-rw-r--r--remoting/host/differ.h5
-rw-r--r--remoting/host/event_executor_win.cc12
-rw-r--r--remoting/proto/video.proto4
31 files changed, 397 insertions, 214 deletions
diff --git a/remoting/base/capture_data.h b/remoting/base/capture_data.h
index f399e70..dd6c4b9 100644
--- a/remoting/base/capture_data.h
+++ b/remoting/base/capture_data.h
@@ -38,6 +38,10 @@ class CaptureData : public base::RefCountedThreadSafe<CaptureData> {
// written into |rects|.
const InvalidRects& dirty_rects() const { return dirty_rects_; }
+ // TODO(simonmorris): The next two methods should be replaced by a
+ // gfx::Size size(), and objects that store that size should also
+ // use a gfx::Size to do so.
+
// Get the width of the image captured.
int width() const { return width_; }
diff --git a/remoting/base/encoder_row_based.cc b/remoting/base/encoder_row_based.cc
index e035a42..6159207a 100644
--- a/remoting/base/encoder_row_based.cc
+++ b/remoting/base/encoder_row_based.cc
@@ -42,6 +42,8 @@ EncoderRowBased::EncoderRowBased(Compressor* compressor,
VideoPacketFormat::Encoding encoding)
: encoding_(encoding),
compressor_(compressor),
+ screen_width_(0),
+ screen_height_(0),
packet_size_(kPacketSize) {
}
@@ -50,6 +52,8 @@ EncoderRowBased::EncoderRowBased(Compressor* compressor,
int packet_size)
: encoding_(encoding),
compressor_(compressor),
+ screen_width_(0),
+ screen_height_(0),
packet_size_(packet_size) {
}
@@ -147,6 +151,13 @@ void EncoderRowBased::PrepareUpdateStart(const gfx::Rect& rect,
format->set_width(rect.width());
format->set_height(rect.height());
format->set_encoding(encoding_);
+ if ((capture_data_->width() != screen_width_) ||
+ (capture_data_->height() != screen_height_)) {
+ screen_width_ = capture_data_->width();
+ screen_height_ = capture_data_->height();
+ format->set_screen_width(screen_width_);
+ format->set_screen_height(screen_height_);
+ }
}
uint8* EncoderRowBased::GetOutputBuffer(VideoPacket* packet, size_t size) {
diff --git a/remoting/base/encoder_row_based.h b/remoting/base/encoder_row_based.h
index b3b62d5..fe7f49c 100644
--- a/remoting/base/encoder_row_based.h
+++ b/remoting/base/encoder_row_based.h
@@ -61,6 +61,10 @@ class EncoderRowBased : public Encoder {
scoped_refptr<CaptureData> capture_data_;
scoped_ptr<DataAvailableCallback> callback_;
+ // The most recent screen size.
+ int screen_width_;
+ int screen_height_;
+
int packet_size_;
};
diff --git a/remoting/base/encoder_vp8.cc b/remoting/base/encoder_vp8.cc
index 1d8f8c6..492987d 100644
--- a/remoting/base/encoder_vp8.cc
+++ b/remoting/base/encoder_vp8.cc
@@ -34,7 +34,9 @@ EncoderVp8::EncoderVp8()
image_(NULL),
active_map_width_(0),
active_map_height_(0),
- last_timestamp_(0) {
+ last_timestamp_(0),
+ width_(0),
+ height_(0) {
}
EncoderVp8::~EncoderVp8() {
@@ -45,6 +47,8 @@ EncoderVp8::~EncoderVp8() {
}
bool EncoderVp8::Init(int width, int height) {
+ width_ = width;
+ height_ = height;
codec_.reset(new vpx_codec_ctx_t());
image_.reset(new vpx_image_t());
memset(image_.get(), 0, sizeof(vpx_image_t));
@@ -57,6 +61,30 @@ bool EncoderVp8::Init(int width, int height) {
image_->d_h = height;
image_->h = height;
+ // YUV image size is 1.5 times of a plane. Multiplication is performed first
+ // to avoid rounding error.
+ const int plane_size = width * height;
+ const int size = plane_size * 3 / 2;
+
+ yuv_image_.reset(new uint8[size]);
+
+ // Reset image value to 128 so we just need to fill in the y plane.
+ memset(yuv_image_.get(), 128, size);
+
+ // Fill in the information for |image_|.
+ unsigned char* image = reinterpret_cast<unsigned char*>(yuv_image_.get());
+ image_->planes[0] = image;
+ image_->planes[1] = image + plane_size;
+
+ // The V plane starts from 1.25 of the plane size.
+ image_->planes[2] = image + plane_size + plane_size / 4;
+
+ // In YV12 Y plane has full width, UV plane has half width because of
+ // subsampling.
+ image_->stride[0] = image_->w;
+ image_->stride[1] = image_->w / 2;
+ image_->stride[2] = image_->w / 2;
+
vpx_codec_enc_cfg_t config;
const vpx_codec_iface_t* algo = vpx_codec_vp8_cx();
CHECK(algo);
@@ -112,34 +140,6 @@ static gfx::Rect AlignRect(const gfx::Rect& rect, int width, int height) {
bool EncoderVp8::PrepareImage(scoped_refptr<CaptureData> capture_data,
std::vector<gfx::Rect>* updated_rects) {
- const int plane_size = capture_data->width() * capture_data->height();
-
- if (!yuv_image_.get()) {
-
- // YUV image size is 1.5 times of a plane. Multiplication is performed first
- // to avoid rounding error.
- const int size = plane_size * 3 / 2;
-
- yuv_image_.reset(new uint8[size]);
-
- // Reset image value to 128 so we just need to fill in the y plane.
- memset(yuv_image_.get(), 128, size);
-
- // Fill in the information for |image_|.
- unsigned char* image = reinterpret_cast<unsigned char*>(yuv_image_.get());
- image_->planes[0] = image;
- image_->planes[1] = image + plane_size;
-
- // The V plane starts from 1.25 of the plane size.
- image_->planes[2] = image + plane_size + plane_size / 4;
-
- // In YV12 Y plane has full width, UV plane has half width because of
- // subsampling.
- image_->stride[0] = image_->w;
- image_->stride[1] = image_->w / 2;
- image_->stride[2] = image_->w / 2;
- }
-
// Perform RGB->YUV conversion.
if (capture_data->pixel_format() != media::VideoFrame::RGB32) {
LOG(ERROR) << "Only RGB32 is supported";
@@ -149,6 +149,7 @@ bool EncoderVp8::PrepareImage(scoped_refptr<CaptureData> capture_data,
const InvalidRects& rects = capture_data->dirty_rects();
const uint8* in = capture_data->data_planes().data[0];
const int in_stride = capture_data->data_planes().strides[0];
+ const int plane_size = capture_data->width() * capture_data->height();
uint8* y_out = yuv_image_.get();
uint8* u_out = yuv_image_.get() + plane_size;
uint8* v_out = yuv_image_.get() + plane_size + plane_size / 4;
@@ -205,7 +206,8 @@ void EncoderVp8::PrepareActiveMap(
void EncoderVp8::Encode(scoped_refptr<CaptureData> capture_data,
bool key_frame,
DataAvailableCallback* data_available_callback) {
- if (!initialized_) {
+ if (!initialized_ || (capture_data->width() != width_) ||
+ (capture_data->height() != height_)) {
bool ret = Init(capture_data->width(), capture_data->height());
// TODO(hclam): Handle error better.
DCHECK(ret) << "Initialization of encoder failed";
@@ -269,6 +271,8 @@ void EncoderVp8::Encode(scoped_refptr<CaptureData> capture_data,
message->mutable_format()->set_encoding(VideoPacketFormat::ENCODING_VP8);
message->set_flags(VideoPacket::FIRST_PACKET | VideoPacket::LAST_PACKET |
VideoPacket::LAST_PARTITION);
+ message->mutable_format()->set_screen_width(capture_data->width());
+ message->mutable_format()->set_screen_height(capture_data->height());
for (size_t i = 0; i < updated_rects.size(); ++i) {
Rect* rect = message->add_dirty_rects();
rect->set_x(updated_rects[i].x());
diff --git a/remoting/base/encoder_vp8.h b/remoting/base/encoder_vp8.h
index e283d16..2bf73dc 100644
--- a/remoting/base/encoder_vp8.h
+++ b/remoting/base/encoder_vp8.h
@@ -51,6 +51,10 @@ class EncoderVp8 : public Encoder {
// Buffer for storing the yuv image.
scoped_array<uint8> yuv_image_;
+ // The current frame dimensions.
+ int width_;
+ int height_;
+
DISALLOW_COPY_AND_ASSIGN(EncoderVp8);
};
diff --git a/remoting/client/appengine/static_files/chromoting_session.js b/remoting/client/appengine/static_files/chromoting_session.js
index 9d4c481..3e22c85 100644
--- a/remoting/client/appengine/static_files/chromoting_session.js
+++ b/remoting/client/appengine/static_files/chromoting_session.js
@@ -24,6 +24,7 @@ function init() {
// a 'callback' property that contains the callback function.
plugin.connectionInfoUpdate = connectionInfoUpdateCallback;
plugin.debugInfo = debugInfoCallback;
+ plugin.desktopSizeUpdate = desktopSizeChanged;
plugin.loginChallenge = loginChallengeCallback;
console.log('connect request received: ' + chromoting.hostname + ' by ' +
diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc
index eacd49e..0cdfe62 100644
--- a/remoting/client/plugin/chromoting_instance.cc
+++ b/remoting/client/plugin/chromoting_instance.cc
@@ -73,9 +73,8 @@ bool ChromotingInstance::Init(uint32_t argc,
context_.jingle_thread()));
view_.reset(new PepperView(this, &context_));
view_proxy_ = new PepperViewProxy(this, view_.get());
- rectangle_decoder_.reset(
- new RectangleUpdateDecoder(context_.decode_message_loop(),
- view_proxy_));
+ rectangle_decoder_ = new RectangleUpdateDecoder(
+ context_.decode_message_loop(), view_proxy_);
input_handler_.reset(new PepperInputHandler(&context_,
host_connection_.get(),
view_proxy_));
diff --git a/remoting/client/plugin/chromoting_instance.h b/remoting/client/plugin/chromoting_instance.h
index 9e1c2d3..554760b 100644
--- a/remoting/client/plugin/chromoting_instance.h
+++ b/remoting/client/plugin/chromoting_instance.h
@@ -101,7 +101,7 @@ class ChromotingInstance : public pp::Instance {
// both ChromotingInstance and PepperView are destroyed and there will be
// outstanding tasks on the pepper message loo.
scoped_refptr<PepperViewProxy> view_proxy_;
- scoped_ptr<RectangleUpdateDecoder> rectangle_decoder_;
+ scoped_refptr<RectangleUpdateDecoder> rectangle_decoder_;
scoped_ptr<InputHandler> input_handler_;
scoped_ptr<ChromotingClient> client_;
diff --git a/remoting/client/plugin/chromoting_scriptable_object.cc b/remoting/client/plugin/chromoting_scriptable_object.cc
index b45b822..d1b7eec 100644
--- a/remoting/client/plugin/chromoting_scriptable_object.cc
+++ b/remoting/client/plugin/chromoting_scriptable_object.cc
@@ -19,6 +19,7 @@ const char kConnectionInfoUpdate[] = "connectionInfoUpdate";
const char kDebugInfo[] = "debugInfo";
const char kDesktopHeight[] = "desktopHeight";
const char kDesktopWidth[] = "desktopWidth";
+const char kDesktopSizeUpdate[] = "desktopSizeUpdate";
const char kLoginChallenge[] = "loginChallenge";
const char kQualityAttribute[] = "quality";
const char kStatusAttribute[] = "status";
@@ -57,6 +58,7 @@ void ChromotingScriptableObject::Init() {
// Debug info to display.
AddAttribute(kConnectionInfoUpdate, Var());
AddAttribute(kDebugInfo, Var());
+ AddAttribute(kDesktopSizeUpdate, Var());
AddAttribute(kLoginChallenge, Var());
AddAttribute(kDesktopWidth, Var(0));
AddAttribute(kDesktopHeight, Var(0));
@@ -142,6 +144,7 @@ void ChromotingScriptableObject::SetProperty(const Var& name,
std::string property_name = name.AsString();
if (property_name != kConnectionInfoUpdate &&
property_name != kDebugInfo &&
+ property_name != kDesktopSizeUpdate &&
property_name != kLoginChallenge &&
property_name != kDesktopWidth &&
property_name != kDesktopHeight) {
@@ -208,6 +211,7 @@ void ChromotingScriptableObject::SetDesktopSize(int width, int height) {
properties_[height_index].attribute.AsInt() != height) {
properties_[width_index].attribute = Var(width);
properties_[height_index].attribute = Var(height);
+ SignalDesktopSizeChange();
}
LogDebugInfo(base::StringPrintf("Update desktop size to: %d x %d.",
@@ -239,6 +243,23 @@ void ChromotingScriptableObject::SignalConnectionInfoChange() {
"Exception when invoking connectionInfoUpdate JS callback.");
}
+void ChromotingScriptableObject::SignalDesktopSizeChange() {
+ Var exception;
+
+ // The JavaScript callback function is the 'callback' property on the
+ // 'desktopSizeUpdate' object.
+ Var cb = GetProperty(Var(kDesktopSizeUpdate), &exception);
+
+ // Var() means call the object directly as a function rather than calling
+ // a method in the object.
+ cb.Call(Var(), 0, NULL, &exception);
+
+ if (!exception.is_undefined()) {
+ LOG(WARNING) << "Exception when invoking JS callback"
+ << exception.AsString();
+ }
+}
+
void ChromotingScriptableObject::SignalLoginChallenge() {
Var exception;
Var cb = GetProperty(Var(kLoginChallenge), &exception);
diff --git a/remoting/client/plugin/chromoting_scriptable_object.h b/remoting/client/plugin/chromoting_scriptable_object.h
index b8b848e62..9ebc8fa 100644
--- a/remoting/client/plugin/chromoting_scriptable_object.h
+++ b/remoting/client/plugin/chromoting_scriptable_object.h
@@ -160,6 +160,9 @@ class ChromotingScriptableObject
// changed.
void SignalConnectionInfoChange();
+ // Signal the JS code that the desktop size has changed.
+ void SignalDesktopSizeChange();
+
pp::Var DoConnect(const std::vector<pp::Var>& args, pp::Var* exception);
pp::Var DoDisconnect(const std::vector<pp::Var>& args, pp::Var* exception);
diff --git a/remoting/client/plugin/pepper_view.cc b/remoting/client/plugin/pepper_view.cc
index 5d154ba..6bc4508 100644
--- a/remoting/client/plugin/pepper_view.cc
+++ b/remoting/client/plugin/pepper_view.cc
@@ -20,8 +20,6 @@ namespace remoting {
PepperView::PepperView(ChromotingInstance* instance, ClientContext* context)
: instance_(instance),
context_(context),
- viewport_x_(0),
- viewport_y_(0),
viewport_width_(0),
viewport_height_(0),
is_static_fill_(false),
@@ -83,6 +81,8 @@ void PepperView::PaintFrame(media::VideoFrame* frame, UpdatedRects* rects) {
TraceContext::tracer()->PrintString("Start Paint Frame.");
+ SetViewport(0, 0, frame->width(), frame->height());
+
uint8* frame_data = frame->data(media::VideoFrame::kRGBPlane);
const int kFrameStride = frame->stride(media::VideoFrame::kRGBPlane);
const int kBytesPerPixel = GetBytesPerPixel(media::VideoFrame::RGB32);
@@ -178,11 +178,9 @@ void PepperView::UpdateLoginStatus(bool success, const std::string& info) {
void PepperView::SetViewport(int x, int y, int width, int height) {
DCHECK(instance_->CurrentlyOnPluginThread());
- // TODO(ajwong): Should we ignore x & y updates? What do those even mean?
+ if ((width == viewport_width_) && (height == viewport_height_))
+ return;
- // TODO(ajwong): What does viewport x, y mean to a plugin anyways?
- viewport_x_ = x;
- viewport_y_ = y;
viewport_width_ = width;
viewport_height_ = height;
diff --git a/remoting/client/plugin/pepper_view.h b/remoting/client/plugin/pepper_view.h
index f7822f3..119d1ca 100644
--- a/remoting/client/plugin/pepper_view.h
+++ b/remoting/client/plugin/pepper_view.h
@@ -16,7 +16,6 @@
#include "ppapi/cpp/graphics_2d.h"
#include "remoting/client/chromoting_view.h"
#include "remoting/client/frame_consumer.h"
-#include "remoting/client/rectangle_update_decoder.h"
namespace remoting {
@@ -68,8 +67,6 @@ class PepperView : public ChromotingView,
pp::Graphics2D graphics2d_;
- int viewport_x_;
- int viewport_y_;
int viewport_width_;
int viewport_height_;
diff --git a/remoting/client/rectangle_update_decoder.cc b/remoting/client/rectangle_update_decoder.cc
index 2690e14..5659fc5 100644
--- a/remoting/client/rectangle_update_decoder.cc
+++ b/remoting/client/rectangle_update_decoder.cc
@@ -44,15 +44,16 @@ class PartialFrameCleanup : public Task {
RectangleUpdateDecoder::RectangleUpdateDecoder(MessageLoop* message_loop,
FrameConsumer* consumer)
: message_loop_(message_loop),
- consumer_(consumer) {
+ consumer_(consumer),
+ frame_is_new_(false) {
}
RectangleUpdateDecoder::~RectangleUpdateDecoder() {
}
void RectangleUpdateDecoder::Initialize(const SessionConfig* config) {
- screen_size_ = gfx::Size(config->initial_resolution().width,
- config->initial_resolution().height);
+ initial_screen_size_ = gfx::Size(config->initial_resolution().width,
+ config->initial_resolution().height);
// Initialize decoder based on the selected codec.
ChannelConfig::Codec codec = config->video_config().codec;
@@ -87,77 +88,90 @@ void RectangleUpdateDecoder::DecodePacket(const VideoPacket* packet,
TraceContext::tracer()->PrintString("Decode Packet called.");
- if (!decoder_->IsReadyForData()) {
- InitializeDecoder(
- NewTracedMethod(this,
- &RectangleUpdateDecoder::ProcessPacketData,
- packet, done_runner.release()));
- } else {
- ProcessPacketData(packet, done_runner.release());
- }
+ AllocateFrame(packet, done_runner.release());
}
-void RectangleUpdateDecoder::ProcessPacketData(
- const VideoPacket* packet, Task* done) {
- AutoTaskRunner done_runner(done);
-
- if (!decoder_->IsReadyForData()) {
- // TODO(ajwong): This whole thing should move into an invalid state.
- LOG(ERROR) << "Decoder is unable to process data. Dropping packet.";
- return;
- }
-
- TraceContext::tracer()->PrintString("Executing Decode.");
-
- Decoder::DecodeResult result = decoder_->DecodePacket(packet);
-
- if (result == Decoder::DECODE_DONE) {
- UpdatedRects* rects = new UpdatedRects();
- decoder_->GetUpdatedRects(rects);
- consumer_->OnPartialFrameOutput(frame_, rects,
- new PartialFrameCleanup(frame_, rects));
- }
-}
-
-void RectangleUpdateDecoder::InitializeDecoder(Task* done) {
+void RectangleUpdateDecoder::AllocateFrame(const VideoPacket* packet,
+ Task* done) {
if (message_loop_ != MessageLoop::current()) {
message_loop_->PostTask(
FROM_HERE,
NewTracedMethod(this,
- &RectangleUpdateDecoder::InitializeDecoder, done));
+ &RectangleUpdateDecoder::AllocateFrame, packet, done));
return;
}
AutoTaskRunner done_runner(done);
- // Check if we need to request a new frame.
- if (!frame_ ||
- frame_->width() != static_cast<size_t>(screen_size_.width()) ||
- frame_->height() != static_cast<size_t>(screen_size_.height())) {
+ TraceContext::tracer()->PrintString("AllocateFrame called.");
+
+ // Find the required frame size.
+ bool has_screen_size = packet->format().has_screen_width() &&
+ packet->format().has_screen_height();
+ gfx::Size screen_size(packet->format().screen_width(),
+ packet->format().screen_height());
+ if (!has_screen_size)
+ screen_size = initial_screen_size_;
+
+ // Find the current frame size.
+ gfx::Size frame_size(0, 0);
+ if (frame_)
+ frame_size = gfx::Size(static_cast<int>(frame_->width()),
+ static_cast<int>(frame_->height()));
+
+ // Allocate a new frame, if necessary.
+ if ((!frame_) || (has_screen_size && (screen_size != frame_size))) {
if (frame_) {
TraceContext::tracer()->PrintString("Releasing old frame.");
consumer_->ReleaseFrame(frame_);
frame_ = NULL;
}
TraceContext::tracer()->PrintString("Requesting new frame.");
+
consumer_->AllocateFrame(media::VideoFrame::RGB32,
- screen_size_.width(), screen_size_.height(),
+ screen_size.width(), screen_size.height(),
base::TimeDelta(), base::TimeDelta(),
&frame_,
- NewTracedMethod(
- this,
- &RectangleUpdateDecoder::InitializeDecoder,
- done_runner.release()));
+ NewRunnableMethod(this,
+ &RectangleUpdateDecoder::ProcessPacketData,
+ packet, done_runner.release()));
+ frame_is_new_ = true;
return;
}
+ ProcessPacketData(packet, done_runner.release());
+}
+
+void RectangleUpdateDecoder::ProcessPacketData(
+ const VideoPacket* packet, Task* done) {
+ if (message_loop_ != MessageLoop::current()) {
+ message_loop_->PostTask(
+ FROM_HERE,
+ NewTracedMethod(this,
+ &RectangleUpdateDecoder::ProcessPacketData, packet,
+ done));
+ return;
+ }
+ AutoTaskRunner done_runner(done);
+
+ if (frame_is_new_) {
+ decoder_->Reset();
+ decoder_->Initialize(frame_);
+ frame_is_new_ = false;
+ }
- // TODO(ajwong): We need to handle the allocator failing to create a frame
- // and properly disable this class.
- CHECK(frame_);
+ if (!decoder_->IsReadyForData()) {
+ // TODO(ajwong): This whole thing should move into an invalid state.
+ LOG(ERROR) << "Decoder is unable to process data. Dropping packet.";
+ return;
+ }
- decoder_->Reset();
- decoder_->Initialize(frame_);
+ TraceContext::tracer()->PrintString("Executing Decode.");
- TraceContext::tracer()->PrintString("Decoder is Initialized");
+ if (decoder_->DecodePacket(packet) == Decoder::DECODE_DONE) {
+ UpdatedRects* rects = new UpdatedRects();
+ decoder_->GetUpdatedRects(rects);
+ consumer_->OnPartialFrameOutput(frame_, rects,
+ new PartialFrameCleanup(frame_, rects));
+ }
}
} // namespace remoting
diff --git a/remoting/client/rectangle_update_decoder.h b/remoting/client/rectangle_update_decoder.h
index bcd521a..fbcc69b 100644
--- a/remoting/client/rectangle_update_decoder.h
+++ b/remoting/client/rectangle_update_decoder.h
@@ -8,13 +8,13 @@
#include "base/scoped_ptr.h"
#include "base/task.h"
#include "media/base/video_frame.h"
+#include "remoting/base/decoder.h"
#include "ui/gfx/size.h"
class MessageLoop;
namespace remoting {
-class Decoder;
class FrameConsumer;
class VideoPacketFormat;
class VideoPacket;
@@ -26,11 +26,11 @@ class SessionConfig;
// TODO(ajwong): Re-examine this API, especially with regards to how error
// conditions on each step are reported. Should they be CHECKs? Logs? Other?
// TODO(sergeyu): Rename this class.
-class RectangleUpdateDecoder {
+class RectangleUpdateDecoder :
+ public base::RefCountedThreadSafe<RectangleUpdateDecoder> {
public:
RectangleUpdateDecoder(MessageLoop* message_loop,
FrameConsumer* consumer);
- ~RectangleUpdateDecoder();
// Initializes decoder with the infromation from the protocol config.
void Initialize(const protocol::SessionConfig* config);
@@ -45,20 +45,23 @@ class RectangleUpdateDecoder {
void DecodePacket(const VideoPacket* packet, Task* done);
private:
- void InitializeDecoder(Task* done);
+ friend class base::RefCountedThreadSafe<RectangleUpdateDecoder>;
+ ~RectangleUpdateDecoder();
+ void AllocateFrame(const VideoPacket* packet, Task* done);
void ProcessPacketData(const VideoPacket* packet, Task* done);
// Pointers to infrastructure objects. Not owned.
MessageLoop* message_loop_;
FrameConsumer* consumer_;
- gfx::Size screen_size_;
+ gfx::Size initial_screen_size_;
scoped_ptr<Decoder> decoder_;
- // Framebuffer for the decoder.
+ // The video frame that the decoder writes to.
scoped_refptr<media::VideoFrame> frame_;
+ bool frame_is_new_;
};
} // namespace remoting
diff --git a/remoting/client/x11_client.cc b/remoting/client/x11_client.cc
index 7bfd3b4..5d0867f 100644
--- a/remoting/client/x11_client.cc
+++ b/remoting/client/x11_client.cc
@@ -34,11 +34,12 @@ int main(int argc, char** argv) {
remoting::ClientContext context;
remoting::protocol::ConnectionToHost connection(context.jingle_thread());
remoting::X11View view;
- remoting::RectangleUpdateDecoder rectangle_decoder(
- context.decode_message_loop(), &view);
+ scoped_refptr<remoting::RectangleUpdateDecoder> rectangle_decoder =
+ new remoting::RectangleUpdateDecoder(context.decode_message_loop(),
+ &view);
remoting::X11InputHandler input_handler(&context, &connection, &view);
remoting::ChromotingClient client(
- config, &context, &connection, &view, &rectangle_decoder, &input_handler,
+ config, &context, &connection, &view, rectangle_decoder, &input_handler,
NewRunnableFunction(&ClientQuit, &ui_loop));
// Run the client on a new MessageLoop until
diff --git a/remoting/client/x11_view.h b/remoting/client/x11_view.h
index 9ba7fc1..d3e9623 100644
--- a/remoting/client/x11_view.h
+++ b/remoting/client/x11_view.h
@@ -9,8 +9,8 @@
#include "base/task.h"
#include "media/base/video_frame.h"
#include "remoting/base/decoder.h" // For UpdatedRects
-#include "remoting/client/frame_consumer.h"
#include "remoting/client/chromoting_view.h"
+#include "remoting/client/frame_consumer.h"
typedef unsigned long XID;
typedef struct _XDisplay Display;
diff --git a/remoting/host/capturer.cc b/remoting/host/capturer.cc
index 59854f1..0dd09ab 100644
--- a/remoting/host/capturer.cc
+++ b/remoting/host/capturer.cc
@@ -11,27 +11,16 @@
namespace remoting {
Capturer::Capturer(MessageLoop* message_loop)
- : width_(0),
- height_(0),
- pixel_format_(media::VideoFrame::INVALID),
- bytes_per_row_(0),
+ : pixel_format_(media::VideoFrame::INVALID),
current_buffer_(0),
- message_loop_(message_loop) {
+ message_loop_(message_loop),
+ width_most_recent_(0),
+ height_most_recent_(0) {
}
Capturer::~Capturer() {
}
-// Return the width of the screen.
-int Capturer::width() const {
- return width_;
-}
-
-// Return the height of the screen.
-int Capturer::height() const {
- return height_;
-}
-
// Return the pixel format of the screen.
media::VideoFrame::Format Capturer::pixel_format() const {
return pixel_format_;
@@ -53,10 +42,14 @@ void Capturer::InvalidateRects(const InvalidRects& inval_rects) {
}
}
-void Capturer::InvalidateFullScreen() {
+void Capturer::InvalidateFullScreen(int width, int height) {
base::AutoLock auto_inval_rects_lock(inval_rects_lock_);
inval_rects_.clear();
- inval_rects_.insert(gfx::Rect(0, 0, width_, height_));
+ inval_rects_.insert(gfx::Rect(0, 0, width, height));
+}
+
+void Capturer::InvalidateFullScreen() {
+ InvalidateFullScreen(width_most_recent_, height_most_recent_);
}
void Capturer::CaptureInvalidRects(CaptureCompletedCallback* callback) {
@@ -81,16 +74,19 @@ void Capturer::FinishCapture(scoped_refptr<CaptureData> data,
// Select the next buffer to be the current buffer.
current_buffer_ = (current_buffer_ + 1) % kNumBuffers;
+ width_most_recent_ = data->width();
+ height_most_recent_ = data->height();
+
callback->Run(data);
delete callback;
}
-bool Capturer::IsCaptureFullScreen() {
+bool Capturer::IsCaptureFullScreen(int width, int height) {
base::AutoLock auto_inval_rects_lock(inval_rects_lock_);
return inval_rects_.size() == 1u &&
inval_rects_.begin()->x() == 0 && inval_rects_.begin()->y() == 0 &&
- inval_rects_.begin()->width() == width_ &&
- inval_rects_.begin()->height() == height_;
+ inval_rects_.begin()->width() == width &&
+ inval_rects_.begin()->height() == height;
}
} // namespace remoting
diff --git a/remoting/host/capturer.h b/remoting/host/capturer.h
index a769abc..a91dcd7 100644
--- a/remoting/host/capturer.h
+++ b/remoting/host/capturer.h
@@ -52,12 +52,6 @@ class Capturer {
// Called when the screen configuration is changed.
virtual void ScreenConfigurationChanged() = 0;
- // Return the width of the screen.
- virtual int width() const;
-
- // Return the height of the screen.
- virtual int height() const;
-
// Return the pixel format of the screen.
virtual media::VideoFrame::Format pixel_format() const;
@@ -67,7 +61,11 @@ class Capturer {
// Invalidate the specified screen rects.
void InvalidateRects(const InvalidRects& inval_rects);
- // Invalidate the entire screen.
+ // Invalidate the entire screen, of a given size.
+ void InvalidateFullScreen(int width, int height);
+
+ // Invalidate the entire screen, using the size of the most recently
+ // captured screen.
virtual void InvalidateFullScreen();
// Capture the screen data associated with each of the accumulated
@@ -85,6 +83,10 @@ class Capturer {
// method is called.
virtual void CaptureInvalidRects(CaptureCompletedCallback* callback);
+ // Get the width/height of the most recently captured screen.
+ int width_most_recent() { return width_most_recent_; }
+ int height_most_recent() { return height_most_recent_; }
+
protected:
explicit Capturer(MessageLoop* message_loop);
@@ -116,18 +118,13 @@ class Capturer {
// Called by subclasses' CalculateInvalidRects() method to check if
// InvalidateFullScreen() was called by user.
- bool IsCaptureFullScreen();
+ bool IsCaptureFullScreen(int width, int height);
// Number of screen buffers.
static const int kNumBuffers = 2;
- // Capture screen dimensions.
- int width_;
- int height_;
-
// Format of pixels returned in buffer.
media::VideoFrame::Format pixel_format_;
- int bytes_per_row_;
// The current buffer with valid data for reading.
int current_buffer_;
@@ -143,6 +140,10 @@ class Capturer {
// A lock protecting |inval_rects_| across threads.
base::Lock inval_rects_lock_;
+
+ // The width and height of the most recently captured screen.
+ int width_most_recent_;
+ int height_most_recent_;
};
} // namespace remoting
diff --git a/remoting/host/capturer_fake.cc b/remoting/host/capturer_fake.cc
index 0cc0f37..a574457 100644
--- a/remoting/host/capturer_fake.cc
+++ b/remoting/host/capturer_fake.cc
@@ -26,6 +26,7 @@ static const int kBytesPerPixel = 4; // 32 bit RGB is 4 bytes per pixel.
CapturerFake::CapturerFake(MessageLoop* message_loop)
: Capturer(message_loop),
+ bytes_per_row_(0),
box_pos_x_(0),
box_pos_y_(0),
box_speed_x_(kSpeed),
@@ -39,8 +40,8 @@ CapturerFake::~CapturerFake() {
void CapturerFake::ScreenConfigurationChanged() {
width_ = kWidth;
height_ = kHeight;
- pixel_format_ = media::VideoFrame::RGB32;
bytes_per_row_ = width_ * kBytesPerPixel;
+ pixel_format_ = media::VideoFrame::RGB32;
// Create memory for the buffers.
int buffer_size = height_ * bytes_per_row_;
@@ -51,7 +52,7 @@ void CapturerFake::ScreenConfigurationChanged() {
void CapturerFake::CalculateInvalidRects() {
GenerateImage();
- InvalidateFullScreen();
+ InvalidateFullScreen(width_, height_);
}
void CapturerFake::CaptureRects(const InvalidRects& rects,
diff --git a/remoting/host/capturer_fake.h b/remoting/host/capturer_fake.h
index a6279b7..420d30e 100644
--- a/remoting/host/capturer_fake.h
+++ b/remoting/host/capturer_fake.h
@@ -29,6 +29,9 @@ class CapturerFake : public Capturer {
// Generates an image in the front buffer.
void GenerateImage();
+ int width_;
+ int height_;
+ int bytes_per_row_;
int box_pos_x_;
int box_pos_y_;
int box_speed_x_;
diff --git a/remoting/host/capturer_fake_ascii.cc b/remoting/host/capturer_fake_ascii.cc
index 1729fb6..8ea73c4 100644
--- a/remoting/host/capturer_fake_ascii.cc
+++ b/remoting/host/capturer_fake_ascii.cc
@@ -22,8 +22,8 @@ CapturerFakeAscii::~CapturerFakeAscii() {
void CapturerFakeAscii::ScreenConfigurationChanged() {
width_ = kWidth;
height_ = kHeight;
- pixel_format_ = media::VideoFrame::ASCII;
bytes_per_row_ = width_ * kBytesPerPixel;
+ pixel_format_ = media::VideoFrame::ASCII;
// Create memory for the buffers.
int buffer_size = height_ * bytes_per_row_;
diff --git a/remoting/host/capturer_fake_ascii.h b/remoting/host/capturer_fake_ascii.h
index cd02bc4..e68b8b4 100644
--- a/remoting/host/capturer_fake_ascii.h
+++ b/remoting/host/capturer_fake_ascii.h
@@ -30,6 +30,11 @@ class CapturerFakeAscii : public Capturer {
// Generates an image in the front buffer.
void GenerateImage();
+ // The screen dimensions.
+ int width_;
+ int height_;
+ int bytes_per_row_;
+
// We have two buffers for the screen images as required by Capturer.
scoped_array<uint8> buffers_[kNumBuffers];
diff --git a/remoting/host/capturer_gdi.cc b/remoting/host/capturer_gdi.cc
index bdaf756..36c8945 100644
--- a/remoting/host/capturer_gdi.cc
+++ b/remoting/host/capturer_gdi.cc
@@ -18,6 +18,7 @@ CapturerGdi::CapturerGdi(MessageLoop* message_loop)
: Capturer(message_loop),
desktop_dc_(NULL),
memory_dc_(NULL),
+ dc_size_(0, 0),
capture_fullscreen_(true) {
memset(target_bitmap_, 0, sizeof(target_bitmap_));
memset(buffers_, 0, sizeof(buffers_));
@@ -34,9 +35,9 @@ void CapturerGdi::ReleaseBuffers() {
DeleteObject(target_bitmap_[i]);
target_bitmap_[i] = NULL;
}
- if (buffers_[i]) {
- DeleteObject(buffers_[i]);
- buffers_[i] = NULL;
+ if (buffers_[i].data) {
+ DeleteObject(buffers_[i].data);
+ buffers_[i].data = NULL;
}
}
@@ -48,96 +49,149 @@ void CapturerGdi::ReleaseBuffers() {
}
void CapturerGdi::ScreenConfigurationChanged() {
- ReleaseBuffers();
+ // We poll for screen configuration changes, so ignore notifications.
+}
- desktop_dc_ = GetDC(GetDesktopWindow());
- memory_dc_ = CreateCompatibleDC(desktop_dc_);
+void CapturerGdi::UpdateBufferCapture(const gfx::Size& size) {
+ // Make sure the DCs have the correct dimensions.
+ if (size != dc_size_) {
+ // TODO(simonmorris): screen dimensions changing isn't equivalent to needing
+ // a new DC, but it's good enough for now.
+ desktop_dc_ = GetDC(GetDesktopWindow());
+ if (memory_dc_)
+ DeleteDC(memory_dc_);
+ memory_dc_ = CreateCompatibleDC(desktop_dc_);
+ dc_size_ = size;
+ }
+
+ // Make sure the current bitmap has the correct dimensions.
+ if (size != buffers_[current_buffer_].size) {
+ ReallocateBuffer(current_buffer_, size);
+ capture_fullscreen_ = true;
+ }
+}
+
+void CapturerGdi::ReallocateBuffer(int buffer_index, const gfx::Size& size) {
+ // Delete any previously constructed bitmap.
+ if (target_bitmap_[buffer_index]) {
+ DeleteObject(target_bitmap_[buffer_index]);
+ target_bitmap_[buffer_index] = NULL;
+ }
+ if (buffers_[buffer_index].data) {
+ DeleteObject(buffers_[buffer_index].data);
+ buffers_[buffer_index].data = NULL;
+ }
// Create a bitmap to keep the desktop image.
- width_ = GetSystemMetrics(SM_CXSCREEN);
- height_ = GetSystemMetrics(SM_CYSCREEN);
- int rounded_width = (width_ + 3) & (~3);
+ int rounded_width = (size.width() + 3) & (~3);
// Dimensions of screen.
pixel_format_ = media::VideoFrame::RGB32;
- bytes_per_row_ = rounded_width * kBytesPerPixel;
-
- // Create a differ for this screen size.
- differ_.reset(new Differ(width_, height_, 4, bytes_per_row_));
+ int bytes_per_row = rounded_width * kBytesPerPixel;
- // Create a device independant bitmap (DIB) that is the same size.
+ // Create a device independent bitmap (DIB) that is the same size.
BITMAPINFO bmi;
memset(&bmi, 0, sizeof(bmi));
- bmi.bmiHeader.biHeight = -height_;
- bmi.bmiHeader.biWidth = width_;
+ bmi.bmiHeader.biHeight = -size.height();
+ bmi.bmiHeader.biWidth = size.width();
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = kBytesPerPixel * 8;
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
- bmi.bmiHeader.biSizeImage = bytes_per_row_ * height_;
+ bmi.bmiHeader.biSizeImage = bytes_per_row * size.height();
bmi.bmiHeader.biXPelsPerMeter = kPixelsPerMeter;
bmi.bmiHeader.biYPelsPerMeter = kPixelsPerMeter;
// Create memory for the buffers.
- for (int i = 0; i < kNumBuffers; i++) {
- target_bitmap_[i] = CreateDIBSection(desktop_dc_, &bmi, DIB_RGB_COLORS,
- static_cast<void**>(&buffers_[i]),
- NULL, 0);
- }
-
- capture_fullscreen_ = true;
+ target_bitmap_[buffer_index] =
+ CreateDIBSection(desktop_dc_, &bmi, DIB_RGB_COLORS,
+ static_cast<void**>(&buffers_[buffer_index].data),
+ NULL, 0);
+ buffers_[buffer_index].size = gfx::Size(bmi.bmiHeader.biWidth,
+ std::abs(bmi.bmiHeader.biHeight));
+ buffers_[buffer_index].bytes_per_pixel = bmi.bmiHeader.biBitCount / 8;
+ buffers_[buffer_index].bytes_per_row =
+ bmi.bmiHeader.biSizeImage / std::abs(bmi.bmiHeader.biHeight);
}
void CapturerGdi::CalculateInvalidRects() {
CaptureImage();
- if (IsCaptureFullScreen())
+ const VideoFrameBuffer& current = buffers_[current_buffer_];
+ if (IsCaptureFullScreen(current.size.width(), current.size.height()))
capture_fullscreen_ = true;
if (capture_fullscreen_) {
- InvalidateFullScreen();
- } else {
- // Calculate the difference between the previous and current screen.
- int prev_buffer_id = current_buffer_ - 1;
- if (prev_buffer_id < 0) {
- prev_buffer_id = kNumBuffers - 1;
- }
-
- void* prev_buffer = buffers_[prev_buffer_id];
- void* curr_buffer = buffers_[current_buffer_];
+ InvalidateFullScreen(current.size.width(), current.size.height());
+ capture_fullscreen_ = false;
+ return;
+ }
- InvalidRects rects;
- differ_->CalcDirtyRects(prev_buffer, curr_buffer, &rects);
+ // Find the previous and current screens.
+ int prev_buffer_id = current_buffer_ - 1;
+ if (prev_buffer_id < 0) {
+ prev_buffer_id = kNumBuffers - 1;
+ }
+ const VideoFrameBuffer& prev = buffers_[prev_buffer_id];
+
+ // Maybe the previous and current screens can't be differenced.
+ if ((current.size != prev.size) ||
+ (current.bytes_per_pixel != prev.bytes_per_pixel) ||
+ (current.bytes_per_row != prev.bytes_per_row)) {
+ InvalidateFullScreen(current.size.width(), current.size.height());
+ return;
+ }
- InvalidateRects(rects);
+ // Make sure the differencer is set up correctly for these previous and
+ // current screens.
+ if (!differ_.get() ||
+ (differ_->width() != current.size.width()) ||
+ (differ_->height() != current.size.height()) ||
+ (differ_->bytes_per_pixel() != current.bytes_per_pixel) ||
+ (differ_->bytes_per_row() != current.bytes_per_row)) {
+ differ_.reset(new Differ(current.size.width(), current.size.height(),
+ current.bytes_per_pixel, current.bytes_per_row));
}
- capture_fullscreen_ = false;
+ InvalidRects rects;
+ differ_->CalcDirtyRects(prev.data, current.data, &rects);
+
+ InvalidateRects(rects);
}
void CapturerGdi::CaptureRects(const InvalidRects& rects,
CaptureCompletedCallback* callback) {
+ const VideoFrameBuffer& buffer = buffers_[current_buffer_];
DataPlanes planes;
- planes.data[0] = static_cast<uint8*>(buffers_[current_buffer_]);
- planes.strides[0] = bytes_per_row_;
+ planes.data[0] = static_cast<uint8*>(buffer.data);
+ planes.strides[0] = buffer.bytes_per_row;
scoped_refptr<CaptureData> data(new CaptureData(planes,
- width(),
- height(),
- pixel_format()));
+ buffer.size.width(),
+ buffer.size.height(),
+ pixel_format_));
data->mutable_dirty_rects() = rects;
FinishCapture(data, callback);
}
void CapturerGdi::CaptureImage() {
+ // Make sure the structures we use to capture the image have the correct size.
+ UpdateBufferCapture(GetScreenSize());
+
// Select the target bitmap into the memory dc.
SelectObject(memory_dc_, target_bitmap_[current_buffer_]);
// And then copy the rect from desktop to memory.
- BitBlt(memory_dc_, 0, 0, width_, height_, desktop_dc_, 0, 0,
+ BitBlt(memory_dc_, 0, 0, buffers_[current_buffer_].size.width(),
+ buffers_[current_buffer_].size.height(), desktop_dc_, 0, 0,
SRCCOPY | CAPTUREBLT);
}
+gfx::Size CapturerGdi::GetScreenSize() {
+ return gfx::Size(GetSystemMetrics(SM_CXSCREEN),
+ GetSystemMetrics(SM_CYSCREEN));
+}
+
// static
Capturer* Capturer::Create(MessageLoop* message_loop) {
return new CapturerGdi(message_loop);
diff --git a/remoting/host/capturer_gdi.h b/remoting/host/capturer_gdi.h
index 72aa261..634520e 100644
--- a/remoting/host/capturer_gdi.h
+++ b/remoting/host/capturer_gdi.h
@@ -26,6 +26,31 @@ class CapturerGdi : public Capturer {
virtual void ScreenConfigurationChanged();
private:
+ struct VideoFrameBuffer {
+ VideoFrameBuffer(void* data, const gfx::Size& size, int bytes_per_pixel,
+ int bytes_per_row)
+ : data(data), size(size), bytes_per_pixel(bytes_per_pixel),
+ bytes_per_row(bytes_per_row) {
+ }
+ VideoFrameBuffer() {
+ data = 0;
+ size = gfx::Size(0, 0);
+ bytes_per_pixel = 0;
+ bytes_per_row = 0;
+ }
+ void* data;
+ gfx::Size size;
+ int bytes_per_pixel;
+ int bytes_per_row;
+ };
+
+ // Make sure that the current buffer has the same size as the screen.
+ void UpdateBufferCapture(const gfx::Size& size);
+
+ // Allocate memory for a buffer of a given size, freeing any memory previously
+ // allocated for that buffer.
+ void ReallocateBuffer(int buffer_index, const gfx::Size& size);
+
virtual void CalculateInvalidRects();
virtual void CaptureRects(const InvalidRects& rects,
CaptureCompletedCallback* callback);
@@ -34,13 +59,24 @@ class CapturerGdi : public Capturer {
// Generates an image in the current buffer.
void CaptureImage();
+ // Gets the current screen size and calls ScreenConfigurationChanged
+ // if the screen size has changed.
+ void MaybeChangeScreenConfiguration();
+
+ // Gets the screen size.
+ gfx::Size GetScreenSize();
+
// Gdi specific information about screen.
HDC desktop_dc_;
HDC memory_dc_;
HBITMAP target_bitmap_[kNumBuffers];
+ // The screen size attached to the device contexts through which the screen
+ // is captured.
+ gfx::Size dc_size_;
+
// We have two buffers for the screen images as required by Capturer.
- void* buffers_[kNumBuffers];
+ VideoFrameBuffer buffers_[kNumBuffers];
// Class to calculate the difference between two screen bitmaps.
scoped_ptr<Differ> differ_;
diff --git a/remoting/host/capturer_linux.cc b/remoting/host/capturer_linux.cc
index f8e3fc6..408eda0 100644
--- a/remoting/host/capturer_linux.cc
+++ b/remoting/host/capturer_linux.cc
@@ -68,6 +68,8 @@ class CapturerLinuxPimpl {
Display* display_;
GC gc_;
Window root_window_;
+ int width_;
+ int height_;
// XDamage information.
Damage damage_handle_;
@@ -117,6 +119,8 @@ CapturerLinuxPimpl::CapturerLinuxPimpl(CapturerLinux* capturer)
display_(NULL),
gc_(NULL),
root_window_(BadValue),
+ width_(0),
+ height_(0),
damage_handle_(BadValue),
damage_event_base_(-1),
damage_error_base_(-1),
@@ -182,23 +186,21 @@ bool CapturerLinuxPimpl::Init() {
// Set up the dimensions of the catpure framebuffer.
XWindowAttributes root_attr;
XGetWindowAttributes(display_, root_window_, &root_attr);
- capturer_->width_ = root_attr.width;
- capturer_->height_ = root_attr.height;
- stride_ = capturer_->width() * kBytesPerPixel;
- VLOG(1) << "Initialized with Geometry: " << capturer_->width()
- << "x" << capturer_->height();
+ width_ = root_attr.width;
+ height_ = root_attr.height;
+ stride_ = width_ * kBytesPerPixel;
+ VLOG(1) << "Initialized with Geometry: " << width_ << "x" << height_;
// Allocate the screen buffers.
for (int i = 0; i < CapturerLinux::kNumBuffers; i++) {
- buffers_[i] =
- new uint8[capturer_->width() * capturer_->height() * kBytesPerPixel];
+ buffers_[i] = new uint8[width_ * height_ * kBytesPerPixel];
}
return true;
}
void CapturerLinuxPimpl::CalculateInvalidRects() {
- if (capturer_->IsCaptureFullScreen())
+ if (capturer_->IsCaptureFullScreen(width_, height_))
capture_fullscreen_ = true;
// TODO(ajwong): The capture_fullscreen_ logic here is very ugly. Refactor.
@@ -243,8 +245,7 @@ void CapturerLinuxPimpl::CaptureRects(
planes.strides[0] = stride_;
scoped_refptr<CaptureData> capture_data(
- new CaptureData(planes, capturer_->width(), capturer_->height(),
- media::VideoFrame::RGB32));
+ new CaptureData(planes, width_, height_, media::VideoFrame::RGB32));
// Synchronize the current buffer with the last one since we do not capture
// the entire desktop. Note that encoder may be reading from the previous
@@ -259,7 +260,7 @@ void CapturerLinuxPimpl::CaptureRects(
for (int i = 0; i < it->height(); ++i) {
memcpy(buffer + offset, last_buffer_ + offset,
it->width() * kBytesPerPixel);
- offset += capturer_->width() * kBytesPerPixel;
+ offset += width_ * kBytesPerPixel;
}
}
@@ -343,7 +344,7 @@ void CapturerLinuxPimpl::SlowBlit(XImage* image, int dest_x, int dest_y,
unsigned int max_green = image->green_mask >> green_shift;
// Produce an upside-down image.
- uint8* dst_pos = dst_buffer + dst_stride * (capturer_->height() - dest_y - 1);
+ uint8* dst_pos = dst_buffer + dst_stride * (height_ - dest_y - 1);
dst_pos += dest_x * kBytesPerPixel;
// TODO(jamiewalch): Optimize, perhaps using MMX code or by converting to
// YUV directly
diff --git a/remoting/host/capturer_mac.cc b/remoting/host/capturer_mac.cc
index dd94649..614386f 100644
--- a/remoting/host/capturer_mac.cc
+++ b/remoting/host/capturer_mac.cc
@@ -12,7 +12,10 @@ namespace remoting {
CapturerMac::CapturerMac(MessageLoop* message_loop)
: Capturer(message_loop),
- cgl_context_(NULL) {
+ cgl_context_(NULL),
+ width_(0),
+ height_(0),
+ bytes_per_row_(0) {
// TODO(dmaclach): move this initialization out into session_manager,
// or at least have session_manager call into here to initialize it.
CGError err =
@@ -51,7 +54,7 @@ void CapturerMac::ScreenConfigurationChanged() {
height_ = CGDisplayPixelsHigh(mainDevice);
pixel_format_ = media::VideoFrame::RGB32;
bytes_per_row_ = width_ * sizeof(uint32_t);
- size_t buffer_size = height() * bytes_per_row_;
+ size_t buffer_size = height_ * bytes_per_row_;
for (int i = 0; i < kNumBuffers; ++i) {
buffers_[i].reset(new uint8[buffer_size]);
}
@@ -93,19 +96,17 @@ void CapturerMac::CaptureRects(const InvalidRects& rects,
glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
// Read a block of pixels from the frame buffer.
- int h = height();
- int w = width();
uint8* flip_buffer = flip_buffer_.get();
uint8* current_buffer = buffers_[current_buffer_].get();
-
- glReadPixels(0, 0, w, h, GL_BGRA, GL_UNSIGNED_BYTE, flip_buffer);
+ glReadPixels(0, 0, width_, height_, GL_BGRA, GL_UNSIGNED_BYTE, flip_buffer);
glPopClientAttrib();
// OpenGL reads with a vertical flip, and sadly there is no optimized
// way to get it flipped automatically.
- for (int y = 0; y < h; ++y) {
+ for (int y = 0; y < height_; ++y) {
uint8* flip_row = &(flip_buffer[y * bytes_per_row_]);
- uint8* current_row = &(current_buffer[(h - (y + 1)) * bytes_per_row_]);
+ uint8* current_row =
+ &(current_buffer[(height_ - (y + 1)) * bytes_per_row_]);
memcpy(current_row, flip_row, bytes_per_row_);
}
@@ -114,7 +115,7 @@ void CapturerMac::CaptureRects(const InvalidRects& rects,
planes.strides[0] = bytes_per_row_;
scoped_refptr<CaptureData> data(
- new CaptureData(planes, w, h, pixel_format()));
+ new CaptureData(planes, width_, height_, pixel_format()));
data->mutable_dirty_rects() = rects;
FinishCapture(data, callback);
}
@@ -123,7 +124,7 @@ void CapturerMac::ScreenRefresh(CGRectCount count, const CGRect *rect_array) {
InvalidRects rects;
for (CGRectCount i = 0; i < count; ++i) {
CGRect rect = rect_array[i];
- rect.origin.y = height() - rect.size.height;
+ rect.origin.y = height_ - rect.size.height;
rects.insert(gfx::Rect(rect));
}
InvalidateRects(rects);
@@ -135,7 +136,7 @@ void CapturerMac::ScreenUpdateMove(CGScreenUpdateMoveDelta delta,
InvalidRects rects;
for (CGRectCount i = 0; i < count; ++i) {
CGRect rect = rect_array[i];
- rect.origin.y = height() - rect.size.height;
+ rect.origin.y = height_ - rect.size.height;
rects.insert(gfx::Rect(rect));
rect = CGRectOffset(rect, delta.dX, delta.dY);
rects.insert(gfx::Rect(rect));
diff --git a/remoting/host/capturer_mac.h b/remoting/host/capturer_mac.h
index eaedb47..7ea8d99 100644
--- a/remoting/host/capturer_mac.h
+++ b/remoting/host/capturer_mac.h
@@ -44,6 +44,13 @@ class CapturerMac : public Capturer {
CGLContextObj cgl_context_;
scoped_array<uint8> buffers_[kNumBuffers];
scoped_array<uint8> flip_buffer_;
+
+ // Screen size.
+ int width_;
+ int height_;
+
+ int bytes_per_row_;
+
DISALLOW_COPY_AND_ASSIGN(CapturerMac);
};
diff --git a/remoting/host/chromoting_host.cc b/remoting/host/chromoting_host.cc
index 9522b5c..5b2a21d 100644
--- a/remoting/host/chromoting_host.cc
+++ b/remoting/host/chromoting_host.cc
@@ -299,9 +299,10 @@ void ChromotingHost::OnNewClientSession(
return;
}
+ // TODO(simonmorris): The resolution is set in the video stream now,
+ // so it doesn't need to be set here.
*protocol_config_->mutable_initial_resolution() =
- protocol::ScreenResolution(desktop_environment_->capturer()->width(),
- desktop_environment_->capturer()->height());
+ protocol::ScreenResolution(2048, 2048);
// TODO(sergeyu): Respect resolution requested by the client if supported.
protocol::SessionConfig* config = protocol_config_->Select(
session->candidate_config(), true /* force_host_resolution */);
diff --git a/remoting/host/differ.h b/remoting/host/differ.h
index 8386e7a..a5af54f 100644
--- a/remoting/host/differ.h
+++ b/remoting/host/differ.h
@@ -27,6 +27,11 @@ class Differ {
Differ(int width, int height, int bytes_per_pixel, int stride);
~Differ();
+ int width() { return width_; }
+ int height() { return height_; }
+ int bytes_per_pixel() { return bytes_per_pixel_; }
+ int bytes_per_row() { return bytes_per_row_; }
+
// Given the previous and current screen buffer, calculate the set of
// rectangles that enclose all the changed pixels in the new screen.
void CalcDirtyRects(const void* prev_buffer, const void* curr_buffer,
diff --git a/remoting/host/event_executor_win.cc b/remoting/host/event_executor_win.cc
index e9229b2..95da76b 100644
--- a/remoting/host/event_executor_win.cc
+++ b/remoting/host/event_executor_win.cc
@@ -97,10 +97,14 @@ void EventExecutorWin::HandleMouse(const MouseEvent* event) {
INPUT input;
input.type = INPUT_MOUSE;
input.mi.time = 0;
- input.mi.dx = static_cast<int>((x * 65535) / capturer_->width());
- input.mi.dy = static_cast<int>((y * 65535) / capturer_->height());
- input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
- SendInput(1, &input, sizeof(INPUT));
+ int screen_width = capturer_->width_most_recent();
+ int screen_height = capturer_->height_most_recent();
+ if ((screen_width > 0) && (screen_height > 0)) {
+ input.mi.dx = static_cast<int>((x * 65535) / screen_width);
+ input.mi.dy = static_cast<int>((y * 65535) / screen_height);
+ input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
+ SendInput(1, &input, sizeof(INPUT));
+ }
}
if (event->has_wheel_offset_x() && event->has_wheel_offset_y()) {
diff --git a/remoting/proto/video.proto b/remoting/proto/video.proto
index 2dadcb8..245db10 100644
--- a/remoting/proto/video.proto
+++ b/remoting/proto/video.proto
@@ -30,6 +30,10 @@ message VideoPacketFormat {
// The encoding used for this image update.
optional Encoding encoding = 5 [default = ENCODING_INVALID];
+
+ // Width and height of the whole screen.
+ optional int32 screen_width = 6;
+ optional int32 screen_height = 7;
}
// TODO(hclam): Remove this message once we can obtain dirty rects from libvpx.