Skip to content

Commit

Permalink
Add support for "unicam image" RPi HDMI capture card and UYVY format
Browse files Browse the repository at this point in the history
  • Loading branch information
awawa-dev committed Nov 24, 2024
1 parent cfefbc5 commit 1b2573c
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 9 deletions.
9 changes: 9 additions & 0 deletions include/utils/PixelFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

enum class PixelFormat {
YUYV,
UYVY,
RGB24,
XRGB,
I420,
Expand All @@ -23,6 +24,10 @@ inline PixelFormat parsePixelFormat(const QString& pixelFormat)
{
return PixelFormat::YUYV;
}
else if (format.compare("uyvy") == 0)
{
return PixelFormat::UYVY;
}
else if (format.compare("rgb24") == 0)
{
return PixelFormat::RGB24;
Expand Down Expand Up @@ -58,6 +63,10 @@ inline QString pixelFormatToString(const PixelFormat& pixelFormat)
{
return "yuyv";
}
else if (pixelFormat == PixelFormat::UYVY)
{
return "uyvy";
}
else if (pixelFormat == PixelFormat::RGB24)
{
return "rgb24";
Expand Down
50 changes: 45 additions & 5 deletions sources/grabber/linux/v4l2/V4L2Grabber.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,13 @@ namespace
static const V4L2Grabber::HyperHdrFormat supportedFormats[] =
{
{ V4L2_PIX_FMT_YUYV, PixelFormat::YUYV },
{ V4L2_PIX_FMT_UYVY, PixelFormat::UYVY },
{ V4L2_PIX_FMT_XRGB32, PixelFormat::XRGB },
{ V4L2_PIX_FMT_RGB24, PixelFormat::RGB24 },
{ V4L2_PIX_FMT_YUV420, PixelFormat::I420 },
{ V4L2_PIX_FMT_NV12, PixelFormat::NV12 },
{ V4L2_PIX_FMT_MJPEG, PixelFormat::MJPEG },
{ V4L2_PIX_FMT_P010, PixelFormat::P010 }
{ V4L2_PIX_FMT_P010, PixelFormat::P010 }
};


Expand Down Expand Up @@ -147,7 +148,7 @@ void V4L2Grabber::setHdrToneMappingEnabled(int mode)
{
Debug(_log, "setHdrToneMappingMode replacing LUT and restarting");
_V4L2WorkerManager.Stop();
if ((_actualVideoFormat == PixelFormat::YUYV) || (_actualVideoFormat == PixelFormat::I420) || (_actualVideoFormat == PixelFormat::NV12)
if ((_actualVideoFormat == PixelFormat::YUYV) || (_actualVideoFormat == PixelFormat::UYVY) || (_actualVideoFormat == PixelFormat::I420) || (_actualVideoFormat == PixelFormat::NV12)
|| (_actualVideoFormat == PixelFormat::P010) || (_actualVideoFormat == PixelFormat::MJPEG))
loadLutFile(PixelFormat::YUYV);
else
Expand Down Expand Up @@ -577,6 +578,28 @@ void V4L2Grabber::enumerateV4L2devices(bool silent)
}
}

if (properties.valid.size() == 0 && devName == "/dev/video0")
{
DevicePropertiesItem di;
di.x = fmt.fmt.pix.width;
di.y = fmt.fmt.pix.height;
di.fps = 0;
di.pf = identifyFormat(fmt.fmt.pix.pixelformat);
di.v4l2PixelFormat = fmt.fmt.pix.pixelformat;
di.input = inputIndex;

QString pixelFormat = pixelFormatToString(di.pf);
if (di.pf == PixelFormat::NO_CHANGE)
{
Debug(_log, "%s %d x %d @ %d fps %s (unsupported)", QSTRING_CSTR(properties.name), di.x, di.y, di.fps, QSTRING_CSTR(pixelFormat));
}
else
{
Debug(_log, "%s %d x %d @ %d fps %s, input = %i (seems supported, device not fully compatible with v4l2 grabber model, frame rate is unknown)", QSTRING_CSTR(properties.name), di.x, di.y, di.fps, QSTRING_CSTR(pixelFormat), di.input);
properties.valid.append(di);
}
}

_deviceProperties.insert(realName, properties);

if (!silent)
Expand Down Expand Up @@ -904,7 +927,7 @@ bool V4L2Grabber::init_device(QString selectedDeviceName, DevicePropertiesItem p

streamparms.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
// Check that the driver knows about framerate get/set
if (xioctl(VIDIOC_G_PARM, &streamparms) >= 0)
if (props.fps > 0 && xioctl(VIDIOC_G_PARM, &streamparms) >= 0)
{
// Check if the device is able to accept a capture framerate set.
if (streamparms.parm.capture.capability == V4L2_CAP_TIMEPERFRAME)
Expand All @@ -918,6 +941,13 @@ bool V4L2Grabber::init_device(QString selectedDeviceName, DevicePropertiesItem p
Info(_log, "Set framerate to %d FPS", streamparms.parm.capture.timeperframe.denominator);
}
}
else
{
if (props.fps == 0)
Warning(_log, "The device doesnt report frame rate settings");
else
Error(_log, "The device doesnt support VIDIOC_G_PARM for frame rate settings");
}

// set the line length
_lineLength = fmt.fmt.pix.bytesperline;
Expand Down Expand Up @@ -974,6 +1004,15 @@ bool V4L2Grabber::init_device(QString selectedDeviceName, DevicePropertiesItem p
}
break;

case V4L2_PIX_FMT_UYVY:
{
loadLutFile(PixelFormat::YUYV);
_actualVideoFormat = PixelFormat::UYVY;
_frameByteSize = props.x * props.y * 2;
Info(_log, "Video pixel format is set to: UYVY");
}
break;

case V4L2_PIX_FMT_XRGB32:
{
loadLutFile(PixelFormat::RGB24);
Expand Down Expand Up @@ -1209,10 +1248,11 @@ bool V4L2Grabber::process_image(v4l2_buffer* buf, const void* frameImageBuffer,
{
V4L2Worker* _workerThread = _V4L2WorkerManager.workers[i];

if ((_actualVideoFormat == PixelFormat::YUYV || _actualVideoFormat == PixelFormat::I420 ||
if ((_actualVideoFormat == PixelFormat::YUYV || _actualVideoFormat == PixelFormat::UYVY || _actualVideoFormat == PixelFormat::I420 ||
_actualVideoFormat == PixelFormat::NV12 || _hdrToneMappingEnabled) && !_lutBufferInit)
{
if ((_actualVideoFormat == PixelFormat::YUYV) || (_actualVideoFormat == PixelFormat::I420) || (_actualVideoFormat == PixelFormat::NV12) || (_actualVideoFormat == PixelFormat::MJPEG))
if ((_actualVideoFormat == PixelFormat::YUYV) || (_actualVideoFormat == PixelFormat::UYVY) || (_actualVideoFormat == PixelFormat::I420) ||
(_actualVideoFormat == PixelFormat::NV12) || (_actualVideoFormat == PixelFormat::MJPEG))
{
loadLutFile(PixelFormat::YUYV, true);
}
Expand Down
53 changes: 49 additions & 4 deletions sources/utils/FrameDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ void FrameDecoder::processImage(
uint8_t buffer[8];

// validate format
if (pixelFormat != PixelFormat::YUYV &&
if (pixelFormat != PixelFormat::YUYV && pixelFormat != PixelFormat::UYVY &&
pixelFormat != PixelFormat::XRGB && pixelFormat != PixelFormat::RGB24 &&
pixelFormat != PixelFormat::I420 && pixelFormat != PixelFormat::NV12 && pixelFormat != PixelFormat::P010 && pixelFormat != PixelFormat::MJPEG)
{
Expand All @@ -200,7 +200,7 @@ void FrameDecoder::processImage(
}

// validate format LUT
if ((pixelFormat == PixelFormat::YUYV || pixelFormat == PixelFormat::I420 || pixelFormat == PixelFormat::MJPEG ||
if ((pixelFormat == PixelFormat::YUYV || pixelFormat == PixelFormat::UYVY || pixelFormat == PixelFormat::I420 || pixelFormat == PixelFormat::MJPEG ||
pixelFormat == PixelFormat::NV12 || pixelFormat == PixelFormat::P010) && lutBuffer == NULL)
{
Error(Logger::getInstance("FrameDecoder"), "Missing LUT table for YUV colorspace");
Expand Down Expand Up @@ -248,6 +248,30 @@ void FrameDecoder::processImage(
return;
}

if (pixelFormat == PixelFormat::UYVY)
{
for (int yDest = 0, ySource = _cropTop; yDest < outputHeight; ++ySource, ++yDest)
{
uint8_t* currentDest = destMemory + ((uint64_t)destLineSize) * yDest;
uint8_t* endDest = currentDest + destLineSize;
uint8_t* currentSource = (uint8_t*)data + (((uint64_t)lineLength * ySource) + (((uint64_t)_cropLeft) << 1));

while (currentDest < endDest)
{
*((uint32_t*)&buffer) = *((uint32_t*)currentSource);

ind_lutd = LUT_INDEX(buffer[1], buffer[0], buffer[2]);
ind_lutd2 = LUT_INDEX(buffer[3], buffer[0], buffer[2]);

*((uint32_t*)currentDest) = *((uint32_t*)(&lutBuffer[ind_lutd]));
currentDest += 3;
*((uint32_t*)currentDest) = *((uint32_t*)(&lutBuffer[ind_lutd2]));
currentDest += 3;
currentSource += 4;
}
}
return;
}

if (pixelFormat == PixelFormat::RGB24)
{
Expand Down Expand Up @@ -474,7 +498,7 @@ void FrameDecoder::processQImage(
uint8_t buffer[8];

// validate format
if (pixelFormat != PixelFormat::YUYV &&
if (pixelFormat != PixelFormat::YUYV && pixelFormat != PixelFormat::UYVY &&
pixelFormat != PixelFormat::XRGB && pixelFormat != PixelFormat::RGB24 &&
pixelFormat != PixelFormat::I420 && pixelFormat != PixelFormat::NV12 && pixelFormat != PixelFormat::P010)
{
Expand All @@ -483,7 +507,7 @@ void FrameDecoder::processQImage(
}

// validate format LUT
if ((pixelFormat == PixelFormat::YUYV || pixelFormat == PixelFormat::I420 ||
if ((pixelFormat == PixelFormat::YUYV || pixelFormat == PixelFormat::UYVY || pixelFormat == PixelFormat::I420 ||
pixelFormat == PixelFormat::NV12 || pixelFormat == PixelFormat::P010) && lutBuffer == NULL)
{
Error(Logger::getInstance("FrameDecoder"), "Missing LUT table for YUV colorspace");
Expand Down Expand Up @@ -522,6 +546,27 @@ void FrameDecoder::processQImage(
return;
}

if (pixelFormat == PixelFormat::UYVY)
{
for (int yDest = 0, ySource = 0; yDest < outputHeight; ySource += 2, ++yDest)
{
uint8_t* currentDest = destMemory + ((uint64_t)destLineSize) * yDest;
uint8_t* endDest = currentDest + destLineSize;
uint8_t* currentSource = (uint8_t*)data + (((uint64_t)lineLength * ySource));

while (currentDest < endDest)
{
*((uint32_t*)&buffer) = *((uint32_t*)currentSource);

ind_lutd = LUT_INDEX(buffer[1], buffer[0], buffer[2]);

*((uint32_t*)currentDest) = *((uint32_t*)(&lutBuffer[ind_lutd]));
currentDest += 3;
currentSource += 4;
}
}
return;
}

if (pixelFormat == PixelFormat::RGB24)
{
Expand Down

0 comments on commit 1b2573c

Please sign in to comment.