一、V4L2基础知识

v4l2:是内核提供给应用程序访问音、视频驱动的统一接口。
基本的工作流程:打开摄像头->检查和设置设备属性->设置帧格式->设置输入输出方法->循环获取数据->关闭设备.
1、打开摄像头
在v4l2中,视频设备被看做一个文件。使用open函数打开这个设备:
可以用非阻塞方式打开摄像头设备
fd = open (“dev_name”, O_RDWR| O_NONBLOCK)
也可以用阻塞方式打开摄像头设备
fd = open (“dev_name”, O_RDWR)
如果使用非阻塞模式调用视频设备,即使尚未捕获到信息,驱动依旧会把缓存(DQBUFF)里的东西返回给应用程序。
设置视频设备属性通过ioctl来进行设置,ioctl有三个参数,分别是fd, cmd,和parameter,表示设备描述符,控制命令和控制命令参数。
int ioctl(int fd, int cmd, ...);
2、查询设备属性:控制命令VIDIOC_QUERYCAP
功能:查询视频设备的功能 ;
参数:参数类型为v4l2的能力描述类型struct v4l2_capability ;
返回值:执行成功时,函数返回值为 0;函数执行成功后,struct v4l2_capability结构体变量中的返回当前视频设备所支持的功能;
3、设置视频的制式和帧格式:
制式包括PAL,NTSC,帧的格式包括宽度和高度。
v4l2_cropcap 结构体用来设置摄像头的捕捉能力。
v4l2_cropcap 的 type 域,再通过 VIDIO_CROPCAP 操作命令获取设备捕捉能力的参数,保存于 v4l2_cropcap 结构体中,包括 bounds(最大捕捉方框的左上角坐标和宽高),defrect(默认捕捉方框的左上角坐标和宽高)等。
v4l2_format 结构体用来设置摄像头的视频制式、帧格式等,在设置这个参数时应先填 好 v4l2_format 的各个域,如 type(传输流类型),fmt.pix.width(宽),fmt.pix.heigth(高),fmt.pix.field(采样区域,如隔行采样),fmt.pix.pixelformat(采样类型,如 YUV4:2:2),然后通过 VIDIO_S_FMT 操作命令设置视频捕捉格式。
控制命令VIDIOC_S_FMT        
功能: 设置视频设备的视频数据格式,例如设置视频图像数据的长、宽,图像格式(JPEG、YUYV格式);
参数:参数类型为v4l2的视频数据格式类型 struct v4l2_format  ;
返回值: 执行成功时,函数返回值为 0;
4、查询并显示所有支持的格式
控制命令 VIDIOC_ENUM_FMT    
功能: 获取当前视频设备支持的视频格式 。
参数:参数类型为v4l2的视频格式描述符类型 struct v4l2_fmtdesc
返回值: 执行成功时,函数返回值为 0;struct v4l2_fmtdesc 结构体中的 .pixelformat和 .description 成员返回当前视频设备所支持的视频格式;
5、图像的缩放 VIDIOC_CROPCAP
相关函数:
int ioctl(int fd, int request, struct v4l2_cropcap *argp);int ioctl(int fd, int request, struct v4l2_crop *argp);int ioctl(int fd, int request, const struct v4l2_crop *argp);
Cropping 和 scaling 主要指的是图像的取景范围及图片的比例缩放的支持。Crop就是把得到的数据作一定的裁剪和伸缩,裁剪可以只取样我们可以得到的图像大小的一部分,剪裁的主要参数是位置、长度、宽度。scale 的设置是通过VIDIOC_G_FMT 和 VIDIOC_S_FMT 来获得和设置当前的 p_w_picpath 的长度,宽度来实现的。
6、设置设备捕捉能力的参数
相关结构体:
struct v4l2_cropcap{enum v4l2_buf_type type; // 数据流的类型,应用程序设置struct v4l2_rect bounds; // 这是 camera 的镜头能捕捉到的窗口大小的局限struct v4l2_rect defrect; // 定义默认窗口大小,包括起点位置及长,宽的大小,大小以像素为单位struct v4l2_fract pixelaspect; // 定义了图片的宽高比};
7、设置窗口取景参数  VIDIOC_G_CROP 和 VIDIOC_S_CROP
struct v4l2_crop{
enum v4l2_buf_type type;// 应用程序设置struct v4l2_rect c;
}
8、设置输入输出:
VIDIOC_G_INPUT 和 VIDIOC_S_INPUT 用来查询和选则当前的 input,一个 video 设备 节点可能对应多个视频源,如果上层应用想在多个视频输入间切换,就会调用 ioctl(fd, VIDIOC_S_INPUT, &input) 来切换;
可以通过VIDIOC_ENUMINPUT and VIDIOC_ENUMOUTPUT 分别列举一个input或者 output的信息,我们使用一个v4l2_input结构体来存放查询结果,这个结构体中有一个 index域用来指定你索要查询的是第几个input/ouput,如果你所查询的这个input是当前正 在使用的,那么在v4l2_input还会包含一些当前的状态信息,如果所 查询的input/output 不存在,那么回返回EINVAL错误,所以,我们通过循环查找,直到返回错误来遍历所有的 input/output. VIDIOC_G_INPUT and VIDIOC_G_OUTPUT 返回当前的video input和output 的index.
9、申请和管理缓冲区
应用程序和设备有三种交换数据的方法,直接 read/write、内存映射(memory mapping)和用户指针,这里采用内存映射(memory mapping);
1、向设备申请缓冲区
控制命令VIDIOC_REQBUFS    
功能: 请求v4l2驱动分配视频缓冲区(申请v4l2视频驱动分配内存),v4l2是视频设备的驱动层,位于内核空间,所以通过VIDIOC_REQBUFS控制命令字申请的内存位于内核空间,应用程序不能直接访问,需要通过调用mmap内存映射函数把内核空间内存映射到用户空间后,应用程序通过访问用户空间地址来访问内核空间。
参数:参数类型为v4l2的申请缓冲区数据结构体类型struct v4l2_requestbuffers  ;
返回值: 执行成功时,函数返回值为 0;v4l2驱动层分配好了视频缓冲区;
2、获取缓冲帧的地址,长度:VIDIOC_QUERYBUF
功能:查询已经分配的v4l2的视频缓冲区的相关信息,包括视频缓冲区的使用状态、在内核空间的偏移地址、缓冲区长度等。在应用程序设计中通过调VIDIOC_QUERYBUF来获取内核空间的视频缓冲区信息,然后调用函数mmap把内核空间地址映射到用户空间,这样应用程序才能够访问位于内核空间的视频缓冲区。
参数:参数类型为v4l2缓冲区数据结构类型 struct v4l2_buffer  ;
返回值: 执行成功时,函数返回值为 0;struct v4l2_buffer结构体变量中保存了指令的缓冲区的相关信息;
一般情况下,应用程序中调用VIDIOC_QUERYBUF取得了内核缓冲区信息后,紧接着调用mmap函数把内核空间地址映射到用户空间,方便用户空间应用程序的访问。
3、内存映射MMAP 及定义一个结构体来映射每个缓冲帧
相关结构体:
struct buffer{void* start;
unsigned int length;
}*buffers;
相关函数:void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
//addr 映射起始地址,一般为NULL ,让内核自动选择
//length 被映射内存块的长度
//prot 标志映射后能否被读写,其值为PROT_EXEC,PROT_READ,PROT_WRITE, PROT_NONE
//flags 确定此内存映射能否被其他进程共享,MAP_SHARED,MAP_PRIVATE
//fd,offset, 确定被映射的内存地址 返回成功映射后的地址,不成功返回MAP_FAILED ((void*)-1)
int munmap(void *addr, size_t length);// 断开映射
将申请到的缓冲帧映射到应用程序,用buffers 指针记录。
10、循环获取数据
启动数据流,控制命令VIDIOC_STREAMON
功能: 启动视频采集命令,应用程序调用VIDIOC_STREAMON启动视频采集命令后,视频设备驱动程序开始采集视频数据,并把采集到的视频数据保存到视频驱动的视频缓冲区中。
参数:参数类型为v4l2的视频缓冲区类型 enum v4l2_buf_type ;
返回值: 执行成功时,函数返回值为 0;函数执行成功后,视频设备驱动程序开始采集视频数据,此时应用程序一般通过调用select函数来判断一帧视频数据是否采集完成,当视频设备驱动完成一帧视频数据采集并保存到视频缓冲区中时,select函数返回,应用程序接着可以读取视频数据;否则select函数阻塞直到视频数据采集完成。
停止数据流:控制命令VIDIOC_STREAMOFF
功能:停止视频采集命令,应用程序调用VIDIOC_ STREAMOFF停止视频采集命令后,视频设备驱动程序不在采集视频数据。
参数:参数类型为v4l2的视频缓冲区类型 enum v4l2_buf_type ;
返回值:执行成功时,函数返回值为 0;函数执行成功后,视频设备停止采集视频数据。

11、关闭设备;close(fd);

参考:http://blog.chinaunix.net/uid-26851094-id-3356224.html


二、YUV格式:
Yuv概念:Y表示明亮度即灰阶值(0~255);U(-122~+122) 和V(-157~+157)表示色度,用于描述影像色彩饱和度,指定像素的颜色;YUV原理:是把亮度与色度分离;可以用于优化彩色视频信号的传输。
YUV格式的特点:
1、彩色YUV图像转黑白YUV图像转换非常简单,这一特性用在于电视信号上。
2、相较于RGB占用较少的频宽(RGB要求三个独立的视频信号同时传输);
YUV的存储格式:
(打包格式)Packed格式:YUV的数据中为了节约空间,U,V分量空间会减小。每一个点的Y分量独立保存,但连续几个点的U,V分量是保存在一起的;
(平面格式)Planar模式:把一幅图像中Y,U,V分别用三个独立的数组表示;
YUV的采样格式:
Y,U,V三者的比率来表示不同格式;常见的有 YUV444、YUV420、YUV422等等;
4:4:4 表示色度值(UV)没有减少采样。即Y,U,V各占一个字节,加上Alpha通道一个字节,总共占4字节.
4:2:2 表示UV分量采样减半(垂直采样率相同,水平采样率色度分量是亮度分量的一半),比如第一个像素采样Y,U,第二个像素采样Y,V,依次类推,这样每个点占用2个字节,二个像素组成一个宏像素.
4:2:0  这种采样并不意味着只有Y,U而没有V分量,这里的0表示U,V分量隔行才采样一次; 水平和垂直取样率色度分量都是亮度分量的一半,即水平垂直方向上,每4个亮度像素,相应的就有1个U和1个V。
注:H264支持4:2:0的连续或隔行视频的编码和解码。
三、H264基本概念:
H264:是由ITU-T视频编码专家组(VCEG)和ISO/IEC动态图像专家组(MPEG)联合组成的联合视频组(JVT,Joint Video Team)提出的高度压缩数字视频编×××标准.主要应用于有线电视远程监控、交互媒体、数字电视、视频会议、视频点播、流媒体服务等
H264编码的框架分两层:
视频编码层VCL(Video Coding Layer):负责高效的视频内容表示。
网络提取层NAL(Network Abstraction Layer):负责以网络所要求的恰当的方式对数据进行打包和传送。分为两层是为解决不同应用中的网络传输的差异。
数据组织形式:

数据的组织形式从大到小排序是:序列(sequence)、图像(frame/field-picture)、片组(slice group)、片(slice)、宏块(macroblock)、块(block)、子块(sub-block)、像素(pixel)。


参考:http://blog.csdn.net/searchsun/article/details/2443867

四、rtsp协议传输流媒体

rtsp协议概念:实时流传输协议,是TCP/IP协议体系中的一个应用层协议,该协议定义了一对多应用程序如何有效地通过IP网络传送多媒体数据。RTSP在体系结构上位于RTP和RTCP之上,它使用TCP或UDP完成数据传输。HTTP与RTSP相比,HTTP请求由客户机发出,服务器作出响应;使用RTSP时,客户机和服务器都可以发出请求,即RTSP可以是双向的。RTSP提供一种可扩展的框架,使能够提供能控制的,按需传输实时数据,比如音频和视频文件。源数据可以包括现场数据的反馈和存贮的文件。rtsp对流媒体提供了诸如暂停,快进等控制,而它本身并不传输数据,rtsp作用相当于流媒体服务器的远程控制。传输数据可以通过传输层的tcp,udp协议,rtsp也提供了基于rtp传输机制的一些有效的方法。
RTSP消息格式:
请求信息
   方法 URI RTSP版本        CR LF
      消息头 CR LF           CR LF          
      消息体 CR LF
其中方法包括OPTION回应中所有的命令,URI是接受方的地址,例如:rtsp://192.168.20.136
RTSP版本一般都是 RTSP/1.0.每行后面的CR LF表示回车换行,需要接受端有相应的解析,最后一个消息头需要有两个CR LF
2、回应信息
    RTSP版本 状态码 解释       CR LF
      消息头 CR LF           CR LF
      消息体 CR LF
其中RTSP版本一般都是RTSP/1.0,状态码是一个数值,200表示成功,解释是与状态码对应的文本解释。
简单的rtsp交互过程:
C表示rtsp客户端,S表示rtsp服务端
1.C->S:OPTION request       //询问S有哪些方法可用
1.S->C:OPTION response    //S回应信息中包括提供的所有可用方法
2.C->S:DESCRIBE request    //要求得到S提供的媒体初始化描述信息
2.S->C:DESCRIBE response   //S回应媒体初始化描述信息,主要是sdp
3.C->S:SETUP request             //设置会话的属性,以及传输模式,提醒S建立会话
3.S->C:SETUP response          //S建立会话,返回会话标识符,以及会话相关信息
4.C->S:PLAY request        //C请求播放
4.S->C:PLAY response            //S回应该请求的信息
S->C:发送流媒体数据            
5.C->S:TEARDOWN request      //C请求关闭会话

5.S->C:TEARDOWN response //S回应该请求


参考:http://blog.csdn.net/chaigang1983/article/details/4738408