mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-19 16:47:50 +01:00

Bug: webrtc:347737882 Change-Id: I61e5a7a538bf43a9377fc9e3b8d399754232a2f8 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/362081 Commit-Queue: Ilya Nikolaevskiy <ilnik@webrtc.org> Reviewed-by: Sergey Silkin <ssilkin@webrtc.org> Cr-Commit-Position: refs/heads/main@{#42983}
141 lines
5.2 KiB
C++
141 lines
5.2 KiB
C++
/*
|
|
* Copyright (c) 2024 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/svc/simulcast_to_svc_converter.h"
|
|
|
|
#include "modules/video_coding/svc/create_scalability_structure.h"
|
|
#include "modules/video_coding/svc/scalability_mode_util.h"
|
|
#include "rtc_base/checks.h"
|
|
|
|
namespace webrtc {
|
|
|
|
SimulcastToSvcConverter::SimulcastToSvcConverter(const VideoCodec& codec) {
|
|
config_ = codec;
|
|
int num_temporal_layers =
|
|
config_.simulcastStream[0].GetNumberOfTemporalLayers();
|
|
int num_spatial_layers = config_.numberOfSimulcastStreams;
|
|
ScalabilityMode scalability_mode;
|
|
switch (num_temporal_layers) {
|
|
case 1:
|
|
scalability_mode = ScalabilityMode::kL1T1;
|
|
break;
|
|
case 2:
|
|
scalability_mode = ScalabilityMode::kL1T2;
|
|
break;
|
|
case 3:
|
|
scalability_mode = ScalabilityMode::kL1T3;
|
|
break;
|
|
default:
|
|
RTC_DCHECK_NOTREACHED();
|
|
}
|
|
|
|
for (int i = 0; i < num_spatial_layers; ++i) {
|
|
config_.spatialLayers[i] = config_.simulcastStream[i];
|
|
}
|
|
config_.simulcastStream[0] =
|
|
config_.simulcastStream[config_.numberOfSimulcastStreams - 1];
|
|
config_.VP9()->numberOfSpatialLayers = config_.numberOfSimulcastStreams;
|
|
config_.VP9()->numberOfTemporalLayers =
|
|
config_.spatialLayers[0].numberOfTemporalLayers;
|
|
config_.VP9()->interLayerPred = InterLayerPredMode::kOff;
|
|
config_.numberOfSimulcastStreams = 1;
|
|
config_.UnsetScalabilityMode();
|
|
|
|
for (int i = 0; i < num_spatial_layers; ++i) {
|
|
layers_.emplace_back(scalability_mode, num_temporal_layers);
|
|
}
|
|
}
|
|
|
|
VideoCodec SimulcastToSvcConverter::GetConfig() const {
|
|
return config_;
|
|
}
|
|
|
|
void SimulcastToSvcConverter::EncodeStarted(bool force_keyframe) {
|
|
// Check if at least one layer was encoded successfully.
|
|
bool some_layers_has_completed = false;
|
|
for (size_t i = 0; i < layers_.size(); ++i) {
|
|
some_layers_has_completed |= !layers_[i].awaiting_frame;
|
|
}
|
|
for (size_t i = 0; i < layers_.size(); ++i) {
|
|
if (layers_[i].awaiting_frame && some_layers_has_completed) {
|
|
// Simulcast SVC controller updates pattern on all layers, even
|
|
// if some layers has dropped the frame.
|
|
// Simulate that behavior for all controllers, not updated
|
|
// while rewriting frame descriptors.
|
|
layers_[i].video_controller->OnEncodeDone(layers_[i].layer_config);
|
|
}
|
|
layers_[i].awaiting_frame = true;
|
|
auto configs = layers_[i].video_controller->NextFrameConfig(force_keyframe);
|
|
RTC_CHECK_EQ(configs.size(), 1u);
|
|
layers_[i].layer_config = configs[0];
|
|
}
|
|
}
|
|
|
|
bool SimulcastToSvcConverter::ConvertFrame(EncodedImage& encoded_image,
|
|
CodecSpecificInfo& codec_specific) {
|
|
int sid = encoded_image.SpatialIndex().value_or(0);
|
|
encoded_image.SetSimulcastIndex(sid);
|
|
encoded_image.SetSpatialIndex(std::nullopt);
|
|
codec_specific.end_of_picture = true;
|
|
if (codec_specific.scalability_mode) {
|
|
int num_temporal_layers =
|
|
ScalabilityModeToNumTemporalLayers(*codec_specific.scalability_mode);
|
|
RTC_DCHECK_LE(num_temporal_layers, 3);
|
|
if (num_temporal_layers == 1) {
|
|
codec_specific.scalability_mode = ScalabilityMode::kL1T1;
|
|
} else if (num_temporal_layers == 2) {
|
|
codec_specific.scalability_mode = ScalabilityMode::kL1T2;
|
|
} else if (num_temporal_layers == 3) {
|
|
codec_specific.scalability_mode = ScalabilityMode::kL1T3;
|
|
}
|
|
}
|
|
CodecSpecificInfoVP9& vp9_info = codec_specific.codecSpecific.VP9;
|
|
vp9_info.num_spatial_layers = 1;
|
|
vp9_info.first_active_layer = 0;
|
|
vp9_info.first_frame_in_picture = true;
|
|
if (vp9_info.ss_data_available) {
|
|
vp9_info.width[0] = vp9_info.width[sid];
|
|
vp9_info.height[0] = vp9_info.height[sid];
|
|
}
|
|
|
|
auto& video_controller = *layers_[sid].video_controller;
|
|
if (codec_specific.generic_frame_info) {
|
|
layers_[sid].awaiting_frame = false;
|
|
uint8_t tid = encoded_image.TemporalIndex().value_or(0);
|
|
auto& frame_config = layers_[sid].layer_config;
|
|
RTC_DCHECK_EQ(frame_config.TemporalId(), tid == kNoTemporalIdx ? 0 : tid);
|
|
if (frame_config.TemporalId() != (tid == kNoTemporalIdx ? 0 : tid)) {
|
|
return false;
|
|
}
|
|
codec_specific.generic_frame_info =
|
|
video_controller.OnEncodeDone(frame_config);
|
|
}
|
|
if (codec_specific.template_structure) {
|
|
auto resolution = codec_specific.template_structure->resolutions[sid];
|
|
codec_specific.template_structure = video_controller.DependencyStructure();
|
|
codec_specific.template_structure->resolutions.resize(1);
|
|
codec_specific.template_structure->resolutions[0] = resolution;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
SimulcastToSvcConverter::LayerState::LayerState(
|
|
ScalabilityMode scalability_mode,
|
|
int num_temporal_layers)
|
|
: video_controller(CreateScalabilityStructure(scalability_mode)),
|
|
awaiting_frame(false) {
|
|
VideoBitrateAllocation dummy_bitrates;
|
|
for (int i = 0; i < num_temporal_layers; ++i) {
|
|
dummy_bitrates.SetBitrate(0, i, 10000);
|
|
}
|
|
video_controller->OnRatesUpdated(dummy_bitrates);
|
|
}
|
|
|
|
} // namespace webrtc
|