一、交叉编译器
对于Linux平台的开发,官方只提供了yocto工程的源码,没有SDK,yocto工程也不能制作SDK包,可能是我自己的问题,最后只能在yocto中自建layer来进行开发。
由于官方源码编译采用arm-unisoc-linux-gnueabi-gcc,32位arm,所以整个软件包工程均为32位,包括生成的镜像。源码中有一个aarch64的交叉编译链安装脚本,好像是用来做chipram的编译。
对于简单的应用开发,可以使用linaro提供的arm-linux-gnueabihf来做交叉编译,但是对于依赖较多的复杂应用,例如摄像头开发,需要sysroot的支持。因此本次实验需要在yocto工程中新建自己的meta来实现,根据源码中已经编译过的库来进行编译。
二、源码移植
开发板的主摄像头为三星的s5k4h7,出场源码烧录至开发板后,/dev目录下看不到video设备:
使用常规的USB方式open系统调用无法打开,因为确实没有这个设备节点。使用官方提供的摄像头demo却可以正常运行,拍照和视频都可以。
翻看源码后发现,demo程序封装了一个V4l2AdapterInterface的接口:
class V4l2AdapterInterface {
public:
virtual ~V4l2AdapterInterface(){};
virtual int open(const char *__path, int __flags) = 0;
virtual long ioctl(int fd_, unsigned long request, void *argp) = 0;
virtual void *mmap(void *addr, size_t length, int prot, int flags, int fd,
off_t offset) = 0;
virtual int munmap(void *addr, size_t length) = 0;
virtual int poll(struct pollfd *fds, nfds_t nfds, int timeout) = 0;
virtual int close(int __flags) = 0;
virtual int write_i2c_t(int fd_, void *reg, int count) {
return this->write_i2c_t(fd_, reg, count);
};
virtual int read_i2c(int fd_, unsigned short reg_addr) {
return this->read_i2c(fd_, reg_addr);
};
template<class T,int N> int write_i2c(int fd_, T (&array)[N]){
int count = 0;
for(int i=0;i<N;i++) {
if(!array)
break;
if(!((struct sensor_reg_info)array[i]).reg_addr &&
!((struct sensor_reg_info)array[i]).reg_value)
continue;
count++;
}
return write_i2c_t(fd_, (void *)array, count);
};
const char *name_;
};
class V4l2Client {
public:
V4l2Client(const char *name);
virtual ~V4l2Client() {}
static V4l2AdapterInterface *create();
static void registerType(V4l2Client *factory);
const std::string &name() const { return name_; }
private:
virtual V4l2AdapterInterface *createInstance();
std::string name_;
};
class V4l2Adapter : public V4l2AdapterInterface {
public:
V4l2Adapter() { std::cout << "constructor V4l2Adapter" << std::endl; }
~V4l2Adapter() { std::cout << "deconstructor ~V4l2Adapter" << std::endl; }
int open(const char *__path, int __flags) { return ::open(__path, __flags); }
long ioctl(int fd_, unsigned long request, void *argp) {
return ::ioctl(fd_, request, argp);
}
void *mmap(void *addr, size_t length, int prot, int flags, int fd,
off_t offset) {
return mmap(addr, length, prot, flags, fd, offset);
}
int munmap(void *addr, size_t length) {
return munmap(addr, length);
}
int poll(struct pollfd *fds, nfds_t nfds, int timeout) {
return poll(fds, nfds, timeout);
}
int close(int __flags) {
return close(__flags);
}
};
这个接口也只是对常用的几个系统调用做了封装,并没有施加什么魔法,我引入这个头文件重新封装了自己的app,结果还是不行,依然无法打开,于是直接复制源码到自己的meta中,干脆在源码上做修改。
编译时只需要添加 -b 参数来指定单个bb文件编译即可,注意指定输出的路径,方便push到开发板。
三、数据格式
不改变最基本的摄像头开发框架,只在数据读取时,根据需要写入文件。先快速编写一个应用,再去深入了解每一个ioctl操作。
网上有很多开发框可参考,例如:
需要注意camera支持的pixelformat,也就是数据流格式,大部分摄像头都支持YUV 4:2:0格式,参数为V4L2_PIX_FMT_YUV420,部分camera支持V4L2_PIX_FMT_MJPEG直接导出jpg图片。如果是YUV格式可能会需要转码至RGB色彩空间,编码为jpg图片方便其他设备打开,可参考:yuv420p转jpg linux(纯C语言实现) - quinncy - 博客园 (cnblogs.com)https://www.cnblogs.com/zhq-blog/p/8832157.html
最后生成的yuv文件可用 YUView 软件打开,github上开源的。
四、总结
网上很少有移远通信智能模组相关的社区讨论与学习资料(毕竟正经学生谁玩移远), 本篇博客在于学习记录与提供应用开发的思路,很多知识没有细讲,我也是Linux新鸟,欢迎广大读者交流学习。
标签:int,virtual,移远,编译,源码,fd,摄像头,Linux,SC200L From: https://blog.csdn.net/plmm__/article/details/139838226