JZ2440 mjpg-streamer学习笔记6----输入通道--主要涉及函数

1、init_videoIn函数

int init_videoIn(struct vdIn *vd, char *device, int width, int height, int fps, int format, int grabmethod)
{

各种参数判断(设备节点是否为空,分辨率是否为0,如果不符合要求,直接返回)
if (vd == NULL || device == NULL)
return -1;
if (width == 0 || height == 0)
return -1;
if (grabmethod < 0 || grabmethod &gt; 1)
grabmethod = 1;//mmap by default;


/* 重新设置vdIn结构体的每个成员 */
vd->videodevice = NULL;
vd->status = NULL;
vd->pictName = NULL;
vd->videodevice = (char *) calloc (1, 16 * sizeof (char));
vd->status = (char *) calloc (1, 100 * sizeof (char));
vd->pictName = (char *) calloc (1, 80 * sizeof (char));
snprintf (vd->videodevice, 12, "%s", device);
vd->toggleAvi = 0;
vd->getPict = 0;
vd->signalquit = 1;
vd->width = width;
vd->height = height;
vd->fps = fps;
vd->formatIn = format;
vd->grabmethod = grabmethod;

调用init_v4l2 这个函数
if (init_v4l2 (vd) < 0)
{
fprintf (stderr, " Init v4L2 failed !! exit fatal \n");
goto error;;
}

/* alloc a temp buffer to reconstruct the pict */
/* 分配一个临时缓冲区,用于接收摄像头数据 */不同的输出格式有不同的分配方式
vd->framesizeIn = (vd->width * vd->height << 1);
switch (vd->formatIn)
{
case V4L2_PIX_FMT_MJPEG:
vd->tmpbuffer = (unsigned char *) calloc(1, (size_t) vd->framesizeIn);
if (!vd->tmpbuffer)
goto error;
vd->framebuffer =
(unsigned char *) calloc(1, (size_t) vd->width * (vd->height + 8) * 2);
break;
case V4L2_PIX_FMT_YUYV:
vd->framebuffer =
(unsigned char *) calloc(1, (size_t) vd->framesizeIn);
break;
default:
fprintf(stderr, " should never arrive exit fatal !!\n");
goto error;
break;
}
分配缓存是否分配成功
if (!vd->framebuffer)
goto error;
成功返回0
return 0;
error:
free(vd->videodevice);
free(vd->status);
free(vd->pictName);
close(vd->fd);
return -1;

2、init_v4l2函数

static int init_v4l2(struct vdIn *vd)
{
int i;
int ret = 0;


/* 打开摄像头的设备节点(/dev/vide0) */具体是哪一个设备节点由我们传入的参数决定
if ((vd->fd = open(vd->videodevice, O_RDWR)) == -1)
{
perror("ERROR opening V4L interface");
return -1;
}
接下来的操作是通过V4L2提供的一系列IOCTL函数来初始化摄像头

/* 查看所打开的设备是否是视频捕获设备 */
memset(&vd->cap, 0, sizeof(struct v4l2_capability));
ret = ioctl(vd->fd,VIDIOC_QUERYCAP, &vd->cap);
if (ret < 0)
{
fprintf(stderr, "Error opening device %s: unable to query device.\n", vd->videodevice);
goto fatal;
}


/* 判断是否是视频捕获设备 */
if ((vd->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0)
{
fprintf(stderr, "Error opening device %s: video capture not supported.\n",
vd->videodevice);
goto fatal;;
}


/* 判断是否支持该种数据传输方式 */
if (vd->grabmethod)
{
if (!(vd->cap.capabilities & V4L2_CAP_STREAMING))// 流传输
{
fprintf(stderr, "%s does not support streaming i/o\n", vd->videodevice);
goto fatal;
}
}
else
{
if (!(vd->cap.capabilities & V4L2_CAP_READWRITE))// 读写方式传输
{
fprintf(stderr, "%s does not support read i/o\n", vd->videodevice);
goto fatal;
}
}


/*
* set format in
*/
/*
设置摄像头的输出格式(分辨率、输出格式(MJPEG/YUV))
*/
memset(&vd->fmt, 0, sizeof(struct v4l2_format));
vd->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
vd->fmt.fmt.pix.width = vd->width;
vd->fmt.fmt.pix.height = vd->height;
vd->fmt.fmt.pix.pixelformat = vd->formatIn;
vd->fmt.fmt.pix.field = V4L2_FIELD_ANY;
ret = ioctl(vd->fd, VIDIOC_S_FMT, &vd->fmt);
if (ret < 0)
{
perror("Unable to set format");
goto fatal;
}


if ((vd->fmt.fmt.pix.width != vd->width) ||
(vd->fmt.fmt.pix.height != vd->height)) {
fprintf(stderr, " format asked unavailable get width %d height %d \n", vd->fmt.fmt.pix.width, vd->fmt.fmt.pix.height);
vd->width = vd->fmt.fmt.pix.width;
vd->height = vd->fmt.fmt.pix.height;
/*
* look the format is not part of the deal ???
*/
// vd->formatIn = vd->fmt.fmt.pix.pixelformat;
}


/*
* set framerate
*/
/*
设置摄像头参数,比如输出帧率
*/
struct v4l2_streamparm *setfps;
setfps = (struct v4l2_streamparm *) calloc(1, sizeof(struct v4l2_streamparm));
memset(setfps, 0, sizeof(struct v4l2_streamparm));
setfps->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
setfps->parm.capture.timeperframe.numerator = 1;
setfps->parm.capture.timeperframe.denominator = vd->fps;
ret = ioctl(vd->fd, VIDIOC_S_PARM, setfps);


/*
* request buffers
*/
/*
申请缓存
*/
memset(&vd->rb, 0, sizeof(struct v4l2_requestbuffers));
vd->rb.count = NB_BUFFER;
vd->rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
vd->rb.memory = V4L2_MEMORY_MMAP;


ret = ioctl(vd->fd, VIDIOC_REQBUFS, &vd->rb);

if (ret < 0)
{
perror("Unable to query buffer");
goto fatal;
}

/*
* map the buffers
*/
/* 将上述申请的缓存映射到用户空间 */
for (i = 0; i < NB_BUFFER; i++)
{
/* 获取内核空间的视频缓冲区的信息 */
memset(&vd->buf, 0, sizeof(struct v4l2_buffer));
vd->buf.index = i;
vd->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
vd->buf.memory = V4L2_MEMORY_MMAP;
ret = ioctl(vd->fd, VIDIOC_QUERYBUF, &vd->buf);
if (ret < 0)
{
perror("Unable to query buffer");
goto fatal;
}


if (debug)
fprintf(stderr, "length: %u offset: %u\n", vd->buf.length, vd->buf.m.offset);
/* 做映射操作 */
vd->mem[i] = mmap(0 /* start anywhere */ ,
         vd->buf.length, PROT_READ, MAP_SHARED, vd->fd,
         vd->buf.m.offset);
if (vd->mem[i] == MAP_FAILED) {
perror("Unable to map buffer");
goto fatal;
}
if (debug)
fprintf(stderr, "Buffer mapped at address %p.\n", vd->mem[i]);
}


/*
* Queue the buffers.
*/
/*
投放一个空的视频缓冲区到视频缓冲区队列中
*/
for (i = 0; i < NB_BUFFER; ++i)
{
memset(&vd->buf, 0, sizeof(struct v4l2_buffer));
vd->buf.index = i;
vd->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
vd->buf.memory = V4L2_MEMORY_MMAP;
ret = ioctl(vd->fd, VIDIOC_QBUF, &vd->buf);
if (ret < 0) {
perror("Unable to queue buffer");
goto fatal;;
}
}
return 0;
fatal:
return -1;


}

3、uvcGrab函数

int uvcGrab(struct vdIn *vd)
{
#define HEADERFRAME1 0xaf
int ret;


if (!vd->isstreaming)
if (video_enable(vd)) // 使能视频捕获设备,通过ioctl发VIDIOC_STREAMON来实现
goto err;


/* 从视频缓冲区队列中取出一个已经存有一帧数据的视频缓冲区 */
memset(&vd->buf, 0, sizeof(struct v4l2_buffer));
vd->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
vd->buf.memory = V4L2_MEMORY_MMAP;


ret = ioctl(vd->fd, VIDIOC_DQBUF, &vd->buf);
if (ret < 0)
{
perror("Unable to dequeue buffer");
goto err;
}


switch (vd->formatIn)
{
case V4L2_PIX_FMT_MJPEG:
if (vd->buf.bytesused <= HEADERFRAME1) // 根据视频数据的大小,判断该帧数据是否有效
{    /* Prevent crash
                      * on empty image */
fprintf(stderr, "Ignoring empty buffer ...\n");
return 0;
}


/* memcpy(vd->tmpbuffer, vd->mem[vd->buf.index], vd->buf.bytesused);


memcpy (vd->tmpbuffer, vd->mem[vd->buf.index], HEADERFRAME1);
memcpy (vd->tmpbuffer + HEADERFRAME1, dht_data, sizeof(dht_data));
memcpy (vd->tmpbuffer + HEADERFRAME1 + sizeof(dht_data), vd->mem[vd->buf.index] + HEADERFRAME1, (vd->buf.bytesused - HEADERFRAME1));
*/


// 将视频数据拷贝到 vd->tmpbuffer 中
memcpy(vd->tmpbuffer, vd->mem[vd->buf.index], vd->buf.bytesused);


if (debug)
fprintf(stderr, "bytes in used %d \n", vd->buf.bytesused); // 如果使能了调试功能,则打印出调试信息
break;


case V4L2_PIX_FMT_YUYV:
/* 将一帧视频数据拷贝到 vd->framebuffer */
if (vd->buf.bytesused > vd->framesizeIn)
memcpy (vd->framebuffer, vd->mem[vd->buf.index], (size_t) vd->framesizeIn);
else
memcpy (vd->framebuffer, vd->mem[vd->buf.index], (size_t) vd->buf.bytesused);
break;


default:
goto err;
break;
}


/* 投放一个空的视频缓冲区到视频缓冲区队列中 */
ret = ioctl(vd->fd, VIDIOC_QBUF, &vd->buf);
if (ret < 0)
{
perror("Unable to requeue buffer");
goto err;
}


return 0;


err:
vd->signalquit = 0;
return -1;
}

4、video_enable函数

static int video_enable(struct vdIn *vd)
{
int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
int ret;


ret = ioctl(vd->fd, VIDIOC_STREAMON, &type);
if (ret < 0)
{
perror("Unable to start capture");
return ret;
}
vd->isstreaming = 1;
return 0;
}

5、compress_yuyv_to_jpeg函数

int compress_yuyv_to_jpeg(struct vdIn *vd, unsigned char *buffer, int size, int quality)
{
/*
将YUV转换为JPEG
YUV->RGB->JPEG (利用libjpeg)
*/
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
JSAMPROW row_pointer[1];
unsigned char *line_buffer, *yuyv;
int z;
static int written;


line_buffer = calloc (vd->width * 3, 1);
yuyv = vd->framebuffer;


cinfo.err = jpeg_std_error (&jerr);
jpeg_create_compress (&cinfo);
/* jpeg_stdio_dest (&cinfo, file); */
dest_buffer(&cinfo, buffer, size, &written);


cinfo.image_width = vd->width;
cinfo.image_height = vd->height;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;


jpeg_set_defaults (&cinfo);
jpeg_set_quality (&cinfo, quality, TRUE);


jpeg_start_compress (&cinfo, TRUE);


z = 0;
while (cinfo.next_scanline < vd->height) {
int x;
unsigned char *ptr = line_buffer;


for (x = 0; x < vd->width; x++)
{
/* 首先将 YUV->RGB */
int r, g, b;
int y, u, v;


if (!z)
y = yuyv[0] << 8;
else
y = yuyv[2] << 8;
u = yuyv[1] - 128;
v = yuyv[3] - 128;


r = (y + (359 * v)) >> 8;
g = (y - (88 * u) - (183 * v)) >> 8;
b = (y + (454 * u)) >> 8;


*(ptr++) = (r > 255) ? 255 : ((r < 0) ? 0 : r);
*(ptr++) = (g > 255) ? 255 : ((g < 0) ? 0 : g);
*(ptr++) = (b > 255) ? 255 : ((b < 0) ? 0 : b);


if (z++) {
z = 0;
yuyv += 4;
}
}


row_pointer[0] = line_buffer;
jpeg_write_scanlines (&cinfo, row_pointer, 1);
}


jpeg_finish_compress (&cinfo);
jpeg_destroy_compress (&cinfo);


free (line_buffer);


return (written);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值