程序要实现对摄像头数据的采集,然后压缩编码,然后把编码后的数据输出。但程序运行到编码的部分时出现Segmentation fault错误,还请大家帮忙看看是什么原因,多谢了。
/* 服务端程序 server.c */
//WB
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <linux/types.h>
#include <linux/videodev2.h>
#include <setjmp.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
//#include "convert.h"
#include "../avc-src-0.14/avc/common/T264.h"
//#define SERVER_PORT 8888
#define WB
T264_t* m_t264;//表示编码器和解码器的一个实例。
T264_param_t m_param;//代表编码器所采用的参数,比如图片帧宽度高度、要用怎么样的压缩率等等。
char* m_pSrc;
char* m_pDst;
int* m_lDstSize;
char* m_pPoolData;
//WB
#define USB_VIDEO "/dev/video2"
int fd;
#define CLEAR(x) memset (&(x), 0, sizeof (x))
struct buffer
{
char* start;
size_t length;
};//定义一个buffer结构体,这个结构体用于盛放申请到的内存首地址和长度
struct v4l2_capability cap;//设备属性
struct v4l2_format fmt;//帧格式
struct v4l2_requestbuffers req;
struct v4l2_buffer buf;/*摄像头存储缓冲区的帧信息*/
struct buffer * buffers = NULL;
static unsigned int n_buffers =0;
static void errno_exit (const char * s)
{
fprintf (stderr, "%s error %d, %s\n",s, errno, strerror (errno));//根据指定的格式发送信息(参数)到标准输出.
exit (EXIT_FAILURE);
}
static int read_frame()
{
unsigned int i;
CLEAR (buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if (-1 == ioctl (fd, VIDIOC_DQBUF, &buf)) //从视频缓冲区的输出队列中取得一个已经保存有一帧视频数据的视频缓冲区
{
errno_exit ("VIDIOC_DQBUF");
}
else
printf("VIDIOC_DQBUF is OK\n");
if (buf.index < n_buffers)
{
int w,h;
int32_t iActualLen;
int row_stride = w*2*h;
/*对采集到的数据通过H264编码*/
iActualLen = T264_encode(m_t264, buffers[n_buffers].start, m_pDst, row_stride);
free(buffers);
printf("encoded:%d, %d bytes.\n",row_stride,iActualLen);
/*frame_num:存放帧号*/
memcpy(m_pPoolData,&m_t264->frame_num,1);
/*m_pDst编码后的数据*/
memcpy(m_pPoolData+1, m_pDst, iActualLen);
iActualLen++;
/*printf编码后的数据*/
printf(" %d \n",m_pPoolData);
free(m_pDst );
}
if(-1 == ioctl (fd, VIDIOC_QBUF, &buf))////将缓冲重新入队列尾,这样可以循环采集
errno_exit ("VIDIOC_QBUF");
else
printf("VIDIOC_QBUF is OK\n");
}
static void mainloop ()//判断一帧数据是否采集完
{
for (;;) {
fd_set fds;
struct timeval tv;
int r;
FD_ZERO (&fds);//将指定的文件描述符集清空
FD_SET (fd, &fds);//在文件描述符集合中增加一个新的文件描述符
/* Timeout. */
tv.tv_sec = 2;
tv.tv_usec = 0;
r = select (fd + 1, &fds, NULL, NULL, &tv);//判断是否可读(即摄像头是否准备好),tv是定时
if (-1 == r) {
if (EINTR == errno)
continue;
printf ("select err\n");
}
if (0 == r) {
fprintf (stderr, "select timeout\n");
exit (EXIT_FAILURE);
}
if (read_frame ())//如果可读,执行read_frame ()函数,并跳出循环
break;
}
}
void init_video() /* bpp == bytes per pixel*/
{
int ret;
/*设备的打开*/
fd = open( USB_VIDEO, O_NONBLOCK);
if( fd<0 )
printf("Can't open video device\n");
else
printf("USB_video is OK\n");
CLEAR (fmt);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = 160;//帧宽
fmt.fmt.pix.height = 120;//帧高
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;//像素格式
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;//隔行扫描
//设置当前驱动的视频捕获格式
if (-1 == ioctl (fd, VIDIOC_S_FMT, &fmt))
errno_exit ("VIDIOC_S_FMT");
else
printf("VIDIOC_S_FMT is OK\n");
struct v4l2_requestbuffers req;
CLEAR (req);
req.count = 4;//在缓存队列里保存多少张照片
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;//内存映射
/*向驱动申请帧缓冲,一般不超过5个。*/
if (-1 == ioctl (fd, VIDIOC_REQBUFS, &req))
{
errno_exit ("VIDIOC_REQBUFS");
}
else
printf("VIDIOC_REQBUFS is OK\n");
buffers = calloc (req.count, sizeof (*buffers));//分配连续的内存给刚才申请的缓冲区,并且初始化为0,返回值是首地址(物理地址)
if (!buffers) {
fprintf (stderr, "Out of memory\n");
exit (EXIT_FAILURE);
}
else
printf("buffers is OK\n");
for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
struct v4l2_buffer buf;
CLEAR (buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = n_buffers;//缓冲区序号
if (-1 == ioctl (fd, VIDIOC_QUERYBUF, &buf))//把数据缓存转换成物理地址
errno_exit ("VIDIOC_QUERYBUF");
else
printf("VIDIOC_QUERYBUF is OK\n");
buffers[n_buffers].length = buf.length;
buffers[n_buffers].start =
(char*)mmap (NULL /* 映射起始地址,NULL内核自动选择 */,
buf.length,//被映射内存块的长度
PROT_EXEC|PROT_READ | PROT_WRITE /*标志映射后能否被读写 */,
MAP_PRIVATE /* 可以被其他进城共享 */,
fd, buf.m.offset);//确定被映射的内存地址
if (MAP_FAILED == buffers[n_buffers].start)
printf("mmap is failed\n");
else
printf("mmap is OK\n");
}
}
void init_param(T264_param_t* param, const char* file)
{
int total_no;
FILE* fd;
char line[255];
int32_t b;//4个字节
if (!(fd = fopen(file,"r")))
{
printf("Couldn't open parameter file %s.\n", file);
exit(-1);
}
memset(param, 0, sizeof(*param));
fgets(line, 254, fd); sscanf(line,"%d", &b);
if (b != 4)
{
printf("wrong param file version, expect v4.0\n");
exit(-1);
}
fgets(line, 254, fd); sscanf(line,"%d", ¶m->width);
fgets(line, 254, fd); sscanf(line,"%d", ¶m->height);
fgets(line, 254, fd); sscanf(line,"%d", ¶m->search_x);
fgets(line, 254, fd); sscanf(line,"%d", ¶m->search_y);
fgets(line, 254, fd); sscanf(line,"%d", &total_no);
fgets(line, 254, fd); sscanf(line,"%d", ¶m->iframe);
fgets(line, 254, fd); sscanf(line,"%d", ¶m->idrframe);
fgets(line, 254, fd); sscanf(line,"%d", ¶m->b_num);
fgets(line, 254, fd); sscanf(line,"%d", ¶m->ref_num);
fgets(line, 254, fd); sscanf(line,"%d", ¶m->enable_rc);
fgets(line, 254, fd); sscanf(line,"%d", ¶m->bitrate);
fgets(line, 254, fd); sscanf(line,"%f", ¶m->framerate);
fgets(line, 254, fd); sscanf(line,"%d", ¶m->qp);
fgets(line, 254, fd); sscanf(line,"%d", ¶m->min_qp);
fgets(line, 254, fd); sscanf(line,"%d", ¶m->max_qp);
fgets(line, 254, fd); sscanf(line,"%d", ¶m->enable_stat);
fgets(line, 254, fd); sscanf(line,"%d", ¶m->disable_filter);
fgets(line, 254, fd); sscanf(line,"%d", ¶m->aspect_ratio);
fgets(line, 254, fd); sscanf(line,"%d", ¶m->video_format);
fgets(line, 254, fd); sscanf(line,"%d", ¶m->luma_coeff_cost);
fgets(line, 254, fd); sscanf(line,"%d", &b);
param->flags |= (USE_INTRA16x16) * (!!b);
fgets(line, 254, fd); sscanf(line,"%d", &b);
param->flags |= (USE_INTRA4x4) * (!!b);
fgets(line, 254, fd); sscanf(line,"%d", &b);
param->flags |= (USE_INTRAININTER) * (!!b);
fgets(line, 254, fd); sscanf(line,"%d", &b);
param->flags |= (USE_HALFPEL) * (!!b);
fgets(line, 254, fd); sscanf(line,"%d", &b);
param->flags |= (USE_QUARTPEL) * (!!b);
fgets(line, 254, fd); sscanf(line,"%d", &b);
param->flags |= (USE_SUBBLOCK) * (!!b);
fgets(line, 254, fd); sscanf(line,"%d", &b);
param->flags |= (USE_FULLSEARCH) * (!!b);
fgets(line, 254, fd); sscanf(line,"%d", &b);
param->flags |= (USE_DIAMONDSEACH) * (!!b);
fgets(line, 254, fd); sscanf(line,"%d", &b);
param->flags |= (USE_FORCEBLOCKSIZE) * (!!b);
fgets(line, 254, fd); sscanf(line,"%d", &b);
param->flags |= (USE_FASTINTERPOLATE) * (!!b);
fgets(line, 254, fd); sscanf(line,"%d", &b);
param->flags |= (USE_SAD) * b;
fgets(line, 254, fd); sscanf(line,"%d", &b);
param->flags |= (USE_EXTRASUBPELSEARCH) * (!!b);
fgets(line, 254, fd); sscanf(line,"%d", &b);
param->flags |= (USE_SCENEDETECT) * (!!b);
fgets(line, 254, fd); sscanf(line,"%d", &b);
param->block_size |= (SEARCH_16x16P) * (!!b);
fgets(line, 254, fd); sscanf(line,"%d", &b);
param->block_size |= (SEARCH_16x8P) * (!!b);
fgets(line, 254, fd); sscanf(line,"%d", &b);
param->block_size |= (SEARCH_8x16P) * (!!b);
fgets(line, 254, fd); sscanf(line,"%d", &b);
param->block_size |= (SEARCH_8x8P) * (!!b);
fgets(line, 254, fd); sscanf(line,"%d", &b);
param->block_size |= (SEARCH_8x4P) * (!!b);
fgets(line, 254, fd); sscanf(line,"%d", &b);
param->block_size |= (SEARCH_4x8P) * (!!b);
fgets(line, 254, fd); sscanf(line,"%d", &b);
param->block_size |= (SEARCH_4x4P) * (!!b);
fgets(line, 254, fd); sscanf(line,"%d", &b);
param->block_size |= (SEARCH_16x16B) * (!!b);
fgets(line, 254, fd); sscanf(line,"%d", &b);
param->block_size |= (SEARCH_16x8B) * (!!b);
fgets(line, 254, fd); sscanf(line,"%d", &b);
param->block_size |= (SEARCH_8x16B) * (!!b);
fgets(line, 254, fd); sscanf(line,"%d", &b);
param->block_size |= (SEARCH_8x8B) * (!!b);
fgets(line, 254, fd); sscanf(line,"%d", ¶m->cpu);
fgets(line, 254, fd); sscanf(line, "%d", ¶m->cabac);
// fgets(line, 254, fd); sscanf(line,"%s", src_path);
// fgets(line, 254, fd); sscanf(line,"%s", out_path);
// fgets(line, 254, fd); sscanf(line,"%s", rec_path);
// param->rec_name = rec_path;
fclose(fd);
}
static void start_capturing ()//采集数据
{
unsigned int i;
enum v4l2_buf_type type;
for (i = 0; i < n_buffers; ++i) {
struct v4l2_buffer buf;
CLEAR (buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if (-1 == ioctl (fd, VIDIOC_QBUF, &buf))////将申请到的帧缓冲全部入队列,以便存放采集到的数据.
errno_exit("VIDIOC_QBUF");
else
printf("VIDIOC_QBUF is OK\n");
}
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == ioctl (fd, VIDIOC_STREAMON, &type))
errno_exit ("VIDIOC_STREAMON");
else
printf("VIDIOC_STREAMON is OK\n");
}
void init_encoder()
{
//编码准备
const char* paramfile = "fastspeed.txt";
/*获取fastspeed.txt文件信息*/
init_param(&m_param, paramfile);//初始化编码器的参数
m_param.direct_flag = 1;//支持运动矢量直接预测
/*t264编码的打开*/
m_t264 = T264_open(&m_param);//根据param 参数配置,打开并初始化一个编码器实例,返回编码器实例指针,可以当成句柄理解。
//内存大小
m_lDstSize = m_param.height * m_param.width + (m_param.height * m_param.width >> 1);
/*分配t264解码后数据存放的内存*/
m_pDst = (uint32_t*)T264_malloc(m_lDstSize, CACHE_SIZE);
/*分配内存用于存放一帧数据长度的数据*/
m_pPoolData = malloc(m_param.width*m_param.height*2);
}
void free_dev()
{
printf("free device\n");
close(fd);
}
/*主函数入口*/
int main(void)
{
/*该函数完成编码前的准备*/
init_encoder();
#ifdef WB
atexit( &free_dev );
/*采集数据前的初始化函数*/
init_video();
while(1)
{
/*数据的采集*/
start_capturing ();
mainloop();
}
#endif
}
编码的参数设置如下:
4 # version; recommend for fast speed parameter
176 # width
144# height
16 # search x
16 # search y
1 # total frame number
30 # i intervals
30 # idr intervals
0 # b frame number between 2 p-frame(0, 1, 2)
1 # Number of previous frames used for inter motion search(1 - 4)
0 # enable rate control
200000 # bps
30 # framerate(rc only)
30 # init i,p qp, if NOT used fixed qp mode it is just the first i&p qp, 0 means auto select the first i&p qp(do not suggest)
0 # min qp
51 # max qp
0 # enable psnr
0 # disable_deblock_filter
2 # aspect_ratio, 2 means 720 * 576 4:3
1 # video_format, 1 means pal
4 # luma_coeff_cost, default 4, min qp please decrease this value(< 0 disable)
0 # USE_INTRA16x16
1 # USE_INTRA4x4
0 # USE_INTRAININTER
1 # USE_HALFPEL
1 # USE_QUARTPEL
1 # USE_SUBBLOCK
0 # USE_FULLSEARCH
1 # USE_DIAMONDSEACH
1 # USE_FORCEBLOCKSIZE
1 # USE_FASTINTERPOLATE
1 # USE_SAD
1 # USE_EXTRASUBPELSEARCH
1 # USE_SCENEDETECT
#1 # SEARCH_16x16P
1 # SEARCH_16x8P
1 # SEARCH_8x16P
0 # SEARCH_8x8P
0 # SEARCH_8x4P
0 # SEARCH_4x8P
0 # SEARCH_4x4P
#1 # SEARCH_16x16B, always valid
0 # SEARCH_16x8B
0 # SEARCH_8x16B
0 # SEARCH_8x8B
0 # T264_CPU_FORCE = 1
0 # CABAC