首页 > 系统 > Linux > 正文

Linux下实现视频读取

2024-06-28 13:24:31
字体:
来源:转载
供稿:网友
linux下实现视频读取

  V4L(video4linux是一些视频系统,视频软件、音频软件的基础,经常时候在需要采集图像的场合,如视频监控,webcam,可视电话,经常使用在embedded linux中是linux嵌入式开发中经常使用的系统接口。它是linux内核提供给用户空间的编程接口,各种的视频和音频设备开发相应的驱动程序后,就可以通过v4l提供的系统API来控制视频和音频设备,也就是说v4l分为两层,底层为音视频设备在内核中的驱动,上层为系统提供的API,而对于我们来说需要的就是使用这些系统API。V4L2是V4L的升级版本,为linux下视频设备程序提供了一套接口规范。包括一套数据结构和底层V4L2驱动接口。V4L2采用流水线的方式,操作更简单直观,基本遵循打开视频设备、设置格式、处理数据、关闭设备,更多的具体操作通过ioctl函数来实现。

1、打开设备  int open(const char *device_name, int flags);  int fd = open("/dev/video0", O_RDONLY); //O_NONBLOCK --非阻塞(不推荐使用)2、关闭设备 int close(int fd)  int ret = close(fd);3、v4l2_capability 查看属性  int ioctl(int fd, int request, struct v4l2_capability *argp);  struct v4l2_capability  {    u8 driver[16]; // 驱动名字    u8 card[32]; // 设备名字    u8 bus_info[32]; // 设备在系统中的位置    u32 version; // 驱动版本号    u32 capabilities; // 设备支持的操作    u32 reserved[4]; // 保留字段  };4、设置视频格式与制式相关函数:int ioctl(int fd, int request, struct v4l2_fmtdesc *argp);int ioctl(int fd, int request, struct v4l2_format *argp);

相关结构体: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 操作命令设置视频捕捉格式。struct v4l2_fmtdesc{u32 index; // 要查询的格式序号,应用程序设置enum v4l2_buf_type type; // 帧类型,应用程序设置u32 flags; // 是否为压缩格式u8 description[32]; // 格式名称u32 pixelformat; // 格式u32 reserved[4]; // 保留};所有的视频格式可以能下面的方法查看#define v4l2_fourcc(a, b, c, d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))All format : VIDIOC_ENUM_FMT, v4l2_fmtdesc

struct v4l2_format{enum v4l2_buf_type type; // 帧类型,应用程序设置union fmt{struct v4l2_pix_format pix; // 视频设备使用struct v4l2_window win;struct v4l2_vbi_format vbi;struct v4l2_sliced_vbi_format sliced;u8 raw_data[200];};};struct v4l2_pix_format{u32 width; // 帧宽,单位像素u32 height; // 帧高,单位像素u32 pixelformat; // 帧格式enum v4l2_field field;u32 bytesperline;u32 sizeimage;enum v4l2_colorspace colorspace;u32 PRiv;};

5、查看视频的帧率int ioctl(int fd, int request, struct v4l2_streamparm parm* argp);struct v4l2_streamparm parm;parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;其中VIDIOC_G_PARM是用取帧率的,VIDIOC_S_PARM是用来设定帧率6、定制ioctl函数在内核目录下找到kernel/include/linux/videodev2.h头文件,你可查看所有的io控制的命令/* *Experimental, third param 0--video, 1--tracking*/#define VIDIOC_POCCESS_NOTIFY _IOW('V', 99, int) //add by Henry.Wen 20131126

实例:

#ifndef CAMERA_V4L2CAMERA_H#define CAMERA_V4L2CAMERA_H#include <stdio.h>#include <stdlib.h>#include <string.h>#include <assert.h>#include <getopt.h>             /* getopt_long() */#include <fcntl.h>              /* low-level i/o */#include <unistd.h>#include <errno.h>#include <malloc.h>#include <sys/stat.h>#include <sys/types.h>#include <sys/time.h>#include <sys/mman.h>#include <sys/ioctl.h>#include <asm/types.h>          /* for videodev2.h */#include <linux/videodev2.h>#define CONFIG_CAMERA_UVC_INVAL_FRAMECNT    5namespace v4l2{/** * return error code */enum _RET_ERROR_CODE{RET_ERROR_FAIL = -1,RET_ERROR_OK = 0,RET_ERROR_CAPTURE_NULL = -9999,RET_ERROR_CAPTURE_NAME,RET_ERROR_CAPTURE_CAPABILITY,RET_ERROR_CAPTURE_FORMAT,RET_ERROR_CAPTURE_BUFFER,RET_ERROR_CAPTURE_OUTMEMORY,RET_ERROR_CAPTURE_MMAP,RET_ERROR_CAPTURE_FORM,RET_ERROR_CAPTURE_MUMAP,RET_ERROR_CAPTURE_VIDIOC,};/** *  Name: video_format enum *  Function: Describe formats V4L2 will support */typedef enum _pFormat{UNKNOWN,YUYV,MJPEG,YV12,YU12,NV12,NV21,H264,}pFormat;/** * frame width and height infomation */typedef struct _V4l2Info{unsigned int width;unsigned int height;unsigned int stepWidth;unsigned int length;void*        buffer;}V4l2Info;/** * caputre properties */typedef struct _V4l2Capture{pFormat      format;char         name[31];//dev_nameint          fd;unsigned int rate;unsigned int quality;unsigned int brightness;V4l2Info     v4l2Info;}V4l2Capture;/** * */class V4l2Camera{public:V4l2Camera();virtual ~V4l2Camera();public:/** * get the number of cameras * * @return the number of camera */static int getNumberOfCameras();/** * initialize v4l2 device * @param capture v4l2 capture handl * @param width frame width * @param height fram height * * @return 0/other successful or failure */int InitDevice(V4l2Capture *capture, pFormat format, const char* name, unsigned int rate, unsigned int width, unsigned int height);/** * initialize v4l2 device * @param capture v4l2 capture handl * @param width frame width * @param height fram height * * @return 0/other successful or failure */int UninitDevice(V4l2Capture *capture);/** * Set v4l2 device brightness * @param capture v4l2 capture handl * @param value brightness value * * @return 0/other successful or failure */int SetBrightness(V4l2Capture *capture, unsigned int value);/** * start v4l2 device * @param fd v4l2 capture handl * * @return 0/other successful or failure */int StartDevice(int fd);/** * stop v4l2 device * @fd capture v4l2 capture handl * * @return 0/other successful or failure */int StopDevice(int fd);/** * Get frame data * @param capture v4l2 capture handl * * @return 0/other successful or failure */int GetFrame(V4l2Capture *capture);private:int InitMmap(int fd);int xioctl(int fd, int request, void *arg);unsigned int GetCameraFormat(pFormat format);int AdjustV4l2Info(unsigned int& width, unsigned int& height);int MSleep(int fd, unsigned int msec);int MatchCameraAuto(int cameraId);private:typedef struct _Buffers{void *start;size_t length;}V4l2Buffers;int                    m_stime;V4l2Buffers*           m_buffers;unsigned int           m_nBuffers;V4l2Capture*           m_capture;static int mNumberOfCameras;static int mCameraIndex[10];int mUsbCameraIvalidFrameCnt;bool m_InitDevice;};}//end namespace#endif //CAMERA_V4L2CAMERA_H

  V4l2Camera.cpp

#include "V4l2Camera.h"namespace v4l2{#define BUFFERS_COUNT  4#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))#define MEMST_VALUE(x) memset(&(x), 0, sizeof (x))const V4l2Info g_v4l2Info[] = {{160, 120}, {320, 240}, {640, 480}, {1024, 768}, {1200, 900}, {1440, 1080}, {1600, 900}, {1600, 1200}};V4l2Camera::V4l2Camera(){// TODO Auto-generated constructor stubm_capture = NULL;mUsbCameraIvalidFrameCnt = 0;m_InitDevice = false;}V4l2Camera::~V4l2Camera(){// TODO Auto-generated destructor stubif(m_capture)UninitDevice(m_capture);}int V4l2Camera::xioctl(int fd, int request, void *arg){int r;int nCount= 0;do{r = ioctl (fd, request, arg);}while (RET_ERROR_FAIL == r && (EINTR == errno) && (++nCount < 100));return r;}int V4l2Camera::mNumberOfCameras = 0;int V4l2Camera::mCameraIndex[] = {0};unsigned int V4l2Camera::GetCameraFormat(pFormat format){unsigned int ret = UNKNOWN;switch(format){case YUYV:ret = V4L2_PIX_FMT_YUYV;break;case MJPEG:ret = V4L2_PIX_FMT_MJPEG;break;case YV12:ret = V4L2_PIX_FMT_YVU420;break;case YU12:ret = V4L2_PIX_FMT_YUV420;break;case NV12:ret = V4L2_PIX_FMT_NV12;break;case NV21:ret = V4L2_PIX_FMT_NV21;break;case H264:ret = V4L2_PIX_FMT_MPEG;break;default:break;}return ret;}int V4l2Camera::InitMmap(int fd){int ret = RET_ERROR_OK;struct v4l2_requestbuffers req;req.count = BUFFERS_COUNT;req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;req.memory = V4L2_MEMORY_MMAP;if (RET_ERROR_FAIL == xioctl (fd, VIDIOC_REQBUFS, &req) || req.count < 2){return RET_ERROR_CAPTURE_BUFFER;}m_buffers = (V4l2Buffers*)calloc(req.count, sizeof(V4l2Buffers));if (!m_buffers){return RET_ERROR_CAPTURE_OUTMEMORY;}for (m_nBuffers = 0; m_nBuffers < req.count; ++m_nBuffers){struct v4l2_buffer buf;MEMST_VALUE (buf);buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory = V4L2_MEMORY_MMAP;buf.index = m_nBuffers;if (RET_ERROR_FAIL == xioctl (fd, VIDIOC_QUERYBUF, &buf)){ret = RET_ERROR_CAPTURE_BUFFER;break;}m_buffers[m_nBuffers].length = buf.length;m_buffers[m_nBuffers].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);if (MAP_FAILED == m_buffers[m_nBuffers].start){ret = RET_ERROR_CAPTURE_MMAP;break;}}return ret;}int V4l2Camera::AdjustV4l2Info(unsigned int& width, unsigned int& height){int ret = RET_ERROR_FAIL;int index = 0;for(int nCount = ARRAY_LEN(g_v4l2Info) - 1, i = nCount; i >= 0; --i){if(width <= (g_v4l2Info[i].width + 50)){index = i;ret = RET_ERROR_OK;}else if(0 != nCount){width  = g_v4l2Info[index].width;height = g_v4l2Info[index].height;break;}}return ret;}int V4l2Camera::getNumberOfCameras(){char cam_path[20];int fd = -1, i=0;struct v4l2_capability capability;mNumberOfCameras = 0;memset(mCameraIndex,0x00,sizeof(mCameraIndex));for (i = 0; i < 10; ++i){memset(cam_path,0x00,20);sprintf(cam_path, "/dev/video%d",i);fd = open(cam_path, O_RDONLY);if (fd < 0)continue;memset(&capability, 0, sizeof(struct v4l2_capability));if (ioctl(fd, VIDIOC_QUERYCAP, &capability) < 0){//LOGE("Video device(%s): query capability not supported./n", cam_path);goto loop_continue;}if ((capability.capabilities& (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING))!= (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING)){}else{mCameraIndex[mNumberOfCameras] = i;mNumberOfCameras++;}loop_continue:if (fd > 0){close(fd);fd = -1;}continue;}return mNumberOfCameras;}int V4l2Camera::MatchCameraAuto(int cameraId){if (mNumberOfCameras <= 0 || mNumberOfCameras > 10 || cameraId < 0){return -1;}// search for camera ID normallyfor (int i = 0; i < mNumberOfCameras; ++i){if (cameraId == mCameraIndex[i]){return cameraId;}}if (mNumberOfCameras == 1){return mCameraIndex[0];}return cameraId > mCameraIndex[mNumberOfCameras -1] ? mCameraIndex[mNumberOfCameras -1] : mCameraIndex[0];}int V4l2Camera::InitDevice(V4l2Capture *capture, pFormat format, const char* name, unsigned int rate, unsigned int width, unsigned int height){// TODO Auto-generated function stubstruct stat st;int fd = 0, nRealCameraNameLen = 0, nMinCameraNameLen = 0;int ret = RET_ERROR_OK;char szcameraID[4], szCameraName[20];int cameraId = 0;struct v4l2_capability cap;struct v4l2_cropcap cropcap;struct v4l2_crop crop;if(NULL == capture || NULL == name || 0 == rate || 0 == width || 0 == height) {ret = RET_ERROR_CAPTURE_NULL;goto InitDeviceFAILED;}if ((nRealCameraNameLen = strlen(name)) < (nMinCameraNameLen =strlen("/dev/video0"))) {ret = RET_ERROR_CAPTURE_NULL;goto InitDeviceFAILED;}// Get camera IDmemset(szcameraID,0x00,4);for (int i=0;i<3;i++) {if (nRealCameraNameLen >= (nMinCameraNameLen + i))szcameraID[i] = name[nMinCameraNameLen - 1 + i];}cameraId = atoi(szcameraID);mNumberOfCameras = 0;memset(mCameraIndex, 0x00, sizeof(mCameraIndex));if (0 == getNumberOfCameras()) {//LOGE("There is NO camera!");ret = RET_ERROR_CAPTURE_NAME;goto InitDeviceFAILED;}if (-1 == (cameraId = MatchCameraAuto(cameraId))) {//LOGE("There is NO camera!");ret = RET_ERROR_CAPTURE_NAME;goto InitDeviceFAILED;}memset(szCameraName, 0x00, 20);sprintf(szCameraName, "/dev/video%d", cameraId);//LOGI("camera name is %s.", name);//if ((RET_ERROR_FAIL == stat (szCameraName, &st)) || (!S_ISCHR (st.st_mode))|| (RET_ERROR_FAIL == (fd = open(szCameraName, O_RDWR | O_NONBLOCK, 0)))){ret = RET_ERROR_CAPTURE_NAME;goto InitDeviceFAILED;}if (RET_ERROR_FAIL == xioctl(fd, VIDIOC_QUERYCAP, &cap) || !(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)|| !(cap.capabilities & V4L2_CAP_STREAMING)){ret = RET_ERROR_CAPTURE_CAPABILITY;goto InitDeviceFAILED;}MEMST_VALUE(cropcap);cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;if(RET_ERROR_OK == xioctl (fd, VIDIOC_CROPCAP, &cropcap)){crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;crop.c = cropcap.defrect; /* reset to default */xioctl(fd, VIDIOC_S_CROP, &crop);}struct v4l2_format fmt;MEMST_VALUE (fmt);ret = GetCameraFormat(format);if(UNKNOWN == ret) {return RET_ERROR_CAPTURE_FORMAT;goto InitDeviceFAILED;}if(RET_ERROR_OK != AdjustV4l2Info(width, height)){ret = RET_ERROR_CAPTURE_FORM;goto InitDeviceFAILED;}//SetBrightness(capture, capture->brightness);fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;fmt.fmt.pix.width       = width;fmt.fmt.pix.height      = height;fmt.fmt.pix.pixelformat = ret;fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;printf("%s(%d) pixel format is %d/n", __FUNCTION__,__LINE__,ret);if (RET_ERROR_FAIL == xioctl (fd, VIDIOC_S_FMT, &fmt)) {ret = RET_ERROR_CAPTURE_FORMAT;goto InitDeviceFAILED;}if(RET_ERROR_OK != (ret = InitMmap(fd)) ) {// || RET_ERROR_OK != (ret = SetBrightness(capture, capture->brightness)))goto InitDeviceFAILED;}// set video frame ratestruct v4l2_streamparm parm;parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;if (RET_ERROR_OK != ioctl(fd, VIDIOC_G_PARM, &parm)) {//LOGI("VIDIOC_G_PARM fail....");}parm.parm.capture.timeperframe.numerator = 1;parm.parm.capture.timeperframe.denominator = rate;if (RET_ERROR_OK != ioctl(fd, VIDIOC_S_PARM, &parm)) {//LOGI("VIDIOC_S_PARM  Fail....");}//check setting of frame ratememset(&parm, 0x00, sizeof(v4l2_streamparm));parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;ret = ioctl(fd, VIDIOC_G_PARM, &parm);if (ret != RET_ERROR_OK) {//LOGI("VIDIOC_G_PARM fail....");}capture->fd = fd;capture->v4l2Info.width = fmt.fmt.pix.width;capture->v4l2Info.height = fmt.fmt.pix.height;capture->format = format;capture->rate = rate;capture->v4l2Info.length = fmt.fmt.pix.sizeimage;capture->v4l2Info.stepWidth = fmt.fmt.pix.bytesperline;capture->v4l2Info.buffer = malloc(fmt.fmt.pix.sizeimage);strncpy(capture->name, name, sizeof(capture->name));m_stime = 1000 / rate;m_capture = capture;m_InitDevice = true;return ret;InitDeviceFAILED:if (fd >= 0){close(fd);fd = -1;}return ret;}int V4l2Camera::UninitDevice(V4l2Capture *capture){// TODO Auto-generated function stubprintf("%s(%d)...[BEGIN]/n", __FUNCTION__, __LINE__);int ret = RET_ERROR_OK;if (!m_InitDevice) {return ret;} else {m_InitDevice = false;}if (m_buffers) {for (unsigned int i = 0; i < m_nBuffers; ++i) {printf("%s(%d) munmap() i = %d/n", __FUNCTION__, __LINE__, i);if (RET_ERROR_FAIL == munmap(m_buffers[i].start, m_buffers[i].length)) {ret = RET_ERROR_CAPTURE_MUMAP;break;}}if (RET_ERROR_OK == ret) {printf("%s(%d) free(m_buffers)/n", __FUNCTION__, __LINE__);free(m_buffers);}m_buffers = NULL;if (capture) {if (capture->v4l2Info.buffer) {printf("%s(%d) free(capture->v4l2Info.buffer)/n", __FUNCTION__,__LINE__);free(capture->v4l2Info.buffer);capture->v4l2Info.buffer = NULL;}if (capture->fd >= 0) {printf("%s(%d) close(capture->fd)/n", __FUNCTION__, __LINE__);ret = close(capture->fd);}}}printf("%s(%d)...[END]/n", __FUNCTION__, __LINE__);return ret;}int V4l2Camera::SetBrightness(V4l2Capture *capture, unsigned int value){// TODO Auto-generated function stubif(!capture || value > 10000)return RET_ERROR_FAIL;struct v4l2_control control;control.id = V4L2_CID_BRIGHTNESS;control.value = 255;if(RET_ERROR_FAIL == xioctl(capture->fd, VIDIOC_S_CTRL, &control)){return RET_ERROR_FAIL;}capture->brightness = control.value;return RET_ERROR_OK;}int V4l2Camera::StartDevice(int fd){// TODO Auto-generated function stubif(fd < 0)return RET_ERROR_FAIL;int ret = RET_ERROR_OK;for (unsigned int i = 0; i < m_nBuffers; ++i){struct v4l2_buffer buf;MEMST_VALUE(buf);buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory      = V4L2_MEMORY_MMAP;buf.index       = i;if (RET_ERROR_FAIL == xioctl(fd, VIDIOC_QBUF, &buf)){ret = RET_ERROR_CAPTURE_VIDIOC;break;}}enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;if (RET_ERROR_FAIL == xioctl(fd, VIDIOC_STREAMON, &type))ret = RET_ERROR_CAPTURE_VIDIOC;return ret;}int V4l2Camera::StopDevice(int fd){// TODO Auto-generated function stubenum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;if (RET_ERROR_FAIL == xioctl(fd, VIDIOC_STREAMOFF, &type)){return RET_ERROR_FAIL;}return 0;}int V4l2Camera::MSleep(int fd, unsigned int msec){fd_set fds;FD_ZERO (&fds);FD_SET (fd, &fds);struct timeval tv;tv.tv_sec = msec;tv.tv_usec = 0;return select (fd + 1, &fds, NULL, NULL, &tv);}int V4l2Camera::GetFrame(V4l2Capture *capture){// TODO Auto-generated function stubif(!capture)return RET_ERROR_FAIL;int fd = capture->fd;if(RET_ERROR_FAIL == MSleep(capture->fd, m_stime))return RET_ERROR_FAIL;struct v4l2_buffer buf;MEMST_VALUE(buf);buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory = V4L2_MEMORY_MMAP;buf.reserved = 0;// Skip the first CONFIG_CAMERA_UVC_INVAL_FRAMECNT video frames// because they are possibly invalidif (mUsbCameraIvalidFrameCnt< CONFIG_CAMERA_UVC_INVAL_FRAMECNT) {mUsbCameraIvalidFrameCnt++;if(xioctl(fd, VIDIOC_DQBUF, &buf) >= 0) {xioctl(fd, VIDIOC_QBUF, &buf);}return RET_ERROR_OK;}if(RET_ERROR_FAIL == xioctl(fd, VIDIOC_DQBUF, &buf) || buf.index >=  m_nBuffers){return RET_ERROR_FAIL;}memcpy(capture->v4l2Info.buffer, m_buffers[buf.index].start, buf.bytesused);if(RET_ERROR_FAIL == xioctl(fd, VIDIOC_QBUF, &buf))return RET_ERROR_FAIL;return RET_ERROR_OK;}}//end namespace

  


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表