目前OSD主流的实现方案 freetype2+SDL2+SDL2_ttf等开源库来生成位图进行填
各个库的链接:
freetype-2.10.4:https://mirror.yongbok.net/nongnu/freetype/freetype-2.10.4.tar.gz
SDL2-2.0.14:https://www.libsdl.org/release/SDL2-2.0.14.tar.gz
SDL2_ttf-2.0.15:https://www.libsdl.org/projects/SDL_ttf/release/SDL2_ttf-2.0.15.tar.gz
RK3568交叉编译器:
https://download.csdn.net/download/yinsui1839/87352165
自行配置好交叉编译器环境变量
freetype库:
./configure --prefix=$PWD/.. CC=aarch64-linux-android-gcc CXX=aarch64-linux-android-g++ --host=arm-linux --without-zlib --enable-freetype-config
make -j16 && make install
SDL库:
./configure --prefix=$PWD/.. CC=aarch64-linux-android-gcc CXX=aarch64-linux-android-g++ --host=arm-linux --disable-alsa --disable-pulseaudio --enable-esd=no
make -j16 && make install
SDL2_ttf库:
./configure --prefix=$PWD CC=aarch64-linux-android-gcc CXX=aarch64-linux-android-g++ --host=arm-linux --with-sdl-prefix=$PWD/.. --with-sdl-exec-prefix=$PWD/.. FT2_CONFIG=$PWD/../bin/freetype-config PKG_CONFIG_PATH=$PWD/../lib/pkgconfig
make -j16 && make install
编译好后会产生libfreetype.a libSDL.a libSDLmain.a libSDL_ttf.a
需要使用到库的CMakeLists.txt加上
include_directories(/xxxxx/freetype-2.4.10/include/freetype)
include_directories(/xxxxx/SDL-1.2.15/SDL/include/SDL)
include_directories(/xxxxx/SDL_ttf-2.0.11/SDLTtf/include/SDL)
//注意.a链接顺序,报错调整一下
target_link_libraries(
...
z
${PROJECT_SOURCE_DIR}/mpp/project/osd/so/libSDL_ttf.a
${PROJECT_SOURCE_DIR}/mpp/project/osd/so/libfreetype.a
${PROJECT_SOURCE_DIR}/mpp/project/osd/so/libSDL.a
${PROJECT_SOURCE_DIR}/mpp/project/osd/so/libSDLmain.a)
//字体ttf路径
#define Font_Path "/sdcard/Download/1.ttf"
//osdBuf 输入OSD的图像
//srcWidthOSD宽
// srcHeight OSD高
//dst_buf 在打底图像 格式NV21 NV12
//打底图像 dstWidth 宽
//打底图像 dstHeight 高
//x y覆盖的起始坐标
void ImcompositeYuv(unsigned char *osdBuf, int srcWidth, int srcHeight,
unsigned char *dst_buf, int dstWidth, int dstHeight, int x, int y)
{
int dstOffset = x + y * dstWidth;
int nv_start = dstWidth * dstHeight;
int len = dstWidth * dstHeight * 3 / 2;
int nv_index;
int yOffset;
int uOffset;
int vOffset;
for (int h = 0; h < srcHeight; h++)
{
for (int w = 0; w < srcWidth; w++)
{
if (osdBuf[w + h * srcWidth] == 1)
{
nv_index = (h + y) / 2 * dstWidth + (w + x) - (w + x) % 2;
if(nv_index > len) continue;
yOffset = (dstOffset + (h * dstWidth) + w);
uOffset = nv_start + nv_index;
vOffset = uOffset + 1;
dst_buf[yOffset] = 0xff;
dst_buf[uOffset] = 128;
dst_buf[vOffset] = 128;
}
}
}
}
int SDL_OSDtoBMP(char *pstrShow)
{
static SDL_Surface *text = NULL;
static TTF_Font *font = NULL;
int x = 0, y = 0;
int i = 0, n = 0;
char *pTempPixels = NULL;
char *l_ps8Bmp = NULL;
if (NULL == pstrShow)
return -1;
if (strlen(pstrShow) <= 0)
return -1;
SDL_Color forecol = {(unsigned char)((0xffffffff >> 24) & 0xff),
(unsigned char)((0xffffffff >> 16) & 0xff),
(unsigned char)((0xffffffff >> 8) & 0xff),
(unsigned char)((0xffffffff >> 0) & 0xff)};
if (font == NULL)
{
if (font != NULL)
{
TTF_CloseFont(font);
font = NULL;
}
font = TTF_OpenFont(Font_Path, 16);
}
if (font == NULL)
{
fprintf(stderr, "Couldn't load[%s] %s %d \n", Font_Path, "ptsize", 12);
return -1;
}
if (pstrShow != NULL )
{
text = TTF_RenderUTF8_Solid(font, pstrShow, forecol);
unsigned char *ImageBuf = NULL;
ImcompositeYuv(text->pixels,text->pitch,text->h,/*图像buf*/ ImageBuf,
1920,1080,300,300);
SDL_FreeSurface(text);
}
return 0;
}
int main(){
SDL_OSDtoBMP("hello world");
return 0;
}
可以使用RGA imblend(srcA, dst)进行叠加,输入的图像和OSD都要求RGB格式和宽高一致,灵活性不是很好,而且覆盖一张高达50ms,耗时较高所以弃用!
所以自己写了 ImcompositeYuv可以对YUV格式的图像进行OSD叠加,目前自测只有500微妙的耗时
附上另外两种覆盖函数:
//RGB
void ImcompositeRgb(unsigned char *osdBuf, int srcWidth, int srcHeight,
unsigned char *dst_buf, int dstWidth, int dstHeight, int x, int y)
{
int dstOffset = x + y * dstWidth;
for (int h = 0; h < srcHeight; h++)
{
for (int w = 0; w < srcWidth; w++)
{
if (osdBuf[w + h * srcWidth] & 0x8000)
{
int rOffset = (dstOffset + (h * dstWidth) + w);
int gOffset = rOffset + 1;
int bOffset = rOffset + 2;
dst_buf[rOffset] = 0xff;
dst_buf[gOffset] = 0xff;
dst_buf[bOffset] = 0xff;
}
}
}
}
//RK rgb覆盖 必须是RGB类型数据,宽高也必须保持与覆盖图像一致
void Imcomposite(char *srcdata, int srcWidth, int srcHeight, int srcFormat,
char *dst_buf, int dstWidth, int dstHeight, int dstFormat)
{
TimeDelayLog time("Imcomposite",false);
im_rect src_rect;
im_rect dst_rect;
rga_buffer_t srcA;
rga_buffer_t dst;
IM_STATUS STATUS;
int ret = 0;
memset(&src_rect, 0, sizeof(src_rect));
memset(&dst_rect, 0, sizeof(dst_rect));
memset(&srcA, 0, sizeof(srcA));
memset(&dst, 0, sizeof(dst));
srcA = wrapbuffer_virtualaddr(srcdata, srcWidth, srcHeight, srcFormat);
dst = wrapbuffer_virtualaddr(dst_buf, dstWidth, dstHeight, dstFormat);
if (srcA.width == 0 || dst.width == 0)
{
printf("%s, %s\n", __FUNCTION__, imStrError());
return;
}
srcA.format = srcFormat;
dst.format = dstFormat;
EasyMutex Lock(&mMutex);
ret = imcheck(srcA, dst, src_rect, dst_rect);
if (IM_STATUS_NOERROR != ret)
{
printf("%d, check error! %s\n", __LINE__, imStrError((IM_STATUS)ret));
return;
}
STATUS = imblend(srcA, dst);
}
本片完