Skip to content

Commit 348f44d

Browse files
GongHeng2017deepin-bot[bot]
authored andcommitted
Fix: the screen size error.
-- Get all screen size and judge it by base screen size. Log: fix issue Bug: https://pms.uniontech.com/bug-view-354275.html
1 parent a45de1e commit 348f44d

2 files changed

Lines changed: 147 additions & 25 deletions

File tree

deepin-devicemanager/src/Tool/EDIDParser.cpp

Lines changed: 119 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -204,31 +204,30 @@ void EDIDParser::parseScreenSize()
204204
{
205205
qCDebug(appLog) << "Parsing screen size from EDID";
206206

207-
//Detailed Timing: 字节66-68 (第4行字节2-4)包含详细屏幕尺寸信息
208-
// 字节66: Active Image Width低8位
209-
// 字节67: Active Image Height低8位
210-
// 字节68: 高4位(0xF0)=宽度高4位, 低4位(0x0F)=高度高4位
211-
// 注意:大端模式下,字节位置会交换:byte 2<->3, byte 4->5
212-
QString s66 = getBytes(4, m_LittleEndianMode ? 2 : 3), // 宽度低8位
213-
s67 = getBytes(4, m_LittleEndianMode ? 3 : 2), // 高度低8位
214-
s68 = getBytes(4, m_LittleEndianMode ? 4 : 5); // [宽度高4位|高度高4位]
215-
216-
if (!s66.isEmpty() && !s67.isEmpty() && !s68.isEmpty()) {
217-
int byte68_val = hexToDec(s68).toInt();
218-
// 宽度 = (byte68高4位 << 8) + s66
219-
m_Width = ((byte68_val & 0xF0) << 4) + hexToDec(s66).toInt();
220-
// 高度 = (byte68低4位 << 8) + s67
221-
m_Height = ((byte68_val & 0x0F) << 8) + hexToDec(s67).toInt();
222-
}
223-
224-
// edid中的 15H和16H就是屏幕大小 , 与Detailed Timing相差超10mm 则用15H和16H的。
225-
int width15 = hexToDec(getBytes(1, m_LittleEndianMode ? 5 : 4)).toInt()*10;
226-
int height16 = hexToDec(getBytes(1, m_LittleEndianMode ? 6 : 7)).toInt()*10;
227-
qCDebug(appLog) << "Parsed width and height from bytes 15H/16H:" << width15 << "x" << height16;
228-
if(m_Width+10 < width15 || m_Height+10 < height16) {
229-
qCDebug(appLog) << "Detailed timing differs significantly, using 15H/16H values.";
207+
parseDTDs();
208+
// edid中的 15H和16H是基本屏幕大小(单位cm), 与 Detailed Timing 相差超10mm 则用15H和16H的。
209+
int width15 = hexToDec(getBytes(1, m_LittleEndianMode ? 5 : 4)).toInt() * 10;
210+
int height16 = hexToDec(getBytes(1, m_LittleEndianMode ? 6 : 7)).toInt() * 10;
211+
if (width15 != 0 && height16 != 0) {
230212
m_Width = width15;
231213
m_Height = height16;
214+
// 从所有的详细尺寸中寻找接近基本屏幕大小的值
215+
for (int i = 0; i < m_DTDSizeInfoList.size(); ++i) {
216+
if (abs(m_DTDSizeInfoList.at(i).width - width15) < 10
217+
&& abs(m_DTDSizeInfoList.at(i).height - height16) < 10) {
218+
m_Width = m_DTDSizeInfoList.at(i).width;
219+
m_Height = m_DTDSizeInfoList.at(i).height;
220+
break;
221+
}
222+
}
223+
} else {
224+
if (!m_DTDSizeInfoList.isEmpty()) {
225+
m_Width = m_DTDSizeInfoList.at(0).width;
226+
m_Height = m_DTDSizeInfoList.at(0).height;
227+
} else {
228+
m_Width = 0;
229+
m_Height = 0;
230+
}
232231
}
233232

234233
if (Common::specialComType == Common::kSpecialType7){ // sepcial task:378963
@@ -237,8 +236,8 @@ void EDIDParser::parseScreenSize()
237236
}
238237
double inch = sqrt((m_Width / 2.54) * (m_Width / 2.54) + (m_Height / 2.54) * (m_Height / 2.54))/10;
239238
m_ScreenSize = QString("%1 %2(%3mm×%4mm)")
240-
.arg(QString::number(inch, '0', Common::specialComType == Common::kSpecialType7 ? 0 : 1))
241-
.arg(QObject::tr("inch")).arg(m_Width).arg(m_Height);
239+
.arg(QString::number(inch, '0', Common::specialComType == Common::kSpecialType7 ? 0 : 1))
240+
.arg(QObject::tr("inch")).arg(m_Width).arg(m_Height);
242241
qCDebug(appLog) << "Screen size parsed:" << m_ScreenSize << "Width:" << m_Width << "Height:" << m_Height;
243242
}
244243

@@ -302,6 +301,101 @@ void EDIDParser::parseMonitorName()
302301
m_MonitorName = "Unknown Monitor";
303302
}
304303

304+
void EDIDParser::parseDTDs()
305+
{
306+
// 清空之前的 DTD 信息列表
307+
m_DTDSizeInfoList.clear();
308+
309+
// 基础块中最多有 4 个 DTD,起始字节为 54, 72, 90, 108
310+
for (int i = 0; i < 4; i++) {
311+
int startByte = 54 + i * 18;
312+
parseOneDTD(startByte, i, true);
313+
}
314+
}
315+
316+
void EDIDParser::parseOneDTD(int startByte, int dtdIndex, bool isBaseBlock)
317+
{
318+
// 字节布局(在 DTD 内的相对位置):
319+
// 字节0-1: 像素时钟(2字节,用于验证是否为有效 DTD)
320+
// 字节2-3: H Active(水平主动像素数)低字节 | H Blank
321+
// 字节4-5: V Active(垂直主动像素数)低字节 | V Blank
322+
// 字节12: Image Size Width(物理宽度)低8位
323+
// 字节13: Image Size Height(物理高度)低8位
324+
// 字节14: 高4位=宽度高4位,低4位=高度高4位
325+
326+
// 注意:在 EDID 的 16 进制字符串格式中
327+
// 每行 16 字节 = 32 个字符
328+
// 每字节 = 2 个字符
329+
330+
// 注意:大端模式下,字节位置会交换:
331+
// - 相邻字节对会交换(如 byte12 <-> byte13)
332+
// - byte14 会变成 byte15
333+
334+
// 计算 DTD 内的字节位置对应的 EDID 位置
335+
int line = startByte / 16;
336+
int byteInLine = startByte % 16;
337+
338+
// 获取像素时钟(字节0-1),用于验证 DTD 是否有效
339+
// 大端模式下字节0和字节1交换
340+
QString pixelClockByte0 = getBytes(line, m_LittleEndianMode ? byteInLine : byteInLine + 1);
341+
QString pixelClockByte1 = getBytes(line, m_LittleEndianMode ? byteInLine + 1 : byteInLine);
342+
343+
if (pixelClockByte0.isEmpty() || pixelClockByte1.isEmpty()) {
344+
return;
345+
}
346+
347+
int pixelClockLow = hexToDec(pixelClockByte0).toInt();
348+
int pixelClockHigh = hexToDec(pixelClockByte1).toInt();
349+
int pixelClock = pixelClockLow + (pixelClockHigh << 8);
350+
351+
// 如果像素时钟为 0,说明这不是一个有效的 DTD
352+
if (pixelClock == 0) {
353+
return;
354+
}
355+
356+
// 获取物理尺寸信息
357+
// 字节12: 宽度低8位
358+
// 字节13: 高度低8位
359+
// 字节14: 高4位=宽度高位,低4位=高度高位
360+
// 大端模式下:byte12 <-> byte13 交换,byte14 -> byte15
361+
362+
int byte12Pos = m_LittleEndianMode ? (startByte + 12) : (startByte + 13);
363+
int byte13Pos = m_LittleEndianMode ? (startByte + 13) : (startByte + 12);
364+
int byte14Pos = m_LittleEndianMode ? (startByte + 14) : (startByte + 15);
365+
366+
int lineWidthByte12 = byte12Pos / 16;
367+
int byteInLineWidthByte12 = byte12Pos % 16;
368+
369+
int lineWidthByte13 = byte13Pos / 16;
370+
int byteInLineWidthByte13 = byte13Pos % 16;
371+
372+
int lineWidthByte14 = byte14Pos / 16;
373+
int byteInLineWidthByte14 = byte14Pos % 16;
374+
375+
QString s12 = getBytes(lineWidthByte12, byteInLineWidthByte12); // 宽度低8位
376+
QString s13 = getBytes(lineWidthByte13, byteInLineWidthByte13); // 高度低8位
377+
QString s14 = getBytes(lineWidthByte14, byteInLineWidthByte14); // [宽度高4位|高度高4位]
378+
379+
if (s12.isEmpty() || s13.isEmpty() || s14.isEmpty()) {
380+
return;
381+
}
382+
383+
int byte14_val = hexToDec(s14).toInt();
384+
// 宽度(mm) = (byte14高4位 << 8) + s12
385+
int width = ((byte14_val & 0xF0) << 4) + hexToDec(s12).toInt();
386+
// 高度(mm) = (byte14低4位 << 8) + s13
387+
int height = ((byte14_val & 0x0F) << 8) + hexToDec(s13).toInt();
388+
389+
// 保存 DTD 尺寸信息
390+
DTDSizeInfo info;
391+
info.dtdIndex = dtdIndex;
392+
info.width = width;
393+
info.height = height;
394+
info.isBaseBlock = isBaseBlock;
395+
396+
m_DTDSizeInfoList.append(info);
397+
}
398+
305399
QString EDIDParser::binToDec(QString strBin) //二进制转十进制
306400
{
307401
// qCDebug(appLog) << "Converting binary to decimal";

deepin-devicemanager/src/Tool/EDIDParser.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,20 @@
88
#include<QString>
99
#include<QStringList>
1010
#include<QMap>
11+
#include <QVector>
12+
13+
/**
14+
* @brief DTDSizeInfo - 存储单个DTD的尺寸信息
15+
*/
16+
struct DTDSizeInfo
17+
{
18+
int dtdIndex; // DTD索引(从0开始)
19+
int width; // 物理宽度(毫米)
20+
int height; // 物理高度(毫米)
21+
bool isBaseBlock; // 是否来自基础块
22+
23+
DTDSizeInfo() : dtdIndex(0), width(0), height(0), isBaseBlock(true) {}
24+
};
1125

1226
/**
1327
* @brief The EDIDParser class
@@ -92,6 +106,19 @@ class EDIDParser
92106
*/
93107
void parseMonitorName();
94108

109+
/**
110+
* @brief parseDTDs:解析所有 DTD 的屏幕尺寸
111+
*/
112+
void parseDTDs();
113+
114+
/**
115+
* @brief parseOneDTD:解析单个 DTD
116+
* @param startByte: DTD 起始字节位置
117+
* @param dtdIndex: DTD 索引
118+
* @param isBaseBlock: 是否来自基础块
119+
*/
120+
void parseOneDTD(int startByte, int dtdIndex, bool isBaseBlock);
121+
95122
/**
96123
* @brief binToDec:将二进制转换成十进制
97124
* @param strBin:二进制字符串
@@ -157,6 +184,7 @@ class EDIDParser
157184
int m_Height; // height
158185
QStringList m_ListEdid; // edid数据
159186
QMap<QString, QString> m_MapCh; // 二进制字符串映射到字母A-Z
187+
QVector<DTDSizeInfo> m_DTDSizeInfoList; // 所有 DTD 的尺寸信息列表
160188

161189

162190
};

0 commit comments

Comments
 (0)