blob: c759e84a36d8bd19db81cff0af6e291d2f204daa [file] [log] [blame]
Erik Språng08127a92016-11-16 16:41:30 +01001/*
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
Erik Språng08127a92016-11-16 16:41:30 +010013#include "webrtc/common_types.h"
ilnik04f4d122017-06-19 07:18:55 -070014#include "webrtc/common_video/include/video_bitrate_allocator.h"
Erik Språng08127a92016-11-16 16:41:30 +010015#include "webrtc/modules/video_coding/codecs/vp8/screenshare_layers.h"
kjellandera8d8aad2017-03-08 05:42:26 -080016#include "webrtc/modules/video_coding/codecs/vp8/simulcast_rate_allocator.h"
Erik Språng08127a92016-11-16 16:41:30 +010017#include "webrtc/modules/video_coding/codecs/vp8/temporal_layers.h"
ilnik04f4d122017-06-19 07:18:55 -070018#include "webrtc/modules/video_coding/include/video_coding_defines.h"
Erik Språng08127a92016-11-16 16:41:30 +010019#include "webrtc/modules/video_coding/utility/default_video_bitrate_allocator.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020020#include "webrtc/rtc_base/basictypes.h"
21#include "webrtc/rtc_base/logging.h"
Erik Språng08127a92016-11-16 16:41:30 +010022#include "webrtc/system_wrappers/include/clock.h"
23
24namespace webrtc {
25
26bool VideoCodecInitializer::SetupCodec(
27 const VideoEncoderConfig& config,
28 const VideoSendStream::Config::EncoderSettings settings,
29 const std::vector<VideoStream>& streams,
asapersson5f7226f2016-11-25 04:37:00 -080030 bool nack_enabled,
Erik Språng08127a92016-11-16 16:41:30 +010031 VideoCodec* codec,
32 std::unique_ptr<VideoBitrateAllocator>* bitrate_allocator) {
asapersson5f7226f2016-11-25 04:37:00 -080033 *codec =
34 VideoEncoderConfigToVideoCodec(config, streams, settings.payload_name,
35 settings.payload_type, nack_enabled);
Erik Språng08127a92016-11-16 16:41:30 +010036
37 std::unique_ptr<TemporalLayersFactory> tl_factory;
38 switch (codec->codecType) {
39 case kVideoCodecVP8: {
40 if (!codec->VP8()->tl_factory) {
41 if (codec->mode == kScreensharing &&
sprang429600d2017-01-26 06:12:26 -080042 (codec->numberOfSimulcastStreams > 1 ||
43 (codec->numberOfSimulcastStreams == 1 &&
44 codec->VP8()->numberOfTemporalLayers == 2))) {
Erik Språng08127a92016-11-16 16:41:30 +010045 // Conference mode temporal layering for screen content.
46 tl_factory.reset(new ScreenshareTemporalLayersFactory());
47 } else {
48 // Standard video temporal layers.
49 tl_factory.reset(new TemporalLayersFactory());
50 }
51 codec->VP8()->tl_factory = tl_factory.get();
52 }
53 break;
54 }
55 default: {
56 // TODO(sprang): Warn, once we have specific allocators for all supported
57 // codec types.
58 break;
59 }
60 }
61 *bitrate_allocator = CreateBitrateAllocator(*codec, std::move(tl_factory));
62
63 return true;
64}
65
66std::unique_ptr<VideoBitrateAllocator>
67VideoCodecInitializer::CreateBitrateAllocator(
68 const VideoCodec& codec,
69 std::unique_ptr<TemporalLayersFactory> tl_factory) {
70 std::unique_ptr<VideoBitrateAllocator> rate_allocator;
71
72 switch (codec.codecType) {
73 case kVideoCodecVP8: {
74 // Set up default VP8 temporal layer factory, if not provided.
75 rate_allocator.reset(
76 new SimulcastRateAllocator(codec, std::move(tl_factory)));
77 } break;
78 default:
79 rate_allocator.reset(new DefaultVideoBitrateAllocator(codec));
80 }
81
82 return rate_allocator;
83}
84
85// TODO(sprang): Split this up and separate the codec specific parts.
86VideoCodec VideoCodecInitializer::VideoEncoderConfigToVideoCodec(
87 const VideoEncoderConfig& config,
88 const std::vector<VideoStream>& streams,
89 const std::string& payload_name,
asapersson5f7226f2016-11-25 04:37:00 -080090 int payload_type,
91 bool nack_enabled) {
Erik Språng08127a92016-11-16 16:41:30 +010092 static const int kEncoderMinBitrateKbps = 30;
93 RTC_DCHECK(!streams.empty());
94 RTC_DCHECK_GE(config.min_transmit_bitrate_bps, 0);
95
96 VideoCodec video_codec;
97 memset(&video_codec, 0, sizeof(video_codec));
98 video_codec.codecType = PayloadNameToCodecType(payload_name)
99 .value_or(VideoCodecType::kVideoCodecGeneric);
100
101 switch (config.content_type) {
102 case VideoEncoderConfig::ContentType::kRealtimeVideo:
103 video_codec.mode = kRealtimeVideo;
104 break;
105 case VideoEncoderConfig::ContentType::kScreen:
106 video_codec.mode = kScreensharing;
aleloi47037412017-01-26 07:57:15 -0800107 if (!streams.empty() &&
Erik Språng08127a92016-11-16 16:41:30 +0100108 streams[0].temporal_layer_thresholds_bps.size() == 1) {
109 video_codec.targetBitrate =
110 streams[0].temporal_layer_thresholds_bps[0] / 1000;
111 }
112 break;
113 }
114
115 if (config.encoder_specific_settings)
116 config.encoder_specific_settings->FillEncoderSpecificSettings(&video_codec);
117
118 switch (video_codec.codecType) {
119 case kVideoCodecVP8: {
120 if (!config.encoder_specific_settings)
121 *video_codec.VP8() = VideoEncoder::GetDefaultVp8Settings();
122 video_codec.VP8()->numberOfTemporalLayers = static_cast<unsigned char>(
123 streams.back().temporal_layer_thresholds_bps.size() + 1);
emircan7b532db2017-08-17 18:20:40 -0700124 bool temporal_layers_configured = false;
125 for (const VideoStream& stream : streams) {
126 if (stream.temporal_layer_thresholds_bps.size() > 0)
127 temporal_layers_configured = true;
128 }
129 if (nack_enabled && !temporal_layers_configured) {
asapersson5f7226f2016-11-25 04:37:00 -0800130 LOG(LS_INFO) << "No temporal layers and nack enabled -> resilience off";
131 video_codec.VP8()->resilience = kResilienceOff;
132 }
Erik Språng08127a92016-11-16 16:41:30 +0100133 break;
134 }
135 case kVideoCodecVP9: {
136 if (!config.encoder_specific_settings)
137 *video_codec.VP9() = VideoEncoder::GetDefaultVp9Settings();
138 if (video_codec.mode == kScreensharing &&
139 config.encoder_specific_settings) {
140 video_codec.VP9()->flexibleMode = true;
141 // For now VP9 screensharing use 1 temporal and 2 spatial layers.
142 RTC_DCHECK_EQ(1, video_codec.VP9()->numberOfTemporalLayers);
143 RTC_DCHECK_EQ(2, video_codec.VP9()->numberOfSpatialLayers);
144 }
145 video_codec.VP9()->numberOfTemporalLayers = static_cast<unsigned char>(
146 streams.back().temporal_layer_thresholds_bps.size() + 1);
147 break;
148 }
149 case kVideoCodecH264: {
150 if (!config.encoder_specific_settings)
151 *video_codec.H264() = VideoEncoder::GetDefaultH264Settings();
152 break;
153 }
154 default:
155 // TODO(pbos): Support encoder_settings codec-agnostically.
156 RTC_DCHECK(!config.encoder_specific_settings)
157 << "Encoder-specific settings for codec type not wired up.";
158 break;
159 }
160
161 strncpy(video_codec.plName, payload_name.c_str(), kPayloadNameSize - 1);
162 video_codec.plName[kPayloadNameSize - 1] = '\0';
163 video_codec.plType = payload_type;
164 video_codec.numberOfSimulcastStreams =
165 static_cast<unsigned char>(streams.size());
166 video_codec.minBitrate = streams[0].min_bitrate_bps / 1000;
167 if (video_codec.minBitrate < kEncoderMinBitrateKbps)
168 video_codec.minBitrate = kEncoderMinBitrateKbps;
ilnik04f4d122017-06-19 07:18:55 -0700169 video_codec.timing_frame_thresholds = {kDefaultTimingFramesDelayMs,
170 kDefaultOutlierFrameSizePercent};
kwiberg352444f2016-11-28 15:58:53 -0800171 RTC_DCHECK_LE(streams.size(), kMaxSimulcastStreams);
Erik Språng08127a92016-11-16 16:41:30 +0100172 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.VP9()->numberOfSpatialLayers);
177 RTC_DCHECK_LE(video_codec.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];
kwibergaf476c72016-11-28 15:21:39 -0800184 RTC_DCHECK_GT(streams[i].width, 0);
185 RTC_DCHECK_GT(streams[i].height, 0);
Erik Språng08127a92016-11-16 16:41:30 +0100186 RTC_DCHECK_GT(streams[i].max_framerate, 0);
sprang429600d2017-01-26 06:12:26 -0800187 // Different framerates not supported per stream at the moment, unless it's
188 // screenshare where there is an exception and a simulcast encoder adapter,
189 // which supports different framerates, is used instead.
190 if (config.content_type != VideoEncoderConfig::ContentType::kScreen) {
191 RTC_DCHECK_EQ(streams[i].max_framerate, streams[0].max_framerate);
192 }
Erik Språng08127a92016-11-16 16:41:30 +0100193 RTC_DCHECK_GE(streams[i].min_bitrate_bps, 0);
194 RTC_DCHECK_GE(streams[i].target_bitrate_bps, streams[i].min_bitrate_bps);
195 RTC_DCHECK_GE(streams[i].max_bitrate_bps, streams[i].target_bitrate_bps);
196 RTC_DCHECK_GE(streams[i].max_qp, 0);
197
198 sim_stream->width = static_cast<uint16_t>(streams[i].width);
199 sim_stream->height = static_cast<uint16_t>(streams[i].height);
200 sim_stream->minBitrate = streams[i].min_bitrate_bps / 1000;
201 sim_stream->targetBitrate = streams[i].target_bitrate_bps / 1000;
202 sim_stream->maxBitrate = streams[i].max_bitrate_bps / 1000;
203 sim_stream->qpMax = streams[i].max_qp;
204 sim_stream->numberOfTemporalLayers = static_cast<unsigned char>(
205 streams[i].temporal_layer_thresholds_bps.size() + 1);
206
207 video_codec.width =
208 std::max(video_codec.width, static_cast<uint16_t>(streams[i].width));
209 video_codec.height =
210 std::max(video_codec.height, static_cast<uint16_t>(streams[i].height));
211 video_codec.minBitrate =
212 std::min(static_cast<uint16_t>(video_codec.minBitrate),
213 static_cast<uint16_t>(streams[i].min_bitrate_bps / 1000));
214 video_codec.maxBitrate += streams[i].max_bitrate_bps / 1000;
215 video_codec.qpMax = std::max(video_codec.qpMax,
216 static_cast<unsigned int>(streams[i].max_qp));
217 }
218
219 if (video_codec.maxBitrate == 0) {
220 // Unset max bitrate -> cap to one bit per pixel.
221 video_codec.maxBitrate =
222 (video_codec.width * video_codec.height * video_codec.maxFramerate) /
223 1000;
224 }
225 if (video_codec.maxBitrate < kEncoderMinBitrateKbps)
226 video_codec.maxBitrate = kEncoderMinBitrateKbps;
227
228 RTC_DCHECK_GT(streams[0].max_framerate, 0);
229 video_codec.maxFramerate = streams[0].max_framerate;
230 return video_codec;
231}
232
233} // namespace webrtc