1.准备素材图片
D1s的显示引擎支持很多种像素格式,这里我只测试2种:
1.DISP_FORMAT_ARGB_8888 = 0x00
2.DISP_FORMAT_YUV420_SP_UVUV = 0x4c,
在 《D1s-Melis\ekernel\drivers\include\hal\sunxi_display2.h》 可以看到所有的格式,这里摘选部分:
enum disp_pixel_format {
DISP_FORMAT_ARGB_8888 = 0x00,/* MSB A-R-G-B LSB */
DISP_FORMAT_ABGR_8888 = 0x01,
DISP_FORMAT_RGBA_8888 = 0x02,
DISP_FORMAT_BGRA_8888 = 0x03,
......
DISP_FORMAT_YUV420_SP_UVUV = 0x4c,
......
DISP_FORMAT_YUV411_SP_VUVU_10BIT = 0x60,
DISP_FORMAT_MAX,
};
1.1 测试图片像素格式的软件RawViewer.exe
RawViewer.exe可以在《https://gitee.com/lindenis/lindenis-v833-rtos-melis-4.0/tree/master/document/user-docs/data_test/g2d-scale-test/software》这里下载。是官方v833-rtos-melis-4.0 SDK的一部分。当然这个链接不是官方的仓库。
软件所在的文件夹有一些图片素材:
《g2d-scale-test》
bike_320x240_020.bin
bike_480x320_220.bin
bike_960x640_221.bin
《g2d-blend-test》
333_333_rgb.bin
bike_480x320_150.bin
bike_480x320_220.bin
bike_720x480_150.bin
memin-800x480-220.bin
src2_800x480_rgb.bin
src_800x480_rgb.bin
1.1.1 使用方法
这里测试了 bike_480x320_220.bin ,颜色空间为NV21(对应的像素格式DISP_FORMAT_YUV420_SP_UVUV = 0x4c)
再测试 src_800x480_rgb.bin ,这次颜色空间选择“智能检测”:
被RawViewer.exe检测到颜色空间为ARGB的文件,在melis中使用像素格式 DISP_FORMAT_ARGB_8888 = 0x00 可以正确显示。
1.2 自己生成测试图片
如果想自己生成测试图片,可以使用ffmpeg。在ffmpeg官网下载下载windows平台的可执行文件使用下面的命令可以得到测试素材:
ffmpeg -i girl_800_480.jpg -vcodec rawvideo -pix_fmt bgra girl_800_480_argb.rgb
参数 | 取值 | 含义 |
---|---|---|
-i | girl_800_480.jpg | 输入文件名 |
-pix_fmt | bgra | 输出格式 |
最后一个参数 | girl_800_480_argb.rgb | 输出文件名 |
使用以上命令,得到的文件《girl_800_480_argb.rgb》,使用RawViewer.exe智能识别得到两种格式ARGB和ABGR,其中 ARGB 为正确格式。
2.D1s显示引擎介绍(不保证正确)
官方文档 RTOS_Display_开发指南.pdf 介绍了显示引擎,可能由于本人没有相关的基础,看得云里雾里。
这里说说我自己的理解(有可能是错误的):
结合上图和《D1s-Melis\ekernel\drivers\hal\source\disp2\disp\de\lowlevel_v2x\de_feat.c》源文件,说说我的理解:
2.1 D1s 可以有2个独立的display device输出(可以同时接2个显示器)
分别是LCD和TV, 这里使用了DISP0,对应的是 LCD接口。
static const int sun20iw1_de_supported_output_types[] = {
/* DISP0 */
DE_OUTPUT_TYPE_LCD,
/* DISP1 */
DE_OUTPUT_TYPE_TV | DE_OUTPUT_TYPE_HDMI,
};
2.2 D1s 的 DISP0 有2个通道(channel),每个通道有4个图层(layer)
DISP0有2个通道,每个通道可以同时处理接受 4 个格式相同的图层,总共可以接受 2 x 4 =8个图层的输入数据,通过混合处理后,合并输出到LCD上。
• 支持多图层叠加混合处理
• 支持多种显示效果处理(alpha, colorkey, 图像增强,亮度/对比度/饱和度/色度调整)
• 支持多种图像数据格式输入 (argb,yuv)
• 支持图像缩放处理
static const int sun20iw1_de_num_chns[] = {
/* DISP0 */
2,
/* DISP1 */
1,
};
2.3 D1s每个通道有4个图层
上面说了DISP0有2个通道,这里怎么有3个通道?不理解。 下面的两点理解也不知道是否正确:
1----DISP0的通道0是视频通道。视频通道功能强大,可以支持YUV 格式和 RGB 图层。
2----DISP0的通道1是UI 通道,只支持 RGB 图层。
static const int sun20iw1_de_num_layers[] = {
/* DISP0 CH0 */
4,
/* DISP0 CH1 */
4,
/* DISP0 CH2 */
4,
};
2.4 每个图层有一个显示顺序参数zorder
当各个图层的透明度都是alpha=255时,图层会相互覆盖。zorder的范围是 0-15,数值越大,显示越靠前。比如我现在使用了 ch【0】layer【0】 图层显示视频,ch【1】layer【0】图层显示UI。把 ch【0】layer【0】的zorder固定为1,当ch【1】layer【0】的zorder设置为0时,显示视频;当ch【1】layer【0】的zorder设置为2时,显示UI。
3.测试透明度实例
有了上面的知识储备,下面我开始测试显示像素格式、透明度和显示顺序。
通过修改《D1s-Melis\ekernel\drivers\hal\test\disp2\disp_layer_alpha_test.c》源码来测试。
3.1 vi图层设置为yuv格式,ui图层设置为RGB格式
配置UI图层,channel = 0,layer = 0,format = 76(0x4C,DISP_FORMAT_YUV420_SP_UVUV),zorder = 1,
disp_mem(1, 480, 320, 0, "F:\\pic\\bike_480x320_220.bin");
static int show_vi_layer(struct test_layer_cfg *cfg, u32 alpha_mode, u32 alpha_value,bool isEnable)
{
......
cfg->layer_cfg.layer_id = 0;
cfg->mem_id = 1;
cfg->layer_cfg.channel = 0;
cfg->layer_cfg.info.fb.format = 76;
cfg->layer_cfg.info.fb.size[0].width = 480;
cfg->layer_cfg.info.fb.size[0].height = 320;
cfg->layer_cfg.info.fb.crop.x = 0;
cfg->layer_cfg.info.fb.crop.y = 0;
cfg->layer_cfg.info.fb.crop.width = 480;
cfg->layer_cfg.info.fb.crop.height = 320;
......
}
配置UI图层,channel = 1,layer = 0,format = 0(0x00,ARGB),zorder 可以改变。
disp_mem(0, 800, 480, 0, "F:\\pic\\girl_800_480_argb.bin");
static int show_ui_layer(struct test_layer_cfg *cfg,u32 ch,
u32 alpha_mode, u32 alpha_value,unsigned char zorder)
{
......
cfg->mem_id = 0;
cfg->layer_cfg.channel = 1;
cfg->layer_cfg.info.fb.size[0].width = 800;
cfg->layer_cfg.info.fb.size[0].height = 480;
cfg->layer_cfg.info.fb.crop.x = 0;
cfg->layer_cfg.info.fb.crop.y = 0;
cfg->layer_cfg.info.fb.crop.width = 800;
cfg->layer_cfg.info.fb.crop.height = 480;
cfg->layer_cfg.info.alpha_mode = alpha_mode;
cfg->layer_cfg.info.alpha_value = alpha_value;
//cfg->layer_cfg.info.zorder = 0;
cfg->layer_cfg.info.zorder = zorder;
......
}
3.2 透明度测试
alpha_mode有3种模式,其中当ui图层设置为0(pixel alpha)时,无法和vi图层混合,故将该部分测试代码屏蔽。
0: pixel alpha;
1: global alpha;
2: global pixel alpha
#define DELAY_MS 300
ch_index = 1;
__log("set ui ch%d lyr0 to global_alpha=255.\n",ch_index);
show_ui_layer(&test_cfg, ch_index, 1, 255,2);
msleep(2000);
msleep(DELAY_MS);
/*pixel mode*/
for (i = 0; i < 255; i+=25) {
//show_ui_layer(*cfg,ch, alpha_mode, alpha_value, zorder)
show_ui_layer(&test_cfg, ch_index, 1, i,2);
msleep(DELAY_MS);
}
msleep(DELAY_MS);
#if 0 // 这部分代码没有效果,故注释
__log("set ui ch%d lyr0 to pixel_alpha=255.\n",ch_index);
show_ui_layer(&test_cfg, ch_index, 0, 255,1);
msleep(2000);
msleep(DELAY_MS);
/*pixel mode*/
for (i = 0; i < 255; i+=25) {
show_ui_layer(&test_cfg, ch_index, 0, i,1);
msleep(DELAY_MS);
}
#endif
/*global pixel mode*/
msleep(2000);
for (i = 0; i < 255; i+=25) {
show_ui_layer(&test_cfg, ch_index, 2, i,2);
msleep(DELAY_MS);
}
//msleep(2000);
这段代码的效果:
使用disp命令查看当前的图层参数:
msh />disp
screen 0:
de_rate 300000000 hz, ref_fps: 59
mgr0: 800x480 fmt[rgb] cs[0x204] range[full] eotf[0x4] bits[8bits] err[0] force_sync[0] unblank direct_show[false]
dmabuf: cache[0] cache max[0] umap skip[0] overflow[0]
lcd output backlight(192) fps:58.4 800x 480
err:0 skip:8 irq:26775 vsync:0 vsync_skip:0
# ch[0] lyr[0]是vi图层,zorder 为 1
BUF enable ch[0] lyr[0] z[1] prem[N] a[pixel 0] fmt[ 76] fb[ 480, 320; 240, 160; 240, 160] crop[ 0, 0, 480, 320] frame[ 0, 0, 480, 320] addr[0x41250000,0x41275800,0x4127ee00] flags[0x 0] trd[0,0]
# ch[1] lyr[0]是ui图层,zorder 为 2
BUF enable ch[1] lyr[0] z[2] prem[N] a[globl 250] fmt[ 0] fb[ 800, 480; 800, 480; 800, 480] crop[ 0, 0, 800, 480] frame[ 0, 0, 800, 480] addr[0x41457000,0x41476400,0x41495800] flags[0x 0] trd[0,0]
3.3 改变图层透明度和显示顺序
3.3.1 修改源码增加测试参数
在原有的基础上,增加[1]=mode [2]=alpha [3]=zorder 这3个参数。
int disp_layer_alpha_test(int argc, char **argv)
{ ......
if(argc == 4){ // [1]=mode [2]=alpha [3]=zorder
mode = atoi(argv[1]);
alpha = atoi(argv[2]);
i = atoi(argv[3]);
show_ui_layer(&test_cfg, 1, mode, alpha,(unsigned char)i);
return 0;
} else
g_screen_index = 0;
......
}
FINSH_FUNCTION_EXPORT_ALIAS(disp_layer_alpha_test, __cmd_disp_layer_alpha_test, disp_layer_alpha_test);
3.3.2 测试alpha参数
使用 disp_layer_alpha_test 命令后,图层参数如下:
# 不带参数
msh />disp_layer_alpha_test
msh />disp
# ch[0] lyr[0]是vi图层,alpha_mode = 0 (pixel alpha),alpha = 0,zorder 为 1
BUF enable ch[0] lyr[0] z[1] prem[N] a[pixel 0] fmt[ 76]
# ch[1] lyr[0]是ui图层,alpha_mode = 2 (global pixel alpha),alpha = 250,zorder 为 2
BUF enable ch[1] lyr[0] z[2] prem[N] a[globl 250] fmt[ 0]
3.3.2.1 改变alpha值:disp_layer_alpha_test mode alpha=x zorder
只改变alpha = 30:
disp_layer_alpha_test 2 30 2
效果:
再改变alpha = 100:
disp_layer_alpha_test 2 100 2
效果:
最后改变alpha = 255:
disp_layer_alpha_test 2 255 2
效果:
3.3.3 测试zorder参数
如果图层不混合显示时,alpha值应该设置为最大255 。
接着上面的状态,使用disp命令查看图层参数(此时ui图层在vi图层的上面):
msh />disp
# ch[0] lyr[0]是vi图层,alpha_mode = 0 (pixel alpha),alpha = 0,zorder 为 1
BUF enable ch[0] lyr[0] z[1] prem[N] a[pixel 0] fmt[ 76] fb[ 480, 320; 240, 160; 240, 160] crop[ 0, 0, 480, 320] frame[ 0, 0, 480, 320] addr[0x41250000,0x41275800,0x4127ee00] flags[0x 0] trd[0,0]
# ch[1] lyr[0]是ui图层,alpha_mode = 2 (global pixel alpha),alpha = 255,zorder 为 2
BUF enable ch[1] lyr[0] z[0] prem[N] a[globl 255] fmt[ 0] fb[ 800, 480; 800, 480; 800, 480] crop[ 0, 0, 800, 480] frame[ 0, 0, 800, 480] addr[0x41457000,0x41476400,0x41495800] flags[0x 0] trd[0,0]
使ui图层的zorder = 0:
disp_layer_alpha_test 2 255 0
效果(此时ui图层在vi图层的下面):
4.完整测试代码
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <rtthread.h>
#include <hal_mem.h>
#include <log.h>
#include <video/sunxi_display2.h>
#include "disp_layer_cfg.h"
#include "disp_mem.h"
int msleep(unsigned int msecs);
static u32 g_screen_index;
#define DELAY_MS 300
static int show_vi_layer(struct test_layer_cfg *cfg, u32 alpha_mode, u32 alpha_value,bool isEnable)
{
if (!cfg)
return -1;
cfg->mem_id = 1;
cfg->screen_id = g_screen_index;
cfg->layer_cfg.channel = 0;
cfg->layer_id = 0;
cfg->layer_cfg.layer_id = 0;
cfg->layer_cfg.enable = isEnable;
cfg->layer_cfg.info.fb.format = 76;
cfg->layer_cfg.info.fb.size[0].width = 480;
cfg->layer_cfg.info.fb.size[0].height = 320;
cfg->layer_cfg.info.fb.crop.x = 0;
cfg->layer_cfg.info.fb.crop.y = 0;
cfg->layer_cfg.info.fb.crop.width = 480;
cfg->layer_cfg.info.fb.crop.height = 320;
cfg->layer_cfg.info.fb.align[0] = 4;
cfg->layer_cfg.info.mode = 0;
cfg->layer_cfg.info.alpha_mode = alpha_mode;
cfg->layer_cfg.info.alpha_value = alpha_value;
cfg->layer_cfg.info.zorder = 1;
cfg->layer_cfg.info.screen_win.x = 0;
cfg->layer_cfg.info.screen_win.y = 0;
return disp_layer_cfg(cfg);
}
//static int show_ui_layer(struct test_layer_cfg *cfg,u32 ch, u32 alpha_mode, u32 alpha_value)
static int show_ui_layer(struct test_layer_cfg *cfg,u32 ch,
u32 alpha_mode, u32 alpha_value,unsigned char zorder)
{
if (!cfg)
return -1;
cfg->mem_id = 0;
cfg->screen_id = g_screen_index;
cfg->layer_cfg.channel = ch;
cfg->layer_id = 0;
cfg->layer_cfg.layer_id = 0;
cfg->layer_cfg.enable = 1;
//cfg->layer_cfg.enable = isEnable;
cfg->layer_cfg.info.fb.format = 0;
cfg->layer_cfg.info.fb.size[0].width = 800;
cfg->layer_cfg.info.fb.size[0].height = 480;
cfg->layer_cfg.info.fb.crop.x = 0;
cfg->layer_cfg.info.fb.crop.y = 0;
cfg->layer_cfg.info.fb.crop.width = 800;
cfg->layer_cfg.info.fb.crop.height = 480;
cfg->layer_cfg.info.fb.align[0] = 4;
cfg->layer_cfg.info.mode = 0;
cfg->layer_cfg.info.alpha_mode = alpha_mode;
cfg->layer_cfg.info.alpha_value = alpha_value;
//cfg->layer_cfg.info.zorder = 0;
cfg->layer_cfg.info.zorder = zorder;
cfg->layer_cfg.info.screen_win.x = 0;
cfg->layer_cfg.info.screen_win.y = 0;
cfg->layer_cfg.info.screen_win.width = 800;
cfg->layer_cfg.info.screen_win.height = 480;
return disp_layer_cfg(cfg);
}
int disp_layer_alpha_test(int argc, char **argv)
{
struct test_layer_cfg test_cfg;
int ch_index = 0, i , j;
int ch_num = 3, vi_chn_num = 1;
u32 mode,alpha;
/*main test start*/
memset(&test_cfg, 0, sizeof(struct test_layer_cfg));
if (argc == 2) {
//g_screen_index = atoi(argv[1]);
// 如果带有一个参数,这个参数就是zorder
i = atoi(argv[1]);
show_ui_layer(&test_cfg, 1, 0, 0,(unsigned char)i);
return 0;
}else if(argc == 4){ // [1]=mode [2]=alpha [3]=zorder
mode = atoi(argv[1]);
alpha = atoi(argv[2]);
i = atoi(argv[3]);
show_ui_layer(&test_cfg, 1, mode, alpha,(unsigned char)i);
return 0;
} else
g_screen_index = 0;
disp_layer_clear_all(g_screen_index);
printf("request mem_id 0,800, 480,\n");
disp_mem(0, 800, 480, 0, "F:\\pic\\girl_800_480_argb.bin");
printf("request mem_id 1,480, 320,\n");
disp_mem(1, 480, 320, 0, "F:\\pic\\bike_480x320_220.bin");
printf("Start show layer\n");
show_vi_layer(&test_cfg, 0, 0,1);
memset(&test_cfg, 0, sizeof(struct test_layer_cfg));
msleep(DELAY_MS);
ch_index = vi_chn_num;
__log("set ui ch%d lyr0 to global_alpha=255.\n",ch_index);
show_ui_layer(&test_cfg, ch_index, 1, 255,2);
msleep(2000);
msleep(DELAY_MS);
/*pixel mode*/
for (i = 0; i < 255; i+=25) {
show_ui_layer(&test_cfg, ch_index, 1, i,2);
msleep(DELAY_MS);
}
msleep(DELAY_MS);
#if 0
__log("set ui ch%d lyr0 to pixel_alpha=255.\n",ch_index);
show_ui_layer(&test_cfg, ch_index, 0, 255,1);
msleep(2000);
msleep(DELAY_MS);
/*pixel mode*/
for (i = 0; i < 255; i+=25) {
show_ui_layer(&test_cfg, ch_index, 0, i,1);
msleep(DELAY_MS);
}
#endif
/*global pixel mode*/
__log("set ui ch%d lyr0 to global pixel=0.\n",ch_index);
msleep(2000);
for (i = 0; i < 255; i+=25) {
show_ui_layer(&test_cfg, ch_index, 2, i,2);
msleep(DELAY_MS);
}
//msleep(2000);
__log("exit.\n");
return 0;
}
FINSH_FUNCTION_EXPORT_ALIAS(disp_layer_alpha_test, __cmd_disp_layer_alpha_test, disp_layer_alpha_test);
5. 测试cedar多媒体解码库,视频和lvgl混合显示
请阅读下一篇文章:《Melis4.0[D1s]:9.测试cedar多媒体解码库,视频和lvgl混合显示》。