Added an encode/decode test parameterizable via command line
This enables testing different settings without updating code and rebuilding the test binary. Example of command: video_codec_perf_tests --gtest_also_run_disabled_tests --gtest_filter=*EncodeDecode --encoder=libaom-av1 --decoder=dav1d --scalability_mode=L1T3 --bitrate_kbps=100,200,300 --framerate_fps=30 --write_csv Also added writing per-frame stats to a CSV. It is more convenient to work with CSV than to parse metrics proto. Bug: webrtc:14852 Change-Id: I1b3970f7ffa88c016133197aff585de5bc4e35c6 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/327600 Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org> Commit-Queue: Sergey Silkin <ssilkin@webrtc.org> Reviewed-by: Rasmus Brandt <brandtr@webrtc.org> Cr-Commit-Position: refs/heads/main@{#41179}
This commit is contained in:
parent
b6d69708fe
commit
496893e89e
@ -1005,7 +1005,9 @@ if (rtc_include_tests) {
|
|||||||
"../../api/video:resolution",
|
"../../api/video:resolution",
|
||||||
"../../api/video_codecs:builtin_video_decoder_factory",
|
"../../api/video_codecs:builtin_video_decoder_factory",
|
||||||
"../../api/video_codecs:builtin_video_encoder_factory",
|
"../../api/video_codecs:builtin_video_encoder_factory",
|
||||||
|
"../../modules/video_coding/svc:scalability_mode_util",
|
||||||
"../../rtc_base:logging",
|
"../../rtc_base:logging",
|
||||||
|
"../../rtc_base:stringutils",
|
||||||
"../../test:fileutils",
|
"../../test:fileutils",
|
||||||
"../../test:test_flags",
|
"../../test:test_flags",
|
||||||
"../../test:test_main",
|
"../../test:test_main",
|
||||||
|
|||||||
@ -23,19 +23,48 @@
|
|||||||
#if defined(WEBRTC_ANDROID)
|
#if defined(WEBRTC_ANDROID)
|
||||||
#include "modules/video_coding/codecs/test/android_codec_factory_helper.h"
|
#include "modules/video_coding/codecs/test/android_codec_factory_helper.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include "modules/video_coding/svc/scalability_mode_util.h"
|
||||||
#include "rtc_base/logging.h"
|
#include "rtc_base/logging.h"
|
||||||
|
#include "rtc_base/strings/str_join.h"
|
||||||
|
#include "rtc_base/strings/string_builder.h"
|
||||||
#include "test/gtest.h"
|
#include "test/gtest.h"
|
||||||
#include "test/test_flags.h"
|
#include "test/test_flags.h"
|
||||||
#include "test/testsupport/file_utils.h"
|
#include "test/testsupport/file_utils.h"
|
||||||
#include "test/video_codec_tester.h"
|
#include "test/video_codec_tester.h"
|
||||||
|
|
||||||
|
ABSL_FLAG(std::string,
|
||||||
|
video_name,
|
||||||
|
"FourPeople_1280x720_30",
|
||||||
|
"Name of input video sequence.");
|
||||||
|
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(int, width, 1280, "Width.");
|
||||||
|
ABSL_FLAG(int, height, 720, "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(double,
|
||||||
|
framerate_fps,
|
||||||
|
30.0,
|
||||||
|
"Encode target frame rate of the top temporal layer in fps.");
|
||||||
|
ABSL_FLAG(int, num_frames, 300, "Number of frames to encode and/or decode.");
|
||||||
|
ABSL_FLAG(std::string, test_name, "", "Test name.");
|
||||||
ABSL_FLAG(bool, dump_decoder_input, false, "Dump decoder input.");
|
ABSL_FLAG(bool, dump_decoder_input, false, "Dump decoder input.");
|
||||||
|
|
||||||
ABSL_FLAG(bool, dump_decoder_output, false, "Dump decoder output.");
|
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_input, false, "Dump encoder input.");
|
||||||
|
|
||||||
ABSL_FLAG(bool, dump_encoder_output, false, "Dump encoder output.");
|
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 webrtc {
|
||||||
namespace test {
|
namespace test {
|
||||||
@ -55,13 +84,58 @@ struct VideoInfo {
|
|||||||
Frequency framerate;
|
Frequency framerate;
|
||||||
};
|
};
|
||||||
|
|
||||||
const VideoInfo kFourPeople_1280x720_30 = {
|
const std::map<std::string, VideoInfo> kRawVideos = {
|
||||||
.name = "FourPeople_1280x720_30",
|
{"FourPeople_1280x720_30",
|
||||||
.resolution = {.width = 1280, .height = 720},
|
{.name = "FourPeople_1280x720_30",
|
||||||
.framerate = Frequency::Hertz(30)};
|
.resolution = {.width = 1280, .height = 720},
|
||||||
|
.framerate = Frequency::Hertz(30)}},
|
||||||
|
{"vidyo1_1280x720_30",
|
||||||
|
{.name = "vidyo1_1280x720_30",
|
||||||
|
.resolution = {.width = 1280, .height = 720},
|
||||||
|
.framerate = Frequency::Hertz(30)}},
|
||||||
|
{"vidyo4_1280x720_30",
|
||||||
|
{.name = "vidyo4_1280x720_30",
|
||||||
|
.resolution = {.width = 1280, .height = 720},
|
||||||
|
.framerate = Frequency::Hertz(30)}},
|
||||||
|
{"KristenAndSara_1280x720_30",
|
||||||
|
{.name = "KristenAndSara_1280x720_30",
|
||||||
|
.resolution = {.width = 1280, .height = 720},
|
||||||
|
.framerate = Frequency::Hertz(30)}},
|
||||||
|
{"Johnny_1280x720_30",
|
||||||
|
{.name = "Johnny_1280x720_30",
|
||||||
|
.resolution = {.width = 1280, .height = 720},
|
||||||
|
.framerate = Frequency::Hertz(30)}}};
|
||||||
|
|
||||||
static constexpr Frequency k90kHz = Frequency::Hertz(90000);
|
static constexpr Frequency k90kHz = Frequency::Hertz(90000);
|
||||||
|
|
||||||
|
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) {
|
std::unique_ptr<VideoEncoderFactory> CreateEncoderFactory(std::string impl) {
|
||||||
if (impl == "builtin") {
|
if (impl == "builtin") {
|
||||||
return CreateBuiltinVideoEncoderFactory();
|
return CreateBuiltinVideoEncoderFactory();
|
||||||
@ -86,10 +160,17 @@ std::unique_ptr<VideoDecoderFactory> CreateDecoderFactory(std::string impl) {
|
|||||||
#endif
|
#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 TestOutputPath() {
|
||||||
std::string output_path =
|
std::string output_path =
|
||||||
OutputPath() +
|
(rtc::StringBuilder() << OutputPath() << TestName()).str();
|
||||||
::testing::UnitTest::GetInstance()->current_test_info()->name();
|
|
||||||
std::string output_dir = DirName(output_path);
|
std::string output_dir = DirName(output_path);
|
||||||
bool result = CreateDir(output_dir);
|
bool result = CreateDir(output_dir);
|
||||||
RTC_CHECK(result) << "Cannot create " << output_dir;
|
RTC_CHECK(result) << "Cannot create " << output_dir;
|
||||||
@ -98,7 +179,6 @@ std::string TestOutputPath() {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
std::unique_ptr<VideoCodecStats> RunEncodeDecodeTest(
|
std::unique_ptr<VideoCodecStats> RunEncodeDecodeTest(
|
||||||
std::string codec_type,
|
|
||||||
std::string codec_impl,
|
std::string codec_impl,
|
||||||
const VideoInfo& video_info,
|
const VideoInfo& video_info,
|
||||||
const std::map<uint32_t, EncodingSettings>& encoding_settings) {
|
const std::map<uint32_t, EncodingSettings>& encoding_settings) {
|
||||||
@ -239,7 +319,7 @@ TEST_P(SpatialQualityTest, SpatialQuality) {
|
|||||||
{bitrate_kbps}, framerate_fps, num_frames);
|
{bitrate_kbps}, framerate_fps, num_frames);
|
||||||
|
|
||||||
std::unique_ptr<VideoCodecStats> stats =
|
std::unique_ptr<VideoCodecStats> stats =
|
||||||
RunEncodeDecodeTest(codec_type, codec_impl, video_info, frames_settings);
|
RunEncodeDecodeTest(codec_impl, video_info, frames_settings);
|
||||||
|
|
||||||
VideoCodecStats::Stream stream;
|
VideoCodecStats::Stream stream;
|
||||||
if (stats != nullptr) {
|
if (stats != nullptr) {
|
||||||
@ -252,6 +332,7 @@ TEST_P(SpatialQualityTest, SpatialQuality) {
|
|||||||
stream.LogMetrics(
|
stream.LogMetrics(
|
||||||
GetGlobalMetricsLogger(),
|
GetGlobalMetricsLogger(),
|
||||||
::testing::UnitTest::GetInstance()->current_test_info()->name(),
|
::testing::UnitTest::GetInstance()->current_test_info()->name(),
|
||||||
|
/*prefix=*/"",
|
||||||
/*metadata=*/
|
/*metadata=*/
|
||||||
{{"video_name", video_info.name},
|
{{"video_name", video_info.name},
|
||||||
{"codec_type", codec_type},
|
{"codec_type", codec_type},
|
||||||
@ -267,7 +348,7 @@ INSTANTIATE_TEST_SUITE_P(
|
|||||||
#else
|
#else
|
||||||
Values("builtin"),
|
Values("builtin"),
|
||||||
#endif
|
#endif
|
||||||
Values(kFourPeople_1280x720_30),
|
Values(kRawVideos.at("FourPeople_1280x720_30")),
|
||||||
Values(std::make_tuple(320, 180, 30, 32, 28),
|
Values(std::make_tuple(320, 180, 30, 32, 28),
|
||||||
std::make_tuple(320, 180, 30, 64, 30),
|
std::make_tuple(320, 180, 30, 64, 30),
|
||||||
std::make_tuple(320, 180, 30, 128, 33),
|
std::make_tuple(320, 180, 30, 128, 33),
|
||||||
@ -337,6 +418,7 @@ TEST_P(BitrateAdaptationTest, BitrateAdaptation) {
|
|||||||
stream.LogMetrics(
|
stream.LogMetrics(
|
||||||
GetGlobalMetricsLogger(),
|
GetGlobalMetricsLogger(),
|
||||||
::testing::UnitTest::GetInstance()->current_test_info()->name(),
|
::testing::UnitTest::GetInstance()->current_test_info()->name(),
|
||||||
|
/*prefix=*/"",
|
||||||
/*metadata=*/
|
/*metadata=*/
|
||||||
{{"codec_type", codec_type},
|
{{"codec_type", codec_type},
|
||||||
{"codec_impl", codec_impl},
|
{"codec_impl", codec_impl},
|
||||||
@ -345,18 +427,18 @@ TEST_P(BitrateAdaptationTest, BitrateAdaptation) {
|
|||||||
std::to_string(bitrate_kbps.second)}});
|
std::to_string(bitrate_kbps.second)}});
|
||||||
}
|
}
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(All,
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
BitrateAdaptationTest,
|
All,
|
||||||
Combine(Values("AV1", "VP9", "VP8", "H264", "H265"),
|
BitrateAdaptationTest,
|
||||||
|
Combine(Values("AV1", "VP9", "VP8", "H264", "H265"),
|
||||||
#if defined(WEBRTC_ANDROID)
|
#if defined(WEBRTC_ANDROID)
|
||||||
Values("builtin", "mediacodec"),
|
Values("builtin", "mediacodec"),
|
||||||
#else
|
#else
|
||||||
Values("builtin"),
|
Values("builtin"),
|
||||||
#endif
|
#endif
|
||||||
Values(kFourPeople_1280x720_30),
|
Values(kRawVideos.at("FourPeople_1280x720_30")),
|
||||||
Values(std::pair(1024, 512),
|
Values(std::pair(1024, 512), std::pair(512, 1024))),
|
||||||
std::pair(512, 1024))),
|
BitrateAdaptationTest::TestParamsToString);
|
||||||
BitrateAdaptationTest::TestParamsToString);
|
|
||||||
|
|
||||||
class FramerateAdaptationTest
|
class FramerateAdaptationTest
|
||||||
: public ::testing::TestWithParam<std::tuple</*codec_type=*/std::string,
|
: public ::testing::TestWithParam<std::tuple</*codec_type=*/std::string,
|
||||||
@ -416,6 +498,7 @@ TEST_P(FramerateAdaptationTest, FramerateAdaptation) {
|
|||||||
stream.LogMetrics(
|
stream.LogMetrics(
|
||||||
GetGlobalMetricsLogger(),
|
GetGlobalMetricsLogger(),
|
||||||
::testing::UnitTest::GetInstance()->current_test_info()->name(),
|
::testing::UnitTest::GetInstance()->current_test_info()->name(),
|
||||||
|
/*prefix=*/"",
|
||||||
/*metadata=*/
|
/*metadata=*/
|
||||||
{{"codec_type", codec_type},
|
{{"codec_type", codec_type},
|
||||||
{"codec_impl", codec_impl},
|
{"codec_impl", codec_impl},
|
||||||
@ -424,17 +507,72 @@ TEST_P(FramerateAdaptationTest, FramerateAdaptation) {
|
|||||||
std::to_string(framerate_fps.second)}});
|
std::to_string(framerate_fps.second)}});
|
||||||
}
|
}
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(All,
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
FramerateAdaptationTest,
|
All,
|
||||||
Combine(Values("AV1", "VP9", "VP8", "H264", "H265"),
|
FramerateAdaptationTest,
|
||||||
|
Combine(Values("AV1", "VP9", "VP8", "H264", "H265"),
|
||||||
#if defined(WEBRTC_ANDROID)
|
#if defined(WEBRTC_ANDROID)
|
||||||
Values("builtin", "mediacodec"),
|
Values("builtin", "mediacodec"),
|
||||||
#else
|
#else
|
||||||
Values("builtin"),
|
Values("builtin"),
|
||||||
#endif
|
#endif
|
||||||
Values(kFourPeople_1280x720_30),
|
Values(kRawVideos.at("FourPeople_1280x720_30")),
|
||||||
Values(std::pair(30, 15), std::pair(15, 30))),
|
Values(std::pair(30, 15), std::pair(15, 30))),
|
||||||
FramerateAdaptationTest::TestParamsToString);
|
FramerateAdaptationTest::TestParamsToString);
|
||||||
|
|
||||||
|
TEST(VideoCodecTest, DISABLED_EncodeDecode) {
|
||||||
|
std::vector<std::string> bitrate_str = absl::GetFlag(FLAGS_bitrate_kbps);
|
||||||
|
std::vector<int> bitrate_kbps;
|
||||||
|
std::transform(bitrate_str.begin(), bitrate_str.end(),
|
||||||
|
std::back_inserter(bitrate_kbps),
|
||||||
|
[](const std::string& str) { return std::stoi(str); });
|
||||||
|
|
||||||
|
std::map<uint32_t, EncodingSettings> frames_settings =
|
||||||
|
VideoCodecTester::CreateEncodingSettings(
|
||||||
|
CodecNameToCodecType(absl::GetFlag(FLAGS_encoder)),
|
||||||
|
absl::GetFlag(FLAGS_scalability_mode), absl::GetFlag(FLAGS_width),
|
||||||
|
absl::GetFlag(FLAGS_height), {bitrate_kbps},
|
||||||
|
absl::GetFlag(FLAGS_framerate_fps), absl::GetFlag(FLAGS_num_frames));
|
||||||
|
|
||||||
|
// 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(
|
||||||
|
CodecNameToCodecImpl(absl::GetFlag(FLAGS_encoder)),
|
||||||
|
kRawVideos.at(absl::GetFlag(FLAGS_video_name)), frames_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 test
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|||||||
@ -455,10 +455,12 @@ class VideoCodecAnalyzer : public VideoCodecTester::VideoCodecStats {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (filter.layer_id) {
|
if (filter.layer_id) {
|
||||||
if ((is_svc &&
|
if (is_svc &&
|
||||||
frame.layer_id.spatial_idx > filter.layer_id->spatial_idx) ||
|
frame.layer_id.spatial_idx > filter.layer_id->spatial_idx) {
|
||||||
(!is_svc &&
|
continue;
|
||||||
frame.layer_id.spatial_idx != filter.layer_id->spatial_idx)) {
|
}
|
||||||
|
if (!is_svc &&
|
||||||
|
frame.layer_id.spatial_idx != filter.layer_id->spatial_idx) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (frame.layer_id.temporal_idx > filter.layer_id->temporal_idx) {
|
if (frame.layer_id.temporal_idx > filter.layer_id->temporal_idx) {
|
||||||
@ -592,6 +594,61 @@ class VideoCodecAnalyzer : public VideoCodecTester::VideoCodecStats {
|
|||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LogMetrics(absl::string_view csv_path,
|
||||||
|
std::vector<Frame> frames,
|
||||||
|
std::map<std::string, std::string> metadata) const {
|
||||||
|
RTC_LOG(LS_INFO) << "Write metrics to " << csv_path;
|
||||||
|
FILE* csv_file = fopen(csv_path.data(), "w");
|
||||||
|
const std::string delimiter = ";";
|
||||||
|
rtc::StringBuilder header;
|
||||||
|
header
|
||||||
|
<< "timestamp_rtp;spatial_idx;temporal_idx;width;height;frame_size_"
|
||||||
|
"bytes;keyframe;qp;encode_time_us;decode_time_us;psnr_y_db;psnr_u_"
|
||||||
|
"db;psnr_v_db;target_bitrate_kbps;target_framerate_fps";
|
||||||
|
for (const auto& data : metadata) {
|
||||||
|
header << ";" << data.first;
|
||||||
|
}
|
||||||
|
fwrite(header.str().c_str(), 1, header.size(), csv_file);
|
||||||
|
|
||||||
|
for (const Frame& f : frames) {
|
||||||
|
rtc::StringBuilder row;
|
||||||
|
row << "\n" << f.timestamp_rtp;
|
||||||
|
row << ";" << f.layer_id.spatial_idx;
|
||||||
|
row << ";" << f.layer_id.temporal_idx;
|
||||||
|
row << ";" << f.width;
|
||||||
|
row << ";" << f.height;
|
||||||
|
row << ";" << f.frame_size.bytes();
|
||||||
|
row << ";" << f.keyframe;
|
||||||
|
row << ";";
|
||||||
|
if (f.qp) {
|
||||||
|
row << *f.qp;
|
||||||
|
}
|
||||||
|
row << ";" << f.encode_time.us();
|
||||||
|
row << ";" << f.decode_time.us();
|
||||||
|
if (f.psnr) {
|
||||||
|
row << ";" << f.psnr->y;
|
||||||
|
row << ";" << f.psnr->u;
|
||||||
|
row << ";" << f.psnr->v;
|
||||||
|
} else {
|
||||||
|
row << ";;;";
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& es = encoding_settings_.at(f.timestamp_rtp);
|
||||||
|
row << ";"
|
||||||
|
<< f.target_bitrate.value_or(GetTargetBitrate(es, f.layer_id)).kbps();
|
||||||
|
row << ";"
|
||||||
|
<< f.target_framerate.value_or(GetTargetFramerate(es, f.layer_id))
|
||||||
|
.hertz<double>();
|
||||||
|
|
||||||
|
for (const auto& data : metadata) {
|
||||||
|
row << ";" << data.second;
|
||||||
|
}
|
||||||
|
fwrite(row.str().c_str(), 1, row.size(), csv_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(csv_file);
|
||||||
|
}
|
||||||
|
|
||||||
void Flush() { task_queue_.WaitForPreviouslyPostedTasks(); }
|
void Flush() { task_queue_.WaitForPreviouslyPostedTasks(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -1077,55 +1134,60 @@ SplitBitrateAndUpdateScalabilityMode(std::string codec_type,
|
|||||||
void VideoCodecStats::Stream::LogMetrics(
|
void VideoCodecStats::Stream::LogMetrics(
|
||||||
MetricsLogger* logger,
|
MetricsLogger* logger,
|
||||||
std::string test_case_name,
|
std::string test_case_name,
|
||||||
|
std::string prefix,
|
||||||
std::map<std::string, std::string> metadata) const {
|
std::map<std::string, std::string> metadata) const {
|
||||||
logger->LogMetric("width", test_case_name, width, Unit::kCount,
|
logger->LogMetric(prefix + "width", test_case_name, width, Unit::kCount,
|
||||||
ImprovementDirection::kBiggerIsBetter, metadata);
|
ImprovementDirection::kBiggerIsBetter, metadata);
|
||||||
logger->LogMetric("height", test_case_name, height, Unit::kCount,
|
logger->LogMetric(prefix + "height", test_case_name, height, Unit::kCount,
|
||||||
ImprovementDirection::kBiggerIsBetter, metadata);
|
ImprovementDirection::kBiggerIsBetter, metadata);
|
||||||
logger->LogMetric("frame_size_bytes", test_case_name, frame_size_bytes,
|
logger->LogMetric(prefix + "frame_size_bytes", test_case_name,
|
||||||
Unit::kBytes, ImprovementDirection::kNeitherIsBetter,
|
frame_size_bytes, Unit::kBytes,
|
||||||
metadata);
|
ImprovementDirection::kNeitherIsBetter, metadata);
|
||||||
logger->LogMetric("keyframe", test_case_name, keyframe, Unit::kCount,
|
logger->LogMetric(prefix + "keyframe", test_case_name, keyframe, Unit::kCount,
|
||||||
ImprovementDirection::kSmallerIsBetter, metadata);
|
ImprovementDirection::kSmallerIsBetter, metadata);
|
||||||
logger->LogMetric("qp", test_case_name, qp, Unit::kUnitless,
|
logger->LogMetric(prefix + "qp", test_case_name, qp, Unit::kUnitless,
|
||||||
ImprovementDirection::kSmallerIsBetter, metadata);
|
ImprovementDirection::kSmallerIsBetter, metadata);
|
||||||
logger->LogMetric("encode_time_ms", test_case_name, encode_time_ms,
|
// TODO(webrtc:14852): Change to us or even ns.
|
||||||
|
logger->LogMetric(prefix + "encode_time_ms", test_case_name, encode_time_ms,
|
||||||
Unit::kMilliseconds, ImprovementDirection::kSmallerIsBetter,
|
Unit::kMilliseconds, ImprovementDirection::kSmallerIsBetter,
|
||||||
metadata);
|
metadata);
|
||||||
logger->LogMetric("decode_time_ms", test_case_name, decode_time_ms,
|
logger->LogMetric(prefix + "decode_time_ms", test_case_name, decode_time_ms,
|
||||||
Unit::kMilliseconds, ImprovementDirection::kSmallerIsBetter,
|
Unit::kMilliseconds, ImprovementDirection::kSmallerIsBetter,
|
||||||
metadata);
|
metadata);
|
||||||
// TODO(webrtc:14852): Change to kUnitLess. kKilobitsPerSecond are converted
|
// TODO(webrtc:14852): Change to kUnitLess. kKilobitsPerSecond are converted
|
||||||
// to bytes per second in Chromeperf dash.
|
// to bytes per second in Chromeperf dash.
|
||||||
logger->LogMetric("target_bitrate_kbps", test_case_name, target_bitrate_kbps,
|
logger->LogMetric(prefix + "target_bitrate_kbps", test_case_name,
|
||||||
Unit::kKilobitsPerSecond,
|
target_bitrate_kbps, Unit::kKilobitsPerSecond,
|
||||||
ImprovementDirection::kBiggerIsBetter, metadata);
|
ImprovementDirection::kBiggerIsBetter, metadata);
|
||||||
logger->LogMetric("target_framerate_fps", test_case_name,
|
logger->LogMetric(prefix + "target_framerate_fps", test_case_name,
|
||||||
target_framerate_fps, Unit::kHertz,
|
target_framerate_fps, Unit::kHertz,
|
||||||
ImprovementDirection::kBiggerIsBetter, metadata);
|
ImprovementDirection::kBiggerIsBetter, metadata);
|
||||||
// TODO(webrtc:14852): Change to kUnitLess. kKilobitsPerSecond are converted
|
// TODO(webrtc:14852): Change to kUnitLess. kKilobitsPerSecond are converted
|
||||||
// to bytes per second in Chromeperf dash.
|
// to bytes per second in Chromeperf dash.
|
||||||
logger->LogMetric("encoded_bitrate_kbps", test_case_name,
|
logger->LogMetric(prefix + "encoded_bitrate_kbps", test_case_name,
|
||||||
encoded_bitrate_kbps, Unit::kKilobitsPerSecond,
|
encoded_bitrate_kbps, Unit::kKilobitsPerSecond,
|
||||||
ImprovementDirection::kBiggerIsBetter, metadata);
|
ImprovementDirection::kBiggerIsBetter, metadata);
|
||||||
logger->LogMetric("encoded_framerate_fps", test_case_name,
|
logger->LogMetric(prefix + "encoded_framerate_fps", test_case_name,
|
||||||
encoded_framerate_fps, Unit::kHertz,
|
encoded_framerate_fps, Unit::kHertz,
|
||||||
ImprovementDirection::kBiggerIsBetter, metadata);
|
ImprovementDirection::kBiggerIsBetter, metadata);
|
||||||
logger->LogMetric("bitrate_mismatch_pct", test_case_name,
|
logger->LogMetric(prefix + "bitrate_mismatch_pct", test_case_name,
|
||||||
bitrate_mismatch_pct, Unit::kPercent,
|
bitrate_mismatch_pct, Unit::kPercent,
|
||||||
ImprovementDirection::kNeitherIsBetter, metadata);
|
ImprovementDirection::kNeitherIsBetter, metadata);
|
||||||
logger->LogMetric("framerate_mismatch_pct", test_case_name,
|
logger->LogMetric(prefix + "framerate_mismatch_pct", test_case_name,
|
||||||
framerate_mismatch_pct, Unit::kPercent,
|
framerate_mismatch_pct, Unit::kPercent,
|
||||||
ImprovementDirection::kNeitherIsBetter, metadata);
|
ImprovementDirection::kNeitherIsBetter, metadata);
|
||||||
logger->LogMetric("transmission_time_ms", test_case_name,
|
logger->LogMetric(prefix + "transmission_time_ms", test_case_name,
|
||||||
transmission_time_ms, Unit::kMilliseconds,
|
transmission_time_ms, Unit::kMilliseconds,
|
||||||
ImprovementDirection::kSmallerIsBetter, metadata);
|
ImprovementDirection::kSmallerIsBetter, metadata);
|
||||||
logger->LogMetric("psnr_y_db", test_case_name, psnr.y, Unit::kUnitless,
|
logger->LogMetric(prefix + "psnr_y_db", test_case_name, psnr.y,
|
||||||
ImprovementDirection::kBiggerIsBetter, metadata);
|
Unit::kUnitless, ImprovementDirection::kBiggerIsBetter,
|
||||||
logger->LogMetric("psnr_u_db", test_case_name, psnr.u, Unit::kUnitless,
|
metadata);
|
||||||
ImprovementDirection::kBiggerIsBetter, metadata);
|
logger->LogMetric(prefix + "psnr_u_db", test_case_name, psnr.u,
|
||||||
logger->LogMetric("psnr_v_db", test_case_name, psnr.v, Unit::kUnitless,
|
Unit::kUnitless, ImprovementDirection::kBiggerIsBetter,
|
||||||
ImprovementDirection::kBiggerIsBetter, metadata);
|
metadata);
|
||||||
|
logger->LogMetric(prefix + "psnr_v_db", test_case_name, psnr.v,
|
||||||
|
Unit::kUnitless, ImprovementDirection::kBiggerIsBetter,
|
||||||
|
metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(ssilkin): use Frequency and DataRate for framerate and bitrate.
|
// TODO(ssilkin): use Frequency and DataRate for framerate and bitrate.
|
||||||
|
|||||||
@ -68,7 +68,6 @@ class VideoCodecTester {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Frame {
|
struct Frame {
|
||||||
int frame_num = 0;
|
|
||||||
uint32_t timestamp_rtp = 0;
|
uint32_t timestamp_rtp = 0;
|
||||||
LayerId layer_id;
|
LayerId layer_id;
|
||||||
bool encoded = false;
|
bool encoded = false;
|
||||||
@ -118,6 +117,7 @@ class VideoCodecTester {
|
|||||||
// Logs `Stream` metrics to provided `MetricsLogger`.
|
// Logs `Stream` metrics to provided `MetricsLogger`.
|
||||||
void LogMetrics(MetricsLogger* logger,
|
void LogMetrics(MetricsLogger* logger,
|
||||||
std::string test_case_name,
|
std::string test_case_name,
|
||||||
|
std::string prefix,
|
||||||
std::map<std::string, std::string> metadata = {}) const;
|
std::map<std::string, std::string> metadata = {}) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -130,6 +130,12 @@ class VideoCodecTester {
|
|||||||
|
|
||||||
// Returns video statistics aggregated for the slice specified by `filter`.
|
// Returns video statistics aggregated for the slice specified by `filter`.
|
||||||
virtual Stream Aggregate(Filter filter) const = 0;
|
virtual Stream Aggregate(Filter filter) const = 0;
|
||||||
|
|
||||||
|
// Write metrics to a CSV file.
|
||||||
|
virtual void LogMetrics(
|
||||||
|
absl::string_view csv_path,
|
||||||
|
std::vector<Frame> frames,
|
||||||
|
std::map<std::string, std::string> metadata) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Pacing settings for codec input.
|
// Pacing settings for codec input.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user