hi3519叠加OSD

编译环境:Ubuntu16.04 64位
交叉编译工具:arm-hisiv500-linux-gcc

最近需要在hi3519为图像叠加osd信息,目前已完成,这里做个总结。

1. 交叉编译freetype

下载合适版本的freetype源码,我这里使用的是freetype-2.9.1.tar.gz,网上介绍交叉编译freetype的资料有很多,不多说。

1.1 裁剪

修改modules.cfg,去掉不需要的功能,最后保留如下选项:

FONT_MODULES += truetype
FONT_MODULES += sfnt
RASTER_MODULES += raster
AUX_MODULES += gzip
AUX_MODULES += psnames
BASE_EXTENSIONS += ftbitmap.c
BASE_EXTENSIONS += ftglyph.c
BASE_EXTENSIONS += ftstroke.c

1.2 配置编译

./configure CC=arm-hisiv500-linux-gcc --host=arm-hisiv500-linux --prefix=/home/jerry/work/freetype-2.9.1/freetype.install --with-zlib=no --with-png=no
make
make install

1.3 目标文件

如下:

jerry@ubuntu:~/work/freetype-2.9.1/freetype.install$ tree
.
├── include
│   └── freetype2
│       ├── freetype
│       │   ├── config
│       │   │   ├── ftconfig.h
│       │   │   ├── ftheader.h
│       │   │   ├── ftmodule.h
│       │   │   ├── ftoption.h
│       │   │   └── ftstdlib.h
│       │   ├── freetype.h
│       │   ├── ftadvanc.h
│       │   ├── ftbbox.h
│       │   ├── ftbdf.h
│       │   ├── ftbitmap.h
│       │   ├── ftbzip2.h
│       │   ├── ftcache.h
│       │   ├── ftchapters.h
│       │   ├── ftcid.h
│       │   ├── ftdriver.h
│       │   ├── fterrdef.h
│       │   ├── fterrors.h
│       │   ├── ftfntfmt.h
│       │   ├── ftgasp.h
│       │   ├── ftglyph.h
│       │   ├── ftgxval.h
│       │   ├── ftgzip.h
│       │   ├── ftimage.h
│       │   ├── ftincrem.h
│       │   ├── ftlcdfil.h
│       │   ├── ftlist.h
│       │   ├── ftlzw.h
│       │   ├── ftmac.h
│       │   ├── ftmm.h
│       │   ├── ftmodapi.h
│       │   ├── ftmoderr.h
│       │   ├── ftotval.h
│       │   ├── ftoutln.h
│       │   ├── ftparams.h
│       │   ├── ftpfr.h
│       │   ├── ftrender.h
│       │   ├── ftsizes.h
│       │   ├── ftsnames.h
│       │   ├── ftstroke.h
│       │   ├── ftsynth.h
│       │   ├── ftsystem.h
│       │   ├── fttrigon.h
│       │   ├── fttypes.h
│       │   ├── ftwinfnt.h
│       │   ├── t1tables.h
│       │   ├── ttnameid.h
│       │   ├── tttables.h
│       │   └── tttags.h
│       └── ft2build.h
├── lib
│   ├── libfreetype.a
│   ├── libfreetype.la
│   ├── libfreetype.so -> libfreetype.so.6.16.1
│   ├── libfreetype.so.6 -> libfreetype.so.6.16.1
│   ├── libfreetype.so.6.16.1
│   └── pkgconfig
│       └── freetype2.pc
└── share
    └── aclocal
        └── freetype2.m4

8 directories, 56 files

libfreetype.a和include/freetype2/目录下的头文件就是我们需要的。

2. freetype的封装

需要提供读取ttf字库,设置字体大小,C字符串转位图的功能。

2.1 头文件

#ifndef __AF_FONT_H__
#define __AF_FONT_H__

int AF_FT_Init();
int AF_FT_Exit();

int AF_FT_SetSize(unsigned int nSize);
int AF_FT_GetSize();

int AF_FT_StringConvert(const char *str, unsigned int nWidth, unsigned int nHeight, unsigned short usColor, unsigned char *pBuf);

#endif

2.2 代码部分

#include <stdbool.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include "aflog.h"
#include "affont.h"

//#define SUPPORT_ARBIC
// 注:ToArabic部分代码已注掉,这里不提供源码。

#define FONT_PATH "/config/arial.ttf"

static FT_Library g_lib = NULL;
static FT_Face g_face = NULL;
static unsigned int g_size = 0;// 16 22 28

static bool g_Init = false;
static pthread_mutex_t g_FontMutex;

我使用的是从windows拷贝的arial.ttf字库,通过FontCreator工具进行裁剪,也可以不做裁剪直接使用,需要注意复制粘贴的过程中一定不要遗漏Unicode码,这里不做详细描述,网上可以找到资料。
注意:这里头文件的包含一定要注意!!!

2.2.1 初始化
int AF_FT_Init()
{
	if (g_Init)
		return 0;
	
	if (pthread_mutex_init(&g_FontMutex, NULL) != 0)
		return -1;
		
	pthread_mutex_lock(&g_FontMutex);
	g_Init = true;	
		
	if (g_lib != NULL)
	{
		FT_Done_FreeType(g_lib);
		g_lib = NULL;
		g_face = NULL;
	}

	int nRet = FT_Init_FreeType(&g_lib);
	if (nRet != 0)
	{
		AFERR("FT_Init_FreeType failed nRet = %d\n", nRet);
		pthread_mutex_unlock(&g_FontMutex);
		return -1;
	}

	nRet = FT_New_Face(g_lib, FONT_PATH, 0, &g_face);
	if (nRet != 0)
	{
		AFERR("FT_New_Face failed nRet = %d\n", nRet);
		FT_Done_FreeType(g_lib);
		g_lib = NULL;
		pthread_mutex_unlock(&g_FontMutex);
		return -1;
	}

	AF_FT_SetFontSize(22, NULL, NULL, NULL);// 16 22 28
	pthread_mutex_unlock(&g_FontMutex);

	return 0;
}

2.2.2 去初始化
int AF_FT_Exit()
{
	pthread_mutex_lock(&g_FontMutex);
   	if (g_lib != NULL)
	{
		FT_Done_FreeType(g_lib);
		g_lib = NULL;
		g_face = NULL;
	}
	g_Init = false;
	pthread_mutex_unlock(&g_FontMutex);

	pthread_mutex_destroy(&g_FontMutex);
    return 0;
}

2.2.3 设置和获取字体大小
static int AF_FT_SetFontSize(unsigned int nSize, unsigned int *nLineNum, unsigned int *nLineBase, unsigned int *nPixelMax)
{
	if (g_face == NULL)
		return -1;
		
	if (nSize < 16)
		nSize = 16;
	if (nSize > 28)
		nSize = 28;

	int nRet = 0;
	if (nSize != g_size)
	{
		nRet = FT_Set_Pixel_Sizes(g_face, 0, nSize);// 设置成nSize*nSize像素
		if (nRet != 0)
		{
			AFERR("FT_Set_Pixel_Sizes nSize(%d) failed nRet = %d\n", nSize, nRet);
		}
		g_size = nSize;
	}
	FT_Size size = g_face->size;
	if (nLineNum != NULL)
		*nLineNum = (unsigned int)(size->metrics.height >> 6);
	if (nLineBase != NULL)
		*nLineBase = (unsigned int)((size->metrics.height >> 6) + (size->metrics.descender >> 6) - 1);
   	if (nPixelMax != NULL)
        *nPixelMax = (unsigned int)(size->metrics.max_advance >> 6);

	return 0;
}

int AF_FT_SetSize(unsigned int nSize)
{
	pthread_mutex_lock(&g_FontMutex);
	int nRet = AF_FT_SetFontSize(nSize, NULL, NULL, NULL);
	pthread_mutex_unlock(&g_FontMutex);
	return nRet;
}

int AF_FT_GetSize()
{
	pthread_mutex_lock(&g_FontMutex);
	int nSize = g_size;
	pthread_mutex_unlock(&g_FontMutex);
	return nSize;
}
2.2.4 字符串转位图
static unsigned short GetCharCode(const char* pch, unsigned int *pn)
{
	unsigned char ch = 0;//single char
	unsigned short code = 0;//unicode
	int flag = 0; //0 - empty, 1 - 1 char to finish unicode, 2 - 2 chars to finish unicode, -1 - error

	*pn = 0;
	while ((ch = (unsigned char)*pch))
	{
		pch++;
		if(ch & 0x80)
		{
			if((ch & 0xc0) == 0xc0)
			{
				if((ch & 0xe0) == 0xe0)
				{
					if((ch & 0xf0) == 0xf0) //ucs-4?
						break;
					if(flag)
						break;
					*pn = 3;
					flag = 2;
					code |= ((ch & 0x0f) << 12);
				}
				else
				{
					if(flag)
						break;
					*pn = 2;
					flag = 1;
					code |= ((ch & 0x1f) << 6);
				}
			}
			else
			{
				if(flag == 0)
				{
					break;
				}
				else if(flag == 1) //unicode finished
				{
					code |= (ch & 0x3f);
					break;
				}
				else
				{
					code |= ((ch & 0x3f) << 6);
				}
				flag--;
			}
		}
		else //ASCII
		{
			if(flag)
				break;
			*pn = 1;
			code = ch;
			break;
		}
	}

	if(ch == 0)
		code = 0;
	return code;
}

static int IsArbic(const unsigned short word)
{
	if ((word >= 0x0600 && word <= 0x06FF)
		//|| (word >= 0x0750 && word <= 0x077F)
		|| (word >= 0xFB50 && word <= 0xFDFF)
		|| (word >= 0xFE70 && word <= 0xFEFF))
		return 1;
	return 0;
}

static unsigned int ToUCS2(const char* str, unsigned int nSize, unsigned short *pCode, bool *pbArabic)
{
	*pbArabic = false;
	if (str == NULL || nSize == 0 || pCode == NULL)
		return 0;
	unsigned int i = 0, l = 0;
	unsigned int nNum = 0;
	for (i = 0; i < nSize; i += l)
	{
		pCode[nNum] = GetCharCode(&str[i], &l);
		if (l == 0 || pCode[nNum] == 0)
			break;
		if ((*pbArabic == false) && IsArbic(pCode[nNum]))
		{
			*pbArabic = true;
		}
		else if (('n' == pCode[nNum]) && (nNum > 0) && ('\\' == pCode[nNum - 1]))
		{
			pCode[nNum - 1] = '\n';
			continue;
		}
        nNum++;
        if (nNum >= nSize)
            break;
	}

	return nNum;
}

int AF_FT_StringConvert(const char *str, unsigned int nWidth, unsigned int nHeight, unsigned short usColor, unsigned char *pBuf)
{
	pthread_mutex_lock(&g_FontMutex);
	
	if ((g_face == NULL) || (str == NULL) || (nWidth == 0) || (nHeight == 0) || (pBuf == NULL))
	{
		pthread_mutex_unlock(&g_FontMutex);
		return -1;
	}

	unsigned int nLen = strlen(str);
	if (nLen == 0)
	{
		pthread_mutex_unlock(&g_FontMutex);
		return -1;
	}

	FT_Size	size = g_face->size;
	unsigned int nLineNum = (unsigned int)(size->metrics.height >> 6);// 最大线数
	unsigned int nLineBase = (unsigned int)((size->metrics.height >> 6) + (size->metrics.descender >> 6) - 1);// 基线
	unsigned int nPixelnum = (unsigned int)(size->metrics.max_advance >> 6);//最大像素数
	if (nHeight * 2 < nPixelnum)// 因为字体设置成宽高像素相等
	{
		pthread_mutex_unlock(&g_FontMutex);
		return -1;
	}
	
	bool bArabic = false;
	unsigned short *pCode = (unsigned short *)malloc(nLen * sizeof(unsigned short));
	unsigned int nNum = ToUCS2(str, nLen, pCode, &bArabic);
	if (bArabic)
	{
#ifdef SUPPORT_ARBIC	// 注:ToArabic部分代码已注掉,这里不提供源码。
		nNum = ToArabic(pCode, nNum);
#else
		nNum = 0;
#endif
	}
	if (nNum == 0)
	{
		AFERR("ToUCS2 error\n");
		free(pCode);
		pthread_mutex_unlock(&g_FontMutex);
		return -1;
	}
	
	nPixelnum = (nPixelnum * nNum < nWidth) ? nPixelnum * nNum : nWidth;

	unsigned int idx = 0;
	unsigned int nPixel = 0;
	for (idx = 0; idx < nNum; idx++)
	{
		if (nPixel >= nPixelnum)
			break;
		FT_UInt nIdx = FT_Get_Char_Index(g_face, pCode[idx]);
		int nRet = FT_Load_Glyph(g_face, nIdx, FT_LOAD_MONOCHROME | FT_LOAD_RENDER);
//		int nRet = FT_Load_Char(g_face, pCode[idx], FT_LOAD_MONOCHROME | FT_LOAD_RENDER);
		if (nRet != 0)
			continue;
		FT_GlyphSlot slot = g_face->glyph;
		if (slot == NULL)
			continue;
		int startx = nPixel + slot->bitmap_left;
		nPixel += (slot->advance.x >> 6);
    	if (nPixel >= nPixelnum)
        	nPixel = nPixelnum;		
		if (startx >= nPixelnum)
			break;
		int starty = nLineBase - slot->bitmap_top;
		int row, col, x;
		for (row = starty; row < (int)(starty + slot->bitmap.rows); row++)
		{
			if (row < 0)
				continue;
			if (row >= nLineNum)
				break;
			unsigned char *dst = pBuf + row * (nWidth * 2);
			unsigned char *src = slot->bitmap.buffer + (row - starty) * slot->bitmap.pitch;
			for (col = 0; col < (int)slot->bitmap.width; col++)
			{
				x = startx + col;
				if (x < 0)
					continue;
				if (x >= nPixel)
					break;
				if (src[col >> 3] & (0x80 >> (col & 0x07)))
					*(((unsigned short *)dst) + x) |= usColor;
			}
		}
	}

	free(pCode);
	pthread_mutex_unlock(&g_FontMutex);
	return 0;
}


2.3 基于hi3519测试代码

2.3.1 头文件
#ifndef __OSD_H__
#define __OSD_H__

#define OSD_UDEF_STRING_LEN 64
#define OSD_STRING_MAX 4

typedef enum tagOSD_TYPE
{
	OSD_TYPE_TIME = 0,
	OSD_TYPE_GPS,
	OSD_TYPE_TEMP,
	OSD_TYPE_ATTI,

	OSD_TYPE_UDEF0,
	OSD_TYPE_UDEF1,
	OSD_TYPE_UDEF2,

	OSD_TYPE_MAX
}OSD_TYPE;

typedef struct tag_AF_OSDAttr
{
	int nPosX;
	int nPosY;
	int bShow;

	int nStringNum;// <=OSD_STRING_MAX
	char ppString[OSD_STRING_MAX][OSD_UDEF_STRING_LEN];
}AF_OSDAttr;

int AF_OSD_START(int nVenc, OSD_TYPE nOSDType, AF_OSDAttr *pstOSDAttr);
int AF_OSD_STOP(int nVenc, OSD_TYPE nOSDType);
int AF_OSD_REFRESH(int nVenc, OSD_TYPE nOSDType, AF_OSDAttr *pstOSDAttr);

#endif

2.3.2 代码部分
int AF_OSD_START(int nVenc, OSD_TYPE nOSDType, AF_OSDAttr *pstOSDAttr)
{
	HI_S32 s32Ret;
	RGN_HANDLE Handle = nVenc * (int)OSD_TYPE_MAX + (int)nOSDType;
	RGN_ATTR_S stRgnAttr;
	stRgnAttr.enType = OVERLAY_RGN;
	stRgnAttr.unAttr.stOverlay.enPixelFmt = PIXEL_FORMAT_RGB_1555;
	stRgnAttr.unAttr.stOverlay.stSize.u32Width = 512;// >= 2 * FontSize * FontNum
	stRgnAttr.unAttr.stOverlay.stSize.u32Height = 128;// >= 2 * FontSize
	stRgnAttr.unAttr.stOverlay.u32BgColor = 0x0000ffff;
	stRgnAttr.unAttr.stOverlay.u32CanvasNum = 2;

	s32Ret = HI_MPI_RGN_Create(Handle, &stRgnAttr);
	if (HI_SUCCESS != s32Ret)
	{
		printf("HI_MPI_RGN_Create failed %#x\n", s32Ret);
		return -1;
	}

    MPP_CHN_S stChn;
    RGN_CHN_ATTR_S stChnAttr;
	stChn.enModId = HI_ID_VENC;
	stChn.s32DevId = 0;
	stChn.s32ChnId = nVenc;

	stChnAttr.bShow = pstOSDAttr->bShow;
	stChnAttr.enType = OVERLAY_RGN;
	stChnAttr.unChnAttr.stOverlayChn.stPoint.s32X = pstOSDAttr->nPosX & 0x1ffe;
	stChnAttr.unChnAttr.stOverlayChn.stPoint.s32Y = pstOSDAttr->nPosY & 0x1ffe;
	stChnAttr.unChnAttr.stOverlayChn.u32BgAlpha = 0;
	stChnAttr.unChnAttr.stOverlayChn.u32FgAlpha = 128;
	stChnAttr.unChnAttr.stOverlayChn.u32Layer = 0;

	stChnAttr.unChnAttr.stOverlayChn.stQpInfo.bAbsQp = HI_FALSE;
	stChnAttr.unChnAttr.stOverlayChn.stQpInfo.s32Qp  = 0;
	stChnAttr.unChnAttr.stOverlayChn.stQpInfo.bQpDisable = HI_FALSE;
	stChnAttr.unChnAttr.stOverlayChn.stInvertColor.bInvColEn = HI_FALSE;

	s32Ret = HI_MPI_RGN_AttachToChn(Handle, &stChn, &stChnAttr);
	if (HI_SUCCESS != s32Ret)
	{
		printf("HI_MPI_RGN_AttachToChn failed %#x\n", s32Ret);
		return -1;
	}

	return 0;
}

int AF_OSD_STOP(int nVenc, OSD_TYPE nOSDType)
{
	HI_S32 s32Ret;
	MPP_CHN_S stChn;
	stChn.enModId = HI_ID_VENC;
	stChn.s32DevId = 0;
	stChn.s32ChnId = nVenc;
	RGN_HANDLE Handle = nVenc * (int)OSD_TYPE_MAX + (int)nOSDType;

	s32Ret = HI_MPI_RGN_DetachFromChn(Handle, &stChn);
	if (HI_SUCCESS != s32Ret)
	{
		printf("HI_MPI_RGN_DetachFromChn failed %#x\n", s32Ret);
		return -1;
	}

	s32Ret = HI_MPI_RGN_Destroy(Handle);
	if (HI_SUCCESS != s32Ret)
	{
		printf("HI_MPI_RGN_Destroy failed %#x\n", s32Ret);
		return -1;
	}

	return 0;
}

int AF_OSD_REFRESH(int nVenc, OSD_TYPE nOSDType, AF_OSDAttr *pstOSDAttr)
{
	HI_S32 s32Ret;
	RGN_HANDLE Handle = nVenc * (int)OSD_TYPE_MAX + (int)nOSDType;
	RGN_ATTR_S stRgnAttr;
	s32Ret = HI_MPI_RGN_GetAttr(Handle, &stRgnAttr);
	if (HI_SUCCESS != s32Ret)
	{
		printf("HI_MPI_RGN_GetAttr failed %#x\n", s32Ret);
		return -1;
	}

	MPP_CHN_S stChn;
	stChn.enModId = HI_ID_VENC;
	stChn.s32DevId = 0;
	stChn.s32ChnId = nVenc;
	RGN_CHN_ATTR_S stChnAttr;
	s32Ret = HI_MPI_RGN_GetDisplayAttr(Handle, &stChn, &stChnAttr);
	if (HI_SUCCESS != s32Ret)
	{
		printf("HI_MPI_RGN_GetDisplayAttr failed %#x\n", s32Ret);
		return -1;
	}

	stChnAttr.bShow = pstOSDAttr->bShow;
	stChnAttr.unChnAttr.stOverlayChn.stPoint.s32X = pstOSDAttr->nPosX & 0x1ffe;
	stChnAttr.unChnAttr.stOverlayChn.stPoint.s32Y = pstOSDAttr->nPosY & 0x1ffe;
	s32Ret = HI_MPI_RGN_SetDisplayAttr(Handle, &stChn, &stChnAttr);
	if (HI_SUCCESS != s32Ret)
	{
		printf("HI_MPI_RGN_GetDisplayAttr failed %#x\n", s32Ret);
		return -1;
	}

	unsigned int nWidth = stRgnAttr.unAttr.stOverlay.stSize.u32Width;
	unsigned int nHeight = stRgnAttr.unAttr.stOverlay.stSize.u32Height;
	unsigned char *pBuffer = (unsigned char *)malloc(nWidth * nHeight * 2);
	memset(pBuffer, 0, nWidth * nHeight * 2);
	int i = 0;
	int nFontSize = AF_FT_GetSize() + 4;
	unsigned short usColor = (1 << 15) /*| (0x1f << 10)*/ | (0x1f << 5)/* | 0x1f*/; // 绿色
	for (i = 0; i < pstOSDAttr->nStringNum; i++)
	{
		char *pstring = pstOSDAttr->ppString[i];
		int nHeightPos = nFontSize * i;
		if (nHeightPos >= nHeight)
			break;
		unsigned char *pBuf = pBuffer + nHeightPos * nWidth * 2;
		if (AF_FT_StringConvert(pstring, nWidth, nFontSize, usColor, pBuf) != 0)
		{
			continue;
		}
	}

	BITMAP_S stBitmap;
	stBitmap.u32Width		= stRgnAttr.unAttr.stOverlay.stSize.u32Width;
	stBitmap.u32Height		= stRgnAttr.unAttr.stOverlay.stSize.u32Height;
	stBitmap.enPixelFormat	= PIXEL_FORMAT_RGB_1555;
	stBitmap.pData 			= (HI_VOID *)pBuffer;
	s32Ret = HI_MPI_RGN_SetBitMap(Handle, &stBitmap);
	if (HI_SUCCESS != s32Ret)
	{
		printf("HI_MPI_RGN_SetBitMap failed %#x\n", s32Ret);
		free(pBuffer);
		return -1;
	}

	free(pBuffer);
	return 0;
}

转载请注明出处,如有错漏之处,敬请指正。

  • 1
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值