天天看点

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 > 1)

grabmethod = 1;//mmap by default;

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;;

}

不同的输出格式有不同的分配方式

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;

具体是哪一个设备节点由我们传入的参数决定

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;

}

}

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;

// vd->formatIn = vd->fmt.fmt.pix.pixelformat;

}

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);

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;

}

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 ,

         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]);

}

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) // 根据视频数据的大小,判断该帧数据是否有效

{    

fprintf(stderr, "Ignoring empty buffer ...\n");

return 0;

}

// 将视频数据拷贝到 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:

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)

{

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);

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++)

{

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);

}