📄 video_input.c
字号:
/* * video_input.c *//* Standard Linux headers */#include <stdio.h> // always include stdio.h#include <stdlib.h> // always include stdlib.h#include <string.h> // defines memset and memcpy methods#include <fcntl.h> // defines open, read, write methods#include <unistd.h> // defines close and sleep methods#include <sys/mman.h> // defines mmap method#include <sys/ioctl.h> // defines ioctl method#include <asm/types.h> // standard typedefs required by v4l2 header#include <linux/videodev2.h> // v4l2 driver definitions/* Application header files */#include "video_input.h"#include "debug.h" // DBG and ERR macros/* Macro for clearing structures */#define CLEAR(x) memset (&(x), 0, sizeof (x))/****************************************************************************** * video_input_setup ******************************************************************************//* input parameters: *//* int *fdByRef -- file descriptor passed by reference. Used to *//* return the file descriptor of newly opened device *//* char *device -- device node for V4L2 capture driver *//* VideoBuffer **vidBufsPtrByRef -- pointer to VideoBuffer structure *//* that is passed by reference. *//* (VideoBuffer struct def in video_capture.h ) *//* used to return the location of an array of type *//* VideoBuffer describing buffers allocated by the *//* capture device. *//* int *numVidBufsByRef -- used as both an input and output value: *//* on input, *numVidBufsByRef is the requested # bufs *//* on output it is filled with the actual # alloc'd *//* int *captureWidthByRef -- used as both an input and output value: *//* on input: requested capture frame width *//* on output: granted capture frame width *//* int *captureHeightByRef -- identical to captureWidthByRef, *//* but for height *//* *//* *//* return value: *//* int -- VIN_SUCCESS or VIN_FAILURE as defined in video_input.h *//* *//******************************************************************************/int video_input_setup(int *fdByRef, char *device, VideoBuffer **vidBufsPtrByRef, int *numVidBufsByRef, int *captureWidthByRef, int *captureHeightByRef){ struct v4l2_requestbuffers req; // buffer request structure enum v4l2_buf_type type; // buffer type struct v4l2_buffer buf; // V4L2 buffer descriptor VideoBuffer *buffersPtr; // ptr to array of buffers int numBufs; // number buffers pointed to // by buffersPtr struct v4l2_format fmt; // buffer format v4l2_std_id std; // analog video input standard struct v4l2_cropcap cropCap; // input cropping capability int captureFd; // video capture file descriptor /* Define a macro to handle the (repetitive) cleanup for a failure */ #define failure_procedure() close(captureFd); \ *fdByRef = -1; \ *vidBufsPtrByRef = NULL; \ *numVidBufsByRef = 0; \ *captureWidthByRef = 0; \ *captureHeightByRef = 0; \ return VIN_FAILURE DBG("Initializing video capture device: %s\n", device); /* Open video capture device */ if( (captureFd = open(device, O_RDWR | O_NONBLOCK, 0)) == -1){ ERR("Cannot open %s\n", device); failure_procedure(); // macro defined at top of this function } DBG("\tVideo capture device opened with file descriptor: %d\n", captureFd); /* No cropping on input */ cropCap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(captureFd, VIDIOC_CROPCAP, &cropCap) == -1) { ERR("VIDIOC_CROPCAP failed on file descriptor %d\n", captureFd); failure_procedure(); // macro defined at top of this function } /* Set analog video input standard to either NTSC or PAL */ std = V4L2_STD_NTSC;// std = V4L2_STD_PAL; if(ioctl(captureFd, VIDIOC_S_STD, &std) == -1) { ERR("VIDIOC_S_STD failed on file descriptor %d\n", captureFd); failure_procedure(); // macro defined at top of this function } /* Set the captured buffer format to UYUV interlaced w/ given resolution */ CLEAR(fmt); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; fmt.fmt.pix.width = *captureWidthByRef; fmt.fmt.pix.height = *captureHeightByRef; /* Set the video capture format */ if (ioctl(captureFd, VIDIOC_S_FMT, &fmt) == -1) { ERR("VIDIOC_S_FMT failed on file descriptor %d\n", captureFd); failure_procedure(); // macro defined at top of this function } DBG("\tCapturing %dx%d video \n", fmt.fmt.pix.width, fmt.fmt.pix.height); /* Request the capture device allocate N memory mapped video capture */ /* buffers -- where N is specified by dereferencing numVidBufPtr */ CLEAR(req); req.count = *numVidBufsByRef; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; /* Allocate buffers in the capture device driver */ if (ioctl(captureFd, VIDIOC_REQBUFS, &req) == -1) { ERR("VIDIOC_REQBUFS failed on file descriptor %d\n", captureFd); return VIN_FAILURE; } DBG("%d capture buffers were successfully allocated.\n", req.count); /* if the driver can't allocate all buffers, it will allocate as many */ /* as it can and set req.count to this value */ if (req.count < *numVidBufsByRef) { ERR("Insufficient buffer memory on file descriptor %d\n", captureFd); failure_procedure(); // macro defined at top of this function } /* Allocate memory for the array of buffer descriptors */ buffersPtr = calloc(req.count, sizeof(*buffersPtr)); if (!buffersPtr) { ERR("Failed to allocate memory for capture buffer structs.\n"); close(captureFd); failure_procedure(); // macro defined at top of this function } /* Map the allocated buffers to user space and store their locations */ /* in the array pointed to by buffersPtr. */ for (numBufs = 0; numBufs < req.count; numBufs++) { CLEAR(buf); /* type, memory and index are inputs in the buf structure for */ /* VIDIOC_QUERYBUF ioctl, which will return the corresponding */ /* buffer length (based on format and cropping settings */ /* already specified) as well as an offset value from a */ /* driver-memory-space pointer. These values are then used to */ /* mmap the buffers into user space. */ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = numBufs; if (ioctl(captureFd, VIDIOC_QUERYBUF, &buf) == -1) { ERR("Failed VIDIOC_QUERYBUF on file descriptor %d\n", captureFd); failure_procedure(); // macro defined at top of this function } /* use buf.length and buf.m.offset returned by VIDIOC_QUERYBUF to */ /* fill in buffer descriptor array with location and size of */ /* each buffer allocated by V4L2 capture device. */ buffersPtr[numBufs].length = buf.length; buffersPtr[numBufs].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, captureFd, buf.m.offset); if (buffersPtr[numBufs].start == MAP_FAILED) { ERR("Failed to mmap buffer on file descriptor %d\n", captureFd); failure_procedure(); // macro defined at top of this function } DBG("\tCapture buffer %d, size %d mapped to address %p\n", numBufs, buf.length, buffersPtr[numBufs].start); /* Enqueue all of the allocated buffers to be available for capture */ if (ioctl(captureFd, VIDIOC_QBUF, &buf) == -1) { ERR("VIODIOC_QBUF failed on file descriptor %d\n", captureFd); failure_procedure(); // macro defined at top of this function } } /* Start the video streaming */ type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(captureFd, VIDIOC_STREAMON, &type) == -1) { ERR("VIDIOC_STREAMON failed on file descriptor %d\n", captureFd); failure_procedure(); // macro defined at top of this function } /* Return VIN_SUCCESS and the various returns by reference */ /* return the file descriptor of the newly opened device */ *fdByRef = captureFd; /* Return buffers and numBufs values through provided pointers */ *vidBufsPtrByRef = buffersPtr; *numVidBufsByRef = numBufs; /* Capture width and height may be different from requested values */ *captureWidthByRef = fmt.fmt.pix.width; *captureHeightByRef = fmt.fmt.pix.height; return VIN_SUCCESS;}/****************************************************************************** * wait_for_frame ******************************************************************************//* description: *//* used to block thread until a new frame is available in the capture *//* device. (VIDIOC_DQBUF is non-blocking, so this must be used) *//* *//* input parameters: *//* int fd -- file descriptor for the driver as returned by *//* video_input_setup *//* *//* *//* return value: *//* VIN_SUCCESS or VIN_FAILURE as defined in video_capture.h *//* *//******************************************************************************/inline int wait_for_frame(int fd){ struct timeval tv; // timeout value so fxn doesn't block forever fd_set fds; // set of file descriptors to wait on int ret; // return value FD_ZERO(&fds); // using a file descriptor set of only one FD_SET(fd, &fds); // value (fd from parameters) // (as opposed to blocking until any of a // number of file descriptors becomes avail) /* Timeout. */ tv.tv_sec = 2; // timeout after 2 seconds if no new frame tv.tv_usec = 0; // becomes available /* VIDIOC_DQBUF does not block. Select method must be used to wait for */ /* the next outgoing frame to be filled. */ ret = select(fd + 1, &fds, NULL, NULL, &tv); if (ret == -1) { ERR("Select failed for video capture device\n"); return VIN_FAILURE; } if (ret == 0) { ERR("Select timed out\n"); return VIN_FAILURE; } /* indicate successful completion of function with return value */ return VIN_SUCCESS;}/****************************************************************************** * video_input_cleanup ******************************************************************************//* input parameters: *//* int fd -- file descriptor for the driver as returned by *//* video_input_setup *//* VideoBuffer *vidBufsPtr -- pointer to an array of video buffers *//* allocated by the capture device, i.e. *//* *vidBufsPtrByRef as returned by reference from *//* video_input_setup *//* (VideoBuffer struct defined in video_capture.h ) *//* int numVidBufs -- number of video buffers pointed to by vidBufsPtr *//* *//* *//* return value: *//* int -- VIN_SUCCESS or VIN_FAILURE as defined in video_capture.h *//* *//******************************************************************************/int video_input_cleanup(int fd, VideoBuffer *vidBufsPtr, int numVidBufs){ enum v4l2_buf_type type; // video buffer type unsigned int i; // for loop index int status = VIN_SUCCESS; // return value for function /* Shut off the video capture */ type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(fd, VIDIOC_STREAMOFF, &type) == -1) { ERR("VIDIOC_STREAMOFF failed\n"); status = VIN_FAILURE; } DBG("Halted video capture stream on file descriptor %d\n", fd); /* Unmap the capture frame buffers from user space */ for (i = 0; i < numVidBufs; ++i) { if (munmap(vidBufsPtr[i].start, vidBufsPtr[i].length) == -1) { ERR("Failed to unmap capture buffer %d\n", i); status = VIN_FAILURE; } else{ DBG("\tunmapped video capture frame, size %d located at %p\n", vidBufsPtr[i].length, vidBufsPtr[i].start); } } /* Free the array itself after each buffer described by it has been freed */ free(vidBufsPtr); if (close(fd) == -1) { ERR("Failed to close capture device\n"); status = VIN_FAILURE; } DBG("\tClosed video capture device (file descriptor %d)\n", fd); return status;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -