Files
dmf-studio-rnd/shared/V210.hpp
T
2026-07-07 17:26:47 +03:00

177 lines
6.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#pragma once
#include <array>
#include <cstddef>
#include <cstdint>
#include <cstring>
namespace dmf::v210 {
// SMPTE 75% color bars — 10-bit limited range
// Y: 64 (black) to 940 (white)
// Cb/Cr: 64 to 960, 512 = neutral grey
struct Color { uint16_t y, cb, cr; };
constexpr std::array<Color, 7> SMPTE_BARS = {{
{721, 512, 512}, // white
{674, 176, 543}, // yellow
{581, 589, 176}, // cyan
{534, 253, 207}, // green
{251, 771, 817}, // magenta
{204, 435, 848}, // red
{111, 848, 481}, // blue
}};
// IRE 11-step greyscale bars
// from total black to 100% white
// Y_10bit = 64 + (IRE / 100) × (940 64) Rec. 709/Rec. 2020
// Y_10bit = 64 + (IRE × 8.76)
constexpr std::array<Color, 11> IRE_BARS = {{
{64, 512, 512}, // IRE 0
{152, 512, 512}, // IRE 10
{239, 512, 512}, // IRE 20 and so on
{327, 512, 512},
{414, 512, 512},
{502, 512, 512},
{590, 512, 512},
{677, 512, 512},
{765, 512, 512},
{852, 512, 512},
{940, 512, 512},
}};
// Pack 6 pixels into 4 x 32-bit V210 words (16 bytes total).
//
// V210 is 4:2:2 — each pair of pixels shares one Cb and one Cr sample.
// The three pairs in a block map to words like this (bits [9:0],[19:10],[29:20]):
// word 0: Cb(pair0) | Y(px0) | Cr(pair0)
// word 1: Y(px1) | Cb(pair1) | Y(px2)
// word 2: Cr(pair1) | Y(px3) | Cb(pair2)
// word 3: Y(px4) | Cr(pair2) | Y(px5)
inline void pack_block(
uint8_t* out,
Color p01, uint16_t y0, uint16_t y1, // pair 01
Color p23, uint16_t y2, uint16_t y3, // pair 23
Color p45, uint16_t y4, uint16_t y5) // pair 45
{
auto* w = reinterpret_cast<uint32_t*>(out);
w[0] = (p01.cb & 0x3FFu) | ((y0 & 0x3FFu) << 10) | ((p01.cr & 0x3FFu) << 20);
w[1] = (y1 & 0x3FFu) | ((p23.cb & 0x3FFu) << 10) | ((y2 & 0x3FFu) << 20);
w[2] = (p23.cr & 0x3FFu) | ((y3 & 0x3FFu) << 10) | ((p45.cb & 0x3FFu) << 20);
w[3] = (y4 & 0x3FFu) | ((p45.cr & 0x3FFu) << 10) | ((y5 & 0x3FFu) << 20);
}
// Write one horizontal line of an arbitrary bar palette.
template<std::size_t N>
inline void write_palette_line(uint8_t* line, int width, const std::array<Color, N>& palette)
{
const int n = static_cast<int>(N);
const int blocks = width / 6;
for (int b = 0; b < blocks; b++) {
int x = b * 6;
auto color = [&](int px) -> const Color& {
return palette[static_cast<std::size_t>(px * n / width)];
};
const Color& c01 = color(x);
const Color& c23 = color(x + 2);
const Color& c45 = color(x + 4);
pack_block(line + b * 16,
c01, c01.y, color(x+1).y,
c23, c23.y, color(x+3).y,
c45, c45.y, color(x+5).y);
}
}
// Fill a frame with a solid color.
inline void fill_solid(uint8_t* buf, int width, int height, uint32_t stride, Color c)
{
const int blocks = width / 6;
for (int b = 0; b < blocks; b++)
pack_block(buf + b * 16, c, c.y, c.y, c, c.y, c.y, c, c.y, c.y);
for (int y = 1; y < height; y++)
std::memcpy(buf + static_cast<ptrdiff_t>(y) * stride, buf, blocks * 16);
}
// SMPTE 75% color bars.
inline void fill_colorbars(uint8_t* buf, int width, int height, uint32_t stride)
{
for (int y = 0; y < height; y++)
write_palette_line(buf + static_cast<ptrdiff_t>(y) * stride, width, SMPTE_BARS);
}
// IRE 11-step greyscale ramp.
inline void fill_ire_ramp(uint8_t* buf, int width, int height, uint32_t stride)
{
for (int y = 0; y < height; y++)
write_palette_line(buf + static_cast<ptrdiff_t>(y) * stride, width, IRE_BARS);
}
// 10-bit limited black (Y=64, Cb=Cr=512).
inline void fill_black(uint8_t* buf, int width, int height, uint32_t stride)
{
fill_solid(buf, width, height, stride, {64, 512, 512});
}
// 10-bit limited white (Y=940, Cb=Cr=512).
inline void fill_white(uint8_t* buf, int width, int height, uint32_t stride)
{
fill_solid(buf, width, height, stride, {940, 512, 512});
}
inline void UYVYtoV210(uint8_t* src_buf, uint8_t* dst_buf, int width, int height, uint32_t src_stride, uint32_t dst_stride)
{
const uint8_t* src = src_buf;
uint8_t* dst = dst_buf;
const int blocks = width / 6;
for (int y = 0; y < height; y++) {
for (int b = 0; b < blocks; b++) {
const uint8_t* mp = src + b * 12; // 3 macropixels = 12 bytes
// mp[0]=U0, mp[1]=Y0, mp[2]=V0, mp[3]=Y1
// mp[4]=U1, mp[5]=Y2, mp[6]=V1, mp[7]=Y3
// mp[8]=U2, mp[9]=Y4, mp[10]=V2, mp[11]=Y5
dmf::v210::pack_block(dst + b * 16,
{0, static_cast<uint16_t>(mp[0]<<2), static_cast<uint16_t>(mp[2]<<2)},
static_cast<uint16_t>(mp[1]<<2), static_cast<uint16_t>(mp[3]<<2),
{0, static_cast<uint16_t>(mp[4]<<2), static_cast<uint16_t>(mp[6]<<2)},
static_cast<uint16_t>(mp[5]<<2), static_cast<uint16_t>(mp[7]<<2),
{0, static_cast<uint16_t>(mp[8]<<2), static_cast<uint16_t>(mp[10]<<2)},
static_cast<uint16_t>(mp[9]<<2), static_cast<uint16_t>(mp[11]<<2));
}
src += src_stride;
dst += dst_stride;
}
}
inline void YUV422P10toV210(
const uint16_t* y, const uint16_t* u, const uint16_t* v,
uint8_t* dst, int width, int height,
int y_stride, int u_stride, int v_stride,
uint32_t dst_stride)
{
for (int row = 0; row < height; row++) {
const uint16_t* y_row = reinterpret_cast<const uint16_t*>(
reinterpret_cast<const uint8_t*>(y) + row * y_stride);
const uint16_t* u_row = reinterpret_cast<const uint16_t*>(
reinterpret_cast<const uint8_t*>(u) + row * u_stride);
const uint16_t* v_row = reinterpret_cast<const uint16_t*>(
reinterpret_cast<const uint8_t*>(v) + row * v_stride);
uint8_t* dst_row = dst + static_cast<ptrdiff_t>(row) * dst_stride;
const int blocks = width / 6;
for (int b = 0; b < blocks; b++) {
const int x = b * 6;
const uint16_t cb0 = u_row[x/2], cb1 = u_row[x/2+1], cb2 = u_row[x/2+2];
const uint16_t cr0 = v_row[x/2], cr1 = v_row[x/2+1], cr2 = v_row[x/2+2];
const uint16_t y0 = y_row[x], y1 = y_row[x+1], y2 = y_row[x+2];
const uint16_t y3 = y_row[x+3], y4 = y_row[x+4], y5 = y_row[x+5];
auto* w = reinterpret_cast<uint32_t*>(dst_row + b * 16);
w[0] = (cb0 & 0x3FFu) | ((y0 & 0x3FFu) << 10) | ((cr0 & 0x3FFu) << 20);
w[1] = (y1 & 0x3FFu) | ((cb1 & 0x3FFu) << 10) | ((y2 & 0x3FFu) << 20);
w[2] = (cr1 & 0x3FFu) | ((y3 & 0x3FFu) << 10) | ((cb2 & 0x3FFu) << 20);
w[3] = (y4 & 0x3FFu) | ((cr2 & 0x3FFu) << 10) | ((y5 & 0x3FFu) << 20);
}
}
}
} // namespace dmf::v210