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

Side by Side Diff: remoting/client/rectangle_update_decoder.cc

Issue 10867039: Moved video stub implementation to RectangleUpdateDecoder. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Added DCHECK Created 8 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "remoting/client/rectangle_update_decoder.h" 5 #include "remoting/client/rectangle_update_decoder.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h" 8 #include "base/bind_helpers.h"
9 #include "base/callback.h"
10 #include "base/location.h" 9 #include "base/location.h"
11 #include "base/logging.h" 10 #include "base/logging.h"
12 #include "base/message_loop_proxy.h" 11 #include "base/message_loop_proxy.h"
13 #include "ppapi/cpp/image_data.h" 12 #include "ppapi/cpp/image_data.h"
14 #include "remoting/base/util.h" 13 #include "remoting/base/util.h"
15 #include "remoting/codec/video_decoder.h" 14 #include "remoting/codec/video_decoder.h"
16 #include "remoting/codec/video_decoder_row_based.h" 15 #include "remoting/codec/video_decoder_row_based.h"
17 #include "remoting/codec/video_decoder_vp8.h" 16 #include "remoting/codec/video_decoder_vp8.h"
18 #include "remoting/client/frame_consumer.h" 17 #include "remoting/client/frame_consumer.h"
19 #include "remoting/protocol/session_config.h" 18 #include "remoting/protocol/session_config.h"
20 19
21 using base::Passed; 20 using base::Passed;
22 using remoting::protocol::ChannelConfig; 21 using remoting::protocol::ChannelConfig;
23 using remoting::protocol::SessionConfig; 22 using remoting::protocol::SessionConfig;
24 23
25 namespace remoting { 24 namespace remoting {
26 25
26 RectangleUpdateDecoder::QueuedVideoPacket::QueuedVideoPacket(
27 scoped_ptr<VideoPacket> packet, const base::Closure& done)
Sergey Ulanov 2012/08/23 22:22:09 nit: one argument per line please when arguments a
kxing 2012/08/24 17:05:22 Done.
28 : packet(packet.release()), done(done) {
Sergey Ulanov 2012/08/23 22:22:09 nit: move done initializer to a separate line
kxing 2012/08/24 17:05:22 Done.
29 }
30
31 RectangleUpdateDecoder::QueuedVideoPacket::~QueuedVideoPacket() {
32 }
33
27 RectangleUpdateDecoder::RectangleUpdateDecoder( 34 RectangleUpdateDecoder::RectangleUpdateDecoder(
28 scoped_refptr<base::SingleThreadTaskRunner> task_runner, 35 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
36 scoped_refptr<base::SingleThreadTaskRunner> decode_task_runner,
29 scoped_refptr<FrameConsumerProxy> consumer) 37 scoped_refptr<FrameConsumerProxy> consumer)
30 : task_runner_(task_runner), 38 : main_task_runner_(main_task_runner),
39 decode_task_runner_(decode_task_runner),
31 consumer_(consumer), 40 consumer_(consumer),
32 source_size_(SkISize::Make(0, 0)), 41 source_size_(SkISize::Make(0, 0)),
33 source_dpi_(SkIPoint::Make(0, 0)), 42 source_dpi_(SkIPoint::Make(0, 0)),
34 view_size_(SkISize::Make(0, 0)), 43 view_size_(SkISize::Make(0, 0)),
35 clip_area_(SkIRect::MakeEmpty()), 44 clip_area_(SkIRect::MakeEmpty()),
36 paint_scheduled_(false) { 45 paint_scheduled_(false),
46 packet_being_processed_(false),
47 last_sequence_number_(0) {
37 } 48 }
38 49
39 RectangleUpdateDecoder::~RectangleUpdateDecoder() { 50 RectangleUpdateDecoder::~RectangleUpdateDecoder() {
40 } 51 }
41 52
42 void RectangleUpdateDecoder::Initialize(const SessionConfig& config) { 53 void RectangleUpdateDecoder::Initialize(const SessionConfig& config) {
43 // Initialize decoder based on the selected codec. 54 // Initialize decoder based on the selected codec.
44 ChannelConfig::Codec codec = config.video_config().codec; 55 ChannelConfig::Codec codec = config.video_config().codec;
45 if (codec == ChannelConfig::CODEC_VERBATIM) { 56 if (codec == ChannelConfig::CODEC_VERBATIM) {
46 decoder_.reset(DecoderRowBased::CreateVerbatimDecoder()); 57 decoder_.reset(DecoderRowBased::CreateVerbatimDecoder());
47 } else if (codec == ChannelConfig::CODEC_ZIP) { 58 } else if (codec == ChannelConfig::CODEC_ZIP) {
48 decoder_.reset(DecoderRowBased::CreateZlibDecoder()); 59 decoder_.reset(DecoderRowBased::CreateZlibDecoder());
49 } else if (codec == ChannelConfig::CODEC_VP8) { 60 } else if (codec == ChannelConfig::CODEC_VP8) {
50 decoder_.reset(new DecoderVp8()); 61 decoder_.reset(new DecoderVp8());
51 } else { 62 } else {
52 NOTREACHED() << "Invalid Encoding found: " << codec; 63 NOTREACHED() << "Invalid Encoding found: " << codec;
53 } 64 }
54 } 65 }
55 66
56 void RectangleUpdateDecoder::DecodePacket(scoped_ptr<VideoPacket> packet, 67 void RectangleUpdateDecoder::DecodePacket(scoped_ptr<VideoPacket> packet,
57 const base::Closure& done) { 68 const base::Closure& done) {
58 if (!task_runner_->BelongsToCurrentThread()) { 69 if (!decode_task_runner_->BelongsToCurrentThread()) {
Sergey Ulanov 2012/08/23 22:22:09 Better to PostTask() in DispatchPacket() and here
kxing 2012/08/24 17:05:22 Done.
59 task_runner_->PostTask( 70 decode_task_runner_->PostTask(
60 FROM_HERE, base::Bind(&RectangleUpdateDecoder::DecodePacket, 71 FROM_HERE, base::Bind(&RectangleUpdateDecoder::DecodePacket,
61 this, base::Passed(&packet), done)); 72 this, base::Passed(&packet), done));
62 return; 73 return;
63 } 74 }
64 75
65 base::ScopedClosureRunner done_runner(done); 76 base::ScopedClosureRunner done_runner(done);
66 bool decoder_needs_reset = false; 77 bool decoder_needs_reset = false;
67 bool notify_size_or_dpi_change = false; 78 bool notify_size_or_dpi_change = false;
68 79
69 // If the packet includes screen size or DPI information, store them. 80 // If the packet includes screen size or DPI information, store them.
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 } 113 }
103 114
104 if (decoder_->DecodePacket(packet.get()) == Decoder::DECODE_DONE) 115 if (decoder_->DecodePacket(packet.get()) == Decoder::DECODE_DONE)
105 SchedulePaint(); 116 SchedulePaint();
106 } 117 }
107 118
108 void RectangleUpdateDecoder::SchedulePaint() { 119 void RectangleUpdateDecoder::SchedulePaint() {
109 if (paint_scheduled_) 120 if (paint_scheduled_)
110 return; 121 return;
111 paint_scheduled_ = true; 122 paint_scheduled_ = true;
112 task_runner_->PostTask( 123 decode_task_runner_->PostTask(
113 FROM_HERE, base::Bind(&RectangleUpdateDecoder::DoPaint, this)); 124 FROM_HERE, base::Bind(&RectangleUpdateDecoder::DoPaint, this));
114 } 125 }
115 126
116 void RectangleUpdateDecoder::DoPaint() { 127 void RectangleUpdateDecoder::DoPaint() {
117 DCHECK(paint_scheduled_); 128 DCHECK(paint_scheduled_);
118 paint_scheduled_ = false; 129 paint_scheduled_ = false;
119 130
120 // If the view size is empty or we have no output buffers ready, return. 131 // If the view size is empty or we have no output buffers ready, return.
121 if (buffers_.empty() || view_size_.isEmpty()) 132 if (buffers_.empty() || view_size_.isEmpty())
122 return; 133 return;
(...skipping 11 matching lines...) Expand all
134 &output_region); 145 &output_region);
135 146
136 // Notify the consumer that painting is done. 147 // Notify the consumer that painting is done.
137 if (!output_region.isEmpty()) { 148 if (!output_region.isEmpty()) {
138 buffers_.pop_front(); 149 buffers_.pop_front();
139 consumer_->ApplyBuffer(view_size_, clip_area_, buffer, output_region); 150 consumer_->ApplyBuffer(view_size_, clip_area_, buffer, output_region);
140 } 151 }
141 } 152 }
142 153
143 void RectangleUpdateDecoder::RequestReturnBuffers(const base::Closure& done) { 154 void RectangleUpdateDecoder::RequestReturnBuffers(const base::Closure& done) {
144 if (!task_runner_->BelongsToCurrentThread()) { 155 if (!decode_task_runner_->BelongsToCurrentThread()) {
145 task_runner_->PostTask( 156 decode_task_runner_->PostTask(
146 FROM_HERE, base::Bind(&RectangleUpdateDecoder::RequestReturnBuffers, 157 FROM_HERE, base::Bind(&RectangleUpdateDecoder::RequestReturnBuffers,
147 this, done)); 158 this, done));
148 return; 159 return;
149 } 160 }
150 161
151 while (!buffers_.empty()) { 162 while (!buffers_.empty()) {
152 consumer_->ReturnBuffer(buffers_.front()); 163 consumer_->ReturnBuffer(buffers_.front());
153 buffers_.pop_front(); 164 buffers_.pop_front();
154 } 165 }
155 166
156 if (!done.is_null()) 167 if (!done.is_null())
157 done.Run(); 168 done.Run();
158 } 169 }
159 170
160 void RectangleUpdateDecoder::DrawBuffer(pp::ImageData* buffer) { 171 void RectangleUpdateDecoder::DrawBuffer(pp::ImageData* buffer) {
161 if (!task_runner_->BelongsToCurrentThread()) { 172 if (!decode_task_runner_->BelongsToCurrentThread()) {
162 task_runner_->PostTask( 173 decode_task_runner_->PostTask(
163 FROM_HERE, base::Bind(&RectangleUpdateDecoder::DrawBuffer, 174 FROM_HERE, base::Bind(&RectangleUpdateDecoder::DrawBuffer,
164 this, buffer)); 175 this, buffer));
165 return; 176 return;
166 } 177 }
167 178
168 DCHECK(clip_area_.width() <= buffer->size().width() && 179 DCHECK(clip_area_.width() <= buffer->size().width() &&
169 clip_area_.height() <= buffer->size().height()); 180 clip_area_.height() <= buffer->size().height());
170 181
171 buffers_.push_back(buffer); 182 buffers_.push_back(buffer);
172 SchedulePaint(); 183 SchedulePaint();
173 } 184 }
174 185
175 void RectangleUpdateDecoder::InvalidateRegion(const SkRegion& region) { 186 void RectangleUpdateDecoder::InvalidateRegion(const SkRegion& region) {
176 if (!task_runner_->BelongsToCurrentThread()) { 187 if (!decode_task_runner_->BelongsToCurrentThread()) {
177 task_runner_->PostTask( 188 decode_task_runner_->PostTask(
178 FROM_HERE, base::Bind(&RectangleUpdateDecoder::InvalidateRegion, 189 FROM_HERE, base::Bind(&RectangleUpdateDecoder::InvalidateRegion,
179 this, region)); 190 this, region));
180 return; 191 return;
181 } 192 }
182 193
183 if (decoder_.get()) { 194 if (decoder_.get()) {
184 decoder_->Invalidate(view_size_, region); 195 decoder_->Invalidate(view_size_, region);
185 SchedulePaint(); 196 SchedulePaint();
186 } 197 }
187 } 198 }
188 199
189 void RectangleUpdateDecoder::SetOutputSizeAndClip(const SkISize& view_size, 200 void RectangleUpdateDecoder::SetOutputSizeAndClip(const SkISize& view_size,
190 const SkIRect& clip_area) { 201 const SkIRect& clip_area) {
191 if (!task_runner_->BelongsToCurrentThread()) { 202 if (!decode_task_runner_->BelongsToCurrentThread()) {
192 task_runner_->PostTask( 203 decode_task_runner_->PostTask(
193 FROM_HERE, base::Bind(&RectangleUpdateDecoder::SetOutputSizeAndClip, 204 FROM_HERE, base::Bind(&RectangleUpdateDecoder::SetOutputSizeAndClip,
194 this, view_size, clip_area)); 205 this, view_size, clip_area));
195 return; 206 return;
196 } 207 }
197 208
198 // The whole frame needs to be repainted if the scaling factor has changed. 209 // The whole frame needs to be repainted if the scaling factor has changed.
199 if (view_size_ != view_size && decoder_.get()) { 210 if (view_size_ != view_size && decoder_.get()) {
200 SkRegion region; 211 SkRegion region;
201 region.op(SkIRect::MakeSize(view_size), SkRegion::kUnion_Op); 212 region.op(SkIRect::MakeSize(view_size), SkRegion::kUnion_Op);
202 decoder_->Invalidate(view_size, region); 213 decoder_->Invalidate(view_size, region);
(...skipping 15 matching lines...) Expand all
218 i = buffers_.erase(i); 229 i = buffers_.erase(i);
219 } else { 230 } else {
220 ++i; 231 ++i;
221 } 232 }
222 } 233 }
223 234
224 SchedulePaint(); 235 SchedulePaint();
225 } 236 }
226 } 237 }
227 238
239 void RectangleUpdateDecoder::ProcessVideoPacket(scoped_ptr<VideoPacket> packet,
240 const base::Closure& done) {
Sergey Ulanov 2012/08/23 22:22:09 nit: indentation
kxing 2012/08/24 17:05:22 Done.
241 DCHECK(main_task_runner_->BelongsToCurrentThread());
242
243 // If the video packet is empty then drop it. Empty packets are used to
244 // maintain activity on the network.
245 if (!packet->has_data() || packet->data().size() == 0) {
246 done.Run();
247 return;
248 }
249
250 // Add one frame to the counter.
251 stats_.video_frame_rate()->Record(1);
252
253 // Record other statistics received from host.
254 stats_.video_bandwidth()->Record(packet->data().size());
255 if (packet->has_capture_time_ms())
256 stats_.video_capture_ms()->Record(packet->capture_time_ms());
257 if (packet->has_encode_time_ms())
258 stats_.video_encode_ms()->Record(packet->encode_time_ms());
259 if (packet->has_client_sequence_number() &&
260 packet->client_sequence_number() > last_sequence_number_) {
261 last_sequence_number_ = packet->client_sequence_number();
262 base::TimeDelta round_trip_latency =
263 base::Time::Now() -
264 base::Time::FromInternalValue(packet->client_sequence_number());
265 stats_.round_trip_ms()->Record(round_trip_latency.InMilliseconds());
266 }
267
268 received_packets_.push_back(QueuedVideoPacket(packet.Pass(), done));
269 if (!packet_being_processed_)
270 DispatchPacket();
271 }
272
273 int RectangleUpdateDecoder::GetPendingVideoPackets() {
274 DCHECK(main_task_runner_->BelongsToCurrentThread());
275 return received_packets_.size();
276 }
277
278 void RectangleUpdateDecoder::DropAllPackets() {
Sergey Ulanov 2012/08/23 22:22:09 I think we no longer need this method. (we needed
kxing 2012/08/24 17:05:22 I'll let someone do this in a separate CL.
279 DCHECK(main_task_runner_->BelongsToCurrentThread());
280
281 while(!received_packets_.empty()) {
282 delete received_packets_.front().packet;
283 received_packets_.front().done.Run();
284 received_packets_.pop_front();
285 }
286 }
287
288 void RectangleUpdateDecoder::DispatchPacket() {
Wez 2012/08/23 22:10:48 nit: Rename to ProcessNextPacket?
kxing 2012/08/24 17:05:22 Done.
289 DCHECK(main_task_runner_->BelongsToCurrentThread());
290 CHECK(!packet_being_processed_);
291
292 if (received_packets_.empty()) {
293 // Nothing to do!
294 return;
295 }
296
297 scoped_ptr<VideoPacket> packet(received_packets_.front().packet);
298 received_packets_.front().packet = NULL;
299 packet_being_processed_ = true;
300
301 // Measure the latency between the last packet being received and presented.
302 bool last_packet = (packet->flags() & VideoPacket::LAST_PACKET) != 0;
303 base::Time decode_start;
304 if (last_packet)
305 decode_start = base::Time::Now();
306
307 DecodePacket(
308 packet.Pass(),
309 base::Bind(&RectangleUpdateDecoder::OnPacketDone, base::Unretained(this),
Sergey Ulanov 2012/08/23 22:22:09 Why do you need Unretained() here? This object is
kxing 2012/08/24 17:05:22 Done.
310 last_packet, decode_start));
311 }
312
313 void RectangleUpdateDecoder::OnPacketDone(bool last_packet,
314 base::Time decode_start) {
Sergey Ulanov 2012/08/23 22:22:09 nit: indentation
kxing 2012/08/24 17:05:22 Done.
315 if (!main_task_runner_->BelongsToCurrentThread()) {
316 main_task_runner_->PostTask(FROM_HERE, base::Bind(
317 &RectangleUpdateDecoder::OnPacketDone, base::Unretained(this),
318 last_packet, decode_start));
319 return;
320 }
321
322 // Record the latency between the final packet being received and
323 // presented.
324 if (last_packet) {
325 stats_.video_decode_ms()->Record(
326 (base::Time::Now() - decode_start).InMilliseconds());
327 }
328
329 received_packets_.front().done.Run();
330 received_packets_.pop_front();
331
332 packet_being_processed_ = false;
333
334 // Process the next video packet.
335 DispatchPacket();
336 }
337
338 ChromotingStats* RectangleUpdateDecoder::GetStats() {
339 DCHECK(main_task_runner_->BelongsToCurrentThread());
340 return &stats_;
341 }
342
228 } // namespace remoting 343 } // namespace remoting
OLDNEW
« remoting/client/rectangle_update_decoder.h ('K') | « remoting/client/rectangle_update_decoder.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698