author | David Huang <d-huang@ti.com> | |
Fri, 13 Sep 2019 19:14:40 +0000 (14:14 -0500) | ||
committer | David Huang <d-huang@ti.com> | |
Fri, 13 Sep 2019 20:54:31 +0000 (15:54 -0500) |
Signed-off-by: David Huang <d-huang@ti.com>
Makefile.am | [new file with mode: 0644] | patch | blob |
autogen.sh | [new file with mode: 0644] | patch | blob |
configure.ac | [new file with mode: 0644] | patch | blob |
main.c | [new file with mode: 0644] | patch | blob |
main.h | [new file with mode: 0644] | patch | blob |
diff --git a/Makefile.am b/Makefile.am
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,24 @@
+#
+# Copyright (C) 2018 Texas Instruments
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 as published by
+# the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+bin_PROGRAMS = tienc_encode
+
+LDADD_COMMON = @DRM_LIBS@
+AM_CFLAGS = @DRM_CFLAGS@ @WARN_CFLAGS@ -I$(top_srcdir)/util -DDRMMODE -DDRM
+LDFLAGS = -lm
+
+tienc_encode_SOURCES = main.c
+tienc_encode_LDADD = $(LDADD_COMMON)
diff --git a/autogen.sh b/autogen.sh
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,18 @@
+#! /bin/sh
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+ORIGDIR=`pwd`
+cd $srcdir
+
+autoreconf -v --install || exit 1
+cd $ORIGDIR || exit $?
+
+test -n "$NOCONFIGURE" && {
+ echo "skipping configure stage as requested."
+ echo "autogen.sh done."
+ exit 0
+}
+
+$srcdir/configure --enable-maintainer-mode "$@"
diff --git a/configure.ac b/configure.ac
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,98 @@
+#
+# Copyright (C) 2018 Texas Instruments
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 as published by
+# the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# Initialize Autoconf
+AC_PREREQ([2.60])
+AC_INIT([tienc_encode], [1.0.0], [https://www.ti.com], [tienc_encode])
+AC_CONFIG_SRCDIR([Makefile.am])
+AC_CONFIG_HEADERS([config.h])
+
+# Initialize Automake
+AM_INIT_AUTOMAKE([foreign dist-bzip2])
+AM_MAINTAINER_MODE
+
+# Enable quiet compiles on automake 1.11.
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+# Initialize libtool
+AC_PROG_LIBTOOL
+AC_PROG_CXX
+
+# Obtain compiler/linker options for depedencies
+PKG_CHECK_MODULES(DRM, libdrm)
+
+dnl ===========================================================================
+dnl check compiler flags
+AC_DEFUN([LIBDRM_CC_TRY_FLAG], [
+ AC_MSG_CHECKING([whether $CC supports $1])
+
+ libdrm_save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $1"
+
+ AC_COMPILE_IFELSE([ ], [libdrm_cc_flag=yes], [libdrm_cc_flag=no])
+ CFLAGS="$libdrm_save_CFLAGS"
+
+ if test "x$libdrm_cc_flag" = "xyes"; then
+ ifelse([$2], , :, [$2])
+ else
+ ifelse([$3], , :, [$3])
+ fi
+ AC_MSG_RESULT([$libdrm_cc_flag])
+])
+
+MAYBE_WARN="-Wall -Wextra \
+-Wsign-compare -Werror-implicit-function-declaration \
+-Wpointer-arith -Wwrite-strings -Wstrict-prototypes \
+-Wnested-externs \
+-Wpacked -Wswitch-enum -Wmissing-format-attribute \
+-Wstrict-aliasing=2 -Winit-self -Wunsafe-loop-optimizations \
+-Wdeclaration-after-statement -Wold-style-definition \
+-Wno-missing-field-initializers -Wno-unused-parameter \
+-Wno-attributes -Wno-long-long -Winline"
+
+# invalidate cached value if MAYBE_WARN has changed
+if test "x$libdrm_cv_warn_maybe" != "x$MAYBE_WARN"; then
+ unset libdrm_cv_warn_cflags
+fi
+AC_CACHE_CHECK([for supported warning flags], libdrm_cv_warn_cflags, [
+ echo
+ WARN_CFLAGS=""
+
+ # Some warning options are not supported by all versions of
+ # gcc, so test all desired options against the current
+ # compiler.
+ #
+ # Note that there are some order dependencies
+ # here. Specifically, an option that disables a warning will
+ # have no net effect if a later option then enables that
+ # warnings, (perhaps implicitly). So we put some grouped
+ # options (-Wall and -Wextra) up front and the -Wno options
+ # last.
+
+ for W in $MAYBE_WARN; do
+ LIBDRM_CC_TRY_FLAG([$W], [WARN_CFLAGS="$WARN_CFLAGS $W"])
+ done
+
+ libdrm_cv_warn_cflags=$WARN_CFLAGS
+ libdrm_cv_warn_maybe=$MAYBE_WARN
+
+ AC_MSG_CHECKING([which warning flags were supported])])
+WARN_CFLAGS="$libdrm_cv_warn_cflags"
+AC_SUBST(WARN_CFLAGS)
+
+
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
diff --git a/main.c b/main.c
--- /dev/null
+++ b/main.c
@@ -0,0 +1,1824 @@
+/*
+ * Texas Instruments IMG video encoder driver test application.
+ *
+ * Copyright (c) 2019 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+#include <poll.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include "main.h"
+
+#ifdef DRMMODE
+#include <xf86drmMode.h>
+#else
+#ifdef DRM
+#include <drm.h>
+#endif /* DRM */
+#endif /* DRMMODE */
+
+//#define DEBUG
+#ifdef DEBUG
+#define debug_printf(fmt, arg...) printf("tienc: " fmt, ##arg);
+#else
+#define debug_printf(fmt, arg...)
+#endif
+
+static const struct tienc_format out_formats[] = {
+ {
+ .name = "NV12",
+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .size_num = 3,
+ .size_den = 2,
+ .n_planes = 1,
+ .bytes_pp = 1,
+ },
+ {
+ .name = "RGBA",
+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .fourcc = V4L2_PIX_FMT_RGB32,
+ .size_num = 1,
+ .size_den = 1,
+ .n_planes = 1,
+ .bytes_pp = 4,
+ }
+};
+
+static const struct tienc_format cap_formats[] = {
+ {
+ .name = "H264",
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+ .fourcc = V4L2_PIX_FMT_H264,
+ .size_num = 2,
+ .size_den = 1,
+ .n_planes = 1,
+ .bytes_pp = 1,
+ }
+};
+
+static int queue_buffer(int fd, int index, struct tienc_buffer buffer,
+ struct tienc_format format)
+{
+ struct v4l2_buffer buf;
+ struct v4l2_plane buf_planes[MAX_PLANES];
+ int ret = 0;
+
+ memset(&buf, 0, sizeof(buf));
+ memset(&buf_planes, 0, sizeof(buf_planes));
+
+ if (V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == format.type)
+ buf_planes[0].bytesused = format.size;
+
+ if (format.memory == V4L2_MEMORY_MMAP) {
+ buf_planes[0].m.mem_offset = buffer.offset;
+ } else if (format.memory == V4L2_MEMORY_DMABUF) {
+ buf_planes[0].m.fd = buffer.dbuf_fd;
+ buf_planes[0].length = buffer.length;
+ } else {
+ printf("Invalid memory type selected\n");
+ return -1;
+ }
+
+ buf.index = index;
+ buf.type = format.type;
+ buf.memory = format.memory;
+ buf.m.planes = buf_planes;
+ buf.length = format.n_planes;
+
+ ret = ioctl(fd, VIDIOC_QBUF, &buf);
+ if (ret < 0)
+ printf("%s QBUF buffer %d failed %d: %s\n",
+ (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == format.type) ?
+ ("CAPTURE") : ("OUTPUT"), index, errno, strerror(errno));
+ else
+ debug_printf("%s QBUF buffer %d success\n",
+ (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == format.type)
+ ? ("CAPTURE") : ("OUTPUT"), index);
+
+ return ret;
+}
+
+static int handle_outbuf(int fd, int rdfd, int index,
+ struct tienc_buffer buffer,
+ struct tienc_format format,
+ int n_frames)
+{
+ int i, ret = 0;
+ static int frame_count = 1; /* Start at 1 to send EOS before last frame */
+ struct v4l2_encoder_cmd cmd = {0};
+
+ if (frame_count == n_frames) {
+ cmd.cmd = V4L2_ENC_CMD_STOP;
+ cmd.flags = V4L2_ENC_CMD_STOP_AT_GOP_END;
+ ret = ioctl(fd, VIDIOC_TRY_ENCODER_CMD, &cmd);
+ if (0 > ret)
+ printf("handle_outbuf TRY_ENCODER_CMD failed %d %s\n",
+ errno, strerror(errno));
+ ret = ioctl(fd, VIDIOC_ENCODER_CMD, &cmd);
+ if (0 > ret)
+ printf("handle_outbuf ENCODER_CMD failed %d %s\n",
+ errno, strerror(errno));
+ frame_count++;
+ }
+
+ if (frame_count > n_frames) {
+ debug_printf("All source frames send %d\n", n_frames);
+ return 0;
+ }
+
+ memset(buffer.mapped, 0, buffer.length);
+
+ for(i = 0; i < (format.height * format.size_num)/format.size_den; i++) {
+ ret = read(rdfd, (buffer.mapped + (i * format.stride)), format.width * format.bytes_pp);
+ if (!ret) {
+ debug_printf("read returned 0, exiting handle_outbuf\n");
+ return 0;
+ }
+ }
+#if 0
+ debug_printf("%s printing contents of buffer %d\n", __func__, index);
+ for (i = 0; i < 2400; i = i + 8) {
+ debug_printf("0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",
+ ((char*)buffer.mapped)[i+0],
+ ((char*)buffer.mapped)[i+1],
+ ((char*)buffer.mapped)[i+2],
+ ((char*)buffer.mapped)[i+3],
+ ((char*)buffer.mapped)[i+4],
+ ((char*)buffer.mapped)[i+5],
+ ((char*)buffer.mapped)[i+6],
+ ((char*)buffer.mapped)[i+7]);
+ }
+#endif
+ ret = queue_buffer(fd, index, buffer, format);
+
+ frame_count++;
+
+ return ret;
+}
+
+static int handle_capbuf(int fd, int wrfd, int index,
+ struct tienc_buffer buffer,
+ struct tienc_format format,
+ int write_length)
+{
+ int ret = 0;
+
+ if (write_length)
+ ret = write(wrfd, buffer.mapped, write_length);
+ if (0 > ret)
+ printf("write returned error: %d: %s\n", errno,
+ strerror(errno));
+
+ ret = queue_buffer(fd, index, buffer, format);
+
+ return ret;
+}
+
+static int streaming_loop(int fd, int rdfd, int wrfd,
+ struct tienc_buffer outbuffers[],
+ struct tienc_buffer capbuffers[],
+ int n_outbuffers, int n_capbuffers,
+ struct tienc_format out_format,
+ struct tienc_format cap_format,
+ int n_frames)
+{
+ struct v4l2_buffer buf;
+ struct v4l2_plane buf_planes[MAX_PLANES];
+ struct pollfd pfd;
+ int type, i, ret = 0;
+ uint32_t flags = 0;
+ struct v4l2_event event;
+
+ debug_printf("%s Enter\n", __func__);
+
+ for (i = 0; i < n_outbuffers; i++)
+ handle_outbuf(fd, rdfd, i, outbuffers[i], out_format, n_frames);
+
+ for (i = 0; i < n_capbuffers; i++)
+ handle_capbuf(fd, wrfd, i, capbuffers[i], cap_format, 0);
+
+ type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ ret = ioctl(fd, VIDIOC_STREAMON, &type);
+ if (ret) {
+ printf("OUTPUT VIDIOC_STREAMON failed %d: %s\n", errno,
+ strerror(errno));
+ return ret;
+ }
+ debug_printf("OUTPUT VIDIOC_STREAMON succeeded\n");
+
+ type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ ret = ioctl(fd, VIDIOC_STREAMON, &type);
+ if (ret) {
+ printf("CAPTURE VIDIOC_STREAMON failed %d: %s\n", errno,
+ strerror(errno));
+ return ret;
+ }
+ debug_printf("CAPTURE VIDIOC_STREAMON succeeded\n");
+
+ pfd.fd = fd;
+ pfd.events = POLLIN | POLLOUT | POLLPRI;
+
+ while(!(flags & V4L2_BUF_FLAG_LAST)) {
+ /* Poll for any event for 100ms */
+ pfd.revents = 0;
+ ret = poll(&pfd, 1, 100);
+ if (0 > ret) {
+ printf("poll had an error %d: %s\n",
+ errno, strerror(errno));
+ } else if (0 < ret) {
+ if (pfd.revents & POLLOUT) {
+ while(1) {
+ memset(&buf, 0, sizeof(buf));
+ memset(&buf_planes, 0, sizeof(buf_planes));
+ buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ buf.memory = out_format.memory;
+ buf.m.planes = buf_planes;
+ buf.length = out_format.n_planes;
+ ret = ioctl(fd, VIDIOC_DQBUF, &buf);
+ if (ret < 0) {
+ if (EAGAIN != errno) {
+ printf("OUTPUT VIDIOC_DQBUF failed %d: %s\n",
+ errno,
+ strerror(errno));
+ } else {
+ debug_printf("OUTPUT EAGAIN\n");
+ break;
+ }
+ } else {
+ handle_outbuf(fd, rdfd, buf.index,
+ outbuffers[buf.index],
+ out_format,
+ n_frames);
+ }
+ }
+ }
+ if (pfd.revents & POLLIN) {
+ while(1) {
+ memset(&buf, 0, sizeof(buf));
+ memset(&buf_planes, 0, sizeof(buf_planes));
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ buf.memory = cap_format.memory;
+ buf.m.planes = buf_planes;
+ buf.length = cap_format.n_planes;
+ ret = ioctl(fd, VIDIOC_DQBUF, &buf);
+ if (ret < 0) {
+ if (EAGAIN != errno) {
+ printf("CAPTURE VIDIOC_DQBUF failed %d: %s\n",
+ errno,
+ strerror(errno));
+ if (EPIPE == errno) {
+ printf("Got EPIPE, exiting\n");
+ flags |= V4L2_BUF_FLAG_LAST;
+ break;
+ }
+ } else {
+ debug_printf("CAPTURE EAGAIN\n");
+ break;
+ }
+ } else {
+ handle_capbuf(fd, wrfd, buf.index,
+ capbuffers[buf.index],
+ cap_format,
+ buf.m.planes[0].bytesused);
+ flags = buf.flags;
+ debug_printf("CAPTURE VIDIOC_DQBUF buffer %d flags=%#08x FLAG_LAST=%#08x\n",
+ buf.index, flags,
+ V4L2_BUF_FLAG_LAST);
+ if (buf.flags & V4L2_BUF_FLAG_LAST)
+ break;
+ }
+ }
+ }
+ if (pfd.revents & POLLPRI) {
+ memset(&event, 0, sizeof(event));
+ ret = ioctl(fd, VIDIOC_DQEVENT, &event);
+ if (ret < 0) {
+ printf("VIDIOC_DQEVENT failed %d: %s\n",
+ errno, strerror(errno));
+ } else if (event.type == V4L2_EVENT_EOS) {
+ debug_printf("GOT EOS EVENT\n");
+ } else {
+ printf("VIDIOC_DQEVENT got unexpected event %d\n",
+ event.type);
+ }
+ }
+ }
+ }
+
+ type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ ret = ioctl(fd, VIDIOC_STREAMOFF, &type);
+ if (ret)
+ printf("OUTPUT VIDIOC_STREAMOFF failed %d: %s\n", errno,
+ strerror(errno));
+
+ type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ ret = ioctl(fd, VIDIOC_STREAMOFF, &type);
+ if (ret)
+ printf("CAPTURE VIDIOC_STREAMOFF failed %d: %s\n", errno,
+ strerror(errno));
+
+ return 0;
+}
+
+#ifdef DRM
+static int create_drm_buffer(int drmfd, struct tienc_buffer *b,
+ struct tienc_format format)
+{
+ struct drm_mode_create_dumb gem;
+ struct drm_prime_handle prime;
+ struct drm_mode_map_dumb gem_map;
+ int ret;
+
+ memset(&gem, 0, sizeof gem);
+ gem.width = format.stride;
+ gem.height = (format.height * format.size_num) / format.size_den;
+ gem.bpp = 8 * format.bytes_pp;
+
+ ret = ioctl(drmfd, DRM_IOCTL_MODE_CREATE_DUMB, &gem);
+ if (ret) {
+ printf("DRM_IOCTL_MODE_CREATE_DUMB failed %d: %s\n",
+ errno, strerror(errno));
+ return ret;
+ }
+
+ b->bo_handle = gem.handle;
+
+ memset(&prime, 0, sizeof prime);
+ prime.handle = b->bo_handle;
+
+ ret = ioctl(drmfd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &prime);
+ if (ret) {
+ printf("DRM_IOCTL_PRIME_HANDLE_TO_FD failed %d: %s\n",
+ errno, strerror(errno));
+ return ret;
+ }
+ b->dbuf_fd = prime.fd;
+
+ memset(&gem_map, 0, sizeof(gem_map));
+ gem_map.handle = gem.handle;
+
+ ret = ioctl(drmfd, DRM_IOCTL_MODE_MAP_DUMB, &gem_map);
+ if (ret) {
+ printf("DRM_IOCTL_MODE_MAP_DUMB failed %d: %s\n",
+ errno, strerror(errno));
+ return ret;
+ }
+
+ if (format.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ b->mapped = mmap(NULL, (size_t)gem.size, PROT_READ,
+ MAP_SHARED, drmfd, gem_map.offset);
+ } else if (format.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ b->mapped = mmap(NULL, (size_t)gem.size, PROT_WRITE,
+ MAP_SHARED, drmfd, gem_map.offset);
+ } else {
+ }
+
+ if (MAP_FAILED == b->mapped) {
+ printf("mmap of %s GEM buffer failed %d: %s\n",
+ (format.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) ?
+ ("CAPTURE") : ("OUTPUT"), errno, strerror(errno));
+ return -1;
+ }
+ b->offset = gem_map.offset;
+ b->length = gem.size;
+
+ return 0;
+}
+#endif
+
+static int create_mmap_buffer(int fd, struct tienc_buffer *b,
+ enum v4l2_buf_type type, int index,
+ struct tienc_format format)
+{
+ struct v4l2_buffer buf;
+ struct v4l2_plane buf_planes[MAX_PLANES];
+
+ memset(&buf, 0, sizeof(buf));
+ buf.type = type;
+ buf.index = index;
+ buf.m.planes = buf_planes;
+ buf.length = 1;
+
+ if (ioctl(fd, VIDIOC_QUERYBUF, &buf)) {
+ printf("VIDIOC_QUERYBUF %s %d failed: %d: %s\n",
+ (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) ?
+ ("CAPTURE") : ("OUTPUT"), index, errno,
+ strerror(errno));
+ return -1;
+ }
+
+ debug_printf("QUERYBUF %s: buffer %d length (planes)=%d length=%d offset=%d\n",
+ (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) ?
+ ("CAPTURE") : ("OUTPUT"), index, buf.length,
+ buf.m.planes[0].length,
+ buf.m.planes[0].data_offset);
+
+ /*
+ * Required size for CAPTURE can be more finely tuned by driver.
+ * Our calculated size for CAPTURE is a worst case scenario, so allow
+ * driver to take priority.
+ */
+ if ((type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) &&
+ (buf.m.planes[0].length < format.size)) {
+ printf("Buffer length %d less than required %d\n",
+ buf.m.planes[0].length, format.size);
+ return -1;
+ }
+
+ b->mapped = mmap(NULL, buf.m.planes[0].length,
+ PROT_READ | PROT_WRITE, MAP_SHARED,
+ fd, buf.m.planes[0].m.mem_offset);
+ b->offset = buf.m.planes[0].m.mem_offset;
+ b->length = buf.m.planes[0].length;
+
+ debug_printf("After mmap, buffers[%d].mapped = 0x%p\n", index,
+ b->mapped);
+
+ if (MAP_FAILED == b->mapped) {
+ printf("mmap of %s buffer failed %d: %s\n",
+ (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) ?
+ ("CAPTURE") : ("OUTPUT"), errno,
+ strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+static int alloc_bufs(int fd, int drmfd, int *n_buffers,
+ struct tienc_buffer buffers[], enum v4l2_buf_type type,
+ struct tienc_format format)
+{
+ int i, max, ret = 0;
+ struct v4l2_requestbuffers reqbuf = {0};
+ debug_printf("%s Enter\n", __func__);
+
+ reqbuf.count = *n_buffers;
+ reqbuf.type = type;
+ reqbuf.memory = format.memory;
+
+ ret = ioctl(fd, VIDIOC_REQBUFS, &reqbuf);
+ if (ret) {
+ printf("VIDIOC_REQBUF %s failed %d: %s\n",
+ (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) ?
+ ("CAPTURE") : ("OUTPUT"), errno, strerror(errno));
+ return ret;
+ }
+
+ debug_printf("After VIDIOC_REQBUFS %s getting buf_cnt %d\n",
+ (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) ?
+ ("CAPTURE") : ("OUTPUT"), reqbuf.count);
+
+ *n_buffers = reqbuf.count;
+
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type) {
+ max = MAX_CAPBUFS;
+ } else if (V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == type) {
+ max = MAX_OUTBUFS;
+ } else {
+ printf("Invalid type %#08x chosen\n", type);
+ return -1;
+ }
+
+ if (max < *n_buffers) {
+ printf("Driver returned more %s buffers %d than MAX %d\n",
+ (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) ?
+ ("CAPTURE") : ("OUTPUT"), *n_buffers, max);
+ return -1;
+ }
+
+ for (i = 0; i < *n_buffers; i++) {
+ if (format.memory == V4L2_MEMORY_MMAP) {
+ ret = create_mmap_buffer(fd, &buffers[i], type, i, format);
+ if (ret)
+ return ret;
+ } else if (format.memory == V4L2_MEMORY_DMABUF) {
+#ifdef DRM
+ ret = create_drm_buffer(drmfd, &buffers[i], format);
+ if (ret)
+ return ret;
+#endif
+ }
+ }
+
+ return 0;
+}
+
+static void dealloc_bufs(int fd, int drmfd, int *n_buffers, struct tienc_buffer buffers[],
+ struct tienc_format format)
+{
+#ifdef DRM
+ struct drm_mode_destroy_dumb gem_destroy;
+#endif
+ int i, ret = 0;
+
+ debug_printf("%s Enter\n", __func__);
+
+ for (i = 0; i < *n_buffers; i++) {
+ if (NULL == buffers[i].mapped) {
+ debug_printf("buffer %d not mapped, skip munmap\n", i);
+ continue;
+ }
+ debug_printf("munmap buffer %d mapped=0x%p length =%d\n",
+ i, buffers[i].mapped, buffers[i].length);
+ ret = munmap(buffers[i].mapped, buffers[i].length);
+ if (ret)
+ printf("munmap failed for buffer %d. %d: %s\n",
+ i, errno, strerror(errno));
+ buffers[i].mapped = NULL;
+
+#ifdef DRM
+ if (format.memory == V4L2_MEMORY_DMABUF) {
+ memset(&gem_destroy, 0, sizeof(gem_destroy));
+ gem_destroy.handle = buffers[i].bo_handle;
+ ret = ioctl(drmfd, DRM_IOCTL_MODE_DESTROY_DUMB,
+ &gem_destroy);
+ if (ret)
+ printf("DRM_IOCTL_MODE_DESTROY_DUMB failed for buffer %d. %d: %s\n",
+ i, errno, strerror(errno));
+ }
+#endif
+ }
+}
+
+static void print_v4l2_format(struct v4l2_format *fmt)
+{
+ int i;
+
+ debug_printf("type = %d\n", fmt->type);
+ debug_printf("width=%d height=%d\n", fmt->fmt.pix_mp.width,
+ fmt->fmt.pix_mp.height);
+ debug_printf("pixelformat=%d\n", fmt->fmt.pix_mp.pixelformat);
+ debug_printf("field=%d colorspace=%d\n", fmt->fmt.pix_mp.field,
+ fmt->fmt.pix_mp.colorspace);
+ for (i = 0; i < fmt->fmt.pix_mp.num_planes; i++) {
+ debug_printf("plane_fmt[%d].sizeimage=%d\n", i,
+ fmt->fmt.pix_mp.plane_fmt[i].sizeimage);
+ debug_printf("plane_fmt[%d].bytesperline=%d\n", i,
+ fmt->fmt.pix_mp.plane_fmt[i].bytesperline);
+ }
+ debug_printf("num_planes=%d flags=%d\n", fmt->fmt.pix_mp.num_planes,
+ fmt->fmt.pix_mp.flags);
+}
+
+static void get_format(int fd, struct tienc_format format)
+{
+ struct v4l2_format fmt = {0};
+
+ debug_printf("%s Enter\n", __func__);
+
+ fmt.type = format.type;
+
+ if (ioctl(fd, VIDIOC_G_FMT, &fmt)) {
+ printf("VIDIOC_G_FMT %s errno %d: %s\n",
+ (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == format.type) ?
+ ("CAPTURE") : ("OUTPUT"), errno, strerror(errno));
+ return;
+ }
+
+ debug_printf("%s printing returned v4l2_format\n", __func__);
+ print_v4l2_format(&fmt);
+}
+
+static int try_format(int fd, struct tienc_format format)
+{
+ struct v4l2_format fmt = {0};
+ int ret = 0;
+
+ debug_printf("%s Enter\n", __func__);
+
+ fmt.type = format.type;
+ fmt.fmt.pix_mp.width = format.width;
+ fmt.fmt.pix_mp.height = format.height;
+ fmt.fmt.pix_mp.pixelformat = format.fourcc;
+ fmt.fmt.pix_mp.field = V4L2_FIELD_NONE;
+ fmt.fmt.pix_mp.colorspace = V4L2_COLORSPACE_DEFAULT;
+ fmt.fmt.pix_mp.plane_fmt[0].sizeimage = format.size;
+ fmt.fmt.pix_mp.plane_fmt[0].bytesperline = format.stride;
+ fmt.fmt.pix_mp.num_planes = format.n_planes;
+
+ ret = ioctl(fd, VIDIOC_TRY_FMT, &fmt);
+ if (ret) {
+ printf("VIDIOC_TRY_FMT %s errno %d: %s\n",
+ (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == format.type) ?
+ ("CAPTURE") : ("OUTPUT"), errno, strerror(errno));
+ return ret;
+ }
+
+ debug_printf("%s printing returned v4l2_format\n", __func__);
+ print_v4l2_format(&fmt);
+ return 0;
+}
+
+static int set_format(int fd, struct tienc_format format)
+{
+ struct v4l2_format fmt = {0};
+ int ret = 0;
+
+ debug_printf("%s Enter\n", __func__);
+
+ fmt.type = format.type;
+ fmt.fmt.pix_mp.width = format.width;
+ fmt.fmt.pix_mp.height = format.height;
+ fmt.fmt.pix_mp.pixelformat = format.fourcc;
+ fmt.fmt.pix_mp.field = V4L2_FIELD_NONE;
+ fmt.fmt.pix_mp.colorspace = V4L2_COLORSPACE_DEFAULT;
+ fmt.fmt.pix_mp.plane_fmt[0].sizeimage = format.size;
+ fmt.fmt.pix_mp.plane_fmt[0].bytesperline = format.stride;
+ fmt.fmt.pix_mp.num_planes = format.n_planes;
+
+ ret = ioctl(fd, VIDIOC_S_FMT, &fmt);
+ if (ret) {
+ printf("VIDIOC_S_FMT %s errno %d: %s\n",
+ (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == format.type) ?
+ ("CAPTURE") : ("OUTPUT"), errno, strerror(errno));
+ return ret;
+ }
+
+ debug_printf("%s printing returned v4l2_format\n", __func__);
+ print_v4l2_format(&fmt);
+ return 0;
+}
+
+static void get_parameters(int fd)
+{
+ struct v4l2_streamparm parm = {0};
+
+ parm.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ parm.parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+
+ if (ioctl(fd, VIDIOC_G_PARM, &parm)) {
+ printf("VIDIOC_G_PARM failed %d %s\n", errno, strerror(errno));
+ return;
+ }
+
+ debug_printf("VIDIOC_G_PARM got back framerate %d / %d = %d\n",
+ parm.parm.output.timeperframe.denominator,
+ parm.parm.output.timeperframe.numerator,
+ (parm.parm.output.timeperframe.denominator /
+ parm.parm.output.timeperframe.numerator));
+
+ return;
+}
+
+static int set_parameters(int fd, int num, int den)
+{
+ struct v4l2_streamparm parm = {0};
+
+ parm.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ parm.parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+ parm.parm.output.timeperframe.numerator = num;
+ parm.parm.output.timeperframe.denominator = den;
+
+ if (ioctl(fd, VIDIOC_S_PARM, &parm)) {
+ printf("VIDIOC_S_PARM failed %d %s\n", errno, strerror(errno));
+ return 1;
+ }
+
+ debug_printf("VIDIOC_S_PARM got back framerate %d / %d = %d\n",
+ parm.parm.output.timeperframe.denominator,
+ parm.parm.output.timeperframe.numerator,
+ (parm.parm.output.timeperframe.denominator /
+ parm.parm.output.timeperframe.numerator));
+
+ return 0;
+}
+
+static void query_ctrls(int fd)
+{
+ struct v4l2_queryctrl ctrl;
+ struct v4l2_query_ext_ctrl ext_ctrl;
+
+ debug_printf("%s Enter\n", __func__);
+
+ printf("%s Enumerating all non-compound\n", __func__);
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = 0;
+ ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
+ while (! ioctl(fd, VIDIOC_QUERYCTRL, &ctrl)) {
+ printf("%s Got ctrl.id=%#08x type=%d\n",
+ __func__, ctrl.id, ctrl.type);
+ printf("%s\tname=%s minimum=%d maximum=%d\n",
+ __func__, ctrl.name, ctrl.minimum, ctrl.maximum);
+ printf("%s\tstep=%d default_value=%d\n",
+ __func__, ctrl.step, ctrl.default_value);
+ printf("%s\tflags=%#08x\n", __func__, ctrl.flags);
+ ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
+ }
+ printf("%s Enumerating all non-compound ended errno=%d %s\n",
+ __func__, errno, strerror(errno));
+
+ printf("%s Enumerating all non-compound ext\n", __func__);
+ memset(&ext_ctrl, 0, sizeof(ext_ctrl));
+ ext_ctrl.id = 0;
+ ext_ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
+ while (! ioctl(fd, VIDIOC_QUERY_EXT_CTRL, &ext_ctrl)) {
+ printf("%s Got ext_ctrl.id=%#08x type=%d\n",
+ __func__, ext_ctrl.id, ext_ctrl.type);
+ printf("%s\tname=%s minimum=%lld maximum=%lld\n",
+ __func__, ext_ctrl.name, ext_ctrl.minimum,
+ ext_ctrl.maximum);
+ printf("%s\tstep=%lld default_value=%lld\n",
+ __func__, ext_ctrl.step, ext_ctrl.default_value);
+ printf("%s\telem_size=%d elems=%d nr_of_dims=%d\n",
+ __func__, ext_ctrl.elem_size, ext_ctrl.elems,
+ ext_ctrl.nr_of_dims);
+ printf("%s\tflags=%#08x\n", __func__, ctrl.flags);
+ ext_ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
+ }
+ printf("%s Enumerating all non-compound ext ended errno=%d %s\n",
+ __func__, errno, strerror(errno));
+
+ printf("%s Enumerating all compound ext\n", __func__);
+ memset(&ext_ctrl, 0, sizeof(ext_ctrl));
+ ext_ctrl.id = 0;
+ ext_ctrl.id |= V4L2_CTRL_FLAG_NEXT_COMPOUND;
+ while (! ioctl(fd, VIDIOC_QUERY_EXT_CTRL, &ext_ctrl)) {
+ printf("%s Got ext_ctrl.id=%#08x type=%d\n",
+ __func__, ext_ctrl.id, ext_ctrl.type);
+ printf("%s\tname=%s minimum=%lld maximum=%lld\n",
+ __func__, ext_ctrl.name, ext_ctrl.minimum,
+ ext_ctrl.maximum);
+ printf("%s\tstep=%lld default_value=%lld\n",
+ __func__, ext_ctrl.step, ext_ctrl.default_value);
+ printf("%s\telem_size=%d elems=%d nr_of_dims=%d\n",
+ __func__, ext_ctrl.elem_size, ext_ctrl.elems,
+ ext_ctrl.nr_of_dims);
+ printf("%s\tflags=%#08x\n", __func__, ctrl.flags);
+ ext_ctrl.id |= V4L2_CTRL_FLAG_NEXT_COMPOUND;
+ }
+ printf("%s Enumerating all compound ext ended errno=%d %s\n",
+ __func__, errno, strerror(errno));
+
+ printf("%s Enumerating all controls ext\n", __func__);
+ memset(&ext_ctrl, 0, sizeof(ext_ctrl));
+ ext_ctrl.id = 0;
+ ext_ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
+ ext_ctrl.id |= V4L2_CTRL_FLAG_NEXT_COMPOUND;
+ while (! ioctl(fd, VIDIOC_QUERY_EXT_CTRL, &ext_ctrl)) {
+ printf("%s Got ext_ctrl.id=%#08x type=%d\n",
+ __func__, ext_ctrl.id, ext_ctrl.type);
+ printf("%s\tname=%s minimum=%lld maximum=%lld\n",
+ __func__, ext_ctrl.name, ext_ctrl.minimum,
+ ext_ctrl.maximum);
+ printf("%s\tstep=%lld default_value=%lld\n",
+ __func__, ext_ctrl.step, ext_ctrl.default_value);
+ printf("%s\telem_size=%d elems=%d nr_of_dims=%d\n",
+ __func__, ext_ctrl.elem_size, ext_ctrl.elems,
+ ext_ctrl.nr_of_dims);
+ printf("%s\tflags=%#08x\n", __func__, ctrl.flags);
+ ext_ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
+ ext_ctrl.id |= V4L2_CTRL_FLAG_NEXT_COMPOUND;
+ }
+ printf("%s Enumerating all controls ext ended errno=%d %s\n",
+ __func__, errno, strerror(errno));
+
+ /* Query individual controls */
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = V4L2_CID_MPEG_VIDEO_GOP_SIZE;
+ if (ioctl(fd, VIDIOC_QUERYCTRL, &ctrl)) {
+ printf("%s error querying V4L2_CID_MPEG_VIDEO_GOP_SIZE errno=%d %s\n",
+ __func__, errno, strerror(errno));
+ } else {
+ printf("%s Got ctrl.id=%#08x type=%d\n",
+ __func__, ctrl.id, ctrl.type);
+ printf("%s\tname=%s minimum=%d maximum=%d\n",
+ __func__, ctrl.name, ctrl.minimum, ctrl.maximum);
+ printf("%s\tstep=%d default_value=%d\n",
+ __func__, ctrl.step, ctrl.default_value);
+ printf("%s\tflags=%#08x\n", __func__, ctrl.flags);
+ }
+
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = V4L2_CID_MPEG_VIDEO_BITRATE;
+ if (ioctl(fd, VIDIOC_QUERYCTRL, &ctrl)) {
+ printf("%s error querying V4L2_CID_MPEG_VIDEO_BITRATE errno=%d %s\n",
+ __func__, errno, strerror(errno));
+ } else {
+ printf("%s Got ctrl.id=%#08x type=%d\n",
+ __func__, ctrl.id, ctrl.type);
+ printf("%s\tname=%s minimum=%d maximum=%d\n",
+ __func__, ctrl.name, ctrl.minimum, ctrl.maximum);
+ printf("%s\tstep=%d default_value=%d\n",
+ __func__, ctrl.step, ctrl.default_value);
+ printf("%s\tflags=%#08x\n", __func__, ctrl.flags);
+ }
+
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD;
+ if (ioctl(fd, VIDIOC_QUERYCTRL, &ctrl)) {
+ printf("%s error querying V4L2_CID_MPEG_VIDEO_H264_I_PERIOD errno=%d %s\n",
+ __func__, errno, strerror(errno));
+ } else {
+ printf("%s Got ctrl.id=%#08x type=%d\n",
+ __func__, ctrl.id, ctrl.type);
+ printf("%s\tname=%s minimum=%d maximum=%d\n",
+ __func__, ctrl.name, ctrl.minimum, ctrl.maximum);
+ printf("%s\tstep=%d default_value=%d\n",
+ __func__, ctrl.step, ctrl.default_value);
+ printf("%s\tflags=%#08x\n", __func__, ctrl.flags);
+ }
+
+ /* Query individual extended controls */
+ memset(&ext_ctrl, 0, sizeof(ext_ctrl));
+ ext_ctrl.id = V4L2_CID_MPEG_VIDEO_GOP_SIZE;
+ if (ioctl(fd, VIDIOC_QUERY_EXT_CTRL, &ext_ctrl)) {
+ printf("%s error querying ext V4L2_CID_MPEG_VIDEO_GOP_SIZE errno=%d %s\n",
+ __func__, errno, strerror(errno));
+ } else {
+ printf("%s Got ext_ctrl.id=%#08x type=%d\n",
+ __func__, ext_ctrl.id, ext_ctrl.type);
+ printf("%s\tname=%s minimum=%lld maximum=%lld\n",
+ __func__, ext_ctrl.name, ext_ctrl.minimum,
+ ext_ctrl.maximum);
+ printf("%s\tstep=%lld default_value=%lld\n",
+ __func__, ext_ctrl.step, ext_ctrl.default_value);
+ printf("%s\telem_size=%d elems=%d nr_of_dims=%d\n",
+ __func__, ext_ctrl.elem_size, ext_ctrl.elems,
+ ext_ctrl.nr_of_dims);
+ printf("%s\tflags=%#08x\n", __func__, ctrl.flags);
+ }
+
+ memset(&ext_ctrl, 0, sizeof(ext_ctrl));
+ ext_ctrl.id = V4L2_CID_MPEG_VIDEO_BITRATE;
+ if (ioctl(fd, VIDIOC_QUERY_EXT_CTRL, &ext_ctrl)) {
+ printf("%s error querying ext V4L2_CID_MPEG_VIDEO_BITRATE errno=%d %s\n",
+ __func__, errno, strerror(errno));
+ } else {
+ printf("%s Got ext_ctrl.id=%#08x type=%d\n",
+ __func__, ext_ctrl.id, ext_ctrl.type);
+ printf("%s\tname=%s minimum=%lld maximum=%lld\n",
+ __func__, ext_ctrl.name, ext_ctrl.minimum,
+ ext_ctrl.maximum);
+ printf("%s\tstep=%lld default_value=%lld\n",
+ __func__, ext_ctrl.step, ext_ctrl.default_value);
+ printf("%s\telem_size=%d elems=%d nr_of_dims=%d\n",
+ __func__, ext_ctrl.elem_size, ext_ctrl.elems,
+ ext_ctrl.nr_of_dims);
+ printf("%s\tflags=%#08x\n", __func__, ctrl.flags);
+ }
+
+ memset(&ext_ctrl, 0, sizeof(ext_ctrl));
+ ext_ctrl.id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD;
+ if (ioctl(fd, VIDIOC_QUERY_EXT_CTRL, &ext_ctrl)) {
+ printf("%s error querying ext V4L2_CID_MPEG_VIDEO_H264_I_PERIOD errno=%d %s\n",
+ __func__, errno, strerror(errno));
+ } else {
+ printf("%s Got ext_ctrl.id=%#08x type=%d\n",
+ __func__, ext_ctrl.id, ext_ctrl.type);
+ printf("%s\tname=%s minimum=%lld maximum=%lld\n",
+ __func__, ext_ctrl.name, ext_ctrl.minimum,
+ ext_ctrl.maximum);
+ printf("%s\tstep=%lld default_value=%lld\n",
+ __func__, ext_ctrl.step, ext_ctrl.default_value);
+ printf("%s\telem_size=%d elems=%d nr_of_dims=%d\n",
+ __func__, ext_ctrl.elem_size, ext_ctrl.elems,
+ ext_ctrl.nr_of_dims);
+ printf("%s\tflags=%#08x\n", __func__, ctrl.flags);
+ }
+}
+
+static void get_ctrls(int fd)
+{
+ struct v4l2_ext_controls ctrls;
+ struct v4l2_ext_control controls[3];
+ int i;
+
+ memset(&ctrls, 0, sizeof(ctrls));
+ memset(controls, 0, sizeof(controls));
+
+ ctrls.which = V4L2_CTRL_WHICH_CUR_VAL;
+ ctrls.count = 3;
+ ctrls.controls = controls;
+
+ controls[0].id = V4L2_CID_MPEG_VIDEO_GOP_SIZE;
+ controls[1].id = V4L2_CID_MPEG_VIDEO_BITRATE;
+ controls[2].id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD;
+
+ if (ioctl(fd, VIDIOC_G_EXT_CTRLS, &ctrls)) {
+ printf("%s error getting VIDIOC_G_EXT_CTRLS errno=%d %s\n",
+ __func__, errno, strerror(errno));
+ return;
+ }
+
+ debug_printf("%s got %d values back from VIDIOC_G_EXT_CTRLS\n",
+ __func__, ctrls.count);
+ for (i = 0; i < ctrls.count; i++) {
+ debug_printf("%s controls[%d] id=%#08x got size=%d value=%d\n",
+ __func__, i, controls[i].id,
+ controls[i].size, controls[i].value);
+ }
+}
+
+static void try_ctrls(int fd, int bitrate, int gop_size, int i_period)
+{
+ struct v4l2_ext_controls ctrls;
+ struct v4l2_ext_control controls[3];
+ int i;
+
+ memset(&ctrls, 0, sizeof(ctrls));
+ memset(controls, 0, sizeof(controls));
+
+ ctrls.which = V4L2_CTRL_WHICH_CUR_VAL;
+ ctrls.count = 3;
+ ctrls.controls = controls;
+
+ controls[0].id = V4L2_CID_MPEG_VIDEO_GOP_SIZE;
+ controls[0].value = gop_size;
+ controls[1].id = V4L2_CID_MPEG_VIDEO_BITRATE;
+ controls[1].value = bitrate;
+ controls[2].id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD;
+ controls[2].value = i_period;
+
+ if (ioctl(fd, VIDIOC_TRY_EXT_CTRLS, &ctrls)) {
+ printf("%s error getting VIDIOC_TRY_EXT_CTRLS error_idx=%d errno=%d %s\n",
+ __func__, ctrls.error_idx, errno, strerror(errno));
+ printf("%s Successful commands TRYed:\n", __func__);
+ for (i = 0; i < ctrls.error_idx; i++) {
+ debug_printf("%s controls[%d] id=%#08x got size=%d value=%d\n",
+ __func__, i, controls[i].id,
+ controls[i].size, controls[i].value);
+ }
+ } else {
+ printf("%s VIDIOC_TRY_EXT_CTRLS succeeded\n", __func__);
+ for (i = 0; i < ctrls.count; i++) {
+ debug_printf("%s controls[%d] id=%#08x got size=%d value=%d\n",
+ __func__, i, controls[i].id,
+ controls[i].size, controls[i].value);
+ }
+ }
+
+#ifdef DEBUG
+ printf("%s Testing TRY setting DEF_VAL, EINVAL expected\n", __func__);
+ memset(&ctrls, 0, sizeof(ctrls));
+ memset(controls, 0, sizeof(controls));
+
+ ctrls.which = V4L2_CTRL_WHICH_DEF_VAL;
+ ctrls.count = 3;
+ ctrls.controls = controls;
+
+ controls[0].id = V4L2_CID_MPEG_VIDEO_GOP_SIZE;
+ controls[0].value = 0;
+ controls[1].id = V4L2_CID_MPEG_VIDEO_BITRATE;
+ controls[1].value = 0;
+ controls[2].id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD;
+ controls[2].value = 0;
+
+ if (ioctl(fd, VIDIOC_TRY_EXT_CTRLS, &ctrls)) {
+ printf("%s error getting VIDIOC_TRY_EXT_CTRLS error_idx=%d errno=%d %s\n",
+ __func__, ctrls.error_idx, errno, strerror(errno));
+ for (i = 0; i < ctrls.error_idx; i++) {
+ debug_printf("%s controls[%d] id=%#08x got size=%d value=%d\n",
+ __func__, i, controls[i].id,
+ controls[i].size, controls[i].value);
+ }
+ } else {
+ printf("%s VIDIOC_TRY_EXT_CTRLS succeeded\n", __func__);
+ for (i = 0; i < ctrls.count; i++) {
+ debug_printf("%s controls[%d] id=%#08x got size=%d value=%d\n",
+ __func__, i, controls[i].id,
+ controls[i].size, controls[i].value);
+ }
+ }
+
+ printf("%s Testing TRY setting controls[0] to invalid, ERANGE expected with idx=0\n", __func__);
+ memset(&ctrls, 0, sizeof(ctrls));
+ memset(controls, 0, sizeof(controls));
+
+ ctrls.which = V4L2_CTRL_WHICH_CUR_VAL;
+ ctrls.count = 3;
+ ctrls.controls = controls;
+
+ controls[0].id = V4L2_CID_MPEG_VIDEO_GOP_SIZE;
+ controls[0].value = 0;
+ controls[1].id = V4L2_CID_MPEG_VIDEO_BITRATE;
+ controls[1].value = 0;
+ controls[2].id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD;
+ controls[2].value = 0;
+
+ if (ioctl(fd, VIDIOC_TRY_EXT_CTRLS, &ctrls)) {
+ printf("%s error getting VIDIOC_TRY_EXT_CTRLS error_idx=%d errno=%d %s\n",
+ __func__, ctrls.error_idx, errno, strerror(errno));
+ for (i = 0; i < ctrls.error_idx; i++) {
+ debug_printf("%s controls[%d] id=%#08x got size=%d value=%d\n",
+ __func__, i, controls[i].id,
+ controls[i].size, controls[i].value);
+ }
+ } else {
+ printf("%s VIDIOC_TRY_EXT_CTRLS succeeded\n", __func__);
+ for (i = 0; i < ctrls.count; i++) {
+ debug_printf("%s controls[%d] id=%#08x got size=%d value=%d\n",
+ __func__, i, controls[i].id,
+ controls[i].size, controls[i].value);
+ }
+ }
+
+ printf("%s Testing TRY setting controls[1] to invalid, ERANGE expected with idx=1\n", __func__);
+ memset(&ctrls, 0, sizeof(ctrls));
+ memset(controls, 0, sizeof(controls));
+
+ ctrls.which = V4L2_CTRL_WHICH_CUR_VAL;
+ ctrls.count = 3;
+ ctrls.controls = controls;
+
+ controls[0].id = V4L2_CID_MPEG_VIDEO_GOP_SIZE;
+ controls[0].value = 5;
+ controls[1].id = V4L2_CID_MPEG_VIDEO_BITRATE;
+ controls[1].value = 0;
+ controls[2].id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD;
+ controls[2].value = 0;
+
+ if (ioctl(fd, VIDIOC_TRY_EXT_CTRLS, &ctrls)) {
+ printf("%s error getting VIDIOC_TRY_EXT_CTRLS error_idx=%d errno=%d %s\n",
+ __func__, ctrls.error_idx, errno, strerror(errno));
+ for (i = 0; i < ctrls.error_idx; i++) {
+ debug_printf("%s controls[%d] id=%#08x got size=%d value=%d\n",
+ __func__, i, controls[i].id,
+ controls[i].size, controls[i].value);
+ }
+ } else {
+ printf("%s VIDIOC_TRY_EXT_CTRLS succeeded\n", __func__);
+ for (i = 0; i < ctrls.count; i++) {
+ debug_printf("%s controls[%d] id=%#08x got size=%d value=%d\n",
+ __func__, i, controls[i].id,
+ controls[i].size, controls[i].value);
+ }
+ }
+
+ printf("%s Testing TRY setting controls[2] to invalid, ERANGE expected with idx=2\n", __func__);
+ memset(&ctrls, 0, sizeof(ctrls));
+ memset(controls, 0, sizeof(controls));
+
+ ctrls.which = V4L2_CTRL_WHICH_CUR_VAL;
+ ctrls.count = 3;
+ ctrls.controls = controls;
+
+ controls[0].id = V4L2_CID_MPEG_VIDEO_GOP_SIZE;
+ controls[0].value = 5;
+ controls[1].id = V4L2_CID_MPEG_VIDEO_BITRATE;
+ controls[1].value = 1000000;
+ controls[2].id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD;
+ controls[2].value = 0;
+
+ if (ioctl(fd, VIDIOC_TRY_EXT_CTRLS, &ctrls)) {
+ printf("%s error getting VIDIOC_TRY_EXT_CTRLS error_idx=%d errno=%d %s\n",
+ __func__, ctrls.error_idx, errno, strerror(errno));
+ for (i = 0; i < ctrls.error_idx; i++) {
+ debug_printf("%s controls[%d] id=%#08x got size=%d value=%d\n",
+ __func__, i, controls[i].id,
+ controls[i].size, controls[i].value);
+ }
+ } else {
+ printf("%s VIDIOC_TRY_EXT_CTRLS succeeded\n", __func__);
+ for (i = 0; i < ctrls.count; i++) {
+ debug_printf("%s controls[%d] id=%#08x got size=%d value=%d\n",
+ __func__, i, controls[i].id,
+ controls[i].size, controls[i].value);
+ }
+ }
+#endif
+}
+
+static void set_ctrls(int fd, int bitrate, int gop_size, int i_period)
+{
+ struct v4l2_ext_controls ctrls;
+ struct v4l2_ext_control controls[3];
+ int i;
+
+ memset(&ctrls, 0, sizeof(ctrls));
+ memset(controls, 0, sizeof(controls));
+
+ ctrls.which = V4L2_CTRL_WHICH_CUR_VAL;
+ ctrls.count = 3;
+ ctrls.controls = controls;
+
+ controls[0].id = V4L2_CID_MPEG_VIDEO_GOP_SIZE;
+ controls[0].value = gop_size;
+ controls[1].id = V4L2_CID_MPEG_VIDEO_BITRATE;
+ controls[1].value = bitrate;
+ controls[2].id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD;
+ controls[2].value = i_period;
+
+ if (ioctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls)) {
+ printf("%s error getting VIDIOC_S_EXT_CTRLS error_idx=%d errno=%d %s\n",
+ __func__, ctrls.error_idx, errno, strerror(errno));
+ if (ctrls.error_idx == ctrls.count) {
+ printf("%s S_EXT_CTRLS failed during pre-check\n",
+ __func__);
+ } else {
+ printf("%s S_EXT_CTRLS failed during set. Controls set before failure:\n",
+ __func__);
+ for (i = 0; i < ctrls.error_idx; i++) {
+ printf("%s controls[%d] id=%#08x got size=%d value=%d\n",
+ __func__, i, controls[i].id,
+ controls[i].size, controls[i].value);
+ }
+ }
+ } else {
+ printf("%s VIDIOC_S_EXT_CTRLS succeeded\n", __func__);
+ for (i = 0; i < ctrls.count; i++) {
+ debug_printf("%s controls[%d] id=%#08x got size=%d value=%d\n",
+ __func__, i, controls[i].id,
+ controls[i].size, controls[i].value);
+ }
+ }
+}
+
+static int subscribe_events(int fd)
+{
+ struct v4l2_event_subscription sub;
+
+ sub.type = V4L2_EVENT_EOS;
+ debug_printf("Calling V4L2 IOCTL VIDIOC_SUBSCRIBE_EVENT\n");
+ if (ioctl(fd, VIDIOC_SUBSCRIBE_EVENT, &sub)) {
+ printf("Failed to subscribe to events: err: %d %s\n",
+ errno, strerror(errno));
+ return 1;
+ }
+
+ sub.type = V4L2_EVENT_EOS;
+ debug_printf("Calling V4L2 IOCTL VIDIOC_SUBSCRIBE_EVENT\n");
+ if (ioctl(fd, VIDIOC_SUBSCRIBE_EVENT, &sub)) {
+ printf("Failed to subscribe to events: err: %d %s\n",
+ errno, strerror(errno));
+ return 1;
+ }
+
+ return 0;
+}
+
+static void unsubscribe_events(int fd)
+{
+ struct v4l2_event_subscription sub;
+
+ sub.type = V4L2_EVENT_ALL;
+ debug_printf("Calling V4L2 IOCTL VIDIOC_UNSUBSCRIBE_EVENT\n");
+ if (ioctl(fd, VIDIOC_UNSUBSCRIBE_EVENT, &sub))
+ printf("Failed to unsubscribe from events: err: %d %s\n",
+ errno, strerror(errno));
+
+ return;
+}
+
+static int query_device(int fd)
+{
+ struct v4l2_capability cap = {0};
+ struct v4l2_fmtdesc desc = {0};
+ struct v4l2_frmsizeenum frmsize = {0};
+ int ret = 0;
+
+ debug_printf("%s Enter\n", __func__);
+
+ ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);
+ if (ret) {
+ printf("VIDIOC_QUERYCAP failed\n");
+ return -1;
+ }
+
+ debug_printf("Querycaps: fd=%#x driver=%s card=%s bus_info=%s\n",
+ fd, cap.driver, cap.card, cap.bus_info);
+ debug_printf("Querycaps: device_caps=%#08x capabilities=%#08x\n",
+ cap.device_caps, cap.capabilities);
+
+ desc.index = 0;
+ desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+
+ debug_printf("Calling VIDIOC_ENUM_FMT on CAPTURE\n");
+ while ((ret = ioctl(fd, VIDIOC_ENUM_FMT, &desc)) == 0) {
+ debug_printf("desc.index = %d, pixelformat = %c%c%c%c, desciption = %s\n",
+ desc.index, desc.pixelformat & 0xff,
+ (desc.pixelformat >> 8) & 0xff,
+ (desc.pixelformat >> 16) & 0xff,
+ (desc.pixelformat >> 24) & 0xff,
+ desc.description);
+ desc.index++;
+ }
+
+ desc.index = 0;
+ desc.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+
+ debug_printf("Calling VIDIOC_ENUM_FMT on OUTPUT\n");
+ while ((ret = ioctl(fd, VIDIOC_ENUM_FMT, &desc)) == 0) {
+ debug_printf("desc.index = %d, pixelformat = %c%c%c%c, desciption = %s\n",
+ desc.index, desc.pixelformat & 0xff,
+ (desc.pixelformat >> 8) & 0xff,
+ (desc.pixelformat >> 16) & 0xff,
+ (desc.pixelformat >> 24) & 0xff,
+ desc.description);
+ desc.index++;
+ }
+
+ frmsize.index = 0;
+
+ debug_printf("Calling VIDIOC_ENUM_FRAMESIZES\n");
+ ret = ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmsize);
+ if (ret) {
+ printf("VIDIOC_ENUM_FRAMESIZES failed %d %s\n",
+ errno, strerror(errno));
+ } else if (frmsize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
+ debug_printf("VIDIOC_ENUM_FRAMESIZES got DISCRETE\n");
+ debug_printf("frmsizes[%d] width=%d height=%d\n", frmsize.index,
+ frmsize.discrete.width,
+ frmsize.discrete.height);
+ frmsize.index++;
+ while (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) == 0) {
+ debug_printf("frmsizes[%d] width=%d height=%d\n",
+ frmsize.index,
+ frmsize.discrete.width,
+ frmsize.discrete.height);
+ frmsize.index++;
+ }
+ } else {
+ debug_printf("VIDIOC_ENUM_FRAMESIZES got %s\n",
+ ((frmsize.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) ?
+ "CONTINUOUS" : "STEPWISE"));
+ debug_printf("frmsizes min_width=%d max_width=%d step_width=%d\n",
+ frmsize.stepwise.min_width,
+ frmsize.stepwise.max_width,
+ frmsize.stepwise.step_width);
+ debug_printf("frmsizes min_height=%d max_height=%d step_height=%d\n",
+ frmsize.stepwise.min_height,
+ frmsize.stepwise.max_height,
+ frmsize.stepwise.step_height);
+ }
+ return 0;
+}
+
+static int check_framerate(int fd, int *frameival_num, int *frameival_den)
+{
+ struct v4l2_frmivalenum fival = {0};
+
+ fival.index = 0;
+
+ debug_printf("Calling VIDIOC_ENUM_FRAMEINTERVALS\n");
+ if (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &fival)) {
+ printf("VIDIOC_ENUM_FRAMEINTERVALS failed %d %s\n",
+ errno, strerror(errno));
+ } else if (fival.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
+ debug_printf("VIDIOC_ENUM_FRAMEINTERVALS got DISCRETE\n");
+ debug_printf("fival[%d] numerator=%d denominator=%d framerate=%d\n",
+ fival.index, fival.discrete.numerator,
+ fival.discrete.denominator,
+ (fival.discrete.denominator /
+ fival.discrete.numerator));
+ fival.index++;
+ while (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &fival) == 0) {
+ debug_printf("fival[%d] numerator=%d denominator=%d framerate=%d\n",
+ fival.index, fival.discrete.numerator,
+ fival.discrete.denominator,
+ (fival.discrete.denominator /
+ fival.discrete.numerator));
+ fival.index++;
+ }
+
+ fival.index = 0;
+ while (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &fival) == 0) {
+ if ((fival.discrete.denominator /
+ fival.discrete.numerator) ==
+ (*frameival_den / *frameival_num)) {
+ *frameival_num = fival.discrete.numerator;
+ *frameival_den = fival.discrete.denominator;
+ return 0;
+ }
+ fival.index++;
+ }
+
+ } else {
+ debug_printf("VIDIOC_ENUM_FRAMEINTERVALS got %s\n",
+ ((fival.type == V4L2_FRMIVAL_TYPE_CONTINUOUS) ?
+ "CONTINUOUS" : "STEPWISE"));
+ debug_printf("fival min: numerator=%d denominator=%d framerate=%d\n",
+ fival.stepwise.min.numerator,
+ fival.stepwise.min.denominator,
+ (fival.stepwise.min.denominator /
+ fival.stepwise.min.numerator));
+ debug_printf("fival max: numerator=%d denominator=%d framerate=%d\n",
+ fival.stepwise.max.numerator,
+ fival.stepwise.max.denominator,
+ (fival.stepwise.max.denominator /
+ fival.stepwise.max.numerator));
+ debug_printf("fival step: numerator=%d denominator=%d",
+ fival.stepwise.step.numerator,
+ fival.stepwise.step.denominator);
+
+ printf("CONTINUOUS and STEPWISE FRAMEINTERVALS not supported\n");
+ return 1;
+ }
+
+ printf("Requested frame interval not found, exiting\n");
+ return 1;
+}
+
+static int get_n_frames(int rdfd, int frame_size)
+{
+ int size, ret;;
+ debug_printf("Discovering number of frames in file\n");
+ /*
+ * Seek to end of file to get size, then move file offset
+ * back to beginning of file
+ */
+ size = lseek(rdfd, 0, SEEK_END);
+ lseek(rdfd, 0, SEEK_SET);
+
+ ret = size / frame_size;
+
+ if (size != (frame_size * ret)) {
+ printf("Input file does not contain a whole number of frames\n");
+ return -1;
+ }
+ if (0 == ret){
+ printf("Input file contains no frames\n");
+ return -1;
+ }
+
+ debug_printf("Found %d frames in input file\n", ret);
+ return ret;
+}
+
+static void find_format(char name[], struct tienc_format *format,
+ const struct tienc_format formats[], int formats_size)
+{
+ int i;
+
+ for (i = 0; i < formats_size; i++) {
+ if (0 == strcmp(name, formats[i].name)) {
+ debug_printf("Found format %s\n", name);
+ *format = formats[i];
+ break;
+ }
+ }
+
+ if (i >= formats_size) {
+ printf("No format found. Defaulting to %s\n",
+ formats[0].name);
+ *format = formats[0];
+ }
+}
+
+static void calculate_formats(char format_name[], char codec_name[],
+ struct tienc_format *out_format,
+ struct tienc_format *cap_format,
+ int width, int height)
+{
+ find_format(format_name, out_format, out_formats,
+ (sizeof(out_formats) / sizeof(out_formats[0])));
+ find_format(codec_name, cap_format, cap_formats,
+ (sizeof(cap_formats) / sizeof(cap_formats[0])));
+
+ /* Fill user supplied and calculated values */
+ out_format->width = width;
+ out_format->height = height;
+ out_format->stride = ALIGN(width * out_format->bytes_pp, HW_ALIGN);
+ out_format->size = ((out_format->stride * height) *
+ out_format->size_num) / out_format->size_den;
+
+ cap_format->width = width;
+ cap_format->height = height;
+ cap_format->stride = width;
+ cap_format->size = cap_format->stride * height;
+}
+
+#ifdef DRMMODE
+int find_drm_device(char *drm_path)
+{
+ const char *drm_name = "cardx";
+ char name[256] = "";
+ DIR *d;
+ struct dirent *dir;
+ drmModeResPtr res;
+ int fd;
+
+ d = opendir(drm_path);
+ if (!d) {
+ printf("Failed to open drm device path %s %d %s\n", drm_path,
+ errno, strerror(errno));
+ return -1;
+ }
+
+ while ((dir = readdir(d)) != NULL) {
+ if (strncmp(dir->d_name, drm_name, 4) == 0) {
+ strncpy(name, drm_path, sizeof(name));
+ strncat(name, dir->d_name, sizeof(name));
+ fd = open(name, O_CLOEXEC | O_RDWR);
+ if (fd < 0) {
+ printf("Failed to open drm device %s %d %s\n",
+ name, errno, strerror(errno));
+ continue;
+ }
+
+ res = drmModeGetResources(fd);
+ if (res && res->count_crtcs > 0 &&
+ res->count_connectors > 0 &&
+ res->count_encoders > 0) {
+ debug_printf("No drm device specified, using %s\n",
+ name);
+ break;
+ }
+ close(fd);
+ fd = -1;
+ }
+ }
+
+ if (fd < 0)
+ printf("Failed to find a drm device in %s\n", drm_path);
+
+ return fd;
+}
+#endif
+
+int find_device(char *dev_path)
+{
+ const char *dev_name = "videox";
+ const char *driver_name = "vxe-enc";
+ struct v4l2_capability cap = {0};
+ char name[256] = "";
+ DIR *d;
+ struct dirent *dir;
+ int fd = -1;
+
+ d = opendir(dev_path);
+ if (!d) {
+ printf("Failed to open device path %s %d %s\n", dev_path,
+ errno, strerror(errno));
+ return -1;
+ }
+
+ while ((dir = readdir(d)) != NULL) {
+ if (strncmp(dir->d_name, dev_name, 5) == 0) {
+ strncpy(name, dev_path, sizeof(name));
+ strncat(name, dir->d_name, sizeof(name));
+ fd = open(name, O_RDWR | O_NONBLOCK, 0);
+ if (fd < 0) {
+ printf("Failed to open device %s %d %s\n",
+ name, errno, strerror(errno));
+ continue;
+ }
+
+ memset(&cap, 0, sizeof(cap));
+
+ if (ioctl(fd, VIDIOC_QUERYCAP, &cap)) {
+ printf("VIDIOC_QUERYCAP failed on device %s %d %s\n",
+ name, errno, strerror(errno));
+ close(fd);
+ continue;
+ }
+
+ if (strcmp((const char *)cap.driver, driver_name) == 0) {
+ debug_printf("No device specified, using %s\n",
+ name);
+ break;
+ }
+
+ close(fd);
+ fd = -1;
+ }
+ }
+
+ if (fd < 0)
+ printf("Failed to find device in %s\n", dev_path);
+
+ return fd;
+}
+
+int main (int argc, char **argv)
+{
+ int c, ret;
+ char input_file[256] = {0};
+ char output_file[256] = {0};
+#ifdef DRMMODE
+ const char *default_drm_path = "/dev/dri/";
+#endif
+ const char *default_dev_path = "/dev/";
+ char drm_path[256] = "";
+ char drm_name[256] = "";
+ char dev_path[256] = "";
+ char dev_name[256] = "";
+ char format_name[8] = {0};
+ char codec_name[8] = {0};
+ int fd = -1, drmfd = -1, rdfd = -1, wrfd = -1;
+ int width = 0, height = 0;
+ int n_outbuffers, n_capbuffers;
+ int n_frames = 0;
+ int bitrate = 500000, gop_size = 1800, i_period = 30;
+ int frameival_num = 1, frameival_den = 30;
+ struct tienc_buffer outbuffers[MAX_OUTBUFS];
+ struct tienc_buffer capbuffers[MAX_CAPBUFS];
+ struct tienc_format out_format = {0};
+ struct tienc_format cap_format = {0};
+ enum v4l2_memory out_memory = V4L2_MEMORY_MMAP;
+ enum v4l2_memory cap_memory = V4L2_MEMORY_MMAP;
+
+ debug_printf("%s Enter\n", __func__);
+
+ n_capbuffers = MAX_CAPBUFS;
+ n_outbuffers = MAX_OUTBUFS;
+
+ while (1) {
+ c = getopt(argc, argv, "i:o:d:w:h:f:c:n:b:g:p:r:jkl:m:");
+ if (-1 == c)
+ break;
+ switch (c) {
+ case 'i':
+ snprintf(input_file, sizeof(input_file),
+ "%s", optarg);
+ break;
+ case 'o':
+ snprintf(output_file, sizeof(output_file),
+ "%s", optarg);
+ break;
+ case 'd':
+ snprintf(dev_name, sizeof(dev_name), "%s", optarg);
+ break;
+ case 'e':
+ snprintf(dev_path, sizeof(dev_path), "%s", optarg);
+ break;
+ case 'w':
+ width = atoi(optarg);
+ break;
+ case 'h':
+ height = atoi(optarg);
+ break;
+ case 'f':
+ snprintf(format_name, sizeof(format_name),
+ "%s", optarg);
+ break;
+ case 'c':
+ snprintf(codec_name, sizeof(codec_name),
+ "%s", optarg);
+ break;
+ case 'n':
+ n_frames = atoi(optarg);
+ break;
+ case 'b':
+ bitrate = atoi(optarg);
+ break;
+ case 'g':
+ gop_size = atoi(optarg);
+ break;
+ case 'p':
+ i_period = atoi(optarg);
+ break;
+ case 'r':
+ frameival_den = atoi(optarg);
+ break;
+ case 'j':
+ out_memory = V4L2_MEMORY_DMABUF;
+ break;
+ case 'k':
+ cap_memory = V4L2_MEMORY_DMABUF;
+ break;
+ case 'l':
+ snprintf(drm_name, sizeof(drm_name), "%s", optarg);
+ break;
+ case 'm':
+ snprintf(drm_path, sizeof(drm_path), "%s", optarg);
+ break;
+ default:
+ printf("Use:\n");
+ printf("\t./tienc_encode -i <input_file> -w <width> -h <height> [OPTIONS]\n");
+ break;
+ }
+ }
+
+ /* Validate input args */
+ if ((0 == strlen(input_file)) || (0 >= width) || (0 >= height)) {
+ printf("Requires input values\n");
+ printf("\t./tienc_encode -i <input_file> -w <width> -h <height> [OPTIONS]\n");
+ printf("\tOPTIONS:\n");
+ printf("\t\t-o <output_file_name>\n");
+ printf("\t\t\tDump output stream to file\n");
+ printf("\t\t-d <device>\n");
+ printf("\t\t\tLocation of device node (ex. /dev/video0)\n");
+ printf("\t\t-e <device_path>\n");
+ printf("\t\t\tDirectory of device node (ex. /dev/)\n");
+ printf("\t\t\tNot needed if -d argument is provided\n");
+ printf("\t\t-f <format>\n");
+ printf("\t\t\tInput image format. Available formats:\n");
+ printf("\t\t\t\tNV12\n");
+ printf("\t\t\t\tRGBA\n");
+ printf("\t\t-c <codec>\n");
+ printf("\t\t\tOutput stream codec. Available codecs\n");
+ printf("\t\t\t\tH264\n");
+ printf("\t\t-n <n_frames>\n");
+ printf("\t\t\tNumber of frames to encode\n");
+ printf("\t\t-b <bitrate>\n");
+ printf("\t\t\tBitrate in bits per second\n");
+ printf("\t\t-g <gop_size>\n");
+ printf("\t\t\tIDR frame interval\n");
+ printf("\t\t-p <i_period>\n");
+ printf("\t\t\tI frame period in H264\n");
+ printf("\t\t-r <framerate>\n");
+ printf("\t\t\tFramerate in frames per second\n");
+ printf("\t\t-j\n");
+ printf("\t\t\tUse DMA buffers for output stream\n");
+ printf("\t\t-k\n");
+ printf("\t\t\tUse DMA buffers for capture stream\n");
+ printf("\t\t-l <drm_device_name>\n");
+ printf("\t\t\tLocation of drm device (ex. /dev/dri/card0)\n");
+ printf("\t\t-m <drm_device-path>\n");
+ printf("\t\t\tDirectory of drm device node (ex. /dev/dri/)\n");
+ printf("\t\t\tNot needed if -l argument is provided\n");
+ ret = -1;
+ goto exit_failure;
+ }
+
+ calculate_formats(format_name, codec_name, &out_format, &cap_format,
+ width, height);
+
+ out_format.memory = out_memory;
+ cap_format.memory = cap_memory;
+
+ if ((out_format.memory == V4L2_MEMORY_DMABUF) ||
+ (cap_format.memory == V4L2_MEMORY_DMABUF)) {
+ if (strlen(drm_name)) {
+#ifdef DRM
+ /* Known DRM node name */
+ drmfd = open(drm_name, O_CLOEXEC | O_RDWR);
+ if (drmfd < 0) {
+ printf("Failed to open drm device %d %s\n",
+ errno, strerror(errno));
+ ret = -1;
+ goto exit_failure;
+ }
+#else
+ printf("DRM not supported with current build arguments\n");
+ ret = -1;
+ goto exit_failure;
+#endif
+ } else {
+#ifdef DRMMODE
+ /* Search DRM directory */
+ if (strlen(drm_path) == 0)
+ snprintf(drm_path, sizeof(drm_path), "%s",
+ default_drm_path);
+
+ drmfd = find_drm_device(drm_path);
+ if (drmfd < 0) {
+ printf("Failed to find drm device\n");
+ ret = -1;
+ goto exit_failure;
+ }
+#else
+ printf("Can't search DRM directory\n");
+ ret = -1;
+ goto exit_failure;
+#endif
+ }
+ }
+
+ rdfd = open(input_file, O_RDONLY);
+ if (0 > rdfd) {
+ printf("Failed to open input file: %s\n", input_file);
+ ret = -1;
+ goto drm_opened;
+ }
+ debug_printf("Opened input file: %s\n", input_file);
+
+ ret = get_n_frames(rdfd, ((out_format.width * out_format.height *
+ out_format.size_num) / out_format.size_den));
+ if (0 >= ret)
+ goto rdfd_opened;
+
+ if (n_frames == 0) {
+ debug_printf("Found %d frames\n", ret);
+ n_frames = ret;
+ } else if (ret > n_frames) {
+ debug_printf("More than %d frames found, limiting to %d frames\n",
+ n_frames, n_frames);
+ } else {
+ debug_printf("Less than %d frames found, using max of %d frames\n",
+ n_frames, ret);
+ n_frames = ret;
+ }
+
+ if (strlen(output_file)) {
+ wrfd = open(output_file, O_CREAT | O_WRONLY | O_TRUNC, 0777);
+ if (0 > wrfd) {
+ printf("Failed to open output file: %s\n", output_file);
+ ret = -1;
+ goto rdfd_opened;
+ }
+ debug_printf("Outputting to %s\n", output_file);
+ }
+
+ if (strlen(dev_name)) {
+ fd = open(dev_name, O_RDWR | O_NONBLOCK, 0);
+ if (0 > fd) {
+ printf("Failed to open device: %s\n", dev_name);
+ ret = -1;
+ goto wrfd_opened;
+ }
+ debug_printf("Opened device %s\n", dev_name);
+ } else {
+ /* Search dev directory */
+ if (strlen(dev_path) == 0)
+ snprintf(dev_path, sizeof(dev_path), "%s",
+ default_dev_path);
+
+ fd = find_device(dev_path);
+ if (fd < 0) {
+ printf("Failed to find device\n");
+ ret = -1;
+ goto wrfd_opened;
+ }
+ }
+
+ ret = query_device(fd);
+ if (ret)
+ goto dev_opened;
+
+ ret = check_framerate(fd, &frameival_num, &frameival_den);
+ if (ret)
+ goto dev_opened;
+
+ ret = subscribe_events(fd);
+ if (ret)
+ goto dev_opened;
+
+ query_ctrls(fd);
+ get_ctrls(fd);
+ try_ctrls(fd, bitrate, gop_size, i_period);
+ set_ctrls(fd, bitrate, gop_size, i_period);
+ get_ctrls(fd);
+
+ get_parameters(fd);
+ ret = set_parameters(fd, frameival_num, frameival_den);
+ if (ret)
+ goto dev_opened;
+ get_parameters(fd);
+
+ get_format(fd, out_format);
+ get_format(fd, cap_format);
+
+ try_format(fd, out_format);
+ try_format(fd, cap_format);
+
+ ret = set_format(fd, out_format);
+ if (ret)
+ goto events_subscribed;
+
+ ret = set_format(fd, cap_format);
+ if (ret)
+ goto events_subscribed;
+
+ get_format(fd, out_format);
+ get_format(fd, cap_format);
+
+ ret = alloc_bufs(fd, drmfd, &n_outbuffers, outbuffers,
+ V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, out_format);
+ if (ret)
+ goto bufs_alloced;
+
+ ret = alloc_bufs(fd, drmfd, &n_capbuffers, capbuffers,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, cap_format);
+ if (ret)
+ goto bufs_alloced;
+
+ ret = streaming_loop(fd, rdfd, wrfd, outbuffers,
+ capbuffers, n_outbuffers,
+ n_capbuffers, out_format, cap_format,
+ n_frames);
+ if (ret)
+ goto bufs_alloced;
+
+ ret = 0;
+
+bufs_alloced:
+ dealloc_bufs(fd, drmfd, &n_outbuffers, outbuffers, out_format);
+ dealloc_bufs(fd, drmfd, &n_capbuffers, capbuffers, cap_format);
+events_subscribed:
+ unsubscribe_events(fd);
+dev_opened:
+ close(fd);
+wrfd_opened:
+ if (0 <= wrfd)
+ close(wrfd);
+rdfd_opened:
+ close(rdfd);
+drm_opened:
+ close(drmfd);
+exit_failure:
+ return ret;
+}
diff --git a/main.h b/main.h
--- /dev/null
+++ b/main.h
@@ -0,0 +1,61 @@
+/*
+ * Texas Instruments IMG video encoder driver test application header
+ *
+ * Copyright (c) 2019 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/videodev2.h>
+
+#define MAX_CAPBUFS 2
+#define MAX_OUTBUFS 2
+#define MAX_PLANES 3
+
+#define ALIGN(x,a) (((x) + (a) - 1L) & ~((a) - 1L))
+#define HW_ALIGN 64
+struct tienc_buffer {
+ void *mapped;
+ int offset;
+ int length;
+ unsigned int bo_handle;
+ int dbuf_fd;
+};
+
+/*
+ * struct tienc_format: Describes formats
+ *
+ * name: Name of format for finding
+ * type: V4L2 type of format (input/output)
+ * fourcc: V4L2 fourcc
+ * size_num: Numerator for image buffer size calculation
+ * size_den: Denominator for image buffer size calculation
+ * n_planes: Number of buffer planes
+ * width: Image width
+ * height: Image height
+ * stride: Image stride
+ * size: Calculated size of image data
+ * bytes_pp: Number of bytes per pixel
+ * memory: Type of memory to use
+ */
+struct tienc_format {
+ char *name;
+ uint32_t type;
+ uint32_t fourcc;
+ int size_num;
+ int size_den;
+ int n_planes;
+ int width;
+ int height;
+ int stride;
+ int size;
+ int bytes_pp;
+ enum v4l2_memory memory;
+};