Linux上C的networking摄像头库?

有没有任何C库来从Linux上的networking摄像头获取video?

Solutions Collecting From Web of "Linux上C的networking摄像头库?"

我们很多人使用OpenCV (跨平台的计算机视觉库,目前在2.1版)

下面的代码片段从相机抓取帧,将它们转换为灰度并将其显示在屏幕上:

#include <stdio.h> #include "cv.h" #include "highgui.h" typedef IplImage* (*callback_prototype)(IplImage*); /* * make_it_gray: custom callback to convert a colored frame to its grayscale version. * Remember that you must deallocate the returned IplImage* yourself after calling this function. */ IplImage* make_it_gray(IplImage* frame) { // Allocate space for a new image IplImage* gray_frame = 0; gray_frame = cvCreateImage(cvSize(frame->width, frame->height), frame->depth, 1); if (!gray_frame) { fprintf(stderr, "!!! cvCreateImage failed!\n" ); return NULL; } cvCvtColor(frame, gray_frame, CV_RGB2GRAY); return gray_frame; } /* * process_video: retrieves frames from camera and executes a callback to do individual frame processing. * Keep in mind that if your callback takes too much time to execute, you might loose a few frames from * the camera. */ void process_video(callback_prototype custom_cb) { // Initialize camera CvCapture *capture = 0; capture = cvCaptureFromCAM(-1); if (!capture) { fprintf(stderr, "!!! Cannot open initialize webcam!\n" ); return; } // Create a window for the video cvNamedWindow("result", CV_WINDOW_AUTOSIZE); IplImage* frame = 0; char key = 0; while (key != 27) // ESC { frame = cvQueryFrame(capture); if(!frame) { fprintf( stderr, "!!! cvQueryFrame failed!\n" ); break; } // Execute callback on each frame IplImage* processed_frame = (*custom_cb)(frame); // Display processed frame cvShowImage("result", processed_frame); // Release resources cvReleaseImage(&processed_frame); // Exit when user press ESC key = cvWaitKey(10); } // Free memory cvDestroyWindow("result"); cvReleaseCapture(&capture); } int main( int argc, char **argv ) { process_video(make_it_gray); return 0; } 

你最好的选择可能是: video4linux(V4L)

它很容易使用,功能强大。

v4l2官方例子

你得到什么:

  • ./v4l2grab :捕捉几个快照到文件outNNN.ppm
  • ./v4l2gl :使用OpenGL纹理(立即渲染,嘿!)和原始的X11窗口(加上GLUT的gluLookAt来实现更好的效果),在视窗上显示视频。

如何在Ubuntu 16.04上获得它:

 sudo apt-get install libv4l-dev sudo apt-get build-dep libv4l-dev git clone git://linuxtv.org/v4l-utils.git cd v4l-utils # Matching the installed version of dpkg -s libv4l-dev git checkout v4l-utils-1.10.0 ./bootstrap.sh ./configure make # TODO: fails halfway, but it does not matter for us now. cd contrib/tests make 

在Git树之外使用这些例子也很容易,只需将它们复制出来,使相对包含""绝对<> ,然后删除config.h 。 我已经在https://github.com/cirosantilli/cpp-cheat/tree/09fe73d248f7da2e9c9f3eff2520a143c259f4a6/v4l2

来自文档的最小示例

文档4.9.0包含在https://linuxtv.org/downloads/v4l-dvb-apis-new/uapi/v4l/v4l2grab-example.html中似乎&#x662F;./v4l2grab的最低版本。 我需要对它进行最小程度的修补,并且我已经发布了补丁到http://www.spinics.net/lists/linux-media/ (他们的文档首先在Linux内核树中生活),在那里被忽略。

用法:

 gcc v4l2grab.c -lv4l2 ./a.out 

补丁码:

 /* V4L2 video picture grabber Copyright (C) 2009 Mauro Carvalho Chehab <mchehab@infradead.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <errno.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/time.h> #include <sys/mman.h> #include <linux/videodev2.h> #include <libv4l2.h> #define CLEAR(x) memset(&(x), 0, sizeof(x)) struct buffer { void *start; size_t length; }; static void xioctl(int fh, int request, void *arg) { int r; do { r = v4l2_ioctl(fh, request, arg); } while (r == -1 && ((errno == EINTR) || (errno == EAGAIN))); if (r == -1) { fprintf(stderr, "error %d, %s\\n", errno, strerror(errno)); exit(EXIT_FAILURE); } } int main(int argc, char **argv) { struct v4l2_format fmt; struct v4l2_buffer buf; struct v4l2_requestbuffers req; enum v4l2_buf_type type; fd_set fds; struct timeval tv; int r, fd = -1; unsigned int i, n_buffers; char *dev_name = "/dev/video0"; char out_name[256]; FILE *fout; struct buffer *buffers; fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0); if (fd < 0) { perror("Cannot open device"); exit(EXIT_FAILURE); } CLEAR(fmt); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = 640; fmt.fmt.pix.height = 480; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24; fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; xioctl(fd, VIDIOC_S_FMT, &fmt); if (fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_RGB24) { printf("Libv4l didn't accept RGB24 format. Can't proceed.\\n"); exit(EXIT_FAILURE); } if ((fmt.fmt.pix.width != 640) || (fmt.fmt.pix.height != 480)) printf("Warning: driver is sending image at %dx%d\\n", fmt.fmt.pix.width, fmt.fmt.pix.height); CLEAR(req); req.count = 2; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; xioctl(fd, VIDIOC_REQBUFS, &req); buffers = calloc(req.count, sizeof(*buffers)); for (n_buffers = 0; n_buffers < req.count; ++n_buffers) { CLEAR(buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = n_buffers; xioctl(fd, VIDIOC_QUERYBUF, &buf); buffers[n_buffers].length = buf.length; buffers[n_buffers].start = v4l2_mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset); if (MAP_FAILED == buffers[n_buffers].start) { perror("mmap"); exit(EXIT_FAILURE); } } for (i = 0; i < n_buffers; ++i) { CLEAR(buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; xioctl(fd, VIDIOC_QBUF, &buf); } type = V4L2_BUF_TYPE_VIDEO_CAPTURE; xioctl(fd, VIDIOC_STREAMON, &type); for (i = 0; i < 20; i++) { do { FD_ZERO(&fds); FD_SET(fd, &fds); /* Timeout. */ tv.tv_sec = 2; tv.tv_usec = 0; r = select(fd + 1, &fds, NULL, NULL, &tv); } while ((r == -1 && (errno = EINTR))); if (r == -1) { perror("select"); return errno; } CLEAR(buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; xioctl(fd, VIDIOC_DQBUF, &buf); sprintf(out_name, "out%03d.ppm", i); fout = fopen(out_name, "w"); if (!fout) { perror("Cannot open image"); exit(EXIT_FAILURE); } fprintf(fout, "P6\n%d %d 255\n", fmt.fmt.pix.width, fmt.fmt.pix.height); fwrite(buffers[buf.index].start, buf.bytesused, 1, fout); fclose(fout); xioctl(fd, VIDIOC_QBUF, &buf); } type = V4L2_BUF_TYPE_VIDEO_CAPTURE; xioctl(fd, VIDIOC_STREAMOFF, &type); for (i = 0; i < n_buffers; ++i) v4l2_munmap(buffers[i].start, buffers[i].length); v4l2_close(fd); return 0; } 

头只有面向对象的版本才能重用

从文档中的示例中提取,但以一种使其非常容易重用的形式提取。

common_v4l2.h

 #ifndef COMMON_V4L2_H #define COMMON_V4L2_H #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <sys/time.h> #include <sys/types.h> #include <libv4l2.h> #include <linux/videodev2.h> #define COMMON_V4L2_CLEAR(x) memset(&(x), 0, sizeof(x)) typedef struct { void *start; size_t length; } CommonV4l2_Buffer; typedef struct { int fd; CommonV4l2_Buffer *buffers; struct v4l2_buffer buf; unsigned int n_buffers; } CommonV4l2; void CommonV4l2_xioctl(int fh, unsigned long int request, void *arg) { int r; do { r = v4l2_ioctl(fh, request, arg); } while (r == -1 && ((errno == EINTR) || (errno == EAGAIN))); if (r == -1) { fprintf(stderr, "error %d, %s\n", errno, strerror(errno)); exit(EXIT_FAILURE); } } void CommonV4l2_init(CommonV4l2 *this, char *dev_name, unsigned int x_res, unsigned int y_res) { enum v4l2_buf_type type; struct v4l2_format fmt; struct v4l2_requestbuffers req; unsigned int i; this->fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0); if (this->fd < 0) { perror("Cannot open device"); exit(EXIT_FAILURE); } COMMON_V4L2_CLEAR(fmt); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = x_res; fmt.fmt.pix.height = y_res; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24; fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; CommonV4l2_xioctl(this->fd, VIDIOC_S_FMT, &fmt); if ((fmt.fmt.pix.width != x_res) || (fmt.fmt.pix.height != y_res)) printf("Warning: driver is sending image at %dx%d\n", fmt.fmt.pix.width, fmt.fmt.pix.height); COMMON_V4L2_CLEAR(req); req.count = 2; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; CommonV4l2_xioctl(this->fd, VIDIOC_REQBUFS, &req); this->buffers = calloc(req.count, sizeof(*this->buffers)); for (this->n_buffers = 0; this->n_buffers < req.count; ++this->n_buffers) { COMMON_V4L2_CLEAR(this->buf); this->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; this->buf.memory = V4L2_MEMORY_MMAP; this->buf.index = this->n_buffers; CommonV4l2_xioctl(this->fd, VIDIOC_QUERYBUF, &this->buf); this->buffers[this->n_buffers].length = this->buf.length; this->buffers[this->n_buffers].start = v4l2_mmap(NULL, this->buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, this->fd, this->buf.m.offset); if (MAP_FAILED == this->buffers[this->n_buffers].start) { perror("mmap"); exit(EXIT_FAILURE); } } for (i = 0; i < this->n_buffers; ++i) { COMMON_V4L2_CLEAR(this->buf); this->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; this->buf.memory = V4L2_MEMORY_MMAP; this->buf.index = i; CommonV4l2_xioctl(this->fd, VIDIOC_QBUF, &this->buf); } type = V4L2_BUF_TYPE_VIDEO_CAPTURE; CommonV4l2_xioctl(this->fd, VIDIOC_STREAMON, &type); } void CommonV4l2_update_image(CommonV4l2 *this) { fd_set fds; int r; struct timeval tv; do { FD_ZERO(&fds); FD_SET(this->fd, &fds); /* Timeout. */ tv.tv_sec = 2; tv.tv_usec = 0; r = select(this->fd + 1, &fds, NULL, NULL, &tv); } while ((r == -1 && (errno == EINTR))); if (r == -1) { perror("select"); exit(EXIT_FAILURE); } COMMON_V4L2_CLEAR(this->buf); this->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; this->buf.memory = V4L2_MEMORY_MMAP; CommonV4l2_xioctl(this->fd, VIDIOC_DQBUF, &this->buf); CommonV4l2_xioctl(this->fd, VIDIOC_QBUF, &this->buf); } char * CommonV4l2_get_image(CommonV4l2 *this) { return ((char *)this->buffers[this->buf.index].start); } size_t CommonV4l2_get_image_size(CommonV4l2 *this) { return this->buffers[this->buf.index].length; } void CommonV4l2_deinit(CommonV4l2 *this) { unsigned int i; enum v4l2_buf_type type; type = V4L2_BUF_TYPE_VIDEO_CAPTURE; CommonV4l2_xioctl(this->fd, VIDIOC_STREAMOFF, &type); for (i = 0; i < this->n_buffers; ++i) v4l2_munmap(this->buffers[i].start, this->buffers[i].length); v4l2_close(this->fd); free(this->buffers); } #endif 

main.c

 #include <stdio.h> #include <stdlib.h> #include "common_v4l2.h" static void save_ppm( unsigned int i, unsigned int x_res, unsigned int y_res, size_t data_lenght, char *data ) { FILE *fout; char out_name[256]; sprintf(out_name, "out%03d.ppm", i); fout = fopen(out_name, "w"); if (!fout) { perror("error: fopen"); exit(EXIT_FAILURE); } fprintf(fout, "P6\n%d %d 255\n", x_res, y_res); fwrite(data, data_lenght, 1, fout); fclose(fout); } int main(void) { CommonV4l2 common_v4l2; char *dev_name = "/dev/video0"; struct buffer *buffers; unsigned int i, x_res = 640, y_res = 480 ; CommonV4l2_init(&common_v4l2, dev_name, x_res, y_res); for (i = 0; i < 20; i++) { CommonV4l2_update_image(&common_v4l2); save_ppm( i, x_res, y_res, CommonV4l2_get_image_size(&common_v4l2), CommonV4l2_get_image(&common_v4l2) ); } CommonV4l2_deinit(&common_v4l2); return EXIT_SUCCESS; } 

上游: https : //github.com/cirosantilli/cpp-cheat/blob/be5d6444bddab93e95949b3388d92007b5ca916f/v4l2/common_v4l2.h

SDL

视频捕捉是在他们的路线图: https ://wiki.libsdl.org/Roadmap,我敢打赌,它将在Linux上包装V4L。

当我们获得这个可移植性层时,它会比较甜美,并且比OpenCV的膨胀度要小。