- Two quality layers (same resolution, different bitrate). - Max bitrate of low layer is limited to 200kbps. The choice of the limit is driven by VP8 screen sharing which limits max bitrate of low temporal layer to 200kbps. Using the same value for VP9 guarantees that there will be no regressions for participants with limited bandwidth. - Max bitrate of high layer is limited to 500kbps. According to test results this value is enough to get up to +5dB higher PSNR than VP8 SS provides on 1.2Mbps (max total bitrate for VP8 SS) link. - Max total sent bitrate is limited to 700kbps. It is 500kbps lower than that in VP8 SS (1200kbps). Bug: webrtc:9261 Change-Id: I7919cc3933064664567c39e380a44cad0c65f1e8 Reviewed-on: https://webrtc-review.googlesource.com/76380 Commit-Queue: Sergey Silkin <ssilkin@webrtc.org> Reviewed-by: Erik Språng <sprang@webrtc.org> Cr-Commit-Position: refs/heads/master@{#23226}
114 lines
4.5 KiB
C++
114 lines
4.5 KiB
C++
/*
|
|
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
#include "modules/video_coding/codecs/vp9/svc_config.h"
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <vector>
|
|
|
|
#include "modules/video_coding/include/video_codec_interface.h"
|
|
|
|
namespace webrtc {
|
|
|
|
namespace {
|
|
const size_t kMinVp9SvcBitrateKbps = 30;
|
|
|
|
const size_t kMaxNumLayersForScreenSharing = 2;
|
|
const size_t kMaxScreenSharingLayerBitrateKbps[] = {200, 500};
|
|
} // namespace
|
|
|
|
std::vector<SpatialLayer> ConfigureSvcScreenSharing(size_t input_width,
|
|
size_t input_height,
|
|
size_t num_spatial_layers) {
|
|
num_spatial_layers =
|
|
std::min(num_spatial_layers, kMaxNumLayersForScreenSharing);
|
|
std::vector<SpatialLayer> spatial_layers;
|
|
|
|
for (size_t sl_idx = 0; sl_idx < num_spatial_layers; ++sl_idx) {
|
|
SpatialLayer spatial_layer = {0};
|
|
spatial_layer.width = input_width;
|
|
spatial_layer.height = input_height;
|
|
spatial_layer.numberOfTemporalLayers = 1;
|
|
spatial_layer.minBitrate = static_cast<int>(kMinVp9SvcBitrateKbps);
|
|
spatial_layer.maxBitrate =
|
|
static_cast<int>(kMaxScreenSharingLayerBitrateKbps[sl_idx]);
|
|
spatial_layer.targetBitrate = spatial_layer.maxBitrate;
|
|
spatial_layers.push_back(spatial_layer);
|
|
}
|
|
|
|
return spatial_layers;
|
|
}
|
|
|
|
std::vector<SpatialLayer> ConfigureSvcNormalVideo(size_t input_width,
|
|
size_t input_height,
|
|
size_t num_spatial_layers,
|
|
size_t num_temporal_layers) {
|
|
std::vector<SpatialLayer> spatial_layers;
|
|
|
|
// Limit number of layers for given resolution.
|
|
const size_t num_layers_fit_horz = static_cast<size_t>(std::floor(
|
|
1 + std::max(0.0f,
|
|
std::log2(1.0f * input_width / kMinVp9SpatialLayerWidth))));
|
|
const size_t num_layers_fit_vert = static_cast<size_t>(
|
|
std::floor(1 + std::max(0.0f, std::log2(1.0f * input_height /
|
|
kMinVp9SpatialLayerHeight))));
|
|
num_spatial_layers =
|
|
std::min({num_spatial_layers, num_layers_fit_horz, num_layers_fit_vert});
|
|
|
|
for (size_t sl_idx = 0; sl_idx < num_spatial_layers; ++sl_idx) {
|
|
SpatialLayer spatial_layer = {0};
|
|
spatial_layer.width = input_width >> (num_spatial_layers - sl_idx - 1);
|
|
spatial_layer.height = input_height >> (num_spatial_layers - sl_idx - 1);
|
|
spatial_layer.numberOfTemporalLayers = num_temporal_layers;
|
|
|
|
// minBitrate and maxBitrate formulas were derived from
|
|
// subjective-quality data to determing bit rates below which video
|
|
// quality is unacceptable and above which additional bits do not provide
|
|
// benefit. The formulas express rate in units of kbps.
|
|
|
|
// TODO(ssilkin): Add to the comment PSNR/SSIM we get at encoding certain
|
|
// video to min/max bitrate specified by those formulas.
|
|
const size_t num_pixels = spatial_layer.width * spatial_layer.height;
|
|
const size_t min_bitrate =
|
|
static_cast<int>((600. * std::sqrt(num_pixels) - 95000.) / 1000.);
|
|
spatial_layer.minBitrate = std::max(min_bitrate, kMinVp9SvcBitrateKbps);
|
|
spatial_layer.maxBitrate =
|
|
static_cast<int>((1.6 * num_pixels + 50 * 1000) / 1000);
|
|
spatial_layer.targetBitrate =
|
|
(spatial_layer.maxBitrate + spatial_layer.minBitrate) / 2;
|
|
|
|
spatial_layers.push_back(spatial_layer);
|
|
}
|
|
|
|
return spatial_layers;
|
|
}
|
|
|
|
std::vector<SpatialLayer> GetSvcConfig(size_t input_width,
|
|
size_t input_height,
|
|
size_t num_spatial_layers,
|
|
size_t num_temporal_layers,
|
|
bool is_screen_sharing) {
|
|
RTC_DCHECK_GT(input_width, 0);
|
|
RTC_DCHECK_GT(input_height, 0);
|
|
RTC_DCHECK_GT(num_spatial_layers, 0);
|
|
RTC_DCHECK_GT(num_temporal_layers, 0);
|
|
|
|
if (is_screen_sharing) {
|
|
return ConfigureSvcScreenSharing(input_width, input_height,
|
|
num_spatial_layers);
|
|
} else {
|
|
return ConfigureSvcNormalVideo(input_width, input_height,
|
|
num_spatial_layers, num_temporal_layers);
|
|
}
|
|
}
|
|
|
|
} // namespace webrtc
|