| Index: remoting/client/rectangle_update_decoder.cc
|
| diff --git a/remoting/client/rectangle_update_decoder.cc b/remoting/client/rectangle_update_decoder.cc
|
| index 673c2a037061f78d23afbd4c916b6c5995e750a7..3581f1d1c1af1ba5d3257335a4d40c56c3ca87af 100644
|
| --- a/remoting/client/rectangle_update_decoder.cc
|
| +++ b/remoting/client/rectangle_update_decoder.cc
|
| @@ -10,6 +10,7 @@
|
| #include "base/location.h"
|
| #include "base/logging.h"
|
| #include "base/message_loop_proxy.h"
|
| +#include "ppapi/cpp/image_data.h"
|
| #include "remoting/base/decoder.h"
|
| #include "remoting/base/decoder_row_based.h"
|
| #include "remoting/base/decoder_vp8.h"
|
| @@ -17,6 +18,7 @@
|
| #include "remoting/client/frame_consumer.h"
|
| #include "remoting/protocol/session_config.h"
|
|
|
| +using base::Passed;
|
| using remoting::protocol::ChannelConfig;
|
| using remoting::protocol::SessionConfig;
|
|
|
| @@ -27,8 +29,8 @@ RectangleUpdateDecoder::RectangleUpdateDecoder(
|
| : message_loop_(message_loop),
|
| consumer_(consumer),
|
| screen_size_(SkISize::Make(0, 0)),
|
| - clip_rect_(SkIRect::MakeEmpty()),
|
| - decoder_needs_reset_(false) {
|
| + view_size_(SkISize::Make(0, 0)),
|
| + clip_area_(SkIRect::MakeEmpty()) {
|
| }
|
|
|
| RectangleUpdateDecoder::~RectangleUpdateDecoder() {
|
| @@ -56,24 +58,19 @@ void RectangleUpdateDecoder::DecodePacket(const VideoPacket* packet,
|
| this, packet, done));
|
| return;
|
| }
|
| - AllocateFrame(packet, done);
|
| -}
|
|
|
| -void RectangleUpdateDecoder::AllocateFrame(const VideoPacket* packet,
|
| - const base::Closure& done) {
|
| - if (!message_loop_->BelongsToCurrentThread()) {
|
| - message_loop_->PostTask(
|
| - FROM_HERE, base::Bind(&RectangleUpdateDecoder::AllocateFrame,
|
| - this, packet, done));
|
| - return;
|
| - }
|
| base::ScopedClosureRunner done_runner(done);
|
| + bool decoder_needs_reset = false;
|
|
|
| // If the packet includes a screen size, store it.
|
| if (packet->format().has_screen_width() &&
|
| packet->format().has_screen_height()) {
|
| - screen_size_.set(packet->format().screen_width(),
|
| - packet->format().screen_height());
|
| + SkISize screen_size = SkISize::Make(packet->format().screen_width(),
|
| + packet->format().screen_height());
|
| + if (screen_size_ != screen_size) {
|
| + screen_size_ = screen_size;
|
| + decoder_needs_reset = true;
|
| + }
|
| }
|
|
|
| // If we've never seen a screen size, ignore the packet.
|
| @@ -81,42 +78,9 @@ void RectangleUpdateDecoder::AllocateFrame(const VideoPacket* packet,
|
| return;
|
| }
|
|
|
| - // Ensure the output frame is the right size.
|
| - SkISize frame_size = SkISize::Make(0, 0);
|
| - if (frame_)
|
| - frame_size.set(frame_->width(), frame_->height());
|
| -
|
| - // Allocate a new frame, if necessary.
|
| - if ((!frame_) || (screen_size_ != frame_size)) {
|
| - if (frame_) {
|
| - consumer_->ReleaseFrame(frame_);
|
| - frame_ = NULL;
|
| - }
|
| -
|
| - consumer_->AllocateFrame(
|
| - media::VideoFrame::RGB32, screen_size_, &frame_,
|
| - base::Bind(&RectangleUpdateDecoder::ProcessPacketData,
|
| - this, packet, done_runner.Release()));
|
| - decoder_needs_reset_ = true;
|
| - return;
|
| - }
|
| - ProcessPacketData(packet, done_runner.Release());
|
| -}
|
| -
|
| -void RectangleUpdateDecoder::ProcessPacketData(
|
| - const VideoPacket* packet, const base::Closure& done) {
|
| - if (!message_loop_->BelongsToCurrentThread()) {
|
| - message_loop_->PostTask(
|
| - FROM_HERE, base::Bind(&RectangleUpdateDecoder::ProcessPacketData,
|
| - this, packet, done));
|
| - return;
|
| - }
|
| - base::ScopedClosureRunner done_runner(done);
|
| -
|
| - if (decoder_needs_reset_) {
|
| - decoder_->Reset();
|
| - decoder_->Initialize(frame_);
|
| - decoder_needs_reset_ = false;
|
| + if (decoder_needs_reset) {
|
| + decoder_->Initialize(screen_size_);
|
| + consumer_->SetScreenSize(screen_size_);
|
| }
|
|
|
| if (!decoder_->IsReadyForData()) {
|
| @@ -126,109 +90,102 @@ void RectangleUpdateDecoder::ProcessPacketData(
|
| }
|
|
|
| if (decoder_->DecodePacket(packet) == Decoder::DECODE_DONE)
|
| - SubmitToConsumer();
|
| + DoPaint();
|
| }
|
|
|
| -void RectangleUpdateDecoder::SetOutputSize(const SkISize& size) {
|
| - if (!message_loop_->BelongsToCurrentThread()) {
|
| - message_loop_->PostTask(
|
| - FROM_HERE, base::Bind(&RectangleUpdateDecoder::SetOutputSize,
|
| - this, size));
|
| +void RectangleUpdateDecoder::DoPaint() {
|
| + if (buffers_.empty())
|
| return;
|
| - }
|
|
|
| - // TODO(wez): Refresh the frame only if the ratio has changed.
|
| - if (frame_) {
|
| - SkIRect frame_rect = SkIRect::MakeWH(frame_->width(), frame_->height());
|
| - refresh_region_.op(frame_rect, SkRegion::kUnion_Op);
|
| - }
|
| + // Draw the invalidated region to the buffer.
|
| + pp::ImageData* buffer = buffers_.front();
|
| + SkRegion output_region;
|
| + decoder_->RenderFrame(view_size_, clip_area_,
|
| + reinterpret_cast<uint8*>(buffer->data()),
|
| + buffer->stride(),
|
| + &output_region);
|
|
|
| - // TODO(hclam): If the scale ratio has changed we should reallocate a
|
| - // VideoFrame of different size. However if the scale ratio is always
|
| - // smaller than 1.0 we can use the same video frame.
|
| - if (decoder_.get()) {
|
| - decoder_->SetOutputSize(size);
|
| - RefreshFullFrame();
|
| + // Notify the consumer that painting is done.
|
| + if (!output_region.isEmpty()) {
|
| + buffers_.pop();
|
| + consumer_->PaintBuffer(view_size_, clip_area_, buffer, output_region);
|
| }
|
| }
|
|
|
| -void RectangleUpdateDecoder::UpdateClipRect(const SkIRect& new_clip_rect) {
|
| +void RectangleUpdateDecoder::DrainQueue(const base::Closure& done) {
|
| if (!message_loop_->BelongsToCurrentThread()) {
|
| message_loop_->PostTask(
|
| - FROM_HERE, base::Bind(&RectangleUpdateDecoder::UpdateClipRect,
|
| - this, new_clip_rect));
|
| + FROM_HERE, base::Bind(&RectangleUpdateDecoder::DrainQueue, this, done));
|
| return;
|
| }
|
|
|
| - if (new_clip_rect == clip_rect_ || !decoder_.get())
|
| - return;
|
| -
|
| - // TODO(wez): Only refresh newly-exposed portions of the frame.
|
| - if (frame_) {
|
| - SkIRect frame_rect = SkIRect::MakeWH(frame_->width(), frame_->height());
|
| - refresh_region_.op(frame_rect, SkRegion::kUnion_Op);
|
| + while (!buffers_.empty()) {
|
| + consumer_->ReturnBuffer(buffers_.front());
|
| + buffers_.pop();
|
| }
|
|
|
| - clip_rect_ = new_clip_rect;
|
| - decoder_->SetClipRect(new_clip_rect);
|
| -
|
| - // TODO(wez): Defer refresh so that multiple events can be batched.
|
| - DoRefresh();
|
| + if (!done.is_null())
|
| + done.Run();
|
| }
|
|
|
| -void RectangleUpdateDecoder::RefreshFullFrame() {
|
| +void RectangleUpdateDecoder::EnqueueBuffer(pp::ImageData* buffer) {
|
| if (!message_loop_->BelongsToCurrentThread()) {
|
| message_loop_->PostTask(
|
| - FROM_HERE, base::Bind(&RectangleUpdateDecoder::RefreshFullFrame, this));
|
| + FROM_HERE, base::Bind(&RectangleUpdateDecoder::EnqueueBuffer,
|
| + this, buffer));
|
| return;
|
| }
|
|
|
| - // If a video frame or the decoder is not allocated yet then don't
|
| - // save the refresh rectangle to avoid wasted computation.
|
| - if (!frame_ || !decoder_.get())
|
| - return;
|
| -
|
| - SkIRect frame_rect = SkIRect::MakeWH(frame_->width(), frame_->height());
|
| - refresh_region_.op(frame_rect, SkRegion::kUnion_Op);
|
| -
|
| - DoRefresh();
|
| -}
|
| -
|
| -void RectangleUpdateDecoder::SubmitToConsumer() {
|
| - // A frame is not allocated yet, we can reach here because of a refresh
|
| - // request.
|
| - if (!frame_)
|
| - return;
|
| -
|
| - SkRegion* dirty_region = new SkRegion;
|
| - decoder_->GetUpdatedRegion(dirty_region);
|
| + DCHECK(clip_area_.width() <= buffer->size().width() &&
|
| + clip_area_.height() <= buffer->size().height());
|
|
|
| - consumer_->OnPartialFrameOutput(frame_, dirty_region, base::Bind(
|
| - &RectangleUpdateDecoder::OnFrameConsumed, this, dirty_region));
|
| + buffers_.push(buffer);
|
| + DoPaint();
|
| }
|
|
|
| -void RectangleUpdateDecoder::DoRefresh() {
|
| - DCHECK(message_loop_->BelongsToCurrentThread());
|
| -
|
| - if (refresh_region_.isEmpty())
|
| +void RectangleUpdateDecoder::Invalidate(const SkRegion& region) {
|
| + if (!message_loop_->BelongsToCurrentThread()) {
|
| + message_loop_->PostTask(
|
| + FROM_HERE, base::Bind(&RectangleUpdateDecoder::Invalidate,
|
| + this, region));
|
| return;
|
| + }
|
|
|
| - decoder_->RefreshRegion(refresh_region_);
|
| - refresh_region_.setEmpty();
|
| - SubmitToConsumer();
|
| + if (decoder_.get()) {
|
| + decoder_->Invalidate(view_size_, region);
|
| + DoPaint();
|
| + }
|
| }
|
|
|
| -void RectangleUpdateDecoder::OnFrameConsumed(SkRegion* region) {
|
| +void RectangleUpdateDecoder::SetView(const SkISize& view_size,
|
| + const SkIRect& clip_area) {
|
| if (!message_loop_->BelongsToCurrentThread()) {
|
| message_loop_->PostTask(
|
| - FROM_HERE, base::Bind(&RectangleUpdateDecoder::OnFrameConsumed,
|
| - this, region));
|
| + FROM_HERE, base::Bind(&RectangleUpdateDecoder::SetView,
|
| + this, view_size, clip_area));
|
| return;
|
| }
|
|
|
| - delete region;
|
| + // The whole frame needs to be repainted if the scaling factor has changed.
|
| + // Otherwise the newly exposed parts of the frame will be automatically
|
| + // updated because they haven't been validated by RenderFrame() yet.
|
| + if (view_size_ != view_size && decoder_.get()) {
|
| + SkRegion region;
|
| + region.op(SkIRect::MakeSize(view_size), SkRegion::kUnion_Op);
|
| + decoder_->Invalidate(view_size, region);
|
| + }
|
| +
|
| + if (view_size_ != view_size ||
|
| + clip_area_ != clip_area) {
|
| + view_size_ = view_size;
|
| + clip_area_ = clip_area;
|
|
|
| - DoRefresh();
|
| + // Return buffers to the consumer for reuse/reallocation.
|
| + while (!buffers_.empty()) {
|
| + consumer_->ReturnBuffer(buffers_.front());
|
| + buffers_.pop();
|
| + }
|
| + }
|
| }
|
|
|
| } // namespace remoting
|
|
|