MythTV master
mythedid.cpp
Go to the documentation of this file.
1// MythTV
3#include "mythedid.h"
4
5// Qt
6#include <QObject>
7
8// Std
9#include <algorithm>
10#include <cmath>
11
12//static constexpr uint8_t DESCRIPTOR_ALPHANUMERIC_STRING { 0xFE };
13static constexpr uint8_t DESCRIPTOR_PRODUCT_NAME { 0xFC };
14static constexpr uint8_t DESCRIPTOR_RANGE_LIMITS { 0xFD };
15static constexpr uint8_t DESCRIPTOR_SERIAL_NUMBER { 0xFF };
16static constexpr size_t DATA_BLOCK_OFFSET { 0x36 };
17static constexpr size_t SERIAL_OFFSET { 0x0C };
18static constexpr size_t VERSION_OFFSET { 0x12 };
19//static constexpr size_t DISPLAY_OFFSET { 0x14 };
20static constexpr size_t WIDTH_OFFSET { 0x15 };
21static constexpr size_t HEIGHT_OFFSET { 0x16 };
22static constexpr size_t GAMMA_OFFSET { 0x17 };
23static constexpr size_t FEATURES_OFFSET { 0x18 };
24static constexpr size_t EXTENSIONS_OFFSET { 0x7E };
25
26#define LOC QString("EDID: ")
27
28MythEDID::MythEDID(QByteArray Data)
29 : m_data(std::move(Data))
30{
31 Parse();
32}
33
34MythEDID::MythEDID(const char* Data, int Length)
35 : m_data(Data, Length)
36{
37 Parse();
38}
39
40bool MythEDID::Valid() const
41{
42 return m_valid;
43}
44
45QStringList MythEDID::SerialNumbers() const
46{
47 return m_serialNumbers;
48}
49
51{
52 return m_displaySize;
53}
54
56{
57 return m_displayAspect;
58}
59
61{
62 return m_physicalAddress;
63}
64
65float MythEDID::Gamma() const
66{
67 return m_gamma;
68}
69
70bool MythEDID::IsHDMI() const
71{
72 return m_isHDMI;
73}
74
75bool MythEDID::IsSRGB() const
76{
77 return m_sRGB;
78}
79
81{
82 return m_likeSRGB;
83}
84
86{
87 return m_primaries;
88}
89
90int MythEDID::AudioLatency(bool Interlaced) const
91{
92 return m_audioLatency[Interlaced ? 1 : 0];
93}
94
95int MythEDID::VideoLatency(bool Interlaced) const
96{
97 return m_videoLatency[Interlaced ? 1 : 0];
98}
99
101{
103}
104
115{
116 if (m_valid && m_vrrMin && m_vrrMax)
117 return { m_vrrMin, m_vrrMax, true };
119 return { m_vrangeMin, m_vrangeMax, false };
120 return { 0, 0, false };
121}
122
123// from QEdidParser
124static QString ParseEdidString(const quint8* data, bool Replace)
125{
126 QByteArray buffer(reinterpret_cast<const char *>(data), 13);
127
128 // Erase carriage return and line feed
129 buffer = buffer.replace('\r', '\0').replace('\n', '\0');
130
131 // Replace non-printable characters with dash
132 // Earlier versions of QEdidParser got this wrong - so we potentially get
133 // different values for serialNumber from QScreen
134 if (Replace)
135 {
136 for (auto && i : buffer) {
137 if (i < '\040' || i > '\176')
138 i = '-';
139 }
140 }
141 return QString::fromLatin1(buffer.trimmed());
142}
143
145{
146 // This is adapted from various sources including QEdidParser, edid-decode and xrandr
147 if (!m_data.constData() || m_data.isEmpty())
148 {
149 LOG(VB_GENERAL, LOG_DEBUG, LOC + "Invalid EDID");
150 return;
151 }
152
153 m_size = static_cast<uint>(m_data.size());
154 const auto *data = reinterpret_cast<const quint8 *>(m_data.constData());
155
156 // EDID data should be in 128 byte blocks
157 if ((m_size % 0x80) || data[0] != 0x00 || data[1] != 0xff)
158 {
159 LOG(VB_GENERAL, LOG_DEBUG, LOC + "Invalid EDID");
160 return;
161 }
162
163 // checksum
164 // NOLINTNEXTLINE(modernize-use-transparent-functors)
165 if (auto sum = std::accumulate(m_data.cbegin(), m_data.cend(), 0, std::plus<char>()); (sum % 0xff) != 0)
166 {
167 LOG(VB_GENERAL, LOG_INFO, LOC + "Checksum error");
168 return;
169 }
170
171 if (!ParseBaseBlock(data))
172 return;
173
174 // Look at extension blocks
175 uint extensions = data[EXTENSIONS_OFFSET];
176 uint available = (m_size / 128) - 1;
177 if (extensions != available)
178 {
179 LOG(VB_GENERAL, LOG_WARNING, LOC + "Extension count error");
180 return;
181 }
182
183 if (extensions < 1)
184 return;
185
186 LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("EDID has %1 extension blocks").arg(extensions));
187 for (uint i = 1; i <= available; ++i)
188 {
189 uint offset = i * 128;
190 switch (data[offset])
191 {
192 case 0x02: m_valid &= ParseCTA861(data, offset); break;
193 default: continue;
194 }
195 }
196}
197
198bool MythEDID::ParseBaseBlock(const quint8* Data)
199{
200 // retrieve version
201 if (Data[VERSION_OFFSET] != 1)
202 {
203 LOG(VB_GENERAL, LOG_DEBUG, LOC + "Unknown major version number");
204 return false;
205 }
206 m_minorVersion = Data[VERSION_OFFSET + 1];
207
208 // retrieve serial number. This may be subsequently overridden.
209 // N.B. 0 is a valid serial number.
210 qint32 serial = Data[SERIAL_OFFSET] +
211 (Data[SERIAL_OFFSET + 1] << 8) +
212 (Data[SERIAL_OFFSET + 2] << 16) +
213 (Data[SERIAL_OFFSET + 3] << 24);
214 m_serialNumbers << QString::number(serial);
215
216 // digital or analog
217 //bool digital = Data[DISPLAY_OFFSET] & 0x80;
218
219 // Display size
220 if (Data[WIDTH_OFFSET] && Data[HEIGHT_OFFSET])
221 {
222 m_displaySize = QSize(Data[WIDTH_OFFSET] * 10, Data[HEIGHT_OFFSET] * 10);
223 }
224 else if (m_minorVersion >= 4 && (Data[WIDTH_OFFSET] || Data[HEIGHT_OFFSET]))
225 {
226 if (Data[WIDTH_OFFSET])
227 m_displayAspect = 100.0 / (Data[HEIGHT_OFFSET] + 99); // Landscape
228 else
229 m_displayAspect = 100.0 / (Data[WIDTH_OFFSET] + 99); // Portrait
230 }
231
232 // retrieve gamma
233 quint8 gamma = Data[GAMMA_OFFSET];
234 if (gamma == 0xFF)
235 {
236 // for 1.4 - this means gamma is defined in an extension block
237 if (m_minorVersion < 4)
238 m_gamma = 1.0F;
239 }
240 else
241 {
242 m_gamma = (gamma + 100.0F) / 100.0F;
243 }
244
245 // Chromaticity
246 // Note - the EDID format introduces slight rounding errors when converting
247 // to sRGB specs. If sRGB is set, the client should use the spec values - not
248 // the computed values
249 m_sRGB = ((Data[FEATURES_OFFSET] & 0x04) != 0);
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);
253
254 if (!m_sRGB && srgb)
255 m_sRGB = true;
256 else if (m_sRGB && !srgb)
257 LOG(VB_GENERAL, LOG_WARNING, LOC + "Chromaticity mismatch!");
258
259 // Red
260 m_primaries.m_primaries[0][0] = ((Data[0x1B] << 2) | (Data[0x19] >> 6)) / 1024.0F;
261 m_primaries.m_primaries[0][1] = ((Data[0x1C] << 2) | ((Data[0x19] >> 4) & 3)) / 1024.0F;
262 // Green
263 m_primaries.m_primaries[1][0] = ((Data[0x1D] << 2) | ((Data[0x19] >> 2) & 3)) / 1024.0F;
264 m_primaries.m_primaries[1][1] = ((Data[0x1E] << 2) | (Data[0x19] & 3)) / 1024.0F;
265 // Blue
266 m_primaries.m_primaries[2][0] = ((Data[0x1F] << 2) | (Data[0x1A] >> 6)) / 1024.0F;
267 m_primaries.m_primaries[2][1] = ((Data[0x20] << 2) | ((Data[0x1A] >> 4) & 3)) / 1024.0F;
268 // White
269 m_primaries.m_whitePoint[0] = ((Data[0x21] << 2) | ((Data[0x1A] >> 2) & 3)) / 1024.0F;
270 m_primaries.m_whitePoint[1] = ((Data[0x22] << 2) | (Data[0x1A] & 3)) / 1024.0F;
271
272 // Check whether this is very similar to sRGB and hence if non-exact colourspace
273 // handling is preferred, then just use sRGB.
275 qFuzzyCompare(m_gamma + 1.0F, 2.20F + 1.0F);
276
277 // Parse blocks
278 for (size_t i = 0; i < 4; ++i)
279 {
280 size_t offset = DATA_BLOCK_OFFSET + (i * 18);
281 if (Data[offset] == 0 || Data[offset + 1] == 0 || Data[offset + 2] == 0)
282 ParseDisplayDescriptor(Data, offset);
283 else
284 ParseDetailedTimingDescriptor(Data, offset);
285 }
286
287 // Set status
288 m_valid = std::ranges::any_of(std::as_const(m_serialNumbers),
289 [](const QString& Serial) { return !Serial.isEmpty(); });
290 if (!m_valid)
291 LOG(VB_GENERAL, LOG_WARNING, LOC + "No serial number(s) in EDID");
292 return m_valid;
293}
294
295void MythEDID::ParseDisplayDescriptor(const quint8* Data, uint Offset)
296{
297 auto type = Data[Offset + 3];
298 auto offset = Offset + 5;
300 {
301 m_serialNumbers << ParseEdidString(&Data[offset], false);
302 m_serialNumbers << ParseEdidString(&Data[offset], true);
303 }
304 else if (DESCRIPTOR_PRODUCT_NAME == type)
305 {
306 m_name = ParseEdidString(&Data[offset], true);
307 }
308 else if (DESCRIPTOR_RANGE_LIMITS == type)
309 {
310 auto vminoffset = 0;
311 auto vmaxoffset = 0;
312 if (m_minorVersion > 3)
313 {
314 if (Data[Offset + 4] & 0x02)
315 {
316 vmaxoffset = 255;
317 if (Data[Offset + 4] & 0x01)
318 vminoffset = 255;
319 }
320 }
321 m_vrangeMin = Data[Offset + 5] + vminoffset;
322 m_vrangeMax = Data[Offset + 6] + vmaxoffset;
323 }
324}
325
326void MythEDID::ParseDetailedTimingDescriptor(const quint8* Data, size_t Offset)
327{
328 // We're only really interested in a more accurate display size
329 auto width = Data[Offset + 12] + ((Data[Offset + 14] & 0xF0) << 4);
330 auto height = Data[Offset + 13] + ((Data[Offset + 14] & 0x0F) << 8);
331
332 // 1.4 may have set an aspect ratio instead of size, otherwise use if this
333 // looks like a more accurate version of our current size
334 if (m_displaySize.isEmpty() ||
335 ((abs(m_displaySize.width() - width) < 10) && (abs(m_displaySize.height() - height) < 10)))
336 {
337 m_displaySize = { width, height };
338 }
339}
340
341bool MythEDID::ParseCTA861(const quint8* Data, size_t Offset)
342{
343 if (Offset >= m_size)
344 return false;
345
346 bool result = true;
347 quint8 version = Data[Offset + 1];
348 quint8 offset = Data[Offset + 2];
349
350 if (offset < 4 || version != 3)
351 return result;
352
353 for (uint i = Offset + 4; (i < (Offset + offset)) && (i < m_size); i += (Data[i] & 0x1F) + 1)
354 result &= ParseCTABlock(Data, i);
355 return result;
356}
357
358bool MythEDID::ParseCTABlock(const quint8* Data, size_t Offset)
359{
360 uint length = Data[Offset] & 0x1F;
361 uint type = (Data[Offset] & 0xE0) >> 5;
362 switch (type)
363 {
364 case 0x01: break; // Audio data block // NOLINT(bugprone-branch-clone)
365 case 0x02: break; // Video data block
366 case 0x03: ParseVSDB(Data, Offset + 1, length); break; // Vendor Specific Data Block
367 case 0x04: break; // Speaker Allocation data block // NOLINT(bugprone-branch-clone)
368 case 0x05: break; // VESA DTC data block
369 case 0x07: ParseExtended(Data, Offset + 1, length); break; // Extended tag. HDR metadata here
370 default: break;
371 }
372 return true;
373}
374
375bool MythEDID::ParseVSDB(const quint8* Data, size_t Offset, size_t Length)
376{
377 if (Offset + 3 >= m_size)
378 return false;
379
380 // N.B. Little endian
381 int registration = Data[Offset] + (Data[Offset + 1] << 8) + (Data[Offset + 2] << 16);
382
383 // "HDMI Licensing, LLC"
384 while (registration == 0x000C03)
385 {
386 m_isHDMI = true;
387
388 if (Length < 5 || (Offset + 5 >= m_size))
389 break;
390
391 // CEC physical address
392 m_physicalAddress = static_cast<uint16_t>((Data[Offset + 3] << 8) + Data[Offset + 4]);
393
394 if (Length < 6 || (Offset + 6 >= m_size))
395 break;
396
397 // Deep color
398 m_deepColor = Data[Offset + 5] & 0x78;
399
400 if (Length < 8 || (Offset + 8 >= m_size))
401 break;
402
403 // Audio and video latencies
404 m_latencies = ((Data[Offset + 7] & 0x80) != 0);
405 m_interLatencies = ((Data[Offset + 7] & 0x40) != 0) && m_latencies;
406
407 if (Length < 10 || (Offset + 10 >= m_size))
408 break;
409 if (m_latencies)
410 {
411 quint8 video = Data[Offset + 8];
412 if (video > 0 && video <= 251)
413 m_videoLatency[0] = (video - 1) << 1;
414 quint8 audio = Data[Offset + 9];
415 if (audio > 0 && audio <= 251)
416 m_audioLatency[0] = (audio - 1) << 1;
417 }
418
419 if (Length < 12 || (Offset + 12 >= m_size))
420 break;
421
423 {
424 quint8 video = Data[Offset + 10];
425 if (video > 0 && video <= 251)
426 m_videoLatency[1] = (video - 1) << 1;
427 quint8 audio = Data[Offset + 11];
428 if (audio > 0 && audio <= 251)
429 m_audioLatency[1] = (audio - 1) << 1;
430 }
431
432 break;
433 }
434
435 // "HDMI Forum"
436 while (registration == 0xC45DD8)
437 {
438 if (Length < 5 || (Offset + 5 >= m_size))
439 break;
440
441 // Deep Color 4:2:0
442 m_deepYUV = Data[Offset + 4] & 0x7;
443
444 if (Length < 11 || (Offset + 11 >= m_size))
445 break;
446
447 // Variable Refresh Rate
448 m_vrrMin = Data[Offset + 9] & 0x3f;
449 m_vrrMax = ((Data[Offset + 9] & 0xc0) << 2) | Data[Offset + 10];
450 break;
451 }
452
453 return true;
454}
455
456bool MythEDID::ParseExtended(const quint8* Data, size_t Offset, size_t Length)
457{
458 if (Offset + 1 >= m_size)
459 return false;
460
461 // HDR Static Metadata Data Block
462 if (Data[Offset] == 0x06 && Length)
463 {
464 if (Length >= 3 && (Offset + 3 < m_size))
465 {
466 int hdrsupport = Data[Offset + 1] & 0x3f;
467 if (hdrsupport & HDR10)
469 if (hdrsupport & HLG)
471 m_hdrMetaTypes = Data[Offset + 2] & 0xff;
472 }
473
474 if (Length >= 4)
475 m_maxLuminance = 50.0 * pow(2, Data[Offset + 3] / 32.0);
476
477 if (Length >= 5)
478 m_maxAvgLuminance = 50.0 * pow(2, Data[Offset + 4] / 32.0);
479
480 if (Length >= 6)
481 m_minLuminance = (50.0 * pow(2, Data[Offset + 3] / 32.0)) * pow(Data[Offset + 5] / 255.0, 2) / 100.0;
482 }
483 return true;
484}
485
486void MythEDID::Debug() const
487{
488 auto deep = [](uint8_t Deep)
489 {
490 QStringList res;
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(",");
496 };
497
498 auto deepyuv = [](uint8_t Deep)
499 {
500 QStringList res;
501 if (Deep & 0x01) res << "10bit";
502 if (Deep & 0x02) res << "12bit";
503 if (Deep & 0x04) res << "16bit";
504 return res.join(",");
505 };
506
507 if (!m_valid)
508 {
509 LOG(VB_GENERAL, LOG_INFO, LOC + "Invalid EDID");
510 return;
511 }
512
513 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Version:1.%1 Size:%2 Exensions:%3")
514 .arg(m_minorVersion).arg(m_size).arg((m_size / 128) - 1));
515 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Gamma:%1 sRGB:%2")
516 .arg(static_cast<double>(m_gamma)).arg(m_sRGB));
517 LOG(VB_GENERAL, LOG_INFO, LOC + "Display chromaticity:-");
518 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Red:\t%1,\t%2")
519 .arg(static_cast<double>(m_primaries.m_primaries[0][0]), 0, 'f', 4)
520 .arg(static_cast<double>(m_primaries.m_primaries[0][1]), 0, 'f', 4));
521 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Green:\t%1,\t%2")
522 .arg(static_cast<double>(m_primaries.m_primaries[1][0]), 0, 'f', 4)
523 .arg(static_cast<double>(m_primaries.m_primaries[1][1]), 0, 'f', 4));
524 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Blue:\t%1,\t%2")
525 .arg(static_cast<double>(m_primaries.m_primaries[2][0]), 0, 'f', 4)
526 .arg(static_cast<double>(m_primaries.m_primaries[2][1]), 0, 'f', 4));
527 LOG(VB_GENERAL, LOG_INFO, LOC + QString("White:\t%1,\t%2")
528 .arg(static_cast<double>(m_primaries.m_whitePoint[0]), 0, 'f', 4)
529 .arg(static_cast<double>(m_primaries.m_whitePoint[1]), 0, 'f', 4));
530 QString address = !m_physicalAddress ? QString("N/A") :
531 QString("%1.%2.%3.%4").arg((m_physicalAddress >> 12) & 0xF)
532 .arg((m_physicalAddress >> 8) & 0xF)
533 .arg((m_physicalAddress >> 4) & 0xF)
534 .arg(m_physicalAddress & 0xF);
535 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Physical address: %1").arg(address));
536 if (m_deepColor)
537 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Deep color: %1").arg(deep(m_deepColor)));
538 if (m_latencies)
539 {
540 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Latencies: Audio:%1 Video:%2")
541 .arg(m_audioLatency[0]).arg(m_videoLatency[0]));
543 {
544 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Latencies: Audio:%1 Video:%2 (Interlaced)")
545 .arg(m_audioLatency[1]).arg(m_videoLatency[1]));
546 }
547 }
548 if (m_deepYUV)
549 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Deep YUV 4:2:0 %1").arg(deepyuv(m_deepYUV)));
550 if (m_vrrMin || m_vrrMax)
551 LOG(VB_GENERAL, LOG_INFO, LOC + QString("VRR: %1<->%2").arg(m_vrrMin).arg(m_vrrMax));
552 if (m_hdrSupport)
553 LOG(VB_GENERAL, LOG_INFO, LOC + QString("HDR types: %1").arg(MythHDR::TypesToString(m_hdrSupport).join(",")));
554 if (m_maxLuminance > 0.0 || m_maxAvgLuminance > 0.0)
555 {
556 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Desired luminance: Min: %1 Max: %2 Avg: %3")
557 .arg(m_minLuminance, 3, 'f', 3).arg(m_maxLuminance, 3, 'f', 3).arg(m_maxAvgLuminance, 3, 'f', 3));
558 }
559}
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
Definition: mythedid.h:77
MythHDRDesc GetHDRSupport() const
Definition: mythedid.cpp:100
bool ParseVSDB(const quint8 *Data, size_t Offset, size_t Length)
Definition: mythedid.cpp:375
std::array< int, 2 > m_audioLatency
Definition: mythedid.h:81
uint8_t m_deepColor
Definition: mythedid.h:78
int AudioLatency(bool Interlaced) const
Definition: mythedid.cpp:90
double m_minLuminance
Definition: mythedid.h:90
void Parse()
Definition: mythedid.cpp:144
QSize m_displaySize
Definition: mythedid.h:66
QStringList m_serialNumbers
Definition: mythedid.h:68
void Debug() const
Definition: mythedid.cpp:486
bool m_sRGB
Definition: mythedid.h:73
int m_vrrMax
Definition: mythedid.h:85
bool m_latencies
Definition: mythedid.h:79
double m_maxLuminance
Definition: mythedid.h:88
MythEDID()=default
bool IsSRGB() const
Definition: mythedid.cpp:75
bool ParseExtended(const quint8 *Data, size_t Offset, size_t Length)
Definition: mythedid.cpp:456
MythHDR::HDRTypes m_hdrSupport
Definition: mythedid.h:87
QByteArray m_data
Definition: mythedid.h:63
bool ParseCTABlock(const quint8 *Data, size_t Offset)
Definition: mythedid.cpp:358
bool m_isHDMI
Definition: mythedid.h:76
int VideoLatency(bool Interlaced) const
Definition: mythedid.cpp:95
MythColourSpace m_primaries
Definition: mythedid.h:75
size_t m_size
Definition: mythedid.h:64
bool m_valid
Definition: mythedid.h:62
QSize DisplaySize() const
Definition: mythedid.cpp:50
uint16_t PhysicalAddress() const
Definition: mythedid.cpp:60
std::array< int, 2 > m_videoLatency
Definition: mythedid.h:82
@ HDR10
Definition: mythedid.h:49
QStringList SerialNumbers() const
Definition: mythedid.cpp:45
bool m_interLatencies
Definition: mythedid.h:80
double m_displayAspect
Definition: mythedid.h:67
uint8_t m_deepYUV
Definition: mythedid.h:83
void ParseDetailedTimingDescriptor(const quint8 *Data, size_t Offset)
Definition: mythedid.cpp:326
MythColourSpace ColourPrimaries() const
Definition: mythedid.cpp:85
bool m_likeSRGB
Definition: mythedid.h:74
int m_hdrMetaTypes
Definition: mythedid.h:86
QString m_name
Definition: mythedid.h:69
float Gamma() const
Definition: mythedid.cpp:65
quint8 m_minorVersion
Definition: mythedid.h:65
bool IsHDMI() const
Definition: mythedid.cpp:70
float m_gamma
Definition: mythedid.h:72
bool IsLikeSRGB() const
Definition: mythedid.cpp:80
int m_vrangeMin
Definition: mythedid.h:70
int m_vrrMin
Definition: mythedid.h:84
bool ParseBaseBlock(const quint8 *Data)
Definition: mythedid.cpp:198
double m_maxAvgLuminance
Definition: mythedid.h:89
bool Valid() const
Definition: mythedid.cpp:40
double DisplayAspect() const
Definition: mythedid.cpp:55
void ParseDisplayDescriptor(const quint8 *Data, uint Offset)
Definition: mythedid.cpp:295
int m_vrangeMax
Definition: mythedid.h:71
bool ParseCTA861(const quint8 *Data, size_t Offset)
Definition: mythedid.cpp:341
MythVRRRange GetVRRRange() const
Return the range of supported refresh rates.
Definition: mythedid.cpp:114
QStringList TypesToString() const
Definition: mythhdr.cpp:83
@ HDR10
Definition: mythhdr.h:39
@ HLG
Definition: mythhdr.h:40
unsigned int uint
Definition: compat.h:60
unsigned short uint16_t
Definition: iso6937tables.h:3
#define LOC
Definition: mythedid.cpp:26
static constexpr uint8_t DESCRIPTOR_RANGE_LIMITS
Definition: mythedid.cpp:14
static constexpr size_t HEIGHT_OFFSET
Definition: mythedid.cpp:21
static constexpr size_t WIDTH_OFFSET
Definition: mythedid.cpp:20
static constexpr size_t GAMMA_OFFSET
Definition: mythedid.cpp:22
static constexpr size_t VERSION_OFFSET
Definition: mythedid.cpp:18
static constexpr size_t EXTENSIONS_OFFSET
Definition: mythedid.cpp:24
static constexpr uint8_t DESCRIPTOR_PRODUCT_NAME
Definition: mythedid.cpp:13
static constexpr size_t SERIAL_OFFSET
Definition: mythedid.cpp:17
static QString ParseEdidString(const quint8 *data, bool Replace)
Definition: mythedid.cpp:124
static constexpr uint8_t DESCRIPTOR_SERIAL_NUMBER
Definition: mythedid.cpp:15
static constexpr size_t DATA_BLOCK_OFFSET
Definition: mythedid.cpp:16
static constexpr size_t FEATURES_OFFSET
Definition: mythedid.cpp:23
std::tuple< MythHDR::HDRTypes, double, double, double > MythHDRDesc
Definition: mythedid.h:18
std::tuple< int, int, bool > MythVRRRange
Definition: mythedid.h:19
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
string version
Definition: giantbomb.py:185