Use vector_math::FCLAMP
This CL replaces various custom clamping code with the standardized FCLAMP. Important note: this CL standardizes replacing NaNs with zeros, rather than -1.0 or +1.0, depending on the code path. This is a behavioral change, but it's better to replace NaNs with silence than with "the loudest possible value". Optimized FCLAMP code will be added per-architecture in upcoming CLs. Bug: 401598584 Change-Id: Id3c994bd574bf551652e70218496652f4b8508f7 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6336773 Reviewed-by: Yuchen Liu <yucliu@chromium.org> Reviewed-by: Dale Curtis <dalecurtis@chromium.org> Commit-Queue: Thomas Guilbert <tguilbert@chromium.org> Cr-Commit-Position: refs/heads/main@{#1430578}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
699099ce48
commit
65dc0219f7
chromecast/media/cma/backend/mixer
media/base
services/audio
@ -16,6 +16,7 @@
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/location.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/numerics/checked_math.h"
|
||||
#include "base/strings/pattern.h"
|
||||
#include "base/task/sequenced_task_runner.h"
|
||||
#include "chromecast/media/audio/audio_fader.h"
|
||||
@ -31,6 +32,7 @@
|
||||
#include "media/base/audio_bus.h"
|
||||
#include "media/base/channel_layout.h"
|
||||
#include "media/base/channel_mixer.h"
|
||||
#include "media/base/vector_math.h"
|
||||
|
||||
namespace chromecast {
|
||||
namespace media {
|
||||
@ -465,9 +467,13 @@ void AudioOutputRedirector::FinishBuffer() {
|
||||
}
|
||||
|
||||
// Hard limit to [1.0, -1.0].
|
||||
for (int s = 0; s < config_.num_output_channels * next_num_frames_; ++s) {
|
||||
current_mix_data_[s] = std::clamp(current_mix_data_[s], -1.0f, 1.0f);
|
||||
}
|
||||
size_t total_frames =
|
||||
base::CheckMul(next_num_frames_, config_.num_output_channels)
|
||||
.Cast<size_t>()
|
||||
.ValueOrDie();
|
||||
|
||||
auto data_to_clamp = base::span(current_mix_data_, total_frames);
|
||||
::media::vector_math::FCLAMP(data_to_clamp, data_to_clamp);
|
||||
|
||||
io_task_runner_->PostTask(
|
||||
FROM_HERE,
|
||||
|
@ -350,9 +350,8 @@ void AudioBus::CopyAndClipTo(AudioBus* dest) const {
|
||||
DCHECK(!is_bitstream_format_);
|
||||
CHECK_EQ(channels(), dest->channels());
|
||||
CHECK_LE(frames(), dest->frames());
|
||||
for (int ch = 0; ch < channels(); ++ch) {
|
||||
std::ranges::transform(channel_span(ch), dest->channel_span(ch).begin(),
|
||||
Float32SampleTypeTraits::FromFloat);
|
||||
for (auto [src_ch, dest_ch] : base::zip(channel_data_, dest->AllChannels())) {
|
||||
vector_math::FCLAMP(src_ch, dest_ch);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -433,7 +433,7 @@ static const float kTestVectorFloat32Invalid[kTestVectorSize] = {
|
||||
std::numeric_limits<float>::quiet_NaN()};
|
||||
|
||||
static const float kTestVectorFloat32Sanitized[kTestVectorSize] = {
|
||||
-1.0f, 0.0f, 1.0f, -1.0f, 0.5f, -0.5f, 0.0f, 1.0f, -1.0f, -1.0f};
|
||||
-1.0f, 0.0f, 1.0f, -1.0f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f};
|
||||
|
||||
// Expected results.
|
||||
static constexpr size_t kTestVectorFrameCount = kTestVectorSize / 2;
|
||||
|
@ -66,7 +66,7 @@ class FloatSampleTypeTraits {
|
||||
// level drivers that may not properly handle these values.
|
||||
// Note: Passing NaN to `std::clamp()` is UB.
|
||||
return std::isnan(source_value)
|
||||
? kMinValue
|
||||
? kZeroPointValue
|
||||
: std::clamp(static_cast<SampleType>(source_value), kMinValue,
|
||||
kMaxValue);
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "base/trace_event/trace_event.h"
|
||||
#include "media/base/audio_timestamp_helper.h"
|
||||
#include "media/base/loopback_audio_converter.h"
|
||||
#include "media/base/vector_math.h"
|
||||
#include "services/audio/sync_mixing_graph_input.h"
|
||||
|
||||
namespace audio {
|
||||
@ -28,17 +29,8 @@ std::unique_ptr<media::LoopbackAudioConverter> CreateConverter(
|
||||
|
||||
// Clamps all samples to the interval [-1, 1].
|
||||
void SanitizeOutput(media::AudioBus* bus) {
|
||||
for (int channel = 0; channel < bus->channels(); ++channel) {
|
||||
float* data = bus->channel(channel);
|
||||
for (int frame = 0; frame < bus->frames(); frame++) {
|
||||
float value = data[frame];
|
||||
if (value * value <= 1.0f) [[likely]] {
|
||||
continue;
|
||||
}
|
||||
// The sample is out of range. Negative values are clamped to -1. Positive
|
||||
// values and NaN are clamped to 1.
|
||||
data[frame] = value < 0.0f ? -1.0f : 1.0f;
|
||||
}
|
||||
for (auto channel : bus->AllChannels()) {
|
||||
media::vector_math::FCLAMP(channel, channel);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -404,7 +404,7 @@ TEST_F(MixingGraphInputTest, OutOfRange) {
|
||||
// Verifies that invalid input is sanitized.
|
||||
TEST_F(MixingGraphInputTest, InvalidInput) {
|
||||
// Pairs of input values and expected output values.
|
||||
std::array<std::pair<float, float>, 8> test_values = {{
|
||||
std::array<std::pair<float, float>, 9> test_values = {{
|
||||
{-1.5f, -1.0f}, // Negative overflow.
|
||||
{2.0f, 1.0f}, // Positive overflow.
|
||||
{-0.8, -0.8f}, // Valid.
|
||||
@ -412,7 +412,8 @@ TEST_F(MixingGraphInputTest, InvalidInput) {
|
||||
{0.0, 0.0f}, // Valid.
|
||||
{std::numeric_limits<float>::infinity(), 1.0f}, // Positive infinity.
|
||||
{-std::numeric_limits<float>::infinity(), -1.0f}, // Negative infinity.
|
||||
{NAN, 1.0f}, // NaN.
|
||||
{std::numeric_limits<float>::quiet_NaN(), 0.0f}, // NaN.
|
||||
{std::numeric_limits<float>::signaling_NaN(), 0.0f}, // NaN.
|
||||
}};
|
||||
for (const auto& test_pair : test_values) {
|
||||
float input_value = test_pair.first;
|
||||
|
Reference in New Issue
Block a user