📄 video.c
字号:
/* * video.c * * ============================================================================ * Copyright (c) Texas Instruments Inc 2005 * * Use of this software is controlled by the terms and conditions found in the * license agreement under which this software has been supplied or provided. * ============================================================================ *//* Standard Linux headers */#include <stdio.h>#include <fcntl.h>#include <errno.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <pthread.h>#include <sys/mman.h>#include <sys/ioctl.h>#include <asm/types.h>#include <linux/videodev2.h>/* Davinci specific kernel headers */#include <media/davinci_vpfe.h>#include <media/tvp5146.h>/* Codec Engine headers */#include <xdc/std.h>#include <ti/sdo/ce/Engine.h>#include <ti/sdo/ce/osal/Memory.h>#include <ti/sdo/ce/video/videnc.h>/* Demo headers */#include <rendezvous.h>#include <fifoutil.h>#include "encode.h"#include "video.h"#include "display.h"#include "writer.h"/* Macro for clearing structures */#define CLEAR(x) memset (&(x), 0, sizeof (x))/* The levels of initialization */#define INFIFODISPLAYOPENED 0x1#define OUTFIFODISPLAYOPENED 0x2#define DISPLAYTHREADCREATED 0x4#define INFIFOWRITEROPENED 0x8#define OUTFIFOWRITEROPENED 0x10#define WRITERTHREADCREATED 0x20#define CAPTUREDEVICEINITIALIZED 0x40#define ENGINEOPENED 0x80#define VIDEOENCODERCREATED 0x100#define ENCODEDBUFFERSALLOCATED 0x200/* Black color in UYVY format */#define UYVY_BLACK 0x10801080/* Triple buffering for the capture driver */#define NUM_BUFS 3/* Number of buffers for the writer thread */#define IO_BUFFERS 2/* Describes a capture frame buffer */typedef struct VideoBuffer { void *start; size_t length;} VideoBuffer;char *videoEncodeAlgNames[NUM_VIDEO_ENCODERS] = { "mpeg4enc", "h264enc"};/* Local function prototypes */static int videoEncodeAlgCreate(Engine_Handle hEngine, VIDENC_Handle *hEncodePtr, VideoEncoder videoEncoder, int width, int height, int bitrate);static int encodeVideoBuffer(VIDENC_Handle hEncode, char *inBuf, int inBufSize, char *outBuf, int *outBufSize);static int initCaptureDevice(VideoBuffer **vidBufsPtr, int *numVidBufsPtr, int svideoInput, int captureWidth, int captureHeight);static void cleanupCaptureDevice(int fd, VideoBuffer *vidBufs, int numVidBufs);/****************************************************************************** * videoEncodeAlgCreate ******************************************************************************/static int videoEncodeAlgCreate(Engine_Handle hEngine, VIDENC_Handle *hEncodePtr, VideoEncoder videoEncoder, int width, int height, int bitrate){ VIDENC_DynamicParams dynamicParams; VIDENC_Status encStatus; VIDENC_Params params; XDAS_Int32 status; char *algName; VIDENC_Handle hEncode; algName = videoEncodeAlgNames[videoEncoder]; params.size = sizeof(VIDENC_Params); params.encodingPreset = XDM_DEFAULT; params.rateControlPreset = bitrate < 0 ? IVIDEO_NONE : IVIDEO_LOW_DELAY; params.maxHeight = D1_HEIGHT; params.maxWidth = D1_WIDTH; params.maxFrameRate = gblGetYFactor() == NTSCSTD ? 30000 : 25000; params.maxBitRate = bitrate < 0 ? 0 : bitrate; params.dataEndianness = XDM_BYTE; params.maxInterFrameInterval = 0; params.inputChromaFormat = XDM_YUV_422ILE; params.inputContentType = IVIDEO_PROGRESSIVE; /* Create video encoder instance */ hEncode = VIDENC_create(hEngine, algName, ¶ms); if (hEncode == NULL) { ERR("Failed to open video encode algorithm\n"); return FAILURE; } dynamicParams.size = sizeof(VIDENC_DynamicParams); dynamicParams.inputHeight = height; dynamicParams.inputWidth = width; dynamicParams.targetBitRate = bitrate < 0 ? 0 : bitrate; dynamicParams.intraFrameInterval = 30; dynamicParams.generateHeader = XDM_ENCODE_AU; dynamicParams.captureWidth = 0; dynamicParams.forceIFrame = 0; if (gblGetYFactor() == NTSCSTD) { dynamicParams.targetFrameRate = 30000; dynamicParams.refFrameRate = 30000; } else { dynamicParams.targetFrameRate = 25000; dynamicParams.refFrameRate = 25000; } /* Set video encoder dynamic parameters */ encStatus.size = sizeof(VIDENC_Status); status = VIDENC_control(hEncode, XDM_SETPARAMS, &dynamicParams, &encStatus); if (status != VIDENC_EOK) { ERR("XDM_SETPARAMS failed, status=%ld\n", status); return FAILURE; } *hEncodePtr = hEncode; return SUCCESS;}/****************************************************************************** * encodeVideoBuffer ******************************************************************************/static int encodeVideoBuffer(VIDENC_Handle hEncode, char *inBuf, int inBufSize, char *outBuf, int *outBufSize){ XDM_BufDesc inBufDesc; XDM_BufDesc outBufDesc; XDAS_Int32 inBufSizeArray[1]; XDAS_Int32 outBufSizeArray[1]; XDAS_Int32 status; VIDENC_InArgs inArgs; VIDENC_OutArgs outArgs; inBufSizeArray[0] = inBufSize; outBufSizeArray[0] = D1_FRAME_SIZE; inBufDesc.numBufs = 1; inBufDesc.bufSizes = inBufSizeArray; inBufDesc.bufs = (XDAS_Int8 **) &inBuf; outBufDesc.numBufs = 1; outBufDesc.bufSizes = outBufSizeArray; outBufDesc.bufs = (XDAS_Int8 **) &outBuf; inArgs.size = sizeof(VIDENC_InArgs); outArgs.size = sizeof(VIDENC_OutArgs); /* Encode video buffer */ status = VIDENC_process(hEncode, &inBufDesc, &outBufDesc, &inArgs, &outArgs); if (status != VIDENC_EOK) { ERR("VIDENC_process() failed with a fatal error (%ld ext: %#lx\n", status, outArgs.extendedError); return FAILURE; } *outBufSize = outArgs.bytesGenerated; return SUCCESS;}/****************************************************************************** * initCaptureDevice ******************************************************************************/static int initCaptureDevice(VideoBuffer **vidBufsPtr, int *numVidBufsPtr, int svideoInput, int captureWidth, int captureHeight){ struct v4l2_requestbuffers req; struct v4l2_capability cap; struct v4l2_cropcap cropCap; struct v4l2_crop crop; struct v4l2_format fmt; struct v4l2_buffer buf; enum v4l2_buf_type type; v4l2_std_id std; int input; int fd; int ret; VideoBuffer *buffers; int numBufs; DBG("captureWidth = %d, captureHeight = %d\n", captureWidth, captureHeight); /* Open video capture device */ fd = open(V4L2_DEVICE, O_RDWR | O_NONBLOCK, 0); if (fd == -1) { ERR("Cannot open %s (%s)\n", V4L2_DEVICE, strerror(errno)); return FAILURE; } /* Select the video input */ if (svideoInput == TRUE) { input = TVP5146_AMUX_SVIDEO; } else { input = TVP5146_AMUX_COMPOSITE; } if (ioctl(fd, VIDIOC_S_INPUT, &input) == -1) { ERR("Failed to set video input to %d\n", input); return FAILURE; } DBG("Set the capture input to id %d\n", input); /* Query for capture device capabilities */ if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1) { if (errno == EINVAL) { ERR("%s is no V4L2 device\n", V4L2_DEVICE); return FAILURE; } ERR("Failed VIDIOC_QUERYCAP on %s (%s)\n", V4L2_DEVICE, strerror(errno)); return FAILURE; } if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { ERR("%s is no video capture device\n", V4L2_DEVICE); return FAILURE; } if (!(cap.capabilities & V4L2_CAP_STREAMING)) { ERR("%s does not support streaming i/o\n", V4L2_DEVICE); return FAILURE; } cropCap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(fd, VIDIOC_CROPCAP, &cropCap) == -1) { ERR("VIDIOC_CROPCAP failed %d, %s\n", errno, strerror(errno)); return FAILURE; } /* Auto detect PAL or NTSC using the capture driver as sanity check */ std = VPFE_STD_AUTO; if(ioctl(fd, VIDIOC_S_STD, &std) == -1) { ERR("VIDIOC_S_STD (auto) failed on %s (%s)\n", V4L2_DEVICE, strerror(errno)); return FAILURE; } DBG("Checking video standard\n"); do { ret = ioctl(fd, VIDIOC_QUERYSTD, &std); } while (ret == -1 && errno == EAGAIN); if (ret == -1) { ERR("VIDIOC_QUERYSTD failed on %s (%s)\n", V4L2_DEVICE, strerror(errno)); return FAILURE; } switch (std) { case V4L2_STD_NTSC: DBG("NTSC camera detected\n"); if (gblGetYFactor() == PALSTD) { ERR("NTSC camera connected but PAL selected.\n"); return FAILURE; } break; case V4L2_STD_PAL: DBG("PAL camera detected\n"); if (gblGetYFactor() == NTSCSTD) { ERR("PAL camera connected but NTSC selected.\n"); return FAILURE; } break; default: ERR("Camera (%s) using unsupported video standard\n", V4L2_DEVICE); return FAILURE; } /* Use either NTSC or PAL depending on display kernel parameter */ std = gblGetYFactor() == NTSCSTD ? V4L2_STD_NTSC : V4L2_STD_PAL; if(ioctl(fd, VIDIOC_S_STD, &std) == -1) { ERR("VIDIOC_S_STD failed on %s (%s)\n", V4L2_DEVICE, strerror(errno)); return FAILURE; } /* Set the video capture image format */ CLEAR(fmt); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = D1_WIDTH; fmt.fmt.pix.height = D1_HEIGHT; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; DBG("Setting capture video format\n"); /* Set the video capture format */ if (ioctl(fd, VIDIOC_S_FMT, &fmt) == -1) { ERR("VIDIOC_S_FMT failed on %s (%s)\n", V4L2_DEVICE, strerror(errno)); return FAILURE; } crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; crop.c.left = D1_WIDTH / 2 - captureWidth / 2; crop.c.top = D1_HEIGHT / 2 - captureHeight / 2; crop.c.width = captureWidth; crop.c.height = captureHeight; DBG("Setting capture cropping (%dx%d)\n", crop.c.width, crop.c.height); /* Crop the image depending on requested image size */ if (ioctl(fd, VIDIOC_S_CROP, &crop) == -1) { ERR("VIDIOC_S_CROP failed %d, %s\n", errno, strerror(errno)); return FAILURE; } printf("Capturing %dx%d video (cropped to %dx%d)\n", fmt.fmt.pix.width, fmt.fmt.pix.height, crop.c.width, crop.c.height); CLEAR(req); req.count = NUM_BUFS; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; /* Allocate buffers in the capture device driver */ if (ioctl(fd, VIDIOC_REQBUFS, &req) == -1) { ERR("VIDIOC_REQBUFS failed on %s (%s)\n", V4L2_DEVICE, strerror(errno)); return FAILURE; } DBG("%d capture buffers were successfully allocated.\n", req.count); if (req.count < NUM_BUFS) { ERR("Insufficient buffer memory on %s\n", V4L2_DEVICE); return FAILURE; } buffers = calloc(req.count, sizeof(*buffers)); if (!buffers) { ERR("Failed to allocate memory for capture buffer structs.\n"); return FAILURE; } /* Map the allocated buffers to user space */ for (numBufs = 0; numBufs < req.count; numBufs++) { CLEAR(buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = numBufs; if (ioctl(fd, VIDIOC_QUERYBUF, &buf) == -1) { ERR("Failed VIDIOC_QUERYBUF on %s (%s)\n", V4L2_DEVICE,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -