Files
2026-05-18 00:03:06 +03:00

185 lines
6.1 KiB
C++

#include "PixelFormat.hpp"
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
namespace
{
struct YCbCr10
{
uint32_t y;
uint32_t cb;
uint32_t cr;
};
struct BarSpec
{
const char* name;
RgbColor rgb75;
};
const BarSpec bars[] = {
{"White", {191, 191, 191}},
{"Yellow", {191, 191, 0}},
{"Cyan", { 0, 191, 191}},
{"Green", { 0, 191, 0}},
{"Magenta", {191, 0, 191}},
{"Red", {191, 0, 0}},
{"Blue", { 0, 0, 191}},
{"Black", { 0, 0, 0}},
};
YCbCr10 rgbToYCbCr10(RgbColor rgb)
{
double r = rgb.r / 255.0;
double g = rgb.g / 255.0;
double b = rgb.b / 255.0;
double y = 0.2126 * r + 0.7152 * g + 0.0722 * b;
double cb = -0.1146 * r - 0.3854 * g + 0.5000 * b;
double cr = 0.5000 * r - 0.4542 * g - 0.0458 * b;
uint32_t y10 = static_cast<uint32_t>(std::round(y * 876.0 + 64.0));
uint32_t cb10 = static_cast<uint32_t>(std::round(cb * 896.0 + 512.0));
uint32_t cr10 = static_cast<uint32_t>(std::round(cr * 896.0 + 512.0));
return {y10, cb10, cr10};
}
void encodeV210Line(
const YCbCr10* pixels,
uint32_t width,
uint8_t* out)
{
uint32_t groups = (width + 5) / 6;
for (uint32_t g = 0; g < groups; ++g)
{
uint32_t cb0 = (g * 6 + 0 < width) ? pixels[g * 6 + 0].cb : pixels[width - 1].cb;
uint32_t y0 = (g * 6 + 0 < width) ? pixels[g * 6 + 0].y : pixels[width - 1].y;
uint32_t cr0 = (g * 6 + 0 < width) ? pixels[g * 6 + 0].cr : pixels[width - 1].cr;
uint32_t y1 = (g * 6 + 1 < width) ? pixels[g * 6 + 1].y : pixels[width - 1].y;
uint32_t cb2 = (g * 6 + 2 < width) ? pixels[g * 6 + 2].cb : pixels[width - 1].cb;
uint32_t y2 = (g * 6 + 2 < width) ? pixels[g * 6 + 2].y : pixels[width - 1].y;
uint32_t cr2 = (g * 6 + 3 < width) ? pixels[g * 6 + 3].cr : pixels[width - 1].cr;
uint32_t y3 = (g * 6 + 3 < width) ? pixels[g * 6 + 3].y : pixels[width - 1].y;
uint32_t cb4 = (g * 6 + 4 < width) ? pixels[g * 6 + 4].cb : pixels[width - 1].cb;
uint32_t y4 = (g * 6 + 4 < width) ? pixels[g * 6 + 4].y : pixels[width - 1].y;
uint32_t cr4 = (g * 6 + 5 < width) ? pixels[g * 6 + 5].cr : pixels[width - 1].cr;
uint32_t y5 = (g * 6 + 5 < width) ? pixels[g * 6 + 5].y : pixels[width - 1].y;
uint32_t w0 = (cb0 & 0x3FF)
| ((y0 & 0x3FF) << 10)
| ((cr0 & 0x3FF) << 20);
uint32_t w1 = (y1 & 0x3FF)
| ((cb2 & 0x3FF) << 10)
| ((y2 & 0x3FF) << 20);
uint32_t w2 = (cr2 & 0x3FF)
| ((y3 & 0x3FF) << 10)
| ((cb4 & 0x3FF) << 20);
uint32_t w3 = (y4 & 0x3FF)
| ((cr4 & 0x3FF) << 10)
| ((y5 & 0x3FF) << 20);
uint8_t* p = out + g * 16;
p[0] = static_cast<uint8_t>(w0);
p[1] = static_cast<uint8_t>(w0 >> 8);
p[2] = static_cast<uint8_t>(w0 >> 16);
p[3] = static_cast<uint8_t>(w0 >> 24);
p[4] = static_cast<uint8_t>(w1);
p[5] = static_cast<uint8_t>(w1 >> 8);
p[6] = static_cast<uint8_t>(w1 >> 16);
p[7] = static_cast<uint8_t>(w1 >> 24);
p[8] = static_cast<uint8_t>(w2);
p[9] = static_cast<uint8_t>(w2 >> 8);
p[10] = static_cast<uint8_t>(w2 >> 16);
p[11] = static_cast<uint8_t>(w2 >> 24);
p[12] = static_cast<uint8_t>(w3);
p[13] = static_cast<uint8_t>(w3 >> 8);
p[14] = static_cast<uint8_t>(w3 >> 16);
p[15] = static_cast<uint8_t>(w3 >> 24);
}
}
}
int main()
{
constexpr uint32_t width = 1920;
constexpr uint32_t height = 1;
constexpr uint32_t dstWidth = 512;
constexpr uint32_t dstHeight = 1;
uint32_t groups = (width + 5) / 6;
uint32_t stride = ((groups * 16 + 127) / 128) * 128;
printf("v210 conversion test\n");
printf("width=%u stride=%u\n", width, stride);
std::vector<YCbCr10> line(width);
for (uint32_t x = 0; x < width; ++x)
{
size_t bar = (x * 8) / width;
if (bar > 7) bar = 7;
line[x] = rgbToYCbCr10(bars[bar].rgb75);
}
printf("\nReference YCbCr values:\n");
for (size_t i = 0; i < 8; ++i)
{
YCbCr10 ref = rgbToYCbCr10(bars[i].rgb75);
printf(" %-10s Y=%4u Cb=%4u Cr=%4u\n",
bars[i].name, ref.y, ref.cb, ref.cr);
}
std::vector<uint8_t> v210Data(stride, 0);
encodeV210Line(line.data(), width, v210Data.data());
std::vector<uint32_t> rgbaBuf(dstWidth * dstHeight, 0);
convertV210ToRgba(
v210Data.data(),
width,
height,
stride,
rgbaBuf.data(),
dstWidth,
dstHeight);
printf("\nDecode results:\n");
int totalErrors = 0;
for (size_t i = 0; i < 8; ++i)
{
uint32_t x = (i * dstWidth) / 8 + dstWidth / 16;
if (x >= dstWidth) x = dstWidth - 1;
uint32_t pixel = rgbaBuf[x];
uint8_t r = static_cast<uint8_t>(pixel & 0xFF);
uint8_t g = static_cast<uint8_t>((pixel >> 8) & 0xFF);
uint8_t b = static_cast<uint8_t>((pixel >> 16) & 0xFF);
RgbColor expected = bars[i].rgb75;
int dr = static_cast<int>(r) - static_cast<int>(expected.r);
int dg = static_cast<int>(g) - static_cast<int>(expected.g);
int db = static_cast<int>(b) - static_cast<int>(expected.b);
bool ok = (dr >= -3 && dr <= 3 && dg >= -3 && dg <= 3 && db >= -3 && db <= 3);
if (!ok) totalErrors++;
printf(" %-10s: got (%3u,%3u,%3u) expected (%3u,%3u,%3u) delta=(%+d,%+d,%+d) %s\n",
bars[i].name, r, g, b,
expected.r, expected.g, expected.b,
dr, dg, db,
ok ? "OK" : "FAIL");
}
printf("\n%d bar(s) out of tolerance\n", totalErrors);
return totalErrors > 0 ? 1 : 0;
}