소스 정리
parent
1709e4ad2f
commit
4ef17a44ef
Binary file not shown.
@ -1,7 +0,0 @@
|
|||||||
src/*.o
|
|
||||||
*.a
|
|
||||||
*.cmake
|
|
||||||
CMakeCache.txt
|
|
||||||
CMakeFiles/
|
|
||||||
libv4l2cpptest
|
|
||||||
Makefile
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.5)
|
|
||||||
|
|
||||||
# set project name from current directory
|
|
||||||
get_filename_component(BASENAME ${CMAKE_CURRENT_LIST_DIR} NAME)
|
|
||||||
project(${BASENAME})
|
|
||||||
|
|
||||||
set (CMAKE_CXX_STANDARD 11)
|
|
||||||
|
|
||||||
aux_source_directory(src SRC_FILES)
|
|
||||||
add_library(${PROJECT_NAME} STATIC ${SRC_FILES})
|
|
||||||
target_include_directories(${PROJECT_NAME} PUBLIC "${CMAKE_CURRENT_LIST_DIR}/inc")
|
|
||||||
|
|
||||||
add_executable (${PROJECT_NAME}test main.cpp)
|
|
||||||
target_link_libraries (${PROJECT_NAME}test ${PROJECT_NAME})
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
|
|
||||||
libv4l2cpp
|
|
||||||
====================
|
|
||||||
|
|
||||||
It is a C++ wrapper for V4L2
|
|
||||||
|
|
||||||
Dependencies
|
|
||||||
------------
|
|
||||||
- liblog4cpp5-dev (optional)
|
|
||||||
|
|
||||||
V4L2 Capture
|
|
||||||
-------------
|
|
||||||
- create a V4L2 Capture interface using MMAP interface:
|
|
||||||
|
|
||||||
V4L2DeviceParameters param("/dev/video0", V4L2_PIX_FMT_*, width, height, fps, IOTYPE_MMAP);
|
|
||||||
V4l2Capture* videoCapture = V4l2Capture::create(param);
|
|
||||||
|
|
||||||
- data are available :
|
|
||||||
|
|
||||||
timeval timeout;
|
|
||||||
bool isReadable = videoCapture->isReadable(&timeout);
|
|
||||||
|
|
||||||
- read data :
|
|
||||||
|
|
||||||
size_t nb = videoCapture->read(buffer, bufferSize);
|
|
||||||
|
|
||||||
|
|
||||||
V4L2 Output
|
|
||||||
-------------
|
|
||||||
|
|
||||||
- To create a V4L2 Output interface using MMAP interface:
|
|
||||||
|
|
||||||
V4L2DeviceParameters param("/dev/video0", V4L2_PIX_FMT_*, width, height, fps, IOTYPE_MMAP);
|
|
||||||
V4l2Output* videoOutput = V4l2Output::create(param);
|
|
||||||
|
|
||||||
- data could be written :
|
|
||||||
|
|
||||||
timeval timeout;
|
|
||||||
bool isWritable = videoOutput->isWritable(&timeout);
|
|
||||||
|
|
||||||
- write data :
|
|
||||||
|
|
||||||
size_t nb = videoOutput->write(buffer, bufferSize);
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
This is free and unencumbered software released into the public domain.
|
|
||||||
|
|
||||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
|
||||||
distribute this software, either in source code form or as a compiled
|
|
||||||
binary, for any purpose, commercial or non-commercial, and by any
|
|
||||||
means.
|
|
||||||
|
|
||||||
In jurisdictions that recognize copyright laws, the author or authors
|
|
||||||
of this software dedicate any and all copyright interest in the
|
|
||||||
software to the public domain. We make this dedication for the benefit
|
|
||||||
of the public at large and to the detriment of our heirs and
|
|
||||||
successors. We intend this dedication to be an overt act of
|
|
||||||
relinquishment in perpetuity of all present and future rights to this
|
|
||||||
software under copyright law.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
||||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
||||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
For more information, please refer to <http://unlicense.org>
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
/* ---------------------------------------------------------------------------
|
|
||||||
** This software is in the public domain, furnished "as is", without technical
|
|
||||||
** support, and with no warranty, express or implied, as to its usefulness for
|
|
||||||
** any purpose.
|
|
||||||
**
|
|
||||||
** V4l2Access.h
|
|
||||||
**
|
|
||||||
** V4L2 wrapper
|
|
||||||
**
|
|
||||||
** -------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "V4l2Device.h"
|
|
||||||
|
|
||||||
class V4l2Access
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit V4l2Access(V4l2Device* device);
|
|
||||||
virtual ~V4l2Access();
|
|
||||||
|
|
||||||
int getFd() { return m_device->getFd(); }
|
|
||||||
unsigned int getBufferSize() { return m_device->getBufferSize(); }
|
|
||||||
unsigned int getFormat() { return m_device->getFormat(); }
|
|
||||||
unsigned int getWidth() { return m_device->getWidth(); }
|
|
||||||
unsigned int getHeight() { return m_device->getHeight(); }
|
|
||||||
|
|
||||||
void queryFormat() { m_device->queryFormat(); }
|
|
||||||
int setFormat(unsigned int format, unsigned int width, unsigned int height) {
|
|
||||||
return m_device->setFormat(format, width, height);
|
|
||||||
}
|
|
||||||
int setFps(int fps) {
|
|
||||||
return m_device->setFps(fps);
|
|
||||||
}
|
|
||||||
|
|
||||||
int isReady() { return m_device->isReady(); }
|
|
||||||
int start() { return m_device->start(); }
|
|
||||||
int stop() { return m_device->stop(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
V4l2Access(const V4l2Access&);
|
|
||||||
V4l2Access & operator=(const V4l2Access&);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
V4l2Device* m_device;
|
|
||||||
};
|
|
||||||
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
/* ---------------------------------------------------------------------------
|
|
||||||
** This software is in the public domain, furnished "as is", without technical
|
|
||||||
** support, and with no warranty, express or implied, as to its usefulness for
|
|
||||||
** any purpose.
|
|
||||||
**
|
|
||||||
** V4l2Capture.h
|
|
||||||
**
|
|
||||||
** V4L2 Capture wrapper
|
|
||||||
**
|
|
||||||
** -------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "V4l2Access.h"
|
|
||||||
|
|
||||||
// ---------------------------------
|
|
||||||
// V4L2 Capture
|
|
||||||
// ---------------------------------
|
|
||||||
class V4l2Capture : public V4l2Access
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
explicit V4l2Capture(V4l2Device* device);
|
|
||||||
|
|
||||||
public:
|
|
||||||
static V4l2Capture* create(const V4L2DeviceParameters & param);
|
|
||||||
virtual ~V4l2Capture();
|
|
||||||
|
|
||||||
size_t read(char* buffer, size_t bufferSize);
|
|
||||||
bool isReadable(timeval* tv);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,124 +0,0 @@
|
|||||||
/* ---------------------------------------------------------------------------
|
|
||||||
** This software is in the public domain, furnished "as is", without technical
|
|
||||||
** support, and with no warranty, express or implied, as to its usefulness for
|
|
||||||
** any purpose.
|
|
||||||
**
|
|
||||||
** V4l2Device.h
|
|
||||||
**
|
|
||||||
** V4L2 wrapper
|
|
||||||
**
|
|
||||||
** -------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <list>
|
|
||||||
#include <linux/videodev2.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
|
|
||||||
#ifndef V4L2_PIX_FMT_VP8
|
|
||||||
#define V4L2_PIX_FMT_VP8 v4l2_fourcc('V', 'P', '8', '0')
|
|
||||||
#endif
|
|
||||||
#ifndef V4L2_PIX_FMT_VP9
|
|
||||||
#define V4L2_PIX_FMT_VP9 v4l2_fourcc('V', 'P', '9', '0')
|
|
||||||
#endif
|
|
||||||
#ifndef V4L2_PIX_FMT_HEVC
|
|
||||||
#define V4L2_PIX_FMT_HEVC v4l2_fourcc('H', 'E', 'V', 'C')
|
|
||||||
#endif
|
|
||||||
|
|
||||||
enum V4l2IoType
|
|
||||||
{
|
|
||||||
IOTYPE_READWRITE,
|
|
||||||
IOTYPE_MMAP
|
|
||||||
};
|
|
||||||
|
|
||||||
// ---------------------------------
|
|
||||||
// V4L2 Device parameters
|
|
||||||
// ---------------------------------
|
|
||||||
struct V4L2DeviceParameters
|
|
||||||
{
|
|
||||||
V4L2DeviceParameters(const char* devname, const std::list<unsigned int> & formatList, unsigned int width, unsigned int height, int fps, V4l2IoType ioType = IOTYPE_MMAP, int openFlags = O_RDWR | O_NONBLOCK) :
|
|
||||||
m_devName(devname), m_formatList(formatList), m_width(width), m_height(height), m_fps(fps), m_iotype(ioType), m_openFlags(openFlags) {}
|
|
||||||
|
|
||||||
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) :
|
|
||||||
m_devName(devname), m_width(width), m_height(height), m_fps(fps), m_iotype(ioType), m_openFlags(openFlags) {
|
|
||||||
if (format) {
|
|
||||||
m_formatList.push_back(format);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string m_devName;
|
|
||||||
std::list<unsigned int> m_formatList;
|
|
||||||
unsigned int m_width;
|
|
||||||
unsigned int m_height;
|
|
||||||
int m_fps;
|
|
||||||
V4l2IoType m_iotype;
|
|
||||||
int m_verbose;
|
|
||||||
int m_openFlags;
|
|
||||||
};
|
|
||||||
|
|
||||||
// ---------------------------------
|
|
||||||
// V4L2 Device
|
|
||||||
// ---------------------------------
|
|
||||||
class V4l2Device
|
|
||||||
{
|
|
||||||
friend class V4l2Capture;
|
|
||||||
friend class V4l2Output;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void close();
|
|
||||||
|
|
||||||
int initdevice(const char *dev_name, unsigned int mandatoryCapabilities);
|
|
||||||
int checkCapabilities(int fd, unsigned int mandatoryCapabilities);
|
|
||||||
int configureFormat(int fd);
|
|
||||||
int configureFormat(int fd, unsigned int format, unsigned int width, unsigned int height);
|
|
||||||
int configureParam(int fd, int fps);
|
|
||||||
|
|
||||||
virtual bool init(unsigned int mandatoryCapabilities);
|
|
||||||
virtual size_t writeInternal(char*, size_t) { return -1; }
|
|
||||||
virtual bool startPartialWrite() { return false; }
|
|
||||||
virtual size_t writePartialInternal(char*, size_t) { return -1; }
|
|
||||||
virtual bool endPartialWrite() { return false; }
|
|
||||||
virtual size_t readInternal(char*, size_t) { return -1; }
|
|
||||||
|
|
||||||
public:
|
|
||||||
V4l2Device(const V4L2DeviceParameters& params, v4l2_buf_type deviceType);
|
|
||||||
virtual ~V4l2Device();
|
|
||||||
|
|
||||||
virtual bool isReady() { return (m_fd != -1); }
|
|
||||||
virtual bool start() { return true; }
|
|
||||||
virtual bool stop() { return true; }
|
|
||||||
|
|
||||||
unsigned int getBufferSize() { return m_bufferSize; }
|
|
||||||
unsigned int getFormat() { return m_format; }
|
|
||||||
unsigned int getWidth() { return m_width; }
|
|
||||||
unsigned int getHeight() { return m_height; }
|
|
||||||
int getFd() { return m_fd; }
|
|
||||||
void queryFormat();
|
|
||||||
|
|
||||||
int setFormat(unsigned int format, unsigned int width, unsigned int height) {
|
|
||||||
return this->configureFormat(m_fd, format, width, height);
|
|
||||||
}
|
|
||||||
int setFps(int fps) {
|
|
||||||
return this->configureParam(m_fd, fps);
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string fourcc(unsigned int format);
|
|
||||||
static unsigned int fourcc(const char* format);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
V4L2DeviceParameters m_params;
|
|
||||||
int m_fd;
|
|
||||||
v4l2_buf_type m_deviceType;
|
|
||||||
|
|
||||||
unsigned int m_bufferSize;
|
|
||||||
unsigned int m_format;
|
|
||||||
unsigned int m_width;
|
|
||||||
unsigned int m_height;
|
|
||||||
|
|
||||||
struct v4l2_buffer m_partialWriteBuf;
|
|
||||||
bool m_partialWriteInProgress;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
/* ---------------------------------------------------------------------------
|
|
||||||
** This software is in the public domain, furnished "as is", without technical
|
|
||||||
** support, and with no warranty, express or implied, as to its usefulness for
|
|
||||||
** any purpose.
|
|
||||||
**
|
|
||||||
** V4l2MmapDevice.h
|
|
||||||
**
|
|
||||||
** V4L2 source using mmap API
|
|
||||||
**
|
|
||||||
** -------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "V4l2Device.h"
|
|
||||||
|
|
||||||
#define V4L2MMAP_NBBUFFER 10
|
|
||||||
|
|
||||||
class V4l2MmapDevice : public V4l2Device
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
size_t writeInternal(char* buffer, size_t bufferSize);
|
|
||||||
bool startPartialWrite();
|
|
||||||
size_t writePartialInternal(char*, size_t);
|
|
||||||
bool endPartialWrite();
|
|
||||||
size_t readInternal(char* buffer, size_t bufferSize);
|
|
||||||
|
|
||||||
public:
|
|
||||||
V4l2MmapDevice(const V4L2DeviceParameters & params, v4l2_buf_type deviceType);
|
|
||||||
virtual ~V4l2MmapDevice();
|
|
||||||
|
|
||||||
virtual bool init(unsigned int mandatoryCapabilities);
|
|
||||||
virtual bool isReady() { return ((m_fd != -1)&& (n_buffers != 0)); }
|
|
||||||
virtual bool start();
|
|
||||||
virtual bool stop();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
unsigned int n_buffers;
|
|
||||||
|
|
||||||
struct buffer
|
|
||||||
{
|
|
||||||
void * start;
|
|
||||||
size_t length;
|
|
||||||
};
|
|
||||||
buffer m_buffer[V4L2MMAP_NBBUFFER];
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
/* ---------------------------------------------------------------------------
|
|
||||||
** This software is in the public domain, furnished "as is", without technical
|
|
||||||
** support, and with no warranty, express or implied, as to its usefulness for
|
|
||||||
** any purpose.
|
|
||||||
**
|
|
||||||
** V4l2Output.h
|
|
||||||
**
|
|
||||||
** V4L2 Output wrapper
|
|
||||||
**
|
|
||||||
** -------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "V4l2Access.h"
|
|
||||||
|
|
||||||
// ---------------------------------
|
|
||||||
// V4L2 Output
|
|
||||||
// ---------------------------------
|
|
||||||
class V4l2Output : public V4l2Access
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
explicit V4l2Output(V4l2Device* device);
|
|
||||||
|
|
||||||
public:
|
|
||||||
static V4l2Output* create(const V4L2DeviceParameters & param);
|
|
||||||
virtual ~V4l2Output();
|
|
||||||
|
|
||||||
size_t write(char* buffer, size_t bufferSize);
|
|
||||||
bool isWritable(timeval* tv);
|
|
||||||
bool startPartialWrite();
|
|
||||||
size_t writePartial(char* buffer, size_t bufferSize);
|
|
||||||
bool endPartialWrite();
|
|
||||||
};
|
|
||||||
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
/* ---------------------------------------------------------------------------
|
|
||||||
** This software is in the public domain, furnished "as is", without technical
|
|
||||||
** support, and with no warranty, express or implied, as to its usefulness for
|
|
||||||
** any purpose.
|
|
||||||
**
|
|
||||||
** V4l2ReadWriteDevice.h
|
|
||||||
**
|
|
||||||
** V4L2 source using read/write API
|
|
||||||
**
|
|
||||||
** -------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "V4l2Device.h"
|
|
||||||
|
|
||||||
|
|
||||||
class V4l2ReadWriteDevice : public V4l2Device
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
virtual size_t writeInternal(char* buffer, size_t bufferSize);
|
|
||||||
virtual size_t readInternal(char* buffer, size_t bufferSize);
|
|
||||||
|
|
||||||
public:
|
|
||||||
V4l2ReadWriteDevice(const V4L2DeviceParameters& params, v4l2_buf_type deviceType);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,112 +0,0 @@
|
|||||||
/* ---------------------------------------------------------------------------
|
|
||||||
** This software is in the public domain, furnished "as is", without technical
|
|
||||||
** support, and with no warranty, express or implied, as to its usefulness for
|
|
||||||
** any purpose.
|
|
||||||
**
|
|
||||||
** logger.h
|
|
||||||
**
|
|
||||||
** -------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
|
|
||||||
|
|
||||||
#ifdef HAVE_LOG4CPP
|
|
||||||
#include "log4cpp/Category.hh"
|
|
||||||
#include "log4cpp/FileAppender.hh"
|
|
||||||
#include "log4cpp/PatternLayout.hh"
|
|
||||||
|
|
||||||
#define LOG(__level) log4cpp::Category::getRoot() << log4cpp::Priority::__level << __FILENAME__ << ":" << __LINE__ << "\n\t"
|
|
||||||
|
|
||||||
|
|
||||||
inline int getLogLevel() {
|
|
||||||
log4cpp::Category &log = log4cpp::Category::getRoot();
|
|
||||||
return log.getPriority();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void setLogLevel(int verbose) {
|
|
||||||
log4cpp::Category &log = log4cpp::Category::getRoot();
|
|
||||||
switch (verbose)
|
|
||||||
{
|
|
||||||
case 2: log.setPriority(log4cpp::Priority::DEBUG); break;
|
|
||||||
case 1: log.setPriority(log4cpp::Priority::INFO); break;
|
|
||||||
default: log.setPriority(log4cpp::Priority::NOTICE); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void initLogger(int verbose)
|
|
||||||
{
|
|
||||||
// initialize log4cpp
|
|
||||||
log4cpp::Category &log = log4cpp::Category::getRoot();
|
|
||||||
log4cpp::Appender *app = new log4cpp::FileAppender("root", fileno(stdout));
|
|
||||||
if (app)
|
|
||||||
{
|
|
||||||
log4cpp::PatternLayout *plt = new log4cpp::PatternLayout();
|
|
||||||
if (plt)
|
|
||||||
{
|
|
||||||
plt->setConversionPattern("%d [%-6p] - %m%n");
|
|
||||||
app->setLayout(plt);
|
|
||||||
}
|
|
||||||
log.addAppender(app);
|
|
||||||
}
|
|
||||||
|
|
||||||
setLogLevel(verbose);
|
|
||||||
|
|
||||||
LOG(INFO) << "level:" << log4cpp::Priority::getPriorityName(log.getPriority());
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
|
|
||||||
typedef enum {EMERG = 0,
|
|
||||||
FATAL = 0,
|
|
||||||
ALERT = 100,
|
|
||||||
CRIT = 200,
|
|
||||||
ERROR = 300,
|
|
||||||
WARN = 400,
|
|
||||||
NOTICE = 500,
|
|
||||||
INFO = 600,
|
|
||||||
DEBUG = 700,
|
|
||||||
NOTSET = 800
|
|
||||||
} PriorityLevel;
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <sstream>
|
|
||||||
extern int LogLevel;
|
|
||||||
inline std::string getLevel(const char* level) {
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << "[" << level << "]";
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
inline std::string getFilename(const char* filename, int line) {
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << "(" << filename << ":" << line << ")";
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
#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"
|
|
||||||
|
|
||||||
|
|
||||||
inline int getLogLevel() {
|
|
||||||
return LogLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void setLogLevel(int verbose) {
|
|
||||||
switch (verbose)
|
|
||||||
{
|
|
||||||
case 2: LogLevel=DEBUG; break;
|
|
||||||
case 1: LogLevel=INFO; break;
|
|
||||||
default: LogLevel=NOTICE; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void initLogger(int verbose)
|
|
||||||
{
|
|
||||||
setLogLevel(verbose);
|
|
||||||
std::cout << "log level:" << LogLevel << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,130 +0,0 @@
|
|||||||
/* ---------------------------------------------------------------------------
|
|
||||||
** This software is in the public domain, furnished "as is", without technical
|
|
||||||
** support, and with no warranty, express or implied, as to its usefulness for
|
|
||||||
** any purpose.
|
|
||||||
**
|
|
||||||
** main.cpp
|
|
||||||
**
|
|
||||||
** test V4L2 capture device
|
|
||||||
**
|
|
||||||
** -------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <signal.h>
|
|
||||||
|
|
||||||
#include "logger.h"
|
|
||||||
#include "V4l2Capture.h"
|
|
||||||
|
|
||||||
int stop=0;
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------
|
|
||||||
** SIGINT handler
|
|
||||||
** -------------------------------------------------------------------------*/
|
|
||||||
void sighandler(int)
|
|
||||||
{
|
|
||||||
printf("SIGINT\n");
|
|
||||||
stop =1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------
|
|
||||||
** main
|
|
||||||
** -------------------------------------------------------------------------*/
|
|
||||||
int main(int argc, char* argv[])
|
|
||||||
{
|
|
||||||
int verbose = 0;
|
|
||||||
const char *in_devname = "/dev/video0";
|
|
||||||
V4l2IoType ioTypeIn = IOTYPE_MMAP;
|
|
||||||
int format = 0;
|
|
||||||
int width = 0;
|
|
||||||
int height = 0;
|
|
||||||
int fps = 0;
|
|
||||||
int framecount = 0;
|
|
||||||
int c = 0;
|
|
||||||
while ((c = getopt (argc, argv, "x:hv:" "G:f:r")) != -1)
|
|
||||||
{
|
|
||||||
switch (c)
|
|
||||||
{
|
|
||||||
case 'v': verbose = 1; if (optarg && *optarg=='v') verbose++; break;
|
|
||||||
case 'r': ioTypeIn = IOTYPE_READWRITE ; break;
|
|
||||||
case 'G': sscanf(optarg,"%dx%dx%d", &width, &height, &fps) ; break;
|
|
||||||
case 'f': format = V4l2Device::fourcc(optarg) ; break;
|
|
||||||
case 'x': sscanf(optarg,"%d", &framecount) ; break;
|
|
||||||
case 'h':
|
|
||||||
{
|
|
||||||
std::cout << argv[0] << " [-v[v]] [-G <width>x<height>x<fps>] [-f format] [device] [-r]" << std::endl;
|
|
||||||
std::cout << "\t -G <width>x<height>x<fps> : set capture resolution" << std::endl;
|
|
||||||
std::cout << "\t -v : verbose " << std::endl;
|
|
||||||
std::cout << "\t -vv : very verbose " << std::endl;
|
|
||||||
std::cout << "\t -r : V4L2 capture using read interface (default use memory mapped buffers)" << std::endl;
|
|
||||||
std::cout << "\t -x <count> : read <count> frames and save them in current dir." << std::endl;
|
|
||||||
std::cout << "\t device : V4L2 capture device (default "<< in_devname << ")" << std::endl;
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (optind<argc)
|
|
||||||
{
|
|
||||||
in_devname = argv[optind];
|
|
||||||
optind++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize log4cpp
|
|
||||||
initLogger(verbose);
|
|
||||||
|
|
||||||
// init V4L2 capture interface
|
|
||||||
V4L2DeviceParameters param(in_devname, format, width, height, fps, ioTypeIn);
|
|
||||||
V4l2Capture* videoCapture = V4l2Capture::create(param);
|
|
||||||
|
|
||||||
if (videoCapture == NULL)
|
|
||||||
{
|
|
||||||
LOG(WARN) << "Cannot reading from V4L2 capture interface for device:" << in_devname;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
timeval tv;
|
|
||||||
|
|
||||||
LOG(NOTICE) << "Start reading from " << in_devname;
|
|
||||||
signal(SIGINT,sighandler);
|
|
||||||
while (!stop)
|
|
||||||
{
|
|
||||||
tv.tv_sec=1;
|
|
||||||
tv.tv_usec=0;
|
|
||||||
int ret = videoCapture->isReadable(&tv);
|
|
||||||
if (ret == 1)
|
|
||||||
{
|
|
||||||
char buffer[videoCapture->getBufferSize()];
|
|
||||||
int rsize = videoCapture->read(buffer, sizeof(buffer));
|
|
||||||
if (rsize == -1)
|
|
||||||
{
|
|
||||||
LOG(NOTICE) << "stop " << strerror(errno);
|
|
||||||
stop=1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG(NOTICE) << "size:" << rsize;
|
|
||||||
static int stop_count = 0;
|
|
||||||
if(framecount and stop_count < framecount){
|
|
||||||
std::string filename = "Frame" + std::to_string(stop_count) + '.' + V4l2Device::fourcc(videoCapture->getFormat());
|
|
||||||
stop_count++;
|
|
||||||
FILE *fp = fopen(filename.c_str(), "wb");
|
|
||||||
fwrite(buffer, 1, rsize, fp);
|
|
||||||
fclose(fp);
|
|
||||||
LOG(NOTICE) << "saved:\t" << filename;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (ret == -1)
|
|
||||||
{
|
|
||||||
LOG(NOTICE) << "stop " << strerror(errno);
|
|
||||||
stop=1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
delete videoCapture;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
/* ---------------------------------------------------------------------------
|
|
||||||
** This software is in the public domain, furnished "as is", without technical
|
|
||||||
** support, and with no warranty, express or implied, as to its usefulness for
|
|
||||||
** any purpose.
|
|
||||||
**
|
|
||||||
** V4l2Access.cpp
|
|
||||||
**
|
|
||||||
** V4L2 wrapper
|
|
||||||
**
|
|
||||||
** -------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include "V4l2Access.h"
|
|
||||||
|
|
||||||
V4l2Access::V4l2Access(V4l2Device* device) : m_device(device) {
|
|
||||||
}
|
|
||||||
|
|
||||||
V4l2Access::~V4l2Access() {
|
|
||||||
delete m_device;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,90 +0,0 @@
|
|||||||
/* ---------------------------------------------------------------------------
|
|
||||||
** This software is in the public domain, furnished "as is", without technical
|
|
||||||
** support, and with no warranty, express or implied, as to its usefulness for
|
|
||||||
** any purpose.
|
|
||||||
**
|
|
||||||
** V4l2Capture.cpp
|
|
||||||
**
|
|
||||||
** V4L2 wrapper
|
|
||||||
**
|
|
||||||
** -------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
|
|
||||||
// libv4l2
|
|
||||||
#include <linux/videodev2.h>
|
|
||||||
|
|
||||||
// project
|
|
||||||
#include "logger.h"
|
|
||||||
#include "V4l2Capture.h"
|
|
||||||
#include "V4l2MmapDevice.h"
|
|
||||||
#include "V4l2ReadWriteDevice.h"
|
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------
|
|
||||||
// create video capture interface
|
|
||||||
// -----------------------------------------
|
|
||||||
V4l2Capture* V4l2Capture::create(const V4L2DeviceParameters & param)
|
|
||||||
{
|
|
||||||
V4l2Capture* videoCapture = NULL;
|
|
||||||
V4l2Device* videoDevice = NULL;
|
|
||||||
int caps = V4L2_CAP_VIDEO_CAPTURE;
|
|
||||||
switch (param.m_iotype)
|
|
||||||
{
|
|
||||||
case IOTYPE_MMAP:
|
|
||||||
videoDevice = new V4l2MmapDevice(param, V4L2_BUF_TYPE_VIDEO_CAPTURE);
|
|
||||||
caps |= V4L2_CAP_STREAMING;
|
|
||||||
break;
|
|
||||||
case IOTYPE_READWRITE:
|
|
||||||
videoDevice = new V4l2ReadWriteDevice(param, V4L2_BUF_TYPE_VIDEO_CAPTURE);
|
|
||||||
caps |= V4L2_CAP_READWRITE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (videoDevice && !videoDevice->init(caps))
|
|
||||||
{
|
|
||||||
delete videoDevice;
|
|
||||||
videoDevice=NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (videoDevice)
|
|
||||||
{
|
|
||||||
videoCapture = new V4l2Capture(videoDevice);
|
|
||||||
}
|
|
||||||
return videoCapture;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------
|
|
||||||
// constructor
|
|
||||||
// -----------------------------------------
|
|
||||||
V4l2Capture::V4l2Capture(V4l2Device* device) : V4l2Access(device)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------
|
|
||||||
// destructor
|
|
||||||
// -----------------------------------------
|
|
||||||
V4l2Capture::~V4l2Capture()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------
|
|
||||||
// check readability
|
|
||||||
// -----------------------------------------
|
|
||||||
bool V4l2Capture::isReadable(timeval* tv)
|
|
||||||
{
|
|
||||||
int fd = m_device->getFd();
|
|
||||||
fd_set fdset;
|
|
||||||
FD_ZERO(&fdset);
|
|
||||||
FD_SET(fd, &fdset);
|
|
||||||
return (select(fd+1, &fdset, NULL, NULL, tv) == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------
|
|
||||||
// read from V4l2Device
|
|
||||||
// -----------------------------------------
|
|
||||||
size_t V4l2Capture::read(char* buffer, size_t bufferSize)
|
|
||||||
{
|
|
||||||
return m_device->readInternal(buffer, bufferSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,253 +0,0 @@
|
|||||||
/* ---------------------------------------------------------------------------
|
|
||||||
** This software is in the public domain, furnished "as is", without technical
|
|
||||||
** support, and with no warranty, express or implied, as to its usefulness for
|
|
||||||
** any purpose.
|
|
||||||
**
|
|
||||||
** V4l2Device.cpp
|
|
||||||
**
|
|
||||||
** -------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
// libv4l2
|
|
||||||
#include <linux/videodev2.h>
|
|
||||||
|
|
||||||
#include "logger.h"
|
|
||||||
|
|
||||||
#include "V4l2Device.h"
|
|
||||||
|
|
||||||
std::string V4l2Device::fourcc(unsigned int format) {
|
|
||||||
char formatArray[] = { (char)(format&0xff), (char)((format>>8)&0xff), (char)((format>>16)&0xff), (char)((format>>24)&0xff), 0 };
|
|
||||||
return std::string(formatArray, strlen(formatArray));
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int V4l2Device::fourcc(const char* format) {
|
|
||||||
char fourcc[4];
|
|
||||||
memset(&fourcc, 0, sizeof(fourcc));
|
|
||||||
if (format != NULL)
|
|
||||||
{
|
|
||||||
strncpy(fourcc, format, 4);
|
|
||||||
}
|
|
||||||
return v4l2_fourcc(fourcc[0], fourcc[1], fourcc[2], fourcc[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------
|
|
||||||
// V4L2Device
|
|
||||||
// -----------------------------------------
|
|
||||||
V4l2Device::V4l2Device(const V4L2DeviceParameters& params, v4l2_buf_type deviceType) : m_params(params), m_fd(-1), m_deviceType(deviceType), m_bufferSize(0), m_format(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
V4l2Device::~V4l2Device()
|
|
||||||
{
|
|
||||||
this->close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void V4l2Device::close()
|
|
||||||
{
|
|
||||||
if (m_fd != -1)
|
|
||||||
::close(m_fd);
|
|
||||||
|
|
||||||
m_fd = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// query current format
|
|
||||||
void V4l2Device::queryFormat()
|
|
||||||
{
|
|
||||||
struct v4l2_format fmt;
|
|
||||||
memset(&fmt,0,sizeof(fmt));
|
|
||||||
fmt.type = m_deviceType;
|
|
||||||
if (0 == ioctl(m_fd,VIDIOC_G_FMT,&fmt))
|
|
||||||
{
|
|
||||||
m_format = fmt.fmt.pix.pixelformat;
|
|
||||||
m_width = fmt.fmt.pix.width;
|
|
||||||
m_height = fmt.fmt.pix.height;
|
|
||||||
m_bufferSize = fmt.fmt.pix.sizeimage;
|
|
||||||
|
|
||||||
LOG(DEBUG) << m_params.m_devName << ":" << fourcc(m_format) << " size:" << m_width << "x" << m_height << " bufferSize:" << m_bufferSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// intialize the V4L2 connection
|
|
||||||
bool V4l2Device::init(unsigned int mandatoryCapabilities)
|
|
||||||
{
|
|
||||||
struct stat sb;
|
|
||||||
if ( (stat(m_params.m_devName.c_str(), &sb)==0) && ((sb.st_mode & S_IFMT) == S_IFCHR) )
|
|
||||||
{
|
|
||||||
if (initdevice(m_params.m_devName.c_str(), mandatoryCapabilities) == -1)
|
|
||||||
{
|
|
||||||
LOG(ERROR) << "Cannot init device:" << m_params.m_devName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// open a normal file
|
|
||||||
m_fd = open(m_params.m_devName.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
|
|
||||||
}
|
|
||||||
return (m_fd!=-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// intialize the V4L2 device
|
|
||||||
int V4l2Device::initdevice(const char *dev_name, unsigned int mandatoryCapabilities)
|
|
||||||
{
|
|
||||||
m_fd = open(dev_name, m_params.m_openFlags);
|
|
||||||
if (m_fd < 0)
|
|
||||||
{
|
|
||||||
LOG(ERROR) << "Cannot open device:" << m_params.m_devName << " " << strerror(errno);
|
|
||||||
this->close();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (checkCapabilities(m_fd,mandatoryCapabilities) !=0)
|
|
||||||
{
|
|
||||||
this->close();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (configureFormat(m_fd) !=0)
|
|
||||||
{
|
|
||||||
this->close();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (configureParam(m_fd, m_params.m_fps) !=0)
|
|
||||||
{
|
|
||||||
this->close();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check needed V4L2 capabilities
|
|
||||||
int V4l2Device::checkCapabilities(int fd, unsigned int mandatoryCapabilities)
|
|
||||||
{
|
|
||||||
struct v4l2_capability cap;
|
|
||||||
memset(&(cap), 0, sizeof(cap));
|
|
||||||
if (-1 == ioctl(fd, VIDIOC_QUERYCAP, &cap))
|
|
||||||
{
|
|
||||||
LOG(ERROR) << "Cannot get capabilities for device:" << m_params.m_devName << " " << strerror(errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
LOG(INFO) << "driver:" << cap.driver << " capabilities:" << std::hex << cap.capabilities << " mandatory:" << mandatoryCapabilities << std::dec;
|
|
||||||
|
|
||||||
if ((cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)) LOG(DEBUG) << m_params.m_devName << " support output";
|
|
||||||
if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) LOG(DEBUG) << m_params.m_devName << " support capture";
|
|
||||||
|
|
||||||
if ((cap.capabilities & V4L2_CAP_READWRITE)) LOG(DEBUG) << m_params.m_devName << " support read/write";
|
|
||||||
if ((cap.capabilities & V4L2_CAP_STREAMING)) LOG(DEBUG) << m_params.m_devName << " support streaming";
|
|
||||||
|
|
||||||
if ((cap.capabilities & V4L2_CAP_TIMEPERFRAME)) LOG(DEBUG) << m_params.m_devName << " support timeperframe";
|
|
||||||
|
|
||||||
if ( (cap.capabilities & mandatoryCapabilities) != mandatoryCapabilities )
|
|
||||||
{
|
|
||||||
LOG(ERROR) << "Mandatory capability not available for device:" << m_params.m_devName;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// configure capture format
|
|
||||||
int V4l2Device::configureFormat(int fd)
|
|
||||||
{
|
|
||||||
// get current configuration
|
|
||||||
this->queryFormat();
|
|
||||||
|
|
||||||
unsigned int width = m_width;
|
|
||||||
unsigned int height = m_height;
|
|
||||||
if (m_params.m_width != 0) {
|
|
||||||
width= m_params.m_width;
|
|
||||||
}
|
|
||||||
if (m_params.m_height != 0) {
|
|
||||||
height= m_params.m_height;
|
|
||||||
}
|
|
||||||
if ( (m_params.m_formatList.size()==0) && (m_format != 0) ) {
|
|
||||||
m_params.m_formatList.push_back(m_format);
|
|
||||||
}
|
|
||||||
|
|
||||||
// try to set format, widht, height
|
|
||||||
std::list<unsigned int>::iterator it;
|
|
||||||
for (it = m_params.m_formatList.begin(); it != m_params.m_formatList.end(); ++it) {
|
|
||||||
unsigned int format = *it;
|
|
||||||
if (this->configureFormat(fd, format, width, height)==0) {
|
|
||||||
// format has been set
|
|
||||||
// get the format again because calling SET-FMT return a bad buffersize using v4l2loopback
|
|
||||||
this->queryFormat();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// configure capture format
|
|
||||||
int V4l2Device::configureFormat(int fd, unsigned int format, unsigned int width, unsigned int height)
|
|
||||||
{
|
|
||||||
struct v4l2_format fmt;
|
|
||||||
memset(&(fmt), 0, sizeof(fmt));
|
|
||||||
fmt.type = m_deviceType;
|
|
||||||
if (ioctl(m_fd,VIDIOC_G_FMT,&fmt) == -1)
|
|
||||||
{
|
|
||||||
LOG(ERROR) << m_params.m_devName << ": Cannot get format " << strerror(errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (width != 0) {
|
|
||||||
fmt.fmt.pix.width = width;
|
|
||||||
}
|
|
||||||
if (height != 0) {
|
|
||||||
fmt.fmt.pix.height = height;
|
|
||||||
}
|
|
||||||
if (format != 0) {
|
|
||||||
fmt.fmt.pix.pixelformat = format;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ioctl(fd, VIDIOC_S_FMT, &fmt) == -1)
|
|
||||||
{
|
|
||||||
LOG(ERROR) << m_params.m_devName << ": Cannot set format:" << fourcc(format) << " " << strerror(errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (fmt.fmt.pix.pixelformat != format)
|
|
||||||
{
|
|
||||||
LOG(ERROR) << m_params.m_devName << ": Cannot set pixelformat to:" << fourcc(format) << " format is:" << fourcc(fmt.fmt.pix.pixelformat);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if ((fmt.fmt.pix.width != width) || (fmt.fmt.pix.height != height))
|
|
||||||
{
|
|
||||||
LOG(WARN) << m_params.m_devName << ": Cannot set size to:" << width << "x" << height << " size is:" << fmt.fmt.pix.width << "x" << fmt.fmt.pix.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_format = fmt.fmt.pix.pixelformat;
|
|
||||||
m_width = fmt.fmt.pix.width;
|
|
||||||
m_height = fmt.fmt.pix.height;
|
|
||||||
m_bufferSize = fmt.fmt.pix.sizeimage;
|
|
||||||
|
|
||||||
LOG(INFO) << m_params.m_devName << ":" << fourcc(m_format) << " size:" << m_width << "x" << m_height << " bufferSize:" << m_bufferSize;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// configure capture FPS
|
|
||||||
int V4l2Device::configureParam(int fd, int fps)
|
|
||||||
{
|
|
||||||
if (fps!=0)
|
|
||||||
{
|
|
||||||
struct v4l2_streamparm param;
|
|
||||||
memset(&(param), 0, sizeof(param));
|
|
||||||
param.type = m_deviceType;
|
|
||||||
param.parm.capture.timeperframe.numerator = 1;
|
|
||||||
param.parm.capture.timeperframe.denominator = fps;
|
|
||||||
|
|
||||||
if (ioctl(fd, VIDIOC_S_PARM, ¶m) == -1)
|
|
||||||
{
|
|
||||||
LOG(WARN) << "Cannot set param for device:" << m_params.m_devName << " " << strerror(errno);
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG(INFO) << "fps:" << param.parm.capture.timeperframe.numerator << "/" << param.parm.capture.timeperframe.denominator;
|
|
||||||
LOG(INFO) << "nbBuffer:" << param.parm.capture.readbuffers;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,311 +0,0 @@
|
|||||||
/* ---------------------------------------------------------------------------
|
|
||||||
** This software is in the public domain, furnished "as is", without technical
|
|
||||||
** support, and with no warranty, express or implied, as to its usefulness for
|
|
||||||
** any purpose.
|
|
||||||
**
|
|
||||||
** V4l2MmapDevice.cpp
|
|
||||||
**
|
|
||||||
** V4L2 source using mmap API
|
|
||||||
**
|
|
||||||
** -------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
|
|
||||||
// libv4l2
|
|
||||||
#include <linux/videodev2.h>
|
|
||||||
|
|
||||||
// project
|
|
||||||
#include "logger.h"
|
|
||||||
#include "V4l2MmapDevice.h"
|
|
||||||
|
|
||||||
V4l2MmapDevice::V4l2MmapDevice(const V4L2DeviceParameters & params, v4l2_buf_type deviceType) : V4l2Device(params, deviceType), n_buffers(0)
|
|
||||||
{
|
|
||||||
memset(&m_buffer, 0, sizeof(m_buffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool V4l2MmapDevice::init(unsigned int mandatoryCapabilities)
|
|
||||||
{
|
|
||||||
bool ret = V4l2Device::init(mandatoryCapabilities);
|
|
||||||
if (ret)
|
|
||||||
{
|
|
||||||
ret = this->start();
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
V4l2MmapDevice::~V4l2MmapDevice()
|
|
||||||
{
|
|
||||||
this->stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool V4l2MmapDevice::start()
|
|
||||||
{
|
|
||||||
LOG(INFO) << "Device " << m_params.m_devName;
|
|
||||||
|
|
||||||
bool success = true;
|
|
||||||
struct v4l2_requestbuffers req;
|
|
||||||
memset (&req, 0, sizeof(req));
|
|
||||||
req.count = V4L2MMAP_NBBUFFER;
|
|
||||||
req.type = m_deviceType;
|
|
||||||
req.memory = V4L2_MEMORY_MMAP;
|
|
||||||
|
|
||||||
if (-1 == ioctl(m_fd, VIDIOC_REQBUFS, &req))
|
|
||||||
{
|
|
||||||
if (EINVAL == errno)
|
|
||||||
{
|
|
||||||
LOG(ERROR) << "Device " << m_params.m_devName << " does not support memory mapping";
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
perror("VIDIOC_REQBUFS");
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG(INFO) << "Device " << m_params.m_devName << " nb buffer:" << req.count;
|
|
||||||
|
|
||||||
// allocate buffers
|
|
||||||
memset(&m_buffer,0, sizeof(m_buffer));
|
|
||||||
for (n_buffers = 0; n_buffers < req.count; ++n_buffers)
|
|
||||||
{
|
|
||||||
struct v4l2_buffer buf;
|
|
||||||
memset (&buf, 0, sizeof(buf));
|
|
||||||
buf.type = m_deviceType;
|
|
||||||
buf.memory = V4L2_MEMORY_MMAP;
|
|
||||||
buf.index = n_buffers;
|
|
||||||
|
|
||||||
if (-1 == ioctl(m_fd, VIDIOC_QUERYBUF, &buf))
|
|
||||||
{
|
|
||||||
perror("VIDIOC_QUERYBUF");
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG(INFO) << "Device " << m_params.m_devName << " buffer idx:" << n_buffers << " size:" << buf.length << " offset:" << buf.m.offset;
|
|
||||||
m_buffer[n_buffers].length = buf.length;
|
|
||||||
if (!m_buffer[n_buffers].length) {
|
|
||||||
m_buffer[n_buffers].length = buf.bytesused;
|
|
||||||
}
|
|
||||||
m_buffer[n_buffers].start = mmap ( NULL /* start anywhere */,
|
|
||||||
m_buffer[n_buffers].length,
|
|
||||||
PROT_READ | PROT_WRITE /* required */,
|
|
||||||
MAP_SHARED /* recommended */,
|
|
||||||
m_fd,
|
|
||||||
buf.m.offset);
|
|
||||||
|
|
||||||
if (MAP_FAILED == m_buffer[n_buffers].start)
|
|
||||||
{
|
|
||||||
perror("mmap");
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// queue buffers
|
|
||||||
for (unsigned int i = 0; i < n_buffers; ++i)
|
|
||||||
{
|
|
||||||
struct v4l2_buffer buf;
|
|
||||||
memset (&buf, 0, sizeof(buf));
|
|
||||||
buf.type = m_deviceType;
|
|
||||||
buf.memory = V4L2_MEMORY_MMAP;
|
|
||||||
buf.index = i;
|
|
||||||
|
|
||||||
if (-1 == ioctl(m_fd, VIDIOC_QBUF, &buf))
|
|
||||||
{
|
|
||||||
perror("VIDIOC_QBUF");
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// start stream
|
|
||||||
int type = m_deviceType;
|
|
||||||
if (-1 == ioctl(m_fd, VIDIOC_STREAMON, &type))
|
|
||||||
{
|
|
||||||
perror("VIDIOC_STREAMON");
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool V4l2MmapDevice::stop()
|
|
||||||
{
|
|
||||||
LOG(INFO) << "Device " << m_params.m_devName;
|
|
||||||
|
|
||||||
bool success = true;
|
|
||||||
|
|
||||||
int type = m_deviceType;
|
|
||||||
if (-1 == ioctl(m_fd, VIDIOC_STREAMOFF, &type))
|
|
||||||
{
|
|
||||||
perror("VIDIOC_STREAMOFF");
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < n_buffers; ++i)
|
|
||||||
{
|
|
||||||
if (-1 == munmap (m_buffer[i].start, m_buffer[i].length))
|
|
||||||
{
|
|
||||||
perror("munmap");
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// free buffers
|
|
||||||
struct v4l2_requestbuffers req;
|
|
||||||
memset (&req, 0, sizeof(req));
|
|
||||||
req.count = 0;
|
|
||||||
req.type = m_deviceType;
|
|
||||||
req.memory = V4L2_MEMORY_MMAP;
|
|
||||||
if (-1 == ioctl(m_fd, VIDIOC_REQBUFS, &req))
|
|
||||||
{
|
|
||||||
perror("VIDIOC_REQBUFS");
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
n_buffers = 0;
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t V4l2MmapDevice::readInternal(char* buffer, size_t bufferSize)
|
|
||||||
{
|
|
||||||
size_t size = 0;
|
|
||||||
if (n_buffers > 0)
|
|
||||||
{
|
|
||||||
struct v4l2_buffer buf;
|
|
||||||
memset (&buf, 0, sizeof(buf));
|
|
||||||
buf.type = m_deviceType;
|
|
||||||
buf.memory = V4L2_MEMORY_MMAP;
|
|
||||||
|
|
||||||
if (-1 == ioctl(m_fd, VIDIOC_DQBUF, &buf))
|
|
||||||
{
|
|
||||||
if (errno == EAGAIN) {
|
|
||||||
size = 0;
|
|
||||||
} else {
|
|
||||||
perror("VIDIOC_DQBUF");
|
|
||||||
size = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (buf.index < n_buffers)
|
|
||||||
{
|
|
||||||
size = buf.bytesused;
|
|
||||||
if (size > bufferSize)
|
|
||||||
{
|
|
||||||
size = bufferSize;
|
|
||||||
LOG(WARN) << "Device " << m_params.m_devName << " buffer truncated available:" << bufferSize << " needed:" << buf.bytesused;
|
|
||||||
}
|
|
||||||
memcpy(buffer, m_buffer[buf.index].start, size);
|
|
||||||
|
|
||||||
if (-1 == ioctl(m_fd, VIDIOC_QBUF, &buf))
|
|
||||||
{
|
|
||||||
perror("VIDIOC_QBUF");
|
|
||||||
size = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t V4l2MmapDevice::writeInternal(char* buffer, size_t bufferSize)
|
|
||||||
{
|
|
||||||
size_t size = 0;
|
|
||||||
if (n_buffers > 0)
|
|
||||||
{
|
|
||||||
struct v4l2_buffer buf;
|
|
||||||
memset (&buf, 0, sizeof(buf));
|
|
||||||
buf.type = m_deviceType;
|
|
||||||
buf.memory = V4L2_MEMORY_MMAP;
|
|
||||||
|
|
||||||
if (-1 == ioctl(m_fd, VIDIOC_DQBUF, &buf))
|
|
||||||
{
|
|
||||||
perror("VIDIOC_DQBUF");
|
|
||||||
size = -1;
|
|
||||||
}
|
|
||||||
else if (buf.index < n_buffers)
|
|
||||||
{
|
|
||||||
size = bufferSize;
|
|
||||||
if (size > buf.length)
|
|
||||||
{
|
|
||||||
LOG(WARN) << "Device " << m_params.m_devName << " buffer truncated available:" << buf.length << " needed:" << size;
|
|
||||||
size = buf.length;
|
|
||||||
}
|
|
||||||
memcpy(m_buffer[buf.index].start, buffer, size);
|
|
||||||
buf.bytesused = size;
|
|
||||||
|
|
||||||
if (-1 == ioctl(m_fd, VIDIOC_QBUF, &buf))
|
|
||||||
{
|
|
||||||
perror("VIDIOC_QBUF");
|
|
||||||
size = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool V4l2MmapDevice::startPartialWrite()
|
|
||||||
{
|
|
||||||
if (n_buffers <= 0)
|
|
||||||
return false;
|
|
||||||
if (m_partialWriteInProgress)
|
|
||||||
return false;
|
|
||||||
memset(&m_partialWriteBuf, 0, sizeof(m_partialWriteBuf));
|
|
||||||
m_partialWriteBuf.type = m_deviceType;
|
|
||||||
m_partialWriteBuf.memory = V4L2_MEMORY_MMAP;
|
|
||||||
if (-1 == ioctl(m_fd, VIDIOC_DQBUF, &m_partialWriteBuf))
|
|
||||||
{
|
|
||||||
perror("VIDIOC_DQBUF");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
m_partialWriteBuf.bytesused = 0;
|
|
||||||
m_partialWriteInProgress = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t V4l2MmapDevice::writePartialInternal(char* buffer, size_t bufferSize)
|
|
||||||
{
|
|
||||||
size_t new_size = 0;
|
|
||||||
size_t size = 0;
|
|
||||||
if ((n_buffers > 0) && m_partialWriteInProgress)
|
|
||||||
{
|
|
||||||
if (m_partialWriteBuf.index < n_buffers)
|
|
||||||
{
|
|
||||||
new_size = m_partialWriteBuf.bytesused + bufferSize;
|
|
||||||
if (new_size > m_partialWriteBuf.length)
|
|
||||||
{
|
|
||||||
LOG(WARN) << "Device " << m_params.m_devName << " buffer truncated available:" << m_partialWriteBuf.length << " needed:" << new_size;
|
|
||||||
new_size = m_partialWriteBuf.length;
|
|
||||||
}
|
|
||||||
size = new_size - m_partialWriteBuf.bytesused;
|
|
||||||
memcpy(&((char *)m_buffer[m_partialWriteBuf.index].start)[m_partialWriteBuf.bytesused], buffer, size);
|
|
||||||
|
|
||||||
m_partialWriteBuf.bytesused += size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool V4l2MmapDevice::endPartialWrite()
|
|
||||||
{
|
|
||||||
if (!m_partialWriteInProgress)
|
|
||||||
return false;
|
|
||||||
if (n_buffers <= 0)
|
|
||||||
{
|
|
||||||
m_partialWriteInProgress = false; // abort partial write
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (-1 == ioctl(m_fd, VIDIOC_QBUF, &m_partialWriteBuf))
|
|
||||||
{
|
|
||||||
perror("VIDIOC_QBUF");
|
|
||||||
m_partialWriteInProgress = false; // abort partial write
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
m_partialWriteInProgress = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
@ -1,106 +0,0 @@
|
|||||||
/* ---------------------------------------------------------------------------
|
|
||||||
** This software is in the public domain, furnished "as is", without technical
|
|
||||||
** support, and with no warranty, express or implied, as to its usefulness for
|
|
||||||
** any purpose.
|
|
||||||
**
|
|
||||||
** V4l2Output.cpp
|
|
||||||
**
|
|
||||||
** V4L2 wrapper
|
|
||||||
**
|
|
||||||
** -------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
// libv4l2
|
|
||||||
#include <linux/videodev2.h>
|
|
||||||
|
|
||||||
// project
|
|
||||||
#include "logger.h"
|
|
||||||
|
|
||||||
#include "V4l2Output.h"
|
|
||||||
#include "V4l2MmapDevice.h"
|
|
||||||
#include "V4l2ReadWriteDevice.h"
|
|
||||||
|
|
||||||
// -----------------------------------------
|
|
||||||
// create video output interface
|
|
||||||
// -----------------------------------------
|
|
||||||
V4l2Output* V4l2Output::create(const V4L2DeviceParameters & param)
|
|
||||||
{
|
|
||||||
V4l2Output* videoOutput = NULL;
|
|
||||||
V4l2Device* videoDevice = NULL;
|
|
||||||
int caps = V4L2_CAP_VIDEO_OUTPUT;
|
|
||||||
switch (param.m_iotype)
|
|
||||||
{
|
|
||||||
case IOTYPE_MMAP:
|
|
||||||
videoDevice = new V4l2MmapDevice(param, V4L2_BUF_TYPE_VIDEO_OUTPUT);
|
|
||||||
caps |= V4L2_CAP_STREAMING;
|
|
||||||
break;
|
|
||||||
case IOTYPE_READWRITE:
|
|
||||||
videoDevice = new V4l2ReadWriteDevice(param, V4L2_BUF_TYPE_VIDEO_OUTPUT);
|
|
||||||
caps |= V4L2_CAP_READWRITE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (videoDevice && !videoDevice->init(caps))
|
|
||||||
{
|
|
||||||
delete videoDevice;
|
|
||||||
videoDevice=NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (videoDevice)
|
|
||||||
{
|
|
||||||
videoOutput = new V4l2Output(videoDevice);
|
|
||||||
}
|
|
||||||
return videoOutput;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------
|
|
||||||
// constructor
|
|
||||||
// -----------------------------------------
|
|
||||||
V4l2Output::V4l2Output(V4l2Device* device) : V4l2Access(device)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------
|
|
||||||
// destructor
|
|
||||||
// -----------------------------------------
|
|
||||||
V4l2Output::~V4l2Output()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------
|
|
||||||
// check writability
|
|
||||||
// -----------------------------------------
|
|
||||||
bool V4l2Output::isWritable(timeval* tv)
|
|
||||||
{
|
|
||||||
int fd = m_device->getFd();
|
|
||||||
fd_set fdset;
|
|
||||||
FD_ZERO(&fdset);
|
|
||||||
FD_SET(fd, &fdset);
|
|
||||||
return (select(fd+1, NULL, &fdset, NULL, tv) == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------
|
|
||||||
// write to V4l2Device
|
|
||||||
// -----------------------------------------
|
|
||||||
size_t V4l2Output::write(char* buffer, size_t bufferSize)
|
|
||||||
{
|
|
||||||
return m_device->writeInternal(buffer, bufferSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool V4l2Output::startPartialWrite()
|
|
||||||
{
|
|
||||||
return m_device->startPartialWrite();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t V4l2Output::writePartial(char* buffer, size_t bufferSize)
|
|
||||||
{
|
|
||||||
return m_device->writePartialInternal(buffer, bufferSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool V4l2Output::endPartialWrite()
|
|
||||||
{
|
|
||||||
return m_device->endPartialWrite();
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
/* ---------------------------------------------------------------------------
|
|
||||||
** This software is in the public domain, furnished "as is", without technical
|
|
||||||
** support, and with no warranty, express or implied, as to its usefulness for
|
|
||||||
** any purpose.
|
|
||||||
**
|
|
||||||
** V4l2ReadWriteDevice.cpp
|
|
||||||
**
|
|
||||||
** V4L2 source using read/write API
|
|
||||||
**
|
|
||||||
** -------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "V4l2ReadWriteDevice.h"
|
|
||||||
|
|
||||||
V4l2ReadWriteDevice::V4l2ReadWriteDevice(const V4L2DeviceParameters& params, v4l2_buf_type deviceType) : V4l2Device(params, deviceType) {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
size_t V4l2ReadWriteDevice::writeInternal(char* buffer, size_t bufferSize) {
|
|
||||||
return ::write(m_fd, buffer, bufferSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t V4l2ReadWriteDevice::readInternal(char* buffer, size_t bufferSize) {
|
|
||||||
return ::read(m_fd, buffer, bufferSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
/* ---------------------------------------------------------------------------
|
|
||||||
** This software is in the public domain, furnished "as is", without technical
|
|
||||||
** support, and with no warranty, express or implied, as to its usefulness for
|
|
||||||
** any purpose.
|
|
||||||
**
|
|
||||||
** logger.cpp
|
|
||||||
**
|
|
||||||
** -------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include "logger.h"
|
|
||||||
|
|
||||||
#ifndef HAVE_LOG4CPP
|
|
||||||
int LogLevel=NOTICE;
|
|
||||||
#endif
|
|
||||||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue