linux如何将两份hdmi edid合并 - 指南
目录
方法 2:使用 Shell 脚本 + edid-decode
合并策略:取 EDID1 的基本信息 + (EDID1 + EDID2) 的详细时序
在 Linux 下合并两份 HDMI EDID,并采用 "EDID1 的基本信息 + (EDID1 + EDID2) 的详细时序" 的策略,可以按照以下步骤实现。EDID 的标准结构是 128 字节,其中:
0x00-0x35 (前54字节):基本显示信息(厂商、序列号、基础分辨率等)
0x36-0x7F (后74字节):详细时序描述符(通常包含 4 个 18 字节的时序块)
合并目标
保留 EDID1 的前 54 字节(基本信息)。
合并 EDID1 和 EDID2 的详细时序(0x36-0x7F),确保不重复且有效。
方法 1:使用 Python 合并 EDID
步骤
读取两份 EDID:
python with open("edid1.bin", "rb") as f1, open("edid2.bin", "rb") as f2: edid1 = bytearray(f1.read()) edid2 = bytearray(f2.read())提取 EDID1 的基本信息(0x00-0x35):
python merged_edid = edid1[:0x36] # 前54字节合并 EDID1 和 EDID2 的详细时序(0x36-0x7F):
EDID 的详细时序通常有 4 个 18 字节的块(0x36-0x47, 0x48-0x59, 0x5A-0x6B, 0x6C-0x7D)。
我们需要 去重,并确保不超过 4 个时序描述符。
python # 提取 EDID1 和 EDID2 的所有详细时序块(每个18字节) edid1_timings = [edid1[i:i+18] for i in range(0x36, 0x7F, 18)] edid2_timings = [edid2[i:i+18] for i in range(0x36, 0x7F, 18)] # 合并并去重(避免重复的时序) unique_timings = [] for timing in edid1_timings + edid2_timings: if timing not in unique_timings and not all(b == 0 for b in timing): unique_timings.append(timing) # 只保留前4个(EDID最多支持4个详细时序) final_timings = unique_timings[:4] # 填充剩余的时序块(如果不足4个,用0填充) while len(final_timings) < 4: final_timings.append(bytes(18)) # 填充空时序重新组装 EDID:
python # 合并时序块 for i, timing in enumerate(final_timings): merged_edid[0x36 + i*18 : 0x36 + (i+1)*18] = timing # 重新计算校验和(最后一个字节必须是校验和) checksum = (256 - (sum(merged_edid[:127]) % 256)) % 256 merged_edid[127] = checksum保存合并后的 EDID:
python with open("merged_edid.bin", "wb") as f_out: f_out.write(merged_edid) print("EDID merged successfully!")
方法 2:使用 Shell 脚本 + edid-decode
如果不想用 Python,可以用 dd + xxd 手动合并:
Shell 脚本
bash
#!/bin/bash
# 1. 提取 EDID1 的基本信息(前54字节)
dd if=edid1.bin of=merged.bin bs=1 count=54
# 2. 提取 EDID1 和 EDID2 的所有时序块(各4x18字节)
dd if=edid1.bin of=timing1.bin bs=1 skip=54 count=72
dd if=edid2.bin of=timing2.bin bs=1 skip=54 count=72
# 3. 合并时序块(去重)
cat timing1.bin timing2.bin | awk '!seen[$0]++' > unique_timings.bin
# 4. 只取前4个时序(72字节)
dd if=unique_timings.bin of=final_timings.bin bs=18 count=4
# 5. 合并到最终 EDID
cat merged.bin final_timings.bin > merged_temp.bin
# 6. 填充剩余字节(确保128字节)
truncate -s 128 merged_temp.bin
# 7. 重新计算校验和
checksum=$(hexdump -v -e '/1 "%u\n"' merged_temp.bin | head -n 127 | awk '{sum += $1} END {print (256 - (sum % 256)) % 256}')
printf "\\x$(printf "%02x" $checksum)" | dd of=merged_temp.bin bs=1 seek=127 conv=notrunc
# 8. 重命名
mv merged_temp.bin merged_edid.bin
echo "EDID merged into merged_edid.bin"
说明
awk '!seen[$0]++'用于去重时序块。truncate -s 128确保文件是 128 字节。最后重新计算校验和(第 128 字节)。
方法 3:使用 C 程序(高效方式)
如果需要高性能合并(如嵌入式设备),可以用 C 语言:
C 代码 (merge_edid.c)
c
#include
#include
#include
// 检查时序块是否有效(非全0)
bool is_valid_timing(const uint8_t *timing) {
for (int i = 0; i < 18; i++) {
if (timing[i] != 0) return true;
}
return false;
}
// 检查是否已存在相同时序
bool is_duplicate(const uint8_t *merged, const uint8_t *timing, int count) {
for (int i = 0; i < count; i++) {
bool match = true;
for (int j = 0; j < 18; j++) {
if (merged[0x36 + i * 18 + j] != timing[j]) {
match = false;
break;
}
}
if (match) return true;
}
return false;
}
int main() {
uint8_t edid1[128], edid2[128], merged[128];
FILE *f1 = fopen("edid1.bin", "rb");
FILE *f2 = fopen("edid2.bin", "rb");
fread(edid1, 1, 128, f1);
fread(edid2, 1, 128, f2);
fclose(f1);
fclose(f2);
// 1. 复制 EDID1 的基本信息
for (int i = 0; i < 0x36; i++) merged[i] = edid1[i];
// 2. 合并 EDID1 和 EDID2 的时序(去重)
int timing_count = 0;
for (int src = 0; src < 2; src++) {
const uint8_t *edid = (src == 0) ? edid1 : edid2;
for (int i = 0; i < 4 && timing_count < 4; i++) {
const uint8_t *timing = &edid[0x36 + i * 18];
if (is_valid_timing(timing) && !is_duplicate(merged, timing, timing_count)) {
for (int j = 0; j < 18; j++) {
merged[0x36 + timing_count * 18 + j] = timing[j];
}
timing_count++;
}
}
}
// 3. 填充剩余的时序(如果不足4个)
while (timing_count < 4) {
for (int j = 0; j < 18; j++) {
merged[0x36 + timing_count * 18 + j] = 0;
}
timing_count++;
}
// 4. 计算校验和
uint8_t sum = 0;
for (int i = 0; i < 127; i++) sum += merged[i];
merged[127] = (256 - sum) % 256;
// 5. 保存合并后的 EDID
FILE *fout = fopen("merged_edid.bin", "wb");
fwrite(merged, 1, 128, fout);
fclose(fout);
printf("EDID merged successfully!\n");
return 0;
}
编译 & 运行
bash
gcc merge_edid.c -o merge_edid
./merge_edid
如何验证合并后的 EDID?
使用
edid-decode:bash
edid-decode merged_edid.bin在 Linux 中测试加载:
bash
sudo cp merged_edid.bin /sys/kernel/debug/dri/0/HDMI-A-1/edid_override
总结
| 方法 | 适用场景 | 优点 |
|---|---|---|
| Python | 灵活修改 | 适合复杂逻辑 |
| Shell | 快速合并 | 依赖命令行工具 |
| C 程序 | 高性能 | 适合嵌入式 |
选择最适合你的方式即可!
在这段代码中,EDID2 的时序确实会覆盖 EDID1 的时序,因为:
代码执行逻辑分析
外层循环
for (int src = 0; src < 2; src++):先处理
src=0(EDID1),再处理src=1(EDID2)。如果 EDID1 和 EDID2 的时序有冲突(比如相同分辨率),后处理的 EDID2 会覆盖 EDID1 的时序。
内层循环
for (int i = 0; i < 4 && timing_count < 4; i++):遍历每个 EDID 的 4 个时序块(0x36-0x7F)。
如果 EDID1 和 EDID2 的时序块有重复,
is_duplicate()会阻止重复写入,但 不重复的 EDID2 时序会继续填充。
具体问题场景
假设:
EDID1 的时序块:
[A, B, C, D]EDID2 的时序块:
[B, E, F, G]
合并后的结果:
先处理 EDID1:
写入
A, B, C, D(timing_count=4)。
处理 EDID2:
B会被is_duplicate()跳过。但剩余空间已满(
timing_count=4),所以E, F, G不会写入。
最终合并结果:[A, B, C, D](EDID2 的时序被丢弃)。
浙公网安备 33010602011771号