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