summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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.