├── .gitignore ├── CMakeLists.txt ├── README.md ├── UNLICENSE ├── inc ├── V4l2Access.h ├── V4l2Capture.h ├── V4l2Device.h ├── V4l2MmapDevice.h ├── V4l2Output.h ├── V4l2ReadWriteDevice.h └── logger.h ├── main.cpp └── src ├── V4l2Access.cpp ├── V4l2Capture.cpp ├── V4l2Device.cpp ├── V4l2MmapDevice.cpp ├── V4l2Output.cpp ├── V4l2ReadWriteDevice.cpp └── logger.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | src/*.o 2 | *.a 3 | *.cmake 4 | CMakeCache.txt 5 | CMakeFiles/ 6 | libv4l2cpptest 7 | Makefile 8 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 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 | 9 | aux_source_directory(src SRC_FILES) 10 | add_library(${PROJECT_NAME} STATIC ${SRC_FILES}) 11 | target_include_directories(${PROJECT_NAME} PUBLIC "${CMAKE_CURRENT_LIST_DIR}/inc") 12 | 13 | add_executable (${PROJECT_NAME}test main.cpp) 14 | target_link_libraries (${PROJECT_NAME}test ${PROJECT_NAME}) 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | libv4l2cpp 3 | ==================== 4 | 5 | It is a C++ wrapper for V4L2 6 | 7 | Dependencies 8 | ------------ 9 | - liblog4cpp5-dev (optional) 10 | 11 | V4L2 Capture 12 | ------------- 13 | - create a V4L2 Capture interface using MMAP interface: 14 | 15 | V4L2DeviceParameters param("/dev/video0", V4L2_PIX_FMT_*, width, height, fps, IOTYPE_MMAP); 16 | V4l2Capture* videoCapture = V4l2Capture::create(param); 17 | 18 | - data are available : 19 | 20 | timeval timeout; 21 | bool isReadable = videoCapture->isReadable(&timeout); 22 | 23 | - read data : 24 | 25 | size_t nb = videoCapture->read(buffer, bufferSize); 26 | 27 | 28 | V4L2 Output 29 | ------------- 30 | 31 | - To create a V4L2 Output interface using MMAP interface: 32 | 33 | V4L2DeviceParameters param("/dev/video0", V4L2_PIX_FMT_*, width, height, fps, IOTYPE_MMAP); 34 | V4l2Output* videoOutput = V4l2Output::create(param); 35 | 36 | - data could be written : 37 | 38 | timeval timeout; 39 | bool isWritable = videoOutput->isWritable(&timeout); 40 | 41 | - write data : 42 | 43 | size_t nb = videoOutput->write(buffer, bufferSize); 44 | -------------------------------------------------------------------------------- /UNLICENSE: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /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 | #pragma once 14 | 15 | #include "V4l2Device.h" 16 | 17 | class V4l2Access 18 | { 19 | public: 20 | explicit V4l2Access(V4l2Device* device); 21 | virtual ~V4l2Access(); 22 | 23 | int getFd() { return m_device->getFd(); } 24 | unsigned int getBufferSize() { return m_device->getBufferSize(); } 25 | unsigned int getFormat() { return m_device->getFormat(); } 26 | unsigned int getWidth() { return m_device->getWidth(); } 27 | unsigned int getHeight() { return m_device->getHeight(); } 28 | 29 | void queryFormat() { m_device->queryFormat(); } 30 | int setFormat(unsigned int format, unsigned int width, unsigned int height) { 31 | return m_device->setFormat(format, width, height); 32 | } 33 | int setFps(int fps) { 34 | return m_device->setFps(fps); 35 | } 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 | -------------------------------------------------------------------------------- /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 | #pragma once 14 | 15 | #include "V4l2Access.h" 16 | 17 | // --------------------------------- 18 | // V4L2 Capture 19 | // --------------------------------- 20 | class V4l2Capture : public V4l2Access 21 | { 22 | protected: 23 | explicit V4l2Capture(V4l2Device* device); 24 | 25 | public: 26 | static V4l2Capture* create(const V4L2DeviceParameters & param); 27 | virtual ~V4l2Capture(); 28 | 29 | size_t read(char* buffer, size_t bufferSize); 30 | bool isReadable(timeval* tv); 31 | }; 32 | 33 | 34 | -------------------------------------------------------------------------------- /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 | #pragma once 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #ifndef V4L2_PIX_FMT_VP8 21 | #define V4L2_PIX_FMT_VP8 v4l2_fourcc('V', 'P', '8', '0') 22 | #endif 23 | #ifndef V4L2_PIX_FMT_VP9 24 | #define V4L2_PIX_FMT_VP9 v4l2_fourcc('V', 'P', '9', '0') 25 | #endif 26 | #ifndef V4L2_PIX_FMT_HEVC 27 | #define V4L2_PIX_FMT_HEVC v4l2_fourcc('H', 'E', 'V', 'C') 28 | #endif 29 | 30 | enum V4l2IoType 31 | { 32 | IOTYPE_READWRITE, 33 | IOTYPE_MMAP 34 | }; 35 | 36 | // --------------------------------- 37 | // V4L2 Device parameters 38 | // --------------------------------- 39 | struct V4L2DeviceParameters 40 | { 41 | V4L2DeviceParameters(const char* devname, const std::list & formatList, unsigned int width, unsigned int height, int fps, V4l2IoType ioType = IOTYPE_MMAP, int openFlags = O_RDWR | O_NONBLOCK) : 42 | m_devName(devname), m_formatList(formatList), m_width(width), m_height(height), m_fps(fps), m_iotype(ioType), m_openFlags(openFlags) {} 43 | 44 | V4L2DeviceParameters(const char* devname, unsigned int format, unsigned int width, unsigned int height, int fps, V4l2IoType ioType = IOTYPE_MMAP, int openFlags = O_RDWR | O_NONBLOCK) : 45 | m_devName(devname), m_width(width), m_height(height), m_fps(fps), m_iotype(ioType), m_openFlags(openFlags) { 46 | if (format) { 47 | m_formatList.push_back(format); 48 | } 49 | } 50 | 51 | std::string m_devName; 52 | std::list m_formatList; 53 | unsigned int m_width; 54 | unsigned int m_height; 55 | int m_fps; 56 | V4l2IoType m_iotype; 57 | int m_verbose; 58 | int m_openFlags; 59 | }; 60 | 61 | // --------------------------------- 62 | // V4L2 Device 63 | // --------------------------------- 64 | class V4l2Device 65 | { 66 | friend class V4l2Capture; 67 | friend class V4l2Output; 68 | 69 | protected: 70 | void close(); 71 | 72 | int initdevice(const char *dev_name, unsigned int mandatoryCapabilities); 73 | int checkCapabilities(int fd, unsigned int mandatoryCapabilities); 74 | int configureFormat(int fd); 75 | int configureFormat(int fd, unsigned int format, unsigned int width, unsigned int height); 76 | int configureParam(int fd, int fps); 77 | 78 | virtual bool init(unsigned int mandatoryCapabilities); 79 | virtual size_t writeInternal(char*, size_t) { return -1; } 80 | virtual bool startPartialWrite() { return false; } 81 | virtual size_t writePartialInternal(char*, size_t) { return -1; } 82 | virtual bool endPartialWrite() { return false; } 83 | virtual size_t readInternal(char*, size_t) { return -1; } 84 | 85 | public: 86 | V4l2Device(const V4L2DeviceParameters& params, v4l2_buf_type deviceType); 87 | virtual ~V4l2Device(); 88 | 89 | virtual bool isReady() { return (m_fd != -1); } 90 | virtual bool start() { return true; } 91 | virtual bool stop() { return true; } 92 | 93 | unsigned int getBufferSize() { return m_bufferSize; } 94 | unsigned int getFormat() { return m_format; } 95 | unsigned int getWidth() { return m_width; } 96 | unsigned int getHeight() { return m_height; } 97 | int getFd() { return m_fd; } 98 | void queryFormat(); 99 | 100 | int setFormat(unsigned int format, unsigned int width, unsigned int height) { 101 | return this->configureFormat(m_fd, format, width, height); 102 | } 103 | int setFps(int fps) { 104 | return this->configureParam(m_fd, fps); 105 | } 106 | 107 | static std::string fourcc(unsigned int format); 108 | static unsigned int fourcc(const char* format); 109 | 110 | protected: 111 | V4L2DeviceParameters m_params; 112 | int m_fd; 113 | v4l2_buf_type m_deviceType; 114 | 115 | unsigned int m_bufferSize; 116 | unsigned int m_format; 117 | unsigned int m_width; 118 | unsigned int m_height; 119 | 120 | struct v4l2_buffer m_partialWriteBuf; 121 | bool m_partialWriteInProgress; 122 | }; 123 | 124 | 125 | -------------------------------------------------------------------------------- /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 | #pragma once 14 | 15 | #include "V4l2Device.h" 16 | 17 | #define V4L2MMAP_NBBUFFER 10 18 | 19 | class V4l2MmapDevice : public V4l2Device 20 | { 21 | protected: 22 | size_t writeInternal(char* buffer, size_t bufferSize); 23 | bool startPartialWrite(); 24 | size_t writePartialInternal(char*, size_t); 25 | bool endPartialWrite(); 26 | size_t readInternal(char* buffer, size_t bufferSize); 27 | 28 | public: 29 | V4l2MmapDevice(const V4L2DeviceParameters & params, v4l2_buf_type deviceType); 30 | virtual ~V4l2MmapDevice(); 31 | 32 | virtual bool init(unsigned int mandatoryCapabilities); 33 | virtual bool isReady() { return ((m_fd != -1)&& (n_buffers != 0)); } 34 | virtual bool start(); 35 | virtual bool stop(); 36 | 37 | protected: 38 | unsigned int n_buffers; 39 | 40 | struct buffer 41 | { 42 | void * start; 43 | size_t length; 44 | }; 45 | buffer m_buffer[V4L2MMAP_NBBUFFER]; 46 | }; 47 | 48 | 49 | -------------------------------------------------------------------------------- /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 | #pragma once 14 | 15 | #include "V4l2Access.h" 16 | 17 | // --------------------------------- 18 | // V4L2 Output 19 | // --------------------------------- 20 | class V4l2Output : public V4l2Access 21 | { 22 | protected: 23 | explicit V4l2Output(V4l2Device* device); 24 | 25 | public: 26 | static V4l2Output* create(const V4L2DeviceParameters & param); 27 | virtual ~V4l2Output(); 28 | 29 | size_t write(char* buffer, size_t bufferSize); 30 | bool isWritable(timeval* tv); 31 | bool startPartialWrite(); 32 | size_t writePartial(char* buffer, size_t bufferSize); 33 | bool endPartialWrite(); 34 | }; 35 | 36 | -------------------------------------------------------------------------------- /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 | #pragma once 14 | 15 | #include "V4l2Device.h" 16 | 17 | 18 | class V4l2ReadWriteDevice : public V4l2Device 19 | { 20 | protected: 21 | virtual size_t writeInternal(char* buffer, size_t bufferSize); 22 | virtual size_t readInternal(char* buffer, size_t bufferSize); 23 | 24 | public: 25 | V4l2ReadWriteDevice(const V4L2DeviceParameters& params, v4l2_buf_type deviceType); 26 | }; 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /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 | #pragma once 11 | 12 | #include 13 | #include 14 | 15 | #define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) 16 | 17 | #ifdef HAVE_LOG4CPP 18 | #include "log4cpp/Category.hh" 19 | #include "log4cpp/FileAppender.hh" 20 | #include "log4cpp/PatternLayout.hh" 21 | 22 | #define LOG(__level) log4cpp::Category::getRoot() << log4cpp::Priority::__level << __FILENAME__ << ":" << __LINE__ << "\n\t" 23 | 24 | 25 | inline int getLogLevel() { 26 | log4cpp::Category &log = log4cpp::Category::getRoot(); 27 | return log.getPriority(); 28 | } 29 | 30 | inline void setLogLevel(int verbose) { 31 | log4cpp::Category &log = log4cpp::Category::getRoot(); 32 | switch (verbose) 33 | { 34 | case 2: log.setPriority(log4cpp::Priority::DEBUG); break; 35 | case 1: log.setPriority(log4cpp::Priority::INFO); break; 36 | default: log.setPriority(log4cpp::Priority::NOTICE); break; 37 | } 38 | } 39 | 40 | inline void initLogger(int verbose) 41 | { 42 | // initialize log4cpp 43 | log4cpp::Category &log = log4cpp::Category::getRoot(); 44 | log4cpp::Appender *app = new log4cpp::FileAppender("root", fileno(stdout)); 45 | if (app) 46 | { 47 | log4cpp::PatternLayout *plt = new log4cpp::PatternLayout(); 48 | if (plt) 49 | { 50 | plt->setConversionPattern("%d [%-6p] - %m%n"); 51 | app->setLayout(plt); 52 | } 53 | log.addAppender(app); 54 | } 55 | 56 | setLogLevel(verbose); 57 | 58 | LOG(INFO) << "level:" << log4cpp::Priority::getPriorityName(log.getPriority()); 59 | } 60 | #else 61 | 62 | typedef enum {EMERG = 0, 63 | FATAL = 0, 64 | ALERT = 100, 65 | CRIT = 200, 66 | ERROR = 300, 67 | WARN = 400, 68 | NOTICE = 500, 69 | INFO = 600, 70 | DEBUG = 700, 71 | NOTSET = 800 72 | } PriorityLevel; 73 | 74 | #include 75 | #include 76 | #include 77 | extern int LogLevel; 78 | inline std::string getLevel(const char* level) { 79 | std::stringstream ss; 80 | ss << "[" << level << "]"; 81 | return ss.str(); 82 | } 83 | inline std::string getFilename(const char* filename, int line) { 84 | std::stringstream ss; 85 | ss << "(" << filename << ":" << line << ")"; 86 | return ss.str(); 87 | } 88 | #define LOG(__level) if (__level<=LogLevel) std::cout << "\n" << std::setw(8) << std::left << getLevel(#__level) << " " << std::setw(30) << std::left << getFilename(__FILENAME__, __LINE__) << "\t" 89 | 90 | 91 | inline int getLogLevel() { 92 | return LogLevel; 93 | } 94 | 95 | inline void setLogLevel(int verbose) { 96 | switch (verbose) 97 | { 98 | case 2: LogLevel=DEBUG; break; 99 | case 1: LogLevel=INFO; break; 100 | default: LogLevel=NOTICE; break; 101 | } 102 | } 103 | 104 | inline void initLogger(int verbose) 105 | { 106 | setLogLevel(verbose); 107 | std::cout << "log level:" << LogLevel << std::endl; 108 | } 109 | 110 | #endif 111 | 112 | 113 | -------------------------------------------------------------------------------- /main.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 | ** main.cpp 7 | ** 8 | ** test V4L2 capture device 9 | ** 10 | ** -------------------------------------------------------------------------*/ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "logger.h" 18 | #include "V4l2Capture.h" 19 | 20 | int stop=0; 21 | 22 | /* --------------------------------------------------------------------------- 23 | ** SIGINT handler 24 | ** -------------------------------------------------------------------------*/ 25 | void sighandler(int) 26 | { 27 | printf("SIGINT\n"); 28 | stop =1; 29 | } 30 | 31 | /* --------------------------------------------------------------------------- 32 | ** main 33 | ** -------------------------------------------------------------------------*/ 34 | int main(int argc, char* argv[]) 35 | { 36 | int verbose = 0; 37 | const char *in_devname = "/dev/video0"; 38 | V4l2IoType ioTypeIn = IOTYPE_MMAP; 39 | int format = 0; 40 | int width = 0; 41 | int height = 0; 42 | int fps = 0; 43 | int framecount = 0; 44 | int c = 0; 45 | while ((c = getopt (argc, argv, "x:hv:" "G:f:r")) != -1) 46 | { 47 | switch (c) 48 | { 49 | case 'v': verbose = 1; if (optarg && *optarg=='v') verbose++; break; 50 | case 'r': ioTypeIn = IOTYPE_READWRITE ; break; 51 | case 'G': sscanf(optarg,"%dx%dx%d", &width, &height, &fps) ; break; 52 | case 'f': format = V4l2Device::fourcc(optarg) ; break; 53 | case 'x': sscanf(optarg,"%d", &framecount) ; break; 54 | case 'h': 55 | { 56 | std::cout << argv[0] << " [-v[v]] [-G xx] [-f format] [device] [-r]" << std::endl; 57 | std::cout << "\t -G xx : set capture resolution" << std::endl; 58 | std::cout << "\t -v : verbose " << std::endl; 59 | std::cout << "\t -vv : very verbose " << std::endl; 60 | std::cout << "\t -r : V4L2 capture using read interface (default use memory mapped buffers)" << std::endl; 61 | std::cout << "\t -x : read frames and save them in current dir." << std::endl; 62 | std::cout << "\t device : V4L2 capture device (default "<< in_devname << ")" << std::endl; 63 | exit(0); 64 | } 65 | } 66 | } 67 | if (optindisReadable(&tv); 95 | if (ret == 1) 96 | { 97 | char buffer[videoCapture->getBufferSize()]; 98 | int rsize = videoCapture->read(buffer, sizeof(buffer)); 99 | if (rsize == -1) 100 | { 101 | LOG(NOTICE) << "stop " << strerror(errno); 102 | stop=1; 103 | } 104 | else 105 | { 106 | LOG(NOTICE) << "size:" << rsize; 107 | static int stop_count = 0; 108 | if(framecount and stop_count < framecount){ 109 | std::string filename = "Frame" + std::to_string(stop_count) + '.' + V4l2Device::fourcc(videoCapture->getFormat()); 110 | stop_count++; 111 | FILE *fp = fopen(filename.c_str(), "wb"); 112 | fwrite(buffer, 1, rsize, fp); 113 | fclose(fp); 114 | LOG(NOTICE) << "saved:\t" << filename; 115 | } 116 | } 117 | } 118 | else if (ret == -1) 119 | { 120 | LOG(NOTICE) << "stop " << strerror(errno); 121 | stop=1; 122 | } 123 | } 124 | 125 | 126 | delete videoCapture; 127 | } 128 | 129 | return 0; 130 | } 131 | -------------------------------------------------------------------------------- /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 | // project 17 | #include "logger.h" 18 | #include "V4l2Capture.h" 19 | #include "V4l2MmapDevice.h" 20 | #include "V4l2ReadWriteDevice.h" 21 | 22 | 23 | // ----------------------------------------- 24 | // create video capture interface 25 | // ----------------------------------------- 26 | V4l2Capture* V4l2Capture::create(const V4L2DeviceParameters & param) 27 | { 28 | V4l2Capture* videoCapture = NULL; 29 | V4l2Device* videoDevice = NULL; 30 | int caps = V4L2_CAP_VIDEO_CAPTURE; 31 | switch (param.m_iotype) 32 | { 33 | case IOTYPE_MMAP: 34 | videoDevice = new V4l2MmapDevice(param, V4L2_BUF_TYPE_VIDEO_CAPTURE); 35 | caps |= V4L2_CAP_STREAMING; 36 | break; 37 | case IOTYPE_READWRITE: 38 | videoDevice = new V4l2ReadWriteDevice(param, V4L2_BUF_TYPE_VIDEO_CAPTURE); 39 | caps |= V4L2_CAP_READWRITE; 40 | break; 41 | } 42 | 43 | if (videoDevice && !videoDevice->init(caps)) 44 | { 45 | delete videoDevice; 46 | videoDevice=NULL; 47 | } 48 | 49 | if (videoDevice) 50 | { 51 | videoCapture = new V4l2Capture(videoDevice); 52 | } 53 | return videoCapture; 54 | } 55 | 56 | // ----------------------------------------- 57 | // constructor 58 | // ----------------------------------------- 59 | V4l2Capture::V4l2Capture(V4l2Device* device) : V4l2Access(device) 60 | { 61 | } 62 | 63 | // ----------------------------------------- 64 | // destructor 65 | // ----------------------------------------- 66 | V4l2Capture::~V4l2Capture() 67 | { 68 | } 69 | 70 | // ----------------------------------------- 71 | // check readability 72 | // ----------------------------------------- 73 | bool V4l2Capture::isReadable(timeval* tv) 74 | { 75 | int fd = m_device->getFd(); 76 | fd_set fdset; 77 | FD_ZERO(&fdset); 78 | FD_SET(fd, &fdset); 79 | return (select(fd+1, &fdset, NULL, NULL, tv) == 1); 80 | } 81 | 82 | // ----------------------------------------- 83 | // read from V4l2Device 84 | // ----------------------------------------- 85 | size_t V4l2Capture::read(char* buffer, size_t bufferSize) 86 | { 87 | return m_device->readInternal(buffer, bufferSize); 88 | } 89 | 90 | 91 | -------------------------------------------------------------------------------- /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 V4l2Device::fourcc(unsigned int format) { 24 | char formatArray[] = { (char)(format&0xff), (char)((format>>8)&0xff), (char)((format>>16)&0xff), (char)((format>>24)&0xff), 0 }; 25 | return std::string(formatArray, strlen(formatArray)); 26 | } 27 | 28 | unsigned int V4l2Device::fourcc(const char* format) { 29 | char fourcc[4]; 30 | memset(&fourcc, 0, sizeof(fourcc)); 31 | if (format != NULL) 32 | { 33 | strncpy(fourcc, format, 4); 34 | } 35 | return v4l2_fourcc(fourcc[0], fourcc[1], fourcc[2], fourcc[3]); 36 | } 37 | 38 | // ----------------------------------------- 39 | // V4L2Device 40 | // ----------------------------------------- 41 | V4l2Device::V4l2Device(const V4L2DeviceParameters& params, v4l2_buf_type deviceType) : m_params(params), m_fd(-1), m_deviceType(deviceType), m_bufferSize(0), m_format(0) 42 | { 43 | } 44 | 45 | V4l2Device::~V4l2Device() 46 | { 47 | this->close(); 48 | } 49 | 50 | void V4l2Device::close() 51 | { 52 | if (m_fd != -1) 53 | ::close(m_fd); 54 | 55 | m_fd = -1; 56 | } 57 | 58 | // query current format 59 | void V4l2Device::queryFormat() 60 | { 61 | struct v4l2_format fmt; 62 | memset(&fmt,0,sizeof(fmt)); 63 | fmt.type = m_deviceType; 64 | if (0 == ioctl(m_fd,VIDIOC_G_FMT,&fmt)) 65 | { 66 | m_format = fmt.fmt.pix.pixelformat; 67 | m_width = fmt.fmt.pix.width; 68 | m_height = fmt.fmt.pix.height; 69 | m_bufferSize = fmt.fmt.pix.sizeimage; 70 | 71 | LOG(DEBUG) << m_params.m_devName << ":" << fourcc(m_format) << " size:" << m_width << "x" << m_height << " bufferSize:" << m_bufferSize; 72 | } 73 | } 74 | 75 | // intialize the V4L2 connection 76 | bool V4l2Device::init(unsigned int mandatoryCapabilities) 77 | { 78 | struct stat sb; 79 | if ( (stat(m_params.m_devName.c_str(), &sb)==0) && ((sb.st_mode & S_IFMT) == S_IFCHR) ) 80 | { 81 | if (initdevice(m_params.m_devName.c_str(), mandatoryCapabilities) == -1) 82 | { 83 | LOG(ERROR) << "Cannot init device:" << m_params.m_devName; 84 | } 85 | } 86 | else 87 | { 88 | // open a normal file 89 | m_fd = open(m_params.m_devName.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU); 90 | } 91 | return (m_fd!=-1); 92 | } 93 | 94 | // intialize the V4L2 device 95 | int V4l2Device::initdevice(const char *dev_name, unsigned int mandatoryCapabilities) 96 | { 97 | m_fd = open(dev_name, m_params.m_openFlags); 98 | if (m_fd < 0) 99 | { 100 | LOG(ERROR) << "Cannot open device:" << m_params.m_devName << " " << strerror(errno); 101 | this->close(); 102 | return -1; 103 | } 104 | if (checkCapabilities(m_fd,mandatoryCapabilities) !=0) 105 | { 106 | this->close(); 107 | return -1; 108 | } 109 | if (configureFormat(m_fd) !=0) 110 | { 111 | this->close(); 112 | return -1; 113 | } 114 | if (configureParam(m_fd, m_params.m_fps) !=0) 115 | { 116 | this->close(); 117 | return -1; 118 | } 119 | 120 | return m_fd; 121 | } 122 | 123 | // check needed V4L2 capabilities 124 | int V4l2Device::checkCapabilities(int fd, unsigned int mandatoryCapabilities) 125 | { 126 | struct v4l2_capability cap; 127 | memset(&(cap), 0, sizeof(cap)); 128 | if (-1 == ioctl(fd, VIDIOC_QUERYCAP, &cap)) 129 | { 130 | LOG(ERROR) << "Cannot get capabilities for device:" << m_params.m_devName << " " << strerror(errno); 131 | return -1; 132 | } 133 | LOG(INFO) << "driver:" << cap.driver << " capabilities:" << std::hex << cap.capabilities << " mandatory:" << mandatoryCapabilities << std::dec; 134 | 135 | if ((cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)) LOG(DEBUG) << m_params.m_devName << " support output"; 136 | if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) LOG(DEBUG) << m_params.m_devName << " support capture"; 137 | 138 | if ((cap.capabilities & V4L2_CAP_READWRITE)) LOG(DEBUG) << m_params.m_devName << " support read/write"; 139 | if ((cap.capabilities & V4L2_CAP_STREAMING)) LOG(DEBUG) << m_params.m_devName << " support streaming"; 140 | 141 | if ((cap.capabilities & V4L2_CAP_TIMEPERFRAME)) LOG(DEBUG) << m_params.m_devName << " support timeperframe"; 142 | 143 | if ( (cap.capabilities & mandatoryCapabilities) != mandatoryCapabilities ) 144 | { 145 | LOG(ERROR) << "Mandatory capability not available for device:" << m_params.m_devName; 146 | return -1; 147 | } 148 | 149 | return 0; 150 | } 151 | 152 | // configure capture format 153 | int V4l2Device::configureFormat(int fd) 154 | { 155 | // get current configuration 156 | this->queryFormat(); 157 | 158 | unsigned int width = m_width; 159 | unsigned int height = m_height; 160 | if (m_params.m_width != 0) { 161 | width= m_params.m_width; 162 | } 163 | if (m_params.m_height != 0) { 164 | height= m_params.m_height; 165 | } 166 | if ( (m_params.m_formatList.size()==0) && (m_format != 0) ) { 167 | m_params.m_formatList.push_back(m_format); 168 | } 169 | 170 | // try to set format, widht, height 171 | std::list::iterator it; 172 | for (it = m_params.m_formatList.begin(); it != m_params.m_formatList.end(); ++it) { 173 | unsigned int format = *it; 174 | if (this->configureFormat(fd, format, width, height)==0) { 175 | // format has been set 176 | // get the format again because calling SET-FMT return a bad buffersize using v4l2loopback 177 | this->queryFormat(); 178 | return 0; 179 | } 180 | } 181 | return -1; 182 | } 183 | 184 | // configure capture format 185 | int V4l2Device::configureFormat(int fd, unsigned int format, unsigned int width, unsigned int height) 186 | { 187 | struct v4l2_format fmt; 188 | memset(&(fmt), 0, sizeof(fmt)); 189 | fmt.type = m_deviceType; 190 | if (ioctl(m_fd,VIDIOC_G_FMT,&fmt) == -1) 191 | { 192 | LOG(ERROR) << m_params.m_devName << ": Cannot get format " << strerror(errno); 193 | return -1; 194 | } 195 | if (width != 0) { 196 | fmt.fmt.pix.width = width; 197 | } 198 | if (height != 0) { 199 | fmt.fmt.pix.height = height; 200 | } 201 | if (format != 0) { 202 | fmt.fmt.pix.pixelformat = format; 203 | } 204 | 205 | if (ioctl(fd, VIDIOC_S_FMT, &fmt) == -1) 206 | { 207 | LOG(ERROR) << m_params.m_devName << ": Cannot set format:" << fourcc(format) << " " << strerror(errno); 208 | return -1; 209 | } 210 | if (fmt.fmt.pix.pixelformat != format) 211 | { 212 | LOG(ERROR) << m_params.m_devName << ": Cannot set pixelformat to:" << fourcc(format) << " format is:" << fourcc(fmt.fmt.pix.pixelformat); 213 | return -1; 214 | } 215 | if ((fmt.fmt.pix.width != width) || (fmt.fmt.pix.height != height)) 216 | { 217 | LOG(WARN) << m_params.m_devName << ": Cannot set size to:" << width << "x" << height << " size is:" << fmt.fmt.pix.width << "x" << fmt.fmt.pix.height; 218 | } 219 | 220 | m_format = fmt.fmt.pix.pixelformat; 221 | m_width = fmt.fmt.pix.width; 222 | m_height = fmt.fmt.pix.height; 223 | m_bufferSize = fmt.fmt.pix.sizeimage; 224 | 225 | LOG(INFO) << m_params.m_devName << ":" << fourcc(m_format) << " size:" << m_width << "x" << m_height << " bufferSize:" << m_bufferSize; 226 | 227 | return 0; 228 | } 229 | 230 | // configure capture FPS 231 | int V4l2Device::configureParam(int fd, int fps) 232 | { 233 | if (fps!=0) 234 | { 235 | struct v4l2_streamparm param; 236 | memset(&(param), 0, sizeof(param)); 237 | param.type = m_deviceType; 238 | param.parm.capture.timeperframe.numerator = 1; 239 | param.parm.capture.timeperframe.denominator = fps; 240 | 241 | if (ioctl(fd, VIDIOC_S_PARM, ¶m) == -1) 242 | { 243 | LOG(WARN) << "Cannot set param for device:" << m_params.m_devName << " " << strerror(errno); 244 | } 245 | 246 | LOG(INFO) << "fps:" << param.parm.capture.timeperframe.numerator << "/" << param.parm.capture.timeperframe.denominator; 247 | LOG(INFO) << "nbBuffer:" << param.parm.capture.readbuffers; 248 | } 249 | 250 | return 0; 251 | } 252 | 253 | 254 | -------------------------------------------------------------------------------- /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(INFO) << "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(INFO) << "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(INFO) << "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 | if (errno == EAGAIN) { 190 | size = 0; 191 | } else { 192 | perror("VIDIOC_DQBUF"); 193 | size = -1; 194 | } 195 | } 196 | else if (buf.index < n_buffers) 197 | { 198 | size = buf.bytesused; 199 | if (size > bufferSize) 200 | { 201 | size = bufferSize; 202 | LOG(WARN) << "Device " << m_params.m_devName << " buffer truncated available:" << bufferSize << " needed:" << buf.bytesused; 203 | } 204 | memcpy(buffer, m_buffer[buf.index].start, size); 205 | 206 | if (-1 == ioctl(m_fd, VIDIOC_QBUF, &buf)) 207 | { 208 | perror("VIDIOC_QBUF"); 209 | size = -1; 210 | } 211 | } 212 | } 213 | return size; 214 | } 215 | 216 | size_t V4l2MmapDevice::writeInternal(char* buffer, size_t bufferSize) 217 | { 218 | size_t size = 0; 219 | if (n_buffers > 0) 220 | { 221 | struct v4l2_buffer buf; 222 | memset (&buf, 0, sizeof(buf)); 223 | buf.type = m_deviceType; 224 | buf.memory = V4L2_MEMORY_MMAP; 225 | 226 | if (-1 == ioctl(m_fd, VIDIOC_DQBUF, &buf)) 227 | { 228 | perror("VIDIOC_DQBUF"); 229 | size = -1; 230 | } 231 | else if (buf.index < n_buffers) 232 | { 233 | size = bufferSize; 234 | if (size > buf.length) 235 | { 236 | LOG(WARN) << "Device " << m_params.m_devName << " buffer truncated available:" << buf.length << " needed:" << size; 237 | size = buf.length; 238 | } 239 | memcpy(m_buffer[buf.index].start, buffer, size); 240 | buf.bytesused = size; 241 | 242 | if (-1 == ioctl(m_fd, VIDIOC_QBUF, &buf)) 243 | { 244 | perror("VIDIOC_QBUF"); 245 | size = -1; 246 | } 247 | } 248 | } 249 | return size; 250 | } 251 | 252 | bool V4l2MmapDevice::startPartialWrite() 253 | { 254 | if (n_buffers <= 0) 255 | return false; 256 | if (m_partialWriteInProgress) 257 | return false; 258 | memset(&m_partialWriteBuf, 0, sizeof(m_partialWriteBuf)); 259 | m_partialWriteBuf.type = m_deviceType; 260 | m_partialWriteBuf.memory = V4L2_MEMORY_MMAP; 261 | if (-1 == ioctl(m_fd, VIDIOC_DQBUF, &m_partialWriteBuf)) 262 | { 263 | perror("VIDIOC_DQBUF"); 264 | return false; 265 | } 266 | m_partialWriteBuf.bytesused = 0; 267 | m_partialWriteInProgress = true; 268 | return true; 269 | } 270 | 271 | size_t V4l2MmapDevice::writePartialInternal(char* buffer, size_t bufferSize) 272 | { 273 | size_t new_size = 0; 274 | size_t size = 0; 275 | if ((n_buffers > 0) && m_partialWriteInProgress) 276 | { 277 | if (m_partialWriteBuf.index < n_buffers) 278 | { 279 | new_size = m_partialWriteBuf.bytesused + bufferSize; 280 | if (new_size > m_partialWriteBuf.length) 281 | { 282 | LOG(WARN) << "Device " << m_params.m_devName << " buffer truncated available:" << m_partialWriteBuf.length << " needed:" << new_size; 283 | new_size = m_partialWriteBuf.length; 284 | } 285 | size = new_size - m_partialWriteBuf.bytesused; 286 | memcpy(&((char *)m_buffer[m_partialWriteBuf.index].start)[m_partialWriteBuf.bytesused], buffer, size); 287 | 288 | m_partialWriteBuf.bytesused += size; 289 | } 290 | } 291 | return size; 292 | } 293 | 294 | bool V4l2MmapDevice::endPartialWrite() 295 | { 296 | if (!m_partialWriteInProgress) 297 | return false; 298 | if (n_buffers <= 0) 299 | { 300 | m_partialWriteInProgress = false; // abort partial write 301 | return true; 302 | } 303 | if (-1 == ioctl(m_fd, VIDIOC_QBUF, &m_partialWriteBuf)) 304 | { 305 | perror("VIDIOC_QBUF"); 306 | m_partialWriteInProgress = false; // abort partial write 307 | return true; 308 | } 309 | m_partialWriteInProgress = false; 310 | return true; 311 | } 312 | -------------------------------------------------------------------------------- /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) 28 | { 29 | V4l2Output* videoOutput = NULL; 30 | V4l2Device* videoDevice = NULL; 31 | int caps = V4L2_CAP_VIDEO_OUTPUT; 32 | switch (param.m_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 | bool 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) == 1); 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() 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() 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 | --------------------------------------------------------------------------------