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

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

Issue 2329653002: Add WebrtcVideoEncoder interface (Closed)
Patch Set: win Created 4 years, 3 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
« no previous file with comments | « remoting/codec/webrtc_video_encoder_vpx.h ('k') | remoting/proto/video.proto » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 258 matching lines...) Expand 10 before | Expand all | Expand 10 after
269 lossless_color_ = want_lossless; 269 lossless_color_ = want_lossless;
270 // TODO(wez): Switch to ConfigureCodec() path once libvpx supports it. 270 // TODO(wez): Switch to ConfigureCodec() path once libvpx supports it.
271 // See https://code.google.com/p/webm/issues/detail?id=913. 271 // See https://code.google.com/p/webm/issues/detail?id=913.
272 // if (codec_) 272 // if (codec_)
273 // Configure(webrtc::DesktopSize(codec_->config.enc->g_w, 273 // Configure(webrtc::DesktopSize(codec_->config.enc->g_w,
274 // codec_->config.enc->g_h)); 274 // codec_->config.enc->g_h));
275 codec_.reset(); 275 codec_.reset();
276 } 276 }
277 } 277 }
278 278
279 void WebrtcVideoEncoderVpx::UpdateTargetBitrate(int new_bitrate_kbps) { 279 std::unique_ptr<WebrtcVideoEncoder::EncodedFrame> WebrtcVideoEncoderVpx::Encode(
280 target_bitrate_kbps_ = new_bitrate_kbps;
281 // Configuration not initialized.
282 if (config_.g_timebase.den == 0)
283 return;
284
285 if (config_.rc_target_bitrate == static_cast<unsigned int>(new_bitrate_kbps))
286 return;
287 config_.rc_target_bitrate = new_bitrate_kbps;
288
289 // Update encoder context.
290 if (vpx_codec_enc_config_set(codec_.get(), &config_))
291 NOTREACHED() << "Unable to set encoder config";
292
293 VLOG(1) << "New rc_target_bitrate: " << new_bitrate_kbps << " kbps";
294 }
295
296 std::unique_ptr<VideoPacket> WebrtcVideoEncoderVpx::Encode(
297 const webrtc::DesktopFrame& frame, 280 const webrtc::DesktopFrame& frame,
298 uint32_t flags) { 281 const FrameParams& params) {
299 DCHECK_LE(32, frame.size().width()); 282 DCHECK_LE(32, frame.size().width());
300 DCHECK_LE(32, frame.size().height()); 283 DCHECK_LE(32, frame.size().height());
301 284
302 // Based on information fetching active map, we return here if there is 285 // Based on information fetching active map, we return here if there is
303 // nothing to top-off. 286 // nothing to top-off.
304 if (frame.updated_region().is_empty() && !encode_unchanged_frame_) 287 if (frame.updated_region().is_empty() && !encode_unchanged_frame_ &&
288 !params.key_frame) {
305 return nullptr; 289 return nullptr;
290 }
306 291
307 // Create or reconfigure the codec to match the size of |frame|. 292 // Create or reconfigure the codec to match the size of |frame|.
308 if (!codec_ || 293 if (!codec_ ||
309 (image_ && 294 (image_ &&
310 !frame.size().equals(webrtc::DesktopSize(image_->w, image_->h)))) { 295 !frame.size().equals(webrtc::DesktopSize(image_->w, image_->h)))) {
311 Configure(frame.size()); 296 Configure(frame.size());
312 } 297 }
313 298
299 UpdateTargetBitrate(params.bitrate_kbps);
300
314 vpx_active_map_t act_map; 301 vpx_active_map_t act_map;
315 act_map.rows = active_map_size_.height(); 302 act_map.rows = active_map_size_.height();
316 act_map.cols = active_map_size_.width(); 303 act_map.cols = active_map_size_.width();
317 act_map.active_map = active_map_.get(); 304 act_map.active_map = active_map_.get();
318 305
319 webrtc::DesktopRegion updated_region; 306 webrtc::DesktopRegion updated_region;
320 if (!frame.updated_region().is_empty()) { 307 if (!frame.updated_region().is_empty()) {
321 // Convert the updated capture data ready for encode. 308 // Convert the updated capture data ready for encode.
322 PrepareImage(frame, &updated_region); 309 PrepareImage(frame, &updated_region);
323 310
324 // Update active map based on updated region. 311 // Update active map based on updated region.
325 SetActiveMapFromRegion(updated_region); 312 SetActiveMapFromRegion(updated_region);
326 313
327 // Apply active map to the encoder. 314 // Apply active map to the encoder.
328 315
329 if (vpx_codec_control(codec_.get(), VP8E_SET_ACTIVEMAP, &act_map)) { 316 if (vpx_codec_control(codec_.get(), VP8E_SET_ACTIVEMAP, &act_map)) {
330 LOG(ERROR) << "Unable to apply active map"; 317 LOG(ERROR) << "Unable to apply active map";
331 } 318 }
332 } 319 }
333 320
334 // Frame rate is adapted based on how well the encoder meets the target
335 // bandwidth requirement. We specify a target rate of 1 / 15 fps here.
336 // TODO(isheriff): Investigate if it makes sense to increase the target FPS.
337 vpx_codec_err_t ret = vpx_codec_encode( 321 vpx_codec_err_t ret = vpx_codec_encode(
338 codec_.get(), image_.get(), 0, 66666, 322 codec_.get(), image_.get(), 0, params.duration.InMicroseconds(),
339 (flags & REQUEST_KEY_FRAME) ? VPX_EFLAG_FORCE_KF : 0, VPX_DL_REALTIME); 323 (params.key_frame) ? VPX_EFLAG_FORCE_KF : 0, VPX_DL_REALTIME);
340 DCHECK_EQ(ret, VPX_CODEC_OK) 324 DCHECK_EQ(ret, VPX_CODEC_OK)
341 << "Encoding error: " << vpx_codec_err_to_string(ret) << "\n" 325 << "Encoding error: " << vpx_codec_err_to_string(ret) << "\n"
342 << "Details: " << vpx_codec_error(codec_.get()) << "\n" 326 << "Details: " << vpx_codec_error(codec_.get()) << "\n"
343 << vpx_codec_error_detail(codec_.get()); 327 << vpx_codec_error_detail(codec_.get());
344 328
345 if (!lossless_encode_) { 329 if (!lossless_encode_) {
346 // VP8 doesn't return active map, so we assume it's the same on the output 330 // VP8 doesn't return active map, so we assume it's the same on the output
347 // as on the input. 331 // as on the input.
348 if (use_vp9_) { 332 if (use_vp9_) {
349 ret = vpx_codec_control(codec_.get(), VP9E_GET_ACTIVEMAP, &act_map); 333 ret = vpx_codec_control(codec_.get(), VP9E_GET_ACTIVEMAP, &act_map);
350 DCHECK_EQ(ret, VPX_CODEC_OK) 334 DCHECK_EQ(ret, VPX_CODEC_OK)
351 << "Failed to fetch active map: " << vpx_codec_err_to_string(ret) 335 << "Failed to fetch active map: " << vpx_codec_err_to_string(ret)
352 << "\n"; 336 << "\n";
353 337
354 // If the encoder output no changes then there's nothing left to top-off. 338 // If the encoder output no changes then there's nothing left to top-off.
355 encode_unchanged_frame_ = !updated_region.is_empty(); 339 encode_unchanged_frame_ = !updated_region.is_empty();
356 } else { 340 } else {
357 // Always set |encode_unchanged_frame_| when using VP8. It will be reset 341 // Always set |encode_unchanged_frame_| when using VP8. It will be reset
358 // below once the target quantizer value is reached. 342 // below once the target quantizer value is reached.
359 encode_unchanged_frame_ = true; 343 encode_unchanged_frame_ = true;
360 } 344 }
361 345
362 UpdateRegionFromActiveMap(&updated_region); 346 UpdateRegionFromActiveMap(&updated_region);
363 } 347 }
364 348
365 // Read the encoded data. 349 // Read the encoded data.
366 vpx_codec_iter_t iter = nullptr; 350 vpx_codec_iter_t iter = nullptr;
367 bool got_data = false; 351 bool got_data = false;
368 352
369 // TODO(hclam): Make sure we get exactly one frame from the packet. 353 std::unique_ptr<EncodedFrame> encoded_frame(new EncodedFrame());
370 // TODO(hclam): We should provide the output buffer to avoid one copy. 354 encoded_frame->size = frame.size();
371 std::unique_ptr<VideoPacket> packet(
372 helper_.CreateVideoPacketWithUpdatedRegion(frame, updated_region));
373 packet->mutable_format()->set_encoding(VideoPacketFormat::ENCODING_VP8);
374 355
375 while (!got_data) { 356 while (!got_data) {
376 const vpx_codec_cx_pkt_t* vpx_packet = 357 const vpx_codec_cx_pkt_t* vpx_packet =
377 vpx_codec_get_cx_data(codec_.get(), &iter); 358 vpx_codec_get_cx_data(codec_.get(), &iter);
378 if (!vpx_packet) 359 if (!vpx_packet)
379 continue; 360 continue;
380 361
381 switch (vpx_packet->kind) { 362 switch (vpx_packet->kind) {
382 case VPX_CODEC_CX_FRAME_PKT: { 363 case VPX_CODEC_CX_FRAME_PKT: {
383 got_data = true; 364 got_data = true;
384 packet->set_data(vpx_packet->data.frame.buf, vpx_packet->data.frame.sz); 365 // TODO(sergeyu): Avoid copying the data here..
385 packet->set_key_frame(vpx_packet->data.frame.flags & VPX_FRAME_IS_KEY); 366 encoded_frame->data.assign(
367 reinterpret_cast<const char*>(vpx_packet->data.frame.buf),
368 vpx_packet->data.frame.sz);
369 encoded_frame->key_frame =
370 vpx_packet->data.frame.flags & VPX_FRAME_IS_KEY;
386 int quantizer = -1; 371 int quantizer = -1;
387 CHECK_EQ(vpx_codec_control(codec_.get(), VP8E_GET_LAST_QUANTIZER_64, 372 CHECK_EQ(vpx_codec_control(codec_.get(), VP8E_GET_LAST_QUANTIZER_64,
388 &quantizer), 373 &quantizer),
389 VPX_CODEC_OK); 374 VPX_CODEC_OK);
390 // VP8: Stop top-off as soon as the target quantizer value is reached. 375 // VP8: Stop top-off as soon as the target quantizer value is reached.
391 if (!use_vp9_ && quantizer <= kTargetQuantizerForVp8TopOff) 376 if (!use_vp9_ && quantizer <= kTargetQuantizerForVp8TopOff)
392 encode_unchanged_frame_ = false; 377 encode_unchanged_frame_ = false;
393 break; 378 break;
394 } 379 }
395 default: 380 default:
396 break; 381 break;
397 } 382 }
398 } 383 }
399 384
400 return packet; 385 return encoded_frame;
401 } 386 }
402 387
403 WebrtcVideoEncoderVpx::WebrtcVideoEncoderVpx(bool use_vp9) 388 WebrtcVideoEncoderVpx::WebrtcVideoEncoderVpx(bool use_vp9)
404 : use_vp9_(use_vp9), 389 : use_vp9_(use_vp9),
405 target_bitrate_kbps_(kDefaultTargetBitrateKbps), 390 target_bitrate_kbps_(kDefaultTargetBitrateKbps),
406 encode_unchanged_frame_(false), 391 encode_unchanged_frame_(false),
407 clock_(&default_tick_clock_) { 392 clock_(&default_tick_clock_) {
408 // Indicates config is still uninitialized. 393 // Indicates config is still uninitialized.
409 config_.g_timebase.den = 0; 394 config_.g_timebase.den = 0;
410 } 395 }
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
460 } 445 }
461 446
462 // Apply further customizations to the codec now it's initialized. 447 // Apply further customizations to the codec now it's initialized.
463 if (use_vp9_) { 448 if (use_vp9_) {
464 SetVp9CodecOptions(codec_.get(), lossless_encode_); 449 SetVp9CodecOptions(codec_.get(), lossless_encode_);
465 } else { 450 } else {
466 SetVp8CodecOptions(codec_.get()); 451 SetVp8CodecOptions(codec_.get());
467 } 452 }
468 } 453 }
469 454
455 void WebrtcVideoEncoderVpx::UpdateTargetBitrate(int new_bitrate_kbps) {
456 target_bitrate_kbps_ = new_bitrate_kbps;
457
458 // Configuration not initialized.
459 if (config_.g_timebase.den == 0)
460 return;
461
462 if (config_.rc_target_bitrate == static_cast<unsigned int>(new_bitrate_kbps))
463 return;
464 config_.rc_target_bitrate = new_bitrate_kbps;
465
466 // Update encoder context.
467 if (vpx_codec_enc_config_set(codec_.get(), &config_))
468 NOTREACHED() << "Unable to set encoder config";
469
470 VLOG(1) << "New rc_target_bitrate: " << new_bitrate_kbps << " kbps";
471 }
472
470 void WebrtcVideoEncoderVpx::PrepareImage( 473 void WebrtcVideoEncoderVpx::PrepareImage(
471 const webrtc::DesktopFrame& frame, 474 const webrtc::DesktopFrame& frame,
472 webrtc::DesktopRegion* updated_region) { 475 webrtc::DesktopRegion* updated_region) {
473 if (frame.updated_region().is_empty()) { 476 if (frame.updated_region().is_empty()) {
474 updated_region->Clear(); 477 updated_region->Clear();
475 return; 478 return;
476 } 479 }
477 480
478 updated_region->Clear(); 481 updated_region->Clear();
479 if (image_) { 482 if (image_) {
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
591 kMacroBlockSize * (y + 1))); 594 kMacroBlockSize * (y + 1)));
592 } 595 }
593 x0 = x1 + 1; 596 x0 = x1 + 1;
594 } 597 }
595 } 598 }
596 updated_region->IntersectWith( 599 updated_region->IntersectWith(
597 webrtc::DesktopRect::MakeWH(image_->w, image_->h)); 600 webrtc::DesktopRect::MakeWH(image_->w, image_->h));
598 } 601 }
599 602
600 } // namespace remoting 603 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/codec/webrtc_video_encoder_vpx.h ('k') | remoting/proto/video.proto » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698