From fc59ea333d4f79fc2d46c5b7e6f203b74d23eca9 Mon Sep 17 00:00:00 2001 From: kallaballa Date: Sat, 15 Oct 2022 03:15:23 +0200 Subject: [PATCH] full capture example --- src/camera/camera-demo.cpp | 127 ++++++++++++++++++++++++++++++++++--- 1 file changed, 119 insertions(+), 8 deletions(-) diff --git a/src/camera/camera-demo.cpp b/src/camera/camera-demo.cpp index 115f33493..a9d49b30c 100644 --- a/src/camera/camera-demo.cpp +++ b/src/camera/camera-demo.cpp @@ -1,20 +1,80 @@ #define CL_TARGET_OPENCL_VERSION 220 -const long unsigned int WIDTH = 1920; -const long unsigned int HEIGHT = 1080; +constexpr long unsigned int WIDTH = 1920; +constexpr long unsigned int HEIGHT = 1080; +constexpr const char* INPUT_FILENAME = "example.mp4"; +constexpr const char* OUTPUT_FILENAME = "camera-demo.mkv"; +constexpr const int VA_HW_DEVICE_INDEX = 0; double FPS; -constexpr double OFFSCREEN = false; -#include "../tetra/subsystems.hpp" +#include "../common/subsystems.hpp" using std::cerr; using std::endl; cv::ocl::OpenCLExecutionContext VA_CONTEXT; +cv::ocl::OpenCLExecutionContext GL_CONTEXT; + +void render() { + //Render a tetrahedron using immediate mode because the code is more concise for a demo + glBindFramebuffer(GL_FRAMEBUFFER, kb::gl::frame_buf); + glViewport(0, 0, WIDTH , HEIGHT ); + glRotatef(1, 0, 1, 0); + glClearColor(0.0f, 0.0f, 1.0f, 1.0f); + + glColor3f(1.0, 1.0, 1.0); + glBegin(GL_LINES); + for (GLfloat i = -2.5; i <= 2.5; i += 0.25) { + glVertex3f(i, 0, 2.5); + glVertex3f(i, 0, -2.5); + glVertex3f(2.5, 0, i); + glVertex3f(-2.5, 0, i); + } + glEnd(); + + glBegin(GL_TRIANGLE_STRIP); + glColor3f(1, 1, 1); + glVertex3f(0, 2, 0); + glColor3f(1, 0, 0); + glVertex3f(-1, 0, 1); + glColor3f(0, 1, 0); + glVertex3f(1, 0, 1); + glColor3f(0, 0, 1); + glVertex3f(0, 0, -1.4); + glColor3f(1, 1, 1); + glVertex3f(0, 2, 0); + glColor3f(1, 0, 0); + glVertex3f(-1, 0, 1); + glEnd(); + glFlush(); + kb::gl::swapBuffers(); +} + +void glow(cv::UMat &src, int ksize = WIDTH / 85 % 2 == 0 ? WIDTH / 85 + 1 : WIDTH / 85) { + static cv::UMat resize; + static cv::UMat blur; + static cv::UMat src16; + + cv::bitwise_not(src, src); + + //Resize for some extra performance + cv::resize(src, resize, cv::Size(), 0.5, 0.5); + //Cheap blur + cv::boxFilter(resize, resize, -1, cv::Size(ksize, ksize), cv::Point(-1,-1), true, cv::BORDER_REPLICATE); + //Back to original size + cv::resize(resize, blur, cv::Size(WIDTH, HEIGHT)); + + //Multiply the src image with a blurred version of itself + cv::multiply(src, blur, src16, 1, CV_16U); + //Normalize and convert back to CV_8U + cv::divide(src16, cv::Scalar::all(255.0), src, 1, CV_8U); + + cv::bitwise_not(src, src); +} int main(int argc, char **argv) { using namespace kb; - + //Initialize OpenCL Context for VAAPI va::init_va(); /* * The OpenCLExecutionContext for VAAPI needs to be copied right after init_va(). @@ -22,8 +82,9 @@ int main(int argc, char **argv) { */ VA_CONTEXT = cv::ocl::OpenCLExecutionContext::getCurrent(); - cv::VideoCapture cap("/dev/video0", cv::CAP_FFMPEG, { - cv::CAP_PROP_HW_DEVICE, 0, + //Initialize MJPEG HW decoding using VAAPI + cv::VideoCapture cap(INPUT_FILENAME, cv::CAP_FFMPEG, { + cv::CAP_PROP_HW_DEVICE, VA_HW_DEVICE_INDEX, cv::CAP_PROP_HW_ACCELERATION, cv::VIDEO_ACCELERATION_VAAPI, cv::CAP_PROP_HW_ACCELERATION_USE_OPENCL, 1 }); @@ -34,24 +95,74 @@ int main(int argc, char **argv) { } FPS = cap.get(cv::CAP_PROP_FPS); - std::cerr << "FPS: " << FPS << std::endl; + std::cerr << "Detected FPS: " << FPS << std::endl; + + cv::VideoWriter video(OUTPUT_FILENAME, cv::CAP_FFMPEG, cv::VideoWriter::fourcc('V', 'P', '9', '0'), FPS, cv::Size(WIDTH, HEIGHT), { + cv::VIDEOWRITER_PROP_HW_DEVICE, VA_HW_DEVICE_INDEX, + cv::VIDEOWRITER_PROP_HW_ACCELERATION, cv::VIDEO_ACCELERATION_VAAPI, + cv::VIDEOWRITER_PROP_HW_ACCELERATION_USE_OPENCL, 1 + }); + + //Passing true to init_egl will create a OpenGL debug context + egl::init_egl(); + //Initialize OpenCL Context for OpenGL + gl::init_gl(); + /* + * The OpenCLExecutionContext for OpenGL needs to be copied right after init_gl(). + * Now everytime you want to do OpenGL interop first bind the context. + */ + GL_CONTEXT = cv::ocl::OpenCLExecutionContext::getCurrent(); cerr << "VA Version: " << va::get_info() << endl; + cerr << "EGL Version: " << egl::get_info() << endl; + cerr << "OpenGL Version: " << gl::get_info() << endl; cerr << "OpenCL Platforms: " << endl << cl::get_info() << endl; + cv::UMat frameBuffer; cv::UMat videoFrame; + cv::UMat videoFrameRGBA; uint64_t cnt = 1; int64 start = cv::getTickCount(); double tickFreq = cv::getTickFrequency(); while (true) { + //Activate the OpenCL context for VAAPI + VA_CONTEXT.bind(); + //Decode a frame using HW acceleration into a cv::UMat cap >> videoFrame; if (videoFrame.empty()) { cerr << "End of stream. Exiting" << endl; break; } + //The video is upside-down. Flip it. (OpenCL) + cv::flip(videoFrame, videoFrame, 0); + //Color-conversion from BGRA to RGB. (OpenCL) + cv::cvtColor(videoFrame, videoFrameRGBA, cv::COLOR_RGB2BGRA); + //Resize the frame. (OpenCL) + cv::resize(videoFrameRGBA, frameBuffer, cv::Size(WIDTH, HEIGHT)); + + //Activate the OpenCL context for OpenGL + GL_CONTEXT.bind(); + //Transfer buffer ownership to OpenGL + gl::return_frame_buffer(frameBuffer); + render(); + //Transfer buffer ownership to OpenCL + gl::fetch_frame_buffer(frameBuffer); + + //Glow effect (OpenCL) + glow(frameBuffer); + + //Color-conversion from BGRA to RGB. (OpenCL) + cv::cvtColor(frameBuffer, videoFrame, cv::COLOR_BGRA2RGB); + cv::flip(videoFrame, videoFrame, 0); + + //Activate the OpenCL context for VAAPI + VA_CONTEXT.bind(); + //Encode the frame using VAAPI on the GPU. + video.write(videoFrame); + //Measure FPS if (cnt % uint64(FPS) == 0) { int64 tick = cv::getTickCount();