26#define LOC QString("EDID: ")
29 : m_data(std::move(Data))
35 : m_data(Data, Length)
120 return { 0, 0,
false };
126 QByteArray buffer(
reinterpret_cast<const char *
>(data), 13);
129 buffer = buffer.replace(
'\r',
'\0').replace(
'\n',
'\0');
136 for (
auto && i : buffer) {
137 if (i < '\040' || i >
'\176')
141 return QString::fromLatin1(buffer.trimmed());
149 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
"Invalid EDID");
154 const auto *data =
reinterpret_cast<const quint8 *
>(
m_data.constData());
157 if ((
m_size % 0x80) || data[0] != 0x00 || data[1] != 0xff)
159 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
"Invalid EDID");
165 if (
auto sum = std::accumulate(
m_data.cbegin(),
m_data.cend(), 0, std::plus<char>()); (sum % 0xff) != 0)
167 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Checksum error");
177 if (extensions != available)
179 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Extension count error");
186 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"EDID has %1 extension blocks").arg(extensions));
187 for (
uint i = 1; i <= available; ++i)
189 uint offset = i * 128;
190 switch (data[offset])
203 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
"Unknown major version number");
242 m_gamma = (gamma + 100.0F) / 100.0F;
250 static constexpr std::array<const uint8_t,10> s_sRGB =
251 { 0xEE, 0x91, 0xA3, 0x54, 0x4C, 0x99, 0x26, 0x0F, 0x50, 0x54 };
252 bool srgb = std::equal(s_sRGB.cbegin(), s_sRGB.cend(), Data + 0x19);
257 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Chromaticity mismatch!");
275 qFuzzyCompare(
m_gamma + 1.0F, 2.20F + 1.0F);
278 for (
size_t i = 0; i < 4; ++i)
281 if (Data[offset] == 0 || Data[offset + 1] == 0 || Data[offset + 2] == 0)
289 [](
const QString& Serial) {
return !Serial.isEmpty(); });
291 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"No serial number(s) in EDID");
297 auto type = Data[Offset + 3];
298 auto offset = Offset + 5;
314 if (Data[Offset + 4] & 0x02)
317 if (Data[Offset + 4] & 0x01)
329 auto width = Data[Offset + 12] + ((Data[Offset + 14] & 0xF0) << 4);
330 auto height = Data[Offset + 13] + ((Data[Offset + 14] & 0x0F) << 8);
347 quint8
version = Data[Offset + 1];
348 quint8 offset = Data[Offset + 2];
350 if (offset < 4 ||
version != 3)
353 for (
uint i = Offset + 4; (i < (Offset + offset)) && (i <
m_size); i += (Data[i] & 0x1F) + 1)
360 uint length = Data[Offset] & 0x1F;
361 uint type = (Data[Offset] & 0xE0) >> 5;
366 case 0x03:
ParseVSDB(Data, Offset + 1, length);
break;
381 int registration = Data[Offset] + (Data[Offset + 1] << 8) + (Data[Offset + 2] << 16);
384 while (registration == 0x000C03)
388 if (Length < 5 || (Offset + 5 >=
m_size))
394 if (Length < 6 || (Offset + 6 >=
m_size))
400 if (Length < 8 || (Offset + 8 >=
m_size))
407 if (Length < 10 || (Offset + 10 >=
m_size))
411 quint8 video = Data[Offset + 8];
412 if (video > 0 && video <= 251)
414 quint8 audio = Data[Offset + 9];
415 if (audio > 0 && audio <= 251)
419 if (Length < 12 || (Offset + 12 >=
m_size))
424 quint8 video = Data[Offset + 10];
425 if (video > 0 && video <= 251)
427 quint8 audio = Data[Offset + 11];
428 if (audio > 0 && audio <= 251)
436 while (registration == 0xC45DD8)
438 if (Length < 5 || (Offset + 5 >=
m_size))
444 if (Length < 11 || (Offset + 11 >=
m_size))
449 m_vrrMax = ((Data[Offset + 9] & 0xc0) << 2) | Data[Offset + 10];
462 if (Data[Offset] == 0x06 && Length)
464 if (Length >= 3 && (Offset + 3 <
m_size))
466 int hdrsupport = Data[Offset + 1] & 0x3f;
467 if (hdrsupport &
HDR10)
469 if (hdrsupport &
HLG)
481 m_minLuminance = (50.0 * pow(2, Data[Offset + 3] / 32.0)) * pow(Data[Offset + 5] / 255.0, 2) / 100.0;
488 auto deep = [](uint8_t Deep)
491 if (Deep & 0x08) res <<
"Y444";
492 if (Deep & 0x10) res <<
"30bit";
493 if (Deep & 0x20) res <<
"36bit";
494 if (Deep & 0x40) res <<
"48bit";
495 return res.join(
",");
498 auto deepyuv = [](uint8_t Deep)
501 if (Deep & 0x01) res <<
"10bit";
502 if (Deep & 0x02) res <<
"12bit";
503 if (Deep & 0x04) res <<
"16bit";
504 return res.join(
",");
509 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Invalid EDID");
513 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Version:1.%1 Size:%2 Exensions:%3")
515 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Gamma:%1 sRGB:%2")
517 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Display chromaticity:-");
518 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Red:\t%1,\t%2")
521 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Green:\t%1,\t%2")
524 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Blue:\t%1,\t%2")
527 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"White:\t%1,\t%2")
535 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Physical address: %1").arg(address));
537 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Deep color: %1").arg(deep(
m_deepColor)));
540 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Latencies: Audio:%1 Video:%2")
544 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Latencies: Audio:%1 Video:%2 (Interlaced)")
549 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Deep YUV 4:2:0 %1").arg(deepyuv(
m_deepYUV)));
556 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Desired luminance: Min: %1 Max: %2 Avg: %3")
static bool Alike(const MythColourSpace &First, const MythColourSpace &Second, float Fuzz)
MythPrimaryFloat m_whitePoint
static MythColourSpace s_sRGB
MythPrimariesFloat m_primaries
uint16_t m_physicalAddress
MythHDRDesc GetHDRSupport() const
bool ParseVSDB(const quint8 *Data, size_t Offset, size_t Length)
std::array< int, 2 > m_audioLatency
int AudioLatency(bool Interlaced) const
QStringList m_serialNumbers
bool ParseExtended(const quint8 *Data, size_t Offset, size_t Length)
MythHDR::HDRTypes m_hdrSupport
bool ParseCTABlock(const quint8 *Data, size_t Offset)
int VideoLatency(bool Interlaced) const
MythColourSpace m_primaries
QSize DisplaySize() const
uint16_t PhysicalAddress() const
std::array< int, 2 > m_videoLatency
QStringList SerialNumbers() const
void ParseDetailedTimingDescriptor(const quint8 *Data, size_t Offset)
MythColourSpace ColourPrimaries() const
bool ParseBaseBlock(const quint8 *Data)
double DisplayAspect() const
void ParseDisplayDescriptor(const quint8 *Data, uint Offset)
bool ParseCTA861(const quint8 *Data, size_t Offset)
MythVRRRange GetVRRRange() const
Return the range of supported refresh rates.
QStringList TypesToString() const
static constexpr uint8_t DESCRIPTOR_RANGE_LIMITS
static constexpr size_t HEIGHT_OFFSET
static constexpr size_t WIDTH_OFFSET
static constexpr size_t GAMMA_OFFSET
static constexpr size_t VERSION_OFFSET
static constexpr size_t EXTENSIONS_OFFSET
static constexpr uint8_t DESCRIPTOR_PRODUCT_NAME
static constexpr size_t SERIAL_OFFSET
static QString ParseEdidString(const quint8 *data, bool Replace)
static constexpr uint8_t DESCRIPTOR_SERIAL_NUMBER
static constexpr size_t DATA_BLOCK_OFFSET
static constexpr size_t FEATURES_OFFSET
std::tuple< MythHDR::HDRTypes, double, double, double > MythHDRDesc
std::tuple< int, int, bool > MythVRRRange
#define LOG(_MASK_, _LEVEL_, _QSTRING_)