1 /* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
2 *
3 * Use of this source code is governed by a BSD-style license
4 * that can be found in the LICENSE file in the root of the source
5 * tree. An additional intellectual property rights grant can be found
6 * in the file PATENTS. All contributing project authors may
7 * be found in the AUTHORS file in the root of the source tree.
8 */
9
10 #include <stdlib.h>
11 #include <algorithm>
12
13 #include "vpx/vpx_encoder.h"
14 #include "vpx/vp8cx.h"
15 #include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
16 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8_common_types.h"
17 #include "webrtc/modules/video_coding/codecs/vp8/temporal_layers.h"
18
19 // This file implements logic to adapt the number of temporal layers based on
20 // input frame rate in order to avoid having the base layer being relaying at
21 // a below acceptable framerate.
22 namespace webrtc {
23 namespace {
24 enum {
25 kTemporalUpdateLast = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
26 VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF,
27
28 kTemporalUpdateGolden =
29 VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST,
30
31 kTemporalUpdateGoldenWithoutDependency =
32 kTemporalUpdateGolden | VP8_EFLAG_NO_REF_GF,
33
34 kTemporalUpdateAltref = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_LAST,
35
36 kTemporalUpdateAltrefWithoutDependency =
37 kTemporalUpdateAltref | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_REF_GF,
38
39 kTemporalUpdateNone = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
40 VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ENTROPY,
41
42 kTemporalUpdateNoneNoRefAltref = kTemporalUpdateNone | VP8_EFLAG_NO_REF_ARF,
43
44 kTemporalUpdateNoneNoRefGoldenRefAltRef =
45 VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
46 VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ENTROPY,
47
48 kTemporalUpdateGoldenWithoutDependencyRefAltRef =
49 VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST,
50
51 kTemporalUpdateLastRefAltRef =
52 VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF,
53
54 kTemporalUpdateGoldenRefAltRef = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST,
55
56 kTemporalUpdateLastAndGoldenRefAltRef =
57 VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF,
58
59 kTemporalUpdateLastRefAll = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_GF,
60 };
61
CalculateNumberOfTemporalLayers(int current_temporal_layers,int input_fps)62 int CalculateNumberOfTemporalLayers(int current_temporal_layers,
63 int input_fps) {
64 if (input_fps >= 24) {
65 return 3;
66 }
67 if (input_fps >= 20 && current_temporal_layers >= 3) {
68 // Keep doing 3 temporal layers until we go below 20fps.
69 return 3;
70 }
71 if (input_fps >= 10) {
72 return 2;
73 }
74 if (input_fps > 8 && current_temporal_layers >= 2) {
75 // keep doing 2 temporal layers until we go below 8fps
76 return 2;
77 }
78 return 1;
79 }
80
81 class RealTimeTemporalLayers : public TemporalLayers {
82 public:
RealTimeTemporalLayers(int max_num_temporal_layers,uint8_t initial_tl0_pic_idx)83 RealTimeTemporalLayers(int max_num_temporal_layers,
84 uint8_t initial_tl0_pic_idx)
85 : temporal_layers_(1),
86 max_temporal_layers_(max_num_temporal_layers),
87 tl0_pic_idx_(initial_tl0_pic_idx),
88 frame_counter_(static_cast<unsigned int>(-1)),
89 timestamp_(0),
90 last_base_layer_sync_(0),
91 layer_ids_length_(0),
92 layer_ids_(NULL),
93 encode_flags_length_(0),
94 encode_flags_(NULL) {
95 assert(max_temporal_layers_ >= 1);
96 assert(max_temporal_layers_ <= 3);
97 }
98
~RealTimeTemporalLayers()99 virtual ~RealTimeTemporalLayers() {}
100
ConfigureBitrates(int bitrate_kbit,int max_bitrate_kbit,int framerate,vpx_codec_enc_cfg_t * cfg)101 virtual bool ConfigureBitrates(int bitrate_kbit,
102 int max_bitrate_kbit,
103 int framerate,
104 vpx_codec_enc_cfg_t* cfg) {
105 temporal_layers_ =
106 CalculateNumberOfTemporalLayers(temporal_layers_, framerate);
107 temporal_layers_ = std::min(temporal_layers_, max_temporal_layers_);
108 assert(temporal_layers_ >= 1 && temporal_layers_ <= 3);
109
110 cfg->ts_number_layers = temporal_layers_;
111 for (int tl = 0; tl < temporal_layers_; ++tl) {
112 cfg->ts_target_bitrate[tl] =
113 bitrate_kbit * kVp8LayerRateAlloction[temporal_layers_ - 1][tl];
114 }
115
116 switch (temporal_layers_) {
117 case 1: {
118 static const unsigned int layer_ids[] = {0u};
119 layer_ids_ = layer_ids;
120 layer_ids_length_ = sizeof(layer_ids) / sizeof(*layer_ids);
121
122 static const int encode_flags[] = {kTemporalUpdateLastRefAll};
123 encode_flags_length_ = sizeof(encode_flags) / sizeof(*layer_ids);
124 encode_flags_ = encode_flags;
125
126 cfg->ts_rate_decimator[0] = 1;
127 cfg->ts_periodicity = layer_ids_length_;
128 } break;
129
130 case 2: {
131 static const unsigned int layer_ids[] = {0u, 1u};
132 layer_ids_ = layer_ids;
133 layer_ids_length_ = sizeof(layer_ids) / sizeof(*layer_ids);
134
135 static const int encode_flags[] = {
136 kTemporalUpdateLastAndGoldenRefAltRef,
137 kTemporalUpdateGoldenWithoutDependencyRefAltRef,
138 kTemporalUpdateLastRefAltRef, kTemporalUpdateGoldenRefAltRef,
139 kTemporalUpdateLastRefAltRef, kTemporalUpdateGoldenRefAltRef,
140 kTemporalUpdateLastRefAltRef, kTemporalUpdateNone
141 };
142 encode_flags_length_ = sizeof(encode_flags) / sizeof(*layer_ids);
143 encode_flags_ = encode_flags;
144
145 cfg->ts_rate_decimator[0] = 2;
146 cfg->ts_rate_decimator[1] = 1;
147 cfg->ts_periodicity = layer_ids_length_;
148 } break;
149
150 case 3: {
151 static const unsigned int layer_ids[] = {0u, 2u, 1u, 2u};
152 layer_ids_ = layer_ids;
153 layer_ids_length_ = sizeof(layer_ids) / sizeof(*layer_ids);
154
155 static const int encode_flags[] = {
156 kTemporalUpdateLastAndGoldenRefAltRef,
157 kTemporalUpdateNoneNoRefGoldenRefAltRef,
158 kTemporalUpdateGoldenWithoutDependencyRefAltRef, kTemporalUpdateNone,
159 kTemporalUpdateLastRefAltRef, kTemporalUpdateNone,
160 kTemporalUpdateGoldenRefAltRef, kTemporalUpdateNone
161 };
162 encode_flags_length_ = sizeof(encode_flags) / sizeof(*layer_ids);
163 encode_flags_ = encode_flags;
164
165 cfg->ts_rate_decimator[0] = 4;
166 cfg->ts_rate_decimator[1] = 2;
167 cfg->ts_rate_decimator[2] = 1;
168 cfg->ts_periodicity = layer_ids_length_;
169 } break;
170
171 default:
172 assert(false);
173 return false;
174 }
175 memcpy(
176 cfg->ts_layer_id, layer_ids_, sizeof(unsigned int) * layer_ids_length_);
177 return true;
178 }
179
EncodeFlags(uint32_t timestamp)180 virtual int EncodeFlags(uint32_t timestamp) {
181 frame_counter_++;
182 return CurrentEncodeFlags();
183 }
184
CurrentEncodeFlags() const185 int CurrentEncodeFlags() const {
186 assert(encode_flags_length_ > 0 && encode_flags_ != NULL);
187 int index = frame_counter_ % encode_flags_length_;
188 assert(index >= 0 && index < encode_flags_length_);
189 return encode_flags_[index];
190 }
191
CurrentLayerId() const192 virtual int CurrentLayerId() const {
193 assert(layer_ids_length_ > 0 && layer_ids_ != NULL);
194 int index = frame_counter_ % layer_ids_length_;
195 assert(index >= 0 && index < layer_ids_length_);
196 return layer_ids_[index];
197 }
198
PopulateCodecSpecific(bool base_layer_sync,CodecSpecificInfoVP8 * vp8_info,uint32_t timestamp)199 virtual void PopulateCodecSpecific(bool base_layer_sync,
200 CodecSpecificInfoVP8* vp8_info,
201 uint32_t timestamp) {
202 assert(temporal_layers_ > 0);
203
204 if (temporal_layers_ == 1) {
205 vp8_info->temporalIdx = kNoTemporalIdx;
206 vp8_info->layerSync = false;
207 vp8_info->tl0PicIdx = kNoTl0PicIdx;
208 } else {
209 if (base_layer_sync) {
210 vp8_info->temporalIdx = 0;
211 vp8_info->layerSync = true;
212 } else {
213 vp8_info->temporalIdx = CurrentLayerId();
214 int temporal_reference = CurrentEncodeFlags();
215
216 if (temporal_reference == kTemporalUpdateAltrefWithoutDependency ||
217 temporal_reference == kTemporalUpdateGoldenWithoutDependency ||
218 temporal_reference ==
219 kTemporalUpdateGoldenWithoutDependencyRefAltRef ||
220 temporal_reference == kTemporalUpdateNoneNoRefGoldenRefAltRef ||
221 (temporal_reference == kTemporalUpdateNone &&
222 temporal_layers_ == 4)) {
223 vp8_info->layerSync = true;
224 } else {
225 vp8_info->layerSync = false;
226 }
227 }
228 if (last_base_layer_sync_ && vp8_info->temporalIdx != 0) {
229 // Regardless of pattern the frame after a base layer sync will always
230 // be a layer sync.
231 vp8_info->layerSync = true;
232 }
233 if (vp8_info->temporalIdx == 0 && timestamp != timestamp_) {
234 timestamp_ = timestamp;
235 tl0_pic_idx_++;
236 }
237 last_base_layer_sync_ = base_layer_sync;
238 vp8_info->tl0PicIdx = tl0_pic_idx_;
239 }
240 }
241
FrameEncoded(unsigned int size,uint32_t timestamp)242 void FrameEncoded(unsigned int size, uint32_t timestamp) {}
243
244 private:
245 int temporal_layers_;
246 int max_temporal_layers_;
247
248 int tl0_pic_idx_;
249 unsigned int frame_counter_;
250 uint32_t timestamp_;
251 bool last_base_layer_sync_;
252
253 // Pattern of temporal layer ids.
254 int layer_ids_length_;
255 const unsigned int* layer_ids_;
256
257 // Pattern of encode flags.
258 int encode_flags_length_;
259 const int* encode_flags_;
260 };
261 } // namespace
262
Create(int max_temporal_layers,uint8_t initial_tl0_pic_idx) const263 TemporalLayers* RealTimeTemporalLayersFactory::Create(
264 int max_temporal_layers,
265 uint8_t initial_tl0_pic_idx) const {
266 return new RealTimeTemporalLayers(max_temporal_layers, initial_tl0_pic_idx);
267 }
268 } // namespace webrtc
269