海思mmp学习——tde
本文学习 sample_tde 历程,来提升 mmp 的理解。
TDE(Two Dimension Engine)功能函数参考提供 2D 加速相关操作。
一、释放资源
该函数主要用于程序在收到 SIGINT
(Ctrl+C)或 SIGTERM
(kill 命令) 时执行清理操作,防止资源泄露。
/******************************************************************************
* function : to process abnormal case
******************************************************************************/
void SAMPLE_TDE_HandleSig(HI_S32 signo)
{
if (SIGINT == signo || SIGTERM == signo)
{
/*释放映射的屏幕缓冲区*/
if (NULL != g_pu8Screen)
{
(HI_VOID)munmap(g_pu8Screen, g_u32Size);
g_pu8Screen = NULL;
}
/*释放背景缓冲区*/
if (NULL != g_pu8BackGroundVir)
{
HI_MPI_SYS_MmzFree(g_stBackGround.PhyAddr, g_pu8BackGroundVir);
g_pu8BackGroundVir = NULL;
}
/*关闭帧缓冲设备*/
if (g_s32Fd != -1)
{
close(g_s32Fd);
g_s32Fd = -1;
}
/*关闭 TDE 图像引擎*/
HI_TDE2_Close();
/*关闭 HDMI 输出*/
if (IntType & VO_INTF_HDMI)
{
SAMPLE_COMM_VO_HdmiStop();
}
/*禁用视频输出*/
HI_MPI_VO_Disable(VoDev);
/*释放系统资源*/
SAMPLE_COMM_SYS_Exit();
printf("\033[0;31mprogram termination abnormally!\033[0;39m\n");
}
exit(-1);
}
分析API
HI_MPI_SYS_MmzFree(g_stBackGround.PhyAddr, g_pu8BackGroundVir);
查阅 HiMPP V4.0 媒体处理软件开发参考.pdf ,2.系统控制章节。
要释放背景缓冲区,需要提供物理和虚拟地址。
HI_MPI_VO_Disable(VoDev);
查阅 HiMPP V4.0 媒体处理软件开发参考.pdf ,4.视频输出章节。
二、读取图像数据
从文件中读取图像数据,并填充 TDE2_SURFACE_S
结构体,以便后续的 TDE(图形加速引擎)处理。
static HI_S32 TDE_CreateSurfaceByFile(const HI_CHAR *pszFileName, TDE2_SURFACE_S *pstSurface, HI_U8 *pu8Virt)
{
FILE *fp;
HI_U32 colorfmt, w, h, stride;
HI_U64 packagelen;
/*参数检查,防止非法访问*/
if((NULL == pszFileName) || (NULL == pstSurface))
{
TDE_PRINT("%s, LINE %d, NULL ptr!\n", __FUNCTION__, __LINE__);
return -1;
}
/*打开文件*/
fp = fopen(pszFileName, "rb");
if(NULL == fp)
{
TDE_PRINT("error when open pszFileName %s, line:%d\n", pszFileName, __LINE__);
return -1;
}
/*读取图片的基本信息
* 颜色格式、宽度、高度、步长
*/
if (4 != fread(&colorfmt, 1, 4, fp))
{
TDE_PRINT("error when read pszFileName %s, line:%d\n", pszFileName, __LINE__);
fclose(fp);
return -1;
}
if (4 != fread(&w, 1, 4, fp))
{
TDE_PRINT("error when read pszFileName %s, line:%d\n", pszFileName, __LINE__);
fclose(fp);
return -1;
}
if (4 != fread(&h, 1, 4, fp))
{
TDE_PRINT("error when read pszFileName %s, line:%d\n", pszFileName, __LINE__);
fclose(fp);
return -1;
}
if (4 != fread(&stride, 1, 4, fp))
{
TDE_PRINT("error when read pszFileName %s, line:%d\n", pszFileName, __LINE__);
fclose(fp);
return -1;
}
/*填充位图结构体*/
pstSurface->enColorFmt = colorfmt;
pstSurface->u32Width = w;
pstSurface->u32Height = h;
pstSurface->u32Stride = stride;
pstSurface->u8Alpha0 = 0xff;
pstSurface->u8Alpha1 = 0xff;
pstSurface->bAlphaMax255 = HI_TRUE;
pstSurface->bAlphaExt1555 = HI_TRUE;
/*计算图像数据大小*/
packagelen = (HI_U64)stride * (HI_U64)h;
if ( packagelen > 0x7FFFFFFF)
{
TDE_PRINT("stride * h not valid: %d %d, line:%d\n", stride, h, __LINE__);
fclose(fp);
return -1;
}
//读取图像数据
fread(pu8Virt, 1, stride*h, fp);
fclose(fp);
return 0;
}
分析API
全局区域,定义了位图 surface 结构体3个变量:
static TDE2_SURFACE_S g_stScreen[2];
static TDE2_SURFACE_S g_stBackGround;
static TDE2_SURFACE_S g_stImgSur[N_IMAGES];
三、图像显示
static HI_VOID circumrotate (HI_U32 u32CurOnShow)
{
/*TDE 引擎的任务句柄。*/
TDE_HANDLE s32Handle;
/*TDE 操作选项,设置颜色键模式等。*/
TDE2_OPT_S stOpt = {0};
/*旋转中心点的坐标。*/
HI_FLOAT eXMid, eYMid;
/*旋转半径*/
HI_FLOAT eRadius;
HI_U32 i;
/*当前帧的进度,用于计算旋转角度*/
HI_FLOAT f;
/*下一个显示的图像缓冲区索引*/
HI_U32 u32NextOnShow;
/*源图像的矩形区域*/
TDE2_RECT_S stSrcRect;
/*目标屏幕上的矩形区域*/
TDE2_RECT_S stDstRect;
/*函数返回值,用于错误处理。*/
HI_S32 s32Ret = HI_SUCCESS;
/*切换到下一个屏幕缓冲区,u32CurOnShow 和 u32NextOnShow 是两个缓冲区的索引,通过位取反操作切换。*/
u32NextOnShow = !u32CurOnShow;
/*设置 TDE 操作选项,主要是颜色键模式和透明度处理。*/
stOpt.enOutAlphaFrom = TDE2_COLORKEY_MODE_FOREGROUND;
stOpt.unColorKeyValue.struCkARGB.stRed.u8CompMask = 0xff;
stOpt.unColorKeyValue.struCkARGB.stGreen.u8CompMask = 0xff;
stOpt.unColorKeyValue.struCkARGB.stBlue.u8CompMask = 0xff;
stOpt.enColorKeyMode = TDE2_COLORKEY_MODE_FOREGROUND;
stOpt.unColorKeyValue.struCkARGB.stAlpha.bCompIgnore = HI_TRUE;
//计算当前帧的进度 f,用于控制旋转动画的进度。
f = (float) (g_s32FrameNum % CYCLE_LEN) / CYCLE_LEN;
/*源图像*/
stSrcRect.s32Xpos = 0;
stSrcRect.s32Ypos = 0;
stSrcRect.u32Width = g_stBackGround.u32Width;
stSrcRect.u32Height = g_stBackGround.u32Height;
//旋转中心点
eXMid = g_stBackGround.u32Width/2.16f;
eYMid = g_stBackGround.u32Height/2.304f;
eRadius = MIN (eXMid, eYMid) / 2.0f;
/* 1. start job */
s32Handle = HI_TDE2_BeginJob();
if(HI_ERR_TDE_INVALID_HANDLE == s32Handle)
{
TDE_PRINT("start job failed!\n");
return ;
}
/* 2. bitblt background to screen */
s32Ret = HI_TDE2_QuickCopy(s32Handle, &g_stBackGround, &stSrcRect,
&g_stScreen[u32NextOnShow], &stSrcRect);
if(s32Ret < 0)
{
TDE_PRINT("Line:%d failed,ret=0x%x!\n", __LINE__, s32Ret);
HI_TDE2_CancelJob(s32Handle);
return ;
}
/*绘制旋转图像*/
for(i = 0; i < N_IMAGES; i++)
{
HI_FLOAT ang;
HI_FLOAT r;
stSrcRect.s32Xpos = 0;
stSrcRect.s32Ypos = 0;
stSrcRect.u32Width = g_stImgSur[i].u32Width;
stSrcRect.u32Height = g_stImgSur[i].u32Height;
/* 3. calculate new pisition */
/*计算旋转参数*/
ang = 2.0f * (HI_FLOAT) M_PI * (HI_FLOAT) i / N_IMAGES - f * 2.0f * (HI_FLOAT) M_PI;
r = eRadius + (eRadius / 3.0f) * sinf (f * 2.0 * M_PI);
/*计算目标位置*/
stDstRect.s32Xpos = eXMid + r * cosf (ang) - g_stImgSur[i].u32Width / 2.0f;;
stDstRect.s32Ypos = eYMid + r * sinf (ang) - g_stImgSur[i].u32Height / 2.0f;
stDstRect.u32Width = g_stImgSur[i].u32Width;
stDstRect.u32Height = g_stImgSur[i].u32Height;
/* 4. bitblt image to screen */
s32Ret = HI_TDE2_Bitblit(s32Handle, &g_stScreen[u32NextOnShow], &stDstRect,
&g_stImgSur[i], &stSrcRect, &g_stScreen[u32NextOnShow], &stDstRect, &stOpt);
if(s32Ret < 0)
{
TDE_PRINT("Line:%d,HI_TDE2_Bitblit failed,ret=0x%x!\n", __LINE__, s32Ret);
HI_TDE2_CancelJob(s32Handle);
return ;
}
}
/* 5. submit job */
s32Ret = HI_TDE2_EndJob(s32Handle, HI_FALSE, HI_TRUE, 1000);
if(s32Ret < 0)
{
TDE_PRINT("Line:%d,HI_TDE2_EndJob failed,ret=0x%x!\n", __LINE__, s32Ret);
HI_TDE2_CancelJob(s32Handle);
return ;
}
g_s32FrameNum++;
return;
}
分析API
TDE2_OPT_S stOpt = {0};
/*设置 TDE 操作选项,主要是颜色键模式和透明度处理。*/
stOpt.enOutAlphaFrom = TDE2_COLORKEY_MODE_FOREGROUND;
stOpt.unColorKeyValue.struCkARGB.stRed.u8CompMask = 0xff;
stOpt.unColorKeyValue.struCkARGB.stGreen.u8CompMask = 0xff;
stOpt.unColorKeyValue.struCkARGB.stBlue.u8CompMask = 0xff;
stOpt.enColorKeyMode = TDE2_COLORKEY_MODE_FOREGROUND;
stOpt.unColorKeyValue.struCkARGB.stAlpha.bCompIgnore = HI_TRUE;
/*源图像的矩形区域*/
TDE2_RECT_S stSrcRect;
/*目标屏幕上的矩形区域*/
TDE2_RECT_S stDstRect;
/*源图像*/
stSrcRect.s32Xpos = 0;
stSrcRect.s32Ypos = 0;
stSrcRect.u32Width = g_stBackGround.u32Width;
stSrcRect.u32Height = g_stBackGround.u32Height;
/* 1. start job */
s32Handle = HI_TDE2_BeginJob();
if(HI_ERR_TDE_INVALID_HANDLE == s32Handle)
{
TDE_PRINT("start job failed!\n");
return ;
}
/* 2. bitblt background to screen */
s32Ret = HI_TDE2_QuickCopy(s32Handle, &g_stBackGround, &stSrcRect,
&g_stScreen[u32NextOnShow], &stSrcRect);
if(s32Ret < 0)
{
TDE_PRINT("Line:%d failed,ret=0x%x!\n", __LINE__, s32Ret);
HI_TDE2_CancelJob(s32Handle);
return ;
}
/* 4. bitblt image to screen */
s32Ret = HI_TDE2_Bitblit(s32Handle, &g_stScreen[u32NextOnShow], &stDstRect,
&g_stImgSur[i], &stSrcRect, &g_stScreen[u32NextOnShow], &stDstRect, &stOpt);
if(s32Ret < 0)
{
TDE_PRINT("Line:%d,HI_TDE2_Bitblit failed,ret=0x%x!\n", __LINE__, s32Ret);
HI_TDE2_CancelJob(s32Handle);
return ;
}
/* 5. submit job */
s32Ret = HI_TDE2_EndJob(s32Handle, HI_FALSE, HI_TRUE, 1000);
if(s32Ret < 0)
{
TDE_PRINT("Line:%d,HI_TDE2_EndJob failed,ret=0x%x!\n", __LINE__, s32Ret);
HI_TDE2_CancelJob(s32Handle);
return ;
}
四、绘图
1. 操作缓冲区
HI_S32 TDE_DrawGraphicSample()
{
HI_U32 u32Times;
HI_U32 u32PhyAddr;
HI_S32 s32Ret = -1;
HI_U32 i = 0;
HI_BOOL bShow;
HIFB_ALPHA_S stAlpha = {0};
/* 1. open tde device */
s32Ret = HI_TDE2_Open();
if (HI_SUCCESS != s32Ret)
{
TDE_PRINT("HI_TDE2_Open failed:0x%x\n", s32Ret);
return s32Ret;
}
/* 2. framebuffer operation */
g_s32Fd = open("/dev/fb0", O_RDWR);
if (g_s32Fd < 0)
{
TDE_PRINT("open frame buffer device error\n");
goto FB_OPEN_ERROR;
}
/*配置帧缓冲区的 Alpha 属性*/
stAlpha.bAlphaChannel = HI_FALSE;
stAlpha.bAlphaEnable = HI_FALSE;
if (ioctl(g_s32Fd, FBIOPUT_ALPHA_HIFB, &stAlpha) < 0)
{
TDE_PRINT("Put alpha info failed!\n");
goto FB_PROCESS_ERROR0;
}
struct hifb_info info;
/*获取帧缓冲区的固定信息*/
if (ioctl(g_s32Fd, FBIOGET_SCREENINFO_HIFB, &info) < 0)
{
SAMPLE_PRT("FBIOGET_SCREENINFO_HIFB failed!\n");
close(g_s32Fd);
return HI_NULL;
}
/*配置屏幕的分辨率和颜色格式*/
info.vinfo.xres = SCREEN_WIDTH;
info.vinfo.yres = SCREEN_HEIGHT;
info.oinfo.sarea.w = SCREEN_WIDTH;
info.oinfo.sarea.h = SCREEN_HEIGHT;
info.oinfo.bpp = 16;
info.activate = 0;
info.vinfo.fmt = HIFB_FMT_ARGB1555;
/*应用屏幕的可变信息*/
if (ioctl(g_s32Fd, FBIOPUT_SCREENINFO_HIFB, &info) < 0)
{
TDE_PRINT("Put variable screen info failed!\n");
goto FB_PROCESS_ERROR0;
}
if (ioctl(g_s32Fd, FBIOGET_SCREENINFO_HIFB, &info) < 0)
{
TDE_PRINT("Get fix screen info failed!\n");
goto FB_PROCESS_ERROR0;
}
/*获取帧缓冲区的内存地址和大小*/
g_u32Size = info.oinfo.fblen;
u32PhyAddr = (HI_U32)info.oinfo.fbmem;
g_pu8Screen = (HI_U8*)(info.oinfo.fbmem);;
/*清空帧缓冲区*/
memset_s(g_pu8Screen, g_u32Size, 0x00, g_u32Size);
/*获取屏幕的步幅*/
g_stScreen[0].u32Stride = info.oinfo.stride;
2.1 API分析
ioctl 的 cmd 的参数命令:
cmddata 参数:
对于下面这段代码,FBIOGET_VSCREENINFO对应struct fb_var_screeninfo *类型,给其成员进行了赋值,其中有屏幕分辨率和虚拟分辨率,偏移,时钟,颜色等。
if (ioctl(g_s32Fd, FBIOGET_VSCREENINFO, &stVarInfo) < 0)
{
TDE_PRINT("Get variable screen info failed!\n");
goto FB_PROCESS_ERROR0;
}
stVarInfo.xres_virtual = SCREEN_WIDTH;
stVarInfo.yres_virtual = SCREEN_HEIGHT*2;
stVarInfo.xres = SCREEN_WIDTH;
stVarInfo.yres = SCREEN_HEIGHT;
stVarInfo.activate = FB_ACTIVATE_NOW;
stVarInfo.bits_per_pixel = 16;
stVarInfo.xoffset = 0;
stVarInfo.yoffset = 0;
stVarInfo.red = stR32;
stVarInfo.green = stG32;
stVarInfo.blue = stB32;
stVarInfo.transp = stA32;
2. 创建图形表面
/* 3. create surface */
/*创建屏幕表面*/
g_stScreen[0].enColorFmt = PIXFMT;
g_stScreen[0].PhyAddr = u32PhyAddr;
g_stScreen[0].u32Width = SCREEN_WIDTH;
g_stScreen[0].u32Height = SCREEN_HEIGHT;
g_stScreen[0].bAlphaMax255 = HI_TRUE;
g_stScreen[1] = g_stScreen[0];
g_stScreen[1].PhyAddr = g_stScreen[0].PhyAddr + (HI_U64)g_stScreen[0].u32Stride * (HI_U64)g_stScreen[0].u32Height;
/* allocate memory (720*576*2*N_IMAGES bytes) to save Images' infornation */
if (HI_FAILURE == HI_MPI_SYS_MmzAlloc(&(g_stBackGround.PhyAddr), ((void**)&g_pu8BackGroundVir),
NULL, NULL, 720*576*2*N_IMAGES))
{
TDE_PRINT("allocate memory (720*576*2*N_IMAGES bytes) failed\n");
goto FB_PROCESS_ERROR1;
}
TDE_CreateSurfaceByFile(BACKGROUND_NAME, &g_stBackGround, g_pu8BackGroundVir);
/*创建子图像表面*/
g_stImgSur[0].PhyAddr = g_stBackGround.PhyAddr + (HI_U64)g_stBackGround.u32Stride * (HI_U64)g_stBackGround.u32Height;
for(i = 0; i < N_IMAGES - 1; i++)
{
TDE_CreateSurfaceByFile(pszImageNames[i], &g_stImgSur[i],
g_pu8BackGroundVir + ((HI_U32)g_stImgSur[i].PhyAddr - g_stBackGround.PhyAddr));
g_stImgSur[i+1].PhyAddr = g_stImgSur[i].PhyAddr + (HI_U64)g_stImgSur[i].u32Stride * (HI_U64)g_stImgSur[i].u32Height;
}
TDE_CreateSurfaceByFile(pszImageNames[i], &g_stImgSur[i],
g_pu8BackGroundVir + ((HI_U32)g_stImgSur[i].PhyAddr - g_stBackGround.PhyAddr));
/*显示帧缓冲区*/
bShow = HI_TRUE;
if (ioctl(g_s32Fd, FBIOPUT_SHOW_HIFB, &bShow) < 0)
{
fprintf (stderr, "Couldn't show fb\n");
goto FB_PROCESS_ERROR2;
}
/*初始化帧计数器*/
g_s32FrameNum = 0;
/* 3. use tde and framebuffer to realize rotational effect */
/*实现旋转*/
for (u32Times = 0; u32Times < 20; u32Times++)
{
circumrotate(u32Times%2);
info.oinfo.sarea.y = (u32Times%2)?0:576;
/*set frame buffer start position*/
/*更新帧缓冲区的显示位置*/
if (ioctl(g_s32Fd, FBIOPAN_DISPLAY_HIFB, &info.oinfo) < 0)
{
TDE_PRINT("FBIOPAN_DISPLAY error\n");
goto FB_PROCESS_ERROR2;
}
sleep(1);
}
五、启动设备、运行示例
HI_S32 sample_circumrotate(HI_VOID)
{
/*视频输出设备(VO)的配置结构体,用于存储 VO 的初始化参数。*/
SAMPLE_VO_CONFIG_S vo_config = {0};
/*显存池(Video Buffer)的配置结构体,用于初始化显存池。*/
VB_CONFIG_S vb_conf = {0};
HI_S32 ret = 0;
/*1 enable Vo device HD first*/
/*初始化显存池*/
vb_conf.u32MaxPoolCnt = 16;
ret = SAMPLE_COMM_SYS_Init(&vb_conf);
if (ret != HI_SUCCESS) {
SAMPLE_PRT("SAMPLE_COMM_SYS_Init failed with %d!\n", ret);
return -1;
}
/*获取默认的 VO 配置*/
ret = SAMPLE_COMM_VO_GetDefConfig(&vo_config);
if (ret != HI_SUCCESS) {
SAMPLE_PRT("SAMPLE_COMM_VO_GetDefConfig failed with %d!\n", ret);
return -1;
}
/*启动视频输出设备(VO)*/
ret = SAMPLE_COMM_VO_StartVO(&vo_config);
if (ret != HI_SUCCESS) {
SAMPLE_PRT("SAMPLE_COMM_VO_StartVO failed with %d!\n", ret);
goto ERR0;
}
/*2 run tde sample which draw grahpic on HiFB memory*/
/*运行 TDE 图形绘制示例*/
ret = TDE_DrawGraphicSample();
if (ret != HI_SUCCESS) {
goto ERR1;
}
ERR1:
SAMPLE_COMM_VO_StopVO(&vo_config);
ERR0:
SAMPLE_COMM_SYS_Exit();
return ret;
}
六、主函数
#ifdef __HuaweiLite__
#define SAMPLE_HIFB_NAME "sample"
int app_main(int argc, char *argv[])
#else
int main(int argc, char *argv[])
#endif
{
HI_S32 ret = 0;
#ifdef __HuaweiLite__
#else
signal(SIGINT, SAMPLE_TDE_HandleSig);
signal(SIGTERM, SAMPLE_TDE_HandleSig);
#endif
if (argc != 2) {
sample_usage1(argv[0]);
return HI_FAILURE;
}
if ((*argv[1] != '0') || (strlen(argv[1]) != 1)) {
SAMPLE_PRT("index invaild!only support index 0, please try again.\n");
sample_usage1(argv[0]);
return HI_FAILURE;
}
if (!strncmp(argv[1], "-h", 2)) {
sample_usage1(argv[0]);
return HI_SUCCESS;
}
SAMPLE_PRT("\nindex 0 selected.\n");
ret = sample_circumrotate();
if (ret == HI_SUCCESS) {
SAMPLE_PRT("program exit normally!\n");
} else {
SAMPLE_PRT("program exit abnormally!\n");
}
return ret;
}
七、提供选项
static inline HI_VOID sample_usage2(HI_VOID)
{
SAMPLE_PRT("\n\n/****************index******************/\n");
SAMPLE_PRT("please choose the case which you want to run:\n");
SAMPLE_PRT("\t0: circumrotate \n");
return;
}
static inline HI_VOID sample_usage1(HI_CHAR* argv)
{
SAMPLE_PRT("Usage : %s <index>\n", argv);
sample_usage2();
return;
}