summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@ideasonboard.com>2021-10-06 10:26:00 +0300
committerTomi Valkeinen <tomi.valkeinen@ideasonboard.com>2021-10-06 10:44:26 +0300
commit2b1a8f48f3a414e565cefb809f3e6a7c6aa5f8a7 (patch)
tree3f274b92d00754e6a5980f07b2c9cefcbf2cae53
parentf691ed65d6bcfff0abbc2d7ce58e560af3ee63dc (diff)
Split V4L2 code into separate libs
Create v4l2++ library and pyv4l2, which are independent from the rest of the kms++. Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
-rw-r--r--kms++util/meson.build2
-rw-r--r--meson.build4
-rw-r--r--meson_options.txt6
-rw-r--r--py/meson.build4
-rw-r--r--py/pykms/meson.build1
-rw-r--r--py/pykms/pykms.cpp3
-rw-r--r--py/pykms/pyvid.cpp46
-rw-r--r--py/pyv4l2/__init__.py5
-rw-r--r--py/pyv4l2/meson.build38
-rw-r--r--py/pyv4l2/pyv4l2.cpp153
-rw-r--r--utils/meson.build6
-rw-r--r--utils/omap-wbcap.cpp29
-rw-r--r--utils/omap-wbm2m.cpp50
-rw-r--r--v4l2++/inc/v4l2++/helpers.h60
-rw-r--r--v4l2++/inc/v4l2++/pixelformats.h111
-rw-r--r--v4l2++/inc/v4l2++/videodevice.h (renamed from kms++util/inc/kms++util/videodevice.h)77
-rw-r--r--v4l2++/meson.build32
-rw-r--r--v4l2++/src/helpers.cpp16
-rw-r--r--v4l2++/src/pixelformats.cpp301
-rw-r--r--v4l2++/src/videodevice.cpp (renamed from kms++util/src/videodevice.cpp)153
20 files changed, 974 insertions, 123 deletions
diff --git a/kms++util/meson.build b/kms++util/meson.build
index 9df75e1..1b226f3 100644
--- a/kms++util/meson.build
+++ b/kms++util/meson.build
@@ -8,7 +8,6 @@ libkmsxxutil_sources = files([
'src/resourcemanager.cpp',
'src/strhelpers.cpp',
'src/testpat.cpp',
- 'src/videodevice.cpp',
])
public_headers = [
@@ -20,7 +19,6 @@ public_headers = [
'inc/kms++util/opts.h',
'inc/kms++util/extcpuframebuffer.h',
'inc/kms++util/resourcemanager.h',
- 'inc/kms++util/videodevice.h',
]
private_includes = include_directories('src', 'inc')
diff --git a/meson.build b/meson.build
index 1325a3f..3de7b6a 100644
--- a/meson.build
+++ b/meson.build
@@ -38,6 +38,10 @@ libdrmomap_dep = dependency('libdrm_omap', required : get_option('omap'))
subdir('kms++')
+if get_option('v4l2').enabled()
+ subdir('v4l2++')
+endif
+
if get_option('libutils')
subdir('kms++util')
endif
diff --git a/meson_options.txt b/meson_options.txt
index 979753e..9e17c24 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -13,5 +13,11 @@ option('utils', type : 'boolean', value : true,
option('pykms', type : 'feature', value : 'auto',
description : 'Build python bindings')
+option('v4l2', type : 'feature', value : 'disabled',
+ description : 'Build V4L2++ library (HACK)')
+
+option('pyv4l2', type : 'feature', value : 'disabled',
+ description : 'Build V4L2 python bindings (HACK)')
+
option('kmscube', type : 'boolean', value : false,
description : 'Build kmscube test application')
diff --git a/py/meson.build b/py/meson.build
index 3130bf2..fcba3e5 100644
--- a/py/meson.build
+++ b/py/meson.build
@@ -1 +1,5 @@
subdir('pykms')
+
+if get_option('v4l2').enabled()
+ subdir('pyv4l2')
+endif
diff --git a/py/pykms/meson.build b/py/pykms/meson.build
index e030ce8..db5cbd0 100644
--- a/py/pykms/meson.build
+++ b/py/pykms/meson.build
@@ -19,7 +19,6 @@ pykms_sources = files([
if get_option('utils')
pykms_sources += files([
'pykmsutil.cpp',
- 'pyvid.cpp',
])
endif
diff --git a/py/pykms/pykms.cpp b/py/pykms/pykms.cpp
index b91a1a9..e9266a4 100644
--- a/py/pykms/pykms.cpp
+++ b/py/pykms/pykms.cpp
@@ -9,7 +9,6 @@ using namespace std;
void init_pykmstest(py::module& m);
void init_pykmsbase(py::module& m);
-void init_pyvid(py::module& m);
#if HAS_LIBDRM_OMAP
void init_pykmsomap(py::module& m);
@@ -21,8 +20,6 @@ PYBIND11_MODULE(pykms, m)
init_pykmstest(m);
- init_pyvid(m);
-
#if HAS_LIBDRM_OMAP
init_pykmsomap(m);
#endif
diff --git a/py/pykms/pyvid.cpp b/py/pykms/pyvid.cpp
deleted file mode 100644
index 54ad480..0000000
--- a/py/pykms/pyvid.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-#include <pybind11/pybind11.h>
-#include <pybind11/stl.h>
-#include <kms++/kms++.h>
-#include <kms++util/kms++util.h>
-#include <kms++util/videodevice.h>
-
-namespace py = pybind11;
-
-using namespace kms;
-using namespace std;
-
-void init_pyvid(py::module& m)
-{
- py::class_<VideoDevice>(m, "VideoDevice")
- .def(py::init<const string&>())
- .def_property_readonly("fd", &VideoDevice::fd)
- .def_property_readonly("has_capture", &VideoDevice::has_capture)
- .def_property_readonly("has_output", &VideoDevice::has_output)
- .def_property_readonly("has_m2m", &VideoDevice::has_m2m)
- .def_property_readonly("capture_streamer", &VideoDevice::get_capture_streamer)
- .def_property_readonly("output_streamer", &VideoDevice::get_output_streamer)
- .def_property_readonly("discrete_frame_sizes", &VideoDevice::get_discrete_frame_sizes)
- .def_property_readonly("frame_sizes", &VideoDevice::get_frame_sizes)
- .def("get_capture_devices", &VideoDevice::get_capture_devices);
-
- py::class_<VideoStreamer>(m, "VideoStreamer")
- .def_property_readonly("fd", &VideoStreamer::fd)
- .def_property_readonly("ports", &VideoStreamer::get_ports)
- .def("set_port", &VideoStreamer::set_port)
- .def_property_readonly("formats", &VideoStreamer::get_formats)
- .def("set_format", &VideoStreamer::set_format)
- .def("get_selection", [](VideoStreamer* self) {
- uint32_t left, top, width, height;
- self->get_selection(left, top, width, height);
- return make_tuple(left, top, width, height);
- })
- .def("set_selection", [](VideoStreamer* self, uint32_t left, uint32_t top, uint32_t width, uint32_t height) {
- self->set_selection(left, top, width, height);
- return make_tuple(left, top, width, height);
- })
- .def("set_queue_size", &VideoStreamer::set_queue_size)
- .def("queue", &VideoStreamer::queue)
- .def("dequeue", &VideoStreamer::dequeue)
- .def("stream_on", &VideoStreamer::stream_on)
- .def("stream_off", &VideoStreamer::stream_off);
-}
diff --git a/py/pyv4l2/__init__.py b/py/pyv4l2/__init__.py
new file mode 100644
index 0000000..02541c5
--- /dev/null
+++ b/py/pyv4l2/__init__.py
@@ -0,0 +1,5 @@
+from .pyv4l2 import *
+from enum import Enum
+import os
+import struct
+
diff --git a/py/pyv4l2/meson.build b/py/pyv4l2/meson.build
new file mode 100644
index 0000000..03b0dcc
--- /dev/null
+++ b/py/pyv4l2/meson.build
@@ -0,0 +1,38 @@
+py3_dep = dependency('python3', required : get_option('pyv4l2'))
+
+if py3_dep.found() == false
+ subdir_done()
+endif
+
+pybind11_dep = dependency('pybind11', fallback : ['pybind11', 'pybind11_dep'],
+ required : get_option('pyv4l2'))
+
+if pybind11_dep.found() == false
+ subdir_done()
+endif
+
+pyv4l2_sources = files([
+ 'pyv4l2.cpp',
+])
+
+pyv4l2_deps = [
+ libv4l2xx_dep,
+ py3_dep,
+ pybind11_dep,
+]
+
+pyv4l2_args = [ '-fvisibility=hidden' ]
+
+destdir = get_option('libdir') / 'python' + py3_dep.version() / 'site-packages/pyv4l2'
+
+pyv4l2 = shared_module('pyv4l2',
+ pyv4l2_sources,
+ install : true,
+ install_dir : destdir,
+ name_prefix : '',
+ dependencies : pyv4l2_deps,
+ cpp_args : pyv4l2_args)
+
+# Copy __init__.py to build dir so that we can run without installing
+configure_file(input: '__init__.py', output: '__init__.py', copy: true,
+ install : true, install_dir : destdir)
diff --git a/py/pyv4l2/pyv4l2.cpp b/py/pyv4l2/pyv4l2.cpp
new file mode 100644
index 0000000..ec96835
--- /dev/null
+++ b/py/pyv4l2/pyv4l2.cpp
@@ -0,0 +1,153 @@
+#include <pybind11/pybind11.h>
+#include <pybind11/stl.h>
+#include <v4l2++/videodevice.h>
+#include <fmt/format.h>
+
+namespace py = pybind11;
+
+using namespace v4l2;
+using namespace std;
+
+PYBIND11_MODULE(pyv4l2, m)
+{
+ py::class_<VideoDevice>(m, "VideoDevice")
+ .def(py::init<const string&>())
+ .def_property_readonly("fd", &VideoDevice::fd)
+ .def_property_readonly("has_capture", &VideoDevice::has_capture)
+ .def_property_readonly("has_output", &VideoDevice::has_output)
+ .def_property_readonly("has_m2m", &VideoDevice::has_m2m)
+ .def_property_readonly("capture_streamer", &VideoDevice::get_capture_streamer)
+ .def_property_readonly("output_streamer", &VideoDevice::get_output_streamer)
+ .def_property_readonly("meta_capture_streamer", &VideoDevice::get_meta_capture_streamer)
+ .def_property_readonly("discrete_frame_sizes", &VideoDevice::get_discrete_frame_sizes)
+ .def_property_readonly("frame_sizes", &VideoDevice::get_frame_sizes)
+ .def("get_capture_devices", &VideoDevice::get_capture_devices);
+
+ py::enum_<VideoMemoryType>(m, "VideoMemoryType")
+ .value("MMAP", VideoMemoryType::MMAP)
+ .value("DMABUF", VideoMemoryType::DMABUF)
+ ;
+
+ m.def("create_dmabuffer", [](int fd) {
+ VideoBuffer buf {};
+ buf.m_mem_type = VideoMemoryType::DMABUF;
+ buf.m_fd = fd;
+ return buf;
+ });
+
+ m.def("create_mmapbuffer", []() {
+ VideoBuffer buf {};
+ buf.m_mem_type = VideoMemoryType::MMAP;
+ return buf;
+ });
+
+ py::class_<VideoBuffer>(m, "VideoBuffer")
+ .def_readonly("index", &VideoBuffer::m_index)
+ .def_readonly("offset", &VideoBuffer::m_offset)
+ .def_readonly("fd", &VideoBuffer::m_fd)
+ .def_readonly("length", &VideoBuffer::m_length)
+ ;
+
+ py::class_<VideoStreamer>(m, "VideoStreamer")
+ .def_property_readonly("fd", &VideoStreamer::fd)
+ .def_property_readonly("ports", &VideoStreamer::get_ports)
+ .def("set_port", &VideoStreamer::set_port)
+ .def_property_readonly("formats", &VideoStreamer::get_formats)
+ .def("get_format", [](VideoStreamer* self) {
+ PixelFormat fmt;
+ uint32_t w, h;
+
+ int r = self->get_format(fmt, w, h);
+ if (r)
+ throw std::system_error(errno, std::generic_category(), "get_format failed");
+
+ return make_tuple(w, h, fmt);
+ })
+ .def("set_format", &VideoStreamer::set_format)
+ .def("get_selection", [](VideoStreamer* self) {
+ uint32_t left, top, width, height;
+ self->get_selection(left, top, width, height);
+ return make_tuple(left, top, width, height);
+ })
+ .def("set_selection", [](VideoStreamer* self, uint32_t left, uint32_t top, uint32_t width, uint32_t height) {
+ self->set_selection(left, top, width, height);
+ return make_tuple(left, top, width, height);
+ })
+ .def("set_queue_size", &VideoStreamer::set_queue_size)
+ .def("queue", &VideoStreamer::queue)
+ .def("dequeue", &VideoStreamer::dequeue)
+ .def("stream_on", &VideoStreamer::stream_on)
+ .def("stream_off", &VideoStreamer::stream_off);
+
+ py::class_<MetaStreamer>(m, "MetaStreamer")
+ .def_property_readonly("fd", &MetaStreamer::fd)
+ .def("set_format", &MetaStreamer::set_format)
+ .def("set_queue_size", &MetaStreamer::set_queue_size)
+ .def("queue", &MetaStreamer::queue)
+ .def("dequeue", &MetaStreamer::dequeue)
+ .def("stream_on", &MetaStreamer::stream_on)
+ .def("stream_off", &MetaStreamer::stream_off);
+
+ py::enum_<PixelFormat>(m, "PixelFormat")
+ .value("Undefined", PixelFormat::Undefined)
+
+ .value("NV12", PixelFormat::NV12)
+ .value("NV21", PixelFormat::NV21)
+ .value("NV16", PixelFormat::NV16)
+ .value("NV61", PixelFormat::NV61)
+
+ .value("YUV420", PixelFormat::YUV420)
+ .value("YVU420", PixelFormat::YVU420)
+ .value("YUV422", PixelFormat::YUV422)
+ .value("YVU422", PixelFormat::YVU422)
+ .value("YUV444", PixelFormat::YUV444)
+ .value("YVU444", PixelFormat::YVU444)
+
+ .value("UYVY", PixelFormat::UYVY)
+ .value("YUYV", PixelFormat::YUYV)
+ .value("YVYU", PixelFormat::YVYU)
+ .value("VYUY", PixelFormat::VYUY)
+
+ .value("XRGB8888", PixelFormat::XRGB8888)
+ .value("XBGR8888", PixelFormat::XBGR8888)
+ .value("RGBX8888", PixelFormat::RGBX8888)
+ .value("BGRX8888", PixelFormat::BGRX8888)
+
+ .value("ARGB8888", PixelFormat::ARGB8888)
+ .value("ABGR8888", PixelFormat::ABGR8888)
+ .value("RGBA8888", PixelFormat::RGBA8888)
+ .value("BGRA8888", PixelFormat::BGRA8888)
+
+ .value("RGB888", PixelFormat::RGB888)
+ .value("BGR888", PixelFormat::BGR888)
+
+ .value("RGB332", PixelFormat::RGB332)
+
+ .value("RGB565", PixelFormat::RGB565)
+ .value("BGR565", PixelFormat::BGR565)
+
+ .value("XRGB4444", PixelFormat::XRGB4444)
+ .value("XRGB1555", PixelFormat::XRGB1555)
+
+ .value("ARGB4444", PixelFormat::ARGB4444)
+ .value("ARGB1555", PixelFormat::ARGB1555)
+
+ .value("XRGB2101010", PixelFormat::XRGB2101010)
+ .value("XBGR2101010", PixelFormat::XBGR2101010)
+ .value("RGBX1010102", PixelFormat::RGBX1010102)
+ .value("BGRX1010102", PixelFormat::BGRX1010102)
+
+ .value("ARGB2101010", PixelFormat::ARGB2101010)
+ .value("ABGR2101010", PixelFormat::ABGR2101010)
+ .value("RGBA1010102", PixelFormat::RGBA1010102)
+ .value("BGRA1010102", PixelFormat::BGRA1010102)
+
+ .value("SBGGR12", PixelFormat::SBGGR12)
+ .value("SRGGB12", PixelFormat::SRGGB12)
+
+ .value("META_8", PixelFormat::META_8)
+ .value("META_16", PixelFormat::META_16);
+
+
+ m.def("fourcc_to_pixelformat", &FourCCToPixelFormat);
+}
diff --git a/utils/meson.build b/utils/meson.build
index b1e7918..ac73b5b 100644
--- a/utils/meson.build
+++ b/utils/meson.build
@@ -13,5 +13,7 @@ if libevdev_dep.found()
executable('kmstouch', 'kmstouch.cpp', dependencies : [ common_deps, libevdev_dep ], install : false)
endif
-executable('omap-wbcap', 'omap-wbcap.cpp', dependencies : [ common_deps ], install : false)
-executable('omap-wbm2m', 'omap-wbm2m.cpp', dependencies : [ common_deps ], install : false)
+if get_option('v4l2').enabled()
+ executable('omap-wbcap', 'omap-wbcap.cpp', dependencies : [ common_deps, libv4l2xx_dep ], install : false)
+ executable('omap-wbm2m', 'omap-wbm2m.cpp', dependencies : [ common_deps, libv4l2xx_dep ], install : false)
+endif
diff --git a/utils/omap-wbcap.cpp b/utils/omap-wbcap.cpp
index 8033869..5080159 100644
--- a/utils/omap-wbcap.cpp
+++ b/utils/omap-wbcap.cpp
@@ -6,7 +6,7 @@
#include <kms++/kms++.h>
#include <kms++util/kms++util.h>
-#include <kms++util/videodevice.h>
+#include <v4l2++/videodevice.h>
#define CAMERA_BUF_QUEUE_SIZE 5
@@ -21,17 +21,21 @@ static vector<DumbFramebuffer*> s_ready_fbs;
class WBStreamer
{
public:
- WBStreamer(VideoStreamer* streamer, Crtc* crtc, PixelFormat pixfmt)
+ WBStreamer(v4l2::VideoStreamer* streamer, Crtc* crtc, PixelFormat pixfmt)
: m_capdev(*streamer)
{
Videomode m = crtc->mode();
m_capdev.set_port(crtc->idx());
- m_capdev.set_format(pixfmt, m.hdisplay, m.vdisplay / (m.interlace() ? 2 : 1));
- m_capdev.set_queue_size(s_fbs.size());
+ m_capdev.set_format((v4l2::PixelFormat)pixfmt, m.hdisplay, m.vdisplay / (m.interlace() ? 2 : 1));
+ m_capdev.set_queue_size(s_fbs.size(), v4l2::VideoMemoryType::DMABUF);
for (auto fb : s_free_fbs) {
- m_capdev.queue(fb);
+ v4l2::VideoBuffer vbuf {};
+ vbuf.m_mem_type = v4l2::VideoMemoryType::DMABUF;
+ vbuf.m_fd = fb->prime_fd(0);
+
+ m_capdev.queue(vbuf);
s_wb_fbs.push_back(fb);
}
@@ -59,9 +63,10 @@ public:
DumbFramebuffer* Dequeue()
{
- auto fb = m_capdev.dequeue();
+ auto vbuf = m_capdev.dequeue();
- auto iter = find(s_wb_fbs.begin(), s_wb_fbs.end(), fb);
+ auto iter = find_if(s_wb_fbs.begin(), s_wb_fbs.end(), [fd=vbuf.m_fd](auto& fb) { return fb->prime_fd(0) == fd; });
+ auto fb = *iter;
s_wb_fbs.erase(iter);
s_ready_fbs.insert(s_ready_fbs.begin(), fb);
@@ -77,13 +82,17 @@ public:
auto fb = s_free_fbs.back();
s_free_fbs.pop_back();
- m_capdev.queue(fb);
+ v4l2::VideoBuffer vbuf {};
+ vbuf.m_mem_type = v4l2::VideoMemoryType::DMABUF;
+ vbuf.m_fd = fb->prime_fd(0);
+
+ m_capdev.queue(vbuf);
s_wb_fbs.insert(s_wb_fbs.begin(), fb);
}
private:
- VideoStreamer& m_capdev;
+ v4l2::VideoStreamer& m_capdev;
};
class WBFlipState : private PageFlipHandlerBase
@@ -304,7 +313,7 @@ int main(int argc, char** argv)
if (dst_conn_name.empty())
EXIT("No destination connector defined");
- VideoDevice vid("/dev/video11");
+ v4l2::VideoDevice vid("/dev/video11");
Card card;
ResourceManager resman(card);
diff --git a/utils/omap-wbm2m.cpp b/utils/omap-wbm2m.cpp
index a00fab2..6ac08e0 100644
--- a/utils/omap-wbm2m.cpp
+++ b/utils/omap-wbm2m.cpp
@@ -10,7 +10,7 @@
#include <kms++/kms++.h>
#include <kms++util/kms++util.h>
-#include <kms++util/videodevice.h>
+#include <v4l2++/videodevice.h>
const uint32_t NUM_SRC_BUFS = 2;
const uint32_t NUM_DST_BUFS = 2;
@@ -106,38 +106,55 @@ int main(int argc, char** argv)
printf("writing to %s\n", filename.c_str());
- VideoDevice vid("/dev/video10");
+ v4l2::VideoDevice vid("/dev/video10");
Card card;
uint32_t src_frame_num = 0;
uint32_t dst_frame_num = 0;
- VideoStreamer* out = vid.get_output_streamer();
- VideoStreamer* in = vid.get_capture_streamer();
+ v4l2::VideoStreamer* out = vid.get_output_streamer();
+ v4l2::VideoStreamer* in = vid.get_capture_streamer();
- out->set_format(src_fmt, src_width, src_height);
- in->set_format(dst_fmt, dst_width, dst_height);
+ out->set_format((v4l2::PixelFormat)src_fmt, src_width, src_height);
+ in->set_format((v4l2::PixelFormat)dst_fmt, dst_width, dst_height);
if (use_selection) {
out->set_selection(c_left, c_top, c_width, c_height);
printf("crop -> %u,%u-%ux%u\n", c_left, c_top, c_width, c_height);
}
- out->set_queue_size(NUM_SRC_BUFS);
- in->set_queue_size(NUM_DST_BUFS);
+ out->set_queue_size(NUM_SRC_BUFS, v4l2::VideoMemoryType::DMABUF);
+ in->set_queue_size(NUM_DST_BUFS, v4l2::VideoMemoryType::DMABUF);
+
+ vector<DumbFramebuffer*> out_fbs;
for (unsigned i = 0; i < min(NUM_SRC_BUFS, num_src_frames); ++i) {
auto fb = new DumbFramebuffer(card, src_width, src_height, src_fmt);
read_frame(fb, src_frame_num++);
- out->queue(fb);
+ out_fbs.push_back(fb);
+
+ v4l2::VideoBuffer vbuf {};
+ vbuf.m_mem_type = v4l2::VideoMemoryType::DMABUF;
+ vbuf.m_fd = fb->prime_fd(0);
+
+ out->queue(vbuf);
}
+ vector<DumbFramebuffer*> in_fbs;
+
for (unsigned i = 0; i < min(NUM_DST_BUFS, num_src_frames); ++i) {
auto fb = new DumbFramebuffer(card, dst_width, dst_height, dst_fmt);
- in->queue(fb);
+
+ in_fbs.push_back(fb);
+
+ v4l2::VideoBuffer vbuf {};
+ vbuf.m_mem_type = v4l2::VideoMemoryType::DMABUF;
+ vbuf.m_fd = fb->prime_fd(0);
+
+ in->queue(vbuf);
}
vector<pollfd> fds(3);
@@ -165,11 +182,14 @@ int main(int argc, char** argv)
fds[1].revents = 0;
try {
- DumbFramebuffer* dst_fb = in->dequeue();
+ auto dst_vbuf = in->dequeue();
+
+ auto dst_fb = *find_if(in_fbs.begin(), in_fbs.end(), [fd=dst_vbuf.m_fd](auto& fb) { return fb->prime_fd(0) == fd; });
+
printf("Writing frame %u\n", dst_frame_num);
for (unsigned i = 0; i < dst_fb->num_planes(); ++i)
os.write((char*)dst_fb->map(i), dst_fb->size(i));
- in->queue(dst_fb);
+ in->queue(dst_vbuf);
dst_frame_num++;
@@ -183,11 +203,13 @@ int main(int argc, char** argv)
break;
}
- DumbFramebuffer* src_fb = out->dequeue();
+ auto src_vbuf = out->dequeue();
+
+ auto src_fb = *find_if(out_fbs.begin(), out_fbs.end(), [fd=src_vbuf.m_fd](auto& fb) { return fb->prime_fd(0) == fd; });
if (src_frame_num < num_src_frames) {
read_frame(src_fb, src_frame_num++);
- out->queue(src_fb);
+ out->queue(src_vbuf);
}
}
diff --git a/v4l2++/inc/v4l2++/helpers.h b/v4l2++/inc/v4l2++/helpers.h
new file mode 100644
index 0000000..b5c3284
--- /dev/null
+++ b/v4l2++/inc/v4l2++/helpers.h
@@ -0,0 +1,60 @@
+#pragma once
+
+#include <fmt/format.h>
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+#define unlikely(x) __builtin_expect(!!(x), 0)
+
+/* __STRING(x) is a glibcism (i.e. not standard), which happens to also
+ * be available in uClibc. However, musl does not define it. Do it here.
+ */
+#ifndef __STRING
+#define __STRING(x) #x
+#endif
+
+#define ASSERT(x) \
+ if (unlikely(!(x))) { \
+ fprintf(stderr, "%s:%d: %s: ASSERT(%s) failed\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, __STRING(x)); \
+ abort(); \
+ }
+
+#define FAIL(fmt, ...) \
+ do { \
+ fprintf(stderr, "%s:%d: %s:\n" fmt "\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, ##__VA_ARGS__); \
+ abort(); \
+ } while (0)
+
+#define FAIL_IF(x, format, ...) \
+ if (unlikely(x)) { \
+ fprintf(stderr, "%s:%d: %s:\n" format "\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, ##__VA_ARGS__); \
+ abort(); \
+ }
+
+#define EXIT(fmt, ...) \
+ do { \
+ fprintf(stderr, fmt "\n", ##__VA_ARGS__); \
+ exit(-1); \
+ } while (0)
+
+#define EXIT_IF(x, fmt, ...) \
+ if (unlikely(x)) { \
+ fprintf(stderr, fmt "\n", ##__VA_ARGS__); \
+ exit(-1); \
+ }
+
+void __my_throw(const char* file, int line, const char* funcname, const char* cond, fmt::string_view format, fmt::format_args args);
+
+template<typename S, typename... Args>
+void _my_throw(const char* file, int line, const char* funcname, const char* cond, const S& format, Args&&... args)
+{
+ __my_throw(file, line, funcname, cond, format, fmt::make_format_args(args...));
+}
+
+#define THROW(format, ...) \
+ _my_throw(__FILE__, __LINE__, __PRETTY_FUNCTION__, nullptr, format, ##__VA_ARGS__);
+
+#define THROW_IF(x, format, ...) \
+ if (unlikely(x)) { \
+ _my_throw(__FILE__, __LINE__, __PRETTY_FUNCTION__, #x, format, ##__VA_ARGS__); \
+ }
diff --git a/v4l2++/inc/v4l2++/pixelformats.h b/v4l2++/inc/v4l2++/pixelformats.h
new file mode 100644
index 0000000..609ff4f
--- /dev/null
+++ b/v4l2++/inc/v4l2++/pixelformats.h
@@ -0,0 +1,111 @@
+#pragma once
+
+#include <cstdint>
+#include <string>
+#include <stdexcept>
+
+namespace v4l2
+{
+
+constexpr uint32_t MakeFourCC(const char* fourcc)
+{
+ return fourcc[0] | (fourcc[1] << 8) | (fourcc[2] << 16) | (fourcc[3] << 24);
+}
+
+enum class PixelFormat : uint32_t {
+ Undefined = 0,
+
+ NV12 = MakeFourCC("NV12"),
+ NV21 = MakeFourCC("NV21"),
+ NV16 = MakeFourCC("NV16"),
+ NV61 = MakeFourCC("NV61"),
+
+ YUV420 = MakeFourCC("YU12"),
+ YVU420 = MakeFourCC("YV12"),
+ YUV422 = MakeFourCC("YU16"),
+ YVU422 = MakeFourCC("YV16"),
+ YUV444 = MakeFourCC("YU24"),
+ YVU444 = MakeFourCC("YV24"),
+
+ UYVY = MakeFourCC("UYVY"),
+ YUYV = MakeFourCC("YUYV"),
+ YVYU = MakeFourCC("YVYU"),
+ VYUY = MakeFourCC("VYUY"),
+
+ XRGB8888 = MakeFourCC("XR24"),
+ XBGR8888 = MakeFourCC("XB24"),
+ RGBX8888 = MakeFourCC("RX24"),
+ BGRX8888 = MakeFourCC("BX24"),
+
+ ARGB8888 = MakeFourCC("AR24"),
+ ABGR8888 = MakeFourCC("AB24"),
+ RGBA8888 = MakeFourCC("RA24"),
+ BGRA8888 = MakeFourCC("BA24"),
+
+ RGB888 = MakeFourCC("RG24"),
+ BGR888 = MakeFourCC("BG24"),
+
+ RGB332 = MakeFourCC("RGB8"),
+
+ RGB565 = MakeFourCC("RG16"),
+ BGR565 = MakeFourCC("BG16"),
+
+ XRGB4444 = MakeFourCC("XR12"),
+ XRGB1555 = MakeFourCC("XR15"),
+
+ ARGB4444 = MakeFourCC("AR12"),
+ ARGB1555 = MakeFourCC("AR15"),
+
+ XRGB2101010 = MakeFourCC("XR30"),
+ XBGR2101010 = MakeFourCC("XB30"),
+ RGBX1010102 = MakeFourCC("RX30"),
+ BGRX1010102 = MakeFourCC("BX30"),
+
+ ARGB2101010 = MakeFourCC("AR30"),
+ ABGR2101010 = MakeFourCC("AB30"),
+ RGBA1010102 = MakeFourCC("RA30"),
+ BGRA1010102 = MakeFourCC("BA30"),
+
+ SBGGR12 = MakeFourCC("BG12"),
+ SRGGB12 = MakeFourCC("RG12"),
+
+ META_8 = MakeFourCC("ME08"),
+ META_16 = MakeFourCC("ME16"),
+};
+
+static inline PixelFormat FourCCToPixelFormat(const std::string& fourcc)
+{
+ return (PixelFormat)MakeFourCC(fourcc.c_str());
+}
+
+static inline std::string PixelFormatToFourCC(PixelFormat f)
+{
+ char buf[5] = { (char)(((uint32_t)f >> 0) & 0xff),
+ (char)(((uint32_t)f >> 8) & 0xff),
+ (char)(((uint32_t)f >> 16) & 0xff),
+ (char)(((uint32_t)f >> 24) & 0xff),
+ 0 };
+ return std::string(buf);
+}
+
+enum class PixelColorType {
+ RGB,
+ YUV,
+ RAW,
+};
+
+struct PixelFormatPlaneInfo {
+ uint8_t bitspp;
+ uint8_t xsub;
+ uint8_t ysub;
+};
+
+struct PixelFormatInfo {
+ PixelColorType type;
+ uint8_t num_planes;
+ struct PixelFormatPlaneInfo planes[4];
+};
+
+const struct PixelFormatInfo& get_pixel_format_info(PixelFormat format);
+
+} // namespace kms
diff --git a/kms++util/inc/kms++util/videodevice.h b/v4l2++/inc/v4l2++/videodevice.h
index 3bce4a9..bdb290e 100644
--- a/kms++util/inc/kms++util/videodevice.h
+++ b/v4l2++/inc/v4l2++/videodevice.h
@@ -2,9 +2,31 @@
#include <string>
#include <memory>
-#include <kms++/kms++.h>
+#include <vector>
+#include <v4l2++/pixelformats.h>
+
+namespace v4l2
+{
class VideoStreamer;
+class MetaStreamer;
+
+enum class VideoMemoryType
+{
+ MMAP,
+ DMABUF,
+};
+
+class VideoBuffer
+{
+public:
+ VideoMemoryType m_mem_type;
+ uint32_t m_index;
+ uint32_t m_length;
+ int m_fd;
+ uint32_t m_offset;
+ PixelFormat m_format;
+};
class VideoDevice
{
@@ -23,9 +45,10 @@ public:
VideoStreamer* get_capture_streamer();
VideoStreamer* get_output_streamer();
+ MetaStreamer* get_meta_capture_streamer();
- std::vector<std::tuple<uint32_t, uint32_t>> get_discrete_frame_sizes(kms::PixelFormat fmt);
- VideoFrameSize get_frame_sizes(kms::PixelFormat fmt);
+ std::vector<std::tuple<uint32_t, uint32_t>> get_discrete_frame_sizes(PixelFormat fmt);
+ VideoFrameSize get_frame_sizes(PixelFormat fmt);
int fd() const { return m_fd; }
bool has_capture() const { return m_has_capture; }
@@ -38,20 +61,20 @@ public:
private:
int m_fd;
- bool m_has_capture;
- bool m_has_mplane_capture;
+ bool m_has_capture = false;
+ bool m_has_mplane_capture = false;
- bool m_has_output;
- bool m_has_mplane_output;
+ bool m_has_output = false;
+ bool m_has_mplane_output = false;
- bool m_has_m2m;
- bool m_has_mplane_m2m;
+ bool m_has_m2m = false;
+ bool m_has_mplane_m2m = false;
- std::vector<kms::DumbFramebuffer*> m_capture_fbs;
- std::vector<kms::DumbFramebuffer*> m_output_fbs;
+ bool m_has_meta_capture = false;
std::unique_ptr<VideoStreamer> m_capture_streamer;
std::unique_ptr<VideoStreamer> m_output_streamer;
+ std::unique_ptr<MetaStreamer> m_meta_capture_streamer;
};
class VideoStreamer
@@ -62,27 +85,43 @@ public:
CaptureMulti,
OutputSingle,
OutputMulti,
- };
+ CaptureMeta,
+ OutputMeta,
+ };
VideoStreamer(int fd, StreamerType type);
+ virtual ~VideoStreamer() { }
std::vector<std::string> get_ports();
void set_port(uint32_t index);
- std::vector<kms::PixelFormat> get_formats();
- void set_format(kms::PixelFormat fmt, uint32_t width, uint32_t height);
+ std::vector<PixelFormat> get_formats();
+ int get_format(PixelFormat& fmt, uint32_t& width, uint32_t& height);
+ void set_format(PixelFormat fmt, uint32_t width, uint32_t height);
void get_selection(uint32_t& left, uint32_t& top, uint32_t& width, uint32_t& height);
void set_selection(uint32_t& left, uint32_t& top, uint32_t& width, uint32_t& height);
- void set_queue_size(uint32_t queue_size);
- void queue(kms::DumbFramebuffer* fb);
- kms::DumbFramebuffer* dequeue();
+ void set_queue_size(uint32_t queue_size, VideoMemoryType mem_type);
+ void queue(VideoBuffer& fb);
+ VideoBuffer dequeue();
void stream_on();
void stream_off();
int fd() const { return m_fd; }
-private:
+protected:
int m_fd;
StreamerType m_type;
- std::vector<kms::DumbFramebuffer*> m_fbs;
+ VideoMemoryType m_mem_type;
+ std::vector<bool> m_fbs;
};
+
+
+class MetaStreamer : public VideoStreamer
+{
+public:
+ MetaStreamer(int fd, VideoStreamer::StreamerType type);
+
+ void set_format(PixelFormat fmt, uint32_t size);
+};
+
+}
diff --git a/v4l2++/meson.build b/v4l2++/meson.build
new file mode 100644
index 0000000..2f425d6
--- /dev/null
+++ b/v4l2++/meson.build
@@ -0,0 +1,32 @@
+libv4l2xx_sources = files([
+ 'src/videodevice.cpp',
+ 'src/pixelformats.cpp',
+ 'src/helpers.cpp',
+])
+
+public_headers = [
+ 'inc/v4l2++/videodevice.h',
+ 'inc/v4l2++/pixelformats.h',
+ 'inc/v4l2++/helpers.h',
+]
+
+private_includes = include_directories('src', 'inc')
+public_includes = include_directories('inc')
+
+libv4l2xx_deps = [ libfmt_dep ]
+
+libv4l2xx = library('v4l2++',
+ libv4l2xx_sources,
+ install : true,
+ include_directories : [ private_includes ],
+ dependencies : libv4l2xx_deps,
+ version : meson.project_version())
+
+
+libv4l2xx_dep = declare_dependency(include_directories : public_includes,
+ link_with : libv4l2xx)
+
+install_headers(public_headers, subdir : 'v4l2++')
+
+pkg = import('pkgconfig')
+pkg.generate(libv4l2xx)
diff --git a/v4l2++/src/helpers.cpp b/v4l2++/src/helpers.cpp
new file mode 100644
index 0000000..db80408
--- /dev/null
+++ b/v4l2++/src/helpers.cpp
@@ -0,0 +1,16 @@
+#include <v4l2++/helpers.h>
+
+void __my_throw(const char* file, int line, const char *funcname, const char *cond, fmt::string_view format, fmt::format_args args)
+{
+ std::string str = fmt::vformat(format, args);
+
+ fmt::print(stderr, "{}:{}: {}:\n{}", file, line, funcname, str);
+ if (cond)
+ fmt::print(stderr, " ({})\n", cond);
+ else
+ fmt::print("\n");
+
+ fflush(stderr);
+
+ throw std::runtime_error(str);
+}
diff --git a/v4l2++/src/pixelformats.cpp b/v4l2++/src/pixelformats.cpp
new file mode 100644
index 0000000..1c8453f
--- /dev/null
+++ b/v4l2++/src/pixelformats.cpp
@@ -0,0 +1,301 @@
+#include <map>
+
+#include <v4l2++/pixelformats.h>
+
+using namespace std;
+
+namespace v4l2
+{
+static const map<PixelFormat, PixelFormatInfo> format_info_array = {
+ /* YUV packed */
+ { PixelFormat::UYVY, {
+ PixelColorType::YUV,
+ 1,
+ { { 16, 2, 1 } },
+ } },
+ { PixelFormat::YUYV, {
+ PixelColorType::YUV,
+ 1,
+ { { 16, 2, 1 } },
+ } },
+ { PixelFormat::YVYU, {
+ PixelColorType::YUV,
+ 1,
+ { { 16, 2, 1 } },
+ } },
+ { PixelFormat::VYUY, {
+ PixelColorType::YUV,
+ 1,
+ { { 16, 2, 1 } },
+ } },
+ /* YUV semi-planar */
+ { PixelFormat::NV12, {
+ PixelColorType::YUV,
+ 2,
+ { {
+ 8,
+ 1,
+ 1,
+ },
+ { 8, 2, 2 } },
+ } },
+ { PixelFormat::NV21, {
+ PixelColorType::YUV,
+ 2,
+ { {
+ 8,
+ 1,
+ 1,
+ },
+ { 8, 2, 2 } },
+ } },
+ { PixelFormat::NV16, {
+ PixelColorType::YUV,
+ 2,
+ { {
+ 8,
+ 1,
+ 1,
+ },
+ { 8, 2, 1 } },
+ } },
+ { PixelFormat::NV61, {
+ PixelColorType::YUV,
+ 2,
+ { {
+ 8,
+ 1,
+ 1,
+ },
+ { 8, 2, 1 } },
+ } },
+ /* YUV planar */
+ { PixelFormat::YUV420, {
+ PixelColorType::YUV,
+ 3,
+ { {
+ 8,
+ 1,
+ 1,
+ },
+ { 8, 2, 2 },
+ { 8, 2, 2 } },
+ } },
+ { PixelFormat::YVU420, {
+ PixelColorType::YUV,
+ 3,
+ { {
+ 8,
+ 1,
+ 1,
+ },
+ { 8, 2, 2 },
+ { 8, 2, 2 } },
+ } },
+ { PixelFormat::YUV422, {
+ PixelColorType::YUV,
+ 3,
+ { {
+ 8,
+ 1,
+ 1,
+ },
+ { 8, 2, 1 },
+ { 8, 2, 1 } },
+ } },
+ { PixelFormat::YVU422, {
+ PixelColorType::YUV,
+ 3,
+ { {
+ 8,
+ 1,
+ 1,
+ },
+ { 8, 2, 1 },
+ { 8, 2, 1 } },
+ } },
+ { PixelFormat::YUV444, {
+ PixelColorType::YUV,
+ 3,
+ { {
+ 8,
+ 1,
+ 1,
+ },
+ { 8, 1, 1 },
+ { 8, 1, 1 } },
+ } },
+ { PixelFormat::YVU444, {
+ PixelColorType::YUV,
+ 3,
+ { {
+ 8,
+ 1,
+ 1,
+ },
+ { 8, 1, 1 },
+ { 8, 1, 1 } },
+ } },
+ /* RGB8 */
+ { PixelFormat::RGB332, {
+ PixelColorType::RGB,
+ 1,
+ { { 8, 1, 1 } },
+ } },
+ /* RGB16 */
+ { PixelFormat::RGB565, {
+ PixelColorType::RGB,
+ 1,
+ { { 16, 1, 1 } },
+ } },
+ { PixelFormat::BGR565, {
+ PixelColorType::RGB,
+ 1,
+ { { 16, 1, 1 } },
+ } },
+ { PixelFormat::XRGB4444, {
+ PixelColorType::RGB,
+ 1,
+ { { 16, 1, 1 } },
+ } },
+ { PixelFormat::XRGB1555, {
+ PixelColorType::RGB,
+ 1,
+ { { 16, 1, 1 } },
+ } },
+ { PixelFormat::ARGB4444, {
+ PixelColorType::RGB,
+ 1,
+ { { 16, 1, 1 } },
+ } },
+ { PixelFormat::ARGB1555, {
+ PixelColorType::RGB,
+ 1,
+ { { 16, 1, 1 } },
+ } },
+ /* RGB24 */
+ { PixelFormat::RGB888, {
+ PixelColorType::RGB,
+ 1,
+ { { 24, 1, 1 } },
+ } },
+ { PixelFormat::BGR888, {
+ PixelColorType::RGB,
+ 1,
+ { { 24, 1, 1 } },
+ } },
+ /* RGB32 */
+ { PixelFormat::XRGB8888, {
+ PixelColorType::RGB,
+ 1,
+ { { 32, 1, 1 } },
+ } },
+ { PixelFormat::XBGR8888, {
+ PixelColorType::RGB,
+ 1,
+ { { 32, 1, 1 } },
+ } },
+ { PixelFormat::RGBX8888, {
+ PixelColorType::RGB,
+ 1,
+ { { 32, 1, 1 } },
+ } },
+ { PixelFormat::BGRX8888, {
+ PixelColorType::RGB,
+ 1,
+ { { 32, 1, 1 } },
+ } },
+
+ { PixelFormat::ARGB8888, {
+ PixelColorType::RGB,
+ 1,
+ { { 32, 1, 1 } },
+ } },
+ { PixelFormat::ABGR8888, {
+ PixelColorType::RGB,
+ 1,
+ { { 32, 1, 1 } },
+ } },
+ { PixelFormat::RGBA8888, {
+ PixelColorType::RGB,
+ 1,
+ { { 32, 1, 1 } },
+ } },
+ { PixelFormat::BGRA8888, {
+ PixelColorType::RGB,
+ 1,
+ { { 32, 1, 1 } },
+ } },
+
+ { PixelFormat::XRGB2101010, {
+ PixelColorType::RGB,
+ 1,
+ { { 32, 1, 1 } },
+ } },
+ { PixelFormat::XBGR2101010, {
+ PixelColorType::RGB,
+ 1,
+ { { 32, 1, 1 } },
+ } },
+ { PixelFormat::RGBX1010102, {
+ PixelColorType::RGB,
+ 1,
+ { { 32, 1, 1 } },
+ } },
+ { PixelFormat::BGRX1010102, {
+ PixelColorType::RGB,
+ 1,
+ { { 32, 1, 1 } },
+ } },
+
+ { PixelFormat::ARGB2101010, {
+ PixelColorType::RGB,
+ 1,
+ { { 32, 1, 1 } },
+ } },
+ { PixelFormat::ABGR2101010, {
+ PixelColorType::RGB,
+ 1,
+ { { 32, 1, 1 } },
+ } },
+ { PixelFormat::RGBA1010102, {
+ PixelColorType::RGB,
+ 1,
+ { { 32, 1, 1 } },
+ } },
+ { PixelFormat::BGRA1010102, {
+ PixelColorType::RGB,
+ 1,
+ { { 32, 1, 1 } },
+ } },
+ { PixelFormat::SBGGR12, {
+ PixelColorType::RAW,
+ 1,
+ { { 16, 1, 1 } },
+ } },
+ { PixelFormat::SRGGB12, {
+ PixelColorType::RAW,
+ 1,
+ { { 16, 1, 1 } },
+ } },
+ { PixelFormat::META_8, {
+ PixelColorType::RGB,
+ 1,
+ { { 8, 1, 1 } },
+ } },
+ { PixelFormat::META_16, {
+ PixelColorType::RGB,
+ 1,
+ { { 16, 1, 1 } },
+ } },
+};
+
+const struct PixelFormatInfo& get_pixel_format_info(PixelFormat format)
+{
+ if (!format_info_array.count(format))
+ throw invalid_argument("get_pixel_format_info: Unsupported pixelformat");
+
+ return format_info_array.at(format);
+}
+
+}
diff --git a/kms++util/src/videodevice.cpp b/v4l2++/src/videodevice.cpp
index 9530d60..5ab7099 100644
--- a/kms++util/src/videodevice.cpp
+++ b/v4l2++/src/videodevice.cpp
@@ -8,12 +8,11 @@
#include <unistd.h>
#include <system_error>
-#include <kms++/kms++.h>
-#include <kms++util/kms++util.h>
-#include <kms++util/videodevice.h>
+#include <v4l2++/videodevice.h>
+#include <v4l2++/helpers.h>
using namespace std;
-using namespace kms;
+using namespace v4l2;
/*
* V4L2 and DRM differ in their interpretation of YUV420::NV12
@@ -27,6 +26,18 @@ using namespace kms;
* and forth to keep the data view consistent.
*/
+static v4l2_memory get_mem_type(VideoMemoryType type)
+{
+ switch (type) {
+ case VideoMemoryType::MMAP:
+ return V4L2_MEMORY_MMAP;
+ case VideoMemoryType::DMABUF:
+ return V4L2_MEMORY_DMABUF;
+ default:
+ FAIL("Bad VideoMemoryType");
+ }
+}
+
/* V4L2 helper funcs */
static vector<PixelFormat> v4l2_get_formats(int fd, uint32_t buf_type)
{
@@ -47,6 +58,27 @@ static vector<PixelFormat> v4l2_get_formats(int fd, uint32_t buf_type)
return v;
}
+static int v4l2_get_format(int fd, uint32_t buf_type, PixelFormat& fmt, uint32_t& width, uint32_t& height)
+{
+ int r;
+
+ v4l2_format v4lfmt{};
+
+ v4lfmt.type = buf_type;
+ r = ioctl(fd, VIDIOC_G_FMT, &v4lfmt);
+ ASSERT(r == 0);
+
+ bool mplane = buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE || buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+
+ FAIL_IF(mplane, "mplane not supported");
+
+ fmt = (PixelFormat)v4lfmt.fmt.pix.pixelformat;
+ width = v4lfmt.fmt.pix.width;
+ height = v4lfmt.fmt.pix.height;
+
+ return 0;
+}
+
static void v4l2_set_format(int fd, PixelFormat fmt, uint32_t width, uint32_t height, uint32_t buf_type)
{
int r;
@@ -107,6 +139,7 @@ static void v4l2_set_format(int fd, PixelFormat fmt, uint32_t width, uint32_t he
v4lfmt.fmt.pix.width = width;
v4lfmt.fmt.pix.height = height;
v4lfmt.fmt.pix.bytesperline = width * pfi.planes[0].bitspp / 8;
+ v4lfmt.fmt.pix.field = V4L2_FIELD_NONE;
r = ioctl(fd, VIDIOC_S_FMT, &v4lfmt);
ASSERT(r == 0);
@@ -175,29 +208,31 @@ static void v4l2_set_selection(int fd, uint32_t& left, uint32_t& top, uint32_t&
height = selection.r.height;
}
-static void v4l2_request_bufs(int fd, uint32_t queue_size, uint32_t buf_type)
+static void v4l2_request_bufs(int fd, uint32_t queue_size, uint32_t buf_type, uint32_t mem_type)
{
v4l2_requestbuffers v4lreqbuf{};
v4lreqbuf.type = buf_type;
- v4lreqbuf.memory = V4L2_MEMORY_DMABUF;
+ v4lreqbuf.memory = mem_type;
v4lreqbuf.count = queue_size;
int r = ioctl(fd, VIDIOC_REQBUFS, &v4lreqbuf);
- ASSERT(r == 0);
+ FAIL_IF(r != 0, "VIDIOC_REQBUFS failed: %d", errno);
ASSERT(v4lreqbuf.count == queue_size);
}
-static void v4l2_queue_dmabuf(int fd, uint32_t index, DumbFramebuffer* fb, uint32_t buf_type)
+static void v4l2_queue(int fd, VideoBuffer& fb, uint32_t buf_type)
{
v4l2_buffer buf{};
buf.type = buf_type;
- buf.memory = V4L2_MEMORY_DMABUF;
- buf.index = index;
-
- const PixelFormatInfo& pfi = get_pixel_format_info(fb->format());
+ buf.memory = get_mem_type(fb.m_mem_type);
+ buf.index = fb.m_index;
bool mplane = buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE || buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
if (mplane) {
+ ASSERT(false);
+ /*
+ const PixelFormatInfo& pfi = get_pixel_format_info(fb->m_format);
+
buf.length = pfi.num_planes;
v4l2_plane planes[4]{};
@@ -211,19 +246,21 @@ static void v4l2_queue_dmabuf(int fd, uint32_t index, DumbFramebuffer* fb, uint3
int r = ioctl(fd, VIDIOC_QBUF, &buf);
ASSERT(r == 0);
+ */
} else {
- buf.m.fd = fb->prime_fd(0);
+ if (fb.m_mem_type == VideoMemoryType::DMABUF)
+ buf.m.fd = fb.m_fd;
int r = ioctl(fd, VIDIOC_QBUF, &buf);
ASSERT(r == 0);
}
}
-static uint32_t v4l2_dequeue(int fd, uint32_t buf_type)
+static uint32_t v4l2_dequeue(int fd, VideoBuffer& fb, uint32_t buf_type)
{
v4l2_buffer buf{};
buf.type = buf_type;
- buf.memory = V4L2_MEMORY_DMABUF;
+ buf.memory = get_mem_type(fb.m_mem_type);
// V4L2 crashes if planes are not set
v4l2_plane planes[4]{};
@@ -234,6 +271,14 @@ static uint32_t v4l2_dequeue(int fd, uint32_t buf_type)
if (r)
throw system_error(errno, generic_category());
+ fb.m_index = buf.index;
+ fb.m_length = buf.length;
+
+ if (fb.m_mem_type == VideoMemoryType::DMABUF)
+ fb.m_fd = buf.m.fd;
+ else
+ fb.m_offset = buf.m.offset;
+
return buf.index;
}
@@ -243,7 +288,7 @@ VideoDevice::VideoDevice(const string& dev)
}
VideoDevice::VideoDevice(int fd)
- : m_fd(fd), m_has_capture(false), m_has_output(false), m_has_m2m(false)
+ : m_fd(fd)
{
if (fd < 0)
throw runtime_error("bad fd");
@@ -283,6 +328,10 @@ VideoDevice::VideoDevice(int fd)
m_has_mplane_capture = false;
m_has_mplane_output = false;
}
+
+ if (cap.capabilities & V4L2_CAP_META_CAPTURE) {
+ m_has_meta_capture = true;
+ }
}
VideoDevice::~VideoDevice()
@@ -314,6 +363,16 @@ VideoStreamer* VideoDevice::get_output_streamer()
return m_output_streamer.get();
}
+MetaStreamer* VideoDevice::get_meta_capture_streamer()
+{
+ ASSERT(m_has_meta_capture);
+
+ if (!m_meta_capture_streamer)
+ m_meta_capture_streamer = make_unique<MetaStreamer>(m_fd, MetaStreamer::StreamerType::CaptureMeta);
+
+ return m_meta_capture_streamer.get();
+}
+
vector<tuple<uint32_t, uint32_t>> VideoDevice::get_discrete_frame_sizes(PixelFormat fmt)
{
vector<tuple<uint32_t, uint32_t>> v;
@@ -480,6 +539,10 @@ static v4l2_buf_type get_buf_type(VideoStreamer::StreamerType type)
return V4L2_BUF_TYPE_VIDEO_OUTPUT;
case VideoStreamer::StreamerType::OutputMulti:
return V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ case MetaStreamer::StreamerType::CaptureMeta:
+ return V4L2_BUF_TYPE_META_CAPTURE;
+ case MetaStreamer::StreamerType::OutputMeta:
+ return (v4l2_buf_type)14; // XXX V4L2_BUF_TYPE_META_OUTPUT;
default:
FAIL("Bad StreamerType");
}
@@ -490,6 +553,11 @@ std::vector<PixelFormat> VideoStreamer::get_formats()
return v4l2_get_formats(m_fd, get_buf_type(m_type));
}
+int VideoStreamer::get_format(PixelFormat &fmt, uint32_t &width, uint32_t &height)
+{
+ return v4l2_get_format(m_fd, get_buf_type(m_type), fmt, width, height);
+}
+
void VideoStreamer::set_format(PixelFormat fmt, uint32_t width, uint32_t height)
{
v4l2_set_format(m_fd, fmt, width, height, get_buf_type(m_type));
@@ -505,34 +573,41 @@ void VideoStreamer::set_selection(uint32_t& left, uint32_t& top, uint32_t& width
v4l2_set_selection(m_fd, left, top, width, height, get_buf_type(m_type));
}
-void VideoStreamer::set_queue_size(uint32_t queue_size)
+void VideoStreamer::set_queue_size(uint32_t queue_size, VideoMemoryType mem_type)
{
- v4l2_request_bufs(m_fd, queue_size, get_buf_type(m_type));
+ m_mem_type = mem_type;
+
+ v4l2_request_bufs(m_fd, queue_size, get_buf_type(m_type), get_mem_type(m_mem_type));
+
m_fbs.resize(queue_size);
}
-void VideoStreamer::queue(DumbFramebuffer* fb)
+void VideoStreamer::queue(VideoBuffer &fb)
{
uint32_t idx;
for (idx = 0; idx < m_fbs.size(); ++idx) {
- if (m_fbs[idx] == nullptr)
+ if (m_fbs[idx] == false)
break;
}
FAIL_IF(idx == m_fbs.size(), "queue full");
- m_fbs[idx] = fb;
+ fb.m_index = idx;
+
+ m_fbs[idx] = true;
- v4l2_queue_dmabuf(m_fd, idx, fb, get_buf_type(m_type));
+ v4l2_queue(m_fd, fb, get_buf_type(m_type));
}
-DumbFramebuffer* VideoStreamer::dequeue()
+VideoBuffer VideoStreamer::dequeue()
{
- uint32_t idx = v4l2_dequeue(m_fd, get_buf_type(m_type));
+ VideoBuffer fb {};
+ fb.m_mem_type = m_mem_type;
- auto fb = m_fbs[idx];
- m_fbs[idx] = nullptr;
+ uint32_t idx = v4l2_dequeue(m_fd, fb, get_buf_type(m_type));
+
+ m_fbs[idx] = false;
return fb;
}
@@ -550,3 +625,29 @@ void VideoStreamer::stream_off()
int r = ioctl(m_fd, VIDIOC_STREAMOFF, &buf_type);
FAIL_IF(r, "Failed to disable stream: %d", r);
}
+
+
+
+
+
+MetaStreamer::MetaStreamer(int fd, StreamerType type)
+ : VideoStreamer(fd, type)
+{
+}
+
+void MetaStreamer::set_format(PixelFormat fmt, uint32_t size)
+{
+ int r;
+
+ v4l2_format v4lfmt {};
+
+ v4lfmt.type = get_buf_type(m_type);
+ //r = ioctl(m_fd, VIDIOC_G_FMT, &v4lfmt);
+ //ASSERT(r == 0);
+
+ v4lfmt.fmt.meta.dataformat = (uint32_t)fmt;
+ v4lfmt.fmt.meta.buffersize = size;
+
+ r = ioctl(m_fd, VIDIOC_S_FMT, &v4lfmt);
+ ASSERT(r == 0);
+}