/* * Copyright (c) 2019 Amlogic, Inc. All rights reserved. * * This source code is subject to the terms and conditions defined in the * file 'LICENSE' which is part of this source code package. * * Description: */ #define LOG_MODULE_TAG "TV" #define LOG_CLASS_TAG "CTv" #include #include #include "CTv.h" #include "tvutils.h" #include "TvConfigManager.h" #include "CTvLog.h" #include "CVpp.h" #include #include #include "CVrr.h" /* static tv_hdmi_edid_version_t Hdmi1CurrentEdidVer = HDMI_EDID_VER_14; static tv_hdmi_edid_version_t Hdmi2CurrentEdidVer = HDMI_EDID_VER_14; static tv_hdmi_edid_version_t Hdmi3CurrentEdidVer = HDMI_EDID_VER_14; static tv_hdmi_edid_version_t Hdmi4CurrentEdidVer = HDMI_EDID_VER_14; */ #define NEW_FRAME_TIME_OUT_COUNT 10 //PORT_NUM define as 3 in the kernel. #define K_PORT_NUM (3) CTv::CTv() { mpObserver = NULL; UenvInit(); const char* tvConfigFilePath = getenv(CFG_TV_CONFIG_FILE_PATH_STR); if (!tvConfigFilePath) { LOGD("%s: read tvconfig file path failed!\n", __FUNCTION__); tvConfigFilePath = CONFIG_FILE_PATH_DEF; } else { LOGD("%s: tvconfig file path is %s!\n", __FUNCTION__, tvConfigFilePath); } LoadConfigFile(tvConfigFilePath); const char * value; value = ConfigGetStr( CFG_SECTION_TV, CFG_TVIN_ATV_DISPLAY_SNOW, "null" ); if (strcmp(value, "enable") == 0 ) { mATVDisplaySnow = true; } else { mATVDisplaySnow = false; } LOGD("%s: load mATVDisplaySnow status [%d]!\n", __FUNCTION__, mATVDisplaySnow); mpAmVideo = new CAmVideo(); mpTvin = CTvin::getInstance(); mpTvin->Tvin_AddVideoPath(TV_PATH_VDIN_AMLVIDEO2_PPMGR_DEINTERLACE_AMVIDEO); mpTvin->Tvin_LoadSourceInputToPortMap(); if (IsSupportPIP()) { mpPipTvin = CTvin::getInstance(VDIN2); mpPipTvin->Tvin_LoadSourceInputToPortMap(); mpTvSubDisplayadapter = new CTvDisplayadapter(SUB_WINDOW); } mpTvMainDisplayadapter = new CTvDisplayadapter(MAIN_WINDOW); mpHDMIRxManager = new CHDMIRxManager(); // update cec port sequence from hdmi tv config. mpHDMIRxManager->SetHdmiPortCecPhysicAddr(); mpTvWayland = new CTvWayland(); tvin_info_t signalInfo; signalInfo.trans_fmt = TVIN_TFMT_2D; signalInfo.fmt = TVIN_SIG_FMT_NULL; signalInfo.status = TVIN_SIG_STATUS_NULL; signalInfo.cfmt = TVIN_COLOR_FMT_MAX; signalInfo.signal_type= 0; signalInfo.fps = 60; signalInfo.is_dvi = 0; signalInfo.aspect_ratio = TVIN_ASPECT_NULL; SetCurrenSourceInfo(signalInfo); SetCurrentPipSourceInfo(signalInfo); //EDID load int edidAutoLoadEnable = ConfigGetInt(CFG_SECTION_HDMI, CFG_HDMI_EDID_AUTO_LOAD_EN, 1); if (edidAutoLoadEnable == 1) { LOGD("%s: EDID data load by tvserver!\n", __FUNCTION__); mInitEdid = true; const char* buf = GetUenv(HDMI_UBOOT_EDID_VERSION); if (buf == NULL) { const char* edidDefaultVersion = ConfigGetStr(CFG_SECTION_HDMI, CFG_HDMI_EDID_DEFAULT_VERSION, "1.4"); int edidSetValue = 0; if (strcmp(edidDefaultVersion, "2.0") == 0 ) { LOGD("%s: Set EDID default version to 2.0!\n", __FUNCTION__); /* Hdmi1CurrentEdidVer = HDMI_EDID_VER_20; Hdmi2CurrentEdidVer = HDMI_EDID_VER_20; Hdmi3CurrentEdidVer = HDMI_EDID_VER_20; Hdmi4CurrentEdidVer = HDMI_EDID_VER_20; */ for (int i = 0;i < 4; i ++) edidSetValue |= (1 << (4*i)); } SetUenv(HDMI_UBOOT_EDID_VERSION, std::to_string(edidSetValue).c_str()); } if (GetHdmiDlgEnabled()) { mDlgVisionEnableState = true; } bool dolbyVisionEnableState = GetDolbyVisionSupportStatus(); LoadEdidDataWithPort(0, dolbyVisionEnableState); } else { LOGD("%s: EDID data load by customer!\n", __FUNCTION__); } mTvDevicesPollDetect.setObserver(this); mTvDevicesPollDetect.startDetect(); mTvMsgQueue = new CTvMsgQueue(this); mTvMsgQueue->startMsgQueue(); mLastScreenMode = -1; //panel tconless init CTvPanel *mPanel = CTvPanel::getInstance(); mPanel->AM_PANEL_Init(); } CTv::~CTv() { if (mpTvin != NULL) { mpTvin->Tvin_RemoveVideoPath(TV_PATH_TYPE_TVIN); delete mpTvin; mpTvin = NULL; } if (mpHDMIRxManager != NULL) { delete mpHDMIRxManager; mpHDMIRxManager = NULL; } if (mpAmVideo != NULL) { delete mpAmVideo; mpAmVideo = NULL; } mpObserver = NULL; UnloadConfigFile(); } int CTv::StartTv(tv_source_input_t source) { LOGD("%s: source = %d!\n", __FUNCTION__, source); int ret = 0; if (SOURCE_MPEG == source) { LOGD("%s: new source is %d! RETURN\n", __FUNCTION__,source); return ret; } mpTvWayland->setMainTunnelId(0); mpTvWayland->startMainVideo(); mpTvWayland->commitAll(); //main source set 0, 0 as default mpTvMainDisplayadapter->TV_setDisplayadapterParam(0,0); mpTvMainDisplayadapter->TV_dispAdptCreateLayer(); mpTvMainDisplayadapter->TV_dispAdptSetLayerZorder(0); int freerun_mode = 0; mpAmVideo->AmVideoDeviceIOCtl(AMSTREAM_IOC_SET_FREERUN_MODE, &freerun_mode); //CVpp::getInstance()->setVideoaxis();//when open source set video axis full screen tvin_port_t source_port = mpTvin->Tvin_GetSourcePortBySourceInput(source); ret = mpTvin->Tvin_OpenPort(source_port); mCurrentSource = source; mCurrentSourceType = mpTvin->Tvin_SourceInputToSourceInputType(mCurrentSource); #ifdef HAVE_AUDIO CTvAudio::getInstance()->create_audio_patch(TV_CHANNEL_MAIN, mapSourcetoAudiotupe(source)); if (AvAudioMode && SOURCE_TYPE_AV == mCurrentSourceType) { CTvAudio::getInstance()->set_audio_av_audio_only_enabled(true); CTvAudio::getInstance()->set_audio_av_mute(false); } else { CTvAudio::getInstance()->set_audio_av_mute(true); } #endif return ret; } int CTv::StopTv(tv_source_input_t source) { LOGD("%s: source = %d!\n", __FUNCTION__, source); int ret = 0; if (SOURCE_MPEG == source) { LOGD("%s:current source is %d! return\n", __FUNCTION__,source); return ret; } #ifdef HAVE_AUDIO CTvAudio::getInstance()->release_audio_patch(TV_CHANNEL_MAIN); CTvAudio::getInstance()->set_audio_av_mute(false); #endif mpTvWayland->stopMainVideo(); if (mCurrentPipSource == SOURCE_INVALID) { mpTvWayland->shutdown(); } mpTvMainDisplayadapter->TV_dispAdptDestroyLayer(); mpAmVideo->SetVideoLayerStatus(VIDEO_LAYER_STATUS_DISABLE); mpAmVideo->SetVideoGlobalOutputMode(VIDEO_GLOBAL_OUTPUT_MODE_DISABLE); mpTvin->Tvin_StopDecoder(); tvin_port_t source_port = mpTvin->Tvin_GetSourcePortBySourceInput(source); mpTvin->Tvin_ClosePort(source_port); mVdinWorkMode = VDIN_WORK_MODE_VFM; mCurrentSource = SOURCE_INVALID; mCurrentSourceType = SOURCE_TYPE_MPEG; tvin_info_t tempSignalInfo; tempSignalInfo.trans_fmt = TVIN_TFMT_2D; tempSignalInfo.fmt = TVIN_SIG_FMT_NULL; tempSignalInfo.status = TVIN_SIG_STATUS_NULL; tempSignalInfo.cfmt = TVIN_COLOR_FMT_MAX; tempSignalInfo.signal_type= 0; tempSignalInfo.fps = 60; tempSignalInfo.is_dvi = 0; tempSignalInfo.aspect_ratio = TVIN_ASPECT_NULL; SetCurrenSourceInfo(tempSignalInfo); return ret; } int CTv::SwitchSource(tv_source_input_t dest_source) { if (dest_source != mCurrentSource) { StopTv(mCurrentSource); StartTv(dest_source); } else { LOGD("same source,no need switch!\n"); } return 0; } tv_source_input_t CTv::GetCurrentSource() { return mCurrentSource; } void CTv::onSourceConnect(int source, int connect_status) { LOGD("onSourceConnect: source = %d, connect_status= %d!\n", source, connect_status); //To do TvEvent::SourceConnectEvent event; event.mSourceInput = source; event.connectionState = connect_status; sendTvEvent(event); } void CTv::onVdinSignalChange() { vdin_event_info_s SignalEventInfo; memset(&SignalEventInfo, 0, sizeof(vdin_event_info_s)); int ret = mpTvin->Tvin_GetSignalEventInfo(&SignalEventInfo); if (ret < 0) { LOGD("Get vidn event error!\n"); } else { tv_source_input_type_t source_type = mpTvin->Tvin_SourceInputToSourceInputType(mCurrentSource); tvin_sig_change_flag_t vdinEventType = (tvin_sig_change_flag_t)SignalEventInfo.event_sts; switch (vdinEventType) { case TVIN_SIG_CHG_SDR2HDR: case TVIN_SIG_CHG_HDR2SDR: case TVIN_SIG_CHG_DV2NO: case TVIN_SIG_CHG_NO2DV: { LOGD("%s: hdr info change!\n", __FUNCTION__); tvin_info_t vdinSignalInfo; memset(&vdinSignalInfo, 0, sizeof(tvin_info_t)); ret = mpTvin->Tvin_GetSignalInfo(&vdinSignalInfo); if (ret < 0) { LOGD("%s: Get vidn event error!\n", __FUNCTION__); } else { if ((mCurrentSignalInfo.status == TVIN_SIG_STATUS_STABLE) && (mCurrentSignalInfo.signal_type != vdinSignalInfo.signal_type)) { if (source_type == SOURCE_TYPE_HDMI) { //tvSetCurrentHdrInfo(vdinSignalInfo.signal_type); } mCurrentSignalInfo.signal_type = vdinSignalInfo.signal_type; } else { LOGD("%s: hdmi signal don't stable!\n", __FUNCTION__); } } break; } case TVIN_SIG_CHG_COLOR_FMT: LOGD("%s: no need do any thing for colorFmt change!\n", __FUNCTION__); break; case TVIN_SIG_CHG_RANGE: LOGD("%s: no need do any thing for colorRange change!\n", __FUNCTION__); break; case TVIN_SIG_CHG_BIT: LOGD("%s: no need do any thing for color bit deepth change!\n", __FUNCTION__); break; case TVIN_SIG_CHG_VS_FRQ: LOGD("%s: no need do any thing for VS_FRQ change!\n", __FUNCTION__); break; case TVIN_SIG_CHG_STS: LOGD("%s: vdin signal status change!\n", __FUNCTION__); onSigStatusChange(); break; case TVIN_SIG_CHG_AFD: { LOGD("%s: AFD info change!\n", __FUNCTION__); if (source_type == SOURCE_TYPE_HDMI) { tvin_info_t newSignalInfo; memset(&newSignalInfo, 0, sizeof(tvin_info_t)); int ret = mpTvin->Tvin_GetSignalInfo(&newSignalInfo); if (ret < 0) { LOGD("%s: Get Signal Info error!\n", __FUNCTION__); } else { if ((newSignalInfo.status == TVIN_SIG_STATUS_STABLE) && (mCurrentSignalInfo.aspect_ratio != newSignalInfo.aspect_ratio)) { mCurrentSignalInfo.aspect_ratio = newSignalInfo.aspect_ratio; //tvSetCurrentAspectRatioInfo(newSignalInfo.aspect_ratio); } else { LOGD("%s: signal not stable or same AFD info!\n", __FUNCTION__); } } } break; } case TVIN_SIG_CHG_DV_ALLM: LOGD("%s: allm info change!\n", __FUNCTION__); if (source_type == SOURCE_TYPE_HDMI) { onSigDvAllmChange(); } else { LOGD("%s: not hdmi source!\n", __FUNCTION__); } break; case TVIN_SIG_CHG_VRR: LOGD("%s: vrr change!\n", __FUNCTION__); if (source_type == SOURCE_TYPE_HDMI) { onSigVrrChange(); } else { LOGD("%s: not hdmi source!\n", __FUNCTION__); } break; case TVIN_SIG_CHG_QMS: { if (GetHdmiQmsEnabled()) { LOGD("%s: QMS change!\n", __FUNCTION__); vdin_qms_param_t qmsInfo; memset(&qmsInfo, 0, sizeof(vdin_qms_param_t)); int ret = mpTvin->VDIN_GetQmsParm(&qmsInfo); if (ret < 0) { LOGD("%s: Get QMS Info error!\n", __FUNCTION__); } else if (TVIN_SIG_STATUS_STABLE == mCurrentSignalInfo.status) { LOGD("%s: send QMS change event,qms_en:%d, qms_fr:%d, qms_base_fr: %d, fps: %d!\n", __FUNCTION__,qmsInfo.qms_en, qmsInfo.qms_fr, qmsInfo.qms_base_fr, mCurrentSignalInfo.fps); TvEvent::QMSEvent ev; ev.qms_en = (int)qmsInfo.qms_en; ev.qms_fps = (int)qmsInfo.qms_fr; ev.qms_base_fps = qmsInfo.qms_en ? (int)qmsInfo.qms_base_fr:(int)(mCurrentSignalInfo.fps * 1000); sendTvEvent ( ev ); } else { LOGD("%s: invalid qms event!\n", __FUNCTION__); } } else { LOGD("%s: qms switch closed!\n", __FUNCTION__); } break; } default: LOGD("%s: invalid vdin event!\n", __FUNCTION__); break; } } } void CTv::onSigDvAllmChange(void) { tvin_latency_s AllmInfo; int ret = mpTvin->Tvin_GetAllmInfo(&AllmInfo); if (ret < 0) { LOGE("%s: mpTvin->Tvin_GetAllmInfo() failed!\n", __FUNCTION__); return; } TvEvent::SignalDvAllmEvent event; event.allm_mode = static_cast(AllmInfo.allm_mode); event.it_content = AllmInfo.it_content ? 1 : 0; event.cn_type = AllmInfo.cn_type; sendTvEvent(event); } int CTv::GetCurrentSourceAllmInfo(tvin_latency_s *info) { int ret = mpTvin->Tvin_GetAllmInfo(info); if (ret < 0) { LOGE("%s: mpTvin->Tvin_GetAllmInfo() failed!\n", __FUNCTION__); } return ret; } void CTv::onSigVrrChange(void) { vdin_vrr_freesync_param_s vrrparm; int ret = mpTvin->VDIN_GetVrrFreesyncParm(&vrrparm); if (ret < 0) { LOGE("%s: mpTvin->VDIN_GetVrrFreesyncParm() failed!\n", __FUNCTION__); return; } TvEvent::SignalVrrEvent event; event.cur_vrr_status = vrrparm.cur_vrr_status; sendTvEvent(event); } vdin_vrr_mode_t CTv::GetHdmiVrrMode() { vdin_vrr_freesync_param_s vrrparm; int ret = mpTvin->VDIN_GetVrrFreesyncParm(&vrrparm); if (ret < 0) { LOGE("%s: mpTvin->VDIN_GetVrrFreesyncParm() failed!\n", __FUNCTION__); return (vdin_vrr_mode_t)0; } return (vdin_vrr_mode_t)vrrparm.cur_vrr_status; } void CTv::onSigStatusChange(void) { LOGD("%s\n", __FUNCTION__); tvin_info_s tempSignalInfo; int ret = mpTvin->Tvin_GetSignalInfo(&tempSignalInfo); if (ret < 0) { LOGD("Get Signal Info error!\n"); return; } else { SetCurrenSourceInfo(tempSignalInfo); LOGD("sig_fmt is %d, status is %d, isDVI is %d, hdr_info is 0x%x\n", mCurrentSignalInfo.fmt, mCurrentSignalInfo.status, mCurrentSignalInfo.is_dvi, mCurrentSignalInfo.signal_type); if ( mCurrentSignalInfo.status == TVIN_SIG_STATUS_STABLE ) { setDisplayCrop(MAIN_WINDOW); onSigToStable(); } else if (mCurrentSignalInfo.status == TVIN_SIG_STATUS_UNSTABLE ) { onSigToUnstable(); } else if ( mCurrentSignalInfo.status == TVIN_SIG_STATUS_NOTSUP ) { onSigToUnSupport(); } else if ( mCurrentSignalInfo.status == TVIN_SIG_STATUS_NOSIG ) { onSigToNoSig(); } else { LOGD("%s: invalid signal status!\n",__FUNCTION__); } return; } } int CTv::SetCurrenSourceInfo(tvin_info_t sig_info) { mCurrentSignalInfo.trans_fmt = sig_info.trans_fmt; mCurrentSignalInfo.fmt = sig_info.fmt; mCurrentSignalInfo.status = sig_info.status; mCurrentSignalInfo.cfmt = sig_info.cfmt; mCurrentSignalInfo.signal_type= sig_info.signal_type; mCurrentSignalInfo.fps = sig_info.fps; mCurrentSignalInfo.is_dvi = sig_info.is_dvi; mCurrentSignalInfo.aspect_ratio = sig_info.aspect_ratio; return 0; } tvin_info_t CTv::GetCurrentSourceInfo(void) { LOGD("mCurrentSource = %d, trans_fmt is %d,fmt is %d, status is %d.\n", mCurrentSource, mCurrentSignalInfo.trans_fmt, mCurrentSignalInfo.fmt, mCurrentSignalInfo.status); return mCurrentSignalInfo; } int CTv::setTvObserver ( TvIObserver *ob ) { LOGD("%s\n", __FUNCTION__); if (ob != NULL) { mpObserver = ob; } else { LOGD("%s: Observer is NULL.\n", __FUNCTION__); } return 0; } int CTv::SetEdidData(tv_source_input_t source, char *data) { LOGD("%s\n", __FUNCTION__); int ret = -1; if (data == NULL) { LOGD("%s: data is NULL.\n", __FUNCTION__); } else { unsigned char edidData[REAL_EDID_DATA_SIZE]; memcpy(edidData, data, REAL_EDID_DATA_SIZE); tvin_port_id_t portId = mpTvin->Tvin_GetHdmiPortIdBySourceInput(source); ret = mpHDMIRxManager->UpdataEdidDataWithPort(portId, edidData); } return ret; } int CTv::GetEdidData(tv_source_input_t source, char *data) { char edidData[REAL_EDID_DATA_SIZE]; char edidFileName[100] = {0}; int port = (int)source - SOURCE_HDMI1 + 1; int edidVer = (GetEdidVersion(source) == HDMI_EDID_VER_20)?20:14; char dv_support[4] = {0}; const char *edidFilePath = ConfigGetStr(CFG_SECTION_HDMI, CFG_HDMI_EDID_FILE_PATH, "/vendor/etc/tvconfig/hdmi"); if (GetDolbyVisionSupportStatus() == 1) strcpy(dv_support, "_dv"); memset(edidData, 0, REAL_EDID_DATA_SIZE); sprintf(edidFileName, "%s/port%d_%d%s.bin", edidFilePath, port, edidVer, dv_support); LOGD("%s: EDID file: %s\n", __FUNCTION__, edidFileName); ReadDataFromFile(edidFileName, 0, REAL_EDID_DATA_SIZE, edidData); memcpy(data, edidData, REAL_EDID_DATA_SIZE); return 0; } #define MMC_DEVICE ("/dev/mmcblk0") #define PANEL_ID_OFFSET 0x9000004 int CTv::GetPanelSize() { int fd, len, panelSize=0; off_t offset = 0L; char buf[2] = {0}, psize[8]={0}; if ((fd = open(MMC_DEVICE, O_RDONLY)) < 0) { LOGE("open %s error(%s)", MMC_DEVICE, strerror (errno)); return 0; } offset = lseek (fd, PANEL_ID_OFFSET, SEEK_SET); if ( offset != PANEL_ID_OFFSET ) { LOGE("Failed to seek. offset[0x%x] requested[0x%x]\n", (uint32_t)offset, PANEL_ID_OFFSET); close(fd); return 0; } len = read(fd, buf, 2); if (len < 0) { LOGE("Read %s error, %s\n", MMC_DEVICE, strerror(errno)); close(fd); return 0; } sprintf(psize, "%d", buf[1]); panelSize = atoi(psize); close(fd); return panelSize; } int CTv::LoadEdidData(int isNeedBlackScreen, int isDolbyVisionEnable) { if (isNeedBlackScreen == 1) { mpTvin->Tvin_StopDecoder(); } char edidLoadBuf[(TVIN_PORT_ID_MAX - 1) * 2 * REAL_EDID_DATA_SIZE]; char edidFileName[100] = {0}; int loadNum = 1; int i = 0; tvin_port_t tvin_port = TVIN_PORT_NULL; ui_hdmi_port_id_t ui_port = UI_HDMI_PORT_ID_MAX; tv_source_input_t source_input; const char *edidFilePath = ConfigGetStr(CFG_SECTION_HDMI, CFG_HDMI_EDID_FILE_PATH, "/vendor/etc/tvconfig/hdmi"); LOGD("%s: sizeof edidLoadBuf:[%d] isDolbyVisionEnable = %d.\n", __FUNCTION__, sizeof(edidLoadBuf), isDolbyVisionEnable); memset(edidLoadBuf, 0, sizeof(edidLoadBuf)); for (loadNum = (int)TVIN_PORT_ID_1; loadNum < (int)TVIN_PORT_ID_MAX; loadNum++) { tvin_port = mpTvin->Tvin_GetVdinPortByVdinPortID((tvin_port_id_t)loadNum); source_input = mpTvin->Tvin_PortToSourceInput(tvin_port); ui_port = mpTvin->Tvin_GetUIHdmiPortIdBySourceInput(source_input); LOGD("%s:tvin port ID:%d tvin_port:0x%x source_input:%d ui_port:%d\n", __FUNCTION__, loadNum, tvin_port, source_input, ui_port); // Load EDID 1.4 then load EDID 2.0. for (i = 0; i < 2; i++) { /* sprintf will add a null-terminated character ('\0') at the end of the formatted string. So, do not need to memset the buffer.*/ sprintf(edidFileName, "%s/port%d_%s%s.bin", edidFilePath, ui_port, i ? "20" : "14", isDolbyVisionEnable ? "_dv" : ""); if (!isFileExist(edidFileName)) sprintf(edidFileName, "%s/port%d_%s%s.bin", edidFilePath, UI_HDMI_PORT_ID_1, i ? "20" : "14", isDolbyVisionEnable ? "_dv" : ""); ReadDataFromFile(edidFileName, 0, REAL_EDID_DATA_SIZE, edidLoadBuf + (2 * loadNum - 2 + i) * REAL_EDID_DATA_SIZE); LOGD("%s:File:%s\n", __FUNCTION__, edidFileName); } } int ret = mpHDMIRxManager->HdmiRxEdidDataSwitch(2 * K_PORT_NUM, edidLoadBuf); if (ret == 0) { ui_hdmi_port_id_t portId = UI_HDMI_PORT_ID_MAX; int edidSetValue = 0; int portEdidVersion = 0; for (int i=SOURCE_HDMI1;iTvin_GetUIHdmiPortIdBySourceInput((tv_source_input_t)i); portEdidVersion = GetEdidVersion((tv_source_input_t)i); edidSetValue |= (portEdidVersion << (4*portId - 4)); } LOGD("%s:[edidSetValue:0x%x]", __FUNCTION__, edidSetValue); //for HDMI feature(allm,vrr,qms) status init const char *buf = GetUenv(HDMI_UBOOT_EDID_FEATURE); int value = 0; int allmEnable = 0; int VrrEnable = 0; int QmsEnable = 0; if (buf) { value = atoi(buf); allmEnable = (value & 1); VrrEnable = ((value >> 1) & 1); QmsEnable = ((value >> 2) & 1); LOGD("%s init HDMI feature status allmEnable:%d, VrrEnable:%d, QmsEnable:%d.\n", __FUNCTION__, allmEnable, VrrEnable, QmsEnable); mpHDMIRxManager->SetHDMIFeatureInit(allmEnable, VrrEnable, QmsEnable); } else { allmEnable = mpHDMIRxManager->GetAllmEnabled(); VrrEnable = mpHDMIRxManager->GetVrrEnabled(); QmsEnable = mpHDMIRxManager->GetQmsEnabled(); value = ((QmsEnable << 2)|(VrrEnable << 1)|allmEnable); LOGD("%s HDMI feature uenv unexist, save it allmEnable:%d, VrrEnable:%d, QmsEnable:%d.\n", __FUNCTION__ , allmEnable, VrrEnable, QmsEnable); SetUenv(HDMI_UBOOT_EDID_FEATURE, std::to_string(value).c_str()); } LOGD("%s [UI sequence] edidSetValue:0x%x\n", __FUNCTION__, edidSetValue); ret = mpHDMIRxManager->HdmiRxEdidVerSwitch(edidSetValue); } else { LOGE("%s failed!\n", __FUNCTION__); } return ret; } int CTv::LoadEdidDataWithPort(int isNeedBlackScreen, int isDolbyVisionEnable) { int ret = 0; if (isNeedBlackScreen == 1) { mpTvin->Tvin_StopDecoder(); } char edidFileName[100] = {0}; int loadNum = 1; int i = 0; tvin_port_t tvin_port = TVIN_PORT_NULL; ui_hdmi_port_id_t ui_port = UI_HDMI_PORT_ID_MAX; tv_source_input_t source_input; const char *edidFilePath = ConfigGetStr(CFG_SECTION_HDMI, CFG_HDMI_EDID_FILE_PATH, "/vendor/etc/tvconfig/hdmi"); const char *subString = "21"; bool support21Edid = hasFileWithSubstring(edidFilePath, subString); LOGD("%s: isDolbyVisionEnable = [%d], support21Edid = [%d].\n", __FUNCTION__, isDolbyVisionEnable, support21Edid); char fileSuffix_14[32] = {0}; char fileSuffix_20[32] = {0}; char fileSuffix_21[32] = {0}; if (isDolbyVisionEnable) { strcat(fileSuffix_14, "_dv"); strcat(fileSuffix_20, "_dv"); } if (mDlgVisionEnableState) { strcat(fileSuffix_20, "_dlg"); } if (support21Edid) { strcpy(fileSuffix_21, fileSuffix_20); strcpy(fileSuffix_20, fileSuffix_14); } LOGD("%s: 1.4 edid suffix:[%s], 2.0 edid suffix:[%s], 2.1 edid suffix:[%s]\n", __FUNCTION__, fileSuffix_14, fileSuffix_20, fileSuffix_21); for (loadNum = (int)TVIN_PORT_ID_1; loadNum < (int)TVIN_PORT_ID_MAX; loadNum++) { tvin_port = mpTvin->Tvin_GetVdinPortByVdinPortID((tvin_port_id_t)loadNum); source_input = mpTvin->Tvin_PortToSourceInput(tvin_port); ui_port = mpTvin->Tvin_GetUIHdmiPortIdBySourceInput(source_input); LOGD("%s:tvin port ID:%d tvin_port:0x%x source_input:%d ui_port:%d\n", __FUNCTION__, loadNum, tvin_port, source_input, ui_port); char edidLoadBuf[3 * REAL_EDID_DATA_SIZE_MAX]; memset(edidLoadBuf, 0, sizeof(edidLoadBuf)); int edid_14_size = 0; int edid_20_size = 0; int edid_21_size = 0; // Load EDID 1.4 then load EDID 2.1 last 2.0 for (i = 0; i < 3; i++) { /* sprintf will add a null-terminated character ('\0') at the end of the formatted string. So, do not need to memset the buffer.*/ sprintf(edidFileName, "%s/port%d_%s%s.bin", edidFilePath, ui_port, i ? (i == 1 ? "21" : "20") : "14", i ? (i == 1 ? fileSuffix_21 : fileSuffix_20) : fileSuffix_14); if (!isFileExist(edidFileName)) { LOGD("%s: %s, file unexist\n", __FUNCTION__, edidFileName); if (i == 2 && support21Edid) { LOGD("%s: only load edid 1.4 & 2.1\n", __FUNCTION__); break; } sprintf(edidFileName, "%s/port%d_%s%s.bin", edidFilePath, ui_port, i ? "20" : "14", ""); } if (i == 0) { edid_14_size = GetFileSize(edidFileName); } else if (i == 1) { edid_21_size = GetFileSize(edidFileName); } else if (i == 2) { edid_20_size = GetFileSize(edidFileName); } ReadDataFromFile(edidFileName, 0, i? (i == 1 ? edid_21_size : edid_20_size) : edid_14_size, i? (i == 1 ? (edidLoadBuf + edid_14_size) : (edidLoadBuf + edid_14_size + edid_21_size)) : edidLoadBuf); LOGD("%s:File:%s\n", __FUNCTION__, edidFileName); } edidLoadBuf[edid_14_size +edid_21_size + edid_20_size] = '\0'; int type = mpHDMIRxManager->GetHdmiRxLoadEdidType(edid_14_size, edid_21_size, edid_20_size); mpHDMIRxManager->HdmiRxLoadEdidDataWithPort(loadNum, type, edid_14_size+edid_21_size+edid_20_size, (unsigned char*)edidLoadBuf); } if (mInitEdid) { tvin_port_id_t portId = TVIN_PORT_ID_MAX; int edidSetValue = 0; int portEdidVersion = 0; for (int i=SOURCE_HDMI1;iTvin_GetHdmiPortIdBySourceInput((tv_source_input_t)i); portEdidVersion = GetEdidVersion((tv_source_input_t)i); edidSetValue |= (portEdidVersion << (4*portId - 4)); } LOGD("%s:[edidSetValue:0x%x]", __FUNCTION__, edidSetValue); //for HDMI feature(allm,vrr,qms) status init const char *buf = GetUenv(HDMI_UBOOT_EDID_FEATURE); int value = 0; int allmEnable = 0; int VrrEnable = 0; int QmsEnable = 0; if (buf) { value = atoi(buf); allmEnable = (value & 1); VrrEnable = ((value >> 1) & 1); QmsEnable = ((value >> 2) & 1); LOGD("%s init HDMI feature status allmEnable:%d, VrrEnable:%d, QmsEnable:%d.\n", __FUNCTION__, allmEnable, VrrEnable, QmsEnable); mpHDMIRxManager->SetHDMIFeatureInit(allmEnable, VrrEnable, QmsEnable); } else { allmEnable = mpHDMIRxManager->GetAllmEnabled(); VrrEnable = mpHDMIRxManager->GetVrrEnabled(); QmsEnable = mpHDMIRxManager->GetQmsEnabled(); value = ((QmsEnable << 2)|(VrrEnable << 1)|allmEnable); LOGD("%s HDMI feature uenv unexist, save it allmEnable:%d, VrrEnable:%d, QmsEnable%d.\n", __FUNCTION__ , allmEnable, VrrEnable, QmsEnable); SetUenv(HDMI_UBOOT_EDID_FEATURE, std::to_string(value).c_str()); } LOGD("%s [UI sequence] edidSetValue:0x%x\n", __FUNCTION__, edidSetValue); ret = mpHDMIRxManager->HdmiRxEdidVerSwitch(edidSetValue); } mInitEdid = false; for (int i=TVIN_PORT_ID_1;iHdmiRxEdidUpdateWithPort(i); } return ret; } int CTv::SetEdidVersion(tv_source_input_t source, int edidVer) { LOGD("%s: setSource: %d, setVersion: %d\n", __FUNCTION__, source, edidVer); int ret = -1; int currentVersion = GetEdidVersion(source); if (currentVersion != edidVer) { mpTvin->Tvin_StopDecoder(); tvin_port_id_t portId = TVIN_PORT_ID_MAX; int edidSetValue = 0; //We have already set the port map to kernel.So we should use UI sequence. int portEdidVersion = 0; for (int i=SOURCE_HDMI1;iTvin_GetHdmiPortIdBySourceInput((tv_source_input_t)i); if (i == source) { portEdidVersion = edidVer; } else { portEdidVersion = GetEdidVersion((tv_source_input_t)i); } edidSetValue |= (portEdidVersion << (4*portId - 4)); } LOGD("%s [UI sequence] edidSetValue:0x%x\n", __FUNCTION__, edidSetValue); ret = mpHDMIRxManager->HdmiRxEdidVerSwitch(edidSetValue); if (mCurrentSource == source) { //mpHDMIRxManager->HDMIRxDeviceIOCtl(HDMI_IOC_EDID_UPDATE); tvin_port_id_t port = mpTvin->Tvin_GetHdmiPortIdBySourceInput(mCurrentSource); mpHDMIRxManager->HdmiRxEdidUpdateWithPort((int)port); } if (ret < 0) { LOGE("%s failed.\n", __FUNCTION__); ret = -1; } else { /* switch (source) { case SOURCE_HDMI1: Hdmi1CurrentEdidVer = edidVer; break; case SOURCE_HDMI2: Hdmi2CurrentEdidVer = edidVer; break; case SOURCE_HDMI3: Hdmi3CurrentEdidVer = edidVer; break; case SOURCE_HDMI4: Hdmi4CurrentEdidVer = edidVer; break; default: LOGD("%s: not hdmi source.\n", __FUNCTION__); break; } */ SetUenv(HDMI_UBOOT_EDID_VERSION, std::to_string(edidSetValue).c_str()); } } else { LOGD("%s: same EDID version, no need set.\n", __FUNCTION__); ret = 0; } return ret; } int CTv::GetEdidVersion(tv_source_input_t source) { //TODO:add user setting read/write flow int retValue = HDMI_EDID_VER_14; const char *buf = GetUenv(HDMI_UBOOT_EDID_VERSION); int version = 0; tvin_port_id_t port_id = TVIN_PORT_ID_MAX; if (buf) { version = atoi(buf); } port_id = mpTvin->Tvin_GetHdmiPortIdBySourceInput(source); switch (port_id) { case TVIN_PORT_ID_1: //retValue = Hdmi1CurrentEdidVer; retValue = version & 0xf; break; case TVIN_PORT_ID_2: //retValue = Hdmi2CurrentEdidVer; retValue = (version >> 4) & 0xf; break; case TVIN_PORT_ID_3: //retValue = Hdmi3CurrentEdidVer; retValue = (version >> 8) & 0xf; break; case TVIN_PORT_ID_4: //retValue = Hdmi4CurrentEdidVer; retValue = (version >> 12) & 0xf; break; default: LOGD("%s: not hdmi source.\n", __FUNCTION__); break; } return retValue; } int CTv::SetVdinWorkMode(vdin_work_mode_t vdinWorkMode) { mVdinWorkMode = vdinWorkMode; return 0; } int CTv::GetHdmiSPDInfo(tv_source_input_t source, char* data, size_t datalen) { if (mCurrentSource < SOURCE_HDMI1 || mCurrentSource > SOURCE_HDMI4) { LOGE("Current source is not HDMI input source.\n"); return -1; } if (source != mCurrentSource) { LOGE("%d is not current input source, skipped.\n", source); return -1; } int ret = -1; struct spd_infoframe_st spd; memset(&spd, 0, sizeof(spd)); ret = mpHDMIRxManager->HdmiRxGetSPDInfoframe(&spd); if (ret < 0) { LOGE("Get SPD infoframe from HDMIRX manager failed.\n"); } else { if (datalen > sizeof(spd)) { memcpy(data, &spd, sizeof(spd)); } else { memcpy(data, &spd, datalen); } } return ret; } int CTv::GetFrontendInfo(tvin_frontend_info_t *frontendInfo) { int ret = -1; if (frontendInfo == NULL) { LOGD("%s: param is NULL.\n", __FUNCTION__); } else { ret = mpTvin->Tvin_GetFrontendInfo(frontendInfo); /*LOGD("%s: scan mode:%d, colorfmt:%d, fps:%d, width:%d, height:%d, colordepth:%d.\n", __FUNCTION__, frontendInfo->scan_mode, frontendInfo->cfmt, frontendInfo->fps,frontendInfo->width,frontendInfo->height,frontendInfo->colordepth);*/ } if (ret < 0) { LOGE("%s failed.\n", __FUNCTION__); } else { LOGD("%s success.\n", __FUNCTION__); } return ret; } int CTv::SetCurrentSourceColorRange(tvin_color_range_t range_mode) { int ret = -1; if ((range_mode >= TVIN_COLOR_RANGE_MAX) || (range_mode Tvin_SetColorRangeMode(range_mode); } if (ret < 0) { LOGE("%s failed.\n", __FUNCTION__); } else { LOGD("%s success.\n", __FUNCTION__); } return ret; } tvin_color_range_t CTv::GetCurrentSourceColorRange() { int ret = mpTvin->Tvin_GetColorRangeMode(); LOGD("%s: mode is %d.\n", __FUNCTION__, ret); return (tvin_color_range_t)ret; } int CTv::GetSourceConnectStatus(tv_source_input_t source) { return mTvDevicesPollDetect.GetSourceConnectStatus(source); } int CTv::SetEdidBoostOn(int bBoostOn) { int ret = -1; if (mBoostOn == bBoostOn ) { LOGD("%s: same EDIDs are loaded for %d, no more action\n", __FUNCTION__, bBoostOn); return 0; } else { LOGD("%s: mBoostOn=%d to be switched to %d\n", __FUNCTION__, mBoostOn, bBoostOn); // pass flag for dynamic loading EDID data, switch data to kernel and switch version. mBoostOn = bBoostOn; ret = LoadEdidDataWithPort(0, mDolbyVisionEnableState); return ret; } } void CTv::onSigToStable() { LOGD("%s: mVdinWorkMode is %d\n", __FUNCTION__, mVdinWorkMode); mpTvin->Tvin_StartDecoder(mCurrentSignalInfo); #ifdef HAVE_AUDIO tv_source_input_type_t sourceType = mpTvin->Tvin_SourceInputToSourceInputType(mCurrentSource); LOGD("%s: mCurrent sourceType[%d], is_dvi[%d]\n", __FUNCTION__, sourceType, mCurrentSignalInfo.is_dvi); if (SOURCE_TYPE_HDMI == sourceType && mCurrentSignalInfo.is_dvi) { LOGD("%s: DVI signal, change audio to linein\n", __FUNCTION__); CTvAudio::getInstance()->release_audio_patch(TV_CHANNEL_MAIN); CTvAudio::getInstance()->create_audio_patch(TV_CHANNEL_MAIN, AUDIO_DEVICE_IN_LINE); } CTvAudio::getInstance()->set_audio_av_mute(false); #endif CMessage msg; msg.mDelayMs = std::chrono::milliseconds(0); msg.mType = CTvMsgQueue::TV_MSG_ENABLE_VIDEO_LATER; msg.mpPara[0] = 5; mTvMsgQueue->sendMsg ( msg ); //send signal to apk TvEvent::SignalDetectEvent event; event.mSourceInput = mCurrentSource; event.mFmt = mCurrentSignalInfo.fmt; event.mTrans_fmt = mCurrentSignalInfo.trans_fmt; event.mStatus = mCurrentSignalInfo.status; event.mDviFlag = mCurrentSignalInfo.is_dvi; event.mhdr_info = mCurrentSignalInfo.signal_type; sendTvEvent(event); tv_source_input_type_t source_type = mpTvin->Tvin_SourceInputToSourceInputType(mCurrentSource); if (source_type == SOURCE_TYPE_HDMI && true == GetHdmiQmsEnabled()) { sendQmsEvent(); } } void CTv::onSigToUnstable() { mpAmVideo->SetVideoLayerStatus(VIDEO_LAYER_STATUS_DISABLE); mpTvin->Tvin_StopDecoder(); #ifdef HAVE_AUDIO if (!(AvAudioMode && SOURCE_TYPE_AV == mCurrentSourceType)) CTvAudio::getInstance()->set_audio_av_mute(true); #endif LOGD("signal to Unstable!\n"); //To do } void CTv::onSigToUnSupport() { LOGD("%s\n", __FUNCTION__); mpAmVideo->SetVideoLayerStatus(VIDEO_LAYER_STATUS_DISABLE); mpTvin->Tvin_StopDecoder(); #ifdef HAVE_AUDIO if (!(AvAudioMode && SOURCE_TYPE_AV == mCurrentSourceType)) CTvAudio::getInstance()->set_audio_av_mute(true); #endif TvEvent::SignalDetectEvent event; event.mSourceInput = mCurrentSource; event.mFmt = mCurrentSignalInfo.fmt; event.mTrans_fmt = mCurrentSignalInfo.trans_fmt; event.mStatus = mCurrentSignalInfo.status; event.mDviFlag = mCurrentSignalInfo.is_dvi; event.mhdr_info = mCurrentSignalInfo.signal_type; sendTvEvent(event); //To do } void CTv::onSigToNoSig() { LOGD("%s\n", __FUNCTION__); if (needSnowEffect()) { SetSnowShowEnable(true); mpTvin->Tvin_StartDecoder(mCurrentSignalInfo); mpAmVideo->SetVideoLayerStatus(VIDEO_LAYER_STATUS_ENABLE); } else { LOGD("%s video layer has disabled \n", __FUNCTION__); mpAmVideo->SetVideoLayerStatus(VIDEO_LAYER_STATUS_DISABLE); mpTvin->Tvin_StopDecoder(); #ifdef HAVE_AUDIO if (!(AvAudioMode && SOURCE_TYPE_AV == mCurrentSourceType)) CTvAudio::getInstance()->set_audio_av_mute(true); #endif } TvEvent::SignalDetectEvent event; event.mSourceInput = mCurrentSource; event.mFmt = mCurrentSignalInfo.fmt; event.mTrans_fmt = mCurrentSignalInfo.trans_fmt; event.mStatus = mCurrentSignalInfo.status; event.mDviFlag = mCurrentSignalInfo.is_dvi; event.mhdr_info = mCurrentSignalInfo.signal_type; sendTvEvent (event); //To do } bool CTv::needSnowEffect() { bool isEnable = false; LOGD("%s: mCurrentSource = [%d].\n", __FUNCTION__,mCurrentSource); if ((SOURCE_TV == mCurrentSource) && mATVDisplaySnow ) { isEnable = true; LOGD("%s: ATV:snow display is enabled.\n", __FUNCTION__); } else { LOGD("%s: ATV:snow display is disabled.\n", __FUNCTION__); } return isEnable; } int CTv::SetSnowShowEnable(bool enable) { LOGD("%s: enable = [%d]\n", __FUNCTION__ , enable); if (enable) { mLastScreenMode = CVpp::getInstance()->getVideoScreenMode(); LOGD("%s: Get LastScreenMode = %d\n", __FUNCTION__, mLastScreenMode); CVpp::getInstance()->setVideoScreenMode(1);//while show snow,need show full screen } else { LOGD("%s: Set LastScreenMode = %d\n", __FUNCTION__, mLastScreenMode); CVpp::getInstance()->setVideoScreenMode(mLastScreenMode); } return mpTvin->Tvin_SwitchSnow(enable); } int CTv::sendTvEvent(CTvEvent &event) { LOGD("%s\n", __FUNCTION__); if (mpObserver != NULL) { mpObserver->onTvEvent(event); } else { LOGD("%s: Observer is NULL.\n", __FUNCTION__); } return 0; } #ifdef HAVE_AUDIO int CTv::mapSourcetoAudiotupe(tv_source_input_t dest_source) { int ret = -1; switch (dest_source) { case SOURCE_TV: ret = AUDIO_DEVICE_IN_TV_TUNER; break; case SOURCE_AV1: case SOURCE_AV2: ret = AUDIO_DEVICE_IN_LINE; break; case SOURCE_HDMI1: case SOURCE_HDMI2: case SOURCE_HDMI3: case SOURCE_HDMI4: ret = AUDIO_DEVICE_IN_HDMI; break; case SOURCE_SPDIF: ret = AUDIO_DEVICE_IN_SPDIF; break; default: ret = AUDIO_DEVICE_IN_LINE; break; } return ret; } #endif bool CTv::GetDolbyVisionSupportStatus(void) { //return dv support info from current platform device, not display device. char buf[1024+1] = {0}; int fd, len; bool ret = false; /*bit0: 0-> efuse, 1->no efuse; */ /*bit1: 1-> ko loaded*/ /*bit2: 1-> value updated*/ /*bit3: 1-> tv */ int supportInfo = 0; constexpr int dvDriverEnabled = (1 << 2); constexpr int dvSupported = ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3 )); if ((fd = open(SYS_DOLBYVISION_SUPPORT_INFO, O_RDONLY)) < 0) { LOGE("open %s fail.\n", SYS_DOLBYVISION_SUPPORT_INFO); return false; } else { if ((len = read(fd, buf, 1024)) < 0) { LOGE("read %s error: %s\n", SYS_DOLBYVISION_SUPPORT_INFO, strerror(errno)); ret = false; } else if (sscanf(buf, "%d", &supportInfo) == 1) { if ((supportInfo & dvDriverEnabled) == 0) { LOGD("%s is not ready\n",SYS_DOLBYVISION_SUPPORT_INFO); } ret = ((supportInfo & dvSupported) == dvSupported) ? true : false; } close(fd); return ret; } } int CTv::SetHdmiAllmEnabled(bool enable) { LOGD("%s: [%s]\n", __FUNCTION__, enable == 1?"enable":"disable"); const char *buf = GetUenv(HDMI_UBOOT_EDID_FEATURE); int saveValue = 0; if (buf) { saveValue = atoi(buf); if ((saveValue & 0x1) == enable) { LOGD("%s: same status return!\n", __FUNCTION__); return 0; } } muteVideoOnHDMISource(); saveValue = enable|(saveValue & ~0b1); SetUenv(HDMI_UBOOT_EDID_FEATURE, std::to_string(saveValue).c_str()); return mpHDMIRxManager->SetAllmEnabled(enable); } bool CTv::GetHdmiAllmEnabled() { bool ret = mpHDMIRxManager->GetAllmEnabled(); LOGD("%s: [%d]\n", __FUNCTION__, ret); return ret; } bool CTv::GetHdmiVrrSupport() { bool ret = false; ret = CVrr::getInstance()->GetVrrSupport(); return ret; } int CTv::SetHdmiVrrEnabled(bool enable) { LOGD("%s: [%s]\n", __FUNCTION__, enable == 1?"enable":"disable"); const char*buf = GetUenv(HDMI_UBOOT_EDID_FEATURE); int saveValue = 0; if (buf) { saveValue = atoi(buf); if ((saveValue >> 1) == enable) { LOGD("%s: same status return!\n", __FUNCTION__); return 0; } } muteVideoOnHDMISource(); saveValue = (enable << 1)|(saveValue & ~0b10); SetUenv(HDMI_UBOOT_EDID_FEATURE, std::to_string(saveValue).c_str()); return mpHDMIRxManager->SetVrrEnabled(enable); } bool CTv::GetHdmiVrrEnabled() { bool ret = mpHDMIRxManager->GetVrrEnabled(); LOGD("%s: [%d]\n", __FUNCTION__, ret); return ret; } bool CTv::GetHdmiQmsSupport() { int ret = 0; ret = ConfigGetInt(CFG_SECTION_HDMI, CFG_HDMI_QMS_SUPPORT, 0); LOGD("%s:%d !\n",__FUNCTION__, ret); return ret?true:false; } int CTv::SetHdmiQmsEnabled (bool enable) { int ret = -1; LOGD("%s: Set QMS enable = [%d]\n", __FUNCTION__, enable); const char*buf = GetUenv(HDMI_UBOOT_EDID_FEATURE); int saveValue = 0; if (buf) { saveValue = atoi(buf); if (((saveValue >> 2) & 1) == enable) { LOGD("%s: same status return!\n", __FUNCTION__); return 0; } } saveValue = (enable << 2)|(saveValue & ~0b100); SetUenv(HDMI_UBOOT_EDID_FEATURE, std::to_string(saveValue).c_str()); // RX request: //qms_func_ctrl only close qms, reopen qms need reload edid if (enable) { char buf[8] = {0}; sprintf(buf, "%d", enable); tvWriteSysfs(QMS_FUNC_CTRL_PATH, buf); bool dolbyVisionEnableState = GetDolbyVisionSupportStatus(); ret = LoadEdidDataWithPort(1, dolbyVisionEnableState); return ret; } else { return mpHDMIRxManager->SetQmsEnabled(enable); } } bool CTv::GetHdmiQmsEnabled(void) { int qmsEnable = 0; const char*buf = GetUenv(HDMI_UBOOT_EDID_FEATURE); int saveValue = 0; if (buf) { saveValue = atoi(buf); qmsEnable = ((saveValue >> 2) & 1); } LOGD("%s:QMS status [%d] !\n",__FUNCTION__,qmsEnable); return (bool)qmsEnable; } void CTv::sendQmsEvent(void) { LOGD("%s\n", __FUNCTION__); vdin_qms_param_t qmsInfo; memset(&qmsInfo, 0, sizeof(vdin_qms_param_t)); int ret = mpTvin->VDIN_GetQmsParm(&qmsInfo); if (ret < 0) { LOGD("%s: Get QMS Info error!\n", __FUNCTION__); } else { if ((int)qmsInfo.qms_en == 0) { LOGD("%s: non-qms signal,return!\n", __FUNCTION__); return; } LOGD("%s: send QMS change event, new fps:%d!\n", __FUNCTION__, qmsInfo.qms_fr); TvEvent::QMSEvent ev; ev.qms_en = (int)qmsInfo.qms_en; ev.qms_fps = (int)qmsInfo.qms_fr; ev.qms_base_fps = (int)qmsInfo.qms_base_fr; sendTvEvent ( ev ); } } int CTv::SetHdmiDlgEnabled(bool enable) { int ret = -1; if (GetHdmiDlgSupport()) { LOGD("%s:update DLG EDID status, new status = [%d]!\n",__FUNCTION__,enable); mDlgVisionEnableState = enable; bool dolbyVisionEnableState = GetDolbyVisionSupportStatus(); ret = LoadEdidDataWithPort(0, dolbyVisionEnableState); if ( 0 == ret ) { LOGD("%s:update DLG EDID status success!\n",__FUNCTION__); const char*buf = GetUenv(HDMI_UBOOT_EDID_FEATURE); int saveValue = 0; if (buf) { saveValue = atoi(buf); if (((saveValue >> 3) & 1) == enable) { LOGD("%s: same status return!\n", __FUNCTION__); return ret; } } saveValue = (enable << 3)|(saveValue & ~0b1000); SetUenv(HDMI_UBOOT_EDID_FEATURE, std::to_string(saveValue).c_str()); } else { LOGD("%s:update DLG EDID status fail!\n",__FUNCTION__); } }else { LOGE("%s:unsupport DLG func,return !\n",__FUNCTION__); } return ret; } bool CTv::GetHdmiDlgEnabled() { int dlgEnable = 0; const char*buf = GetUenv(HDMI_UBOOT_EDID_FEATURE); int saveValue = 0; if (buf) { saveValue = atoi(buf); dlgEnable = ((saveValue >> 3) & 1); } LOGD("%s:QMS status [%d] !\n",__FUNCTION__,dlgEnable); return (bool)dlgEnable; } bool CTv::GetHdmiDlgSupport() { bool ret = false; char buf[1024] = {0}; ret = tvReadSysfs(DLG_FUNC_PATH, buf); LOGD("%s: %s\n", __FUNCTION__, buf); if (ret < 0) { LOGD("%s: read /sys/class/display/cap error, return!\n",__FUNCTION__); return ret; } std::string parm = buf; //if 4k1k && 4k2k exist,support dlg std::string support4K1K = "3840x1080"; //The format of 4K2K includes the following variants std::string support4K2K_1 = "3840x2160"; std::string support4K2K_2 = "2160p60hz"; std::string support4K2K_3 = "4k2k60hz"; if ((parm.find(support4K1K) != -1) && ((parm.find(support4K2K_1) != -1) || (parm.find(support4K2K_2) != -1) || (parm.find(support4K2K_3) != -1))) { LOGD("%s: find exist!\n",__FUNCTION__); ret = true; }else{ LOGD("%s: unsupport DLG func,return!\n",__FUNCTION__); } return ret; } void CTv::muteVideoOnHDMISource() { if (mCurrentSource < SOURCE_HDMI1 || mCurrentSource > SOURCE_HDMI4) { return; } mpAmVideo->SetVideoLayerStatus(VIDEO_LAYER_STATUS_DISABLE); } int CTv::GetCurrentStdInfo (struct tvin_std_s *info) { int ret = 0; memset(info, 0 , sizeof(struct tvin_std_s)); info->source = mCurrentSource; info->edid_version = GetEdidVersion(mCurrentSource); info->allm_enabled = GetHdmiAllmEnabled(); info->vrr_enabled = GetHdmiVrrEnabled(); info->qms_enabled = GetHdmiQmsEnabled(); LOGD("%s: source:[%d], edid_version:[%d], allm:[%d], vrr:[%d], qms:[%d]",__FUNCTION__, info->source, info->edid_version, info->allm_enabled, info->vrr_enabled, info->qms_enabled); return ret; } void CTv::isVideoFrameAvailable(unsigned int u32NewFrameCount) { unsigned int u32TimeOutCount = 0; unsigned int frameCount = 0; while (true) { frameCount = (unsigned int)mpAmVideo->GetVideoFrameCount(); if (frameCount >= u32NewFrameCount) { LOGD("%s video available\n", __FUNCTION__); break; } else { if (u32TimeOutCount >= NEW_FRAME_TIME_OUT_COUNT) { LOGD("%s Not available frame\n", __FUNCTION__); break; } } LOGD("%s new frame count = %d, get time = %d\n",__FUNCTION__, frameCount, u32TimeOutCount); usleep(50*1000); u32TimeOutCount++; } mpAmVideo->SetVideoLayerStatus(VIDEO_LAYER_STATUS_ENABLE); mpAmVideo->SetVideoGlobalOutputMode(VIDEO_GLOBAL_OUTPUT_MODE_ENABLE); } int CTv::SetAudioDecoderId(int channel, int id) { #ifdef HAVE_AUDIO CTvAudio::getInstance()->set_audio_decoder_id(channel, id); #endif return 0; } int CTv::SetAvAudioModeEnabled (bool enable) { LOGD("%s endable = %s\n",__FUNCTION__, enable ? "enable":"disable"); AvAudioMode = enable; return 0; } bool CTv::IsSupportPIP() { bool ret = false; if (isFileExist("/dev/vdin2")) { LOGD("%s: support HDMI PIP\n",__FUNCTION__); ret = true; } else { LOGD("%s: unsupport HDMI PIP\n",__FUNCTION__); } return ret; } int CTv::SetCurrentPipSourceInfo(tvin_info_t sig_info) { mCurrentPipSignalInfo.trans_fmt = sig_info.trans_fmt; mCurrentPipSignalInfo.fmt = sig_info.fmt; mCurrentPipSignalInfo.status = sig_info.status; mCurrentPipSignalInfo.cfmt = sig_info.cfmt; mCurrentPipSignalInfo.signal_type= sig_info.signal_type; mCurrentPipSignalInfo.fps = sig_info.fps; mCurrentPipSignalInfo.is_dvi = sig_info.is_dvi; mCurrentPipSignalInfo.aspect_ratio = sig_info.aspect_ratio; return 0; } void CTv::setDisplayCrop(int source) { tvin_frontend_info_t frontendInfo; tv_rect crop; memset(&crop, 0, sizeof(tv_rect)); if (source == MAIN_WINDOW) { mpTvin->Tvin_GetFrontendInfo(&frontendInfo); crop.w = frontendInfo.width; crop.h = frontendInfo.height; mpTvMainDisplayadapter->TV_dispAdptSetLayerSourceCrop(crop); } else if (source == SUB_WINDOW && mpTvSubDisplayadapter != nullptr) { mpPipTvin->Tvin_GetFrontendInfo(&frontendInfo); crop.w = frontendInfo.width; crop.h = frontendInfo.height; mpTvSubDisplayadapter->TV_dispAdptSetLayerSourceCrop(crop); } } int CTv::StartTvInPIP ( tv_source_input_t source ) { if (nullptr == mpPipTvin) { LOGD("%s: unsupport PIP return!\n", __FUNCTION__); return 0; } LOGD("%s: source = %d!\n", __FUNCTION__, source); int ret = 0; mpTvWayland->setPipTunnelId(1); mpTvWayland->startPipVideo(); mpTvWayland->commitAll(); //sub source set 1, 3 as default mpTvMainDisplayadapter->TV_setDisplayadapterParam(1,3); mpTvMainDisplayadapter->TV_dispAdptCreateLayer(); //value limit in {0,64} and big than main mpTvMainDisplayadapter->TV_dispAdptSetLayerZorder(1); tvin_port_t source_port = mpPipTvin->Tvin_GetSourcePortBySourceInput(source); ret = mpPipTvin->Tvin_OpenPort(source_port); mCurrentPipSource = source; #ifdef HAVE_AUDIO int Audiotupe = mapSourcetoAudiotupe(source); if (Audiotupe == AUDIO_DEVICE_IN_HDMI) { Audiotupe = AUDIO_DEVICE_IN_HDMI1; } CTvAudio::getInstance()->create_audio_patch(TV_CHANNEL_SUB, Audiotupe); #endif return ret; } int CTv::StopTvInPIP ( tv_source_input_t source ) { if (nullptr == mpPipTvin) { LOGD("%s: unsupport PIP return!\n", __FUNCTION__); return 0; } LOGD("%s: source = %d!\n", __FUNCTION__, source); int ret = 0; #ifdef HAVE_AUDIO CTvAudio::getInstance()->release_audio_patch(TV_CHANNEL_SUB); #endif mpTvWayland->stopPipVideo(); if (mCurrentSource == SOURCE_INVALID) { mpTvWayland->shutdown(); } mpPipTvin->Tvin_StopDecoder(); tvin_port_t source_port = mpPipTvin->Tvin_GetSourcePortBySourceInput(source); mpPipTvin->Tvin_ClosePort(source_port); mCurrentPipSource = SOURCE_INVALID; tvin_info_t tempSignalInfo; tempSignalInfo.trans_fmt = TVIN_TFMT_2D; tempSignalInfo.fmt = TVIN_SIG_FMT_NULL; tempSignalInfo.status = TVIN_SIG_STATUS_NULL; tempSignalInfo.cfmt = TVIN_COLOR_FMT_MAX; tempSignalInfo.signal_type= 0; tempSignalInfo.fps = 60; tempSignalInfo.is_dvi = 0; tempSignalInfo.aspect_ratio = TVIN_ASPECT_NULL; SetCurrentPipSourceInfo(tempSignalInfo); return ret; } void CTv::onVdin2SignalChange() { if (mCurrentPipSource == SOURCE_INVALID) { LOGD("%s: none opened source,return!\n",__FUNCTION__); return; } vdin_event_info_s SignalEventInfo; memset(&SignalEventInfo, 0, sizeof(vdin_event_info_s)); int ret = mpPipTvin->Tvin_GetSignalEventInfo(&SignalEventInfo); if (ret < 0) { LOGD("%s: Get vidn event error!\n",__FUNCTION__); } else { tv_source_input_type_t source_type = mpPipTvin->Tvin_SourceInputToSourceInputType(mCurrentSource); tvin_sig_change_flag_t vdinEventType = (tvin_sig_change_flag_t)SignalEventInfo.event_sts; switch (vdinEventType) { case TVIN_SIG_CHG_STS: LOGD("%s: vdin2 signal status change!\n", __FUNCTION__); onPipSigStatusChange(); break; default: LOGD("%s: invalid vdin event!\n", __FUNCTION__); break; } } } void CTv::onPipSigStatusChange(void) { LOGD("%s\n", __FUNCTION__); tvin_info_s tempSignalInfo; int ret = mpPipTvin->Tvin_GetSignalInfo(&tempSignalInfo); if (ret < 0) { LOGD("%s: Get Signal Info error!\n",__FUNCTION__); return; } else { SetCurrentPipSourceInfo(tempSignalInfo); LOGD("sig_fmt is %d, status is %d, isDVI is %d, hdr_info is 0x%x\n", mCurrentPipSignalInfo.fmt, mCurrentPipSignalInfo.status, mCurrentPipSignalInfo.is_dvi, mCurrentPipSignalInfo.signal_type); if ( mCurrentPipSignalInfo.status == TVIN_SIG_STATUS_STABLE ) { setDisplayCrop(SUB_WINDOW); mpPipTvin->Tvin_StartDecoder(mCurrentPipSignalInfo); } else if (mCurrentPipSignalInfo.status == TVIN_SIG_STATUS_UNSTABLE ) { mpPipTvin->Tvin_StopDecoder(); } else if ( mCurrentPipSignalInfo.status == TVIN_SIG_STATUS_NOTSUP ) { mpPipTvin->Tvin_StopDecoder(); } else if ( mCurrentPipSignalInfo.status == TVIN_SIG_STATUS_NOSIG ) { mpPipTvin->Tvin_StopDecoder(); } else { LOGD("%s: invalid signal status!\n",__FUNCTION__); return; } // send PIP signal detect event to APK TvEvent::PipSignalDetectEvent pipEvent; pipEvent.mSourceInput = mCurrentPipSource; pipEvent.mFmt = mCurrentPipSignalInfo.fmt; pipEvent.mTrans_fmt = mCurrentPipSignalInfo.trans_fmt; pipEvent.mStatus = mCurrentPipSignalInfo.status; pipEvent.mDviFlag = mCurrentPipSignalInfo.is_dvi; pipEvent.mhdr_info = mCurrentPipSignalInfo.signal_type; sendTvEvent(pipEvent); return; } } CTv::CTvMsgQueue::CTvMsgQueue(CTv *tv) { mpTv = tv; } CTv::CTvMsgQueue::~CTvMsgQueue() { } void CTv::CTvMsgQueue::handleMessage ( CMessage &msg ) { LOGD ("%s, CTv::CTvMsgQueue::handleMessage type = %d\n", __FUNCTION__, msg.mType); switch ( msg.mType ) { case TV_MSG_ENABLE_VIDEO_LATER: { int fc = msg.mpPara[0]; mpTv->isVideoFrameAvailable(fc); break; } default: break; } }