【展讯】lk camera 代码流程梳理

4 阅读8分钟

下面是基于 lk_cameraplatform/sprd_shareduis7870_3h10_car 源码的整理。


1. LK Camera 框架(分层与主流程)

1.1 启动与线程模型

函数作用
pre_task_create()app/sprdboot/sprd_threads.c快速开机时在 CAMERA_CORErules.mk 里为 CPU1)上 thread_create("camera_th", run_camera, ...)
run_camera()start_camera.c初始化 s_cam_mgr、置 START_FLAG,调用 run_camera_internel(),结束时 clear_camera_state()sem_post(sem_con)
run_camera_internel()与 Android 侧 camcomm 协同:camcomm_initregister_cam_msg_cb(LKCAM_STATE_STOPPING, stopping_msg_callback),再 check_open_cameracheck_config_cameracheck_wait_camera_exitcheck_flush_cameracheck_close_camera
camera_init() / camera_entry()APP_START(lk_camera)当前实现为空:真正预览在 run_camera 线程里跑,不在 app 的 .init
force_close_camera()notify_camera_exit_block(true)camera_recycle()sprd_cam_sys_pw_on()reset_lk_clk_pd_clk_en(),供切核/关机等路径调用

1.2 对外 API(start_camera.h)与状态封装

函数作用
check_open_camera / check_config_camera / check_flush_camera / check_close_cameras_cam_mgr 互斥下推进 OPEN/CONFIG/FLUSH/CLOSE 状态位,避免重复或乱序
open_camera()dlopen("libcamoem.so")dlsym OEM 符号,oem->ops->camera_init(..., camera_callback, ...),初始化 buffer 链表、信号量、互斥锁
config_camera()alloc_buffer(5 块 NV21)→ 可选 pthread_create(display_loop)async_display==true)→ pthread_create(reverse_line_loop)start_preview() → 把所有 preview buffer set_img_request 交给驱动
flush_camera()camera_stop_preview,停显示线程 pthread_join(display_th)
close_camera()camera_deinitfree_buffer、销毁同步原语
notify_camera_exit() / wait_camera_exit()check_wait_camera_exit 配合,用于线程退出同步

1.3 采集与显示数据路径

函数作用
camera_callback()仅处理 CAMERA_EVT_CB_FRAME + CAMERA_FUNC_START_PREVIEWenqueue_display_buffersem_post(display_sem);同步模式会直接 display_one_frame(本工程 async_display=true,走异步)
start_preview()camera_fast_ctrl(..., CAMERA_FAST_MODE_FD, 0),设置 preview 尺寸/格式 YUV420、zoom、fps,camera_set_mem_funccamera_start_preview(..., CAMERA_NORMAL_MODE)
camera_alloc() / camera_free()非 preview/video 类型用 cam_mem_alloc/cam_mem_free 向 OEM 提供物理 buffer
alloc_buffer() / free_buffer()预览环形 buffer:NV21 大小 w*h*3/2,链入 prevbuff_list
enqueue_display_buffer() / dequeue_display_buffer()驱动回传的 fd 与 prevbuff_list 匹配后挂到 display_list
set_img_request()camera_set_preview_buffer,把空 buffer 还给采集
display_loop()循环调用 display_one_frame(),直到 stopping

1.4 设备与 OEM(cameradev

函数作用
dev_init()注册 gsprd_imagegsprd_sensorgsprd_camsys_pw_domain 等,按 dev_idprobe 或 sensor minit()
dev_read / dev_write / dev_close对注册设备的统一访问(与 Linux 侧 camera 节点抽象类似)

1.5 与 Android 通信(camcomm

函数/机制作用
camcomm_init() / camcomm_deinit()共享内存/消息线程,同步 LK 与 Android 的相机状态、电源、GPIO 等
set_camera_msg() / get_camera_msg()LKCAM_STATE_RUNNINGLKCAM_STATE_STOPPINGLKCAM_STATE_STOPPING_SUSLKCAM_DISPLAY_STATE_*
register_cam_msg_cb()例如注册 LKCAM_STATE_STOPPINGstopping_msg_callback

1.6 大屏输出(展讯 DPU)

函数作用
rvc_flip()platform/sprd_shared/driver/video/sprd/sprd_main.c组两层 sprd_restruct_configaction = ACTION_RVC,在满足宏与 g_env_bootmode/g_last_step/rvc_gpio_check() 时调用 sprd_dispc_flip()

1.7 板级供电/时钟(uis7870_3h10_carstart_camera.c

函数作用
wait_mm_wakeup()target/.../init.c轮询 REG_PMU_APB_PWR_STATUS_DBG_6 中 camera 电源域就绪
enable_global_clocks()BIT_CAMERASYS_GLB_CKG_EN 等打开 MM/相机相关时钟
clear_force_shutdown() / sprd_cam_sys_pw_on() / dcam_domain_power_on() / isp_domain_power_on()start_camera.c通过 PMU 寄存器解除 camera/dcam/isp 强制下电并轮询 power status(调试/回收路径)
sprd_cam_sys_pw_off()强制关 camera 域(配合 force_close_camera 等)

regulator_init.c / ldo_sleep.c 属于板级 PMIC/LDO 初始化,与 RVC 逻辑无直接函数调用关系,属于整机供电上下文。


2. RVC「快速倒车」相关逻辑(函数列表)

2.1 倒车信号输入

函数作用
rvc_gpio_check()rvc/rvc_gpio.c,需 ENABLE_RVC=1CONFIG_SPRD_RVC配置 GPIO(代码中为 RVC_GPIO 48),读电平:有效则认为进入倒车场景
rvc_gpio.h未定义 CONFIG_SPRD_RVC 时内联返回 false,整段 RVC 显示路径被编译裁掉

2.2 显示线程里:视频 + 辅助线合成

函数作用
display_one_frame()取一帧 NV21;若 rvc_gpio_check():填 hwlayers[0] 为相机 buffer、hwlayers[1]REVERSELINE_RESERVED_ADDR(LVGL 画的 BGRA 叠加层),调用 rvc_flip(&hwlayers[0],&hwlayers[1]);否则根据 LKCAM_STATE_STOPPING* 走退出或仅更新 display 状态
rvc_flip()DPU 双图层混合(底层 NV21 + 顶层 BGRA 辅助线),ACTION_RVC;在 sprd_main.c 里还有额外条件(如 boot mode、rvc_gpio_check())才执行 sprd_dispc_flip

2.3 倒车辅助线(LVGL)

函数作用
reverse_line_loop()reverseline/reverseline.clv_init(),画缓冲用 REVERSELINE_RESERVED_ADDRdummy_flush(不落屏,只配合 LVGL),子线程 reverse_line_tick_loop 驱动 lv_tick_inc,主循环 lv_task_handler() 画红/蓝/绿辅助线
reverse_line_tick_loop()5ms 睡眠 + lv_tick_inc(5)

2.4 与 Android 切相机的协调(「快速」停 LK 相机)

函数作用
stopping_msg_callback()收到 LKCAM_STATE_STOPPING 时:若 rvc_gpio_check() 仍为真,直接返回 0(打 log「Displaying...」), notify_camera_exit_block,避免倒车时 LK 相机被立刻停掉;无倒车信号则 notify_camera_exit_block(false) 让 LK 侧退出

3. 逻辑串联(便于你对照代码)

  1. CPU1run_camerarun_camera_internel:打开 OEM、配置分辨率、起 display_loop + reverse_line_loop、开始 preview。
  2. 帧到达camera_callback → 显示队列 → display_one_frame
  3. GPIO 倒车有效 → 填双层参数 → rvc_flip → DPU 显示相机+辅助线;sprd_main.c 里对 sprd_dispc_flip 还有 boot 阶段条件。
  4. Android 要抢相机时发 STOPPINGstopping_msg_callback:倒车时先住退出,实现倒车场景下 LK 持续显示。

关键点(按函数/文件)

  • RVC 触发与显示主链路

    • rvc_gpio_check()app/lk_camera/rvc/rvc_gpio.c
    • display_one_frame()app/lk_camera/start_camera.c(判定倒车、组双 layer、调用 rvc_flip()
    • rvc_flip()platform/sprd_shared/driver/video/sprd/sprd_main.c(最终 sprd_dispc_flip() 的条件)
  • 倒车辅助线生成(叠加层)

    • reverse_line_loop() / reverse_line_tick_loop()app/lk_camera/reverseline/reverseline.c
    • 关键缓冲:REVERSELINE_RESERVED_ADDR(叠加层地址)
  • 快速倒车“不断流”机制

    • stopping_msg_callback()app/lk_camera/start_camera.c(Android 发 STOPPING 时,若仍倒车则不退出)
  • LK camera 启动框架

    • pre_task_create()app/sprdboot/sprd_threads.c(把 run_camera() pin 到 CAMERA_CORE=1
    • run_camera() / run_camera_internel()app/lk_camera/start_camera.c
    • open_camera() / config_camera() / flush_camera() / close_camera()app/lk_camera/start_camera.c
    • camera_callback():帧回调入队、唤醒显示线程

RVC(快速倒车)从 GPIO 到上屏的时序(函数链)

  • 线程拉起

    • pre_task_create()thread_create("camera_th", run_camera, ...)app/sprdboot/sprd_threads.c
    • run_camera()run_camera_internel()app/lk_camera/start_camera.c
  • 相机初始化与预览启动

    • check_open_camera()open_camera()
      • dlopen("libcamoem.so")oem->ops->camera_init(..., camera_callback, ...)
    • check_config_camera()config_camera()
      • alloc_buffer()pthread_create(display_loop)pthread_create(reverse_line_loop)start_preview()set_img_request()(把 5 个 buffer 全部喂给驱动)
  • 帧回调到显示

    • camera_callback()enqueue_display_buffer()sem_post(display_sem)
    • display_loop():循环 display_one_frame()
  • 倒车触发判定(关键分支)

    • display_one_frame()
      • rvc_gpio_check()app/lk_camera/rvc/rvc_gpio.c:读 RVC_GPIO 电平)
      • true
        • hwlayers[0] = 相机 NV21 帧(底层)
        • hwlayers[1] = REVERSELINE_RESERVED_ADDR(BGRA8888 辅助线叠加层)
        • rvc_flip(&hwlayers[0], &hwlayers[1])
  • 真正上屏(DPU 双层 flip)

    • rvc_flip()platform/sprd_shared/driver/video/sprd/sprd_main.c
      • sprd_restruct_config 两层、action = ACTION_RVC
      • 满足条件时调用 sprd_dispc_flip(dispc, rvc_config) 完成上屏

倒车辅助线生成链(叠加层)

  • config_camera() 里启动 reverse_line_loop(handle)
  • reverse_line_loop()
    • lv_init()lv_disp_draw_buf_init(..., REVERSELINE_RESERVED_ADDR, ...)
    • pthread_create(reverse_line_tick_loop):周期 lv_tick_inc(5)
    • 循环 lv_task_handler() 持续绘制线条到 REVERSELINE_RESERVED_ADDR

“快速倒车不断流”的退出抑制点

  • run_camera_internel() 里:register_cam_msg_cb(LKCAM_STATE_STOPPING, stopping_msg_callback, NULL)
  • stopping_msg_callback()
    • rvc_gpio_check()==true:直接返回(保持显示,不触发退出)
    • 否则:notify_camera_exit_block(false)check_wait_camera_exit() 尽快返回并进入 flush/close

rvc_flip() 上屏“门控条件表”(决定是否真的 sprd_dispc_flip()

platform/sprd_shared/driver/video/sprd/sprd_main.c 里,rvc_flip() 并不是每次都 flip,上屏被下面条件卡住:

  • 编译期开关

    • #ifndef GSP0_SPLICE_DUAL_DISPLAY && defined(CONFIG_BOOT_ANIMATION)
    • 含义:只有在 未定义 GSP0_SPLICE_DUAL_DISPLAY定义了 CONFIG_BOOT_ANIMATION 时,rvc_flip() 内部才会调用 sprd_dispc_flip();否则函数只构造 config 但不实际上屏。
  • 运行时条件(全部必须满足)

    • !strcmp("normal", g_env_bootmode)
      • 只有 normal boot 才允许 RVC flip
    • (g_last_step & (1 << PHASE_LINUX_MODE))
      • 只有进入到“Linux mode 阶段”之后才允许 flip(属于 boot 阶段门控)
    • rvc_gpio_check() == 1
      • 倒车信号必须仍然为真

对应源码片段(关键判断)来自 sprd_main.c

#ifndef GSP0_SPLICE_DUAL_DISPLAY && defined(CONFIG_BOOT_ANIMATION)
	if (!strcmp("normal", g_env_bootmode) && (g_last_step & (1<< PHASE_LINUX_MODE)) && rvc_gpio_check() == 1)
		sprd_dispc_flip(dispc, rvc_config);
#endif

这些条件的变量/枚举在哪里来的(便于你追)

  • g_env_bootmode

    • 在多处被 extern 使用(如 sprd_main.cdpu_r6p0.csec_common.c 等)
    • 定义声明可见:app/sprdboot/include/boot_mode.hextern const char* g_env_bootmode;
  • g_last_step & PHASE_LINUX_MODE

    • g_last_stepplatform/sprd_shared/driver/log_pointing/sprd_log_point.c 定义 volatile uint32_t g_last_step = 0;
    • PHASE_LINUX_MODEplatform/sprd_shared/driver/log_pointing/sprd_log_point.h 枚举里定义
  • CONFIG_BOOT_ANIMATION

    • app/sprdboot/rules.mk 里可以看到被加入 GLOBAL_DEFINES(使得编译期 defined(CONFIG_BOOT_ANIMATION) 生效)

顺带一提:animation_flip() 与 RVC 是互斥门控

在同一文件里 animation_flip() 也用了同样的门控条件,但最后一项是 rvc_gpio_check()==0,也就是:

  • 倒车信号为 1 → 走 RVC 双层
  • 倒车信号为 0 → 才允许 boot animation 的 flip