This is more logical way to remove inactive lower layers. Current way is to notify the encoder that the layer is inactive, then renumber layers at the packatization level. This Cl will allow to simplify libvpx vp9 encoder, svcRateAllocator and vp9 packetizer. Bug: webrtc:11319 Change-Id: Idf0bb30b729f5ecc97e31454b32934546b681aa2 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/173182 Commit-Queue: Ilya Nikolaevskiy <ilnik@webrtc.org> Reviewed-by: Henrik Boström <hbos@webrtc.org> Cr-Commit-Position: refs/heads/master@{#31058}
137 lines
5.8 KiB
C++
137 lines
5.8 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/codecs/vp9/include/vp9_globals.h"
|
|
#include "rtc_base/checks.h"
|
|
|
|
namespace webrtc {
|
|
|
|
namespace {
|
|
const size_t kMinVp9SvcBitrateKbps = 30;
|
|
|
|
const size_t kMaxNumLayersForScreenSharing = 3;
|
|
const float kMaxScreenSharingLayerFramerateFps[] = {5.0, 10.0, 30.0};
|
|
const size_t kMinScreenSharingLayerBitrateKbps[] = {30, 200, 500};
|
|
const size_t kTargetScreenSharingLayerBitrateKbps[] = {150, 350, 950};
|
|
const size_t kMaxScreenSharingLayerBitrateKbps[] = {250, 500, 950};
|
|
|
|
} // namespace
|
|
|
|
std::vector<SpatialLayer> ConfigureSvcScreenSharing(size_t input_width,
|
|
size_t input_height,
|
|
float max_framerate_fps,
|
|
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.maxFramerate =
|
|
std::min(kMaxScreenSharingLayerFramerateFps[sl_idx], max_framerate_fps);
|
|
spatial_layer.numberOfTemporalLayers = 1;
|
|
spatial_layer.minBitrate =
|
|
static_cast<int>(kMinScreenSharingLayerBitrateKbps[sl_idx]);
|
|
spatial_layer.maxBitrate =
|
|
static_cast<int>(kMaxScreenSharingLayerBitrateKbps[sl_idx]);
|
|
spatial_layer.targetBitrate =
|
|
static_cast<int>(kTargetScreenSharingLayerBitrateKbps[sl_idx]);
|
|
spatial_layer.active = true;
|
|
spatial_layers.push_back(spatial_layer);
|
|
}
|
|
|
|
return spatial_layers;
|
|
}
|
|
|
|
std::vector<SpatialLayer> ConfigureSvcNormalVideo(size_t input_width,
|
|
size_t input_height,
|
|
float max_framerate_fps,
|
|
size_t first_active_layer,
|
|
size_t num_spatial_layers,
|
|
size_t num_temporal_layers) {
|
|
RTC_DCHECK_LT(first_active_layer, num_spatial_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});
|
|
// First active layer must be configured.
|
|
num_spatial_layers = std::max(num_spatial_layers, first_active_layer + 1);
|
|
|
|
for (size_t sl_idx = first_active_layer; 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.maxFramerate = max_framerate_fps;
|
|
spatial_layer.numberOfTemporalLayers = num_temporal_layers;
|
|
spatial_layer.active = true;
|
|
|
|
// 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;
|
|
int min_bitrate =
|
|
static_cast<int>((600. * std::sqrt(num_pixels) - 95000.) / 1000.);
|
|
min_bitrate = std::max(min_bitrate, 0);
|
|
spatial_layer.minBitrate =
|
|
std::max(static_cast<size_t>(min_bitrate), kMinVp9SvcBitrateKbps);
|
|
spatial_layer.maxBitrate =
|
|
static_cast<int>((1.6 * num_pixels + 50 * 1000) / 1000);
|
|
spatial_layer.targetBitrate =
|
|
(spatial_layer.minBitrate + spatial_layer.maxBitrate) / 2;
|
|
spatial_layers.push_back(spatial_layer);
|
|
}
|
|
|
|
return spatial_layers;
|
|
}
|
|
|
|
std::vector<SpatialLayer> GetSvcConfig(size_t input_width,
|
|
size_t input_height,
|
|
float max_framerate_fps,
|
|
size_t first_active_layer,
|
|
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,
|
|
max_framerate_fps, num_spatial_layers);
|
|
} else {
|
|
return ConfigureSvcNormalVideo(input_width, input_height, max_framerate_fps,
|
|
first_active_layer, num_spatial_layers,
|
|
num_temporal_layers);
|
|
}
|
|
}
|
|
|
|
} // namespace webrtc
|