├── .gitignore ├── CMakeLists.txt ├── CMakeLists.txt.user ├── LICENSE ├── Makefile ├── README.md ├── inc ├── V4l2Access.h ├── V4l2Capture.h ├── V4l2Device.h ├── V4l2MmapDevice.h ├── V4l2Output.h ├── V4l2ReadWriteDevice.h └── logger.h ├── src ├── V4l2Access.cpp ├── V4l2Capture.cpp ├── V4l2Device.cpp ├── V4l2MmapDevice.cpp ├── V4l2Output.cpp ├── V4l2ReadWriteDevice.cpp └── logger.cpp └── test.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | src/*.o 2 | *.a 3 | *.cmake 4 | CMakeCache.txt 5 | CMakeFiles/ 6 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | # set project name from current directory 4 | get_filename_component(BASENAME ${CMAKE_CURRENT_LIST_DIR} NAME) 5 | project(${BASENAME}) 6 | 7 | set (CMAKE_CXX_STANDARD 11) 8 | set(CMAKE_C_FLAGS "-Wall") 9 | set(CMAKE_CXX_FLAGS "-Wall") 10 | 11 | find_package (OpenCV REQUIRED NO_CMAKE_FIND_ROOT_PATH) 12 | 13 | if(OpenCV_FOUND) 14 | include_directories(${OpenCV_INCLUDE_DIRS}) 15 | message(STATUS "OpenCV library status:") 16 | message(STATUS " version: ${OpenCV_VERSION}") 17 | message(STATUS " libraries: ${OpenCV_LIBS}") 18 | message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}") 19 | endif() 20 | 21 | 22 | # define executable to build 23 | include_directories("inc") 24 | aux_source_directory(src SRC_FILES) 25 | add_library(v4l2cpp SHARED ${SRC_FILES}) 26 | target_link_libraries(v4l2cpp ${OpenCV_LIBS}) 27 | 28 | add_executable(client test.cpp) 29 | target_link_libraries(client v4l2cpp ${OpenCV_LIBS}) 30 | -------------------------------------------------------------------------------- /CMakeLists.txt.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | EnvironmentId 7 | {8f5ce50b-8e1f-455e-9db1-b612bd70303e} 8 | 9 | 10 | ProjectExplorer.Project.ActiveTarget 11 | 0 12 | 13 | 14 | ProjectExplorer.Project.EditorSettings 15 | 16 | true 17 | false 18 | true 19 | 20 | Cpp 21 | 22 | CppGlobal 23 | 24 | 25 | 26 | QmlJS 27 | 28 | QmlJSGlobal 29 | 30 | 31 | 2 32 | UTF-8 33 | false 34 | 4 35 | false 36 | 80 37 | true 38 | true 39 | 1 40 | true 41 | false 42 | 0 43 | true 44 | true 45 | 0 46 | 8 47 | true 48 | 1 49 | true 50 | true 51 | true 52 | false 53 | 54 | 55 | 56 | ProjectExplorer.Project.PluginSettings 57 | 58 | 59 | 60 | ProjectExplorer.Project.Target.0 61 | 62 | Desktop Qt 5.10.1 GCC 64bit 63 | Desktop Qt 5.10.1 GCC 64bit 64 | qt.qt5.5101.gcc_64_kit 65 | 0 66 | 0 67 | 0 68 | 69 | 70 | CMAKE_BUILD_TYPE:STRING=Debug 71 | 72 | /home/shining/work/Optimization/build-libv4l2cpp-Desktop_Qt_5_10_1_GCC_64bit-Debug 73 | 74 | 75 | 76 | 77 | all 78 | 79 | true 80 | CMake Build 81 | 82 | CMakeProjectManager.MakeStep 83 | 84 | 1 85 | Build 86 | 87 | ProjectExplorer.BuildSteps.Build 88 | 89 | 90 | 91 | 92 | 93 | clean 94 | 95 | true 96 | CMake Build 97 | 98 | CMakeProjectManager.MakeStep 99 | 100 | 1 101 | Clean 102 | 103 | ProjectExplorer.BuildSteps.Clean 104 | 105 | 2 106 | false 107 | 108 | Debug 109 | Debug 110 | CMakeProjectManager.CMakeBuildConfiguration 111 | 112 | 113 | 114 | CMAKE_BUILD_TYPE:STRING=Release 115 | 116 | /home/shining/work/Optimization/build-libv4l2cpp-Desktop_Qt_5_10_1_GCC_64bit-Release 117 | 118 | 119 | 120 | 121 | all 122 | 123 | true 124 | CMake Build 125 | 126 | CMakeProjectManager.MakeStep 127 | 128 | 1 129 | Build 130 | 131 | ProjectExplorer.BuildSteps.Build 132 | 133 | 134 | 135 | 136 | 137 | clean 138 | 139 | true 140 | CMake Build 141 | 142 | CMakeProjectManager.MakeStep 143 | 144 | 1 145 | Clean 146 | 147 | ProjectExplorer.BuildSteps.Clean 148 | 149 | 2 150 | false 151 | 152 | Release 153 | Release 154 | CMakeProjectManager.CMakeBuildConfiguration 155 | 156 | 2 157 | 158 | 159 | 0 160 | Deploy 161 | 162 | ProjectExplorer.BuildSteps.Deploy 163 | 164 | 1 165 | Deploy locally 166 | 167 | ProjectExplorer.DefaultDeployConfiguration 168 | 169 | 1 170 | 171 | 172 | false 173 | false 174 | 1000 175 | 176 | true 177 | 178 | false 179 | false 180 | false 181 | false 182 | true 183 | 0.01 184 | 10 185 | true 186 | 1 187 | 25 188 | 189 | 1 190 | true 191 | false 192 | true 193 | valgrind 194 | 195 | 0 196 | 1 197 | 2 198 | 3 199 | 4 200 | 5 201 | 6 202 | 7 203 | 8 204 | 9 205 | 10 206 | 11 207 | 12 208 | 13 209 | 14 210 | 211 | client 212 | 213 | 214 | /home/shining/work/Optimization/build-libv4l2cpp-Desktop_Qt_5_10_1_GCC_64bit-Debug 215 | 2 216 | 217 | client 218 | 219 | CMakeProjectManager.CMakeRunConfiguration.client 220 | 3768 221 | false 222 | true 223 | false 224 | false 225 | true 226 | 227 | 1 228 | 229 | 230 | 231 | ProjectExplorer.Project.TargetCount 232 | 1 233 | 234 | 235 | ProjectExplorer.Project.Updater.FileVersion 236 | 18 237 | 238 | 239 | Version 240 | 18 241 | 242 | 243 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CXXFLAGS = -W -Wall -pthread -g -pipe $(EXTRA_CXXFLAGS) 2 | CXXFLAGS += -I inc 3 | RM = rm -rf 4 | CXX ?= $(CROSS)g++ 5 | AR ?= $(CROSS)ar 6 | PREFIX?=/usr 7 | 8 | ifneq ($(wildcard $(SYSROOT)$(PREFIX)/include/log4cpp/Category.hh),) 9 | CXXFLAGS += -DHAVE_LOG4CPP -I $(SYSROOT)$(PREFIX)/include 10 | endif 11 | 12 | V4L2WRAPPER_CPP:=$(wildcard src/*.cpp) 13 | V4L2WRAPPER_OBJ:=$(V4L2WRAPPER_CPP:%.cpp=%.o) 14 | 15 | .DEFAULT_GOAL := all 16 | 17 | all: libv4l2wrapper.a 18 | 19 | %.o: %.cpp 20 | $(CXX) -c -o $@ $< $(CXXFLAGS) 21 | 22 | libv4l2wrapper.a: $(V4L2WRAPPER_OBJ) 23 | $(AR) rcs $@ $^ 24 | 25 | 26 | clean: 27 | -@$(RM) *.a $(V4L2WRAPPER_OBJ) 28 | 29 | install: 30 | mkdir -p $(PREFIX)/include/libv4l2cpp/ 31 | install -D -m 0755 inc/*.h $(PREFIX)/include/libv4l2cpp/ 32 | install -D -m 0755 *.a $(PREFIX)/lib 33 | 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | libv4l2cpp 3 | ==================== 4 | 5 | It is a C++ wrapper for V4L2 mofified from https://github.com/mpromonet/libv4l2cpp by mpromonet. 6 | I added more prints and solved problem which is a video device may have rather than one video resource.And main keypoints I added was opencv Mat BGR format surport. 7 | 8 | Dependencies 9 | ------------ 10 | - liblog4cpp5-dev (optional) 11 | 12 | V4L2 Capture 13 | ------------- 14 | - create a V4L2 Capture interface using MMAP interface: 15 | 16 | V4L2DeviceParameters param("/dev/video0", V4L2_PIX_FMT_*, width, height, fps, input_index, verbose); 17 | V4l2Capture* videoCapture = V4l2Capture::create(param, V4l2Access::IOTYPE_MMAP); 18 | 19 | - data are available : 20 | 21 | timeval timeout; 22 | bool isReadable = (videoCapture->isReadable(&timeout) == 1); 23 | 24 | - read data : 25 | 26 | size_t nb = videoCapture->read(buffer, bufferSize); 27 | 28 | 29 | V4L2 Output 30 | ------------- 31 | 32 | - To create a V4L2 Output interface using MMAP interface: 33 | 34 | V4L2DeviceParameters param("/dev/video0", V4L2_PIX_FMT_*, width, height, fps, input_index , verbose); 35 | V4l2Output* videoOutput = V4l2Output::create(param, V4l2Access::IOTYPE_MMAP); 36 | 37 | - data could be written : 38 | 39 | timeval timeout; 40 | bool isWritable = (videoOutput->isWritable(&timeout) == 1); 41 | 42 | - write data : 43 | 44 | size_t nb = videoOutput->write(buffer, bufferSize); 45 | -------------------------------------------------------------------------------- /inc/V4l2Access.h: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------- 2 | ** This software is in the public domain, furnished "as is", without technical 3 | ** support, and with no warranty, express or implied, as to its usefulness for 4 | ** any purpose. 5 | ** 6 | ** V4l2Access.h 7 | ** 8 | ** V4L2 wrapper 9 | ** 10 | ** -------------------------------------------------------------------------*/ 11 | 12 | 13 | #ifndef V4L2_ACCESS 14 | #define V4L2_ACCESS 15 | 16 | #include "V4l2Device.h" 17 | 18 | class V4l2Access 19 | { 20 | public: 21 | enum IoType 22 | { 23 | IOTYPE_READWRITE, 24 | IOTYPE_MMAP 25 | }; 26 | 27 | V4l2Access(V4l2Device* device); 28 | virtual ~V4l2Access(); 29 | 30 | int getFd() { return m_device->getFd(); } 31 | unsigned int getBufferSize() { return m_device->getBufferSize(); } 32 | unsigned int getFormat() { return m_device->getFormat(); } 33 | unsigned int getWidth() { return m_device->getWidth(); } 34 | unsigned int getHeight() { return m_device->getHeight(); } 35 | void queryFormat() { m_device->queryFormat(); } 36 | 37 | int isReady() { return m_device->isReady(); } 38 | int start() { return m_device->start(); } 39 | int stop() { return m_device->stop(); } 40 | 41 | private: 42 | V4l2Access(const V4l2Access&); 43 | V4l2Access & operator=(const V4l2Access&); 44 | 45 | protected: 46 | V4l2Device* m_device; 47 | }; 48 | 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /inc/V4l2Capture.h: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------- 2 | ** This software is in the public domain, furnished "as is", without technical 3 | ** support, and with no warranty, express or implied, as to its usefulness for 4 | ** any purpose. 5 | ** 6 | ** V4l2Capture.h 7 | ** 8 | ** V4L2 Capture wrapper 9 | ** 10 | ** -------------------------------------------------------------------------*/ 11 | 12 | 13 | #ifndef V4L2_CAPTURE 14 | #define V4L2_CAPTURE 15 | 16 | #include "V4l2Access.h" 17 | #include "opencv2/core/core.hpp" 18 | 19 | 20 | // --------------------------------- 21 | // V4L2 Capture 22 | // --------------------------------- 23 | class V4l2Capture : public V4l2Access 24 | { 25 | protected: 26 | V4l2Capture(V4l2Device* device); 27 | 28 | public: 29 | /** 30 | * @brief create 创建Capture 31 | * @param param 32 | *使用说明,我们读取UVC免驱的摄像头时,应该避免直接使用opencv的videocpature, 33 | * 因为简单的API使得我们并不知道我们到底获取的时摄像头的哪种图片格式。应该直接使用Qt v4l2 test benchmark软件去获取我们真正需要的 34 | * 图像帧格式。 35 | * V4L2_PIX_FMT_MJPEG (MJPEG) 36 | 使用范例 V4L2DeviceParameters param("/dev/video0", V4L2_PIX_FMT_MJPEG , 1920, 1080, 30, 0,verbose); 37 | * @param iotype 38 | * @return 39 | */ 40 | static V4l2Capture* create(const V4L2DeviceParameters & param, IoType iotype = V4l2Access::IOTYPE_MMAP); 41 | virtual ~V4l2Capture(); 42 | 43 | size_t read(char* buffer, size_t bufferSize); 44 | /** 45 | * @brief read 读取图像 46 | * @param readImage 获取的图像 47 | * @return 48 | */ 49 | int read(cv::Mat &readImage); 50 | /** 51 | * @brief isReadable 判断是都可读取图像 52 | * @param tv 等待的时间 53 | * timeval tv; 54 | tv.tv_sec=1; 55 | tv.tv_usec=0; 56 | int ret = this->isReadable(&tv); 57 | * 58 | * @return -1 不可读 0 超时 1 成功 59 | */ 60 | int isReadable(timeval* tv); 61 | /** 62 | * @brief getBusInfo 获取总线的地址,多个摄像头输入设备时便于判断我们现在采集的到底是哪个摄像头 63 | * @return 64 | */ 65 | const char * getBusInfo(); 66 | 67 | }; 68 | 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /inc/V4l2Device.h: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------- 2 | ** This software is in the public domain, furnished "as is", without technical 3 | ** support, and with no warranty, express or implied, as to its usefulness for 4 | ** any purpose. 5 | ** 6 | ** V4l2Device.h 7 | ** 8 | ** V4L2 wrapper 9 | ** 10 | ** -------------------------------------------------------------------------*/ 11 | 12 | 13 | #ifndef V4L2_DEVICE 14 | #define V4L2_DEVICE 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #ifndef V4L2_PIX_FMT_VP8 22 | #define V4L2_PIX_FMT_VP8 v4l2_fourcc('V', 'P', '8', '0') 23 | #endif 24 | #ifndef V4L2_PIX_FMT_VP9 25 | #define V4L2_PIX_FMT_VP9 v4l2_fourcc('V', 'P', '9', '0') 26 | #endif 27 | #ifndef V4L2_PIX_FMT_HEVC 28 | #define V4L2_PIX_FMT_HEVC v4l2_fourcc('H', 'E', 'V', 'C') 29 | #endif 30 | 31 | // --------------------------------- 32 | // V4L2 Device parameters 33 | // --------------------------------- 34 | /* 35 | * YUV 格式对照表,根据Qt v4l2 test benchmark软件(debain类系统 apt-get install qv4l2 安装)的capture image format一栏进行对应 36 | 2.6.1. Packed YUV formats 37 | 2.6.2. V4L2_PIX_FMT_GREY (‘GREY’) 38 | 2.6.3. V4L2_PIX_FMT_Y10 (‘Y10 ‘) 39 | 2.6.4. V4L2_PIX_FMT_Y12 (‘Y12 ‘) 40 | 2.6.5. V4L2_PIX_FMT_Y10BPACK (‘Y10B’) 41 | 2.6.6. V4L2_PIX_FMT_Y16 (‘Y16 ‘) 42 | 2.6.7. V4L2_PIX_FMT_Y16_BE (‘Y16 ‘ | (1 << 31)) 43 | 2.6.8. V4L2_PIX_FMT_Y8I (‘Y8I ‘) 44 | 2.6.9. V4L2_PIX_FMT_Y12I (‘Y12I’) 45 | 2.6.10. V4L2_PIX_FMT_UV8 (‘UV8’) 46 | 2.6.11. V4L2_PIX_FMT_YUYV (‘YUYV’) 47 | 2.6.12. V4L2_PIX_FMT_UYVY (‘UYVY’) 48 | 2.6.13. V4L2_PIX_FMT_YVYU (‘YVYU’) 49 | 2.6.14. V4L2_PIX_FMT_VYUY (‘VYUY’) 50 | 2.6.15. V4L2_PIX_FMT_Y41P (‘Y41P’) 51 | 2.6.16. V4L2_PIX_FMT_YVU420 (‘YV12’), V4L2_PIX_FMT_YUV420 (‘YU12’) 52 | 2.6.17. V4L2_PIX_FMT_YUV420M (‘YM12’), V4L2_PIX_FMT_YVU420M (‘YM21’) 53 | 2.6.18. V4L2_PIX_FMT_YUV422M (‘YM16’), V4L2_PIX_FMT_YVU422M (‘YM61’) 54 | 2.6.19. V4L2_PIX_FMT_YUV444M (‘YM24’), V4L2_PIX_FMT_YVU444M (‘YM42’) 55 | 2.6.20. V4L2_PIX_FMT_YVU410 (‘YVU9’), V4L2_PIX_FMT_YUV410 (‘YUV9’) 56 | 2.6.21. V4L2_PIX_FMT_YUV422P (‘422P’) 57 | 2.6.22. V4L2_PIX_FMT_YUV411P (‘411P’) 58 | 2.6.23. V4L2_PIX_FMT_NV12 (‘NV12’), V4L2_PIX_FMT_NV21 (‘NV21’) 59 | 2.6.24. V4L2_PIX_FMT_NV12M (‘NM12’), V4L2_PIX_FMT_NV21M (‘NM21’), V4L2_PIX_FMT_NV12MT_16X16 60 | 2.6.25. V4L2_PIX_FMT_NV12MT (‘TM12’) 61 | 2.6.26. V4L2_PIX_FMT_NV16 (‘NV16’), V4L2_PIX_FMT_NV61 (‘NV61’) 62 | 2.6.27. V4L2_PIX_FMT_NV16M (‘NM16’), V4L2_PIX_FMT_NV61M (‘NM61’) 63 | 2.6.28. V4L2_PIX_FMT_NV24 (‘NV24’), V4L2_PIX_FMT_NV42 (‘NV42’) 64 | 2.6.29. V4L2_PIX_FMT_M420 (‘M420’) 65 | */ 66 | struct V4L2DeviceParameters 67 | { /** 68 | * @brief V4L2DeviceParameters 69 | * @param devname 设备名,如输入"/dev/video0" 70 | * @param formatList 多个图像帧格式 71 | * @param width 设置的输出图像宽,并不一定生效。 72 | * @param height 设置的输出图像高,并不一定生效。 73 | * @param fps 设置的输出图像帧率,并不一定生效。 74 | * @param input_index 单设备多输入的情况下,指定输入index的参数,如果单设备单输入,直接传入参数0 75 | * @param verbose 76 | * @param openFlags 77 | */ 78 | V4L2DeviceParameters(const char* devname, const std::list & formatList, unsigned int width, unsigned int height, int fps,unsigned int input_index = 0, int verbose = 0, int openFlags = O_RDWR | O_NONBLOCK) : 79 | m_devName(devname), m_inputIndex(input_index), m_formatList(formatList), m_width(width), m_height(height), m_fps(fps), m_verbose(verbose), m_openFlags(openFlags) {} 80 | /** 81 | * @brief V4L2DeviceParameters 82 | * @param devname 83 | * @param format 图像帧格式 84 | * @param width 设置的输出图像宽,并不一定生效。 85 | * @param height 设置的输出图像高,并不一定生效。 86 | * @param fps 设置的输出图像帧率,并不一定生效。 87 | * @param input_index 单设备多输入的情况下,指定输入index的参数,如果单设备单输入,直接传入参数0 88 | * @param verbose 89 | * @param openFlags 90 | */ 91 | V4L2DeviceParameters(const char* devname, unsigned int format, unsigned int width, unsigned int height, int fps,unsigned int input_index = 0, int verbose = 0, int openFlags = O_RDWR | O_NONBLOCK) : 92 | m_devName(devname), m_inputIndex(input_index), m_width(width), m_height(height), m_fps(fps), m_verbose(verbose), m_openFlags(openFlags) { 93 | if (format) { 94 | m_formatList.push_back(format); 95 | } 96 | } 97 | 98 | std::string m_devName; 99 | unsigned int m_inputIndex; 100 | std::list m_formatList; 101 | unsigned int m_width; 102 | unsigned int m_height; 103 | int m_fps; 104 | int m_verbose; 105 | int m_openFlags; 106 | }; 107 | 108 | // --------------------------------- 109 | // V4L2 Device 110 | // --------------------------------- 111 | class V4l2Device 112 | { 113 | friend class V4l2Capture; 114 | friend class V4l2Output; 115 | 116 | protected: 117 | void close(); 118 | 119 | int initdevice(const char *dev_name , unsigned int mandatoryCapabilities ); 120 | int checkCapabilities(int fd, unsigned int mandatoryCapabilities); 121 | int configureFormat(int fd); 122 | int configureFormat(int fd, unsigned int format, unsigned int width, unsigned int height); 123 | int configureParam(int fd); 124 | 125 | virtual bool init(unsigned int mandatoryCapabilities); 126 | virtual size_t writeInternal(char*, size_t) { return -1; } 127 | virtual bool startPartialWrite(void) { return false; } 128 | virtual size_t writePartialInternal(char*, size_t) { return -1; } 129 | virtual bool endPartialWrite(void) { return false; } 130 | virtual size_t readInternal(char*, size_t) { return -1; } 131 | 132 | public: 133 | V4l2Device(const V4L2DeviceParameters& params, v4l2_buf_type deviceType); 134 | virtual ~V4l2Device(); 135 | 136 | virtual bool isReady() { return (m_fd != -1); } 137 | virtual bool start() { return true; } 138 | virtual bool stop() { return true; } 139 | 140 | unsigned int getBufferSize() { return m_bufferSize; } 141 | unsigned int getFormat() { return m_format; } 142 | unsigned int getWidth() { return m_width; } 143 | unsigned int getHeight() { return m_height; } 144 | unsigned char *getBusInfo() { return bus_info; } 145 | int getFd() { return m_fd; } 146 | void queryFormat(); 147 | 148 | protected: 149 | V4L2DeviceParameters m_params; 150 | int m_fd; 151 | v4l2_buf_type m_deviceType; 152 | 153 | unsigned int m_bufferSize; 154 | unsigned int m_format; 155 | unsigned int m_width; 156 | unsigned int m_height; 157 | 158 | struct v4l2_buffer m_partialWriteBuf; 159 | bool m_partialWriteInProgress; 160 | unsigned char bus_info[32]; 161 | }; 162 | 163 | 164 | #endif 165 | -------------------------------------------------------------------------------- /inc/V4l2MmapDevice.h: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------- 2 | ** This software is in the public domain, furnished "as is", without technical 3 | ** support, and with no warranty, express or implied, as to its usefulness for 4 | ** any purpose. 5 | ** 6 | ** V4l2MmapDevice.h 7 | ** 8 | ** V4L2 source using mmap API 9 | ** 10 | ** -------------------------------------------------------------------------*/ 11 | 12 | 13 | #ifndef V4L2_MMAP_DEVICE 14 | #define V4L2_MMAP_DEVICE 15 | 16 | #include "V4l2Device.h" 17 | 18 | #define V4L2MMAP_NBBUFFER 10 19 | 20 | class V4l2MmapDevice : public V4l2Device 21 | { 22 | protected: 23 | size_t writeInternal(char* buffer, size_t bufferSize); 24 | bool startPartialWrite(void); 25 | size_t writePartialInternal(char*, size_t); 26 | bool endPartialWrite(void); 27 | size_t readInternal(char* buffer, size_t bufferSize); 28 | 29 | public: 30 | V4l2MmapDevice(const V4L2DeviceParameters & params, v4l2_buf_type deviceType); 31 | virtual ~V4l2MmapDevice(); 32 | 33 | virtual bool init(unsigned int mandatoryiCapabilities); 34 | virtual bool isReady() { return ((m_fd != -1)&& (n_buffers != 0)); } 35 | virtual bool start(); 36 | virtual bool stop(); 37 | 38 | protected: 39 | unsigned int n_buffers; 40 | 41 | struct buffer 42 | { 43 | void * start; 44 | size_t length; 45 | }; 46 | buffer m_buffer[V4L2MMAP_NBBUFFER]; 47 | }; 48 | 49 | #endif 50 | 51 | -------------------------------------------------------------------------------- /inc/V4l2Output.h: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------- 2 | ** This software is in the public domain, furnished "as is", without technical 3 | ** support, and with no warranty, express or implied, as to its usefulness for 4 | ** any purpose. 5 | ** 6 | ** V4l2Output.h 7 | ** 8 | ** V4L2 Output wrapper 9 | ** 10 | ** -------------------------------------------------------------------------*/ 11 | 12 | 13 | #ifndef V4L2_OUTPUT 14 | #define V4L2_OUTPUT 15 | 16 | #include "V4l2Access.h" 17 | 18 | // --------------------------------- 19 | // V4L2 Output 20 | // --------------------------------- 21 | class V4l2Output : public V4l2Access 22 | { 23 | protected: 24 | V4l2Output(V4l2Device* device); 25 | 26 | public: 27 | static V4l2Output* create(const V4L2DeviceParameters & param, IoType iotype = V4l2Access::IOTYPE_MMAP); 28 | ~V4l2Output(); 29 | 30 | size_t write(char* buffer, size_t bufferSize); 31 | int isWritable(timeval* tv); 32 | bool startPartialWrite(void); 33 | size_t writePartial(char* buffer, size_t bufferSize); 34 | bool endPartialWrite(void); 35 | }; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /inc/V4l2ReadWriteDevice.h: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------- 2 | ** This software is in the public domain, furnished "as is", without technical 3 | ** support, and with no warranty, express or implied, as to its usefulness for 4 | ** any purpose. 5 | ** 6 | ** V4l2ReadWriteDevice.h 7 | ** 8 | ** V4L2 source using read/write API 9 | ** 10 | ** -------------------------------------------------------------------------*/ 11 | 12 | 13 | #ifndef V4L2_RW_DEVICE 14 | #define V4L2_RW_DEVICE 15 | 16 | #include "V4l2Device.h" 17 | 18 | 19 | class V4l2ReadWriteDevice : public V4l2Device 20 | { 21 | protected: 22 | virtual size_t writeInternal(char* buffer, size_t bufferSize); 23 | virtual size_t readInternal(char* buffer, size_t bufferSize); 24 | 25 | public: 26 | V4l2ReadWriteDevice(const V4L2DeviceParameters& params, v4l2_buf_type deviceType); 27 | }; 28 | 29 | 30 | #endif 31 | 32 | -------------------------------------------------------------------------------- /inc/logger.h: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------- 2 | ** This software is in the public domain, furnished "as is", without technical 3 | ** support, and with no warranty, express or implied, as to its usefulness for 4 | ** any purpose. 5 | ** 6 | ** logger.h 7 | ** 8 | ** -------------------------------------------------------------------------*/ 9 | 10 | #ifndef LOGGER_H 11 | #define LOGGER_H 12 | 13 | #include 14 | 15 | #ifdef HAVE_LOG4CPP 16 | #include "log4cpp/Category.hh" 17 | #include "log4cpp/FileAppender.hh" 18 | #include "log4cpp/PatternLayout.hh" 19 | 20 | #define LOG(__level) log4cpp::Category::getRoot() << log4cpp::Priority::__level << __FILE__ << ":" << __LINE__ << "\n\t" 21 | 22 | inline void initLogger(int verbose) 23 | { 24 | // initialize log4cpp 25 | log4cpp::Category &log = log4cpp::Category::getRoot(); 26 | log4cpp::Appender *app = new log4cpp::FileAppender("root", fileno(stdout)); 27 | if (app) 28 | { 29 | log4cpp::PatternLayout *plt = new log4cpp::PatternLayout(); 30 | if (plt) 31 | { 32 | plt->setConversionPattern("%d [%-6p] - %m%n"); 33 | app->setLayout(plt); 34 | } 35 | log.addAppender(app); 36 | } 37 | switch (verbose) 38 | { 39 | case 2: log.setPriority(log4cpp::Priority::DEBUG); break; 40 | case 1: log.setPriority(log4cpp::Priority::INFO); break; 41 | default: log.setPriority(log4cpp::Priority::NOTICE); break; 42 | 43 | } 44 | LOG(INFO) << "level:" << log4cpp::Priority::getPriorityName(log.getPriority()); 45 | } 46 | #else 47 | 48 | typedef enum {EMERG = 0, 49 | FATAL = 0, 50 | ALERT = 100, 51 | CRIT = 200, 52 | ERROR = 300, 53 | WARN = 400, 54 | NOTICE = 500, 55 | INFO = 600, 56 | DEBUG = 700, 57 | NOTSET = 800 58 | } PriorityLevel; 59 | 60 | #include 61 | extern int LogLevel; 62 | #define LOG(__level) if (__level<=LogLevel) std::cout << "\n[" << #__level << "] " << __FILE__ << ":" << __LINE__ << "\n\t" 63 | 64 | //#define LOG(__level) if (__level<=LogLevel) std::cout << "\n[" << #__level << "] " << __FILE__ << ":" << __LINE__ << "\n\t" 65 | //#define LOG(__level) if (__level<=LogLevel) std::cout<< "\n" 66 | 67 | inline void initLogger(int verbose) 68 | { 69 | switch (verbose) 70 | { 71 | case 2: LogLevel=DEBUG; break; 72 | case 1: LogLevel=INFO; break; 73 | default: LogLevel=NOTICE; break; 74 | 75 | } 76 | std::cout << "log level:" << LogLevel << std::endl; 77 | 78 | #endif 79 | 80 | #endif 81 | 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/V4l2Access.cpp: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------- 2 | ** This software is in the public domain, furnished "as is", without technical 3 | ** support, and with no warranty, express or implied, as to its usefulness for 4 | ** any purpose. 5 | ** 6 | ** V4l2Access.cpp 7 | ** 8 | ** V4L2 wrapper 9 | ** 10 | ** -------------------------------------------------------------------------*/ 11 | 12 | #include "V4l2Access.h" 13 | 14 | V4l2Access::V4l2Access(V4l2Device* device) : m_device(device) { 15 | } 16 | 17 | V4l2Access::~V4l2Access() { 18 | delete m_device; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /src/V4l2Capture.cpp: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------- 2 | ** This software is in the public domain, furnished "as is", without technical 3 | ** support, and with no warranty, express or implied, as to its usefulness for 4 | ** any purpose. 5 | ** 6 | ** V4l2Capture.cpp 7 | ** 8 | ** V4L2 wrapper 9 | ** 10 | ** -------------------------------------------------------------------------*/ 11 | 12 | 13 | // libv4l2 14 | #include 15 | 16 | #include 17 | 18 | // project 19 | #include "logger.h" 20 | #include "V4l2Capture.h" 21 | #include "V4l2MmapDevice.h" 22 | #include "V4l2ReadWriteDevice.h" 23 | #include "opencv2/opencv.hpp" 24 | 25 | // ----------------------------------------- 26 | // create video capture interface 27 | // ----------------------------------------- 28 | V4l2Capture* V4l2Capture::create(const V4L2DeviceParameters & param, IoType iotype) 29 | { 30 | V4l2Capture* videoCapture = NULL; 31 | V4l2Device* videoDevice = NULL; 32 | int caps = V4L2_CAP_VIDEO_CAPTURE; 33 | switch (iotype) 34 | { 35 | case IOTYPE_MMAP: 36 | videoDevice = new V4l2MmapDevice(param, V4L2_BUF_TYPE_VIDEO_CAPTURE); 37 | caps |= V4L2_CAP_STREAMING; 38 | break; 39 | case IOTYPE_READWRITE: 40 | videoDevice = new V4l2ReadWriteDevice(param, V4L2_BUF_TYPE_VIDEO_CAPTURE); 41 | caps |= V4L2_CAP_READWRITE; 42 | break; 43 | } 44 | 45 | if (videoDevice && !videoDevice->init(caps)) 46 | { 47 | delete videoDevice; 48 | videoDevice=NULL; 49 | } 50 | 51 | if (videoDevice) 52 | { 53 | videoCapture = new V4l2Capture(videoDevice); 54 | } 55 | return videoCapture; 56 | } 57 | 58 | // ----------------------------------------- 59 | // constructor 60 | // ----------------------------------------- 61 | V4l2Capture::V4l2Capture(V4l2Device* device) : V4l2Access(device) 62 | { 63 | } 64 | 65 | // ----------------------------------------- 66 | // destructor 67 | // ----------------------------------------- 68 | V4l2Capture::~V4l2Capture() 69 | { 70 | } 71 | 72 | // ----------------------------------------- 73 | // check readability 74 | // ----------------------------------------- 75 | int V4l2Capture::isReadable(timeval* tv) 76 | { 77 | int fd = m_device->getFd(); 78 | fd_set fdset; 79 | FD_ZERO(&fdset); 80 | FD_SET(fd, &fdset); 81 | return select(fd+1, &fdset, NULL, NULL, tv); 82 | } 83 | 84 | const char *V4l2Capture::getBusInfo() 85 | { 86 | return (const char *)this->m_device->getBusInfo(); 87 | } 88 | 89 | // ----------------------------------------- 90 | // read from V4l2Device 91 | // ----------------------------------------- 92 | size_t V4l2Capture::read(char* buffer, size_t bufferSize) 93 | { 94 | return m_device->readInternal(buffer, bufferSize); 95 | } 96 | 97 | int V4l2Capture::read(cv::Mat &readImage) 98 | { 99 | //清除原图像的数据,避免错误 100 | if(!readImage.empty()){ 101 | readImage.release(); 102 | } 103 | char buffer[this->getBufferSize()]; 104 | int rsize = this->read(buffer, sizeof(buffer)); 105 | if (rsize == -1) 106 | { 107 | return -1; 108 | } 109 | else 110 | { 111 | /* 112 | 2.6.1. Packed YUV formats 113 | 2.6.2. V4L2_PIX_FMT_GREY (‘GREY’) 114 | 2.6.3. V4L2_PIX_FMT_Y10 (‘Y10 ‘) 115 | 2.6.4. V4L2_PIX_FMT_Y12 (‘Y12 ‘) 116 | 2.6.5. V4L2_PIX_FMT_Y10BPACK (‘Y10B’) 117 | 2.6.6. V4L2_PIX_FMT_Y16 (‘Y16 ‘) 118 | 2.6.7. V4L2_PIX_FMT_Y16_BE (‘Y16 ‘ | (1 << 31)) 119 | 2.6.8. V4L2_PIX_FMT_Y8I (‘Y8I ‘) 120 | 2.6.9. V4L2_PIX_FMT_Y12I (‘Y12I’) 121 | 2.6.10. V4L2_PIX_FMT_UV8 (‘UV8’) 122 | 2.6.11. V4L2_PIX_FMT_YUYV (‘YUYV’) 123 | 2.6.12. V4L2_PIX_FMT_UYVY (‘UYVY’) 124 | 2.6.13. V4L2_PIX_FMT_YVYU (‘YVYU’) 125 | 2.6.14. V4L2_PIX_FMT_VYUY (‘VYUY’) 126 | 2.6.15. V4L2_PIX_FMT_Y41P (‘Y41P’) 127 | 2.6.16. V4L2_PIX_FMT_YVU420 (‘YV12’), V4L2_PIX_FMT_YUV420 (‘YU12’) 128 | 2.6.17. V4L2_PIX_FMT_YUV420M (‘YM12’), V4L2_PIX_FMT_YVU420M (‘YM21’) 129 | 2.6.18. V4L2_PIX_FMT_YUV422M (‘YM16’), V4L2_PIX_FMT_YVU422M (‘YM61’) 130 | 2.6.19. V4L2_PIX_FMT_YUV444M (‘YM24’), V4L2_PIX_FMT_YVU444M (‘YM42’) 131 | 2.6.20. V4L2_PIX_FMT_YVU410 (‘YVU9’), V4L2_PIX_FMT_YUV410 (‘YUV9’) 132 | 2.6.21. V4L2_PIX_FMT_YUV422P (‘422P’) 133 | 2.6.22. V4L2_PIX_FMT_YUV411P (‘411P’) 134 | 2.6.23. V4L2_PIX_FMT_NV12 (‘NV12’), V4L2_PIX_FMT_NV21 (‘NV21’) 135 | 2.6.24. V4L2_PIX_FMT_NV12M (‘NM12’), V4L2_PIX_FMT_NV21M (‘NM21’), V4L2_PIX_FMT_NV12MT_16X16 136 | 2.6.25. V4L2_PIX_FMT_NV12MT (‘TM12’) 137 | 2.6.26. V4L2_PIX_FMT_NV16 (‘NV16’), V4L2_PIX_FMT_NV61 (‘NV61’) 138 | 2.6.27. V4L2_PIX_FMT_NV16M (‘NM16’), V4L2_PIX_FMT_NV61M (‘NM61’) 139 | 2.6.28. V4L2_PIX_FMT_NV24 (‘NV24’), V4L2_PIX_FMT_NV42 (‘NV42’) 140 | 2.6.29. V4L2_PIX_FMT_M420 (‘M420’) 141 | 142 | * */ 143 | if(m_device->getFormat() == V4L2_PIX_FMT_YUYV){ 144 | cv::Mat v4l2Mat = cv::Mat( m_device->getHeight(),m_device->getWidth(), CV_8UC2, (void*)buffer); 145 | cv::cvtColor(v4l2Mat,readImage,cv::COLOR_YUV2BGRA_YUYV); 146 | }else if(m_device->getFormat() == V4L2_PIX_FMT_MJPEG){ 147 | cv::Mat v4l2Mat = cv::Mat( m_device->getHeight(),m_device->getWidth(), CV_8UC3, (void*)buffer); 148 | readImage = cv::imdecode(v4l2Mat, 1); 149 | }else if(m_device->getFormat() == V4L2_PIX_FMT_H264){ 150 | 151 | }else if(m_device->getFormat() == V4L2_PIX_FMT_NV12){ 152 | cv::Mat v4l2Mat = cv::Mat (m_device->getHeight()* 3 / 2, m_device->getWidth(), CV_8UC1, (void*)buffer); 153 | cv::cvtColor(v4l2Mat,readImage,cv::COLOR_YUV2BGR_NV12); 154 | }else if ((m_device->getFormat() == V4L2_PIX_FMT_BGR24) || (m_device->getFormat() == V4L2_PIX_FMT_RGB24)) { 155 | readImage = cv::Mat (m_device->getHeight(), m_device->getWidth(), CV_8UC3, (void*)buffer); 156 | }else if ((m_device->getFormat() == V4L2_PIX_FMT_YVU420) || (m_device->getFormat() == V4L2_PIX_FMT_YUV420)) { 157 | cv::Mat v4l2Mat = cv::Mat (m_device->getHeight()* 3 / 2, m_device->getWidth(), CV_8UC1, (void*)buffer); 158 | cv::cvtColor(v4l2Mat,readImage,cv::COLOR_YUV420p2BGR); 159 | } 160 | return 0; 161 | } 162 | 163 | } 164 | 165 | 166 | -------------------------------------------------------------------------------- /src/V4l2Device.cpp: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------- 2 | ** This software is in the public domain, furnished "as is", without technical 3 | ** support, and with no warranty, express or implied, as to its usefulness for 4 | ** any purpose. 5 | ** 6 | ** V4l2Device.cpp 7 | ** 8 | ** -------------------------------------------------------------------------*/ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | // libv4l2 17 | #include 18 | 19 | #include "logger.h" 20 | 21 | #include "V4l2Device.h" 22 | 23 | std::string fourcc(unsigned int format) 24 | { 25 | char formatArray[] = { (char)(format&0xff), (char)((format>>8)&0xff), (char)((format>>16)&0xff), (char)((format>>24)&0xff), 0 }; 26 | return std::string(formatArray, strlen(formatArray)); 27 | } 28 | 29 | // ----------------------------------------- 30 | // V4L2Device 31 | // ----------------------------------------- 32 | V4l2Device::V4l2Device(const V4L2DeviceParameters& params, v4l2_buf_type deviceType) : m_params(params), m_fd(-1), m_deviceType(deviceType), m_bufferSize(0), m_format(0) 33 | { 34 | } 35 | 36 | V4l2Device::~V4l2Device() 37 | { 38 | this->close(); 39 | } 40 | 41 | void V4l2Device::close() 42 | { 43 | if (m_fd != -1) 44 | ::close(m_fd); 45 | 46 | m_fd = -1; 47 | } 48 | 49 | // query current format 50 | void V4l2Device::queryFormat() 51 | { 52 | struct v4l2_format fmt; 53 | memset(&fmt,0,sizeof(fmt)); 54 | fmt.type = m_deviceType; 55 | if (0 == ioctl(m_fd,VIDIOC_G_FMT,&fmt)) 56 | { 57 | m_format = fmt.fmt.pix.pixelformat; 58 | m_width = fmt.fmt.pix.width; 59 | m_height = fmt.fmt.pix.height; 60 | m_bufferSize = fmt.fmt.pix.sizeimage; 61 | 62 | LOG(NOTICE) << m_params.m_devName << ":" << fourcc(m_format) << " size:" << m_width << "x" << m_height << " bufferSize:" << m_bufferSize; 63 | } 64 | } 65 | 66 | // intialize the V4L2 connection 67 | bool V4l2Device::init(unsigned int mandatoryCapabilities ) 68 | { 69 | struct stat sb; 70 | if ( (stat(m_params.m_devName.c_str(), &sb)==0) && ((sb.st_mode & S_IFMT) == S_IFCHR) ) 71 | { 72 | if (initdevice(m_params.m_devName.c_str(), mandatoryCapabilities) == -1 ) 73 | { 74 | LOG(ERROR) << "Cannot init device:" << m_params.m_devName; 75 | } 76 | } 77 | else 78 | { 79 | // open a normal file 80 | m_fd = open(m_params.m_devName.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU); 81 | } 82 | return (m_fd!=-1); 83 | } 84 | 85 | // intialize the V4L2 device 86 | int V4l2Device::initdevice(const char *dev_name,unsigned int mandatoryCapabilities ) 87 | { 88 | m_fd = open(dev_name, m_params.m_openFlags); 89 | if (m_fd < 0) 90 | { 91 | LOG(ERROR) << "Cannot open device:" << m_params.m_devName << " " << strerror(errno); 92 | this->close(); 93 | return -1; 94 | } 95 | /* 96 | * 查询video的可输入设备数,和对应的名字 97 | */ 98 | struct v4l2_input input; 99 | 100 | struct v4l2_standard standard; 101 | 102 | memset (&input, 0, sizeof (input)); 103 | 104 | //首先获得当前输入的 index,注意只是 index,要获得具体的信息,就的调用列举操作 105 | input.index = m_params.m_inputIndex; 106 | if (-1 == ioctl(m_fd, VIDIOC_S_INPUT, &input)){ 107 | LOG(ERROR) << "can not set " << m_params.m_inputIndex <<" input index"; 108 | return -1; 109 | } 110 | if (-1 == ioctl (m_fd, VIDIOC_G_INPUT, &input.index)) { 111 | 112 | LOG(ERROR) << "get VIDIOC_G_INPUT error "; 113 | return -1; 114 | } 115 | 116 | 117 | //调用列举操作,获得 input.index 对应的输入的具体信息 118 | 119 | if (-1 == ioctl (m_fd, VIDIOC_ENUMINPUT, &input)) { 120 | LOG(ERROR) << "Get ”VIDIOC_ENUM_INPUT” error"; 121 | return -1; 122 | } 123 | LOG(NOTICE) << "Current input " <close(); 147 | return -1; 148 | } 149 | if (configureFormat(m_fd) !=0) 150 | { 151 | this->close(); 152 | return -1; 153 | } 154 | if (configureParam(m_fd) !=0) 155 | { 156 | this->close(); 157 | return -1; 158 | } 159 | 160 | return m_fd; 161 | } 162 | static std::string frmtype2s(unsigned type) 163 | { 164 | static const char *types[] = { 165 | "Unknown", 166 | "Discrete", 167 | "Continuous", 168 | "Stepwise" 169 | }; 170 | 171 | if (type > 3) 172 | type = 0; 173 | return types[type]; 174 | } 175 | static std::string fract2sec(const struct v4l2_fract &f) 176 | { 177 | char buf[100]; 178 | 179 | sprintf(buf, "%.3f s", (1.0 * f.numerator) / f.denominator); 180 | return buf; 181 | } 182 | 183 | static std::string fract2fps(const struct v4l2_fract &f) 184 | { 185 | char buf[100]; 186 | 187 | sprintf(buf, "%.3f fps", (1.0 * f.denominator) / f.numerator); 188 | return buf; 189 | } 190 | 191 | static void print_frmival(const struct v4l2_frmivalenum &frmival) 192 | { 193 | // printf("%s\tInterval: %s ", prefix, frmtype2s(frmival.type).c_str()); 194 | 195 | if (frmival.type == V4L2_FRMIVAL_TYPE_DISCRETE) { 196 | LOG(NOTICE) << "Interval: "<"<< fract2fps(frmival.discrete); 197 | } else if (frmival.type == V4L2_FRMIVAL_TYPE_STEPWISE) { 198 | LOG(NOTICE) << "Interval: "<= 0) { 272 | LOG(NOTICE) <<(fmtdesc.index+1) <<"."<= 0){ 276 | 277 | if(frmsize.type == V4L2_FRMSIZE_TYPE_DISCRETE){ 278 | LOG(NOTICE) << "width:"<= 0) { 284 | print_frmival(frmival); 285 | frmival.index++; 286 | } 287 | }else if(frmsize.type == V4L2_FRMSIZE_TYPE_STEPWISE){ 288 | LOG(NOTICE) << "width:"<queryFormat(); 322 | 323 | unsigned int width = m_width; 324 | unsigned int height = m_height; 325 | if (m_params.m_width != 0) { 326 | width= m_params.m_width; 327 | } 328 | if (m_params.m_height != 0) { 329 | height= m_params.m_height; 330 | } 331 | if ( (m_params.m_formatList.size()==0) && (m_format != 0) ) { 332 | m_params.m_formatList.push_back(m_format); 333 | } 334 | 335 | // try to set format, widht, height 336 | std::list::iterator it; 337 | for (it = m_params.m_formatList.begin(); it != m_params.m_formatList.end(); ++it) { 338 | unsigned int format = *it; 339 | if (this->configureFormat(fd, format, width, height)==0) { 340 | // format has been set 341 | // get the format again because calling SET-FMT return a bad buffersize using v4l2loopback 342 | this->queryFormat(); 343 | return 0; 344 | } 345 | } 346 | return -1; 347 | } 348 | 349 | // configure capture format 350 | int V4l2Device::configureFormat(int fd, unsigned int format, unsigned int width, unsigned int height) 351 | { 352 | struct v4l2_format fmt; 353 | memset(&(fmt), 0, sizeof(fmt)); 354 | fmt.type = m_deviceType; 355 | fmt.fmt.pix.width = width; 356 | fmt.fmt.pix.height = height; 357 | fmt.fmt.pix.pixelformat = format; 358 | fmt.fmt.pix.field = V4L2_FIELD_ANY; 359 | 360 | if (ioctl(fd, VIDIOC_S_FMT, &fmt) == -1) 361 | { 362 | LOG(ERROR) << "Cannot set format:" << fourcc(format) << " for device:" << m_params.m_devName << " " << strerror(errno); 363 | return -1; 364 | } 365 | if (fmt.fmt.pix.pixelformat != format) 366 | { 367 | LOG(ERROR) << "Cannot set pixelformat to:" << fourcc(format) << " format is:" << fourcc(fmt.fmt.pix.pixelformat); 368 | return -1; 369 | } 370 | if ((fmt.fmt.pix.width != width) || (fmt.fmt.pix.height != height)) 371 | { 372 | LOG(WARN) << "Cannot set size to:" << width << "x" << height << " size is:" << fmt.fmt.pix.width << "x" << fmt.fmt.pix.height; 373 | } 374 | 375 | m_format = fmt.fmt.pix.pixelformat; 376 | m_width = fmt.fmt.pix.width; 377 | m_height = fmt.fmt.pix.height; 378 | m_bufferSize = fmt.fmt.pix.sizeimage; 379 | 380 | LOG(NOTICE) <<"Setting "<< m_params.m_devName << ":" << fourcc(m_format) << " size:" << m_width << "x" << m_height << " bufferSize:" << m_bufferSize; 381 | 382 | return 0; 383 | } 384 | 385 | // configure capture FPS 386 | int V4l2Device::configureParam(int fd) 387 | { 388 | if (m_params.m_fps!=0) 389 | { 390 | struct v4l2_streamparm param; 391 | memset(&(param), 0, sizeof(param)); 392 | param.type = m_deviceType; 393 | param.parm.capture.timeperframe.numerator = 1; 394 | param.parm.capture.timeperframe.denominator = m_params.m_fps; 395 | 396 | if (ioctl(fd, VIDIOC_S_PARM, ¶m) == -1) 397 | { 398 | LOG(WARN) << "Cannot set param for device:" << m_params.m_devName << " " << strerror(errno); 399 | } 400 | 401 | LOG(NOTICE) <<"Setting "<< "fps:" << param.parm.capture.timeperframe.numerator << "/" << param.parm.capture.timeperframe.denominator; 402 | LOG(NOTICE) <<"Setting "<< "nbBuffer:" << param.parm.capture.readbuffers; 403 | } 404 | 405 | return 0; 406 | } 407 | 408 | 409 | -------------------------------------------------------------------------------- /src/V4l2MmapDevice.cpp: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------- 2 | ** This software is in the public domain, furnished "as is", without technical 3 | ** support, and with no warranty, express or implied, as to its usefulness for 4 | ** any purpose. 5 | ** 6 | ** V4l2MmapDevice.cpp 7 | ** 8 | ** V4L2 source using mmap API 9 | ** 10 | ** -------------------------------------------------------------------------*/ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | // libv4l2 20 | #include 21 | 22 | // project 23 | #include "logger.h" 24 | #include "V4l2MmapDevice.h" 25 | 26 | V4l2MmapDevice::V4l2MmapDevice(const V4L2DeviceParameters & params, v4l2_buf_type deviceType) : V4l2Device(params, deviceType), n_buffers(0) 27 | { 28 | memset(&m_buffer, 0, sizeof(m_buffer)); 29 | } 30 | 31 | bool V4l2MmapDevice::init(unsigned int mandatoryCapabilities) 32 | { 33 | bool ret = V4l2Device::init(mandatoryCapabilities); 34 | if (ret) 35 | { 36 | ret = this->start(); 37 | } 38 | return ret; 39 | } 40 | 41 | V4l2MmapDevice::~V4l2MmapDevice() 42 | { 43 | this->stop(); 44 | } 45 | 46 | 47 | bool V4l2MmapDevice::start() 48 | { 49 | LOG(NOTICE) << "Device " << m_params.m_devName; 50 | 51 | bool success = true; 52 | struct v4l2_requestbuffers req; 53 | memset (&req, 0, sizeof(req)); 54 | req.count = V4L2MMAP_NBBUFFER; 55 | req.type = m_deviceType; 56 | req.memory = V4L2_MEMORY_MMAP; 57 | 58 | if (-1 == ioctl(m_fd, VIDIOC_REQBUFS, &req)) 59 | { 60 | if (EINVAL == errno) 61 | { 62 | LOG(ERROR) << "Device " << m_params.m_devName << " does not support memory mapping"; 63 | success = false; 64 | } 65 | else 66 | { 67 | perror("VIDIOC_REQBUFS"); 68 | success = false; 69 | } 70 | } 71 | else 72 | { 73 | LOG(NOTICE) << "Device " << m_params.m_devName << " nb buffer:" << req.count; 74 | 75 | // allocate buffers 76 | memset(&m_buffer,0, sizeof(m_buffer)); 77 | for (n_buffers = 0; n_buffers < req.count; ++n_buffers) 78 | { 79 | struct v4l2_buffer buf; 80 | memset (&buf, 0, sizeof(buf)); 81 | buf.type = m_deviceType; 82 | buf.memory = V4L2_MEMORY_MMAP; 83 | buf.index = n_buffers; 84 | 85 | if (-1 == ioctl(m_fd, VIDIOC_QUERYBUF, &buf)) 86 | { 87 | perror("VIDIOC_QUERYBUF"); 88 | success = false; 89 | } 90 | else 91 | { 92 | LOG(INFO) << "Device " << m_params.m_devName << " buffer idx:" << n_buffers << " size:" << buf.length << " offset:" << buf.m.offset; 93 | m_buffer[n_buffers].length = buf.length; 94 | if (!m_buffer[n_buffers].length) { 95 | m_buffer[n_buffers].length = buf.bytesused; 96 | } 97 | m_buffer[n_buffers].start = mmap ( NULL /* start anywhere */, 98 | m_buffer[n_buffers].length, 99 | PROT_READ | PROT_WRITE /* required */, 100 | MAP_SHARED /* recommended */, 101 | m_fd, 102 | buf.m.offset); 103 | 104 | if (MAP_FAILED == m_buffer[n_buffers].start) 105 | { 106 | perror("mmap"); 107 | success = false; 108 | } 109 | } 110 | } 111 | 112 | // queue buffers 113 | for (unsigned int i = 0; i < n_buffers; ++i) 114 | { 115 | struct v4l2_buffer buf; 116 | memset (&buf, 0, sizeof(buf)); 117 | buf.type = m_deviceType; 118 | buf.memory = V4L2_MEMORY_MMAP; 119 | buf.index = i; 120 | 121 | if (-1 == ioctl(m_fd, VIDIOC_QBUF, &buf)) 122 | { 123 | perror("VIDIOC_QBUF"); 124 | success = false; 125 | } 126 | } 127 | 128 | // start stream 129 | int type = m_deviceType; 130 | if (-1 == ioctl(m_fd, VIDIOC_STREAMON, &type)) 131 | { 132 | perror("VIDIOC_STREAMON"); 133 | success = false; 134 | } 135 | } 136 | return success; 137 | } 138 | 139 | bool V4l2MmapDevice::stop() 140 | { 141 | LOG(NOTICE) << "Device " << m_params.m_devName; 142 | 143 | bool success = true; 144 | 145 | int type = m_deviceType; 146 | if (-1 == ioctl(m_fd, VIDIOC_STREAMOFF, &type)) 147 | { 148 | perror("VIDIOC_STREAMOFF"); 149 | success = false; 150 | } 151 | 152 | for (unsigned int i = 0; i < n_buffers; ++i) 153 | { 154 | if (-1 == munmap (m_buffer[i].start, m_buffer[i].length)) 155 | { 156 | perror("munmap"); 157 | success = false; 158 | } 159 | } 160 | 161 | // free buffers 162 | struct v4l2_requestbuffers req; 163 | memset (&req, 0, sizeof(req)); 164 | req.count = 0; 165 | req.type = m_deviceType; 166 | req.memory = V4L2_MEMORY_MMAP; 167 | if (-1 == ioctl(m_fd, VIDIOC_REQBUFS, &req)) 168 | { 169 | perror("VIDIOC_REQBUFS"); 170 | success = false; 171 | } 172 | 173 | n_buffers = 0; 174 | return success; 175 | } 176 | 177 | size_t V4l2MmapDevice::readInternal(char* buffer, size_t bufferSize) 178 | { 179 | size_t size = 0; 180 | if (n_buffers > 0) 181 | { 182 | struct v4l2_buffer buf; 183 | memset (&buf, 0, sizeof(buf)); 184 | buf.type = m_deviceType; 185 | buf.memory = V4L2_MEMORY_MMAP; 186 | 187 | if (-1 == ioctl(m_fd, VIDIOC_DQBUF, &buf)) 188 | { 189 | perror("VIDIOC_DQBUF"); 190 | size = -1; 191 | } 192 | else if (buf.index < n_buffers) 193 | { 194 | size = buf.bytesused; 195 | if (size > bufferSize) 196 | { 197 | size = bufferSize; 198 | LOG(WARN) << "Device " << m_params.m_devName << " buffer truncated available:" << bufferSize << " needed:" << buf.bytesused; 199 | } 200 | memcpy(buffer, m_buffer[buf.index].start, size); 201 | 202 | if (-1 == ioctl(m_fd, VIDIOC_QBUF, &buf)) 203 | { 204 | perror("VIDIOC_QBUF"); 205 | size = -1; 206 | } 207 | } 208 | } 209 | return size; 210 | } 211 | 212 | size_t V4l2MmapDevice::writeInternal(char* buffer, size_t bufferSize) 213 | { 214 | size_t size = 0; 215 | if (n_buffers > 0) 216 | { 217 | struct v4l2_buffer buf; 218 | memset (&buf, 0, sizeof(buf)); 219 | buf.type = m_deviceType; 220 | buf.memory = V4L2_MEMORY_MMAP; 221 | 222 | if (-1 == ioctl(m_fd, VIDIOC_DQBUF, &buf)) 223 | { 224 | perror("VIDIOC_DQBUF"); 225 | size = -1; 226 | } 227 | else if (buf.index < n_buffers) 228 | { 229 | size = bufferSize; 230 | if (size > buf.length) 231 | { 232 | LOG(WARN) << "Device " << m_params.m_devName << " buffer truncated available:" << buf.length << " needed:" << size; 233 | size = buf.length; 234 | } 235 | memcpy(m_buffer[buf.index].start, buffer, size); 236 | buf.bytesused = size; 237 | 238 | if (-1 == ioctl(m_fd, VIDIOC_QBUF, &buf)) 239 | { 240 | perror("VIDIOC_QBUF"); 241 | size = -1; 242 | } 243 | } 244 | } 245 | return size; 246 | } 247 | 248 | bool V4l2MmapDevice::startPartialWrite(void) 249 | { 250 | if (n_buffers <= 0) 251 | return false; 252 | if (m_partialWriteInProgress) 253 | return false; 254 | memset(&m_partialWriteBuf, 0, sizeof(m_partialWriteBuf)); 255 | m_partialWriteBuf.type = m_deviceType; 256 | m_partialWriteBuf.memory = V4L2_MEMORY_MMAP; 257 | if (-1 == ioctl(m_fd, VIDIOC_DQBUF, &m_partialWriteBuf)) 258 | { 259 | perror("VIDIOC_DQBUF"); 260 | return false; 261 | } 262 | m_partialWriteBuf.bytesused = 0; 263 | m_partialWriteInProgress = true; 264 | return true; 265 | } 266 | 267 | size_t V4l2MmapDevice::writePartialInternal(char* buffer, size_t bufferSize) 268 | { 269 | size_t new_size = 0; 270 | size_t size = 0; 271 | if ((n_buffers > 0) && m_partialWriteInProgress) 272 | { 273 | if (m_partialWriteBuf.index < n_buffers) 274 | { 275 | new_size = m_partialWriteBuf.bytesused + bufferSize; 276 | if (new_size > m_partialWriteBuf.length) 277 | { 278 | LOG(WARN) << "Device " << m_params.m_devName << " buffer truncated available:" << m_partialWriteBuf.length << " needed:" << new_size; 279 | new_size = m_partialWriteBuf.length; 280 | } 281 | size = new_size - m_partialWriteBuf.bytesused; 282 | memcpy(&((char *)m_buffer[m_partialWriteBuf.index].start)[m_partialWriteBuf.bytesused], buffer, size); 283 | 284 | m_partialWriteBuf.bytesused += size; 285 | } 286 | } 287 | return size; 288 | } 289 | 290 | bool V4l2MmapDevice::endPartialWrite(void) 291 | { 292 | if (!m_partialWriteInProgress) 293 | return false; 294 | if (n_buffers <= 0) 295 | { 296 | m_partialWriteInProgress = false; // abort partial write 297 | return true; 298 | } 299 | if (-1 == ioctl(m_fd, VIDIOC_QBUF, &m_partialWriteBuf)) 300 | { 301 | perror("VIDIOC_QBUF"); 302 | m_partialWriteInProgress = false; // abort partial write 303 | return true; 304 | } 305 | m_partialWriteInProgress = false; 306 | return true; 307 | } 308 | -------------------------------------------------------------------------------- /src/V4l2Output.cpp: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------- 2 | ** This software is in the public domain, furnished "as is", without technical 3 | ** support, and with no warranty, express or implied, as to its usefulness for 4 | ** any purpose. 5 | ** 6 | ** V4l2Output.cpp 7 | ** 8 | ** V4L2 wrapper 9 | ** 10 | ** -------------------------------------------------------------------------*/ 11 | 12 | #include 13 | 14 | // libv4l2 15 | #include 16 | 17 | // project 18 | #include "logger.h" 19 | 20 | #include "V4l2Output.h" 21 | #include "V4l2MmapDevice.h" 22 | #include "V4l2ReadWriteDevice.h" 23 | 24 | // ----------------------------------------- 25 | // create video output interface 26 | // ----------------------------------------- 27 | V4l2Output* V4l2Output::create(const V4L2DeviceParameters & param, IoType iotype) 28 | { 29 | V4l2Output* videoOutput = NULL; 30 | V4l2Device* videoDevice = NULL; 31 | int caps = V4L2_CAP_VIDEO_OUTPUT; 32 | switch (iotype) 33 | { 34 | case IOTYPE_MMAP: 35 | videoDevice = new V4l2MmapDevice(param, V4L2_BUF_TYPE_VIDEO_OUTPUT); 36 | caps |= V4L2_CAP_STREAMING; 37 | break; 38 | case IOTYPE_READWRITE: 39 | videoDevice = new V4l2ReadWriteDevice(param, V4L2_BUF_TYPE_VIDEO_OUTPUT); 40 | caps |= V4L2_CAP_READWRITE; 41 | break; 42 | } 43 | 44 | if (videoDevice && !videoDevice->init(caps)) 45 | { 46 | delete videoDevice; 47 | videoDevice=NULL; 48 | } 49 | 50 | if (videoDevice) 51 | { 52 | videoOutput = new V4l2Output(videoDevice); 53 | } 54 | return videoOutput; 55 | } 56 | 57 | // ----------------------------------------- 58 | // constructor 59 | // ----------------------------------------- 60 | V4l2Output::V4l2Output(V4l2Device* device) : V4l2Access(device) 61 | { 62 | } 63 | 64 | // ----------------------------------------- 65 | // destructor 66 | // ----------------------------------------- 67 | V4l2Output::~V4l2Output() 68 | { 69 | } 70 | 71 | // ----------------------------------------- 72 | // check writability 73 | // ----------------------------------------- 74 | int V4l2Output::isWritable(timeval* tv) 75 | { 76 | int fd = m_device->getFd(); 77 | fd_set fdset; 78 | FD_ZERO(&fdset); 79 | FD_SET(fd, &fdset); 80 | return select(fd+1, NULL, &fdset, NULL, tv); 81 | } 82 | 83 | // ----------------------------------------- 84 | // write to V4l2Device 85 | // ----------------------------------------- 86 | size_t V4l2Output::write(char* buffer, size_t bufferSize) 87 | { 88 | return m_device->writeInternal(buffer, bufferSize); 89 | } 90 | 91 | 92 | bool V4l2Output::startPartialWrite(void) 93 | { 94 | return m_device->startPartialWrite(); 95 | } 96 | 97 | size_t V4l2Output::writePartial(char* buffer, size_t bufferSize) 98 | { 99 | return m_device->writePartialInternal(buffer, bufferSize); 100 | } 101 | 102 | bool V4l2Output::endPartialWrite(void) 103 | { 104 | return m_device->endPartialWrite(); 105 | } 106 | 107 | -------------------------------------------------------------------------------- /src/V4l2ReadWriteDevice.cpp: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------- 2 | ** This software is in the public domain, furnished "as is", without technical 3 | ** support, and with no warranty, express or implied, as to its usefulness for 4 | ** any purpose. 5 | ** 6 | ** V4l2ReadWriteDevice.cpp 7 | ** 8 | ** V4L2 source using read/write API 9 | ** 10 | ** -------------------------------------------------------------------------*/ 11 | 12 | #include 13 | 14 | #include "V4l2ReadWriteDevice.h" 15 | 16 | V4l2ReadWriteDevice::V4l2ReadWriteDevice(const V4L2DeviceParameters& params, v4l2_buf_type deviceType) : V4l2Device(params, deviceType) { 17 | } 18 | 19 | 20 | size_t V4l2ReadWriteDevice::writeInternal(char* buffer, size_t bufferSize) { 21 | return ::write(m_fd, buffer, bufferSize); 22 | } 23 | 24 | size_t V4l2ReadWriteDevice::readInternal(char* buffer, size_t bufferSize) { 25 | return ::read(m_fd, buffer, bufferSize); 26 | } 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/logger.cpp: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------- 2 | ** This software is in the public domain, furnished "as is", without technical 3 | ** support, and with no warranty, express or implied, as to its usefulness for 4 | ** any purpose. 5 | ** 6 | ** logger.cpp 7 | ** 8 | ** -------------------------------------------------------------------------*/ 9 | 10 | #include "logger.h" 11 | 12 | #ifndef HAVE_LOG4CPP 13 | int LogLevel=NOTICE; 14 | #endif 15 | -------------------------------------------------------------------------------- /test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "logger.h" 4 | #include "opencv2/opencv.hpp" 5 | #include "opencv2/highgui/highgui.hpp" 6 | 7 | int main(){ 8 | int verbose=0; 9 | int stop=0; 10 | const char * in_devname = "/dev/video0";/* V4L2_PIX_FMT_YUYV V4L2_PIX_FMT_MJPEG*/ 11 | /* 12 | *使用说明,我们读取UVC免驱的摄像头时,应该避免直接使用opencv的videocpature, 13 | * 因为简单的API使得我们并不知道我们到底获取的时摄像头的哪种图片格式。应该直接使用Qt v4l2 test benchmark软件去获取我们真正需要的 14 | * 图像帧格式。 15 | * V4L2_PIX_FMT_MJPEG (MJPEG) 16 | */ 17 | V4L2DeviceParameters param(in_devname, V4L2_PIX_FMT_MJPEG , 1920, 1080, 30, 0,verbose); 18 | V4l2Capture* videoCapture = V4l2Capture::create(param, V4l2Access::IOTYPE_MMAP); 19 | if (videoCapture == NULL) 20 | { 21 | LOG(WARN) << "Cannot create V4L2 capture interface for device:" << "/dev/video0"; 22 | return -1; 23 | } 24 | timeval tv; 25 | LOG(NOTICE) << "USB bus:" <getBusInfo(); 26 | LOG(NOTICE) << "Start Uncompressing " << in_devname ; 27 | 28 | while (!stop) 29 | { 30 | tv.tv_sec=1; 31 | tv.tv_usec=0; 32 | int ret = videoCapture->isReadable(&tv); 33 | if (ret == 1) 34 | { 35 | cv::Mat v4l2Mat; 36 | ret = videoCapture->read(v4l2Mat); 37 | 38 | if (ret != 0) 39 | { 40 | LOG(NOTICE) << "stop " ; 41 | stop=1; 42 | } 43 | else 44 | { 45 | cv::imwrite("test.jpg",v4l2Mat); 46 | } 47 | } 48 | else if (ret == -1) //返回错误 49 | { 50 | LOG(NOTICE) << "stop " << strerror(errno); 51 | stop=1; 52 | }else if( ret == 0) // 返回超时 53 | { 54 | 55 | } 56 | break; 57 | } 58 | delete videoCapture; 59 | V4L2DeviceParameters mparam(in_devname, V4L2_PIX_FMT_YUYV , 1920, 1080, 5, 0,verbose); 60 | videoCapture = V4l2Capture::create(mparam, V4l2Access::IOTYPE_MMAP); 61 | while (!stop) 62 | { 63 | tv.tv_sec=1; 64 | tv.tv_usec=0; 65 | int ret = videoCapture->isReadable(&tv); 66 | if (ret == 1) 67 | { 68 | cv::Mat v4l2Mat; 69 | ret = videoCapture->read(v4l2Mat); 70 | 71 | if (ret != 0) 72 | { 73 | LOG(NOTICE) << "stop " ; 74 | stop=1; 75 | } 76 | else 77 | { 78 | cv::imwrite("test.jpg",v4l2Mat); 79 | } 80 | } 81 | else if (ret == -1) //返回错误 82 | { 83 | LOG(NOTICE) << "stop " << strerror(errno); 84 | stop=1; 85 | }else if( ret == 0) // 返回超时 86 | { 87 | 88 | } 89 | } 90 | } 91 | --------------------------------------------------------------------------------