blob: 55ac374d09dae2336bc47d8818ec29123b25c314 [file]
/*
* Copyright 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 "video/corruption_detection/frame_pair_corruption_score.h"
#include <memory>
#include <optional>
#include <string>
#include "absl/strings/string_view.h"
#include "api/scoped_refptr.h"
#include "api/video/i420_buffer.h"
#include "api/video/video_frame_buffer.h"
#include "test/gtest.h"
#include "test/testsupport/file_utils.h"
#include "test/testsupport/frame_reader.h"
namespace webrtc {
namespace {
using test::FrameReader;
// Input video.
constexpr absl::string_view kFilename = "ConferenceMotion_1280_720_50";
constexpr int kWidth = 1280;
constexpr int kHeight = 720;
constexpr absl::string_view kCodecName = "VP8";
// Scale function parameters.
constexpr float kScaleFactor = 14;
// Logistic function parameters.
constexpr float kGrowthRate = 0.5;
constexpr float kMidpoint = 3;
std::unique_ptr<FrameReader> GetFrameGenerator() {
std::string clip_path = test::ResourcePath(kFilename, "yuv");
EXPECT_TRUE(test::FileExists(clip_path));
return CreateYuvFrameReader(clip_path, {.width = kWidth, .height = kHeight},
test::YuvFrameReaderImpl::RepeatMode::kPingPong);
}
scoped_refptr<I420BufferInterface> GetDowscaledFrame(
scoped_refptr<I420BufferInterface> frame,
float downscale_factor) {
scoped_refptr<I420Buffer> downscaled_frame =
I420Buffer::Create(kWidth * downscale_factor, kHeight * downscale_factor);
downscaled_frame->ScaleFrom(*frame);
return downscaled_frame;
}
TEST(FramePairCorruptionScorerTest, SameFrameReturnsNoCorruptionScaleFunction) {
std::unique_ptr<FrameReader> frame_reader = GetFrameGenerator();
scoped_refptr<I420Buffer> frame = frame_reader->PullFrame();
FramePairCorruptionScorer frame_pair_corruption_score(
kCodecName, kScaleFactor, std::nullopt);
EXPECT_LT(
frame_pair_corruption_score.CalculateScore(/*qp=*/1, *frame, *frame),
0.5);
}
TEST(FramePairCorruptionScorerTest,
SameFrameReturnsNoCorruptionLogisticFunction) {
std::unique_ptr<FrameReader> frame_reader = GetFrameGenerator();
scoped_refptr<I420Buffer> frame = frame_reader->PullFrame();
FramePairCorruptionScorer frame_pair_corruption_score(
kCodecName, kGrowthRate, kMidpoint, std::nullopt);
EXPECT_LT(
frame_pair_corruption_score.CalculateScore(/*qp=*/1, *frame, *frame),
0.5);
}
TEST(FramePairCorruptionScorerTest,
HalfScaledFrameReturnsNoCorruptionScaleFunction) {
std::unique_ptr<FrameReader> frame_reader = GetFrameGenerator();
scoped_refptr<I420Buffer> frame = frame_reader->PullFrame();
FramePairCorruptionScorer frame_pair_corruption_score(
kCodecName, kScaleFactor, std::nullopt);
EXPECT_LT(frame_pair_corruption_score.CalculateScore(
/*qp=*/1, *frame,
*GetDowscaledFrame(frame, /*downscale_factor=*/0.5)),
0.5);
}
TEST(FramePairCorruptionScorerTest,
HalfScaledFrameReturnsNoCorruptionLogisticFunction) {
std::unique_ptr<FrameReader> frame_reader = GetFrameGenerator();
scoped_refptr<I420Buffer> frame = frame_reader->PullFrame();
FramePairCorruptionScorer frame_pair_corruption_score(
kCodecName, kGrowthRate, kMidpoint, std::nullopt);
EXPECT_LT(frame_pair_corruption_score.CalculateScore(
/*qp=*/1, *frame,
*GetDowscaledFrame(frame, /*downscale_factor=*/0.5)),
0.5);
}
TEST(FramePairCorruptionScorerTest, QuarterScaledFrameReturnsNoCorruption) {
std::unique_ptr<FrameReader> frame_reader = GetFrameGenerator();
scoped_refptr<I420Buffer> frame = frame_reader->PullFrame();
FramePairCorruptionScorer frame_pair_corruption_score(
kCodecName, kScaleFactor, std::nullopt);
EXPECT_LT(frame_pair_corruption_score.CalculateScore(
/*qp=*/1, *frame,
*GetDowscaledFrame(frame, /*downscale_factor=*/0.25)),
0.5);
}
TEST(FramePairCorruptionScorerTest,
DifferentFrameResultsInCorruptionScaleFunction) {
std::unique_ptr<FrameReader> frame_reader = GetFrameGenerator();
scoped_refptr<I420Buffer> frame = frame_reader->PullFrame();
// Get frame number 5, which should be different from the first frame, and
// hence, indicate a corruption.
scoped_refptr<I420Buffer> different_frame =
frame_reader->ReadFrame(/*frame_num=*/5);
FramePairCorruptionScorer frame_pair_corruption_score(
kCodecName, kScaleFactor, std::nullopt);
EXPECT_GT(frame_pair_corruption_score.CalculateScore(/*qp=*/1, *frame,
*different_frame),
0.5);
}
TEST(FramePairCorruptionScorerTest,
DifferentFrameResultsInCorruptionLogisticFunction) {
std::unique_ptr<FrameReader> frame_reader = GetFrameGenerator();
scoped_refptr<I420Buffer> frame = frame_reader->PullFrame();
// Get frame number 5, which should be different from the first frame, and
// hence, indicate a corruption.
scoped_refptr<I420Buffer> different_frame =
frame_reader->ReadFrame(/*frame_num=*/5);
FramePairCorruptionScorer frame_pair_corruption_score(
kCodecName, kGrowthRate, kMidpoint, std::nullopt);
EXPECT_GT(frame_pair_corruption_score.CalculateScore(/*qp=*/1, *frame,
*different_frame),
0.5);
}
TEST(FramePairCorruptionScorerTest,
HalfScaledDifferentFrameResultsInCorruptionScaleFunction) {
std::unique_ptr<FrameReader> frame_reader = GetFrameGenerator();
scoped_refptr<I420Buffer> frame = frame_reader->PullFrame();
// Get frame number 5, which should be different from the first frame, and
// hence, indicate a corruption.
scoped_refptr<I420Buffer> different_frame =
frame_reader->ReadFrame(/*frame_num=*/5);
FramePairCorruptionScorer frame_pair_corruption_score(
kCodecName, kScaleFactor, std::nullopt);
EXPECT_GT(frame_pair_corruption_score.CalculateScore(
/*qp=*/1, *frame,
*GetDowscaledFrame(different_frame, /*downscale_factor=*/0.25)),
0.5);
}
TEST(FramePairCorruptionScorerTest,
HalfScaledDifferentFrameResultsInCorruptionLogisticFunction) {
std::unique_ptr<FrameReader> frame_reader = GetFrameGenerator();
scoped_refptr<I420Buffer> frame = frame_reader->PullFrame();
// Get frame number 5, which should be different from the first frame, and
// hence, indicate a corruption.
scoped_refptr<I420Buffer> different_frame =
frame_reader->ReadFrame(/*frame_num=*/5);
FramePairCorruptionScorer frame_pair_corruption_score(
kCodecName, kGrowthRate, kMidpoint, std::nullopt);
EXPECT_GT(frame_pair_corruption_score.CalculateScore(
/*qp=*/1, *frame,
*GetDowscaledFrame(different_frame, /*downscale_factor=*/0.25)),
0.5);
}
} // namespace
} // namespace webrtc