Files
BPI-CM9-Linux/aml-comp/vendor/amlogic/aml_tvserver/libtv/CTv.cpp
T
2026-08-24 10:03:24 +08:00

1682 lines
55 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 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 <stdint.h>
#include <string.h>
#include "CTv.h"
#include "tvutils.h"
#include "TvConfigManager.h"
#include "CTvLog.h"
#include "CVpp.h"
#include <sys/ioctl.h>
#include <chrono>
#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<int>(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;i<SOURCE_VGA;i++) {
portId = mpTvin->Tvin_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;i<SOURCE_VGA;i++) {
portId = mpTvin->Tvin_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;i<TVIN_PORT_ID_MAX;i++) {
mpHDMIRxManager->HdmiRxEdidUpdateWithPort(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;i<SOURCE_VGA;i++) {
portId = mpTvin->Tvin_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_COLOR_RANGE_AUTO)) {
LOGD("%s: invalid range mode.\n", __FUNCTION__);
} else {
ret = mpTvin->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;
}
}