OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2014 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 |
11 #include "webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter.h" | 11 #include "webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter.h" |
12 | 12 |
13 #include <algorithm> | 13 #include <algorithm> |
14 | 14 |
15 // NOTE(ajm): Path provided by gyp. | 15 // NOTE(ajm): Path provided by gyp. |
16 #include "libyuv/scale.h" // NOLINT | 16 #include "libyuv/scale.h" // NOLINT |
17 | 17 |
18 #include "webrtc/base/checks.h" | 18 #include "webrtc/base/checks.h" |
19 #include "webrtc/modules/video_coding/codecs/vp8/screenshare_layers.h" | 19 #include "webrtc/modules/video_coding/codecs/vp8/screenshare_layers.h" |
20 #include "webrtc/modules/video_coding/utility/simulcast_state.h" | |
20 #include "webrtc/system_wrappers/include/clock.h" | 21 #include "webrtc/system_wrappers/include/clock.h" |
21 | 22 |
22 namespace { | 23 namespace { |
23 | 24 |
24 const unsigned int kDefaultMinQp = 2; | 25 const unsigned int kDefaultMinQp = 2; |
25 const unsigned int kDefaultMaxQp = 56; | 26 const unsigned int kDefaultMaxQp = 56; |
26 // Max qp for lowest spatial resolution when doing simulcast. | 27 // Max qp for lowest spatial resolution when doing simulcast. |
27 const unsigned int kLowestResMaxQp = 45; | 28 const unsigned int kLowestResMaxQp = 45; |
28 | 29 |
29 uint32_t SumStreamTargetBitrate(int streams, const webrtc::VideoCodec& codec) { | |
30 uint32_t bitrate_sum = 0; | |
31 for (int i = 0; i < streams; ++i) { | |
32 bitrate_sum += codec.simulcastStream[i].targetBitrate; | |
33 } | |
34 return bitrate_sum; | |
35 } | |
36 | |
37 uint32_t SumStreamMaxBitrate(int streams, const webrtc::VideoCodec& codec) { | |
38 uint32_t bitrate_sum = 0; | |
39 for (int i = 0; i < streams; ++i) { | |
40 bitrate_sum += codec.simulcastStream[i].maxBitrate; | |
41 } | |
42 return bitrate_sum; | |
43 } | |
44 | |
45 int NumberOfStreams(const webrtc::VideoCodec& codec) { | |
46 int streams = | |
47 codec.numberOfSimulcastStreams < 1 ? 1 : codec.numberOfSimulcastStreams; | |
48 uint32_t simulcast_max_bitrate = SumStreamMaxBitrate(streams, codec); | |
49 if (simulcast_max_bitrate == 0) { | |
50 streams = 1; | |
51 } | |
52 return streams; | |
53 } | |
54 | |
55 bool ValidSimulcastResolutions(const webrtc::VideoCodec& codec, | 30 bool ValidSimulcastResolutions(const webrtc::VideoCodec& codec, |
56 int num_streams) { | 31 int num_streams) { |
57 if (codec.width != codec.simulcastStream[num_streams - 1].width || | 32 if (codec.width != codec.simulcastStream[num_streams - 1].width || |
58 codec.height != codec.simulcastStream[num_streams - 1].height) { | 33 codec.height != codec.simulcastStream[num_streams - 1].height) { |
59 return false; | 34 return false; |
60 } | 35 } |
61 for (int i = 0; i < num_streams; ++i) { | 36 for (int i = 0; i < num_streams; ++i) { |
62 if (codec.width * codec.simulcastStream[i].height != | 37 if (codec.width * codec.simulcastStream[i].height != |
63 codec.height * codec.simulcastStream[i].width) { | 38 codec.height * codec.simulcastStream[i].width) { |
64 return false; | 39 return false; |
(...skipping 20 matching lines...) Expand all Loading... | |
85 inst->numberOfSimulcastStreams > 1) { | 60 inst->numberOfSimulcastStreams > 1) { |
86 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | 61 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; |
87 } | 62 } |
88 if (inst->codecSpecific.VP8.automaticResizeOn && | 63 if (inst->codecSpecific.VP8.automaticResizeOn && |
89 inst->numberOfSimulcastStreams > 1) { | 64 inst->numberOfSimulcastStreams > 1) { |
90 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | 65 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; |
91 } | 66 } |
92 return WEBRTC_VIDEO_CODEC_OK; | 67 return WEBRTC_VIDEO_CODEC_OK; |
93 } | 68 } |
94 | 69 |
95 // TL1 FrameDropper's max time to drop frames. | |
96 const float kTl1MaxTimeToDropFrames = 20.0f; | |
97 | |
98 struct ScreenshareTemporalLayersFactory : webrtc::TemporalLayersFactory { | 70 struct ScreenshareTemporalLayersFactory : webrtc::TemporalLayersFactory { |
99 ScreenshareTemporalLayersFactory() | 71 ScreenshareTemporalLayersFactory() {} |
100 : tl1_frame_dropper_(kTl1MaxTimeToDropFrames) {} | |
101 | |
102 virtual ~ScreenshareTemporalLayersFactory() {} | 72 virtual ~ScreenshareTemporalLayersFactory() {} |
103 | 73 |
104 virtual webrtc::TemporalLayers* Create(int num_temporal_layers, | 74 virtual webrtc::TemporalLayers* Create(int num_temporal_layers, |
105 uint8_t initial_tl0_pic_idx) const { | 75 uint8_t initial_tl0_pic_idx) const { |
106 return new webrtc::ScreenshareLayers(num_temporal_layers, rand(), | 76 return new webrtc::ScreenshareLayers(num_temporal_layers, rand(), |
107 webrtc::Clock::GetRealTimeClock()); | 77 webrtc::Clock::GetRealTimeClock()); |
108 } | 78 } |
109 | |
110 mutable webrtc::FrameDropper tl0_frame_dropper_; | |
111 mutable webrtc::FrameDropper tl1_frame_dropper_; | |
112 }; | 79 }; |
113 | 80 |
114 // An EncodedImageCallback implementation that forwards on calls to a | 81 // An EncodedImageCallback implementation that forwards on calls to a |
115 // SimulcastEncoderAdapter, but with the stream index it's registered with as | 82 // SimulcastEncoderAdapter, but with the stream index it's registered with as |
116 // the first parameter to Encoded. | 83 // the first parameter to Encoded. |
117 class AdapterEncodedImageCallback : public webrtc::EncodedImageCallback { | 84 class AdapterEncodedImageCallback : public webrtc::EncodedImageCallback { |
118 public: | 85 public: |
119 AdapterEncodedImageCallback(webrtc::SimulcastEncoderAdapter* adapter, | 86 AdapterEncodedImageCallback(webrtc::SimulcastEncoderAdapter* adapter, |
120 size_t stream_idx) | 87 size_t stream_idx) |
121 : adapter_(adapter), stream_idx_(stream_idx) {} | 88 : adapter_(adapter), stream_idx_(stream_idx) {} |
(...skipping 25 matching lines...) Expand all Loading... | |
147 SimulcastEncoderAdapter::~SimulcastEncoderAdapter() { | 114 SimulcastEncoderAdapter::~SimulcastEncoderAdapter() { |
148 Release(); | 115 Release(); |
149 } | 116 } |
150 | 117 |
151 int SimulcastEncoderAdapter::Release() { | 118 int SimulcastEncoderAdapter::Release() { |
152 // TODO(pbos): Keep the last encoder instance but call ::Release() on it, then | 119 // TODO(pbos): Keep the last encoder instance but call ::Release() on it, then |
153 // re-use this instance in ::InitEncode(). This means that changing | 120 // re-use this instance in ::InitEncode(). This means that changing |
154 // resolutions doesn't require reallocation of the first encoder, but only | 121 // resolutions doesn't require reallocation of the first encoder, but only |
155 // reinitialization, which makes sense. Then Destroy this instance instead in | 122 // reinitialization, which makes sense. Then Destroy this instance instead in |
156 // ~SimulcastEncoderAdapter(). | 123 // ~SimulcastEncoderAdapter(). |
157 while (!streaminfos_.empty()) { | 124 stream_states_.reset(); |
158 VideoEncoder* encoder = streaminfos_.back().encoder; | 125 for (auto& it : encoders_) |
159 EncodedImageCallback* callback = streaminfos_.back().callback; | 126 factory_->Destroy(it.second.first); |
160 factory_->Destroy(encoder); | 127 encoders_.clear(); |
161 delete callback; | 128 |
162 streaminfos_.pop_back(); | |
163 } | |
164 return WEBRTC_VIDEO_CODEC_OK; | 129 return WEBRTC_VIDEO_CODEC_OK; |
165 } | 130 } |
166 | 131 |
167 int SimulcastEncoderAdapter::InitEncode(const VideoCodec* inst, | 132 int SimulcastEncoderAdapter::InitEncode(const VideoCodec* inst, |
168 int number_of_cores, | 133 int number_of_cores, |
169 size_t max_payload_size) { | 134 size_t max_payload_size) { |
170 if (number_of_cores < 1) { | 135 if (number_of_cores < 1) { |
171 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | 136 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; |
172 } | 137 } |
173 | 138 |
174 int ret = VerifyCodec(inst); | 139 int ret = VerifyCodec(inst); |
175 if (ret < 0) { | 140 if (ret < 0) { |
176 return ret; | 141 return ret; |
177 } | 142 } |
178 | 143 |
179 ret = Release(); | 144 ret = Release(); |
180 if (ret < 0) { | 145 if (ret < 0) { |
181 return ret; | 146 return ret; |
182 } | 147 } |
183 | 148 |
184 int number_of_streams = NumberOfStreams(*inst); | 149 std::unique_ptr<SimulcastState> simulcast(new SimulcastState(*inst)); |
150 | |
151 int number_of_streams = simulcast->NumStreams(); | |
185 const bool doing_simulcast = (number_of_streams > 1); | 152 const bool doing_simulcast = (number_of_streams > 1); |
186 | 153 |
187 if (doing_simulcast && !ValidSimulcastResolutions(*inst, number_of_streams)) { | 154 if (doing_simulcast && !ValidSimulcastResolutions(*inst, number_of_streams)) { |
188 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | 155 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; |
189 } | 156 } |
190 | 157 |
191 codec_ = *inst; | 158 codec_ = *inst; |
192 | 159 |
193 // Special mode when screensharing on a single stream. | 160 // Special mode when screensharing on a single stream. |
194 if (number_of_streams == 1 && inst->mode == kScreensharing) { | 161 if (number_of_streams == 1 && inst->mode == kScreensharing) { |
195 screensharing_tl_factory_.reset(new ScreenshareTemporalLayersFactory()); | 162 screensharing_tl_factory_.reset(new ScreenshareTemporalLayersFactory()); |
196 codec_.codecSpecific.VP8.tl_factory = screensharing_tl_factory_.get(); | 163 codec_.codecSpecific.VP8.tl_factory = screensharing_tl_factory_.get(); |
197 } | 164 } |
198 | 165 |
199 std::string implementation_name; | 166 std::string implementation_name; |
200 // Create |number_of_streams| of encoder instances and init them. | 167 // Create |number_of_streams| of encoder instances and init them. |
201 for (int i = 0; i < number_of_streams; ++i) { | 168 stream_states_ = std::move(simulcast); |
169 for (SimulcastState::Stream stream : *stream_states_) { | |
202 VideoCodec stream_codec; | 170 VideoCodec stream_codec; |
203 bool send_stream = true; | |
204 if (!doing_simulcast) { | 171 if (!doing_simulcast) { |
205 stream_codec = codec_; | 172 stream_codec = codec_; |
206 stream_codec.numberOfSimulcastStreams = 1; | 173 stream_codec.numberOfSimulcastStreams = 1; |
207 } else { | 174 } else { |
208 bool highest_resolution_stream = (i == (number_of_streams - 1)); | 175 stream_codec = stream.AsCodec(); |
209 PopulateStreamCodec(&codec_, i, number_of_streams, | 176 if (stream.idx == 0) { |
210 highest_resolution_stream, &stream_codec, | 177 // Settings for lowest spatial resolutions. |
211 &send_stream); | 178 stream_codec.qpMax = kLowestResMaxQp; |
179 } | |
180 if (stream.idx < codec_.numberOfSimulcastStreams - 1) { | |
181 // For resolutions below CIF, set the codec |complexity| parameter to | |
182 // kComplexityHigher, which maps to cpu_used = -4. | |
183 if (stream_codec.width * stream_codec.height < 352 * 288) { | |
184 stream_codec.codecSpecific.VP8.complexity = webrtc::kComplexityHigher; | |
185 } | |
186 // Turn off denoising for all streams but the highest resolution. | |
187 stream_codec.codecSpecific.VP8.denoisingOn = false; | |
188 } | |
212 } | 189 } |
213 | 190 |
214 // TODO(ronghuawu): Remove once this is handled in VP8EncoderImpl. | 191 // TODO(ronghuawu): Remove once this is handled in VP8EncoderImpl. |
215 if (stream_codec.qpMax < kDefaultMinQp) { | 192 if (stream_codec.qpMax < kDefaultMinQp) { |
216 stream_codec.qpMax = kDefaultMaxQp; | 193 stream_codec.qpMax = kDefaultMaxQp; |
217 } | 194 } |
218 | 195 |
219 VideoEncoder* encoder = factory_->Create(); | 196 VideoEncoder* encoder = factory_->Create(); |
220 ret = encoder->InitEncode(&stream_codec, number_of_cores, max_payload_size); | 197 ret = encoder->InitEncode(&stream_codec, number_of_cores, max_payload_size); |
221 if (ret < 0) { | 198 if (ret < 0) { |
222 Release(); | 199 Release(); |
223 return ret; | 200 return ret; |
224 } | 201 } |
225 EncodedImageCallback* callback = new AdapterEncodedImageCallback(this, i); | 202 EncodedImageCallback* callback = |
203 new AdapterEncodedImageCallback(this, stream.idx); | |
226 encoder->RegisterEncodeCompleteCallback(callback); | 204 encoder->RegisterEncodeCompleteCallback(callback); |
227 streaminfos_.push_back(StreamInfo(encoder, callback, stream_codec.width, | 205 encoders_[stream.idx] = EncoderContext( |
228 stream_codec.height, send_stream)); | 206 encoder, std::unique_ptr<EncodedImageCallback>(callback)); |
229 if (i != 0) | 207 if (stream.idx != 0) |
230 implementation_name += ", "; | 208 implementation_name += ", "; |
231 implementation_name += streaminfos_[i].encoder->ImplementationName(); | 209 implementation_name += encoder->ImplementationName(); |
232 } | 210 } |
211 | |
233 if (doing_simulcast) { | 212 if (doing_simulcast) { |
234 implementation_name_ = | 213 implementation_name_ = |
235 "SimulcastEncoderAdapter (" + implementation_name + ")"; | 214 "SimulcastEncoderAdapter (" + implementation_name + ")"; |
236 } else { | 215 } else { |
237 implementation_name_ = implementation_name; | 216 implementation_name_ = implementation_name; |
238 } | 217 } |
239 return WEBRTC_VIDEO_CODEC_OK; | 218 return WEBRTC_VIDEO_CODEC_OK; |
240 } | 219 } |
241 | 220 |
242 int SimulcastEncoderAdapter::Encode( | 221 int SimulcastEncoderAdapter::Encode( |
243 const VideoFrame& input_image, | 222 const VideoFrame& input_image, |
244 const CodecSpecificInfo* codec_specific_info, | 223 const CodecSpecificInfo* codec_specific_info, |
245 const std::vector<FrameType>* frame_types) { | 224 const std::vector<FrameType>* frame_types) { |
246 if (!Initialized()) { | 225 if (!Initialized()) { |
247 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 226 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
248 } | 227 } |
249 if (encoded_complete_callback_ == NULL) { | 228 if (encoded_complete_callback_ == NULL) { |
250 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 229 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
251 } | 230 } |
252 | 231 |
253 // All active streams should generate a key frame if | 232 // All active streams should generate a key frame if a key frame is requested |
254 // a key frame is requested by any stream. | 233 // by any stream. |
255 bool send_key_frame = false; | 234 bool send_key_frame = stream_states_->AnyKeyFrameRequested() || |
256 if (frame_types) { | 235 (frame_types && |
257 for (size_t i = 0; i < frame_types->size(); ++i) { | 236 std::find(frame_types->begin(), frame_types->end(), |
258 if (frame_types->at(i) == kVideoFrameKey) { | 237 kVideoFrameKey) != frame_types->end()); |
259 send_key_frame = true; | |
260 break; | |
261 } | |
262 } | |
263 } | |
264 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) { | |
265 if (streaminfos_[stream_idx].key_frame_request && | |
266 streaminfos_[stream_idx].send_stream) { | |
267 send_key_frame = true; | |
268 break; | |
269 } | |
270 } | |
271 | 238 |
272 int src_width = input_image.width(); | 239 int src_width = input_image.width(); |
273 int src_height = input_image.height(); | 240 int src_height = input_image.height(); |
274 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) { | 241 for (const SimulcastState::Stream& stream : *stream_states_) { |
275 // Don't encode frames in resolutions that we don't intend to send. | 242 if (!stream.sending) |
276 if (!streaminfos_[stream_idx].send_stream) | |
277 continue; | 243 continue; |
278 | 244 |
279 std::vector<FrameType> stream_frame_types; | 245 std::vector<FrameType> stream_frame_types; |
280 if (send_key_frame) { | 246 if (send_key_frame) { |
281 stream_frame_types.push_back(kVideoFrameKey); | 247 stream_frame_types.push_back(kVideoFrameKey); |
282 streaminfos_[stream_idx].key_frame_request = false; | 248 stream_states_->GetAndResetKeyFrameRequest(stream.idx); |
283 } else { | 249 } else { |
284 stream_frame_types.push_back(kVideoFrameDelta); | 250 stream_frame_types.push_back(kVideoFrameDelta); |
285 } | 251 } |
286 | 252 |
287 int dst_width = streaminfos_[stream_idx].width; | 253 int dst_width = stream.config.width; |
288 int dst_height = streaminfos_[stream_idx].height; | 254 int dst_height = stream.config.height; |
289 // If scaling isn't required, because the input resolution | 255 // If scaling isn't required, because the input resolution matches the |
290 // matches the destination or the input image is empty (e.g. | 256 // destination or the input image is empty (e.g. a keyframe request for |
291 // a keyframe request for encoders with internal camera | 257 // encoders with internal camera sources), pass the image on directly. |
292 // sources), pass the image on directly. Otherwise, we'll | 258 // Otherwise, we'll scale it to match what the encoder expects (below). |
293 // scale it to match what the encoder expects (below). | |
294 if ((dst_width == src_width && dst_height == src_height) || | 259 if ((dst_width == src_width && dst_height == src_height) || |
295 input_image.IsZeroSize()) { | 260 input_image.IsZeroSize()) { |
296 streaminfos_[stream_idx].encoder->Encode(input_image, codec_specific_info, | 261 encoders_[stream.idx].first->Encode(input_image, codec_specific_info, |
297 &stream_frame_types); | 262 &stream_frame_types); |
298 } else { | 263 } else { |
299 VideoFrame dst_frame; | 264 VideoFrame dst_frame; |
300 // Making sure that destination frame is of sufficient size. | 265 // Making sure that destination frame is of sufficient size. |
301 // Aligning stride values based on width. | 266 // Aligning stride values based on width. |
302 dst_frame.CreateEmptyFrame(dst_width, dst_height, dst_width, | 267 dst_frame.CreateEmptyFrame(dst_width, dst_height, dst_width, |
303 (dst_width + 1) / 2, (dst_width + 1) / 2); | 268 (dst_width + 1) / 2, (dst_width + 1) / 2); |
304 libyuv::I420Scale( | 269 libyuv::I420Scale( |
305 input_image.buffer(kYPlane), input_image.stride(kYPlane), | 270 input_image.buffer(kYPlane), input_image.stride(kYPlane), |
306 input_image.buffer(kUPlane), input_image.stride(kUPlane), | 271 input_image.buffer(kUPlane), input_image.stride(kUPlane), |
307 input_image.buffer(kVPlane), input_image.stride(kVPlane), src_width, | 272 input_image.buffer(kVPlane), input_image.stride(kVPlane), src_width, |
308 src_height, dst_frame.buffer(kYPlane), dst_frame.stride(kYPlane), | 273 src_height, dst_frame.buffer(kYPlane), dst_frame.stride(kYPlane), |
309 dst_frame.buffer(kUPlane), dst_frame.stride(kUPlane), | 274 dst_frame.buffer(kUPlane), dst_frame.stride(kUPlane), |
310 dst_frame.buffer(kVPlane), dst_frame.stride(kVPlane), dst_width, | 275 dst_frame.buffer(kVPlane), dst_frame.stride(kVPlane), dst_width, |
311 dst_height, libyuv::kFilterBilinear); | 276 dst_height, libyuv::kFilterBilinear); |
312 dst_frame.set_timestamp(input_image.timestamp()); | 277 dst_frame.set_timestamp(input_image.timestamp()); |
313 dst_frame.set_render_time_ms(input_image.render_time_ms()); | 278 dst_frame.set_render_time_ms(input_image.render_time_ms()); |
314 streaminfos_[stream_idx].encoder->Encode(dst_frame, codec_specific_info, | 279 encoders_[stream.idx].first->Encode(dst_frame, codec_specific_info, |
315 &stream_frame_types); | 280 &stream_frame_types); |
316 } | 281 } |
317 } | 282 } |
318 | 283 |
319 return WEBRTC_VIDEO_CODEC_OK; | 284 return WEBRTC_VIDEO_CODEC_OK; |
320 } | 285 } |
321 | 286 |
322 int SimulcastEncoderAdapter::RegisterEncodeCompleteCallback( | 287 int SimulcastEncoderAdapter::RegisterEncodeCompleteCallback( |
323 EncodedImageCallback* callback) { | 288 EncodedImageCallback* callback) { |
324 encoded_complete_callback_ = callback; | 289 encoded_complete_callback_ = callback; |
325 return WEBRTC_VIDEO_CODEC_OK; | 290 return WEBRTC_VIDEO_CODEC_OK; |
326 } | 291 } |
327 | 292 |
328 int SimulcastEncoderAdapter::SetChannelParameters(uint32_t packet_loss, | 293 int SimulcastEncoderAdapter::SetChannelParameters(uint32_t packet_loss, |
329 int64_t rtt) { | 294 int64_t rtt) { |
330 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) { | 295 for (const auto& it : encoders_) |
331 streaminfos_[stream_idx].encoder->SetChannelParameters(packet_loss, rtt); | 296 it.second.first->SetChannelParameters(packet_loss, rtt); |
332 } | |
333 return WEBRTC_VIDEO_CODEC_OK; | 297 return WEBRTC_VIDEO_CODEC_OK; |
334 } | 298 } |
335 | 299 |
336 int SimulcastEncoderAdapter::SetRates(uint32_t new_bitrate_kbit, | 300 int SimulcastEncoderAdapter::SetRates(uint32_t new_bitrate_kbit, |
337 uint32_t new_framerate) { | 301 uint32_t new_framerate) { |
338 if (!Initialized()) { | 302 if (!Initialized()) |
339 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 303 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
340 } | 304 |
341 if (new_framerate < 1) { | 305 if (new_framerate < 1) |
342 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | 306 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; |
343 } | 307 |
344 if (codec_.maxBitrate > 0 && new_bitrate_kbit > codec_.maxBitrate) { | 308 if (codec_.maxBitrate > 0 && new_bitrate_kbit > codec_.maxBitrate) |
345 new_bitrate_kbit = codec_.maxBitrate; | 309 new_bitrate_kbit = codec_.maxBitrate; |
346 } | 310 |
347 if (new_bitrate_kbit < codec_.minBitrate) { | 311 if (new_bitrate_kbit < codec_.minBitrate) |
348 new_bitrate_kbit = codec_.minBitrate; | 312 new_bitrate_kbit = codec_.minBitrate; |
349 } | 313 |
350 if (codec_.numberOfSimulcastStreams > 0 && | 314 if (codec_.numberOfSimulcastStreams > 0 && |
351 new_bitrate_kbit < codec_.simulcastStream[0].minBitrate) { | 315 new_bitrate_kbit < codec_.simulcastStream[0].minBitrate) { |
352 new_bitrate_kbit = codec_.simulcastStream[0].minBitrate; | 316 new_bitrate_kbit = codec_.simulcastStream[0].minBitrate; |
353 } | 317 } |
318 | |
354 codec_.maxFramerate = new_framerate; | 319 codec_.maxFramerate = new_framerate; |
355 | 320 stream_states_->AllocateBitrate(new_bitrate_kbit); |
pbos-webrtc
2016/04/29 21:23:27
Shouldn't we also set the rates? I'm concerned wit
| |
356 bool send_stream = true; | |
357 uint32_t stream_bitrate = 0; | |
358 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) { | |
359 stream_bitrate = GetStreamBitrate(stream_idx, streaminfos_.size(), | |
360 new_bitrate_kbit, &send_stream); | |
361 // Need a key frame if we have not sent this stream before. | |
362 if (send_stream && !streaminfos_[stream_idx].send_stream) { | |
363 streaminfos_[stream_idx].key_frame_request = true; | |
364 } | |
365 streaminfos_[stream_idx].send_stream = send_stream; | |
366 | |
367 // TODO(holmer): This is a temporary hack for screensharing, where we | |
368 // interpret the startBitrate as the encoder target bitrate. This is | |
369 // to allow for a different max bitrate, so if the codec can't meet | |
370 // the target we still allow it to overshoot up to the max before dropping | |
371 // frames. This hack should be improved. | |
372 if (codec_.targetBitrate > 0 && | |
373 (codec_.codecSpecific.VP8.numberOfTemporalLayers == 2 || | |
374 codec_.simulcastStream[0].numberOfTemporalLayers == 2)) { | |
375 stream_bitrate = std::min(codec_.maxBitrate, stream_bitrate); | |
376 // TODO(ronghuawu): Can't change max bitrate via the VideoEncoder | |
377 // interface. And VP8EncoderImpl doesn't take negative framerate. | |
378 // max_bitrate = std::min(codec_.maxBitrate, stream_bitrate); | |
379 // new_framerate = -1; | |
380 } | |
381 | |
382 streaminfos_[stream_idx].encoder->SetRates(stream_bitrate, new_framerate); | |
383 } | |
384 | 321 |
385 return WEBRTC_VIDEO_CODEC_OK; | 322 return WEBRTC_VIDEO_CODEC_OK; |
386 } | 323 } |
387 | 324 |
388 int32_t SimulcastEncoderAdapter::Encoded( | 325 int32_t SimulcastEncoderAdapter::Encoded( |
389 size_t stream_idx, | 326 size_t stream_idx, |
390 const EncodedImage& encodedImage, | 327 const EncodedImage& encodedImage, |
391 const CodecSpecificInfo* codecSpecificInfo, | 328 const CodecSpecificInfo* codecSpecificInfo, |
392 const RTPFragmentationHeader* fragmentation) { | 329 const RTPFragmentationHeader* fragmentation) { |
393 CodecSpecificInfo stream_codec_specific = *codecSpecificInfo; | 330 CodecSpecificInfo stream_codec_specific = *codecSpecificInfo; |
394 CodecSpecificInfoVP8* vp8Info = &(stream_codec_specific.codecSpecific.VP8); | 331 CodecSpecificInfoVP8* vp8Info = &(stream_codec_specific.codecSpecific.VP8); |
395 vp8Info->simulcastIdx = stream_idx; | 332 vp8Info->simulcastIdx = stream_idx; |
396 | 333 |
397 return encoded_complete_callback_->Encoded( | 334 return encoded_complete_callback_->Encoded( |
398 encodedImage, &stream_codec_specific, fragmentation); | 335 encodedImage, &stream_codec_specific, fragmentation); |
399 } | 336 } |
400 | 337 |
401 uint32_t SimulcastEncoderAdapter::GetStreamBitrate( | |
402 int stream_idx, | |
403 size_t total_number_of_streams, | |
404 uint32_t new_bitrate_kbit, | |
405 bool* send_stream) const { | |
406 if (total_number_of_streams == 1) { | |
407 *send_stream = true; | |
408 return new_bitrate_kbit; | |
409 } | |
410 | |
411 // The bitrate needed to start sending this stream is given by the | |
412 // minimum bitrate allowed for encoding this stream, plus the sum target | |
413 // rates of all lower streams. | |
414 uint32_t sum_target_lower_streams = | |
415 SumStreamTargetBitrate(stream_idx, codec_); | |
416 uint32_t bitrate_to_send_this_layer = | |
417 codec_.simulcastStream[stream_idx].minBitrate + sum_target_lower_streams; | |
418 if (new_bitrate_kbit >= bitrate_to_send_this_layer) { | |
419 // We have enough bandwidth to send this stream. | |
420 *send_stream = true; | |
421 // Bitrate for this stream is the new bitrate (|new_bitrate_kbit|) minus the | |
422 // sum target rates of the lower streams, and capped to a maximum bitrate. | |
423 // The maximum cap depends on whether we send the next higher stream. | |
424 // If we will be sending the next higher stream, |max_rate| is given by | |
425 // current stream's |targetBitrate|, otherwise it's capped by |maxBitrate|. | |
426 if (stream_idx < codec_.numberOfSimulcastStreams - 1) { | |
427 unsigned int max_rate = codec_.simulcastStream[stream_idx].maxBitrate; | |
428 if (new_bitrate_kbit >= | |
429 SumStreamTargetBitrate(stream_idx + 1, codec_) + | |
430 codec_.simulcastStream[stream_idx + 1].minBitrate) { | |
431 max_rate = codec_.simulcastStream[stream_idx].targetBitrate; | |
432 } | |
433 return std::min(new_bitrate_kbit - sum_target_lower_streams, max_rate); | |
434 } else { | |
435 // For the highest stream (highest resolution), the |targetBitRate| and | |
436 // |maxBitrate| are not used. Any excess bitrate (above the targets of | |
437 // all lower streams) is given to this (highest resolution) stream. | |
438 return new_bitrate_kbit - sum_target_lower_streams; | |
439 } | |
440 } else { | |
441 // Not enough bitrate for this stream. | |
442 // Return our max bitrate of |stream_idx| - 1, but we don't send it. We need | |
443 // to keep this resolution coding in order for the multi-encoder to work. | |
444 *send_stream = false; | |
445 return codec_.simulcastStream[stream_idx - 1].maxBitrate; | |
446 } | |
447 } | |
448 | |
449 void SimulcastEncoderAdapter::PopulateStreamCodec( | |
450 const webrtc::VideoCodec* inst, | |
451 int stream_index, | |
452 size_t total_number_of_streams, | |
453 bool highest_resolution_stream, | |
454 webrtc::VideoCodec* stream_codec, | |
455 bool* send_stream) { | |
456 *stream_codec = *inst; | |
457 | |
458 // Stream specific settings. | |
459 stream_codec->codecSpecific.VP8.numberOfTemporalLayers = | |
460 inst->simulcastStream[stream_index].numberOfTemporalLayers; | |
461 stream_codec->numberOfSimulcastStreams = 0; | |
462 stream_codec->width = inst->simulcastStream[stream_index].width; | |
463 stream_codec->height = inst->simulcastStream[stream_index].height; | |
464 stream_codec->maxBitrate = inst->simulcastStream[stream_index].maxBitrate; | |
465 stream_codec->minBitrate = inst->simulcastStream[stream_index].minBitrate; | |
466 stream_codec->qpMax = inst->simulcastStream[stream_index].qpMax; | |
467 // Settings that are based on stream/resolution. | |
468 if (stream_index == 0) { | |
469 // Settings for lowest spatial resolutions. | |
470 stream_codec->qpMax = kLowestResMaxQp; | |
471 } | |
472 if (!highest_resolution_stream) { | |
473 // For resolutions below CIF, set the codec |complexity| parameter to | |
474 // kComplexityHigher, which maps to cpu_used = -4. | |
475 int pixels_per_frame = stream_codec->width * stream_codec->height; | |
476 if (pixels_per_frame < 352 * 288) { | |
477 stream_codec->codecSpecific.VP8.complexity = webrtc::kComplexityHigher; | |
478 } | |
479 // Turn off denoising for all streams but the highest resolution. | |
480 stream_codec->codecSpecific.VP8.denoisingOn = false; | |
481 } | |
482 // TODO(ronghuawu): what to do with targetBitrate. | |
483 | |
484 int stream_bitrate = GetStreamBitrate(stream_index, total_number_of_streams, | |
485 inst->startBitrate, send_stream); | |
486 stream_codec->startBitrate = stream_bitrate; | |
487 } | |
488 | |
489 bool SimulcastEncoderAdapter::Initialized() const { | 338 bool SimulcastEncoderAdapter::Initialized() const { |
490 return !streaminfos_.empty(); | 339 return stream_states_.get() != nullptr; |
491 } | 340 } |
492 | 341 |
493 void SimulcastEncoderAdapter::OnDroppedFrame() { | 342 void SimulcastEncoderAdapter::OnDroppedFrame() { |
494 streaminfos_[0].encoder->OnDroppedFrame(); | 343 encoders_[0].first->OnDroppedFrame(); |
pbos-webrtc
2016/04/29 21:23:27
I think this should report to all encoders.
| |
495 } | 344 } |
496 | 345 |
497 int SimulcastEncoderAdapter::GetTargetFramerate() { | 346 int SimulcastEncoderAdapter::GetTargetFramerate() { |
498 return streaminfos_[0].encoder->GetTargetFramerate(); | 347 return encoders_[0].first->GetTargetFramerate(); |
499 } | 348 } |
500 | 349 |
501 bool SimulcastEncoderAdapter::SupportsNativeHandle() const { | 350 bool SimulcastEncoderAdapter::SupportsNativeHandle() const { |
502 // We should not be calling this method before streaminfos_ are configured. | 351 // We should not be calling this method before streaminfos_ are configured. |
503 RTC_DCHECK(!streaminfos_.empty()); | 352 RTC_DCHECK(Initialized()); |
504 // TODO(pbos): Support textures when using more than one encoder. | 353 // TODO(pbos): Support textures when using more than one encoder. |
505 if (streaminfos_.size() != 1) | 354 if (encoders_.size() != 1) |
506 return false; | 355 return false; |
507 return streaminfos_[0].encoder->SupportsNativeHandle(); | 356 return encoders_.begin()->second.first->SupportsNativeHandle(); |
508 } | 357 } |
509 | 358 |
510 const char* SimulcastEncoderAdapter::ImplementationName() const { | 359 const char* SimulcastEncoderAdapter::ImplementationName() const { |
511 return implementation_name_.c_str(); | 360 return implementation_name_.c_str(); |
512 } | 361 } |
513 | 362 |
514 } // namespace webrtc | 363 } // namespace webrtc |
OLD | NEW |