blob: d2672d8a71c90c6de253cf7e71d4e4c7be9cb544 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/ui/lib/yuv/yuv.h"
#include <algorithm>
#include <cmath>
namespace {
// Convert linear RGB values to sRGB. |in| is a float
// value between 0 and 1.
float LinearRgbToSrgb(float in) {
if (in <= 0.0031308f) {
return in * 12.92f;
} else {
return 1.055f * pow(in, 1.f / 2.4f) - 0.055f;
}
}
uint8_t NormalizedFloatToUnsignedByte(float in) {
int32_t out = static_cast<int32_t>(std::lround(in * 255.0f));
return static_cast<uint8_t>(std::clamp(out, 0, 255));
}
} // namespace
namespace yuv {
// Letting compiler decide whether to inline, for now.
void YuvToBgra(uint8_t y_raw, uint8_t u_raw, uint8_t v_raw, uint8_t* bgra) {
// Convert from encoded space to normalized space assuming eItuNarrow.
int32_t y = static_cast<int32_t>(y_raw) - 16;
int32_t u = static_cast<int32_t>(u_raw) - 128;
int32_t v = static_cast<int32_t>(v_raw) - 128;
// Note: Normally, we would clamp here. But some drivers do not clamp in the
// middle of their implementation, and this function is used for pixel tests.
float fy = static_cast<float>(y) / 219.0f;
float fu = static_cast<float>(u) / 224.0f;
float fv = static_cast<float>(v) / 224.0f;
// Convert from YUV to RGB using the coefficients for eYcbcr709.
float r = fy + 1.5748f * fv;
float g = fy - (0.13397432f / 0.7152f) * fu - (0.33480248f / 0.7152f) * fv;
float b = fy + 1.8556f * fu;
// Convert to sRGB, then store the value as unsigned bytes.
bgra[0] = NormalizedFloatToUnsignedByte(LinearRgbToSrgb(b)); // blue
bgra[1] = NormalizedFloatToUnsignedByte(LinearRgbToSrgb(g)); // green
bgra[2] = NormalizedFloatToUnsignedByte(LinearRgbToSrgb(r)); // red
bgra[3] = 0xff; // alpha
}
} // namespace yuv