summaryrefslogtreecommitdiffstats
path: root/remoting/client/rectangle_update_decoder.cc
diff options
context:
space:
mode:
Diffstat (limited to 'remoting/client/rectangle_update_decoder.cc')
-rw-r--r--remoting/client/rectangle_update_decoder.cc206
1 files changed, 85 insertions, 121 deletions
diff --git a/remoting/client/rectangle_update_decoder.cc b/remoting/client/rectangle_update_decoder.cc
index 673c2a0..6f58564 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;
@@ -26,9 +28,9 @@ RectangleUpdateDecoder::RectangleUpdateDecoder(
base::MessageLoopProxy* message_loop, FrameConsumer* consumer)
: message_loop_(message_loop),
consumer_(consumer),
- screen_size_(SkISize::Make(0, 0)),
- clip_rect_(SkIRect::MakeEmpty()),
- decoder_needs_reset_(false) {
+ source_size_(SkISize::Make(0, 0)),
+ view_size_(SkISize::Make(0, 0)),
+ clip_area_(SkIRect::MakeEmpty()) {
}
RectangleUpdateDecoder::~RectangleUpdateDecoder() {
@@ -56,67 +58,29 @@ 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());
- }
-
- // If we've never seen a screen size, ignore the packet.
- if (screen_size_.isZero()) {
- 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;
+ SkISize source_size = SkISize::Make(packet->format().screen_width(),
+ packet->format().screen_height());
+ if (source_size_ != source_size) {
+ source_size_ = source_size;
+ decoder_needs_reset = true;
}
-
- 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));
+ // If we've never seen a screen size, ignore the packet.
+ if (source_size_.isZero()) {
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(source_size_);
+ consumer_->SetSourceSize(source_size_);
}
if (!decoder_->IsReadyForData()) {
@@ -126,109 +90,109 @@ 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_front();
+ consumer_->ApplyBuffer(view_size_, clip_area_, buffer, output_region);
}
}
-void RectangleUpdateDecoder::UpdateClipRect(const SkIRect& new_clip_rect) {
+void RectangleUpdateDecoder::RequestReturnBuffers(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::RequestReturnBuffers,
+ 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_front();
}
- 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::DrawBuffer(pp::ImageData* buffer) {
if (!message_loop_->BelongsToCurrentThread()) {
message_loop_->PostTask(
- FROM_HERE, base::Bind(&RectangleUpdateDecoder::RefreshFullFrame, this));
+ FROM_HERE, base::Bind(&RectangleUpdateDecoder::DrawBuffer,
+ 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_back(buffer);
+ DoPaint();
}
-void RectangleUpdateDecoder::DoRefresh() {
- DCHECK(message_loop_->BelongsToCurrentThread());
-
- if (refresh_region_.isEmpty())
+void RectangleUpdateDecoder::InvalidateRegion(const SkRegion& region) {
+ if (!message_loop_->BelongsToCurrentThread()) {
+ message_loop_->PostTask(
+ FROM_HERE, base::Bind(&RectangleUpdateDecoder::InvalidateRegion,
+ 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::SetOutputSizeAndClip(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::SetOutputSizeAndClip,
+ this, view_size, clip_area));
return;
}
- delete region;
-
- DoRefresh();
+ // The whole frame needs to be repainted if the scaling factor has changed.
+ 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;
+
+ // Return buffers that are smaller than needed to the consumer for
+ // reuse/reallocation.
+ std::list<pp::ImageData*>::iterator i = buffers_.begin();
+ while (i != buffers_.end()) {
+ pp::Size buffer_size = (*i)->size();
+ if (buffer_size.width() < clip_area_.width() ||
+ buffer_size.height() < clip_area_.height()) {
+ consumer_->ReturnBuffer(*i);
+ i = buffers_.erase(i);
+ } else {
+ ++i;
+ }
+ }
+ }
}
} // namespace remoting