Add scalability mode to RTCOutboundRtpStreamStats stats

This is in the webrtc-stats spec at
https://www.w3.org/TR/webrtc-stats/#dom-rtcoutboundrtpstreamstats-scalabilitymode.

This adds the scalability mode to CodecSpecificInfo which is used to
plumb the modes for each simulcast layer.

TBR=orphis@webrtc.org

Tested: Compiled into Chrome and confirmed the scalability mode set for AV1, VP9, VP8 and H264 software encoders in chrome://webrtc-internals.
Bug: webrtc:14730
Change-Id: I71ceba8f6485a4f4a73e0856031b8d5f16f913f2
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/285085
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Reviewed-by: Åsa Persson <asapersson@webrtc.org>
Commit-Queue: Evan Shrubsole <eshr@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#38847}
This commit is contained in:
Evan Shrubsole 2022-12-06 10:09:10 +00:00 committed by WebRTC LUCI CQ
parent d34c4ee141
commit 9b235cd93b
25 changed files with 178 additions and 43 deletions

View File

@ -561,6 +561,7 @@ class RTC_EXPORT RTCOutboundRTPStreamStats final : public RTCRTPStreamStats {
RTCStatsMember<bool> active;
RTCRestrictedStatsMember<bool, StatExposureCriteria::kHardwareCapability>
power_efficient_encoder;
RTCStatsMember<std::string> scalability_mode;
};
// https://w3c.github.io/webrtc-stats/#remoteinboundrtpstats-dict*

View File

@ -385,6 +385,7 @@ rtc_library("video_stream_api") {
"../api/video:video_frame",
"../api/video:video_rtp_headers",
"../api/video:video_stream_encoder",
"../api/video_codecs:scalability_mode",
"../api/video_codecs:video_codecs_api",
"../common_video",
"../common_video:frame_counts",

View File

@ -30,6 +30,7 @@
#include "api/video/video_sink_interface.h"
#include "api/video/video_source_interface.h"
#include "api/video/video_stream_encoder_settings.h"
#include "api/video_codecs/scalability_mode.h"
#include "call/rtp_config.h"
#include "common_video/frame_counts.h"
#include "common_video/include/quality_limitation_reason.h"
@ -93,6 +94,7 @@ class VideoSendStream {
uint64_t total_encode_time_ms = 0;
uint64_t total_encoded_bytes_target = 0;
uint32_t huge_frames_sent = 0;
absl::optional<ScalabilityMode> scalability_mode;
};
struct Stats {

View File

@ -74,6 +74,7 @@ rtc_library("rtc_media_base") {
"../api/video:video_bitrate_allocator_factory",
"../api/video:video_frame",
"../api/video:video_rtp_headers",
"../api/video_codecs:scalability_mode",
"../api/video_codecs:video_codecs_api",
"../call:call_interfaces",
"../call:video_stream_api",

View File

@ -35,6 +35,7 @@
#include "api/video/video_sink_interface.h"
#include "api/video/video_source_interface.h"
#include "api/video/video_timing.h"
#include "api/video_codecs/scalability_mode.h"
#include "api/video_codecs/video_encoder_factory.h"
#include "call/video_receive_stream.h"
#include "common_video/include/quality_limitation_reason.h"
@ -651,6 +652,7 @@ struct VideoSenderInfo : public MediaSenderInfo {
uint32_t aggregated_huge_frames_sent = 0;
absl::optional<std::string> rid;
absl::optional<bool> power_efficient_encoder;
absl::optional<webrtc::ScalabilityMode> scalability_mode;
};
struct VideoReceiverInfo : public MediaReceiverInfo {

View File

@ -2731,6 +2731,7 @@ WebRtcVideoChannel::WebRtcVideoSendStream::GetPerLayerVideoSenderInfos(
info.total_encode_time_ms = stream_stats.total_encode_time_ms;
info.total_encoded_bytes_target = stream_stats.total_encoded_bytes_target;
info.huge_frames_sent = stream_stats.huge_frames_sent;
info.scalability_mode = stream_stats.scalability_mode;
infos.push_back(info);
}
return infos;

View File

@ -331,6 +331,7 @@ rtc_library("video_codec_interface") {
":codec_globals_headers",
"../../api/video:video_frame",
"../../api/video:video_rtp_headers",
"../../api/video_codecs:scalability_mode",
"../../api/video_codecs:video_codecs_api",
"../../common_video",
"../../common_video/generic_frame_descriptor",
@ -516,6 +517,8 @@ rtc_library("webrtc_h264") {
deps = [
":video_codec_interface",
":video_coding_utility",
"../../api/transport/rtp:dependency_descriptor",
"../../api/video:video_codec_constants",
"../../api/video:video_frame",
"../../api/video:video_frame_i010",
"../../api/video:video_rtp_headers",
@ -630,6 +633,7 @@ rtc_library("webrtc_vp8") {
"../../api/video:encoded_image",
"../../api/video:video_frame",
"../../api/video:video_rtp_headers",
"../../api/video_codecs:scalability_mode",
"../../api/video_codecs:video_codecs_api",
"../../api/video_codecs:vp8_temporal_layers_factory",
"../../common_video",
@ -777,6 +781,7 @@ rtc_library("webrtc_vp9") {
"//third_party/abseil-cpp/absl/container:inlined_vector",
"//third_party/abseil-cpp/absl/memory",
"//third_party/abseil-cpp/absl/strings:strings",
"//third_party/abseil-cpp/absl/types:optional",
]
if (rtc_build_libvpx) {
deps += [ rtc_libvpx_dir ]

View File

@ -57,6 +57,7 @@ rtc_library("libaom_av1_encoder") {
"../../../../api:scoped_refptr",
"../../../../api/video:encoded_image",
"../../../../api/video:video_frame",
"../../../../api/video_codecs:scalability_mode",
"../../../../api/video_codecs:video_codecs_api",
"../../../../common_video",
"../../../../rtc_base:checks",

View File

@ -23,6 +23,7 @@
#include "api/video/encoded_image.h"
#include "api/video/i420_buffer.h"
#include "api/video/video_frame.h"
#include "api/video_codecs/scalability_mode.h"
#include "api/video_codecs/video_codec.h"
#include "api/video_codecs/video_encoder.h"
#include "modules/video_coding/include/video_codec_interface.h"
@ -109,6 +110,7 @@ class LibaomAv1Encoder final : public VideoEncoder {
void MaybeRewrapImgWithFormat(const aom_img_fmt_t fmt);
std::unique_ptr<ScalableVideoController> svc_controller_;
absl::optional<ScalabilityMode> scalability_mode_;
bool inited_;
bool rates_configured_;
absl::optional<aom_svc_params_t> svc_params_;
@ -185,16 +187,15 @@ int LibaomAv1Encoder::InitEncode(const VideoCodec* codec_settings,
RTC_LOG(LS_WARNING) << "Simulcast is not implemented by LibaomAv1Encoder.";
return result;
}
absl::optional<ScalabilityMode> scalability_mode =
encoder_settings_.GetScalabilityMode();
if (!scalability_mode.has_value()) {
scalability_mode_ = encoder_settings_.GetScalabilityMode();
if (!scalability_mode_.has_value()) {
RTC_LOG(LS_WARNING) << "Scalability mode is not set, using 'L1T1'.";
scalability_mode = ScalabilityMode::kL1T1;
scalability_mode_ = ScalabilityMode::kL1T1;
}
svc_controller_ = CreateScalabilityStructure(*scalability_mode);
svc_controller_ = CreateScalabilityStructure(*scalability_mode_);
if (svc_controller_ == nullptr) {
RTC_LOG(LS_WARNING) << "Failed to set scalability mode "
<< static_cast<int>(*scalability_mode);
<< static_cast<int>(*scalability_mode_);
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
}
@ -709,6 +710,7 @@ int32_t LibaomAv1Encoder::Encode(
CodecSpecificInfo codec_specific_info;
codec_specific_info.codecType = kVideoCodecAV1;
codec_specific_info.end_of_picture = end_of_picture;
codec_specific_info.scalability_mode = scalability_mode_;
bool is_keyframe = layer_frame->IsKeyframe();
codec_specific_info.generic_frame_info =
svc_controller_->OnEncodeDone(*layer_frame);

View File

@ -44,6 +44,7 @@ using ::testing::Ge;
using ::testing::IsEmpty;
using ::testing::Not;
using ::testing::NotNull;
using ::testing::Optional;
using ::testing::Pointwise;
using ::testing::SizeIs;
using ::testing::Truly;
@ -248,6 +249,8 @@ TEST_P(LibaomAv1SvcTest, EncodeAndDecodeAllDecodeTargets) {
requested_ids.push_back(frame_id);
decoder.Decode(frame_id, frame.encoded_image);
}
EXPECT_THAT(frame.codec_specific_info.scalability_mode,
Optional(param.GetScalabilityMode()));
}
ASSERT_THAT(requested_ids, SizeIs(Ge(2u)));

View File

@ -21,6 +21,9 @@
#include <string>
#include "absl/strings/match.h"
#include "absl/types/optional.h"
#include "api/video/video_codec_constants.h"
#include "api/video_codecs/scalability_mode.h"
#include "common_video/libyuv/include/webrtc_libyuv.h"
#include "modules/video_coding/svc/create_scalability_structure.h"
#include "modules/video_coding/utility/simulcast_rate_allocator.h"
@ -86,6 +89,23 @@ VideoFrameType ConvertToVideoFrameType(EVideoFrameType type) {
return VideoFrameType::kEmptyFrame;
}
absl::optional<ScalabilityMode> ScalabilityModeFromTemporalLayers(
int num_temporal_layers) {
switch (num_temporal_layers) {
case 0:
break;
case 1:
return ScalabilityMode::kL1T1;
case 2:
return ScalabilityMode::kL1T2;
case 3:
return ScalabilityMode::kL1T3;
default:
RTC_DCHECK_NOTREACHED();
}
return absl::nullopt;
}
} // namespace
// Helper method used by H264EncoderImpl::Encode.
@ -199,6 +219,7 @@ int32_t H264EncoderImpl::InitEncode(const VideoCodec* inst,
encoders_.resize(number_of_streams);
pictures_.resize(number_of_streams);
svc_controllers_.resize(number_of_streams);
scalability_modes_.resize(number_of_streams);
configurations_.resize(number_of_streams);
tl0sync_limit_.resize(number_of_streams);
@ -284,25 +305,10 @@ int32_t H264EncoderImpl::InitEncode(const VideoCodec* inst,
encoded_images_[i].set_size(0);
tl0sync_limit_[i] = configurations_[i].num_temporal_layers;
absl::optional<ScalabilityMode> scalability_mode;
switch (configurations_[i].num_temporal_layers) {
case 0:
break;
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();
}
if (scalability_mode.has_value()) {
svc_controllers_[i] =
CreateScalabilityStructure(scalability_mode.value());
scalability_modes_[i] = ScalabilityModeFromTemporalLayers(
configurations_[i].num_temporal_layers);
if (scalability_modes_[i].has_value()) {
svc_controllers_[i] = CreateScalabilityStructure(*scalability_modes_[i]);
if (svc_controllers_[i] == nullptr) {
RTC_LOG(LS_ERROR) << "Failed to create scalability structure";
Release();
@ -335,6 +341,7 @@ int32_t H264EncoderImpl::Release() {
pictures_.clear();
tl0sync_limit_.clear();
svc_controllers_.clear();
scalability_modes_.clear();
return WEBRTC_VIDEO_CODEC_OK;
}
@ -568,6 +575,7 @@ int32_t H264EncoderImpl::Encode(
codec_specific.template_structure =
svc_controllers_[i]->DependencyStructure();
}
codec_specific.scalability_mode = scalability_modes_[i];
}
encoded_image_callback_->OnEncodedImage(encoded_images_[i],
&codec_specific);

View File

@ -24,7 +24,11 @@
#include <memory>
#include <vector>
#include "absl/container/inlined_vector.h"
#include "api/transport/rtp/dependency_descriptor.h"
#include "api/video/i420_buffer.h"
#include "api/video/video_codec_constants.h"
#include "api/video_codecs/scalability_mode.h"
#include "api/video_codecs/video_encoder.h"
#include "common_video/h264/h264_bitstream_parser.h"
#include "modules/video_coding/codecs/h264/include/h264.h"
@ -99,6 +103,8 @@ class H264EncoderImpl : public H264Encoder {
std::vector<LayerConfig> configurations_;
std::vector<EncodedImage> encoded_images_;
std::vector<std::unique_ptr<ScalableVideoController>> svc_controllers_;
absl::InlinedVector<absl::optional<ScalabilityMode>, kMaxSimulcastStreams>
scalability_modes_;
VideoCodec codec_;
H264PacketizationMode packetization_mode_;

View File

@ -25,6 +25,7 @@
#include "api/video/video_content_type.h"
#include "api/video/video_frame_buffer.h"
#include "api/video/video_timing.h"
#include "api/video_codecs/scalability_mode.h"
#include "api/video_codecs/vp8_temporal_layers.h"
#include "api/video_codecs/vp8_temporal_layers_factory.h"
#include "modules/video_coding/codecs/interface/common_constants.h"
@ -1103,6 +1104,17 @@ void LibvpxVp8Encoder::PopulateCodecSpecific(CodecSpecificInfo* codec_specific,
codec_specific->template_structure->resolutions = {
RenderResolution(pkt.data.frame.width[0], pkt.data.frame.height[0])};
}
switch (vpx_configs_[encoder_idx].ts_number_layers) {
case 1:
codec_specific->scalability_mode = ScalabilityMode::kL1T1;
break;
case 2:
codec_specific->scalability_mode = ScalabilityMode::kL1T2;
break;
case 3:
codec_specific->scalability_mode = ScalabilityMode::kL1T3;
break;
}
}
int LibvpxVp8Encoder::GetEncodedPartitions(const VideoFrame& input_image,

View File

@ -9,23 +9,26 @@
*
*/
#include <memory>
#ifdef RTC_ENABLE_VP9
#include "modules/video_coding/codecs/vp9/libvpx_vp9_encoder.h"
#include <algorithm>
#include <limits>
#include <tuple>
#include <utility>
#include <vector>
#include "absl/algorithm/container.h"
#include "absl/memory/memory.h"
#include "absl/strings/match.h"
#include "absl/types/optional.h"
#include "api/video/color_space.h"
#include "api/video/i010_buffer.h"
#include "api/video_codecs/scalability_mode.h"
#include "common_video/include/video_frame_buffer.h"
#include "common_video/libyuv/include/webrtc_libyuv.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/video_coding/codecs/vp9/libvpx_vp9_encoder.h"
#include "modules/video_coding/svc/create_scalability_structure.h"
#include "modules/video_coding/svc/scalability_mode_util.h"
#include "modules/video_coding/svc/scalable_video_controller.h"
@ -79,13 +82,17 @@ std::pair<size_t, size_t> GetActiveLayers(
return {0, 0};
}
std::unique_ptr<ScalableVideoController> CreateVp9ScalabilityStructure(
using Vp9ScalabilityStructure =
std::tuple<std::unique_ptr<ScalableVideoController>, ScalabilityMode>;
absl::optional<Vp9ScalabilityStructure> CreateVp9ScalabilityStructure(
const VideoCodec& codec) {
int num_spatial_layers = codec.VP9().numberOfSpatialLayers;
int num_temporal_layers =
std::max(1, int{codec.VP9().numberOfTemporalLayers});
if (num_spatial_layers == 1 && num_temporal_layers == 1) {
return std::make_unique<ScalableVideoControllerNoLayering>();
return absl::make_optional<Vp9ScalabilityStructure>(
std::make_unique<ScalableVideoControllerNoLayering>(),
ScalabilityMode::kL1T1);
}
char name[20];
@ -93,7 +100,7 @@ std::unique_ptr<ScalableVideoController> CreateVp9ScalabilityStructure(
if (codec.mode == VideoCodecMode::kScreensharing) {
// TODO(bugs.webrtc.org/11999): Compose names of the structures when they
// are implemented.
return nullptr;
return absl::nullopt;
} else if (codec.VP9().interLayerPred == InterLayerPredMode::kOn ||
num_spatial_layers == 1) {
ss << "L" << num_spatial_layers << "T" << num_temporal_layers;
@ -110,7 +117,7 @@ std::unique_ptr<ScalableVideoController> CreateVp9ScalabilityStructure(
codec.height != codec.spatialLayers[num_spatial_layers - 1].height) {
RTC_LOG(LS_WARNING)
<< "Top layer resolution expected to match overall resolution";
return nullptr;
return absl::nullopt;
}
// Check if the ratio is one of the supported.
int numerator;
@ -128,7 +135,7 @@ std::unique_ptr<ScalableVideoController> CreateVp9ScalabilityStructure(
RTC_LOG(LS_WARNING) << "Unsupported scalability ratio "
<< codec.spatialLayers[0].width << ":"
<< codec.spatialLayers[1].width;
return nullptr;
return absl::nullopt;
}
// Validate ratio is consistent for all spatial layer transitions.
for (int sid = 1; sid < num_spatial_layers; ++sid) {
@ -138,7 +145,7 @@ std::unique_ptr<ScalableVideoController> CreateVp9ScalabilityStructure(
codec.spatialLayers[sid - 1].height * denominator) {
RTC_LOG(LS_WARNING) << "Inconsistent scalability ratio " << numerator
<< ":" << denominator;
return nullptr;
return absl::nullopt;
}
}
}
@ -147,7 +154,7 @@ std::unique_ptr<ScalableVideoController> CreateVp9ScalabilityStructure(
ScalabilityModeFromString(name);
if (!scalability_mode.has_value()) {
RTC_LOG(LS_WARNING) << "Invalid scalability mode " << name;
return nullptr;
return absl::nullopt;
}
auto scalability_structure_controller =
CreateScalabilityStructure(*scalability_mode);
@ -156,7 +163,8 @@ std::unique_ptr<ScalableVideoController> CreateVp9ScalabilityStructure(
} else {
RTC_LOG(LS_INFO) << "Created scalability structure " << name;
}
return scalability_structure_controller;
return absl::make_optional<Vp9ScalabilityStructure>(
std::move(scalability_structure_controller), *scalability_mode);
}
vpx_svc_ref_frame_config_t Vp9References(
@ -570,12 +578,12 @@ int LibvpxVp9Encoder::InitEncode(const VideoCodec* inst,
force_key_frame_ = true;
pics_since_key_ = 0;
absl::optional<ScalabilityMode> scalability_mode = inst->GetScalabilityMode();
if (scalability_mode.has_value()) {
scalability_mode_ = inst->GetScalabilityMode();
if (scalability_mode_.has_value()) {
// Use settings from `ScalabilityMode` identifier.
RTC_LOG(LS_INFO) << "Create scalability structure "
<< ScalabilityModeToString(*scalability_mode);
svc_controller_ = CreateScalabilityStructure(*scalability_mode);
<< ScalabilityModeToString(*scalability_mode_);
svc_controller_ = CreateScalabilityStructure(*scalability_mode_);
if (!svc_controller_) {
RTC_LOG(LS_WARNING) << "Failed to create scalability structure.";
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
@ -584,7 +592,7 @@ int LibvpxVp9Encoder::InitEncode(const VideoCodec* inst,
svc_controller_->StreamConfig();
num_spatial_layers_ = info.num_spatial_layers;
num_temporal_layers_ = info.num_temporal_layers;
inter_layer_pred_ = ScalabilityModeToInterLayerPredMode(*scalability_mode);
inter_layer_pred_ = ScalabilityModeToInterLayerPredMode(*scalability_mode_);
} else {
num_spatial_layers_ = inst->VP9().numberOfSpatialLayers;
RTC_DCHECK_GT(num_spatial_layers_, 0);
@ -593,7 +601,14 @@ int LibvpxVp9Encoder::InitEncode(const VideoCodec* inst,
num_temporal_layers_ = 1;
}
inter_layer_pred_ = inst->VP9().interLayerPred;
svc_controller_ = CreateVp9ScalabilityStructure(*inst);
auto vp9_scalability = CreateVp9ScalabilityStructure(*inst);
if (vp9_scalability.has_value()) {
std::tie(svc_controller_, scalability_mode_) =
std::move(vp9_scalability.value());
} else {
svc_controller_ = nullptr;
scalability_mode_ = absl::nullopt;
}
}
framerate_controller_ = std::vector<FramerateControllerDeprecated>(
@ -1443,6 +1458,7 @@ bool LibvpxVp9Encoder::PopulateCodecSpecific(CodecSpecificInfo* codec_specific,
}
}
}
codec_specific->scalability_mode = scalability_mode_;
return true;
}

View File

@ -20,6 +20,7 @@
#include "api/fec_controller_override.h"
#include "api/field_trials_view.h"
#include "api/video_codecs/scalability_mode.h"
#include "api/video_codecs/video_encoder.h"
#include "api/video_codecs/vp9_profile.h"
#include "common_video/include/video_frame_buffer_pool.h"
@ -151,6 +152,7 @@ class LibvpxVp9Encoder : public VP9Encoder {
bool force_all_active_layers_;
std::unique_ptr<ScalableVideoController> svc_controller_;
absl::optional<ScalabilityMode> scalability_mode_;
std::vector<FramerateControllerDeprecated> framerate_controller_;
// Used for flexible mode.

View File

@ -16,6 +16,7 @@
#include "absl/base/attributes.h"
#include "absl/types/optional.h"
#include "api/video/video_frame.h"
#include "api/video_codecs/scalability_mode.h"
#include "api/video_codecs/video_decoder.h"
#include "api/video_codecs/video_encoder.h"
#include "common_video/generic_frame_descriptor/generic_frame_info.h"
@ -112,6 +113,7 @@ struct RTC_EXPORT CodecSpecificInfo {
bool end_of_picture = true;
absl::optional<GenericFrameInfo> generic_frame_info;
absl::optional<FrameDependencyStructure> template_structure;
absl::optional<ScalabilityMode> scalability_mode;
};
} // namespace webrtc

View File

@ -1008,6 +1008,7 @@ rtc_source_set("rtc_stats_collector") {
"../api/task_queue:task_queue",
"../api/units:time_delta",
"../api/video:video_rtp_headers",
"../api/video_codecs:scalability_mode",
"../call:call_interfaces",
"../common_video:common_video",
"../media:rtc_media_base",
@ -2367,6 +2368,7 @@ if (rtc_include_tests && !build_with_chromium) {
"../api/video:video_codec_constants",
"../api/video:video_frame",
"../api/video:video_rtp_headers",
"../api/video_codecs:scalability_mode",
"../call/adaptation:resource_adaptation_test_utilities",
"../common_video",
"../logging:fake_rtc_event_log",
@ -2726,6 +2728,7 @@ if (rtc_include_tests && !build_with_chromium) {
"../api:media_stream_interface",
"../api:network_emulation_manager_api",
"../api:peer_connection_quality_test_fixture_api",
"../api:rtc_stats_api",
"../api:simulated_network_api",
"../api:time_controller",
"../api/test/metrics:global_metrics_logger_and_exporter",

View File

@ -33,6 +33,7 @@
#include "api/stats/rtcstats_objects.h"
#include "api/units/time_delta.h"
#include "api/video/video_content_type.h"
#include "api/video_codecs/scalability_mode.h"
#include "common_video/include/quality_limitation_reason.h"
#include "media/base/media_channel.h"
#include "modules/audio_processing/include/audio_processing_statistics.h"
@ -792,6 +793,10 @@ void SetOutboundRTPStreamStatsFromVideoSenderInfo(
outbound_video->power_efficient_encoder =
video_sender_info.power_efficient_encoder.value();
}
if (video_sender_info.scalability_mode) {
outbound_video->scalability_mode = std::string(
ScalabilityModeToString(*video_sender_info.scalability_mode));
}
}
std::unique_ptr<RTCRemoteInboundRtpStreamStats>

View File

@ -39,6 +39,7 @@
#include "api/video/video_sink_interface.h"
#include "api/video/video_source_interface.h"
#include "api/video/video_timing.h"
#include "api/video_codecs/scalability_mode.h"
#include "common_video/include/quality_limitation_reason.h"
#include "media/base/media_channel.h"
#include "modules/audio_processing/include/audio_processing_statistics.h"
@ -2835,6 +2836,7 @@ TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRTPStreamStats_Video) {
video_media_info.senders[0].frames_sent = 5;
video_media_info.senders[0].huge_frames_sent = 2;
video_media_info.senders[0].active = false;
video_media_info.senders[0].scalability_mode = ScalabilityMode::kL3T3_KEY;
video_media_info.aggregated_senders.push_back(video_media_info.senders[0]);
RtpCodecParameters codec_parameters;
codec_parameters.payload_type = 42;
@ -2894,6 +2896,7 @@ TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRTPStreamStats_Video) {
expected_video.huge_frames_sent = 2;
expected_video.active = false;
expected_video.power_efficient_encoder = false;
expected_video.scalability_mode = "L3T3_KEY";
// `expected_video.content_type` should be undefined.
// `expected_video.qp_sum` should be undefined.
// `expected_video.encoder_implementation` should be undefined.

View File

@ -984,6 +984,7 @@ class RTCStatsReportVerifier {
verifier.TestMemberIsNonNegative<uint32_t>(
outbound_stream.huge_frames_sent);
verifier.MarkMemberTested(outbound_stream.rid, true);
verifier.TestMemberIsDefined(outbound_stream.scalability_mode);
} else {
verifier.TestMemberIsUndefined(outbound_stream.frames_encoded);
verifier.TestMemberIsUndefined(outbound_stream.key_frames_encoded);
@ -1005,6 +1006,7 @@ class RTCStatsReportVerifier {
verifier.TestMemberIsUndefined(outbound_stream.frame_width);
verifier.TestMemberIsUndefined(outbound_stream.frames_sent);
verifier.TestMemberIsUndefined(outbound_stream.huge_frames_sent);
verifier.TestMemberIsUndefined(outbound_stream.scalability_mode);
}
return verifier.ExpectAllMembersSuccessfullyTested();
}

View File

@ -13,6 +13,7 @@
#include <vector>
#include "api/media_stream_interface.h"
#include "api/stats/rtcstats_objects.h"
#include "api/test/create_network_emulation_manager.h"
#include "api/test/create_peer_connection_quality_test_frame_generator.h"
#include "api/test/create_peerconnection_quality_test_fixture.h"
@ -46,6 +47,7 @@ using ::cricket::kH264CodecName;
using ::cricket::kVp8CodecName;
using ::cricket::kVp9CodecName;
using ::testing::Combine;
using ::testing::Optional;
using ::testing::UnitTest;
using ::testing::Values;
using ::testing::ValuesIn;
@ -203,16 +205,32 @@ class SvcVideoQualityAnalyzer : public DefaultVideoQualityAnalyzer {
input_image);
}
void OnStatsReports(
absl::string_view pc_label,
const rtc::scoped_refptr<const RTCStatsReport>& report) override {
// Extract the scalability mode reported in the stats.
auto outbound_stats = report->GetStatsOfType<RTCOutboundRTPStreamStats>();
for (const auto& stat : outbound_stats) {
if (stat->scalability_mode.is_defined()) {
reported_scalability_mode_ = *stat->scalability_mode;
}
}
}
const SpatialTemporalLayerCounts& encoder_layers_seen() const {
return encoder_layers_seen_;
}
const SpatialTemporalLayerCounts& decoder_layers_seen() const {
return decoder_layers_seen_;
}
const absl::optional<std::string> reported_scalability_mode() const {
return reported_scalability_mode_;
}
private:
SpatialTemporalLayerCounts encoder_layers_seen_;
SpatialTemporalLayerCounts decoder_layers_seen_;
absl::optional<std::string> reported_scalability_mode_;
};
MATCHER_P2(HasSpatialAndTemporalLayers,
@ -342,6 +360,8 @@ TEST_P(SvcTest, ScalabilityModeSupported) {
SvcTestParameters().expected_spatial_layers,
SvcTestParameters().expected_temporal_layers));
}
EXPECT_THAT(analyzer_ptr->reported_scalability_mode(),
Optional(SvcTestParameters().scalability_mode));
RTC_LOG(LS_INFO) << "Encoder layers seen: "
<< analyzer_ptr->encoder_layers_seen().size();

View File

@ -678,7 +678,8 @@ WEBRTC_RTCSTATS_IMPL(
&nack_count,
&qp_sum,
&active,
&power_efficient_encoder)
&power_efficient_encoder,
&scalability_mode)
// clang-format on
RTCOutboundRTPStreamStats::RTCOutboundRTPStreamStats(const std::string& id,
@ -719,7 +720,8 @@ RTCOutboundRTPStreamStats::RTCOutboundRTPStreamStats(std::string&& id,
nack_count("nackCount"),
qp_sum("qpSum"),
active("active"),
power_efficient_encoder("powerEfficientEncoder") {}
power_efficient_encoder("powerEfficientEncoder"),
scalability_mode("scalabilityMode") {}
RTCOutboundRTPStreamStats::RTCOutboundRTPStreamStats(
const RTCOutboundRTPStreamStats& other) = default;

View File

@ -859,6 +859,7 @@ if (rtc_include_tests) {
"../api/video:video_frame_type",
"../api/video:video_rtp_headers",
"../api/video/test:video_frame_matchers",
"../api/video_codecs:scalability_mode",
"../api/video_codecs:video_codecs_api",
"../api/video_codecs:vp8_temporal_layers_factory",
"../call:call_interfaces",

View File

@ -985,6 +985,8 @@ void SendStatisticsProxy::OnSendEncodedImage(
stats->frames_encoded++;
stats->total_encode_time_ms += encoded_image.timing_.encode_finish_ms -
encoded_image.timing_.encode_start_ms;
if (codec_info)
stats->scalability_mode = codec_info->scalability_mode;
// Report resolution of the top spatial layer.
bool is_top_spatial_layer =
codec_info == nullptr || codec_info->end_of_picture;

View File

@ -21,6 +21,7 @@
#include "api/video/video_adaptation_reason.h"
#include "api/video/video_bitrate_allocation.h"
#include "api/video/video_codec_type.h"
#include "api/video_codecs/scalability_mode.h"
#include "api/video_codecs/video_codec.h"
#include "rtc_base/fake_clock.h"
#include "system_wrappers/include/metrics.h"
@ -32,6 +33,9 @@
namespace webrtc {
namespace {
using ::testing::Optional;
const uint32_t kFirstSsrc = 17;
const uint32_t kSecondSsrc = 42;
const uint32_t kFirstRtxSsrc = 18;
@ -397,6 +401,34 @@ TEST_F(SendStatisticsProxyTest, OnSendEncodedImageWithoutQpQpSumWontExist) {
statistics_proxy_->GetStats().substreams[ssrc].qp_sum);
}
TEST_F(SendStatisticsProxyTest,
OnSendEncodedImageSetsScalabilityModeOfCurrentLayer) {
EncodedImage encoded_image;
CodecSpecificInfo codec_info;
ScalabilityMode layer0_mode = ScalabilityMode::kL1T1;
ScalabilityMode layer1_mode = ScalabilityMode::kL1T3;
auto ssrc0 = config_.rtp.ssrcs[0];
auto ssrc1 = config_.rtp.ssrcs[1];
EXPECT_EQ(absl::nullopt,
statistics_proxy_->GetStats().substreams[ssrc0].scalability_mode);
EXPECT_EQ(absl::nullopt,
statistics_proxy_->GetStats().substreams[ssrc1].scalability_mode);
encoded_image.SetSpatialIndex(0);
codec_info.scalability_mode = layer0_mode;
statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
EXPECT_THAT(statistics_proxy_->GetStats().substreams[ssrc0].scalability_mode,
layer0_mode);
EXPECT_EQ(absl::nullopt,
statistics_proxy_->GetStats().substreams[ssrc1].scalability_mode);
encoded_image.SetSpatialIndex(1);
codec_info.scalability_mode = layer1_mode;
statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
EXPECT_THAT(statistics_proxy_->GetStats().substreams[ssrc0].scalability_mode,
layer0_mode);
EXPECT_THAT(statistics_proxy_->GetStats().substreams[ssrc1].scalability_mode,
layer1_mode);
}
TEST_F(SendStatisticsProxyTest, TotalEncodedBytesTargetFirstFrame) {
const uint32_t kTargetBytesPerSecond = 100000;
statistics_proxy_->OnSetEncoderTargetRate(kTargetBytesPerSecond * 8);