diff options
Diffstat (limited to 'v4l2-mfc-example/fimc.c')
-rw-r--r-- | v4l2-mfc-example/fimc.c | 335 |
1 files changed, 335 insertions, 0 deletions
diff --git a/v4l2-mfc-example/fimc.c b/v4l2-mfc-example/fimc.c new file mode 100644 index 0000000..9f257d6 --- /dev/null +++ b/v4l2-mfc-example/fimc.c @@ -0,0 +1,335 @@ +/* + * V4L2 Codec decoding example application + * Kamil Debski <k.debski@samsung.com> + * + * FIMC operations + * + * Copyright 2012 Samsung 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. + * + */ + +#include <linux/videodev2.h> +#include <fcntl.h> +#include <string.h> +#include <sys/ioctl.h> + +#include <sys/types.h> +#include <unistd.h> + +#include "common.h" +#include "fimc.h" + +static char *dbg_type[2] = {"OUTPUT", "CAPTURE"}; +static char *dbg_status[2] = {"ON", "OFF"}; + +int fimc_open(struct instance *i, char *name) +{ + struct v4l2_capability cap; + int ret; + + i->fimc.fd = open(name, O_RDWR, 0); + if (i->fimc.fd < 0) { + err("Failed to open FIMC: %s", name); + return -1; + } + + memzero(cap); + ret = ioctl(i->fimc.fd, VIDIOC_QUERYCAP, &cap); + if (ret != 0) { + err("Failed to verify capabilities"); + return -1; + } + + dbg("FIMC Info (%s): driver=\"%s\" bus_info=\"%s\" card=\"%s\" fd=0x%x", + name, cap.driver, cap.bus_info, cap.card, i->fimc.fd); + + if ( !(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE) || + !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT_MPLANE) || + !(cap.capabilities & V4L2_CAP_STREAMING)) { + err("Insufficient capabilities of FIMC device (is %s correct?)", + name); + return -1; + } + + return 0; +} + +void fimc_close(struct instance *i) +{ + close(i->fimc.fd); +} + +int fimc_sfmt(struct instance *i, int width, int height, + enum v4l2_buf_type type, unsigned long pix_fmt, int num_planes, + struct v4l2_plane_pix_format planes[]) +{ + struct v4l2_format fmt; + int ret; + int n; + + memzero(fmt); + fmt.fmt.pix_mp.pixelformat = pix_fmt; + fmt.type = type; + fmt.fmt.pix_mp.width = width; + fmt.fmt.pix_mp.height = height; + fmt.fmt.pix_mp.num_planes = num_planes; + + for (n = 0; n < num_planes; n++) + memcpy(&fmt.fmt.pix_mp.plane_fmt[n], &planes[n], + sizeof(*planes)); + + fmt.fmt.pix_mp.field = V4L2_FIELD_ANY; + + ret = ioctl(i->fimc.fd, VIDIOC_S_FMT, &fmt); + + if (ret != 0) { + err("Failed to SFMT on %s of FIMC", + dbg_type[type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE]); + return -1; + } + + if (fmt.fmt.pix_mp.width != width || + fmt.fmt.pix_mp.height != height || + fmt.fmt.pix_mp.num_planes != num_planes || + fmt.fmt.pix_mp.pixelformat != pix_fmt) { + err("Format was changed by FIMC so we abort operations"); + return -1; + } + + + dbg("Successful SFMT on %s of FIMC (%dx%d)", + dbg_type[type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE], + width, height); + + return 0; +} + +int fimc_setup_output_from_mfc(struct instance *i) +{ + struct v4l2_plane_pix_format planes[MFC_CAP_PLANES]; + struct v4l2_requestbuffers reqbuf; + int ret; + int n; + + for (n = 0; n < MFC_CAP_PLANES; n++) { + planes[n].sizeimage = i->mfc.cap_buf_size[n]; + planes[n].bytesperline = i->mfc.cap_w; + } + + ret = fimc_sfmt(i, i->mfc.cap_w, i->mfc.cap_h, + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, V4L2_PIX_FMT_NV12MT, + MFC_CAP_PLANES, planes); + + if (ret) + return ret; + + memzero(reqbuf); + reqbuf.count = i->mfc.cap_buf_cnt; + reqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + reqbuf.memory = V4L2_MEMORY_USERPTR; + + ret = ioctl(i->fimc.fd, VIDIOC_REQBUFS, &reqbuf); + if (ret) { + err("REQBUFS failed on OUTPUT of FIMC"); + return -1; + } + + dbg("Succesfully setup OUTPUT of FIMC"); + + return 0; +} + +int fimc_setup_capture_from_fb(struct instance *i) +{ + struct v4l2_plane_pix_format planes[MFC_OUT_PLANES]; + struct v4l2_requestbuffers reqbuf; + unsigned long fmt; + int ret; + + planes[0].sizeimage = i->fb.stride * i->fb.height; + planes[0].bytesperline = i->fb.stride; + + switch (i->fb.bpp) { + case 16: + fmt = V4L2_PIX_FMT_RGB565; + break; + case 32: + fmt = V4L2_PIX_FMT_RGB32; + break; + default: + err("Framebuffer format in not recognized. Bpp=%d", i->fb.bpp); + return -1; + } + + ret = fimc_sfmt(i, i->fb.width, i->fb.height, + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, fmt, 1, planes); + + if (ret) + return -1; + + memzero(reqbuf); + reqbuf.count = i->fb.buffers; + reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + reqbuf.memory = V4L2_MEMORY_USERPTR; + + ret = ioctl(i->fimc.fd, VIDIOC_REQBUFS, &reqbuf); + if (ret) { + err("REQBUFS failed on CAPTURE of FIMC"); + return -1; + } + + dbg("Succesfully setup CAPTURE of FIMC"); + + return 0; +} + +int fimc_stream(struct instance *i, enum v4l2_buf_type type, int status) +{ + int ret; + + ret = ioctl(i->fimc.fd, status, &type); + if (ret) { + err("Failed to change streaming on FIMC (type=%s, status=%s)", + dbg_type[type==V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE], + dbg_status[status==VIDIOC_STREAMOFF]); + return -1; + } + + dbg("Stream %s on %s queue\n", dbg_status[status==VIDIOC_STREAMOFF], + dbg_type[type==V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE]); + + return 0; +} + +int fimc_dec_queue_buf_out_from_mfc(struct instance *i, int n) +{ + struct v4l2_buffer buf; + struct v4l2_plane planes[MFC_CAP_PLANES]; + int ret; + + memzero(buf); + buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + buf.memory = V4L2_MEMORY_USERPTR; + buf.index = n; + buf.m.planes = planes; + buf.length = MFC_CAP_PLANES; + + buf.m.planes[0].bytesused = i->mfc.cap_buf_size[0]; + buf.m.planes[0].length = i->mfc.cap_buf_size[0]; + buf.m.planes[0].m.userptr = (unsigned long)i->mfc.cap_buf_addr[n][0]; + + buf.m.planes[1].bytesused = i->mfc.cap_buf_size[1]; + buf.m.planes[1].length = i->mfc.cap_buf_size[1]; + buf.m.planes[1].m.userptr = (unsigned long)i->mfc.cap_buf_addr[n][1]; + + ret = ioctl(i->fimc.fd, VIDIOC_QBUF, &buf); + + if (ret) { + err("Failed to queue buffer (index=%d) on CAPTURE", n); + return -1; + } + + dbg("Queued buffer on CAPTURE queue with index %d", n); + + return 0; +} + +int fimc_dec_queue_buf_cap_from_fb(struct instance *i, int n) +{ + struct v4l2_buffer buf; + struct v4l2_plane planes[FIMC_CAP_PLANES]; + int ret; + + memzero(buf); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + buf.memory = V4L2_MEMORY_USERPTR; + buf.index = n; + buf.m.planes = planes; + buf.length = FIMC_CAP_PLANES; + + buf.m.planes[0].bytesused = i->fb.size; + buf.m.planes[0].length = i->fb.size; + buf.m.planes[0].m.userptr = (unsigned long)i->fb.p[n]; + + ret = ioctl(i->fimc.fd, VIDIOC_QBUF, &buf); + + if (ret) { + err("Failed to queue buffer (index=%d) on OUTPUT", n); + return -1; + } + + dbg("Queued buffer on OUTPUT queue with index %d", n); + + return 0; +} + +int fimc_dec_dequeue_buf(struct instance *i, int *n, int nplanes, int type) +{ + struct v4l2_buffer buf; + struct v4l2_plane planes[MFC_MAX_PLANES]; + int ret; + + memzero(buf); + buf.type = type; + buf.memory = V4L2_MEMORY_USERPTR; + buf.m.planes = planes; + buf.length = nplanes; + + ret = ioctl(i->fimc.fd, VIDIOC_DQBUF, &buf); + + if (ret) { + err("Failed to dequeue buffer"); + return -1; + } + + *n = buf.index; + + dbg("Dequeued buffer with index %d on %s queue", buf.index, + dbg_type[type==V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE]); + + return 0; +} + +int fimc_dec_dequeue_buf_cap(struct instance *i, int *n) +{ + return fimc_dec_dequeue_buf(i, n, 1, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); +} + +int fimc_dec_dequeue_buf_out(struct instance *i, int *n) +{ + return fimc_dec_dequeue_buf(i, n, 2, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); +} + +int fimc_set_crop(struct instance *i, int type, int width, int height, int left, + int top) +{ + struct v4l2_crop crop; + + memzero(crop); + crop.type = type; + crop.c.width = width; + crop.c.height = height; + crop.c.left = left; + crop.c.top = top; + + if (ioctl(i->fimc.fd, VIDIOC_S_CROP, &crop)) { + err("Failed to set CROP on %s", + dbg_type[type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE]); + return -1; + } + + return 0; +} + |