
OSD概念OSDOn-Screen Display的字面意思是“屏幕显示”在视频处理中它泛指叠加在视频画面上用于显示特定信息的图形或文字例如通道号、时间戳、设备Logo等。这里的添加是指软件制作好的画布添加到板子端当视频流到达上位机的时候就带好了这些信息不是在上位机进行处理添加进去的。在Hi3519DV500的实现中这个概念被统一并扩展了所有叠加在视频上的OSD内容以及用于遮挡视频的纯色块都被统称为“区域”Region。芯片的REGION模块就是用来统一管理这些区域资源的负责区域的创建、配置和叠加。软件制作好的画布这个的含义是什么呢硬件只知道“矩形像素图”不知道文字、字体、字符串长度和中文。也就是说你可以显示任何信息只要你软件能画出来大小合规硬件只按照像素叠加上去不管你到底是汉字还是图片还是普通字符串。region数量关于区域的数量在Hi3519DV500的规格中明确指出芯片支持8个区域的编码前OSD叠加。这意味着你可以同时创建和管理最多8个独立的Region用于显示不同的信息或实现遮挡功能。Region作为一个可管理的逻辑单元包含几个关键的属性定义决定了它在视频上的表现形式和行为。区域类型OVERLAY可以任意画内容的 Bitmap 图层。可以放任意像素所以可以显示logo、文字、图标等等。OVERLAY扩展版 Overlay仍然是一张 Bitmap。在 VPSS 等更早阶段做更灵活的图片图层代价就是消耗更多带宽。COVER用纯色遮挡一个区域实现隐私遮挡等功能。COVEREX除了普通矩形它还能支持更灵活的形状和坐标例如四边形框。因为工作方式扩展了所以会经过更灵活的图形处理通路可能增加带宽。LINE / LINEEX本质就是从起点到终点的一条直线。可以调节粗细颜色。它不是 Bitmap硬件根据参数直接生成因此比在 Overlay 中画一条线更省内存。MOSAIC / MOSAICEX把指定区域变成马赛克。大小支持4x48x816x16...128x128CORNER_RECTEX它不会把整个矩形填满而是只绘制四个角。这里有好几个是EX版本比如COVER和COVEREX这种。其实类似这种就是一个扩展版本更加灵活但是更加消耗带宽。区域层次当多个区域在视频上发生位置重叠时需要由区域层次来决定谁显示在最上面。层次值越大区域的显示级别就越高会覆盖层次值较小的区域。如果两个区域的层次值相同则后附加attach的区域会覆盖先附加的区域。对于不同类型的区域则以其内部模块的处理顺序为准。模块类型最大数量VENCOverlay8VPSSOverlayEX8VPSSCoverEX8VPSSLineEX40VPSSMosaic12VPSSMosaicEX8VPSSCornerRect12VPSSCornerRectEX32这个表的含义是不同模块支持哪些类型的REGION以及最多挂几个。VENC 负责把未压缩视频压缩成码流就是负责编码。VPSS 主要负责一帧图像进入编码器之前的处理负责缩放、裁剪和多路输出内部有更多图形处理能力。SDK中有定义最多可以创建 16 个逻辑 VENC 编码通道。但是不是理论上“16 个 VENC × 每通道 8 个 Overlay”是128个。不能这么理解全部按最大的乘。要按实际需求来使用。最多 16 个 VPSS Group一个 Group 总共最多 8 个逻辑输出通道四个物理通道可能还有四个逻辑扩展通道。大家看到这里应该挺蒙的这么多参数到底哪个是哪个我一个REGION应该这么区分1. HandleRegion 编号2. TypeOverlay、Cover、Line 等3. Target挂在 VENC 还是 VPSS4. Group/Channel挂在哪个通道5. Layer多个图层重叠时的层级就从这五个来进行区分示例实现#define OSD_HANDLE 0 #define OSD_WIDTH 640 #define OSD_HEIGHT 72 #define OSD_SCALE 3 #define OSD_TEXT_X 18 #define OSD_TEXT_Y 24 #define OSD_COLOR_BG 0x8000 #define OSD_COLOR_FG 0xffff #define OSD_COLOR_ACCENT 0xfc00宏含义OSD_HANDLE 0使用 0 号 RegionOSD_WIDTH 640位图宽度 640 像素OSD_HEIGHT 72位图高度 72 像素OSD_SCALE 3字体放大 3 倍OSD_TEXT_X 18文字在 Bitmap 内的 X 坐标OSD_TEXT_Y 24文字在 Bitmap 内的 Y 坐标OSD_COLOR_BG不透明黑色背景OSD_COLOR_FG白色文字OSD_COLOR_ACCENT红色装饰条Hi3519DV500 的这个 OSD 模式下不支持半透明渐变因为ARGB1555 的 Alpha A只有 1 位要么透明要么不透明。static td_bool g_osd_started TD_FALSE; static volatile td_bool g_osd_running TD_FALSE; static pthread_t g_osd_thread; static td_u8 *g_osd_bitmap TD_NULL;g_osd_started防止重复创建 Regiong_osd_running控制时间刷新线程g_osd_threadOSD 更新线程g_osd_bitmap保存 640×72 ARGB1555 像素内存点阵文字这里绘制的图片都是要以像素点为单位来进行绘制的这个就是0static const td_u8 font_digit_0[7] { 0x0e, 0x11, 0x13, 0x15, 0x19, 0x11, 0x0e };这里0代表不绘制1代表绘制就可以得到右边这个格式的0但是这个0是放大三倍后的这里的放大三倍是指像素点变为3x3不是我们手机上的放大的含义。核心函数static td_void sample_vio_osd_draw_text( td_u8 *data, td_u32 width, td_u32 height, td_u32 x, td_u32 y, const td_char *text)处理过程从字符串第一个字符开始。找到字符对应的点阵。遍历点阵的 7 行、5 列。如果该位置是 1就画一个3×3的白色方块。绘制完成后X 坐标增加 18。到达 Bitmap 右边后停止。生成整张OSD位图sample_vio_osd_render() //清空画布 memset_s(...); //填充不透明黑色背景 for (i 0; i OSD_WIDTH * OSD_HEIGHT; i) { ((td_u16 *)g_osd_bitmap)[i] OSD_COLOR_BG; } //绘制顶部红色装饰条 for (i 0; i OSD_WIDTH * 4; i) { ((td_u16 *)g_osd_bitmap)[i] OSD_COLOR_ACCENT; } //获取板端本地时间 time_t now time(TD_NULL); struct tm local_time; localtime_r(now, local_time); //格式化字符串 snprintf_s( text, sizeof(text), sizeof(text) - 1, IMX385 OSD %04d-%02d-%02d %02d:%02d:%02d, local_time.tm_year 1900, local_time.tm_mon 1, local_time.tm_mday, local_time.tm_hour, local_time.tm_min, local_time.tm_sec); //把文字画进 Bitmap sample_vio_osd_draw_text( g_osd_bitmap, OSD_WIDTH, OSD_HEIGHT, OSD_TEXT_X, OSD_TEXT_Y, text); //发送给 RGN 硬件 ot_bmp bmp; bmp.pixel_format OT_PIXEL_FORMAT_ARGB_1555; bmp.width OSD_WIDTH; bmp.height OSD_HEIGHT; bmp.data g_osd_bitmap; ss_mpi_rgn_set_bmp(handle, bmp);首先第一步清空画布然后把整个REGION填充为黑色在给一个红色装饰条然后获取实际格式化字符串这个就是得到我们要显示的内容然后把这个文字在写入g_osd_bitmap中然后把最后的bmp和编号给RGN硬件。到这一步软件把一张完整 Bitmap 交给底层 RGN。这里注意比如我们要显示hellog_osd_bitmap存放的可不是hello是对应的一个个像素。创建REGIONot_rgn_attr region {0}; region.type OT_RGN_OVERLAY; region.attr.overlay.pixel_format OT_PIXEL_FORMAT_ARGB_1555; region.attr.overlay.size.width 640; region.attr.overlay.size.height 72; region.attr.overlay.bg_color 0x8000; region.attr.overlay.canvas_num 2; ss_mpi_rgn_create(OSD_HANDLE, region);含义向 MPP 申请一个 Region 资源Handle 使用 0类型为 Overlay像素格式为 ARGB1555尺寸为 640×72申请 2 个 Canvas 缓冲区把REGION绑定到VENCot_mpp_chn venc_chn; venc_chn.mod_id OT_ID_VENC; venc_chn.dev_id 0; venc_chn.chn_id 0; ot_rgn_chn_attr chn_attr {0}; chn_attr.is_show TD_TRUE; chn_attr.type OT_RGN_OVERLAY; chn_attr.attr.overlay_chn.point.x 24; chn_attr.attr.overlay_chn.point.y 24; chn_attr.attr.overlay_chn.fg_alpha 255; chn_attr.attr.overlay_chn.bg_alpha 255; chn_attr.attr.overlay_chn.layer 0; ss_mpi_rgn_attach_to_chn( OSD_HANDLE, venc_chn, chn_attr);VENC 设备 0通道 0后面为属性显示 RegionBitmap 左上角位于视频(24,24)前景 Alpha 255背景 Alpha 255图层为 0时间刷新线程while (g_osd_running g_sig_flag 0) { sample_vio_osd_render(handle); sleep(1); }秒重新获取时间重新绘制 Bitmap调用ss_mpi_rgn_set_bmp()更新 Region接到视频启动流程ret sample_vio_start_venc_and_vo(...); if (ret ! TD_SUCCESS) { goto start_venc_and_vo_failed; } if (sample_vio_osd_start() ! TD_SUCCESS) { printf(OSD demo failed; video streaming continues.\n); }停止流程sample_vio_osd_stop(); sample_vio_stop_venc_and_vo(...); g_osd_running TD_FALSE; pthread_join(g_osd_thread, TD_NULL); ss_mpi_rgn_detach_from_chn(OSD_HANDLE, venc_chn); ss_mpi_rgn_destroy(OSD_HANDLE); free(g_osd_bitmap); g_osd_bitmap TD_NULL;补充概念canvas它只属于带位图Bitmap的 region也就是overlay和overlayex。取值只能为1/21就是没有缓存2就是有缓存。它的作用在于对刷新频繁的位图进行刷新比如现在显示canvas0后台可以更新canvas1canvas1在下一次被选中。也就是一块正在显示一块正在被改写。硬件读 canvas 0 显示set_bmp() 写 canvas 1写完后驱动切换硬件改读 canvas 1canvas 0 变成后台。(CPU写硬件读)typedef struct { td_phys_addr_t phys_addr; // 物理地址 ot_size size; // 画布宽高 td_u32 stride; // 每行字节数可能带对齐 ot_pixel_format pixel_format; // 像素格式 td_void *virt_addr; // 用户态虚拟地址 } ot_rgn_canvas_info;最后要把OSD的内容加到视频中其实就是把canvas加到了视频中。但是canvas这里还是ARGB1555不过这些数据放到了驱动内存中这块内存是映射好的DMA可以进行读取的。这里主要有三个类型regionbmp和chn_attrregionregion.type OT_RGN_OVERLAY; region.attr.overlay.pixel_format OT_PIXEL_FORMAT_ARGB_1555; region.attr.overlay.size.width LOGO_WIDTH; region.attr.overlay.size.height LOGO_HEIGHT; region.attr.overlay.bg_color 0x0000; region.attr.overlay.canvas_num 1;type这里指定哪种OSD要创建哪种类型的regionattr.overlay.pixel_format表示创建的canvas是什么来表示的attr.overlay.size.width/attr.overlay.size.hight,这里表示我这个region的宽和高这里不是logo的宽和高但是一般设置为一样overlay.bg_color表示region的背景颜色为ARGBoverlay.canvas_num表示有几个画布用于缓存上面已经讲解。bmpbmp.pixel_format OT_PIXEL_FORMAT_ARGB_1555; bmp.width LOGO_WIDTH; bmp.height LOGO_HEIGHT; bmp.data g_logo_bitmap;pixel_format表示我传进去的数据是什么格式最好和region保持一致width/heigh这个就表示logo的宽和高data表示用户内存要传入的数据chn_attrchn_attr.is_show TD_TRUE; chn_attr.type OT_RGN_OVERLAY; chn_attr.attr.overlay_chn.point.x LOGO_X; chn_attr.attr.overlay_chn.point.y LOGO_Y; chn_attr.attr.overlay_chn.fg_alpha 255; chn_attr.attr.overlay_chn.bg_alpha 0; chn_attr.attr.overlay_chn.layer 1; chn_attr.attr.overlay_chn.dst OT_RGN_ATTACH_JPEG_MAIN;这个 region 在某个通道上的显示配置把 handle 这个 region绑定到 venc_chn 这个通道按照 chn_attr 的参数显示is_show表示是否显示这个区域type表示按这个类型来解释和region的type要对上attr.overlay_chn.point.x/attr.overlay_chn.point.y表示region的位置attr.overlay_chn.fg_alpha/attr.overlay_chn.bg_alpha表示前景和背景背景就是region设置的背景前景就是bmp画出来的东西ARGB中A为1