📄 video.c
字号:
strerror(errno)); return FAILURE; } buffers[numBufs].length = buf.length; buffers[numBufs].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset); if (buffers[numBufs].start == MAP_FAILED) { ERR("Failed to mmap buffer on %s (%s)\n", V4L2_DEVICE, strerror(errno)); return FAILURE; } DBG("Capture buffer %d mapped to address %#lx\n", numBufs, (unsigned long) buffers[numBufs].start); if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) { ERR("VIODIOC_QBUF failed on %s (%s)\n", V4L2_DEVICE, strerror(errno)); return FAILURE; } } /* Start the video streaming */ type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(fd, VIDIOC_STREAMON, &type) == -1) { ERR("VIDIOC_STREAMON failed on %s (%s)\n", V4L2_DEVICE, strerror(errno)); return FAILURE; } *vidBufsPtr = buffers; *numVidBufsPtr = numBufs; return fd;}/****************************************************************************** * cleanupCaptureDevice ******************************************************************************/static void cleanupCaptureDevice(int fd, VideoBuffer *vidBufs, int numVidBufs){ enum v4l2_buf_type type; unsigned int i; /* Shut off the video capture */ type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(fd, VIDIOC_STREAMOFF, &type) == -1) { ERR("VIDIOC_STREAMOFF failed (%s)\n", strerror(errno)); } if (close(fd) == -1) { ERR("Failed to close capture device (%s)\n", strerror(errno)); } for (i = 0; i < numVidBufs; ++i) { if (munmap(vidBufs[i].start, vidBufs[i].length) == -1) { ERR("Failed to unmap capture buffer %d\n", i); } } free(vidBufs);}/****************************************************************************** * videoThrFxn ******************************************************************************/void *videoThrFxn(void *arg){ BufferElement flush = { DISPLAY_FLUSH }; OutBufferElement outFlush = { WRITER_FLUSH }; Engine_Handle hEngine = NULL; unsigned int initMask = 0; VideoEnv *envp = (VideoEnv *) arg; void *status = THREAD_SUCCESS; int inputFd = 0; char *encodedBuffers[IO_BUFFERS]; pthread_t displayThread; pthread_t writerThread; struct v4l2_buffer v4l2buf; struct sched_param schedParam; DisplayEnv displayEnv; WriterEnv writerEnv; int imageSize; int bufIdx; unsigned int numVidBufs; VideoBuffer *vidBufs; VIDENC_Handle hEncode; pthread_attr_t attr; OutBufferElement oe; BufferElement e; void *ret; imageSize = envp->imageWidth * envp->imageHeight * SCREEN_BPP / 8; /* Open the display input fifo */ if (FifoUtil_open(&displayEnv.inFifo, sizeof(BufferElement)) == FIFOUTIL_FAILURE) { ERR("Failed to open input fifo\n"); cleanup(THREAD_FAILURE); } initMask |= INFIFODISPLAYOPENED; /* Open the display output fifo */ if (FifoUtil_open(&displayEnv.outFifo, sizeof(BufferElement)) == FIFOUTIL_FAILURE) { ERR("Failed to open output fifo\n"); cleanup(THREAD_FAILURE); } initMask |= OUTFIFODISPLAYOPENED; /* Initialize the priming synchronization mutex */ pthread_mutex_init(&displayEnv.prime, NULL); /* Initialize the thread attributes */ if (pthread_attr_init(&attr)) { ERR("Failed to initialize thread attrs\n"); cleanup(THREAD_FAILURE); } /* Force the thread to use custom scheduling attributes */ if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) { ERR("Failed to set schedule inheritance attribute\n"); cleanup(THREAD_FAILURE); } /* Set the thread to be fifo real time scheduled */ if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO)) { ERR("Failed to set FIFO scheduling policy\n"); cleanup(THREAD_FAILURE); } /* Set the thread priority */ schedParam.sched_priority = sched_get_priority_max(SCHED_FIFO); if (pthread_attr_setschedparam(&attr, &schedParam)) { ERR("Failed to set scheduler parameters\n"); cleanup(THREAD_FAILURE); } /* Create the display thread */ displayEnv.hRendezvous = envp->hRendezvous; if (pthread_create(&displayThread, &attr, displayThrFxn, &displayEnv)) { ERR("Failed to create display thread\n"); cleanup(THREAD_FAILURE); } initMask |= DISPLAYTHREADCREATED; DBG("Display thread created\n"); /* Open the writer input fifo */ if (FifoUtil_open(&writerEnv.inFifo, sizeof(OutBufferElement)) == FIFOUTIL_FAILURE) { ERR("Failed to open input writer fifo\n"); cleanup(THREAD_FAILURE); } initMask |= INFIFOWRITEROPENED; /* Open the writer output fifo */ if (FifoUtil_open(&writerEnv.outFifo, sizeof(OutBufferElement)) == FIFOUTIL_FAILURE) { ERR("Failed to open output writer fifo\n"); cleanup(THREAD_FAILURE); } initMask |= OUTFIFOWRITEROPENED; /* Set the thread priority */ schedParam.sched_priority = sched_get_priority_max(SCHED_FIFO) - 1; if (pthread_attr_setschedparam(&attr, &schedParam)) { ERR("Failed to set scheduler parameters\n"); cleanup(THREAD_FAILURE); } /* Create the writer thread */ writerEnv.hRendezvous = envp->hRendezvous; writerEnv.videoFile = envp->videoFile; if (pthread_create(&writerThread, &attr, writerThrFxn, &writerEnv)) { ERR("Failed to create writer thread\n"); cleanup(THREAD_FAILURE); } initMask |= WRITERTHREADCREATED; DBG("Writer thread created\n"); /* Initialize the video capture device */ inputFd = initCaptureDevice(&vidBufs, &numVidBufs, envp->svideoInput, envp->imageWidth, envp->imageHeight); if (inputFd == FAILURE) { cleanup(THREAD_FAILURE); } DBG("Video capture initialized and started\n"); initMask |= CAPTUREDEVICEINITIALIZED; /* Reset, load, and start DSP Engine */ hEngine = Engine_open(ENGINE_NAME, NULL, NULL); if (hEngine == NULL) { ERR("Failed to open codec engine %s\n", ENGINE_NAME); cleanup(THREAD_FAILURE); } DBG("Codec Engine opened in video thread\n"); initMask |= ENGINEOPENED; /* Allocate and initialize video encoder on the engine */ if (videoEncodeAlgCreate(hEngine, &hEncode, envp->videoEncoder, envp->imageWidth, envp->imageHeight, envp->videoBitRate) == FAILURE) { cleanup(THREAD_FAILURE); } DBG("Video encoder created\n"); initMask |= VIDEOENCODERCREATED; /* Allocate buffers for encoded data and prime the writer thread */ for (bufIdx=0; bufIdx<IO_BUFFERS; bufIdx++) { encodedBuffers[bufIdx] = Memory_contigAlloc(D1_FRAME_SIZE, Memory_DEFAULTALIGNMENT); if (encodedBuffers[bufIdx] == NULL) { ERR("Failed to allocate contiguous memory block.\n"); cleanup(THREAD_FAILURE); } DBG("Contiguous buffer allocated at physical address %#lx\n", Memory_getPhysicalAddress(encodedBuffers[bufIdx])); oe.id = WRITER_PRIME; oe.encodedBuffer = encodedBuffers[bufIdx]; if (FifoUtil_put(&writerEnv.outFifo, &oe) == FIFOUTIL_FAILURE) { ERR("Failed to put buffer in output fifo\n"); cleanup(THREAD_FAILURE); } } initMask |= ENCODEDBUFFERSALLOCATED; /* Signal that initialization is done and wait for other threads */ Rendezvous_meet(envp->hRendezvous); DBG("Entering video main loop.\n"); while (!gblGetQuit()) { if (!gblGetRecord()) { usleep(PAUSE); continue; } CLEAR(v4l2buf); v4l2buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; v4l2buf.memory = V4L2_MEMORY_MMAP; /* Get a frame buffer with captured data */ if (ioctl(inputFd, VIDIOC_DQBUF, &v4l2buf) == -1) { if (errno == EAGAIN) { continue; } ERR("VIDIOC_DQBUF failed (%s)\n", strerror(errno)); breakLoop(THREAD_FAILURE); } e.frameBuffer = vidBufs[v4l2buf.index].start; e.width = envp->imageWidth; e.height = envp->imageHeight; /* Display raw frame while encoding it */ if (FifoUtil_put(&displayEnv.outFifo, &e) == FIFOUTIL_FAILURE) { ERR("Failed to put buffer in output fifo\n"); breakLoop(THREAD_FAILURE); } /* Get a buffer back from the writer thread */ if (FifoUtil_get(&writerEnv.inFifo, &oe) == FIFOUTIL_FAILURE) { ERR("Failed to put buffer in output fifo\n"); breakLoop(THREAD_FAILURE); } /* Is the writer thread flushing the pipe? */ if (oe.id == WRITER_FLUSH) { breakLoop(THREAD_SUCCESS); } /* Encode the captured video frame */ if (encodeVideoBuffer(hEncode, vidBufs[v4l2buf.index].start, imageSize, oe.encodedBuffer, &oe.frameSize) == FAILURE) { breakLoop(THREAD_FAILURE); } /* Send the encoded buffer to be written to the filesystem */ if (FifoUtil_put(&writerEnv.outFifo, &oe) == FIFOUTIL_FAILURE) { ERR("Failed to put buffer in output fifo\n"); breakLoop(THREAD_FAILURE); } /* Receive a buffer with a displayed frame from the display thread */ if (FifoUtil_get(&displayEnv.inFifo, &e) == FIFOUTIL_FAILURE) { breakLoop(THREAD_FAILURE); } /* Is the display thread flushing the pipe? */ if (e.id == DISPLAY_FLUSH) { breakLoop(THREAD_SUCCESS); } /* Issue captured frame buffer back to device driver */ if (ioctl(inputFd, VIDIOC_QBUF, &v4l2buf) == -1) { ERR("VIDIOC_QBUF failed (%s)\n", strerror(errno)); breakLoop(THREAD_FAILURE); } /* Increment statistics for OSD display */ gblIncVideoBytesEncoded(oe.frameSize); }cleanup: /* Make sure the other threads aren't waiting for init to complete */ Rendezvous_force(envp->hRendezvous); /* Make sure the video thread isn't stuck in FifoUtil_get() */ FifoUtil_put(&displayEnv.outFifo, &flush); /* Make sure the writer thread isn't stuck in FifoUtil_get() */ FifoUtil_put(&writerEnv.outFifo, &outFlush); if (initMask & VIDEOENCODERCREATED) { VIDENC_delete(hEncode); } if (initMask & ENGINEOPENED) { Engine_close(hEngine); } if (initMask & CAPTUREDEVICEINITIALIZED) { cleanupCaptureDevice(inputFd, vidBufs, numVidBufs); } if (initMask & WRITERTHREADCREATED) { if (pthread_join(writerThread, &ret) == 0) { status = ret; } } if (initMask & OUTFIFOWRITEROPENED) { FifoUtil_close(&writerEnv.outFifo); } if (initMask & INFIFOWRITEROPENED) { FifoUtil_close(&writerEnv.inFifo); } if (initMask & DISPLAYTHREADCREATED) { if (pthread_join(displayThread, &ret) == 0) { status = ret; } } if (initMask & OUTFIFODISPLAYOPENED) { FifoUtil_close(&displayEnv.outFifo); } if (initMask & INFIFODISPLAYOPENED) { FifoUtil_close(&displayEnv.inFifo); } /* Clean up the video thread */ if (initMask & ENCODEDBUFFERSALLOCATED) { for (bufIdx=0; bufIdx<IO_BUFFERS; bufIdx++) { Memory_contigFree(encodedBuffers[bufIdx], D1_FRAME_SIZE); } } return status;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -