/* * mfc codec encoding example application * Andrzej Hajda * * MFC device. * * 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 #include #include #include "common.h" #include "mfc.h" #include "v4l_dev.h" #define MAX_STREAM_SIZE (2*1024*1024) int align(int x, int a) { return ((x + a - 1) / a) * a; } /* runs v4l_deq_buf and correct ending conditions according to MFC driver */ int mfc_deq_buf(struct io_dev *dev, enum io_dir dir) { int idx; idx = v4l_deq_buf(dev, dir); if (dir == DIR_IN && dev->io[DIR_IN].state == FS_END && dev->io[DIR_OUT].limit) dev->io[DIR_OUT].limit = 0; return idx; } struct io_dev_ops mfc_dev_ops = { .req_bufs = v4l_req_bufs, .enq_buf = v4l_enq_buf, .deq_buf = mfc_deq_buf, .deq_event = v4l_deq_event, .destroy = v4l_destroy }; struct io_dev *mfc_create(char const *name) { struct io_dev *dev; int ret; dev = malloc(sizeof(*dev)); memzero(*dev); dev->ops = &mfc_dev_ops; dev->io[DIR_IN].type = IO_MMAP; dev->io[DIR_OUT].type = IO_MMAP; dev->fd = open(name, O_RDWR, 0); if (dev->fd < 0) { err("Cannot open MFC device %s", name); free(dev); return NULL; } struct v4l2_event_subscription ev_sub; memzero(ev_sub); ev_sub.type = V4L2_EVENT_EOS; ret = ioctl(dev->fd, VIDIOC_SUBSCRIBE_EVENT, &ev_sub); if (ret != 0) err("Cannot subscribe EOS event for MFC"); dbg("MFC device %s opened with fd=%d", name, dev->fd); return dev; } int mfc_set_codec(struct io_dev *dev, enum io_dir dir, int codec) { struct v4l2_format fmt; int ret; memzero(fmt); fmt.type = io_dir_to_type(dir); fmt.fmt.pix_mp.pixelformat = codec; fmt.fmt.pix_mp.plane_fmt[0].sizeimage = MAX_STREAM_SIZE; ret = ioctl(dev->fd, VIDIOC_S_FMT, &fmt); return ret; } /* set format with proper alignement */ int mfc_set_fmt(struct io_dev *dev, enum io_dir dir, int width, int height) { struct v4l2_format fmt; int ret; memzero(fmt); fmt.type = io_dir_to_type(dir); fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M; fmt.fmt.pix_mp.width = width; fmt.fmt.pix_mp.height = height; fmt.fmt.pix_mp.num_planes = 2; fmt.fmt.pix_mp.plane_fmt[0].bytesperline = align(width, 128); fmt.fmt.pix_mp.plane_fmt[0].sizeimage = align(width * height, 2048); fmt.fmt.pix_mp.plane_fmt[1].bytesperline = align(width, 128); fmt.fmt.pix_mp.plane_fmt[1].sizeimage = align(width * (height / 2), 2048); ret = ioctl(dev->fd, VIDIOC_S_FMT, &fmt); if (ret != 0) err("Cannot set format on %d:%d", dev->fd, dir); return ret; } int mfc_set_rate(struct io_dev *dev, int rate) { struct v4l2_streamparm fps; int ret; fps.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; fps.parm.output.timeperframe.numerator = 1000; fps.parm.output.timeperframe.denominator = rate; ret = ioctl(dev->fd, VIDIOC_S_PARM, &fps); if (ret != 0) err("Cannot set rate on %d", dev->fd); return ret; } int mfc_set_mpeg_control(struct io_dev *dev, int id, int value) { struct v4l2_ext_control ctrl; struct v4l2_ext_controls ctrls; int ret; ctrl.id = id; ctrl.value = value; ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG; ctrls.count = 1; ctrls.controls = &ctrl; ret = ioctl(dev->fd, VIDIOC_S_EXT_CTRLS, &ctrls); if (ret < 0) err("Cannot set control %d to %d on %d", id, value, dev->fd); return ret; } int mfc_set_bitrate(struct io_dev *dev, int bitrate) { struct v4l2_ext_control ctrl; struct v4l2_ext_controls ctrls; int ret; ctrl.id = V4L2_CID_MPEG_VIDEO_BITRATE; ctrl.value = bitrate; ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG; ctrls.count = 1; ctrls.controls = &ctrl; ret = ioctl(dev->fd, VIDIOC_S_EXT_CTRLS, &ctrls); if (ret < 0) err("Cannot set bitrate on %d", dev->fd); return ret; }