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 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |