Merge branch 'add_rgb32_for_v4l2'

Former-commit-id: e7d892ab8ab1bb3aeed6ef3238f7d999dfd19013
This commit is contained in:
johan 2014-04-11 19:53:29 +02:00
commit fbb60d2006
10 changed files with 166 additions and 35 deletions

View File

@ -0,0 +1,36 @@
#pragma once
#include <string>
#include <algorithm>
/**
* Enumeration of the possible pixel formats the grabber can be set to
*/
enum PixelFormat {
PIXELFORMAT_YUYV,
PIXELFORMAT_UYVY,
PIXELFORMAT_RGB32,
PIXELFORMAT_NO_CHANGE
};
inline PixelFormat parsePixelFormat(std::string pixelFormat)
{
// convert to lower case
std::transform(pixelFormat.begin(), pixelFormat.end(), pixelFormat.begin(), ::tolower);
if (pixelFormat == "yuyv")
{
return PIXELFORMAT_YUYV;
}
else if (pixelFormat == "uyvy")
{
return PIXELFORMAT_UYVY;
}
else if (pixelFormat == "rgb32")
{
return PIXELFORMAT_RGB32;
}
// return the default NO_CHANGE
return PIXELFORMAT_NO_CHANGE;
}

View File

@ -15,6 +15,7 @@
// grabber includes // grabber includes
#include <grabber/VideoStandard.h> #include <grabber/VideoStandard.h>
#include <grabber/PixelFormat.h>
/// Capture class for V4L2 devices /// Capture class for V4L2 devices
/// ///
@ -26,7 +27,7 @@ class V4L2Grabber : public QObject
public: public:
V4L2Grabber(const std::string & device, V4L2Grabber(const std::string & device,
int input, int input,
VideoStandard videoStandard, VideoStandard videoStandard, PixelFormat pixelFormat,
int width, int width,
int height, int height,
int frameDecimation, int frameDecimation,
@ -104,7 +105,7 @@ private:
int _fileDescriptor; int _fileDescriptor;
std::vector<buffer> _buffers; std::vector<buffer> _buffers;
uint32_t _pixelFormat; PixelFormat _pixelFormat;
int _width; int _width;
int _height; int _height;
int _cropLeft; int _cropLeft;

View File

@ -18,6 +18,7 @@ public:
V4L2Wrapper(const std::string & device, V4L2Wrapper(const std::string & device,
int input, int input,
VideoStandard videoStandard, VideoStandard videoStandard,
PixelFormat pixelFormat,
int width, int width,
int height, int height,
int frameDecimation, int frameDecimation,

View File

@ -9,6 +9,7 @@ SET(V4L2_QT_HEADERS
SET(V4L2_HEADERS SET(V4L2_HEADERS
${CURRENT_HEADER_DIR}/VideoStandard.h ${CURRENT_HEADER_DIR}/VideoStandard.h
${CURRENT_HEADER_DIR}/PixelFormat.h
) )
SET(V4L2_SOURCES SET(V4L2_SOURCES

View File

@ -39,6 +39,7 @@ static void yuv2rgb(uint8_t y, uint8_t u, uint8_t v, uint8_t & r, uint8_t & g, u
V4L2Grabber::V4L2Grabber(const std::string & device, V4L2Grabber::V4L2Grabber(const std::string & device,
int input, int input,
VideoStandard videoStandard, VideoStandard videoStandard,
PixelFormat pixelFormat,
int width, int width,
int height, int height,
int frameDecimation, int frameDecimation,
@ -48,7 +49,7 @@ V4L2Grabber::V4L2Grabber(const std::string & device,
_ioMethod(IO_METHOD_MMAP), _ioMethod(IO_METHOD_MMAP),
_fileDescriptor(-1), _fileDescriptor(-1),
_buffers(), _buffers(),
_pixelFormat(0), _pixelFormat(pixelFormat),
_width(width), _width(width),
_height(height), _height(height),
_cropLeft(0), _cropLeft(0),
@ -380,17 +381,25 @@ void V4L2Grabber::init_device(VideoStandard videoStandard, int input)
throw_errno_exception("VIDIOC_G_FMT"); throw_errno_exception("VIDIOC_G_FMT");
} }
// check pixel format // set the requested pixel format
switch (fmt.fmt.pix.pixelformat) switch (_pixelFormat)
{ {
case V4L2_PIX_FMT_UYVY: case PIXELFORMAT_UYVY:
case V4L2_PIX_FMT_YUYV: fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
_pixelFormat = fmt.fmt.pix.pixelformat;
break; break;
case PIXELFORMAT_YUYV:
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
break;
case PIXELFORMAT_RGB32:
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32;
break;
case PIXELFORMAT_NO_CHANGE:
default: default:
throw_exception("Only pixel formats UYVY and YUYV are supported"); // No change to device settings
break;
} }
// set the requested withd and height
if (_width > 0 || _height > 0) if (_width > 0 || _height > 0)
{ {
if (_width > 0) if (_width > 0)
@ -402,6 +411,7 @@ void V4L2Grabber::init_device(VideoStandard videoStandard, int input)
{ {
fmt.fmt.pix.height = _height; fmt.fmt.pix.height = _height;
} }
}
// set the settings // set the settings
if (-1 == xioctl(VIDIOC_S_FMT, &fmt)) if (-1 == xioctl(VIDIOC_S_FMT, &fmt))
@ -415,6 +425,24 @@ void V4L2Grabber::init_device(VideoStandard videoStandard, int input)
{ {
throw_errno_exception("VIDIOC_G_FMT"); throw_errno_exception("VIDIOC_G_FMT");
} }
// check pixel format
switch (fmt.fmt.pix.pixelformat)
{
case V4L2_PIX_FMT_UYVY:
_pixelFormat = PIXELFORMAT_UYVY;
std::cout << "V4L2 pixel format=UYVY" << std::endl;
break;
case V4L2_PIX_FMT_YUYV:
_pixelFormat = PIXELFORMAT_YUYV;
std::cout << "V4L2 pixel format=YUYV" << std::endl;
break;
case V4L2_PIX_FMT_RGB32:
_pixelFormat = PIXELFORMAT_RGB32;
std::cout << "V4L2 pixel format=RGB32" << std::endl;
break;
default:
throw_exception("Only pixel formats UYVY, YUYV, and RGB32 are supported");
} }
// store width & height // store width & height
@ -680,27 +708,40 @@ void V4L2Grabber::process_image(const uint8_t * data)
{ {
for (int xSource = _cropLeft + _horizontalPixelDecimation/2, xDest = 0; xSource < width - _cropRight; xSource += _horizontalPixelDecimation, ++xDest) for (int xSource = _cropLeft + _horizontalPixelDecimation/2, xDest = 0; xSource < width - _cropRight; xSource += _horizontalPixelDecimation, ++xDest)
{ {
int index = (_width * ySource + xSource) * 2; ColorRgb & rgb = image(xDest, yDest);
uint8_t y = 0;
uint8_t u = 0;
uint8_t v = 0;
switch (_pixelFormat) switch (_pixelFormat)
{ {
case V4L2_PIX_FMT_UYVY: case PIXELFORMAT_UYVY:
y = data[index+1]; {
u = (xSource%2 == 0) ? data[index ] : data[index-2]; int index = (_width * ySource + xSource) * 2;
v = (xSource%2 == 0) ? data[index+2] : data[index ]; uint8_t y = data[index+1];
uint8_t u = (xSource%2 == 0) ? data[index ] : data[index-2];
uint8_t v = (xSource%2 == 0) ? data[index+2] : data[index ];
yuv2rgb(y, u, v, rgb.red, rgb.green, rgb.blue);
}
break; break;
case V4L2_PIX_FMT_YUYV: case PIXELFORMAT_YUYV:
y = data[index]; {
u = (xSource%2 == 0) ? data[index+1] : data[index-1]; int index = (_width * ySource + xSource) * 2;
v = (xSource%2 == 0) ? data[index+3] : data[index+1]; uint8_t y = data[index];
uint8_t u = (xSource%2 == 0) ? data[index+1] : data[index-1];
uint8_t v = (xSource%2 == 0) ? data[index+3] : data[index+1];
yuv2rgb(y, u, v, rgb.red, rgb.green, rgb.blue);
}
break;
case PIXELFORMAT_RGB32:
{
int index = (_width * ySource + xSource) * 4;
rgb.red = data[index+1];
rgb.green = data[index+2];
rgb.blue = data[index+3];
}
break;
default:
// this should not be possible
break; break;
} }
ColorRgb & rgb = image(xDest, yDest);
yuv2rgb(y, u, v, rgb.red, rgb.green, rgb.blue);
} }
} }

View File

@ -7,6 +7,7 @@
V4L2Wrapper::V4L2Wrapper(const std::string &device, V4L2Wrapper::V4L2Wrapper(const std::string &device,
int input, int input,
VideoStandard videoStandard, VideoStandard videoStandard,
PixelFormat pixelFormat,
int width, int width,
int height, int height,
int frameDecimation, int frameDecimation,
@ -21,6 +22,7 @@ V4L2Wrapper::V4L2Wrapper(const std::string &device,
_grabber(device, _grabber(device,
input, input,
videoStandard, videoStandard,
pixelFormat,
width, width,
height, height,
frameDecimation, frameDecimation,

View File

@ -21,6 +21,7 @@ set(Hyperion_V4L2_QT_HEADERS
set(Hyperion_V4L2_HEADERS set(Hyperion_V4L2_HEADERS
VideoStandardParameter.h VideoStandardParameter.h
PixelFormatParameter.h
ProtoConnection.h ProtoConnection.h
) )

View File

@ -0,0 +1,43 @@
// getoptPlusPLus includes
#include <getoptPlusPlus/getoptpp.h>
// grabber includes
#include <grabber/PixelFormat.h>
using namespace vlofgren;
/// Data parameter for the pixel format
typedef vlofgren::PODParameter<PixelFormat> PixelFormatParameter;
namespace vlofgren {
/// Translates a string (as passed on the commandline) to a pixel format
///
/// @param[in] s The string (as passed on the commandline)
/// @return The pixel format
/// @throws Parameter::ParameterRejected If the string did not result in a pixel format
template<>
PixelFormat PixelFormatParameter::validate(const std::string& s) throw (Parameter::ParameterRejected)
{
QString input = QString::fromStdString(s).toLower();
if (input == "yuyv")
{
return PIXELFORMAT_YUYV;
}
else if (input == "uyvy")
{
return PIXELFORMAT_UYVY;
}
else if (input == "rgb32")
{
return PIXELFORMAT_RGB32;
}
else if (input == "no-change")
{
return PIXELFORMAT_NO_CHANGE;
}
throw Parameter::ParameterRejected("Invalid value for pixel format. Valid values are: YUYV, UYVY, RGB32, and NO-CHANGE");
return PIXELFORMAT_NO_CHANGE;
}
}

View File

@ -18,6 +18,7 @@
// hyperion-v4l2 includes // hyperion-v4l2 includes
#include "ProtoConnection.h" #include "ProtoConnection.h"
#include "VideoStandardParameter.h" #include "VideoStandardParameter.h"
#include "PixelFormatParameter.h"
#include "ImageHandler.h" #include "ImageHandler.h"
#include "ScreenshotHandler.h" #include "ScreenshotHandler.h"
@ -50,6 +51,7 @@ int main(int argc, char** argv)
StringParameter & argDevice = parameters.add<StringParameter> ('d', "device", "The device to use [default=/dev/video0]"); StringParameter & argDevice = parameters.add<StringParameter> ('d', "device", "The device to use [default=/dev/video0]");
VideoStandardParameter & argVideoStandard = parameters.add<VideoStandardParameter>('v', "video-standard", "The used video standard. Valid values are PAL or NTSC (optional)"); VideoStandardParameter & argVideoStandard = parameters.add<VideoStandardParameter>('v', "video-standard", "The used video standard. Valid values are PAL or NTSC (optional)");
PixelFormatParameter & argPixelFormat = parameters.add<PixelFormatParameter> (0x0, "pixel-format", "The use pixel format. Valid values are YUYV, UYVY, and RGB32 (optional)");
IntParameter & argInput = parameters.add<IntParameter> (0x0, "input", "Input channel (optional)"); IntParameter & argInput = parameters.add<IntParameter> (0x0, "input", "Input channel (optional)");
IntParameter & argWidth = parameters.add<IntParameter> (0x0, "width", "Try to set the width of the video input (optional)"); IntParameter & argWidth = parameters.add<IntParameter> (0x0, "width", "Try to set the width of the video input (optional)");
IntParameter & argHeight = parameters.add<IntParameter> (0x0, "height", "Try to set the height of the video input (optional)"); IntParameter & argHeight = parameters.add<IntParameter> (0x0, "height", "Try to set the height of the video input (optional)");
@ -76,6 +78,7 @@ int main(int argc, char** argv)
// set defaults // set defaults
argDevice.setDefault("/dev/video0"); argDevice.setDefault("/dev/video0");
argVideoStandard.setDefault(VIDEOSTANDARD_NO_CHANGE); argVideoStandard.setDefault(VIDEOSTANDARD_NO_CHANGE);
argPixelFormat.setDefault(PIXELFORMAT_NO_CHANGE);
argInput.setDefault(-1); argInput.setDefault(-1);
argWidth.setDefault(-1); argWidth.setDefault(-1);
argHeight.setDefault(-1); argHeight.setDefault(-1);
@ -107,6 +110,7 @@ int main(int argc, char** argv)
argDevice.getValue(), argDevice.getValue(),
argInput.getValue(), argInput.getValue(),
argVideoStandard.getValue(), argVideoStandard.getValue(),
argPixelFormat.getValue(),
argWidth.getValue(), argWidth.getValue(),
argHeight.getValue(), argHeight.getValue(),
std::max(1, argFrameDecimation.getValue()), std::max(1, argFrameDecimation.getValue()),

View File

@ -180,6 +180,7 @@ int main(int argc, char** argv)
grabberConfig.get("device", "/dev/video0").asString(), grabberConfig.get("device", "/dev/video0").asString(),
grabberConfig.get("input", 0).asInt(), grabberConfig.get("input", 0).asInt(),
parseVideoStandard(grabberConfig.get("standard", "no-change").asString()), parseVideoStandard(grabberConfig.get("standard", "no-change").asString()),
parsePixelFormat(grabberConfig.get("pixelFormat", "no-change").asString()),
grabberConfig.get("width", -1).asInt(), grabberConfig.get("width", -1).asInt(),
grabberConfig.get("height", -1).asInt(), grabberConfig.get("height", -1).asInt(),
grabberConfig.get("frameDecimation", 2).asInt(), grabberConfig.get("frameDecimation", 2).asInt(),