Line data Source code
1 : /*
2 : * Copyright (c) 2016 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/modules/video_coding/protection_bitrate_calculator.h"
12 :
13 : namespace webrtc {
14 :
15 : using rtc::CritScope;
16 :
17 : struct ProtectionBitrateCalculator::EncodedFrameSample {
18 : EncodedFrameSample(size_t size_bytes,
19 : uint32_t timestamp,
20 : int64_t time_complete_ms)
21 : : size_bytes(size_bytes),
22 : timestamp(timestamp),
23 : time_complete_ms(time_complete_ms) {}
24 : size_t size_bytes;
25 : uint32_t timestamp;
26 : int64_t time_complete_ms;
27 : };
28 :
29 0 : ProtectionBitrateCalculator::ProtectionBitrateCalculator(
30 : Clock* clock,
31 0 : VCMProtectionCallback* protection_callback)
32 : : clock_(clock),
33 : protection_callback_(protection_callback),
34 : loss_prot_logic_(new media_optimization::VCMLossProtectionLogic(
35 0 : clock_->TimeInMilliseconds())),
36 0 : max_payload_size_(1460) {}
37 :
38 0 : ProtectionBitrateCalculator::~ProtectionBitrateCalculator(void) {
39 0 : loss_prot_logic_->Release();
40 0 : }
41 :
42 0 : void ProtectionBitrateCalculator::SetEncodingData(size_t width,
43 : size_t height,
44 : size_t num_temporal_layers,
45 : size_t max_payload_size) {
46 0 : CritScope lock(&crit_sect_);
47 0 : loss_prot_logic_->UpdateFrameSize(width, height);
48 0 : loss_prot_logic_->UpdateNumLayers(num_temporal_layers);
49 0 : max_payload_size_ = max_payload_size;
50 0 : }
51 :
52 0 : uint32_t ProtectionBitrateCalculator::SetTargetRates(
53 : uint32_t estimated_bitrate_bps,
54 : int actual_framerate_fps,
55 : uint8_t fraction_lost,
56 : int64_t round_trip_time_ms) {
57 : float target_bitrate_kbps =
58 0 : static_cast<float>(estimated_bitrate_bps) / 1000.0f;
59 : // Sanity check.
60 0 : if (actual_framerate_fps < 1.0) {
61 0 : actual_framerate_fps = 1.0;
62 : }
63 :
64 : FecProtectionParams delta_fec_params;
65 : FecProtectionParams key_fec_params;
66 : {
67 0 : CritScope lock(&crit_sect_);
68 :
69 0 : loss_prot_logic_->UpdateBitRate(target_bitrate_kbps);
70 0 : loss_prot_logic_->UpdateRtt(round_trip_time_ms);
71 :
72 : // Update frame rate for the loss protection logic class: frame rate should
73 : // be the actual/sent rate.
74 0 : loss_prot_logic_->UpdateFrameRate(actual_framerate_fps);
75 :
76 : // Returns the filtered packet loss, used for the protection setting.
77 : // The filtered loss may be the received loss (no filter), or some
78 : // filtered value (average or max window filter).
79 : // Use max window filter for now.
80 : media_optimization::FilterPacketLossMode filter_mode =
81 0 : media_optimization::kMaxFilter;
82 0 : uint8_t packet_loss_enc = loss_prot_logic_->FilteredLoss(
83 0 : clock_->TimeInMilliseconds(), filter_mode, fraction_lost);
84 :
85 : // For now use the filtered loss for computing the robustness settings.
86 0 : loss_prot_logic_->UpdateFilteredLossPr(packet_loss_enc);
87 :
88 0 : if (loss_prot_logic_->SelectedType() == media_optimization::kNone) {
89 0 : return estimated_bitrate_bps;
90 : }
91 :
92 : // Update method will compute the robustness settings for the given
93 : // protection method and the overhead cost
94 : // the protection method is set by the user via SetVideoProtection.
95 0 : loss_prot_logic_->UpdateMethod();
96 :
97 : // Get the bit cost of protection method, based on the amount of
98 : // overhead data actually transmitted (including headers) the last
99 : // second.
100 :
101 : // Get the FEC code rate for Key frames (set to 0 when NA).
102 0 : key_fec_params.fec_rate =
103 0 : loss_prot_logic_->SelectedMethod()->RequiredProtectionFactorK();
104 :
105 : // Get the FEC code rate for Delta frames (set to 0 when NA).
106 0 : delta_fec_params.fec_rate =
107 0 : loss_prot_logic_->SelectedMethod()->RequiredProtectionFactorD();
108 :
109 : // The RTP module currently requires the same |max_fec_frames| for both
110 : // key and delta frames.
111 0 : delta_fec_params.max_fec_frames =
112 0 : loss_prot_logic_->SelectedMethod()->MaxFramesFec();
113 0 : key_fec_params.max_fec_frames =
114 0 : loss_prot_logic_->SelectedMethod()->MaxFramesFec();
115 : }
116 :
117 : // Set the FEC packet mask type. |kFecMaskBursty| is more effective for
118 : // consecutive losses and little/no packet re-ordering. As we currently
119 : // do not have feedback data on the degree of correlated losses and packet
120 : // re-ordering, we keep default setting to |kFecMaskRandom| for now.
121 0 : delta_fec_params.fec_mask_type = kFecMaskRandom;
122 0 : key_fec_params.fec_mask_type = kFecMaskRandom;
123 :
124 : // Update protection callback with protection settings.
125 0 : uint32_t sent_video_rate_bps = 0;
126 0 : uint32_t sent_nack_rate_bps = 0;
127 0 : uint32_t sent_fec_rate_bps = 0;
128 : // Rate cost of the protection methods.
129 0 : float protection_overhead_rate = 0.0f;
130 :
131 : // TODO(Marco): Pass FEC protection values per layer.
132 0 : protection_callback_->ProtectionRequest(
133 : &delta_fec_params, &key_fec_params, &sent_video_rate_bps,
134 0 : &sent_nack_rate_bps, &sent_fec_rate_bps);
135 :
136 : uint32_t sent_total_rate_bps =
137 0 : sent_video_rate_bps + sent_nack_rate_bps + sent_fec_rate_bps;
138 : // Estimate the overhead costs of the next second as staying the same
139 : // wrt the source bitrate.
140 0 : if (sent_total_rate_bps > 0) {
141 0 : protection_overhead_rate =
142 0 : static_cast<float>(sent_nack_rate_bps + sent_fec_rate_bps) /
143 : sent_total_rate_bps;
144 : }
145 : // Cap the overhead estimate to 50%.
146 0 : if (protection_overhead_rate > 0.5)
147 0 : protection_overhead_rate = 0.5;
148 :
149 : // Source coding rate: total rate - protection overhead.
150 0 : return estimated_bitrate_bps * (1.0 - protection_overhead_rate);
151 : }
152 :
153 0 : void ProtectionBitrateCalculator::SetProtectionMethod(bool enable_fec,
154 : bool enable_nack) {
155 0 : media_optimization::VCMProtectionMethodEnum method(media_optimization::kNone);
156 0 : if (enable_fec && enable_nack) {
157 0 : method = media_optimization::kNackFec;
158 0 : } else if (enable_nack) {
159 0 : method = media_optimization::kNack;
160 0 : } else if (enable_fec) {
161 0 : method = media_optimization::kFec;
162 : }
163 0 : CritScope lock(&crit_sect_);
164 0 : loss_prot_logic_->SetMethod(method);
165 0 : }
166 :
167 0 : void ProtectionBitrateCalculator::UpdateWithEncodedData(
168 : const EncodedImage& encoded_image) {
169 0 : const size_t encoded_length = encoded_image._length;
170 0 : CritScope lock(&crit_sect_);
171 0 : if (encoded_length > 0) {
172 0 : const bool delta_frame = encoded_image._frameType != kVideoFrameKey;
173 :
174 0 : if (max_payload_size_ > 0 && encoded_length > 0) {
175 : const float min_packets_per_frame =
176 0 : encoded_length / static_cast<float>(max_payload_size_);
177 0 : if (delta_frame) {
178 0 : loss_prot_logic_->UpdatePacketsPerFrame(min_packets_per_frame,
179 0 : clock_->TimeInMilliseconds());
180 : } else {
181 0 : loss_prot_logic_->UpdatePacketsPerFrameKey(
182 0 : min_packets_per_frame, clock_->TimeInMilliseconds());
183 : }
184 : }
185 0 : if (!delta_frame && encoded_length > 0) {
186 0 : loss_prot_logic_->UpdateKeyFrameSize(static_cast<float>(encoded_length));
187 : }
188 : }
189 0 : }
190 :
191 : } // namespace webrtc
|