Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(747)

Side by Side Diff: webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter.cc

Issue 2434073003: Extract bitrate allocation of spatial/temporal layers out of codec impl. (Closed)
Patch Set: Fixed sign mismatch Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
78 inst->numberOfSimulcastStreams > 1) { 78 inst->numberOfSimulcastStreams > 1) {
79 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; 79 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
80 } 80 }
81 if (inst->codecSpecific.VP8.automaticResizeOn && 81 if (inst->codecSpecific.VP8.automaticResizeOn &&
82 inst->numberOfSimulcastStreams > 1) { 82 inst->numberOfSimulcastStreams > 1) {
83 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; 83 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
84 } 84 }
85 return WEBRTC_VIDEO_CODEC_OK; 85 return WEBRTC_VIDEO_CODEC_OK;
86 } 86 }
87 87
88 struct ScreenshareTemporalLayersFactory : webrtc::TemporalLayersFactory {
89 ScreenshareTemporalLayersFactory() {}
90 virtual ~ScreenshareTemporalLayersFactory() {}
91
92 virtual webrtc::TemporalLayers* Create(int num_temporal_layers,
93 uint8_t initial_tl0_pic_idx) const {
94 return new webrtc::ScreenshareLayers(num_temporal_layers, rand(),
95 webrtc::Clock::GetRealTimeClock());
96 }
97 };
98
99 // An EncodedImageCallback implementation that forwards on calls to a 88 // An EncodedImageCallback implementation that forwards on calls to a
100 // SimulcastEncoderAdapter, but with the stream index it's registered with as 89 // SimulcastEncoderAdapter, but with the stream index it's registered with as
101 // the first parameter to Encoded. 90 // the first parameter to Encoded.
102 class AdapterEncodedImageCallback : public webrtc::EncodedImageCallback { 91 class AdapterEncodedImageCallback : public webrtc::EncodedImageCallback {
103 public: 92 public:
104 AdapterEncodedImageCallback(webrtc::SimulcastEncoderAdapter* adapter, 93 AdapterEncodedImageCallback(webrtc::SimulcastEncoderAdapter* adapter,
105 size_t stream_idx) 94 size_t stream_idx)
106 : adapter_(adapter), stream_idx_(stream_idx) {} 95 : adapter_(adapter), stream_idx_(stream_idx) {}
107 96
108 EncodedImageCallback::Result OnEncodedImage( 97 EncodedImageCallback::Result OnEncodedImage(
109 const webrtc::EncodedImage& encoded_image, 98 const webrtc::EncodedImage& encoded_image,
110 const webrtc::CodecSpecificInfo* codec_specific_info, 99 const webrtc::CodecSpecificInfo* codec_specific_info,
111 const webrtc::RTPFragmentationHeader* fragmentation) override { 100 const webrtc::RTPFragmentationHeader* fragmentation) override {
112 return adapter_->OnEncodedImage(stream_idx_, encoded_image, 101 return adapter_->OnEncodedImage(stream_idx_, encoded_image,
113 codec_specific_info, fragmentation); 102 codec_specific_info, fragmentation);
114 } 103 }
115 104
116 private: 105 private:
117 webrtc::SimulcastEncoderAdapter* const adapter_; 106 webrtc::SimulcastEncoderAdapter* const adapter_;
118 const size_t stream_idx_; 107 const size_t stream_idx_;
119 }; 108 };
120 109
110 // Utility class used to adapt the simulcast id as reported by the temporal
111 // layers factory, since each sub-encoder will report stream 0.
112 class TemporalLayersFactoryAdapter : public webrtc::TemporalLayersFactory {
113 public:
114 TemporalLayersFactoryAdapter(int adapted_simulcast_id,
115 const TemporalLayersFactory& tl_factory)
116 : adapted_simulcast_id_(adapted_simulcast_id), tl_factory_(tl_factory) {}
117 ~TemporalLayersFactoryAdapter() override {}
118 webrtc::TemporalLayers* Create(int simulcast_id,
119 int temporal_layers,
120 uint8_t initial_tl0_pic_idx) const override {
121 return tl_factory_.Create(adapted_simulcast_id_, temporal_layers,
122 initial_tl0_pic_idx);
123 }
124
125 const int adapted_simulcast_id_;
126 const TemporalLayersFactory& tl_factory_;
127 };
128
121 } // namespace 129 } // namespace
122 130
123 namespace webrtc { 131 namespace webrtc {
124 132
125 SimulcastEncoderAdapter::SimulcastEncoderAdapter(VideoEncoderFactory* factory) 133 SimulcastEncoderAdapter::SimulcastEncoderAdapter(VideoEncoderFactory* factory)
126 : factory_(factory), 134 : factory_(factory),
127 encoded_complete_callback_(nullptr), 135 encoded_complete_callback_(nullptr),
128 implementation_name_("SimulcastEncoderAdapter") { 136 implementation_name_("SimulcastEncoderAdapter") {
129 memset(&codec_, 0, sizeof(webrtc::VideoCodec)); 137 memset(&codec_, 0, sizeof(webrtc::VideoCodec));
130 rate_allocator_.reset(new SimulcastRateAllocator(codec_));
131 } 138 }
132 139
133 SimulcastEncoderAdapter::~SimulcastEncoderAdapter() { 140 SimulcastEncoderAdapter::~SimulcastEncoderAdapter() {
134 Release(); 141 Release();
135 } 142 }
136 143
137 int SimulcastEncoderAdapter::Release() { 144 int SimulcastEncoderAdapter::Release() {
138 // TODO(pbos): Keep the last encoder instance but call ::Release() on it, then 145 // TODO(pbos): Keep the last encoder instance but call ::Release() on it, then
139 // re-use this instance in ::InitEncode(). This means that changing 146 // re-use this instance in ::InitEncode(). This means that changing
140 // resolutions doesn't require reallocation of the first encoder, but only 147 // resolutions doesn't require reallocation of the first encoder, but only
(...skipping 27 matching lines...) Expand all
168 } 175 }
169 176
170 int number_of_streams = NumberOfStreams(*inst); 177 int number_of_streams = NumberOfStreams(*inst);
171 const bool doing_simulcast = (number_of_streams > 1); 178 const bool doing_simulcast = (number_of_streams > 1);
172 179
173 if (doing_simulcast && !ValidSimulcastResolutions(*inst, number_of_streams)) { 180 if (doing_simulcast && !ValidSimulcastResolutions(*inst, number_of_streams)) {
174 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; 181 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
175 } 182 }
176 183
177 codec_ = *inst; 184 codec_ = *inst;
178 rate_allocator_.reset(new SimulcastRateAllocator(codec_)); 185 SimulcastRateAllocator rate_allocator(codec_, nullptr);
179 std::vector<uint32_t> start_bitrates = 186 BitrateAllocation allocation = rate_allocator.GetAllocation(
180 rate_allocator_->GetAllocation(codec_.startBitrate); 187 codec_.startBitrate * 1000, codec_.maxFramerate);
181 188 std::vector<uint32_t> start_bitrates;
182 // Special mode when screensharing on a single stream. 189 for (int i = 0; i < kMaxSimulcastStreams; ++i) {
183 if (number_of_streams == 1 && inst->mode == kScreensharing) { 190 uint32_t stream_bitrate = allocation.GetSpatialLayerSum(i) / 1000;
184 screensharing_tl_factory_.reset(new ScreenshareTemporalLayersFactory()); 191 start_bitrates.push_back(stream_bitrate);
185 codec_.codecSpecific.VP8.tl_factory = screensharing_tl_factory_.get();
186 } 192 }
187 193
188 std::string implementation_name; 194 std::string implementation_name;
189 // Create |number_of_streams| of encoder instances and init them. 195 // Create |number_of_streams| of encoder instances and init them.
190 for (int i = 0; i < number_of_streams; ++i) { 196 for (int i = 0; i < number_of_streams; ++i) {
191 VideoCodec stream_codec; 197 VideoCodec stream_codec;
192 uint32_t start_bitrate_kbps = start_bitrates[i]; 198 uint32_t start_bitrate_kbps = start_bitrates[i];
193 if (!doing_simulcast) { 199 if (!doing_simulcast) {
194 stream_codec = codec_; 200 stream_codec = codec_;
195 stream_codec.numberOfSimulcastStreams = 1; 201 stream_codec.numberOfSimulcastStreams = 1;
196 } else { 202 } else {
197 // Cap start bitrate to the min bitrate in order to avoid strange codec 203 // 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. 204 // behavior. Since sending sending will be false, this should not matter.
199 start_bitrate_kbps = 205 start_bitrate_kbps =
200 std::max(codec_.simulcastStream[i].minBitrate, start_bitrate_kbps); 206 std::max(codec_.simulcastStream[i].minBitrate, start_bitrate_kbps);
201 bool highest_resolution_stream = (i == (number_of_streams - 1)); 207 bool highest_resolution_stream = (i == (number_of_streams - 1));
202 PopulateStreamCodec(&codec_, i, start_bitrate_kbps, 208 PopulateStreamCodec(&codec_, i, start_bitrate_kbps,
203 highest_resolution_stream, &stream_codec); 209 highest_resolution_stream, &stream_codec);
204 } 210 }
211 TemporalLayersFactoryAdapter tl_factory_adapter(
212 i, *codec_.codecSpecific.VP8.tl_factory);
213 stream_codec.codecSpecific.VP8.tl_factory = &tl_factory_adapter;
205 214
206 // TODO(ronghuawu): Remove once this is handled in VP8EncoderImpl. 215 // TODO(ronghuawu): Remove once this is handled in VP8EncoderImpl.
207 if (stream_codec.qpMax < kDefaultMinQp) { 216 if (stream_codec.qpMax < kDefaultMinQp) {
208 stream_codec.qpMax = kDefaultMaxQp; 217 stream_codec.qpMax = kDefaultMaxQp;
209 } 218 }
210 219
211 VideoEncoder* encoder = factory_->Create(); 220 VideoEncoder* encoder = factory_->Create();
212 ret = encoder->InitEncode(&stream_codec, number_of_cores, max_payload_size); 221 ret = encoder->InitEncode(&stream_codec, number_of_cores, max_payload_size);
213 if (ret < 0) { 222 if (ret < 0) {
214 Release(); 223 Release();
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
335 } 344 }
336 345
337 int SimulcastEncoderAdapter::SetChannelParameters(uint32_t packet_loss, 346 int SimulcastEncoderAdapter::SetChannelParameters(uint32_t packet_loss,
338 int64_t rtt) { 347 int64_t rtt) {
339 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) { 348 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
340 streaminfos_[stream_idx].encoder->SetChannelParameters(packet_loss, rtt); 349 streaminfos_[stream_idx].encoder->SetChannelParameters(packet_loss, rtt);
341 } 350 }
342 return WEBRTC_VIDEO_CODEC_OK; 351 return WEBRTC_VIDEO_CODEC_OK;
343 } 352 }
344 353
345 int SimulcastEncoderAdapter::SetRates(uint32_t new_bitrate_kbit, 354 int SimulcastEncoderAdapter::SetRateAllocation(const BitrateAllocation& bitrate,
346 uint32_t new_framerate) { 355 uint32_t new_framerate) {
347 if (!Initialized()) { 356 if (!Initialized())
348 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; 357 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
349 } 358
350 if (new_framerate < 1) { 359 if (new_framerate < 1)
351 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; 360 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
352 } 361
353 if (codec_.maxBitrate > 0 && new_bitrate_kbit > codec_.maxBitrate) { 362 if (codec_.maxBitrate > 0 && bitrate.get_sum_kbps() > codec_.maxBitrate)
354 new_bitrate_kbit = codec_.maxBitrate; 363 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
364
365 if (bitrate.get_sum_bps() > 0) {
366 // Make sure the bitrate fits the configured min bitrates. 0 is a special
367 // value that means paused, though, so leave it alone.
368 if (bitrate.get_sum_kbps() < codec_.minBitrate)
369 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
370
371 if (codec_.numberOfSimulcastStreams > 0 &&
372 bitrate.get_sum_kbps() < codec_.simulcastStream[0].minBitrate) {
373 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
374 }
355 } 375 }
356 376
357 std::vector<uint32_t> stream_bitrates;
358 if (new_bitrate_kbit > 0) {
359 // Make sure the bitrate fits the configured min bitrates. 0 is a special
360 // value that means paused, though, so leave it alone.
361 if (new_bitrate_kbit < codec_.minBitrate) {
362 new_bitrate_kbit = codec_.minBitrate;
363 }
364 if (codec_.numberOfSimulcastStreams > 0 &&
365 new_bitrate_kbit < codec_.simulcastStream[0].minBitrate) {
366 new_bitrate_kbit = codec_.simulcastStream[0].minBitrate;
367 }
368 stream_bitrates = rate_allocator_->GetAllocation(new_bitrate_kbit);
369 }
370 codec_.maxFramerate = new_framerate; 377 codec_.maxFramerate = new_framerate;
371 378
372 // Disable any stream not in the current allocation. 379 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
373 stream_bitrates.resize(streaminfos_.size(), 0U); 380 uint32_t stream_bitrate_kbps =
381 bitrate.GetSpatialLayerSum(stream_idx) / 1000;
374 382
375 for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
376 uint32_t stream_bitrate_kbps = stream_bitrates[stream_idx];
377 // Need a key frame if we have not sent this stream before. 383 // Need a key frame if we have not sent this stream before.
378 if (stream_bitrate_kbps > 0 && !streaminfos_[stream_idx].send_stream) { 384 if (stream_bitrate_kbps > 0 && !streaminfos_[stream_idx].send_stream) {
379 streaminfos_[stream_idx].key_frame_request = true; 385 streaminfos_[stream_idx].key_frame_request = true;
380 } 386 }
381 streaminfos_[stream_idx].send_stream = stream_bitrate_kbps > 0; 387 streaminfos_[stream_idx].send_stream = stream_bitrate_kbps > 0;
382 388
383 // TODO(holmer): This is a temporary hack for screensharing, where we 389 // Slice the temporal layers out of the full allocation and pass it on to
384 // interpret the startBitrate as the encoder target bitrate. This is 390 // the encoder handling the current simulcast stream.
385 // to allow for a different max bitrate, so if the codec can't meet 391 BitrateAllocation stream_allocation;
386 // the target we still allow it to overshoot up to the max before dropping 392 for (int i = 0; i < kMaxTemporalStreams; ++i)
387 // frames. This hack should be improved. 393 stream_allocation.SetBitrate(0, i, bitrate.GetBitrate(stream_idx, i));
388 if (codec_.targetBitrate > 0 && 394 streaminfos_[stream_idx].encoder->SetRateAllocation(stream_allocation,
389 (codec_.codecSpecific.VP8.numberOfTemporalLayers == 2 || 395 new_framerate);
390 codec_.simulcastStream[0].numberOfTemporalLayers == 2)) {
391 stream_bitrate_kbps = std::min(codec_.maxBitrate, stream_bitrate_kbps);
392 // TODO(ronghuawu): Can't change max bitrate via the VideoEncoder
393 // interface. And VP8EncoderImpl doesn't take negative framerate.
394 // max_bitrate = std::min(codec_.maxBitrate, stream_bitrate_kbps);
395 // new_framerate = -1;
396 }
397
398 streaminfos_[stream_idx].encoder->SetRates(stream_bitrate_kbps,
399 new_framerate);
400 } 396 }
401 397
402 return WEBRTC_VIDEO_CODEC_OK; 398 return WEBRTC_VIDEO_CODEC_OK;
403 } 399 }
404 400
405 EncodedImageCallback::Result SimulcastEncoderAdapter::OnEncodedImage( 401 EncodedImageCallback::Result SimulcastEncoderAdapter::OnEncodedImage(
406 size_t stream_idx, 402 size_t stream_idx,
407 const EncodedImage& encodedImage, 403 const EncodedImage& encodedImage,
408 const CodecSpecificInfo* codecSpecificInfo, 404 const CodecSpecificInfo* codecSpecificInfo,
409 const RTPFragmentationHeader* fragmentation) { 405 const RTPFragmentationHeader* fragmentation) {
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
469 return false; 465 return false;
470 } 466 }
471 return true; 467 return true;
472 } 468 }
473 469
474 const char* SimulcastEncoderAdapter::ImplementationName() const { 470 const char* SimulcastEncoderAdapter::ImplementationName() const {
475 return implementation_name_.c_str(); 471 return implementation_name_.c_str();
476 } 472 }
477 473
478 } // namespace webrtc 474 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698