Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 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 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 21 | 21 |
| 22 #include "webrtc/base/checks.h" | 22 #include "webrtc/base/checks.h" |
| 23 #include "webrtc/base/trace_event.h" | 23 #include "webrtc/base/trace_event.h" |
| 24 #include "webrtc/common_types.h" | 24 #include "webrtc/common_types.h" |
| 25 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" | 25 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" |
| 26 #include "webrtc/modules/include/module_common_types.h" | 26 #include "webrtc/modules/include/module_common_types.h" |
| 27 #include "webrtc/modules/video_coding/include/video_codec_interface.h" | 27 #include "webrtc/modules/video_coding/include/video_codec_interface.h" |
| 28 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8_common_types.h" | 28 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8_common_types.h" |
| 29 #include "webrtc/modules/video_coding/codecs/vp8/screenshare_layers.h" | 29 #include "webrtc/modules/video_coding/codecs/vp8/screenshare_layers.h" |
| 30 #include "webrtc/modules/video_coding/codecs/vp8/temporal_layers.h" | 30 #include "webrtc/modules/video_coding/codecs/vp8/temporal_layers.h" |
| 31 #include "webrtc/modules/video_coding/utility/simulcast_state.h" | |
| 31 #include "webrtc/system_wrappers/include/clock.h" | 32 #include "webrtc/system_wrappers/include/clock.h" |
| 32 #include "webrtc/system_wrappers/include/tick_util.h" | 33 #include "webrtc/system_wrappers/include/tick_util.h" |
| 33 | 34 |
| 34 namespace webrtc { | 35 namespace webrtc { |
| 35 namespace { | 36 namespace { |
| 36 | 37 |
| 37 enum { kVp8ErrorPropagationTh = 30 }; | 38 enum { kVp8ErrorPropagationTh = 30 }; |
| 38 enum { kVp832ByteAlign = 32 }; | 39 enum { kVp832ByteAlign = 32 }; |
| 39 | 40 |
| 40 // VP8 denoiser states. | 41 // VP8 denoiser states. |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 52 int GCD(int a, int b) { | 53 int GCD(int a, int b) { |
| 53 int c = a % b; | 54 int c = a % b; |
| 54 while (c != 0) { | 55 while (c != 0) { |
| 55 a = b; | 56 a = b; |
| 56 b = c; | 57 b = c; |
| 57 c = a % b; | 58 c = a % b; |
| 58 } | 59 } |
| 59 return b; | 60 return b; |
| 60 } | 61 } |
| 61 | 62 |
| 62 std::vector<int> GetStreamBitratesKbps(const VideoCodec& codec, | |
| 63 int bitrate_to_allocate_kbps) { | |
| 64 if (codec.numberOfSimulcastStreams <= 1) { | |
| 65 return std::vector<int>(1, bitrate_to_allocate_kbps); | |
| 66 } | |
| 67 | |
| 68 std::vector<int> bitrates_kbps(codec.numberOfSimulcastStreams); | |
| 69 // Allocate min -> target bitrates as long as we have bitrate to spend. | |
| 70 size_t last_active_stream = 0; | |
| 71 for (size_t i = 0; i < static_cast<size_t>(codec.numberOfSimulcastStreams) && | |
| 72 bitrate_to_allocate_kbps >= | |
| 73 static_cast<int>(codec.simulcastStream[i].minBitrate); | |
| 74 ++i) { | |
| 75 last_active_stream = i; | |
| 76 int allocated_bitrate_kbps = | |
| 77 std::min(static_cast<int>(codec.simulcastStream[i].targetBitrate), | |
| 78 bitrate_to_allocate_kbps); | |
| 79 bitrates_kbps[i] = allocated_bitrate_kbps; | |
| 80 bitrate_to_allocate_kbps -= allocated_bitrate_kbps; | |
| 81 } | |
| 82 | |
| 83 // Spend additional bits on the highest-quality active layer, up to max | |
| 84 // bitrate. | |
| 85 // TODO(pbos): Consider spending additional bits on last_active_stream-1 down | |
| 86 // to 0 and not just the top layer when we have additional bitrate to spend. | |
| 87 int allocated_bitrate_kbps = std::min( | |
| 88 static_cast<int>(codec.simulcastStream[last_active_stream].maxBitrate - | |
| 89 bitrates_kbps[last_active_stream]), | |
| 90 bitrate_to_allocate_kbps); | |
| 91 bitrates_kbps[last_active_stream] += allocated_bitrate_kbps; | |
| 92 bitrate_to_allocate_kbps -= allocated_bitrate_kbps; | |
| 93 | |
| 94 // Make sure we can always send something. Suspending below min bitrate is | |
| 95 // controlled outside the codec implementation and is not overriden by this. | |
| 96 if (bitrates_kbps[0] < static_cast<int>(codec.simulcastStream[0].minBitrate)) | |
| 97 bitrates_kbps[0] = static_cast<int>(codec.simulcastStream[0].minBitrate); | |
| 98 | |
| 99 return bitrates_kbps; | |
| 100 } | |
| 101 | |
| 102 uint32_t SumStreamMaxBitrate(int streams, const VideoCodec& codec) { | |
| 103 uint32_t bitrate_sum = 0; | |
| 104 for (int i = 0; i < streams; ++i) { | |
| 105 bitrate_sum += codec.simulcastStream[i].maxBitrate; | |
| 106 } | |
| 107 return bitrate_sum; | |
| 108 } | |
| 109 | |
| 110 int NumberOfStreams(const VideoCodec& codec) { | |
| 111 int streams = | |
| 112 codec.numberOfSimulcastStreams < 1 ? 1 : codec.numberOfSimulcastStreams; | |
| 113 uint32_t simulcast_max_bitrate = SumStreamMaxBitrate(streams, codec); | |
| 114 if (simulcast_max_bitrate == 0) { | |
| 115 streams = 1; | |
| 116 } | |
| 117 return streams; | |
| 118 } | |
| 119 | |
| 120 bool ValidSimulcastResolutions(const VideoCodec& codec, int num_streams) { | 63 bool ValidSimulcastResolutions(const VideoCodec& codec, int num_streams) { |
| 121 if (codec.width != codec.simulcastStream[num_streams - 1].width || | 64 if (codec.width != codec.simulcastStream[num_streams - 1].width || |
| 122 codec.height != codec.simulcastStream[num_streams - 1].height) { | 65 codec.height != codec.simulcastStream[num_streams - 1].height) { |
| 123 return false; | 66 return false; |
| 124 } | 67 } |
| 125 for (int i = 0; i < num_streams; ++i) { | 68 for (int i = 0; i < num_streams; ++i) { |
| 126 if (codec.width * codec.simulcastStream[i].height != | 69 if (codec.width * codec.simulcastStream[i].height != |
| 127 codec.height * codec.simulcastStream[i].width) { | 70 codec.height * codec.simulcastStream[i].width) { |
| 128 return false; | 71 return false; |
| 129 } | 72 } |
| 130 } | 73 } |
| 131 return true; | 74 return true; |
| 132 } | 75 } |
| 133 | 76 |
| 134 int NumStreamsDisabled(const std::vector<bool>& streams) { | |
| 135 int num_disabled = 0; | |
| 136 for (bool stream : streams) { | |
| 137 if (!stream) | |
| 138 ++num_disabled; | |
| 139 } | |
| 140 return num_disabled; | |
| 141 } | |
| 142 } // namespace | 77 } // namespace |
| 143 | 78 |
| 144 VP8Encoder* VP8Encoder::Create() { | 79 VP8Encoder* VP8Encoder::Create() { |
| 145 return new VP8EncoderImpl(); | 80 return new VP8EncoderImpl(); |
| 146 } | 81 } |
| 147 | 82 |
| 148 VP8Decoder* VP8Decoder::Create() { | 83 VP8Decoder* VP8Decoder::Create() { |
| 149 return new VP8DecoderImpl(); | 84 return new VP8DecoderImpl(); |
| 150 } | 85 } |
| 151 | 86 |
| 152 const float kTl1MaxTimeToDropFrames = 20.0f; | |
| 153 | |
| 154 VP8EncoderImpl::VP8EncoderImpl() | 87 VP8EncoderImpl::VP8EncoderImpl() |
| 155 : encoded_complete_callback_(NULL), | 88 : encoded_complete_callback_(NULL), |
| 156 inited_(false), | 89 inited_(false), |
| 157 timestamp_(0), | 90 timestamp_(0), |
| 158 feedback_mode_(false), | 91 feedback_mode_(false), |
| 159 qp_max_(56), // Setting for max quantizer. | 92 qp_max_(56), // Setting for max quantizer. |
| 160 cpu_speed_default_(-6), | 93 cpu_speed_default_(-6), |
| 161 rc_max_intra_target_(0), | 94 rc_max_intra_target_(0), |
| 162 token_partitions_(VP8_ONE_TOKENPARTITION), | 95 token_partitions_(VP8_ONE_TOKENPARTITION), |
| 163 down_scale_requested_(false), | 96 down_scale_requested_(false), |
| 164 down_scale_bitrate_(0), | 97 down_scale_bitrate_(0), |
| 165 tl0_frame_dropper_(), | |
| 166 tl1_frame_dropper_(kTl1MaxTimeToDropFrames), | |
| 167 key_frame_request_(kMaxSimulcastStreams, false), | |
| 168 quality_scaler_enabled_(false) { | 98 quality_scaler_enabled_(false) { |
| 169 uint32_t seed = static_cast<uint32_t>(TickTime::MillisecondTimestamp()); | 99 uint32_t seed = static_cast<uint32_t>(TickTime::MillisecondTimestamp()); |
| 170 srand(seed); | 100 srand(seed); |
| 171 | 101 |
| 172 picture_id_.reserve(kMaxSimulcastStreams); | 102 picture_id_.reserve(kMaxSimulcastStreams); |
| 173 last_key_frame_picture_id_.reserve(kMaxSimulcastStreams); | 103 last_key_frame_picture_id_.reserve(kMaxSimulcastStreams); |
| 174 temporal_layers_.reserve(kMaxSimulcastStreams); | 104 temporal_layers_.reserve(kMaxSimulcastStreams); |
| 175 raw_images_.reserve(kMaxSimulcastStreams); | 105 raw_images_.reserve(kMaxSimulcastStreams); |
| 176 encoded_images_.reserve(kMaxSimulcastStreams); | 106 encoded_images_.reserve(kMaxSimulcastStreams); |
| 177 send_stream_.reserve(kMaxSimulcastStreams); | |
| 178 cpu_speed_.assign(kMaxSimulcastStreams, -6); // Set default to -6. | 107 cpu_speed_.assign(kMaxSimulcastStreams, -6); // Set default to -6. |
| 179 encoders_.reserve(kMaxSimulcastStreams); | 108 encoders_.reserve(kMaxSimulcastStreams); |
| 180 configurations_.reserve(kMaxSimulcastStreams); | 109 configurations_.reserve(kMaxSimulcastStreams); |
| 181 downsampling_factors_.reserve(kMaxSimulcastStreams); | 110 downsampling_factors_.reserve(kMaxSimulcastStreams); |
| 182 } | 111 } |
| 183 | 112 |
| 184 VP8EncoderImpl::~VP8EncoderImpl() { | 113 VP8EncoderImpl::~VP8EncoderImpl() { |
| 185 Release(); | 114 Release(); |
| 186 } | 115 } |
| 187 | 116 |
| 188 int VP8EncoderImpl::Release() { | 117 int VP8EncoderImpl::Release() { |
| 189 int ret_val = WEBRTC_VIDEO_CODEC_OK; | 118 int ret_val = WEBRTC_VIDEO_CODEC_OK; |
| 190 | 119 |
| 191 while (!encoded_images_.empty()) { | 120 while (!encoded_images_.empty()) { |
| 192 EncodedImage& image = encoded_images_.back(); | 121 EncodedImage& image = encoded_images_.back(); |
| 193 delete[] image._buffer; | 122 delete[] image._buffer; |
| 194 encoded_images_.pop_back(); | 123 encoded_images_.pop_back(); |
| 195 } | 124 } |
| 196 while (!encoders_.empty()) { | 125 while (!encoders_.empty()) { |
| 197 vpx_codec_ctx_t& encoder = encoders_.back(); | 126 vpx_codec_ctx_t& encoder = encoders_.back(); |
| 198 if (vpx_codec_destroy(&encoder)) { | 127 if (vpx_codec_destroy(&encoder)) { |
| 199 ret_val = WEBRTC_VIDEO_CODEC_MEMORY; | 128 ret_val = WEBRTC_VIDEO_CODEC_MEMORY; |
| 200 } | 129 } |
| 201 encoders_.pop_back(); | 130 encoders_.pop_back(); |
| 202 } | 131 } |
| 203 configurations_.clear(); | 132 configurations_.clear(); |
| 204 send_stream_.clear(); | 133 simulcast_state_.reset(); |
| 205 cpu_speed_.clear(); | 134 cpu_speed_.clear(); |
| 206 while (!raw_images_.empty()) { | 135 while (!raw_images_.empty()) { |
| 207 vpx_img_free(&raw_images_.back()); | 136 vpx_img_free(&raw_images_.back()); |
| 208 raw_images_.pop_back(); | 137 raw_images_.pop_back(); |
| 209 } | 138 } |
| 210 while (!temporal_layers_.empty()) { | 139 while (!temporal_layers_.empty()) { |
| 211 delete temporal_layers_.back(); | 140 delete temporal_layers_.back(); |
| 212 temporal_layers_.pop_back(); | 141 temporal_layers_.pop_back(); |
| 213 } | 142 } |
| 214 inited_ = false; | 143 inited_ = false; |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 243 // Calculate a rough limit for when to trigger a potental down scale. | 172 // Calculate a rough limit for when to trigger a potental down scale. |
| 244 uint32_t k_pixels_per_frame = codec_.width * codec_.height / 1000; | 173 uint32_t k_pixels_per_frame = codec_.width * codec_.height / 1000; |
| 245 // TODO(pwestin): we currently lack CAMA, this is a temporary fix to work | 174 // TODO(pwestin): we currently lack CAMA, this is a temporary fix to work |
| 246 // around the current limitations. | 175 // around the current limitations. |
| 247 // Only trigger keyframes if we are allowed to scale down. | 176 // Only trigger keyframes if we are allowed to scale down. |
| 248 if (configurations_[0].rc_resize_allowed) { | 177 if (configurations_[0].rc_resize_allowed) { |
| 249 if (!down_scale_requested_) { | 178 if (!down_scale_requested_) { |
| 250 if (k_pixels_per_frame > new_bitrate_kbit) { | 179 if (k_pixels_per_frame > new_bitrate_kbit) { |
| 251 down_scale_requested_ = true; | 180 down_scale_requested_ = true; |
| 252 down_scale_bitrate_ = new_bitrate_kbit; | 181 down_scale_bitrate_ = new_bitrate_kbit; |
| 253 key_frame_request_[0] = true; | 182 simulcast_state_->RequestKeyFrame(0); |
| 254 } | 183 } |
| 255 } else { | 184 } else { |
| 256 if (new_bitrate_kbit > (2 * down_scale_bitrate_) || | 185 if (new_bitrate_kbit > (2 * down_scale_bitrate_) || |
| 257 new_bitrate_kbit < (down_scale_bitrate_ / 2)) { | 186 new_bitrate_kbit < (down_scale_bitrate_ / 2)) { |
| 258 down_scale_requested_ = false; | 187 down_scale_requested_ = false; |
| 259 } | 188 } |
| 260 } | 189 } |
| 261 } | 190 } |
| 262 } else { | 191 } else { |
| 263 // If we have more than 1 stream, reduce the qp_max for the low resolution | 192 // If we have more than 1 stream, reduce the qp_max for the low resolution |
| 264 // stream if frame rate is not too low. The trade-off with lower qp_max is | 193 // stream if frame rate is not too low. The trade-off with lower qp_max is |
| 265 // possibly more dropped frames, so we only do this if the frame rate is | 194 // possibly more dropped frames, so we only do this if the frame rate is |
| 266 // above some threshold (base temporal layer is down to 1/4 for 3 layers). | 195 // above some threshold (base temporal layer is down to 1/4 for 3 layers). |
| 267 // We may want to condition this on bitrate later. | 196 // We may want to condition this on bitrate later. |
| 268 if (new_framerate > 20) { | 197 if (new_framerate > 20) { |
| 269 configurations_[encoders_.size() - 1].rc_max_quantizer = 45; | 198 configurations_[encoders_.size() - 1].rc_max_quantizer = 45; |
| 270 } else { | 199 } else { |
| 271 // Go back to default value set in InitEncode. | 200 // Go back to default value set in InitEncode. |
| 272 configurations_[encoders_.size() - 1].rc_max_quantizer = qp_max_; | 201 configurations_[encoders_.size() - 1].rc_max_quantizer = qp_max_; |
| 273 } | 202 } |
| 274 } | 203 } |
| 275 | 204 |
| 276 std::vector<int> stream_bitrates = | 205 simulcast_state_->AllocateBitrate(new_bitrate_kbit); |
| 277 GetStreamBitratesKbps(codec_, new_bitrate_kbit); | 206 for (const SimulcastState::Stream& stream : *simulcast_state_) { |
| 278 size_t stream_idx = encoders_.size() - 1; | 207 unsigned int target_bitrate = stream.allocated_rate_kbps; |
| 279 for (size_t i = 0; i < encoders_.size(); ++i, --stream_idx) { | |
| 280 if (encoders_.size() > 1) | |
| 281 SetStreamState(stream_bitrates[stream_idx] > 0, stream_idx); | |
| 282 | |
| 283 unsigned int target_bitrate = stream_bitrates[stream_idx]; | |
| 284 unsigned int max_bitrate = codec_.maxBitrate; | 208 unsigned int max_bitrate = codec_.maxBitrate; |
| 285 int framerate = new_framerate; | |
| 286 // TODO(holmer): This is a temporary hack for screensharing, where we | 209 // TODO(holmer): This is a temporary hack for screensharing, where we |
| 287 // interpret the startBitrate as the encoder target bitrate. This is | 210 // interpret the startBitrate as the encoder target bitrate. This is |
| 288 // to allow for a different max bitrate, so if the codec can't meet | 211 // to allow for a different max bitrate, so if the codec can't meet |
| 289 // the target we still allow it to overshoot up to the max before dropping | 212 // the target we still allow it to overshoot up to the max before dropping |
| 290 // frames. This hack should be improved. | 213 // frames. This hack should be improved. |
| 291 if (codec_.targetBitrate > 0 && | 214 if (codec_.targetBitrate > 0 && simulcast_state_->NumStreams() == 1 && |
| 292 (codec_.codecSpecific.VP8.numberOfTemporalLayers == 2 || | 215 (codec_.codecSpecific.VP8.numberOfTemporalLayers == 2 || |
| 293 codec_.simulcastStream[0].numberOfTemporalLayers == 2)) { | 216 codec_.simulcastStream[0].numberOfTemporalLayers == 2)) { |
| 294 int tl0_bitrate = std::min(codec_.targetBitrate, target_bitrate); | 217 int tl0_bitrate = std::min(codec_.targetBitrate, target_bitrate); |
| 295 max_bitrate = std::min(codec_.maxBitrate, target_bitrate); | 218 max_bitrate = std::min(codec_.maxBitrate, target_bitrate); |
| 296 target_bitrate = tl0_bitrate; | 219 target_bitrate = tl0_bitrate; |
| 297 } | 220 } |
| 221 int i = simulcast_state_->NumStreams() - stream.idx - 1; | |
| 298 configurations_[i].rc_target_bitrate = target_bitrate; | 222 configurations_[i].rc_target_bitrate = target_bitrate; |
| 299 temporal_layers_[stream_idx]->ConfigureBitrates( | 223 temporal_layers_[stream.idx]->ConfigureBitrates( |
| 300 target_bitrate, max_bitrate, framerate, &configurations_[i]); | 224 target_bitrate, max_bitrate, new_framerate, &configurations_[i]); |
| 301 if (vpx_codec_enc_config_set(&encoders_[i], &configurations_[i])) { | 225 if (vpx_codec_enc_config_set(&encoders_[i], &configurations_[i])) { |
| 302 return WEBRTC_VIDEO_CODEC_ERROR; | 226 return WEBRTC_VIDEO_CODEC_ERROR; |
| 303 } | 227 } |
| 304 } | 228 } |
| 305 quality_scaler_.ReportFramerate(new_framerate); | 229 quality_scaler_.ReportFramerate(new_framerate); |
| 306 return WEBRTC_VIDEO_CODEC_OK; | 230 return WEBRTC_VIDEO_CODEC_OK; |
| 307 } | 231 } |
| 308 | 232 |
| 309 const char* VP8EncoderImpl::ImplementationName() const { | 233 const char* VP8EncoderImpl::ImplementationName() const { |
| 310 return "libvpx"; | 234 return "libvpx"; |
| 311 } | 235 } |
| 312 | 236 |
| 313 void VP8EncoderImpl::SetStreamState(bool send_stream, | |
| 314 int stream_idx) { | |
| 315 if (send_stream && !send_stream_[stream_idx]) { | |
| 316 // Need a key frame if we have not sent this stream before. | |
| 317 key_frame_request_[stream_idx] = true; | |
| 318 } | |
| 319 send_stream_[stream_idx] = send_stream; | |
| 320 } | |
| 321 | |
| 322 void VP8EncoderImpl::SetupTemporalLayers(int num_streams, | 237 void VP8EncoderImpl::SetupTemporalLayers(int num_streams, |
| 323 int num_temporal_layers, | 238 int num_temporal_layers, |
| 324 const VideoCodec& codec) { | 239 const VideoCodec& codec) { |
| 325 TemporalLayersFactory default_factory; | 240 TemporalLayersFactory default_factory; |
| 326 const TemporalLayersFactory* tl_factory = codec.codecSpecific.VP8.tl_factory; | 241 const TemporalLayersFactory* tl_factory = codec.codecSpecific.VP8.tl_factory; |
| 327 if (!tl_factory) | 242 if (!tl_factory) |
| 328 tl_factory = &default_factory; | 243 tl_factory = &default_factory; |
| 329 if (num_streams == 1) { | 244 if (num_streams == 1) { |
| 330 if (codec.mode == kScreensharing) { | 245 if (codec.mode == kScreensharing) { |
| 331 // Special mode when screensharing on a single stream. | 246 // Special mode when screensharing on a single stream. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 371 } | 286 } |
| 372 if (inst->codecSpecific.VP8.automaticResizeOn && | 287 if (inst->codecSpecific.VP8.automaticResizeOn && |
| 373 inst->numberOfSimulcastStreams > 1) { | 288 inst->numberOfSimulcastStreams > 1) { |
| 374 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | 289 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; |
| 375 } | 290 } |
| 376 int retVal = Release(); | 291 int retVal = Release(); |
| 377 if (retVal < 0) { | 292 if (retVal < 0) { |
| 378 return retVal; | 293 return retVal; |
| 379 } | 294 } |
| 380 | 295 |
| 381 int number_of_streams = NumberOfStreams(*inst); | 296 std::unique_ptr<SimulcastState> new_simulcast_state( |
| 297 new SimulcastState(*inst)); | |
| 298 | |
| 299 int number_of_streams = new_simulcast_state->NumStreams(); | |
| 382 bool doing_simulcast = (number_of_streams > 1); | 300 bool doing_simulcast = (number_of_streams > 1); |
| 383 | 301 |
| 384 if (doing_simulcast && !ValidSimulcastResolutions(*inst, number_of_streams)) { | 302 if (doing_simulcast && !ValidSimulcastResolutions(*inst, number_of_streams)) { |
| 385 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | 303 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; |
| 386 } | 304 } |
| 387 | 305 |
| 388 int num_temporal_layers = | 306 int num_temporal_layers = |
| 389 doing_simulcast ? inst->simulcastStream[0].numberOfTemporalLayers | 307 doing_simulcast ? inst->simulcastStream[0].numberOfTemporalLayers |
| 390 : inst->codecSpecific.VP8.numberOfTemporalLayers; | 308 : inst->codecSpecific.VP8.numberOfTemporalLayers; |
| 391 | 309 |
| 392 // TODO(andresp): crash if num temporal layers is bananas. | 310 // TODO(andresp): crash if num temporal layers is bananas. |
| 393 if (num_temporal_layers < 1) | 311 if (num_temporal_layers < 1) |
| 394 num_temporal_layers = 1; | 312 num_temporal_layers = 1; |
| 395 SetupTemporalLayers(number_of_streams, num_temporal_layers, *inst); | 313 SetupTemporalLayers(number_of_streams, num_temporal_layers, *inst); |
| 396 | 314 |
| 397 feedback_mode_ = inst->codecSpecific.VP8.feedbackModeOn; | 315 feedback_mode_ = inst->codecSpecific.VP8.feedbackModeOn; |
| 398 | 316 |
| 399 timestamp_ = 0; | 317 timestamp_ = 0; |
| 400 codec_ = *inst; | 318 codec_ = *inst; |
| 319 simulcast_state_ = std::move(new_simulcast_state); | |
| 401 | 320 |
| 402 // Code expects simulcastStream resolutions to be correct, make sure they are | 321 // Code expects simulcastStream resolutions to be correct, make sure they are |
| 403 // filled even when there are no simulcast layers. | 322 // filled even when there are no simulcast layers. |
| 404 if (codec_.numberOfSimulcastStreams == 0) { | 323 if (codec_.numberOfSimulcastStreams == 0) { |
| 405 codec_.simulcastStream[0].width = codec_.width; | 324 codec_.simulcastStream[0].width = codec_.width; |
| 406 codec_.simulcastStream[0].height = codec_.height; | 325 codec_.simulcastStream[0].height = codec_.height; |
| 407 } | 326 } |
| 408 | 327 |
| 409 picture_id_.resize(number_of_streams); | 328 picture_id_.resize(number_of_streams); |
| 410 last_key_frame_picture_id_.resize(number_of_streams); | 329 last_key_frame_picture_id_.resize(number_of_streams); |
| 411 encoded_images_.resize(number_of_streams); | 330 encoded_images_.resize(number_of_streams); |
| 412 encoders_.resize(number_of_streams); | 331 encoders_.resize(number_of_streams); |
| 413 configurations_.resize(number_of_streams); | 332 configurations_.resize(number_of_streams); |
| 414 downsampling_factors_.resize(number_of_streams); | 333 downsampling_factors_.resize(number_of_streams); |
| 415 raw_images_.resize(number_of_streams); | 334 raw_images_.resize(number_of_streams); |
| 416 send_stream_.resize(number_of_streams); | |
| 417 send_stream_[0] = true; // For non-simulcast case. | |
| 418 cpu_speed_.resize(number_of_streams); | 335 cpu_speed_.resize(number_of_streams); |
| 419 std::fill(key_frame_request_.begin(), key_frame_request_.end(), false); | |
| 420 | 336 |
| 421 int idx = number_of_streams - 1; | 337 int idx = number_of_streams - 1; |
| 422 for (int i = 0; i < (number_of_streams - 1); ++i, --idx) { | 338 for (int i = 0; i < (number_of_streams - 1); ++i, --idx) { |
| 423 int gcd = GCD(inst->simulcastStream[idx].width, | 339 int gcd = GCD(inst->simulcastStream[idx].width, |
| 424 inst->simulcastStream[idx - 1].width); | 340 inst->simulcastStream[idx - 1].width); |
| 425 downsampling_factors_[i].num = inst->simulcastStream[idx].width / gcd; | 341 downsampling_factors_[i].num = inst->simulcastStream[idx].width / gcd; |
| 426 downsampling_factors_[i].den = inst->simulcastStream[idx - 1].width / gcd; | 342 downsampling_factors_[i].den = inst->simulcastStream[idx - 1].width / gcd; |
| 427 send_stream_[i] = false; | 343 simulcast_state_->SetSending(i, false); |
| 428 } | 344 } |
| 429 if (number_of_streams > 1) { | 345 if (number_of_streams > 1) { |
| 430 send_stream_[number_of_streams - 1] = false; | 346 simulcast_state_->SetSending(number_of_streams - 1, false); |
| 431 downsampling_factors_[number_of_streams - 1].num = 1; | 347 downsampling_factors_[number_of_streams - 1].num = 1; |
| 432 downsampling_factors_[number_of_streams - 1].den = 1; | 348 downsampling_factors_[number_of_streams - 1].den = 1; |
| 433 } | 349 } |
| 434 for (int i = 0; i < number_of_streams; ++i) { | 350 for (int i = 0; i < number_of_streams; ++i) { |
| 435 // Random start, 16 bits is enough. | 351 // Random start, 16 bits is enough. |
| 436 picture_id_[i] = static_cast<uint16_t>(rand()) & 0x7FFF; // NOLINT | 352 picture_id_[i] = static_cast<uint16_t>(rand()) & 0x7FFF; // NOLINT |
| 437 last_key_frame_picture_id_[i] = -1; | 353 last_key_frame_picture_id_[i] = -1; |
| 438 // allocate memory for encoded image | 354 // allocate memory for encoded image |
| 439 if (encoded_images_[i]._buffer != NULL) { | 355 if (encoded_images_[i]._buffer != NULL) { |
| 440 delete[] encoded_images_[i]._buffer; | 356 delete[] encoded_images_[i]._buffer; |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 555 // is meaningless (no memory allocation is done here). | 471 // is meaningless (no memory allocation is done here). |
| 556 vpx_img_wrap(&raw_images_[0], VPX_IMG_FMT_I420, inst->width, inst->height, 1, | 472 vpx_img_wrap(&raw_images_[0], VPX_IMG_FMT_I420, inst->width, inst->height, 1, |
| 557 NULL); | 473 NULL); |
| 558 | 474 |
| 559 if (encoders_.size() == 1) { | 475 if (encoders_.size() == 1) { |
| 560 configurations_[0].rc_target_bitrate = inst->startBitrate; | 476 configurations_[0].rc_target_bitrate = inst->startBitrate; |
| 561 temporal_layers_[0]->ConfigureBitrates(inst->startBitrate, inst->maxBitrate, | 477 temporal_layers_[0]->ConfigureBitrates(inst->startBitrate, inst->maxBitrate, |
| 562 inst->maxFramerate, | 478 inst->maxFramerate, |
| 563 &configurations_[0]); | 479 &configurations_[0]); |
| 564 } else { | 480 } else { |
| 481 simulcast_state_->AllocateBitrate(inst->startBitrate); | |
| 565 // Note the order we use is different from webm, we have lowest resolution | 482 // Note the order we use is different from webm, we have lowest resolution |
| 566 // at position 0 and they have highest resolution at position 0. | 483 // at position 0 and they have highest resolution at position 0. |
| 567 int stream_idx = encoders_.size() - 1; | 484 int stream_idx = encoders_.size() - 1; |
| 568 std::vector<int> stream_bitrates = | 485 int stream_bitrate_kbps = simulcast_state_->AllocatedRate(stream_idx); |
| 569 GetStreamBitratesKbps(codec_, inst->startBitrate); | 486 configurations_[0].rc_target_bitrate = stream_bitrate_kbps; |
| 570 SetStreamState(stream_bitrates[stream_idx] > 0, stream_idx); | |
| 571 configurations_[0].rc_target_bitrate = stream_bitrates[stream_idx]; | |
| 572 temporal_layers_[stream_idx]->ConfigureBitrates( | 487 temporal_layers_[stream_idx]->ConfigureBitrates( |
| 573 stream_bitrates[stream_idx], inst->maxBitrate, inst->maxFramerate, | 488 stream_bitrate_kbps, inst->maxBitrate, inst->maxFramerate, |
| 574 &configurations_[0]); | 489 &configurations_[0]); |
| 575 --stream_idx; | 490 --stream_idx; |
| 576 for (size_t i = 1; i < encoders_.size(); ++i, --stream_idx) { | 491 for (size_t i = 1; i < encoders_.size(); ++i, --stream_idx) { |
| 577 memcpy(&configurations_[i], &configurations_[0], | 492 memcpy(&configurations_[i], &configurations_[0], |
| 578 sizeof(configurations_[0])); | 493 sizeof(configurations_[0])); |
| 579 | 494 |
| 580 configurations_[i].g_w = inst->simulcastStream[stream_idx].width; | 495 configurations_[i].g_w = inst->simulcastStream[stream_idx].width; |
| 581 configurations_[i].g_h = inst->simulcastStream[stream_idx].height; | 496 configurations_[i].g_h = inst->simulcastStream[stream_idx].height; |
| 582 | 497 |
| 583 // Use 1 thread for lower resolutions. | 498 // Use 1 thread for lower resolutions. |
| 584 configurations_[i].g_threads = 1; | 499 configurations_[i].g_threads = 1; |
| 585 | 500 |
| 586 // Setting alignment to 32 - as that ensures at least 16 for all | 501 // Setting alignment to 32 - as that ensures at least 16 for all |
| 587 // planes (32 for Y, 16 for U,V). Libvpx sets the requested stride for | 502 // planes (32 for Y, 16 for U,V). Libvpx sets the requested stride for |
| 588 // the y plane, but only half of it to the u and v planes. | 503 // the y plane, but only half of it to the u and v planes. |
| 589 vpx_img_alloc(&raw_images_[i], VPX_IMG_FMT_I420, | 504 vpx_img_alloc(&raw_images_[i], VPX_IMG_FMT_I420, |
| 590 inst->simulcastStream[stream_idx].width, | 505 inst->simulcastStream[stream_idx].width, |
| 591 inst->simulcastStream[stream_idx].height, kVp832ByteAlign); | 506 inst->simulcastStream[stream_idx].height, kVp832ByteAlign); |
| 592 SetStreamState(stream_bitrates[stream_idx] > 0, stream_idx); | 507 stream_bitrate_kbps = simulcast_state_->AllocatedRate(stream_idx); |
| 593 configurations_[i].rc_target_bitrate = stream_bitrates[stream_idx]; | 508 configurations_[i].rc_target_bitrate = stream_bitrate_kbps; |
| 594 temporal_layers_[stream_idx]->ConfigureBitrates( | 509 temporal_layers_[stream_idx]->ConfigureBitrates( |
| 595 stream_bitrates[stream_idx], inst->maxBitrate, inst->maxFramerate, | 510 stream_bitrate_kbps, inst->maxBitrate, inst->maxFramerate, |
| 596 &configurations_[i]); | 511 &configurations_[i]); |
| 597 } | 512 } |
| 598 } | 513 } |
| 599 | 514 |
| 600 rps_.Init(); | 515 rps_.Init(); |
| 601 // Disable both high-QP limits and framedropping. Both are handled by libvpx | 516 // Disable both high-QP limits and framedropping. Both are handled by libvpx |
| 602 // internally. | 517 // internally. |
| 603 // QP thresholds are chosen to be high enough to be hit in practice when | 518 // QP thresholds are chosen to be high enough to be hit in practice when |
| 604 // quality is good, but also low enough to not cause a flip-flop behavior | 519 // quality is good, but also low enough to not cause a flip-flop behavior |
| 605 // (e.g. going up in resolution shouldn't give so bad quality that we should | 520 // (e.g. going up in resolution shouldn't give so bad quality that we should |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 782 vpx_enc_frame_flags_t flags[kMaxSimulcastStreams]; | 697 vpx_enc_frame_flags_t flags[kMaxSimulcastStreams]; |
| 783 for (size_t i = 0; i < encoders_.size(); ++i) { | 698 for (size_t i = 0; i < encoders_.size(); ++i) { |
| 784 int ret = temporal_layers_[i]->EncodeFlags(input_image.timestamp()); | 699 int ret = temporal_layers_[i]->EncodeFlags(input_image.timestamp()); |
| 785 if (ret < 0) { | 700 if (ret < 0) { |
| 786 // Drop this frame. | 701 // Drop this frame. |
| 787 return WEBRTC_VIDEO_CODEC_OK; | 702 return WEBRTC_VIDEO_CODEC_OK; |
| 788 } | 703 } |
| 789 flags[i] = ret; | 704 flags[i] = ret; |
| 790 } | 705 } |
| 791 bool send_key_frame = false; | 706 bool send_key_frame = false; |
| 792 for (size_t i = 0; i < key_frame_request_.size() && i < send_stream_.size(); | 707 size_t num_entries = std::min(frame_types ? frame_types->size() : 0, |
| 793 ++i) { | 708 simulcast_state_->NumStreams()); |
| 794 if (key_frame_request_[i] && send_stream_[i]) { | 709 for (size_t i = 0; i < num_entries; ++i) { |
| 795 send_key_frame = true; | 710 send_key_frame |= simulcast_state_->GetAndResetKeyFrameRequest(i) || |
| 796 break; | 711 (frame_types && (*frame_types)[i] == kVideoFrameKey); |
| 797 } | |
| 798 } | 712 } |
| 799 if (!send_key_frame && frame_types) { | 713 |
| 800 for (size_t i = 0; i < frame_types->size() && i < send_stream_.size(); | |
| 801 ++i) { | |
| 802 if ((*frame_types)[i] == kVideoFrameKey && send_stream_[i]) { | |
| 803 send_key_frame = true; | |
| 804 break; | |
| 805 } | |
| 806 } | |
| 807 } | |
| 808 // The flag modification below (due to forced key frame, RPS, etc.,) for now | 714 // The flag modification below (due to forced key frame, RPS, etc.,) for now |
| 809 // will be the same for all encoders/spatial layers. | 715 // will be the same for all encoders/spatial layers. |
| 810 // TODO(marpan/holmer): Allow for key frame request to be set per encoder. | 716 // TODO(marpan/holmer): Allow for key frame request to be set per encoder. |
| 811 bool only_predict_from_key_frame = false; | 717 bool only_predict_from_key_frame = false; |
| 812 if (send_key_frame) { | 718 if (send_key_frame) { |
| 813 // Adapt the size of the key frame when in screenshare with 1 temporal | 719 // Adapt the size of the key frame when in screenshare with 1 temporal |
| 814 // layer. | 720 // layer. |
| 815 if (encoders_.size() == 1 && codec_.mode == kScreensharing && | 721 if (encoders_.size() == 1 && codec_.mode == kScreensharing && |
| 816 codec_.codecSpecific.VP8.numberOfTemporalLayers <= 1) { | 722 codec_.codecSpecific.VP8.numberOfTemporalLayers <= 1) { |
| 817 const uint32_t forceKeyFrameIntraTh = 100; | 723 const uint32_t forceKeyFrameIntraTh = 100; |
| 818 vpx_codec_control(&(encoders_[0]), VP8E_SET_MAX_INTRA_BITRATE_PCT, | 724 vpx_codec_control(&(encoders_[0]), VP8E_SET_MAX_INTRA_BITRATE_PCT, |
| 819 forceKeyFrameIntraTh); | 725 forceKeyFrameIntraTh); |
| 820 } | 726 } |
| 821 // Key frame request from caller. | 727 // Key frame request from caller. |
| 822 // Will update both golden and alt-ref. | 728 // Will update both golden and alt-ref. |
| 823 for (size_t i = 0; i < encoders_.size(); ++i) { | 729 for (size_t i = 0; i < encoders_.size(); ++i) { |
| 824 flags[i] = VPX_EFLAG_FORCE_KF; | 730 flags[i] = VPX_EFLAG_FORCE_KF; |
| 825 } | 731 } |
| 826 std::fill(key_frame_request_.begin(), key_frame_request_.end(), false); | |
| 827 } else if (codec_specific_info && | 732 } else if (codec_specific_info && |
| 828 codec_specific_info->codecType == kVideoCodecVP8) { | 733 codec_specific_info->codecType == kVideoCodecVP8) { |
| 829 if (feedback_mode_) { | 734 if (feedback_mode_) { |
| 830 // Handle RPSI and SLI messages and set up the appropriate encode flags. | 735 // Handle RPSI and SLI messages and set up the appropriate encode flags. |
| 831 bool sendRefresh = false; | 736 bool sendRefresh = false; |
| 832 if (codec_specific_info->codecSpecific.VP8.hasReceivedRPSI) { | 737 if (codec_specific_info->codecSpecific.VP8.hasReceivedRPSI) { |
| 833 rps_.ReceivedRPSI(codec_specific_info->codecSpecific.VP8.pictureIdRPSI); | 738 rps_.ReceivedRPSI(codec_specific_info->codecSpecific.VP8.pictureIdRPSI); |
| 834 } | 739 } |
| 835 if (codec_specific_info->codecSpecific.VP8.hasReceivedSLI) { | 740 if (codec_specific_info->codecSpecific.VP8.hasReceivedSLI) { |
| 836 sendRefresh = rps_.ReceivedSLI(input_image.timestamp()); | 741 sendRefresh = rps_.ReceivedSLI(input_image.timestamp()); |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 957 only_predicting_from_key_frame; | 862 only_predicting_from_key_frame; |
| 958 temporal_layers_[stream_idx]->PopulateCodecSpecific(base_layer_sync_point, | 863 temporal_layers_[stream_idx]->PopulateCodecSpecific(base_layer_sync_point, |
| 959 vp8Info, timestamp); | 864 vp8Info, timestamp); |
| 960 // Prepare next. | 865 // Prepare next. |
| 961 picture_id_[stream_idx] = (picture_id_[stream_idx] + 1) & 0x7FFF; | 866 picture_id_[stream_idx] = (picture_id_[stream_idx] + 1) & 0x7FFF; |
| 962 } | 867 } |
| 963 | 868 |
| 964 int VP8EncoderImpl::GetEncodedPartitions(const VideoFrame& input_image, | 869 int VP8EncoderImpl::GetEncodedPartitions(const VideoFrame& input_image, |
| 965 bool only_predicting_from_key_frame) { | 870 bool only_predicting_from_key_frame) { |
| 966 int bw_resolutions_disabled = | 871 int bw_resolutions_disabled = |
| 967 (encoders_.size() > 1) ? NumStreamsDisabled(send_stream_) : -1; | 872 (encoders_.size() > 1) ? simulcast_state_->NumSendingStreams() : -1; |
|
pbos-webrtc
2016/04/29 21:23:27
This is not NumStreamsDisabled? Why are tests not
| |
| 968 | 873 |
| 969 int stream_idx = static_cast<int>(encoders_.size()) - 1; | 874 int stream_idx = static_cast<int>(encoders_.size()) - 1; |
| 970 int result = WEBRTC_VIDEO_CODEC_OK; | 875 int result = WEBRTC_VIDEO_CODEC_OK; |
| 971 for (size_t encoder_idx = 0; encoder_idx < encoders_.size(); | 876 for (size_t encoder_idx = 0; encoder_idx < encoders_.size(); |
| 972 ++encoder_idx, --stream_idx) { | 877 ++encoder_idx, --stream_idx) { |
| 973 vpx_codec_iter_t iter = NULL; | 878 vpx_codec_iter_t iter = NULL; |
| 974 int part_idx = 0; | 879 int part_idx = 0; |
| 975 encoded_images_[encoder_idx]._length = 0; | 880 encoded_images_[encoder_idx]._length = 0; |
| 976 encoded_images_[encoder_idx]._frameType = kVideoFrameDelta; | 881 encoded_images_[encoder_idx]._frameType = kVideoFrameDelta; |
| 977 RTPFragmentationHeader frag_info; | 882 RTPFragmentationHeader frag_info; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1023 encoded_images_[encoder_idx]._timeStamp = input_image.timestamp(); | 928 encoded_images_[encoder_idx]._timeStamp = input_image.timestamp(); |
| 1024 encoded_images_[encoder_idx].capture_time_ms_ = | 929 encoded_images_[encoder_idx].capture_time_ms_ = |
| 1025 input_image.render_time_ms(); | 930 input_image.render_time_ms(); |
| 1026 encoded_images_[encoder_idx].rotation_ = input_image.rotation(); | 931 encoded_images_[encoder_idx].rotation_ = input_image.rotation(); |
| 1027 | 932 |
| 1028 int qp = -1; | 933 int qp = -1; |
| 1029 vpx_codec_control(&encoders_[encoder_idx], VP8E_GET_LAST_QUANTIZER_64, &qp); | 934 vpx_codec_control(&encoders_[encoder_idx], VP8E_GET_LAST_QUANTIZER_64, &qp); |
| 1030 temporal_layers_[stream_idx]->FrameEncoded( | 935 temporal_layers_[stream_idx]->FrameEncoded( |
| 1031 encoded_images_[encoder_idx]._length, | 936 encoded_images_[encoder_idx]._length, |
| 1032 encoded_images_[encoder_idx]._timeStamp, qp); | 937 encoded_images_[encoder_idx]._timeStamp, qp); |
| 1033 if (send_stream_[stream_idx]) { | 938 if (simulcast_state_->IsSending(stream_idx)) { |
| 1034 if (encoded_images_[encoder_idx]._length > 0) { | 939 if (encoded_images_[encoder_idx]._length > 0) { |
| 1035 TRACE_COUNTER_ID1("webrtc", "EncodedFrameSize", encoder_idx, | 940 TRACE_COUNTER_ID1("webrtc", "EncodedFrameSize", encoder_idx, |
| 1036 encoded_images_[encoder_idx]._length); | 941 encoded_images_[encoder_idx]._length); |
| 1037 encoded_images_[encoder_idx]._encodedHeight = | 942 encoded_images_[encoder_idx]._encodedHeight = |
| 1038 codec_.simulcastStream[stream_idx].height; | 943 codec_.simulcastStream[stream_idx].height; |
| 1039 encoded_images_[encoder_idx]._encodedWidth = | 944 encoded_images_[encoder_idx]._encodedWidth = |
| 1040 codec_.simulcastStream[stream_idx].width; | 945 codec_.simulcastStream[stream_idx].width; |
| 1041 encoded_images_[encoder_idx] | 946 encoded_images_[encoder_idx] |
| 1042 .adapt_reason_.quality_resolution_downscales = | 947 .adapt_reason_.quality_resolution_downscales = |
| 1043 quality_scaler_enabled_ ? quality_scaler_.downscale_shift() : -1; | 948 quality_scaler_enabled_ ? quality_scaler_.downscale_shift() : -1; |
| 1044 // Report once per frame (lowest stream always sent). | 949 // Report once per frame (lowest stream always sent). |
| 1045 encoded_images_[encoder_idx].adapt_reason_.bw_resolutions_disabled = | 950 encoded_images_[encoder_idx].adapt_reason_.bw_resolutions_disabled = |
| 1046 (stream_idx == 0) ? bw_resolutions_disabled : -1; | 951 (stream_idx == 0) ? bw_resolutions_disabled : -1; |
| 1047 int qp_128 = -1; | 952 int qp_128 = -1; |
| 1048 vpx_codec_control(&encoders_[encoder_idx], VP8E_GET_LAST_QUANTIZER, | 953 vpx_codec_control(&encoders_[encoder_idx], VP8E_GET_LAST_QUANTIZER, |
| 1049 &qp_128); | 954 &qp_128); |
| 1050 encoded_images_[encoder_idx].qp_ = qp_128; | 955 encoded_images_[encoder_idx].qp_ = qp_128; |
| 1051 encoded_complete_callback_->Encoded(encoded_images_[encoder_idx], | 956 encoded_complete_callback_->Encoded(encoded_images_[encoder_idx], |
| 1052 &codec_specific, &frag_info); | 957 &codec_specific, &frag_info); |
| 1053 } else if (codec_.mode == kScreensharing) { | 958 } else if (codec_.mode == kScreensharing) { |
| 1054 result = WEBRTC_VIDEO_CODEC_TARGET_BITRATE_OVERSHOOT; | 959 result = WEBRTC_VIDEO_CODEC_TARGET_BITRATE_OVERSHOOT; |
| 1055 } | 960 } |
| 1056 } | 961 } |
| 1057 } | 962 } |
| 1058 if (encoders_.size() == 1 && send_stream_[0]) { | 963 if (encoders_.size() == 1 && simulcast_state_->IsSending(0)) { |
| 1059 if (encoded_images_[0]._length > 0) { | 964 if (encoded_images_[0]._length > 0) { |
| 1060 int qp_128; | 965 int qp_128; |
| 1061 vpx_codec_control(&encoders_[0], VP8E_GET_LAST_QUANTIZER, &qp_128); | 966 vpx_codec_control(&encoders_[0], VP8E_GET_LAST_QUANTIZER, &qp_128); |
| 1062 quality_scaler_.ReportQP(qp_128); | 967 quality_scaler_.ReportQP(qp_128); |
| 1063 } else { | 968 } else { |
| 1064 quality_scaler_.ReportDroppedFrame(); | 969 quality_scaler_.ReportDroppedFrame(); |
| 1065 } | 970 } |
| 1066 } | 971 } |
| 1067 return result; | 972 return result; |
| 1068 } | 973 } |
| (...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1413 return -1; | 1318 return -1; |
| 1414 } | 1319 } |
| 1415 if (vpx_codec_control(copy->decoder_, VP8_SET_REFERENCE, ref_frame_) != | 1320 if (vpx_codec_control(copy->decoder_, VP8_SET_REFERENCE, ref_frame_) != |
| 1416 VPX_CODEC_OK) { | 1321 VPX_CODEC_OK) { |
| 1417 return -1; | 1322 return -1; |
| 1418 } | 1323 } |
| 1419 return 0; | 1324 return 0; |
| 1420 } | 1325 } |
| 1421 | 1326 |
| 1422 } // namespace webrtc | 1327 } // namespace webrtc |
| OLD | NEW |