OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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/codec/webrtc_video_encoder_vpx.h" | 5 #include "remoting/codec/webrtc_video_encoder_vpx.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 26 matching lines...) Expand all Loading... |
37 // Magic encoder profile numbers for I420 and I444 input formats. | 37 // Magic encoder profile numbers for I420 and I444 input formats. |
38 const int kVp9I420ProfileNumber = 0; | 38 const int kVp9I420ProfileNumber = 0; |
39 const int kVp9I444ProfileNumber = 1; | 39 const int kVp9I444ProfileNumber = 1; |
40 | 40 |
41 // Magic encoder constants for adaptive quantization strategy. | 41 // Magic encoder constants for adaptive quantization strategy. |
42 const int kVp9AqModeNone = 0; | 42 const int kVp9AqModeNone = 0; |
43 const int kVp9AqModeCyclicRefresh = 3; | 43 const int kVp9AqModeCyclicRefresh = 3; |
44 | 44 |
45 const int kDefaultTargetBitrateKbps = 1000; | 45 const int kDefaultTargetBitrateKbps = 1000; |
46 | 46 |
47 // Target quantizer at which stop the encoding top-off. | |
48 const int kTargetQuantizerForVp8TopOff = 30; | |
49 | |
50 void SetCommonCodecParameters(vpx_codec_enc_cfg_t* config, | 47 void SetCommonCodecParameters(vpx_codec_enc_cfg_t* config, |
51 const webrtc::DesktopSize& size) { | 48 const webrtc::DesktopSize& size) { |
52 // Use millisecond granularity time base. | 49 // Use millisecond granularity time base. |
53 config->g_timebase.num = 1; | 50 config->g_timebase.num = 1; |
54 config->g_timebase.den = base::Time::kMicrosecondsPerSecond; | 51 config->g_timebase.den = base::Time::kMicrosecondsPerSecond; |
55 | 52 |
56 config->g_w = size.width(); | 53 config->g_w = size.width(); |
57 config->g_h = size.height(); | 54 config->g_h = size.height(); |
58 config->g_pass = VPX_RC_ONE_PASS; | 55 config->g_pass = VPX_RC_ONE_PASS; |
59 | 56 |
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
275 codec_.reset(); | 272 codec_.reset(); |
276 } | 273 } |
277 } | 274 } |
278 | 275 |
279 std::unique_ptr<WebrtcVideoEncoder::EncodedFrame> WebrtcVideoEncoderVpx::Encode( | 276 std::unique_ptr<WebrtcVideoEncoder::EncodedFrame> WebrtcVideoEncoderVpx::Encode( |
280 const webrtc::DesktopFrame& frame, | 277 const webrtc::DesktopFrame& frame, |
281 const FrameParams& params) { | 278 const FrameParams& params) { |
282 DCHECK_LE(32, frame.size().width()); | 279 DCHECK_LE(32, frame.size().width()); |
283 DCHECK_LE(32, frame.size().height()); | 280 DCHECK_LE(32, frame.size().height()); |
284 | 281 |
285 // Based on information fetching active map, we return here if there is | |
286 // nothing to top-off. | |
287 if (frame.updated_region().is_empty() && !encode_unchanged_frame_ && | |
288 !params.key_frame) { | |
289 return nullptr; | |
290 } | |
291 | |
292 // Create or reconfigure the codec to match the size of |frame|. | 282 // Create or reconfigure the codec to match the size of |frame|. |
293 if (!codec_ || | 283 if (!codec_ || |
294 (image_ && | 284 (image_ && |
295 !frame.size().equals(webrtc::DesktopSize(image_->w, image_->h)))) { | 285 !frame.size().equals(webrtc::DesktopSize(image_->w, image_->h)))) { |
296 Configure(frame.size()); | 286 Configure(frame.size()); |
297 } | 287 } |
298 | 288 |
299 UpdateTargetBitrate(params.bitrate_kbps); | 289 UpdateConfig(params); |
300 | 290 |
301 vpx_active_map_t act_map; | 291 vpx_active_map_t act_map; |
302 act_map.rows = active_map_size_.height(); | 292 act_map.rows = active_map_size_.height(); |
303 act_map.cols = active_map_size_.width(); | 293 act_map.cols = active_map_size_.width(); |
304 act_map.active_map = active_map_.get(); | 294 act_map.active_map = active_map_.get(); |
305 | 295 |
306 webrtc::DesktopRegion updated_region; | 296 webrtc::DesktopRegion updated_region; |
307 if (!frame.updated_region().is_empty()) { | 297 // Convert the updated capture data ready for encode. |
308 // Convert the updated capture data ready for encode. | 298 PrepareImage(frame, &updated_region); |
309 PrepareImage(frame, &updated_region); | |
310 | 299 |
311 // Update active map based on updated region. | 300 // Update active map based on updated region. |
312 SetActiveMapFromRegion(updated_region); | 301 if (params.clear_active_map) |
| 302 ClearActiveMap(); |
| 303 SetActiveMapFromRegion(updated_region); |
313 | 304 |
314 // Apply active map to the encoder. | 305 // Apply active map to the encoder. |
315 | 306 if (vpx_codec_control(codec_.get(), VP8E_SET_ACTIVEMAP, &act_map)) { |
316 if (vpx_codec_control(codec_.get(), VP8E_SET_ACTIVEMAP, &act_map)) { | 307 LOG(ERROR) << "Unable to apply active map"; |
317 LOG(ERROR) << "Unable to apply active map"; | |
318 } | |
319 } | 308 } |
320 | 309 |
321 vpx_codec_err_t ret = vpx_codec_encode( | 310 vpx_codec_err_t ret = vpx_codec_encode( |
322 codec_.get(), image_.get(), 0, params.duration.InMicroseconds(), | 311 codec_.get(), image_.get(), 0, params.duration.InMicroseconds(), |
323 (params.key_frame) ? VPX_EFLAG_FORCE_KF : 0, VPX_DL_REALTIME); | 312 (params.key_frame) ? VPX_EFLAG_FORCE_KF : 0, VPX_DL_REALTIME); |
324 DCHECK_EQ(ret, VPX_CODEC_OK) | 313 DCHECK_EQ(ret, VPX_CODEC_OK) |
325 << "Encoding error: " << vpx_codec_err_to_string(ret) << "\n" | 314 << "Encoding error: " << vpx_codec_err_to_string(ret) << "\n" |
326 << "Details: " << vpx_codec_error(codec_.get()) << "\n" | 315 << "Details: " << vpx_codec_error(codec_.get()) << "\n" |
327 << vpx_codec_error_detail(codec_.get()); | 316 << vpx_codec_error_detail(codec_.get()); |
328 | 317 |
329 if (!lossless_encode_) { | 318 if (!lossless_encode_) { |
330 // VP8 doesn't return active map, so we assume it's the same on the output | 319 // VP8 doesn't return active map, so we assume it's the same on the output |
331 // as on the input. | 320 // as on the input. |
332 if (use_vp9_) { | 321 if (use_vp9_) { |
333 ret = vpx_codec_control(codec_.get(), VP9E_GET_ACTIVEMAP, &act_map); | 322 ret = vpx_codec_control(codec_.get(), VP9E_GET_ACTIVEMAP, &act_map); |
334 DCHECK_EQ(ret, VPX_CODEC_OK) | 323 DCHECK_EQ(ret, VPX_CODEC_OK) |
335 << "Failed to fetch active map: " << vpx_codec_err_to_string(ret) | 324 << "Failed to fetch active map: " << vpx_codec_err_to_string(ret) |
336 << "\n"; | 325 << "\n"; |
337 | |
338 // If the encoder output no changes then there's nothing left to top-off. | |
339 encode_unchanged_frame_ = !updated_region.is_empty(); | |
340 } else { | |
341 // Always set |encode_unchanged_frame_| when using VP8. It will be reset | |
342 // below once the target quantizer value is reached. | |
343 encode_unchanged_frame_ = true; | |
344 } | 326 } |
345 | 327 |
346 UpdateRegionFromActiveMap(&updated_region); | 328 UpdateRegionFromActiveMap(&updated_region); |
347 } | 329 } |
348 | 330 |
349 // Read the encoded data. | 331 // Read the encoded data. |
350 vpx_codec_iter_t iter = nullptr; | 332 vpx_codec_iter_t iter = nullptr; |
351 bool got_data = false; | 333 bool got_data = false; |
352 | 334 |
353 std::unique_ptr<EncodedFrame> encoded_frame(new EncodedFrame()); | 335 std::unique_ptr<EncodedFrame> encoded_frame(new EncodedFrame()); |
354 encoded_frame->size = frame.size(); | 336 encoded_frame->size = frame.size(); |
355 | 337 |
356 while (!got_data) { | 338 while (!got_data) { |
357 const vpx_codec_cx_pkt_t* vpx_packet = | 339 const vpx_codec_cx_pkt_t* vpx_packet = |
358 vpx_codec_get_cx_data(codec_.get(), &iter); | 340 vpx_codec_get_cx_data(codec_.get(), &iter); |
359 if (!vpx_packet) | 341 if (!vpx_packet) |
360 continue; | 342 continue; |
361 | 343 |
362 switch (vpx_packet->kind) { | 344 switch (vpx_packet->kind) { |
363 case VPX_CODEC_CX_FRAME_PKT: { | 345 case VPX_CODEC_CX_FRAME_PKT: { |
364 got_data = true; | 346 got_data = true; |
365 // TODO(sergeyu): Avoid copying the data here.. | 347 // TODO(sergeyu): Avoid copying the data here.. |
366 encoded_frame->data.assign( | 348 encoded_frame->data.assign( |
367 reinterpret_cast<const char*>(vpx_packet->data.frame.buf), | 349 reinterpret_cast<const char*>(vpx_packet->data.frame.buf), |
368 vpx_packet->data.frame.sz); | 350 vpx_packet->data.frame.sz); |
369 encoded_frame->key_frame = | 351 encoded_frame->key_frame = |
370 vpx_packet->data.frame.flags & VPX_FRAME_IS_KEY; | 352 vpx_packet->data.frame.flags & VPX_FRAME_IS_KEY; |
371 int quantizer = -1; | |
372 CHECK_EQ(vpx_codec_control(codec_.get(), VP8E_GET_LAST_QUANTIZER_64, | 353 CHECK_EQ(vpx_codec_control(codec_.get(), VP8E_GET_LAST_QUANTIZER_64, |
373 &quantizer), | 354 &(encoded_frame->quantizer)), |
374 VPX_CODEC_OK); | 355 VPX_CODEC_OK); |
375 // VP8: Stop top-off as soon as the target quantizer value is reached. | |
376 if (!use_vp9_ && quantizer <= kTargetQuantizerForVp8TopOff) | |
377 encode_unchanged_frame_ = false; | |
378 break; | 356 break; |
379 } | 357 } |
380 default: | 358 default: |
381 break; | 359 break; |
382 } | 360 } |
383 } | 361 } |
384 | 362 |
385 return encoded_frame; | 363 return encoded_frame; |
386 } | 364 } |
387 | 365 |
388 WebrtcVideoEncoderVpx::WebrtcVideoEncoderVpx(bool use_vp9) | 366 WebrtcVideoEncoderVpx::WebrtcVideoEncoderVpx(bool use_vp9) |
389 : use_vp9_(use_vp9), | 367 : use_vp9_(use_vp9), |
390 target_bitrate_kbps_(kDefaultTargetBitrateKbps), | |
391 encode_unchanged_frame_(false), | |
392 clock_(&default_tick_clock_) { | 368 clock_(&default_tick_clock_) { |
393 // Indicates config is still uninitialized. | 369 // Indicates config is still uninitialized. |
394 config_.g_timebase.den = 0; | 370 config_.g_timebase.den = 0; |
395 } | 371 } |
396 | 372 |
397 void WebrtcVideoEncoderVpx::Configure(const webrtc::DesktopSize& size) { | 373 void WebrtcVideoEncoderVpx::Configure(const webrtc::DesktopSize& size) { |
398 DCHECK(use_vp9_ || !lossless_color_); | 374 DCHECK(use_vp9_ || !lossless_color_); |
399 DCHECK(use_vp9_ || !lossless_encode_); | 375 DCHECK(use_vp9_ || !lossless_encode_); |
400 | 376 |
401 // Tear down |image_| if it no longer matches the size and color settings. | 377 // Tear down |image_| if it no longer matches the size and color settings. |
402 // PrepareImage() will then create a new buffer of the required dimensions if | 378 // PrepareImage() will then create a new buffer of the required dimensions if |
403 // |image_| is not allocated. | 379 // |image_| is not allocated. |
404 FreeImageIfMismatched(lossless_color_, size, &image_, &image_buffer_); | 380 FreeImageIfMismatched(lossless_color_, size, &image_, &image_buffer_); |
405 | 381 |
406 // Initialize active map. | 382 // Initialize active map. |
407 active_map_size_ = webrtc::DesktopSize( | 383 active_map_size_ = webrtc::DesktopSize( |
408 (size.width() + kMacroBlockSize - 1) / kMacroBlockSize, | 384 (size.width() + kMacroBlockSize - 1) / kMacroBlockSize, |
409 (size.height() + kMacroBlockSize - 1) / kMacroBlockSize); | 385 (size.height() + kMacroBlockSize - 1) / kMacroBlockSize); |
410 active_map_.reset( | 386 active_map_.reset( |
411 new uint8_t[active_map_size_.width() * active_map_size_.height()]); | 387 new uint8_t[active_map_size_.width() * active_map_size_.height()]); |
| 388 ClearActiveMap(); |
412 | 389 |
413 // TODO(wez): Remove this hack once VPX can handle frame size reconfiguration. | 390 // TODO(wez): Remove this hack once VPX can handle frame size reconfiguration. |
414 // See https://code.google.com/p/webm/issues/detail?id=912. | 391 // See https://code.google.com/p/webm/issues/detail?id=912. |
415 if (codec_) { | 392 if (codec_) { |
416 // If the frame size has changed then force re-creation of the codec. | 393 // If the frame size has changed then force re-creation of the codec. |
417 if (codec_->config.enc->g_w != static_cast<unsigned int>(size.width()) || | 394 if (codec_->config.enc->g_w != static_cast<unsigned int>(size.width()) || |
418 codec_->config.enc->g_h != static_cast<unsigned int>(size.height())) { | 395 codec_->config.enc->g_h != static_cast<unsigned int>(size.height())) { |
419 codec_.reset(); | 396 codec_.reset(); |
420 } | 397 } |
421 } | 398 } |
422 | 399 |
423 // Fetch a default configuration for the desired codec. | 400 // Fetch a default configuration for the desired codec. |
424 const vpx_codec_iface_t* interface = | 401 const vpx_codec_iface_t* interface = |
425 use_vp9_ ? vpx_codec_vp9_cx() : vpx_codec_vp8_cx(); | 402 use_vp9_ ? vpx_codec_vp9_cx() : vpx_codec_vp8_cx(); |
426 vpx_codec_err_t ret = vpx_codec_enc_config_default(interface, &config_, 0); | 403 vpx_codec_err_t ret = vpx_codec_enc_config_default(interface, &config_, 0); |
427 DCHECK_EQ(VPX_CODEC_OK, ret) << "Failed to fetch default configuration"; | 404 DCHECK_EQ(VPX_CODEC_OK, ret) << "Failed to fetch default configuration"; |
428 | 405 |
429 // Customize the default configuration to our needs. | 406 // Customize the default configuration to our needs. |
430 if (use_vp9_) { | 407 if (use_vp9_) { |
431 SetVp9CodecParameters(&config_, size, lossless_color_, lossless_encode_); | 408 SetVp9CodecParameters(&config_, size, lossless_color_, lossless_encode_); |
432 } else { | 409 } else { |
433 SetVp8CodecParameters(&config_, size); | 410 SetVp8CodecParameters(&config_, size); |
434 } | 411 } |
435 config_.rc_target_bitrate = target_bitrate_kbps_; | 412 |
| 413 config_.rc_target_bitrate = kDefaultTargetBitrateKbps; |
436 | 414 |
437 // Initialize or re-configure the codec with the custom configuration. | 415 // Initialize or re-configure the codec with the custom configuration. |
438 if (!codec_) { | 416 if (!codec_) { |
439 codec_.reset(new vpx_codec_ctx_t); | 417 codec_.reset(new vpx_codec_ctx_t); |
440 ret = vpx_codec_enc_init(codec_.get(), interface, &config_, 0); | 418 ret = vpx_codec_enc_init(codec_.get(), interface, &config_, 0); |
441 CHECK_EQ(VPX_CODEC_OK, ret) << "Failed to initialize codec"; | 419 CHECK_EQ(VPX_CODEC_OK, ret) << "Failed to initialize codec"; |
442 } else { | 420 } else { |
443 ret = vpx_codec_enc_config_set(codec_.get(), &config_); | 421 ret = vpx_codec_enc_config_set(codec_.get(), &config_); |
444 CHECK_EQ(VPX_CODEC_OK, ret) << "Failed to reconfigure codec"; | 422 CHECK_EQ(VPX_CODEC_OK, ret) << "Failed to reconfigure codec"; |
445 } | 423 } |
446 | 424 |
447 // Apply further customizations to the codec now it's initialized. | 425 // Apply further customizations to the codec now it's initialized. |
448 if (use_vp9_) { | 426 if (use_vp9_) { |
449 SetVp9CodecOptions(codec_.get(), lossless_encode_); | 427 SetVp9CodecOptions(codec_.get(), lossless_encode_); |
450 } else { | 428 } else { |
451 SetVp8CodecOptions(codec_.get()); | 429 SetVp8CodecOptions(codec_.get()); |
452 } | 430 } |
453 } | 431 } |
454 | 432 |
455 void WebrtcVideoEncoderVpx::UpdateTargetBitrate(int new_bitrate_kbps) { | 433 void WebrtcVideoEncoderVpx::UpdateConfig(const FrameParams& params) { |
456 target_bitrate_kbps_ = new_bitrate_kbps; | |
457 | |
458 // Configuration not initialized. | 434 // Configuration not initialized. |
459 if (config_.g_timebase.den == 0) | 435 if (config_.g_timebase.den == 0) |
460 return; | 436 return; |
461 | 437 |
462 if (config_.rc_target_bitrate == static_cast<unsigned int>(new_bitrate_kbps)) | 438 bool changed = false; |
| 439 |
| 440 if (params.bitrate_kbps >= 0 && |
| 441 config_.rc_target_bitrate != |
| 442 static_cast<unsigned int>(params.bitrate_kbps)) { |
| 443 config_.rc_target_bitrate = params.bitrate_kbps; |
| 444 changed = true; |
| 445 } |
| 446 |
| 447 if (params.vpx_min_quantizer >= 0 && |
| 448 config_.rc_min_quantizer != |
| 449 static_cast<unsigned int>(params.vpx_min_quantizer)) { |
| 450 config_.rc_min_quantizer = params.vpx_min_quantizer; |
| 451 changed = true; |
| 452 } |
| 453 |
| 454 if (params.vpx_max_quantizer >= 0 && |
| 455 config_.rc_max_quantizer != |
| 456 static_cast<unsigned int>(params.vpx_max_quantizer)) { |
| 457 config_.rc_max_quantizer = params.vpx_max_quantizer; |
| 458 changed = true; |
| 459 } |
| 460 |
| 461 if (!changed) |
463 return; | 462 return; |
464 config_.rc_target_bitrate = new_bitrate_kbps; | |
465 | 463 |
466 // Update encoder context. | 464 // Update encoder context. |
467 if (vpx_codec_enc_config_set(codec_.get(), &config_)) | 465 if (vpx_codec_enc_config_set(codec_.get(), &config_)) |
468 NOTREACHED() << "Unable to set encoder config"; | 466 NOTREACHED() << "Unable to set encoder config"; |
469 | 467 |
470 VLOG(1) << "New rc_target_bitrate: " << new_bitrate_kbps << " kbps"; | |
471 } | 468 } |
472 | 469 |
473 void WebrtcVideoEncoderVpx::PrepareImage( | 470 void WebrtcVideoEncoderVpx::PrepareImage( |
474 const webrtc::DesktopFrame& frame, | 471 const webrtc::DesktopFrame& frame, |
475 webrtc::DesktopRegion* updated_region) { | 472 webrtc::DesktopRegion* updated_region) { |
476 if (frame.updated_region().is_empty()) { | 473 if (frame.updated_region().is_empty()) { |
477 updated_region->Clear(); | 474 updated_region->Clear(); |
478 return; | 475 return; |
479 } | 476 } |
480 | 477 |
481 updated_region->Clear(); | 478 updated_region->Clear(); |
482 if (image_) { | 479 if (image_) { |
483 // Pad each rectangle to avoid the block-artefact filters in libvpx from | 480 // Pad each rectangle to avoid the block-artifact filters in libvpx from |
484 // introducing artefacts; VP9 includes up to 8px either side, and VP8 up to | 481 // introducing artifacts; VP9 includes up to 8px either side, and VP8 up to |
485 // 3px, so unchanged pixels up to that far out may still be affected by the | 482 // 3px, so unchanged pixels up to that far out may still be affected by the |
486 // changes in the updated region, and so must be listed in the active map. | 483 // changes in the updated region, and so must be listed in the active map. |
487 // After padding we align each rectangle to 16x16 active-map macroblocks. | 484 // After padding we align each rectangle to 16x16 active-map macroblocks. |
488 // This implicitly ensures all rects have even top-left coords, which is | 485 // This implicitly ensures all rects have even top-left coords, which is |
489 // is required by ConvertRGBToYUVWithRect(). | 486 // is required by ConvertRGBToYUVWithRect(). |
490 // TODO(wez): Do we still need 16x16 align, or is even alignment sufficient? | 487 // TODO(wez): Do we still need 16x16 align, or is even alignment sufficient? |
491 int padding = use_vp9_ ? 8 : 3; | 488 int padding = use_vp9_ ? 8 : 3; |
492 for (webrtc::DesktopRegion::Iterator r(frame.updated_region()); | 489 for (webrtc::DesktopRegion::Iterator r(frame.updated_region()); |
493 !r.IsAtEnd(); r.Advance()) { | 490 !r.IsAtEnd(); r.Advance()) { |
494 const webrtc::DesktopRect& rect = r.rect(); | 491 const webrtc::DesktopRect& rect = r.rect(); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
545 v_data + uv_offset, uv_stride, rect.width(), | 542 v_data + uv_offset, uv_stride, rect.width(), |
546 rect.height()); | 543 rect.height()); |
547 } | 544 } |
548 break; | 545 break; |
549 default: | 546 default: |
550 NOTREACHED(); | 547 NOTREACHED(); |
551 break; | 548 break; |
552 } | 549 } |
553 } | 550 } |
554 | 551 |
| 552 void WebrtcVideoEncoderVpx::ClearActiveMap() { |
| 553 DCHECK(active_map_); |
| 554 // Clear active map first. |
| 555 memset(active_map_.get(), 0, |
| 556 active_map_size_.width() * active_map_size_.height()); |
| 557 } |
| 558 |
555 void WebrtcVideoEncoderVpx::SetActiveMapFromRegion( | 559 void WebrtcVideoEncoderVpx::SetActiveMapFromRegion( |
556 const webrtc::DesktopRegion& updated_region) { | 560 const webrtc::DesktopRegion& updated_region) { |
557 // Clear active map first. | |
558 memset(active_map_.get(), 0, | |
559 active_map_size_.width() * active_map_size_.height()); | |
560 | |
561 // Mark updated areas active. | 561 // Mark updated areas active. |
562 for (webrtc::DesktopRegion::Iterator r(updated_region); !r.IsAtEnd(); | 562 for (webrtc::DesktopRegion::Iterator r(updated_region); !r.IsAtEnd(); |
563 r.Advance()) { | 563 r.Advance()) { |
564 const webrtc::DesktopRect& rect = r.rect(); | 564 const webrtc::DesktopRect& rect = r.rect(); |
565 int left = rect.left() / kMacroBlockSize; | 565 int left = rect.left() / kMacroBlockSize; |
566 int right = (rect.right() - 1) / kMacroBlockSize; | 566 int right = (rect.right() - 1) / kMacroBlockSize; |
567 int top = rect.top() / kMacroBlockSize; | 567 int top = rect.top() / kMacroBlockSize; |
568 int bottom = (rect.bottom() - 1) / kMacroBlockSize; | 568 int bottom = (rect.bottom() - 1) / kMacroBlockSize; |
569 DCHECK_LT(right, active_map_size_.width()); | 569 DCHECK_LT(right, active_map_size_.width()); |
570 DCHECK_LT(bottom, active_map_size_.height()); | 570 DCHECK_LT(bottom, active_map_size_.height()); |
(...skipping 23 matching lines...) Expand all Loading... |
594 kMacroBlockSize * (y + 1))); | 594 kMacroBlockSize * (y + 1))); |
595 } | 595 } |
596 x0 = x1 + 1; | 596 x0 = x1 + 1; |
597 } | 597 } |
598 } | 598 } |
599 updated_region->IntersectWith( | 599 updated_region->IntersectWith( |
600 webrtc::DesktopRect::MakeWH(image_->w, image_->h)); | 600 webrtc::DesktopRect::MakeWH(image_->w, image_->h)); |
601 } | 601 } |
602 | 602 |
603 } // namespace remoting | 603 } // namespace remoting |
OLD | NEW |