140 lines
4.1 KiB
C++
140 lines
4.1 KiB
C++
#include "VideoIOFormat.h"
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
|
|
#ifdef min
|
|
#undef min
|
|
#endif
|
|
#ifdef max
|
|
#undef max
|
|
#endif
|
|
|
|
namespace
|
|
{
|
|
uint16_t Clamp10(int value, int minimum, int maximum)
|
|
{
|
|
return static_cast<uint16_t>(std::max(minimum, std::min(maximum, value)));
|
|
}
|
|
|
|
uint32_t MakeV210Word(uint16_t a, uint16_t b, uint16_t c)
|
|
{
|
|
return (static_cast<uint32_t>(a) & 0x3ffu)
|
|
| ((static_cast<uint32_t>(b) & 0x3ffu) << 10)
|
|
| ((static_cast<uint32_t>(c) & 0x3ffu) << 20);
|
|
}
|
|
|
|
void StoreWord(std::array<uint8_t, 16>& bytes, std::size_t wordIndex, uint32_t word)
|
|
{
|
|
const std::size_t offset = wordIndex * 4;
|
|
bytes[offset + 0] = static_cast<uint8_t>(word & 0xffu);
|
|
bytes[offset + 1] = static_cast<uint8_t>((word >> 8) & 0xffu);
|
|
bytes[offset + 2] = static_cast<uint8_t>((word >> 16) & 0xffu);
|
|
bytes[offset + 3] = static_cast<uint8_t>((word >> 24) & 0xffu);
|
|
}
|
|
|
|
uint32_t LoadWord(const std::array<uint8_t, 16>& bytes, std::size_t wordIndex)
|
|
{
|
|
const std::size_t offset = wordIndex * 4;
|
|
return static_cast<uint32_t>(bytes[offset + 0])
|
|
| (static_cast<uint32_t>(bytes[offset + 1]) << 8)
|
|
| (static_cast<uint32_t>(bytes[offset + 2]) << 16)
|
|
| (static_cast<uint32_t>(bytes[offset + 3]) << 24);
|
|
}
|
|
|
|
uint16_t Component(uint32_t word, unsigned index)
|
|
{
|
|
return static_cast<uint16_t>((word >> (index * 10)) & 0x3ffu);
|
|
}
|
|
}
|
|
|
|
const char* VideoIOPixelFormatName(VideoIOPixelFormat format)
|
|
{
|
|
return format == VideoIOPixelFormat::V210 ? "10-bit YUV v210" : "8-bit YUV UYVY";
|
|
}
|
|
|
|
bool VideoIOPixelFormatIsTenBit(VideoIOPixelFormat format)
|
|
{
|
|
return format == VideoIOPixelFormat::V210;
|
|
}
|
|
|
|
BMDPixelFormat DeckLinkPixelFormatForVideoIO(VideoIOPixelFormat format)
|
|
{
|
|
return format == VideoIOPixelFormat::V210 ? bmdFormat10BitYUV : bmdFormat8BitYUV;
|
|
}
|
|
|
|
VideoIOPixelFormat VideoIOPixelFormatFromDeckLink(BMDPixelFormat format)
|
|
{
|
|
return format == bmdFormat10BitYUV ? VideoIOPixelFormat::V210 : VideoIOPixelFormat::Uyvy8;
|
|
}
|
|
|
|
VideoIOPixelFormat ChoosePreferredVideoIOFormat(bool tenBitSupported)
|
|
{
|
|
return tenBitSupported ? VideoIOPixelFormat::V210 : VideoIOPixelFormat::Uyvy8;
|
|
}
|
|
|
|
unsigned PackedTextureWidthFromRowBytes(unsigned rowBytes)
|
|
{
|
|
return (rowBytes + 3u) / 4u;
|
|
}
|
|
|
|
unsigned MinimumV210RowBytes(unsigned frameWidth)
|
|
{
|
|
return ((frameWidth + 5u) / 6u) * 16u;
|
|
}
|
|
|
|
unsigned ActiveV210WordsForWidth(unsigned frameWidth)
|
|
{
|
|
return ((frameWidth + 5u) / 6u) * 4u;
|
|
}
|
|
|
|
V210CodeValues Rec709RgbToLegalV210(float red, float green, float blue)
|
|
{
|
|
red = std::max(0.0f, std::min(1.0f, red));
|
|
green = std::max(0.0f, std::min(1.0f, green));
|
|
blue = std::max(0.0f, std::min(1.0f, blue));
|
|
|
|
const float y = 0.2126f * red + 0.7152f * green + 0.0722f * blue;
|
|
const float cb = (blue - y) / 1.8556f + 0.5f;
|
|
const float cr = (red - y) / 1.5748f + 0.5f;
|
|
|
|
V210CodeValues values;
|
|
values.y = Clamp10(static_cast<int>(std::lround(64.0f + y * 876.0f)), 64, 940);
|
|
values.cb = Clamp10(static_cast<int>(std::lround(64.0f + cb * 896.0f)), 64, 960);
|
|
values.cr = Clamp10(static_cast<int>(std::lround(64.0f + cr * 896.0f)), 64, 960);
|
|
return values;
|
|
}
|
|
|
|
std::array<uint8_t, 16> PackV210Block(const V210SixPixelBlock& block)
|
|
{
|
|
std::array<uint8_t, 16> bytes = {};
|
|
StoreWord(bytes, 0, MakeV210Word(block.cb[0], block.y[0], block.cr[0]));
|
|
StoreWord(bytes, 1, MakeV210Word(block.y[1], block.cb[1], block.y[2]));
|
|
StoreWord(bytes, 2, MakeV210Word(block.cr[1], block.y[3], block.cb[2]));
|
|
StoreWord(bytes, 3, MakeV210Word(block.y[4], block.cr[2], block.y[5]));
|
|
return bytes;
|
|
}
|
|
|
|
V210SixPixelBlock UnpackV210Block(const std::array<uint8_t, 16>& bytes)
|
|
{
|
|
const uint32_t word0 = LoadWord(bytes, 0);
|
|
const uint32_t word1 = LoadWord(bytes, 1);
|
|
const uint32_t word2 = LoadWord(bytes, 2);
|
|
const uint32_t word3 = LoadWord(bytes, 3);
|
|
|
|
V210SixPixelBlock block;
|
|
block.cb[0] = Component(word0, 0);
|
|
block.y[0] = Component(word0, 1);
|
|
block.cr[0] = Component(word0, 2);
|
|
block.y[1] = Component(word1, 0);
|
|
block.cb[1] = Component(word1, 1);
|
|
block.y[2] = Component(word1, 2);
|
|
block.cr[1] = Component(word2, 0);
|
|
block.y[3] = Component(word2, 1);
|
|
block.cb[2] = Component(word2, 2);
|
|
block.y[4] = Component(word3, 0);
|
|
block.cr[2] = Component(word3, 1);
|
|
block.y[5] = Component(word3, 2);
|
|
return block;
|
|
}
|