From db5e57cdba31439ab2ae0e85c0ffc0c200ac3082 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 24 Feb 2023 15:37:10 +0200 Subject: Drop v4l2 Drop (hacky) v4l2 support from kms++, and move it to a new, separate, library. Signed-off-by: Tomi Valkeinen --- meson.build | 4 - meson_options.txt | 6 - py/meson.build | 4 - py/pyv4l2/__init__.py | 5 - py/pyv4l2/meson.build | 38 --- py/pyv4l2/pyv4l2.cpp | 117 ------- py/tests/cam.py | 129 -------- utils/meson.build | 5 - utils/omap-wbcap.cpp | 420 ------------------------- utils/omap-wbm2m.cpp | 222 ------------- v4l2++/inc/v4l2++/helpers.h | 60 ---- v4l2++/inc/v4l2++/pixelformats.h | 113 ------- v4l2++/inc/v4l2++/videodevice.h | 127 -------- v4l2++/meson.build | 32 -- v4l2++/src/helpers.cpp | 16 - v4l2++/src/pixelformats.cpp | 314 ------------------- v4l2++/src/videodevice.cpp | 660 --------------------------------------- 17 files changed, 2272 deletions(-) delete mode 100644 py/pyv4l2/__init__.py delete mode 100644 py/pyv4l2/meson.build delete mode 100644 py/pyv4l2/pyv4l2.cpp delete mode 100755 py/tests/cam.py delete mode 100644 utils/omap-wbcap.cpp delete mode 100644 utils/omap-wbm2m.cpp delete mode 100644 v4l2++/inc/v4l2++/helpers.h delete mode 100644 v4l2++/inc/v4l2++/pixelformats.h delete mode 100644 v4l2++/inc/v4l2++/videodevice.h delete mode 100644 v4l2++/meson.build delete mode 100644 v4l2++/src/helpers.cpp delete mode 100644 v4l2++/src/pixelformats.cpp delete mode 100644 v4l2++/src/videodevice.cpp diff --git a/meson.build b/meson.build index 6fffc20..9e1b471 100644 --- a/meson.build +++ b/meson.build @@ -46,10 +46,6 @@ endif 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 9e17c24..979753e 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -13,11 +13,5 @@ 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 fcba3e5..3130bf2 100644 --- a/py/meson.build +++ b/py/meson.build @@ -1,5 +1 @@ subdir('pykms') - -if get_option('v4l2').enabled() - subdir('pyv4l2') -endif diff --git a/py/pyv4l2/__init__.py b/py/pyv4l2/__init__.py deleted file mode 100644 index 02541c5..0000000 --- a/py/pyv4l2/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from .pyv4l2 import * -from enum import Enum -import os -import struct - diff --git a/py/pyv4l2/meson.build b/py/pyv4l2/meson.build deleted file mode 100644 index 03b0dcc..0000000 --- a/py/pyv4l2/meson.build +++ /dev/null @@ -1,38 +0,0 @@ -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 deleted file mode 100644 index b88ab5e..0000000 --- a/py/pyv4l2/pyv4l2.cpp +++ /dev/null @@ -1,117 +0,0 @@ -#include -#include -#include -#include - -namespace py = pybind11; - -using namespace v4l2; -using namespace std; - -PYBIND11_MODULE(pyv4l2, m) -{ - py::class_(m, "VideoDevice") - .def(py::init()) - .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_(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_(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_(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) - .def("export_buffer", &VideoStreamer::export_buffer); - - py::class_(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_(m, "PixelFormat") - .value("Undefined", PixelFormat::Undefined) - - .value("NV12", PixelFormat::NV12) - .value("NV21", PixelFormat::NV21) - .value("NV16", PixelFormat::NV16) - .value("NV61", PixelFormat::NV61) - - .value("UYVY", PixelFormat::UYVY) - .value("YUYV", PixelFormat::YUYV) - .value("YVYU", PixelFormat::YVYU) - .value("VYUY", PixelFormat::VYUY) - - .value("RGB888", PixelFormat::RGB888) - .value("XRGB8888", PixelFormat::XRGB8888) - - .value("RGB565", PixelFormat::RGB565) - - .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); - m.def("pixelformat_to_fourcc", &PixelFormatToFourCC); - m.def("drm_fourcc_to_pixelformat", &DRMFourCCToPixelFormat); -} diff --git a/py/tests/cam.py b/py/tests/cam.py deleted file mode 100755 index b2d88c4..0000000 --- a/py/tests/cam.py +++ /dev/null @@ -1,129 +0,0 @@ -#!/usr/bin/python3 - -import sys -import selectors -import pykms -import pyv4l2 as v4l2 -import argparse -import time - -parser = argparse.ArgumentParser() -parser.add_argument("width", type=int) -parser.add_argument("height", type=int) -parser.add_argument("fourcc", type=str, nargs="?", default="UYVY") -parser.add_argument("-t", "--type", type=str, default="drm", help="buffer type (drm/v4l2)") -args = parser.parse_args() - -if not args.type in ["drm", "v4l2"]: - print("Bad buffer type", args.type) - exit(-1) - -w = args.width -h = args.height -fmt = pykms.fourcc_to_pixelformat(args.fourcc) -vfmt = v4l2.drm_fourcc_to_pixelformat(pykms.pixelformat_to_fourcc(fmt)) - -print("Capturing in {}x{}, drm fmt {} ({}), v4l2 fmt {} ({})".format(w, h, - fmt, pykms.pixelformat_to_fourcc(fmt), vfmt, v4l2.pixelformat_to_fourcc(vfmt))) - -card = pykms.Card() -res = pykms.ResourceManager(card) -conn = res.reserve_connector("hdmi") -crtc = res.reserve_crtc(conn) -plane = res.reserve_overlay_plane(crtc, fmt) - -mode = conn.get_default_mode() -modeb = mode.to_blob(card) - -req = pykms.AtomicReq(card) -req.add(conn, "CRTC_ID", crtc.id) -req.add(crtc, {"ACTIVE": 1, - "MODE_ID": modeb.id}) -req.commit_sync(allow_modeset = True) - -NUM_BUFS = 5 - -vidpath = v4l2.VideoDevice.get_capture_devices()[0] - -vid = v4l2.VideoDevice(vidpath) -cap = vid.capture_streamer -cap.set_port(0) -cap.set_format(vfmt, w, h) -cap.set_queue_size(NUM_BUFS, v4l2.VideoMemoryType.DMABUF if args.type == "drm" else v4l2.VideoMemoryType.MMAP) - -fbs = [] - -def export_v4l2_buf_to_drm(card, i, vfmt): - finfo = pykms.get_pixel_format_info(fmt) - - if fmt == pykms.PixelFormat.NV12: - fd = cap.export_buffer(i) - buf_fds = [fd, fd] - pitches = [w * finfo.plane(0).bitspp // 8, w * finfo.plane(1).bitspp // 8] - offsets = [0, w * h * finfo.plane(0).bitspp // 8] - else: - buf_fds = [cap.export_buffer(i)] - pitches = [w * finfo.plane(0).bitspp // 8] - offsets = [0] - - fb = pykms.DmabufFramebuffer(card, w, h, fmt, - buf_fds, pitches, offsets) - - return fb - - -for i in range(NUM_BUFS): - if args.type == "drm": - fb = pykms.DumbFramebuffer(card, w, h, fmt) - else: - fb = export_v4l2_buf_to_drm(card, i, vfmt) - - print(fb) - - fbs.append(fb) - -for i in range(NUM_BUFS): - if args.type == "drm": - vbuf = v4l2.create_dmabuffer(fbs[i].fd(0)) - else: - vbuf = v4l2.create_mmapbuffer() - cap.queue(vbuf) - -cap.stream_on() - - -def readvid(conn, mask): - vbuf = cap.dequeue() - - fb = fbs[vbuf.index] - assert(fb != None) - - if card.has_atomic: - plane.set_props({ - "FB_ID": fb.id, - "CRTC_ID": crtc.id, - "SRC_W": fb.width << 16, - "SRC_H": fb.height << 16, - "CRTC_W": fb.width, - "CRTC_H": fb.height, - }) - else: - crtc.set_plane(plane, fb, 0, 0, fb.width, fb.height, - 0, 0, fb.width, fb.height) - - cap.queue(vbuf) - -def readkey(conn, mask): - #print("KEY EVENT"); - sys.stdin.readline() - exit(0) - -sel = selectors.DefaultSelector() -sel.register(cap.fd, selectors.EVENT_READ, readvid) -sel.register(sys.stdin, selectors.EVENT_READ, readkey) - -while True: - events = sel.select() - for key, mask in events: - callback = key.data - callback(key.fileobj, mask) diff --git a/utils/meson.build b/utils/meson.build index 7a86c68..8a05775 100644 --- a/utils/meson.build +++ b/utils/meson.build @@ -16,8 +16,3 @@ executable('kmsblank', 'kmsblank.cpp', dependencies : [ common_deps ], install : if libevdev_dep.found() executable('kmstouch', 'kmstouch.cpp', dependencies : [ common_deps, libevdev_dep ], install : false) endif - -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 deleted file mode 100644 index fc004cc..0000000 --- a/utils/omap-wbcap.cpp +++ /dev/null @@ -1,420 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include -#include - -#define CAMERA_BUF_QUEUE_SIZE 5 - -using namespace std; -using namespace kms; - -static vector s_fbs; -static vector s_free_fbs; -static vector s_wb_fbs; -static vector s_ready_fbs; - -class WBStreamer -{ -public: - 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((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) { - 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); - } - - s_free_fbs.clear(); - } - - ~WBStreamer() - { - } - - WBStreamer(const WBStreamer& other) = delete; - WBStreamer& operator=(const WBStreamer& other) = delete; - - int fd() const { return m_capdev.fd(); } - - void start_streaming() - { - m_capdev.stream_on(); - } - - void stop_streaming() - { - m_capdev.stream_off(); - } - - DumbFramebuffer* Dequeue() - { - auto vbuf = m_capdev.dequeue(); - - 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); - - return fb; - } - - void Queue() - { - if (s_free_fbs.size() == 0) - return; - - auto fb = s_free_fbs.back(); - s_free_fbs.pop_back(); - - 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: - v4l2::VideoStreamer& m_capdev; -}; - -class WBFlipState : private PageFlipHandlerBase -{ -public: - WBFlipState(Card& card, Crtc* crtc, Plane* plane) - : m_card(card), m_crtc(crtc), m_plane(plane) - { - auto fb = s_ready_fbs.back(); - s_ready_fbs.pop_back(); - - AtomicReq req(m_card); - - req.add(m_plane, "CRTC_ID", m_crtc->id()); - req.add(m_plane, "FB_ID", fb->id()); - - req.add(m_plane, "CRTC_X", 0); - req.add(m_plane, "CRTC_Y", 0); - req.add(m_plane, "CRTC_W", min((uint32_t)m_crtc->mode().hdisplay, fb->width())); - req.add(m_plane, "CRTC_H", min((uint32_t)m_crtc->mode().vdisplay, fb->height())); - - req.add(m_plane, "SRC_X", 0); - req.add(m_plane, "SRC_Y", 0); - req.add(m_plane, "SRC_W", fb->width() << 16); - req.add(m_plane, "SRC_H", fb->height() << 16); - - int r = req.commit_sync(); - FAIL_IF(r, "initial plane setup failed"); - - m_current_fb = fb; - } - - void queue_next() - { - if (m_queued_fb) - return; - - if (s_ready_fbs.size() == 0) - return; - - auto fb = s_ready_fbs.back(); - s_ready_fbs.pop_back(); - - AtomicReq req(m_card); - req.add(m_plane, "FB_ID", fb->id()); - - int r = req.commit(this); - if (r) - EXIT("Flip commit failed: %d\n", r); - - m_queued_fb = fb; - } - -private: - void handle_page_flip(uint32_t frame, double time) - { - if (m_queued_fb) { - if (m_current_fb) - s_free_fbs.insert(s_free_fbs.begin(), m_current_fb); - - m_current_fb = m_queued_fb; - m_queued_fb = nullptr; - } - - queue_next(); - } - - Card& m_card; - Crtc* m_crtc; - Plane* m_plane; - - DumbFramebuffer* m_current_fb = nullptr; - DumbFramebuffer* m_queued_fb = nullptr; -}; - -class BarFlipState : private PageFlipHandlerBase -{ -public: - BarFlipState(Card& card, Crtc* crtc, Plane* plane, uint32_t width, uint32_t height) - : m_card(card), m_crtc(crtc), m_plane(plane) - { - for (unsigned i = 0; i < s_num_buffers; ++i) - m_fbs[i] = new DumbFramebuffer(card, width, height, PixelFormat::XRGB8888); - } - - ~BarFlipState() - { - for (unsigned i = 0; i < s_num_buffers; ++i) - delete m_fbs[i]; - } - - void start_flipping() - { - m_frame_num = 0; - queue_next(); - } - -private: - void handle_page_flip(uint32_t frame, double time) - { - m_frame_num++; - queue_next(); - } - - static unsigned get_bar_pos(DumbFramebuffer* fb, unsigned frame_num) - { - return (frame_num * bar_speed) % (fb->width() - bar_width + 1); - } - - void draw_bar(DumbFramebuffer* fb, unsigned frame_num) - { - int old_xpos = frame_num < s_num_buffers ? -1 : get_bar_pos(fb, frame_num - s_num_buffers); - int new_xpos = get_bar_pos(fb, frame_num); - - draw_color_bar(*fb, old_xpos, new_xpos, bar_width); - draw_text(*fb, fb->width() / 2, 0, to_string(frame_num), RGB(255, 255, 255)); - } - - void queue_next() - { - AtomicReq req(m_card); - - unsigned cur = m_frame_num % s_num_buffers; - - auto fb = m_fbs[cur]; - - draw_bar(fb, m_frame_num); - - req.add(m_plane, { - { "CRTC_ID", m_crtc->id() }, - { "FB_ID", fb->id() }, - - { "CRTC_X", 0 }, - { "CRTC_Y", 0 }, - { "CRTC_W", min((uint32_t)m_crtc->mode().hdisplay, fb->width()) }, - { "CRTC_H", min((uint32_t)m_crtc->mode().vdisplay, fb->height()) }, - - { "SRC_X", 0 }, - { "SRC_Y", 0 }, - { "SRC_W", fb->width() << 16 }, - { "SRC_H", fb->height() << 16 }, - }); - - int r = req.commit(this); - if (r) - EXIT("Flip commit failed: %d\n", r); - } - - static const unsigned s_num_buffers = 3; - - DumbFramebuffer* m_fbs[s_num_buffers]; - - Card& m_card; - Crtc* m_crtc; - Plane* m_plane; - - unsigned m_frame_num; - - static const unsigned bar_width = 20; - static const unsigned bar_speed = 8; -}; - -static const char* usage_str = - "Usage: wbcap [OPTIONS]\n\n" - "Options:\n" - " -s, --src=CONN Source connector\n" - " -d, --dst=CONN Destination connector\n" - " -m, --smode=MODE Source connector videomode\n" - " -M, --dmode=MODE Destination connector videomode\n" - " -f, --format=4CC Format\n" - " -w, --write Write captured frames to wbcap.raw file\n" - " -h, --help Print this help\n"; - -int main(int argc, char** argv) -{ - string src_conn_name; - string src_mode_name; - string dst_conn_name; - string dst_mode_name; - PixelFormat pixfmt = PixelFormat::XRGB8888; - bool write_file = false; - - OptionSet optionset = { - Option("s|src=", [&](string s) { - src_conn_name = s; - }), - Option("m|smode=", [&](string s) { - src_mode_name = s; - }), - Option("d|dst=", [&](string s) { - dst_conn_name = s; - }), - Option("M|dmode=", [&](string s) { - dst_mode_name = s; - }), - Option("f|format=", [&](string s) { - pixfmt = FourCCToPixelFormat(s); - }), - Option("w|write", [&]() { - write_file = true; - }), - Option("h|help", [&]() { - puts(usage_str); - exit(-1); - }), - }; - - optionset.parse(argc, argv); - - if (optionset.params().size() > 0) { - puts(usage_str); - exit(-1); - } - - if (src_conn_name.empty()) - EXIT("No source connector defined"); - - if (dst_conn_name.empty()) - EXIT("No destination connector defined"); - - v4l2::VideoDevice vid("/dev/video11"); - - Card card; - ResourceManager resman(card); - - card.disable_all(); - - auto src_conn = resman.reserve_connector(src_conn_name); - auto src_crtc = resman.reserve_crtc(src_conn); - auto src_plane = resman.reserve_generic_plane(src_crtc, pixfmt); - FAIL_IF(!src_plane, "Plane not found"); - Videomode src_mode = src_mode_name.empty() ? src_conn->get_default_mode() : src_conn->get_mode(src_mode_name); - src_crtc->set_mode(src_conn, src_mode); - - auto dst_conn = resman.reserve_connector(dst_conn_name); - auto dst_crtc = resman.reserve_crtc(dst_conn); - auto dst_plane = resman.reserve_overlay_plane(dst_crtc, pixfmt); - FAIL_IF(!dst_plane, "Plane not found"); - Videomode dst_mode = dst_mode_name.empty() ? dst_conn->get_default_mode() : dst_conn->get_mode(dst_mode_name); - dst_crtc->set_mode(dst_conn, dst_mode); - - uint32_t src_width = src_mode.hdisplay; - uint32_t src_height = src_mode.vdisplay; - - uint32_t dst_width = src_mode.hdisplay; - uint32_t dst_height = src_mode.vdisplay; - if (src_mode.interlace()) - dst_height /= 2; - - printf("src %s, crtc %s\n", src_conn->fullname().c_str(), src_mode.to_string_short().c_str()); - - printf("dst %s, crtc %s\n", dst_conn->fullname().c_str(), dst_mode.to_string_short().c_str()); - - printf("src_fb %ux%u, dst_fb %ux%u\n", src_width, src_height, dst_width, dst_height); - - for (int i = 0; i < CAMERA_BUF_QUEUE_SIZE; ++i) { - auto fb = new DumbFramebuffer(card, dst_width, dst_height, pixfmt); - s_fbs.push_back(fb); - s_free_fbs.push_back(fb); - } - - // get one fb for initial setup - s_ready_fbs.push_back(s_free_fbs.back()); - s_free_fbs.pop_back(); - - // This draws a moving bar to SRC display - BarFlipState barflipper(card, src_crtc, src_plane, src_width, src_height); - barflipper.start_flipping(); - - // This shows the captured SRC frames on DST display - WBFlipState wbflipper(card, dst_crtc, dst_plane); - - WBStreamer wb(vid.get_capture_streamer(), src_crtc, pixfmt); - wb.start_streaming(); - - vector fds(3); - - fds[0].fd = 0; - fds[0].events = POLLIN; - fds[1].fd = wb.fd(); - fds[1].events = POLLIN; - fds[2].fd = card.fd(); - fds[2].events = POLLIN; - - uint32_t dst_frame_num = 0; - - const string filename = "wbcap.raw"; - unique_ptr os; - if (write_file) - os = unique_ptr(new ofstream(filename, ofstream::binary)); - - while (true) { - int r = poll(fds.data(), fds.size(), -1); - ASSERT(r > 0); - - if (fds[0].revents != 0) - break; - - if (fds[1].revents) { - fds[1].revents = 0; - - DumbFramebuffer* fb = wb.Dequeue(); - - if (write_file) { - printf("Writing frame %u to %s\n", dst_frame_num, filename.c_str()); - - for (unsigned i = 0; i < fb->num_planes(); ++i) - os->write((char*)fb->map(i), fb->size(i)); - - dst_frame_num++; - } - - wbflipper.queue_next(); - } - - if (fds[2].revents) { - fds[2].revents = 0; - - card.call_page_flip_handlers(); - wb.Queue(); - } - } - - printf("exiting...\n"); -} diff --git a/utils/omap-wbm2m.cpp b/utils/omap-wbm2m.cpp deleted file mode 100644 index 7dcae2e..0000000 --- a/utils/omap-wbm2m.cpp +++ /dev/null @@ -1,222 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -const uint32_t NUM_SRC_BUFS = 2; -const uint32_t NUM_DST_BUFS = 2; - -using namespace std; -using namespace kms; - -static const char* usage_str = - "Usage: wbm2m [OPTIONS]\n\n" - "Options:\n" - " -f, --format=4CC Output format\n" - " -c, --crop=CROP CROP is ,-x\n" - " -h, --help Print this help\n"; - -const int bar_speed = 4; -const int bar_width = 10; - -static unsigned get_bar_pos(DumbFramebuffer* fb, unsigned frame_num) -{ - return (frame_num * bar_speed) % (fb->width() - bar_width + 1); -} - -static void read_frame(DumbFramebuffer* fb, unsigned frame_num) -{ - static map s_bar_pos_map; - - int old_pos = -1; - if (s_bar_pos_map.find(fb) != s_bar_pos_map.end()) - old_pos = s_bar_pos_map[fb]; - - int pos = get_bar_pos(fb, frame_num); - draw_color_bar(*fb, old_pos, pos, bar_width); - draw_text(*fb, fb->width() / 2, 0, to_string(frame_num), RGB(255, 255, 255)); - s_bar_pos_map[fb] = pos; -} - -static void parse_crop(const string& crop_str, uint32_t& c_left, uint32_t& c_top, - uint32_t& c_width, uint32_t& c_height) -{ - const regex crop_re("(\\d+),(\\d+)-(\\d+)x(\\d+)"); // 400,400-400x400 - - smatch sm; - if (!regex_match(crop_str, sm, crop_re)) - EXIT("Failed to parse crop option '%s'", crop_str.c_str()); - - c_left = stoul(sm[1]); - c_top = stoul(sm[2]); - c_width = stoul(sm[3]); - c_height = stoul(sm[4]); -} - -int main(int argc, char** argv) -{ - // XXX get from args - const uint32_t src_width = 800; - const uint32_t src_height = 480; - const auto src_fmt = PixelFormat::XRGB8888; - const uint32_t num_src_frames = 10; - - const uint32_t dst_width = 800; - const uint32_t dst_height = 480; - uint32_t c_top, c_left, c_width, c_height; - - auto dst_fmt = PixelFormat::XRGB8888; - bool use_selection = false; - - OptionSet optionset = { - Option("f|format=", [&](string s) { - dst_fmt = FourCCToPixelFormat(s); - }), - Option("c|crop=", [&](string s) { - parse_crop(s, c_left, c_top, c_width, c_height); - use_selection = true; - }), - Option("h|help", [&]() { - puts(usage_str); - exit(-1); - }), - }; - - optionset.parse(argc, argv); - - if (optionset.params().size() > 0) { - puts(usage_str); - exit(-1); - } - - printf("%ux%u-%s -> %ux%u-%s\n", src_width, src_height, PixelFormatToFourCC(src_fmt).c_str(), - dst_width, dst_height, PixelFormatToFourCC(dst_fmt).c_str()); - - const string filename = fmt::format("wb-out-{}x{}-{}.raw", dst_width, dst_height, - PixelFormatToFourCC(dst_fmt)); - - printf("writing to %s\n", filename.c_str()); - - v4l2::VideoDevice vid("/dev/video10"); - - Card card; - - uint32_t src_frame_num = 0; - uint32_t dst_frame_num = 0; - - v4l2::VideoStreamer* out = vid.get_output_streamer(); - v4l2::VideoStreamer* in = vid.get_capture_streamer(); - - 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, v4l2::VideoMemoryType::DMABUF); - in->set_queue_size(NUM_DST_BUFS, v4l2::VideoMemoryType::DMABUF); - - vector 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_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 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_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 fds(3); - - fds[0].fd = 0; - fds[0].events = POLLIN; - fds[1].fd = vid.fd(); - fds[1].events = POLLIN; - fds[2].fd = card.fd(); - fds[2].events = POLLIN; - - ofstream os(filename, ofstream::binary); - - out->stream_on(); - in->stream_on(); - - while (true) { - int r = poll(fds.data(), fds.size(), -1); - ASSERT(r > 0); - - if (fds[0].revents != 0) - break; - - if (fds[1].revents) { - fds[1].revents = 0; - - try { - 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_vbuf); - - dst_frame_num++; - - if (dst_frame_num >= num_src_frames) - break; - - } catch (system_error& se) { - if (se.code() != errc::resource_unavailable_try_again) - FAIL("dequeue failed: %s", se.what()); - - break; - } - - 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_vbuf); - } - } - - if (fds[2].revents) { - fds[2].revents = 0; - } - } - - printf("exiting...\n"); -} diff --git a/v4l2++/inc/v4l2++/helpers.h b/v4l2++/inc/v4l2++/helpers.h deleted file mode 100644 index f672b10..0000000 --- a/v4l2++/inc/v4l2++/helpers.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include - -#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 -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 deleted file mode 100644 index d5af2c2..0000000 --- a/v4l2++/inc/v4l2++/pixelformats.h +++ /dev/null @@ -1,113 +0,0 @@ -#pragma once - -#include -#include -#include - -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"), -}; - -inline PixelFormat FourCCToPixelFormat(const std::string& fourcc) -{ - return (PixelFormat)MakeFourCC(fourcc.c_str()); -} - -PixelFormat DRMFourCCToPixelFormat(const std::string& fourcc); - -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 v4l2 diff --git a/v4l2++/inc/v4l2++/videodevice.h b/v4l2++/inc/v4l2++/videodevice.h deleted file mode 100644 index 4ceafa3..0000000 --- a/v4l2++/inc/v4l2++/videodevice.h +++ /dev/null @@ -1,127 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -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 -{ -public: - struct VideoFrameSize { - uint32_t min_w, max_w, step_w; - uint32_t min_h, max_h, step_h; - }; - - VideoDevice(const std::string& dev); - VideoDevice(int fd); - ~VideoDevice(); - - VideoDevice(const VideoDevice& other) = delete; - VideoDevice& operator=(const VideoDevice& other) = delete; - - VideoStreamer* get_capture_streamer(); - VideoStreamer* get_output_streamer(); - MetaStreamer* get_meta_capture_streamer(); - - std::vector> 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; } - bool has_output() const { return m_has_output; } - bool has_m2m() const { return m_has_m2m; } - - static std::vector get_capture_devices(); - static std::vector get_m2m_devices(); - -private: - int m_fd; - - bool m_has_capture = false; - bool m_has_mplane_capture = false; - - bool m_has_output = false; - bool m_has_mplane_output = false; - - bool m_has_m2m = false; - bool m_has_mplane_m2m = false; - - bool m_has_meta_capture = false; - - std::unique_ptr m_capture_streamer; - std::unique_ptr m_output_streamer; - std::unique_ptr m_meta_capture_streamer; -}; - -class VideoStreamer -{ -public: - enum class StreamerType { - CaptureSingle, - CaptureMulti, - OutputSingle, - OutputMulti, - CaptureMeta, - OutputMeta, - }; - - VideoStreamer(int fd, StreamerType type); - virtual ~VideoStreamer() {} - - std::vector get_ports(); - void set_port(uint32_t index); - - std::vector 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, VideoMemoryType mem_type); - void queue(VideoBuffer& fb); - VideoBuffer dequeue(); - void stream_on(); - void stream_off(); - - int export_buffer(uint32_t index); - - int fd() const { return m_fd; } - -protected: - int m_fd; - StreamerType m_type; - VideoMemoryType m_mem_type; - std::vector m_fbs; -}; - -class MetaStreamer : public VideoStreamer -{ -public: - MetaStreamer(int fd, VideoStreamer::StreamerType type); - - void set_format(PixelFormat fmt, uint32_t size); -}; - -} // namespace v4l2 diff --git a/v4l2++/meson.build b/v4l2++/meson.build deleted file mode 100644 index 2f425d6..0000000 --- a/v4l2++/meson.build +++ /dev/null @@ -1,32 +0,0 @@ -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 deleted file mode 100644 index d24c4f8..0000000 --- a/v4l2++/src/helpers.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include - -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 deleted file mode 100644 index f892c97..0000000 --- a/v4l2++/src/pixelformats.cpp +++ /dev/null @@ -1,314 +0,0 @@ -#include - -#include - -using namespace std; - -namespace v4l2 -{ -static const map 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 } }, - } }, -}; - -PixelFormat DRMFourCCToPixelFormat(const std::string& fourcc) -{ - // Handle the formats which differ between DRM and V4L2 - if (fourcc == "RG16") - return PixelFormat::RGB565; - if (fourcc == "XR24") - return PixelFormat::XRGB8888; - if (fourcc == "RG24") - return PixelFormat::RGB888; - - return FourCCToPixelFormat(fourcc); -} - -const struct PixelFormatInfo& get_pixel_format_info(PixelFormat format) -{ - if (!format_info_array.count(format)) - throw invalid_argument("v4l2: get_pixel_format_info: Unsupported pixelformat"); - - return format_info_array.at(format); -} - -} // namespace v4l2 diff --git a/v4l2++/src/videodevice.cpp b/v4l2++/src/videodevice.cpp deleted file mode 100644 index 909cb1b..0000000 --- a/v4l2++/src/videodevice.cpp +++ /dev/null @@ -1,660 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -using namespace std; -using namespace v4l2; - -/* - * V4L2 and DRM differ in their interpretation of YUV420::NV12 - * - * V4L2 NV12 is a Y and UV co-located planes in a single plane buffer. - * DRM NV12 is a Y and UV planes presented as dual plane buffer, - * which is known as NM12 in V4L2. - * - * Since here we have hybrid DRM/V4L2 user space helper functions - * we need to translate DRM::NV12 to V4L2:NM12 pixel format back - * 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 v4l2_get_formats(int fd, uint32_t buf_type) -{ - vector v; - - v4l2_fmtdesc desc{}; - desc.type = buf_type; - - while (ioctl(fd, VIDIOC_ENUM_FMT, &desc) == 0) { - if (desc.pixelformat == V4L2_PIX_FMT_NV12M) - v.push_back(PixelFormat::NV12); - else if (desc.pixelformat != V4L2_PIX_FMT_NV12) - v.push_back((PixelFormat)desc.pixelformat); - - desc.index++; - } - - 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; - - v4l2_format v4lfmt{}; - - v4lfmt.type = buf_type; - r = ioctl(fd, VIDIOC_G_FMT, &v4lfmt); - ASSERT(r == 0); - - const PixelFormatInfo& pfi = get_pixel_format_info(fmt); - - bool mplane = buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE || buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - - if (mplane) { - v4l2_pix_format_mplane& mp = v4lfmt.fmt.pix_mp; - uint32_t used_fmt; - - if (fmt == PixelFormat::NV12) - used_fmt = V4L2_PIX_FMT_NV12M; - else - used_fmt = (uint32_t)fmt; - - mp.pixelformat = used_fmt; - mp.width = width; - mp.height = height; - - mp.num_planes = pfi.num_planes; - - for (unsigned i = 0; i < pfi.num_planes; ++i) { - const PixelFormatPlaneInfo& pfpi = pfi.planes[i]; - v4l2_plane_pix_format& p = mp.plane_fmt[i]; - - p.bytesperline = width * pfpi.bitspp / 8; - p.sizeimage = p.bytesperline * height / pfpi.ysub; - } - - r = ioctl(fd, VIDIOC_S_FMT, &v4lfmt); - ASSERT(r == 0); - - ASSERT(mp.pixelformat == used_fmt); - ASSERT(mp.width == width); - ASSERT(mp.height == height); - - ASSERT(mp.num_planes == pfi.num_planes); - - for (unsigned i = 0; i < pfi.num_planes; ++i) { - const PixelFormatPlaneInfo& pfpi = pfi.planes[i]; - v4l2_plane_pix_format& p = mp.plane_fmt[i]; - - ASSERT(p.bytesperline == width * pfpi.bitspp / 8); - ASSERT(p.sizeimage == p.bytesperline * height / pfpi.ysub); - } - } else { - v4lfmt.fmt.pix.pixelformat = (uint32_t)fmt; - 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); - - ASSERT(v4lfmt.fmt.pix.pixelformat == (uint32_t)fmt); - ASSERT(v4lfmt.fmt.pix.width == width); - ASSERT(v4lfmt.fmt.pix.height == height); - ASSERT(v4lfmt.fmt.pix.bytesperline == width * pfi.planes[0].bitspp / 8); - } -} - -static void v4l2_get_selection(int fd, uint32_t& left, uint32_t& top, uint32_t& width, uint32_t& height, uint32_t buf_type) -{ - int r; - struct v4l2_selection selection; - - if (buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT || - buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - selection.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - selection.target = V4L2_SEL_TGT_CROP; - } else if (buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE || - buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - selection.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - selection.target = V4L2_SEL_TGT_COMPOSE; - } else { - FAIL("buf_type (%d) is not valid\n", buf_type); - } - - r = ioctl(fd, VIDIOC_G_SELECTION, &selection); - ASSERT(r == 0); - - left = selection.r.left; - top = selection.r.top; - width = selection.r.width; - height = selection.r.height; -} - -static void v4l2_set_selection(int fd, uint32_t& left, uint32_t& top, uint32_t& width, uint32_t& height, uint32_t buf_type) -{ - int r; - struct v4l2_selection selection; - - if (buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT || - buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - selection.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - selection.target = V4L2_SEL_TGT_CROP; - } else if (buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE || - buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - selection.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - selection.target = V4L2_SEL_TGT_COMPOSE; - } else { - FAIL("buf_type (%d) is not valid\n", buf_type); - } - - selection.r.left = left; - selection.r.top = top; - selection.r.width = width; - selection.r.height = height; - - r = ioctl(fd, VIDIOC_S_SELECTION, &selection); - ASSERT(r == 0); - - left = selection.r.left; - top = selection.r.top; - width = selection.r.width; - height = selection.r.height; -} - -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 = mem_type; - v4lreqbuf.count = queue_size; - int r = ioctl(fd, VIDIOC_REQBUFS, &v4lreqbuf); - FAIL_IF(r != 0, "VIDIOC_REQBUFS failed: %d", errno); - ASSERT(v4lreqbuf.count == queue_size); -} - -static void v4l2_queue(int fd, VideoBuffer& fb, uint32_t buf_type) -{ - v4l2_buffer buf{}; - buf.type = buf_type; - 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]{}; - buf.m.planes = planes; - - for (unsigned i = 0; i < pfi.num_planes; ++i) { - planes[i].m.fd = fb->prime_fd(i); - planes[i].bytesused = fb->size(i); - planes[i].length = fb->size(i); - } - - int r = ioctl(fd, VIDIOC_QBUF, &buf); - ASSERT(r == 0); - */ - } else { - 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, VideoBuffer& fb, uint32_t buf_type) -{ - v4l2_buffer buf{}; - buf.type = buf_type; - buf.memory = get_mem_type(fb.m_mem_type); - - // V4L2 crashes if planes are not set - v4l2_plane planes[4]{}; - buf.m.planes = planes; - buf.length = 4; - - int r = ioctl(fd, VIDIOC_DQBUF, &buf); - 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; -} - -VideoDevice::VideoDevice(const string& dev) - : VideoDevice(::open(dev.c_str(), O_RDWR | O_NONBLOCK)) -{ -} - -VideoDevice::VideoDevice(int fd) - : m_fd(fd) -{ - if (fd < 0) - throw runtime_error("bad fd"); - - struct v4l2_capability cap = {}; - int r = ioctl(fd, VIDIOC_QUERYCAP, &cap); - ASSERT(r == 0); - - if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE) { - m_has_capture = true; - m_has_mplane_capture = true; - } else if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) { - m_has_capture = true; - m_has_mplane_capture = false; - } - - if (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT_MPLANE) { - m_has_output = true; - m_has_mplane_output = true; - } else if (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) { - m_has_output = true; - m_has_mplane_output = false; - } - - if (cap.capabilities & V4L2_CAP_VIDEO_M2M_MPLANE) { - m_has_m2m = true; - m_has_capture = true; - m_has_output = true; - m_has_mplane_m2m = true; - m_has_mplane_capture = true; - m_has_mplane_output = true; - } else if (cap.capabilities & V4L2_CAP_VIDEO_M2M) { - m_has_m2m = true; - m_has_capture = true; - m_has_output = true; - m_has_mplane_m2m = false; - m_has_mplane_capture = false; - m_has_mplane_output = false; - } - - if (cap.capabilities & V4L2_CAP_META_CAPTURE) { - m_has_meta_capture = true; - } -} - -VideoDevice::~VideoDevice() -{ - ::close(m_fd); -} - -VideoStreamer* VideoDevice::get_capture_streamer() -{ - ASSERT(m_has_capture); - - if (!m_capture_streamer) { - auto type = m_has_mplane_capture ? VideoStreamer::StreamerType::CaptureMulti : VideoStreamer::StreamerType::CaptureSingle; - m_capture_streamer = std::unique_ptr(new VideoStreamer(m_fd, type)); - } - - return m_capture_streamer.get(); -} - -VideoStreamer* VideoDevice::get_output_streamer() -{ - ASSERT(m_has_output); - - if (!m_output_streamer) { - auto type = m_has_mplane_output ? VideoStreamer::StreamerType::OutputMulti : VideoStreamer::StreamerType::OutputSingle; - m_output_streamer = std::unique_ptr(new VideoStreamer(m_fd, type)); - } - - 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(m_fd, MetaStreamer::StreamerType::CaptureMeta); - - return m_meta_capture_streamer.get(); -} - -vector> VideoDevice::get_discrete_frame_sizes(PixelFormat fmt) -{ - vector> v; - - v4l2_frmsizeenum v4lfrms{}; - v4lfrms.pixel_format = (uint32_t)fmt; - - int r = ioctl(m_fd, VIDIOC_ENUM_FRAMESIZES, &v4lfrms); - ASSERT(r); - - FAIL_IF(v4lfrms.type != V4L2_FRMSIZE_TYPE_DISCRETE, "No discrete frame sizes"); - - while (ioctl(m_fd, VIDIOC_ENUM_FRAMESIZES, &v4lfrms) == 0) { - v.emplace_back(v4lfrms.discrete.width, v4lfrms.discrete.height); - v4lfrms.index++; - }; - - return v; -} - -VideoDevice::VideoFrameSize VideoDevice::get_frame_sizes(PixelFormat fmt) -{ - v4l2_frmsizeenum v4lfrms{}; - v4lfrms.pixel_format = (uint32_t)fmt; - - int r = ioctl(m_fd, VIDIOC_ENUM_FRAMESIZES, &v4lfrms); - ASSERT(r); - - FAIL_IF(v4lfrms.type == V4L2_FRMSIZE_TYPE_DISCRETE, "No continuous frame sizes"); - - VideoFrameSize s; - - s.min_w = v4lfrms.stepwise.min_width; - s.max_w = v4lfrms.stepwise.max_width; - s.step_w = v4lfrms.stepwise.step_width; - - s.min_h = v4lfrms.stepwise.min_height; - s.max_h = v4lfrms.stepwise.max_height; - s.step_h = v4lfrms.stepwise.step_height; - - return s; -} - -vector VideoDevice::get_capture_devices() -{ - vector v; - - for (int i = 0; i < 20; ++i) { - string name = "/dev/video" + to_string(i); - - struct stat buffer; - if (stat(name.c_str(), &buffer) != 0) - continue; - - try { - VideoDevice vid(name); - - if (vid.has_capture() && !vid.has_m2m()) - v.push_back(name); - } catch (...) { - } - } - - return v; -} - -vector VideoDevice::get_m2m_devices() -{ - vector v; - - for (int i = 0; i < 20; ++i) { - string name = "/dev/video" + to_string(i); - - struct stat buffer; - if (stat(name.c_str(), &buffer) != 0) - continue; - - try { - VideoDevice vid(name); - - if (vid.has_m2m()) - v.push_back(name); - } catch (...) { - } - } - - return v; -} - -VideoStreamer::VideoStreamer(int fd, StreamerType type) - : m_fd(fd), m_type(type) -{ -} - -std::vector VideoStreamer::get_ports() -{ - vector v; - - switch (m_type) { - case StreamerType::CaptureSingle: - case StreamerType::CaptureMulti: { - struct v4l2_input input { - }; - - while (ioctl(m_fd, VIDIOC_ENUMINPUT, &input) == 0) { - v.push_back(string((char*)&input.name)); - input.index++; - } - - break; - } - - case StreamerType::OutputSingle: - case StreamerType::OutputMulti: { - struct v4l2_output output { - }; - - while (ioctl(m_fd, VIDIOC_ENUMOUTPUT, &output) == 0) { - v.push_back(string((char*)&output.name)); - output.index++; - } - - break; - } - - default: - FAIL("Bad StreamerType"); - } - - return v; -} - -void VideoStreamer::set_port(uint32_t index) -{ - unsigned long req; - - switch (m_type) { - case StreamerType::CaptureSingle: - case StreamerType::CaptureMulti: - req = VIDIOC_S_INPUT; - break; - - case StreamerType::OutputSingle: - case StreamerType::OutputMulti: - req = VIDIOC_S_OUTPUT; - break; - - default: - FAIL("Bad StreamerType"); - } - - int r = ioctl(m_fd, req, &index); - ASSERT(r == 0); -} - -static v4l2_buf_type get_buf_type(VideoStreamer::StreamerType type) -{ - switch (type) { - case VideoStreamer::StreamerType::CaptureSingle: - return V4L2_BUF_TYPE_VIDEO_CAPTURE; - case VideoStreamer::StreamerType::CaptureMulti: - return V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - case VideoStreamer::StreamerType::OutputSingle: - 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"); - } -} - -std::vector 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)); -} - -void VideoStreamer::get_selection(uint32_t& left, uint32_t& top, uint32_t& width, uint32_t& height) -{ - v4l2_get_selection(m_fd, left, top, width, height, get_buf_type(m_type)); -} - -void VideoStreamer::set_selection(uint32_t& left, uint32_t& top, uint32_t& width, uint32_t& height) -{ - v4l2_set_selection(m_fd, left, top, width, height, get_buf_type(m_type)); -} - -void VideoStreamer::set_queue_size(uint32_t queue_size, VideoMemoryType mem_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(VideoBuffer& fb) -{ - uint32_t idx; - - for (idx = 0; idx < m_fbs.size(); ++idx) { - if (m_fbs[idx] == false) - break; - } - - FAIL_IF(idx == m_fbs.size(), "queue full"); - - fb.m_index = idx; - - m_fbs[idx] = true; - - v4l2_queue(m_fd, fb, get_buf_type(m_type)); -} - -VideoBuffer VideoStreamer::dequeue() -{ - VideoBuffer fb{}; - fb.m_mem_type = m_mem_type; - - uint32_t idx = v4l2_dequeue(m_fd, fb, get_buf_type(m_type)); - - m_fbs[idx] = false; - - return fb; -} - -void VideoStreamer::stream_on() -{ - uint32_t buf_type = get_buf_type(m_type); - int r = ioctl(m_fd, VIDIOC_STREAMON, &buf_type); - FAIL_IF(r, "Failed to enable stream: %d", r); -} - -void VideoStreamer::stream_off() -{ - uint32_t buf_type = get_buf_type(m_type); - int r = ioctl(m_fd, VIDIOC_STREAMOFF, &buf_type); - FAIL_IF(r, "Failed to disable stream: %d", r); -} - -int VideoStreamer::export_buffer(uint32_t index) -{ - struct v4l2_exportbuffer expbuf; - - memset(&expbuf, 0, sizeof(expbuf)); - expbuf.type = get_buf_type(m_type); - expbuf.index = index; - int r = ioctl(m_fd, VIDIOC_EXPBUF, &expbuf); - FAIL_IF(r, "VIDIOC_EXPBUF failed: %d", r); - - return expbuf.fd; -} - -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); -} -- cgit v1.2.3