118 lines
4.1 KiB
C++
118 lines
4.1 KiB
C++
#pragma once
|
||
#include <array>
|
||
#include <cstddef>
|
||
#include <cstdint>
|
||
|
||
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 0–1
|
||
Color p23, uint16_t y2, uint16_t y3, // pair 2–3
|
||
Color p45, uint16_t y4, uint16_t y5) // pair 4–5
|
||
{
|
||
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 bars.
|
||
// `stride` is the line size in bytes as returned by MXL (configInfo.discrete.sliceSizes[0]).
|
||
// Bytes beyond the active pixels are already zeroed by the mmap, so no explicit padding needed.
|
||
inline void write_bar_line(uint8_t* line, int width, uint32_t /*stride*/)
|
||
{
|
||
const int n = static_cast<int>(SMPTE_BARS.size());
|
||
const int blocks = width / 6; // one V210 block = 6 pixels = 16 bytes
|
||
|
||
for (int b = 0; b < blocks; b++) {
|
||
int x = b * 6;
|
||
auto color = [&](int px) -> const Color& {
|
||
return SMPTE_BARS[static_cast<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 an entire frame buffer with color bars.
|
||
inline void fill_frame(uint8_t* buf, int width, int height, uint32_t stride)
|
||
{
|
||
for (int y = 0; y < height; y++) {
|
||
write_bar_line(buf + static_cast<ptrdiff_t>(y) * stride, width, stride);
|
||
}
|
||
}
|
||
|
||
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, (uint16_t)(mp[0]<<2), (uint16_t)(mp[2]<<2)}, (uint16_t)(mp[1]<<2), (uint16_t)(mp[3]<<2),
|
||
{0, (uint16_t)(mp[4]<<2), (uint16_t)(mp[6]<<2)}, (uint16_t)(mp[5]<<2), (uint16_t)(mp[7]<<2),
|
||
{0, (uint16_t)(mp[8]<<2), (uint16_t)(mp[10]<<2)}, (uint16_t)(mp[9]<<2), (uint16_t)(mp[11]<<2)
|
||
);
|
||
}
|
||
src += src_stride;
|
||
dst += dst_stride;
|
||
}
|
||
}
|
||
|
||
} // namespace dmf::v210
|