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_rate_allocator.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) { | 30 uint32_t SumStreamMaxBitrate(int streams, const webrtc::VideoCodec& codec) { |
38 uint32_t bitrate_sum = 0; | 31 uint32_t bitrate_sum = 0; |
39 for (int i = 0; i < streams; ++i) { | 32 for (int i = 0; i < streams; ++i) { |
40 bitrate_sum += codec.simulcastStream[i].maxBitrate; | 33 bitrate_sum += codec.simulcastStream[i].maxBitrate; |
41 } | 34 } |
42 return bitrate_sum; | 35 return bitrate_sum; |
43 } | 36 } |
44 | 37 |
45 int NumberOfStreams(const webrtc::VideoCodec& codec) { | 38 int NumberOfStreams(const webrtc::VideoCodec& codec) { |
46 int streams = | 39 int streams = |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
85 inst->numberOfSimulcastStreams > 1) { | 78 inst->numberOfSimulcastStreams > 1) { |
86 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | 79 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; |
87 } | 80 } |
88 if (inst->codecSpecific.VP8.automaticResizeOn && | 81 if (inst->codecSpecific.VP8.automaticResizeOn && |
89 inst->numberOfSimulcastStreams > 1) { | 82 inst->numberOfSimulcastStreams > 1) { |
90 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | 83 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; |
91 } | 84 } |
92 return WEBRTC_VIDEO_CODEC_OK; | 85 return WEBRTC_VIDEO_CODEC_OK; |
93 } | 86 } |
94 | 87 |
95 // TL1 FrameDropper's max time to drop frames. | |
96 const float kTl1MaxTimeToDropFrames = 20.0f; | |
97 | |
98 struct ScreenshareTemporalLayersFactory : webrtc::TemporalLayersFactory { | 88 struct ScreenshareTemporalLayersFactory : webrtc::TemporalLayersFactory { |
99 ScreenshareTemporalLayersFactory() | 89 ScreenshareTemporalLayersFactory() {} |
100 : tl1_frame_dropper_(kTl1MaxTimeToDropFrames) {} | |
101 | |
102 virtual ~ScreenshareTemporalLayersFactory() {} | 90 virtual ~ScreenshareTemporalLayersFactory() {} |
103 | 91 |
104 virtual webrtc::TemporalLayers* Create(int num_temporal_layers, | 92 virtual webrtc::TemporalLayers* Create(int num_temporal_layers, |
105 uint8_t initial_tl0_pic_idx) const { | 93 uint8_t initial_tl0_pic_idx) const { |
106 return new webrtc::ScreenshareLayers(num_temporal_layers, rand(), | 94 return new webrtc::ScreenshareLayers(num_temporal_layers, rand(), |
107 webrtc::Clock::GetRealTimeClock()); | 95 webrtc::Clock::GetRealTimeClock()); |
108 } | 96 } |
109 | |
110 mutable webrtc::FrameDropper tl0_frame_dropper_; | |
111 mutable webrtc::FrameDropper tl1_frame_dropper_; | |
112 }; | 97 }; |
113 | 98 |
114 // An EncodedImageCallback implementation that forwards on calls to a | 99 // An EncodedImageCallback implementation that forwards on calls to a |
115 // SimulcastEncoderAdapter, but with the stream index it's registered with as | 100 // SimulcastEncoderAdapter, but with the stream index it's registered with as |
116 // the first parameter to Encoded. | 101 // the first parameter to Encoded. |
117 class AdapterEncodedImageCallback : public webrtc::EncodedImageCallback { | 102 class AdapterEncodedImageCallback : public webrtc::EncodedImageCallback { |
118 public: | 103 public: |
119 AdapterEncodedImageCallback(webrtc::SimulcastEncoderAdapter* adapter, | 104 AdapterEncodedImageCallback(webrtc::SimulcastEncoderAdapter* adapter, |
120 size_t stream_idx) | 105 size_t stream_idx) |
121 : adapter_(adapter), stream_idx_(stream_idx) {} | 106 : adapter_(adapter), stream_idx_(stream_idx) {} |
(...skipping 10 matching lines...) Expand all Loading... |
132 webrtc::SimulcastEncoderAdapter* const adapter_; | 117 webrtc::SimulcastEncoderAdapter* const adapter_; |
133 const size_t stream_idx_; | 118 const size_t stream_idx_; |
134 }; | 119 }; |
135 | 120 |
136 } // namespace | 121 } // namespace |
137 | 122 |
138 namespace webrtc { | 123 namespace webrtc { |
139 | 124 |
140 SimulcastEncoderAdapter::SimulcastEncoderAdapter(VideoEncoderFactory* factory) | 125 SimulcastEncoderAdapter::SimulcastEncoderAdapter(VideoEncoderFactory* factory) |
141 : factory_(factory), | 126 : factory_(factory), |
142 encoded_complete_callback_(NULL), | 127 encoded_complete_callback_(nullptr), |
143 implementation_name_("SimulcastEncoderAdapter") { | 128 implementation_name_("SimulcastEncoderAdapter") { |
144 memset(&codec_, 0, sizeof(webrtc::VideoCodec)); | 129 memset(&codec_, 0, sizeof(webrtc::VideoCodec)); |
| 130 rate_allocator_.reset(new SimulcastRateAllocator(codec_)); |
145 } | 131 } |
146 | 132 |
147 SimulcastEncoderAdapter::~SimulcastEncoderAdapter() { | 133 SimulcastEncoderAdapter::~SimulcastEncoderAdapter() { |
148 Release(); | 134 Release(); |
149 } | 135 } |
150 | 136 |
151 int SimulcastEncoderAdapter::Release() { | 137 int SimulcastEncoderAdapter::Release() { |
152 // TODO(pbos): Keep the last encoder instance but call ::Release() on it, then | 138 // TODO(pbos): Keep the last encoder instance but call ::Release() on it, then |
153 // re-use this instance in ::InitEncode(). This means that changing | 139 // re-use this instance in ::InitEncode(). This means that changing |
154 // resolutions doesn't require reallocation of the first encoder, but only | 140 // resolutions doesn't require reallocation of the first encoder, but only |
(...skipping 27 matching lines...) Expand all Loading... |
182 } | 168 } |
183 | 169 |
184 int number_of_streams = NumberOfStreams(*inst); | 170 int number_of_streams = NumberOfStreams(*inst); |
185 const bool doing_simulcast = (number_of_streams > 1); | 171 const bool doing_simulcast = (number_of_streams > 1); |
186 | 172 |
187 if (doing_simulcast && !ValidSimulcastResolutions(*inst, number_of_streams)) { | 173 if (doing_simulcast && !ValidSimulcastResolutions(*inst, number_of_streams)) { |
188 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | 174 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; |
189 } | 175 } |
190 | 176 |
191 codec_ = *inst; | 177 codec_ = *inst; |
| 178 rate_allocator_.reset(new SimulcastRateAllocator(codec_)); |
| 179 std::vector<uint32_t> start_bitrates = |
| 180 rate_allocator_->GetAllocation(codec_.startBitrate); |
192 | 181 |
193 // Special mode when screensharing on a single stream. | 182 // Special mode when screensharing on a single stream. |
194 if (number_of_streams == 1 && inst->mode == kScreensharing) { | 183 if (number_of_streams == 1 && inst->mode == kScreensharing) { |
195 screensharing_tl_factory_.reset(new ScreenshareTemporalLayersFactory()); | 184 screensharing_tl_factory_.reset(new ScreenshareTemporalLayersFactory()); |
196 codec_.codecSpecific.VP8.tl_factory = screensharing_tl_factory_.get(); | 185 codec_.codecSpecific.VP8.tl_factory = screensharing_tl_factory_.get(); |
197 } | 186 } |
198 | 187 |
199 std::string implementation_name; | 188 std::string implementation_name; |
200 // Create |number_of_streams| of encoder instances and init them. | 189 // Create |number_of_streams| of encoder instances and init them. |
201 for (int i = 0; i < number_of_streams; ++i) { | 190 for (int i = 0; i < number_of_streams; ++i) { |
202 VideoCodec stream_codec; | 191 VideoCodec stream_codec; |
203 bool send_stream = true; | 192 uint32_t start_bitrate_kbps = start_bitrates[i]; |
204 if (!doing_simulcast) { | 193 if (!doing_simulcast) { |
205 stream_codec = codec_; | 194 stream_codec = codec_; |
206 stream_codec.numberOfSimulcastStreams = 1; | 195 stream_codec.numberOfSimulcastStreams = 1; |
207 } else { | 196 } else { |
| 197 // Cap start bitrate to the min bitrate in order to avoid strange codec |
| 198 // behavior. Since sending sending will be false, this should not matter. |
| 199 start_bitrate_kbps = |
| 200 std::max(codec_.simulcastStream[i].minBitrate, start_bitrate_kbps); |
208 bool highest_resolution_stream = (i == (number_of_streams - 1)); | 201 bool highest_resolution_stream = (i == (number_of_streams - 1)); |
209 PopulateStreamCodec(&codec_, i, number_of_streams, | 202 PopulateStreamCodec(&codec_, i, start_bitrate_kbps, |
210 highest_resolution_stream, &stream_codec, | 203 highest_resolution_stream, &stream_codec); |
211 &send_stream); | |
212 } | 204 } |
213 | 205 |
214 // TODO(ronghuawu): Remove once this is handled in VP8EncoderImpl. | 206 // TODO(ronghuawu): Remove once this is handled in VP8EncoderImpl. |
215 if (stream_codec.qpMax < kDefaultMinQp) { | 207 if (stream_codec.qpMax < kDefaultMinQp) { |
216 stream_codec.qpMax = kDefaultMaxQp; | 208 stream_codec.qpMax = kDefaultMaxQp; |
217 } | 209 } |
218 | 210 |
219 VideoEncoder* encoder = factory_->Create(); | 211 VideoEncoder* encoder = factory_->Create(); |
220 ret = encoder->InitEncode(&stream_codec, number_of_cores, max_payload_size); | 212 ret = encoder->InitEncode(&stream_codec, number_of_cores, max_payload_size); |
221 if (ret < 0) { | 213 if (ret < 0) { |
222 Release(); | 214 Release(); |
223 return ret; | 215 return ret; |
224 } | 216 } |
225 EncodedImageCallback* callback = new AdapterEncodedImageCallback(this, i); | 217 EncodedImageCallback* callback = new AdapterEncodedImageCallback(this, i); |
226 encoder->RegisterEncodeCompleteCallback(callback); | 218 encoder->RegisterEncodeCompleteCallback(callback); |
227 streaminfos_.push_back(StreamInfo(encoder, callback, stream_codec.width, | 219 streaminfos_.push_back(StreamInfo(encoder, callback, stream_codec.width, |
228 stream_codec.height, send_stream)); | 220 stream_codec.height, |
| 221 start_bitrate_kbps > 0)); |
229 if (i != 0) | 222 if (i != 0) |
230 implementation_name += ", "; | 223 implementation_name += ", "; |
231 implementation_name += streaminfos_[i].encoder->ImplementationName(); | 224 implementation_name += streaminfos_[i].encoder->ImplementationName(); |
232 } | 225 } |
233 if (doing_simulcast) { | 226 if (doing_simulcast) { |
234 implementation_name_ = | 227 implementation_name_ = |
235 "SimulcastEncoderAdapter (" + implementation_name + ")"; | 228 "SimulcastEncoderAdapter (" + implementation_name + ")"; |
236 } else { | 229 } else { |
237 implementation_name_ = implementation_name; | 230 implementation_name_ = implementation_name; |
238 } | 231 } |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
356 uint32_t new_framerate) { | 349 uint32_t new_framerate) { |
357 if (!Initialized()) { | 350 if (!Initialized()) { |
358 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 351 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
359 } | 352 } |
360 if (new_framerate < 1) { | 353 if (new_framerate < 1) { |
361 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | 354 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; |
362 } | 355 } |
363 if (codec_.maxBitrate > 0 && new_bitrate_kbit > codec_.maxBitrate) { | 356 if (codec_.maxBitrate > 0 && new_bitrate_kbit > codec_.maxBitrate) { |
364 new_bitrate_kbit = codec_.maxBitrate; | 357 new_bitrate_kbit = codec_.maxBitrate; |
365 } | 358 } |
| 359 |
| 360 std::vector<uint32_t> stream_bitrates; |
366 if (new_bitrate_kbit > 0) { | 361 if (new_bitrate_kbit > 0) { |
367 // Make sure the bitrate fits the configured min bitrates. 0 is a special | 362 // Make sure the bitrate fits the configured min bitrates. 0 is a special |
368 // value that means paused, though, so leave it alone. | 363 // value that means paused, though, so leave it alone. |
369 if (new_bitrate_kbit < codec_.minBitrate) { | 364 if (new_bitrate_kbit < codec_.minBitrate) { |
370 new_bitrate_kbit = codec_.minBitrate; | 365 new_bitrate_kbit = codec_.minBitrate; |
371 } | 366 } |
372 if (codec_.numberOfSimulcastStreams > 0 && | 367 if (codec_.numberOfSimulcastStreams > 0 && |
373 new_bitrate_kbit < codec_.simulcastStream[0].minBitrate) { | 368 new_bitrate_kbit < codec_.simulcastStream[0].minBitrate) { |
374 new_bitrate_kbit = codec_.simulcastStream[0].minBitrate; | 369 new_bitrate_kbit = codec_.simulcastStream[0].minBitrate; |
375 } | 370 } |
| 371 stream_bitrates = rate_allocator_->GetAllocation(new_bitrate_kbit); |
376 } | 372 } |
377 codec_.maxFramerate = new_framerate; | 373 codec_.maxFramerate = new_framerate; |
378 | 374 |
379 bool send_stream = true; | 375 // Disable any stream not in the current allocation. |
380 uint32_t stream_bitrate = 0; | 376 stream_bitrates.resize(streaminfos_.size(), 0U); |
| 377 |
381 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) { | 378 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) { |
382 stream_bitrate = GetStreamBitrate(stream_idx, streaminfos_.size(), | 379 uint32_t stream_bitrate_kbps = stream_bitrates[stream_idx]; |
383 new_bitrate_kbit, &send_stream); | |
384 // Need a key frame if we have not sent this stream before. | 380 // Need a key frame if we have not sent this stream before. |
385 if (send_stream && !streaminfos_[stream_idx].send_stream) { | 381 if (stream_bitrate_kbps > 0 && !streaminfos_[stream_idx].send_stream) { |
386 streaminfos_[stream_idx].key_frame_request = true; | 382 streaminfos_[stream_idx].key_frame_request = true; |
387 } | 383 } |
388 streaminfos_[stream_idx].send_stream = send_stream; | 384 streaminfos_[stream_idx].send_stream = stream_bitrate_kbps > 0; |
389 | 385 |
390 // TODO(holmer): This is a temporary hack for screensharing, where we | 386 // TODO(holmer): This is a temporary hack for screensharing, where we |
391 // interpret the startBitrate as the encoder target bitrate. This is | 387 // interpret the startBitrate as the encoder target bitrate. This is |
392 // to allow for a different max bitrate, so if the codec can't meet | 388 // to allow for a different max bitrate, so if the codec can't meet |
393 // the target we still allow it to overshoot up to the max before dropping | 389 // the target we still allow it to overshoot up to the max before dropping |
394 // frames. This hack should be improved. | 390 // frames. This hack should be improved. |
395 if (codec_.targetBitrate > 0 && | 391 if (codec_.targetBitrate > 0 && |
396 (codec_.codecSpecific.VP8.numberOfTemporalLayers == 2 || | 392 (codec_.codecSpecific.VP8.numberOfTemporalLayers == 2 || |
397 codec_.simulcastStream[0].numberOfTemporalLayers == 2)) { | 393 codec_.simulcastStream[0].numberOfTemporalLayers == 2)) { |
398 stream_bitrate = std::min(codec_.maxBitrate, stream_bitrate); | 394 stream_bitrate_kbps = std::min(codec_.maxBitrate, stream_bitrate_kbps); |
399 // TODO(ronghuawu): Can't change max bitrate via the VideoEncoder | 395 // TODO(ronghuawu): Can't change max bitrate via the VideoEncoder |
400 // interface. And VP8EncoderImpl doesn't take negative framerate. | 396 // interface. And VP8EncoderImpl doesn't take negative framerate. |
401 // max_bitrate = std::min(codec_.maxBitrate, stream_bitrate); | 397 // max_bitrate = std::min(codec_.maxBitrate, stream_bitrate_kbps); |
402 // new_framerate = -1; | 398 // new_framerate = -1; |
403 } | 399 } |
404 | 400 |
405 streaminfos_[stream_idx].encoder->SetRates(stream_bitrate, new_framerate); | 401 streaminfos_[stream_idx].encoder->SetRates(stream_bitrate_kbps, |
| 402 new_framerate); |
406 } | 403 } |
407 | 404 |
408 return WEBRTC_VIDEO_CODEC_OK; | 405 return WEBRTC_VIDEO_CODEC_OK; |
409 } | 406 } |
410 | 407 |
411 EncodedImageCallback::Result SimulcastEncoderAdapter::OnEncodedImage( | 408 EncodedImageCallback::Result SimulcastEncoderAdapter::OnEncodedImage( |
412 size_t stream_idx, | 409 size_t stream_idx, |
413 const EncodedImage& encodedImage, | 410 const EncodedImage& encodedImage, |
414 const CodecSpecificInfo* codecSpecificInfo, | 411 const CodecSpecificInfo* codecSpecificInfo, |
415 const RTPFragmentationHeader* fragmentation) { | 412 const RTPFragmentationHeader* fragmentation) { |
416 CodecSpecificInfo stream_codec_specific = *codecSpecificInfo; | 413 CodecSpecificInfo stream_codec_specific = *codecSpecificInfo; |
417 stream_codec_specific.codec_name = implementation_name_.c_str(); | 414 stream_codec_specific.codec_name = implementation_name_.c_str(); |
418 CodecSpecificInfoVP8* vp8Info = &(stream_codec_specific.codecSpecific.VP8); | 415 CodecSpecificInfoVP8* vp8Info = &(stream_codec_specific.codecSpecific.VP8); |
419 vp8Info->simulcastIdx = stream_idx; | 416 vp8Info->simulcastIdx = stream_idx; |
420 | 417 |
421 return encoded_complete_callback_->OnEncodedImage( | 418 return encoded_complete_callback_->OnEncodedImage( |
422 encodedImage, &stream_codec_specific, fragmentation); | 419 encodedImage, &stream_codec_specific, fragmentation); |
423 } | 420 } |
424 | 421 |
425 uint32_t SimulcastEncoderAdapter::GetStreamBitrate( | |
426 int stream_idx, | |
427 size_t total_number_of_streams, | |
428 uint32_t new_bitrate_kbit, | |
429 bool* send_stream) const { | |
430 if (total_number_of_streams == 1) { | |
431 *send_stream = true; | |
432 return new_bitrate_kbit; | |
433 } | |
434 | |
435 // The bitrate needed to start sending this stream is given by the | |
436 // minimum bitrate allowed for encoding this stream, plus the sum target | |
437 // rates of all lower streams. | |
438 uint32_t sum_target_lower_streams = | |
439 SumStreamTargetBitrate(stream_idx, codec_); | |
440 uint32_t bitrate_to_send_this_layer = | |
441 codec_.simulcastStream[stream_idx].minBitrate + sum_target_lower_streams; | |
442 if (new_bitrate_kbit >= bitrate_to_send_this_layer) { | |
443 // We have enough bandwidth to send this stream. | |
444 *send_stream = true; | |
445 // Bitrate for this stream is the new bitrate (|new_bitrate_kbit|) minus the | |
446 // sum target rates of the lower streams, and capped to a maximum bitrate. | |
447 // The maximum cap depends on whether we send the next higher stream. | |
448 // If we will be sending the next higher stream, |max_rate| is given by | |
449 // current stream's |targetBitrate|, otherwise it's capped by |maxBitrate|. | |
450 if (stream_idx < codec_.numberOfSimulcastStreams - 1) { | |
451 unsigned int max_rate = codec_.simulcastStream[stream_idx].maxBitrate; | |
452 if (new_bitrate_kbit >= | |
453 SumStreamTargetBitrate(stream_idx + 1, codec_) + | |
454 codec_.simulcastStream[stream_idx + 1].minBitrate) { | |
455 max_rate = codec_.simulcastStream[stream_idx].targetBitrate; | |
456 } | |
457 return std::min(new_bitrate_kbit - sum_target_lower_streams, max_rate); | |
458 } else { | |
459 // For the highest stream (highest resolution), the |targetBitRate| and | |
460 // |maxBitrate| are not used. Any excess bitrate (above the targets of | |
461 // all lower streams) is given to this (highest resolution) stream. | |
462 return new_bitrate_kbit - sum_target_lower_streams; | |
463 } | |
464 } else { | |
465 // Not enough bitrate for this stream. | |
466 // Return our max bitrate of |stream_idx| - 1, but we don't send it. We need | |
467 // to keep this resolution coding in order for the multi-encoder to work. | |
468 *send_stream = false; | |
469 return codec_.simulcastStream[stream_idx - 1].maxBitrate; | |
470 } | |
471 } | |
472 | |
473 void SimulcastEncoderAdapter::PopulateStreamCodec( | 422 void SimulcastEncoderAdapter::PopulateStreamCodec( |
474 const webrtc::VideoCodec* inst, | 423 const webrtc::VideoCodec* inst, |
475 int stream_index, | 424 int stream_index, |
476 size_t total_number_of_streams, | 425 uint32_t start_bitrate_kbps, |
477 bool highest_resolution_stream, | 426 bool highest_resolution_stream, |
478 webrtc::VideoCodec* stream_codec, | 427 webrtc::VideoCodec* stream_codec) { |
479 bool* send_stream) { | |
480 *stream_codec = *inst; | 428 *stream_codec = *inst; |
481 | 429 |
482 // Stream specific settings. | 430 // Stream specific settings. |
483 stream_codec->codecSpecific.VP8.numberOfTemporalLayers = | 431 stream_codec->codecSpecific.VP8.numberOfTemporalLayers = |
484 inst->simulcastStream[stream_index].numberOfTemporalLayers; | 432 inst->simulcastStream[stream_index].numberOfTemporalLayers; |
485 stream_codec->numberOfSimulcastStreams = 0; | 433 stream_codec->numberOfSimulcastStreams = 0; |
486 stream_codec->width = inst->simulcastStream[stream_index].width; | 434 stream_codec->width = inst->simulcastStream[stream_index].width; |
487 stream_codec->height = inst->simulcastStream[stream_index].height; | 435 stream_codec->height = inst->simulcastStream[stream_index].height; |
488 stream_codec->maxBitrate = inst->simulcastStream[stream_index].maxBitrate; | 436 stream_codec->maxBitrate = inst->simulcastStream[stream_index].maxBitrate; |
489 stream_codec->minBitrate = inst->simulcastStream[stream_index].minBitrate; | 437 stream_codec->minBitrate = inst->simulcastStream[stream_index].minBitrate; |
490 stream_codec->qpMax = inst->simulcastStream[stream_index].qpMax; | 438 stream_codec->qpMax = inst->simulcastStream[stream_index].qpMax; |
491 // Settings that are based on stream/resolution. | 439 // Settings that are based on stream/resolution. |
492 if (stream_index == 0) { | 440 if (stream_index == 0) { |
493 // Settings for lowest spatial resolutions. | 441 // Settings for lowest spatial resolutions. |
494 stream_codec->qpMax = kLowestResMaxQp; | 442 stream_codec->qpMax = kLowestResMaxQp; |
495 } | 443 } |
496 if (!highest_resolution_stream) { | 444 if (!highest_resolution_stream) { |
497 // For resolutions below CIF, set the codec |complexity| parameter to | 445 // For resolutions below CIF, set the codec |complexity| parameter to |
498 // kComplexityHigher, which maps to cpu_used = -4. | 446 // kComplexityHigher, which maps to cpu_used = -4. |
499 int pixels_per_frame = stream_codec->width * stream_codec->height; | 447 int pixels_per_frame = stream_codec->width * stream_codec->height; |
500 if (pixels_per_frame < 352 * 288) { | 448 if (pixels_per_frame < 352 * 288) { |
501 stream_codec->codecSpecific.VP8.complexity = webrtc::kComplexityHigher; | 449 stream_codec->codecSpecific.VP8.complexity = webrtc::kComplexityHigher; |
502 } | 450 } |
503 // Turn off denoising for all streams but the highest resolution. | 451 // Turn off denoising for all streams but the highest resolution. |
504 stream_codec->codecSpecific.VP8.denoisingOn = false; | 452 stream_codec->codecSpecific.VP8.denoisingOn = false; |
505 } | 453 } |
506 // TODO(ronghuawu): what to do with targetBitrate. | 454 // TODO(ronghuawu): what to do with targetBitrate. |
507 | 455 |
508 int stream_bitrate = GetStreamBitrate(stream_index, total_number_of_streams, | 456 stream_codec->startBitrate = start_bitrate_kbps; |
509 inst->startBitrate, send_stream); | |
510 stream_codec->startBitrate = stream_bitrate; | |
511 } | 457 } |
512 | 458 |
513 bool SimulcastEncoderAdapter::Initialized() const { | 459 bool SimulcastEncoderAdapter::Initialized() const { |
514 return !streaminfos_.empty(); | 460 return !streaminfos_.empty(); |
515 } | 461 } |
516 | 462 |
517 void SimulcastEncoderAdapter::OnDroppedFrame() { | 463 void SimulcastEncoderAdapter::OnDroppedFrame() { |
518 streaminfos_[0].encoder->OnDroppedFrame(); | 464 streaminfos_[0].encoder->OnDroppedFrame(); |
519 } | 465 } |
520 | 466 |
521 bool SimulcastEncoderAdapter::SupportsNativeHandle() const { | 467 bool SimulcastEncoderAdapter::SupportsNativeHandle() const { |
522 // We should not be calling this method before streaminfos_ are configured. | 468 // We should not be calling this method before streaminfos_ are configured. |
523 RTC_DCHECK(!streaminfos_.empty()); | 469 RTC_DCHECK(!streaminfos_.empty()); |
524 for (const auto& streaminfo : streaminfos_) { | 470 for (const auto& streaminfo : streaminfos_) { |
525 if (!streaminfo.encoder->SupportsNativeHandle()) | 471 if (!streaminfo.encoder->SupportsNativeHandle()) |
526 return false; | 472 return false; |
527 } | 473 } |
528 return true; | 474 return true; |
529 } | 475 } |
530 | 476 |
531 const char* SimulcastEncoderAdapter::ImplementationName() const { | 477 const char* SimulcastEncoderAdapter::ImplementationName() const { |
532 return implementation_name_.c_str(); | 478 return implementation_name_.c_str(); |
533 } | 479 } |
534 | 480 |
535 } // namespace webrtc | 481 } // namespace webrtc |
OLD | NEW |