| 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 2e510ec897fbb9f8c2c8e1b6b801107b475987a2..82f964dec22440b618491b066ba49b35e924b73f 100644
|
| --- a/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc
|
| +++ b/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc
|
| @@ -113,7 +113,6 @@ VP8Decoder* VP8Decoder::Create() {
|
|
|
| VP8EncoderImpl::VP8EncoderImpl()
|
| : encoded_complete_callback_(nullptr),
|
| - rate_allocator_(new SimulcastRateAllocator(codec_)),
|
| inited_(false),
|
| timestamp_(0),
|
| feedback_mode_(false),
|
| @@ -175,27 +174,32 @@ 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 (bitrate.get_sum_bps() == 0) {
|
| + // Encoder paused, turn off all encoding.
|
| + const int num_streams = static_cast<size_t>(encoders_.size());
|
| + for (int i = 0; i < num_streams; ++i)
|
| + SetStreamState(false, i);
|
| + return WEBRTC_VIDEO_CODEC_OK;
|
| }
|
| - 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;
|
| - }
|
| - if (codec_.numberOfSimulcastStreams > 0 &&
|
| - new_bitrate_kbit < codec_.simulcastStream[0].minBitrate) {
|
| - new_bitrate_kbit = codec_.simulcastStream[0].minBitrate;
|
| - }
|
| +
|
| + // At this point, bitrate allocation should already match codec settings.
|
| + if (codec_.maxBitrate > 0)
|
| + RTC_DCHECK_LE(bitrate.get_sum_kbps(), codec_.maxBitrate);
|
| + RTC_DCHECK_GE(bitrate.get_sum_kbps(), codec_.minBitrate);
|
| + if (codec_.numberOfSimulcastStreams > 0)
|
| + RTC_DCHECK_GE(bitrate.get_sum_kbps(), codec_.simulcastStream[0].minBitrate);
|
| +
|
| codec_.maxFramerate = new_framerate;
|
|
|
| if (encoders_.size() == 1) {
|
| @@ -207,14 +211,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;
|
| }
|
| }
|
| @@ -233,31 +237,18 @@ 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) {
|
| - 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]);
|
| + unsigned int target_bitrate_kbps =
|
| + bitrate.GetSpatialLayerSum(stream_idx) / 1000;
|
| +
|
| + bool send_stream = target_bitrate_kbps > 0;
|
| + if (send_stream || encoders_.size() > 1)
|
| + SetStreamState(send_stream, 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;
|
| }
|
| @@ -287,26 +278,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()));
|
| }
|
| }
|
| }
|
| @@ -351,10 +333,8 @@ 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;
|
| @@ -362,7 +342,6 @@ int VP8EncoderImpl::InitEncode(const VideoCodec* inst,
|
| number_of_cores_ = number_of_cores;
|
| 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.
|
| @@ -514,45 +493,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();
|
|
|