OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | |
3 * | |
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 | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #include "webrtc/video_engine/vie_encoder.h" | |
12 | |
13 #include <assert.h> | |
14 | |
15 #include <algorithm> | |
16 | |
17 #include "webrtc/base/checks.h" | |
18 #include "webrtc/base/logging.h" | |
19 #include "webrtc/base/trace_event.h" | |
20 #include "webrtc/call/bitrate_allocator.h" | |
21 #include "webrtc/common_video/include/video_image.h" | |
22 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" | |
23 #include "webrtc/frame_callback.h" | |
24 #include "webrtc/modules/bitrate_controller/include/bitrate_controller.h" | |
25 #include "webrtc/modules/pacing/paced_sender.h" | |
26 #include "webrtc/modules/utility/include/process_thread.h" | |
27 #include "webrtc/modules/video_coding/include/video_codec_interface.h" | |
28 #include "webrtc/modules/video_coding/include/video_coding.h" | |
29 #include "webrtc/modules/video_coding/include/video_coding_defines.h" | |
30 #include "webrtc/modules/video_coding/encoded_frame.h" | |
31 #include "webrtc/system_wrappers/include/clock.h" | |
32 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" | |
33 #include "webrtc/system_wrappers/include/metrics.h" | |
34 #include "webrtc/system_wrappers/include/tick_util.h" | |
35 #include "webrtc/video/send_statistics_proxy.h" | |
36 #include "webrtc/video_engine/payload_router.h" | |
37 | |
38 namespace webrtc { | |
39 | |
40 // Margin on when we pause the encoder when the pacing buffer overflows relative | |
41 // to the configured buffer delay. | |
42 static const float kEncoderPausePacerMargin = 2.0f; | |
43 | |
44 // Don't stop the encoder unless the delay is above this configured value. | |
45 static const int kMinPacingDelayMs = 200; | |
46 | |
47 static const float kStopPaddingThresholdMs = 2000; | |
48 | |
49 static const int kMinKeyFrameRequestIntervalMs = 300; | |
50 | |
51 std::vector<uint32_t> AllocateStreamBitrates( | |
52 uint32_t total_bitrate, | |
53 const SimulcastStream* stream_configs, | |
54 size_t number_of_streams) { | |
55 if (number_of_streams == 0) { | |
56 std::vector<uint32_t> stream_bitrates(1, 0); | |
57 stream_bitrates[0] = total_bitrate; | |
58 return stream_bitrates; | |
59 } | |
60 std::vector<uint32_t> stream_bitrates(number_of_streams, 0); | |
61 uint32_t bitrate_remainder = total_bitrate; | |
62 for (size_t i = 0; i < stream_bitrates.size() && bitrate_remainder > 0; ++i) { | |
63 if (stream_configs[i].maxBitrate * 1000 > bitrate_remainder) { | |
64 stream_bitrates[i] = bitrate_remainder; | |
65 } else { | |
66 stream_bitrates[i] = stream_configs[i].maxBitrate * 1000; | |
67 } | |
68 bitrate_remainder -= stream_bitrates[i]; | |
69 } | |
70 return stream_bitrates; | |
71 } | |
72 | |
73 class QMVideoSettingsCallback : public VCMQMSettingsCallback { | |
74 public: | |
75 explicit QMVideoSettingsCallback(VideoProcessing* vpm); | |
76 | |
77 ~QMVideoSettingsCallback(); | |
78 | |
79 // Update VPM with QM (quality modes: frame size & frame rate) settings. | |
80 int32_t SetVideoQMSettings(const uint32_t frame_rate, | |
81 const uint32_t width, | |
82 const uint32_t height); | |
83 | |
84 // Update target frame rate. | |
85 void SetTargetFramerate(int frame_rate); | |
86 | |
87 private: | |
88 VideoProcessing* vp_; | |
89 }; | |
90 | |
91 class ViEBitrateObserver : public BitrateObserver { | |
92 public: | |
93 explicit ViEBitrateObserver(ViEEncoder* owner) | |
94 : owner_(owner) { | |
95 } | |
96 virtual ~ViEBitrateObserver() {} | |
97 // Implements BitrateObserver. | |
98 virtual void OnNetworkChanged(uint32_t bitrate_bps, | |
99 uint8_t fraction_lost, | |
100 int64_t rtt) { | |
101 owner_->OnNetworkChanged(bitrate_bps, fraction_lost, rtt); | |
102 } | |
103 private: | |
104 ViEEncoder* owner_; | |
105 }; | |
106 | |
107 ViEEncoder::ViEEncoder(uint32_t number_of_cores, | |
108 ProcessThread* module_process_thread, | |
109 SendStatisticsProxy* stats_proxy, | |
110 I420FrameCallback* pre_encode_callback, | |
111 PacedSender* pacer, | |
112 BitrateAllocator* bitrate_allocator) | |
113 : number_of_cores_(number_of_cores), | |
114 vp_(VideoProcessing::Create()), | |
115 qm_callback_(new QMVideoSettingsCallback(vp_.get())), | |
116 vcm_(VideoCodingModule::Create(Clock::GetRealTimeClock(), | |
117 this, | |
118 qm_callback_.get())), | |
119 send_payload_router_(NULL), | |
120 data_cs_(CriticalSectionWrapper::CreateCriticalSection()), | |
121 stats_proxy_(stats_proxy), | |
122 pre_encode_callback_(pre_encode_callback), | |
123 pacer_(pacer), | |
124 bitrate_allocator_(bitrate_allocator), | |
125 time_of_last_frame_activity_ms_(0), | |
126 encoder_config_(), | |
127 min_transmit_bitrate_kbps_(0), | |
128 last_observed_bitrate_bps_(0), | |
129 target_delay_ms_(0), | |
130 network_is_transmitting_(true), | |
131 encoder_paused_(false), | |
132 encoder_paused_and_dropped_frame_(false), | |
133 module_process_thread_(module_process_thread), | |
134 has_received_sli_(false), | |
135 picture_id_sli_(0), | |
136 has_received_rpsi_(false), | |
137 picture_id_rpsi_(0), | |
138 video_suspended_(false) { | |
139 bitrate_observer_.reset(new ViEBitrateObserver(this)); | |
140 } | |
141 | |
142 bool ViEEncoder::Init() { | |
143 vp_->EnableTemporalDecimation(true); | |
144 | |
145 // Enable/disable content analysis: off by default for now. | |
146 vp_->EnableContentAnalysis(false); | |
147 | |
148 if (vcm_->RegisterTransportCallback(this) != 0) { | |
149 return false; | |
150 } | |
151 if (vcm_->RegisterSendStatisticsCallback(this) != 0) { | |
152 return false; | |
153 } | |
154 return true; | |
155 } | |
156 | |
157 void ViEEncoder::StartThreadsAndSetSharedMembers( | |
158 rtc::scoped_refptr<PayloadRouter> send_payload_router, | |
159 VCMProtectionCallback* vcm_protection_callback) { | |
160 RTC_DCHECK(send_payload_router_ == NULL); | |
161 | |
162 send_payload_router_ = send_payload_router; | |
163 vcm_->RegisterProtectionCallback(vcm_protection_callback); | |
164 module_process_thread_->RegisterModule(vcm_.get()); | |
165 } | |
166 | |
167 void ViEEncoder::StopThreadsAndRemoveSharedMembers() { | |
168 if (bitrate_allocator_) | |
169 bitrate_allocator_->RemoveBitrateObserver(bitrate_observer_.get()); | |
170 module_process_thread_->DeRegisterModule(vcm_.get()); | |
171 } | |
172 | |
173 ViEEncoder::~ViEEncoder() { | |
174 } | |
175 | |
176 void ViEEncoder::SetNetworkTransmissionState(bool is_transmitting) { | |
177 { | |
178 CriticalSectionScoped cs(data_cs_.get()); | |
179 network_is_transmitting_ = is_transmitting; | |
180 } | |
181 } | |
182 | |
183 void ViEEncoder::Pause() { | |
184 CriticalSectionScoped cs(data_cs_.get()); | |
185 encoder_paused_ = true; | |
186 } | |
187 | |
188 void ViEEncoder::Restart() { | |
189 CriticalSectionScoped cs(data_cs_.get()); | |
190 encoder_paused_ = false; | |
191 } | |
192 | |
193 int32_t ViEEncoder::RegisterExternalEncoder(webrtc::VideoEncoder* encoder, | |
194 uint8_t pl_type, | |
195 bool internal_source) { | |
196 if (vcm_->RegisterExternalEncoder(encoder, pl_type, internal_source) != | |
197 VCM_OK) { | |
198 return -1; | |
199 } | |
200 return 0; | |
201 } | |
202 | |
203 int32_t ViEEncoder::DeRegisterExternalEncoder(uint8_t pl_type) { | |
204 if (vcm_->RegisterExternalEncoder(NULL, pl_type) != VCM_OK) { | |
205 return -1; | |
206 } | |
207 return 0; | |
208 } | |
209 | |
210 int32_t ViEEncoder::SetEncoder(const webrtc::VideoCodec& video_codec) { | |
211 RTC_DCHECK(send_payload_router_ != NULL); | |
212 // Setting target width and height for VPM. | |
213 if (vp_->SetTargetResolution(video_codec.width, video_codec.height, | |
214 video_codec.maxFramerate) != VPM_OK) { | |
215 return -1; | |
216 } | |
217 | |
218 // Cache codec before calling AddBitrateObserver (which calls OnNetworkChanged | |
219 // that makes use of the number of simulcast streams configured). | |
220 { | |
221 CriticalSectionScoped cs(data_cs_.get()); | |
222 encoder_config_ = video_codec; | |
223 } | |
224 | |
225 // Add a bitrate observer to the allocator and update the start, max and | |
226 // min bitrates of the bitrate controller as needed. | |
227 int allocated_bitrate_bps = bitrate_allocator_->AddBitrateObserver( | |
228 bitrate_observer_.get(), video_codec.minBitrate * 1000, | |
229 video_codec.maxBitrate * 1000); | |
230 | |
231 webrtc::VideoCodec modified_video_codec = video_codec; | |
232 modified_video_codec.startBitrate = allocated_bitrate_bps / 1000; | |
233 | |
234 size_t max_data_payload_length = send_payload_router_->MaxPayloadLength(); | |
235 if (vcm_->RegisterSendCodec(&modified_video_codec, number_of_cores_, | |
236 static_cast<uint32_t>(max_data_payload_length)) != | |
237 VCM_OK) { | |
238 return -1; | |
239 } | |
240 return 0; | |
241 } | |
242 | |
243 int ViEEncoder::GetPaddingNeededBps() const { | |
244 int64_t time_of_last_frame_activity_ms; | |
245 int min_transmit_bitrate_bps; | |
246 int bitrate_bps; | |
247 VideoCodec send_codec; | |
248 { | |
249 CriticalSectionScoped cs(data_cs_.get()); | |
250 bool send_padding = encoder_config_.numberOfSimulcastStreams > 1 || | |
251 video_suspended_ || min_transmit_bitrate_kbps_ > 0; | |
252 if (!send_padding) | |
253 return 0; | |
254 time_of_last_frame_activity_ms = time_of_last_frame_activity_ms_; | |
255 min_transmit_bitrate_bps = 1000 * min_transmit_bitrate_kbps_; | |
256 bitrate_bps = last_observed_bitrate_bps_; | |
257 send_codec = encoder_config_; | |
258 } | |
259 | |
260 bool video_is_suspended = vcm_->VideoSuspended(); | |
261 | |
262 // Find the max amount of padding we can allow ourselves to send at this | |
263 // point, based on which streams are currently active and what our current | |
264 // available bandwidth is. | |
265 int pad_up_to_bitrate_bps = 0; | |
266 if (send_codec.numberOfSimulcastStreams == 0) { | |
267 pad_up_to_bitrate_bps = send_codec.minBitrate * 1000; | |
268 } else { | |
269 SimulcastStream* stream_configs = send_codec.simulcastStream; | |
270 pad_up_to_bitrate_bps = | |
271 stream_configs[send_codec.numberOfSimulcastStreams - 1].minBitrate * | |
272 1000; | |
273 for (int i = 0; i < send_codec.numberOfSimulcastStreams - 1; ++i) { | |
274 pad_up_to_bitrate_bps += stream_configs[i].targetBitrate * 1000; | |
275 } | |
276 } | |
277 | |
278 // Disable padding if only sending one stream and video isn't suspended and | |
279 // min-transmit bitrate isn't used (applied later). | |
280 if (!video_is_suspended && send_codec.numberOfSimulcastStreams <= 1) | |
281 pad_up_to_bitrate_bps = 0; | |
282 | |
283 // The amount of padding should decay to zero if no frames are being | |
284 // captured/encoded unless a min-transmit bitrate is used. | |
285 int64_t now_ms = TickTime::MillisecondTimestamp(); | |
286 if (now_ms - time_of_last_frame_activity_ms > kStopPaddingThresholdMs) | |
287 pad_up_to_bitrate_bps = 0; | |
288 | |
289 // Pad up to min bitrate. | |
290 if (pad_up_to_bitrate_bps < min_transmit_bitrate_bps) | |
291 pad_up_to_bitrate_bps = min_transmit_bitrate_bps; | |
292 | |
293 // Padding may never exceed bitrate estimate. | |
294 if (pad_up_to_bitrate_bps > bitrate_bps) | |
295 pad_up_to_bitrate_bps = bitrate_bps; | |
296 | |
297 return pad_up_to_bitrate_bps; | |
298 } | |
299 | |
300 bool ViEEncoder::EncoderPaused() const { | |
301 // Pause video if paused by caller or as long as the network is down or the | |
302 // pacer queue has grown too large in buffered mode. | |
303 if (encoder_paused_) { | |
304 return true; | |
305 } | |
306 if (target_delay_ms_ > 0) { | |
307 // Buffered mode. | |
308 // TODO(pwestin): Workaround until nack is configured as a time and not | |
309 // number of packets. | |
310 return pacer_->QueueInMs() >= | |
311 std::max( | |
312 static_cast<int>(target_delay_ms_ * kEncoderPausePacerMargin), | |
313 kMinPacingDelayMs); | |
314 } | |
315 if (pacer_->ExpectedQueueTimeMs() > PacedSender::kMaxQueueLengthMs) { | |
316 // Too much data in pacer queue, drop frame. | |
317 return true; | |
318 } | |
319 return !network_is_transmitting_; | |
320 } | |
321 | |
322 void ViEEncoder::TraceFrameDropStart() { | |
323 // Start trace event only on the first frame after encoder is paused. | |
324 if (!encoder_paused_and_dropped_frame_) { | |
325 TRACE_EVENT_ASYNC_BEGIN0("webrtc", "EncoderPaused", this); | |
326 } | |
327 encoder_paused_and_dropped_frame_ = true; | |
328 return; | |
329 } | |
330 | |
331 void ViEEncoder::TraceFrameDropEnd() { | |
332 // End trace event on first frame after encoder resumes, if frame was dropped. | |
333 if (encoder_paused_and_dropped_frame_) { | |
334 TRACE_EVENT_ASYNC_END0("webrtc", "EncoderPaused", this); | |
335 } | |
336 encoder_paused_and_dropped_frame_ = false; | |
337 } | |
338 | |
339 void ViEEncoder::DeliverFrame(VideoFrame video_frame) { | |
340 RTC_DCHECK(send_payload_router_ != NULL); | |
341 if (!send_payload_router_->active()) { | |
342 // We've paused or we have no channels attached, don't waste resources on | |
343 // encoding. | |
344 return; | |
345 } | |
346 VideoCodecType codec_type; | |
347 { | |
348 CriticalSectionScoped cs(data_cs_.get()); | |
349 time_of_last_frame_activity_ms_ = TickTime::MillisecondTimestamp(); | |
350 if (EncoderPaused()) { | |
351 TraceFrameDropStart(); | |
352 return; | |
353 } | |
354 TraceFrameDropEnd(); | |
355 codec_type = encoder_config_.codecType; | |
356 } | |
357 | |
358 TRACE_EVENT_ASYNC_STEP0("webrtc", "Video", video_frame.render_time_ms(), | |
359 "Encode"); | |
360 const VideoFrame* frame_to_send = &video_frame; | |
361 // TODO(wuchengli): support texture frames. | |
362 if (video_frame.native_handle() == NULL) { | |
363 // Pass frame via preprocessor. | |
364 frame_to_send = vp_->PreprocessFrame(video_frame); | |
365 if (!frame_to_send) { | |
366 // Drop this frame, or there was an error processing it. | |
367 return; | |
368 } | |
369 } | |
370 | |
371 // If we haven't resampled the frame and we have a FrameCallback, we need to | |
372 // make a deep copy of |video_frame|. | |
373 VideoFrame copied_frame; | |
374 if (pre_encode_callback_) { | |
375 copied_frame.CopyFrame(*frame_to_send); | |
376 pre_encode_callback_->FrameCallback(&copied_frame); | |
377 frame_to_send = &copied_frame; | |
378 } | |
379 | |
380 if (codec_type == webrtc::kVideoCodecVP8) { | |
381 webrtc::CodecSpecificInfo codec_specific_info; | |
382 codec_specific_info.codecType = webrtc::kVideoCodecVP8; | |
383 { | |
384 CriticalSectionScoped cs(data_cs_.get()); | |
385 codec_specific_info.codecSpecific.VP8.hasReceivedRPSI = | |
386 has_received_rpsi_; | |
387 codec_specific_info.codecSpecific.VP8.hasReceivedSLI = | |
388 has_received_sli_; | |
389 codec_specific_info.codecSpecific.VP8.pictureIdRPSI = | |
390 picture_id_rpsi_; | |
391 codec_specific_info.codecSpecific.VP8.pictureIdSLI = | |
392 picture_id_sli_; | |
393 has_received_sli_ = false; | |
394 has_received_rpsi_ = false; | |
395 } | |
396 | |
397 vcm_->AddVideoFrame(*frame_to_send, vp_->GetContentMetrics(), | |
398 &codec_specific_info); | |
399 return; | |
400 } | |
401 vcm_->AddVideoFrame(*frame_to_send); | |
402 } | |
403 | |
404 int ViEEncoder::SendKeyFrame() { | |
405 return vcm_->IntraFrameRequest(0); | |
406 } | |
407 | |
408 uint32_t ViEEncoder::LastObservedBitrateBps() const { | |
409 CriticalSectionScoped cs(data_cs_.get()); | |
410 return last_observed_bitrate_bps_; | |
411 } | |
412 | |
413 int ViEEncoder::CodecTargetBitrate(uint32_t* bitrate) const { | |
414 if (vcm_->Bitrate(bitrate) != 0) | |
415 return -1; | |
416 return 0; | |
417 } | |
418 | |
419 void ViEEncoder::SetProtectionMethod(bool nack, bool fec) { | |
420 // Set Video Protection for VCM. | |
421 VCMVideoProtection protection_mode; | |
422 if (fec) { | |
423 protection_mode = | |
424 nack ? webrtc::kProtectionNackFEC : kProtectionFEC; | |
425 } else { | |
426 protection_mode = nack ? kProtectionNack : kProtectionNone; | |
427 } | |
428 vcm_->SetVideoProtection(protection_mode, true); | |
429 } | |
430 | |
431 void ViEEncoder::SetSenderBufferingMode(int target_delay_ms) { | |
432 { | |
433 CriticalSectionScoped cs(data_cs_.get()); | |
434 target_delay_ms_ = target_delay_ms; | |
435 } | |
436 if (target_delay_ms > 0) { | |
437 // Disable external frame-droppers. | |
438 vcm_->EnableFrameDropper(false); | |
439 vp_->EnableTemporalDecimation(false); | |
440 } else { | |
441 // Real-time mode - enable frame droppers. | |
442 vp_->EnableTemporalDecimation(true); | |
443 vcm_->EnableFrameDropper(true); | |
444 } | |
445 } | |
446 | |
447 void ViEEncoder::OnSetRates(uint32_t bitrate_bps, int framerate) { | |
448 if (stats_proxy_) | |
449 stats_proxy_->OnSetRates(bitrate_bps, framerate); | |
450 } | |
451 | |
452 int32_t ViEEncoder::SendData( | |
453 const uint8_t payload_type, | |
454 const EncodedImage& encoded_image, | |
455 const webrtc::RTPFragmentationHeader& fragmentation_header, | |
456 const RTPVideoHeader* rtp_video_hdr) { | |
457 RTC_DCHECK(send_payload_router_ != NULL); | |
458 | |
459 { | |
460 CriticalSectionScoped cs(data_cs_.get()); | |
461 time_of_last_frame_activity_ms_ = TickTime::MillisecondTimestamp(); | |
462 } | |
463 | |
464 if (stats_proxy_ != NULL) | |
465 stats_proxy_->OnSendEncodedImage(encoded_image, rtp_video_hdr); | |
466 | |
467 return send_payload_router_->RoutePayload( | |
468 encoded_image._frameType, payload_type, encoded_image._timeStamp, | |
469 encoded_image.capture_time_ms_, encoded_image._buffer, | |
470 encoded_image._length, &fragmentation_header, rtp_video_hdr) | |
471 ? 0 | |
472 : -1; | |
473 } | |
474 | |
475 int32_t ViEEncoder::SendStatistics(const uint32_t bit_rate, | |
476 const uint32_t frame_rate) { | |
477 if (stats_proxy_) | |
478 stats_proxy_->OnOutgoingRate(frame_rate, bit_rate); | |
479 return 0; | |
480 } | |
481 | |
482 void ViEEncoder::OnReceivedSLI(uint32_t /*ssrc*/, | |
483 uint8_t picture_id) { | |
484 CriticalSectionScoped cs(data_cs_.get()); | |
485 picture_id_sli_ = picture_id; | |
486 has_received_sli_ = true; | |
487 } | |
488 | |
489 void ViEEncoder::OnReceivedRPSI(uint32_t /*ssrc*/, | |
490 uint64_t picture_id) { | |
491 CriticalSectionScoped cs(data_cs_.get()); | |
492 picture_id_rpsi_ = picture_id; | |
493 has_received_rpsi_ = true; | |
494 } | |
495 | |
496 void ViEEncoder::OnReceivedIntraFrameRequest(uint32_t ssrc) { | |
497 // Key frame request from remote side, signal to VCM. | |
498 TRACE_EVENT0("webrtc", "OnKeyFrameRequest"); | |
499 | |
500 int idx = 0; | |
501 { | |
502 CriticalSectionScoped cs(data_cs_.get()); | |
503 auto stream_it = ssrc_streams_.find(ssrc); | |
504 if (stream_it == ssrc_streams_.end()) { | |
505 LOG_F(LS_WARNING) << "ssrc not found: " << ssrc << ", map size " | |
506 << ssrc_streams_.size(); | |
507 return; | |
508 } | |
509 std::map<unsigned int, int64_t>::iterator time_it = | |
510 time_last_intra_request_ms_.find(ssrc); | |
511 if (time_it == time_last_intra_request_ms_.end()) { | |
512 time_last_intra_request_ms_[ssrc] = 0; | |
513 } | |
514 | |
515 int64_t now = TickTime::MillisecondTimestamp(); | |
516 if (time_last_intra_request_ms_[ssrc] + kMinKeyFrameRequestIntervalMs | |
517 > now) { | |
518 return; | |
519 } | |
520 time_last_intra_request_ms_[ssrc] = now; | |
521 idx = stream_it->second; | |
522 } | |
523 // Release the critsect before triggering key frame. | |
524 vcm_->IntraFrameRequest(idx); | |
525 } | |
526 | |
527 void ViEEncoder::OnLocalSsrcChanged(uint32_t old_ssrc, uint32_t new_ssrc) { | |
528 CriticalSectionScoped cs(data_cs_.get()); | |
529 std::map<unsigned int, int>::iterator it = ssrc_streams_.find(old_ssrc); | |
530 if (it == ssrc_streams_.end()) { | |
531 return; | |
532 } | |
533 | |
534 ssrc_streams_[new_ssrc] = it->second; | |
535 ssrc_streams_.erase(it); | |
536 | |
537 std::map<unsigned int, int64_t>::iterator time_it = | |
538 time_last_intra_request_ms_.find(old_ssrc); | |
539 int64_t last_intra_request_ms = 0; | |
540 if (time_it != time_last_intra_request_ms_.end()) { | |
541 last_intra_request_ms = time_it->second; | |
542 time_last_intra_request_ms_.erase(time_it); | |
543 } | |
544 time_last_intra_request_ms_[new_ssrc] = last_intra_request_ms; | |
545 } | |
546 | |
547 void ViEEncoder::SetSsrcs(const std::vector<uint32_t>& ssrcs) { | |
548 CriticalSectionScoped cs(data_cs_.get()); | |
549 ssrc_streams_.clear(); | |
550 time_last_intra_request_ms_.clear(); | |
551 int idx = 0; | |
552 for (uint32_t ssrc : ssrcs) { | |
553 ssrc_streams_[ssrc] = idx++; | |
554 } | |
555 } | |
556 | |
557 void ViEEncoder::SetMinTransmitBitrate(int min_transmit_bitrate_kbps) { | |
558 assert(min_transmit_bitrate_kbps >= 0); | |
559 CriticalSectionScoped crit(data_cs_.get()); | |
560 min_transmit_bitrate_kbps_ = min_transmit_bitrate_kbps; | |
561 } | |
562 | |
563 // Called from ViEBitrateObserver. | |
564 void ViEEncoder::OnNetworkChanged(uint32_t bitrate_bps, | |
565 uint8_t fraction_lost, | |
566 int64_t round_trip_time_ms) { | |
567 LOG(LS_VERBOSE) << "OnNetworkChanged, bitrate" << bitrate_bps | |
568 << " packet loss " << static_cast<int>(fraction_lost) | |
569 << " rtt " << round_trip_time_ms; | |
570 RTC_DCHECK(send_payload_router_ != NULL); | |
571 vcm_->SetChannelParameters(bitrate_bps, fraction_lost, round_trip_time_ms); | |
572 bool video_is_suspended = vcm_->VideoSuspended(); | |
573 bool video_suspension_changed; | |
574 VideoCodec send_codec; | |
575 uint32_t first_ssrc; | |
576 { | |
577 CriticalSectionScoped cs(data_cs_.get()); | |
578 last_observed_bitrate_bps_ = bitrate_bps; | |
579 video_suspension_changed = video_suspended_ != video_is_suspended; | |
580 video_suspended_ = video_is_suspended; | |
581 send_codec = encoder_config_; | |
582 first_ssrc = ssrc_streams_.begin()->first; | |
583 } | |
584 | |
585 SimulcastStream* stream_configs = send_codec.simulcastStream; | |
586 // Allocate the bandwidth between the streams. | |
587 std::vector<uint32_t> stream_bitrates = AllocateStreamBitrates( | |
588 bitrate_bps, stream_configs, send_codec.numberOfSimulcastStreams); | |
589 send_payload_router_->SetTargetSendBitrates(stream_bitrates); | |
590 | |
591 if (!video_suspension_changed) | |
592 return; | |
593 // Video suspend-state changed, inform codec observer. | |
594 LOG(LS_INFO) << "Video suspend state changed " << video_is_suspended | |
595 << " for ssrc " << first_ssrc; | |
596 if (stats_proxy_) | |
597 stats_proxy_->OnSuspendChange(video_is_suspended); | |
598 } | |
599 | |
600 void ViEEncoder::SuspendBelowMinBitrate() { | |
601 vcm_->SuspendBelowMinBitrate(); | |
602 bitrate_allocator_->EnforceMinBitrate(false); | |
603 } | |
604 | |
605 void ViEEncoder::RegisterPostEncodeImageCallback( | |
606 EncodedImageCallback* post_encode_callback) { | |
607 vcm_->RegisterPostEncodeImageCallback(post_encode_callback); | |
608 } | |
609 | |
610 QMVideoSettingsCallback::QMVideoSettingsCallback(VideoProcessing* vpm) | |
611 : vp_(vpm) { | |
612 } | |
613 | |
614 QMVideoSettingsCallback::~QMVideoSettingsCallback() { | |
615 } | |
616 | |
617 int32_t QMVideoSettingsCallback::SetVideoQMSettings( | |
618 const uint32_t frame_rate, | |
619 const uint32_t width, | |
620 const uint32_t height) { | |
621 return vp_->SetTargetResolution(width, height, frame_rate); | |
622 } | |
623 | |
624 void QMVideoSettingsCallback::SetTargetFramerate(int frame_rate) { | |
625 vp_->SetTargetFramerate(frame_rate); | |
626 } | |
627 | |
628 } // namespace webrtc | |
OLD | NEW |