| 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 |