Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(754)

Unified Diff: remoting/client/rectangle_update_decoder.cc

Issue 3335012: Add in a new FrameConsumer interface, Decode API, and a RectangleUpdateDecoder abstraction. (Closed)
Patch Set: Fix silly compile errors Created 10 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « remoting/client/rectangle_update_decoder.h ('k') | remoting/remoting.gyp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: remoting/client/rectangle_update_decoder.cc
diff --git a/remoting/client/rectangle_update_decoder.cc b/remoting/client/rectangle_update_decoder.cc
new file mode 100644
index 0000000000000000000000000000000000000000..9d34e2a8e663b76db689c7287dc5ad62d1f057b1
--- /dev/null
+++ b/remoting/client/rectangle_update_decoder.cc
@@ -0,0 +1,218 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "remoting/client/rectangle_update_decoder.h"
+
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "media/base/callback.h"
+#include "remoting/base/decoder.h"
+#include "remoting/base/decoder_verbatim.h"
+#include "remoting/base/decoder_zlib.h"
+#include "remoting/base/protocol/chromotocol.pb.h"
+#include "remoting/base/tracer.h"
+#include "remoting/client/frame_consumer.h"
+
+using media::AutoTaskRunner;
+
+namespace remoting {
+
+namespace {
+
+class PartialFrameCleanup : public Task {
+ public:
+ PartialFrameCleanup(media::VideoFrame* frame, UpdatedRects* rects)
+ : frame_(frame), rects_(rects) {
+ }
+
+ virtual void Run() {
+ delete rects_;
+ frame_ = NULL;
+ }
+
+ private:
+ scoped_refptr<media::VideoFrame> frame_;
+ UpdatedRects* rects_;
+};
+
+} // namespace
+
+RectangleUpdateDecoder::RectangleUpdateDecoder(MessageLoop* message_loop,
+ FrameConsumer* consumer)
+ : message_loop_(message_loop),
+ consumer_(consumer) {
+}
+
+RectangleUpdateDecoder::~RectangleUpdateDecoder() {
+}
+
+void RectangleUpdateDecoder::DecodePacket(const RectangleUpdatePacket& packet,
+ Task* done) {
+ if (message_loop_ != MessageLoop::current()) {
+ message_loop_->PostTask(
+ FROM_HERE,
+ NewTracedMethod(this,
+ &RectangleUpdateDecoder::DecodePacket, packet,
+ done));
+ return;
+ }
+ AutoTaskRunner done_runner(done);
+
+ TraceContext::tracer()->PrintString("Decode Packet called.");
+
+ if (!IsValidPacket(packet)) {
+ LOG(ERROR) << "Received invalid packet.";
+ return;
+ }
+
+ Task* process_packet_data =
+ NewTracedMethod(this,
+ &RectangleUpdateDecoder::ProcessPacketData,
+ packet, done_runner.release());
+
+ if (packet.flags() | RectangleUpdatePacket::FIRST_PACKET) {
+ const RectangleFormat& format = packet.format();
+
+ InitializeDecoder(format, process_packet_data);
+ } else {
+ process_packet_data->Run();
+ delete process_packet_data;
+ }
+}
+
+void RectangleUpdateDecoder::ProcessPacketData(
+ const RectangleUpdatePacket& 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_->DecodeBytes(packet.encoded_rect());
+
+ if (packet.flags() | RectangleUpdatePacket::LAST_PACKET) {
+ decoder_->Reset();
+
+ UpdatedRects* rects = new UpdatedRects();
+
+ // Empty out the list of current updated rects so the decoder can keep
+ // writing new ones while these are processed.
+ rects->swap(updated_rects_);
+
+ consumer_->OnPartialFrameOutput(frame_, rects,
+ new PartialFrameCleanup(frame_, rects));
+ }
+}
+
+// static
+bool RectangleUpdateDecoder::IsValidPacket(
+ const RectangleUpdatePacket& packet) {
+ if (!packet.IsInitialized()) {
+ LOG(WARNING) << "Protobuf consistency checks fail.";
+ return false;
+ }
+
+ // First packet must have a format.
+ if (packet.flags() | RectangleUpdatePacket::FIRST_PACKET) {
+ if (!packet.has_format()) {
+ LOG(WARNING) << "First packet must have format.";
+ return false;
+ }
+
+ // TODO(ajwong): Verify that we don't need to whitelist encodings.
+ const RectangleFormat& format = packet.format();
+ if (!format.has_encoding() ||
+ format.encoding() == EncodingInvalid) {
+ LOG(WARNING) << "Invalid encoding specified.";
+ return false;
+ }
+ }
+
+ // We shouldn't generate null packets.
+ if (!packet.has_encoded_rect()) {
+ LOG(WARNING) << "Packet w/o an encoded rectangle received.";
+ return false;
+ }
+
+ return true;
+}
+
+void RectangleUpdateDecoder::InitializeDecoder(const RectangleFormat& format,
+ Task* done) {
+ if (message_loop_ != MessageLoop::current()) {
+ message_loop_->PostTask(
+ FROM_HERE,
+ NewTracedMethod(this,
+ &RectangleUpdateDecoder::InitializeDecoder,
+ format, done));
+ return;
+ }
+ AutoTaskRunner done_runner(done);
+
+ // Check if we need to request a new frame.
+ if (!frame_ ||
+ frame_->width() < static_cast<size_t>(format.width()) ||
+ frame_->height() < static_cast<size_t>(format.height())) {
+ if (frame_) {
+ TraceContext::tracer()->PrintString("Releasing old frame.");
+ consumer_->ReleaseFrame(frame_);
+ frame_ = NULL;
+ }
+ TraceContext::tracer()->PrintString("Requesting new frame.");
+ consumer_->AllocateFrame(media::VideoFrame::RGB32,
+ format.width(), format.height(),
+ base::TimeDelta(), base::TimeDelta(),
+ &frame_,
+ NewTracedMethod(
+ this,
+ &RectangleUpdateDecoder::InitializeDecoder,
+ format,
+ done_runner.release()));
+ return;
+ }
+
+ // TODO(ajwong): We need to handle the allocator failing to create a frame
+ // and properly disable this class.
+ CHECK(frame_);
+
+ if (decoder_.get()) {
+ // TODO(ajwong): We need to handle changing decoders midstream correctly
+ // since someone may feed us a corrupt stream, or manually create a
+ // stream that changes decoders. At the very leask, we should not
+ // crash the process.
+ //
+ // For now though, assume that only one encoding is used throughout.
+ //
+ // Note, this may be as simple as just deleting the current decoder.
+ // However, we need to verify the flushing semantics of the decoder first.
+ CHECK(decoder_->Encoding() == format.encoding());
+ } else {
+ // Initialize a new decoder based on this message encoding.
+ if (format.encoding() == EncodingNone) {
+ TraceContext::tracer()->PrintString("Creating Verbatim decoder.");
+ decoder_.reset(new DecoderVerbatim());
+ } else if (format.encoding() == EncodingZlib) {
+ TraceContext::tracer()->PrintString("Creating Zlib decoder");
+ decoder_.reset(new DecoderZlib());
+ } else {
+ NOTREACHED() << "Invalid Encoding found: " << format.encoding();
+ }
+ }
+
+ // TODO(ajwong): This can happen in the face of corrupt input data. Figure
+ // out the right behavior and make this more resilient.
+ CHECK(updated_rects_.empty());
+
+ gfx::Rect rectangle_size(format.x(), format.y(),
+ format.width(), format.height());
+ updated_rects_.push_back(rectangle_size);
+ decoder_->Initialize(frame_, rectangle_size);
+ TraceContext::tracer()->PrintString("Decoder is Initialized");
+}
+
+} // namespace remoting
« no previous file with comments | « remoting/client/rectangle_update_decoder.h ('k') | remoting/remoting.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698