OK536N-C+UVC摄像头+10寸LVDS屏幕实现实时采集绘制(纯软方案)
-
突如其来想法
恰好看到OK536N-C的手册支持UVC,手里恰好有一个UVC摄像头,也恰好有一个LVDS的屏幕,也恰好产生了一个好奇的想法:
是否可以实时采集UVC摄像头的数据然后通过LVDS屏幕绘制出来?
如果可以实现的话,还可以继续延伸,例如:增加AI的一些应用,通过LVDS实时显示出来。
先来看下效果
为好奇买单
为了能快速为我的好奇买单,按照初步调试一个板子的经验,肯定先翻看官方的doc手册,是否支持UVC(USB Video Class).
第一步:确定是否支持:
在Tina_Linux_USB_开发指南.pdf中有说明,是支持UVC的:
Device Drivers ‑‑‑> <*> Multimedia support ‑‑‑> [*] Media USB Adapters ‑‑‑> <*> USB Video Class (UVC) [*] UVC input events device support
第二步:查找是否有案例
因为OK536N-C是基于全志T536的,所以飞凌+强强联手,案例也会弥补一些全志官方空缺的demo.
现在看下飞凌的demo:在forlinx目录下
飞凌的团队确实缺少了这个我这个好奇想法的功能demo的支持。
再来看下全志官方的demo:
有2个demo比较好奇,一个是fbinit_test和usbcam_test
fbinit_test的功能描述:
此demo用于清除当前显示的fb的数据,让显示屏上处于干净的状态,方便测试应用送显。
usbcam_test的功能描述:
此demo用于验证usb camera功能是否正常。
没错,这两个就是我们实现的基石,就是快速开发的地基。
现在目标找到了!!!
开始买单
了解清楚你UVC摄像头和LVDS屏幕的参数。
例如我的UVC摄像头支持YUYV(YUYV 4:2:2)/H264/H265/MJPG(Motion-JPEG):
而且每个格式下还支持不同的分辨率和帧率。
camName=HD Camera,devName=Input 1,camPath=/dev/video1 fmt index=0,description=YUYV 4:2:2,pixelformat=YUYV,v_fmt_type=0 framsize.discrete.height=720,framsize.discrete.width=1280,framsize.frameRates.size()=2,frameRates=,10,5 framsize.discrete.height=576,framsize.discrete.width=1024,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=600,framsize.discrete.width=800,framsize.frameRates.size()=2,frameRates=,10,5 framsize.discrete.height=448,framsize.discrete.width=800,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=480,framsize.discrete.width=640,framsize.frameRates.size()=5,frameRates=,25,20,15,10,5 framsize.discrete.height=360,framsize.discrete.width=640,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=270,framsize.discrete.width=480,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=180,framsize.discrete.width=320,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 fmt index=1,description=Motion-JPEG,pixelformat=MJPG,v_fmt_type=1 framsize.discrete.height=1080,framsize.discrete.width=1920,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=896,framsize.discrete.width=1600,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=720,framsize.discrete.width=1280,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=576,framsize.discrete.width=1024,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=540,framsize.discrete.width=960,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=600,framsize.discrete.width=800,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=448,framsize.discrete.width=800,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=576,framsize.discrete.width=720,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=480,framsize.discrete.width=720,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=480,framsize.discrete.width=640,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=360,framsize.discrete.width=640,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=270,framsize.discrete.width=480,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=288,framsize.discrete.width=352,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=240,framsize.discrete.width=320,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 fmt index=2,description=H.264,pixelformat=H264,v_fmt_type=2 framsize.discrete.height=1080,framsize.discrete.width=1920,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=896,framsize.discrete.width=1600,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=720,framsize.discrete.width=1280,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=576,framsize.discrete.width=1024,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=540,framsize.discrete.width=960,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=600,framsize.discrete.width=800,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=448,framsize.discrete.width=800,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=576,framsize.discrete.width=720,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=480,framsize.discrete.width=720,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=480,framsize.discrete.width=640,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=360,framsize.discrete.width=640,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=270,framsize.discrete.width=480,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=288,framsize.discrete.width=352,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=240,framsize.discrete.width=320,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 fmt index=3,description=35363248-0000-0010-8000-00aa003,pixelformat=,v_fmt_type=2 framsize.discrete.height=1080,framsize.discrete.width=1920,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=896,framsize.discrete.width=1600,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=720,framsize.discrete.width=1280,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=576,framsize.discrete.width=1024,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=540,framsize.discrete.width=960,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=600,framsize.discrete.width=800,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=448,framsize.discrete.width=800,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=576,framsize.discrete.width=720,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=480,framsize.discrete.width=720,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=480,framsize.discrete.width=640,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=360,framsize.discrete.width=640,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=270,framsize.discrete.width=480,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=288,framsize.discrete.width=352,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 framsize.discrete.height=240,framsize.discrete.width=320,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5 ============================================================
LVDS屏幕:
1、支持RGB888的1280*800的分辨率;
有了这些参数,就可以很清楚的知道下一步要干什么。
1、选择采集的格式,因为转RGB,使用YUV是比较合适的,纯软件也简单一些。
所以我们选择采集YUV,才从YUV中选择一个何时的分辨率,我们选择1280*720的,因为这个最接近LVDS屏幕的最大分辨率:
fmt index=0,description=YUYV 4:2:2,pixelformat=YUYV,v_fmt_type=0 framsize.discrete.height=720,framsize.discrete.width=1280,framsize.frameRates.size()=2,frameRates=,10,5
实现功能
1、获取UVC相机的各种参数
这里用到了我的一个开源项目中的一个代码。
https://github.com/truedei/UPlayer
https://github.com/truedei/UPlayer/blob/main/src/core/utils/v4l2utils.h
https://github.com/truedei/UPlayer/blob/main/src/core/utils/v4l2utils.cpp
直接复制出来小改后使用即可.
然后就可以得到UVC的各种参数:
#include "v4l2utils.h" int main(int argc, char *argv[]) { // 查询所有拥有video能力的USB设备 { vector<Camera> cms = GetAllVideoDevices(); for(auto c: cms) { cout << "camName=" << c.camName.c_str() << ",devName=" << c.devName.c_str() << ",camPath=" << c.camPath.c_str() << endl; auto vfmts = c.vfmts; for(auto fmt: vfmts) { cout << "fmt index=" << fmt.index << ",description=" << fmt.description.c_str() << ",pixelformat=" << fmt.pixelformat << ",v_fmt_type=" << fmt.v_fmt_type << endl; auto frmsizes = fmt.frmsizes; for(auto fs: frmsizes) { cout << "framsize.discrete.height=" << fs.height << ",framsize.discrete.width=" << fs.width ; auto frmsizes = fs.frameRates; cout << ",framsize.frameRates.size()=" << frmsizes.size() <<",frameRates="; for(auto fr: frmsizes) { cout << "," << fr; } cout << endl; } } cout << "============================================================" << endl; } } .... .... .... }
main函数分为4大部分:
1、查询UVC的参数,选择合适的参数进行初始化;
2、初始化LVDS屏幕fd描述符,以及获取参数;
3、获取数据&数据转换&渲染数据;
4、释放数据;
比较核心的是转换&绘制图像数据:
这里我还做了特殊处理,上下对齐黑边,因为分辨率不一致,不好看
未使用硬件加速处理的时间:
read_frame time cost 0.145181(s) read_frame time cost 0.111765(s) read_frame time cost 0.111757(s)
效果还是可以的,后期再用硬件加速看看效果。
代码已放在github:
Copyright © 2024 深圳全志在线有限公司 粤ICP备2021084185号 粤公网安备44030502007680号