编译环境:Ubuntu16.04 64位
交叉编译工具:arm-hisiv500-linux-gcc
最近需要在hi3519为图像叠加osd信息,目前已完成,这里做个总结。
下载合适版本的freetype源码,我这里使用的是freetype-2.9.1.tar.gz,网上介绍交叉编译freetype的资料有很多,不多说。
修改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
./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
如下:
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/目录下的头文件就是我们需要的。
需要提供读取ttf字库,设置字体大小,C字符串转位图的功能。
#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
#include
#include
#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码,这里不做详细描述,网上可以找到资料。
注意:这里头文件的包含一定要注意!!!
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;
}
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;
}
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;
}
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;
}
#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
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;
}
转载请注明出处,如有错漏之处,敬请指正。