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 |