文章目录

  • 一、分辨率
    • 1.1、获取/设置分辨率
    • 1.2、初始化默认分辨率
      • 1.2.1、最优分辨率
      • 1.2.2、最大分辨率
  • 二、电视机信息
  • 三、待机

  本系列文章:
     Android STB 遥控器适配
     Android STB ROM体积精简
     Android STB 添加系统接口
     Android STB 高效调试技巧
     Android STB 海思平台调试
    Android STB HDMI开发
     Android STB 编译自定义jar

  在进行机顶盒ROM开发时,HDMI相关功能是常见的功能模块,本篇文章就简单介绍一些常见的HDMI相关需求开发。
  常见的HDMI相关功能可分为三大块:(通过HDMI线获取/设置)分辨率、(通过HDMI线获取)电视机信息、(HDMI)待机。

一、分辨率

  机顶盒通过HDMI线与TV相连时,是通过HDMI线(获取TV的EDID)来获取TV支持的分辨率情况的,所以与此相关的功能有获取/设置分辨率、初始化默认分辨率等。

1.1、获取/设置分辨率

  该功能的相关代码代码看上去和HDMI“没多大关系”,属于Android通用性功能,其实不然,该功能与HDMI息息相关。接下来就以Hi3798MV300和Amlogic905两种平台来简单介绍。
  先以Hi3798MV300为例,获取分辨率用到的接口和Android原生流程是一样的,主要来自于frameworks/base/core/java/android/os/display/DisplayManager.java,关键接口如下:

    /*所有分辨率*/private int[] mAllDisplayStandard = {DISPLAY_STANDARD_1080P_60,DISPLAY_STANDARD_1080P_50,DISPLAY_STANDARD_1080P_30,DISPLAY_STANDARD_1080P_25,DISPLAY_STANDARD_1080P_24,DISPLAY_STANDARD_1080I_60,DISPLAY_STANDARD_1080I_50,DISPLAY_STANDARD_720P_60,DISPLAY_STANDARD_720P_50,DISPLAY_STANDARD_576P_50,DISPLAY_STANDARD_480P_60,DISPLAY_STANDARD_PAL,DISPLAY_STANDARD_NTSC,DISPLAY_STANDARD_3840_2160P_24,DISPLAY_STANDARD_3840_2160P_25,DISPLAY_STANDARD_3840_2160P_30,DISPLAY_STANDARD_3840_2160P_50,DISPLAY_STANDARD_3840_2160P_60,DISPLAY_STANDARD_4096_2160P_24,DISPLAY_STANDARD_4096_2160P_25,DISPLAY_STANDARD_4096_2160P_30,DISPLAY_STANDARD_4096_2160P_50,DISPLAY_STANDARD_4096_2160P_60,}; /*DisplayManager构造函数,该函数中会初始化当前TV所支持分辨率数组mStandard*/public DisplayManager(IDisplayManager server) {mdisplay = server;//see display.c::get_hdmi_capability//                  hisi format value                fmt cap indexmMapEncFmtToIndex.put(ENC_FMT_1080P_60                  ,   1 );mMapEncFmtToIndex.put(ENC_FMT_1080P_50                  ,   2 );mMapEncFmtToIndex.put(ENC_FMT_1080P_30                  ,   3 );mMapEncFmtToIndex.put(ENC_FMT_1080P_25                  ,   4 );mMapEncFmtToIndex.put(ENC_FMT_1080P_24                  ,   5 );mMapEncFmtToIndex.put(ENC_FMT_1080i_60                  ,   6 );mMapEncFmtToIndex.put(ENC_FMT_1080i_50                  ,   7 );mMapEncFmtToIndex.put(ENC_FMT_720P_60                   ,   8 );mMapEncFmtToIndex.put(ENC_FMT_720P_50                   ,   9 );mMapEncFmtToIndex.put(ENC_FMT_576P_50                   ,   10);mMapEncFmtToIndex.put(ENC_FMT_480P_60                   ,   11);mMapEncFmtToIndex.put(ENC_FMT_PAL                       ,   12);mMapEncFmtToIndex.put(ENC_FMT_NTSC                      ,   15);mMapEncFmtToIndex.put(ENC_FMT_3840X2160_24              ,   44);mMapEncFmtToIndex.put(ENC_FMT_3840X2160_25              ,   45);mMapEncFmtToIndex.put(ENC_FMT_3840X2160_30              ,   46);mMapEncFmtToIndex.put(ENC_FMT_3840X2160_50              ,   47);mMapEncFmtToIndex.put(ENC_FMT_3840X2160_60              ,   48);mMapEncFmtToIndex.put(ENC_FMT_4096X2160_24              ,   49);mMapEncFmtToIndex.put(ENC_FMT_4096X2160_25              ,   50);mMapEncFmtToIndex.put(ENC_FMT_4096X2160_30              ,   51);mMapEncFmtToIndex.put(ENC_FMT_4096X2160_50              ,   52);mMapEncFmtToIndex.put(ENC_FMT_4096X2160_60              ,   53);try{int[] dispCapability = mdisplay.getDisplayCapability();for(int i = 0; i < dispCapability.length; i++){Log.d("DisplayManager.java", "dispCapability[" + i + "]=" + dispCapability[i]);}/*过滤分辨率列表,把当前TV支持的分辨率赋值给mStandard*/if(dispCapability != null){int supportFmtCnt = 0;int[] supportFmt = new int[mAllDisplayStandard.length];for(int i = 0; i < mAllDisplayStandard.length; i++){if(dispCapability[mMapEncFmtToIndex.get(covertCMCCFmtToHisi(mAllDisplayStandard[i]))] == 1){supportFmt[supportFmtCnt] = mAllDisplayStandard[i];supportFmtCnt++;Log.d("DisplayManager.java", "supportFmt:" + mAllDisplayStandard[i]);}Log.d("DisplayManager.java", "supportFmtCnt:" + supportFmtCnt);}mStandard = new int[supportFmtCnt];System.arraycopy(supportFmt, 0, mStandard, 0, supportFmtCnt);}else{mStandard = new int[0];}}catch(Exception ex){mStandard = new int[0];}}/*获取当前TV支持的所有分辨率*/public int[] getAllSupportStandards() {return mStandard;}/*是否支持某一分辨率*/public boolean isSupportStandard(int standard) {boolean ret = false;for (int i = 0; i < mStandard.length; i++) {if(standard == mStandard[i]){ret = true;break;}}return ret;}/*设置某一分辨率*/public void setDisplayStandard(int standard) {int hisiFmt = -1;int ret = -1;/*设置分辨率前,要检测当前TV是否支持该分辨率*/if(isSupportStandard(standard)){try {hisiFmt = covertCMCCFmtToHisi(standard);if (hisiFmt >= ENC_FMT_1080P_60) {ret = mdisplay.setFmt(hisiFmt);}} catch(Exception ex) {Log.e(TAG,"setDisplayStandard: " + ex);}} else {Log.e(TAG, "setDisplayStandard: unsupport(" + standard + ")");}Log.i(TAG, "setDisplayStandard: standard=" + standard + ", ret=" + ret);}/*获取当前分辨率*/public int getCurrentStandard() {int hisiFmt = -1;int cmccFmt = -1;try {hisiFmt = mdisplay.getFmt();cmccFmt = covertHisiFmtToCMCC(hisiFmt);} catch (RemoteException e) {Log.e(TAG, "getCurrentStandard: " + e);}if(isSupportStandard(cmccFmt)){return cmccFmt;} else {Log.e(TAG, "getCurrentStandard: CMCC unsupport(" + hisiFmt + ")");return -1;}}

  在Hi3798MV300上,使用以上接口,再结合一些其他的HDMI功能,就可以实现一个较为复杂的需求,比如:将机顶盒上的HDMI线连接到某一TV,判断该TV是否支持4K分辨率,如果支持,则切换到4K分辨率,否则不处理。关键代码示例如下:

    /*检测、设置4K分辨率*/private BroadcastReceiver mHdmiReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();/*监听HDMI插拔广播*/if (action.equals("android.intent.action.HDMI_PLUGGED")) {boolean state = intent.getBooleanExtra("state", false);Log.d(TAG,"HDMI status:"+state+",getHdmiSwitchSet():"+getHdmiSwitchSet());if (state && getHdmiSwitchSet()) {checkTVResolution();}}}};/*获取当前TV所支持的所有分辨率,如果支持4K,则设置为2060P50hz*/private void checkTVResolution(){int DISPLAY_STANDARD_3840_2160P_24 = 256;boolean is4kResolutionSupported = false;int[] supportList =  mDisplayManager.getAllSupportStandards();Arrays.sort(supportList);for(int i=0;i<supportList.length;i++){Log.d(TAG,"supportList["+i+"]:"+supportList[i]);/*所支持的分辨率列表中包含大于DISPLAY_STANDARD_3840_2160P_24的数值,则代表支持2160P,即假4K分辨率*/if(supportList[i] >= DISPLAY_STANDARD_3840_2160P_24){is4kResolutionSupported = true; break;}}if(is4kResolutionSupported){int best4kResolution = 260;if(supportList[supportList.length-1] >= 260)best4kResolution = 260;mDisplayManager.setDisplayStandard(best4kResolution);mDisplayManager.saveParams();}    }/*检测HDMI插拔状态*/private static boolean getHdmiSwitchSet() {File switchFile = new File("/sys/devices/virtual/switch/hdmi/state");if (!switchFile.exists()) {switchFile = new File("/sys/class/switch/hdmi/state");}try {Scanner switchFileScanner = new Scanner(switchFile);int switchValue = switchFileScanner.nextInt();switchFileScanner.close();return switchValue > 0;} catch (Exception e) {return false;}}

  在Amlogic905上,用的不是原生的DisplayManager来处理分辨率,有一套别的实现方式,主要实现代码在frameworks/base/services/java/com/android/server/MboxOutputModeService.java,关键接口如下:

    /*获取当前TV支持的分辨率列表,供上层调用*/public String getSupportResoulutionList() {if (isHDMIPlugged()) {ArrayList<OutputMode> mOutputModeList = readSupportList();Slog.w(TAG, "getSupportResoulutionList error, output list is null!");return null;} }/*读取当前TV支持的分辨率列表*/private ArrayList<OutputMode> readSupportList() {String str = null;ArrayList<OutputMode> mOutputModeList = new ArrayList<OutputMode>();try {/*从相关节点读取分辨率*/FileReader fr = new FileReader(HDMI_SUPPORT_LIST_SYSFS);//HDMI_SUPPORT_LIST_SYSFS = /sys/class/amhdmitx/amhdmitx0/disp_capBufferedReader br = new BufferedReader(fr);try {while ((str = br.readLine()) != null) {if(str != null){//if(DEBUG) Slog.i(TAG, "Output: " + str);boolean filter = false;OutputMode output = new OutputMode();if(str.contains("null edid")) {Slog.w(TAG, "readSupportList error, disp_cap: " + str);return null;}if(str.contains("*")) {output.mode = new String(str.substring(0, str.length()-1));output.isBestMode = true;} else {output.mode = new String(str);output.isBestMode = false;}//if(DEBUG) Slog.i(TAG, "readSupportList, Output: " + output.mode + ", isBestMode: " + output.isBestMode);if(isOutputFilter(output.mode)) {Slog.w(TAG, "readSupportList, filter this mode: " + output.mode);} else {mOutputModeList.add(output);}}};fr.close();br.close();return resolutionSort(mOutputModeList);} catch (IOException e) {e.printStackTrace();return null;}} catch (FileNotFoundException e) {e.printStackTrace();return null;}}/*获取当前分辨率*/public String getCurrentOutPutMode() {String curMode = readSysfs(OutputModeFile);//OutputModeFile = "/sys/class/display/mode"Slog.e(TAG,"getCurrentOutPutMode:" + curMode);return curMode;        }

  从上面的代码可以大致看出Amlogic905在分辨率方面的代码特征,即把相关信息存储在不同的节点中。

1.2、初始化默认分辨率

  机顶盒设置的初始分辨率策略,一般有两种:最优分辨率与最大分辨率。

1.2.1、最优分辨率

  此处的最优并不是TV支持的最大分辨率,而是ROM评估出来的、适合的一个分辨率,一般为720P或1080P,该策略一般也是ROM中的默认设置。
  先以Hi3798MV300为例,该策略的主要实现代码在device/hisilicon/bigfish/frameworks/hidisplaymanager/hal/hi_adp_hdmi.c,以Hdmicap_NativeFormat_Strategy方法为例,关键代码如下:

            else if (strcmp("p50hz", perfer) == 0){if (HI_TRUE == is_format_support(&stSinkCap,HI_UNF_ENC_FMT_4096X2160_50)){stSinkCap.enNativeFormat = HI_UNF_ENC_FMT_4096X2160_50;}else if (HI_TRUE == is_format_support(&stSinkCap,HI_UNF_ENC_FMT_4096X2160_25)){stSinkCap.enNativeFormat = HI_UNF_ENC_FMT_4096X2160_25;}//since tv capability is upgrade now , add max fmt lever to 3840X2160 P50else if (HI_TRUE == is_format_support(&stSinkCap,HI_UNF_ENC_FMT_3840X2160_50)){stSinkCap.enNativeFormat = HI_UNF_ENC_FMT_3840X2160_50;}else if (HI_TRUE == is_format_support(&stSinkCap,HI_UNF_ENC_FMT_3840X2160_25)){stSinkCap.enNativeFormat = HI_UNF_ENC_FMT_3840X2160_25;}else if (HI_TRUE == is_format_support(&stSinkCap,HI_UNF_ENC_FMT_1080P_50)){stSinkCap.enNativeFormat = HI_UNF_ENC_FMT_1080P_50;}else if (HI_TRUE == is_format_support(&stSinkCap,HI_UNF_ENC_FMT_720P_50)){stSinkCap.enNativeFormat = HI_UNF_ENC_FMT_720P_50;}else //if(stSinkCap.enNativeFormat = HI_UNF_ENC_FMT_576P_50){ALOGI("Lowest default to 576p");stSinkCap.enNativeFormat = HI_UNF_ENC_FMT_576P_50;}}

  该段代码中,is_format_support函数是芯片的最优分辨率策略实现函数,一般当persist.sys.optimalfmt.perfer设置为"p50hz"时,默认分辨率是720P50hz。
  Amlogic905的最优分辨率的实现方式也较为底层,framework层代码(frameworks/base/services/java/com/android/server/MboxOutputModeService.java)是根据节点的值来实现的,具体如下:

    /*获取最适合分辨率*/public String getBestMatchResolution() {/*获取支持的分辨率列表*/ArrayList<OutputMode> mOutputModeList = readSupportList();if (mOutputModeList != null && isHDMIPlugged()){int size = mOutputModeList.size();if(DEBUG) Slog.i(TAG, "getBestMatchResolution, output size: " + size);for (int index = 0; index < size; index++) {OutputMode output = mOutputModeList.get(index);if (DEBUG) Slog.i(TAG,"getBestMatchResolution, output: " + output.mode + " isBestMode: " + output.isBestMode);if (output.isBestMode) {Slog.i(TAG, "getBestMatchResolution, return best mode: " + output.mode);return output.mode;}}}else if(!isHDMIPlugged()){/*插AV线时返回固定分辨率*/return "576cvbs";}/*以上读取均出问题时,采用默认分辨率*/String default_mode = getPropertyString("ro.platform.best_outputmode", DEFAULT_OUTPUT_MODE);Slog.w(TAG, "getBestMatchResolution, return defalut outputmode: " + default_mode);return default_mode;}

  Amlogic905方案中,当前TV所支持的分辨率列表是写在/sys/class/amhdmitx/amhdmitx0/disp_cap节点的,该节点值示例如下:

480i60hz
480p60hz
576i50hz
576p50hz
720p60hz
1080i60hz
1080p60hz*
720p50hz
1080i50hz
1080p50hz
1080p24hz

  从上述内容可以看出所有支持的分辨率。其中后面加"*"符号的分辨率(该例子中的1080p60hz)就是系统默认的最适合分辨率,对应到代码中就是该分辨率对应的output.isBestMode为true。

1.2.2、最大分辨率

  除了系统的默认最优分辨率策略,现在也常常使用最大分辨率策略,即自适应到当前TV支持的最大分辨率,该功能主要针对的是4K电视,在连接TV时,可以自适应到4K分辨率。
  先以Hi3798MV300为例,自适应到最大分辨率,设置两个属性即可:

persist.sys.optimalfmt.enable=1
persist.sys.optimalfmt.perfer=max_fmt

  persist.sys.optimalfmt.enable属性代表的意思是分辨率自适应开关,当该属性设置为1时,代表自适应分辨率功能打开;设置为0时,代表关闭。persist.sys.optimalfmt.perfer属性设置为max_fmt,即代表自适应到最高分辨率。该功能涉及的代码为device/hisilicon/bigfish/frameworks/hidisplaymanager/hal/hi_adp_hdmi.c,相关代码如下:

    /*persist.sys.optimalfmt.perfer属性值为max_fmt时,获取最大分辨率*/else if (0 == strcmp("max_fmt", perfer)){stSinkCap.enNativeFormat = getCurrentMaxSupportFmt();}/*获取最大分辨率*/HI_S32 getCurrentMaxSupportFmt(){HI_S32 listCount = 0;HI_S32 MaxFmtListLen = 0;HI_BOOL bSupport = HI_FALSE;MaxFmtListLen = sizeof(HDMI_TV_MAX_SUPPORT_FMT) / sizeof(HDMI_TV_MAX_SUPPORT_FMT[0]);ALOGI("MaxFmtListLen = %d", MaxFmtListLen);for (listCount = 0; listCount < MaxFmtListLen; listCount++){if (HI_TRUE == is_format_support(&stSinkCap,HDMI_TV_MAX_SUPPORT_FMT[listCount])){ALOGI("max support fmt is:%d",HDMI_TV_MAX_SUPPORT_FMT[listCount]);return HDMI_TV_MAX_SUPPORT_FMT[listCount];}}ALOGI("Can't Find Max Support Format, getCurrentMaxFormat return:720P_50 !");return HI_UNF_ENC_FMT_720P_50;}

  在Hi3798MV300上,除了直接设置上述两个属性外,还可以在上层应用实现自适应4K功能,相关代码参考1.1章节。
  在Amlogic905上,可以在frameworks/base/services/java/com/android/server/MboxOutputModeService.java中的getBestMatchResolution中直接遍历所有分辨率,返回最大分辨率即可。

二、电视机信息

  除了第一节提到的分辨率相关功能,还可以获取到TV相关信息,如型号、品牌等。
  以Hi3798MV300为例,对于TV信息的获取是在底层做的,对于的代码为device/hisilicon/bigfish/frameworks/hidisplaymanager/hal/hi_adp_hdmi.c,关键代码如下:

void setTVproperty(display_format_e format)
{int w = 0;int h = 0;int newhdrsuport = 2;int oldhdrsport = 2;char hei[5] ={0};char dpi[15] = {0};char size[10] = {0};char buffer[BUFLEN] = {0};framebuffer_get_max_screen_resolution(format,&w,&h);ALOGI("format %d , w: %d  ,h: %d,",format, w, h);sprintf(dpi, "%d", w);strcat(dpi,"*");sprintf(hei, "%d", h);strcat(dpi,hei);ALOGI("dpi: %s", dpi);sprintf(size,"%d",(int)(sqrt(TVHMax*TVHMax +TVWMax*TVWMax)/2.54 +0.5));ALOGE("TVWidth:%d,Height:%d,TVSzie:%s", TVWMax, TVHMax, size);property_set("persist.sys.tv.name",stSinkCap.stMfrsInfo.u8MfrsName);  //代表电视机的品牌property_set("persist.sys.tv.type",stSinkCap.stMfrsInfo.u8pSinkName); //代表电视机的具体型号property_set("persist.sys.tv.size",size);  //代表电视机的尺寸,即电视机对角线长度                         property_set("persist.sys.tv.dpi",dpi);    //代表电视机DPI,即每英寸像素点数memset(buffer, 0, sizeof(buffer));property_get("persist.sys.tv.Supporthdr", buffer , "2");oldhdrsport = atoi(buffer);if(HI_TRUE == stSinkCap.bHdrSupport && stSinkCap.stHdr.stEotf.bEotfSmpteSt2084)newhdrsuport = 1;//yes 1else if (HI_FALSE == stSinkCap.bHdrSupport)newhdrsuport = 2;//no 2elsenewhdrsuport = 0;//other 0//HSCP2018042722609if(newhdrsuport != oldhdrsport){sprintf(buffer, "%d", newhdrsuport);property_set("persist.sys.tv.Supporthdr",buffer);}}

  在Amlogic905上,电视机相关的信息是写在节点sys/class/amhdmitx/amhdmitx0/edid里的,示例内容如下:

Rx Brand Name: PHL
Rx Product Name: PHILIPS
Physcial size(cm): 52 x 29
Manufacture Week: 1
Manufacture Year: 2015
EDID Verison: 1.3
EDID block number: 0x1
blk0 chksum: 0x2c
Source Physical Address[a.b.c.d]: 1.0.0.0
native Mode f1, VIC (native 16):
ColorDeepSupport 2
31 16 20 5 19 4 2 3 32 22 18 6 7 1
Audio {format, channel, freq, cce}
{1, 1, 7, 7}
{10, 7, 6, 0}
Speaker Allocation: 1
Vendor: 0xc03
MaxTMDSClock1 290 MHz
SCDC: 0
RR_Cap: 0
LTE_340M_Scramble: 0
checkvalue: 0x2cc80000

  Rx Brand Name代表的是电视机品牌;Rx Product Name代表的是电视机型号;Physcial size(cm)代表的是电视机长宽。

三、待机

  此处主要的指的是"HDMI待机"功能,即电视机关机,机顶盒也跟着待机。
  在Hi3798MV300上,一般设置两个属性即可:

persist.hdmi.suspend.enable = 1
persist.hdmi.suspend.time = 5

  persist.hdmi.suspend.enable属性值代表HDMI待机开关,0代表关闭,1代表打开。persist.hdmi.suspend.time属性值代表待机时间,即电视机关机后多久,机顶盒进入待机,单位为分钟。该功能的实现也在device/hisilicon/bigfish/frameworks/hidisplaymanager/hal/hi_adp_hdmi.c,待机代码如下:

void HDMI_Suspend_Timeout()
{ALOGI("HDMI_Suspend_Timeout: hdmi connect status flag hdmi_enable =%d",hdmi_enable);char  buffer[BUFLEN] = {0};HI_UNF_HDMI_STATUS_S  hdmiStatus;//icsl inithdmiStatus.bConnected = HI_FALSE;HI_U8 is_under_cec_suspend = get_HDMI_CEC_Suspend_Status();HI_UNF_HDMI_GetStatus(0,&hdmiStatus);ALOGI("hdmiStatus.bConnected =%d",hdmiStatus.bConnected);//hdmi uplug  or hdmi rsen disconnect event suspend time out, send a power key to system//end by lizheng 20190326 to solve 32a suspendHDMI_Suspend_ReportKeyEvent(KEY_POWER, KPC_EV_KEY_PRESS);HDMI_Suspend_ReportKeyEvent(KEY_POWER, KPC_EV_KEY_RELEASE);ALOGW("\033[31mHDMI_Suspend_Timeout: send power key to suspend \33[0m\n");property_get("ro.product.target", buffer, "0");if(strcmp(buffer,"shcmcc")==0){sleep(4);//unit : secondHDMI_Suspend_ReportKeyEvent(KEY_RIGHT, KPC_EV_KEY_PRESS);HDMI_Suspend_ReportKeyEvent(KEY_RIGHT, KPC_EV_KEY_RELEASE);sleep(2);HDMI_Suspend_ReportKeyEvent(KEY_ENTER, KPC_EV_KEY_PRESS);HDMI_Suspend_ReportKeyEvent(KEY_ENTER, KPC_EV_KEY_RELEASE);}}

  从上面代码可以看出,进行机顶盒待机功能是通过模拟电源键按键操作来实现的。
  在Amlogic905上,HDMI待机功能是在frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java中实现的。简单流程为,在init函数中,初始化HDMI相关的信息,代码如下:

    void initializeHdmiState() {boolean plugged = false;// watch for HDMI plug messages if the hdmi switch existsif (new File("/sys/class/switch/hdmi_hpd/state").exists()) {if (SystemProperties.getBoolean("ro.platform.has.mbxuimode", false)){SystemProperties.set("sys.boot.logo", "android");if(SystemProperties.getBoolean("ro.hw.cvbs.onboard", true) && !SystemProperties.getBoolean("ro.hdmiplugdetect.dis", false)){mMboxOutputModeManager.initOutputMode();mHDMIObserver.startObserving(HDMI_TX_PLUG_UEVENT);}} else {mHDMIObserver.startObserving(HDMI_TX_PLUG_UEVENT);}final String filename = "/sys/class/switch/hdmi_hpd/state";FileReader reader = null;try {reader = new FileReader(filename);char[] buf = new char[15];int n = reader.read(buf);if (n > 1) {plugged = 0 != Integer.parseInt(new String(buf, 0, n-1));}} catch (IOException ex) {Slog.w(TAG, "Couldn't read hdmi state from " + filename + ": " + ex);} catch (NumberFormatException ex) {Slog.w(TAG, "Couldn't read hdmi state from " + filename + ": " + ex);} finally {if (reader != null) {try {reader.close();} catch (IOException ex) {}}}}mHdmiHwPlugged =  plugged;if (!SystemProperties.getBoolean("ro.vout.dualdisplay", false)) {if (getCurDisplayMode().equals("panel") || !plugged || SystemProperties.getBoolean("ro.platform.has.mbxuimode", false)) {plugged = false;}}if (SystemProperties.getBoolean("ro.vout.dualdisplay", false)) {setDualDisplay(plugged);}if (SystemProperties.getBoolean("ro.vout.dualdisplay2", false)) {plugged = false;setDualDisplay(plugged);}        Intent it = new Intent(WindowManagerPolicy.ACTION_HDMI_PLUGGED);it.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);it.putExtra(WindowManagerPolicy.EXTRA_HDMI_PLUGGED_STATE, plugged);mContext.sendStickyBroadcastAsUser(it, UserHandle.OWNER);}

  此函数中有mHDMIObserver.startObserving(HDMI_TX_PLUG_UEVENT),开始监听了HDMI的状态, UEventObserver代码如下:

    private UEventObserver mHDMIObserver = new UEventObserver() {@Overridepublic void onUEvent(UEventObserver.UEvent event) {Log.d(TAG , "mHDMIObserver");setHdmiHwPlugged("1".equals(event.get("SWITCH_STATE")));}};

  setHdmiHwPlugged中有段关键代码为:

        if(SystemProperties.getBoolean("persist.sys.autosuspend.hdmi", false)) {  if (plugged && !isTvSuspend) {disableAutoSuspend();} else {enableAutoSuspend();}}

  persist.sys.autosuspend.hdmi属性为HDMI待机开关,然后当判断HDMI线拔出时,就调用enableAutoSuspend进入待机流程,代码如下:

  public void enableAutoSuspend() {disableAutoSuspend();int def_timeout = 2 * 60 * 1000; //default 2minif (timeout > 0) {Slog.d(TAG, "enable auto suspend");mAutoSuspendTimer = new Timer();TimerTask task = new TimerTask(){public void run() {Slog.d(TAG, "goto auto suspend");String proj_type = SystemProperties.get("sys.proj.type", "ott");String tender_type = SystemProperties.get("sys.proj.tender.type", null);Log.i(TAG, "Auto suspend sys.proj.type: " + proj_type + ", sys.proj.tender.type: " + tender_type);if ("telecom".equals(proj_type) && "jicai".equals(tender_type)) {sendKeyEvent(KeyEvent.KEYCODE_HOME);}String rx_sense = mSystemWriteManager.readSysfs("/sys/class/switch/hdmi_rxsense/state");if("0".equals(rx_sense))mPowerManager.goToSleep(SystemClock.uptimeMillis());}};mAutoSuspendTimer.schedule(task, timeout);isTvSuspend = false;}}

  至此,常用HDMI功能开发已介绍完毕。

Android STB HDMI开发相关推荐

  1. android 平板hdmi开发,安卓平板电脑的新突破口:HDMI in 视频输入,取代便携显示器...

    不知道从什么时候开始,便携显示器进入了小部分数码玩家的生活中,有人喜欢将其与任天堂Switch连接,有人喜欢将其作为笔记本电脑的扩展屏,甚至还有一部分用户,则通过智能手机与便携显示器连接,从而实现安卓 ...

  2. Android STB 高效调试技巧

    文章目录 一.编译 1.1 版本全编 1.2 模块单编 1.3 芯片特有单编模块 1.3.1 Uboot 1.3.2 boot.img&dt.img 二.调试 2.1 文件替换 2.1.1 常 ...

  3. Android STB 海思平台调试

    文章目录 一.产品参数 1.1 Hi3798MV100 1.2 Hi3798MV300 二.网络类&播放类 三.系统类 3.1 输出相关 3.2 CEC 3.3 杜比 3.4 IGMP 3.5 ...

  4. Android STB 添加系统接口

    文章目录 一.知识准备 1.1.电视机屏幕宽高的获取 1.2.电视机屏幕尺寸的计算 1.3.Binder通信 二.在原生Service中添加 三.实现定制的Service 3.1.SystemServ ...

  5. android sdk软件开发套件,ANDROIDSDK-SITARA

    TI 的 Android 开发套件是一套完整的软件,Sitara 器件的开发人员可以用其轻松快速地评估 Android 操作系统.该套件提供稳定且经全面测试的软件基础,可广泛用于包括评估模块和 Bea ...

  6. [置顶]树莓派Android Things物联网开发:入门及资料汇总

    [转载请注明出处: http://blog.csdn.net/leytton/article/details/77848430] <树莓派Android Things物联网开发>系列文章专 ...

  7. Android智能硬件开发心得总结(二)

    Android智能硬件开发心得总结(一) 6.关于屏幕显示 每次一个新项目的开发,我所做的第一件事就是确定所选定显示屏的型号规格,然后将规格书发给主板供应商让其先调屏参. 调屏参是很可能会出现无法点亮 ...

  8. Android底层驱动开发记录:01_JNI

    最近项目中需要用到了Android底层的开发,正好疫情居家所以又把韦老师的老教程第四期Android教程翻出来学习学习,手边也没有合适的板子,找了一块AIO-3288C的板子接了一块HDMI的屏来用. ...

  9. 《精通Android 5 多媒体开发》——第1章,第1.1节智能手机系统介绍

    本节书摘来自异步社区<精通Android 5 多媒体开发>一书中的第1章,第1.1节1.1 智能手机系统介绍,作者 王石磊,更多章节内容可以访问云栖社区"异步社区"公众 ...

最新文章

  1. python课程推荐-推荐几个优质的 Python 学习资料(良心推荐,非广告)
  2. mybatis查询如何返回ListMap类型数据
  3. Android --- 微信支付时出现错误:错误的签名,验签失败,return_code=FAIL
  4. STL训练 HDU - 1716 Ray又对数字的列产生了兴趣:
  5. Java数据库篇5——事务
  6. Docker 修改容器名称
  7. 八皇后问题--C语言学习笔记
  8. 【洛谷 P1772】 [ZJOI2006]物流运输(Spfa,dp)
  9. python大漠插件多开_[求助,]用python调用大漠插件,注册好后调用出错.完全不会了...
  10. 周报(1.13到1.20)
  11. 混合云向边缘延伸!ZStack Mini超融合和ZStack CMP重磅发布!
  12. 基于Tomcat + JNDI + ActiveMQ实现JMS的点对点消息传送
  13. 伺服电机算功率基本公式_伺服电机选型通用计算公式
  14. pytorch关系抽取框架OpenNRE源码解读与实践:PCNN ATT
  15. 如何使用python批量压缩图片_python 实现图片批量压缩的示例
  16. python--异常捕获
  17. Xcode (xip)官方原版下载 Xcode 所有历史版本(转载)
  18. register at least one qt version using“qt vs tools“->“qt options“
  19. js截取字符串(从后往前截)
  20. Bootstrap初识

热门文章

  1. 大数据分析师高级证书_我想请问怎么考大数据分析师资格证书?
  2. Automake 使用手册
  3. 微信扫码支付初步使用
  4. 腾讯开源柠檬 Lemon
  5. 量化选股模型—动量反转模型
  6. 一阶动量与二阶动量的角度理解优化
  7. 使用proxifier实现二级http代理上网
  8. Pandas提取文本信息(身份证号码)
  9. 如何从 iPad 远程访问 Mac
  10. 设计师:设计师知识储备之设计流派(高技派、光亮派、白色派、风格派、极简主义、装饰艺术、后现代、解构主义、新现代主义 )之详细攻略