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

Side by Side Diff: remoting/codec/video_encoder_vpx.cc

Issue 1213323003: Supply empty frames until codec is done with top-off. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix test names Created 5 years, 5 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
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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/video_encoder_vpx.h" 5 #include "remoting/codec/video_encoder_vpx.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/sys_info.h" 9 #include "base/sys_info.h"
10 #include "remoting/base/util.h" 10 #include "remoting/base/util.h"
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after
259 // codec_->config.enc->g_h)); 259 // codec_->config.enc->g_h));
260 codec_.reset(); 260 codec_.reset();
261 } 261 }
262 } 262 }
263 263
264 scoped_ptr<VideoPacket> VideoEncoderVpx::Encode( 264 scoped_ptr<VideoPacket> VideoEncoderVpx::Encode(
265 const webrtc::DesktopFrame& frame) { 265 const webrtc::DesktopFrame& frame) {
266 DCHECK_LE(32, frame.size().width()); 266 DCHECK_LE(32, frame.size().width());
267 DCHECK_LE(32, frame.size().height()); 267 DCHECK_LE(32, frame.size().height());
268 268
269 if (!use_vp9_ || lossless_encode_) { 269 // If there is nothing to encode, and nothing to top-off, then return nothing.
270 // Neither VP8 nor VP9-lossless support top-off, so ignore unchanged frames. 270 if (frame.updated_region().is_empty() && !encode_unchanged_frame_)
271 if (frame.updated_region().is_empty()) 271 return nullptr;
272 return nullptr;
273 } else {
274 // Let VP9-lossy mode top-off, by continuing to pass it unchanged frames
275 // for a short while.
276 if (frame.updated_region().is_empty()) {
277 if (topoff_frame_count_ == 0)
278 return nullptr;
279 topoff_frame_count_--;
280 } else {
281 topoff_frame_count_ = 2;
282 }
283 }
284 272
285 base::TimeTicks encode_start_time = base::TimeTicks::Now(); 273 base::TimeTicks encode_start_time = base::TimeTicks::Now();
286 274
287 // Create or reconfigure the codec to match the size of |frame|. 275 // Create or reconfigure the codec to match the size of |frame|.
288 if (!codec_ || 276 if (!codec_ ||
289 (image_ && 277 (image_ &&
290 !frame.size().equals(webrtc::DesktopSize(image_->w, image_->h)))) { 278 !frame.size().equals(webrtc::DesktopSize(image_->w, image_->h)))) {
291 Configure(frame.size()); 279 Configure(frame.size());
292 } 280 }
293 281
294 // Convert the updated capture data ready for encode. 282 // Convert the updated capture data ready for encode.
295 webrtc::DesktopRegion updated_region; 283 webrtc::DesktopRegion updated_region;
296 PrepareImage(frame, &updated_region); 284 PrepareImage(frame, &updated_region);
297 285
298 // Update active map based on updated region. 286 // Update active map based on updated region.
299 SetActiveMapFromRegion(updated_region); 287 SetActiveMapFromRegion(updated_region);
300 288
301 // Apply active map to the encoder. 289 // Apply active map to the encoder.
302 vpx_active_map_t act_map; 290 vpx_active_map_t act_map;
303 act_map.rows = active_map_height_; 291 act_map.rows = active_map_size_.height();
304 act_map.cols = active_map_width_; 292 act_map.cols = active_map_size_.width();
305 act_map.active_map = active_map_.get(); 293 act_map.active_map = active_map_.get();
306 if (vpx_codec_control(codec_.get(), VP8E_SET_ACTIVEMAP, &act_map)) { 294 if (vpx_codec_control(codec_.get(), VP8E_SET_ACTIVEMAP, &act_map)) {
307 LOG(ERROR) << "Unable to apply active map"; 295 LOG(ERROR) << "Unable to apply active map";
308 } 296 }
309 297
310 // Do the actual encoding. 298 // Do the actual encoding.
311 int timestamp = (encode_start_time - timestamp_base_).InMilliseconds(); 299 int timestamp = (encode_start_time - timestamp_base_).InMilliseconds();
312 vpx_codec_err_t ret = vpx_codec_encode( 300 vpx_codec_err_t ret = vpx_codec_encode(
313 codec_.get(), image_.get(), timestamp, 1, 0, VPX_DL_REALTIME); 301 codec_.get(), image_.get(), timestamp, 1, 0, VPX_DL_REALTIME);
314 DCHECK_EQ(ret, VPX_CODEC_OK) 302 DCHECK_EQ(ret, VPX_CODEC_OK)
315 << "Encoding error: " << vpx_codec_err_to_string(ret) << "\n" 303 << "Encoding error: " << vpx_codec_err_to_string(ret) << "\n"
316 << "Details: " << vpx_codec_error(codec_.get()) << "\n" 304 << "Details: " << vpx_codec_error(codec_.get()) << "\n"
317 << vpx_codec_error_detail(codec_.get()); 305 << vpx_codec_error_detail(codec_.get());
318 306
319 if (use_vp9_ && !lossless_encode_) { 307 if (use_vp9_ && !lossless_encode_) {
320 ret = vpx_codec_control(codec_.get(), VP9E_GET_ACTIVEMAP, &act_map); 308 ret = vpx_codec_control(codec_.get(), VP9E_GET_ACTIVEMAP, &act_map);
321 DCHECK_EQ(ret, VPX_CODEC_OK) 309 DCHECK_EQ(ret, VPX_CODEC_OK)
322 << "Failed to fetch active map: " 310 << "Failed to fetch active map: "
323 << vpx_codec_err_to_string(ret) << "\n"; 311 << vpx_codec_err_to_string(ret) << "\n";
324 UpdateRegionFromActiveMap(&updated_region); 312 UpdateRegionFromActiveMap(&updated_region);
313
314 // If the encoder output no changes then there's nothing left to top-off.
315 encode_unchanged_frame_ = !updated_region.is_empty();
325 } 316 }
326 317
327 // Read the encoded data. 318 // Read the encoded data.
328 vpx_codec_iter_t iter = NULL; 319 vpx_codec_iter_t iter = NULL;
329 bool got_data = false; 320 bool got_data = false;
330 321
331 // TODO(hclam): Make sure we get exactly one frame from the packet. 322 // TODO(hclam): Make sure we get exactly one frame from the packet.
332 // TODO(hclam): We should provide the output buffer to avoid one copy. 323 // TODO(hclam): We should provide the output buffer to avoid one copy.
333 scoped_ptr<VideoPacket> packet( 324 scoped_ptr<VideoPacket> packet(
334 helper_.CreateVideoPacketWithUpdatedRegion(frame, updated_region)); 325 helper_.CreateVideoPacketWithUpdatedRegion(frame, updated_region));
(...skipping 15 matching lines...) Expand all
350 } 341 }
351 } 342 }
352 343
353 // Note the time taken to encode the pixel data. 344 // Note the time taken to encode the pixel data.
354 packet->set_encode_time_ms( 345 packet->set_encode_time_ms(
355 (base::TimeTicks::Now() - encode_start_time).InMillisecondsRoundedUp()); 346 (base::TimeTicks::Now() - encode_start_time).InMillisecondsRoundedUp());
356 347
357 return packet.Pass(); 348 return packet.Pass();
358 } 349 }
359 350
360 VideoEncoderVpx::VideoEncoderVpx(bool use_vp9) : use_vp9_(use_vp9) { 351 VideoEncoderVpx::VideoEncoderVpx(bool use_vp9)
352 : use_vp9_(use_vp9), encode_unchanged_frame_(false) {
361 } 353 }
362 354
363 void VideoEncoderVpx::Configure(const webrtc::DesktopSize& size) { 355 void VideoEncoderVpx::Configure(const webrtc::DesktopSize& size) {
364 DCHECK(use_vp9_ || !lossless_color_); 356 DCHECK(use_vp9_ || !lossless_color_);
365 DCHECK(use_vp9_ || !lossless_encode_); 357 DCHECK(use_vp9_ || !lossless_encode_);
366 358
367 // Tear down |image_| if it no longer matches the size and color settings. 359 // Tear down |image_| if it no longer matches the size and color settings.
368 // PrepareImage() will then create a new buffer of the required dimensions if 360 // PrepareImage() will then create a new buffer of the required dimensions if
369 // |image_| is not allocated. 361 // |image_| is not allocated.
370 FreeImageIfMismatched(lossless_color_, size, &image_, &image_buffer_); 362 FreeImageIfMismatched(lossless_color_, size, &image_, &image_buffer_);
371 363
372 // Initialize active map. 364 // Initialize active map.
373 active_map_width_ = (size.width() + kMacroBlockSize - 1) / kMacroBlockSize; 365 active_map_size_ = webrtc::DesktopSize(
374 active_map_height_ = (size.height() + kMacroBlockSize - 1) / kMacroBlockSize; 366 (size.width() + kMacroBlockSize - 1) / kMacroBlockSize,
375 active_map_.reset(new uint8[active_map_width_ * active_map_height_]); 367 (size.height() + kMacroBlockSize - 1) / kMacroBlockSize);
368 active_map_.reset(
369 new uint8[active_map_size_.width() * active_map_size_.height()]);
376 370
377 // TODO(wez): Remove this hack once VPX can handle frame size reconfiguration. 371 // TODO(wez): Remove this hack once VPX can handle frame size reconfiguration.
378 // See https://code.google.com/p/webm/issues/detail?id=912. 372 // See https://code.google.com/p/webm/issues/detail?id=912.
379 if (codec_) { 373 if (codec_) {
380 // If the frame size has changed then force re-creation of the codec. 374 // If the frame size has changed then force re-creation of the codec.
381 if (codec_->config.enc->g_w != static_cast<unsigned int>(size.width()) || 375 if (codec_->config.enc->g_w != static_cast<unsigned int>(size.width()) ||
382 codec_->config.enc->g_h != static_cast<unsigned int>(size.height())) { 376 codec_->config.enc->g_h != static_cast<unsigned int>(size.height())) {
383 codec_.reset(); 377 codec_.reset();
384 } 378 }
385 } 379 }
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
500 break; 494 break;
501 default: 495 default:
502 NOTREACHED(); 496 NOTREACHED();
503 break; 497 break;
504 } 498 }
505 } 499 }
506 500
507 void VideoEncoderVpx::SetActiveMapFromRegion( 501 void VideoEncoderVpx::SetActiveMapFromRegion(
508 const webrtc::DesktopRegion& updated_region) { 502 const webrtc::DesktopRegion& updated_region) {
509 // Clear active map first. 503 // Clear active map first.
510 memset(active_map_.get(), 0, active_map_width_ * active_map_height_); 504 memset(active_map_.get(), 0,
505 active_map_size_.width() * active_map_size_.height());
511 506
512 // Mark updated areas active. 507 // Mark updated areas active.
513 for (webrtc::DesktopRegion::Iterator r(updated_region); !r.IsAtEnd(); 508 for (webrtc::DesktopRegion::Iterator r(updated_region); !r.IsAtEnd();
514 r.Advance()) { 509 r.Advance()) {
515 const webrtc::DesktopRect& rect = r.rect(); 510 const webrtc::DesktopRect& rect = r.rect();
516 int left = rect.left() / kMacroBlockSize; 511 int left = rect.left() / kMacroBlockSize;
517 int right = (rect.right() - 1) / kMacroBlockSize; 512 int right = (rect.right() - 1) / kMacroBlockSize;
518 int top = rect.top() / kMacroBlockSize; 513 int top = rect.top() / kMacroBlockSize;
519 int bottom = (rect.bottom() - 1) / kMacroBlockSize; 514 int bottom = (rect.bottom() - 1) / kMacroBlockSize;
520 DCHECK_LT(right, active_map_width_); 515 DCHECK_LT(right, active_map_size_.width());
521 DCHECK_LT(bottom, active_map_height_); 516 DCHECK_LT(bottom, active_map_size_.height());
522 517
523 uint8* map = active_map_.get() + top * active_map_width_; 518 uint8* map = active_map_.get() + top * active_map_size_.width();
524 for (int y = top; y <= bottom; ++y) { 519 for (int y = top; y <= bottom; ++y) {
525 for (int x = left; x <= right; ++x) 520 for (int x = left; x <= right; ++x)
526 map[x] = 1; 521 map[x] = 1;
527 map += active_map_width_; 522 map += active_map_size_.width();
528 } 523 }
529 } 524 }
530 } 525 }
531 526
532 void VideoEncoderVpx::UpdateRegionFromActiveMap( 527 void VideoEncoderVpx::UpdateRegionFromActiveMap(
533 webrtc::DesktopRegion* updated_region) { 528 webrtc::DesktopRegion* updated_region) {
534 const uint8* map = active_map_.get(); 529 const uint8* map = active_map_.get();
535 for (int y = 0; y < active_map_height_; ++y) { 530 for (int y = 0; y < active_map_size_.height(); ++y) {
536 for (int x0 = 0; x0 < active_map_width_;) { 531 for (int x0 = 0; x0 < active_map_size_.width();) {
537 int x1 = x0; 532 int x1 = x0;
538 for (; x1 < active_map_width_; ++x1) { 533 for (; x1 < active_map_size_.width(); ++x1) {
539 if (map[y * active_map_width_ + x1] == 0) 534 if (map[y * active_map_size_.width() + x1] == 0)
540 break; 535 break;
541 } 536 }
542 if (x1 > x0) { 537 if (x1 > x0) {
543 updated_region->AddRect(webrtc::DesktopRect::MakeLTRB( 538 updated_region->AddRect(webrtc::DesktopRect::MakeLTRB(
544 kMacroBlockSize * x0, kMacroBlockSize * y, kMacroBlockSize * x1, 539 kMacroBlockSize * x0, kMacroBlockSize * y, kMacroBlockSize * x1,
545 kMacroBlockSize * (y + 1))); 540 kMacroBlockSize * (y + 1)));
546 } 541 }
547 x0 = x1 + 1; 542 x0 = x1 + 1;
548 } 543 }
549 } 544 }
550 updated_region->IntersectWith( 545 updated_region->IntersectWith(
551 webrtc::DesktopRect::MakeWH(image_->w, image_->h)); 546 webrtc::DesktopRect::MakeWH(image_->w, image_->h));
552 } 547 }
553 548
554 } // namespace remoting 549 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698