11#include <promeki/config.h>
12#if PROMEKI_ENABLE_PROAV
17PROMEKI_NAMESPACE_BEGIN
72 static constexpr uint8_t withOddParity(uint8_t c) {
73 uint8_t v =
static_cast<uint8_t
>(c & 0x7F);
75 for (
int i = 0; i < 7; ++i) {
76 if (v & (1u << i)) ++ones;
78 if ((ones & 1u) == 0u) v =
static_cast<uint8_t
>(v | 0x80);
84 static constexpr bool checkOddParity(uint8_t c) {
86 for (
int i = 0; i < 8; ++i) {
87 if (c & (1u << i)) ++ones;
89 return (ones & 1u) != 0u;
93 static constexpr uint8_t stripParity(uint8_t c) {
return static_cast<uint8_t
>(c & 0x7F); }
106 static constexpr bool checkOddParityPair(uint8_t b1, uint8_t b2) {
107 return checkOddParity(b1) && checkOddParity(b2);
120 enum class Channel : uint8_t {
131 static constexpr bool isSecondChannelOfField(Channel ch) {
132 return ch == Channel::CC2 || ch == Channel::CC4;
139 static constexpr bool isFieldTwo(Channel ch) {
140 return ch == Channel::CC3 || ch == Channel::CC4;
151 static constexpr uint8_t Cc1MiscFirstByte = 0x14;
155 static constexpr uint8_t MiscRCL = 0x20;
156 static constexpr uint8_t MiscBS = 0x21;
157 static constexpr uint8_t MiscDER = 0x24;
158 static constexpr uint8_t MiscRU2 = 0x25;
159 static constexpr uint8_t MiscRU3 = 0x26;
160 static constexpr uint8_t MiscRU4 = 0x27;
161 static constexpr uint8_t MiscFON = 0x28;
162 static constexpr uint8_t MiscRDC = 0x29;
163 static constexpr uint8_t MiscTR = 0x2A;
164 static constexpr uint8_t MiscRTD = 0x2B;
165 static constexpr uint8_t MiscEDM = 0x2C;
166 static constexpr uint8_t MiscCR = 0x2D;
167 static constexpr uint8_t MiscENM = 0x2E;
168 static constexpr uint8_t MiscEOC = 0x2F;
173 static constexpr uint8_t RclB1 = Cc1MiscFirstByte;
174 static constexpr uint8_t RclB2 = MiscRCL;
177 static constexpr uint8_t EocB1 = Cc1MiscFirstByte;
178 static constexpr uint8_t EocB2 = MiscEOC;
181 static constexpr uint8_t EdmB1 = Cc1MiscFirstByte;
182 static constexpr uint8_t EdmB2 = MiscEDM;
185 static constexpr uint8_t EnmB1 = Cc1MiscFirstByte;
186 static constexpr uint8_t EnmB2 = MiscENM;
196 static constexpr uint8_t PacRow15Col0WhiteB1 = 0x14;
197 static constexpr uint8_t PacRow15Col0WhiteB2 = 0x70;
231 enum class CaptionColor : uint8_t {
246 static constexpr size_t CaptionColorCount = 8;
262 static constexpr size_t FgCaptionColorCount = 7;
280 static Color::List palette();
293 CaptionColor color = CaptionColor::White;
299 bool underline =
false;
320 static void encodePac(
const PacAttr &attr, uint8_t &b1, uint8_t &b2);
331 static bool isPac(uint8_t b1, uint8_t b2);
339 static bool decodePac(uint8_t b1, uint8_t b2, PacAttr &out);
357 static void encodeMidRow(CaptionColor color,
bool italic,
bool underline, uint8_t &b1,
364 static bool isMidRow(uint8_t b1, uint8_t b2);
371 static bool decodeMidRow(uint8_t b1, uint8_t b2, CaptionColor &outColor,
bool &outItalic,
397 static void encodeBgAttribute(CaptionColor color,
bool semiTransparent, uint8_t &b1,
404 static bool isBgAttribute(uint8_t b1, uint8_t b2);
412 static bool decodeBgAttribute(uint8_t b1, uint8_t b2, CaptionColor &outColor,
413 bool &outSemiTransparent);
430 static bool isBt(uint8_t b1, uint8_t b2);
442 static void encodeBackgroundTransparency(uint8_t &b1, uint8_t &b2) {
465 static constexpr uint8_t Cc1ExtAttrB1 = 0x17;
470 static constexpr uint8_t TabOffsetT1 = 0x21;
471 static constexpr uint8_t TabOffsetT2 = 0x22;
472 static constexpr uint8_t TabOffsetT3 = 0x23;
501 static void encodeTabOffset(
int columns, uint8_t &b1, uint8_t &b2);
507 static bool isTabOffset(uint8_t b1, uint8_t b2);
518 static bool decodeTabOffset(uint8_t b1, uint8_t b2,
int &outColumns);
544 static constexpr uint8_t BtB2 = 0x2D;
546 static constexpr uint8_t FaB2 = 0x2E;
548 static constexpr uint8_t FauB2 = 0x2F;
559 static void encodeFgBlack(
bool underline, uint8_t &b1, uint8_t &b2) {
561 b2 = underline ? FauB2 : FaB2;
567 static bool isFgBlack(uint8_t b1, uint8_t b2) {
568 return b1 == Cc1ExtAttrB1 && (b2 == FaB2 || b2 == FauB2);
575 static bool decodeFgBlack(uint8_t b1, uint8_t b2,
bool &outUnderline) {
576 if (!isFgBlack(b1, b2))
return false;
577 outUnderline = (b2 == FauB2);
588 static constexpr uint8_t NullB1 = 0x00;
589 static constexpr uint8_t NullB2 = 0x00;
599 static constexpr bool isControlPair(uint8_t b1, uint8_t b2) {
601 return b1 >= 0x10 && b1 <= 0x1F;
642 static constexpr uint8_t applyChannel(uint8_t b1, uint8_t b2, Channel channel) {
643 if (b1 < 0x10 || b1 > 0x1F)
return b1;
645 if (isSecondChannelOfField(channel)) {
646 out =
static_cast<uint8_t
>(out | 0x08);
648 if (isFieldTwo(channel) && b2 >= 0x20 && b2 <= 0x2F) {
649 if (out == 0x14) out = 0x15;
650 else if (out == 0x1C) out = 0x1D;
664 static constexpr void applyChannelInPlace(uint8_t &b1, uint8_t b2, Channel channel) {
665 b1 = applyChannel(b1, b2, channel);
675 static constexpr bool isXdsControl(uint8_t b1) {
676 return b1 >= 0x01 && b1 <= 0x0E;
683 static constexpr bool isXdsTerminator(uint8_t b1, uint8_t b2) {
697 static constexpr bool isBasicChar(uint8_t c) {
698 const uint8_t v = stripParity(c);
699 return v >= 0x20 && v <= 0x7F;
737struct Cea608PairDeduper {
743 bool accept(uint8_t b1, uint8_t b2) {
744 if (!Cea608::isControlPair(b1, b2)) {
751 if (_hasPending && b1 == _lastB1 && b2 == _lastB2) {
778 bool _hasPending =
false;