1# HDMI 2 3 4## 概述 5 6### 功能简介 7 8HDMI(High Definition Multimedia Interface),即高清多媒体接口,主要用于DVD、机顶盒等音视频Source到TV、显示器等Sink设备的传输。 9HDMI以主从方式工作,通常有一个Source端和一个Sink端。 10HDMI接口定义了完成HDMI传输的通用方法集合,包括: 11 12- HDMI控制器管理:打开或关闭HDMI控制器 13- HDMI启动/停止传输:启动或停止HDMI传输 14- HDMI控制器设置:设置音频、视频及HDR属性,设置色彩深度、声音图像消隐等 15- HDMI读取EDID:读取Sink端原始的EDID数据 16- HDMI热插拔:注册/注销热插拔回调函数 17 18### 基本概念 19 20HDMI是Hitachi、Panasonic、Philips、Silicon Image、Sony、Thomson、Toshiba共同发布的一款音视频传输协议。传输过程遵循TMDS(Transition Minimized Differential Signaling)协议。 21 22- TMDS(Transition Minimized Differential signal):过渡调制差分信号,也被称为最小化传输差分信号,用于发送音频、视频及各种辅助数据。 23- DDC(Display Data Channel):显示数据通道,发送端与接收端可利用DDC通道得知彼此的发送与接收能力,但HDMI仅需单向获知接收端(显示器)的能力。 24- CEC(Consumer Electronics Control):消费电子控制,该功能应该能够在连接HDMI的发送设备与接收设备之间实现交互操作。 25- FRL(Fixed Rate Link):TMDS 的架构进行讯号传输时,最高带宽可达 18Gbps,而FRL模式的带宽则提升到48 Gbps。 26- HDCP(High-bandwidth Digital Content Protection):即高带宽数字内容保护技术,当用户对高清晰信号进行非法复制时,该技术会进行干扰,降低复制出来的影像的质量,从而对内容进行保护。 27- EDID(Extended Display Identification Data):扩展显示标识数据,通常存储在显示器的固件中,标识供应商信息、EDID版本信息、最大图像大小、颜色设置、厂商预设置、频率范围的限制以及显示器名和序列号的字符串。 28 29### 运作机制 30 31HDMI的Source端提供+5V和GND,用于DDC和CEC通信。通过DDC通道,Source端可以读取Sink端的各项参数,如接受能力等;CEC为可选通道,用于同步Source端与Sink端的控制信号,改善用户体验。TMDS通道有四组差分信号,TMDS Clock Channel为TMDS提供时钟信号,其余三组传输音视频数据及各种辅助数据;HDP为热插拔检测端口,当有Sink端接入时,Source端会通过中断服务程序进行响应。 32 33HDMI物理连接如图1所示: 34 35**图 1** HDMI物理连线示意图 36 37![](figures/HDMI物理连线示意图.png "HDMI物理连线示意图") 38 39### 约束与限制 40 41HDMI模块当前仅支持轻量和小型系统内核(LiteOS)。 42 43## 使用指导 44 45### 场景介绍 46 47HDMI具有体积小,传输速率高,传输带宽宽,兼容性好,能同时传输无压缩音视频信号等优点。与传统的全模拟接口相比,HDMI不但增加了设备间接线的便捷性,还提供了一些HDMI特有的智能化功能,可用于小体积设备进行高质量音视频传输的场景。 48 49### 接口说明 50 51**表 1** HDMI驱动API接口功能介绍 52 53 54| 接口名 | 描述 | 55| ----------------------------- | -------------------------- | 56| HdmiOpen | 打开HDMI控制器 | 57| HdmiClose | 关闭HDMI控制器 | 58| HdmiStart | 启动HDMI传输 | 59| HdmiStop | 停止HDMI传输 | 60| HdmiAvmuteSet | 声音图像消隐设置 | 61| HdmiDeepColorSet | 设置色彩深度 | 62| HdmiDeepColorGet | 获取色彩深度 | 63| HdmiSetVideoAttribute | 设置视频属性 | 64| HdmiSetAudioAttribute | 设置音频属性 | 65| HdmiSetHdrAttribute | 设置HDR属性 | 66| HdmiReadSinkEdid | 读取Sink端原始EDID数据 | 67| HdmiRegisterHpdCallbackFunc | 注册HDMI热插拔检测回调函数 | 68| HdmiUnregisterHpdCallbackFunc | 注销HDMI热插拔检测回调函数 | 69 70### 开发步骤 71 72使用HDMI设备的一般流程如图2所示。 73 74**图 2** HDMI设备使用流程图 75 76![](figures/HDMI使用流程图.png "HDMI使用流程图") 77 78#### 打开HDMI控制器 79 80在进行HDMI通信前,首先要调用HdmiOpen打开HDMI控制器。 81 82```c 83DevHandle HdmiOpen(int16_t number); 84``` 85 86**表 2** HdmiOpen参数和返回值描述 87 88| 参数 | 参数描述 | 89| ---------- | -------------------- | 90| number | HDMI控制器号 | 91| **返回值** | **返回值描述** | 92| NULL | 打开HDMI控制器失败 | 93| 控制器句柄 | 打开的HDMI控制器句柄 | 94 95假设系统中存在2个HDMI控制器,编号从0到1,以下代码示例为获取0号控制器: 96 97```c 98DevHandle hdmiHandle = NULL; /* HDMI控制器句柄 / 99 100/* 打开HDMI控制器 */ 101hdmiHandle = HdmiOpen(0); 102if (hdmiHandle == NULL) { 103 HDF_LOGE("HdmiOpen: failed\n"); 104 return; 105} 106``` 107 108#### 注册热插拔检测回调函数 109 110```c 111int32_t HdmiRegisterHpdCallbackFunc(DevHandle handle, struct HdmiHpdCallbackInfo *callback); 112``` 113 114**表 3** HdmiRegisterHpdCallbackFunc参数和返回值描述 115 116| 参数 | 参数描述 | 117| ---------- | ------------------ | 118| handle | HDMI控制器句柄 | 119| callback | 热插拔回调函数信息 | 120| **返回值** | **返回值描述** | 121| 0 | 注册成功 | 122| 负数 | 注册失败 | 123 124注册热插拔检测回调函数示例: 125 126```c 127/* 热插拔检测回调函数定义 */ 128static void HdmiHpdHandle(void *data, bool hpd) 129{ 130 if (data == NULL) { 131 HDF_LOGE("priv data is NULL"); 132 return; 133 } 134 if (hpd == true) { 135 HDF_LOGD("HdmiHpdHandle: hot plug"); 136 /* 调用者添加相关处理 */ 137 } else { 138 HDF_LOGD("HdmiHpdHandle: hot unplug"); 139 /* 调用者添加相关处理 */ 140 } 141} 142 143/* 热插拔检测回调函数注册示例 */ 144··· 145struct HdmiHpdCallbackInfo info = {0}; 146info.data = handle; 147info.callbackFunc = HdmiHpdHandle; 148ret = HdmiRegisterHpdCallbackFunc(hdmiHandle, info); 149if (ret != 0) { 150 HDF_LOGE("HdmiRegisterHpdCallbackFunc: Register failed."); 151} 152··· 153``` 154 155#### 读取EDID 156 157```c 158int32_t HdmiReadSinkEdid(DevHandle handle, uint8_t *buffer, uint32_t len); 159``` 160 161**表 4** HdmiReadSinkEdid参数和返回值描述 162 163| 参数 | 参数描述 | 164| ---------- | ---------------------- | 165| handle | HDMI控制器句柄 | 166| buffer | 数据缓冲区 | 167| len | 数据长度 | 168| **返回值** | **返回值描述** | 169| 正整数 | 成功读取的原始EDID数据 | 170| 负数或0 | 读取失败 | 171 172读取Sink端的原始EDID数据示例: 173 174```c 175int32_t len; 176uint8_t edid[HDMI_EDID_MAX_LEN] = {0}; 177 178len = HdmiReadSinkEdid(hdmiHandle, edid, HDMI_EDID_MAX_LEN); 179if (len <= 0) { 180 HDF_LOGE("%s: HdmiReadSinkEdid failed len = %d.", __func__, len); 181} 182``` 183 184#### 设置音频属性 185 186```c 187int32_t HdmiSetAudioAttribute(DevHandle handle, struct HdmiAudioAttr *attr); 188``` 189 190**表 5** HdmiSetAudioAttribute参数和返回值描述 191 192 193| 参数 | 参数描述 | 194| ------ | -------------- | 195| handle | HDMI控制器句柄 | 196| attr | 音频属性 | 197| 返回值 | 返回值描述 | 198| 0 | 设置成功 | 199| 负数 | 设置失败 | 200 201设置音频属性示例: 202 203```c 204struct HdmiAudioAttr audioAttr = {0}; 205int32_t ret; 206 207audioAttr.codingType = HDMI_AUDIO_CODING_TYPE_MP3; 208audioAttr.ifType = HDMI_AUDIO_IF_TYPE_I2S; 209audioAttr.bitDepth = HDMI_ADIO_BIT_DEPTH_16; 210audioAttr.sampleRate = HDMI_SAMPLE_RATE_8K; 211audioAttr.channels = HDMI_AUDIO_FORMAT_CHANNEL_3; 212ret = HdmiSetAudioAttribute(handle, &audioAttr); 213if (ret != 0) { 214 HDF_LOGE("HdmiSetAudioAttribute failed."); 215} 216``` 217 218#### 设置视频属性 219 220```c 221int32_t HdmiSetVideoAttribute(DevHandle handle, struct HdmiVideoAttr *attr); 222``` 223 224**表 6** HdmiSetVideoAttribute参数和返回值描述 225 226 227| 参数 | 参数描述 | 228| ---------- | -------------- | 229| handle | HDMI控制器句柄 | 230| attr | 视频属性 | 231| **返回值** | **返回值描述** | 232| 0 | 设置成功 | 233| 负数 | 设置失败 | 234 235设置视频属性示例: 236 237```c 238struct HdmiVideoAttr videoAttr = {0}; 239int32_t ret; 240 241videoAttr.colorSpace = HDMI_COLOR_SPACE_YCBCR444; 242videoAttr.colorimetry = HDMI_COLORIMETRY_EXTENDED; 243videoAttr.extColorimetry = HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM; 244videoAttr.quantization = HDMI_QUANTIZATION_RANGE_FULL; 245ret = HdmiSetVideoAttribute(handle, &videoAttr); 246if (ret != 0) { 247 HDF_LOGE("HdmiSetVideoAttribute failed."); 248} 249``` 250 251#### 设置HDR属性 252 253```c 254int32_t HdmiSetHdrAttribute(DevHandle handle, struct HdmiHdrAttr *attr); 255``` 256 257**表 7** HdmiSetHdrAttribute参数和返回值描述 258 259 260| 参数 | 参数描述 | 261| ---------- | -------------- | 262| handle | HDMI控制器句柄 | 263| attr | HDR属性 | 264| **返回值** | **返回值描述** | 265| 0 | 设置成功 | 266| 负数 | 设置失败 | 267 268设置HDR属性示例: 269 270```c 271struct HdmiHdrAttr hdrAttr = {0}; 272int32_t ret; 273 274hdrAttr.mode = HDMI_HDR_MODE_CEA_861_3; 275hdrAttr.userMode = HDMI_HDR_USERMODE_DOLBY; 276hdrAttr.eotfType = HDMI_EOTF_SMPTE_ST_2048; 277hdrAttr.metadataType = HDMI_DRM_STATIC_METADATA_TYPE_1; 278hdrAttr.colorimetry = HDMI_HDR_EXTENDED_COLORIMETRY_XV_YCC_709; 279ret = HdmiSetHdrAttribute(handle, &hdrAttr); 280if (ret != 0) { 281 HDF_LOGE("HdmiSetHdrAttribute failed."); 282} 283``` 284 285#### 设置HDMI声音图像消隐 286 287```c 288int32_t HdmiAvmuteSet(DevHandle handle, bool enable); 289``` 290 291**表 8** HdmiAvmuteSet参数和返回值描述 292 293 294| 参数 | 参数描述 | 295| ---------- | ----------------- | 296| handle | HDMI控制器句柄 | 297| enable | 使能/去使能avmute | 298| **返回值** | **返回值描述** | 299| 0 | 设置成功 | 300| 负数 | 设置失败 | 301 302设置声音图像消隐示例: 303 304```c 305int32_t ret; 306 307ret = HdmiAvmuteSet(hdmiHandle, true); 308if (ret != 0) { 309 HDF_LOGE("HdmiAvmuteSet failed."); 310} 311``` 312 313#### 设置色彩深度 314 315```c 316int32_t HdmiDeepColorSet(DevHandle handle, enum HdmiDeepColor color); 317``` 318 319**表 9** HdmiDeepColorSet参数和返回值描述 320 321 322| 参数 | 参数描述 | 323| ---------- | -------------- | 324| handle | HDMI控制器句柄 | 325| color | 色彩深度 | 326| **返回值** | **返回值描述** | 327| 0 | 设置成功 | 328| 负数 | 设置失败 | 329 330设置色彩深度示例: 331 332```c 333int32_t ret; 334 335ret = HdmiDeepColorSet(handle, HDMI_DEEP_COLOR_48BITS); 336if (ret != 0) { 337 HDF_LOGE("HdmiDeepColorSet failed."); 338} 339``` 340 341#### 获取色彩深度 342 343```c 344int32_t HdmiDeepColorGet(DevHandle handle, enum HdmiDeepColor *color); 345``` 346 347**表 10** HdmiDeepColorGet参数和返回值描述 348 349 350| 参数 | 参数描述 | 351| ---------- | -------------- | 352| handle | HDMI控制器句柄 | 353| color | 色彩深度 | 354| **返回值** | **返回值描述** | 355| 0 | 获取成功 | 356| 负数 | 获取失败 | 357 358获取色彩深度示例: 359 360```c 361enum HdmiDeepColor color; 362int32_t ret; 363 364ret = HdmiDeepColorGet(handle, &color); 365if (ret != 0) { 366 HDF_LOGE("HdmiDeepColorGet failed."); 367} 368``` 369 370#### 启动HDMI传输 371 372```c 373int32_t HdmiStart(DevHandle handle); 374``` 375 376**表 11** HdmiStart参数和返回值描述 377 378 379| 参数 | 参数描述 | 380| ---------- | -------------- | 381| handle | HDMI控制器句柄 | 382| **返回值** | **返回值描述** | 383| 0 | 启动成功 | 384| 负数 | 启动失败 | 385 386启动HDMI传输示例: 387 388```c 389int32_t ret; 390 391ret = HdmiStart(hdmiHandle); 392if (ret != 0) { 393 HDF_LOGE("start transmission failed."); 394} 395``` 396 397#### 停止HDMI传输<a name="section11"></a> 398 399```c 400int32_t HdmiStop(DevHandle handle); 401``` 402 403**表 12** HdmiStop参数和返回值描述 404 405 406| 参数 | 参数描述 | 407| ---------- | -------------- | 408| handle | HDMI控制器句柄 | 409| **返回值** | **返回值描述** | 410| 0 | 停止成功 | 411| 负数 | 停止失败 | 412 413停止HDMI传输示例: 414 415```c 416int32_t ret; 417 418ret = HdmiStop(hdmiHandle); 419if (ret != 0) { 420 HDF_LOGE("stop transmission failed."); 421} 422``` 423 424#### 注销热插拔检测回调函数 425 426```c 427int32_t HdmiUnregisterHpdCallbackFunc(DevHandle handle); 428``` 429 430**表 13** HdmiUnregisterHpdCallbackFunc参数和返回值描述 431 432 433| 参数 | 参数描述 | 434| ---------- | -------------- | 435| handle | HDMI控制器句柄 | 436| **返回值** | **返回值描述** | 437| 0 | 注销成功 | 438| 负数 | 注销失败 | 439 440注销热插拔检测回调函数示例: 441 442```c 443int32_t ret; 444 445ret = HdmiUnregisterHpdCallbackFunc(hdmiHandle); 446if (ret != 0) { 447 HDF_LOGE("unregister failed."); 448} 449``` 450 451#### 关闭HDMI控制器 452 453```c 454void HdmiClose(DevHandle handle); 455``` 456 457**表 14** HdmiClose参数和返回值描述 458 459 460| 参数 | 参数描述 | 461| ---------- | -------------- | 462| handle | HDMI控制器句柄 | 463 464关闭HDMI控制器示例: 465 466```c 467HdmiClose(hdmiHandle); 468``` 469 470### 使用实例 471 472本例程以操作开发板上的HDMI设备为例,详细展示HDMI接口的完整使用流程。 473 474本例拟在Hi3516DV300开发板上对虚拟驱动进行简单的传输操作: 475 476- SOC:hi3516dv300。 477 478- HDMI控制器:使用0号HDMI控制器。 479 480 481示例如下: 482 483```c 484#include "hdmi_if.h" /* HDMI标准接口头文件 */ 485#include "hdf_log.h" /* 标准日志打印头文件 */ 486#include "osal_time.h" /* 标准延迟&睡眠接口头文件 */ 487 488/* 热插拔回调函数 */ 489static void HdmiHpdHandle(void *data, bool hpd) 490{ 491 if (data == NULL) { 492 HDF_LOGE("priv data is NULL"); 493 return; 494 } 495 496 if (hpd == true) { 497 HDF_LOGD("HdmiHpdHandle: hot plug"); 498 /* 调用者添加相关处理 */ 499 } else { 500 HDF_LOGD("HdmiHpdHandle: hot unplug"); 501 /* 调用者添加相关处理 */ 502 } 503} 504 505/* 设置HDMI相关属性 */ 506static int32_t TestHdmiSetAttr(DevHandle handle) 507{ 508 enum HdmiDeepColor color; 509 struct HdmiVideoAttr videoAttr = {0}; 510 struct HdmiAudioAttr audioAttr = {0}; 511 struct HdmiHdrAttr hdrAttr = {0}; 512 int32_t ret; 513 514 ret = HdmiDeepColorSet(handle, HDMI_DEEP_COLOR_48BITS); 515 516 if (ret != 0) { 517 HDF_LOGE("HdmiDeepColorSet failed."); 518 return ret; 519 } 520 ret = HdmiDeepColorGet(handle, &color); 521 if (ret != 0) { 522 HDF_LOGE("HdmiDeepColorGet failed."); 523 return ret; 524 } 525 HDF_LOGE("HdmiDeepColorGet successful, color = %d.", color); 526 videoAttr.colorSpace = HDMI_COLOR_SPACE_YCBCR444; 527 videoAttr.colorimetry = HDMI_COLORIMETRY_EXTENDED; 528 videoAttr.extColorimetry = HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM; 529 videoAttr.quantization = HDMI_QUANTIZATION_RANGE_FULL; 530 ret = HdmiSetVideoAttribute(handle, &videoAttr); 531 if (ret != 0) { 532 HDF_LOGE("HdmiSetVideoAttribute failed."); 533 return ret; 534 } 535 audioAttr.codingType = HDMI_AUDIO_CODING_TYPE_MP3; 536 audioAttr.ifType = HDMI_AUDIO_IF_TYPE_I2S; 537 audioAttr.bitDepth = HDMI_ADIO_BIT_DEPTH_16; 538 audioAttr.sampleRate = HDMI_SAMPLE_RATE_8K; 539 audioAttr.channels = HDMI_AUDIO_FORMAT_CHANNEL_3; 540 ret = HdmiSetAudioAttribute(handle, &audioAttr); 541 if (ret != 0) { 542 HDF_LOGE("HdmiSetAudioAttribute failed."); 543 return ret; 544 } 545 hdrAttr.mode = HDMI_HDR_MODE_CEA_861_3; 546 hdrAttr.userMode = HDMI_HDR_USERMODE_DOLBY; 547 hdrAttr.eotfType = HDMI_EOTF_SMPTE_ST_2048; 548 hdrAttr.metadataType = HDMI_DRM_STATIC_METADATA_TYPE_1; 549 hdrAttr.colorimetry = HDMI_HDR_EXTENDED_COLORIMETRY_XV_YCC_709; 550 ret = HdmiSetHdrAttribute(handle, &hdrAttr); 551 if (ret != 0) { 552 HDF_LOGE("HdmiSetHdrAttribute failed."); 553 return ret; 554 } 555 556 return 0; 557} 558 559/* HDMI例程总入口 */ 560static int32_t TestCaseHdmi(void) 561{ 562 DevHandle handle = NULL; 563 int32_t ret; 564 565 struct HdmiHpdCallbackInfo info = {0}; 566 uint8_t data[128] = {0}; 567 568 HDF_LOGD("HdmiAdapterInit: successful."); 569 handle = HdmiOpen(0); 570 if (handle == NULL) { 571 HDF_LOGE("HdmiOpen failed."); 572 return ret; 573 } 574 info.data = handle; 575 info.callbackFunc = HdmiHpdHandle; 576 ret = HdmiRegisterHpdCallbackFunc(handle, &info); 577 if (ret != 0) { 578 HDF_LOGE("HdmiRegisterHpdCallbackFunc failed."); 579 return ret; 580 } 581 582 ret = HdmiReadSinkEdid(handle, data, 128); 583 if (ret <= 0) { 584 HDF_LOGE("HdmiReadSinkEdid failed."); 585 return ret; 586 } 587 HDF_LOGE("HdmiReadSinkEdid successful, data[6] = %d, data[8] = %d.", data[6], data[8]); 588 589 ret = TestHdmiSetAttr(handle); 590 if (ret != 0) { 591 HDF_LOGE("TestHdmiSetAttr failed."); 592 return ret; 593 } 594 595 ret = HdmiStart(handle); 596 if (ret != 0) { 597 HDF_LOGE("HdmiStart failed."); 598 return ret; 599 } 600 601 OsalMSleep(1000); 602 603 ret = HdmiStop(handle); 604 if (ret != 0) { 605 HDF_LOGE("HdmiStop failed."); 606 return ret; 607 } 608 609 ret = HdmiUnregisterHpdCallbackFunc(handle); 610 if (ret != 0) { 611 HDF_LOGE("HdmiUnregisterHpdCallbackFunc failed."); 612 return ret; 613 } 614 HdmiClose(handle); 615 return 0; 616} 617 618```