Added setting of PAL/NTSC/NO_CHANGE and input

Former-commit-id: aee087b65b122e34e46b15854b94c720cbbec6b2
This commit is contained in:
johan 2014-01-11 20:43:55 +01:00
parent fdb140c1ae
commit 558ad6a11f
3 changed files with 166 additions and 88 deletions

View File

@ -19,62 +19,70 @@
#define CLEAR(x) memset(&(x), 0, sizeof(x))
V4L2Grabber::V4L2Grabber() :
_deviceName("/dev/video0"),
V4L2Grabber::V4L2Grabber(const std::string &device, int input, VideoStandard videoStandard, double fps) :
_deviceName(device),
_ioMethod(IO_METHOD_MMAP),
_fileDescriptor(-1),
_buffers()
_buffers(),
_width(0),
_height(0)
{
open_device();
init_device(videoStandard, input);
}
V4L2Grabber::~V4L2Grabber()
{
uninit_device();
close_device();
}
void V4L2Grabber::start()
{
open_device();
init_device();
start_capturing();
}
int count = 100;
while (count-- > 0) {
for (;;) {
fd_set fds;
struct timeval tv;
int r;
void V4L2Grabber::capture()
{
int count = 1;
while (count-- > 0) {
for (;;) {
fd_set fds;
struct timeval tv;
int r;
FD_ZERO(&fds);
FD_SET(_fileDescriptor, &fds);
FD_ZERO(&fds);
FD_SET(_fileDescriptor, &fds);
/* Timeout. */
tv.tv_sec = 2;
tv.tv_usec = 0;
/* Timeout. */
tv.tv_sec = 2;
tv.tv_usec = 0;
r = select(_fileDescriptor + 1, &fds, NULL, NULL, &tv);
r = select(_fileDescriptor + 1, &fds, NULL, NULL, &tv);
if (-1 == r)
{
if (EINTR == errno)
continue;
errno_exit("select");
}
if (-1 == r)
{
if (EINTR == errno)
continue;
errno_exit("select");
}
if (0 == r)
{
fprintf(stderr, "select timeout\n");
exit(EXIT_FAILURE);
}
if (0 == r)
{
fprintf(stderr, "select timeout\n");
exit(EXIT_FAILURE);
}
if (read_frame())
break;
/* EAGAIN - continue select loop. */
}
}
if (read_frame())
break;
/* EAGAIN - continue select loop. */
}
}
}
stop_capturing();
uninit_device();
close_device();
void V4L2Grabber::stop()
{
stop_capturing();
}
void V4L2Grabber::open_device()
@ -207,14 +215,10 @@ void V4L2Grabber::init_userp(unsigned int buffer_size)
}
}
void V4L2Grabber::init_device()
void V4L2Grabber::init_device(VideoStandard videoStandard, int input)
{
struct v4l2_capability cap;
struct v4l2_cropcap cropcap;
struct v4l2_crop crop;
struct v4l2_format fmt;
if (-1 == xioctl(VIDIOC_QUERYCAP, &cap))
if (-1 == xioctl(VIDIOC_QUERYCAP, &cap))
{
if (EINVAL == errno) {
fprintf(stderr, "%s is no V4L2 device\n", _deviceName.c_str());
@ -252,13 +256,14 @@ void V4L2Grabber::init_device()
/* Select video input, video standard and tune here. */
struct v4l2_cropcap cropcap;
CLEAR(cropcap);
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (0 == xioctl(VIDIOC_CROPCAP, &cropcap)) {
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
struct v4l2_crop crop;
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
crop.c = cropcap.defrect; /* reset to default */
if (-1 == xioctl(VIDIOC_S_CROP, &crop)) {
@ -275,24 +280,61 @@ void V4L2Grabber::init_device()
/* Errors ignored. */
}
// set input if needed
if (input >= 0)
{
if (-1 == xioctl(VIDIOC_S_INPUT, &input))
{
errno_exit("VIDIOC_S_INPUT");
}
}
// set the video standard if needed
switch (videoStandard)
{
case PAL:
{
v4l2_std_id std_id = V4L2_STD_PAL;
if (-1 == xioctl(VIDIOC_S_STD, &std_id))
{
errno_exit("VIDIOC_S_STD");
}
}
break;
case NTSC:
{
v4l2_std_id std_id = V4L2_STD_NTSC;
if (-1 == xioctl(VIDIOC_S_STD, &std_id))
{
errno_exit("VIDIOC_S_STD");
}
}
break;
case NO_CHANGE:
default:
// No change to device settings
break;
}
// get the current settings
struct v4l2_format fmt;
CLEAR(fmt);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
/* Preserve original settings as set by v4l2-ctl for example */
if (-1 == xioctl(VIDIOC_G_FMT, &fmt))
{
errno_exit("VIDIOC_G_FMT");
errno_exit("VIDIOC_G_FMT");
}
// /* Buggy driver paranoia. */
// min = fmt.fmt.pix.width * 2;
// if (fmt.fmt.pix.bytesperline < min)
// fmt.fmt.pix.bytesperline = min;
// min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
// if (fmt.fmt.pix.sizeimage < min)
// fmt.fmt.pix.sizeimage = min;
// check pixel format
if (fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_UYVY)
{
exit(EXIT_FAILURE);
}
// store width & height
_width = fmt.fmt.pix.width;
_height = fmt.fmt.pix.height;
std::cout << "V4L2 width=" << _width << " height=" << _height << std::endl;
switch (_ioMethod) {
case IO_METHOD_READ:
@ -403,8 +445,11 @@ int V4L2Grabber::read_frame()
switch (_ioMethod) {
case IO_METHOD_READ:
if (-1 == read(_fileDescriptor, _buffers[0].start, _buffers[0].length)) {
switch (errno) {
int size;
if ((size = read(_fileDescriptor, _buffers[0].start, _buffers[0].length)) == -1)
{
switch (errno)
{
case EAGAIN:
return 0;
@ -418,7 +463,7 @@ int V4L2Grabber::read_frame()
}
}
process_image(_buffers[0].start, _buffers[0].length);
process_image(_buffers[0].start, size);
break;
case IO_METHOD_MMAP:
@ -427,8 +472,10 @@ int V4L2Grabber::read_frame()
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if (-1 == xioctl(VIDIOC_DQBUF, &buf)) {
switch (errno) {
if (-1 == xioctl(VIDIOC_DQBUF, &buf))
{
switch (errno)
{
case EAGAIN:
return 0;
@ -444,10 +491,13 @@ int V4L2Grabber::read_frame()
assert(buf.index < _buffers.size());
process_image(_buffers[buf.index].start, buf.bytesused);
process_image(_buffers[buf.index].start, buf.bytesused);
if (-1 == xioctl(VIDIOC_QBUF, &buf))
{
errno_exit("VIDIOC_QBUF");
}
break;
case IO_METHOD_USERPTR:
@ -456,8 +506,10 @@ int V4L2Grabber::read_frame()
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_USERPTR;
if (-1 == xioctl(VIDIOC_DQBUF, &buf)) {
switch (errno) {
if (-1 == xioctl(VIDIOC_DQBUF, &buf))
{
switch (errno)
{
case EAGAIN:
return 0;
@ -472,14 +524,19 @@ int V4L2Grabber::read_frame()
}
for (size_t i = 0; i < _buffers.size(); ++i)
if (buf.m.userptr == (unsigned long)_buffers[i].start
&& buf.length == _buffers[i].length)
{
if (buf.m.userptr == (unsigned long)_buffers[i].start && buf.length == _buffers[i].length)
{
break;
}
}
process_image((void *)buf.m.userptr, buf.bytesused);
process_image((void *)buf.m.userptr, buf.bytesused);
if (-1 == xioctl(VIDIOC_QBUF, &buf))
if (-1 == xioctl(VIDIOC_QBUF, &buf))
{
errno_exit("VIDIOC_QBUF");
}
break;
}
@ -488,38 +545,44 @@ int V4L2Grabber::read_frame()
void V4L2Grabber::process_image(const void *p, int size)
{
if (size != 2*720*480)
{
std::cout << "Frame too small: " << size << "<" << (2*720*480) << std::endl;
return;
}
if (size != 2*_width*_height)
{
std::cout << "Frame too small: " << size << " != " << (2*_width*_height) << std::endl;
}
else
{
process_image(reinterpret_cast<const uint8_t *>(p));
}
}
std::cout << "process image of size = " << size << std::endl;
void V4L2Grabber::process_image(const uint8_t * data)
{
std::cout << "process image" << std::endl;
const uint8_t * data = reinterpret_cast<const uint8_t *>(p);
QImage image(720, 480, QImage::Format_RGB888);
QImage image(_width, _height, QImage::Format_RGB888);
for (int y = 0; y < image.height(); ++y)
{
for (int x = 0; x < image.width(); ++x)
{
uint8_t value = data[(720 * y + x) * 2 + 1];
image.setPixel(x, y, qRgb(value, value, value));
uint8_t value = data[(image.width() * y + x) * 2 + 1];
//std::cout << "data = " << int(value) << std::endl;
image.setPixel(x, y, qRgb(value, value, value));
}
}
image.save("/home/pi/screenshot.png");
image.save("screenshot.png");
}
int V4L2Grabber::xioctl(int request, void *arg)
{
int r;
do {
r = ioctl(_fileDescriptor, request, arg);
} while (-1 == r && EINTR == errno);
do
{
r = ioctl(_fileDescriptor, request, arg);
}
while (-1 == r && EINTR == errno);
return r;
}

View File

@ -10,11 +10,20 @@
class V4L2Grabber
{
public:
V4L2Grabber();
enum VideoStandard {
PAL, NTSC, NO_CHANGE
};
public:
V4L2Grabber(const std::string & device, int input, VideoStandard videoStandard, double fps);
virtual ~V4L2Grabber();
void start();
void capture();
void stop();
private:
void open_device();
@ -26,7 +35,7 @@ private:
void init_userp(unsigned int buffer_size);
void init_device();
void init_device(VideoStandard videoStandard, int input);
void uninit_device();
@ -36,7 +45,9 @@ private:
int read_frame();
void process_image(const void *p, int size);
void process_image(const void *p, int size);
void process_image(const uint8_t *p);
int xioctl(int request, void *arg);
@ -59,4 +70,7 @@ private:
const io_method _ioMethod;
int _fileDescriptor;
std::vector<buffer> _buffers;
int _width;
int _height;
};

View File

@ -40,9 +40,10 @@ int main(int argc, char** argv)
return 1;
}
V4L2Grabber grabber;
V4L2Grabber grabber("/dev/video0", 0, V4L2Grabber::PAL, 10.0);
grabber.start();
grabber.capture();
grabber.stop();
return 0;
}