linux如何将两份hdmi edid合并
目录
合并目标
方法 1:使用 Python 合并 EDID
步骤
方法 2:使用 Shell 脚本 + edid-decode
Shell 脚本
说明
方法 3:使用 C 程序(高效方式)
C 代码 (merge_edid.c)
编译 & 运行
如何验证合并后的 EDID?
总结
代码执行逻辑分析
具体问题场景
合并策略:取 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:
pythonwith open("edid1.bin", "rb") as f1, open("edid2.bin", "rb") as f2:edid1 = bytearray(f1.read())edid2 = bytearray(f2.read())
-
提取 EDID1 的基本信息(0x00-0x35):
pythonmerged_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:
pythonwith 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 <stdio.h>
#include <stdint.h>
#include <stdbool.h>// 检查时序块是否有效(非全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. 保存合并后的 EDIDFILE *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 的时序被丢弃)。