| 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 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 267 // TODO(wez): Switch to ConfigureCodec() path once libvpx supports it. | 267 // TODO(wez): Switch to ConfigureCodec() path once libvpx supports it. |
| 268 // See https://code.google.com/p/webm/issues/detail?id=913. | 268 // See https://code.google.com/p/webm/issues/detail?id=913. |
| 269 // if (codec_) | 269 // if (codec_) |
| 270 // Configure(webrtc::DesktopSize(codec_->config.enc->g_w, | 270 // Configure(webrtc::DesktopSize(codec_->config.enc->g_w, |
| 271 // codec_->config.enc->g_h)); | 271 // codec_->config.enc->g_h)); |
| 272 codec_.reset(); | 272 codec_.reset(); |
| 273 } | 273 } |
| 274 } | 274 } |
| 275 | 275 |
| 276 std::unique_ptr<WebrtcVideoEncoder::EncodedFrame> WebrtcVideoEncoderVpx::Encode( | 276 std::unique_ptr<WebrtcVideoEncoder::EncodedFrame> WebrtcVideoEncoderVpx::Encode( |
| 277 const webrtc::DesktopFrame& frame, | 277 const webrtc::DesktopFrame* frame, |
| 278 const FrameParams& params) { | 278 const FrameParams& params) { |
| 279 DCHECK_LE(32, frame.size().width()); | 279 webrtc::DesktopSize previous_frame_size = |
| 280 DCHECK_LE(32, frame.size().height()); | 280 image_ ? webrtc::DesktopSize(image_->w, image_->h) |
| 281 : webrtc::DesktopSize(); |
| 282 |
| 283 webrtc::DesktopSize frame_size = frame ? frame->size() : previous_frame_size; |
| 284 |
| 285 // Don't need to send anything until we get the first non-null frame. |
| 286 if (frame_size.is_empty()) { |
| 287 return nullptr; |
| 288 } |
| 289 |
| 290 DCHECK_GE(frame_size.width(), 32); |
| 291 DCHECK_GE(frame_size.height(), 32); |
| 281 | 292 |
| 282 // Create or reconfigure the codec to match the size of |frame|. | 293 // Create or reconfigure the codec to match the size of |frame|. |
| 283 if (!codec_ || | 294 if (!codec_ || !frame_size.equals(previous_frame_size)) { |
| 284 (image_ && | 295 Configure(frame_size); |
| 285 !frame.size().equals(webrtc::DesktopSize(image_->w, image_->h)))) { | |
| 286 Configure(frame.size()); | |
| 287 } | 296 } |
| 288 | 297 |
| 289 UpdateConfig(params); | 298 UpdateConfig(params); |
| 290 | 299 |
| 291 vpx_active_map_t act_map; | 300 vpx_active_map_t act_map; |
| 292 act_map.rows = active_map_size_.height(); | 301 act_map.rows = active_map_size_.height(); |
| 293 act_map.cols = active_map_size_.width(); | 302 act_map.cols = active_map_size_.width(); |
| 294 act_map.active_map = active_map_.get(); | 303 act_map.active_map = active_map_.get(); |
| 295 | 304 |
| 296 webrtc::DesktopRegion updated_region; | 305 webrtc::DesktopRegion updated_region; |
| 297 // Convert the updated capture data ready for encode. | 306 // Convert the updated capture data ready for encode. |
| 298 PrepareImage(frame, &updated_region); | 307 PrepareImage(frame, &updated_region); |
| 299 | 308 |
| 300 // Update active map based on updated region. | 309 // Update active map based on updated region. |
| 301 if (params.clear_active_map) | 310 if (params.clear_active_map) |
| 302 ClearActiveMap(); | 311 ClearActiveMap(); |
| 303 | 312 |
| 304 if (params.key_frame) | 313 if (params.key_frame) |
| 305 updated_region.SetRect(webrtc::DesktopRect::MakeSize(frame.size())); | 314 updated_region.SetRect(webrtc::DesktopRect::MakeSize(frame_size)); |
| 306 | 315 |
| 307 SetActiveMapFromRegion(updated_region); | 316 SetActiveMapFromRegion(updated_region); |
| 308 | 317 |
| 309 // Apply active map to the encoder. | 318 // Apply active map to the encoder. |
| 310 if (vpx_codec_control(codec_.get(), VP8E_SET_ACTIVEMAP, &act_map)) { | 319 if (vpx_codec_control(codec_.get(), VP8E_SET_ACTIVEMAP, &act_map)) { |
| 311 LOG(ERROR) << "Unable to apply active map"; | 320 LOG(ERROR) << "Unable to apply active map"; |
| 312 } | 321 } |
| 313 | 322 |
| 314 vpx_codec_err_t ret = vpx_codec_encode( | 323 vpx_codec_err_t ret = vpx_codec_encode( |
| 315 codec_.get(), image_.get(), 0, params.duration.InMicroseconds(), | 324 codec_.get(), image_.get(), 0, params.duration.InMicroseconds(), |
| (...skipping 14 matching lines...) Expand all Loading... |
| 330 } | 339 } |
| 331 | 340 |
| 332 UpdateRegionFromActiveMap(&updated_region); | 341 UpdateRegionFromActiveMap(&updated_region); |
| 333 } | 342 } |
| 334 | 343 |
| 335 // Read the encoded data. | 344 // Read the encoded data. |
| 336 vpx_codec_iter_t iter = nullptr; | 345 vpx_codec_iter_t iter = nullptr; |
| 337 bool got_data = false; | 346 bool got_data = false; |
| 338 | 347 |
| 339 std::unique_ptr<EncodedFrame> encoded_frame(new EncodedFrame()); | 348 std::unique_ptr<EncodedFrame> encoded_frame(new EncodedFrame()); |
| 340 encoded_frame->size = frame.size(); | 349 encoded_frame->size = frame_size; |
| 341 | 350 |
| 342 while (!got_data) { | 351 while (!got_data) { |
| 343 const vpx_codec_cx_pkt_t* vpx_packet = | 352 const vpx_codec_cx_pkt_t* vpx_packet = |
| 344 vpx_codec_get_cx_data(codec_.get(), &iter); | 353 vpx_codec_get_cx_data(codec_.get(), &iter); |
| 345 if (!vpx_packet) | 354 if (!vpx_packet) |
| 346 continue; | 355 continue; |
| 347 | 356 |
| 348 switch (vpx_packet->kind) { | 357 switch (vpx_packet->kind) { |
| 349 case VPX_CODEC_CX_FRAME_PKT: { | 358 case VPX_CODEC_CX_FRAME_PKT: { |
| 350 got_data = true; | 359 got_data = true; |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 465 if (!changed) | 474 if (!changed) |
| 466 return; | 475 return; |
| 467 | 476 |
| 468 // Update encoder context. | 477 // Update encoder context. |
| 469 if (vpx_codec_enc_config_set(codec_.get(), &config_)) | 478 if (vpx_codec_enc_config_set(codec_.get(), &config_)) |
| 470 NOTREACHED() << "Unable to set encoder config"; | 479 NOTREACHED() << "Unable to set encoder config"; |
| 471 | 480 |
| 472 } | 481 } |
| 473 | 482 |
| 474 void WebrtcVideoEncoderVpx::PrepareImage( | 483 void WebrtcVideoEncoderVpx::PrepareImage( |
| 475 const webrtc::DesktopFrame& frame, | 484 const webrtc::DesktopFrame* frame, |
| 476 webrtc::DesktopRegion* updated_region) { | 485 webrtc::DesktopRegion* updated_region) { |
| 477 if (frame.updated_region().is_empty()) { | 486 if (!frame || frame->updated_region().is_empty()) { |
| 478 updated_region->Clear(); | 487 updated_region->Clear(); |
| 479 return; | 488 return; |
| 480 } | 489 } |
| 481 | 490 |
| 482 updated_region->Clear(); | 491 updated_region->Clear(); |
| 483 if (image_) { | 492 if (image_) { |
| 484 // Pad each rectangle to avoid the block-artifact filters in libvpx from | 493 // Pad each rectangle to avoid the block-artifact filters in libvpx from |
| 485 // introducing artifacts; VP9 includes up to 8px either side, and VP8 up to | 494 // introducing artifacts; VP9 includes up to 8px either side, and VP8 up to |
| 486 // 3px, so unchanged pixels up to that far out may still be affected by the | 495 // 3px, so unchanged pixels up to that far out may still be affected by the |
| 487 // changes in the updated region, and so must be listed in the active map. | 496 // changes in the updated region, and so must be listed in the active map. |
| 488 // After padding we align each rectangle to 16x16 active-map macroblocks. | 497 // After padding we align each rectangle to 16x16 active-map macroblocks. |
| 489 // This implicitly ensures all rects have even top-left coords, which is | 498 // This implicitly ensures all rects have even top-left coords, which is |
| 490 // is required by ConvertRGBToYUVWithRect(). | 499 // is required by ConvertRGBToYUVWithRect(). |
| 491 // TODO(wez): Do we still need 16x16 align, or is even alignment sufficient? | 500 // TODO(wez): Do we still need 16x16 align, or is even alignment sufficient? |
| 492 int padding = use_vp9_ ? 8 : 3; | 501 int padding = use_vp9_ ? 8 : 3; |
| 493 for (webrtc::DesktopRegion::Iterator r(frame.updated_region()); | 502 for (webrtc::DesktopRegion::Iterator r(frame->updated_region()); |
| 494 !r.IsAtEnd(); r.Advance()) { | 503 !r.IsAtEnd(); r.Advance()) { |
| 495 const webrtc::DesktopRect& rect = r.rect(); | 504 const webrtc::DesktopRect& rect = r.rect(); |
| 496 updated_region->AddRect(AlignRect(webrtc::DesktopRect::MakeLTRB( | 505 updated_region->AddRect(AlignRect(webrtc::DesktopRect::MakeLTRB( |
| 497 rect.left() - padding, rect.top() - padding, rect.right() + padding, | 506 rect.left() - padding, rect.top() - padding, rect.right() + padding, |
| 498 rect.bottom() + padding))); | 507 rect.bottom() + padding))); |
| 499 } | 508 } |
| 500 DCHECK(!updated_region->is_empty()); | 509 DCHECK(!updated_region->is_empty()); |
| 501 | 510 |
| 502 // Clip back to the screen dimensions, in case they're not macroblock | 511 // Clip back to the screen dimensions, in case they're not macroblock |
| 503 // aligned. The conversion routines don't require even width & height, | 512 // aligned. The conversion routines don't require even width & height, |
| 504 // so this is safe even if the source dimensions are not even. | 513 // so this is safe even if the source dimensions are not even. |
| 505 updated_region->IntersectWith( | 514 updated_region->IntersectWith( |
| 506 webrtc::DesktopRect::MakeWH(image_->w, image_->h)); | 515 webrtc::DesktopRect::MakeWH(image_->w, image_->h)); |
| 507 } else { | 516 } else { |
| 508 CreateImage(lossless_color_, frame.size(), &image_, &image_buffer_); | 517 CreateImage(lossless_color_, frame->size(), &image_, &image_buffer_); |
| 509 updated_region->AddRect(webrtc::DesktopRect::MakeWH(image_->w, image_->h)); | 518 updated_region->AddRect(webrtc::DesktopRect::MakeWH(image_->w, image_->h)); |
| 510 } | 519 } |
| 511 | 520 |
| 512 // Convert the updated region to YUV ready for encoding. | 521 // Convert the updated region to YUV ready for encoding. |
| 513 const uint8_t* rgb_data = frame.data(); | 522 const uint8_t* rgb_data = frame->data(); |
| 514 const int rgb_stride = frame.stride(); | 523 const int rgb_stride = frame->stride(); |
| 515 const int y_stride = image_->stride[0]; | 524 const int y_stride = image_->stride[0]; |
| 516 DCHECK_EQ(image_->stride[1], image_->stride[2]); | 525 DCHECK_EQ(image_->stride[1], image_->stride[2]); |
| 517 const int uv_stride = image_->stride[1]; | 526 const int uv_stride = image_->stride[1]; |
| 518 uint8_t* y_data = image_->planes[0]; | 527 uint8_t* y_data = image_->planes[0]; |
| 519 uint8_t* u_data = image_->planes[1]; | 528 uint8_t* u_data = image_->planes[1]; |
| 520 uint8_t* v_data = image_->planes[2]; | 529 uint8_t* v_data = image_->planes[2]; |
| 521 | 530 |
| 522 switch (image_->fmt) { | 531 switch (image_->fmt) { |
| 523 case VPX_IMG_FMT_I444: | 532 case VPX_IMG_FMT_I444: |
| 524 for (webrtc::DesktopRegion::Iterator r(*updated_region); !r.IsAtEnd(); | 533 for (webrtc::DesktopRegion::Iterator r(*updated_region); !r.IsAtEnd(); |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 598 kMacroBlockSize * (y + 1))); | 607 kMacroBlockSize * (y + 1))); |
| 599 } | 608 } |
| 600 x0 = x1 + 1; | 609 x0 = x1 + 1; |
| 601 } | 610 } |
| 602 } | 611 } |
| 603 updated_region->IntersectWith( | 612 updated_region->IntersectWith( |
| 604 webrtc::DesktopRect::MakeWH(image_->w, image_->h)); | 613 webrtc::DesktopRect::MakeWH(image_->w, image_->h)); |
| 605 } | 614 } |
| 606 | 615 |
| 607 } // namespace remoting | 616 } // namespace remoting |
| OLD | NEW |