blob: f861bfbf03b0bd15a4a32723132b89b0bcd7a36a [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 <optional>
#include <vector>
#include "absl/strings/string_view.h"
#include "api/scoped_refptr.h"
#include "api/video/corruption_detection/corruption_detection_filter_settings.h"
#include "api/video/video_frame.h"
#include "api/video/video_frame_buffer.h"
#include "rtc_base/checks.h"
#include "video/corruption_detection/generic_mapping_functions.h"
#include "video/corruption_detection/halton_frame_sampler.h"
#include "video/corruption_detection/utils.h"
namespace webrtc {
namespace {
constexpr float kDefaultSampleFraction = 0.5;
} // namespace
FramePairCorruptionScorer::FramePairCorruptionScorer(
absl::string_view codec_name,
float scale_factor,
std::optional<float> sample_fraction)
: codec_type_(GetVideoCodecType(codec_name)),
sample_fraction_(sample_fraction.value_or(kDefaultSampleFraction)),
corruption_classifier_(scale_factor) {
RTC_CHECK_GE(sample_fraction_, 0) << "Sample fraction must be non-negative.";
RTC_CHECK_LE(sample_fraction_, 1) << "Sample fraction must be less than or "
"equal to 1.";
}
FramePairCorruptionScorer::FramePairCorruptionScorer(
absl::string_view codec_name,
float growth_rate,
float midpoint,
std::optional<float> sample_fraction)
: codec_type_(GetVideoCodecType(codec_name)),
sample_fraction_(sample_fraction.value_or(kDefaultSampleFraction)),
corruption_classifier_(growth_rate, midpoint) {
RTC_CHECK_GE(sample_fraction_, 0) << "Sample fraction must be non-negative.";
RTC_CHECK_LE(sample_fraction_, 1) << "Sample fraction must be less than or "
"equal to 1.";
}
double FramePairCorruptionScorer::CalculateScore(
int qp,
I420BufferInterface& reference_buffer,
I420BufferInterface& test_buffer) {
RTC_CHECK_GE(reference_buffer.width(), test_buffer.width());
RTC_CHECK_GE(reference_buffer.height(), test_buffer.height());
// Adapted for VP9 and AV1.
RTC_DCHECK_GE(qp, 0);
RTC_DCHECK_LE(qp, 255);
// We calculate corruption score per "sample" rather than per "pixel", hence
// times "3/2".
const int num_samples = static_cast<int>(
(test_buffer.width() * test_buffer.height() * 3 / 2) * sample_fraction_);
std::vector<HaltonFrameSampler::Coordinates> halton_samples =
halton_frame_sampler_.GetSampleCoordinatesForFrame(num_samples);
RTC_DCHECK_EQ(halton_samples.size(), num_samples);
VideoFrame reference_frame =
VideoFrame::Builder()
.set_video_frame_buffer(reference_buffer.ToI420())
.build();
VideoFrame test_frame = VideoFrame::Builder()
.set_video_frame_buffer(test_buffer.ToI420())
.build();
CorruptionDetectionFilterSettings filter_settings =
GetCorruptionFilterSettings(qp, codec_type_);
const std::vector<FilteredSample> filtered_reference_sample_values =
GetSampleValuesForFrame(reference_frame, halton_samples,
test_frame.width(), test_frame.height(),
filter_settings.std_dev);
const std::vector<FilteredSample> filtered_test_sample_values =
GetSampleValuesForFrame(test_frame, halton_samples, test_frame.width(),
test_frame.height(), filter_settings.std_dev);
RTC_CHECK_EQ(filtered_reference_sample_values.size(),
filtered_test_sample_values.size());
return corruption_classifier_.CalculateCorruptionProbability(
filtered_reference_sample_values, filtered_test_sample_values,
filter_settings.luma_error_threshold,
filter_settings.chroma_error_threshold);
}
} // namespace webrtc