一.项目流程
1.工作流程
简言之:我们使用的是开源库mjpg-streamer.摄像头采集的数据会保存在/dev/video0目录下,然后输入进tcp服务器,在浏览器开始访问。
我们要做的就是讲tcp服务器数据进行读取,然后建立自己的客户端,通过客户端将数据发送阿里云,通过上位或者手机查看。
2.具体步骤
摄像头---云服务器
1).本地创建客户端
2).客户端与云服务器建立TCP连接,将摄像头信息通过json-c发送给云服务器,云服务器创建链表记录摄像头信息(客户端id,摄像头id),同时启动udp socket,并将创建绑定的ip地址和端口号通过json格式TCP发送给客户端。
3).客户端---->发送请求给mjpg-streamer服务器---->服务器收到请求后将摄像头数据发送给客户端
4).摄像头创建udp socket向服务器发送视频数据.
5).服务器收到数据以后,读取保存。
APP---云服务器(获取视频数据)
1).上位机通过TCP连接云服务器,发送获取数据请求给服务器
2).服务器收到请求后,创建udp socket,通过json--tcp将ip和端口号返回给上位机
3).上位机收到服务器信息后,创建udp socket发送信息给服务器准备开始接受数据。
4).服务器收到来自上位机udp信息后,返回视频数据(从内存加锁读取)
APP---云服务器(旋转舵机)
1).APP发送数据:{"cmd":"control", "action":"left", "appid":"1000", "deviceid":"0001"}---TCP
2).服务器收到数据解析deviceid
3).遍历链表 找到对应摄像头的 fd 向 fd 发送数据
4).摄像头收到数据 解析 action 并且做出响应
二.NanoPi Duo2
1.根据友善官方教程烧固件,连接wifi,建立ssh连接最后通过xshell进行编写代码
登录账户:root
密码:fa
1).ping开发板ip地址ping不通
解决:关闭Linux 防火墙:ufw disable
关闭电脑防火墙:控制面板---系统安全 (记住杀毒软件也要关闭)
查看路由器设置(可以用手机热点测试)
三.mjpg-streamer(适用于摄像头v4l2框架)
1.启动
直接运行开发板自带的mjpg-streamer,./start.sh运行,在start.sh更改参数
打开浏览器,输入ip和默认端口号
四.访问gpio口
安装wiringNP
然后找到PWM示例’
五.搭建交叉编译环境
我们使用的ubuntu是x86-64位架构,而开发板使用的是arm架构,将ubuntu上的二进制文件拷贝到开发板上是运行不通的。
开发板一般不具备编译器的,因为占用大内存,所以一般不在开发板直接写程序。
所以需要在服务器上安装交叉编译器,使得编译好的文件可以再不通架构上运行
解压完毕后
打开环境变量vim /root/.bashrc,将安装交叉编译器的路径添加到环境变量里边
运行 source /root/.bashrc
注意:编译器只支持64位系统。需要安装64位Ubuntu。所以会提示格式错误
编译通过后:
将本机的可执行文件发送到 开发板---xshell
六.摄像头主程序
1.交叉编译json-c(注意版本不同函数不同)
写程序前需要json-c,如果用linux:apt get得到的是x86的json,我们需要64位json,下载地址 github
下载完毕后移入项目工程文件夹,打开json的readme,按照执行要求
安装插件
apt-get install shtool
执行脚本后,会生成这个文件,configure可以检查编译环境,如果没有问题,则会生成makefile
执行configure
make install
编译
打开json-c vim config.h.in
x因为config配置文件更改,需要重新编译生成makefile
然后打开makefile,把-werro删除
make install
在重新编译我们自己的makefile
示例:
创建Tcp连接---连接阿里云服务器---主线程通过json 发送数据{"cmd":"info", "deviceid":"0001"} ,立即返回{"cmd":"info", "port":"0001"}
struct json_object *obj
创建json类-- obj = json_object_new_object()
{"cmd":"info", "deviceid":"0001"} json_object_object_add(obj,"cmd",json_object_new_string("info"))
json_object_object_add(obj,"deviceid",json_object_new_string("0001"))
将obj类转换成字符串const char *json_object_to_json_string(obj)
解析字符串数据 obj = json_tokener_parse(buff)
从json类获取获取cmd下的数据struct json_object *cmd = json_object_object_get( obj,“cmd”)
从json类获取解析cmd下的字符串数据char *s = json_object_get_string(cmd)
从json类获取解析cmd下的整形数据int a = json_object_get_int(deviceid)
2.大体流程:
1.创建socket套接字,连接阿里云服务器,ip地址选用公网ip(端口号不能使用8080,8080数据mjpg)
2.发送json-c数据{"cmd":"info", "deviceid":"0001"}给服务器
3.服务器收到数据后解析保存fd,deviced
4.服务器发送json数据{"cmd":"port_info", "port":9000}给客户端,同时启动UDP sock
5.客户端解析数据,根据收到port创建UDP线程,发送摄像头数据
5.主线程通过tcp接收QT发送的指令。
七.获取并转发视频数据
在udp线程里获取摄像头数据,编程思路查看mjpg-streamer源码http.c,按照向http发送数据请求的格式推导出如何接每一帧数据。
在http.c中,摄像头发送数据给web流程:
1.web先发送“GET /?action=stream”给摄像头
2.web发送任意两个字节(读取user agent)
3.wed接受一次信息
while(1)
{
4.读取头部信息
5.读取一帧数据(注意解析帧长度)------Sscanf
6.读取尾部信息
}
示例:
八.交叉编译wiringPi
在Ubuntu终端输入:git clone https://github.com/friendlyarm/WiringNP即可安装
安装以后找到Makefile,修改36:gcc ---- arm-linux-gcc
make
因为我们编译的时候需要加-L,目的是需寻找动态库,而文件中只有
需要建立软连接:
make的时候默认相对路径 -L指定库路径 -I指定头文件
为什么要建立连接?
为了解决文件共享使用问题,带来了隐藏文件路径、增加权限安全及节省存储等好处。这是cp /lib无法具备的
语法:ln [-s/p] source_file target_file
-s:建立软链接 特点:如果删除源文件,则软连接文件失效
-P:建立硬链接 特点:如果删除源文件,则硬连接文件正常
软链接与硬链接的区别?
在LInux系统中,文件有文件名和数据。而数据在Linux被分成两部分:用户数据 元数据
用户数据:文件数据块,数据块是基类文件真实内容的地方。
元数据:文件的属性 如:文件大小、创建时间、所有者等信息
Linux中inode编号是文件的唯一标识符。软连接是一个单独的文件(独立的inode编号,数据块存放的是源文件的文件名),硬连接与源文件共享inode编号
1.出现了git is currently not installed.
$ sudo add-apt-repository ppa:git-core/ppa
$ sudo apt-get update
$ sudo apt-get install git
$ git --version
git version 2.21.0
2.尝试了很多次子coding和github网站上均无法实现git clone命令时时,确认自己已经在本机上生成了ssh key,也已经将SSH 公钥添加到coding或者是github中,需要注意自己有没有在ubuntu系统中安装ssh服务,以及有没有开启SSH服务。
输入 $ ssh localhost
显示:ssh: connect to host localhost port 22: Connection refused 表示没有安装ssh server,通过如下命令安装
$ sudo apt-get install openssh-server
安装完成后启动服务
$ sudo /etc/init.d/ssh start
然后进行git clone 就可以了
九.阿里云服务器配置
将json安装包安装进去,然后sh autogen.sh,提示缺几个安装工具就安装上
./configure会提示-Werror,在Makefile中去掉-Werror(不能更改json原码,会出问题)
重新make
make install
在json_object.h 加入include “stdint.h”
编写完毕后在编译的的时候发现这个问题
先将本地本间上传
因为是动态链接,所以动态库路径需要修改。
需要将.so.0拷贝到根目录下的lib
十.QT端
QT创建TCp客户端和UDP客户端,TCP客户端发送命令(JSon数据包),UDP客户端获取图像数据
涉及到的类:
QTcpSocket、QJsonObject、QByteArray、QPixmap、QImage