123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412 |
- /*
- * 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 handle
- RK_U32 bufcnt; // # of buffers
- enum 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 EINTR
- static 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 milliseconds
- poll_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, 0);
- if (ctx->fd < 0) {
- mpp_err_f("Cannot open device\n");
- goto FAIL;
- }
- // Determine if fd is a V4L2 Device
- if (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 example
- vfmt = (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;
- 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 buffers
- req = (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 memory
- for (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;
- }
- ctx->fbuf[i].start = mmap(NULL, buf.length,
- PROT_READ | PROT_WRITE, MAP_SHARED,
- ctx->fd, buf.m.offset);
- 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;
- }
- struct 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);
- camera_source_deinit(ctx);
- goto FAIL;
- }
- }
- // Start capturing
- if (-1 == camera_source_ioctl(ctx->fd, VIDIOC_STREAMON, &type)) {
- mpp_err_f("ERROR: VIDIOC_STREAMON\n");
- camera_source_deinit(ctx);
- goto FAIL;
- }
- //skip some frames at start
- for (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 capturing
- type = ctx->type;
- camera_source_ioctl(ctx->fd, VIDIOC_STREAMOFF, &type);
- // un-mmap() buffers
- for (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, buf.length);
- }
- // Close v4l2 device
- close(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 now
- MPP_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 frame
- if (-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)
- {
- if (idx < 0)
- return NULL;
- return ctx->fbuf[idx].buffer;
- }
|