/** Copyright 2015 Rockchip Electronics Co. LTD** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/#define MODULE_TAG "camera_source"#include <stdio.h>#include <fcntl.h>#include <unistd.h>#include <errno.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <sys/select.h>#include <sys/mman.h>#include <sys/ioctl.h>#include <linux/videodev2.h>#include "mpp_log.h"#include "mpp_mem.h"#include "camera_source.h"typedef struct CamFrame_t {void *start;size_t length;RK_S32 export_fd;RK_S32 sequence;MppBuffer buffer;} CamFrame;struct CamSource {RK_S32 fd; // Device handleRK_U32 bufcnt; // # of buffersenum v4l2_buf_type type;MppFrameFormat fmt;CamFrame fbuf[10];// frame buffers};static RK_U32 V4L2_yuv_cfg[MPP_FMT_YUV_BUTT] = {V4L2_PIX_FMT_NV12,0,V4L2_PIX_FMT_NV16,0,V4L2_PIX_FMT_YVU420,V4L2_PIX_FMT_NV21,V4L2_PIX_FMT_YUV422P,V4L2_PIX_FMT_NV61,V4L2_PIX_FMT_YUYV,V4L2_PIX_FMT_YVYU,V4L2_PIX_FMT_UYVY,V4L2_PIX_FMT_VYUY,V4L2_PIX_FMT_GREY,0,0,0,};static RK_U32 V4L2_RGB_cfg[MPP_FMT_RGB_BUTT - MPP_FRAME_FMT_RGB] = {V4L2_PIX_FMT_RGB565,0,V4L2_PIX_FMT_RGB555,0,V4L2_PIX_FMT_RGB444,0,V4L2_PIX_FMT_RGB24,V4L2_PIX_FMT_BGR24,0,0,V4L2_PIX_FMT_RGB32,V4L2_PIX_FMT_BGR32,0,0,};#define FMT_NUM_PLANES 1// Wrap ioctl() to spin on EINTRstatic RK_S32 camera_source_ioctl(RK_S32 fd, RK_S32 req, void* arg){struct timespec poll_time;RK_S32 ret;while ((ret = ioctl(fd, req, arg))) {if (ret == -1 && (EINTR != errno && EAGAIN != errno)) {// mpp_err("ret = %d, errno %d", ret, errno);break;}// 10 millisecondspoll_time.tv_sec = 0;poll_time.tv_nsec = 10000000;nanosleep(&poll_time, NULL);}return ret;}// Create a new context to capture frames from <fname>.// Returns NULL on error.CamSource *camera_source_init(const char *device, RK_U32 bufcnt, RK_U32 width, RK_U32 height, MppFrameFormat format){struct v4l2_capability cap;struct v4l2_format vfmt;struct v4l2_requestbuffers req;struct v4l2_buffer buf;enum v4l2_buf_type type;RK_U32 i;RK_U32 buf_len = 0;CamSource *ctx;ctx = mpp_calloc(CamSource, 1);if (!ctx)return NULL;ctx->bufcnt = bufcnt;ctx->fd = open(device, O_RDWR | O_CLOEXEC, 0);if (ctx->fd < 0) {mpp_err_f("Cannot open device\n");goto FAIL;}{struct v4l2_input input;input.index = 0;while (!camera_source_ioctl(ctx->fd, VIDIOC_ENUMINPUT, &input)) {mpp_log("input devices:%s\n", input.name);++input.index;}}// Determine if fd is a V4L2 Deviceif (0 != camera_source_ioctl(ctx->fd, VIDIOC_QUERYCAP, &cap)) {mpp_err_f("Not v4l2 compatible\n");goto FAIL;}if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) && !(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE)) {mpp_err_f("Capture not supported\n");goto FAIL;}if (!(cap.capabilities & V4L2_CAP_STREAMING)) {mpp_err_f("Streaming IO Not Supported\n");goto FAIL;}// Preserve original settings as set by v4l2-ctl for examplevfmt = (struct v4l2_format) {0};vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE)vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;vfmt.fmt.pix.width = width;vfmt.fmt.pix.height = height;{struct v4l2_fmtdesc fmtdesc;fmtdesc.index = 0;fmtdesc.type = vfmt.type;while (!camera_source_ioctl(ctx->fd, VIDIOC_ENUM_FMT, &fmtdesc)) {mpp_log("fmt name: [%s]\n", fmtdesc.description);mpp_log("fmt pixelformat: '%c%c%c%c', description = '%s'\n", fmtdesc.pixelformat & 0xFF,(fmtdesc.pixelformat >> 8) & 0xFF, (fmtdesc.pixelformat >> 16) & 0xFF,(fmtdesc.pixelformat >> 24) & 0xFF, fmtdesc.description);fmtdesc.index++;}}if (MPP_FRAME_FMT_IS_YUV(format)) {vfmt.fmt.pix.pixelformat = V4L2_yuv_cfg[format - MPP_FRAME_FMT_YUV];} else if (MPP_FRAME_FMT_IS_RGB(format)) {vfmt.fmt.pix.pixelformat = V4L2_RGB_cfg[format - MPP_FRAME_FMT_RGB];}if (!vfmt.fmt.pix.pixelformat)vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_NV12;type = vfmt.type;ctx->type = vfmt.type;if (-1 == camera_source_ioctl(ctx->fd, VIDIOC_S_FMT, &vfmt)) {mpp_err_f("VIDIOC_S_FMT\n");goto FAIL;}if (-1 == camera_source_ioctl(ctx->fd, VIDIOC_G_FMT, &vfmt)) {mpp_err_f("VIDIOC_G_FMT\n");goto FAIL;}mpp_log("get width %d height %d", vfmt.fmt.pix.width, vfmt.fmt.pix.height);// Request memory-mapped buffersreq = (struct v4l2_requestbuffers) {0};req.count = ctx->bufcnt;req.type = type;req.memory = V4L2_MEMORY_MMAP;if (-1 == camera_source_ioctl(ctx->fd, VIDIOC_REQBUFS, &req)) {mpp_err_f("Device does not support mmap\n");goto FAIL;}if (req.count != ctx->bufcnt) {mpp_err_f("Device buffer count mismatch\n");goto FAIL;}// mmap() the buffers into userspace memoryfor (i = 0 ; i < ctx->bufcnt; i++) {buf = (struct v4l2_buffer) {0};buf.type = type;buf.memory = V4L2_MEMORY_MMAP;buf.index = i;struct v4l2_plane planes[FMT_NUM_PLANES];buf.memory = V4L2_MEMORY_MMAP;if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type) {buf.m.planes = planes;buf.length = FMT_NUM_PLANES;}if (-1 == camera_source_ioctl(ctx->fd, VIDIOC_QUERYBUF, &buf)) {mpp_err_f("ERROR: VIDIOC_QUERYBUF\n");goto FAIL;}if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == buf.type) {// tmp_buffers[n_buffers].length = buf.m.planes[0].length;buf_len = buf.m.planes[0].length;ctx->fbuf[i].start =mmap(NULL /* start anywhere */,buf.m.planes[0].length,PROT_READ | PROT_WRITE /* required */,MAP_SHARED /* recommended */,ctx->fd, buf.m.planes[0].m.mem_offset);} else {buf_len = buf.length;ctx->fbuf[i].start =mmap(NULL /* start anywhere */,buf.length,PROT_READ | PROT_WRITE /* required */,MAP_SHARED /* recommended */,ctx->fd, buf.m.offset);}if (MAP_FAILED == ctx->fbuf[i].start) {mpp_err_f("ERROR: Failed to map device frame buffers\n");goto FAIL;}ctx->fbuf[i].length = buf_len; // record buffer length for unmapstruct v4l2_exportbuffer expbuf = (struct v4l2_exportbuffer) {0} ;// xcam_mem_clear (expbuf);expbuf.type = type;expbuf.index = i;expbuf.flags = O_CLOEXEC;if (camera_source_ioctl(ctx->fd, VIDIOC_EXPBUF, &expbuf) < 0) {mpp_err_f("get dma buf failed\n");goto FAIL;} else {mpp_log("get dma buf(%d)-fd: %d\n", i, expbuf.fd);MppBufferInfo info;memset(&info, 0, sizeof(MppBufferInfo));info.type = MPP_BUFFER_TYPE_EXT_DMA;info.fd = expbuf.fd;info.size = buf_len & 0x07ffffff;info.index = (buf_len & 0xf8000000) >> 27;mpp_buffer_import(&ctx->fbuf[i].buffer, &info);}ctx->fbuf[i].export_fd = expbuf.fd;}for (i = 0; i < ctx->bufcnt; i++ ) {struct v4l2_plane planes[FMT_NUM_PLANES];buf = (struct v4l2_buffer) {0};buf.type = type;buf.memory = V4L2_MEMORY_MMAP;buf.index = i;buf.memory = V4L2_MEMORY_MMAP;if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type) {buf.m.planes = planes;buf.length = FMT_NUM_PLANES;}if (-1 == camera_source_ioctl(ctx->fd, VIDIOC_QBUF, &buf)) {mpp_err_f("ERROR: VIDIOC_QBUF %d\n", i);goto FAIL;}}// Start capturingif (-1 == camera_source_ioctl(ctx->fd, VIDIOC_STREAMON, &type)) {mpp_err_f("ERROR: VIDIOC_STREAMON\n");goto FAIL;}//skip some frames at startfor (i = 0; i < ctx->bufcnt; i++ ) {RK_S32 idx = camera_source_get_frame(ctx);if (idx >= 0)camera_source_put_frame(ctx, idx);}return ctx;FAIL:camera_source_deinit(ctx);return NULL;}// Free a context to capture frames from <fname>.// Returns NULL on error.MPP_RET camera_source_deinit(CamSource *ctx){struct v4l2_buffer buf;enum v4l2_buf_type type;RK_U32 i;if (NULL == ctx)return MPP_OK;if (ctx->fd < 0)return MPP_OK;// Stop capturingtype = ctx->type;camera_source_ioctl(ctx->fd, VIDIOC_STREAMOFF, &type);// un-mmap() buffersfor (i = 0 ; i < ctx->bufcnt; i++) {buf = (struct v4l2_buffer) {0};buf.type = type;buf.memory = V4L2_MEMORY_MMAP;buf.index = i;camera_source_ioctl(ctx->fd, VIDIOC_QUERYBUF, &buf);if (ctx->fbuf[buf.index].buffer) {mpp_buffer_put(ctx->fbuf[buf.index].buffer);}munmap(ctx->fbuf[buf.index].start, ctx->fbuf[buf.index].length);close(ctx->fbuf[i].export_fd);}// Close v4l2 deviceclose(ctx->fd);MPP_FREE(ctx);return MPP_OK;}// Returns a pointer to a captured frame and its meta-data. NOT thread-safe.RK_S32 camera_source_get_frame(CamSource *ctx){struct v4l2_buffer buf;enum v4l2_buf_type type;type = ctx->type;buf = (struct v4l2_buffer) {0};buf.type = type;buf.memory = V4L2_MEMORY_MMAP;struct v4l2_plane planes[FMT_NUM_PLANES];if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type) {buf.m.planes = planes;buf.length = FMT_NUM_PLANES;}if (-1 == camera_source_ioctl(ctx->fd, VIDIOC_DQBUF, &buf)) {mpp_err_f("VIDIOC_DQBUF\n");return -1;}if (buf.index > ctx->bufcnt) {mpp_err_f("buffer index out of bounds\n");return -1;}if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type)buf.bytesused = buf.m.planes[0].bytesused;return buf.index;}// It's OK to capture into this framebuffer nowMPP_RET camera_source_put_frame(CamSource *ctx, RK_S32 idx){struct v4l2_buffer buf;enum v4l2_buf_type type;if (idx < 0)return MPP_OK;type = ctx->type;buf = (struct v4l2_buffer) {0};buf.type = type;buf.memory = V4L2_MEMORY_MMAP;buf.index = idx;struct v4l2_plane planes[FMT_NUM_PLANES];if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type) {buf.m.planes = planes;buf.length = FMT_NUM_PLANES;}// Tell kernel it's ok to overwrite this frameif (-1 == camera_source_ioctl(ctx->fd, VIDIOC_QBUF, &buf)) {mpp_err_f("VIDIOC_QBUF\n");return MPP_OK;}return MPP_OK;}MppBuffer camera_frame_to_buf(CamSource *ctx, RK_S32 idx){MppBuffer buf = NULL;if (idx < 0)return buf;buf = ctx->fbuf[idx].buffer;if (buf)mpp_buffer_sync_end(buf);return buf;}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。