Chromium Code Reviews| 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 // Clear active map first. | |
|
Irfan
2016/09/14 20:01:29
DCHECK(active_map_) ?
Sergey Ulanov
2016/09/16 00:02:47
Done.
| |
| 554 memset(active_map_.get(), 0, | |
| 555 active_map_size_.width() * active_map_size_.height()); | |
| 556 } | |
| 557 | |
| 555 void WebrtcVideoEncoderVpx::SetActiveMapFromRegion( | 558 void WebrtcVideoEncoderVpx::SetActiveMapFromRegion( |
| 556 const webrtc::DesktopRegion& updated_region) { | 559 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. | 560 // Mark updated areas active. |
| 562 for (webrtc::DesktopRegion::Iterator r(updated_region); !r.IsAtEnd(); | 561 for (webrtc::DesktopRegion::Iterator r(updated_region); !r.IsAtEnd(); |
| 563 r.Advance()) { | 562 r.Advance()) { |
| 564 const webrtc::DesktopRect& rect = r.rect(); | 563 const webrtc::DesktopRect& rect = r.rect(); |
| 565 int left = rect.left() / kMacroBlockSize; | 564 int left = rect.left() / kMacroBlockSize; |
| 566 int right = (rect.right() - 1) / kMacroBlockSize; | 565 int right = (rect.right() - 1) / kMacroBlockSize; |
| 567 int top = rect.top() / kMacroBlockSize; | 566 int top = rect.top() / kMacroBlockSize; |
| 568 int bottom = (rect.bottom() - 1) / kMacroBlockSize; | 567 int bottom = (rect.bottom() - 1) / kMacroBlockSize; |
| 569 DCHECK_LT(right, active_map_size_.width()); | 568 DCHECK_LT(right, active_map_size_.width()); |
| 570 DCHECK_LT(bottom, active_map_size_.height()); | 569 DCHECK_LT(bottom, active_map_size_.height()); |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 594 kMacroBlockSize * (y + 1))); | 593 kMacroBlockSize * (y + 1))); |
| 595 } | 594 } |
| 596 x0 = x1 + 1; | 595 x0 = x1 + 1; |
| 597 } | 596 } |
| 598 } | 597 } |
| 599 updated_region->IntersectWith( | 598 updated_region->IntersectWith( |
| 600 webrtc::DesktopRect::MakeWH(image_->w, image_->h)); | 599 webrtc::DesktopRect::MakeWH(image_->w, image_->h)); |
| 601 } | 600 } |
| 602 | 601 |
| 603 } // namespace remoting | 602 } // namespace remoting |
| OLD | NEW |