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

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

Issue 136763009: Add VideoProcessor interface. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 11 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/software_video_renderer.h"
6
7 #include <list>
6 8
7 #include "base/bind.h" 9 #include "base/bind.h"
8 #include "base/callback.h" 10 #include "base/callback.h"
9 #include "base/callback_helpers.h" 11 #include "base/callback_helpers.h"
10 #include "base/location.h" 12 #include "base/location.h"
11 #include "base/logging.h" 13 #include "base/logging.h"
12 #include "base/single_thread_task_runner.h" 14 #include "base/single_thread_task_runner.h"
13 #include "remoting/base/util.h" 15 #include "remoting/base/util.h"
14 #include "remoting/client/frame_consumer.h" 16 #include "remoting/client/frame_consumer.h"
15 #include "remoting/codec/video_decoder.h" 17 #include "remoting/codec/video_decoder.h"
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
67 } 69 }
68 70
69 virtual const webrtc::DesktopRegion* GetImageShape() OVERRIDE { 71 virtual const webrtc::DesktopRegion* GetImageShape() OVERRIDE {
70 return parent_->GetImageShape(); 72 return parent_->GetImageShape();
71 } 73 }
72 74
73 private: 75 private:
74 scoped_ptr<VideoDecoder> parent_; 76 scoped_ptr<VideoDecoder> parent_;
75 }; 77 };
76 78
77 RectangleUpdateDecoder::RectangleUpdateDecoder( 79 class SoftwareVideoRenderer::Core {
80 public:
81 Core(scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
82 scoped_refptr<base::SingleThreadTaskRunner> decode_task_runner,
83 scoped_refptr<FrameConsumerProxy> consumer);
84 ~Core();
85
86 void Initialize(const protocol::SessionConfig& config);
87
88 void DrawBuffer(webrtc::DesktopFrame* buffer);
Wez 2014/01/22 20:17:31 nit: Do you really need the blank line above this?
Sergey Ulanov 2014/01/23 01:02:43 Done.
89 void InvalidateRegion(const webrtc::DesktopRegion& region);
90 void RequestReturnBuffers(const base::Closure& done);
91 void SetOutputSizeAndClip(
92 const webrtc::DesktopSize& view_size,
93 const webrtc::DesktopRect& clip_area);
94
95 // Decodes the contents of |packet|. DecodePacket may keep a reference to
96 // |packet| so the |packet| must remain alive and valid until |done| is
97 // executed.
98 void DecodePacket(scoped_ptr<VideoPacket> packet, const base::Closure& done);
99
100 private:
101 // Paints the invalidated region to the next available buffer and returns it
102 // to the consumer.
103 void SchedulePaint();
104 void DoPaint();
105
106 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
107 scoped_refptr<base::SingleThreadTaskRunner> decode_task_runner_;
108 scoped_refptr<FrameConsumerProxy> consumer_;
109 scoped_ptr<VideoDecoder> decoder_;
110
111 // Remote screen size in pixels.
112 webrtc::DesktopSize source_size_;
113
114 // Vertical and horizontal DPI of the remote screen.
115 webrtc::DesktopVector source_dpi_;
116
117 // The current dimensions of the frame consumer view.
118 webrtc::DesktopSize view_size_;
119 webrtc::DesktopRect clip_area_;
120
121 // The drawing buffers supplied by the frame consumer.
122 std::list<webrtc::DesktopFrame*> buffers_;
123
124 // Flag used to coalesce runs of SchedulePaint()s into a single DoPaint().
125 bool paint_scheduled_;
126
127 base::WeakPtrFactory<Core> weak_factory_;
128 };
129
130 SoftwareVideoRenderer::Core::Core(
78 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, 131 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
79 scoped_refptr<base::SingleThreadTaskRunner> decode_task_runner, 132 scoped_refptr<base::SingleThreadTaskRunner> decode_task_runner,
80 scoped_refptr<FrameConsumerProxy> consumer) 133 scoped_refptr<FrameConsumerProxy> consumer)
81 : main_task_runner_(main_task_runner), 134 : main_task_runner_(main_task_runner),
82 decode_task_runner_(decode_task_runner), 135 decode_task_runner_(decode_task_runner),
83 consumer_(consumer), 136 consumer_(consumer),
84 paint_scheduled_(false), 137 paint_scheduled_(false),
85 latest_sequence_number_(0) { 138 weak_factory_(this) {
86 } 139 }
87 140
88 RectangleUpdateDecoder::~RectangleUpdateDecoder() { 141 SoftwareVideoRenderer::Core::~Core() {
89 } 142 }
90 143
91 void RectangleUpdateDecoder::Initialize(const SessionConfig& config) { 144 void SoftwareVideoRenderer::Core::Initialize(const SessionConfig& config) {
92 if (!decode_task_runner_->BelongsToCurrentThread()) { 145 DCHECK(decode_task_runner_->BelongsToCurrentThread());
93 decode_task_runner_->PostTask(
94 FROM_HERE, base::Bind(&RectangleUpdateDecoder::Initialize, this,
95 config));
96 return;
97 }
98 146
99 // Initialize decoder based on the selected codec. 147 // Initialize decoder based on the selected codec.
100 ChannelConfig::Codec codec = config.video_config().codec; 148 ChannelConfig::Codec codec = config.video_config().codec;
101 if (codec == ChannelConfig::CODEC_VERBATIM) { 149 if (codec == ChannelConfig::CODEC_VERBATIM) {
102 decoder_.reset(new VideoDecoderVerbatim()); 150 decoder_.reset(new VideoDecoderVerbatim());
103 } else if (codec == ChannelConfig::CODEC_VP8) { 151 } else if (codec == ChannelConfig::CODEC_VP8) {
104 decoder_ = VideoDecoderVpx::CreateForVP8(); 152 decoder_ = VideoDecoderVpx::CreateForVP8();
105 } else if (codec == ChannelConfig::CODEC_VP9) { 153 } else if (codec == ChannelConfig::CODEC_VP9) {
106 decoder_ = VideoDecoderVpx::CreateForVP9(); 154 decoder_ = VideoDecoderVpx::CreateForVP9();
107 } else { 155 } else {
108 NOTREACHED() << "Invalid Encoding found: " << codec; 156 NOTREACHED() << "Invalid Encoding found: " << codec;
109 } 157 }
110 158
111 if (consumer_->GetPixelFormat() == FrameConsumer::FORMAT_RGBA) { 159 if (consumer_->GetPixelFormat() == FrameConsumer::FORMAT_RGBA) {
112 scoped_ptr<VideoDecoder> wrapper( 160 scoped_ptr<VideoDecoder> wrapper(
113 new RgbToBgrVideoDecoderFilter(decoder_.Pass())); 161 new RgbToBgrVideoDecoderFilter(decoder_.Pass()));
114 decoder_ = wrapper.Pass(); 162 decoder_ = wrapper.Pass();
115 } 163 }
116 } 164 }
117 165
118 void RectangleUpdateDecoder::DecodePacket(scoped_ptr<VideoPacket> packet, 166 void SoftwareVideoRenderer::Core::DecodePacket(scoped_ptr<VideoPacket> packet,
119 const base::Closure& done) { 167 const base::Closure& done) {
120 DCHECK(decode_task_runner_->BelongsToCurrentThread()); 168 DCHECK(decode_task_runner_->BelongsToCurrentThread());
121 169
122 base::ScopedClosureRunner done_runner(done);
123
124 bool decoder_needs_reset = false; 170 bool decoder_needs_reset = false;
125 bool notify_size_or_dpi_change = false; 171 bool notify_size_or_dpi_change = false;
126 172
127 // If the packet includes screen size or DPI information, store them. 173 // If the packet includes screen size or DPI information, store them.
128 if (packet->format().has_screen_width() && 174 if (packet->format().has_screen_width() &&
129 packet->format().has_screen_height()) { 175 packet->format().has_screen_height()) {
130 webrtc::DesktopSize source_size(packet->format().screen_width(), 176 webrtc::DesktopSize source_size(packet->format().screen_width(),
131 packet->format().screen_height()); 177 packet->format().screen_height());
132 if (!source_size_.equals(source_size)) { 178 if (!source_size_.equals(source_size)) {
133 source_size_ = source_size; 179 source_size_ = source_size;
134 decoder_needs_reset = true; 180 decoder_needs_reset = true;
135 notify_size_or_dpi_change = true; 181 notify_size_or_dpi_change = true;
136 } 182 }
137 } 183 }
138 if (packet->format().has_x_dpi() && packet->format().has_y_dpi()) { 184 if (packet->format().has_x_dpi() && packet->format().has_y_dpi()) {
139 webrtc::DesktopVector source_dpi(packet->format().x_dpi(), 185 webrtc::DesktopVector source_dpi(packet->format().x_dpi(),
140 packet->format().y_dpi()); 186 packet->format().y_dpi());
141 if (!source_dpi.equals(source_dpi_)) { 187 if (!source_dpi.equals(source_dpi_)) {
142 source_dpi_ = source_dpi; 188 source_dpi_ = source_dpi;
143 notify_size_or_dpi_change = true; 189 notify_size_or_dpi_change = true;
144 } 190 }
145 } 191 }
146 192
147 // If we've never seen a screen size, ignore the packet. 193 // If we've never seen a screen size, ignore the packet.
148 if (source_size_.is_empty()) 194 if (source_size_.is_empty()) {
195 main_task_runner_->PostTask(FROM_HERE, base::Bind(done));
149 return; 196 return;
197 }
150 198
151 if (decoder_needs_reset) 199 if (decoder_needs_reset)
152 decoder_->Initialize(source_size_); 200 decoder_->Initialize(source_size_);
153 if (notify_size_or_dpi_change) 201 if (notify_size_or_dpi_change)
154 consumer_->SetSourceSize(source_size_, source_dpi_); 202 consumer_->SetSourceSize(source_size_, source_dpi_);
155 203
156 if (decoder_->DecodePacket(*packet.get())) { 204 if (decoder_->DecodePacket(*packet.get())) {
157 SchedulePaint(); 205 SchedulePaint();
158 } else { 206 } else {
159 LOG(ERROR) << "DecodePacket() failed."; 207 LOG(ERROR) << "DecodePacket() failed.";
160 } 208 }
209
210 main_task_runner_->PostTask(FROM_HERE, base::Bind(done));
161 } 211 }
162 212
163 void RectangleUpdateDecoder::SchedulePaint() { 213 void SoftwareVideoRenderer::Core::SchedulePaint() {
214 DCHECK(decode_task_runner_->BelongsToCurrentThread());
164 if (paint_scheduled_) 215 if (paint_scheduled_)
165 return; 216 return;
166 paint_scheduled_ = true; 217 paint_scheduled_ = true;
167 decode_task_runner_->PostTask( 218 decode_task_runner_->PostTask(
168 FROM_HERE, base::Bind(&RectangleUpdateDecoder::DoPaint, this)); 219 FROM_HERE, base::Bind(&SoftwareVideoRenderer::Core::DoPaint,
220 weak_factory_.GetWeakPtr()));
169 } 221 }
170 222
171 void RectangleUpdateDecoder::DoPaint() { 223 void SoftwareVideoRenderer::Core::DoPaint() {
224 DCHECK(decode_task_runner_->BelongsToCurrentThread());
172 DCHECK(paint_scheduled_); 225 DCHECK(paint_scheduled_);
173 paint_scheduled_ = false; 226 paint_scheduled_ = false;
174 227
175 // If the view size is empty or we have no output buffers ready, return. 228 // If the view size is empty or we have no output buffers ready, return.
176 if (buffers_.empty() || view_size_.is_empty()) 229 if (buffers_.empty() || view_size_.is_empty())
177 return; 230 return;
178 231
179 // If no Decoder is initialized, or the host dimensions are empty, return. 232 // If no Decoder is initialized, or the host dimensions are empty, return.
180 if (!decoder_.get() || source_size_.is_empty()) 233 if (!decoder_.get() || source_size_.is_empty())
181 return; 234 return;
182 235
183 // Draw the invalidated region to the buffer. 236 // Draw the invalidated region to the buffer.
184 webrtc::DesktopFrame* buffer = buffers_.front(); 237 webrtc::DesktopFrame* buffer = buffers_.front();
185 webrtc::DesktopRegion output_region; 238 webrtc::DesktopRegion output_region;
186 decoder_->RenderFrame(view_size_, clip_area_, 239 decoder_->RenderFrame(view_size_, clip_area_,
187 buffer->data(), 240 buffer->data(), buffer->stride(), &output_region);
188 buffer->stride(),
189 &output_region);
190 241
191 // Notify the consumer that painting is done. 242 // Notify the consumer that painting is done.
192 if (!output_region.is_empty()) { 243 if (!output_region.is_empty()) {
193 buffers_.pop_front(); 244 buffers_.pop_front();
194 consumer_->ApplyBuffer(view_size_, clip_area_, buffer, output_region); 245 consumer_->ApplyBuffer(view_size_, clip_area_, buffer, output_region,
246 *decoder_->GetImageShape());
195 } 247 }
196 } 248 }
197 249
198 void RectangleUpdateDecoder::RequestReturnBuffers(const base::Closure& done) { 250 void SoftwareVideoRenderer::Core::RequestReturnBuffers(
199 if (!decode_task_runner_->BelongsToCurrentThread()) { 251 const base::Closure& done) {
200 decode_task_runner_->PostTask( 252 DCHECK(decode_task_runner_->BelongsToCurrentThread());
201 FROM_HERE, base::Bind(&RectangleUpdateDecoder::RequestReturnBuffers,
202 this, done));
203 return;
204 }
205 253
206 while (!buffers_.empty()) { 254 while (!buffers_.empty()) {
207 consumer_->ReturnBuffer(buffers_.front()); 255 consumer_->ReturnBuffer(buffers_.front());
208 buffers_.pop_front(); 256 buffers_.pop_front();
209 } 257 }
210 258
211 if (!done.is_null()) 259 if (!done.is_null())
212 done.Run(); 260 done.Run();
213 } 261 }
214 262
215 void RectangleUpdateDecoder::DrawBuffer(webrtc::DesktopFrame* buffer) { 263 void SoftwareVideoRenderer::Core::DrawBuffer(webrtc::DesktopFrame* buffer) {
216 if (!decode_task_runner_->BelongsToCurrentThread()) { 264 DCHECK(decode_task_runner_->BelongsToCurrentThread());
217 decode_task_runner_->PostTask(
218 FROM_HERE, base::Bind(&RectangleUpdateDecoder::DrawBuffer,
219 this, buffer));
220 return;
221 }
222
223 DCHECK(clip_area_.width() <= buffer->size().width() && 265 DCHECK(clip_area_.width() <= buffer->size().width() &&
224 clip_area_.height() <= buffer->size().height()); 266 clip_area_.height() <= buffer->size().height());
225 267
226 buffers_.push_back(buffer); 268 buffers_.push_back(buffer);
227 SchedulePaint(); 269 SchedulePaint();
228 } 270 }
229 271
230 void RectangleUpdateDecoder::InvalidateRegion( 272 void SoftwareVideoRenderer::Core::InvalidateRegion(
231 const webrtc::DesktopRegion& region) { 273 const webrtc::DesktopRegion& region) {
232 if (!decode_task_runner_->BelongsToCurrentThread()) { 274 DCHECK(decode_task_runner_->BelongsToCurrentThread());
233 decode_task_runner_->PostTask(
234 FROM_HERE, base::Bind(&RectangleUpdateDecoder::InvalidateRegion,
235 this, region));
236 return;
237 }
238 275
239 if (decoder_.get()) { 276 if (decoder_.get()) {
240 decoder_->Invalidate(view_size_, region); 277 decoder_->Invalidate(view_size_, region);
241 SchedulePaint(); 278 SchedulePaint();
242 } 279 }
243 } 280 }
244 281
245 void RectangleUpdateDecoder::SetOutputSizeAndClip( 282 void SoftwareVideoRenderer::Core::SetOutputSizeAndClip(
246 const webrtc::DesktopSize& view_size, 283 const webrtc::DesktopSize& view_size,
247 const webrtc::DesktopRect& clip_area) { 284 const webrtc::DesktopRect& clip_area) {
248 if (!decode_task_runner_->BelongsToCurrentThread()) { 285 DCHECK(decode_task_runner_->BelongsToCurrentThread());
249 decode_task_runner_->PostTask(
250 FROM_HERE, base::Bind(&RectangleUpdateDecoder::SetOutputSizeAndClip,
251 this, view_size, clip_area));
252 return;
253 }
254 286
255 // The whole frame needs to be repainted if the scaling factor has changed. 287 // The whole frame needs to be repainted if the scaling factor has changed.
256 if (!view_size_.equals(view_size) && decoder_.get()) { 288 if (!view_size_.equals(view_size) && decoder_.get()) {
257 webrtc::DesktopRegion region; 289 webrtc::DesktopRegion region;
258 region.AddRect(webrtc::DesktopRect::MakeSize(view_size)); 290 region.AddRect(webrtc::DesktopRect::MakeSize(view_size));
259 decoder_->Invalidate(view_size, region); 291 decoder_->Invalidate(view_size, region);
260 } 292 }
261 293
262 if (!view_size_.equals(view_size) || 294 if (!view_size_.equals(view_size) ||
263 !clip_area_.equals(clip_area)) { 295 !clip_area_.equals(clip_area)) {
(...skipping 10 matching lines...) Expand all
274 i = buffers_.erase(i); 306 i = buffers_.erase(i);
275 } else { 307 } else {
276 ++i; 308 ++i;
277 } 309 }
278 } 310 }
279 311
280 SchedulePaint(); 312 SchedulePaint();
281 } 313 }
282 } 314 }
283 315
284 const webrtc::DesktopRegion* RectangleUpdateDecoder::GetBufferShape() { 316 SoftwareVideoRenderer::SoftwareVideoRenderer(
285 return decoder_->GetImageShape(); 317 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
318 scoped_refptr<base::SingleThreadTaskRunner> decode_task_runner,
319 scoped_refptr<FrameConsumerProxy> consumer)
320 : decode_task_runner_(decode_task_runner),
321 core_(new Core(main_task_runner, decode_task_runner, consumer)),
322 latest_sequence_number_(0),
323 weak_factory_(this) {
324 DCHECK(CalledOnValidThread());
286 } 325 }
287 326
288 void RectangleUpdateDecoder::ProcessVideoPacket(scoped_ptr<VideoPacket> packet, 327 SoftwareVideoRenderer::~SoftwareVideoRenderer() {
328 DCHECK(CalledOnValidThread());
329 decode_task_runner_->DeleteSoon(FROM_HERE, core_.release());
330 }
331
332 void SoftwareVideoRenderer::Initialize(
333 const protocol::SessionConfig& config) {
334 DCHECK(CalledOnValidThread());
335 decode_task_runner_->PostTask(
336 FROM_HERE, base::Bind(&SoftwareVideoRenderer::Core::Initialize,
337 base::Unretained(core_.get()), config));
338 }
339
340 ChromotingStats* SoftwareVideoRenderer::GetStats() {
341 DCHECK(CalledOnValidThread());
342 return &stats_;
343 }
344
345 void SoftwareVideoRenderer::ProcessVideoPacket(scoped_ptr<VideoPacket> packet,
289 const base::Closure& done) { 346 const base::Closure& done) {
290 DCHECK(main_task_runner_->BelongsToCurrentThread()); 347 DCHECK(CalledOnValidThread());
291 348
292 // If the video packet is empty then drop it. Empty packets are used to 349 // If the video packet is empty then drop it. Empty packets are used to
293 // maintain activity on the network. 350 // maintain activity on the network.
294 if (!packet->has_data() || packet->data().size() == 0) { 351 if (!packet->has_data() || packet->data().size() == 0) {
295 done.Run(); 352 done.Run();
296 return; 353 return;
297 } 354 }
298 355
299 // Add one frame to the counter. 356 // Add one frame to the counter.
300 stats_.video_frame_rate()->Record(1); 357 stats_.video_frame_rate()->Record(1);
301 358
302 // Record other statistics received from host. 359 // Record other statistics received from host.
303 stats_.video_bandwidth()->Record(packet->data().size()); 360 stats_.video_bandwidth()->Record(packet->data().size());
304 if (packet->has_capture_time_ms()) 361 if (packet->has_capture_time_ms())
305 stats_.video_capture_ms()->Record(packet->capture_time_ms()); 362 stats_.video_capture_ms()->Record(packet->capture_time_ms());
306 if (packet->has_encode_time_ms()) 363 if (packet->has_encode_time_ms())
307 stats_.video_encode_ms()->Record(packet->encode_time_ms()); 364 stats_.video_encode_ms()->Record(packet->encode_time_ms());
308 if (packet->has_client_sequence_number() && 365 if (packet->has_client_sequence_number() &&
309 packet->client_sequence_number() > latest_sequence_number_) { 366 packet->client_sequence_number() > latest_sequence_number_) {
310 latest_sequence_number_ = packet->client_sequence_number(); 367 latest_sequence_number_ = packet->client_sequence_number();
311 base::TimeDelta round_trip_latency = 368 base::TimeDelta round_trip_latency =
312 base::Time::Now() - 369 base::Time::Now() -
313 base::Time::FromInternalValue(packet->client_sequence_number()); 370 base::Time::FromInternalValue(packet->client_sequence_number());
314 stats_.round_trip_ms()->Record(round_trip_latency.InMilliseconds()); 371 stats_.round_trip_ms()->Record(round_trip_latency.InMilliseconds());
315 } 372 }
316 373
317 // Measure the latency between the last packet being received and presented. 374 // Measure the latency between the last packet being received and presented.
318 base::Time decode_start = base::Time::Now(); 375 base::Time decode_start = base::Time::Now();
319 376
320 base::Closure decode_done = base::Bind( 377 base::Closure decode_done = base::Bind(&SoftwareVideoRenderer::OnPacketDone,
321 &RectangleUpdateDecoder::OnPacketDone, this, decode_start, done); 378 weak_factory_.GetWeakPtr(),
379 decode_start, done);
322 380
323 decode_task_runner_->PostTask(FROM_HERE, base::Bind( 381 decode_task_runner_->PostTask(FROM_HERE, base::Bind(
324 &RectangleUpdateDecoder::DecodePacket, this, 382 &SoftwareVideoRenderer::Core::DecodePacket,
325 base::Passed(&packet), decode_done)); 383 base::Unretained(core_.get()), base::Passed(&packet), decode_done));
326 } 384 }
327 385
328 void RectangleUpdateDecoder::OnPacketDone(base::Time decode_start, 386 void SoftwareVideoRenderer::DrawBuffer(webrtc::DesktopFrame* buffer) {
387 decode_task_runner_->PostTask(
388 FROM_HERE, base::Bind(&SoftwareVideoRenderer::Core::DrawBuffer,
389 base::Unretained(core_.get()), buffer));
390 }
391
392 void SoftwareVideoRenderer::InvalidateRegion(
393 const webrtc::DesktopRegion& region) {
394 decode_task_runner_->PostTask(
395 FROM_HERE, base::Bind(&SoftwareVideoRenderer::Core::InvalidateRegion,
396 base::Unretained(core_.get()), region));
397 }
398
399 void SoftwareVideoRenderer::RequestReturnBuffers(const base::Closure& done) {
400 decode_task_runner_->PostTask(
401 FROM_HERE,
402 base::Bind(&SoftwareVideoRenderer::Core::RequestReturnBuffers,
403 base::Unretained(core_.get()), done));
404 }
405
406 void SoftwareVideoRenderer::SetOutputSizeAndClip(
407 const webrtc::DesktopSize& view_size,
408 const webrtc::DesktopRect& clip_area) {
409 decode_task_runner_->PostTask(
410 FROM_HERE,
411 base::Bind(&SoftwareVideoRenderer::Core::SetOutputSizeAndClip,
412 base::Unretained(core_.get()), view_size, clip_area));
413 }
414
415 void SoftwareVideoRenderer::OnPacketDone(base::Time decode_start,
329 const base::Closure& done) { 416 const base::Closure& done) {
330 if (!main_task_runner_->BelongsToCurrentThread()) { 417 DCHECK(CalledOnValidThread());
331 main_task_runner_->PostTask(FROM_HERE, base::Bind(
332 &RectangleUpdateDecoder::OnPacketDone, this,
333 decode_start, done));
334 return;
335 }
336 418
337 // Record the latency between the packet being received and presented. 419 // Record the latency between the packet being received and presented.
338 stats_.video_decode_ms()->Record( 420 stats_.video_decode_ms()->Record(
339 (base::Time::Now() - decode_start).InMilliseconds()); 421 (base::Time::Now() - decode_start).InMilliseconds());
340 422
341 done.Run(); 423 done.Run();
342 } 424 }
343 425
344 ChromotingStats* RectangleUpdateDecoder::GetStats() {
345 DCHECK(main_task_runner_->BelongsToCurrentThread());
346 return &stats_;
347 }
348
349 } // namespace remoting 426 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698