OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | |
3 * | |
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 | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #include "webrtc/modules/video_coding/include/video_codec_initializer.h" | |
12 | |
13 #include "webrtc/base/basictypes.h" | |
14 #include "webrtc/common_video/include/video_bitrate_allocator.h" | |
15 #include "webrtc/common_types.h" | |
16 #include "webrtc/modules/video_coding/codecs/vp8/screenshare_layers.h" | |
17 #include "webrtc/modules/video_coding/codecs/vp8/temporal_layers.h" | |
18 #include "webrtc/modules/video_coding/utility/simulcast_rate_allocator.h" | |
19 #include "webrtc/modules/video_coding/utility/default_video_bitrate_allocator.h" | |
20 #include "webrtc/system_wrappers/include/clock.h" | |
21 | |
22 namespace webrtc { | |
23 | |
24 struct ScreenshareTemporalLayersFactory : webrtc::TemporalLayersFactory { | |
25 ScreenshareTemporalLayersFactory() {} | |
26 virtual ~ScreenshareTemporalLayersFactory() {} | |
27 | |
28 virtual webrtc::TemporalLayers* Create(int simulcast_id, | |
29 int num_temporal_layers, | |
30 uint8_t initial_tl0_pic_idx) const { | |
31 webrtc::TemporalLayers* tl = new webrtc::ScreenshareLayers( | |
32 num_temporal_layers, rand(), webrtc::Clock::GetRealTimeClock()); | |
33 if (listener_) | |
34 listener_->OnTemporalLayersCreated(simulcast_id, tl); | |
35 return tl; | |
36 } | |
37 }; | |
38 | |
39 bool VideoCodecInitializer::SetupCodec( | |
40 const VideoEncoderConfig& config, | |
41 const VideoSendStream::Config::EncoderSettings settings, | |
42 const std::vector<VideoStream>& streams, | |
43 VideoCodec* codec, | |
44 std::unique_ptr<VideoBitrateAllocator>* bitrate_allocator) { | |
45 *codec = VideoEncoderConfigToVideoCodec( | |
46 config, streams, settings.payload_name, settings.payload_type); | |
47 | |
48 std::unique_ptr<TemporalLayersFactory> tl_factory; | |
49 switch (codec->codecType) { | |
50 case kVideoCodecVP8: { | |
51 if (!codec->VP8()->tl_factory) { | |
52 if (codec->mode == kScreensharing && | |
53 codec->numberOfSimulcastStreams == 1 && | |
54 codec->VP8()->numberOfTemporalLayers == 2) { | |
55 // Conference mode temporal layering for screen content. | |
56 tl_factory.reset(new ScreenshareTemporalLayersFactory()); | |
57 } else { | |
58 // Standard video temporal layers. | |
59 tl_factory.reset(new TemporalLayersFactory()); | |
60 } | |
61 codec->VP8()->tl_factory = tl_factory.get(); | |
62 } | |
63 break; | |
64 } | |
65 default: { | |
66 // TODO(sprang): Warn, once we have specific allocators for all supported | |
67 // codec types. | |
68 break; | |
69 } | |
70 } | |
71 *bitrate_allocator = CreateBitrateAllocator(*codec, std::move(tl_factory)); | |
72 | |
73 return true; | |
74 } | |
75 | |
76 std::unique_ptr<VideoBitrateAllocator> | |
77 VideoCodecInitializer::CreateBitrateAllocator( | |
78 const VideoCodec& codec, | |
79 std::unique_ptr<TemporalLayersFactory> tl_factory) { | |
80 std::unique_ptr<VideoBitrateAllocator> rate_allocator; | |
81 | |
82 switch (codec.codecType) { | |
83 case kVideoCodecVP8: { | |
84 // Set up default VP8 temporal layer factory, if not provided. | |
85 rate_allocator.reset( | |
86 new SimulcastRateAllocator(codec, std::move(tl_factory))); | |
87 } break; | |
88 default: | |
89 rate_allocator.reset(new DefaultVideoBitrateAllocator(codec)); | |
90 } | |
91 | |
92 return rate_allocator; | |
93 } | |
94 | |
95 // TODO(sprang): Split this up and separate the codec specific parts. | |
96 VideoCodec VideoCodecInitializer::VideoEncoderConfigToVideoCodec( | |
97 const VideoEncoderConfig& config, | |
98 const std::vector<VideoStream>& streams, | |
99 const std::string& payload_name, | |
100 int payload_type) { | |
101 static const int kEncoderMinBitrateKbps = 30; | |
102 RTC_DCHECK(!streams.empty()); | |
103 RTC_DCHECK_GE(config.min_transmit_bitrate_bps, 0); | |
104 | |
105 VideoCodec video_codec; | |
106 memset(&video_codec, 0, sizeof(video_codec)); | |
107 video_codec.codecType = PayloadNameToCodecType(payload_name) | |
108 .value_or(VideoCodecType::kVideoCodecGeneric); | |
109 | |
110 switch (config.content_type) { | |
111 case VideoEncoderConfig::ContentType::kRealtimeVideo: | |
112 video_codec.mode = kRealtimeVideo; | |
113 break; | |
114 case VideoEncoderConfig::ContentType::kScreen: | |
115 video_codec.mode = kScreensharing; | |
116 if (streams.size() == 1 && | |
117 streams[0].temporal_layer_thresholds_bps.size() == 1) { | |
118 video_codec.targetBitrate = | |
119 streams[0].temporal_layer_thresholds_bps[0] / 1000; | |
120 } | |
121 break; | |
122 } | |
123 | |
124 if (config.encoder_specific_settings) | |
125 config.encoder_specific_settings->FillEncoderSpecificSettings(&video_codec); | |
126 | |
127 switch (video_codec.codecType) { | |
128 case kVideoCodecVP8: { | |
129 if (!config.encoder_specific_settings) | |
130 video_codec.codecSpecific.VP8 = VideoEncoder::GetDefaultVp8Settings(); | |
131 video_codec.codecSpecific.VP8.numberOfTemporalLayers = | |
132 static_cast<unsigned char>( | |
133 streams.back().temporal_layer_thresholds_bps.size() + 1); | |
134 break; | |
135 } | |
136 case kVideoCodecVP9: { | |
137 if (!config.encoder_specific_settings) | |
138 video_codec.codecSpecific.VP9 = VideoEncoder::GetDefaultVp9Settings(); | |
139 if (video_codec.mode == kScreensharing && | |
140 config.encoder_specific_settings) { | |
141 video_codec.codecSpecific.VP9.flexibleMode = true; | |
142 // For now VP9 screensharing use 1 temporal and 2 spatial layers. | |
143 RTC_DCHECK_EQ(1, video_codec.codecSpecific.VP9.numberOfTemporalLayers); | |
144 RTC_DCHECK_EQ(2, video_codec.codecSpecific.VP9.numberOfSpatialLayers); | |
145 } | |
146 video_codec.codecSpecific.VP9.numberOfTemporalLayers = | |
147 static_cast<unsigned char>( | |
148 streams.back().temporal_layer_thresholds_bps.size() + 1); | |
149 break; | |
150 } | |
151 case kVideoCodecH264: { | |
152 if (!config.encoder_specific_settings) | |
153 video_codec.codecSpecific.H264 = VideoEncoder::GetDefaultH264Settings(); | |
154 break; | |
155 } | |
156 default: | |
157 // TODO(pbos): Support encoder_settings codec-agnostically. | |
158 RTC_DCHECK(!config.encoder_specific_settings) | |
159 << "Encoder-specific settings for codec type not wired up."; | |
160 break; | |
161 } | |
162 | |
163 strncpy(video_codec.plName, payload_name.c_str(), kPayloadNameSize - 1); | |
164 video_codec.plName[kPayloadNameSize - 1] = '\0'; | |
165 video_codec.plType = payload_type; | |
166 video_codec.numberOfSimulcastStreams = | |
167 static_cast<unsigned char>(streams.size()); | |
168 video_codec.minBitrate = streams[0].min_bitrate_bps / 1000; | |
169 if (video_codec.minBitrate < kEncoderMinBitrateKbps) | |
170 video_codec.minBitrate = kEncoderMinBitrateKbps; | |
171 RTC_DCHECK_LE(streams.size(), static_cast<size_t>(kMaxSimulcastStreams)); | |
172 if (video_codec.codecType == kVideoCodecVP9) { | |
173 // If the vector is empty, bitrates will be configured automatically. | |
174 RTC_DCHECK(config.spatial_layers.empty() || | |
175 config.spatial_layers.size() == | |
176 video_codec.codecSpecific.VP9.numberOfSpatialLayers); | |
177 RTC_DCHECK_LE(video_codec.codecSpecific.VP9.numberOfSpatialLayers, | |
178 kMaxSimulcastStreams); | |
179 for (size_t i = 0; i < config.spatial_layers.size(); ++i) | |
180 video_codec.spatialLayers[i] = config.spatial_layers[i]; | |
181 } | |
182 for (size_t i = 0; i < streams.size(); ++i) { | |
183 SimulcastStream* sim_stream = &video_codec.simulcastStream[i]; | |
184 RTC_DCHECK_GT(streams[i].width, 0u); | |
185 RTC_DCHECK_GT(streams[i].height, 0u); | |
186 RTC_DCHECK_GT(streams[i].max_framerate, 0); | |
187 // Different framerates not supported per stream at the moment. | |
188 RTC_DCHECK_EQ(streams[i].max_framerate, streams[0].max_framerate); | |
189 RTC_DCHECK_GE(streams[i].min_bitrate_bps, 0); | |
190 RTC_DCHECK_GE(streams[i].target_bitrate_bps, streams[i].min_bitrate_bps); | |
191 RTC_DCHECK_GE(streams[i].max_bitrate_bps, streams[i].target_bitrate_bps); | |
192 RTC_DCHECK_GE(streams[i].max_qp, 0); | |
193 | |
194 sim_stream->width = static_cast<uint16_t>(streams[i].width); | |
195 sim_stream->height = static_cast<uint16_t>(streams[i].height); | |
196 sim_stream->minBitrate = streams[i].min_bitrate_bps / 1000; | |
197 sim_stream->targetBitrate = streams[i].target_bitrate_bps / 1000; | |
198 sim_stream->maxBitrate = streams[i].max_bitrate_bps / 1000; | |
199 sim_stream->qpMax = streams[i].max_qp; | |
200 sim_stream->numberOfTemporalLayers = static_cast<unsigned char>( | |
201 streams[i].temporal_layer_thresholds_bps.size() + 1); | |
202 | |
203 video_codec.width = | |
204 std::max(video_codec.width, static_cast<uint16_t>(streams[i].width)); | |
205 video_codec.height = | |
206 std::max(video_codec.height, static_cast<uint16_t>(streams[i].height)); | |
207 video_codec.minBitrate = | |
208 std::min(static_cast<uint16_t>(video_codec.minBitrate), | |
209 static_cast<uint16_t>(streams[i].min_bitrate_bps / 1000)); | |
210 video_codec.maxBitrate += streams[i].max_bitrate_bps / 1000; | |
211 video_codec.qpMax = std::max(video_codec.qpMax, | |
212 static_cast<unsigned int>(streams[i].max_qp)); | |
213 } | |
214 | |
215 if (video_codec.maxBitrate == 0) { | |
216 // Unset max bitrate -> cap to one bit per pixel. | |
217 video_codec.maxBitrate = | |
218 (video_codec.width * video_codec.height * video_codec.maxFramerate) / | |
219 1000; | |
220 } | |
221 if (video_codec.maxBitrate < kEncoderMinBitrateKbps) | |
222 video_codec.maxBitrate = kEncoderMinBitrateKbps; | |
223 | |
224 RTC_DCHECK_GT(streams[0].max_framerate, 0); | |
225 video_codec.maxFramerate = streams[0].max_framerate; | |
226 return video_codec; | |
227 } | |
228 | |
229 } // namespace webrtc | |
OLD | NEW |