pip based

This commit is contained in:
JohannesItten
2026-07-09 18:31:53 +03:00
parent 3820d0eeb7
commit 041588b990
5 changed files with 291 additions and 138 deletions
+102
View File
@@ -1,8 +1,10 @@
#pragma once
#include <algorithm>
#include <array>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <vector>
namespace dmf::v210 {
@@ -173,4 +175,104 @@ inline void YUV422P10toV210(
}
}
// Unpack one V210 row into planar uint16_t Y (width values),
// Cb and Cr (width/2 values each). Width must be a multiple of 6.
inline void unpack_row(const uint8_t* src, int width,
uint16_t* Y, uint16_t* Cb, uint16_t* Cr)
{
const auto* w = reinterpret_cast<const uint32_t*>(src);
const int blocks = width / 6;
for (int b = 0; b < blocks; ++b, w += 4) {
const int x = b * 6;
Cb[x/2] = (w[0] >> 0) & 0x3FF;
Y[x] = (w[0] >> 10) & 0x3FF;
Cr[x/2] = (w[0] >> 20) & 0x3FF;
Y[x+1] = (w[1] >> 0) & 0x3FF;
Cb[x/2+1] = (w[1] >> 10) & 0x3FF;
Y[x+2] = (w[1] >> 20) & 0x3FF;
Cr[x/2+1] = (w[2] >> 0) & 0x3FF;
Y[x+3] = (w[2] >> 10) & 0x3FF;
Cb[x/2+2] = (w[2] >> 20) & 0x3FF;
Y[x+4] = (w[3] >> 0) & 0x3FF;
Cr[x/2+2] = (w[3] >> 10) & 0x3FF;
Y[x+5] = (w[3] >> 20) & 0x3FF;
}
}
// Scale the inset V210 frame into a rectangular region of dst using bilinear
// interpolation. pip_x and pip_w must be multiples of 6 (V210 alignment).
// Workspace vectors are passed in to avoid per-call heap allocation.
inline void scale_and_overlay(
const uint8_t* inset, uint32_t inset_stride, int inset_w, int inset_h,
uint8_t* dst, uint32_t dst_stride,
int pip_x, int pip_y, int pip_w, int pip_h,
std::vector<uint16_t>& Y0_buf, std::vector<uint16_t>& Y1_buf,
std::vector<uint16_t>& Cb0_buf, std::vector<uint16_t>& Cb1_buf,
std::vector<uint16_t>& Cr0_buf, std::vector<uint16_t>& Cr1_buf)
{
Y0_buf.resize(inset_w); Y1_buf.resize(inset_w);
Cb0_buf.resize(inset_w / 2); Cb1_buf.resize(inset_w / 2);
Cr0_buf.resize(inset_w / 2); Cr1_buf.resize(inset_w / 2);
const int out_blocks = pip_w / 6;
const int dst_x_bytes = (pip_x / 6) * 16;
const float inv_pip_h = static_cast<float>(inset_h) / pip_h;
const float inv_pip_w = static_cast<float>(inset_w) / pip_w;
const float inv_pip_cw = static_cast<float>(inset_w / 2) / (pip_w / 2);
int cur_row0 = -1, cur_row1 = -1;
for (int dy = 0; dy < pip_h; ++dy) {
const float sy = (dy + 0.5f) * inv_pip_h - 0.5f;
const int sy0 = std::max(0, static_cast<int>(sy));
const int sy1 = std::min(inset_h - 1, sy0 + 1);
const float fy = sy - static_cast<float>(sy0);
if (sy0 != cur_row0) {
unpack_row(inset + static_cast<size_t>(sy0) * inset_stride, inset_w,
Y0_buf.data(), Cb0_buf.data(), Cr0_buf.data());
cur_row0 = sy0;
}
if (sy1 != cur_row1) {
unpack_row(inset + static_cast<size_t>(sy1) * inset_stride, inset_w,
Y1_buf.data(), Cb1_buf.data(), Cr1_buf.data());
cur_row1 = sy1;
}
uint8_t* dst_row = dst + static_cast<size_t>(pip_y + dy) * dst_stride + dst_x_bytes;
for (int b = 0; b < out_blocks; ++b) {
const int bx = b * 6;
uint16_t Y[6], Cb[3], Cr[3];
for (int i = 0; i < 6; ++i) {
const float sx = (bx + i + 0.5f) * inv_pip_w - 0.5f;
const int sx0 = std::max(0, static_cast<int>(sx));
const int sx1 = std::min(inset_w - 1, sx0 + 1);
const float fx = sx - static_cast<float>(sx0);
Y[i] = static_cast<uint16_t>(
Y0_buf[sx0] * (1-fx) * (1-fy) + Y0_buf[sx1] * fx * (1-fy) +
Y1_buf[sx0] * (1-fx) * fy + Y1_buf[sx1] * fx * fy + 0.5f);
}
for (int i = 0; i < 3; ++i) {
const float cx = (b * 3 + i + 0.5f) * inv_pip_cw - 0.5f;
const int cx0 = std::max(0, static_cast<int>(cx));
const int cx1 = std::min(inset_w / 2 - 1, cx0 + 1);
const float cfx = cx - static_cast<float>(cx0);
Cb[i] = static_cast<uint16_t>(
Cb0_buf[cx0]*(1-cfx)*(1-fy) + Cb0_buf[cx1]*cfx*(1-fy) +
Cb1_buf[cx0]*(1-cfx)* fy + Cb1_buf[cx1]*cfx* fy + 0.5f);
Cr[i] = static_cast<uint16_t>(
Cr0_buf[cx0]*(1-cfx)*(1-fy) + Cr0_buf[cx1]*cfx*(1-fy) +
Cr1_buf[cx0]*(1-cfx)* fy + Cr1_buf[cx1]*cfx* fy + 0.5f);
}
pack_block(dst_row + b * 16,
{0, Cb[0], Cr[0]}, Y[0], Y[1],
{0, Cb[1], Cr[1]}, Y[2], Y[3],
{0, Cb[2], Cr[2]}, Y[4], Y[5]);
}
}
}
} // namespace dmf::v210