需求: 在海思3516a芯片上, 显示字幕. 效果图如下:
一, 首先参考这篇博文:https://blog.csdn.net/whereisdog/article/details/82769222 下载并编译freetype sdl sdl_ttf.根据此博文介绍, 你可以很快的完成移植工作.
#include
#include "SDL.h"
#include "SDL_ttf.h"
int main(int argc, const char *argv[])
{
char * pstr = "hello";
SDL_PixelFormat *fmt;
TTF_Font *font;
SDL_Surface *text, *temp;
if (TTF_Init() < 0 )
{
fprintf(stderr, "Couldn't initialize TTF: %s\n",SDL_GetError());
SDL_Quit();
}
font = TTF_OpenFont("./simhei.ttf", 48);
if ( font == NULL )
{
fprintf(stderr, "Couldn't load %d pt font from %s: %s\n",18,"ptsize", SDL_GetError());
}
SDL_Color forecol = { 0xff, 0xff, 0xff, 0xff };
text = TTF_RenderUTF8_Solid(font, pstr, forecol);
fmt = (SDL_PixelFormat*)malloc(sizeof(SDL_PixelFormat));
memset(fmt,0,sizeof(SDL_PixelFormat));
fmt->BitsPerPixel = 16;
fmt->BytesPerPixel = 2;
fmt->colorkey = 0xffffffff;
fmt->alpha = 0xff;
temp = SDL_ConvertSurface(text,fmt,0);
SDL_SaveBMP(temp, "save.bmp");
SDL_FreeSurface(text);
SDL_FreeSurface(temp);
TTF_CloseFont(font);
TTF_Quit();
return 0;
}
二, 介绍一下我所遇到的坑.
1. 应用库的添加.
LIBS += SDL_ttf_2.0.11_out_3516A/lib/libSDL_ttf.a (这个要放在前面, 不然会出现链接不到函数的错误)
LIBS += SDL_1.2.15_out_3516A/lib/libSDL.a
LIBS += freetype_2.4.10_out_3516A/lib/libfreetype.a
2. 保存的图片如果宽高为奇数,如(63,41) 则HI_MPI_RGN_Create报错(0xA0038003 HI_ERR_RGN_ILLEGAL_PARAM 参数超出合法范围)
但是, 用户设置的文字内容长度以及字体大小是不可控的. 所以生成的图片不可能避免会产生奇数宽高, 此时怎么办呢?办法很简单. 直接上代码吧:
BITMAP_S stBitmap;
//因为要把文字镂空部份透明出来, 所以必须使用rgb1555 (1表示alpha值). 这里很重要. 是下面遇坑的伏笔.
stBitmap.enPixelFormat = PIXEL_FORMAT_RGB_1555;
stBitmap.u32Width = w;
stBitmap.u32Height = h;
if (stBitmap.u32Width % 2 != 0)
{
stBitmap.u32Width += 1;
}
if (stBitmap.u32Height % 2 != 0)
{
stBitmap.u32Height += 1;
}
//分配内存
stBitmap.pData = malloc(2 * (stBitmap.u32Width) * (stBitmap.u32Height));
memset(stBitmap.pData, 0, 2 * (stBitmap.u32Width) * (stBitmap.u32Height));
就是说如果遇到了奇数宽高的情况, 我们就人为的给他加1个像素, 使其满足HI_MPI_RGN_Create需要偶数作为参数的需求.
然后是将sdl生成的bmp图片内容复制过来. 这里有2个坑, 一是尺寸,二是颜色问题. 首先来讲尺寸.
我们知道16位的bmp图片. 他的内存长度应该为: len = w*h*2; 一个像素点由2个字节表示. 当sdl生成的图片src_bmp.宽高为偶数的时候, 象下面这样做就可以把内容拷贝过去了.
char* p_src = (char*)temp->pixels;//前文中生成的bmp图片.
char* p_des = (char*)stBitmap.pData; //海思结构体BITMAP_S 也在前文中分配的.
int w = temp->w;
int h = temp->h;
for (i = 0; i < h; ++i)
{
memcpy(p_des + stBitmap.u32Width*2, p_src + w*2, w*2);
}
至此, 如果你生成的图片恰好是偶数的, 那么你可以成功显示出来了. 但如果为奇数的话, 你会发现在编码流上的图片是斜着的.
解决办法如下:(我意外发现是这样的).
for (i = 0; i < h; ++i)
{
int dis_pos = 0;
//这里的w ==> psrc_w;
if(w % 2 != 0)
dis_pos = i*2;
memcpy(p_des + stBitmap.u32Width*2, p_src + w*2 + dis_pos, w*2);
}
好了, 现在不管是奇数还是偶数的图片都能正常显示了.
但是你的老板说, 我们可以设置字体颜色. 你设置白色的时候.是正确的.
见前文 SDL_Color forecol = { 0xff, 0xff, 0xff, 0xff }; 前面3个参数分别代表(rgb最后一个未使用.
当你设置其它颜色的时候, 你会发现显示在编码流上的图片和你设置的不一样. 这个坑我搞了很久, 才找到原因.
首先参考一个博客:https://blog.csdn.net/qq_26671365/article/details/79007066 其实这个博客里.作者说错了. 真实情况是什么呢?
sdl生成的图片格式默认是 rgb565 r占5位, 然后g占6位. b占最后5位. 没有alpha值.
而海思的Bitmap里面的存储方式是可选的. 如果你要用:PIXEL_FORMAT_RGB_1555 带alpha值. 因为字体镂空的地方你需要设置透明. 这个时候颜色就对不上了啊. 所以你要一个像素一个像素的提取出来, 分别计算rgb值 再转成 PIXEL_FORMAT_RGB_1555;代码如下:
for (i = 0; i < h; ++i)
{
int dis_pos = 0;
if(w % 2 != 0)
dis_pos = i*2;
for(j = 0; j < w*2; j += 2)
{
//rgb(565)--
int a;
int r, g , b;
unsigned short src_color;
memcpy((char*)&src_color, p_src + w*i*2 + dis_pos + j, 2);
r = (src_color & 0xF800) >> 11;
g = (src_color & 0x07e0) >> 5;
b = (src_color & 0x001f);
a = 1 << 15;
if (bck_color == src_color)
a = 0;
r = r << 10;
g = (g >> 1) << 5;
b = b;
//argb-->
unsigned short des_color = a + r + g + b;
int color1 = des_color & 0x00ff;
int color2 = (des_color & 0xff00) >> 8;
p_des[i*stBitmap.u32Width*2 + j] = color1;
p_des[i*stBitmap.u32Width*2 + j + 1] = color2;
}
}
这里说一下. bck_color. SDL在生成图片时需要设置文字颜色,这里我们称为 words_color;然后文字以外的镂空部分, 称为bck_color. 它是怎么计算的呢. 如下:
unsigned short words_color = ((r >> 3) << 11) + ((g >> 2) << 5) + (b >> 3);
unsigned short bck_color = 0xffff - words_color;
好了, 至此.就完成功能了. 下面我贴一下我的代码:
int SetWords(unsigned short bck_color, void * buff, int w, int h)
{
HI_S32 s32Ret;
MPP_CHN_S stChn;
RGN_ATTR_S stRgnAttrSet;
RGN_CHN_ATTR_S stChnAttr;
BITMAP_S stBitmap;
char tv_words_xpos[20];
char tv_words_ypos[20];
read_profile_string("TV_WORDS", "x", tv_words_xpos, 20, "200", CONFIG_FILE_PATH);
read_profile_string("TV_WORDS", "y", tv_words_ypos, 20, "0", CONFIG_FILE_PATH);
int osd_x = atoi(tv_words_xpos);
int osd_y = atoi(tv_words_ypos);
stBitmap.enPixelFormat = PIXEL_FORMAT_RGB_1555;
stBitmap.u32Width = w;
stBitmap.u32Height = h;
if (stBitmap.u32Width % 2 != 0)
{
stBitmap.u32Width += 1;
}
if (stBitmap.u32Height % 2 != 0)
{
stBitmap.u32Height += 1;
}
//分配内存
stBitmap.pData = malloc(2 * (stBitmap.u32Width) * (stBitmap.u32Height));
memset(stBitmap.pData, 0, 2 * (stBitmap.u32Width) * (stBitmap.u32Height));
int i,j;
char* p_des = (char*)stBitmap.pData;
char* p_src = (char*)buff;
int flag = 0;
//unsigned short* p_short_src = (unsigned short*)buff;
for (i = 0; i < h; ++i)
{
int dis_pos = 0;
if(w % 2 != 0)
dis_pos = i*2;
for(j = 0; j < w*2; j += 2)
{
//rgb(565)--
int a;
int r, g , b;
unsigned short src_color;
memcpy((char*)&src_color, p_src + w*i*2 + dis_pos + j, 2);
r = (src_color & 0xF800) >> 11;
g = (src_color & 0x07e0) >> 5;
b = (src_color & 0x001f);
a = 1 << 15;
if (bck_color == src_color)
a = 0;
r = r << 10;
g = (g >> 1) << 5;
b = b;
//argb-->
unsigned short des_color = a + r + g + b;
int color1 = des_color & 0x00ff;
int color2 = (des_color & 0xff00) >> 8;
p_des[i*stBitmap.u32Width*2 + j] = color1;
p_des[i*stBitmap.u32Width*2 + j + 1] = color2;
}
}
RGN_HANDLE Handle = 1;
stRgnAttrSet.enType = OVERLAYEX_RGN;
stRgnAttrSet.unAttr.stOverlayEx.enPixelFmt = PIXEL_FORMAT_RGB_1555;
stRgnAttrSet.unAttr.stOverlayEx.stSize.u32Width = stBitmap.u32Width;
stRgnAttrSet.unAttr.stOverlayEx.stSize.u32Height = stBitmap.u32Height;
stRgnAttrSet.unAttr.stOverlayEx.u32BgColor = 0x000003e0;
// printf("w:%d h: %d\n", w, h);
// printf("w:%d h: %d\n", stBitmap.u32Width, stBitmap.u32Height);
HI_MPI_RGN_Create(Handle, &stRgnAttrSet);
HI_MPI_RGN_SetBitMap(Handle,&stBitmap);
/*attach the OSD to the vpss*/
stChn.enModId = HI_ID_VPSS;
stChn.s32DevId = 0;
stChn.s32ChnId = VPSS_CHN3;
stChnAttr.bShow = HI_TRUE;
stChnAttr.enType = OVERLAYEX_RGN;
stChnAttr.unChnAttr.stOverlayExChn.stPoint.s32X = osd_x;
stChnAttr.unChnAttr.stOverlayExChn.stPoint.s32Y = osd_y;
stChnAttr.unChnAttr.stOverlayExChn.u32BgAlpha = 0;
stChnAttr.unChnAttr.stOverlayExChn.u32FgAlpha = 255;
stChnAttr.unChnAttr.stOverlayExChn.u32Layer = 0;
for (int i = 0; i < 4; ++i)
{
stChn.s32ChnId = i;
s32Ret = HI_MPI_RGN_AttachToChn(Handle, &stChn, &stChnAttr);
if(s32Ret != HI_SUCCESS)
{
//printf("\n===========%d========HI_MPI_RGN_AttachToChn error %x\n", i, s32Ret);
return s32Ret;
}
}
//释放内存
free(stBitmap.pData);
return 0;
}
int StartWordsOSD()
{
char tv_words_enable[20];
char tv_words_size[20];
char r_buf[20];
char g_buf[20];
char b_buf[20];
char tv_words[1024];
memset(tv_words, 0, sizeof(tv_words));
read_profile_string("TV_WORDS", "words", tv_words, sizeof(tv_words), "", CONFIG_FILE_PATH);
read_profile_string("TV_WORDS", "enable", tv_words_enable, 20, "0", CONFIG_FILE_PATH);
read_profile_string("TV_WORDS", "size", tv_words_size, 20, "20", CONFIG_FILE_PATH);
read_profile_string("TV_WORDS", "r", r_buf, 20, "255", CONFIG_FILE_PATH);
read_profile_string("TV_WORDS", "g", g_buf, 20, "255", CONFIG_FILE_PATH);
read_profile_string("TV_WORDS", "b", b_buf, 20, "255", CONFIG_FILE_PATH);
if (atoi(tv_words_enable) == 0)
return 0;
Uint8 r = atoi(r_buf);
Uint8 g = atoi(g_buf);
Uint8 b = atoi(b_buf);
int font_size = atoi(tv_words_size);
SDL_PixelFormat *fmt;
TTF_Font *font;
SDL_Surface *text, *temp;
if (TTF_Init() < 0 )
{
printf("Couldn't initialize TTF: %s\n",SDL_GetError());
SDL_Quit();
return -1;
}
font = TTF_OpenFont("my.ttf", font_size);
printf("osd_words color: r:%d g:%d b:%d\n", r, g, b);
unsigned short words_color = ((r >> 3) << 11) + ((g >> 2) << 5) + (b >> 3);
unsigned short bck_color = 0xffff - words_color;
SDL_Color forecol = { r, g, b, 0xff};
text = TTF_RenderUTF8_Solid(font, tv_words, forecol);
fmt = (SDL_PixelFormat*)malloc(sizeof(SDL_PixelFormat));
memset(fmt,0,sizeof(SDL_PixelFormat));
fmt->BitsPerPixel = 16;
fmt->BytesPerPixel = 2;
fmt->colorkey = 0xffffffff;
fmt->alpha = 0xff;
temp = SDL_ConvertSurface(text,fmt,0);
SetWords(bck_color, temp->pixels, temp->w, temp->h);
//SDL_SaveBMP(temp, "save.bmp");
SDL_FreeSurface(text);
SDL_FreeSurface(temp);
TTF_CloseFont(font);
TTF_Quit();
return 0;
}
void CloseWordsOSD()
{
HI_S32 s32Ret;
RGN_HANDLE Handle = 1;
MPP_CHN_S stChn;
for (int i = 0; i < 4; ++i)
{
stChn.enModId = HI_ID_VPSS;
stChn.s32DevId = 0;
stChn.s32ChnId = i;
s32Ret = HI_MPI_RGN_DetachFromChn(Handle, &stChn);
if(s32Ret != HI_SUCCESS)
{
printf("\n===========%d========HI_MPI_RGN_DetachFromChn error %x\n", i, s32Ret);
}
}
HI_MPI_RGN_Destroy(Handle);
}
不怎么写博客. 希望可以帮助到大家.