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

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: Addressed comment Created 8 years, 4 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
« no previous file with comments | « remoting/client/rectangle_update_decoder.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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,
28 const base::Closure& done)
29 : packet(packet.release()),
30 done(done) {
31 }
32
33 RectangleUpdateDecoder::QueuedVideoPacket::~QueuedVideoPacket() {
34 }
35
27 RectangleUpdateDecoder::RectangleUpdateDecoder( 36 RectangleUpdateDecoder::RectangleUpdateDecoder(
28 scoped_refptr<base::SingleThreadTaskRunner> task_runner, 37 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
38 scoped_refptr<base::SingleThreadTaskRunner> decode_task_runner,
29 scoped_refptr<FrameConsumerProxy> consumer) 39 scoped_refptr<FrameConsumerProxy> consumer)
30 : task_runner_(task_runner), 40 : main_task_runner_(main_task_runner),
41 decode_task_runner_(decode_task_runner),
31 consumer_(consumer), 42 consumer_(consumer),
32 source_size_(SkISize::Make(0, 0)), 43 source_size_(SkISize::Make(0, 0)),
33 source_dpi_(SkIPoint::Make(0, 0)), 44 source_dpi_(SkIPoint::Make(0, 0)),
34 view_size_(SkISize::Make(0, 0)), 45 view_size_(SkISize::Make(0, 0)),
35 clip_area_(SkIRect::MakeEmpty()), 46 clip_area_(SkIRect::MakeEmpty()),
36 paint_scheduled_(false) { 47 paint_scheduled_(false),
48 packet_being_processed_(false),
49 latest_sequence_number_(0) {
37 } 50 }
38 51
39 RectangleUpdateDecoder::~RectangleUpdateDecoder() { 52 RectangleUpdateDecoder::~RectangleUpdateDecoder() {
40 } 53 }
41 54
42 void RectangleUpdateDecoder::Initialize(const SessionConfig& config) { 55 void RectangleUpdateDecoder::Initialize(const SessionConfig& config) {
43 // Initialize decoder based on the selected codec. 56 // Initialize decoder based on the selected codec.
44 ChannelConfig::Codec codec = config.video_config().codec; 57 ChannelConfig::Codec codec = config.video_config().codec;
45 if (codec == ChannelConfig::CODEC_VERBATIM) { 58 if (codec == ChannelConfig::CODEC_VERBATIM) {
46 decoder_.reset(VideoDecoderRowBased::CreateVerbatimDecoder()); 59 decoder_.reset(VideoDecoderRowBased::CreateVerbatimDecoder());
47 } else if (codec == ChannelConfig::CODEC_ZIP) { 60 } else if (codec == ChannelConfig::CODEC_ZIP) {
48 decoder_.reset(VideoDecoderRowBased::CreateZlibDecoder()); 61 decoder_.reset(VideoDecoderRowBased::CreateZlibDecoder());
49 } else if (codec == ChannelConfig::CODEC_VP8) { 62 } else if (codec == ChannelConfig::CODEC_VP8) {
50 decoder_.reset(new VideoDecoderVp8()); 63 decoder_.reset(new VideoDecoderVp8());
51 } else { 64 } else {
52 NOTREACHED() << "Invalid Encoding found: " << codec; 65 NOTREACHED() << "Invalid Encoding found: " << codec;
53 } 66 }
54 } 67 }
55 68
56 void RectangleUpdateDecoder::DecodePacket(scoped_ptr<VideoPacket> packet, 69 void RectangleUpdateDecoder::DecodePacket(scoped_ptr<VideoPacket> packet,
57 const base::Closure& done) { 70 const base::Closure& done) {
58 if (!task_runner_->BelongsToCurrentThread()) { 71 DCHECK(decode_task_runner_->BelongsToCurrentThread());
59 task_runner_->PostTask(
60 FROM_HERE, base::Bind(&RectangleUpdateDecoder::DecodePacket,
61 this, base::Passed(&packet), done));
62 return;
63 }
64 72
65 base::ScopedClosureRunner done_runner(done); 73 base::ScopedClosureRunner done_runner(done);
66 bool decoder_needs_reset = false; 74 bool decoder_needs_reset = false;
67 bool notify_size_or_dpi_change = false; 75 bool notify_size_or_dpi_change = false;
68 76
69 // If the packet includes screen size or DPI information, store them. 77 // If the packet includes screen size or DPI information, store them.
70 if (packet->format().has_screen_width() && 78 if (packet->format().has_screen_width() &&
71 packet->format().has_screen_height()) { 79 packet->format().has_screen_height()) {
72 SkISize source_size = SkISize::Make(packet->format().screen_width(), 80 SkISize source_size = SkISize::Make(packet->format().screen_width(),
73 packet->format().screen_height()); 81 packet->format().screen_height());
(...skipping 28 matching lines...) Expand all
102 } 110 }
103 111
104 if (decoder_->DecodePacket(packet.get()) == VideoDecoder::DECODE_DONE) 112 if (decoder_->DecodePacket(packet.get()) == VideoDecoder::DECODE_DONE)
105 SchedulePaint(); 113 SchedulePaint();
106 } 114 }
107 115
108 void RectangleUpdateDecoder::SchedulePaint() { 116 void RectangleUpdateDecoder::SchedulePaint() {
109 if (paint_scheduled_) 117 if (paint_scheduled_)
110 return; 118 return;
111 paint_scheduled_ = true; 119 paint_scheduled_ = true;
112 task_runner_->PostTask( 120 decode_task_runner_->PostTask(
113 FROM_HERE, base::Bind(&RectangleUpdateDecoder::DoPaint, this)); 121 FROM_HERE, base::Bind(&RectangleUpdateDecoder::DoPaint, this));
114 } 122 }
115 123
116 void RectangleUpdateDecoder::DoPaint() { 124 void RectangleUpdateDecoder::DoPaint() {
117 DCHECK(paint_scheduled_); 125 DCHECK(paint_scheduled_);
118 paint_scheduled_ = false; 126 paint_scheduled_ = false;
119 127
120 // If the view size is empty or we have no output buffers ready, return. 128 // If the view size is empty or we have no output buffers ready, return.
121 if (buffers_.empty() || view_size_.isEmpty()) 129 if (buffers_.empty() || view_size_.isEmpty())
122 return; 130 return;
(...skipping 11 matching lines...) Expand all
134 &output_region); 142 &output_region);
135 143
136 // Notify the consumer that painting is done. 144 // Notify the consumer that painting is done.
137 if (!output_region.isEmpty()) { 145 if (!output_region.isEmpty()) {
138 buffers_.pop_front(); 146 buffers_.pop_front();
139 consumer_->ApplyBuffer(view_size_, clip_area_, buffer, output_region); 147 consumer_->ApplyBuffer(view_size_, clip_area_, buffer, output_region);
140 } 148 }
141 } 149 }
142 150
143 void RectangleUpdateDecoder::RequestReturnBuffers(const base::Closure& done) { 151 void RectangleUpdateDecoder::RequestReturnBuffers(const base::Closure& done) {
144 if (!task_runner_->BelongsToCurrentThread()) { 152 if (!decode_task_runner_->BelongsToCurrentThread()) {
145 task_runner_->PostTask( 153 decode_task_runner_->PostTask(
146 FROM_HERE, base::Bind(&RectangleUpdateDecoder::RequestReturnBuffers, 154 FROM_HERE, base::Bind(&RectangleUpdateDecoder::RequestReturnBuffers,
147 this, done)); 155 this, done));
148 return; 156 return;
149 } 157 }
150 158
151 while (!buffers_.empty()) { 159 while (!buffers_.empty()) {
152 consumer_->ReturnBuffer(buffers_.front()); 160 consumer_->ReturnBuffer(buffers_.front());
153 buffers_.pop_front(); 161 buffers_.pop_front();
154 } 162 }
155 163
156 if (!done.is_null()) 164 if (!done.is_null())
157 done.Run(); 165 done.Run();
158 } 166 }
159 167
160 void RectangleUpdateDecoder::DrawBuffer(pp::ImageData* buffer) { 168 void RectangleUpdateDecoder::DrawBuffer(pp::ImageData* buffer) {
161 if (!task_runner_->BelongsToCurrentThread()) { 169 if (!decode_task_runner_->BelongsToCurrentThread()) {
162 task_runner_->PostTask( 170 decode_task_runner_->PostTask(
163 FROM_HERE, base::Bind(&RectangleUpdateDecoder::DrawBuffer, 171 FROM_HERE, base::Bind(&RectangleUpdateDecoder::DrawBuffer,
164 this, buffer)); 172 this, buffer));
165 return; 173 return;
166 } 174 }
167 175
168 DCHECK(clip_area_.width() <= buffer->size().width() && 176 DCHECK(clip_area_.width() <= buffer->size().width() &&
169 clip_area_.height() <= buffer->size().height()); 177 clip_area_.height() <= buffer->size().height());
170 178
171 buffers_.push_back(buffer); 179 buffers_.push_back(buffer);
172 SchedulePaint(); 180 SchedulePaint();
173 } 181 }
174 182
175 void RectangleUpdateDecoder::InvalidateRegion(const SkRegion& region) { 183 void RectangleUpdateDecoder::InvalidateRegion(const SkRegion& region) {
176 if (!task_runner_->BelongsToCurrentThread()) { 184 if (!decode_task_runner_->BelongsToCurrentThread()) {
177 task_runner_->PostTask( 185 decode_task_runner_->PostTask(
178 FROM_HERE, base::Bind(&RectangleUpdateDecoder::InvalidateRegion, 186 FROM_HERE, base::Bind(&RectangleUpdateDecoder::InvalidateRegion,
179 this, region)); 187 this, region));
180 return; 188 return;
181 } 189 }
182 190
183 if (decoder_.get()) { 191 if (decoder_.get()) {
184 decoder_->Invalidate(view_size_, region); 192 decoder_->Invalidate(view_size_, region);
185 SchedulePaint(); 193 SchedulePaint();
186 } 194 }
187 } 195 }
188 196
189 void RectangleUpdateDecoder::SetOutputSizeAndClip(const SkISize& view_size, 197 void RectangleUpdateDecoder::SetOutputSizeAndClip(const SkISize& view_size,
190 const SkIRect& clip_area) { 198 const SkIRect& clip_area) {
191 if (!task_runner_->BelongsToCurrentThread()) { 199 if (!decode_task_runner_->BelongsToCurrentThread()) {
192 task_runner_->PostTask( 200 decode_task_runner_->PostTask(
193 FROM_HERE, base::Bind(&RectangleUpdateDecoder::SetOutputSizeAndClip, 201 FROM_HERE, base::Bind(&RectangleUpdateDecoder::SetOutputSizeAndClip,
194 this, view_size, clip_area)); 202 this, view_size, clip_area));
195 return; 203 return;
196 } 204 }
197 205
198 // The whole frame needs to be repainted if the scaling factor has changed. 206 // The whole frame needs to be repainted if the scaling factor has changed.
199 if (view_size_ != view_size && decoder_.get()) { 207 if (view_size_ != view_size && decoder_.get()) {
200 SkRegion region; 208 SkRegion region;
201 region.op(SkIRect::MakeSize(view_size), SkRegion::kUnion_Op); 209 region.op(SkIRect::MakeSize(view_size), SkRegion::kUnion_Op);
202 decoder_->Invalidate(view_size, region); 210 decoder_->Invalidate(view_size, region);
(...skipping 15 matching lines...) Expand all
218 i = buffers_.erase(i); 226 i = buffers_.erase(i);
219 } else { 227 } else {
220 ++i; 228 ++i;
221 } 229 }
222 } 230 }
223 231
224 SchedulePaint(); 232 SchedulePaint();
225 } 233 }
226 } 234 }
227 235
236 void RectangleUpdateDecoder::ProcessVideoPacket(scoped_ptr<VideoPacket> packet,
237 const base::Closure& done) {
238 DCHECK(main_task_runner_->BelongsToCurrentThread());
239
240 // If the video packet is empty then drop it. Empty packets are used to
241 // maintain activity on the network.
242 if (!packet->has_data() || packet->data().size() == 0) {
243 done.Run();
244 return;
245 }
246
247 // Add one frame to the counter.
248 stats_.video_frame_rate()->Record(1);
249
250 // Record other statistics received from host.
251 stats_.video_bandwidth()->Record(packet->data().size());
252 if (packet->has_capture_time_ms())
253 stats_.video_capture_ms()->Record(packet->capture_time_ms());
254 if (packet->has_encode_time_ms())
255 stats_.video_encode_ms()->Record(packet->encode_time_ms());
256 if (packet->has_client_sequence_number() &&
257 packet->client_sequence_number() > latest_sequence_number_) {
258 latest_sequence_number_ = packet->client_sequence_number();
259 base::TimeDelta round_trip_latency =
260 base::Time::Now() -
261 base::Time::FromInternalValue(packet->client_sequence_number());
262 stats_.round_trip_ms()->Record(round_trip_latency.InMilliseconds());
263 }
264
265 received_packets_.push_back(QueuedVideoPacket(packet.Pass(), done));
266 if (!packet_being_processed_)
267 ProcessNextPacket();
268 }
269
270 int RectangleUpdateDecoder::GetPendingVideoPackets() {
271 DCHECK(main_task_runner_->BelongsToCurrentThread());
272 return received_packets_.size();
273 }
274
275 void RectangleUpdateDecoder::DropAllPackets() {
276 DCHECK(main_task_runner_->BelongsToCurrentThread());
277
278 while(!received_packets_.empty()) {
279 delete received_packets_.front().packet;
280 received_packets_.front().done.Run();
281 received_packets_.pop_front();
282 }
283 }
284
285 void RectangleUpdateDecoder::ProcessNextPacket() {
286 DCHECK(main_task_runner_->BelongsToCurrentThread());
287 CHECK(!packet_being_processed_);
288
289 if (received_packets_.empty()) {
290 // Nothing to do!
291 return;
292 }
293
294 scoped_ptr<VideoPacket> packet(received_packets_.front().packet);
295 received_packets_.front().packet = NULL;
296 packet_being_processed_ = true;
297
298 // Measure the latency between the last packet being received and presented.
299 bool last_packet = (packet->flags() & VideoPacket::LAST_PACKET) != 0;
300 base::Time decode_start;
301 if (last_packet)
302 decode_start = base::Time::Now();
303
304 base::Closure callback = base::Bind(&RectangleUpdateDecoder::OnPacketDone,
305 this,
306 last_packet,
307 decode_start);
308
309 decode_task_runner_->PostTask(FROM_HERE, base::Bind(
310 &RectangleUpdateDecoder::DecodePacket, this,
311 base::Passed(&packet), callback));
312 }
313
314 void RectangleUpdateDecoder::OnPacketDone(bool last_packet,
315 base::Time decode_start) {
316 if (!main_task_runner_->BelongsToCurrentThread()) {
317 main_task_runner_->PostTask(FROM_HERE, base::Bind(
318 &RectangleUpdateDecoder::OnPacketDone, this,
319 last_packet, decode_start));
320 return;
321 }
322
323 // Record the latency between the final packet being received and
324 // presented.
325 if (last_packet) {
326 stats_.video_decode_ms()->Record(
327 (base::Time::Now() - decode_start).InMilliseconds());
328 }
329
330 received_packets_.front().done.Run();
331 received_packets_.pop_front();
332
333 packet_being_processed_ = false;
334
335 // Process the next video packet.
336 ProcessNextPacket();
337 }
338
339 ChromotingStats* RectangleUpdateDecoder::GetStats() {
340 DCHECK(main_task_runner_->BelongsToCurrentThread());
341 return &stats_;
342 }
343
228 } // namespace remoting 344 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/client/rectangle_update_decoder.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698