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