mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 05:40:42 +01:00

This reverts commit 4bf4e1753c
.
Reason for revert: break upstream
Original change's description:
> Provide Environment to construct VideoBitrateAllocator
>
> To allow various VideoBitrateAllocators to use propagated rather than global field trials
>
> Bug: webrtc:42220378
> Change-Id: I52816628169a54b18a4405d84fee69b101f92f72
> Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/349920
> Reviewed-by: Erik Språng <sprang@webrtc.org>
> Reviewed-by: Philip Eliasson <philipel@webrtc.org>
> Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
> Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
> Cr-Commit-Position: refs/heads/main@{#42288}
Bug: webrtc:42220378
Change-Id: I7d47eb635c2d312d97a870c2a8eca0b23d2f86a0
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/350307
Owners-Override: Jeremy Leconte <jleconte@google.com>
Commit-Queue: Jeremy Leconte <jleconte@google.com>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Bot-Commit: rubber-stamper@appspot.gserviceaccount.com <rubber-stamper@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/heads/main@{#42290}
633 lines
24 KiB
C++
633 lines
24 KiB
C++
/*
|
|
* Copyright (c) 2022 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 <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "absl/flags/flag.h"
|
|
#include "absl/functional/any_invocable.h"
|
|
#include "api/environment/environment.h"
|
|
#include "api/environment/environment_factory.h"
|
|
#include "api/test/metrics/global_metrics_logger_and_exporter.h"
|
|
#include "api/units/data_rate.h"
|
|
#include "api/units/frequency.h"
|
|
#include "api/video/resolution.h"
|
|
#include "api/video_codecs/builtin_video_decoder_factory.h"
|
|
#include "api/video_codecs/builtin_video_encoder_factory.h"
|
|
#if defined(WEBRTC_ANDROID)
|
|
#include "modules/video_coding/codecs/test/android_codec_factory_helper.h"
|
|
#endif
|
|
#include "modules/video_coding/svc/scalability_mode_util.h"
|
|
#include "rtc_base/logging.h"
|
|
#include "rtc_base/strings/string_builder.h"
|
|
#include "test/explicit_key_value_config.h"
|
|
#include "test/field_trial.h"
|
|
#include "test/gtest.h"
|
|
#include "test/test_flags.h"
|
|
#include "test/testsupport/file_utils.h"
|
|
#include "test/video_codec_tester.h"
|
|
|
|
ABSL_FLAG(std::string,
|
|
input_path,
|
|
webrtc::test::ResourcePath("FourPeople_1280x720_30", "yuv"),
|
|
"Path to input video file.");
|
|
ABSL_FLAG(int, input_width, 1280, "Input video width.");
|
|
ABSL_FLAG(int, input_height, 720, "Input video height.");
|
|
ABSL_FLAG(double, input_framerate_fps, 30, "Input video framerate, fps.");
|
|
ABSL_FLAG(std::string,
|
|
encoder,
|
|
"libaom-av1",
|
|
"Encoder: libaom-av1, libvpx-vp9, libvpx-vp8, openh264, hw-vp8, "
|
|
"hw-vp9, hw-av1, hw-h264, hw-h265");
|
|
ABSL_FLAG(std::string,
|
|
decoder,
|
|
"dav1d",
|
|
"Decoder: dav1d, libvpx-vp9, libvpx-vp8, ffmpeg-h264, hw-vp8, "
|
|
"hw-vp9, hw-av1, hw-h264, hw-h265");
|
|
ABSL_FLAG(std::string, scalability_mode, "L1T1", "Scalability mode.");
|
|
ABSL_FLAG(absl::optional<int>, width, absl::nullopt, "Encode width.");
|
|
ABSL_FLAG(absl::optional<int>, height, absl::nullopt, "Encode height.");
|
|
ABSL_FLAG(std::vector<std::string>,
|
|
bitrate_kbps,
|
|
{"1024"},
|
|
"Encode target bitrate per layer (l0t0,l0t1,...l1t0,l1t1 and so on) "
|
|
"in kbps.");
|
|
ABSL_FLAG(absl::optional<double>,
|
|
framerate_fps,
|
|
absl::nullopt,
|
|
"Encode target frame rate of the top temporal layer in fps.");
|
|
ABSL_FLAG(bool, screencast, false, "Enable screen encoding mode.");
|
|
ABSL_FLAG(bool, frame_drop, true, "Enable frame dropping.");
|
|
ABSL_FLAG(int,
|
|
key_interval,
|
|
std::numeric_limits<int>::max(),
|
|
"Keyframe interval in frames.");
|
|
ABSL_FLAG(int, num_frames, 300, "Number of frames to encode and/or decode.");
|
|
ABSL_FLAG(std::string, field_trials, "", "Field trials to apply.");
|
|
ABSL_FLAG(std::string, test_name, "", "Test name.");
|
|
ABSL_FLAG(bool, dump_decoder_input, false, "Dump decoder input.");
|
|
ABSL_FLAG(bool, dump_decoder_output, false, "Dump decoder output.");
|
|
ABSL_FLAG(bool, dump_encoder_input, false, "Dump encoder input.");
|
|
ABSL_FLAG(bool, dump_encoder_output, false, "Dump encoder output.");
|
|
ABSL_FLAG(bool, write_csv, false, "Write metrics to a CSV file.");
|
|
|
|
namespace webrtc {
|
|
namespace test {
|
|
|
|
namespace {
|
|
using ::testing::Combine;
|
|
using ::testing::Values;
|
|
using VideoSourceSettings = VideoCodecTester::VideoSourceSettings;
|
|
using EncodingSettings = VideoCodecTester::EncodingSettings;
|
|
using VideoCodecStats = VideoCodecTester::VideoCodecStats;
|
|
using Filter = VideoCodecStats::Filter;
|
|
using PacingMode = VideoCodecTester::PacingSettings::PacingMode;
|
|
|
|
struct VideoInfo {
|
|
std::string name;
|
|
Resolution resolution;
|
|
Frequency framerate;
|
|
};
|
|
|
|
VideoInfo kFourPeople_1280x720_30 = {
|
|
.name = "FourPeople_1280x720_30",
|
|
.resolution = {.width = 1280, .height = 720},
|
|
.framerate = Frequency::Hertz(30)};
|
|
|
|
static constexpr Frequency k90kHz = Frequency::Hertz(90000);
|
|
|
|
VideoSourceSettings ToSourceSettings(VideoInfo video_info) {
|
|
return VideoSourceSettings{.file_path = ResourcePath(video_info.name, "yuv"),
|
|
.resolution = video_info.resolution,
|
|
.framerate = video_info.framerate};
|
|
}
|
|
|
|
std::string CodecNameToCodecType(std::string name) {
|
|
if (name.find("av1") != std::string::npos) {
|
|
return "AV1";
|
|
}
|
|
if (name.find("vp9") != std::string::npos) {
|
|
return "VP9";
|
|
}
|
|
if (name.find("vp8") != std::string::npos) {
|
|
return "VP8";
|
|
}
|
|
if (name.find("h264") != std::string::npos) {
|
|
return "H264";
|
|
}
|
|
if (name.find("h265") != std::string::npos) {
|
|
return "H265";
|
|
}
|
|
RTC_CHECK_NOTREACHED();
|
|
}
|
|
|
|
// TODO(webrtc:14852): Make Create[Encoder,Decoder]Factory to work with codec
|
|
// name directly.
|
|
std::string CodecNameToCodecImpl(std::string name) {
|
|
if (name.find("hw") != std::string::npos) {
|
|
return "mediacodec";
|
|
}
|
|
return "builtin";
|
|
}
|
|
|
|
std::unique_ptr<VideoEncoderFactory> CreateEncoderFactory(std::string impl) {
|
|
if (impl == "builtin") {
|
|
return CreateBuiltinVideoEncoderFactory();
|
|
}
|
|
#if defined(WEBRTC_ANDROID)
|
|
InitializeAndroidObjects();
|
|
return CreateAndroidEncoderFactory();
|
|
#else
|
|
return nullptr;
|
|
#endif
|
|
}
|
|
|
|
std::unique_ptr<VideoDecoderFactory> CreateDecoderFactory(std::string impl) {
|
|
if (impl == "builtin") {
|
|
return CreateBuiltinVideoDecoderFactory();
|
|
}
|
|
#if defined(WEBRTC_ANDROID)
|
|
InitializeAndroidObjects();
|
|
return CreateAndroidDecoderFactory();
|
|
#else
|
|
return nullptr;
|
|
#endif
|
|
}
|
|
|
|
std::string TestName() {
|
|
std::string test_name = absl::GetFlag(FLAGS_test_name);
|
|
if (!test_name.empty()) {
|
|
return test_name;
|
|
}
|
|
return ::testing::UnitTest::GetInstance()->current_test_info()->name();
|
|
}
|
|
|
|
std::string TestOutputPath() {
|
|
std::string output_path =
|
|
(rtc::StringBuilder() << OutputPath() << TestName()).str();
|
|
std::string output_dir = DirName(output_path);
|
|
bool result = CreateDir(output_dir);
|
|
RTC_CHECK(result) << "Cannot create " << output_dir;
|
|
return output_path;
|
|
}
|
|
} // namespace
|
|
|
|
std::unique_ptr<VideoCodecStats> RunEncodeDecodeTest(
|
|
const Environment& env,
|
|
std::string encoder_impl,
|
|
std::string decoder_impl,
|
|
const VideoSourceSettings& source_settings,
|
|
const std::map<uint32_t, EncodingSettings>& encoding_settings) {
|
|
const SdpVideoFormat& sdp_video_format =
|
|
encoding_settings.begin()->second.sdp_video_format;
|
|
|
|
std::unique_ptr<VideoEncoderFactory> encoder_factory =
|
|
CreateEncoderFactory(encoder_impl);
|
|
if (!encoder_factory
|
|
->QueryCodecSupport(sdp_video_format,
|
|
/*scalability_mode=*/absl::nullopt)
|
|
.is_supported) {
|
|
RTC_LOG(LS_WARNING) << "No " << encoder_impl << " encoder for video format "
|
|
<< sdp_video_format.ToString();
|
|
return nullptr;
|
|
}
|
|
|
|
std::unique_ptr<VideoDecoderFactory> decoder_factory =
|
|
CreateDecoderFactory(decoder_impl);
|
|
if (!decoder_factory
|
|
->QueryCodecSupport(sdp_video_format,
|
|
/*reference_scaling=*/false)
|
|
.is_supported) {
|
|
RTC_LOG(LS_WARNING) << "No " << decoder_impl << " decoder for video format "
|
|
<< sdp_video_format.ToString()
|
|
<< ". Trying built-in decoder.";
|
|
// TODO(ssilkin): No H264 support in ffmpeg on ARM. Consider trying HW
|
|
// decoder.
|
|
decoder_factory = CreateDecoderFactory("builtin");
|
|
if (!decoder_factory
|
|
->QueryCodecSupport(sdp_video_format,
|
|
/*reference_scaling=*/false)
|
|
.is_supported) {
|
|
RTC_LOG(LS_WARNING) << "No " << decoder_impl
|
|
<< " decoder for video format "
|
|
<< sdp_video_format.ToString();
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
std::string output_path = TestOutputPath();
|
|
|
|
VideoCodecTester::EncoderSettings encoder_settings;
|
|
encoder_settings.pacing_settings.mode =
|
|
encoder_impl == "builtin" ? PacingMode::kNoPacing : PacingMode::kRealTime;
|
|
if (absl::GetFlag(FLAGS_dump_encoder_input)) {
|
|
encoder_settings.encoder_input_base_path = output_path + "_enc_input";
|
|
}
|
|
if (absl::GetFlag(FLAGS_dump_encoder_output)) {
|
|
encoder_settings.encoder_output_base_path = output_path + "_enc_output";
|
|
}
|
|
|
|
VideoCodecTester::DecoderSettings decoder_settings;
|
|
decoder_settings.pacing_settings.mode =
|
|
decoder_impl == "builtin" ? PacingMode::kNoPacing : PacingMode::kRealTime;
|
|
if (absl::GetFlag(FLAGS_dump_decoder_input)) {
|
|
decoder_settings.decoder_input_base_path = output_path + "_dec_input";
|
|
}
|
|
if (absl::GetFlag(FLAGS_dump_decoder_output)) {
|
|
decoder_settings.decoder_output_base_path = output_path + "_dec_output";
|
|
}
|
|
|
|
return VideoCodecTester::RunEncodeDecodeTest(
|
|
env, source_settings, encoder_factory.get(), decoder_factory.get(),
|
|
encoder_settings, decoder_settings, encoding_settings);
|
|
}
|
|
|
|
std::unique_ptr<VideoCodecStats> RunEncodeTest(
|
|
const Environment& env,
|
|
std::string codec_type,
|
|
std::string codec_impl,
|
|
const VideoSourceSettings& source_settings,
|
|
const std::map<uint32_t, EncodingSettings>& encoding_settings) {
|
|
const SdpVideoFormat& sdp_video_format =
|
|
encoding_settings.begin()->second.sdp_video_format;
|
|
|
|
std::unique_ptr<VideoEncoderFactory> encoder_factory =
|
|
CreateEncoderFactory(codec_impl);
|
|
if (!encoder_factory
|
|
->QueryCodecSupport(sdp_video_format,
|
|
/*scalability_mode=*/absl::nullopt)
|
|
.is_supported) {
|
|
RTC_LOG(LS_WARNING) << "No encoder for video format "
|
|
<< sdp_video_format.ToString();
|
|
return nullptr;
|
|
}
|
|
|
|
std::string output_path = TestOutputPath();
|
|
VideoCodecTester::EncoderSettings encoder_settings;
|
|
encoder_settings.pacing_settings.mode =
|
|
codec_impl == "builtin" ? PacingMode::kNoPacing : PacingMode::kRealTime;
|
|
if (absl::GetFlag(FLAGS_dump_encoder_input)) {
|
|
encoder_settings.encoder_input_base_path = output_path + "_enc_input";
|
|
}
|
|
if (absl::GetFlag(FLAGS_dump_encoder_output)) {
|
|
encoder_settings.encoder_output_base_path = output_path + "_enc_output";
|
|
}
|
|
|
|
return VideoCodecTester::RunEncodeTest(env, source_settings,
|
|
encoder_factory.get(),
|
|
encoder_settings, encoding_settings);
|
|
}
|
|
|
|
class SpatialQualityTest : public ::testing::TestWithParam<std::tuple<
|
|
/*codec_type=*/std::string,
|
|
/*codec_impl=*/std::string,
|
|
VideoInfo,
|
|
std::tuple</*width=*/int,
|
|
/*height=*/int,
|
|
/*framerate_fps=*/double,
|
|
/*bitrate_kbps=*/int,
|
|
/*expected_min_psnr=*/double>>> {
|
|
public:
|
|
static std::string TestParamsToString(
|
|
const ::testing::TestParamInfo<SpatialQualityTest::ParamType>& info) {
|
|
auto [codec_type, codec_impl, video_info, coding_settings] = info.param;
|
|
auto [width, height, framerate_fps, bitrate_kbps, psnr] = coding_settings;
|
|
return std::string(codec_type + codec_impl + video_info.name +
|
|
std::to_string(width) + "x" + std::to_string(height) +
|
|
"p" +
|
|
std::to_string(static_cast<int>(1000 * framerate_fps)) +
|
|
"mhz" + std::to_string(bitrate_kbps) + "kbps");
|
|
}
|
|
};
|
|
|
|
TEST_P(SpatialQualityTest, SpatialQuality) {
|
|
const Environment env = CreateEnvironment();
|
|
auto [codec_type, codec_impl, video_info, coding_settings] = GetParam();
|
|
auto [width, height, framerate_fps, bitrate_kbps, expected_min_psnr] =
|
|
coding_settings;
|
|
int duration_s = 10;
|
|
int num_frames = duration_s * framerate_fps;
|
|
|
|
VideoSourceSettings source_settings = ToSourceSettings(video_info);
|
|
|
|
EncodingSettings encoding_settings = VideoCodecTester::CreateEncodingSettings(
|
|
codec_type, /*scalability_mode=*/"L1T1", width, height,
|
|
{DataRate::KilobitsPerSec(bitrate_kbps)},
|
|
Frequency::Hertz(framerate_fps));
|
|
|
|
std::map<uint32_t, EncodingSettings> frame_settings =
|
|
VideoCodecTester::CreateFrameSettings(encoding_settings, num_frames);
|
|
|
|
std::unique_ptr<VideoCodecStats> stats = RunEncodeDecodeTest(
|
|
env, codec_impl, codec_impl, source_settings, frame_settings);
|
|
|
|
VideoCodecStats::Stream stream;
|
|
if (stats != nullptr) {
|
|
stream = stats->Aggregate(Filter{});
|
|
if (absl::GetFlag(FLAGS_webrtc_quick_perf_test)) {
|
|
EXPECT_GE(stream.psnr.y.GetAverage(), expected_min_psnr);
|
|
}
|
|
}
|
|
|
|
stream.LogMetrics(
|
|
GetGlobalMetricsLogger(),
|
|
::testing::UnitTest::GetInstance()->current_test_info()->name(),
|
|
/*prefix=*/"",
|
|
/*metadata=*/
|
|
{{"video_name", video_info.name},
|
|
{"codec_type", codec_type},
|
|
{"codec_impl", codec_impl}});
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
All,
|
|
SpatialQualityTest,
|
|
Combine(Values("AV1", "VP9", "VP8", "H264", "H265"),
|
|
#if defined(WEBRTC_ANDROID)
|
|
Values("builtin", "mediacodec"),
|
|
#else
|
|
Values("builtin"),
|
|
#endif
|
|
Values(kFourPeople_1280x720_30),
|
|
Values(std::make_tuple(320, 180, 30, 32, 26),
|
|
std::make_tuple(320, 180, 30, 64, 29),
|
|
std::make_tuple(320, 180, 30, 128, 32),
|
|
std::make_tuple(320, 180, 30, 256, 36),
|
|
std::make_tuple(640, 360, 30, 128, 29),
|
|
std::make_tuple(640, 360, 30, 256, 33),
|
|
std::make_tuple(640, 360, 30, 384, 35),
|
|
std::make_tuple(640, 360, 30, 512, 36),
|
|
std::make_tuple(1280, 720, 30, 256, 30),
|
|
std::make_tuple(1280, 720, 30, 512, 34),
|
|
std::make_tuple(1280, 720, 30, 1024, 37),
|
|
std::make_tuple(1280, 720, 30, 2048, 39))),
|
|
SpatialQualityTest::TestParamsToString);
|
|
|
|
class BitrateAdaptationTest
|
|
: public ::testing::TestWithParam<
|
|
std::tuple</*codec_type=*/std::string,
|
|
/*codec_impl=*/std::string,
|
|
VideoInfo,
|
|
std::pair</*bitrate_kbps=*/int, /*bitrate_kbps=*/int>>> {
|
|
public:
|
|
static std::string TestParamsToString(
|
|
const ::testing::TestParamInfo<BitrateAdaptationTest::ParamType>& info) {
|
|
auto [codec_type, codec_impl, video_info, bitrate_kbps] = info.param;
|
|
return std::string(codec_type + codec_impl + video_info.name +
|
|
std::to_string(bitrate_kbps.first) + "kbps" +
|
|
std::to_string(bitrate_kbps.second) + "kbps");
|
|
}
|
|
};
|
|
|
|
TEST_P(BitrateAdaptationTest, BitrateAdaptation) {
|
|
auto [codec_type, codec_impl, video_info, bitrate_kbps] = GetParam();
|
|
const Environment env = CreateEnvironment();
|
|
|
|
int duration_s = 10; // Duration of fixed rate interval.
|
|
int num_frames =
|
|
static_cast<int>(duration_s * video_info.framerate.hertz<double>());
|
|
|
|
VideoSourceSettings source_settings = ToSourceSettings(video_info);
|
|
|
|
EncodingSettings encoding_settings = VideoCodecTester::CreateEncodingSettings(
|
|
codec_type, /*scalability_mode=*/"L1T1",
|
|
/*width=*/640, /*height=*/360,
|
|
{DataRate::KilobitsPerSec(bitrate_kbps.first)},
|
|
/*framerate=*/Frequency::Hertz(30));
|
|
|
|
EncodingSettings encoding_settings2 =
|
|
VideoCodecTester::CreateEncodingSettings(
|
|
codec_type, /*scalability_mode=*/"L1T1",
|
|
/*width=*/640, /*height=*/360,
|
|
{DataRate::KilobitsPerSec(bitrate_kbps.second)},
|
|
/*framerate=*/Frequency::Hertz(30));
|
|
|
|
std::map<uint32_t, EncodingSettings> frame_settings =
|
|
VideoCodecTester::CreateFrameSettings(encoding_settings, num_frames);
|
|
|
|
uint32_t timestamp_rtp =
|
|
frame_settings.rbegin()->first + k90kHz / Frequency::Hertz(30);
|
|
std::map<uint32_t, EncodingSettings> frame_settings2 =
|
|
VideoCodecTester::CreateFrameSettings(encoding_settings2, num_frames,
|
|
timestamp_rtp);
|
|
|
|
frame_settings.merge(frame_settings2);
|
|
|
|
std::unique_ptr<VideoCodecStats> stats = RunEncodeTest(
|
|
env, codec_type, codec_impl, source_settings, frame_settings);
|
|
|
|
VideoCodecStats::Stream stream;
|
|
if (stats != nullptr) {
|
|
stream = stats->Aggregate({.min_timestamp_rtp = timestamp_rtp});
|
|
if (absl::GetFlag(FLAGS_webrtc_quick_perf_test)) {
|
|
EXPECT_NEAR(stream.bitrate_mismatch_pct.GetAverage(), 0, 10);
|
|
EXPECT_NEAR(stream.framerate_mismatch_pct.GetAverage(), 0, 10);
|
|
}
|
|
}
|
|
|
|
stream.LogMetrics(
|
|
GetGlobalMetricsLogger(),
|
|
::testing::UnitTest::GetInstance()->current_test_info()->name(),
|
|
/*prefix=*/"",
|
|
/*metadata=*/
|
|
{{"codec_type", codec_type},
|
|
{"codec_impl", codec_impl},
|
|
{"video_name", video_info.name},
|
|
{"rate_profile", std::to_string(bitrate_kbps.first) + "," +
|
|
std::to_string(bitrate_kbps.second)}});
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(All,
|
|
BitrateAdaptationTest,
|
|
Combine(Values("AV1", "VP9", "VP8", "H264", "H265"),
|
|
#if defined(WEBRTC_ANDROID)
|
|
Values("builtin", "mediacodec"),
|
|
#else
|
|
Values("builtin"),
|
|
#endif
|
|
Values(kFourPeople_1280x720_30),
|
|
Values(std::pair(1024, 512),
|
|
std::pair(512, 1024))),
|
|
BitrateAdaptationTest::TestParamsToString);
|
|
|
|
class FramerateAdaptationTest
|
|
: public ::testing::TestWithParam<std::tuple</*codec_type=*/std::string,
|
|
/*codec_impl=*/std::string,
|
|
VideoInfo,
|
|
std::pair<double, double>>> {
|
|
public:
|
|
static std::string TestParamsToString(
|
|
const ::testing::TestParamInfo<FramerateAdaptationTest::ParamType>&
|
|
info) {
|
|
auto [codec_type, codec_impl, video_info, framerate_fps] = info.param;
|
|
return std::string(
|
|
codec_type + codec_impl + video_info.name +
|
|
std::to_string(static_cast<int>(1000 * framerate_fps.first)) + "mhz" +
|
|
std::to_string(static_cast<int>(1000 * framerate_fps.second)) + "mhz");
|
|
}
|
|
};
|
|
|
|
TEST_P(FramerateAdaptationTest, FramerateAdaptation) {
|
|
auto [codec_type, codec_impl, video_info, framerate_fps] = GetParam();
|
|
const Environment env = CreateEnvironment();
|
|
|
|
int duration_s = 10; // Duration of fixed rate interval.
|
|
|
|
VideoSourceSettings source_settings = ToSourceSettings(video_info);
|
|
|
|
EncodingSettings encoding_settings = VideoCodecTester::CreateEncodingSettings(
|
|
codec_type, /*scalability_mode=*/"L1T1",
|
|
/*width=*/640, /*height=*/360,
|
|
/*bitrate=*/{DataRate::KilobitsPerSec(512)},
|
|
Frequency::Hertz(framerate_fps.first));
|
|
|
|
EncodingSettings encoding_settings2 =
|
|
VideoCodecTester::CreateEncodingSettings(
|
|
codec_type, /*scalability_mode=*/"L1T1",
|
|
/*width=*/640, /*height=*/360,
|
|
/*bitrate=*/{DataRate::KilobitsPerSec(512)},
|
|
Frequency::Hertz(framerate_fps.second));
|
|
|
|
int num_frames = static_cast<int>(duration_s * framerate_fps.first);
|
|
std::map<uint32_t, EncodingSettings> frame_settings =
|
|
VideoCodecTester::CreateFrameSettings(encoding_settings, num_frames);
|
|
|
|
uint32_t timestamp_rtp = frame_settings.rbegin()->first +
|
|
k90kHz / Frequency::Hertz(framerate_fps.first);
|
|
|
|
num_frames = static_cast<int>(duration_s * framerate_fps.second);
|
|
std::map<uint32_t, EncodingSettings> frame_settings2 =
|
|
VideoCodecTester::CreateFrameSettings(encoding_settings2, num_frames,
|
|
timestamp_rtp);
|
|
|
|
frame_settings.merge(frame_settings2);
|
|
|
|
std::unique_ptr<VideoCodecStats> stats = RunEncodeTest(
|
|
env, codec_type, codec_impl, source_settings, frame_settings);
|
|
|
|
VideoCodecStats::Stream stream;
|
|
if (stats != nullptr) {
|
|
stream = stats->Aggregate({.min_timestamp_rtp = timestamp_rtp});
|
|
if (absl::GetFlag(FLAGS_webrtc_quick_perf_test)) {
|
|
EXPECT_NEAR(stream.bitrate_mismatch_pct.GetAverage(), 0, 10);
|
|
EXPECT_NEAR(stream.framerate_mismatch_pct.GetAverage(), 0, 10);
|
|
}
|
|
}
|
|
|
|
stream.LogMetrics(
|
|
GetGlobalMetricsLogger(),
|
|
::testing::UnitTest::GetInstance()->current_test_info()->name(),
|
|
/*prefix=*/"",
|
|
/*metadata=*/
|
|
{{"codec_type", codec_type},
|
|
{"codec_impl", codec_impl},
|
|
{"video_name", video_info.name},
|
|
{"rate_profile", std::to_string(framerate_fps.first) + "," +
|
|
std::to_string(framerate_fps.second)}});
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(All,
|
|
FramerateAdaptationTest,
|
|
Combine(Values("AV1", "VP9", "VP8", "H264", "H265"),
|
|
#if defined(WEBRTC_ANDROID)
|
|
Values("builtin", "mediacodec"),
|
|
#else
|
|
Values("builtin"),
|
|
#endif
|
|
Values(kFourPeople_1280x720_30),
|
|
Values(std::pair(30, 15), std::pair(15, 30))),
|
|
FramerateAdaptationTest::TestParamsToString);
|
|
|
|
TEST(VideoCodecTest, DISABLED_EncodeDecode) {
|
|
ScopedFieldTrials field_trials(absl::GetFlag(FLAGS_field_trials));
|
|
const Environment env =
|
|
CreateEnvironment(std::make_unique<ExplicitKeyValueConfig>(
|
|
absl::GetFlag(FLAGS_field_trials)));
|
|
|
|
VideoSourceSettings source_settings{
|
|
.file_path = absl::GetFlag(FLAGS_input_path),
|
|
.resolution = {.width = absl::GetFlag(FLAGS_input_width),
|
|
.height = absl::GetFlag(FLAGS_input_height)},
|
|
.framerate =
|
|
Frequency::Hertz<double>(absl::GetFlag(FLAGS_input_framerate_fps))};
|
|
|
|
std::vector<std::string> bitrate_str = absl::GetFlag(FLAGS_bitrate_kbps);
|
|
std::vector<DataRate> bitrate;
|
|
std::transform(bitrate_str.begin(), bitrate_str.end(),
|
|
std::back_inserter(bitrate), [](const std::string& str) {
|
|
return DataRate::KilobitsPerSec(std::stoi(str));
|
|
});
|
|
|
|
Frequency framerate = Frequency::Hertz<double>(
|
|
absl::GetFlag(FLAGS_framerate_fps)
|
|
.value_or(absl::GetFlag(FLAGS_input_framerate_fps)));
|
|
|
|
EncodingSettings encoding_settings = VideoCodecTester::CreateEncodingSettings(
|
|
CodecNameToCodecType(absl::GetFlag(FLAGS_encoder)),
|
|
absl::GetFlag(FLAGS_scalability_mode),
|
|
absl::GetFlag(FLAGS_width).value_or(absl::GetFlag(FLAGS_input_width)),
|
|
absl::GetFlag(FLAGS_height).value_or(absl::GetFlag(FLAGS_input_height)),
|
|
{bitrate}, framerate, absl::GetFlag(FLAGS_screencast),
|
|
absl::GetFlag(FLAGS_frame_drop));
|
|
|
|
int num_frames = absl::GetFlag(FLAGS_num_frames);
|
|
int key_interval = absl::GetFlag(FLAGS_key_interval);
|
|
uint32_t timestamp_rtp = 90000;
|
|
std::map<uint32_t, EncodingSettings> frame_settings;
|
|
for (int frame_num = 0; frame_num < num_frames; ++frame_num) {
|
|
encoding_settings.keyframe = (frame_num % (key_interval + 1) == 0);
|
|
frame_settings.emplace(timestamp_rtp, encoding_settings);
|
|
timestamp_rtp += k90kHz / framerate;
|
|
}
|
|
|
|
// TODO(webrtc:14852): Pass encoder and decoder names directly, and update
|
|
// logged test name (implies lossing history in the chromeperf dashboard).
|
|
// Sync with changes in Stream::LogMetrics (see TODOs there).
|
|
std::unique_ptr<VideoCodecStats> stats = RunEncodeDecodeTest(
|
|
env, CodecNameToCodecImpl(absl::GetFlag(FLAGS_encoder)),
|
|
CodecNameToCodecImpl(absl::GetFlag(FLAGS_decoder)), source_settings,
|
|
frame_settings);
|
|
ASSERT_NE(nullptr, stats);
|
|
|
|
// Log unsliced metrics.
|
|
VideoCodecStats::Stream stream = stats->Aggregate(Filter{});
|
|
stream.LogMetrics(GetGlobalMetricsLogger(), TestName(), /*prefix=*/"",
|
|
/*metadata=*/{});
|
|
|
|
// Log metrics sliced on spatial and temporal layer.
|
|
ScalabilityMode scalability_mode =
|
|
*ScalabilityModeFromString(absl::GetFlag(FLAGS_scalability_mode));
|
|
int num_spatial_layers = ScalabilityModeToNumSpatialLayers(scalability_mode);
|
|
int num_temporal_layers =
|
|
ScalabilityModeToNumTemporalLayers(scalability_mode);
|
|
for (int sidx = 0; sidx < num_spatial_layers; ++sidx) {
|
|
for (int tidx = 0; tidx < num_temporal_layers; ++tidx) {
|
|
std::string metric_name_prefix =
|
|
(rtc::StringBuilder() << "s" << sidx << "t" << tidx << "_").str();
|
|
stream = stats->Aggregate(
|
|
{.layer_id = {{.spatial_idx = sidx, .temporal_idx = tidx}}});
|
|
stream.LogMetrics(GetGlobalMetricsLogger(), TestName(),
|
|
metric_name_prefix,
|
|
/*metadata=*/{});
|
|
}
|
|
}
|
|
|
|
if (absl::GetFlag(FLAGS_write_csv)) {
|
|
stats->LogMetrics(
|
|
(rtc::StringBuilder() << TestOutputPath() << ".csv").str(),
|
|
stats->Slice(Filter{}, /*merge=*/false), /*metadata=*/
|
|
{{"test_name", TestName()}});
|
|
}
|
|
}
|
|
|
|
} // namespace test
|
|
|
|
} // namespace webrtc
|