视频叠加区域,其中区域支持位图的加载、背景色更新等功能,简单理解就是可以设置透明度,也就是下面的Alpha值
视频遮挡区域,其中区域支持纯色块遮挡,与Overlay叠加不同的是它不能加载图片,不能设置透明度
如果图形卡具有32位总线,附加的8位信号就被用来保存不可见的透明度信号以方便处理用,这就是Alpha通道。白色的alpha象素用以定义不透明的彩色象素,而黑色的alpha象素用以定义透明象素,黑白之间的灰阶用来定义半透明象素。
Image Stride(内存图像行跨度) 当视频图像存储在内存时,图像的每一行末尾也许包含一些扩展的内容,这些扩展的内容只影响图像如何存储在内存中,但是不影响图像如何显示出来;Stride 就是这些扩展内容的名称,Stride 也被称作 Pitch,如果图像的每一行像素末尾拥有扩展内容,Stride 的值一定大于图像的宽度值,就像下图所示:
两个缓冲区包含同样大小(宽度和高度)的视频帧,却不一定拥有同样的 Stride 值,如果你处理一个视频帧,你必须在计算的时候把 Stride 考虑进去;
在做OSD水印的时候,叠加图片的stride值大于region画布的宽度时,该图像添加到画布会失败。
ARGB---Alpha,Red,Green,Blue.一种色彩模式,也就是RGB色彩模式附加上Alpha(透明度)通道,常见于32位位图的存储结构。
ALPHA_8:数字为8,图形参数应该由一个字节来表示,应该是一种8位的位图,常见的颜色格式:
Argb1555 也就是15位表示透明度和分别使用5位表示R,G,B,构成一个32位的位图,其中有两个位没有使用到。(b)颜色格式:
同样是RGB颜色,但是颜色格式却有很多种,所以查颜色对照表得到的颜色与显示的颜色是不能对应的,需要转换或是直接对应格式查找。
三种RGB格式表示方式:
RGB888转RGB555
RGB888 :R7 R6 R5 R4 R3 R2 R1 R0 G7 G6 G5 G4 G3 G2 G1 G0 B7 B6 B5 B4 B3 B2 B1 B0
RGB555 :0 R7 R6 R5 R4 R3 G7 G6 G5 G4 G3 B7 B6 B5 B4 B3
其它格式于此类似。
在海思官方提供的region sample中,它们使用的是现成的图片,也就是直接拿现成的图片加载到视频流中去,这样有一个问题,就是如果我需要实时改变OSD的内容,这个就不好处理了。比如在视频中添加时间水印。
以时间水印为例,要实现将时间水印添加到视频流流中去,大的流程只有两个:
这里需要使用到freetype、SDL、SDl_ttf这三个库。
需要将这三个库移植到海思设备中去,交叉编译移植过程这里不介绍,网上有很多介绍。
这里提供一个简单的测试程序:
- /************************************************************
- *Copyright (C),lcb0281at163.com lcb0281atgmail.com
- *BlogAddr: caibiao-lee.blog.csdn.net
- *FileName: debug_font_osd.c
- *Description:测试生成带时间字符的图像
- *Date: 2020-02-03
- *Author: Caibiao Lee
- *Version: V1.0
- *Others:
- *History:
- ***********************************************************/
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include "SDL/SDL.h"
- #include "SDL/SDL_ttf.h"
-
- #define FONT_PATH "./font/hisi_osd.ttf"
-
- int string_to_bmp(char *pu8Str)
- {
- 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(FONT_PATH, 80);
- 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, pu8Str, 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;
- }
工程中包含下面些内容:
- biao@ubuntu:~/test/github/hisi_sdk_develop/freetype_SDL_Dl_ttf_debug$ tree -L 2
- .
- ├── bin
- │ └── objs
- ├── debug_font_osd.c
- ├── debug_font_osd.h
- ├── font
- │ ├── hisi_osd.ttf
- │ └── hisi_osd.ttf_df
- ├── inc
- │ ├── freetype2
- │ ├── ft2build.h
- │ └── SDL
- ├── lib
- │ ├── libfreetype.a
- │ ├── libfreetype.so
- │ ├── libfreetype.so.6
- │ ├── libSDL-1.2.so.0
- │ ├── libSDL.a
- │ ├── libSDLmain.a
- │ ├── libSDL.so
- │ ├── libSDL_ttf-2.0.so.0
- │ ├── libSDL_ttf.a
- │ ├── libSDL_ttf.so
- │ └── pkgconfig
- ├── Makefile
- ├── save.bmp
- └── test
-
- 8 directories, 18 files
- biao@ubuntu:~/test/github/hisi_sdk_develop/freetype_SDL_Dl_ttf_debug$
生成保存的save.bmp图像如下:
这里是根据官方sample修改而来,主要流程是:
编码之后的图像带有区域图像的水印,这里可以根据实际的分辨率设置VENC和VDEC。
- /*************************************************
- Function: BIAO_RGN_AddOsdToVenc
- Description: 将视频文件添加时间水印
- Input: none
- OutPut: none
- Return: 0: success,none 0:error
- Others: 解码器输入的分辨率与编码器的输出分辨率可以不相同,
- 比如将1080P图像解码后,可以再编码成720P图像。
- Author: Caibiao Lee
- Date: 2020-03-08
- *************************************************/
- HI_S32 BIAO_RGN_AddOsdToVenc(HI_VOID)
- {
- HI_S32 s32Ret = HI_SUCCESS;
- RGN_HANDLE OverlayHandle;
- HI_S32 u32OverlayRgnNum;
- MPP_CHN_S stSrcChn, stDesChn;
- RGN_ATTR_S stRgnAttrSet;
- RGN_CANVAS_INFO_S stCanvasInfo;
- BITMAP_S stBitmap;
- VENC_CHN VencChn;
- VDEC_CHN VdecChn;
- VDEC_SENDPARAM_S stVdesSendPram;
- VENC_PTHREAD_INFO_S stVencGetPram;
- SIZE_S stSize;
- FILE * pastream = NULL;
- HI_U32 i;
- int l_s32CanvasHandle = 0;
-
- /**分配缓存**/
- s32Ret = BIAO_RGN_SYS_Init();
- if(HI_SUCCESS != s32Ret)
- {
- printf("SAMPLE_RGN_SYS_Init failed! s32Ret: 0x%x.\n", s32Ret);
- goto END_O_VENC0;
- }
-
- /**创建区域,并将它添加到编码通道**/
- OverlayHandle = 0;
- u32OverlayRgnNum = 1;
- s32Ret = BIAO_RGN_CreateOverlayForVenc(OverlayHandle, u32OverlayRgnNum);
- if(HI_SUCCESS != s32Ret)
- {
- printf("SAMPLE_RGN_CreateOverlayForVenc failed! s32Ret: 0x%x.\n", s32Ret);
- goto END_O_VENC1;
- }
-
- /**开启解码通道**/
- VdecChn = 0;
- s32Ret = BIAO_RGN_StartVdec(VdecChn);
- if(HI_SUCCESS != s32Ret)
- {
- printf("SAMPLE_RGN_StartVdec failed! s32Ret: 0x%x.\n", s32Ret);
- goto END_O_VENC2;
- }
-
- /**开启编码通道**/
- VencChn = 0;
- s32Ret = BIAO_RGN_StartVenc(VencChn);
- if(HI_SUCCESS != s32Ret)
- {
- printf("SAMPLE_RGN_StartVenc failed! s32Ret: 0x%x.\n", s32Ret);
- goto END_O_VENC3;
- }
-
- /**将解码通道绑定到编码通道**/
- stSrcChn.enModId = HI_ID_VDEC;
- stSrcChn.s32DevId = 0;
- stSrcChn.s32ChnId = 0;
-
- stDesChn.enModId = HI_ID_VENC;
- stDesChn.s32DevId = 0;
- stDesChn.s32ChnId = 0;
-
- s32Ret = HI_MPI_SYS_Bind(&stSrcChn, &stDesChn);
- if(HI_SUCCESS != s32Ret)
- {
- printf("HI_MPI_SYS_Bind failed! s32Ret: 0x%x.\n", s32Ret);
- goto END_O_VENC4;
- }
-
- /**创建一个线程用来从h264文件中读取数据,模拟h264数据流**/
- stSize.u32Width = DECODE_VIDEO_W;
- stSize.u32Height = DECODE_VIDEO_H;
-
- stVdesSendPram.bRun = HI_TRUE;
- stVdesSendPram.VdChn = VdecChn;
- stVdesSendPram.enPayload = PT_H264;
- stVdesSendPram.enVideoMode = VIDEO_MODE_FRAME;
- stVdesSendPram.s32MinBufSize = stSize.u32Height * stSize.u32Width / 2;
- pthread_create(&g_stVdecThread, NULL, BIAO_RGN_VdecSendStream, (HI_VOID*)&stVdesSendPram);
-
-
- /**更新OSD内容**/
- l_s32CanvasHandle = 0;
- pthread_create(&g_stRgnOsdThread, NULL, BIAO_UpdateCanvas, (HI_VOID*)&l_s32CanvasHandle);
-
-
- /**创建一个线程,将编码器输出的数据存成文件**/
- char pfilename[64];
- sprintf(pfilename, ENCODE_H264_FILE);
- pastream = fopen(pfilename, "wb");
- HI_ASSERT( NULL != pastream);
-
- stVencGetPram.pstream = pastream;
- stVencGetPram.VeChnId = VencChn;
- stVencGetPram.s32FrmCnt = 0;
- pthread_create(&g_stVencThread, 0, BIAO_RGN_VencGetStream, (HI_VOID *)&stVencGetPram);
-
- printf("\n#############Sample start ok! Press Enter to switch!#############\n");
-
-
- /*************************************************
- step 8: stop thread and release all the resource
- *************************************************/
-
- /**延时之后推出编解码**/
- sleep(10);
- bExit = HI_TRUE;
- pthread_join(g_stVdecThread, 0);
-
- pthread_join(g_stVencThread, 0);
-
- pthread_join(g_stRgnOsdThread, 0);
-
- bExit = HI_FALSE;
-
- END_O_VENC4:
- HI_MPI_SYS_UnBind(&stSrcChn, &stDesChn);
-
- END_O_VENC3:
- BIAO_RGN_StopVenc(VencChn);
-
- END_O_VENC2:
- BIAO_RGN_StopVdec(VdecChn);
-
- END_O_VENC1:
- BIAO_RGN_DestroyRegion(OverlayHandle, u32OverlayRgnNum);
-
- END_O_VENC0:
- SAMPLE_COMM_SYS_Exit();
-
- return s32Ret;
- }
将海思官方视频添加水印之后的视频效果如下:
第一个生成时间图像的工程可以从下面获取:
GitHub:freetype_SDL_Dl_ttf_debug