Chromium Code Reviews| Index: webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc |
| diff --git a/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc b/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc |
| index 715f8ff5758df847477e2a78e761081eafe33871..587e626867d80d97ac210aea9f3eb249ad4d6d1d 100644 |
| --- a/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc |
| +++ b/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc |
| @@ -112,7 +112,6 @@ VP8Decoder* VP8Decoder::Create() { |
| VP8EncoderImpl::VP8EncoderImpl() |
| : encoded_complete_callback_(nullptr), |
| - rate_allocator_(new SimulcastRateAllocator(codec_)), |
| inited_(false), |
| timestamp_(0), |
| feedback_mode_(false), |
| @@ -173,27 +172,29 @@ int VP8EncoderImpl::Release() { |
| return ret_val; |
| } |
| -int VP8EncoderImpl::SetRates(uint32_t new_bitrate_kbit, |
| - uint32_t new_framerate) { |
| - if (!inited_) { |
| +int VP8EncoderImpl::SetRateAllocation(const BitrateAllocation& bitrate, |
| + uint32_t new_framerate) { |
| + if (!inited_) |
| return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
| - } |
| - if (encoders_[0].err) { |
| + |
| + if (encoders_[0].err) |
| return WEBRTC_VIDEO_CODEC_ERROR; |
| - } |
| - if (new_framerate < 1) { |
| + |
| + if (new_framerate < 1) |
| return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; |
| - } |
| - if (codec_.maxBitrate > 0 && new_bitrate_kbit > codec_.maxBitrate) { |
| - new_bitrate_kbit = codec_.maxBitrate; |
| - } |
| - if (new_bitrate_kbit < codec_.minBitrate) { |
| - new_bitrate_kbit = codec_.minBitrate; |
| - } |
| + |
| + // At this point, bitrate allocation should already match codec settings. |
| + if (codec_.maxBitrate > 0 && bitrate.get_sum_kbps() > codec_.maxBitrate) |
|
stefan-webrtc
2016/11/02 10:26:35
Should we DCHECK instead if it should match at thi
sprang_webrtc
2016/11/02 13:28:33
Yes, that is probably a good idea.
|
| + return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; |
| + |
| + if (bitrate.get_sum_kbps() < codec_.minBitrate) |
| + return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; |
| + |
| if (codec_.numberOfSimulcastStreams > 0 && |
| - new_bitrate_kbit < codec_.simulcastStream[0].minBitrate) { |
| - new_bitrate_kbit = codec_.simulcastStream[0].minBitrate; |
| + bitrate.get_sum_kbps() < codec_.simulcastStream[0].minBitrate) { |
| + return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; |
| } |
| + |
| codec_.maxFramerate = new_framerate; |
| if (encoders_.size() == 1) { |
| @@ -205,14 +206,14 @@ int VP8EncoderImpl::SetRates(uint32_t new_bitrate_kbit, |
| // Only trigger keyframes if we are allowed to scale down. |
| if (configurations_[0].rc_resize_allowed) { |
| if (!down_scale_requested_) { |
| - if (k_pixels_per_frame > new_bitrate_kbit) { |
| + if (k_pixels_per_frame > bitrate.get_sum_kbps()) { |
| down_scale_requested_ = true; |
| - down_scale_bitrate_ = new_bitrate_kbit; |
| + down_scale_bitrate_ = bitrate.get_sum_kbps(); |
| key_frame_request_[0] = true; |
| } |
| } else { |
| - if (new_bitrate_kbit > (2 * down_scale_bitrate_) || |
| - new_bitrate_kbit < (down_scale_bitrate_ / 2)) { |
| + if (bitrate.get_sum_kbps() > (2 * down_scale_bitrate_) || |
| + bitrate.get_sum_kbps() < (down_scale_bitrate_ / 2)) { |
| down_scale_requested_ = false; |
| } |
| } |
| @@ -231,31 +232,17 @@ int VP8EncoderImpl::SetRates(uint32_t new_bitrate_kbit, |
| } |
| } |
| - std::vector<uint32_t> stream_bitrates = |
| - rate_allocator_->GetAllocation(new_bitrate_kbit); |
| size_t stream_idx = encoders_.size() - 1; |
| for (size_t i = 0; i < encoders_.size(); ++i, --stream_idx) { |
| + unsigned int target_bitrate_kbps = |
| + bitrate.GetSpatialLayerSum(stream_idx) / 1000; |
| + |
| if (encoders_.size() > 1) |
| - SetStreamState(stream_bitrates[stream_idx] > 0, stream_idx); |
| - |
| - unsigned int target_bitrate = stream_bitrates[stream_idx]; |
| - unsigned int max_bitrate = codec_.maxBitrate; |
| - int framerate = new_framerate; |
| - // TODO(holmer): This is a temporary hack for screensharing, where we |
| - // interpret the startBitrate as the encoder target bitrate. This is |
| - // to allow for a different max bitrate, so if the codec can't meet |
| - // the target we still allow it to overshoot up to the max before dropping |
| - // frames. This hack should be improved. |
| - if (codec_.targetBitrate > 0 && |
| - (codec_.VP8()->numberOfTemporalLayers == 2 || |
| - codec_.simulcastStream[0].numberOfTemporalLayers == 2)) { |
| - int tl0_bitrate = std::min(codec_.targetBitrate, target_bitrate); |
| - max_bitrate = std::min(codec_.maxBitrate, target_bitrate); |
| - target_bitrate = tl0_bitrate; |
| - } |
| - configurations_[i].rc_target_bitrate = target_bitrate; |
| - temporal_layers_[stream_idx]->ConfigureBitrates( |
| - target_bitrate, max_bitrate, framerate, &configurations_[i]); |
| + SetStreamState(target_bitrate_kbps > 0, stream_idx); |
| + |
| + configurations_[i].rc_target_bitrate = target_bitrate_kbps; |
| + temporal_layers_[stream_idx]->UpdateConfiguration(&configurations_[i]); |
| + |
| if (vpx_codec_enc_config_set(&encoders_[i], &configurations_[i])) { |
| return WEBRTC_VIDEO_CODEC_ERROR; |
| } |
| @@ -285,26 +272,17 @@ void VP8EncoderImpl::SetStreamState(bool send_stream, |
| void VP8EncoderImpl::SetupTemporalLayers(int num_streams, |
| int num_temporal_layers, |
| const VideoCodec& codec) { |
| - TemporalLayersFactory default_factory; |
| - const TemporalLayersFactory* tl_factory = codec.VP8().tl_factory; |
| - if (!tl_factory) |
| - tl_factory = &default_factory; |
| + RTC_DCHECK(codec.codecSpecific.VP8.tl_factory != nullptr); |
| + const TemporalLayersFactory* tl_factory = codec.codecSpecific.VP8.tl_factory; |
| if (num_streams == 1) { |
| - if (codec.mode == kScreensharing) { |
| - // Special mode when screensharing on a single stream. |
| - temporal_layers_.push_back(new ScreenshareLayers( |
| - num_temporal_layers, rand(), webrtc::Clock::GetRealTimeClock())); |
| - } else { |
| - temporal_layers_.push_back( |
| - tl_factory->Create(num_temporal_layers, rand())); |
| - } |
| + temporal_layers_.push_back( |
| + tl_factory->Create(0, num_temporal_layers, rand())); |
| } else { |
| for (int i = 0; i < num_streams; ++i) { |
| - // TODO(andresp): crash if layers is invalid. |
| - int layers = codec.simulcastStream[i].numberOfTemporalLayers; |
| - if (layers < 1) |
| - layers = 1; |
| - temporal_layers_.push_back(tl_factory->Create(layers, rand())); |
| + RTC_CHECK_GT(num_temporal_layers, 0); |
| + int layers = std::max(static_cast<uint8_t>(1), |
| + codec.simulcastStream[i].numberOfTemporalLayers); |
| + temporal_layers_.push_back(tl_factory->Create(i, layers, rand())); |
| } |
| } |
| } |
| @@ -349,17 +327,13 @@ int VP8EncoderImpl::InitEncode(const VideoCodec* inst, |
| int num_temporal_layers = |
| doing_simulcast ? inst->simulcastStream[0].numberOfTemporalLayers |
| : inst->VP8().numberOfTemporalLayers; |
| + RTC_DCHECK_GT(num_temporal_layers, 0); |
| - // TODO(andresp): crash if num temporal layers is bananas. |
| - if (num_temporal_layers < 1) |
| - num_temporal_layers = 1; |
| SetupTemporalLayers(number_of_streams, num_temporal_layers, *inst); |
| feedback_mode_ = inst->VP8().feedbackModeOn; |
| - |
| timestamp_ = 0; |
| codec_ = *inst; |
| - rate_allocator_.reset(new SimulcastRateAllocator(codec_)); |
| // Code expects simulcastStream resolutions to be correct, make sure they are |
| // filled even when there are no simulcast layers. |
| @@ -511,45 +485,44 @@ int VP8EncoderImpl::InitEncode(const VideoCodec* inst, |
| vpx_img_wrap(&raw_images_[0], VPX_IMG_FMT_I420, inst->width, inst->height, 1, |
| NULL); |
| - if (encoders_.size() == 1) { |
| - configurations_[0].rc_target_bitrate = inst->startBitrate; |
| - temporal_layers_[0]->ConfigureBitrates(inst->startBitrate, inst->maxBitrate, |
| - inst->maxFramerate, |
| - &configurations_[0]); |
| - } else { |
| - // Note the order we use is different from webm, we have lowest resolution |
| - // at position 0 and they have highest resolution at position 0. |
| - int stream_idx = encoders_.size() - 1; |
| - std::vector<uint32_t> stream_bitrates = |
| - rate_allocator_->GetAllocation(inst->startBitrate); |
| + // Note the order we use is different from webm, we have lowest resolution |
| + // at position 0 and they have highest resolution at position 0. |
| + int stream_idx = encoders_.size() - 1; |
| + SimulcastRateAllocator init_allocator(codec_, nullptr); |
| + BitrateAllocation allocation = init_allocator.GetAllocation( |
| + inst->startBitrate * 1000, inst->maxFramerate); |
| + std::vector<uint32_t> stream_bitrates; |
| + for (int i = 0; i == 0 || i < inst->numberOfSimulcastStreams; ++i) { |
| + uint32_t bitrate = allocation.GetSpatialLayerSum(i) / 1000; |
| + stream_bitrates.push_back(bitrate); |
| + } |
| + |
| + configurations_[0].rc_target_bitrate = stream_bitrates[stream_idx]; |
| + temporal_layers_[stream_idx]->OnRatesUpdated( |
| + stream_bitrates[stream_idx], inst->maxBitrate, inst->maxFramerate); |
| + temporal_layers_[stream_idx]->UpdateConfiguration(&configurations_[0]); |
| + --stream_idx; |
| + for (size_t i = 1; i < encoders_.size(); ++i, --stream_idx) { |
| + memcpy(&configurations_[i], &configurations_[0], |
| + sizeof(configurations_[0])); |
| + |
| + configurations_[i].g_w = inst->simulcastStream[stream_idx].width; |
| + configurations_[i].g_h = inst->simulcastStream[stream_idx].height; |
| + |
| + // Use 1 thread for lower resolutions. |
| + configurations_[i].g_threads = 1; |
| + |
| + // Setting alignment to 32 - as that ensures at least 16 for all |
| + // planes (32 for Y, 16 for U,V). Libvpx sets the requested stride for |
| + // the y plane, but only half of it to the u and v planes. |
| + vpx_img_alloc(&raw_images_[i], VPX_IMG_FMT_I420, |
| + inst->simulcastStream[stream_idx].width, |
| + inst->simulcastStream[stream_idx].height, kVp832ByteAlign); |
| SetStreamState(stream_bitrates[stream_idx] > 0, stream_idx); |
| - configurations_[0].rc_target_bitrate = stream_bitrates[stream_idx]; |
| - temporal_layers_[stream_idx]->ConfigureBitrates( |
| - stream_bitrates[stream_idx], inst->maxBitrate, inst->maxFramerate, |
| - &configurations_[0]); |
| - --stream_idx; |
| - for (size_t i = 1; i < encoders_.size(); ++i, --stream_idx) { |
| - memcpy(&configurations_[i], &configurations_[0], |
| - sizeof(configurations_[0])); |
| - |
| - configurations_[i].g_w = inst->simulcastStream[stream_idx].width; |
| - configurations_[i].g_h = inst->simulcastStream[stream_idx].height; |
| - |
| - // Use 1 thread for lower resolutions. |
| - configurations_[i].g_threads = 1; |
| - |
| - // Setting alignment to 32 - as that ensures at least 16 for all |
| - // planes (32 for Y, 16 for U,V). Libvpx sets the requested stride for |
| - // the y plane, but only half of it to the u and v planes. |
| - vpx_img_alloc(&raw_images_[i], VPX_IMG_FMT_I420, |
| - inst->simulcastStream[stream_idx].width, |
| - inst->simulcastStream[stream_idx].height, kVp832ByteAlign); |
| - SetStreamState(stream_bitrates[stream_idx] > 0, stream_idx); |
| - configurations_[i].rc_target_bitrate = stream_bitrates[stream_idx]; |
| - temporal_layers_[stream_idx]->ConfigureBitrates( |
| - stream_bitrates[stream_idx], inst->maxBitrate, inst->maxFramerate, |
| - &configurations_[i]); |
| - } |
| + configurations_[i].rc_target_bitrate = stream_bitrates[stream_idx]; |
| + temporal_layers_[stream_idx]->OnRatesUpdated( |
| + stream_bitrates[stream_idx], inst->maxBitrate, inst->maxFramerate); |
| + temporal_layers_[stream_idx]->UpdateConfiguration(&configurations_[i]); |
| } |
| rps_.Init(); |