summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoralexeypa@chromium.org <alexeypa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-21 10:16:41 +0000
committeralexeypa@chromium.org <alexeypa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-21 10:16:41 +0000
commitda4daa7ff7b7393e7fa4491d1435653d8aa106a5 (patch)
tree5fba881f404af703dfa9b58a35a1ac2671971a0a
parent12ffada4b59da14b009815b59b77350fdb3599a4 (diff)
downloadchromium_src-da4daa7ff7b7393e7fa4491d1435653d8aa106a5.zip
chromium_src-da4daa7ff7b7393e7fa4491d1435653d8aa106a5.tar.gz
chromium_src-da4daa7ff7b7393e7fa4491d1435653d8aa106a5.tar.bz2
Added the desktop shape fields to VideoPacket.
If the host passes the desktop shape region in a VideoPacket the client will use it to draw transparent regions. The client also informs the web-app of the desktop shape changes, so it can set the input passthrough region correctly. Review URL: https://chromiumcodereview.appspot.com/17511004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@207789 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--remoting/client/frame_producer.h3
-rw-r--r--remoting/client/plugin/chromoting_instance.cc24
-rw-r--r--remoting/client/plugin/chromoting_instance.h5
-rw-r--r--remoting/client/plugin/pepper_view.cc7
-rw-r--r--remoting/client/rectangle_update_decoder.cc4
-rw-r--r--remoting/client/rectangle_update_decoder.h1
-rw-r--r--remoting/codec/video_decoder.h4
-rw-r--r--remoting/codec/video_decoder_verbatim.cc4
-rw-r--r--remoting/codec/video_decoder_verbatim.h1
-rw-r--r--remoting/codec/video_decoder_vp8.cc88
-rw-r--r--remoting/codec/video_decoder_vp8.h15
-rw-r--r--remoting/proto/video.proto5
12 files changed, 159 insertions, 2 deletions
diff --git a/remoting/client/frame_producer.h b/remoting/client/frame_producer.h
index 340fbb59..3506e8f 100644
--- a/remoting/client/frame_producer.h
+++ b/remoting/client/frame_producer.h
@@ -42,6 +42,9 @@ class FrameProducer {
virtual void SetOutputSizeAndClip(const SkISize& view_size,
const SkIRect& clip_area) = 0;
+ // Returns a reference to the shape of the most recently drawn buffer.
+ virtual const SkRegion* GetBufferShape() = 0;
+
protected:
virtual ~FrameProducer() {}
diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc
index 7bcc084..d772cfe 100644
--- a/remoting/client/plugin/chromoting_instance.cc
+++ b/remoting/client/plugin/chromoting_instance.cc
@@ -147,7 +147,7 @@ const char ChromotingInstance::kApiFeatures[] =
"asyncPin thirdPartyAuth pinlessAuth";
const char ChromotingInstance::kRequestedCapabilities[] = "";
-const char ChromotingInstance::kSupportedCapabilities[] = "";
+const char ChromotingInstance::kSupportedCapabilities[] = "desktopShape";
bool ChromotingInstance::ParseAuthMethods(const std::string& auth_methods_str,
ClientConfig* config) {
@@ -469,6 +469,28 @@ void ChromotingInstance::SetDesktopSize(const SkISize& size,
PostChromotingMessage("onDesktopSize", data.Pass());
}
+void ChromotingInstance::SetDesktopShape(const SkRegion& shape) {
+ if (desktop_shape_ && shape == *desktop_shape_)
+ return;
+
+ desktop_shape_.reset(new SkRegion(shape));
+
+ scoped_ptr<base::ListValue> rects_value(new base::ListValue());
+ for (SkRegion::Iterator i(shape); !i.done(); i.next()) {
+ SkIRect rect = i.rect();
+ scoped_ptr<base::ListValue> rect_value(new base::ListValue());
+ rect_value->AppendInteger(rect.x());
+ rect_value->AppendInteger(rect.y());
+ rect_value->AppendInteger(rect.width());
+ rect_value->AppendInteger(rect.height());
+ rects_value->Append(rect_value.release());
+ }
+
+ scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue());
+ data->Set("rects", rects_value.release());
+ PostChromotingMessage("onDesktopShape", data.Pass());
+}
+
void ChromotingInstance::OnConnectionState(
protocol::ConnectionToHost::State state,
protocol::ErrorCode error) {
diff --git a/remoting/client/plugin/chromoting_instance.h b/remoting/client/plugin/chromoting_instance.h
index 40f470f..b98d922 100644
--- a/remoting/client/plugin/chromoting_instance.h
+++ b/remoting/client/plugin/chromoting_instance.h
@@ -18,6 +18,7 @@
#include "ppapi/c/pp_resource.h"
#include "ppapi/cpp/var.h"
#include "third_party/skia/include/core/SkPoint.h"
+#include "third_party/skia/include/core/SkRegion.h"
#include "third_party/skia/include/core/SkSize.h"
// Windows defines 'PostMessage', so we have to undef it before we
@@ -135,6 +136,7 @@ class ChromotingInstance :
// Called by PepperView.
void SetDesktopSize(const SkISize& size, const SkIPoint& dpi);
+ void SetDesktopShape(const SkRegion& shape);
void OnFirstFrameReceived();
// Return statistics record by ChromotingClient.
@@ -233,6 +235,9 @@ class ChromotingInstance :
scoped_ptr<PepperView> view_;
pp::View plugin_view_;
+ // Contains the most-recently-reported desktop shape, if any.
+ scoped_ptr<SkRegion> desktop_shape_;
+
scoped_ptr<PepperSignalStrategy> signal_strategy_;
scoped_ptr<protocol::ConnectionToHost> host_connection_;
diff --git a/remoting/client/plugin/pepper_view.cc b/remoting/client/plugin/pepper_view.cc
index b2c8ac3..9f07a7d 100644
--- a/remoting/client/plugin/pepper_view.cc
+++ b/remoting/client/plugin/pepper_view.cc
@@ -104,7 +104,7 @@ void PepperView::SetView(const pp::View& view) {
// Create a 2D rendering context at the chosen frame dimensions.
pp::Size pp_size = pp::Size(view_size_.width(), view_size_.height());
- graphics2d_ = pp::Graphics2D(instance_, pp_size, true);
+ graphics2d_ = pp::Graphics2D(instance_, pp_size, false);
// Specify the scale from our coordinates to DIPs.
pp::Graphics2D_Dev graphics2d_dev(graphics2d_);
@@ -278,6 +278,11 @@ void PepperView::FlushBuffer(const SkIRect& clip_area,
&PepperView::OnFlushDone, AsWeakPtr(), start_time, buffer)));
CHECK(error == PP_OK_COMPLETIONPENDING);
flush_pending_ = true;
+
+ // If the buffer we just rendered has a shape then pass that to JavaScript.
+ const SkRegion* buffer_shape = producer_->GetBufferShape();
+ if (buffer_shape)
+ instance_->SetDesktopShape(*buffer_shape);
}
void PepperView::OnFlushDone(base::Time paint_start,
diff --git a/remoting/client/rectangle_update_decoder.cc b/remoting/client/rectangle_update_decoder.cc
index 4f301ce..6c2f61b 100644
--- a/remoting/client/rectangle_update_decoder.cc
+++ b/remoting/client/rectangle_update_decoder.cc
@@ -222,6 +222,10 @@ void RectangleUpdateDecoder::SetOutputSizeAndClip(const SkISize& view_size,
}
}
+const SkRegion* RectangleUpdateDecoder::GetBufferShape() {
+ return decoder_->GetImageShape();
+}
+
void RectangleUpdateDecoder::ProcessVideoPacket(scoped_ptr<VideoPacket> packet,
const base::Closure& done) {
DCHECK(main_task_runner_->BelongsToCurrentThread());
diff --git a/remoting/client/rectangle_update_decoder.h b/remoting/client/rectangle_update_decoder.h
index 5eefcad..fe71909 100644
--- a/remoting/client/rectangle_update_decoder.h
+++ b/remoting/client/rectangle_update_decoder.h
@@ -60,6 +60,7 @@ class RectangleUpdateDecoder
virtual void RequestReturnBuffers(const base::Closure& done) OVERRIDE;
virtual void SetOutputSizeAndClip(const SkISize& view_size,
const SkIRect& clip_area) OVERRIDE;
+ virtual const SkRegion* GetBufferShape() OVERRIDE;
// VideoStub implementation.
virtual void ProcessVideoPacket(scoped_ptr<VideoPacket> packet,
diff --git a/remoting/codec/video_decoder.h b/remoting/codec/video_decoder.h
index f1eb650..4e1d39f 100644
--- a/remoting/codec/video_decoder.h
+++ b/remoting/codec/video_decoder.h
@@ -68,6 +68,10 @@ class VideoDecoder {
uint8* image_buffer,
int image_stride,
SkRegion* output_region) = 0;
+
+ // Returns the "shape", if any, of the most recently rendered frame.
+ // The shape is returned in source dimensions.
+ virtual const SkRegion* GetImageShape() = 0;
};
} // namespace remoting
diff --git a/remoting/codec/video_decoder_verbatim.cc b/remoting/codec/video_decoder_verbatim.cc
index 56b116f..fa36690 100644
--- a/remoting/codec/video_decoder_verbatim.cc
+++ b/remoting/codec/video_decoder_verbatim.cc
@@ -203,4 +203,8 @@ void VideoDecoderVerbatim::RenderFrame(const SkISize& view_size,
updated_region_.setEmpty();
}
+const SkRegion* VideoDecoderVerbatim::GetImageShape() {
+ return NULL;
+}
+
} // namespace remoting
diff --git a/remoting/codec/video_decoder_verbatim.h b/remoting/codec/video_decoder_verbatim.h
index 46c7069..f058a7e 100644
--- a/remoting/codec/video_decoder_verbatim.h
+++ b/remoting/codec/video_decoder_verbatim.h
@@ -32,6 +32,7 @@ class VideoDecoderVerbatim : public VideoDecoder {
uint8* image_buffer,
int image_stride,
SkRegion* output_region) OVERRIDE;
+ virtual const SkRegion* GetImageShape() OVERRIDE;
private:
enum State {
diff --git a/remoting/codec/video_decoder_vp8.cc b/remoting/codec/video_decoder_vp8.cc
index d871542..33896fb 100644
--- a/remoting/codec/video_decoder_vp8.cc
+++ b/remoting/codec/video_decoder_vp8.cc
@@ -6,6 +6,8 @@
#include <math.h>
+#include <algorithm>
+
#include "base/logging.h"
#include "media/base/media.h"
#include "media/base/yuv_convert.h"
@@ -19,6 +21,10 @@ extern "C" {
namespace remoting {
+enum { kBytesPerPixelRGB32 = 4 };
+
+const uint32 kTransparent = 0;
+
VideoDecoderVp8::VideoDecoderVp8()
: state_(kUninitialized),
codec_(NULL),
@@ -39,6 +45,8 @@ void VideoDecoderVp8::Initialize(const SkISize& screen_size) {
screen_size_ = screen_size;
state_ = kReady;
+
+ transparent_region_.setRect(SkIRect::MakeSize(screen_size_));
}
VideoDecoder::DecodeResult VideoDecoderVp8::DecodePacket(
@@ -98,6 +106,26 @@ VideoDecoder::DecodeResult VideoDecoderVp8::DecodePacket(
}
updated_region_.op(region, SkRegion::kUnion_Op);
+
+ // Update the desktop shape region.
+ SkRegion desktop_shape_region;
+ if (packet->has_use_desktop_shape()) {
+ for (int i = 0; i < packet->desktop_shape_rects_size(); ++i) {
+ Rect remoting_rect = packet->desktop_shape_rects(i);
+ SkIRect rect = SkIRect::MakeXYWH(remoting_rect.x(),
+ remoting_rect.y(),
+ remoting_rect.width(),
+ remoting_rect.height());
+ desktop_shape_region.op(rect, SkRegion::kUnion_Op);
+ }
+ } else {
+ // Fallback for the case when the host didn't include the desktop shape
+ // region.
+ desktop_shape_region = SkRegion(SkIRect::MakeSize(screen_size_));
+ }
+
+ UpdateImageShapeRegion(&desktop_shape_region);
+
return DECODE_DONE;
}
@@ -119,6 +147,13 @@ void VideoDecoderVp8::Invalidate(const SkISize& view_size,
rect = ScaleRect(rect, view_size, screen_size_);
updated_region_.op(rect, SkRegion::kUnion_Op);
}
+
+ // Updated areas outside of the new desktop shape region should be made
+ // transparent, not repainted.
+ SkRegion difference = updated_region_;
+ difference.op(desktop_shape_, SkRegion::kDifference_Op);
+ updated_region_.op(difference, SkRegion::kDifference_Op);
+ transparent_region_.op(difference, SkRegion::kUnion_Op);
}
void VideoDecoderVp8::RenderFrame(const SkISize& view_size,
@@ -208,6 +243,59 @@ void VideoDecoderVp8::RenderFrame(const SkISize& view_size,
updated_region_.op(ScaleRect(clip_area, view_size, screen_size_),
SkRegion::kDifference_Op);
+
+ for (SkRegion::Iterator i(transparent_region_); !i.done(); i.next()) {
+ // Determine the scaled area affected by this rectangle changing.
+ SkIRect rect = i.rect();
+ if (!rect.intersect(source_clip))
+ continue;
+ rect = ScaleRect(rect, screen_size_, view_size);
+ if (!rect.intersect(clip_area))
+ continue;
+
+ // Fill the rectange with transparent pixels.
+ FillRect(image_buffer, image_stride, rect, kTransparent);
+ output_region->op(rect, SkRegion::kUnion_Op);
+ }
+
+ SkIRect scaled_clip_area = ScaleRect(clip_area, view_size, screen_size_);
+ updated_region_.op(scaled_clip_area, SkRegion::kDifference_Op);
+ transparent_region_.op(scaled_clip_area, SkRegion::kDifference_Op);
+}
+
+const SkRegion* VideoDecoderVp8::GetImageShape() {
+ return &desktop_shape_;
+}
+
+void VideoDecoderVp8::FillRect(uint8* buffer,
+ int stride,
+ const SkIRect& rect,
+ uint32 color) {
+ uint32* ptr = reinterpret_cast<uint32*>(buffer + (rect.top() * stride) +
+ (rect.left() * kBytesPerPixelRGB32));
+ int width = rect.width();
+ for (int height = rect.height(); height > 0; --height) {
+ std::fill(ptr, ptr + width, color);
+ ptr += stride / kBytesPerPixelRGB32;
+ }
+}
+
+void VideoDecoderVp8::UpdateImageShapeRegion(SkRegion* new_desktop_shape) {
+ // Add all areas that have been updated or become transparent to the
+ // transparent region. Exclude anything within the new desktop shape.
+ transparent_region_.op(desktop_shape_, SkRegion::kUnion_Op);
+ transparent_region_.op(updated_region_, SkRegion::kUnion_Op);
+ transparent_region_.op(*new_desktop_shape, SkRegion::kDifference_Op);
+
+ // Add newly exposed areas to the update region and limit updates to the new
+ // desktop shape.
+ SkRegion difference = *new_desktop_shape;
+ difference.op(desktop_shape_, SkRegion::kDifference_Op);
+ updated_region_.op(difference, SkRegion::kUnion_Op);
+ updated_region_.op(*new_desktop_shape, SkRegion::kIntersect_Op);
+
+ // Set the new desktop shape region.
+ desktop_shape_.swap(*new_desktop_shape);
}
} // namespace remoting
diff --git a/remoting/codec/video_decoder_vp8.h b/remoting/codec/video_decoder_vp8.h
index 53a720b..2efbd22 100644
--- a/remoting/codec/video_decoder_vp8.h
+++ b/remoting/codec/video_decoder_vp8.h
@@ -30,6 +30,7 @@ class VideoDecoderVp8 : public VideoDecoder {
uint8* image_buffer,
int image_stride,
SkRegion* output_region) OVERRIDE;
+ virtual const SkRegion* GetImageShape() OVERRIDE;
private:
enum State {
@@ -38,6 +39,14 @@ class VideoDecoderVp8 : public VideoDecoder {
kError,
};
+ // Fills the rectangle |rect| with the given ARGB color |color| in |buffer|.
+ void FillRect(uint8* buffer, int stride, const SkIRect& rect, uint32 color);
+
+ // Calculates the difference between the desktop shape regions in two
+ // consecutive frames and updates |updated_region_| and |transparent_region_|
+ // accordingly.
+ void UpdateImageShapeRegion(SkRegion* new_desktop_shape);
+
// The internal state of the decoder.
State state_;
@@ -52,6 +61,12 @@ class VideoDecoderVp8 : public VideoDecoder {
// Output dimensions.
SkISize screen_size_;
+ // The region occupied by the top level windows.
+ SkRegion desktop_shape_;
+
+ // The region that should be make transparent.
+ SkRegion transparent_region_;
+
DISALLOW_COPY_AND_ASSIGN(VideoDecoderVp8);
};
diff --git a/remoting/proto/video.proto b/remoting/proto/video.proto
index 01c57d4..b412857 100644
--- a/remoting/proto/video.proto
+++ b/remoting/proto/video.proto
@@ -99,4 +99,9 @@ message VideoPacket {
// The most recent sequence number received from the client on the event
// channel.
optional int64 client_sequence_number = 9;
+
+ repeated Rect desktop_shape_rects = 10;
+
+ // True when |desktop_shape_rects| should be used.
+ optional bool use_desktop_shape = 11;
}