├── .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 |
--------------------------------------------------------------------------------