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 10 matching lines...) Expand all Loading... |
21 #include "webrtc/modules/pacing/paced_sender.h" | 21 #include "webrtc/modules/pacing/paced_sender.h" |
22 #include "webrtc/modules/video_coding/include/video_coding.h" | 22 #include "webrtc/modules/video_coding/include/video_coding.h" |
23 #include "webrtc/modules/video_coding/include/video_coding_defines.h" | 23 #include "webrtc/modules/video_coding/include/video_coding_defines.h" |
24 #include "webrtc/system_wrappers/include/metrics.h" | 24 #include "webrtc/system_wrappers/include/metrics.h" |
25 #include "webrtc/video/overuse_frame_detector.h" | 25 #include "webrtc/video/overuse_frame_detector.h" |
26 #include "webrtc/video/send_statistics_proxy.h" | 26 #include "webrtc/video/send_statistics_proxy.h" |
27 #include "webrtc/video_frame.h" | 27 #include "webrtc/video_frame.h" |
28 | 28 |
29 namespace webrtc { | 29 namespace webrtc { |
30 | 30 |
31 static const float kStopPaddingThresholdMs = 2000; | |
32 | |
33 ViEEncoder::ViEEncoder(uint32_t number_of_cores, | 31 ViEEncoder::ViEEncoder(uint32_t number_of_cores, |
34 ProcessThread* module_process_thread, | 32 ProcessThread* module_process_thread, |
35 SendStatisticsProxy* stats_proxy, | 33 SendStatisticsProxy* stats_proxy, |
36 OveruseFrameDetector* overuse_detector, | 34 OveruseFrameDetector* overuse_detector, |
37 EncodedImageCallback* sink) | 35 VideoEncoderSink* sink) |
38 : number_of_cores_(number_of_cores), | 36 : number_of_cores_(number_of_cores), |
39 sink_(sink), | 37 sink_(sink), |
40 vp_(VideoProcessing::Create()), | 38 vp_(VideoProcessing::Create()), |
41 video_sender_(Clock::GetRealTimeClock(), this, this, this), | 39 video_sender_(Clock::GetRealTimeClock(), this, this, this), |
42 stats_proxy_(stats_proxy), | 40 stats_proxy_(stats_proxy), |
43 overuse_detector_(overuse_detector), | 41 overuse_detector_(overuse_detector), |
44 time_of_last_frame_activity_ms_(0), | 42 time_of_last_frame_activity_ms_(0), |
45 encoder_config_(), | 43 encoder_config_(), |
46 min_transmit_bitrate_bps_(0), | |
47 last_observed_bitrate_bps_(0), | 44 last_observed_bitrate_bps_(0), |
48 encoder_paused_(true), | 45 encoder_paused_(true), |
49 encoder_paused_and_dropped_frame_(false), | 46 encoder_paused_and_dropped_frame_(false), |
| 47 reported_timeout_(false), |
50 module_process_thread_(module_process_thread), | 48 module_process_thread_(module_process_thread), |
51 has_received_sli_(false), | 49 has_received_sli_(false), |
52 picture_id_sli_(0), | 50 picture_id_sli_(0), |
53 has_received_rpsi_(false), | 51 has_received_rpsi_(false), |
54 picture_id_rpsi_(0), | 52 picture_id_rpsi_(0), |
55 video_suspended_(false) { | 53 video_suspended_(false) { |
56 module_process_thread_->RegisterModule(&video_sender_); | 54 module_process_thread_->RegisterModule(&video_sender_); |
57 vp_->EnableTemporalDecimation(true); | 55 vp_->EnableTemporalDecimation(true); |
58 } | 56 } |
59 | 57 |
(...skipping 21 matching lines...) Expand all Loading... |
81 video_sender_.RegisterExternalEncoder(encoder, pl_type, internal_source); | 79 video_sender_.RegisterExternalEncoder(encoder, pl_type, internal_source); |
82 return 0; | 80 return 0; |
83 } | 81 } |
84 | 82 |
85 int32_t ViEEncoder::DeRegisterExternalEncoder(uint8_t pl_type) { | 83 int32_t ViEEncoder::DeRegisterExternalEncoder(uint8_t pl_type) { |
86 video_sender_.RegisterExternalEncoder(nullptr, pl_type, false); | 84 video_sender_.RegisterExternalEncoder(nullptr, pl_type, false); |
87 return 0; | 85 return 0; |
88 } | 86 } |
89 | 87 |
90 void ViEEncoder::SetEncoder(const webrtc::VideoCodec& video_codec, | 88 void ViEEncoder::SetEncoder(const webrtc::VideoCodec& video_codec, |
91 int min_transmit_bitrate_bps, | |
92 size_t max_data_payload_length) { | 89 size_t max_data_payload_length) { |
93 // Setting target width and height for VPM. | 90 // Setting target width and height for VPM. |
94 RTC_CHECK_EQ(VPM_OK, | 91 RTC_CHECK_EQ(VPM_OK, |
95 vp_->SetTargetResolution(video_codec.width, video_codec.height, | 92 vp_->SetTargetResolution(video_codec.width, video_codec.height, |
96 video_codec.maxFramerate)); | 93 video_codec.maxFramerate)); |
97 | 94 |
98 // Cache codec before calling AddBitrateObserver (which calls OnBitrateUpdated | 95 // Cache codec before calling AddBitrateObserver (which calls OnBitrateUpdated |
99 // that makes use of the number of simulcast streams configured). | 96 // that makes use of the number of simulcast streams configured). |
100 { | 97 { |
101 rtc::CritScope lock(&data_cs_); | 98 rtc::CritScope lock(&data_cs_); |
102 encoder_config_ = video_codec; | 99 encoder_config_ = video_codec; |
103 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps; | |
104 } | 100 } |
105 | 101 |
106 bool success = video_sender_.RegisterSendCodec( | 102 bool success = video_sender_.RegisterSendCodec( |
107 &video_codec, number_of_cores_, | 103 &video_codec, number_of_cores_, |
108 static_cast<uint32_t>(max_data_payload_length)) == VCM_OK; | 104 static_cast<uint32_t>(max_data_payload_length)) == VCM_OK; |
109 if (!success) { | 105 if (!success) { |
110 LOG(LS_ERROR) << "Failed to configure encoder."; | 106 LOG(LS_ERROR) << "Failed to configure encoder."; |
111 RTC_DCHECK(success); | 107 RTC_DCHECK(success); |
112 } | 108 } |
113 | 109 |
114 if (stats_proxy_) { | 110 if (stats_proxy_) { |
115 VideoEncoderConfig::ContentType content_type = | 111 VideoEncoderConfig::ContentType content_type = |
116 VideoEncoderConfig::ContentType::kRealtimeVideo; | 112 VideoEncoderConfig::ContentType::kRealtimeVideo; |
117 switch (video_codec.mode) { | 113 switch (video_codec.mode) { |
118 case kRealtimeVideo: | 114 case kRealtimeVideo: |
119 content_type = VideoEncoderConfig::ContentType::kRealtimeVideo; | 115 content_type = VideoEncoderConfig::ContentType::kRealtimeVideo; |
120 break; | 116 break; |
121 case kScreensharing: | 117 case kScreensharing: |
122 content_type = VideoEncoderConfig::ContentType::kScreen; | 118 content_type = VideoEncoderConfig::ContentType::kScreen; |
123 break; | 119 break; |
124 default: | 120 default: |
125 RTC_NOTREACHED(); | 121 RTC_NOTREACHED(); |
126 break; | 122 break; |
127 } | 123 } |
128 stats_proxy_->SetContentType(content_type); | 124 stats_proxy_->SetContentType(content_type); |
129 } | 125 } |
130 } | 126 } |
131 | 127 |
132 int ViEEncoder::GetPaddingNeededBps() const { | |
133 int64_t time_of_last_frame_activity_ms; | |
134 int min_transmit_bitrate_bps; | |
135 int bitrate_bps; | |
136 VideoCodec send_codec; | |
137 { | |
138 rtc::CritScope lock(&data_cs_); | |
139 bool send_padding = encoder_config_.numberOfSimulcastStreams > 1 || | |
140 video_suspended_ || min_transmit_bitrate_bps_ > 0; | |
141 if (!send_padding) | |
142 return 0; | |
143 time_of_last_frame_activity_ms = time_of_last_frame_activity_ms_; | |
144 min_transmit_bitrate_bps = min_transmit_bitrate_bps_; | |
145 bitrate_bps = last_observed_bitrate_bps_; | |
146 send_codec = encoder_config_; | |
147 } | |
148 | |
149 bool video_is_suspended = video_sender_.VideoSuspended(); | |
150 | |
151 // Find the max amount of padding we can allow ourselves to send at this | |
152 // point, based on which streams are currently active and what our current | |
153 // available bandwidth is. | |
154 int pad_up_to_bitrate_bps = 0; | |
155 if (send_codec.numberOfSimulcastStreams == 0) { | |
156 pad_up_to_bitrate_bps = send_codec.minBitrate * 1000; | |
157 } else { | |
158 SimulcastStream* stream_configs = send_codec.simulcastStream; | |
159 pad_up_to_bitrate_bps = | |
160 stream_configs[send_codec.numberOfSimulcastStreams - 1].minBitrate * | |
161 1000; | |
162 for (int i = 0; i < send_codec.numberOfSimulcastStreams - 1; ++i) { | |
163 pad_up_to_bitrate_bps += stream_configs[i].targetBitrate * 1000; | |
164 } | |
165 } | |
166 | |
167 // Disable padding if only sending one stream and video isn't suspended and | |
168 // min-transmit bitrate isn't used (applied later). | |
169 if (!video_is_suspended && send_codec.numberOfSimulcastStreams <= 1) | |
170 pad_up_to_bitrate_bps = 0; | |
171 | |
172 // The amount of padding should decay to zero if no frames are being | |
173 // captured/encoded unless a min-transmit bitrate is used. | |
174 int64_t now_ms = rtc::TimeMillis(); | |
175 if (now_ms - time_of_last_frame_activity_ms > kStopPaddingThresholdMs) | |
176 pad_up_to_bitrate_bps = 0; | |
177 | |
178 // Pad up to min bitrate. | |
179 if (pad_up_to_bitrate_bps < min_transmit_bitrate_bps) | |
180 pad_up_to_bitrate_bps = min_transmit_bitrate_bps; | |
181 | |
182 // Padding may never exceed bitrate estimate. | |
183 if (pad_up_to_bitrate_bps > bitrate_bps) | |
184 pad_up_to_bitrate_bps = bitrate_bps; | |
185 | |
186 return pad_up_to_bitrate_bps; | |
187 } | |
188 | |
189 bool ViEEncoder::EncoderPaused() const { | 128 bool ViEEncoder::EncoderPaused() const { |
190 // Pause video if paused by caller or as long as the network is down or the | 129 // Pause video if paused by caller or as long as the network is down or the |
191 // pacer queue has grown too large in buffered mode. | 130 // pacer queue has grown too large in buffered mode. |
192 // If the pacer queue has grown to large or the network is down, | 131 // If the pacer queue has grown to large or the network is down, |
193 // last_observed_bitrate_bps_ will be 0. | 132 // last_observed_bitrate_bps_ will be 0. |
194 return encoder_paused_ || video_suspended_ || last_observed_bitrate_bps_ == 0; | 133 return encoder_paused_ || video_suspended_ || last_observed_bitrate_bps_ == 0; |
195 } | 134 } |
196 | 135 |
197 void ViEEncoder::TraceFrameDropStart() { | 136 void ViEEncoder::TraceFrameDropStart() { |
198 // Start trace event only on the first frame after encoder is paused. | 137 // Start trace event only on the first frame after encoder is paused. |
199 if (!encoder_paused_and_dropped_frame_) { | 138 if (!encoder_paused_and_dropped_frame_) { |
200 TRACE_EVENT_ASYNC_BEGIN0("webrtc", "EncoderPaused", this); | 139 TRACE_EVENT_ASYNC_BEGIN0("webrtc", "EncoderPaused", this); |
201 } | 140 } |
202 encoder_paused_and_dropped_frame_ = true; | 141 encoder_paused_and_dropped_frame_ = true; |
203 return; | 142 return; |
204 } | 143 } |
205 | 144 |
206 void ViEEncoder::TraceFrameDropEnd() { | 145 void ViEEncoder::TraceFrameDropEnd() { |
207 // End trace event on first frame after encoder resumes, if frame was dropped. | 146 // End trace event on first frame after encoder resumes, if frame was dropped. |
208 if (encoder_paused_and_dropped_frame_) { | 147 if (encoder_paused_and_dropped_frame_) { |
209 TRACE_EVENT_ASYNC_END0("webrtc", "EncoderPaused", this); | 148 TRACE_EVENT_ASYNC_END0("webrtc", "EncoderPaused", this); |
210 } | 149 } |
211 encoder_paused_and_dropped_frame_ = false; | 150 encoder_paused_and_dropped_frame_ = false; |
212 } | 151 } |
213 | 152 |
214 void ViEEncoder::EncodeVideoFrame(const VideoFrame& video_frame) { | 153 void ViEEncoder::EncodeVideoFrame(const VideoFrame& video_frame) { |
215 VideoCodecType codec_type; | 154 VideoCodecType codec_type; |
| 155 bool do_report_active = false; |
216 { | 156 { |
217 rtc::CritScope lock(&data_cs_); | 157 rtc::CritScope lock(&data_cs_); |
218 time_of_last_frame_activity_ms_ = rtc::TimeMillis(); | 158 time_of_last_frame_activity_ms_ = rtc::TimeMillis(); |
219 if (EncoderPaused()) { | 159 if (EncoderPaused()) { |
220 TraceFrameDropStart(); | 160 TraceFrameDropStart(); |
221 return; | 161 return; |
222 } | 162 } |
223 TraceFrameDropEnd(); | 163 TraceFrameDropEnd(); |
| 164 do_report_active = reported_timeout_; |
| 165 reported_timeout_ = false; |
224 codec_type = encoder_config_.codecType; | 166 codec_type = encoder_config_.codecType; |
225 } | 167 } |
226 | 168 |
| 169 if (do_report_active) { |
| 170 // We have previously reported that the encoder is inactive and we need to |
| 171 // report the state change. |
| 172 LOG(LS_INFO) << "ViEncoder is active."; |
| 173 sink_->OnEncoderActivityChanged(true); |
| 174 } |
| 175 |
227 TRACE_EVENT_ASYNC_STEP0("webrtc", "Video", video_frame.render_time_ms(), | 176 TRACE_EVENT_ASYNC_STEP0("webrtc", "Video", video_frame.render_time_ms(), |
228 "Encode"); | 177 "Encode"); |
229 const VideoFrame* frame_to_send = &video_frame; | 178 const VideoFrame* frame_to_send = &video_frame; |
230 // TODO(wuchengli): support texture frames. | 179 // TODO(wuchengli): support texture frames. |
231 if (!video_frame.video_frame_buffer()->native_handle()) { | 180 if (!video_frame.video_frame_buffer()->native_handle()) { |
232 // Pass frame via preprocessor. | 181 // Pass frame via preprocessor. |
233 frame_to_send = vp_->PreprocessFrame(video_frame); | 182 frame_to_send = vp_->PreprocessFrame(video_frame); |
234 if (!frame_to_send) { | 183 if (!frame_to_send) { |
235 // Drop this frame, or there was an error processing it. | 184 // Drop this frame, or there was an error processing it. |
236 return; | 185 return; |
(...skipping 20 matching lines...) Expand all Loading... |
257 video_sender_.AddVideoFrame(*frame_to_send, &codec_specific_info); | 206 video_sender_.AddVideoFrame(*frame_to_send, &codec_specific_info); |
258 return; | 207 return; |
259 } | 208 } |
260 video_sender_.AddVideoFrame(*frame_to_send, nullptr); | 209 video_sender_.AddVideoFrame(*frame_to_send, nullptr); |
261 } | 210 } |
262 | 211 |
263 void ViEEncoder::SendKeyFrame() { | 212 void ViEEncoder::SendKeyFrame() { |
264 video_sender_.IntraFrameRequest(0); | 213 video_sender_.IntraFrameRequest(0); |
265 } | 214 } |
266 | 215 |
| 216 void ViEEncoder::CheckForActivity() { |
| 217 bool do_report_timeout = false; |
| 218 { |
| 219 rtc::CritScope lock(&data_cs_); |
| 220 // TODO(perkj): Refactor this monitoring once we use TaskQueues and use a |
| 221 // timer instead. |
| 222 // This monitoring was previously achieved by that |
| 223 // VieEncoder::GetPaddingBitrate was by Call for each OnBitrateUpdated. |
| 224 int64_t now_ms = rtc::TimeMillis(); |
| 225 if (!reported_timeout_ && !EncoderPaused() && |
| 226 (now_ms - time_of_last_frame_activity_ms_ > |
| 227 VideoEncoderSink::TimeOutMs)) { |
| 228 do_report_timeout = true; |
| 229 reported_timeout_ = true; |
| 230 } |
| 231 } |
| 232 |
| 233 if (do_report_timeout) { |
| 234 LOG(LS_INFO) << "ViEncoder timed out."; |
| 235 sink_->OnEncoderActivityChanged(false); |
| 236 } |
| 237 } |
| 238 |
267 void ViEEncoder::SetProtectionMethod(bool nack, bool fec) { | 239 void ViEEncoder::SetProtectionMethod(bool nack, bool fec) { |
268 // Set Video Protection for VCM. | 240 // Set Video Protection for VCM. |
269 VCMVideoProtection protection_mode; | 241 VCMVideoProtection protection_mode; |
270 if (fec) { | 242 if (fec) { |
271 protection_mode = | 243 protection_mode = |
272 nack ? webrtc::kProtectionNackFEC : kProtectionFEC; | 244 nack ? webrtc::kProtectionNackFEC : kProtectionFEC; |
273 } else { | 245 } else { |
274 protection_mode = nack ? kProtectionNack : kProtectionNone; | 246 protection_mode = nack ? kProtectionNack : kProtectionNone; |
275 } | 247 } |
276 video_sender_.SetVideoProtection(protection_mode); | 248 video_sender_.SetVideoProtection(protection_mode); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
326 | 298 |
327 void ViEEncoder::OnBitrateUpdated(uint32_t bitrate_bps, | 299 void ViEEncoder::OnBitrateUpdated(uint32_t bitrate_bps, |
328 uint8_t fraction_lost, | 300 uint8_t fraction_lost, |
329 int64_t round_trip_time_ms) { | 301 int64_t round_trip_time_ms) { |
330 LOG(LS_VERBOSE) << "OnBitrateUpdated, bitrate " << bitrate_bps | 302 LOG(LS_VERBOSE) << "OnBitrateUpdated, bitrate " << bitrate_bps |
331 << " packet loss " << static_cast<int>(fraction_lost) | 303 << " packet loss " << static_cast<int>(fraction_lost) |
332 << " rtt " << round_trip_time_ms; | 304 << " rtt " << round_trip_time_ms; |
333 video_sender_.SetChannelParameters(bitrate_bps, fraction_lost, | 305 video_sender_.SetChannelParameters(bitrate_bps, fraction_lost, |
334 round_trip_time_ms); | 306 round_trip_time_ms); |
335 bool video_is_suspended = video_sender_.VideoSuspended(); | 307 bool video_is_suspended = video_sender_.VideoSuspended(); |
| 308 |
336 bool video_suspension_changed; | 309 bool video_suspension_changed; |
337 { | 310 { |
338 rtc::CritScope lock(&data_cs_); | 311 rtc::CritScope lock(&data_cs_); |
339 last_observed_bitrate_bps_ = bitrate_bps; | 312 last_observed_bitrate_bps_ = bitrate_bps; |
340 video_suspension_changed = video_suspended_ != video_is_suspended; | 313 video_suspension_changed = video_suspended_ != video_is_suspended; |
341 video_suspended_ = video_is_suspended; | 314 video_suspended_ = video_is_suspended; |
342 } | 315 } |
343 | 316 |
344 if (!video_suspension_changed) | 317 if (!video_suspension_changed) |
345 return; | 318 return; |
346 // Video suspend-state changed, inform codec observer. | 319 // Video suspend-state changed, inform codec observer. |
347 LOG(LS_INFO) << "Video suspend state changed " << video_is_suspended; | 320 LOG(LS_INFO) << "Video suspend state changed " << video_is_suspended; |
348 | 321 |
349 if (stats_proxy_) | 322 if (stats_proxy_) |
350 stats_proxy_->OnSuspendChange(video_is_suspended); | 323 stats_proxy_->OnSuspendChange(video_is_suspended); |
351 } | 324 } |
352 | 325 |
353 } // namespace webrtc | 326 } // namespace webrtc |
OLD | NEW |