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

Unified Diff: webrtc/video/video_send_stream.cc

Issue 2248713003: Revert of Add task queue to Call. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@move_getpadding
Patch Set: Created 4 years, 4 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « webrtc/video/video_send_stream.h ('k') | webrtc/video/video_send_stream_tests.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: webrtc/video/video_send_stream.cc
diff --git a/webrtc/video/video_send_stream.cc b/webrtc/video/video_send_stream.cc
index 2f8241e28ed1c6b0e273d982a83ef09a0ce35f1f..a46bc859e7c1b2647cbcfbaf018da602be2cd3cd 100644
--- a/webrtc/video/video_send_stream.cc
+++ b/webrtc/video/video_send_stream.cc
@@ -7,6 +7,7 @@
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
+
#include "webrtc/video/video_send_stream.h"
#include <algorithm>
@@ -18,6 +19,7 @@
#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/trace_event.h"
+#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h"
#include "webrtc/modules/congestion_controller/include/congestion_controller.h"
#include "webrtc/modules/pacing/packet_router.h"
@@ -25,12 +27,18 @@
#include "webrtc/modules/utility/include/process_thread.h"
#include "webrtc/modules/video_coding/utility/ivf_file_writer.h"
#include "webrtc/video/call_stats.h"
+#include "webrtc/video/video_capture_input.h"
#include "webrtc/video/vie_remb.h"
#include "webrtc/video_send_stream.h"
namespace webrtc {
+class RtcpIntraFrameObserver;
+class TransportFeedbackObserver;
+
static const int kMinSendSidePacketHistorySize = 600;
+static const int kEncoderTimeOutMs = 2000;
+
namespace {
std::vector<RtpRtcp*> CreateRtpRtcpModules(
@@ -144,6 +152,8 @@
<< (pre_encode_callback ? "(I420FrameCallback)" : "nullptr");
ss << ", post_encode_callback: "
<< (post_encode_callback ? "(EncodedFrameObserver)" : "nullptr");
+ ss << ", local_renderer: "
+ << (local_renderer ? "(VideoRenderer)" : "nullptr");
ss << ", render_delay_ms: " << render_delay_ms;
ss << ", target_delay_ms: " << target_delay_ms;
ss << ", suspend_below_min_bitrate: " << (suspend_below_min_bitrate ? "on"
@@ -194,15 +204,192 @@
namespace {
+VideoCodecType PayloadNameToCodecType(const std::string& payload_name) {
+ if (payload_name == "VP8")
+ return kVideoCodecVP8;
+ if (payload_name == "VP9")
+ return kVideoCodecVP9;
+ if (payload_name == "H264")
+ return kVideoCodecH264;
+ return kVideoCodecGeneric;
+}
+
bool PayloadTypeSupportsSkippingFecPackets(const std::string& payload_name) {
- if (payload_name == "VP8" || payload_name == "VP9")
- return true;
- RTC_DCHECK(payload_name == "H264" || payload_name == "FAKE")
- << "unknown payload_name " << payload_name;
+ switch (PayloadNameToCodecType(payload_name)) {
+ case kVideoCodecVP8:
+ case kVideoCodecVP9:
+ return true;
+ case kVideoCodecH264:
+ case kVideoCodecGeneric:
+ return false;
+ case kVideoCodecI420:
+ case kVideoCodecRED:
+ case kVideoCodecULPFEC:
+ case kVideoCodecUnknown:
+ RTC_NOTREACHED();
+ return false;
+ }
+ RTC_NOTREACHED();
return false;
}
-int CalculateMaxPadBitrateBps(const VideoEncoderConfig& config,
+// TODO(pbos): Lower these thresholds (to closer to 100%) when we handle
+// pipelining encoders better (multiple input frames before something comes
+// out). This should effectively turn off CPU adaptations for systems that
+// remotely cope with the load right now.
+CpuOveruseOptions GetCpuOveruseOptions(bool full_overuse_time) {
+ CpuOveruseOptions options;
+ if (full_overuse_time) {
+ options.low_encode_usage_threshold_percent = 150;
+ options.high_encode_usage_threshold_percent = 200;
+ }
+ return options;
+}
+
+VideoCodec VideoEncoderConfigToVideoCodec(const VideoEncoderConfig& config,
+ const std::string& payload_name,
+ int payload_type) {
+ const std::vector<VideoStream>& streams = config.streams;
+ static const int kEncoderMinBitrateKbps = 30;
+ RTC_DCHECK(!streams.empty());
+ RTC_DCHECK_GE(config.min_transmit_bitrate_bps, 0);
+
+ VideoCodec video_codec;
+ memset(&video_codec, 0, sizeof(video_codec));
+ video_codec.codecType = PayloadNameToCodecType(payload_name);
+
+ switch (config.content_type) {
+ case VideoEncoderConfig::ContentType::kRealtimeVideo:
+ video_codec.mode = kRealtimeVideo;
+ break;
+ case VideoEncoderConfig::ContentType::kScreen:
+ video_codec.mode = kScreensharing;
+ if (config.streams.size() == 1 &&
+ config.streams[0].temporal_layer_thresholds_bps.size() == 1) {
+ video_codec.targetBitrate =
+ config.streams[0].temporal_layer_thresholds_bps[0] / 1000;
+ }
+ break;
+ }
+
+ switch (video_codec.codecType) {
+ case kVideoCodecVP8: {
+ if (config.encoder_specific_settings) {
+ video_codec.codecSpecific.VP8 = *reinterpret_cast<const VideoCodecVP8*>(
+ config.encoder_specific_settings);
+ } else {
+ video_codec.codecSpecific.VP8 = VideoEncoder::GetDefaultVp8Settings();
+ }
+ video_codec.codecSpecific.VP8.numberOfTemporalLayers =
+ static_cast<unsigned char>(
+ streams.back().temporal_layer_thresholds_bps.size() + 1);
+ break;
+ }
+ case kVideoCodecVP9: {
+ if (config.encoder_specific_settings) {
+ video_codec.codecSpecific.VP9 = *reinterpret_cast<const VideoCodecVP9*>(
+ config.encoder_specific_settings);
+ if (video_codec.mode == kScreensharing) {
+ video_codec.codecSpecific.VP9.flexibleMode = true;
+ // For now VP9 screensharing use 1 temporal and 2 spatial layers.
+ RTC_DCHECK_EQ(video_codec.codecSpecific.VP9.numberOfTemporalLayers,
+ 1);
+ RTC_DCHECK_EQ(video_codec.codecSpecific.VP9.numberOfSpatialLayers, 2);
+ }
+ } else {
+ video_codec.codecSpecific.VP9 = VideoEncoder::GetDefaultVp9Settings();
+ }
+ video_codec.codecSpecific.VP9.numberOfTemporalLayers =
+ static_cast<unsigned char>(
+ streams.back().temporal_layer_thresholds_bps.size() + 1);
+ break;
+ }
+ case kVideoCodecH264: {
+ if (config.encoder_specific_settings) {
+ video_codec.codecSpecific.H264 =
+ *reinterpret_cast<const VideoCodecH264*>(
+ config.encoder_specific_settings);
+ } else {
+ video_codec.codecSpecific.H264 = VideoEncoder::GetDefaultH264Settings();
+ }
+ break;
+ }
+ default:
+ // TODO(pbos): Support encoder_settings codec-agnostically.
+ RTC_DCHECK(!config.encoder_specific_settings)
+ << "Encoder-specific settings for codec type not wired up.";
+ break;
+ }
+
+ strncpy(video_codec.plName, payload_name.c_str(), kPayloadNameSize - 1);
+ video_codec.plName[kPayloadNameSize - 1] = '\0';
+ video_codec.plType = payload_type;
+ video_codec.numberOfSimulcastStreams =
+ static_cast<unsigned char>(streams.size());
+ video_codec.minBitrate = streams[0].min_bitrate_bps / 1000;
+ if (video_codec.minBitrate < kEncoderMinBitrateKbps)
+ video_codec.minBitrate = kEncoderMinBitrateKbps;
+ RTC_DCHECK_LE(streams.size(), static_cast<size_t>(kMaxSimulcastStreams));
+ if (video_codec.codecType == kVideoCodecVP9) {
+ // If the vector is empty, bitrates will be configured automatically.
+ RTC_DCHECK(config.spatial_layers.empty() ||
+ config.spatial_layers.size() ==
+ video_codec.codecSpecific.VP9.numberOfSpatialLayers);
+ RTC_DCHECK_LE(video_codec.codecSpecific.VP9.numberOfSpatialLayers,
+ kMaxSimulcastStreams);
+ for (size_t i = 0; i < config.spatial_layers.size(); ++i)
+ video_codec.spatialLayers[i] = config.spatial_layers[i];
+ }
+ for (size_t i = 0; i < streams.size(); ++i) {
+ SimulcastStream* sim_stream = &video_codec.simulcastStream[i];
+ RTC_DCHECK_GT(streams[i].width, 0u);
+ RTC_DCHECK_GT(streams[i].height, 0u);
+ RTC_DCHECK_GT(streams[i].max_framerate, 0);
+ // Different framerates not supported per stream at the moment.
+ RTC_DCHECK_EQ(streams[i].max_framerate, streams[0].max_framerate);
+ RTC_DCHECK_GE(streams[i].min_bitrate_bps, 0);
+ RTC_DCHECK_GE(streams[i].target_bitrate_bps, streams[i].min_bitrate_bps);
+ RTC_DCHECK_GE(streams[i].max_bitrate_bps, streams[i].target_bitrate_bps);
+ RTC_DCHECK_GE(streams[i].max_qp, 0);
+
+ sim_stream->width = static_cast<uint16_t>(streams[i].width);
+ sim_stream->height = static_cast<uint16_t>(streams[i].height);
+ sim_stream->minBitrate = streams[i].min_bitrate_bps / 1000;
+ sim_stream->targetBitrate = streams[i].target_bitrate_bps / 1000;
+ sim_stream->maxBitrate = streams[i].max_bitrate_bps / 1000;
+ sim_stream->qpMax = streams[i].max_qp;
+ sim_stream->numberOfTemporalLayers = static_cast<unsigned char>(
+ streams[i].temporal_layer_thresholds_bps.size() + 1);
+
+ video_codec.width = std::max(video_codec.width,
+ static_cast<uint16_t>(streams[i].width));
+ video_codec.height = std::max(
+ video_codec.height, static_cast<uint16_t>(streams[i].height));
+ video_codec.minBitrate =
+ std::min(static_cast<uint16_t>(video_codec.minBitrate),
+ static_cast<uint16_t>(streams[i].min_bitrate_bps / 1000));
+ video_codec.maxBitrate += streams[i].max_bitrate_bps / 1000;
+ video_codec.qpMax = std::max(video_codec.qpMax,
+ static_cast<unsigned int>(streams[i].max_qp));
+ }
+
+ if (video_codec.maxBitrate == 0) {
+ // Unset max bitrate -> cap to one bit per pixel.
+ video_codec.maxBitrate =
+ (video_codec.width * video_codec.height * video_codec.maxFramerate) /
+ 1000;
+ }
+ if (video_codec.maxBitrate < kEncoderMinBitrateKbps)
+ video_codec.maxBitrate = kEncoderMinBitrateKbps;
+
+ RTC_DCHECK_GT(streams[0].max_framerate, 0);
+ video_codec.maxFramerate = streams[0].max_framerate;
+ video_codec.expect_encode_from_texture = config.expect_encode_from_texture;
+
+ return video_codec;
+}
+
+int CalulcateMaxPadBitrateBps(const VideoEncoderConfig& config,
bool pad_to_min_bitrate) {
int pad_up_to_bitrate_bps = 0;
// Calculate max padding bitrate for a multi layer codec.
@@ -226,443 +413,87 @@
} // namespace
namespace internal {
-
-// VideoSendStreamImpl implements internal::VideoSendStream.
-// It is created and destroyed on |worker_queue|. The intent is to decrease the
-// need for locking and to ensure methods are called in sequence.
-// Public methods except |DeliverRtcp| must be called on |worker_queue|.
-// DeliverRtcp is called on the libjingle worker thread or a network thread.
-// An encoder may deliver frames through the EncodedImageCallback on an
-// arbitrary thread.
-class VideoSendStreamImpl : public webrtc::BitrateAllocatorObserver,
- public webrtc::VCMProtectionCallback,
- public EncodedImageCallback {
- public:
- VideoSendStreamImpl(SendStatisticsProxy* stats_proxy,
- rtc::TaskQueue* worker_queue,
- CallStats* call_stats,
- CongestionController* congestion_controller,
- BitrateAllocator* bitrate_allocator,
- SendDelayStats* send_delay_stats,
- VieRemb* remb,
- ViEEncoder* vie_encoder,
- RtcEventLog* event_log,
- const VideoSendStream::Config* config,
- std::map<uint32_t, RtpState> suspended_ssrcs);
- ~VideoSendStreamImpl() override;
-
- // RegisterProcessThread register |module_process_thread| with those objects
- // that use it. Registration has to happen on the thread were
- // |module_process_thread| was created (libjingle's worker thread).
- // TODO(perkj): Replace the use of |module_process_thread| with a TaskQueue,
- // maybe |worker_queue|.
- void RegisterProcessThread(ProcessThread* module_process_thread);
- void DeRegisterProcessThread();
-
- void SignalNetworkState(NetworkState state);
- bool DeliverRtcp(const uint8_t* packet, size_t length);
- void Start();
- void Stop();
-
- void SignalEncoderConfigurationChanged(const VideoEncoderConfig& config);
- VideoSendStream::RtpStateMap GetRtpStates() const;
-
- private:
- class CheckEncoderActivityTask;
-
- // Implements BitrateAllocatorObserver.
- uint32_t OnBitrateUpdated(uint32_t bitrate_bps,
- uint8_t fraction_loss,
- int64_t rtt) override;
-
- // Implements webrtc::VCMProtectionCallback.
- int ProtectionRequest(const FecProtectionParams* delta_params,
- const FecProtectionParams* key_params,
- uint32_t* sent_video_rate_bps,
- uint32_t* sent_nack_rate_bps,
- uint32_t* sent_fec_rate_bps) override;
-
- // Implements EncodedImageCallback. The implementation routes encoded frames
- // to the |payload_router_| and |config.pre_encode_callback| if set.
- // Called on an arbitrary encoder callback thread.
- EncodedImageCallback::Result OnEncodedImage(
- const EncodedImage& encoded_image,
- const CodecSpecificInfo* codec_specific_info,
- const RTPFragmentationHeader* fragmentation) override;
-
- void ConfigureProtection();
- void ConfigureSsrcs();
- void SignalEncoderTimedOut();
- void SignalEncoderActive();
-
- SendStatisticsProxy* const stats_proxy_;
- const VideoSendStream::Config* const config_;
- std::map<uint32_t, RtpState> suspended_ssrcs_;
-
- ProcessThread* module_process_thread_;
- rtc::ThreadChecker module_process_thread_checker_;
- rtc::TaskQueue* const worker_queue_;
-
- rtc::CriticalSection encoder_activity_crit_sect_;
- CheckEncoderActivityTask* check_encoder_activity_task_
- GUARDED_BY(encoder_activity_crit_sect_);
- CallStats* const call_stats_;
- CongestionController* const congestion_controller_;
- BitrateAllocator* const bitrate_allocator_;
- VieRemb* const remb_;
-
- static const bool kEnableFrameRecording = false;
- static const int kMaxLayers = 3;
- std::unique_ptr<IvfFileWriter> file_writers_[kMaxLayers];
-
- int max_padding_bitrate_;
- int encoder_min_bitrate_bps_;
- uint32_t encoder_max_bitrate_bps_;
- uint32_t encoder_target_rate_bps_;
-
- ViEEncoder* const vie_encoder_;
- EncoderStateFeedback encoder_feedback_;
- ProtectionBitrateCalculator protection_bitrate_calculator_;
-
- const std::unique_ptr<RtcpBandwidthObserver> bandwidth_observer_;
- // RtpRtcp modules, declared here as they use other members on construction.
- const std::vector<RtpRtcp*> rtp_rtcp_modules_;
- PayloadRouter payload_router_;
-};
-
-// TODO(tommi): See if there's a more elegant way to create a task that creates
-// an object on the correct task queue.
-class VideoSendStream::ConstructionTask : public rtc::QueuedTask {
- public:
- ConstructionTask(std::unique_ptr<VideoSendStreamImpl>* send_stream,
- rtc::Event* done_event,
- SendStatisticsProxy* stats_proxy,
- ViEEncoder* vie_encoder,
- ProcessThread* module_process_thread,
- CallStats* call_stats,
- CongestionController* congestion_controller,
- BitrateAllocator* bitrate_allocator,
- SendDelayStats* send_delay_stats,
- VieRemb* remb,
- RtcEventLog* event_log,
- const VideoSendStream::Config* config,
- const std::map<uint32_t, RtpState>& suspended_ssrcs)
- : send_stream_(send_stream),
- done_event_(done_event),
- stats_proxy_(stats_proxy),
- vie_encoder_(vie_encoder),
- call_stats_(call_stats),
- congestion_controller_(congestion_controller),
- bitrate_allocator_(bitrate_allocator),
- send_delay_stats_(send_delay_stats),
- remb_(remb),
- event_log_(event_log),
- config_(config),
- suspended_ssrcs_(suspended_ssrcs) {}
-
- ~ConstructionTask() override { done_event_->Set(); }
-
- private:
- bool Run() override {
- send_stream_->reset(new VideoSendStreamImpl(
- stats_proxy_, rtc::TaskQueue::Current(), call_stats_,
- congestion_controller_, bitrate_allocator_, send_delay_stats_, remb_,
- vie_encoder_, event_log_, config_, std::move(suspended_ssrcs_)));
- return true;
- }
-
- std::unique_ptr<VideoSendStreamImpl>* const send_stream_;
- rtc::Event* const done_event_;
- SendStatisticsProxy* const stats_proxy_;
- ViEEncoder* const vie_encoder_;
- CallStats* const call_stats_;
- CongestionController* const congestion_controller_;
- BitrateAllocator* const bitrate_allocator_;
- SendDelayStats* const send_delay_stats_;
- VieRemb* const remb_;
- RtcEventLog* const event_log_;
- const VideoSendStream::Config* config_;
- std::map<uint32_t, RtpState> suspended_ssrcs_;
-};
-
-class VideoSendStream::DestructAndGetRtpStateTask : public rtc::QueuedTask {
- public:
- DestructAndGetRtpStateTask(VideoSendStream::RtpStateMap* state_map,
- std::unique_ptr<VideoSendStreamImpl> send_stream,
- rtc::Event* done_event)
- : state_map_(state_map),
- send_stream_(std::move(send_stream)),
- done_event_(done_event) {}
-
- ~DestructAndGetRtpStateTask() override { RTC_CHECK(!send_stream_); }
-
- private:
- bool Run() override {
- send_stream_->Stop();
- *state_map_ = send_stream_->GetRtpStates();
- send_stream_.reset();
- done_event_->Set();
- return true;
- }
-
- VideoSendStream::RtpStateMap* state_map_;
- std::unique_ptr<VideoSendStreamImpl> send_stream_;
- rtc::Event* done_event_;
-};
-
-// CheckEncoderActivityTask is used for tracking when the encoder last produced
-// and encoded video frame. If the encoder has not produced anything the last
-// kEncoderTimeOutMs we also want to stop sending padding.
-class VideoSendStreamImpl::CheckEncoderActivityTask : public rtc::QueuedTask {
- public:
- static const int kEncoderTimeOutMs = 2000;
- explicit CheckEncoderActivityTask(VideoSendStreamImpl* send_stream)
- : activity_(0), send_stream_(send_stream), timed_out_(false) {}
-
- void Stop() {
- RTC_CHECK(task_checker_.CalledSequentially());
- send_stream_ = nullptr;
- }
-
- void UpdateEncoderActivity() {
- // UpdateEncoderActivity is called from VideoSendStreamImpl::Encoded on
- // whatever thread the real encoder implementation run on. In the case of
- // hardware encoders, there might be several encoders
- // running in parallel on different threads.
- rtc::AtomicOps::ReleaseStore(&activity_, 1);
- }
-
- private:
- bool Run() override {
- RTC_CHECK(task_checker_.CalledSequentially());
- if (!send_stream_)
- return true;
- if (!rtc::AtomicOps::AcquireLoad(&activity_)) {
- if (!timed_out_) {
- send_stream_->SignalEncoderTimedOut();
- }
- timed_out_ = true;
- } else if (timed_out_) {
- send_stream_->SignalEncoderActive();
- timed_out_ = false;
- }
- rtc::AtomicOps::ReleaseStore(&activity_, 0);
-
- rtc::TaskQueue::Current()->PostDelayedTask(
- std::unique_ptr<rtc::QueuedTask>(this), kEncoderTimeOutMs);
- // Return false to prevent this task from being deleted. Ownership has been
- // transferred to the task queue when PostDelayedTask was called.
- return false;
- }
- volatile int activity_;
-
- rtc::SequencedTaskChecker task_checker_;
- VideoSendStreamImpl* send_stream_;
- bool timed_out_;
-};
-
-class ReconfigureVideoEncoderTask : public rtc::QueuedTask {
- public:
- ReconfigureVideoEncoderTask(VideoSendStreamImpl* send_stream,
- VideoEncoderConfig config)
- : send_stream_(send_stream), config_(std::move(config)) {}
-
- private:
- bool Run() override {
- send_stream_->SignalEncoderConfigurationChanged(std::move(config_));
- return true;
- }
-
- VideoSendStreamImpl* send_stream_;
- VideoEncoderConfig config_;
-};
-
VideoSendStream::VideoSendStream(
int num_cpu_cores,
ProcessThread* module_process_thread,
- rtc::TaskQueue* worker_queue,
CallStats* call_stats,
CongestionController* congestion_controller,
BitrateAllocator* bitrate_allocator,
SendDelayStats* send_delay_stats,
VieRemb* remb,
RtcEventLog* event_log,
- VideoSendStream::Config config,
- VideoEncoderConfig encoder_config,
+ const VideoSendStream::Config& config,
+ const VideoEncoderConfig& encoder_config,
const std::map<uint32_t, RtpState>& suspended_ssrcs)
- : worker_queue_(worker_queue),
- thread_sync_event_(false /* manual_reset */, false),
- stats_proxy_(Clock::GetRealTimeClock(),
+ : stats_proxy_(Clock::GetRealTimeClock(),
config,
encoder_config.content_type),
- config_(std::move(config)) {
- vie_encoder_.reset(
- new ViEEncoder(num_cpu_cores, &stats_proxy_, config_.encoder_settings,
- config_.pre_encode_callback, config_.overuse_callback,
- config_.post_encode_callback));
-
- worker_queue_->PostTask(std::unique_ptr<rtc::QueuedTask>(new ConstructionTask(
- &send_stream_, &thread_sync_event_, &stats_proxy_, vie_encoder_.get(),
- module_process_thread, call_stats, congestion_controller,
- bitrate_allocator, send_delay_stats, remb, event_log, &config_,
- suspended_ssrcs)));
-
- // Wait for ConstructionTask to complete so that |send_stream_| can be used.
- // |module_process_thread| must be registered and deregistered on the thread
- // it was created on.
- thread_sync_event_.Wait(rtc::Event::kForever);
- send_stream_->RegisterProcessThread(module_process_thread);
-
- vie_encoder_->RegisterProcessThread(module_process_thread);
-
- ReconfigureVideoEncoder(std::move(encoder_config));
-}
-
-VideoSendStream::~VideoSendStream() {
- RTC_DCHECK_RUN_ON(&thread_checker_);
- RTC_DCHECK(!send_stream_);
-}
-
-void VideoSendStream::Start() {
- RTC_DCHECK_RUN_ON(&thread_checker_);
- LOG(LS_INFO) << "VideoSendStream::Start";
- VideoSendStreamImpl* send_stream = send_stream_.get();
- worker_queue_->PostTask([this, send_stream] {
- send_stream->Start();
- thread_sync_event_.Set();
- });
-
- // It is expected that after VideoSendStream::Start has been called, incoming
- // frames are not dropped in ViEEncoder. To ensure this, Start has to be
- // synchronized.
- thread_sync_event_.Wait(rtc::Event::kForever);
-}
-
-void VideoSendStream::Stop() {
- RTC_DCHECK_RUN_ON(&thread_checker_);
- LOG(LS_INFO) << "VideoSendStream::Stop";
- VideoSendStreamImpl* send_stream = send_stream_.get();
- worker_queue_->PostTask([send_stream] { send_stream->Stop(); });
-}
-
-VideoCaptureInput* VideoSendStream::Input() {
- // Input() will be called on the thread that deliverers video frames from
- // libjingle.
- // TODO(perkj): Refactor ViEEncoder to register directly as a VideoSink to the
- // VideoSource.
- return vie_encoder_.get();
-}
-
-void VideoSendStream::ReconfigureVideoEncoder(VideoEncoderConfig config) {
- // ReconfigureVideoEncoder will be called on the thread that deliverers video
- // frames. We must change the encoder settings immediately so that
- // the codec settings matches the next frame.
- // TODO(perkj): Move logic for reconfiguration the encoder due to frame size
- // change from WebRtcVideoChannel2::WebRtcVideoSendStream::OnFrame to
- // be internally handled by ViEEncoder.
- vie_encoder_->ConfigureEncoder(config, config_.rtp.max_packet_size);
-
- worker_queue_->PostTask(std::unique_ptr<rtc::QueuedTask>(
- new ReconfigureVideoEncoderTask(send_stream_.get(), std::move(config))));
-}
-
-VideoSendStream::Stats VideoSendStream::GetStats() {
- // TODO(perkj, solenberg): Some test cases in EndToEndTest call GetStats from
- // a network thread. See comment in Call::GetStats().
- // RTC_DCHECK_RUN_ON(&thread_checker_);
- return stats_proxy_.GetStats();
-}
-
-void VideoSendStream::SignalNetworkState(NetworkState state) {
- RTC_DCHECK_RUN_ON(&thread_checker_);
- VideoSendStreamImpl* send_stream = send_stream_.get();
- worker_queue_->PostTask(
- [send_stream, state] { send_stream->SignalNetworkState(state); });
-}
-
-VideoSendStream::RtpStateMap VideoSendStream::StopPermanentlyAndGetRtpStates() {
- RTC_DCHECK_RUN_ON(&thread_checker_);
- vie_encoder_->Stop();
- vie_encoder_->DeRegisterProcessThread();
- VideoSendStream::RtpStateMap state_map;
- send_stream_->DeRegisterProcessThread();
- worker_queue_->PostTask(
- std::unique_ptr<rtc::QueuedTask>(new DestructAndGetRtpStateTask(
- &state_map, std::move(send_stream_), &thread_sync_event_)));
- thread_sync_event_.Wait(rtc::Event::kForever);
- return state_map;
-}
-
-bool VideoSendStream::DeliverRtcp(const uint8_t* packet, size_t length) {
- // Called on a network thread.
- return send_stream_->DeliverRtcp(packet, length);
-}
-
-VideoSendStreamImpl::VideoSendStreamImpl(
- SendStatisticsProxy* stats_proxy,
- rtc::TaskQueue* worker_queue,
- CallStats* call_stats,
- CongestionController* congestion_controller,
- BitrateAllocator* bitrate_allocator,
- SendDelayStats* send_delay_stats,
- VieRemb* remb,
- ViEEncoder* vie_encoder,
- RtcEventLog* event_log,
- const VideoSendStream::Config* config,
- std::map<uint32_t, RtpState> suspended_ssrcs)
- : stats_proxy_(stats_proxy),
config_(config),
- suspended_ssrcs_(std::move(suspended_ssrcs)),
- module_process_thread_(nullptr),
- worker_queue_(worker_queue),
- check_encoder_activity_task_(nullptr),
+ suspended_ssrcs_(suspended_ssrcs),
+ module_process_thread_(module_process_thread),
call_stats_(call_stats),
congestion_controller_(congestion_controller),
bitrate_allocator_(bitrate_allocator),
remb_(remb),
- max_padding_bitrate_(0),
- encoder_min_bitrate_bps_(0),
+ encoder_thread_(EncoderThreadFunction, this, "EncoderThread"),
+ encoder_wakeup_event_(false, false),
+ stop_encoder_thread_(0),
encoder_max_bitrate_bps_(0),
encoder_target_rate_bps_(0),
- vie_encoder_(vie_encoder),
+ state_(State::kStopped),
+ overuse_detector_(
+ Clock::GetRealTimeClock(),
+ GetCpuOveruseOptions(config.encoder_settings.full_overuse_time),
+ this,
+ config.post_encode_callback,
+ &stats_proxy_),
+ vie_encoder_(num_cpu_cores,
+ module_process_thread_,
+ &stats_proxy_,
+ &overuse_detector_,
+ this),
encoder_feedback_(Clock::GetRealTimeClock(),
- config_->rtp.ssrcs,
- vie_encoder),
+ config.rtp.ssrcs,
+ &vie_encoder_),
protection_bitrate_calculator_(Clock::GetRealTimeClock(), this),
+ video_sender_(vie_encoder_.video_sender()),
bandwidth_observer_(congestion_controller_->GetBitrateController()
->CreateRtcpBandwidthObserver()),
rtp_rtcp_modules_(CreateRtpRtcpModules(
- config_->send_transport,
+ config.send_transport,
&encoder_feedback_,
bandwidth_observer_.get(),
congestion_controller_->GetTransportFeedbackObserver(),
call_stats_->rtcp_rtt_stats(),
congestion_controller_->pacer(),
congestion_controller_->packet_router(),
- stats_proxy_,
+ &stats_proxy_,
send_delay_stats,
event_log,
congestion_controller_->GetRetransmissionRateLimiter(),
- config_->rtp.ssrcs.size())),
- payload_router_(rtp_rtcp_modules_,
- config_->encoder_settings.payload_type) {
- RTC_DCHECK_RUN_ON(worker_queue_);
- LOG(LS_INFO) << "VideoSendStreamInternal: " << config_->ToString();
- module_process_thread_checker_.DetachFromThread();
-
- RTC_DCHECK(!config_->rtp.ssrcs.empty());
+ config_.rtp.ssrcs.size())),
+ payload_router_(rtp_rtcp_modules_, config.encoder_settings.payload_type),
+ input_(&encoder_wakeup_event_,
+ config_.local_renderer,
+ &stats_proxy_,
+ &overuse_detector_) {
+ LOG(LS_INFO) << "VideoSendStream: " << config_.ToString();
+
+ RTC_DCHECK(!config_.rtp.ssrcs.empty());
+ RTC_DCHECK(module_process_thread_);
RTC_DCHECK(call_stats_);
RTC_DCHECK(congestion_controller_);
RTC_DCHECK(remb_);
// RTP/RTCP initialization.
for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_) {
+ module_process_thread_->RegisterModule(rtp_rtcp);
congestion_controller_->packet_router()->AddRtpModule(rtp_rtcp);
}
- for (size_t i = 0; i < config_->rtp.extensions.size(); ++i) {
- const std::string& extension = config_->rtp.extensions[i].uri;
- int id = config_->rtp.extensions[i].id;
+ for (size_t i = 0; i < config_.rtp.extensions.size(); ++i) {
+ const std::string& extension = config_.rtp.extensions[i].uri;
+ int id = config_.rtp.extensions[i].id;
// One-byte-extension local identifiers are in the range 1-14 inclusive.
RTC_DCHECK_GE(id, 1);
RTC_DCHECK_LE(id, 14);
@@ -680,184 +511,263 @@
ConfigureSsrcs();
// TODO(pbos): Should we set CNAME on all RTP modules?
- rtp_rtcp_modules_.front()->SetCNAME(config_->rtp.c_name.c_str());
+ rtp_rtcp_modules_.front()->SetCNAME(config_.rtp.c_name.c_str());
// 28 to match packet overhead in ModuleRtpRtcpImpl.
static const size_t kRtpPacketSizeOverhead = 28;
- RTC_DCHECK_LE(config_->rtp.max_packet_size, 0xFFFFu + kRtpPacketSizeOverhead);
- const uint16_t mtu = static_cast<uint16_t>(config_->rtp.max_packet_size +
+ RTC_DCHECK_LE(config_.rtp.max_packet_size, 0xFFFFu + kRtpPacketSizeOverhead);
+ const uint16_t mtu = static_cast<uint16_t>(config_.rtp.max_packet_size +
kRtpPacketSizeOverhead);
for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_) {
- rtp_rtcp->RegisterRtcpStatisticsCallback(stats_proxy_);
- rtp_rtcp->RegisterSendChannelRtpStatisticsCallback(stats_proxy_);
+ rtp_rtcp->RegisterRtcpStatisticsCallback(&stats_proxy_);
+ rtp_rtcp->RegisterSendChannelRtpStatisticsCallback(&stats_proxy_);
rtp_rtcp->SetMaxTransferUnit(mtu);
rtp_rtcp->RegisterVideoSendPayload(
- config_->encoder_settings.payload_type,
- config_->encoder_settings.payload_name.c_str());
- }
-
- RTC_DCHECK(config_->encoder_settings.encoder);
- RTC_DCHECK_GE(config_->encoder_settings.payload_type, 0);
- RTC_DCHECK_LE(config_->encoder_settings.payload_type, 127);
-
- vie_encoder_->SetStartBitrate(bitrate_allocator_->GetStartBitrate(this));
- vie_encoder_->SetSink(this);
-}
-
-void VideoSendStreamImpl::RegisterProcessThread(
- ProcessThread* module_process_thread) {
- RTC_DCHECK_RUN_ON(&module_process_thread_checker_);
- RTC_DCHECK(!module_process_thread_);
- module_process_thread_ = module_process_thread;
-
- for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_)
- module_process_thread_->RegisterModule(rtp_rtcp);
-}
-
-void VideoSendStreamImpl::DeRegisterProcessThread() {
- RTC_DCHECK_RUN_ON(&module_process_thread_checker_);
- for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_)
- module_process_thread_->DeRegisterModule(rtp_rtcp);
-}
-
-VideoSendStreamImpl::~VideoSendStreamImpl() {
- RTC_DCHECK_RUN_ON(worker_queue_);
- RTC_DCHECK(!payload_router_.active())
- << "VideoSendStreamImpl::Stop not called";
- LOG(LS_INFO) << "~VideoSendStreamInternal: " << config_->ToString();
+ config_.encoder_settings.payload_type,
+ config_.encoder_settings.payload_name.c_str());
+ }
+
+ RTC_DCHECK(config.encoder_settings.encoder);
+ RTC_DCHECK_GE(config.encoder_settings.payload_type, 0);
+ RTC_DCHECK_LE(config.encoder_settings.payload_type, 127);
+ ReconfigureVideoEncoder(encoder_config);
+
+ module_process_thread_->RegisterModule(&overuse_detector_);
+
+ encoder_thread_checker_.DetachFromThread();
+ encoder_thread_.Start();
+ encoder_thread_.SetPriority(rtc::kHighPriority);
+}
+
+VideoSendStream::~VideoSendStream() {
+ LOG(LS_INFO) << "~VideoSendStream: " << config_.ToString();
+
+ Stop();
+
+ // Stop the encoder thread permanently.
+ rtc::AtomicOps::ReleaseStore(&stop_encoder_thread_, 1);
+ encoder_wakeup_event_.Set();
+ encoder_thread_.Stop();
+
+ // This needs to happen after stopping the encoder thread,
+ // since the encoder thread calls AddObserver.
+ bitrate_allocator_->RemoveObserver(this);
+
+ module_process_thread_->DeRegisterModule(&overuse_detector_);
rtp_rtcp_modules_[0]->SetREMBStatus(false);
remb_->RemoveRembSender(rtp_rtcp_modules_[0]);
for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_) {
congestion_controller_->packet_router()->RemoveRtpModule(rtp_rtcp);
+ module_process_thread_->DeRegisterModule(rtp_rtcp);
delete rtp_rtcp;
}
}
-bool VideoSendStreamImpl::DeliverRtcp(const uint8_t* packet, size_t length) {
- // Runs on a network thread.
- RTC_DCHECK(!worker_queue_->IsCurrent());
+bool VideoSendStream::DeliverRtcp(const uint8_t* packet, size_t length) {
for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_)
rtp_rtcp->IncomingRtcpPacket(packet, length);
return true;
}
-void VideoSendStreamImpl::Start() {
- RTC_DCHECK_RUN_ON(worker_queue_);
+void VideoSendStream::Start() {
LOG(LS_INFO) << "VideoSendStream::Start";
if (payload_router_.active())
return;
TRACE_EVENT_INSTANT0("webrtc", "VideoSendStream::Start");
payload_router_.set_active(true);
-
- bitrate_allocator_->AddObserver(
- this, encoder_min_bitrate_bps_, encoder_max_bitrate_bps_,
- max_padding_bitrate_, !config_->suspend_below_min_bitrate);
-
- // Start monitoring encoder activity.
{
- rtc::CritScope lock(&encoder_activity_crit_sect_);
- RTC_DCHECK(!check_encoder_activity_task_);
- check_encoder_activity_task_ = new CheckEncoderActivityTask(this);
- worker_queue_->PostDelayedTask(
- std::unique_ptr<rtc::QueuedTask>(check_encoder_activity_task_),
- CheckEncoderActivityTask::kEncoderTimeOutMs);
- }
-
- vie_encoder_->SendKeyFrame();
-}
-
-void VideoSendStreamImpl::Stop() {
- RTC_DCHECK_RUN_ON(worker_queue_);
+ rtc::CritScope lock(&encoder_settings_crit_);
+ pending_state_change_ = rtc::Optional<State>(State::kStarted);
+ }
+ encoder_wakeup_event_.Set();
+}
+
+void VideoSendStream::Stop() {
LOG(LS_INFO) << "VideoSendStream::Stop";
if (!payload_router_.active())
return;
TRACE_EVENT_INSTANT0("webrtc", "VideoSendStream::Stop");
payload_router_.set_active(false);
- bitrate_allocator_->RemoveObserver(this);
{
- rtc::CritScope lock(&encoder_activity_crit_sect_);
- check_encoder_activity_task_->Stop();
- check_encoder_activity_task_ = nullptr;
- }
- vie_encoder_->OnBitrateUpdated(0, 0, 0);
- stats_proxy_->OnSetEncoderTargetRate(0);
-}
-
-void VideoSendStreamImpl::SignalEncoderTimedOut() {
- RTC_DCHECK_RUN_ON(worker_queue_);
- // If the encoder has not produced anything the last kEncoderTimeOutMs and it
- // is supposed to, deregister as BitrateAllocatorObserver. This can happen
- // if a camera stops producing frames.
- if (encoder_target_rate_bps_ > 0) {
- LOG(LS_INFO) << "SignalEncoderTimedOut, Encoder timed out.";
- bitrate_allocator_->RemoveObserver(this);
- }
-}
-
-void VideoSendStreamImpl::SignalEncoderActive() {
- RTC_DCHECK_RUN_ON(worker_queue_);
- LOG(LS_INFO) << "SignalEncoderActive, Encoder is active.";
- bitrate_allocator_->AddObserver(
- this, encoder_min_bitrate_bps_, encoder_max_bitrate_bps_,
- max_padding_bitrate_, !config_->suspend_below_min_bitrate);
-}
-
-void VideoSendStreamImpl::SignalEncoderConfigurationChanged(
+ rtc::CritScope lock(&encoder_settings_crit_);
+ pending_state_change_ = rtc::Optional<State>(State::kStopped);
+ }
+ encoder_wakeup_event_.Set();
+}
+
+VideoCaptureInput* VideoSendStream::Input() {
+ return &input_;
+}
+
+bool VideoSendStream::EncoderThreadFunction(void* obj) {
+ static_cast<VideoSendStream*>(obj)->EncoderProcess();
+ // We're done, return false to abort.
+ return false;
+}
+
+void VideoSendStream::EncoderProcess() {
+ RTC_CHECK_EQ(0, vie_encoder_.RegisterExternalEncoder(
+ config_.encoder_settings.encoder,
+ config_.encoder_settings.payload_type,
+ config_.encoder_settings.internal_source));
+ RTC_DCHECK_RUN_ON(&encoder_thread_checker_);
+ while (true) {
+ // Wake up every kEncodeCheckForActivityPeriodMs to check if the encoder is
+ // active. If not, deregister as BitrateAllocatorObserver.
+ const int kEncodeCheckForActivityPeriodMs = 1000;
+ encoder_wakeup_event_.Wait(kEncodeCheckForActivityPeriodMs);
+ if (rtc::AtomicOps::AcquireLoad(&stop_encoder_thread_))
+ break;
+ bool change_settings = false;
+ rtc::Optional<State> pending_state_change;
+ {
+ rtc::CritScope lock(&encoder_settings_crit_);
+ if (pending_encoder_settings_) {
+ std::swap(current_encoder_settings_, pending_encoder_settings_);
+ pending_encoder_settings_.reset();
+ change_settings = true;
+ } else if (pending_state_change_) {
+ swap(pending_state_change, pending_state_change_);
+ }
+ }
+ if (change_settings) {
+ current_encoder_settings_->video_codec.startBitrate = std::max(
+ bitrate_allocator_->GetStartBitrate(this) / 1000,
+ static_cast<int>(current_encoder_settings_->video_codec.minBitrate));
+
+ if (state_ == State::kStarted) {
+ bitrate_allocator_->AddObserver(
+ this, current_encoder_settings_->video_codec.minBitrate * 1000,
+ current_encoder_settings_->video_codec.maxBitrate * 1000,
+ CalulcateMaxPadBitrateBps(current_encoder_settings_->config,
+ config_.suspend_below_min_bitrate),
+ !config_.suspend_below_min_bitrate);
+ }
+
+ payload_router_.SetSendStreams(current_encoder_settings_->config.streams);
+ vie_encoder_.SetEncoder(current_encoder_settings_->video_codec,
+ payload_router_.MaxPayloadLength());
+
+ // Clear stats for disabled layers.
+ for (size_t i = current_encoder_settings_->config.streams.size();
+ i < config_.rtp.ssrcs.size(); ++i) {
+ stats_proxy_.OnInactiveSsrc(config_.rtp.ssrcs[i]);
+ }
+
+ size_t number_of_temporal_layers =
+ current_encoder_settings_->config.streams.back()
+ .temporal_layer_thresholds_bps.size() +
+ 1;
+ protection_bitrate_calculator_.SetEncodingData(
+ current_encoder_settings_->video_codec.width,
+ current_encoder_settings_->video_codec.height,
+ number_of_temporal_layers, payload_router_.MaxPayloadLength());
+
+ // We might've gotten new settings while configuring the encoder settings,
+ // restart from the top to see if that's the case before trying to encode
+ // a frame (which might correspond to the last frame size).
+ encoder_wakeup_event_.Set();
+ continue;
+ }
+
+ if (pending_state_change) {
+ if (*pending_state_change == State::kStarted &&
+ state_ == State::kStopped) {
+ bitrate_allocator_->AddObserver(
+ this, current_encoder_settings_->video_codec.minBitrate * 1000,
+ current_encoder_settings_->video_codec.maxBitrate * 1000,
+ CalulcateMaxPadBitrateBps(current_encoder_settings_->config,
+ config_.suspend_below_min_bitrate),
+ !config_.suspend_below_min_bitrate);
+ vie_encoder_.SendKeyFrame();
+ state_ = State::kStarted;
+ LOG_F(LS_INFO) << "Encoder started.";
+ } else if (*pending_state_change == State::kStopped) {
+ bitrate_allocator_->RemoveObserver(this);
+ vie_encoder_.OnBitrateUpdated(0, 0, 0);
+ stats_proxy_.OnSetEncoderTargetRate(0);
+ state_ = State::kStopped;
+ LOG_F(LS_INFO) << "Encoder stopped.";
+ }
+ encoder_wakeup_event_.Set();
+ continue;
+ }
+
+ // Check if the encoder has produced anything the last kEncoderTimeOutMs.
+ // If not, deregister as BitrateAllocatorObserver.
+ if (state_ == State::kStarted &&
+ vie_encoder_.time_of_last_frame_activity_ms() <
+ rtc::TimeMillis() - kEncoderTimeOutMs) {
+ // The encoder has timed out.
+ LOG_F(LS_INFO) << "Encoder timed out.";
+ bitrate_allocator_->RemoveObserver(this);
+ state_ = State::kEncoderTimedOut;
+ }
+ if (state_ == State::kEncoderTimedOut &&
+ vie_encoder_.time_of_last_frame_activity_ms() >
+ rtc::TimeMillis() - kEncoderTimeOutMs) {
+ LOG_F(LS_INFO) << "Encoder is active.";
+ bitrate_allocator_->AddObserver(
+ this, current_encoder_settings_->video_codec.minBitrate * 1000,
+ current_encoder_settings_->video_codec.maxBitrate * 1000,
+ CalulcateMaxPadBitrateBps(current_encoder_settings_->config,
+ config_.suspend_below_min_bitrate),
+ !config_.suspend_below_min_bitrate);
+ state_ = State::kStarted;
+ }
+
+ VideoFrame frame;
+ if (input_.GetVideoFrame(&frame)) {
+ // TODO(perkj): |pre_encode_callback| is only used by tests. Tests should
+ // register as a sink to the VideoSource instead.
+ if (config_.pre_encode_callback) {
+ config_.pre_encode_callback->OnFrame(frame);
+ }
+ vie_encoder_.EncodeVideoFrame(frame);
+ }
+ }
+ vie_encoder_.DeRegisterExternalEncoder(config_.encoder_settings.payload_type);
+}
+
+void VideoSendStream::ReconfigureVideoEncoder(
const VideoEncoderConfig& config) {
- RTC_DCHECK_GE(config_->rtp.ssrcs.size(), config.streams.size());
- TRACE_EVENT0("webrtc", "VideoSendStream::SignalEncoderConfigurationChanged");
- LOG(LS_INFO) << "SignalEncoderConfigurationChanged: " << config.ToString();
- RTC_DCHECK_GE(config_->rtp.ssrcs.size(), config.streams.size());
- RTC_DCHECK_RUN_ON(worker_queue_);
-
- const int kEncoderMinBitrateBps = 30000;
- encoder_min_bitrate_bps_ =
- std::max(config.streams[0].min_bitrate_bps, kEncoderMinBitrateBps);
- encoder_max_bitrate_bps_ = 0;
- for (const auto& stream : config.streams)
- encoder_max_bitrate_bps_ += stream.max_bitrate_bps;
- max_padding_bitrate_ =
- CalculateMaxPadBitrateBps(config, config_->suspend_below_min_bitrate);
-
- payload_router_.SetSendStreams(config.streams);
-
- // Clear stats for disabled layers.
- for (size_t i = config.streams.size(); i < config_->rtp.ssrcs.size(); ++i) {
- stats_proxy_->OnInactiveSsrc(config_->rtp.ssrcs[i]);
- }
-
- size_t number_of_temporal_layers =
- config.streams.back().temporal_layer_thresholds_bps.size() + 1;
- protection_bitrate_calculator_.SetEncodingData(
- config.streams[0].width, config.streams[0].height,
- number_of_temporal_layers, config_->rtp.max_packet_size);
-
- if (payload_router_.active()) {
- // The send stream is started already. Update the allocator with new bitrate
- // limits.
- bitrate_allocator_->AddObserver(
- this, encoder_min_bitrate_bps_, encoder_max_bitrate_bps_,
- max_padding_bitrate_, !config_->suspend_below_min_bitrate);
- }
-}
-
-EncodedImageCallback::Result VideoSendStreamImpl::OnEncodedImage(
+ TRACE_EVENT0("webrtc", "VideoSendStream::(Re)configureVideoEncoder");
+ LOG(LS_INFO) << "(Re)configureVideoEncoder: " << config.ToString();
+ RTC_DCHECK_GE(config_.rtp.ssrcs.size(), config.streams.size());
+ VideoCodec video_codec = VideoEncoderConfigToVideoCodec(
+ config, config_.encoder_settings.payload_name,
+ config_.encoder_settings.payload_type);
+ {
+ rtc::CritScope lock(&encoder_settings_crit_);
+ encoder_max_bitrate_bps_ = video_codec.maxBitrate * 1000;
+ pending_encoder_settings_.reset(new EncoderSettings({video_codec, config}));
+ }
+ encoder_wakeup_event_.Set();
+}
+
+VideoSendStream::Stats VideoSendStream::GetStats() {
+ return stats_proxy_.GetStats();
+}
+
+void VideoSendStream::OveruseDetected() {
+ if (config_.overuse_callback)
+ config_.overuse_callback->OnLoadUpdate(LoadObserver::kOveruse);
+}
+
+void VideoSendStream::NormalUsage() {
+ if (config_.overuse_callback)
+ config_.overuse_callback->OnLoadUpdate(LoadObserver::kUnderuse);
+}
+
+EncodedImageCallback::Result VideoSendStream::OnEncodedImage(
const EncodedImage& encoded_image,
const CodecSpecificInfo* codec_specific_info,
const RTPFragmentationHeader* fragmentation) {
- // Encoded is called on whatever thread the real encoder implementation run
- // on. In the case of hardware encoders, there might be several encoders
- // running in parallel on different threads.
- if (config_->post_encode_callback) {
- config_->post_encode_callback->EncodedFrameCallback(
+ if (config_.post_encode_callback) {
+ config_.post_encode_callback->EncodedFrameCallback(
EncodedFrame(encoded_image._buffer, encoded_image._length,
encoded_image._frameType));
- }
- {
- rtc::CritScope lock(&encoder_activity_crit_sect_);
- if (check_encoder_activity_task_)
- check_encoder_activity_task_->UpdateEncoderActivity();
}
protection_bitrate_calculator_.UpdateWithEncodedData(encoded_image);
@@ -873,7 +783,7 @@
if (file_writers_[layer] == nullptr) {
std::ostringstream oss;
oss << "send_bitstream_ssrc";
- for (uint32_t ssrc : config_->rtp.ssrcs)
+ for (uint32_t ssrc : config_.rtp.ssrcs)
oss << "_" << ssrc;
oss << "_layer" << layer << ".ivf";
file_writers_[layer] =
@@ -890,18 +800,17 @@
return result;
}
-void VideoSendStreamImpl::ConfigureProtection() {
- RTC_DCHECK_RUN_ON(worker_queue_);
+void VideoSendStream::ConfigureProtection() {
// Enable NACK, FEC or both.
- const bool enable_protection_nack = config_->rtp.nack.rtp_history_ms > 0;
- bool enable_protection_fec = config_->rtp.fec.ulpfec_payload_type != -1;
+ const bool enable_protection_nack = config_.rtp.nack.rtp_history_ms > 0;
+ bool enable_protection_fec = config_.rtp.fec.ulpfec_payload_type != -1;
// Payload types without picture ID cannot determine that a stream is complete
// without retransmitting FEC, so using FEC + NACK for H.264 (for instance) is
// a waste of bandwidth since FEC packets still have to be transmitted. Note
// that this is not the case with FLEXFEC.
if (enable_protection_nack &&
!PayloadTypeSupportsSkippingFecPackets(
- config_->encoder_settings.payload_name)) {
+ config_.encoder_settings.payload_name)) {
LOG(LS_WARNING) << "Transmitting payload type without picture ID using"
"NACK+FEC is a waste of bandwidth since FEC packets "
"also have to be retransmitted. Disabling FEC.";
@@ -915,21 +824,21 @@
// TODO(changbin): Should set RTX for RED mapping in RTP sender in future.
// Validate payload types. If either RED or FEC payload types are set then
// both should be. If FEC is enabled then they both have to be set.
- if (config_->rtp.fec.red_payload_type != -1) {
- RTC_DCHECK_GE(config_->rtp.fec.red_payload_type, 0);
- RTC_DCHECK_LE(config_->rtp.fec.red_payload_type, 127);
+ if (config_.rtp.fec.red_payload_type != -1) {
+ RTC_DCHECK_GE(config_.rtp.fec.red_payload_type, 0);
+ RTC_DCHECK_LE(config_.rtp.fec.red_payload_type, 127);
// TODO(holmer): We should only enable red if ulpfec is also enabled, but
// but due to an incompatibility issue with previous versions the receiver
// assumes rtx packets are containing red if it has been configured to
// receive red. Remove this in a few versions once the incompatibility
// issue is resolved (M53 timeframe).
- payload_type_red = static_cast<uint8_t>(config_->rtp.fec.red_payload_type);
- }
- if (config_->rtp.fec.ulpfec_payload_type != -1) {
- RTC_DCHECK_GE(config_->rtp.fec.ulpfec_payload_type, 0);
- RTC_DCHECK_LE(config_->rtp.fec.ulpfec_payload_type, 127);
+ payload_type_red = static_cast<uint8_t>(config_.rtp.fec.red_payload_type);
+ }
+ if (config_.rtp.fec.ulpfec_payload_type != -1) {
+ RTC_DCHECK_GE(config_.rtp.fec.ulpfec_payload_type, 0);
+ RTC_DCHECK_LE(config_.rtp.fec.ulpfec_payload_type, 127);
payload_type_fec =
- static_cast<uint8_t>(config_->rtp.fec.ulpfec_payload_type);
+ static_cast<uint8_t>(config_.rtp.fec.ulpfec_payload_type);
}
for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_) {
@@ -948,102 +857,107 @@
enable_protection_nack);
}
-void VideoSendStreamImpl::ConfigureSsrcs() {
- RTC_DCHECK_RUN_ON(worker_queue_);
+void VideoSendStream::ConfigureSsrcs() {
// Configure regular SSRCs.
- for (size_t i = 0; i < config_->rtp.ssrcs.size(); ++i) {
- uint32_t ssrc = config_->rtp.ssrcs[i];
+ for (size_t i = 0; i < config_.rtp.ssrcs.size(); ++i) {
+ uint32_t ssrc = config_.rtp.ssrcs[i];
RtpRtcp* const rtp_rtcp = rtp_rtcp_modules_[i];
rtp_rtcp->SetSSRC(ssrc);
// Restore RTP state if previous existed.
- VideoSendStream::RtpStateMap::iterator it = suspended_ssrcs_.find(ssrc);
+ RtpStateMap::iterator it = suspended_ssrcs_.find(ssrc);
if (it != suspended_ssrcs_.end())
rtp_rtcp->SetRtpState(it->second);
}
// Set up RTX if available.
- if (config_->rtp.rtx.ssrcs.empty())
+ if (config_.rtp.rtx.ssrcs.empty())
return;
// Configure RTX SSRCs.
- RTC_DCHECK_EQ(config_->rtp.rtx.ssrcs.size(), config_->rtp.ssrcs.size());
- for (size_t i = 0; i < config_->rtp.rtx.ssrcs.size(); ++i) {
- uint32_t ssrc = config_->rtp.rtx.ssrcs[i];
+ RTC_DCHECK_EQ(config_.rtp.rtx.ssrcs.size(), config_.rtp.ssrcs.size());
+ for (size_t i = 0; i < config_.rtp.rtx.ssrcs.size(); ++i) {
+ uint32_t ssrc = config_.rtp.rtx.ssrcs[i];
RtpRtcp* const rtp_rtcp = rtp_rtcp_modules_[i];
rtp_rtcp->SetRtxSsrc(ssrc);
- VideoSendStream::RtpStateMap::iterator it = suspended_ssrcs_.find(ssrc);
+ RtpStateMap::iterator it = suspended_ssrcs_.find(ssrc);
if (it != suspended_ssrcs_.end())
rtp_rtcp->SetRtxState(it->second);
}
// Configure RTX payload types.
- RTC_DCHECK_GE(config_->rtp.rtx.payload_type, 0);
+ RTC_DCHECK_GE(config_.rtp.rtx.payload_type, 0);
for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_) {
- rtp_rtcp->SetRtxSendPayloadType(config_->rtp.rtx.payload_type,
- config_->encoder_settings.payload_type);
+ rtp_rtcp->SetRtxSendPayloadType(config_.rtp.rtx.payload_type,
+ config_.encoder_settings.payload_type);
rtp_rtcp->SetRtxSendStatus(kRtxRetransmitted | kRtxRedundantPayloads);
}
- if (config_->rtp.fec.red_payload_type != -1 &&
- config_->rtp.fec.red_rtx_payload_type != -1) {
+ if (config_.rtp.fec.red_payload_type != -1 &&
+ config_.rtp.fec.red_rtx_payload_type != -1) {
for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_) {
- rtp_rtcp->SetRtxSendPayloadType(config_->rtp.fec.red_rtx_payload_type,
- config_->rtp.fec.red_payload_type);
- }
- }
-}
-
-std::map<uint32_t, RtpState> VideoSendStreamImpl::GetRtpStates() const {
- RTC_DCHECK_RUN_ON(worker_queue_);
+ rtp_rtcp->SetRtxSendPayloadType(config_.rtp.fec.red_rtx_payload_type,
+ config_.rtp.fec.red_payload_type);
+ }
+ }
+}
+
+std::map<uint32_t, RtpState> VideoSendStream::GetRtpStates() const {
std::map<uint32_t, RtpState> rtp_states;
- for (size_t i = 0; i < config_->rtp.ssrcs.size(); ++i) {
- uint32_t ssrc = config_->rtp.ssrcs[i];
+ for (size_t i = 0; i < config_.rtp.ssrcs.size(); ++i) {
+ uint32_t ssrc = config_.rtp.ssrcs[i];
RTC_DCHECK_EQ(ssrc, rtp_rtcp_modules_[i]->SSRC());
rtp_states[ssrc] = rtp_rtcp_modules_[i]->GetRtpState();
}
- for (size_t i = 0; i < config_->rtp.rtx.ssrcs.size(); ++i) {
- uint32_t ssrc = config_->rtp.rtx.ssrcs[i];
+ for (size_t i = 0; i < config_.rtp.rtx.ssrcs.size(); ++i) {
+ uint32_t ssrc = config_.rtp.rtx.ssrcs[i];
rtp_states[ssrc] = rtp_rtcp_modules_[i]->GetRtxState();
}
return rtp_states;
}
-void VideoSendStreamImpl::SignalNetworkState(NetworkState state) {
- RTC_DCHECK_RUN_ON(worker_queue_);
+void VideoSendStream::SignalNetworkState(NetworkState state) {
for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_) {
- rtp_rtcp->SetRTCPStatus(state == kNetworkUp ? config_->rtp.rtcp_mode
+ rtp_rtcp->SetRTCPStatus(state == kNetworkUp ? config_.rtp.rtcp_mode
: RtcpMode::kOff);
}
}
-uint32_t VideoSendStreamImpl::OnBitrateUpdated(uint32_t bitrate_bps,
- uint8_t fraction_loss,
- int64_t rtt) {
- RTC_DCHECK_RUN_ON(worker_queue_);
- RTC_DCHECK(payload_router_.active())
- << "VideoSendStream::Start has not been called.";
+uint32_t VideoSendStream::OnBitrateUpdated(uint32_t bitrate_bps,
+ uint8_t fraction_loss,
+ int64_t rtt) {
// Get the encoder target rate. It is the estimated network rate -
// protection overhead.
- encoder_target_rate_bps_ = protection_bitrate_calculator_.SetTargetRates(
- bitrate_bps, stats_proxy_->GetSendFrameRate(), fraction_loss, rtt);
- uint32_t protection_bitrate = bitrate_bps - encoder_target_rate_bps_;
-
- encoder_target_rate_bps_ =
- std::min(encoder_max_bitrate_bps_, encoder_target_rate_bps_);
- vie_encoder_->OnBitrateUpdated(encoder_target_rate_bps_, fraction_loss, rtt);
- stats_proxy_->OnSetEncoderTargetRate(encoder_target_rate_bps_);
+ uint32_t encoder_target_rate_bps =
+ protection_bitrate_calculator_.SetTargetRates(
+ bitrate_bps, stats_proxy_.GetSendFrameRate(), fraction_loss, rtt);
+
+ uint32_t protection_bitrate = bitrate_bps - encoder_target_rate_bps;
+ {
+ // Limit the target bitrate to the configured max bitrate.
+ rtc::CritScope lock(&encoder_settings_crit_);
+ encoder_target_rate_bps =
+ std::min(encoder_max_bitrate_bps_, encoder_target_rate_bps);
+ if ((encoder_target_rate_bps_ == 0 && encoder_target_rate_bps > 0) ||
+ (encoder_target_rate_bps_ > 0 && encoder_target_rate_bps == 0)) {
+ LOG(LS_INFO)
+ << "OnBitrateUpdated: Encoder state changed, target bitrate "
+ << encoder_target_rate_bps << " bps.";
+ }
+ encoder_target_rate_bps_ = encoder_target_rate_bps;
+ }
+ vie_encoder_.OnBitrateUpdated(encoder_target_rate_bps, fraction_loss, rtt);
+ stats_proxy_.OnSetEncoderTargetRate(encoder_target_rate_bps);
+
return protection_bitrate;
}
-int VideoSendStreamImpl::ProtectionRequest(
- const FecProtectionParams* delta_params,
- const FecProtectionParams* key_params,
- uint32_t* sent_video_rate_bps,
- uint32_t* sent_nack_rate_bps,
- uint32_t* sent_fec_rate_bps) {
- RTC_DCHECK_RUN_ON(worker_queue_);
+int VideoSendStream::ProtectionRequest(const FecProtectionParams* delta_params,
+ const FecProtectionParams* key_params,
+ uint32_t* sent_video_rate_bps,
+ uint32_t* sent_nack_rate_bps,
+ uint32_t* sent_fec_rate_bps) {
*sent_video_rate_bps = 0;
*sent_nack_rate_bps = 0;
*sent_fec_rate_bps = 0;
« no previous file with comments | « webrtc/video/video_send_stream.h ('k') | webrtc/video/video_send_stream_tests.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698