海思3559SDK(版本Hi3559AV100_SDK_V2.0.3.0)只定义了以下HDMI输出格式:
typedef enum hiVO_INTF_SYNC_E
{
VO_OUTPUT_PAL = 0, /* PAL standard*/
VO_OUTPUT_NTSC, /* NTSC standard */
VO_OUTPUT_1080P24, /* 1920 x 1080 at 24 Hz. */
VO_OUTPUT_1080P25, /* 1920 x 1080 at 25 Hz. */
VO_OUTPUT_1080P30, /* 1920 x 1080 at 30 Hz. */
VO_OUTPUT_720P50, /* 1280 x 720 at 50 Hz. */
VO_OUTPUT_720P60, /* 1280 x 720 at 60 Hz. */
VO_OUTPUT_1080I50, /* 1920 x 1080 at 50 Hz, interlace. */
VO_OUTPUT_1080I60, /* 1920 x 1080 at 60 Hz, interlace. */
VO_OUTPUT_1080P50, /* 1920 x 1080 at 50 Hz. */
VO_OUTPUT_1080P60, /* 1920 x 1080 at 60 Hz. */
VO_OUTPUT_576P50, /* 720 x 576 at 50 Hz. */
VO_OUTPUT_480P60, /* 720 x 480 at 60 Hz. */
VO_OUTPUT_800x600_60, /* VESA 800 x 600 at 60 Hz (non-interlaced) */
VO_OUTPUT_1024x768_60, /* VESA 1024 x 768 at 60 Hz (non-interlaced) */
VO_OUTPUT_1280x1024_60, /* VESA 1280 x 1024 at 60 Hz (non-interlaced) */
VO_OUTPUT_1366x768_60, /* VESA 1366 x 768 at 60 Hz (non-interlaced) */
VO_OUTPUT_1440x900_60, /* VESA 1440 x 900 at 60 Hz (non-interlaced) CVT Compliant */
VO_OUTPUT_1280x800_60, /* 1280*800@60Hz VGA@60Hz*/
VO_OUTPUT_1600x1200_60, /* VESA 1600 x 1200 at 60 Hz (non-interlaced) */
VO_OUTPUT_1680x1050_60, /* VESA 1680 x 1050 at 60 Hz (non-interlaced) */
VO_OUTPUT_1920x1200_60, /* VESA 1920 x 1600 at 60 Hz (non-interlaced) CVT (Reduced Blanking)*/
VO_OUTPUT_640x480_60, /* VESA 640 x 480 at 60 Hz (non-interlaced) CVT */
VO_OUTPUT_960H_PAL, /* ITU-R BT.1302 960 x 576 at 50 Hz (interlaced)*/
VO_OUTPUT_960H_NTSC, /* ITU-R BT.1302 960 x 480 at 60 Hz (interlaced)*/
VO_OUTPUT_1920x2160_30, /* 1920x2160_30 */
VO_OUTPUT_2560x1440_30, /* 2560x1440_30 */
VO_OUTPUT_2560x1600_60, /* 2560x1600_60 */
VO_OUTPUT_3840x2160_24, /* 3840x2160_24 */
VO_OUTPUT_3840x2160_25, /* 3840x2160_25 */
VO_OUTPUT_3840x2160_30, /* 3840x2160_30 */
VO_OUTPUT_3840x2160_50, /* 3840x2160_50 */
VO_OUTPUT_3840x2160_60, /* 3840x2160_60 */
VO_OUTPUT_320x240_60, /* For ota5182 at 60 Hz (8bit) */
VO_OUTPUT_320x240_50, /* For ili9342 at 50 Hz (6bit) */
VO_OUTPUT_240x320_50, /* For ili9341 at 50 Hz (6bit) */
VO_OUTPUT_240x320_60, /* For ili9341 at 60 Hz (16bit) */
VO_OUTPUT_800x600_50, /* For LCD at 50 Hz (24bit) */
VO_OUTPUT_720x1280_60, /* For MIPI DSI Tx 720 x1280 at 60 Hz */
VO_OUTPUT_1080x1920_60, /* For MIPI DSI Tx 1080x1920 at 60 Hz */
VO_OUTPUT_7680x4320_30, /* For HDMI2.0 at 30 Hz */
VO_OUTPUT_USER, /* User timing. */
VO_OUTPUT_BUTT
} VO_INTF_SYNC_E;
下面以HDMI需要输出分辨率:1280x1024,帧率:30的视频格式为例讲解HDMI自定义输出格式设置流程。
用sample_vio.c中函数HI_S32 SAMPLE_VIO_8K30_PARALLEL(VO_INTF_TYPE_E enVoIntfType)为参考,将其修改成1280x1024@30格式输出。
该函数需要修改一下两个地方。
1、SAMPLE_COMM_VO_GetDefConfig函数功能是初始化输出参数,该函数修改成如下所示:
HI_S32 SAMPLE_COMM_VO_GetDefConfig(SAMPLE_VO_CONFIG_S *pstVoConfig)
{
RECT_S stDefDispRect = {0, 0, 1280, 1024}; //改为1280x1024
SIZE_S stDefImageSize = {1280, 1024};
if(NULL == pstVoConfig)
{
SAMPLE_PRT("Error:argument can not be NULL\n");
return HI_FAILURE;
}
pstVoConfig->VoDev = SAMPLE_VO_DEV_UHD;
pstVoConfig->enVoIntfType = VO_INTF_HDMI;
pstVoConfig->enIntfSync = VO_OUTPUT_USER; //改为自定义格式
pstVoConfig->u32BgColor = COLOR_RGB_BLUE;
pstVoConfig->enPixFormat = PIXEL_FORMAT_YVU_SEMIPLANAR_420;
pstVoConfig->stDispRect = stDefDispRect;
pstVoConfig->stImageSize = stDefImageSize;
pstVoConfig->enVoPartMode = VO_PART_MODE_SINGLE;
pstVoConfig->u32DisBufLen = 3;
pstVoConfig->enDstDynamicRange = DYNAMIC_RANGE_SDR8;
pstVoConfig->enVoMode = VO_MODE_1MUX;
return HI_SUCCESS;
}
2、将视频输出设置函数SAMPLE_COMM_VO_StartVO修改成如下所示:
HI_S32 SAMPLE_COMM_VO_StartVO(SAMPLE_VO_CONFIG_S *pstVoConfig)
{
RECT_S stDefDispRect = {0, 0, 1920, 1080};
SIZE_S stDefImageSize = {1920, 1080};
/*******************************************
* VO device VoDev# information declaration.
********************************************/
VO_DEV VoDev = 0;
VO_LAYER VoLayer = 0;
SAMPLE_VO_MODE_E enVoMode = 0;
VO_INTF_TYPE_E enVoIntfType = VO_INTF_HDMI;
VO_INTF_SYNC_E enIntfSync = VO_OUTPUT_1080P30;
DYNAMIC_RANGE_E enDstDyRg = DYNAMIC_RANGE_SDR8;
VO_PART_MODE_E enVoPartMode = VO_PART_MODE_SINGLE;
VO_PUB_ATTR_S stVoPubAttr = {0};
VO_VIDEO_LAYER_ATTR_S stLayerAttr = {0};
VO_CSC_S stVideoCSC = {0};
HI_S32 s32Ret = HI_SUCCESS;
if (NULL == pstVoConfig)
{
SAMPLE_PRT("Error:argument can not be NULL\n");
return HI_FAILURE;
}
VoDev = pstVoConfig->VoDev;
VoLayer = pstVoConfig->VoDev;
enVoMode = pstVoConfig->enVoMode;
enVoIntfType = pstVoConfig->enVoIntfType;
enIntfSync = pstVoConfig->enIntfSync;
enDstDyRg = pstVoConfig->enDstDynamicRange;
enVoPartMode = pstVoConfig->enVoPartMode;
/********************************
* Set and start VO device VoDev#.
*********************************/
stVoPubAttr.enIntfType = enVoIntfType;
stVoPubAttr.enIntfSync = enIntfSync;
stVoPubAttr.u32BgColor = pstVoConfig->u32BgColor;
/*
s32Ret = SAMPLE_COMM_VO_StartDev(VoDev, &stVoPubAttr);
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("SAMPLE_COMM_VO_StartDev failed!\n");
return s32Ret;
}*/
/*将上面注释部分替换成下面部分*/
/*设置视频输出设备公共属性参数,下面参数一般显示器厂家提供*/
//同步模式
stVoPubAttr.stSyncInfo.bSynm=1;
//0 为隔行,1 为逐行
stVoPubAttr.stSyncInfo.bIop=1;
//无效参数,可以忽略。
stVoPubAttr.stSyncInfo.u8Intfb =0;
//垂直效区,隔行输出时表示顶场垂直效区。单位:行。
stVoPubAttr.stSyncInfo.u16Vact =1024;
//垂直同步信号的宽度。单位:行
stVoPubAttr.stSyncInfo.u16Vpw=3;
//垂直消隐后肩,隔行输出时表示顶场垂直消隐后肩。单位:行。
stVoPubAttr.stSyncInfo.u16Vbb=38;
//垂直消隐前肩,隔行输出时表示顶场垂直消隐前肩。单位:行
stVoPubAttr.stSyncInfo.u16Vfb=1;
//水平效区。单位:像素
stVoPubAttr.stSyncInfo.u16Hact =1280;
//水平同步信号的宽度。单位:像素。
stVoPubAttr.stSyncInfo.u16Hpw=112;
//水平消隐后肩。单位:像素
stVoPubAttr.stSyncInfo.u16Hbb=248;
//水平消隐前肩。单位:像素
stVoPubAttr.stSyncInfo.u16Hfb=48;
//底场垂直效区,隔行时有效。单位:行
stVoPubAttr.stSyncInfo.u16Bvact=512;
//底场垂直同步效像素值
stVoPubAttr.stSyncInfo.u16Hmid =3;
//底场垂直消隐后肩,隔行时有效。单位:行
stVoPubAttr.stSyncInfo.u16Bvbb =38;
//底场垂直消隐前肩,隔行时有效。单位:行
stVoPubAttr.stSyncInfo.u16Bvfb =1;
//数据效信号的极性。配置 0 为高效,配置 1 为低效 。
stVoPubAttr.stSyncInfo.bIdv=0;
//水平效信号的极性,配置 0 为高效,配置 1 为低效。
stVoPubAttr.stSyncInfo.bIhs=0;
//垂直效信号的极性,配置 0 为高效,配置 1 为低效。
stVoPubAttr.stSyncInfo.bIvs=0;
s32Ret = HI_MPI_VO_SetPubAttr(VoDev, &stVoPubAttr);
if (s32Ret != HI_SUCCESS)
{
SAMPLE_PRT("failed with %#x!\n", s32Ret);
return HI_FAILURE;
}
/* Fill user sync info */
VO_USER_INTFSYNC_INFO_S stUserInfo = {0};
stUserInfo.stUserIntfSyncAttr.enClkSource = VO_CLK_SOURCE_PLL;
/*
u32Fbdiv、u32Frac、u32Refdiv 需满足:PLL 引脚 FOUTVCO 范围在[800, 3200],
FOUTVCO=FREF x (u32Fbdiv + u32Frac / 2^24) / u32Refdiv (FREF 值固定为 24)。
u32Postdiv1、u32Postdiv2 需满足 u32Postdiv1 >= u32Postdiv2。
所以:VO=FOUTVCO/(u32Postdiv1 u32Postdiv2)=FREF x (u32Fbdiv + u32Frac / 2^24) /
( u32Refdiv * u32Postdiv1 * u32Postdiv2)
像素时钟计算方法:
Htatal=hpw+hdisp+hfp+hbp
Vtatal=vpw+vdisp+vfp+vbp
pixel_clk = Htatal*Vtatal*fps (单位HZ,程序中采用KHZ)
VO=pixel_clk = 54M= FOUTVCO/(u32Postdiv1 u32Postdiv2)=FREF x (u32Fbdiv +
u32Frac / 2^24) /( u32Refdiv * u32Postdiv1 * u32Postdiv2)
54 = 24 x (u32Fbdiv + u32Frac / 2^24) /( u32Refdiv * u32Postdiv1 *u32Postdiv2)
可以设置PLL相关参数如下:
*/
stUserInfo.stUserIntfSyncAttr.stUserSyncPll.u32Fbdiv = 45;
stUserInfo.stUserIntfSyncAttr.stUserSyncPll.u32Frac = 0;
stUserInfo.stUserIntfSyncAttr.stUserSyncPll.u32Postdiv1 = 5;
stUserInfo.stUserIntfSyncAttr.stUserSyncPll.u32Postdiv2 = 4;
stUserInfo.stUserIntfSyncAttr.stUserSyncPll.u32Refdiv = 1;
stUserInfo.u32PreDiv = 0;// 设备前置分频
stUserInfo.u32DevDiv = 2;// 设备的时钟分频比
//时钟相位是否反向。 1:时钟反向; 0:时钟不反向。
stUserInfo.bClkReverse = 0;
/* Set user interface sync info */
s32Ret = HI_MPI_VO_SetUserIntfSyncInfo(VoDev, &stUserInfo);
if (s32Ret != HI_SUCCESS)
{
SAMPLE_PRT("Set user interface sync info failed with %x.\n",s32Ret);
return HI_FAILURE;
}
s32Ret = HI_MPI_VO_SetDevFrameRate(VoDev, 30);//taolang debug 帧率这里暂时设置为30
if (s32Ret != HI_SUCCESS)
{
SAMPLE_PRT("failed with %#x!\n", s32Ret);
return HI_FAILURE;
}
s32Ret = HI_MPI_VO_Enable(VoDev);
if (s32Ret != HI_SUCCESS)
{
SAMPLE_PRT("failed with %#x!\n", s32Ret);
return HI_FAILURE;
}
/******************************
* Set and start layer VoDev#.
********************************/
/*s32Ret = SAMPLE_COMM_VO_GetWH(stVoPubAttr.enIntfSync,
&stLayerAttr.stDispRect.u32Width,&stLayerAttr.stDispRect.u32Height,
&stLayerAttr.u32DispFrmRt);
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("SAMPLE_COMM_VO_GetWH failed!\n");
SAMPLE_COMM_VO_StopDev(VoDev);
return s32Ret;
}*/
/*将上面注释部分修改成,此处也可以直接修改SAMPLE_COMM_VO_GetWH */
stLayerAttr.stDispRect.u32Width = 1280;
stLayerAttr.stDispRect.u32Height = 1024;
stLayerAttr.u32DispFrmRt = 30;
stLayerAttr.bClusterMode = HI_FALSE;
stLayerAttr.bDoubleFrame = HI_FALSE;
stLayerAttr.enPixFormat = pstVoConfig->enPixFormat;
stLayerAttr.stDispRect.s32X = 0;
stLayerAttr.stDispRect.s32Y = 0;
/******************************
// Set display rectangle if changed.
********************************/
if (0 != memcmp(&pstVoConfig->stDispRect, &stDefDispRect, sizeof(RECT_S)))
{
stLayerAttr.stDispRect = pstVoConfig->stDispRect;
}
stLayerAttr.stImageSize.u32Width = stLayerAttr.stDispRect.u32Width;
stLayerAttr.stImageSize.u32Height = stLayerAttr.stDispRect.u32Height;
stLayerAttr.stImageSize.u32Width = stLayerAttr.stDispRect.u32Width;
stLayerAttr.stImageSize.u32Height = stLayerAttr.stDispRect.u32Height;
/******************************
//Set image size if changed.
********************************/
if (0 != memcmp(&pstVoConfig->stImageSize, &stDefImageSize, sizeof(SIZE_S)))
{
stLayerAttr.stImageSize = pstVoConfig->stImageSize;
}
stLayerAttr.enDstDynamicRange = pstVoConfig->enDstDynamicRange;
if (VO_PART_MODE_MULTI == enVoPartMode)
{
s32Ret = HI_MPI_VO_SetVideoLayerPartitionMode(VoLayer, enVoPartMode);
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("HI_MPI_VO_SetVideoLayerPartitionMode failed!\n");
SAMPLE_COMM_VO_StopDev(VoDev);
return s32Ret;
}
}
if (pstVoConfig->u32DisBufLen)
{
s32Ret = HI_MPI_VO_SetDisplayBufLen(VoLayer, pstVoConfig->u32DisBufLen);
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("HI_MPI_VO_SetDisplayBufLen failed with %#x!\n",s32Ret);
SAMPLE_COMM_VO_StopDev(VoDev);
return s32Ret;
}
}
s32Ret = SAMPLE_COMM_VO_StartLayer(VoLayer, &stLayerAttr);
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("SAMPLE_COMM_VO_Start video layer failed!\n");
SAMPLE_COMM_VO_StopDev(VoDev);
return s32Ret;
}
if(VO_INTF_MIPI == enVoIntfType)
{
s32Ret = HI_MPI_VO_GetVideoLayerCSC(VoLayer, &stVideoCSC);
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("HI_MPI_VO_GetVideoLayerCSC failed!\n");
SAMPLE_COMM_VO_StopDev(VoDev);
return s32Ret;
}
stVideoCSC.enCscMatrix =VO_CSC_MATRIX_BT709_TO_RGB_PC;
s32Ret = HI_MPI_VO_SetVideoLayerCSC(VoLayer, &stVideoCSC);
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("HI_MPI_VO_SetVideoLayerCSC failed!\n");
SAMPLE_COMM_VO_StopDev(VoDev);
return s32Ret;
}
}
/******************************
* start vo channels.
********************************/
s32Ret = SAMPLE_COMM_VO_StartChn(VoLayer, enVoMode);
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("SAMPLE_COMM_VO_StartChn failed!\n");
SAMPLE_COMM_VO_StopLayer(VoLayer);
SAMPLE_COMM_VO_StopDev(VoDev);
return s32Ret;
}
/******************************
* Start hdmi device.
* Note : do this after vo device started.
********************************/
if(VO_INTF_HDMI & enVoIntfType)
{
SAMPLE_COMM_VO_HdmiStartByDyRg(enIntfSync, enDstDyRg);
}
/******************************
* Start mipi_tx device.
* Note : do this after vo device started.
********************************/
if(VO_INTF_MIPI & enVoIntfType)
{
SAMPLE_COMM_VO_StartMipiTx(enIntfSync);
}
return HI_SUCCESS;
}
3、修改SAMPLE_COMM_VO_HdmiStartByDyRg->SAMPLE_COMM_VO_HdmiConvertSync
在SAMPLE_COMM_VO_HdmiConvertSync中针对VO_OUTPUT_USER类型返回HI_HDMI_VIDEO_FMT_VESA_CUSTOMER_DEFINE
海思SDK参考资料说明:
1、《HiMPP V4.0 媒体处理软件开发参考》
通过查阅SDK资料《HiMPP V4.0 媒体处理软件开发参考》中视频输出部分得知
HI_S32 HI_MPI_VO_SetDevFrameRate(VO_DEV VoDev, HI_U32 u32FrameRate);API可以设置输出帧率。该API调用说明如下:
2、《Hi3559AV100ES ultra-HD Mobile Camera SoC 用户指南》
PLL相关寄存器说明:
参考博客资料:
https://blog.csdn.net/weixin_46866980/article/details/111600265