当前位置: 首页 > news >正文

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 字节的时序块)

合并目标

  1. 保留 EDID1 的前 54 字节(基本信息)

  2. 合并 EDID1 和 EDID2 的详细时序(0x36-0x7F),确保不重复且有效。


方法 1:使用 Python 合并 EDID

步骤

  1. 读取两份 EDID

    pythonwith open("edid1.bin", "rb") as f1, open("edid2.bin", "rb") as f2:edid1 = bytearray(f1.read())edid2 = bytearray(f2.read())
  2. 提取 EDID1 的基本信息(0x00-0x35)

    pythonmerged_edid = edid1[:0x36]  # 前54字节
  3. 合并 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))  # 填充空时序
  4. 重新组装 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
  5. 保存合并后的 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?

  1. 使用 edid-decode

    bash

    edid-decode merged_edid.bin
  2. 在 Linux 中测试加载

    bash

    sudo cp merged_edid.bin /sys/kernel/debug/dri/0/HDMI-A-1/edid_override

总结

方法适用场景优点
Python灵活修改适合复杂逻辑
Shell快速合并依赖命令行工具
C 程序高性能适合嵌入式

选择最适合你的方式即可!

在这段代码中,EDID2 的时序确实会覆盖 EDID1 的时序,因为:

代码执行逻辑分析

  1. 外层循环 for (int src = 0; src < 2; src++)

    • 先处理 src=0(EDID1),再处理 src=1(EDID2)。

    • 如果 EDID1 和 EDID2 的时序有冲突(比如相同分辨率),后处理的 EDID2 会覆盖 EDID1 的时序

  2. 内层循环 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]

合并后的结果:

  1. 先处理 EDID1:

    • 写入 A, B, C, Dtiming_count=4)。

  2. 处理 EDID2:

    • B 会被 is_duplicate() 跳过。

    • 但剩余空间已满(timing_count=4),所以 E, F, G 不会写入

最终合并结果:[A, B, C, D](EDID2 的时序被丢弃)。

http://www.dtcms.com/a/308825.html

相关文章:

  • 硬件电路基础学习
  • Cesium 快速入门(五)坐标系
  • LangGraph底层原理与基础应用入门
  • vue3可编辑表格
  • linux自动构建工具make/makefile
  • 【计算机网络】5传输层
  • MySQL 中的 JOIN 操作有哪些类型?它们之间有什么区别?
  • 国标gb28181 SIP协商详细分析
  • 《嵌入式C语言笔记(十七):进制转换、结构体与位运算精要》
  • .map文件中的0x40f (size before relaxing)是什么意思?
  • 这个项目有多急?
  • MySQL常用函数总结
  • 经典算法之美:冒泡排序的优雅实现
  • 多场景-阶梯式碳交易机制下考虑需求响应的综合能源系统优化(MATLAB模型)
  • 智能Agent场景实战指南 Day 27:Agent部署与可扩展性
  • 本地部署VMware ESXi,并实现无公网IP远程访问管理服务器
  • C++手撕简单KNN
  • 如何使用自定义@DS注解切换数据源
  • 中小企业数据保护指南:如何用群晖NAS构建高效备份体系?
  • pytorch程序语句固定开销分析
  • hive新增列之后插入新数据时,新列为NULL的解决办法
  • 火焰图(Flame Graph)深度指南:CPU性能分析与瓶颈定位
  • 2025.8-12月 AI相关国内会议
  • C基础 12_day
  • XL2422 无线收发芯片,可用于遥控玩具和智能家居等应用领域
  • 网络层概述
  • LLM残差流为何会超过1?
  • Lombok 字段魔法:用 @FieldDefaults 解锁“隐身+锁死”双重特效
  • Linux731 shell工具;[]字符
  • kettle插件-kettle http client plus插件,轻松解决https接口无法调用文件流下载问题