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

Side by Side 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, 2 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 unified diff | Download patch
« no previous file with comments | « remoting/client/rectangle_update_decoder.h ('k') | remoting/remoting.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "remoting/client/rectangle_update_decoder.h"
6
7 #include "base/logging.h"
8 #include "base/message_loop.h"
9 #include "media/base/callback.h"
10 #include "remoting/base/decoder.h"
11 #include "remoting/base/decoder_verbatim.h"
12 #include "remoting/base/decoder_zlib.h"
13 #include "remoting/base/protocol/chromotocol.pb.h"
14 #include "remoting/base/tracer.h"
15 #include "remoting/client/frame_consumer.h"
16
17 using media::AutoTaskRunner;
18
19 namespace remoting {
20
21 namespace {
22
23 class PartialFrameCleanup : public Task {
24 public:
25 PartialFrameCleanup(media::VideoFrame* frame, UpdatedRects* rects)
26 : frame_(frame), rects_(rects) {
27 }
28
29 virtual void Run() {
30 delete rects_;
31 frame_ = NULL;
32 }
33
34 private:
35 scoped_refptr<media::VideoFrame> frame_;
36 UpdatedRects* rects_;
37 };
38
39 } // namespace
40
41 RectangleUpdateDecoder::RectangleUpdateDecoder(MessageLoop* message_loop,
42 FrameConsumer* consumer)
43 : message_loop_(message_loop),
44 consumer_(consumer) {
45 }
46
47 RectangleUpdateDecoder::~RectangleUpdateDecoder() {
48 }
49
50 void RectangleUpdateDecoder::DecodePacket(const RectangleUpdatePacket& packet,
51 Task* done) {
52 if (message_loop_ != MessageLoop::current()) {
53 message_loop_->PostTask(
54 FROM_HERE,
55 NewTracedMethod(this,
56 &RectangleUpdateDecoder::DecodePacket, packet,
57 done));
58 return;
59 }
60 AutoTaskRunner done_runner(done);
61
62 TraceContext::tracer()->PrintString("Decode Packet called.");
63
64 if (!IsValidPacket(packet)) {
65 LOG(ERROR) << "Received invalid packet.";
66 return;
67 }
68
69 Task* process_packet_data =
70 NewTracedMethod(this,
71 &RectangleUpdateDecoder::ProcessPacketData,
72 packet, done_runner.release());
73
74 if (packet.flags() | RectangleUpdatePacket::FIRST_PACKET) {
75 const RectangleFormat& format = packet.format();
76
77 InitializeDecoder(format, process_packet_data);
78 } else {
79 process_packet_data->Run();
80 delete process_packet_data;
81 }
82 }
83
84 void RectangleUpdateDecoder::ProcessPacketData(
85 const RectangleUpdatePacket& packet,
86 Task* done) {
87 AutoTaskRunner done_runner(done);
88
89 if (!decoder_->IsReadyForData()) {
90 // TODO(ajwong): This whole thing should move into an invalid state.
91 LOG(ERROR) << "Decoder is unable to process data. Dropping packet.";
92 return;
93 }
94
95 TraceContext::tracer()->PrintString("Executing Decode.");
96 decoder_->DecodeBytes(packet.encoded_rect());
97
98 if (packet.flags() | RectangleUpdatePacket::LAST_PACKET) {
99 decoder_->Reset();
100
101 UpdatedRects* rects = new UpdatedRects();
102
103 // Empty out the list of current updated rects so the decoder can keep
104 // writing new ones while these are processed.
105 rects->swap(updated_rects_);
106
107 consumer_->OnPartialFrameOutput(frame_, rects,
108 new PartialFrameCleanup(frame_, rects));
109 }
110 }
111
112 // static
113 bool RectangleUpdateDecoder::IsValidPacket(
114 const RectangleUpdatePacket& packet) {
115 if (!packet.IsInitialized()) {
116 LOG(WARNING) << "Protobuf consistency checks fail.";
117 return false;
118 }
119
120 // First packet must have a format.
121 if (packet.flags() | RectangleUpdatePacket::FIRST_PACKET) {
122 if (!packet.has_format()) {
123 LOG(WARNING) << "First packet must have format.";
124 return false;
125 }
126
127 // TODO(ajwong): Verify that we don't need to whitelist encodings.
128 const RectangleFormat& format = packet.format();
129 if (!format.has_encoding() ||
130 format.encoding() == EncodingInvalid) {
131 LOG(WARNING) << "Invalid encoding specified.";
132 return false;
133 }
134 }
135
136 // We shouldn't generate null packets.
137 if (!packet.has_encoded_rect()) {
138 LOG(WARNING) << "Packet w/o an encoded rectangle received.";
139 return false;
140 }
141
142 return true;
143 }
144
145 void RectangleUpdateDecoder::InitializeDecoder(const RectangleFormat& format,
146 Task* done) {
147 if (message_loop_ != MessageLoop::current()) {
148 message_loop_->PostTask(
149 FROM_HERE,
150 NewTracedMethod(this,
151 &RectangleUpdateDecoder::InitializeDecoder,
152 format, done));
153 return;
154 }
155 AutoTaskRunner done_runner(done);
156
157 // Check if we need to request a new frame.
158 if (!frame_ ||
159 frame_->width() < static_cast<size_t>(format.width()) ||
160 frame_->height() < static_cast<size_t>(format.height())) {
161 if (frame_) {
162 TraceContext::tracer()->PrintString("Releasing old frame.");
163 consumer_->ReleaseFrame(frame_);
164 frame_ = NULL;
165 }
166 TraceContext::tracer()->PrintString("Requesting new frame.");
167 consumer_->AllocateFrame(media::VideoFrame::RGB32,
168 format.width(), format.height(),
169 base::TimeDelta(), base::TimeDelta(),
170 &frame_,
171 NewTracedMethod(
172 this,
173 &RectangleUpdateDecoder::InitializeDecoder,
174 format,
175 done_runner.release()));
176 return;
177 }
178
179 // TODO(ajwong): We need to handle the allocator failing to create a frame
180 // and properly disable this class.
181 CHECK(frame_);
182
183 if (decoder_.get()) {
184 // TODO(ajwong): We need to handle changing decoders midstream correctly
185 // since someone may feed us a corrupt stream, or manually create a
186 // stream that changes decoders. At the very leask, we should not
187 // crash the process.
188 //
189 // For now though, assume that only one encoding is used throughout.
190 //
191 // Note, this may be as simple as just deleting the current decoder.
192 // However, we need to verify the flushing semantics of the decoder first.
193 CHECK(decoder_->Encoding() == format.encoding());
194 } else {
195 // Initialize a new decoder based on this message encoding.
196 if (format.encoding() == EncodingNone) {
197 TraceContext::tracer()->PrintString("Creating Verbatim decoder.");
198 decoder_.reset(new DecoderVerbatim());
199 } else if (format.encoding() == EncodingZlib) {
200 TraceContext::tracer()->PrintString("Creating Zlib decoder");
201 decoder_.reset(new DecoderZlib());
202 } else {
203 NOTREACHED() << "Invalid Encoding found: " << format.encoding();
204 }
205 }
206
207 // TODO(ajwong): This can happen in the face of corrupt input data. Figure
208 // out the right behavior and make this more resilient.
209 CHECK(updated_rects_.empty());
210
211 gfx::Rect rectangle_size(format.x(), format.y(),
212 format.width(), format.height());
213 updated_rects_.push_back(rectangle_size);
214 decoder_->Initialize(frame_, rectangle_size);
215 TraceContext::tracer()->PrintString("Decoder is Initialized");
216 }
217
218 } // namespace remoting
OLDNEW
« 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