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