OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
(...skipping 23 matching lines...) Expand all Loading... |
34 VideoCodecType PayloadNameToCodecType(const std::string& payload_name) { | 34 VideoCodecType PayloadNameToCodecType(const std::string& payload_name) { |
35 if (payload_name == "VP8") | 35 if (payload_name == "VP8") |
36 return kVideoCodecVP8; | 36 return kVideoCodecVP8; |
37 if (payload_name == "VP9") | 37 if (payload_name == "VP9") |
38 return kVideoCodecVP9; | 38 return kVideoCodecVP9; |
39 if (payload_name == "H264") | 39 if (payload_name == "H264") |
40 return kVideoCodecH264; | 40 return kVideoCodecH264; |
41 return kVideoCodecGeneric; | 41 return kVideoCodecGeneric; |
42 } | 42 } |
43 | 43 |
44 VideoCodec VideoEncoderConfigToVideoCodec(const VideoEncoderConfig& config, | 44 VideoCodec VideoEncoderConfigToVideoCodec( |
45 const std::string& payload_name, | 45 const VideoEncoderConfig& config, |
46 int payload_type) { | 46 const std::vector<VideoStream>& streams, |
47 const std::vector<VideoStream>& streams = config.streams; | 47 const std::string& payload_name, |
| 48 int payload_type) { |
48 static const int kEncoderMinBitrateKbps = 30; | 49 static const int kEncoderMinBitrateKbps = 30; |
49 RTC_DCHECK(!streams.empty()); | 50 RTC_DCHECK(!streams.empty()); |
50 RTC_DCHECK_GE(config.min_transmit_bitrate_bps, 0); | 51 RTC_DCHECK_GE(config.min_transmit_bitrate_bps, 0); |
51 | 52 |
52 VideoCodec video_codec; | 53 VideoCodec video_codec; |
53 memset(&video_codec, 0, sizeof(video_codec)); | 54 memset(&video_codec, 0, sizeof(video_codec)); |
54 video_codec.codecType = PayloadNameToCodecType(payload_name); | 55 video_codec.codecType = PayloadNameToCodecType(payload_name); |
55 | 56 |
56 switch (config.content_type) { | 57 switch (config.content_type) { |
57 case VideoEncoderConfig::ContentType::kRealtimeVideo: | 58 case VideoEncoderConfig::ContentType::kRealtimeVideo: |
58 video_codec.mode = kRealtimeVideo; | 59 video_codec.mode = kRealtimeVideo; |
59 break; | 60 break; |
60 case VideoEncoderConfig::ContentType::kScreen: | 61 case VideoEncoderConfig::ContentType::kScreen: |
61 video_codec.mode = kScreensharing; | 62 video_codec.mode = kScreensharing; |
62 if (config.streams.size() == 1 && | 63 if (streams.size() == 1 && |
63 config.streams[0].temporal_layer_thresholds_bps.size() == 1) { | 64 streams[0].temporal_layer_thresholds_bps.size() == 1) { |
64 video_codec.targetBitrate = | 65 video_codec.targetBitrate = |
65 config.streams[0].temporal_layer_thresholds_bps[0] / 1000; | 66 streams[0].temporal_layer_thresholds_bps[0] / 1000; |
66 } | 67 } |
67 break; | 68 break; |
68 } | 69 } |
69 | 70 |
70 if (config.encoder_specific_settings) | 71 if (config.encoder_specific_settings) |
71 config.encoder_specific_settings->FillEncoderSpecificSettings(&video_codec); | 72 config.encoder_specific_settings->FillEncoderSpecificSettings(&video_codec); |
72 | 73 |
73 switch (video_codec.codecType) { | 74 switch (video_codec.codecType) { |
74 case kVideoCodecVP8: { | 75 case kVideoCodecVP8: { |
75 if (!config.encoder_specific_settings) | 76 if (!config.encoder_specific_settings) |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
162 // Unset max bitrate -> cap to one bit per pixel. | 163 // Unset max bitrate -> cap to one bit per pixel. |
163 video_codec.maxBitrate = | 164 video_codec.maxBitrate = |
164 (video_codec.width * video_codec.height * video_codec.maxFramerate) / | 165 (video_codec.width * video_codec.height * video_codec.maxFramerate) / |
165 1000; | 166 1000; |
166 } | 167 } |
167 if (video_codec.maxBitrate < kEncoderMinBitrateKbps) | 168 if (video_codec.maxBitrate < kEncoderMinBitrateKbps) |
168 video_codec.maxBitrate = kEncoderMinBitrateKbps; | 169 video_codec.maxBitrate = kEncoderMinBitrateKbps; |
169 | 170 |
170 RTC_DCHECK_GT(streams[0].max_framerate, 0); | 171 RTC_DCHECK_GT(streams[0].max_framerate, 0); |
171 video_codec.maxFramerate = streams[0].max_framerate; | 172 video_codec.maxFramerate = streams[0].max_framerate; |
172 video_codec.expect_encode_from_texture = config.expect_encode_from_texture; | |
173 | |
174 return video_codec; | 173 return video_codec; |
175 } | 174 } |
176 | 175 |
177 // TODO(pbos): Lower these thresholds (to closer to 100%) when we handle | 176 // TODO(pbos): Lower these thresholds (to closer to 100%) when we handle |
178 // pipelining encoders better (multiple input frames before something comes | 177 // pipelining encoders better (multiple input frames before something comes |
179 // out). This should effectively turn off CPU adaptations for systems that | 178 // out). This should effectively turn off CPU adaptations for systems that |
180 // remotely cope with the load right now. | 179 // remotely cope with the load right now. |
181 CpuOveruseOptions GetCpuOveruseOptions(bool full_overuse_time) { | 180 CpuOveruseOptions GetCpuOveruseOptions(bool full_overuse_time) { |
182 CpuOveruseOptions options; | 181 CpuOveruseOptions options; |
183 if (full_overuse_time) { | 182 if (full_overuse_time) { |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
299 const VideoSendStream::Config::EncoderSettings& settings, | 298 const VideoSendStream::Config::EncoderSettings& settings, |
300 rtc::VideoSinkInterface<VideoFrame>* pre_encode_callback, | 299 rtc::VideoSinkInterface<VideoFrame>* pre_encode_callback, |
301 LoadObserver* overuse_callback, | 300 LoadObserver* overuse_callback, |
302 EncodedFrameObserver* encoder_timing) | 301 EncodedFrameObserver* encoder_timing) |
303 : shutdown_event_(true /* manual_reset */, false), | 302 : shutdown_event_(true /* manual_reset */, false), |
304 number_of_cores_(number_of_cores), | 303 number_of_cores_(number_of_cores), |
305 source_proxy_(new VideoSourceProxy(this)), | 304 source_proxy_(new VideoSourceProxy(this)), |
306 sink_(nullptr), | 305 sink_(nullptr), |
307 settings_(settings), | 306 settings_(settings), |
308 codec_type_(PayloadNameToCodecType(settings.payload_name)), | 307 codec_type_(PayloadNameToCodecType(settings.payload_name)), |
309 vp_(VideoProcessing::Create()), | |
310 video_sender_(Clock::GetRealTimeClock(), this, this), | 308 video_sender_(Clock::GetRealTimeClock(), this, this), |
311 overuse_detector_(Clock::GetRealTimeClock(), | 309 overuse_detector_(Clock::GetRealTimeClock(), |
312 GetCpuOveruseOptions(settings.full_overuse_time), | 310 GetCpuOveruseOptions(settings.full_overuse_time), |
313 this, | 311 this, |
314 encoder_timing, | 312 encoder_timing, |
315 stats_proxy), | 313 stats_proxy), |
316 load_observer_(overuse_callback), | 314 load_observer_(overuse_callback), |
317 stats_proxy_(stats_proxy), | 315 stats_proxy_(stats_proxy), |
318 pre_encode_callback_(pre_encode_callback), | 316 pre_encode_callback_(pre_encode_callback), |
319 module_process_thread_(nullptr), | 317 module_process_thread_(nullptr), |
320 encoder_config_(), | 318 pending_encoder_reconfiguration_(false), |
321 encoder_start_bitrate_bps_(0), | 319 encoder_start_bitrate_bps_(0), |
322 max_data_payload_length_(0), | 320 max_data_payload_length_(0), |
323 last_observed_bitrate_bps_(0), | 321 last_observed_bitrate_bps_(0), |
324 encoder_paused_and_dropped_frame_(false), | 322 encoder_paused_and_dropped_frame_(false), |
325 has_received_sli_(false), | 323 has_received_sli_(false), |
326 picture_id_sli_(0), | 324 picture_id_sli_(0), |
327 has_received_rpsi_(false), | 325 has_received_rpsi_(false), |
328 picture_id_rpsi_(0), | 326 picture_id_rpsi_(0), |
329 clock_(Clock::GetRealTimeClock()), | 327 clock_(Clock::GetRealTimeClock()), |
330 last_captured_timestamp_(0), | 328 last_captured_timestamp_(0), |
331 delta_ntp_internal_ms_(clock_->CurrentNtpInMilliseconds() - | 329 delta_ntp_internal_ms_(clock_->CurrentNtpInMilliseconds() - |
332 clock_->TimeInMilliseconds()), | 330 clock_->TimeInMilliseconds()), |
333 last_frame_log_ms_(clock_->TimeInMilliseconds()), | 331 last_frame_log_ms_(clock_->TimeInMilliseconds()), |
334 captured_frame_count_(0), | 332 captured_frame_count_(0), |
335 dropped_frame_count_(0), | 333 dropped_frame_count_(0), |
336 encoder_queue_("EncoderQueue") { | 334 encoder_queue_("EncoderQueue") { |
337 vp_->EnableTemporalDecimation(false); | |
338 | |
339 encoder_queue_.PostTask([this, encoder_timing] { | 335 encoder_queue_.PostTask([this, encoder_timing] { |
340 RTC_DCHECK_RUN_ON(&encoder_queue_); | 336 RTC_DCHECK_RUN_ON(&encoder_queue_); |
341 video_sender_.RegisterExternalEncoder( | 337 video_sender_.RegisterExternalEncoder( |
342 settings_.encoder, settings_.payload_type, settings_.internal_source); | 338 settings_.encoder, settings_.payload_type, settings_.internal_source); |
343 overuse_detector_.StartCheckForOveruse(); | 339 overuse_detector_.StartCheckForOveruse(); |
344 }); | 340 }); |
345 } | 341 } |
346 | 342 |
347 ViEEncoder::~ViEEncoder() { | 343 ViEEncoder::~ViEEncoder() { |
348 RTC_DCHECK_RUN_ON(&thread_checker_); | 344 RTC_DCHECK_RUN_ON(&thread_checker_); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
400 size_t max_data_payload_length) { | 396 size_t max_data_payload_length) { |
401 encoder_queue_.PostTask( | 397 encoder_queue_.PostTask( |
402 std::unique_ptr<rtc::QueuedTask>(new ConfigureEncoderTask( | 398 std::unique_ptr<rtc::QueuedTask>(new ConfigureEncoderTask( |
403 this, std::move(config), max_data_payload_length))); | 399 this, std::move(config), max_data_payload_length))); |
404 } | 400 } |
405 | 401 |
406 void ViEEncoder::ConfigureEncoderOnTaskQueue(VideoEncoderConfig config, | 402 void ViEEncoder::ConfigureEncoderOnTaskQueue(VideoEncoderConfig config, |
407 size_t max_data_payload_length) { | 403 size_t max_data_payload_length) { |
408 RTC_DCHECK_RUN_ON(&encoder_queue_); | 404 RTC_DCHECK_RUN_ON(&encoder_queue_); |
409 RTC_DCHECK(sink_); | 405 RTC_DCHECK(sink_); |
410 LOG(LS_INFO) << "ConfigureEncoderOnTaskQueue"; | 406 LOG(LS_INFO) << "ConfigureEncoder requested."; |
411 | 407 |
412 max_data_payload_length_ = max_data_payload_length; | 408 max_data_payload_length_ = max_data_payload_length; |
413 encoder_config_ = std::move(config); | 409 encoder_config_ = std::move(config); |
| 410 pending_encoder_reconfiguration_ = true; |
414 | 411 |
415 VideoCodec video_codec = VideoEncoderConfigToVideoCodec( | 412 // Reconfigure the encoder now if the encoder has an internal source or |
416 encoder_config_, settings_.payload_name, settings_.payload_type); | 413 // if this is the first time the encoder is configured. |
| 414 // Otherwise, the reconfiguration is deferred until the next frame to minimize |
| 415 // the number of reconfigurations. The codec configuration depends on incoming |
| 416 // video frame size. |
| 417 if (!last_frame_info_ || settings_.internal_source) { |
| 418 if (!last_frame_info_) { |
| 419 last_frame_info_ = rtc::Optional<VideoFrameInfo>( |
| 420 VideoFrameInfo(176, 144, kVideoRotation_0, false)); |
| 421 } |
| 422 ReconfigureEncoder(); |
| 423 } |
| 424 } |
417 | 425 |
418 // Setting target width and height for VPM. | 426 void ViEEncoder::ReconfigureEncoder() { |
419 RTC_CHECK_EQ(VPM_OK, | 427 RTC_DCHECK_RUN_ON(&encoder_queue_); |
420 vp_->SetTargetResolution(video_codec.width, video_codec.height, | 428 RTC_DCHECK(pending_encoder_reconfiguration_); |
421 video_codec.maxFramerate)); | 429 std::vector<VideoStream> streams = |
| 430 encoder_config_.video_stream_factory->CreateEncoderStreams( |
| 431 last_frame_info_->width, last_frame_info_->height, encoder_config_); |
422 | 432 |
423 video_codec.startBitrate = | 433 VideoCodec codec = VideoEncoderConfigToVideoCodec( |
424 std::max(encoder_start_bitrate_bps_ / 1000, video_codec.minBitrate); | 434 encoder_config_, streams, settings_.payload_name, settings_.payload_type); |
425 video_codec.startBitrate = | |
426 std::min(video_codec.startBitrate, video_codec.maxBitrate); | |
427 | 435 |
428 bool success = video_sender_.RegisterSendCodec( | 436 codec.startBitrate = |
429 &video_codec, number_of_cores_, | 437 std::max(encoder_start_bitrate_bps_ / 1000, codec.minBitrate); |
430 static_cast<uint32_t>(max_data_payload_length)) == VCM_OK; | 438 codec.startBitrate = std::min(codec.startBitrate, codec.maxBitrate); |
| 439 codec.expect_encode_from_texture = last_frame_info_->is_texture; |
431 | 440 |
| 441 bool success = |
| 442 video_sender_.RegisterSendCodec(&codec, number_of_cores_, |
| 443 max_data_payload_length_) == VCM_OK; |
432 if (!success) { | 444 if (!success) { |
433 LOG(LS_ERROR) << "Failed to configure encoder."; | 445 LOG(LS_ERROR) << "Failed to configure encoder."; |
434 RTC_DCHECK(success); | 446 RTC_DCHECK(success); |
435 } | 447 } |
436 | 448 |
437 rate_allocator_.reset(new SimulcastRateAllocator(video_codec)); | 449 rate_allocator_.reset(new SimulcastRateAllocator(codec)); |
438 if (stats_proxy_) { | 450 if (stats_proxy_) { |
439 stats_proxy_->OnEncoderReconfigured(encoder_config_, | 451 stats_proxy_->OnEncoderReconfigured(encoder_config_, |
440 rate_allocator_->GetPreferedBitrate()); | 452 rate_allocator_->GetPreferedBitrate()); |
441 } | 453 } |
442 | 454 |
| 455 pending_encoder_reconfiguration_ = false; |
| 456 if (stats_proxy_) { |
| 457 stats_proxy_->OnEncoderReconfigured(encoder_config_, |
| 458 rate_allocator_->GetPreferedBitrate()); |
| 459 } |
443 sink_->OnEncoderConfigurationChanged( | 460 sink_->OnEncoderConfigurationChanged( |
444 encoder_config_.streams, encoder_config_.min_transmit_bitrate_bps); | 461 std::move(streams), encoder_config_.min_transmit_bitrate_bps); |
445 } | 462 } |
446 | 463 |
447 void ViEEncoder::OnFrame(const VideoFrame& video_frame) { | 464 void ViEEncoder::OnFrame(const VideoFrame& video_frame) { |
448 RTC_DCHECK_RUNS_SERIALIZED(&incoming_frame_race_checker_); | 465 RTC_DCHECK_RUNS_SERIALIZED(&incoming_frame_race_checker_); |
449 stats_proxy_->OnIncomingFrame(video_frame.width(), video_frame.height()); | 466 stats_proxy_->OnIncomingFrame(video_frame.width(), video_frame.height()); |
450 | 467 |
451 VideoFrame incoming_frame = video_frame; | 468 VideoFrame incoming_frame = video_frame; |
452 | 469 |
453 // Local time in webrtc time base. | 470 // Local time in webrtc time base. |
454 int64_t current_time = clock_->TimeInMilliseconds(); | 471 int64_t current_time = clock_->TimeInMilliseconds(); |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
517 } | 534 } |
518 encoder_paused_and_dropped_frame_ = false; | 535 encoder_paused_and_dropped_frame_ = false; |
519 } | 536 } |
520 | 537 |
521 void ViEEncoder::EncodeVideoFrame(const VideoFrame& video_frame, | 538 void ViEEncoder::EncodeVideoFrame(const VideoFrame& video_frame, |
522 int64_t time_when_posted_in_ms) { | 539 int64_t time_when_posted_in_ms) { |
523 RTC_DCHECK_RUN_ON(&encoder_queue_); | 540 RTC_DCHECK_RUN_ON(&encoder_queue_); |
524 if (pre_encode_callback_) | 541 if (pre_encode_callback_) |
525 pre_encode_callback_->OnFrame(video_frame); | 542 pre_encode_callback_->OnFrame(video_frame); |
526 | 543 |
| 544 if (video_frame.width() != last_frame_info_->width || |
| 545 video_frame.height() != last_frame_info_->height || |
| 546 video_frame.rotation() != last_frame_info_->rotation || |
| 547 video_frame.is_texture() != last_frame_info_->is_texture) { |
| 548 pending_encoder_reconfiguration_ = true; |
| 549 last_frame_info_ = rtc::Optional<VideoFrameInfo>( |
| 550 VideoFrameInfo(video_frame.width(), video_frame.height(), |
| 551 video_frame.rotation(), video_frame.is_texture())); |
| 552 LOG(LS_INFO) << "Video frame parameters changed: dimensions=" |
| 553 << last_frame_info_->width << "x" << last_frame_info_->height |
| 554 << ", rotation=" << last_frame_info_->rotation |
| 555 << ", texture=" << last_frame_info_->is_texture; |
| 556 } |
| 557 |
| 558 if (pending_encoder_reconfiguration_) { |
| 559 ReconfigureEncoder(); |
| 560 } |
| 561 |
527 if (EncoderPaused()) { | 562 if (EncoderPaused()) { |
528 TraceFrameDropStart(); | 563 TraceFrameDropStart(); |
529 return; | 564 return; |
530 } | 565 } |
531 TraceFrameDropEnd(); | 566 TraceFrameDropEnd(); |
532 | 567 |
533 TRACE_EVENT_ASYNC_STEP0("webrtc", "Video", video_frame.render_time_ms(), | 568 TRACE_EVENT_ASYNC_STEP0("webrtc", "Video", video_frame.render_time_ms(), |
534 "Encode"); | 569 "Encode"); |
535 const VideoFrame* frame_to_send = &video_frame; | |
536 // TODO(wuchengli): support texture frames. | |
537 if (!video_frame.video_frame_buffer()->native_handle()) { | |
538 // Pass frame via preprocessor. | |
539 frame_to_send = vp_->PreprocessFrame(video_frame); | |
540 if (!frame_to_send) { | |
541 // Drop this frame, or there was an error processing it. | |
542 return; | |
543 } | |
544 } | |
545 | 570 |
546 overuse_detector_.FrameCaptured(video_frame, time_when_posted_in_ms); | 571 overuse_detector_.FrameCaptured(video_frame, time_when_posted_in_ms); |
547 | 572 |
548 if (codec_type_ == webrtc::kVideoCodecVP8) { | 573 if (codec_type_ == webrtc::kVideoCodecVP8) { |
549 webrtc::CodecSpecificInfo codec_specific_info; | 574 webrtc::CodecSpecificInfo codec_specific_info; |
550 codec_specific_info.codecType = webrtc::kVideoCodecVP8; | 575 codec_specific_info.codecType = webrtc::kVideoCodecVP8; |
551 | 576 |
552 codec_specific_info.codecSpecific.VP8.hasReceivedRPSI = | 577 codec_specific_info.codecSpecific.VP8.hasReceivedRPSI = |
553 has_received_rpsi_; | 578 has_received_rpsi_; |
554 codec_specific_info.codecSpecific.VP8.hasReceivedSLI = | 579 codec_specific_info.codecSpecific.VP8.hasReceivedSLI = |
555 has_received_sli_; | 580 has_received_sli_; |
556 codec_specific_info.codecSpecific.VP8.pictureIdRPSI = | 581 codec_specific_info.codecSpecific.VP8.pictureIdRPSI = |
557 picture_id_rpsi_; | 582 picture_id_rpsi_; |
558 codec_specific_info.codecSpecific.VP8.pictureIdSLI = | 583 codec_specific_info.codecSpecific.VP8.pictureIdSLI = |
559 picture_id_sli_; | 584 picture_id_sli_; |
560 has_received_sli_ = false; | 585 has_received_sli_ = false; |
561 has_received_rpsi_ = false; | 586 has_received_rpsi_ = false; |
562 | 587 |
563 video_sender_.AddVideoFrame(*frame_to_send, &codec_specific_info); | 588 video_sender_.AddVideoFrame(video_frame, &codec_specific_info); |
564 return; | 589 return; |
565 } | 590 } |
566 video_sender_.AddVideoFrame(*frame_to_send, nullptr); | 591 video_sender_.AddVideoFrame(video_frame, nullptr); |
567 } | 592 } |
568 | 593 |
569 void ViEEncoder::SendKeyFrame() { | 594 void ViEEncoder::SendKeyFrame() { |
570 if (!encoder_queue_.IsCurrent()) { | 595 if (!encoder_queue_.IsCurrent()) { |
571 encoder_queue_.PostTask([this] { SendKeyFrame(); }); | 596 encoder_queue_.PostTask([this] { SendKeyFrame(); }); |
572 return; | 597 return; |
573 } | 598 } |
574 RTC_DCHECK_RUN_ON(&encoder_queue_); | 599 RTC_DCHECK_RUN_ON(&encoder_queue_); |
575 video_sender_.IntraFrameRequest(0); | 600 video_sender_.IntraFrameRequest(0); |
576 } | 601 } |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
679 load_observer_->OnLoadUpdate(LoadObserver::kOveruse); | 704 load_observer_->OnLoadUpdate(LoadObserver::kOveruse); |
680 } | 705 } |
681 | 706 |
682 void ViEEncoder::NormalUsage() { | 707 void ViEEncoder::NormalUsage() { |
683 RTC_DCHECK_RUN_ON(&encoder_queue_); | 708 RTC_DCHECK_RUN_ON(&encoder_queue_); |
684 if (load_observer_) | 709 if (load_observer_) |
685 load_observer_->OnLoadUpdate(LoadObserver::kUnderuse); | 710 load_observer_->OnLoadUpdate(LoadObserver::kUnderuse); |
686 } | 711 } |
687 | 712 |
688 } // namespace webrtc | 713 } // namespace webrtc |
OLD | NEW |