启动卡在这,就不会动了,然后也无法烧录了,有什么办法烧录程序?
Posts made by bigfly
-
100ask-t113pro lvds调试问题
RGB屏是可以正常显示的,但是配置完lvds设备树内容,显示异常,用fbshow写图片无法显示
设备树lvds配置如下:&lcd0 { lcd_used = <1>; lcd_driver_name = "default_lcd"; lcd_backlight = <50>; lcd_if = <3>; lcd_x = <800>; lcd_y = <600>; lcd_width = <108>; lcd_height = <94>; lcd_dclk_freq = <39>; lcd_pwm_used = <1>; lcd_pwm_ch = <7>; lcd_pwm_freq = <50000>; lcd_pwm_pol = <0>; lcd_hbp = <88>; lcd_ht = <1024>; lcd_hspw = <64>; lcd_vbp = <15>; lcd_vt = <625>; lcd_vspw = <6>; lcd_lvds_if = <0>; lcd_lvds_colordepth = <0>; lcd_lvds_mode = <1>; lcd_frm = <0>; lcd_io_phase = <0x0000>; lcd_gamma_en = <0>; lcd_bright_curve_en = <0>; lcd_cmap_en = <0>; deu_mode = <0>; lcdgamma4iep = <22>; smart_color = <90>; pinctrl-0 = <&lvds0_pins_a>; pinctrl-1 = <&lvds0_pins_b>; };
请问哪里配置不对吗
-
百问网V853开发板 setusbconfig hid创建hid设备失败
V853开发板,在做usb gadget开发,这板子USB有点毛病,要开下面两条命令后才能用ADB
cat /sys/devices/platform/soc/usbc0/usb_host cat /sys/devices/platform/soc/usbc0/usb_device
而且开第一条命令的时候会不停报错
做mass_storage时也是需要先setusbconfig mass_storage,在重复上面的命令才能用,不过这个问题先放一边。
我把全志D1的setusbconfig脚本替代了我板子上原本的脚本,ADB,mass_storage还是能使用,参考d1-tina-linux-usb-开发指南,开启了内核的HID function
编译,打包,烧入,开机,先关ADB
killall adbd 2>/dev/null setusbconfig none cat /sys/devices/platform/soc/usbc0/usb_null
然后setusbconfig hid,报错
我用命令对/sys/kernel/config/usb_gadget/g1手动配置也是这样的结果
实在没办法了,网上也找不到相关解决办法,求大神解答!
-
芒果派T113编译的时候为什么一直让我配置内核的一些选项?
配置编译的环境来编译驱动,我设置了交叉编译链,还有ARCH参数,以及内核路径,但是我执行make的时候会一直让我配置内核的一些选项,这个是编译时的输出
这个是我的makefile
-
linux下编译完成后打包安全固件失败
linux下编译完成后执行:./build.sh pack_secure
报错
ERROR: dragon toc0 run error
-
Melis4.0测试cedar多媒体解码库,视频和lvgl混合显示
1.测试audio_test命令播放mp3
首先要把cedar模块编译进内核:在 melis 的根目录执行 make menuconfig 命令,选中 cedar 模块。
Modules Setup -->cedar module support
测试命令也包含进来:
Kernel Setup --> Drivers Test Sample --> cedar Test
编译,烧录,运行,输入help命令可以看到下面的命令:
msh />help ...... cedar_close - cedar_close cedar_test - cedar_test audio_close_test - audio_close_test audio_test - audio_play_test ......
1.1 finish命令中文件路径的写法(测试)
audio_test命令的格式为:
audio_test [文件名]
我的sd卡目录下有个 mp3 文件夹,在finish中进入文件夹后的路径为:
cd /mnt/F/mp3 msh /mnt/F/mp3>ls 1906.真的爱你-Beyond.mp3 1912.千千阙歌-陈慧娴.mp3 1916.红日-李克勤.mp3 1917.都是你的错-陈慧琳.mp3 1917.都是你的错65k.mp3 distance.mp3
这时,我要播放distance.mp3,我使用了下面4种路径:
audio_test /mnt/F/mp3/distance.mp3 ------- 播放失败 audio_test \\mnt\\F\\mp3\\distance.mp3 ------- 播放失败 audio_test F:\\mp3\\distance.mp3 ======= 播放成功 audio_test F:/mp3/distance.mp3 ------- 播放失败
只有一种路径是正确的:
audio_test F:\\mp3\\distance.mp3
测试播放纯音频文件不用考虑图层,比较简单。
2.测试cedar_test命令播放mp4
先禁止melis桌面加载,在《startup.sh》注释掉相关内容:
packecho "Execute startup script begin.............." #insmod d:\mod\orange.mod #insmod d:\apps\desktop.mod echo "...............Execute startup script end"
此时开机只显示全志logo。查询一下此时的图层信息:
msh />disp screen 0: # allwinner logo使用 ch[0] lyr[0]图层,alpha_mode = 0 (pixel alpha),alpha = 255,zorder 为 0 BUF enable ch[0] lyr[0] z[0] prem[N] a[pixel 255] fmt[ 0] fb[ 640, 480; 640, 480; 640, 480] crop[ 0, 0, 640, 480] frame[ 80, 0, 640, 480] addr[0x4132b000,0x00000000,0x00000000] flags[0x 0] trd[0,0]
alpha = 255属于全覆盖,不和其他图层混合显示。zorder=0表示最底层,其他图层只要大于0就会覆盖它。当然,覆盖是在图层都是alpha=255的情况下。
2.1 不清除logo图层,无法显示视频
在这种情况下,使用cedar_test播放视频,只有声音,没有图像。
msh />cedar_test F:\\hanfu02.mp4
这种情况下,查看一下图层信息(可以看到2个图层都属于ch[0],图层格式一个是RGB,一个是YUV):
msh />disp screen 0: BUF enable ch[0] lyr[0] z[0] prem[N] a[pixel 255] fmt[ 0] fb[ 640, 480; 640, 480; 640, 480] crop[ 0, 0, 640, 480] frame[ 80, 0, 640, 480] addr[0x4132b000,0x00000000,0x00000000] flags[0x 0] trd[0,0] BUF enable ch[0] lyr[1] z[1] prem[N] a[pixel 0] fmt[ 72] fb[1280, 720; 640, 360; 640, 360] crop[ 0, 0,1280, 720] frame[ 0, 15, 800, 450] addr[0x42b2d000,0x00000000,0x4273a000] flags[0x 0] trd[0,0]
这里是不是说同一通道的4图层,只能使用相同的格式?2.2 使用disp_layer_alpha_test命令清除logo图层,正常播放视频的disp_layer_alpha_test命令再修改一下:
int disp_layer_alpha_test(int argc, char **argv) { ...... if (argc == 2) { // 如果带有一个参数,不用理会参数是什么,清除所有图层 disp_layer_clear_all(0); return 0; }else if(argc == 4){ // 带3个参数,分别是: [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; ...... }
输入下面的命令,注意:只带一个参数。
msh />disp_layer_alpha_test 0
查询图层信息(可以看到没有图层信息):
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:77961 skip:16 irq:124292 vsync:0 vsync_skip:0
现在才可以正常播放视频。播放完毕后,查询图层信息:
msh />disp screen 0: # vi图层ch[0] lyr[1]是,alpha_mode = 0 (pixel alpha),alpha = 0,format = 72,zorder 为 1 BUF enable ch[0] lyr[1] z[1] prem[N] a[pixel 0] fmt[ 72] fb[1280, 720; 640, 360; 640, 360] crop[ 0, 0,1280, 720] frame[ 0, 15, 800, 450] addr[0x42b2d000,0x00000000,0x4273a000] flags[0x 0] trd[0,0]
3. lvgl设置
3.1 ui图层配置
lvgl属于ui图层,所以使用ch[1] lyr[0] ,alpha_mode = 2 (global pixel alpha),alpha = 255,format = 0(ARGB),zorder 为 2(zorder可以改变,其他参数固定)。仿照 show_ui_layer() 写一个show_lvgl_layer() 的函数:
int request_lvgl_layer(unsigned char zorder) { static int isMemInited=0; // struct test_layer_cfg test_cfg; struct test_layer_cfg *cfg = &test_cfg; memset(&test_cfg, 0, sizeof(struct test_layer_cfg)); printf("request mem_id 0,800, 480,\n"); // 第一次初始化,清除所有图层,申请内存;后面就不用了,只是改变zorder if(isMemInited == 0){ disp_layer_clear_all(g_screen_index); disp_mem(0, 800, 480, 0, "r"); memset(g_p_mem_base,0,800*480*4); } isMemInited = 1; cfg->mem_id = 0; cfg->screen_id = 0; cfg->layer_cfg.channel = 1; cfg->layer_id = 0; cfg->layer_cfg.layer_id = 0; 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 = 2; cfg->layer_cfg.info.alpha_value = 255; cfg->layer_cfg.info.zorder = zorder; cfg->layer_cfg.info.screen_win.x = 0; cfg->layer_cfg.info.screen_win.y = 0; return disp_layer_cfg(cfg); }
3.2 lvgl本身配置
参考文章《LVGL视频播放界面实现方法》。
需要在lv_conf.h中设置参数:
#define LV_COLOR_SCREEN_TRANSP 1
然后设置界面背景色的透明度,LV_OPA_0 为透明,LV_OPA_COVER为覆盖,根据需要配置:
/* init screen style */ static lv_style_t style_scr_act; lv_style_init(&style_scr_act); /* set style to LV_OPA_0 为透明,LV_OPA_COVER为覆盖*/ lv_style_set_bg_opa(&style_scr_act, LV_OPA_0); lv_obj_add_style(lv_scr_act(), &style_scr_act, 0);
测试界面源码:
void lv_example_btn_1(void) { // 创建一个组,稍后将需要使用键盘或编码器或按钮控制的部件(对象)添加进去,并且将输入设备和组关联 // 如果将这个组设置为默认组,那么对于那些在创建时会添加到默认组的部件(对象)就可以省略 lv_group_add_obj() lv_group_t * g = lv_group_create(); // 将上面创建的组设置为默认组 // 如果稍后创建的部件(对象),使用默认组那必须要在其创建之前设置好默认组,否则不生效 lv_group_set_default(g); // 将输入设备和组关联(使用前先打开上面注释掉的头文件) lv_indev_set_group(g_keypad_device_object, g); // 键盘 //lv_indev_set_group(lv_win32_encoder_device_object, g); // 鼠标上的滚轮(编码器) /* init screen style */ static lv_style_t style_scr_act; lv_style_init(&style_scr_act); /* set style to LV_OPA_0,no cover*/ lv_style_set_bg_opa(&style_scr_act, LV_OPA_0); lv_obj_add_style(lv_scr_act(), &style_scr_act, 0); #define RIGHT_OFFSET 40 /* 创建一个btn部件(对象) */ lv_obj_t * btn1 = lv_btn_create(lv_scr_act()); // 创建一个btn部件(对象),他的父对象是活动屏幕对象 lv_obj_set_size(btn1, 100, 50); lv_obj_align(btn1, LV_ALIGN_LEFT_MID, 140, 165); lv_obj_t * btn2 = lv_btn_create(lv_scr_act()); // 创建一个btn部件(对象),他的父对象是活动屏幕对象 lv_obj_set_size(btn2, 100, 50); lv_obj_align_to(btn2, btn1, LV_ALIGN_OUT_RIGHT_MID, RIGHT_OFFSET, 0); lv_obj_t * btn3 = lv_btn_create(lv_scr_act()); // 创建一个btn部件(对象),他的父对象是活动屏幕对象 lv_obj_set_size(btn3, 100, 50); lv_obj_align_to(btn3, btn2, LV_ALIGN_OUT_RIGHT_MID, RIGHT_OFFSET, 0); lv_obj_t * btn4 = lv_btn_create(lv_scr_act()); // 创建一个btn部件(对象),他的父对象是活动屏幕对象 lv_obj_set_size(btn4, 100, 50); lv_obj_align_to(btn4, btn3, LV_ALIGN_OUT_RIGHT_MID, RIGHT_OFFSET, 0); lv_obj_t * slider = lv_slider_create(lv_scr_act()); lv_obj_align(slider, LV_ALIGN_BOTTOM_MID, 0, -20); }
3.3 播放视频效果
播放视频效果(按键切换):
原文链接:https://blog.csdn.net/hwd00001/article/details/130145030
-
V853编译的vpm_run sample.txt出现segmentation fault怎么办呢?
想问一下V853编译的vpm_run sample.txt出现segmentation fault如何怎么办呢?
-
mango-MQ-R在移植好的lvgl添加物理按键
没有搞定D1s在Melis下的I2c驱动(gt911触摸屏)。先测试物理按键。
1.lvgl注册keypad驱动
##1.1 在melis的ADC按键中发送消息
先做好ADC按键的驱动,直接在驱动中发送消息。如何在rt-thread中使用消息队列发送消息,请参考官方资料: RT-Thread API参考手册-消息队列
1.1.1 创建消息队列,并初始化
相关代码在
D1s-Melis/ekernel/drivers/drv/source/input/keyboard/sunxi_keyboard.c
中。完整内容点击链接 sunxi_keyboard.c。/* 消息队列控制块 */ struct rt_messagequeue mq; /* 消息队列中用到的放置消息的内存池 */ static rt_uint8_t msg_pool[2048]; int sunxi_keyboard_init(void) { ...... rt_err_t result; /* 初始化消息队列 */ result = rt_mq_init(&mq, "mqt", &msg_pool[0], /* 内存池指向msg_pool */ 1, /* 每个消息的大小是 1 字节 */ sizeof(msg_pool), /* 内存池的大小是msg_pool的大小 */ RT_IPC_FLAG_FIFO); /* 如果有多个线程等待,按照先来先得到的方法分配消息 */ if (result != RT_EOK) { rt_kprintf("init message queue failed.\n"); return -1; } return 0; }
1.1.2 扫描按键时,发送按下和松开消息
这部分代码也在
sunxi_keyboard.c
中。int keyboard_irq_callback(uint32_t data_type, uint32_t data) { if (data_type == GPADC_UP && key_flag == 1) { ...... /* 发送按键松开消息到消息队列中 */ key_data->compare_later = 0xf6; result = rt_mq_send(&mq, &(key_data->compare_later), 1); if (result != RT_EOK) { rt_kprintf("rt_mq_send ERR\n"); } } ....... __log("key: %d",key_data->compare_before); /* 发送按键按下消息到消息队列中 */ result = rt_mq_send(&mq, &(key_data->compare_before), 1); if (result != RT_EOK) { rt_kprintf("rt_mq_send ERR\n"); } return 0; }
1.2 编写读取按键的回调函数
这里只是通过消息队列读取按键按下和松开的消息。
收到按键按下的消息值为0,1,2,3,4;
收到按键松开的消息值为0xF6.extern struct rt_messagequeue mq; uint8_t msgbyte; static void melis_keypad_driver_read_cb(lv_indev_drv_t* indev_drv, lv_indev_data_t* data) { /* 从消息队列中接收消息 */ if (rt_mq_recv(&mq, (void *)&msgbyte, sizeof(msgbyte), RT_WAITING_NO) == RT_EOK) { rt_kprintf("read_cb: recv msg:%d\n", msgbyte); data->state = LV_INDEV_STATE_PR; switch (msgbyte) { case 0: data->key = LV_KEY_PREV; break; case 1: data->key = LV_KEY_NEXT; break; case 2: data->key = LV_KEY_ENTER; break; case 3: data->key = LV_KEY_ENTER; break; case 4: data->key = LV_KEY_ESC; break; case 0xf6: data->state = LV_INDEV_STATE_REL; break; default: break; } } }
1.3 lvgl按键驱动注册
完成前面的准备工作后,就可以在 lv_main()中注册按键驱动,完成lvgl物理按键的初始化。
直接拷贝韦东山老师在windows下键盘的驱动,
00_lv_100ask_sim_codeblocks_win/lv_drivers/win32drv/win32drv.c
完整代码点击链接:static lv_indev_drv_t keypad_driver; lv_indev_drv_init(&keypad_driver); keypad_driver.type = LV_INDEV_TYPE_KEYPAD; keypad_driver.read_cb = lv_win32_keypad_driver_read_callback; lv_win32_keypad_device_object = lv_indev_drv_register(&keypad_driver);
把上面的代码稍作改动。
lv_win32_keypad_driver_read_callback --> melis_keypad_driver_read_cb lv_win32_keypad_device_object --> g_keypad_device_object 【 说明:这个变量其他文件需要用到】
于是,改动后的代码如下(完整代码点击链接 lv_main.c):
#define LV_USE_GPADC 1 lv_indev_t* g_keypad_device_object ; static lv_disp_t * hal_init(void ) { ...... #if LV_USE_GPADC static lv_indev_drv_t keypad_driver; lv_indev_drv_init(&keypad_driver); keypad_driver.type = LV_INDEV_TYPE_KEYPAD; keypad_driver.read_cb = melis_keypad_driver_read_cb; g_keypad_device_object = lv_indev_drv_register(&keypad_driver); #endif lv_disp_t * disp = NULL; return disp; }
2.在gui中测试物理按键效果
在gui中应用物理按键(groups)需要3个步骤:
1.要创建一个 组(Groups) : lv_group_t * g = lv_group_create();
2.然后将一个对象添加到 组(Groups) 中: lv_group_add_obj(g, obj); 也可以指定默认组:lv_group_set_default(g);
3.最后要将组(Groups)与输入设备相关联: lv_indev_set_group(g_keypad_device_object , g);物理按键中有3个必备的按键消息,这3个消息就可以实现焦点切换和触发焦点对象:
消息名称 含义 LV_KEY_NEXT 聚焦到下一个对象 LV_KEY_PREV 聚焦到上一个对象 LV_KEY_ENTER 触发 LV_EVENT_PRESSED/CLICKED/LONG_PRESSED 等事件 其他消息:
消息名称 含义 LV_KEY_UP 增加值或向上移动 LV_KEY_DOWN 减少值或向下移动 LV_KEY_RIGHT 增加值或向右移动 LV_KEY_LEFT 减少值或向左移动 LV_KEY_ESC 关闭或退出(例如关闭 下拉列表) LV_KEY_DEL 删除(例如 文本区域 中右侧的字符) LV_KEY_BACKSPACE 删除左边的一个字符(例如在文本区域) LV_KEY_HOME 跳到开头/顶部(例如在 文本区域) LV_KEY_END 跳到最后(例如在 文本区域)) 这里我使用了官方例程 lv_example_btn_1.c。
extern lv_indev_t* g_keypad_device_object ; static void event_handler(lv_event_t * e) { lv_event_code_t code = lv_event_get_code(e); if(code == LV_EVENT_CLICKED) { LV_LOG_USER("Clicked"); } else if(code == LV_EVENT_VALUE_CHANGED) { LV_LOG_USER("Toggled"); } } void lv_example_btn_1(void) { lv_obj_t * label; // 创建一个组,稍后将需要使用键盘或编码器或按钮控制的部件(对象)添加进去,并且将输入设备和组关联 // 如果将这个组设置为默认组,那么对于那些在创建时会添加到默认组的部件(对象)就可以省略 lv_group_add_obj() lv_group_t * g = lv_group_create(); // 将上面创建的组设置为默认组 // 如果稍后创建的部件(对象),使用默认组那必须要在其创建之前设置好默认组,否则不生效 lv_group_set_default(g); lv_obj_t * btn1 = lv_btn_create(lv_scr_act()); lv_obj_add_event_cb(btn1, event_handler, LV_EVENT_ALL, NULL); lv_obj_align(btn1, LV_ALIGN_CENTER, 0, -40); label = lv_label_create(btn1); lv_label_set_text(label, "Button"); lv_obj_center(label); lv_obj_t * btn2 = lv_btn_create(lv_scr_act()); lv_obj_add_event_cb(btn2, event_handler, LV_EVENT_ALL, NULL); lv_obj_align(btn2, LV_ALIGN_CENTER, 0, 40); lv_obj_add_flag(btn2, LV_OBJ_FLAG_CHECKABLE); lv_obj_set_height(btn2, LV_SIZE_CONTENT); label = lv_label_create(btn2); lv_label_set_text(label, "Toggle"); lv_obj_center(label); lv_indev_set_group(g_keypad_device_object, g); }
原文链接:https://blog.csdn.net/hwd00001/article/details/130106367
-
mango-MQ-R基于Melis移植lvgl
1.下载lvgl源码到《D1s-Melis/ekernel/drivers/hal/test/disp2》目录
我使用的源码是https://github.com/lvgl/lv_port_pc_eclipse
,克隆到D1s-Melis/ekernel/drivers/hal/test/disp2
目录。然后在D1s-Melis/ekernel/drivers/hal/test/disp2/lv_port_pc_eclipse》
目录下建立一个Makefile,把全部的C文件都包含进来编译的。这是因为lvgl的所有非必要的C文件都可以通过宏定义配置是否编译。例如lv_bmp.c里面的代码是否编译,取决于 宏定义LV_USE_BMP:
为了简单起见,很多非必要的组件我都没有包含进来,详情见 lv_conf.h 。
/** * @file lv_conf.h * Configuration file for v9.0.0-dev */ /* * Copy this file as `lv_conf.h` * 1. simply next to the `lvgl` folder * 2. or any other places and * - define `LV_CONF_INCLUDE_SIMPLE` * - add the path as include path */ /* clang-format off */ #if 1 /*Set it to "1" to enable content*/ #ifndef LV_CONF_H #define LV_CONF_H #define LV_USE_DEV_VERSION /*==================== COLOR SETTINGS *====================*/ /*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 24 (RGB888), 32 (ARGB8888)*/ #define LV_COLOR_DEPTH 32 #define LV_COLOR_CHROMA_KEY lv_color_hex(0x00ff00) /*Enable more complex drawing routines to manage screens transparency. *Can be used if the UI is above another layer, e.g. an OSD menu or video player. *Requires `LV_COLOR_DEPTH = 32` colors and the screen's `bg_opa` should be set to non LV_OPA_COVER value*/ #define LV_COLOR_SCREEN_TRANSP 1 /*========================= STDLIB WRAPPER SETTINGS *=========================*/ /*Enable and configure the built-in memory manager*/ #define LV_USE_BUILTIN_MALLOC 1 #if LV_USE_BUILTIN_MALLOC /*Size of the memory available for `lv_malloc()` in bytes (>= 2kB)*/ #define LV_MEM_SIZE (128U * 1024U) /*[bytes]*/ /*Size of the memory expand for `lv_malloc()` in bytes*/ #define LV_MEM_POOL_EXPAND_SIZE 0 /*Set an address for the memory pool instead of allocating it as a normal array. Can be in external SRAM too.*/ #define LV_MEM_ADR 0 /*0: unused*/ /*Instead of an address give a memory allocator that will be called to get a memory pool for LVGL. E.g. my_malloc*/ #if LV_MEM_ADR == 0 #undef LV_MEM_POOL_INCLUDE #undef LV_MEM_POOL_ALLOC #endif #endif /*LV_USE_BUILTIN_MALLOC*/ /*Enable lv_memcpy_builtin, lv_memset_builtin, lv_strlen_builtin, lv_strncpy_builtin*/ #define LV_USE_BUILTIN_MEMCPY 1 /*Enable and configure the built-in (v)snprintf */ #define LV_USE_BUILTIN_SNPRINTF 1 #if LV_USE_BUILTIN_SNPRINTF #define LV_SPRINTF_USE_FLOAT 0 #endif /*LV_USE_BUILTIN_SNPRINTF*/ #define LV_STDLIB_INCLUDE <stdint.h> #define LV_STDIO_INCLUDE <stdint.h> #define LV_STRING_INCLUDE <stdint.h> #define LV_MALLOC lv_malloc_builtin #define LV_REALLOC lv_realloc_builtin #define LV_FREE lv_free_builtin #define LV_MEMSET lv_memset_builtin #define LV_MEMCPY lv_memcpy_builtin #define LV_SNPRINTF lv_snprintf_builtin #define LV_VSNPRINTF lv_vsnprintf_builtin #define LV_STRLEN lv_strlen_builtin #define LV_STRNCPY lv_strncpy_builtin #define LV_COLOR_EXTERN_INCLUDE <stdint.h> #define LV_COLOR_MIX lv_color_mix #define LV_COLOR_PREMULT lv_color_premult #define LV_COLOR_MIX_PREMULT lv_color_mix_premult /*==================== HAL SETTINGS *====================*/ /*Default display refresh, input device read and animation step period.*/ #define LV_DEF_REFR_PERIOD 33 /*[ms]*/ /*Use a custom tick source that tells the elapsed time in milliseconds. *It removes the need to manually update the tick with `lv_tick_inc()`)*/ #define LV_TICK_CUSTOM 0 #if LV_TICK_CUSTOM #define LV_TICK_CUSTOM_INCLUDE "Arduino.h" /*Header for the system time function*/ #define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis()) /*Expression evaluating to current system time in ms*/ /*If using lvgl as ESP32 component*/ // #define LV_TICK_CUSTOM_INCLUDE "esp_timer.h" // #define LV_TICK_CUSTOM_SYS_TIME_EXPR ((esp_timer_get_time() / 1000LL)) #endif /*LV_TICK_CUSTOM*/ /*Default Dot Per Inch. Used to initialize default sizes such as widgets sized, style paddings. *(Not so important, you can adjust it to modify default sizes and spaces)*/ #define LV_DPI_DEF 130 /*[px/inch]*/ /*======================== * DRAW CONFIGURATION *========================*/ /*Enable the built in mask engine. *Required to draw shadow, rounded corners, circles, arc, skew lines, or any other masks*/ #define LV_USE_DRAW_MASKS 1 #define LV_USE_DRAW_SW 1 #if LV_USE_DRAW_SW /*Enable complex draw engine. *Required to draw shadow, gradient, rounded corners, circles, arc, skew lines, image transformations or any masks*/ #define LV_DRAW_SW_COMPLEX 1 /* If a widget has `style_opa < 255` (not `bg_opa`, `text_opa` etc) or not NORMAL blend mode * it is buffered into a "simple" layer before rendering. The widget can be buffered in smaller chunks. * "Transformed layers" (if `transform_angle/zoom` are set) use larger buffers * and can't be drawn in chunks. */ /*The target buffer size for simple layer chunks.*/ #define LV_DRAW_SW_LAYER_SIMPLE_BUF_SIZE (24 * 1024) /*[bytes]*/ /*Used if `LV_DRAW_SW_LAYER_SIMPLE_BUF_SIZE` couldn't be allocated.*/ #define LV_DRAW_SW_LAYER_SIMPLE_FALLBACK_BUF_SIZE (3 * 1024) /*[bytes]*/ /*Allow buffering some shadow calculation. *LV_DRAW_SW_SHADOW_CACHE_SIZE is the max. shadow size to buffer, where shadow size is `shadow_width + radius` *Caching has LV_DRAW_SW_SHADOW_CACHE_SIZE^2 RAM cost*/ #define LV_DRAW_SW_SHADOW_CACHE_SIZE 0 /* Set number of maximally cached circle data. * The circumference of 1/4 circle are saved for anti-aliasing * radius * 4 bytes are used per circle (the most often used radiuses are saved) * 0: to disable caching */ #define LV_DRAW_SW_CIRCLE_CACHE_SIZE 4 /*Default gradient buffer size. *When LVGL calculates the gradient "maps" it can save them into a cache to avoid calculating them again. *LV_DRAW_SW_GRADIENT_CACHE_DEF_SIZE sets the size of this cache in bytes. *If the cache is too small the map will be allocated only while it's required for the drawing. *0 mean no caching.*/ #define LV_DRAW_SW_GRADIENT_CACHE_DEF_SIZE 0 /*Allow dithering the gradients (to achieve visual smooth color gradients on limited color depth display) *LV_DRAW_SW_GRADIENT_DITHER implies allocating one or two more lines of the object's rendering surface *The increase in memory consumption is (32 bits * object width) plus 24 bits * object width if using error diffusion */ #define LV_DRAW_SW_GRADIENT_DITHER 0 #if LV_DRAW_SW_GRADIENT_DITHER /*Add support for error diffusion dithering. *Error diffusion dithering gets a much better visual result, but implies more CPU consumption and memory when drawing. *The increase in memory consumption is (24 bits * object's width)*/ #define LV_DRAW_SW_GRADIENT_DITHER_ERROR_DIFFUSION 0 #endif /*Enable subpixel rendering*/ #define LV_DRAW_SW_FONT_SUBPX 0 #if LV_DRAW_SW_FONT_SUBPX /*Set the pixel order of the display. Physical order of RGB channels. Doesn't matter with "normal" fonts.*/ #define LV_DRAW_SW_FONT_SUBPX_BGR 0 /*0: RGB; 1:BGR order*/ #endif #endif /*Use SDL renderer API*/ #define LV_USE_DRAW_SDL 0 #if LV_USE_DRAW_SDL #define LV_DRAW_SDL_INCLUDE_PATH <SDL2/SDL.h> /*Texture cache size, 8MB by default*/ #define LV_DRAW_SDL_LRU_SIZE (1024 * 1024 * 8) /*Custom blend mode for mask drawing, disable if you need to link with older SDL2 lib*/ #define LV_DRAW_SDL_CUSTOM_BLEND_MODE (SDL_VERSION_ATLEAST(2, 0, 6)) #endif /*===================== * GPU CONFIGURATION *=====================*/ /*Use Arm's 2D acceleration library Arm-2D */ #define LV_USE_GPU_ARM2D 0 /*Use STM32's DMA2D (aka Chrom Art) GPU*/ #define LV_USE_GPU_STM32_DMA2D 0 #if LV_USE_GPU_STM32_DMA2D /*Must be defined to include path of CMSIS header of target processor e.g. "stm32f769xx.h" or "stm32f429xx.h"*/ #define LV_GPU_DMA2D_CMSIS_INCLUDE #endif /*Use GD32 IPA GPU * This adds support for Image Processing Accelerator on GD32F450 and GD32F470 series MCUs * * NOTE: IPA on GD32F450 has a bug where the fill operation overwrites data beyond the * framebuffer. This driver works around it by saving and restoring affected memory, but * this makes it not thread-safe. GD32F470 is not affected. */ #define LV_USE_GPU_GD32_IPA 0 /*Use NXP's PXP GPU iMX RTxxx platforms*/ #define LV_USE_GPU_NXP_PXP 0 #if LV_USE_GPU_NXP_PXP /*1: Add default bare metal and FreeRTOS interrupt handling routines for PXP (lv_gpu_nxp_pxp_osa.c) * and call lv_gpu_nxp_pxp_init() automatically during lv_init(). Note that symbol SDK_OS_FREE_RTOS * has to be defined in order to use FreeRTOS OSA, otherwise bare-metal implementation is selected. *0: lv_gpu_nxp_pxp_init() has to be called manually before lv_init() */ #define LV_USE_GPU_NXP_PXP_AUTO_INIT 0 #endif /*Use NXP's VG-Lite GPU iMX RTxxx platforms*/ #define LV_USE_GPU_NXP_VG_LITE 0 /*Use SWM341's DMA2D GPU*/ #define LV_USE_GPU_SWM341_DMA2D 0 #if LV_USE_GPU_SWM341_DMA2D #define LV_GPU_SWM341_DMA2D_INCLUDE "SWM341.h" #endif /*======================= * FEATURE CONFIGURATION *=======================*/ /*------------- * Logging *-----------*/ /*Enable the log module*/ #define LV_USE_LOG 0 #if LV_USE_LOG /*How important log should be added: *LV_LOG_LEVEL_TRACE A lot of logs to give detailed information *LV_LOG_LEVEL_INFO Log important events *LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't cause a problem *LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail *LV_LOG_LEVEL_USER Only logs added by the user *LV_LOG_LEVEL_NONE Do not log anything*/ #define LV_LOG_LEVEL LV_LOG_LEVEL_WARN /*1: Print the log with 'printf'; *0: User need to register a callback with `lv_log_register_print_cb()`*/ #define LV_LOG_PRINTF 0 /*1: Enable print timestamp; *0: Disable print timestamp*/ #define LV_LOG_USE_TIMESTAMP 1 /*Enable/disable LV_LOG_TRACE in modules that produces a huge number of logs*/ #define LV_LOG_TRACE_MEM 1 #define LV_LOG_TRACE_TIMER 1 #define LV_LOG_TRACE_INDEV 1 #define LV_LOG_TRACE_DISP_REFR 1 #define LV_LOG_TRACE_EVENT 1 #define LV_LOG_TRACE_OBJ_CREATE 1 #define LV_LOG_TRACE_LAYOUT 1 #define LV_LOG_TRACE_ANIM 1 #define LV_LOG_TRACE_MSG 1 #endif /*LV_USE_LOG*/ /*------------- * Asserts *-----------*/ /*Enable asserts if an operation is failed or an invalid data is found. *If LV_USE_LOG is enabled an error message will be printed on failure*/ #define LV_USE_ASSERT_NULL 1 /*Check if the parameter is NULL. (Very fast, recommended)*/ #define LV_USE_ASSERT_MALLOC 1 /*Checks is the memory is successfully allocated or no. (Very fast, recommended)*/ #define LV_USE_ASSERT_STYLE 0 /*Check if the styles are properly initialized. (Very fast, recommended)*/ #define LV_USE_ASSERT_MEM_INTEGRITY 0 /*Check the integrity of `lv_mem` after critical operations. (Slow)*/ #define LV_USE_ASSERT_OBJ 0 /*Check the object's type and existence (e.g. not deleted). (Slow)*/ /*Add a custom handler when assert happens e.g. to restart the MCU*/ #define LV_ASSERT_HANDLER_INCLUDE <stdint.h> #define LV_ASSERT_HANDLER while(1); /*Halt by default*/ /*------------- * Others *-----------*/ /*1: Show CPU usage and FPS count*/ #define LV_USE_PERF_MONITOR 0 #if LV_USE_PERF_MONITOR #define LV_USE_PERF_MONITOR_POS LV_ALIGN_BOTTOM_RIGHT #endif /*1: Show the used memory and the memory fragmentation * Requires `LV_USE_BUILTIN_MALLOC = 1`*/ #define LV_USE_MEM_MONITOR 0 #if LV_USE_MEM_MONITOR #define LV_USE_MEM_MONITOR_POS LV_ALIGN_BOTTOM_LEFT #endif /*1: Draw random colored rectangles over the redrawn areas*/ #define LV_USE_REFR_DEBUG 0 /*Maximum buffer size to allocate for rotation. *Only used if software rotation is enabled in the display driver.*/ #define LV_DISP_ROT_MAX_BUF (10*1024) #define LV_USE_USER_DATA 1 /*Garbage Collector settings *Used if lvgl is bound to higher level language and the memory is managed by that language*/ #define LV_ENABLE_GC 0 #if LV_ENABLE_GC != 0 #define LV_GC_INCLUDE "gc.h" /*Include Garbage Collector related things*/ #endif /*LV_ENABLE_GC*/ /*Default image cache size. Image caching keeps some images opened. *If only the built-in image formats are used there is no real advantage of caching. *With other image decoders (e.g. PNG or JPG) caching save the continuous open/decode of images. *However the opened images consume additional RAM. *0: to disable caching*/ #define LV_IMG_CACHE_DEF_SIZE 0 /*Number of stops allowed per gradient. Increase this to allow more stops. *This adds (sizeof(lv_color_t) + 1) bytes per additional stop*/ #define LV_GRADIENT_MAX_STOPS 2 /* Adjust color mix functions rounding. GPUs might calculate color mix (blending) differently. * 0: round down, 64: round up from x.75, 128: round up from half, 192: round up from x.25, 254: round up */ #define LV_COLOR_MIX_ROUND_OFS 0 /*===================== * COMPILER SETTINGS *====================*/ /*For big endian systems set to 1*/ #define LV_BIG_ENDIAN_SYSTEM 0 /*Define a custom attribute to `lv_tick_inc` function*/ #define LV_ATTRIBUTE_TICK_INC /*Define a custom attribute to `lv_timer_handler` function*/ #define LV_ATTRIBUTE_TIMER_HANDLER /*Define a custom attribute to `lv_disp_flush_ready` function*/ #define LV_ATTRIBUTE_FLUSH_READY /*Required alignment size for buffers*/ #define LV_ATTRIBUTE_MEM_ALIGN_SIZE 1 /*Will be added where memories needs to be aligned (with -Os data might not be aligned to boundary by default). * E.g. __attribute__((aligned(4)))*/ #define LV_ATTRIBUTE_MEM_ALIGN /*Attribute to mark large constant arrays for example font's bitmaps*/ #define LV_ATTRIBUTE_LARGE_CONST /*Compiler prefix for a big array declaration in RAM*/ #define LV_ATTRIBUTE_LARGE_RAM_ARRAY /*Place performance critical functions into a faster memory (e.g RAM)*/ #define LV_ATTRIBUTE_FAST_MEM /*Export integer constant to binding. This macro is used with constants in the form of LV_<CONST> that *should also appear on LVGL binding API such as Micropython.*/ #define LV_EXPORT_CONST_INT(int_value) struct _silence_gcc_warning /*The default value just prevents GCC warning*/ /*Extend the default -32k..32k coordinate range to -4M..4M by using int32_t for coordinates instead of int16_t*/ #define LV_USE_LARGE_COORD 0 /*================== * FONT USAGE *===================*/ /*Montserrat fonts with ASCII range and some symbols using bpp = 4 *https://fonts.google.com/specimen/Montserrat*/ #define LV_FONT_MONTSERRAT_8 1 #define LV_FONT_MONTSERRAT_10 1 #define LV_FONT_MONTSERRAT_12 1 #define LV_FONT_MONTSERRAT_14 1 #define LV_FONT_MONTSERRAT_16 1 #define LV_FONT_MONTSERRAT_18 1 #define LV_FONT_MONTSERRAT_20 1 #define LV_FONT_MONTSERRAT_22 1 #define LV_FONT_MONTSERRAT_24 1 #define LV_FONT_MONTSERRAT_26 1 #define LV_FONT_MONTSERRAT_28 1 #define LV_FONT_MONTSERRAT_30 1 #define LV_FONT_MONTSERRAT_32 1 #define LV_FONT_MONTSERRAT_34 1 #define LV_FONT_MONTSERRAT_36 1 #define LV_FONT_MONTSERRAT_38 1 #define LV_FONT_MONTSERRAT_40 1 #define LV_FONT_MONTSERRAT_42 1 #define LV_FONT_MONTSERRAT_44 1 #define LV_FONT_MONTSERRAT_46 1 #define LV_FONT_MONTSERRAT_48 1 /*Demonstrate special features*/ #define LV_FONT_MONTSERRAT_12_SUBPX 1 #define LV_FONT_MONTSERRAT_28_COMPRESSED 1 /*bpp = 3*/ #define LV_FONT_DEJAVU_16_PERSIAN_HEBREW 1 /*Hebrew, Arabic, Persian letters and all their forms*/ #define LV_FONT_SIMSUN_16_CJK 1 /*1000 most common CJK radicals*/ /*Pixel perfect monospace fonts*/ #define LV_FONT_UNSCII_8 1 #define LV_FONT_UNSCII_16 1 /*Optionally declare custom fonts here. *You can use these fonts as default font too and they will be available globally. *E.g. #define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(my_font_1) LV_FONT_DECLARE(my_font_2)*/ #define LV_FONT_CUSTOM_DECLARE /*Always set a default font*/ #define LV_FONT_DEFAULT &lv_font_montserrat_14 /*Enable handling large font and/or fonts with a lot of characters. *The limit depends on the font size, font face and bpp. *Compiler error will be triggered if a font needs it.*/ #define LV_FONT_FMT_TXT_LARGE 1 /*Enables/disables support for compressed fonts.*/ #define LV_USE_FONT_COMPRESSED 1 /*Enable drawing placeholders when glyph dsc is not found*/ #define LV_USE_FONT_PLACEHOLDER 1 /*================= * TEXT SETTINGS *=================*/ /** * Select a character encoding for strings. * Your IDE or editor should have the same character encoding * - LV_TXT_ENC_UTF8 * - LV_TXT_ENC_ASCII */ #define LV_TXT_ENC LV_TXT_ENC_UTF8 /*Can break (wrap) texts on these chars*/ #define LV_TXT_BREAK_CHARS " ,.;:-_)]}" /*If a word is at least this long, will break wherever "prettiest" *To disable, set to a value <= 0*/ #define LV_TXT_LINE_BREAK_LONG_LEN 0 /*Minimum number of characters in a long word to put on a line before a break. *Depends on LV_TXT_LINE_BREAK_LONG_LEN.*/ #define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 /*Minimum number of characters in a long word to put on a line after a break. *Depends on LV_TXT_LINE_BREAK_LONG_LEN.*/ #define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 3 /*The control character to use for signalling text recoloring.*/ #define LV_TXT_COLOR_CMD "#" /*Support bidirectional texts. Allows mixing Left-to-Right and Right-to-Left texts. *The direction will be processed according to the Unicode Bidirectional Algorithm: *https://www.w3.org/International/articles/inline-bidi-markup/uba-basics*/ #define LV_USE_BIDI 1 #if LV_USE_BIDI /*Set the default direction. Supported values: *`LV_BASE_DIR_LTR` Left-to-Right *`LV_BASE_DIR_RTL` Right-to-Left *`LV_BASE_DIR_AUTO` detect texts base direction*/ #define LV_BIDI_BASE_DIR_DEF LV_BASE_DIR_AUTO #endif /*Enable Arabic/Persian processing *In these languages characters should be replaced with an other form based on their position in the text*/ #define LV_USE_ARABIC_PERSIAN_CHARS 1 /*================== * WIDGETS *================*/ /*Documentation of the widgets: https://docs.lvgl.io/latest/en/html/widgets/index.html*/ #define LV_USE_ANIMIMG 1 #define LV_USE_ARC 1 #define LV_USE_BAR 1 #define LV_USE_BTN 1 #define LV_USE_BTNMATRIX 1 #define LV_USE_CALENDAR 1 #if LV_USE_CALENDAR #define LV_CALENDAR_WEEK_STARTS_MONDAY 0 #if LV_CALENDAR_WEEK_STARTS_MONDAY #define LV_CALENDAR_DEFAULT_DAY_NAMES {"Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"} #else #define LV_CALENDAR_DEFAULT_DAY_NAMES {"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"} #endif #define LV_CALENDAR_DEFAULT_MONTH_NAMES {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"} #define LV_USE_CALENDAR_HEADER_ARROW 1 #define LV_USE_CALENDAR_HEADER_DROPDOWN 1 #endif /*LV_USE_CALENDAR*/ #define LV_USE_CANVAS 1 #define LV_USE_CHART 1 #define LV_USE_CHECKBOX 1 #define LV_USE_COLORWHEEL 1 #define LV_USE_DROPDOWN 1 /*Requires: lv_label*/ #define LV_USE_IMG 1 /*Requires: lv_label*/ #define LV_USE_IMGBTN 1 #define LV_USE_KEYBOARD 1 #define LV_USE_LABEL 1 #if LV_USE_LABEL #define LV_LABEL_TEXT_SELECTION 1 /*Enable selecting text of the label*/ #define LV_LABEL_LONG_TXT_HINT 1 /*Store some extra info in labels to speed up drawing of very long texts*/ #endif #define LV_USE_LED 1 #define LV_USE_LINE 1 #define LV_USE_LIST 1 #define LV_USE_MENU 1 #define LV_USE_METER 1 #define LV_USE_MSGBOX 1 #define LV_USE_ROLLER 1 /*Requires: lv_label*/ #define LV_USE_SLIDER 1 /*Requires: lv_bar*/ #define LV_USE_SPAN 1 #if LV_USE_SPAN /*A line text can contain maximum num of span descriptor */ #define LV_SPAN_SNIPPET_STACK_SIZE 64 #endif #define LV_USE_SPINBOX 1 #define LV_USE_SPINNER 1 #define LV_USE_SWITCH 1 #define LV_USE_TEXTAREA 1 /*Requires: lv_label*/ #if LV_USE_TEXTAREA != 0 #define LV_TEXTAREA_DEF_PWD_SHOW_TIME 1500 /*ms*/ #endif #define LV_USE_TABLE 1 #define LV_USE_TABVIEW 1 #define LV_USE_TILEVIEW 1 #define LV_USE_WIN 1 /*================== * THEMES *==================*/ /*A simple, impressive and very complete theme*/ #define LV_USE_THEME_DEFAULT 1 #if LV_USE_THEME_DEFAULT /*0: Light mode; 1: Dark mode*/ #define LV_THEME_DEFAULT_DARK 0 /*1: Enable grow on press*/ #define LV_THEME_DEFAULT_GROW 1 /*Default transition time in [ms]*/ #define LV_THEME_DEFAULT_TRANSITION_TIME 80 #endif /*LV_USE_THEME_DEFAULT*/ /*A very simple theme that is a good starting point for a custom theme*/ #define LV_USE_THEME_BASIC 1 /*A theme designed for monochrome displays*/ #define LV_USE_THEME_MONO 1 /*================== * LAYOUTS *==================*/ /*A layout similar to Flexbox in CSS.*/ #define LV_USE_FLEX 1 /*A layout similar to Grid in CSS.*/ #define LV_USE_GRID 1 /*==================== * 3RD PARTS LIBRARIES *====================*/ /*File system interfaces for common APIs */ /*API for fopen, fread, etc*/ #define LV_USE_FS_STDIO 0 #if LV_USE_FS_STDIO #define LV_FS_STDIO_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ #define LV_FS_STDIO_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/ #define LV_FS_STDIO_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ #endif /*API for open, read, etc*/ #define LV_USE_FS_POSIX 0 #if LV_USE_FS_POSIX #define LV_FS_POSIX_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ #define LV_FS_POSIX_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/ #define LV_FS_POSIX_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ #endif /*API for CreateFile, ReadFile, etc*/ #define LV_USE_FS_WIN32 0 #if LV_USE_FS_WIN32 #define LV_FS_WIN32_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ #define LV_FS_WIN32_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/ #define LV_FS_WIN32_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ #endif /*API for FATFS (needs to be added separately). Uses f_open, f_read, etc*/ #define LV_USE_FS_FATFS 0 #if LV_USE_FS_FATFS #define LV_FS_FATFS_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ #define LV_FS_FATFS_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ #endif /*PNG decoder library*/ #define LV_USE_PNG 1 /*BMP decoder library*/ #define LV_USE_BMP 1 /* JPG + split JPG decoder library. * Split JPG is a custom format optimized for embedded systems. */ #define LV_USE_SJPG 0 /*GIF decoder library*/ #define LV_USE_GIF 0 /*QR code library*/ #define LV_USE_QRCODE 0 /*Barcode code library*/ #define LV_USE_BARCODE 0 /*FreeType library*/ #define LV_USE_FREETYPE 0 #if LV_USE_FREETYPE /*Memory used by FreeType to cache characters [bytes]*/ #define LV_FREETYPE_CACHE_SIZE (64 * 1024) /*Let FreeType to use LVGL memory and file porting*/ #define LV_FREETYPE_USE_LVGL_PORT 0 /* 1: bitmap cache use the sbit cache, 0:bitmap cache use the image cache. */ /* sbit cache:it is much more memory efficient for small bitmaps(font size < 256) */ /* if font size >= 256, must be configured as image cache */ #define LV_FREETYPE_SBIT_CACHE 0 /* Maximum number of opened FT_Face/FT_Size objects managed by this cache instance. */ /* (0:use system defaults) */ #define LV_FREETYPE_CACHE_FT_FACES 4 #define LV_FREETYPE_CACHE_FT_SIZES 4 #endif /* Built-in TTF decoder */ #define LV_USE_TINY_TTF 1 #if LV_USE_TINY_TTF /* Enable loading TTF data from files */ #define LV_TINY_TTF_FILE_SUPPORT 0 #endif /*Rlottie library*/ #define LV_USE_RLOTTIE 0 /*FFmpeg library for image decoding and playing videos *Supports all major image formats so do not enable other image decoder with it*/ #define LV_USE_FFMPEG 0 #if LV_USE_FFMPEG /*Dump input information to stderr*/ #define LV_FFMPEG_DUMP_FORMAT 0 #endif /*================== * OTHERS *==================*/ /*1: Enable API to take snapshot for object*/ #define LV_USE_SNAPSHOT 1 /*1: Enable Monkey test*/ #define LV_USE_MONKEY 1 /*1: Enable grid navigation*/ #define LV_USE_GRIDNAV 1 /*1: Enable lv_obj fragment*/ #define LV_USE_FRAGMENT 1 /*1: Support using images as font in label or span widgets */ #define LV_USE_IMGFONT 1 #if LV_USE_IMGFONT /*Imgfont image file path maximum length*/ #define LV_IMGFONT_PATH_MAX_LEN 64 /*1: Use img cache to buffer header information*/ #define LV_IMGFONT_USE_IMG_CACHE_HEADER 0 #endif /*1: Enable a published subscriber based messaging system */ #define LV_USE_MSG 1 /*1: Enable Pinyin input method*/ /*Requires: lv_keyboard*/ #define LV_USE_IME_PINYIN 0 #if LV_USE_IME_PINYIN /*1: Use default thesaurus*/ /*If you do not use the default thesaurus, be sure to use `lv_ime_pinyin` after setting the thesauruss*/ #define LV_IME_PINYIN_USE_DEFAULT_DICT 1 /*Set the maximum number of candidate panels that can be displayed*/ /*This needs to be adjusted according to the size of the screen*/ #define LV_IME_PINYIN_CAND_TEXT_NUM 6 /*Use 9 key input(k9)*/ #define LV_IME_PINYIN_USE_K9_MODE 1 #if LV_IME_PINYIN_USE_K9_MODE == 1 #define LV_IME_PINYIN_K9_CAND_TEXT_NUM 3 #endif // LV_IME_PINYIN_USE_K9_MODE #endif /*1: Enable file explorer*/ /*Requires: lv_table*/ #define LV_USE_FILE_EXPLORER 0 #if LV_USE_FILE_EXPLORER /*Maximum length of path*/ #define LV_FILE_EXPLORER_PATH_MAX_LEN (128) /*Quick access bar, 1:use, 0:not use*/ /*Requires: lv_list*/ #define LV_FILE_EXPLORER_QUICK_ACCESS 1 #endif /*================== * DEVICES *==================*/ /*Use SDL to open window on PC and handle mouse and keyboard*/ #define LV_USE_SDL 0 #if LV_USE_SDL #define LV_SDL_INCLUDE_PATH <SDL2/SDL.h> #define LV_SDL_PARTIAL_MODE 0 /*Recommended only to emulate a setup with a display controller*/ #endif /*Driver for /dev/fb*/ #define LV_USE_LINUX_FBDEV 0 #if LV_USE_LINUX_FBDEV #define LV_LINUX_FBDEV_BSD 0 #endif /*Interface for TFT_eSPI*/ #define LV_USE_TFT_ESPI 0 /*================== * EXAMPLES *==================*/ /*Enable the examples to be built with the library*/ #define LV_BUILD_EXAMPLES 1 /*=================== * DEMO USAGE ====================*/ /*Show some widget. It might be required to increase `LV_MEM_SIZE` */ #define LV_USE_DEMO_WIDGETS 1 #if LV_USE_DEMO_WIDGETS #define LV_DEMO_WIDGETS_SLIDESHOW 0 #endif /*Demonstrate the usage of encoder and keyboard*/ #define LV_USE_DEMO_KEYPAD_AND_ENCODER 1 /*Benchmark your system*/ #define LV_USE_DEMO_BENCHMARK 0 #if LV_USE_DEMO_BENCHMARK /*Use RGB565A8 images with 16 bit color depth instead of ARGB8565*/ #define LV_DEMO_BENCHMARK_RGB565A8 0 #endif /*Stress test for LVGL*/ #define LV_USE_DEMO_STRESS 0 /*Music player demo*/ #define LV_USE_DEMO_MUSIC 0 #if LV_USE_DEMO_MUSIC #define LV_DEMO_MUSIC_SQUARE 0 #define LV_DEMO_MUSIC_LANDSCAPE 0 #define LV_DEMO_MUSIC_ROUND 0 #define LV_DEMO_MUSIC_LARGE 0 #define LV_DEMO_MUSIC_AUTO_PLAY 0 #endif /*Flex layout demo*/ #define LV_USE_DEMO_FLEX_LAYOUT 0 /*--END OF LV_CONF_H--*/ #endif /*LV_CONF_H*/ #endif /*End of "Content enable"*/
1.1 修改Makefile
先在
disp2
目录下的Makefile把子目录disp2/lv_port_pc_eclipse
包含进来:subdir-ccflags-y += -I$(srctree)/ekernel/drivers/include \ -I$(srctree)/ekernel/core/rt-thread/include \ -I$(srctree)/ekernel/drivers/drv/source/disp2/soc obj-y += disp_layer_cfg.o disp_mem_hwd.o #disp_mem.o obj-y += disp_layer_alpha_test.o obj-y += disp_layer_scal_test.o obj-y += disp_layer_format_test.o obj-y += disp_lbc_test.o obj-y += lv_port_pc_eclipse/
再将
isp2/lv_port_pc_eclipse
目录下的Makefile改为下面内容(节选):obj-y += \ lvgl/demos/benchmark/assets/img_benchmark_cogwheel_alpha16.o \ lvgl/demos/benchmark/assets/img_benchmark_cogwheel_argb.o \ lvgl/demos/benchmark/assets/img_benchmark_cogwheel_chroma_keyed.o \ lvgl/demos/benchmark/assets/img_benchmark_cogwheel_indexed16.o \ lvgl/demos/benchmark/assets/img_benchmark_cogwheel_rgb.o \ lvgl/demos/benchmark/assets/img_benchmark_cogwheel_rgb565a8.o \ lvgl/demos/benchmark/assets/lv_font_bechmark_montserrat_12_compr_az.c.o \ lvgl/demos/benchmark/assets/lv_font_bechmark_montserrat_16_compr_az.c.o \ lvgl/demos/benchmark/assets/lv_font_bechmark_montserrat_28_compr_az.c.o \ lvgl/demos/benchmark/lv_demo_benchmark.o \ lvgl/demos/keypad_encoder/lv_demo_keypad_encoder.o \ lvgl/demos/music/assets/img_lv_demo_music_btn_corner_large.o \ lvgl/demos/music/assets/img_lv_demo_music_btn_list_pause.o \ lvgl/demos/music/assets/img_lv_demo_music_btn_list_pause_large.o \ lvgl/demos/music/assets/img_lv_demo_music_btn_list_play.o \ lvgl/demos/music/assets/img_lv_demo_music_btn_list_play_large.o \ lvgl/demos/music/assets/img_lv_demo_music_btn_loop.o \ lvgl/demos/music/assets/img_lv_demo_music_btn_loop_large.o \ lvgl/demos/music/assets/img_lv_demo_music_btn_next.o \ lvgl/demos/music/assets/img_lv_demo_music_btn_next_large.o \ lvgl/demos/music/assets/img_lv_demo_music_btn_pause.o \ lvgl/demos/music/assets/img_lv_demo_music_btn_pause_large.o \ lvgl/demos/music/assets/img_lv_demo_music_btn_play.o \ lvgl/demos/music/assets/img_lv_demo_music_btn_play_large.o \ lvgl/demos/music/assets/img_lv_demo_music_btn_prev.o \ lvgl/demos/music/assets/img_lv_demo_music_btn_prev_large.o \ lvgl/demos/music/assets/img_lv_demo_music_btn_rnd.o \ lvgl/demos/music/assets/img_lv_demo_music_btn_rnd_large.o \ lvgl/demos/music/assets/img_lv_demo_music_corner_left.o \ lvgl/demos/music/assets/img_lv_demo_music_corner_left_large.o \ lvgl/demos/music/assets/img_lv_demo_music_corner_right.o \ lvgl/demos/music/assets/img_lv_demo_music_corner_right_large.o \ lvgl/demos/music/assets/img_lv_demo_music_cover_1.o \ lvgl/demos/music/assets/img_lv_demo_music_cover_1_large.o \ lvgl/demos/music/assets/img_lv_demo_music_cover_2.o \ lvgl/demos/music/assets/img_lv_demo_music_cover_2_large.o \ lvgl/demos/music/assets/img_lv_demo_music_cover_3.o \ lvgl/demos/music/assets/img_lv_demo_music_cover_3_large.o \ lvgl/demos/music/assets/img_lv_demo_music_icon_1.o \ lvgl/demos/music/assets/img_lv_demo_music_icon_1_large.o \ lvgl/demos/music/assets/img_lv_demo_music_icon_2.o \ lvgl/demos/music/assets/img_lv_demo_music_icon_2_large.o \ lvgl/demos/music/assets/img_lv_demo_music_icon_3.o \ lvgl/demos/music/assets/img_lv_demo_music_icon_3_large.o \ lvgl/demos/music/assets/img_lv_demo_music_icon_4.o \ lvgl/demos/music/assets/img_lv_demo_music_icon_4_large.o \ lvgl/demos/music/assets/img_lv_demo_music_list_border.o \ lvgl/demos/music/assets/img_lv_demo_music_list_border_large.o \ lvgl/demos/music/assets/img_lv_demo_music_logo.o \ lvgl/demos/music/assets/img_lv_demo_music_slider_knob.o \ lvgl/demos/music/assets/img_lv_demo_music_slider_knob_large.o \ lvgl/demos/music/assets/img_lv_demo_music_wave_bottom.o \ lvgl/demos/music/assets/img_lv_demo_music_wave_bottom_large.o \ lvgl/demos/music/assets/img_lv_demo_music_wave_top.o \ lvgl/demos/music/assets/img_lv_demo_music_wave_top_large.o \ lvgl/demos/music/lv_demo_music.o \ lvgl/demos/music/lv_demo_music_list.o \ lvgl/demos/music/lv_demo_music_main.o \ lvgl/demos/stress/lv_demo_stress.o \ lvgl/demos/widgets/assets/img_clothes.o \ lvgl/demos/widgets/assets/img_demo_widgets_avatar.o \ lvgl/demos/widgets/assets/img_lvgl_logo.o \ lvgl/demos/widgets/lv_demo_widgets.o \ lvgl/examples/anim/lv_example_anim_1.o \ lvgl/examples/anim/lv_example_anim_2.o \ lvgl/examples/anim/lv_example_anim_3.o \ lvgl/examples/anim/lv_example_anim_timeline_1.o \ lvgl/examples/assets/animimg001.o \ lvgl/examples/assets/animimg002.o \ lvgl/examples/assets/animimg003.o \ lvgl/examples/assets/emoji/img_emoji_F617.o \ lvgl/examples/assets/img_caret_down.o \ lvgl/examples/assets/img_cogwheel_alpha16.o \ lvgl/examples/assets/img_cogwheel_argb.o \ lvgl/examples/assets/img_cogwheel_chroma_keyed.o \ lvgl/examples/assets/img_cogwheel_indexed16.o \ lvgl/examples/assets/img_cogwheel_rgb.o \ lvgl/examples/assets/img_hand.o \ lvgl/examples/assets/img_skew_strip.o \ lvgl/examples/assets/img_star.o \ lvgl/examples/assets/imgbtn_left.o \ lvgl/examples/assets/imgbtn_mid.o \ lvgl/examples/assets/imgbtn_right.o \ lvgl/examples/event/lv_example_event_1.o \ lvgl/examples/event/lv_example_event_2.o \ lvgl/examples/event/lv_example_event_3.o \ lvgl/examples/event/lv_example_event_4.o \ lvgl/examples/get_started/lv_example_get_started_1.o \ lvgl/examples/get_started/lv_example_get_started_2.o \ lvgl/examples/get_started/lv_example_get_started_3.o \ lvgl/examples/layouts/flex/lv_example_flex_1.o \ lvgl/examples/layouts/flex/lv_example_flex_2.o \ lvgl/examples/layouts/flex/lv_example_flex_3.o \ lvgl/examples/layouts/flex/lv_example_flex_4.o \ lvgl/examples/layouts/flex/lv_example_flex_5.o \ lvgl/examples/layouts/flex/lv_example_flex_6.o \ lvgl/examples/layouts/grid/lv_example_grid_1.o \ lvgl/examples/layouts/grid/lv_example_grid_2.o \ lvgl/examples/layouts/grid/lv_example_grid_3.o \ lvgl/examples/layouts/grid/lv_example_grid_4.o \ lvgl/examples/layouts/grid/lv_example_grid_5.o \ lvgl/examples/layouts/grid/lv_example_grid_6.o \ lvgl/examples/libs/bmp/lv_example_bmp_1.o \ lvgl/examples/libs/ffmpeg/lv_example_ffmpeg_1.o \ lvgl/examples/libs/ffmpeg/lv_example_ffmpeg_2.o \ lvgl/examples/libs/freetype/lv_example_freetype_1.o \ lvgl/examples/libs/gif/img_bulb_gif.o \ lvgl/examples/libs/gif/lv_example_gif_1.o \ lvgl/examples/libs/png/img_wink_png.o \ lvgl/examples/libs/png/lv_example_png_1.o \ lvgl/examples/libs/qrcode/lv_example_qrcode_1.o \ lvgl/examples/libs/rlottie/lv_example_rlottie_1.o \ lvgl/examples/libs/rlottie/lv_example_rlottie_2.o \ lvgl/examples/libs/rlottie/lv_example_rlottie_approve.o \ lvgl/examples/libs/sjpg/lv_example_sjpg_1.o \ lvgl/examples/others/fragment/lv_example_fragment_1.o \ lvgl/examples/others/fragment/lv_example_fragment_2.o \ lvgl/examples/others/gridnav/lv_example_gridnav_1.o \ lvgl/examples/others/gridnav/lv_example_gridnav_2.o \ lvgl/examples/others/gridnav/lv_example_gridnav_3.o \ lvgl/examples/others/gridnav/lv_example_gridnav_4.o \ lvgl/examples/others/ime/lv_example_ime_pinyin_1.o \ lvgl/examples/others/ime/lv_example_ime_pinyin_2.o \ lvgl/examples/others/imgfont/lv_example_imgfont_1.o \ lvgl/examples/others/monkey/lv_example_monkey_1.o \ lvgl/examples/others/monkey/lv_example_monkey_2.o \ lvgl/examples/others/monkey/lv_example_monkey_3.o \ lvgl/examples/others/msg/lv_example_msg_1.o \ lvgl/examples/others/msg/lv_example_msg_2.o \ lvgl/examples/others/msg/lv_example_msg_3.o \ lvgl/examples/others/snapshot/lv_example_snapshot_1.o \ lvgl/examples/porting/lv_port_disp_template.o \ lvgl/examples/porting/lv_port_fs_template.o \ lvgl/examples/porting/lv_port_indev_template.o \ lvgl/examples/scroll/lv_example_scroll_1.o \ lvgl/examples/scroll/lv_example_scroll_2.o \ lvgl/examples/scroll/lv_example_scroll_3.o \ lvgl/examples/scroll/lv_example_scroll_4.o \ lvgl/examples/scroll/lv_example_scroll_5.o \ lvgl/examples/scroll/lv_example_scroll_6.o \ lvgl/examples/styles/lv_example_style_1.o \ lvgl/examples/styles/lv_example_style_10.o \ lvgl/examples/styles/lv_example_style_11.o \ lvgl/examples/styles/lv_example_style_12.o \ lvgl/examples/styles/lv_example_style_13.o \ lvgl/examples/styles/lv_example_style_14.o \ lvgl/examples/styles/lv_example_style_15.o \ lvgl/examples/styles/lv_example_style_2.o \ lvgl/examples/styles/lv_example_style_3.o \ lvgl/examples/styles/lv_example_style_4.o \ lvgl/examples/styles/lv_example_style_5.o \ lvgl/examples/styles/lv_example_style_6.o \ lvgl/examples/styles/lv_example_style_7.o \ lvgl/examples/styles/lv_example_style_8.o \ lvgl/examples/styles/lv_example_style_9.o \ lvgl/examples/widgets/animimg/lv_example_animimg_1.o \ lvgl/examples/widgets/arc/lv_example_arc_1.o \ lvgl/examples/widgets/arc/lv_example_arc_2.o \ lvgl/examples/widgets/bar/lv_example_bar_1.o \ lvgl/examples/widgets/bar/lv_example_bar_2.o \ lvgl/examples/widgets/bar/lv_example_bar_3.o \ lvgl/examples/widgets/bar/lv_example_bar_4.o \ lvgl/examples/widgets/bar/lv_example_bar_5.o \ lvgl/examples/widgets/bar/lv_example_bar_6.o \ lvgl/examples/widgets/btn/lv_example_btn_1.o \ lvgl/examples/widgets/btn/lv_example_btn_2.o \ lvgl/examples/widgets/btn/lv_example_btn_3.o \ lvgl/examples/widgets/btnmatrix/lv_example_btnmatrix_1.o \ lvgl/examples/widgets/btnmatrix/lv_example_btnmatrix_2.o \ lvgl/examples/widgets/btnmatrix/lv_example_btnmatrix_3.o \ lvgl/examples/widgets/calendar/lv_example_calendar_1.o \ lvgl/examples/widgets/canvas/lv_example_canvas_1.o \ lvgl/examples/widgets/canvas/lv_example_canvas_2.o \ lvgl/examples/widgets/chart/lv_example_chart_1.o \ lvgl/examples/widgets/chart/lv_example_chart_2.o \ lvgl/examples/widgets/chart/lv_example_chart_3.o \ lvgl/examples/widgets/chart/lv_example_chart_4.o \ lvgl/examples/widgets/chart/lv_example_chart_5.o \ lvgl/examples/widgets/chart/lv_example_chart_6.o \ lvgl/examples/widgets/chart/lv_example_chart_7.o \ lvgl/examples/widgets/chart/lv_example_chart_8.o \ lvgl/examples/widgets/chart/lv_example_chart_9.o \ lvgl/examples/widgets/checkbox/lv_example_checkbox_1.o \ lvgl/examples/widgets/checkbox/lv_example_checkbox_2.o \ lvgl/examples/widgets/colorwheel/lv_example_colorwheel_1.o \ lvgl/examples/widgets/dropdown/lv_example_dropdown_1.o \ lvgl/examples/widgets/dropdown/lv_example_dropdown_2.o \ lvgl/examples/widgets/dropdown/lv_example_dropdown_3.o \ lvgl/examples/widgets/img/lv_example_img_1.o \ lvgl/examples/widgets/img/lv_example_img_2.o \ lvgl/examples/widgets/img/lv_example_img_3.o \ lvgl/examples/widgets/img/lv_example_img_4.o \ lvgl/examples/widgets/imgbtn/lv_example_imgbtn_1.o \ lvgl/examples/widgets/keyboard/lv_example_keyboard_1.o \ lvgl/examples/widgets/label/lv_example_label_1.o \ lvgl/examples/widgets/label/lv_example_label_2.o \ lvgl/examples/widgets/label/lv_example_label_3.o \ lvgl/examples/widgets/label/lv_example_label_4.o \ lvgl/examples/widgets/label/lv_example_label_5.o \ lvgl/examples/widgets/led/lv_example_led_1.o \ lvgl/examples/widgets/line/lv_example_line_1.o \ lvgl/examples/widgets/list/lv_example_list_1.o \ lvgl/examples/widgets/list/lv_example_list_2.o \ lvgl/examples/widgets/menu/lv_example_menu_1.o \ lvgl/examples/widgets/menu/lv_example_menu_2.o \ lvgl/examples/widgets/menu/lv_example_menu_3.o \ lvgl/examples/widgets/menu/lv_example_menu_4.o \ lvgl/examples/widgets/menu/lv_example_menu_5.o \ lvgl/examples/widgets/meter/lv_example_meter_1.o \ lvgl/examples/widgets/meter/lv_example_meter_2.o \ lvgl/examples/widgets/meter/lv_example_meter_3.o \ lvgl/examples/widgets/meter/lv_example_meter_4.o \ lvgl/examples/widgets/msgbox/lv_example_msgbox_1.o \ lvgl/examples/widgets/obj/lv_example_obj_1.o \ lvgl/examples/widgets/obj/lv_example_obj_2.o \ lvgl/examples/widgets/roller/lv_example_roller_1.o \ lvgl/examples/widgets/roller/lv_example_roller_2.o \ lvgl/examples/widgets/roller/lv_example_roller_3.o \ lvgl/examples/widgets/slider/lv_example_slider_1.o \ lvgl/examples/widgets/slider/lv_example_slider_2.o \ lvgl/examples/widgets/slider/lv_example_slider_3.o \ lvgl/examples/widgets/span/lv_example_span_1.o \ lvgl/examples/widgets/spinbox/lv_example_spinbox_1.o \ lvgl/examples/widgets/spinner/lv_example_spinner_1.o \ lvgl/examples/widgets/switch/lv_example_switch_1.o \ lvgl/examples/widgets/table/lv_example_table_1.o \ lvgl/examples/widgets/table/lv_example_table_2.o \ lvgl/examples/widgets/tabview/lv_example_tabview_1.o \ lvgl/examples/widgets/tabview/lv_example_tabview_2.o \ lvgl/examples/widgets/textarea/lv_example_textarea_1.o \ lvgl/examples/widgets/textarea/lv_example_textarea_2.o \ lvgl/examples/widgets/textarea/lv_example_textarea_3.o \ lvgl/examples/widgets/tileview/lv_example_tileview_1.o \ lvgl/examples/widgets/win/lv_example_win_1.o \ lvgl/src/core/lv_disp.o \ lvgl/src/core/lv_event.o \ lvgl/src/core/lv_group.o \ lvgl/src/core/lv_indev.o \ lvgl/src/core/lv_indev_scroll.o \ lvgl/src/core/lv_obj.o \ lvgl/src/core/lv_obj_class.o \ lvgl/src/core/lv_obj_draw.o \ lvgl/src/core/lv_obj_pos.o \ lvgl/src/core/lv_obj_scroll.o \ lvgl/src/core/lv_obj_style.o \ lvgl/src/core/lv_obj_style_gen.o \ lvgl/src/core/lv_obj_tree.o \ lvgl/src/core/lv_refr.o \ lvgl/src/core/lv_theme.o \ lvgl/src/draw/arm2d/lv_gpu_arm2d.o \ lvgl/src/draw/lv_draw.o \ lvgl/src/draw/lv_draw_arc.o \ lvgl/src/draw/lv_draw_img.o \ lvgl/src/draw/lv_draw_label.o \ lvgl/src/draw/lv_draw_layer.o \ lvgl/src/draw/lv_draw_line.o \ lvgl/src/draw/lv_draw_mask.o \ lvgl/src/draw/lv_draw_rect.o \ lvgl/src/draw/lv_draw_transform.o \ lvgl/src/draw/lv_draw_triangle.o \ lvgl/src/draw/lv_img_buf.o \ lvgl/src/draw/lv_img_cache.o \ lvgl/src/draw/lv_img_decoder.o \ lvgl/src/draw/nxp/lv_gpu_nxp.o \ lvgl/src/draw/nxp/pxp/lv_draw_pxp_blend.o \ lvgl/src/draw/nxp/pxp/lv_gpu_nxp_pxp.o \ lvgl/src/draw/nxp/pxp/lv_gpu_nxp_pxp_osa.o \ lvgl/src/draw/nxp/vglite/lv_draw_vglite_arc.o \ lvgl/src/draw/nxp/vglite/lv_draw_vglite_blend.o \ lvgl/src/draw/nxp/vglite/lv_draw_vglite_rect.o \ lvgl/src/draw/nxp/vglite/lv_gpu_nxp_vglite.o \ lvgl/src/draw/sdl/lv_draw_sdl.o \ lvgl/src/draw/sdl/lv_draw_sdl_arc.o \ lvgl/src/draw/sdl/lv_draw_sdl_bg.o \ lvgl/src/draw/sdl/lv_draw_sdl_composite.o \ lvgl/src/draw/sdl/lv_draw_sdl_img.o \ lvgl/src/draw/sdl/lv_draw_sdl_label.o \ lvgl/src/draw/sdl/lv_draw_sdl_layer.o \ lvgl/src/draw/sdl/lv_draw_sdl_line.o \ lvgl/src/draw/sdl/lv_draw_sdl_mask.o \ lvgl/src/draw/sdl/lv_draw_sdl_polygon.o \ lvgl/src/draw/sdl/lv_draw_sdl_rect.o \ lvgl/src/draw/sdl/lv_draw_sdl_stack_blur.o \ lvgl/src/draw/sdl/lv_draw_sdl_texture_cache.o \ lvgl/src/draw/sdl/lv_draw_sdl_utils.o \ lvgl/src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.o \ lvgl/src/draw/sw/lv_draw_sw.o \ lvgl/src/draw/sw/lv_draw_sw_arc.o \ lvgl/src/draw/sw/lv_draw_sw_blend.o \ lvgl/src/draw/sw/lv_draw_sw_dither.o \ lvgl/src/draw/sw/lv_draw_sw_gradient.o \ lvgl/src/draw/sw/lv_draw_sw_img.o \ lvgl/src/draw/sw/lv_draw_sw_layer.o \ lvgl/src/draw/sw/lv_draw_sw_letter.o \ lvgl/src/draw/sw/lv_draw_sw_line.o \ lvgl/src/draw/sw/lv_draw_sw_polygon.o \ lvgl/src/draw/sw/lv_draw_sw_rect.o \ lvgl/src/draw/sw/lv_draw_sw_transform.o \ lvgl/src/draw/swm341_dma2d/lv_gpu_swm341_dma2d.o \ lvgl/src/extra/layouts/flex/lv_flex.o \ lvgl/src/extra/layouts/grid/lv_grid.o \ lvgl/src/extra/libs/bmp/lv_bmp.o \ lvgl/src/extra/libs/ffmpeg/lv_ffmpeg.o \ lvgl/src/extra/libs/freetype/lv_freetype.o \ lvgl/src/extra/libs/fsdrv/lv_fs_fatfs.o \ lvgl/src/extra/libs/fsdrv/lv_fs_posix.o \ lvgl/src/extra/libs/fsdrv/lv_fs_stdio.o \ lvgl/src/extra/libs/fsdrv/lv_fs_win32.o \ lvgl/src/extra/libs/gif/gifdec.o \ lvgl/src/extra/libs/gif/lv_gif.o \ lvgl/src/extra/libs/png/lodepng.o \ lvgl/src/extra/libs/png/lv_png.o \ lvgl/src/extra/libs/qrcode/lv_qrcode.o \ lvgl/src/extra/libs/qrcode/qrcodegen.o \ lvgl/src/extra/libs/rlottie/lv_rlottie.o \ lvgl/src/extra/libs/sjpg/lv_sjpg.o \ lvgl/src/extra/libs/sjpg/tjpgd.o \ lvgl/src/extra/lv_extra.o \ lvgl/src/extra/others/fragment/lv_fragment.o \ lvgl/src/extra/others/fragment/lv_fragment_manager.o \ lvgl/src/extra/others/gridnav/lv_gridnav.o \ lvgl/src/extra/others/ime/lv_ime_pinyin.o \ lvgl/src/extra/others/imgfont/lv_imgfont.o \ lvgl/src/extra/others/monkey/lv_monkey.o \ lvgl/src/extra/others/msg/lv_msg.o \ lvgl/src/extra/others/snapshot/lv_snapshot.o \ lvgl/src/extra/themes/basic/lv_theme_basic.o \ lvgl/src/extra/themes/default/lv_theme_default.o \ lvgl/src/extra/themes/mono/lv_theme_mono.o \ lvgl/src/extra/widgets/animimg/lv_animimg.o \ lvgl/src/extra/widgets/calendar/lv_calendar.o \ lvgl/src/extra/widgets/calendar/lv_calendar_header_arrow.o \ lvgl/src/extra/widgets/calendar/lv_calendar_header_dropdown.o \ lvgl/src/extra/widgets/chart/lv_chart.o \ lvgl/src/extra/widgets/colorwheel/lv_colorwheel.o \ lvgl/src/extra/widgets/imgbtn/lv_imgbtn.o \ lvgl/src/extra/widgets/keyboard/lv_keyboard.o \ lvgl/src/extra/widgets/led/lv_led.o \ lvgl/src/extra/widgets/list/lv_list.o \ lvgl/src/extra/widgets/menu/lv_menu.o \ lvgl/src/extra/widgets/meter/lv_meter.o \ lvgl/src/extra/widgets/msgbox/lv_msgbox.o \ lvgl/src/extra/widgets/span/lv_span.o \ lvgl/src/extra/widgets/spinbox/lv_spinbox.o \ lvgl/src/extra/widgets/spinner/lv_spinner.o \ lvgl/src/extra/widgets/tabview/lv_tabview.o \ lvgl/src/extra/widgets/tileview/lv_tileview.o \ lvgl/src/extra/widgets/win/lv_win.o \ lvgl/src/font/lv_font.o \ lvgl/src/font/lv_font_dejavu_16_persian_hebrew.o \ lvgl/src/font/lv_font_fmt_txt.o \ lvgl/src/font/lv_font_loader.o \ lvgl/src/font/lv_font_montserrat_10.o \ lvgl/src/font/lv_font_montserrat_12.o \ lvgl/src/font/lv_font_montserrat_12_subpx.o \ lvgl/src/font/lv_font_montserrat_14.o \ lvgl/src/font/lv_font_montserrat_16.o \ lvgl/src/font/lv_font_montserrat_18.o \ lvgl/src/font/lv_font_montserrat_20.o \ lvgl/src/font/lv_font_montserrat_22.o \ lvgl/src/font/lv_font_montserrat_24.o \ lvgl/src/font/lv_font_montserrat_26.o \ lvgl/src/font/lv_font_montserrat_28.o \ lvgl/src/font/lv_font_montserrat_28_compressed.o \ lvgl/src/font/lv_font_montserrat_30.o \ lvgl/src/font/lv_font_montserrat_32.o \ lvgl/src/font/lv_font_montserrat_34.o \ lvgl/src/font/lv_font_montserrat_36.o \ lvgl/src/font/lv_font_montserrat_38.o \ lvgl/src/font/lv_font_montserrat_40.o \ lvgl/src/font/lv_font_montserrat_42.o \ lvgl/src/font/lv_font_montserrat_44.o \ lvgl/src/font/lv_font_montserrat_46.o \ lvgl/src/font/lv_font_montserrat_48.o \ lvgl/src/font/lv_font_montserrat_8.o \ lvgl/src/font/lv_font_simsun_16_cjk.o \ lvgl/src/font/lv_font_unscii_16.o \ lvgl/src/font/lv_font_unscii_8.o \ lvgl/src/hal/lv_hal_disp.o \ lvgl/src/hal/lv_hal_indev.o \ lvgl/src/hal/lv_hal_tick.o \ lvgl/src/misc/lv_anim.o \ lvgl/src/misc/lv_anim_timeline.o \ lvgl/src/misc/lv_area.o \ lvgl/src/misc/lv_async.o \ lvgl/src/misc/lv_bidi.o \ lvgl/src/misc/lv_color.o \ lvgl/src/misc/lv_fs.o \ lvgl/src/misc/lv_gc.o \ lvgl/src/misc/lv_ll.o \ lvgl/src/misc/lv_log.o \ lvgl/src/misc/lv_lru.o \ lvgl/src/misc/lv_math.o \ lvgl/src/misc/lv_mem.o \ lvgl/src/misc/lv_printf.o \ lvgl/src/misc/lv_style.o \ lvgl/src/misc/lv_style_gen.o \ lvgl/src/misc/lv_templ.o \ lvgl/src/misc/lv_timer.o \ lvgl/src/misc/lv_tlsf.o \ lvgl/src/misc/lv_txt.o \ lvgl/src/misc/lv_txt_ap.o \ lvgl/src/misc/lv_utils.o \ lvgl/src/widgets/lv_arc.o \ lvgl/src/widgets/lv_bar.o \ lvgl/src/widgets/lv_btn.o \ lvgl/src/widgets/lv_btnmatrix.o \ lvgl/src/widgets/lv_canvas.o \ lvgl/src/widgets/lv_checkbox.o \ lvgl/src/widgets/lv_dropdown.o \ lvgl/src/widgets/lv_img.o \ lvgl/src/widgets/lv_label.o \ lvgl/src/widgets/lv_line.o \ lvgl/src/widgets/lv_objx_templ.o \ lvgl/src/widgets/lv_roller.o \ lvgl/src/widgets/lv_slider.o \ lvgl/src/widgets/lv_switch.o \ lvgl/src/widgets/lv_table.o \ lvgl/src/widgets/lv_textarea.o \
1.2 快速测试Makefile修改是否有效
把主函数中和硬件相关的显示,输入等初始化代码屏蔽,main改为lv_main
,并把lv_main
变成一个命令:int lv_main(int argc, char **argv) { //(void *)argc; /*Unused*/ //(void)argv; /*Unused*/ printf("lv_main."); #if 0 /*Initialize LVGL*/ lv_init(); /*Create a default group for keyboard navigation*/ lv_group_set_default(lv_group_create()); /*Initialize the HAL (display, input devices, tick) for LVGL*/ hal_init(); ..... #endif return 0; } static lv_disp_t * hal_init(void ) { #if 0 disp_layer_cfg_def(); static lv_disp_draw_buf_t draw_buf; lv_disp_draw_buf_init(&draw_buf, disp_buf1, disp_buf2, HOR_RES * VER_RES); static lv_disp_drv_t disp_drv; lv_disp_drv_init(&disp_drv); ...... lv_disp_drv_register(&disp_drv); #endif lv_disp_t * disp = NULL; return disp; } FINSH_FUNCTION_EXPORT_ALIAS(lv_main, lv_main, lv_main );
编译通过,烧录测试。输入help,可以看到lv_main命令,输入lv_main,打印“lv_main”:
msh />help RT-Thread shell commands: ...... lv_main - lv_main ...... msh />lv_main lv_main
2.移植刷新显示内存函数dummy_flush_cb
只要往显存地址mem = g_disp_mm[mem_id].info_base
里面填写像素数据,就可以得到我们要显示的内容,把这个地址传给一个全局变量,在lvgl中使用这个全局变量即可。
于是我们在disp_mem
源码所在的C文件声明一个全局变量:uint32_t * g_p_mem_base;
把显存地址传给g_p_mem_base:
g_p_mem_base = g_disp_mm[mem_id].info_base;
有了这个地址,我们就可以编写自己的显示回调函数:
#define HOR_RES 800 #define VER_RES 480 extern uint32_t * g_p_mem_base; #define line_length 800 * sizeof(rt_uint32_t) / 4 static void dummy_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) { /*Truncate the area to the screen*/ int32_t act_x1 = area->x1 < 0 ? 0 : area->x1; int32_t act_y1 = area->y1 < 0 ? 0 : area->y1; int32_t act_x2 = area->x2 > (int32_t)HOR_RES - 1 ? (int32_t)HOR_RES - 1 : area->x2; int32_t act_y2 = area->y2 > (int32_t)VER_RES - 1 ? (int32_t)VER_RES - 1 : area->y2; lv_coord_t w = (act_x2 - act_x1 + 1); long int location = 0; /* 32 bit per pixel */ uint32_t *fbp32 = (uint32_t *)g_p_mem_base; uint32_t y; for (y = act_y1; y <= act_y2; y++) { location = act_x1 + y * line_length; rt_memcpy(&fbp32[location], (uint32_t *)color_p, (act_x2 - act_x1 + 1) * 4); color_p += w; } lv_disp_flush_ready(disp_drv); } static lv_color_t disp_buf1[HOR_RES * VER_RES]; static lv_color_t disp_buf2[HOR_RES * VER_RES]; int disp_layer_cfg_def(void); static lv_disp_t * hal_init(void ) { #if 1 disp_layer_cfg_def(); static lv_disp_draw_buf_t draw_buf; lv_disp_draw_buf_init(&draw_buf, disp_buf1, disp_buf2, HOR_RES * VER_RES); static lv_disp_drv_t disp_drv; lv_disp_drv_init(&disp_drv); disp_drv.draw_buf = &draw_buf; disp_drv.flush_cb = dummy_flush_cb; disp_drv.hor_res = HOR_RES; disp_drv.ver_res = VER_RES; lv_disp_drv_register(&disp_drv); #endif lv_disp_t * disp = NULL; return disp; }
再make编译,通过。
3.创建一个定时器调用lvgl心跳lv_tick_inc()
Melis使用rt-thread内核,rt-thread的节拍由宏定义 CONFIG_HZ决定:#define RT_TICK_PER_SECOND CONFIG_HZ
CONFIG_HZ通过 命令 make menuconfig 配置:
这里是200Hz,也就是一个时钟节拍为5ms。
static rt_timer_t timer1; // lv_tick_inc(5); static lv_disp_t * hal_init(void ) { #if 1 /* 创建定时器1 周期定时器 */ timer1 = rt_timer_create("timer1", lv_tick_inc, // 回调函数 5, // 回调函数的传入参数 1, // 一个时钟节拍调用一次回调函数,具体是5ms RT_TIMER_FLAG_PERIODIC); /* 启动定时器1 */ if (timer1 != RT_NULL) rt_timer_start(timer1); disp_layer_cfg_def(); ...... #endif lv_disp_t * disp = NULL; return disp; }
lv_timer_handler()调用间隔是10ms,而lv_tick_inc()调用间隔是5ms,这样比较合理。
4.pack打包出错:
root@SK-JNTINRTMRDZW:/home/book/D1s-Melis-master# pack INFO: temporarily Enter pack directory: "/home/book/D1s-Melis-master/out/d1s-mq/image", will be back when terminated INFO: copying config/boot binary/phoenix plugin files /home/book/D1s-Melis-master/tools/phoenixplugin/Tools.fex ...... ...... INFO: running the function do_finish "sys_partition_nor.bin" partitation file Path=/home/book/D1s-Melis-master/out/d1s-mq/image/sys_partition_nor.bin mbr_name file Path=/home/book/D1s-Melis-master/out/d1s-mq/image/sunxi_mbr_nor.fex download_name file Path=/home/book/D1s-Melis-master/out/d1s-mq/image/dlinfo.fex ERROR: dl file melis_pkg_nor.fex size too large ERROR: filename = melis_pkg_nor.fex ERROR: dl_file_size = 2272 sector ERROR: part_size = 2048 sector ERROR: update mbr file fail ERROR: update_mbr failed
melis_pkg_nor.fex
文件比分配的空间要大,装不下。
修改分区文件D1s-Melis/projects/d1s-mq/configs/sys_partition_nor.fex
第44,45行:
;--------------------------------------------------------------------------------------------------------- ; 说明: 脚本中的字符串区分大小写,用户可以修改"="后面的数值,但是不要修改前面的字符串 ;--------------------------------------------------------------------------------------------------------- ;-------------------------------------------------------------------------------------------------- ; 固件下载参数配置 ;-------------------------------------------------------------------------------------------------- ;**************************************************** ; mbr的大小, 以Kbyte为单位 ;**************************************************** [mbr] size = 16 ;******************************************************************************************************** ; 分区配置 ; ; ; partition 定义范例: ; [partition] ; //表示是一个分区 ; name = USERFS2 ; //分区名称 ; size = 16384 ; //分区大小 单位: 扇区.分区表示个数最多2^31 * 512 = 2T ; downloadfile = "123.fex" ; //下载文件的路径和名称,可以使用相对路径,相对是指相对于image.cfg文件所在分区。也可以使用绝对路径 ; keydata = 1 ; //私有数据分区,重新量产数据将不丢失 ; encrypt = 1 ; //采用加密方式烧录,将提供数据加密,但损失烧录速度 ; user_type = ? ; //私有用法 ; verify = 1 ; //要求量产完成后校验是否正确 ; ; 注:1、name唯一, 不允许同名 ; 2、name最大12个字符 ; 3、size = 0, 将创建一个无大小的空分区 ; 4、为了安全和效率考虑,分区大小最好保证为16M字节的整数倍 ;******************************************************************************************************** [partition_start] ;[partition] ; name = boot ; size = 6656 ; downloadfile = "boot.fex" ; user_type = 0x8000 [partition] name = bootA ;size = 2048 size = 4096 downloadfile = "melis_pkg_nor.fex" user_type = 0x8000 ;[partition] ; name = bootB ; size = 6144 ; downloadfile = "melis_pkg_nor.fex" ; user_type = 0x8000 ;[partition] ; name = env ; size = 8 ; downloadfile = "env.fex" ; user_type = 0x8000 ;[partition] ; name = env-redund ; size = 8 ; downloadfile = "env.fex" ; user_type = 0x8000 ;rootfs 7616 sector in rootfs.ini make 7616*1024/512=15232 sectors for it. [partition] name = ROOTFS size = 10240 ;size = 20336 downloadfile = "data_udisk.fex" user_type = 0x8000 [partition] name = UDISK ;size = flash size - (boot0 + mbr) size - env - env-redund - ROOTFS ;8(or 16) * 1024 * 2 - 64 * 2 - 5632 - 8 - 8 - 10240 ;size = 20336 ;downloadfile = "data_udisk.fex" user_type = 0x8000
再次pack打包成功。烧录运行,输入lv_main命令:
msh />lv_main
5.设置开机启动
修改startup.sh
(位于目录 D1s-Melis/projects/d1s-mq/data/UDISK/startup.sh):echo "Execute startup script begin.............." #insmod d:\mod\display.mod #insmod d:\mod\orange.mod #insmod d:\apps\desktop.mod lv_main echo "...............Execute startup script end"
6.源码下载
源码没有startup.sh 和 melis_pkg_nor.fex ,这两个文件的修改比较简单。
源码链接:https://gitee.com/huangweide001/linux-d1-h-test/tree/master/disp2
源码包含了可以直接烧录的img文件 melis_d1s-mq_uart0_8Mnor_lvgl.img 。————————————————
本文为CSDN博主「hwd00001」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/hwd00001/article/details/130017849 -
按照东山派的官方教程编译buildroot(东山哪吒,D1-H)踩坑记录
原文链接:https://blog.csdn.net/hwd00001/article/details/127896895
作者 @ hwd00001整个编译的耗时主要是github的下载速度,很多依赖包都需要从github下载。
这里我以东山派的官方教程为主,根据我的实际情况稍作调整,梳理一下编译buildroot流程。
官方教程链接:使用buildroot-SDK编译构建系统
1.编译流程
1.1获取sdk源码
有2个服务器github和gitee,我使用gitee的源。
依次执行命令:
book@virtual-machine:~$ git clone https://gitee.com/weidognshan/buildroot_dongshannezhastu book@virtual-machine:~$ cd buildroot_dshannezhastu book@virtual-machine:~/buildroot_dongshannezhastu$ git submodule update --init --recursive book@virtual-machine:~/buildroot_dongshannezhastu$ git submodule update --recursive --remote
这个步骤还是比较快的,10分钟以内,取决于网速。
1.2 补充:下载riscv64-glibc-gcc-thead_20200702.tar.xz
这个步骤参考后面的问题2.
1.3 补充:安装mtool工具
这个步骤参考后面的问题3.
1.4 安装必要依赖包
sudo apt-get install -y libncurses5-dev u-boot-tools
1.5 编译sdcard 最小系统镜像
book@virtual-machine:~/buildroot_dongshannezhastu$ cd buildroot-awol/ book@virtual-machine:~/buildroot_dongshannezhastu/buildroot-awol$ make BR2_EXTERNAL="../br2lvgl ../br2qt5 ../br2nezhastu" dongshannezhastu_sdcard_core_defconfig book@virtual-machine:~/buildroot_dongshannezhastu/buildroot-awol$ make
1.6 烧录最小镜像系统到tf(SD)卡
原文档:东山哪吒快速启动
1.6.1 安装烧录工具
1.6.2 格式化SD卡
1.6.3 烧录镜像到sd卡
1.7 运行系统
把SD卡插到开发板,上电,检查一下是不是最新编译的:
我对比一下原来的一张烧录官方提供的image的文件日期:
2.问题踩坑记录
问题1:make指令不执行
root@SK-JNTINRTMRDZW:/home/hwd/buildroot_dongshannezhastu/buildroot-awol> make Your PATH contains spaces, TABs, and/or newline (\n) characters. This doesn't work. Fix you PATH. support/dependencies/dependencies.mk:27: recipe for target 'dependencies' failed make: *** [dependencies] Error 1
百度解决方法:《This doesn‘t work. Fix you PATH》
采用这个方法顺利解决(切换环境变量)。
问题2:riscv64-glibc-gcc-thead_20200702.tar.xz File format not recognized
WARNING: no hash file for riscv64-glibc-gcc-thead_20200702.tar.xz ....../riscv64-glibc-gcc-thead_20200702.tar.xz: File format not recognized tar: This does not look like a tar archive tar: Exiting with failure status due to previous errors
去到该文件所在目录
/home/hwd/buildroot_dongshannezhastu/buildroot-awol/dl/toolchain-external-custom
看到,文件的大小只有1k,不知道是什么原因导致的。
继续百度搜到《为全志D1/RISCV64设备移植openwrt-22.03系统》,提到要手动下载riscv64-glibc-gcc-thead_20200702.tar.xz
,提供了东山派的官方链接:《快速使用Tina-SDK 指南》:下载完成后,发现文件名是
riscv64-glibc-gcc-thead_20200702tar.xz
:
增加小数点后,不用解压,重新执行make,自动解压成功,往下进行。问题3: /bin/sh: 1: mcopy: not found
没有安装mtool工具:
apt-get install mtools
重新make,终于完成:
-
求推荐一个视频录像的芯片方案
需要的功能如下:
- 支持数字摄像头输入,
- cvbs输入(和数字摄像头输入不是同时进行),
- cvbs输出,
- LCD屏幕显示(和cvbs输出不是同时进行),
- 支持编码器和解码器,最高支持1920X1080@30fps,可以更高。
- 支持SD
我看F1C100S的datasheet,没有H.264编码器。是不是就可以直接排除F1C100S了?
-
Reply: 参照大佬的教程在Tina下适配 i80 LCD 显示屏,一接屏幕就报错重启
@bayche 谢谢大佬,还有个问题
disp_al_manager_apply ouput_type:0 怎么把 ouput_type:改为1,是修改board.dts的disp么 ? -
参照大佬的教程在Tina下适配 i80 LCD 显示屏,一接屏幕就报错重启
参照大佬的教程来做的:https://www.gloomyghost.com/live/20220424.aspx
然后一装上屏幕就会报以下错误
然后就重启了,是 板子的io没有配制好还是 电路有问题?
-
【米尔MYD-YT507开发板试用】基于Fluter+Django+OpenCV的米尔行车记录仪
经过充分的学习T507开发板,最终选择应用Fluter+Django+OpenCV架构,来实现了一款米尔行车记录仪,现将实现的具体内容,与大家分享。
目录:
- 行车记录仪业务逻辑规划
- 硬件设备准备
- 摄像头信息记录和实时画面播放服务开发
- 摄像头视频信息记录
- 摄像头服务的完整代码
- 历史数据RestFul服务开发
- Flutter Web界面开发
- 整体运行效果
- 车试
- 实际代码使用
- 感谢
- 总结
一、行车记录仪业务逻辑规划
经过详细的分析,规划了如下的基本业务逻辑结构:
整体分为三个部分:
-
记录服务:用于记录摄像头拍摄的视频信息,以及提供摄像头当前画面的实时播放服务。
-
Django服务:包括RestFul提供API接口获取历史数据信息,以及为Flutter的Web界面提供访问服务。
-
Flutter Web界面,用于实时画面播放、历史记录播放的界面。
为了又快又好的开发行车记录仪的实际界面,以及后续进行各移动平台的App开发,选择了Flutter。事实证明,坑太多了。不过,跨平台特性,确实好。
二、硬件设备准备:
开发这款行车记录仪,实际使用到的硬件设备如下:
1.主控板:米尔MYD-YT507开发板
2.摄像头:海康威视DS-E11 720P USB摄像头
3.存储卡:闪迪32GB高速MicroSD存储卡
4.路由器:云来宝盒无线路由器路由器没有拍照,用普通无线路由器即可,当然带宽越高越好。
开发板上有两个USB3.0接口,选一个接上路由器即可。
然后,将开发板使用网线连接到路由器,再上电,就可以进行实际的操作了。
我这边实际使用中,电源接口有点松,容易突然断电,所以使用胶带进行了加固。
三、摄像头实时画面播放服务开发
在之前尝试MJPEG视频流直播的时候,使用了mjpeg_streamer,但不清楚如何进行视频的分割。
因为行车记录仪,一般都是按照一定的时间进行视频的分割存放,避免单个视频过大。
经过仔细的学习了解,OpenCV也可以获取摄像头的信息,并按照需要写入文件。
最后,采用了Python+OpenCV的方案,有Python负责具体的逻辑,Python-OpenCV负责摄像头视频数据的采集。
视频采集部分,包含的具体功能为:
- 能够采集摄像头的数据
- 能够提供实时视频查看
- 能够按时间写入视频数据到文件,自动进行分割
采集摄像头的数据,Python-opencv搞定。
写入视频数据到文件,Python简单搞定。
提供实时视频预览,这个花了不少功夫。
因为同时要写入到文件,还要提供预览,数据需要复用。
经过学习了解,可以将Python-opencv采集的画面,按帧在HTTP以JPEG数据发送,那么播放端,就能收到MJPEG数据流,进行播放了。
因此,第一版,参考资料,实现了一个Python版的MJPEG播放服务,读取帧,写入临时文件,然后从临时文件读取数据返回。
为了提高效率,还进行了优化,不写入临时文件,直接在内存中进行转换。
最终形成的代码如下:
# http服务器请求处理:网页、MJPEG数据流 class CamHandler(BaseHTTPRequestHandler): def do_GET(self): # mjpeg推流 if self.path.endswith('.mjpg'): self.send_response(200) self.send_header('Content-type','multipart/x-mixed-replace; boundary=--jpgboundary') self.end_headers() while True: if is_stop: break try: # rc,img = cameraCapture.read() rc,img = success,frame if not rc: continue if True: imgRGB=cv2.cvtColor(img,cv2.COLOR_BGR2RGB) jpg = Image.fromarray(imgRGB) tmpFile = BytesIO() jpg.save(tmpFile,'JPEG') self.wfile.write(b"--jpgboundary") self.send_header(b'Content-type','image/jpeg') self.send_header(b'Content-length',str(tmpFile.getbuffer().nbytes)) self.end_headers() jpg.save(self.wfile,'JPEG') else: img_fps = JPEG_QUALITY_VALUE img_param = [int(cv2.IMWRITE_JPEG_QUALITY), img_fps] img_str = cv2.imencode('.jpg', img, img_param)[1].tobytes() # change image to jpeg format self.send_header('Content-type','image/jpeg') self.end_headers() self.wfile.write(img_str) self.wfile.write(b" --jpgboundary ") # end of this part time.sleep(0.033) except KeyboardInterrupt: self.wfile.write(b" --jpgboundary-- ") break except BrokenPipeError: continue return # 网页 if self.path == '/' or self.path.endswith('.html'): self.send_response(200) self.send_header('Content-type','text/html') self.end_headers() self.wfile.write(b'<html><head><title>Live video</title></head><body>') self.wfile.write(('<img src="http://%s/live.mjpg"/>' % self.headers.get('Host')).encode()) self.wfile.write(b'</body></html>') return
这段代码,提供了两个功能:
-
如果通过浏览器访问http://ip:端口/index.html,就会返回包含MJPEG调用地址的网页
-
如果通过浏览器访问http://ip:端口/live.mjpg,就会返回MJPEG流媒体数据,以便播放
在开发过程中,运行该服务后,随时可以通过浏览器查看效果。
其中涉及到opencv相关的知识,以及webserver相关的知识,大家可以了解相关的资料做基础,这里就不详细说了。
本来以为提供了MJPEG服务,就能够在Flutter开发的Web界面中调用了。然而,实际使用时,发现坑来了。
Flutter的公共库里面,有MJPEG的库,但是在目前的版本中,已经不能使用了。且官方认为用的人不多,在可预见的将来,不会修复。悲催啊!!!
条条大道通罗马,此处不通开新路。
经过再次的学习了解,Flutter的Video功能,支持Stream模式,其可以采用WebSocket的方式来获取数据,然后进行播放。
那么,只要能够在服务端,将获取的帧数据,使用WebSocket提供,就能够正常播放了。
最终,使用Python开发了能够提供实时视频数据的WebSocket服务,具体代码如下:
# websocket服务请求处理 async def CamTransmitHandler(websocket, path): print("Client Connected !") try : while True: # rc,img = cameraCapture.read() rc,img = success,frame if not rc: continue img_fps = JPEG_QUALITY_VALUE img_param = [int(cv2.IMWRITE_JPEG_QUALITY), img_fps] encoded = cv2.imencode('.jpg', img, img_param)[1] data = str(base64.b64encode(encoded)) data = data[2:len(data)-1] await websocket.send(data) # cv2.imshow("Transimission", frame) # if cv2.waitKey(1) & 0xFF == ord('q'): # break # cap.release() except EXCEPTION_CONNECTION_CLOSE as e: print("Client Disconnected !") # cap.release() except: print("Someting went Wrong !")
这个部分比之前的更简单,就是简单的转换数据,喂数据给WebSocket即可。
上述的两部分代码中,都没有包含完整的逻辑处理过程,只有关键代码部分。
各部分分别讲完以后,将提供完整的代码以供学习。
到这里,实时流媒体功能就实现了。
四、摄像头视频信息记录
实际上,上一步的实时视频功能,也依赖于这一步,因为其需要共享实际获取的摄像头信息。
其基本逻辑也比较简单,步骤如下:- 初始化opencv,开始摄像头数据帧的获取
- 检测是否达到预定时间
- 未达到时间,则继续写入当前视频
- 达到时间了,则关闭当前视频,写入缩略图,并开启新的文件写入
具体代码如下:
# 捕获摄像头 cameraCapture = cv2.VideoCapture(CAMERA_NO) # 摄像头参数设置 cameraCapture.set(cv2.CAP_PROP_FRAME_WIDTH, 320) cameraCapture.set(cv2.CAP_PROP_FRAME_WIDTH, 240) cameraCapture.set(cv2.CAP_PROP_SATURATION, 135) fps = 30 size=(int(cameraCapture.get(cv2.CAP_PROP_FRAME_WIDTH)),int(cameraCapture.get(cv2.CAP_PROP_FRAME_HEIGHT))) # 读取捕获的数据 success,frame = cameraCapture.read()
...
while True: if is_stop: success = False break; success,frame = cameraCapture.read() if not success: continue time_now = get_current_time() if time_now["time"] - time_record["time"] >= ROTATE_TIME: if time_record_prev: thubm_file = get_file_name(time_record_prev, 'thumbs', 'jpg') print("[Info] write to thumb: %s" % thubm_file) if not os.path.isfile(thubm_file): cv2.imwrite(thubm_file, frame) time_record = time_now time_record_prev = get_current_time() video_file = get_file_name(time_record_prev, 'videos', MEDIA_EXT) print("[Info] write to video: %s" % video_file) # encode = cv2.VideoWriter_fourcc(*"mp4v") encode = cv2.VideoWriter_fourcc(*'X264') # encode = cv2.VideoWriter_fourcc(*'AVC1') # encode = cv2.VideoWriter_fourcc(*'XVID') # encode = cv2.VideoWriter_fourcc(*'H264') videoWriter=cv2.VideoWriter(video_file, encode,fps,size) # mp4 numFrameRemaining = ROTATE_TIME * fps #摄像头捕获持续时间 while success and numFrameRemaining > 0: videoWriter.write(frame) success,frame = cameraCapture.read() numFrameRemaining -= 1 cameraCapture.release()
上述代码的逻辑其实很清晰,有opencv的基础,一看就懂。
有一个关键点需要注意的就是
encode = cv2.VideoWriter_fourcc(*'X264')
,在不同的环境下面,提供的编码方式不完全相同。在米尔MYD-YT507开发板的Ubuntu环境中,可以使用X264编码。
上述代码,会持续不断的读取摄像头的数据帧,存放到frame变量中,然后写入到视频文件中。并进行时间判断,以确定是否需要写入到新的视频文件中。
frame变量,在之前实时视频服务中,也会使用,相当于是共享了。
五、摄像头服务的完整代码
经过上面的两个部分,就完成了摄像头部分的服务代码。
整体的代码如下:
# -*- coding: utf-8 -*- import signal import cv2 import time from PIL import Image from threading import Thread from http.server import BaseHTTPRequestHandler,HTTPServer from socketserver import ThreadingMixIn from io import BytesIO import os import sys import websockets import asyncio import base64 import ctypes import inspect CAMERA_NO = 2 ROTATE_TIME = 120 MJPEG_ENABLE = 1 WEBSOCKET_ENABLE = 1 MJPEG_SERVER_PORT = 28888 WEBSOCKET_PORT = 28889 JPEG_QUALITY_VALUE = 65 STORE_DIR = "./data/" if os.uname()[0] == 'Darwin' else "/sdcard/data/" MEDIA_EXT = "mkv" EXCEPTION_CONNECTION_CLOSE = websockets.exceptions.ConnectionClosed if sys.version[:3] == '3.6' else websockets.ConnectionClosed def _async_raise(tid, exctype): """raises the exception, performs cleanup if needed""" try: tid = ctypes.c_long(tid) if not inspect.isclass(exctype): exctype = type(exctype) res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype)) if res == 0: # pass raise ValueError("invalid thread id") elif res != 1: # """if it returns a number greater than one, you're in trouble, # and you should call it again with exc=NULL to revert the effect""" ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None) raise SystemError("PyThreadState_SetAsyncExc failed") except Exception as err: print(err) def stop_thread(thread): """终止线程""" _async_raise(thread.ident, SystemExit) # 信号处理回调 def signal_handler(signum, frame): # global cameraCapture # global thread # global server # global is_stop # global success print('signal_handler: caught signal ' + str(signum)) if signum == signal.SIGINT.value: print('stop server:') is_stop = True success = False print("mjpeg server.socket.close...") server.socket.close() print("mjpeg server.shutdown...") server.shutdown() print("ws server.socket.close...") server_ws.ws_server.close() time.sleep(1) # print("ws server.shutdown...") # await server_ws.ws_server.wait_closed() print("mjpeg thread.shutdown...") thread_mjpeg.join() print("ws loop.shutdown...") # event_loop_ws.stop() event_loop_ws.call_soon_threadsafe(event_loop_ws.stop) time.sleep(1) # print("ws thread.shutdown...") # stop_thread(thread_ws) # time.sleep(1) # print(server) # print(server_ws) print(thread_mjpeg.is_alive()) print(thread_ws.is_alive()) print(event_loop_ws.is_running()) # thread_ws.join() print("cameraCapture.release...") cameraCapture.release() print("quit...") # print(server_ws) sys.exit(0) # http服务器请求处理:网页、MJPEG数据流 class CamHandler(BaseHTTPRequestHandler): def do_GET(self): # mjpeg推流 if self.path.endswith('.mjpg'): self.send_response(200) self.send_header('Content-type','multipart/x-mixed-replace; boundary=--jpgboundary') self.end_headers() while True: if is_stop: break try: # rc,img = cameraCapture.read() rc,img = success,frame if not rc: continue if True: imgRGB=cv2.cvtColor(img,cv2.COLOR_BGR2RGB) jpg = Image.fromarray(imgRGB) tmpFile = BytesIO() jpg.save(tmpFile,'JPEG') self.wfile.write(b"--jpgboundary") self.send_header(b'Content-type','image/jpeg') self.send_header(b'Content-length',str(tmpFile.getbuffer().nbytes)) self.end_headers() jpg.save(self.wfile,'JPEG') else: img_fps = JPEG_QUALITY_VALUE img_param = [int(cv2.IMWRITE_JPEG_QUALITY), img_fps] img_str = cv2.imencode('.jpg', img, img_param)[1].tobytes() # change image to jpeg format self.send_header('Content-type','image/jpeg') self.end_headers() self.wfile.write(img_str) self.wfile.write(b" --jpgboundary ") # end of this part time.sleep(0.033) except KeyboardInterrupt: self.wfile.write(b" --jpgboundary-- ") break except BrokenPipeError: continue return # 网页 if self.path == '/' or self.path.endswith('.html'): self.send_response(200) self.send_header('Content-type','text/html') self.end_headers() self.wfile.write(b'<html><head><title>Live video</title></head><body>') self.wfile.write(('<img src="http://%s/live.mjpg"/>' % self.headers.get('Host')).encode()) self.wfile.write(b'</body></html>') return class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): """Handle requests in a separate thread.""" # 启动MJPEG服务 def mjpeg_server_star(): global success global server global thread_mjpeg try: server = ThreadedHTTPServer(('0.0.0.0', MJPEG_SERVER_PORT), CamHandler) print("mjpeg server started: http://0.0.0.0:%d" % MJPEG_SERVER_PORT) # server.serve_forever() thread_mjpeg = Thread(target=server.serve_forever); thread_mjpeg.start() except KeyboardInterrupt: print("mjpeg server stoping...") server.socket.close() server.shutdown() print("mjpeg server stoped") # websocket服务请求处理 async def CamTransmitHandler(websocket, path): print("Client Connected !") try : while True: # rc,img = cameraCapture.read() rc,img = success,frame if not rc: continue img_fps = JPEG_QUALITY_VALUE img_param = [int(cv2.IMWRITE_JPEG_QUALITY), img_fps] encoded = cv2.imencode('.jpg', img, img_param)[1] data = str(base64.b64encode(encoded)) data = data[2:len(data)-1] await websocket.send(data) # cv2.imshow("Transimission", frame) # if cv2.waitKey(1) & 0xFF == ord('q'): # break # cap.release() except EXCEPTION_CONNECTION_CLOSE as e: print("Client Disconnected !") # cap.release() except: print("Someting went Wrong !") # websocket服务器启动 def websocket_server_start(): global thread_ws global server_ws global event_loop_ws event_loop_ws = asyncio.new_event_loop() def run_server(): global server_ws print("websocket server started: ws://0.0.0.0:%d" % WEBSOCKET_PORT) server_ws = websockets.serve(CamTransmitHandler, port=WEBSOCKET_PORT, loop=event_loop_ws) event_loop_ws.run_until_complete(server_ws) event_loop_ws.run_forever() thread_ws = Thread(target=run_server) thread_ws.start() # try: # yield # except e: # print("An exception occurred") # finally: # event_loop.call_soon_threadsafe(event_loop.stop) # 获取存储的文件名 def get_file_name(time_obj, path, ext): file_name_time = "%04d-%02d-%02d_%02d-%02d-%02d" % (time_obj["year"], time_obj["month"], time_obj["day"], time_obj["hour"], time_obj["min"], 0) return '%s/%s/%s.%s' % (STORE_DIR, path, file_name_time, ext) # 获取当前整分时间 def get_current_time(): time_now = time.localtime() time_int = int(time.time()) return { "year": time_now.tm_year, "month": time_now.tm_mon, "day": time_now.tm_mday, "hour": time_now.tm_hour, "min": time_now.tm_min, "sec": time_now.tm_sec, "time": time_int - time_now.tm_sec } # 设置信号回调 signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler) # 捕获摄像头 cameraCapture = cv2.VideoCapture(CAMERA_NO) # 摄像头参数设置 cameraCapture.set(cv2.CAP_PROP_FRAME_WIDTH, 320) cameraCapture.set(cv2.CAP_PROP_FRAME_WIDTH, 240) cameraCapture.set(cv2.CAP_PROP_SATURATION, 135) fps = 30 size=(int(cameraCapture.get(cv2.CAP_PROP_FRAME_WIDTH)),int(cameraCapture.get(cv2.CAP_PROP_FRAME_HEIGHT))) # 读取捕获的数据 success,frame = cameraCapture.read() if not success: print("camera start failed.") quit() is_stop = False server = None server_ws = None event_loop_ws = None thread_mjpeg = None thread_ws = None mjpeg_server_star() websocket_server_start() print("record server star:") thubm_file = None video_file = None time_start = int(time.time()) time_record = {"time":0} time_record_prev = None while True: if is_stop: success = False break; success,frame = cameraCapture.read() if not success: continue time_now = get_current_time() if time_now["time"] - time_record["time"] >= ROTATE_TIME: if time_record_prev: thubm_file = get_file_name(time_record_prev, 'thumbs', 'jpg') print("[Info] write to thumb: %s" % thubm_file) if not os.path.isfile(thubm_file): cv2.imwrite(thubm_file, frame) time_record = time_now time_record_prev = get_current_time() video_file = get_file_name(time_record_prev, 'videos', MEDIA_EXT) print("[Info] write to video: %s" % video_file) # encode = cv2.VideoWriter_fourcc(*"mp4v") encode = cv2.VideoWriter_fourcc(*'X264') # encode = cv2.VideoWriter_fourcc(*'AVC1') # encode = cv2.VideoWriter_fourcc(*'XVID') # encode = cv2.VideoWriter_fourcc(*'H264') videoWriter=cv2.VideoWriter(video_file, encode,fps,size) # mp4 numFrameRemaining = ROTATE_TIME * fps #摄像头捕获持续时间 while success and numFrameRemaining > 0: videoWriter.write(frame) success,frame = cameraCapture.read() numFrameRemaining -= 1 cameraCapture.release()
在上述代码中,除了前面说过的三个部分,还包括启动web和websocket线程的部分。因为核心逻辑为读取视频数据并写入文件,所以其他部分,以线程的模式启动,以便同时进行处理。
将上述代码保存为DrivingRecorderAndMjpegServer.py,然后运行即可。(依赖包,见代码库中requirements.txt)
实际访问效果如下:
六、历史数据RestFul服务开发
历史数据服务,本来也可以使用Python直接手写,但考虑到可扩展性,使用Django来进行了编写。
Djano服务,需要提供如下的功能:
- 提供api接口,以便获取历史数据记录列表,便于前端界面呈现展示
- 提供Flutter Web界面代码文件的托管,以便通过浏览器访问
- 提供静态文件的访问,例如查看历史视频文件
2和3本质都是一个问题,通过Django的static功能,就能实现。
也就是在settings.py配置中,提供下面的配置即可:
STATIC_URL = 'static/' STATICFILES_DIRS = [ BASE_DIR / "static" ]
1对外提供api服务,则需要设置对应的url接口,以及读取历史文件信息,生成前端需要的json数据结构,这部分的具体代码如下:
# 媒体文件存放目录,以及缩略图和视频文件的后缀 THUMB_HOME_DIR = "%s/%s/data/thumbs/" % (BASE_DIR, STATIC_URL) VIDEO_HOME_DIR = "%s/%s/data/videos/" % (BASE_DIR, STATIC_URL) IMG_FILTER = [".jpg"] MEDIA_FILTER = [ ".mkv"]
import json from django.shortcuts import render, HttpResponse from rest_framework.response import Response from rest_framework.permissions import AllowAny from rest_framework.decorators import api_view, permission_classes import os from django.conf import settings THUMB_HOME_DIR = settings.THUMB_HOME_DIR VIDEO_HOME_DIR = settings.VIDEO_HOME_DIR IMG_FILTER = settings.IMG_FILTER MEDIA_FILTER = settings.MEDIA_FILTER # Create your views here. @api_view(['GET'],) @permission_classes([AllowAny],) def hello_django(request): str = '''[ { "id": 1, "time": "2022-07-28 21:00", "title": "2022-07-28 21:00", "body": "videos/2022-07-28_2100.mp4" }, { "id": 2, "time": "2022-07-28 23:00", "title": "2022-07-28 23:00", "body": "videos/2022-07-28_2300.mp4" }, { "id": 3, "time": "2022-07-28 25:00", "title": "2022-07-28 25:00", "body": "videos/2022-07-28_2500.mp4" } ]''' _json = json.loads(str) return HttpResponse(json.dumps(_json), content_type='application/json') @api_view(['GET'],) @permission_classes([AllowAny],) def history_list(request): next = request.GET.get("next", '') print(f"thumb next = {next}") path = "/".join(request.path.split("/")[3:]) print(f"thumb request.path= {request.path}") print(f"thumb path = {path}") #print os.listdir(FILE_HOME_DIR+".none/") data = {"files":[], "dirs":[]} print(data) child_path = THUMB_HOME_DIR+next print(f"child_path = {child_path}") data['cur_dir'] = path+next print(data) for dir in os.listdir(child_path): if os.path.isfile(child_path+"/"+dir): if os.path.splitext(dir)[1] in IMG_FILTER: data['files'].append(dir) else: data['dirs'].append(dir) print(data) data['files']=sorted(data['files']) data['files'].reverse() data['infos'] = [] for i in range(0,len(data['files'])): thumb_name = data['files'][i] video_name = thumb_name.replace('.jpg', MEDIA_FILTER[0]) file_time = thumb_name.replace('.jpg', '').replace('_', ' ') data['infos'].append( { "id": i, "time": file_time, "title": file_time, "body": thumb_name, 'thumb': thumb_name, 'video': video_name } ) return Response(data['infos'], status = 200)
其中有两个接口:
hello_django
是最开始学习使用的,返回写死的json数据。history_list
,则是自动遍历缩略图文件夹,获取缩略图文件信息,并生成所需要的json数据格式。在对应的代码库文件中,也包含了requirements.txt,其中标明了实际需要的依赖库。
下载代码,进入manage.py所在的目录后,执行下面的命令即可启动:
访问 192.168.1.15:8000/app/hellodjango :
访问:History List – Django REST framework
可以看到 history_list接口,已经可以提供实际需要的数据了。
七、Flutter Web界面开发
这个部分设计的代码比较多,所以只对关键部分的代码进行说明。
开发的实际代码,位于lib目录,具体为:
- globals.dart:全局变量定义
- main.dart:程序入口
- home_page.dart:首页
- live_page.dart:实时播放
- live_page_mp4.dart:测试播放mp4视频
- history_page.dart:历史记录列表页面
- video_detail.dart:单条历史记录详情
- video_play.dart:播放具体的历史视频
- video_model.dart:单条记录的数据模型
- http_service.dart:请求RestFul接口
- websocket.dart:实时视频的WebSocket请求
整个界面,使用了
Scaffold
来模拟手机/Pad的操作界面,具体界面如下:在实时画面界面中,使用了WebSocket监听,获取到信息,就使用Stream模式,推送给视频播放。
在历史记录界面中,则通过RestFul请求列表数据,然后呈现。
八、整体运行效果
实际的运行效果,不用多说,看界面就成:
实时画面:
历史记录列表:
历史记录播放:
九、车试:
经过反复的测试验证,确保各项功能完整后,进行了上车实测。
因为最近的疫情原因,所以只在村里转了一圈,进行了实际测试,可以查看最后的视频。后续有机会,再找个晴朗的天气,去环境优美的地方实际拍摄录制。
十、实际代码说明:
完整的代码,请通过 米尔行车记录仪: 米尔行车记录仪 (https://gitee.com/honestqiao/MYiR-Driving-Recorder) 获取。
代码目录说明如下:
- DrivingRecorder:摄像头服务
- backend:RestFul服务
- frontend:Flutter Web界面
在以上仓库中,包含了详细的代码使用说明。
在实际应用中,将记录视频的data目录与后端static/data目录关联,以便两者统一。
十一、感谢
在研究学习的过程中,参考了数十篇各类资料,先将部分列出如下。对所有学习过的资料的作者,表示深深的感谢。
janakj/py-mjpeg: Python MJPEG streaming utilities (github.com)
Simple Python Motion Jpeg (mjpeg server) from webcam. Using: OpenCV,BaseHTTPServer (github.com)
Python 使用USB Camera录制MP4视频_Frank_Abagnale的博客-CSDN博客
用 Python、nginx 搭建在线家庭影院 - 知乎 (zhihu.com)
Django报错解决:RuntimeError: Model class ...apps... doesn't declare an explicit app_label and isn't in a_lyp039078的博客-CSDN博客
Python OpenCV 调用摄像头并截图保存_Clannad_niu的博客-CSDN博客
用 Python、nginx 搭建在线家庭影院mob604756e97f09的技术博客51CTO博客
Python-OpenCV录制H264编码的MP4视频 - 掘金 (juejin.cn)
[VideoWriter]保存H264/MPEG4格式MP4视频 - image processing (zj-image-processing.readthedocs.io)
Manual USB camera settings in Linux | KUROKESU
UVC Web Cameras (indilib.org)
编写你的第一个 Flutter 网页应用 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter
macOS install | Flutter
[Django 設定 LANGUAGE_CODE 時所遇到的麻煩] OSError: No translation files found for default language zh-TW. (github.com)**
Django And Flutter — 样板应用程序|的分步教程作者:Clever Tech Memes |中等 (medium.com)
joke2k/django-environ: Django-environ allows you to utilize 12factor inspired environment variables to configure your Django application. (github.com)
django 之跨域访问问题解决 access-control-allow-origin - 腾讯云开发者社区-腾讯云 (tencent.com)
django-cors-headers · PyPI
Django项目解决跨域问题 - SegmentFault 思否
video_player | Flutter Package (pub.dev)
视频的播放和暂停 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter
5.7 页面骨架(Scaffold) | 《Flutter实战·第二版》 (flutterchina.club)
itfitness/BottomNavigationBarDemo - 码云 - 开源中国 (gitee.com)
Flutter底部导航 - 简书 (jianshu.com)
Flutter之自定义底部导航条以及页面切换实例——Flutter基础系列houruoyu3的博客-CSDN博客flutter 自定义底部导航
How To Use HTTP Requests in Flutter | DigitalOcean
在Flutter中发起HTTP网络请求 - Flutter中文网 (flutterchina.club)
Fetch data from the internet | Flutter
获取网络数据 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter
深入理解 Function & Closure - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter
Django And Flutter — A Step by Step Tutorial for a Boilerplate Application | by Clever Tech Memes | Medium
multithreading - Multithreaded web server in python - Stack Overflow
Simple Python HTTP Server with multi-threading and partial-content support (github.com)
meska/mjpeg_stream_webcam: Webcam Streamer for Octoprint MacOs (github.com)
blueimp/mjpeg-server: MJPEG Server implements MJPEG over HTTP using FFmpeg or any other input source capable of piping a multipart JPEG stream to stdout. Its primary use case is providing Webdriver screen recordings. (github.com)
n3wtron/simple_mjpeg_streamer_http_server: simple python mjpeg streamer http server (github.com)
Python3远程监控程序实现肥宅Sean的博客-CSDN博客
opencv imencode跟imdecode函数jpg(python) - PythonTechWorld
flutter_mjpeg | Flutter Package (pub.dev)
Can't work on web platform. · Issue #13 · mylisabox/flutter_mjpeg (github.com)
Consider if fetch is widely supported enough to use · Issue #595 · dart-lang/http (github.com)
在 Flutter | 中创建实时视频流应用程序作者:Mitrajeet Golsangi |开发人员学生社区 Vishwakarma 技术学院,浦那 |中等 (medium.com)
Python websockets.serve方法代碼示例 - 純淨天空 (vimsky.com)
Flutter 常用組件講解 | ImageWidget - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天 (ithome.com.tw)
Bad State: Stream has already been listened to. · Issue #29105 · flutter/flutter (github.com)
flutter - Streambuilder with WebSockets stream in TabBarView: Bad state: Stream has already been listened to - Stack Overflow
使用WebSockets - Flutter中文网 (flutterchina.club)
VideoStreaming.dart (github.com)
在 Flutter | 中创建实时视频流应用程序作者:Mitrajeet Golsangi |开发人员学生社区 Vishwakarma 技术学院,浦那 |中等 (medium.com)
Flutter:WebSocket封装-实现心跳、重连机制 - 让我留在你身边 (ricardolsw.github.io)
2.3 状态管理 | 《Flutter实战·第二版》 (flutterchina.club)
路由和导航 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter
7.6 异步UI更新(FutureBuilder、StreamBuilder) | 《Flutter实战·第二版》 (flutterchina.club)
Flutter 常用組件講解 | ImageWidget - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天 (ithome.com.tw)
Step By Step Tutorial in Learning Flutter: Lesson 12 — Adding Image (Ice Pokemon) | by Misterflutter | Quick Code | Medium
Django CORS on static asset - Stack Overflow
配置 | Django 文档 | Django (djangoproject.com)
Global Variables in Dart - Stack Overflow
UVC - Community Help Wiki (ubuntu.com)
利用OpenCV进行H264视频编码的简易方式 - 知乎 (zhihu.com)
Documentation for OPENCV_FFMPEG_WRITER_OPTIONS and OPENCV_FFMPEG_CAPTURE_OPTIONS · Issue #21155 · opencv/opencv (github.com)
利用OpenCV进行H264视频编码的简易方式 - 知乎 (zhihu.com)
FFmpeg概述及编码支持 - 知乎 (zhihu.com)
Web 渲染器 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter十二、总结
在研究学习的过程中,对Linux系统下的UVC框架有了进一步的了解,对Flutter进行应用开发有了实际的了解,对OpenCV的实际应用也有了具体的了解。
在实际开发的过程中,遇到的最大的坑来自Flutter,因为变化太快,有一些功能可能兼容性没有跟上。不过更多是自己学艺不精导致的。
另外,目前还只是V1.0版本,后续还存在较大的优化空间。例如对于OpenCV的应用,可以调整参数,优化获取的视频数据的指令和大小等。这些有待于进一步学习后进行。
最主要的,对米尔MYD-YT507开发板有了深入的了解,进行了实际的应用。作为一款车规级处理器T507的开发板,名不虚传!
-
sipeed的maixsense在arecord里看不到音频设备是什么原因呢
armbian下现在用arecord -l命令找不到音频设备,难道应该重新刷下系统?