diff options
author | alexeypa@chromium.org <alexeypa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-21 10:16:41 +0000 |
---|---|---|
committer | alexeypa@chromium.org <alexeypa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-21 10:16:41 +0000 |
commit | da4daa7ff7b7393e7fa4491d1435653d8aa106a5 (patch) | |
tree | 5fba881f404af703dfa9b58a35a1ac2671971a0a | |
parent | 12ffada4b59da14b009815b59b77350fdb3599a4 (diff) | |
download | chromium_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.h | 3 | ||||
-rw-r--r-- | remoting/client/plugin/chromoting_instance.cc | 24 | ||||
-rw-r--r-- | remoting/client/plugin/chromoting_instance.h | 5 | ||||
-rw-r--r-- | remoting/client/plugin/pepper_view.cc | 7 | ||||
-rw-r--r-- | remoting/client/rectangle_update_decoder.cc | 4 | ||||
-rw-r--r-- | remoting/client/rectangle_update_decoder.h | 1 | ||||
-rw-r--r-- | remoting/codec/video_decoder.h | 4 | ||||
-rw-r--r-- | remoting/codec/video_decoder_verbatim.cc | 4 | ||||
-rw-r--r-- | remoting/codec/video_decoder_verbatim.h | 1 | ||||
-rw-r--r-- | remoting/codec/video_decoder_vp8.cc | 88 | ||||
-rw-r--r-- | remoting/codec/video_decoder_vp8.h | 15 | ||||
-rw-r--r-- | remoting/proto/video.proto | 5 |
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; } |