Files
salmanoff/stimBuffApis/lcameraBuff/pixelAndColorFormatDecisions.cpp
T
hayodea e7b7a311f7 Add lcameraBuff Stage 2 plugin with YUV attach and unit tests.
Introduce params parsing, pixel/format decisions, capture layout, shared
YuvStimProducer per camera, and channel stimulus buffers with attach flow.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-14 11:03:19 -04:00

142 lines
3.2 KiB
C++

#include <pixelAndColorFormatDecisions.h>
#include <algorithm>
#include <cctype>
#include <stdexcept>
#include <string>
#include <unordered_set>
namespace smo {
namespace stim_buff {
namespace lcamera_buff {
namespace {
std::string normalizeFourccToken(std::string token)
{
for (char& character : token)
{
character = static_cast<char>(
std::toupper(static_cast<unsigned char>(character)));
}
return token;
}
bool fourccInSet(
const std::string& fourcc,
const std::unordered_set<std::string>& candidates)
{
return candidates.find(fourcc) != candidates.end();
}
const std::unordered_set<std::string>& yuv420FourccSet()
{
static const std::unordered_set<std::string> fourccs = {
"YU12", "YV12", "YUV420", "YVU420", "NV12", "NV21",
};
return fourccs;
}
const std::unordered_set<std::string>& yuv422FourccSet()
{
static const std::unordered_set<std::string> fourccs = {
"YUYV", "YVYU", "UYVY", "VYUY", "YUV422", "YVU422",
"NV16", "NV61", "YU16", "YV16",
};
return fourccs;
}
const std::unordered_set<std::string>& yuv444FourccSet()
{
static const std::unordered_set<std::string> fourccs = {
"YUV444", "YVU444",
};
return fourccs;
}
unsigned chromaPlaneWidth(unsigned frameWidth, YuvChromaSubsampling subsampling)
{
switch (subsampling)
{
case YuvChromaSubsampling::Yuv420:
case YuvChromaSubsampling::Yuv422:
return (frameWidth + 1u) / 2u;
case YuvChromaSubsampling::Yuv444:
return frameWidth;
}
throw std::logic_error(
"lcameraBuff: unhandled YuvChromaSubsampling in chromaPlaneWidth");
}
unsigned chromaPlaneHeight(unsigned frameHeight, YuvChromaSubsampling subsampling)
{
switch (subsampling)
{
case YuvChromaSubsampling::Yuv420:
return (frameHeight + 1u) / 2u;
case YuvChromaSubsampling::Yuv422:
case YuvChromaSubsampling::Yuv444:
return frameHeight;
}
throw std::logic_error(
"lcameraBuff: unhandled YuvChromaSubsampling in chromaPlaneHeight");
}
} // namespace
YuvChromaSubsampling classifyYuvChromaSubsampling(
const lcamera_dev::LcameraDevConfiguredCameraMode& configuredMode)
{
const std::string fourcc =
normalizeFourccToken(configuredMode.pixelFormatName);
if (fourccInSet(fourcc, yuv420FourccSet())) {
return YuvChromaSubsampling::Yuv420;
}
if (fourccInSet(fourcc, yuv422FourccSet())) {
return YuvChromaSubsampling::Yuv422;
}
if (fourccInSet(fourcc, yuv444FourccSet())) {
return YuvChromaSubsampling::Yuv444;
}
throw std::runtime_error(
"lcameraBuff: unsupported YUV pixel format for chroma geometry: "
+ configuredMode.pixelFormatName);
}
size_t computeDeinterleavedChannelByteSize(
YuvChannelKind channel,
unsigned width, unsigned height,
YuvChromaSubsampling subsampling)
{
switch (channel)
{
case YuvChannelKind::Y:
return static_cast<size_t>(width) * static_cast<size_t>(height);
case YuvChannelKind::U:
case YuvChannelKind::V:
{
const unsigned chromaWidth = chromaPlaneWidth(width, subsampling);
const unsigned chromaHeight =
chromaPlaneHeight(height, subsampling);
return static_cast<size_t>(chromaWidth)
* static_cast<size_t>(chromaHeight);
}
}
throw std::logic_error(
"lcameraBuff: unhandled YuvChannelKind in computeDeinterleavedChannelByteSize");
}
} // namespace lcamera_buff
} // namespace stim_buff
} // namespace smo