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 41257133c55a8aa898ccce316809f9082ba24822..63503d824c25868e54afb38063320d9f064a10a8 100644 |
--- a/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc |
+++ b/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc |
@@ -28,6 +28,7 @@ |
#include "webrtc/modules/video_coding/codecs/vp8/include/vp8_common_types.h" |
#include "webrtc/modules/video_coding/codecs/vp8/screenshare_layers.h" |
#include "webrtc/modules/video_coding/codecs/vp8/temporal_layers.h" |
+#include "webrtc/modules/video_coding/utility/simulcast_state.h" |
#include "webrtc/system_wrappers/include/clock.h" |
#include "webrtc/system_wrappers/include/tick_util.h" |
@@ -59,64 +60,6 @@ int GCD(int a, int b) { |
return b; |
} |
-std::vector<int> GetStreamBitratesKbps(const VideoCodec& codec, |
- int bitrate_to_allocate_kbps) { |
- if (codec.numberOfSimulcastStreams <= 1) { |
- return std::vector<int>(1, bitrate_to_allocate_kbps); |
- } |
- |
- std::vector<int> bitrates_kbps(codec.numberOfSimulcastStreams); |
- // Allocate min -> target bitrates as long as we have bitrate to spend. |
- size_t last_active_stream = 0; |
- for (size_t i = 0; i < static_cast<size_t>(codec.numberOfSimulcastStreams) && |
- bitrate_to_allocate_kbps >= |
- static_cast<int>(codec.simulcastStream[i].minBitrate); |
- ++i) { |
- last_active_stream = i; |
- int allocated_bitrate_kbps = |
- std::min(static_cast<int>(codec.simulcastStream[i].targetBitrate), |
- bitrate_to_allocate_kbps); |
- bitrates_kbps[i] = allocated_bitrate_kbps; |
- bitrate_to_allocate_kbps -= allocated_bitrate_kbps; |
- } |
- |
- // Spend additional bits on the highest-quality active layer, up to max |
- // bitrate. |
- // TODO(pbos): Consider spending additional bits on last_active_stream-1 down |
- // to 0 and not just the top layer when we have additional bitrate to spend. |
- int allocated_bitrate_kbps = std::min( |
- static_cast<int>(codec.simulcastStream[last_active_stream].maxBitrate - |
- bitrates_kbps[last_active_stream]), |
- bitrate_to_allocate_kbps); |
- bitrates_kbps[last_active_stream] += allocated_bitrate_kbps; |
- bitrate_to_allocate_kbps -= allocated_bitrate_kbps; |
- |
- // Make sure we can always send something. Suspending below min bitrate is |
- // controlled outside the codec implementation and is not overriden by this. |
- if (bitrates_kbps[0] < static_cast<int>(codec.simulcastStream[0].minBitrate)) |
- bitrates_kbps[0] = static_cast<int>(codec.simulcastStream[0].minBitrate); |
- |
- return bitrates_kbps; |
-} |
- |
-uint32_t SumStreamMaxBitrate(int streams, const VideoCodec& codec) { |
- uint32_t bitrate_sum = 0; |
- for (int i = 0; i < streams; ++i) { |
- bitrate_sum += codec.simulcastStream[i].maxBitrate; |
- } |
- return bitrate_sum; |
-} |
- |
-int NumberOfStreams(const VideoCodec& codec) { |
- int streams = |
- codec.numberOfSimulcastStreams < 1 ? 1 : codec.numberOfSimulcastStreams; |
- uint32_t simulcast_max_bitrate = SumStreamMaxBitrate(streams, codec); |
- if (simulcast_max_bitrate == 0) { |
- streams = 1; |
- } |
- return streams; |
-} |
- |
bool ValidSimulcastResolutions(const VideoCodec& codec, int num_streams) { |
if (codec.width != codec.simulcastStream[num_streams - 1].width || |
codec.height != codec.simulcastStream[num_streams - 1].height) { |
@@ -131,14 +74,6 @@ bool ValidSimulcastResolutions(const VideoCodec& codec, int num_streams) { |
return true; |
} |
-int NumStreamsDisabled(const std::vector<bool>& streams) { |
- int num_disabled = 0; |
- for (bool stream : streams) { |
- if (!stream) |
- ++num_disabled; |
- } |
- return num_disabled; |
-} |
} // namespace |
VP8Encoder* VP8Encoder::Create() { |
@@ -149,8 +84,6 @@ VP8Decoder* VP8Decoder::Create() { |
return new VP8DecoderImpl(); |
} |
-const float kTl1MaxTimeToDropFrames = 20.0f; |
- |
VP8EncoderImpl::VP8EncoderImpl() |
: encoded_complete_callback_(NULL), |
inited_(false), |
@@ -162,9 +95,6 @@ VP8EncoderImpl::VP8EncoderImpl() |
token_partitions_(VP8_ONE_TOKENPARTITION), |
down_scale_requested_(false), |
down_scale_bitrate_(0), |
- tl0_frame_dropper_(), |
- tl1_frame_dropper_(kTl1MaxTimeToDropFrames), |
- key_frame_request_(kMaxSimulcastStreams, false), |
quality_scaler_enabled_(false) { |
uint32_t seed = static_cast<uint32_t>(TickTime::MillisecondTimestamp()); |
srand(seed); |
@@ -174,7 +104,6 @@ VP8EncoderImpl::VP8EncoderImpl() |
temporal_layers_.reserve(kMaxSimulcastStreams); |
raw_images_.reserve(kMaxSimulcastStreams); |
encoded_images_.reserve(kMaxSimulcastStreams); |
- send_stream_.reserve(kMaxSimulcastStreams); |
cpu_speed_.assign(kMaxSimulcastStreams, -6); // Set default to -6. |
encoders_.reserve(kMaxSimulcastStreams); |
configurations_.reserve(kMaxSimulcastStreams); |
@@ -201,7 +130,7 @@ int VP8EncoderImpl::Release() { |
encoders_.pop_back(); |
} |
configurations_.clear(); |
- send_stream_.clear(); |
+ simulcast_state_.reset(); |
cpu_speed_.clear(); |
while (!raw_images_.empty()) { |
vpx_img_free(&raw_images_.back()); |
@@ -250,7 +179,7 @@ int VP8EncoderImpl::SetRates(uint32_t new_bitrate_kbit, |
if (k_pixels_per_frame > new_bitrate_kbit) { |
down_scale_requested_ = true; |
down_scale_bitrate_ = new_bitrate_kbit; |
- key_frame_request_[0] = true; |
+ simulcast_state_->RequestKeyFrame(0); |
} |
} else { |
if (new_bitrate_kbit > (2 * down_scale_bitrate_) || |
@@ -273,31 +202,26 @@ int VP8EncoderImpl::SetRates(uint32_t new_bitrate_kbit, |
} |
} |
- std::vector<int> stream_bitrates = |
- GetStreamBitratesKbps(codec_, 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]; |
+ simulcast_state_->AllocateBitrate(new_bitrate_kbit); |
+ for (const SimulcastState::Stream& stream : *simulcast_state_) { |
+ unsigned int target_bitrate = stream.allocated_rate_kbps; |
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 && |
+ if (codec_.targetBitrate > 0 && simulcast_state_->NumStreams() == 1 && |
(codec_.codecSpecific.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; |
} |
+ int i = simulcast_state_->NumStreams() - stream.idx - 1; |
configurations_[i].rc_target_bitrate = target_bitrate; |
- temporal_layers_[stream_idx]->ConfigureBitrates( |
- target_bitrate, max_bitrate, framerate, &configurations_[i]); |
+ temporal_layers_[stream.idx]->ConfigureBitrates( |
+ target_bitrate, max_bitrate, new_framerate, &configurations_[i]); |
if (vpx_codec_enc_config_set(&encoders_[i], &configurations_[i])) { |
return WEBRTC_VIDEO_CODEC_ERROR; |
} |
@@ -310,15 +234,6 @@ const char* VP8EncoderImpl::ImplementationName() const { |
return "libvpx"; |
} |
-void VP8EncoderImpl::SetStreamState(bool send_stream, |
- int stream_idx) { |
- if (send_stream && !send_stream_[stream_idx]) { |
- // Need a key frame if we have not sent this stream before. |
- key_frame_request_[stream_idx] = true; |
- } |
- send_stream_[stream_idx] = send_stream; |
-} |
- |
void VP8EncoderImpl::SetupTemporalLayers(int num_streams, |
int num_temporal_layers, |
const VideoCodec& codec) { |
@@ -378,7 +293,10 @@ int VP8EncoderImpl::InitEncode(const VideoCodec* inst, |
return retVal; |
} |
- int number_of_streams = NumberOfStreams(*inst); |
+ std::unique_ptr<SimulcastState> new_simulcast_state( |
+ new SimulcastState(*inst)); |
+ |
+ int number_of_streams = new_simulcast_state->NumStreams(); |
bool doing_simulcast = (number_of_streams > 1); |
if (doing_simulcast && !ValidSimulcastResolutions(*inst, number_of_streams)) { |
@@ -398,6 +316,7 @@ int VP8EncoderImpl::InitEncode(const VideoCodec* inst, |
timestamp_ = 0; |
codec_ = *inst; |
+ simulcast_state_ = std::move(new_simulcast_state); |
// Code expects simulcastStream resolutions to be correct, make sure they are |
// filled even when there are no simulcast layers. |
@@ -413,10 +332,7 @@ int VP8EncoderImpl::InitEncode(const VideoCodec* inst, |
configurations_.resize(number_of_streams); |
downsampling_factors_.resize(number_of_streams); |
raw_images_.resize(number_of_streams); |
- send_stream_.resize(number_of_streams); |
- send_stream_[0] = true; // For non-simulcast case. |
cpu_speed_.resize(number_of_streams); |
- std::fill(key_frame_request_.begin(), key_frame_request_.end(), false); |
int idx = number_of_streams - 1; |
for (int i = 0; i < (number_of_streams - 1); ++i, --idx) { |
@@ -424,10 +340,10 @@ int VP8EncoderImpl::InitEncode(const VideoCodec* inst, |
inst->simulcastStream[idx - 1].width); |
downsampling_factors_[i].num = inst->simulcastStream[idx].width / gcd; |
downsampling_factors_[i].den = inst->simulcastStream[idx - 1].width / gcd; |
- send_stream_[i] = false; |
+ simulcast_state_->SetSending(i, false); |
} |
if (number_of_streams > 1) { |
- send_stream_[number_of_streams - 1] = false; |
+ simulcast_state_->SetSending(number_of_streams - 1, false); |
downsampling_factors_[number_of_streams - 1].num = 1; |
downsampling_factors_[number_of_streams - 1].den = 1; |
} |
@@ -562,15 +478,14 @@ int VP8EncoderImpl::InitEncode(const VideoCodec* inst, |
inst->maxFramerate, |
&configurations_[0]); |
} else { |
+ simulcast_state_->AllocateBitrate(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; |
- std::vector<int> stream_bitrates = |
- GetStreamBitratesKbps(codec_, inst->startBitrate); |
- SetStreamState(stream_bitrates[stream_idx] > 0, stream_idx); |
- configurations_[0].rc_target_bitrate = stream_bitrates[stream_idx]; |
+ int stream_bitrate_kbps = simulcast_state_->AllocatedRate(stream_idx); |
+ configurations_[0].rc_target_bitrate = stream_bitrate_kbps; |
temporal_layers_[stream_idx]->ConfigureBitrates( |
- stream_bitrates[stream_idx], inst->maxBitrate, inst->maxFramerate, |
+ stream_bitrate_kbps, inst->maxBitrate, inst->maxFramerate, |
&configurations_[0]); |
--stream_idx; |
for (size_t i = 1; i < encoders_.size(); ++i, --stream_idx) { |
@@ -589,10 +504,10 @@ int VP8EncoderImpl::InitEncode(const VideoCodec* inst, |
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]; |
+ stream_bitrate_kbps = simulcast_state_->AllocatedRate(stream_idx); |
+ configurations_[i].rc_target_bitrate = stream_bitrate_kbps; |
temporal_layers_[stream_idx]->ConfigureBitrates( |
- stream_bitrates[stream_idx], inst->maxBitrate, inst->maxFramerate, |
+ stream_bitrate_kbps, inst->maxBitrate, inst->maxFramerate, |
&configurations_[i]); |
} |
} |
@@ -789,22 +704,13 @@ int VP8EncoderImpl::Encode(const VideoFrame& frame, |
flags[i] = ret; |
} |
bool send_key_frame = false; |
- for (size_t i = 0; i < key_frame_request_.size() && i < send_stream_.size(); |
- ++i) { |
- if (key_frame_request_[i] && send_stream_[i]) { |
- send_key_frame = true; |
- break; |
- } |
- } |
- if (!send_key_frame && frame_types) { |
- for (size_t i = 0; i < frame_types->size() && i < send_stream_.size(); |
- ++i) { |
- if ((*frame_types)[i] == kVideoFrameKey && send_stream_[i]) { |
- send_key_frame = true; |
- break; |
- } |
- } |
+ size_t num_entries = std::min(frame_types ? frame_types->size() : 0, |
+ simulcast_state_->NumStreams()); |
+ for (size_t i = 0; i < num_entries; ++i) { |
+ send_key_frame |= simulcast_state_->GetAndResetKeyFrameRequest(i) || |
+ (frame_types && (*frame_types)[i] == kVideoFrameKey); |
} |
+ |
// The flag modification below (due to forced key frame, RPS, etc.,) for now |
// will be the same for all encoders/spatial layers. |
// TODO(marpan/holmer): Allow for key frame request to be set per encoder. |
@@ -823,7 +729,6 @@ int VP8EncoderImpl::Encode(const VideoFrame& frame, |
for (size_t i = 0; i < encoders_.size(); ++i) { |
flags[i] = VPX_EFLAG_FORCE_KF; |
} |
- std::fill(key_frame_request_.begin(), key_frame_request_.end(), false); |
} else if (codec_specific_info && |
codec_specific_info->codecType == kVideoCodecVP8) { |
if (feedback_mode_) { |
@@ -964,7 +869,7 @@ void VP8EncoderImpl::PopulateCodecSpecific( |
int VP8EncoderImpl::GetEncodedPartitions(const VideoFrame& input_image, |
bool only_predicting_from_key_frame) { |
int bw_resolutions_disabled = |
- (encoders_.size() > 1) ? NumStreamsDisabled(send_stream_) : -1; |
+ (encoders_.size() > 1) ? simulcast_state_->NumSendingStreams() : -1; |
pbos-webrtc
2016/04/29 21:23:27
This is not NumStreamsDisabled? Why are tests not
|
int stream_idx = static_cast<int>(encoders_.size()) - 1; |
int result = WEBRTC_VIDEO_CODEC_OK; |
@@ -1030,7 +935,7 @@ int VP8EncoderImpl::GetEncodedPartitions(const VideoFrame& input_image, |
temporal_layers_[stream_idx]->FrameEncoded( |
encoded_images_[encoder_idx]._length, |
encoded_images_[encoder_idx]._timeStamp, qp); |
- if (send_stream_[stream_idx]) { |
+ if (simulcast_state_->IsSending(stream_idx)) { |
if (encoded_images_[encoder_idx]._length > 0) { |
TRACE_COUNTER_ID1("webrtc", "EncodedFrameSize", encoder_idx, |
encoded_images_[encoder_idx]._length); |
@@ -1055,7 +960,7 @@ int VP8EncoderImpl::GetEncodedPartitions(const VideoFrame& input_image, |
} |
} |
} |
- if (encoders_.size() == 1 && send_stream_[0]) { |
+ if (encoders_.size() == 1 && simulcast_state_->IsSending(0)) { |
if (encoded_images_[0]._length > 0) { |
int qp_128; |
vpx_codec_control(&encoders_[0], VP8E_GET_LAST_QUANTIZER, &qp_128); |