Files
mxl-multiviewer/PixelFormat.hpp
2026-05-24 21:17:44 +03:00

195 lines
6.7 KiB
C++

#pragma once
#include <cstdint>
struct RgbColor
{
uint8_t r = 0;
uint8_t g = 0;
uint8_t b = 0;
};
inline uint32_t packRgba8(RgbColor color)
{
constexpr uint8_t alpha = 255;
return (alpha << 24) |
(color.b << 16) |
(color.g << 8) |
color.r;
}
inline uint8_t clampUint8(int32_t v)
{
return static_cast<uint8_t>(
v < 0 ? 0 : (v > 255 ? 255 : v)
);
}
inline uint32_t v210LineStride(uint32_t width)
{
uint32_t groups = (width + 5) / 6;
uint32_t rawBytes = groups * 16;
return ((rawBytes + 127) / 128) * 128;
}
inline void decodeV210Line(
const uint8_t* lineData,
uint32_t* rgbaLine,
uint32_t width)
{
for (uint32_t x = 0; x < width; ++x)
{
uint32_t group = x / 6;
uint32_t pos = x % 6;
const uint32_t baseOffset = group * 16;
uint32_t w0;
uint32_t w1;
uint32_t w2;
uint32_t w3;
const uint8_t* p = lineData + baseOffset;
w0 = static_cast<uint32_t>(p[0]) |
(static_cast<uint32_t>(p[1]) << 8) |
(static_cast<uint32_t>(p[2]) << 16) |
(static_cast<uint32_t>(p[3]) << 24);
w1 = static_cast<uint32_t>(p[4]) |
(static_cast<uint32_t>(p[5]) << 8) |
(static_cast<uint32_t>(p[6]) << 16) |
(static_cast<uint32_t>(p[7]) << 24);
w2 = static_cast<uint32_t>(p[8]) |
(static_cast<uint32_t>(p[9]) << 8) |
(static_cast<uint32_t>(p[10]) << 16) |
(static_cast<uint32_t>(p[11]) << 24);
w3 = static_cast<uint32_t>(p[12]) |
(static_cast<uint32_t>(p[13]) << 8) |
(static_cast<uint32_t>(p[14]) << 16) |
(static_cast<uint32_t>(p[15]) << 24);
uint32_t cb0 = (w0 >> 0) & 0x3FF;
uint32_t y0 = (w0 >> 10) & 0x3FF;
uint32_t cr0 = (w0 >> 20) & 0x3FF;
uint32_t y1 = (w1 >> 0) & 0x3FF;
uint32_t cb2 = (w1 >> 10) & 0x3FF;
uint32_t y2 = (w1 >> 20) & 0x3FF;
uint32_t cr2 = (w2 >> 0) & 0x3FF;
uint32_t y3 = (w2 >> 10) & 0x3FF;
uint32_t cb4 = (w2 >> 20) & 0x3FF;
uint32_t y4 = (w3 >> 0) & 0x3FF;
uint32_t cr4 = (w3 >> 10) & 0x3FF;
uint32_t y5 = (w3 >> 20) & 0x3FF;
uint32_t y10;
uint32_t cb10;
uint32_t cr10;
switch (pos)
{
case 0: y10 = y0; cb10 = cb0; cr10 = cr0; break;
case 1: y10 = y1; cb10 = cb0; cr10 = cr0; break;
case 2: y10 = y2; cb10 = cb2; cr10 = cr2; break;
case 3: y10 = y3; cb10 = cb2; cr10 = cr2; break;
case 4: y10 = y4; cb10 = cb4; cr10 = cr4; break;
case 5: y10 = y5; cb10 = cb4; cr10 = cr4; break;
default: y10 = y0; cb10 = cb0; cr10 = cr0; break;
}
// BT.709 limited-range YCbCr to RGB. v210 stores 10-bit video-range
// samples: Y [64, 940], Cb/Cr centered at 512.
int32_t yp = (static_cast<int32_t>(y10) - 64) >> 2;
int32_t cbp = (static_cast<int32_t>(cb10) - 512) >> 2;
int32_t crp = (static_cast<int32_t>(cr10) - 512) >> 2;
int32_t r = (298 * yp + 459 * crp + 128) >> 8;
int32_t g = (298 * yp - 137 * crp - 55 * cbp + 128) >> 8;
int32_t b = (298 * yp + 541 * cbp + 128) >> 8;
rgbaLine[x] = packRgba8({clampUint8(r), clampUint8(g), clampUint8(b)});
}
}
inline void convertV210ToRgba(
const uint8_t* v210Data,
uint32_t srcWidth,
uint32_t srcHeight,
uint32_t srcStride,
uint32_t* rgbaData,
uint32_t dstWidth,
uint32_t dstHeight)
{
for (uint32_t dy = 0; dy < dstHeight; ++dy)
{
uint32_t sy = dy * srcHeight / dstHeight;
const uint8_t* srcLine = v210Data + sy * srcStride;
for (uint32_t dx = 0; dx < dstWidth; ++dx)
{
uint32_t sx = dx * srcWidth / dstWidth;
uint32_t group = sx / 6;
uint32_t pos = sx % 6;
const uint8_t* p = srcLine + group * 16;
uint32_t w0 = static_cast<uint32_t>(p[0]) |
(static_cast<uint32_t>(p[1]) << 8) |
(static_cast<uint32_t>(p[2]) << 16) |
(static_cast<uint32_t>(p[3]) << 24);
uint32_t w1 = static_cast<uint32_t>(p[4]) |
(static_cast<uint32_t>(p[5]) << 8) |
(static_cast<uint32_t>(p[6]) << 16) |
(static_cast<uint32_t>(p[7]) << 24);
uint32_t w2 = static_cast<uint32_t>(p[8]) |
(static_cast<uint32_t>(p[9]) << 8) |
(static_cast<uint32_t>(p[10]) << 16) |
(static_cast<uint32_t>(p[11]) << 24);
uint32_t w3 = static_cast<uint32_t>(p[12]) |
(static_cast<uint32_t>(p[13]) << 8) |
(static_cast<uint32_t>(p[14]) << 16) |
(static_cast<uint32_t>(p[15]) << 24);
uint32_t cb0 = (w0 >> 0) & 0x3FF;
uint32_t y0 = (w0 >> 10) & 0x3FF;
uint32_t cr0 = (w0 >> 20) & 0x3FF;
uint32_t y1 = (w1 >> 0) & 0x3FF;
uint32_t cb2 = (w1 >> 10) & 0x3FF;
uint32_t y2 = (w1 >> 20) & 0x3FF;
uint32_t cr2 = (w2 >> 0) & 0x3FF;
uint32_t y3 = (w2 >> 10) & 0x3FF;
uint32_t cb4 = (w2 >> 20) & 0x3FF;
uint32_t y4 = (w3 >> 0) & 0x3FF;
uint32_t cr4 = (w3 >> 10) & 0x3FF;
uint32_t y5 = (w3 >> 20) & 0x3FF;
uint32_t y10;
uint32_t cb10;
uint32_t cr10;
switch (pos)
{
case 0: y10 = y0; cb10 = cb0; cr10 = cr0; break;
case 1: y10 = y1; cb10 = cb0; cr10 = cr0; break;
case 2: y10 = y2; cb10 = cb2; cr10 = cr2; break;
case 3: y10 = y3; cb10 = cb2; cr10 = cr2; break;
case 4: y10 = y4; cb10 = cb4; cr10 = cr4; break;
case 5: y10 = y5; cb10 = cb4; cr10 = cr4; break;
default: y10 = y0; cb10 = cb0; cr10 = cr0; break;
}
// BT.709 limited-range YCbCr to RGB. v210 stores 10-bit video-range
// samples: Y [64, 940], Cb/Cr centered at 512.
int32_t yp = (static_cast<int32_t>(y10) - 64) >> 2;
int32_t cbp = (static_cast<int32_t>(cb10) - 512) >> 2;
int32_t crp = (static_cast<int32_t>(cr10) - 512) >> 2;
int32_t r = (298 * yp + 459 * crp + 128) >> 8;
int32_t g = (298 * yp - 137 * crp - 55 * cbp + 128) >> 8;
int32_t b = (298 * yp + 541 * cbp + 128) >> 8;
rgbaData[dy * dstWidth + dx] = packRgba8(
{clampUint8(r), clampUint8(g), clampUint8(b)});
}
}
}