mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2025-03-01 10:33:28 +00:00
Support NV12 format on Flatbuffer
This commit is contained in:
parent
27f74af4e3
commit
adfe039feb
@ -71,5 +71,7 @@ private:
|
|||||||
quint16 _port;
|
quint16 _port;
|
||||||
const QJsonDocument _config;
|
const QJsonDocument _config;
|
||||||
|
|
||||||
|
int _pixelDecimation;
|
||||||
|
|
||||||
QVector<FlatBufferClient*> _openConnections;
|
QVector<FlatBufferClient*> _openConnections;
|
||||||
};
|
};
|
||||||
|
@ -13,6 +13,7 @@ public:
|
|||||||
|
|
||||||
void setHorizontalPixelDecimation(int decimator) { _horizontalDecimation = decimator; }
|
void setHorizontalPixelDecimation(int decimator) { _horizontalDecimation = decimator; }
|
||||||
void setVerticalPixelDecimation(int decimator) { _verticalDecimation = decimator; }
|
void setVerticalPixelDecimation(int decimator) { _verticalDecimation = decimator; }
|
||||||
|
void setPixelDecimation(int decimator) { _horizontalDecimation = decimator; _verticalDecimation = decimator;}
|
||||||
void setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom);
|
void setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom);
|
||||||
void setVideoMode(VideoMode mode) { _videoMode = mode; }
|
void setVideoMode(VideoMode mode) { _videoMode = mode; }
|
||||||
void setFlipMode(FlipMode mode) { _flipMode = mode; }
|
void setFlipMode(FlipMode mode) { _flipMode = mode; }
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "FlatBufferClient.h"
|
#include "FlatBufferClient.h"
|
||||||
|
#include <utils/PixelFormat.h>
|
||||||
|
|
||||||
// qt
|
// qt
|
||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
@ -15,6 +16,8 @@ FlatBufferClient::FlatBufferClient(QTcpSocket* socket, int timeout, QObject *par
|
|||||||
, _timeout(timeout * 1000)
|
, _timeout(timeout * 1000)
|
||||||
, _priority()
|
, _priority()
|
||||||
{
|
{
|
||||||
|
_imageResampler.setPixelDecimation(1);
|
||||||
|
|
||||||
// timer setup
|
// timer setup
|
||||||
_timeoutTimer->setSingleShot(true);
|
_timeoutTimer->setSingleShot(true);
|
||||||
_timeoutTimer->setInterval(_timeout);
|
_timeoutTimer->setInterval(_timeout);
|
||||||
@ -25,6 +28,11 @@ FlatBufferClient::FlatBufferClient(QTcpSocket* socket, int timeout, QObject *par
|
|||||||
connect(_socket, &QTcpSocket::disconnected, this, &FlatBufferClient::disconnected);
|
connect(_socket, &QTcpSocket::disconnected, this, &FlatBufferClient::disconnected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FlatBufferClient::setPixelDecimation(int decimator)
|
||||||
|
{
|
||||||
|
_imageResampler.setPixelDecimation(decimator);
|
||||||
|
}
|
||||||
|
|
||||||
void FlatBufferClient::readyRead()
|
void FlatBufferClient::readyRead()
|
||||||
{
|
{
|
||||||
_timeoutTimer->start();
|
_timeoutTimer->start();
|
||||||
@ -141,55 +149,71 @@ void FlatBufferClient::handleRegisterCommand(const hyperionnet::Register *regReq
|
|||||||
|
|
||||||
void FlatBufferClient::handleImageCommand(const hyperionnet::Image *image)
|
void FlatBufferClient::handleImageCommand(const hyperionnet::Image *image)
|
||||||
{
|
{
|
||||||
|
Image<ColorRgb> imageRGB;
|
||||||
|
|
||||||
// extract parameters
|
// extract parameters
|
||||||
int duration = image->duration();
|
int duration = image->duration();
|
||||||
|
|
||||||
const void* reqPtr;
|
const void* reqPtr;
|
||||||
if ((reqPtr = image->data_as_RawImage()) != nullptr)
|
if ((reqPtr = image->data_as_RawImage()) != nullptr)
|
||||||
{
|
{
|
||||||
const auto *img = static_cast<const hyperionnet::RawImage*>(reqPtr);
|
const auto* img = static_cast<const hyperionnet::RawImage*>(reqPtr);
|
||||||
const auto & imageData = img->data();
|
|
||||||
const int width = img->width();
|
|
||||||
const int height = img->height();
|
|
||||||
|
|
||||||
if (width <= 0 || height <= 0)
|
hyperionnet::RawImageT rawImageNative;
|
||||||
|
img->UnPackTo(&rawImageNative);
|
||||||
|
|
||||||
|
const int width = rawImageNative.width;
|
||||||
|
const int height = rawImageNative.height;
|
||||||
|
|
||||||
|
if (width <= 0 || height <= 0 || rawImageNative.data.empty())
|
||||||
{
|
{
|
||||||
sendErrorReply("Size of image data does not match with the width and height");
|
sendErrorReply("Invalid width and/or height or no raw image data provided");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check consistency of the size of the received data
|
// check consistency of the size of the received data
|
||||||
int channelCount = (int)imageData->size()/(width*height);
|
int bytesPerPixel = rawImageNative.data.size() / (width * height);
|
||||||
if (channelCount != 3 && channelCount != 4)
|
if (bytesPerPixel != 3 && bytesPerPixel != 4)
|
||||||
{
|
{
|
||||||
sendErrorReply("Size of image data does not match with the width and height");
|
sendErrorReply("Size of image data does not match with the width and height");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create ImageRgb
|
imageRGB.resize(width, height);
|
||||||
Image<ColorRgb> imageRGB(width, height);
|
processRawImage(rawImageNative, bytesPerPixel, _imageResampler, imageRGB);
|
||||||
if (channelCount == 3)
|
|
||||||
{
|
|
||||||
memmove(imageRGB.memptr(), imageData->data(), imageData->size());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (channelCount == 4)
|
|
||||||
{
|
|
||||||
for (int source=0, destination=0; source < width * height * static_cast<int>(sizeof(ColorRgb)); source+=sizeof(ColorRgb), destination+=sizeof(ColorRgba))
|
|
||||||
{
|
|
||||||
memmove((uint8_t*)imageRGB.memptr() + source, imageData->data() + destination, sizeof(ColorRgb));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
emit setGlobalInputImage(_priority, imageRGB, duration);
|
|
||||||
emit setBufferImage("FlatBuffer", imageRGB);
|
|
||||||
}
|
}
|
||||||
|
else if ((reqPtr = image->data_as_NV12Image()) != nullptr)
|
||||||
|
{
|
||||||
|
const auto* img = static_cast<const hyperionnet::NV12Image*>(reqPtr);
|
||||||
|
|
||||||
|
hyperionnet::NV12ImageT nv12ImageNative;
|
||||||
|
img->UnPackTo(&nv12ImageNative);
|
||||||
|
|
||||||
|
const int width = nv12ImageNative.width;
|
||||||
|
const int height = nv12ImageNative.height;
|
||||||
|
|
||||||
|
if (width <= 0 || height <= 0 || nv12ImageNative.data_y.empty() || nv12ImageNative.data_uv.empty())
|
||||||
|
{
|
||||||
|
sendErrorReply("Invalid width and/or height or no complete NV12 image data provided");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
imageRGB.resize(width, height);
|
||||||
|
processNV12Image(nv12ImageNative, _imageResampler, imageRGB);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sendErrorReply("No or unknown image data provided");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit setGlobalInputImage(_priority, imageRGB, duration);
|
||||||
|
emit setBufferImage("FlatBuffer", imageRGB);
|
||||||
|
|
||||||
// send reply
|
// send reply
|
||||||
sendSuccessReply();
|
sendSuccessReply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FlatBufferClient::handleClearCommand(const hyperionnet::Clear *clear)
|
void FlatBufferClient::handleClearCommand(const hyperionnet::Clear *clear)
|
||||||
{
|
{
|
||||||
// extract parameters
|
// extract parameters
|
||||||
@ -242,3 +266,50 @@ void FlatBufferClient::sendErrorReply(const std::string &error)
|
|||||||
|
|
||||||
_builder.Clear();
|
_builder.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void FlatBufferClient::processRawImage(const hyperionnet::RawImageT& raw_image, int bytesPerPixel, ImageResampler& resampler, Image<ColorRgb>& outputImage) {
|
||||||
|
|
||||||
|
int width = raw_image.width;
|
||||||
|
int height = raw_image.height;
|
||||||
|
|
||||||
|
int lineLength = width * bytesPerPixel;
|
||||||
|
PixelFormat pixelFormat = (bytesPerPixel == 4) ? PixelFormat::RGB32 : PixelFormat::RGB24;
|
||||||
|
|
||||||
|
// Process the image
|
||||||
|
resampler.processImage(
|
||||||
|
raw_image.data.data(), // Raw RGB/RGBA buffer
|
||||||
|
width, // Image width
|
||||||
|
height, // Image height
|
||||||
|
lineLength, // Line length
|
||||||
|
pixelFormat, // Pixel format (RGB24/RGB32)
|
||||||
|
outputImage // Output image
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void FlatBufferClient::processNV12Image(const hyperionnet::NV12ImageT& nv12_image, ImageResampler& resampler, Image<ColorRgb>& outputImage) {
|
||||||
|
// Combine data_y and data_uv into a single buffer
|
||||||
|
int width = nv12_image.width;
|
||||||
|
int height = nv12_image.height;
|
||||||
|
|
||||||
|
size_t y_size = nv12_image.data_y.size();
|
||||||
|
size_t uv_size = nv12_image.data_uv.size();
|
||||||
|
std::vector<uint8_t> combined_buffer(y_size + uv_size);
|
||||||
|
|
||||||
|
std::memcpy(combined_buffer.data(), nv12_image.data_y.data(), y_size);
|
||||||
|
std::memcpy(combined_buffer.data() + y_size, nv12_image.data_uv.data(), uv_size);
|
||||||
|
|
||||||
|
// Determine line length (stride_y)
|
||||||
|
int lineLength = nv12_image.stride_y > 0 ? nv12_image.stride_y : width;
|
||||||
|
|
||||||
|
PixelFormat pixelFormat = PixelFormat::NV12;
|
||||||
|
|
||||||
|
// Process the image
|
||||||
|
resampler.processImage(
|
||||||
|
combined_buffer.data(), // Combined NV12 buffer
|
||||||
|
width, // Image width
|
||||||
|
height, // Image height
|
||||||
|
lineLength, // Line length for Y plane
|
||||||
|
pixelFormat, // Pixel format (NV12)
|
||||||
|
outputImage // Output image
|
||||||
|
);
|
||||||
|
}
|
@ -6,6 +6,7 @@
|
|||||||
#include <utils/ColorRgb.h>
|
#include <utils/ColorRgb.h>
|
||||||
#include <utils/ColorRgba.h>
|
#include <utils/ColorRgba.h>
|
||||||
#include <utils/Components.h>
|
#include <utils/Components.h>
|
||||||
|
#include "utils/ImageResampler.h"
|
||||||
|
|
||||||
// flatbuffer FBS
|
// flatbuffer FBS
|
||||||
#include "hyperion_reply_generated.h"
|
#include "hyperion_reply_generated.h"
|
||||||
@ -33,6 +34,8 @@ public:
|
|||||||
///
|
///
|
||||||
explicit FlatBufferClient(QTcpSocket* socket, int timeout, QObject *parent = nullptr);
|
explicit FlatBufferClient(QTcpSocket* socket, int timeout, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
void setPixelDecimation(int decimator);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
///
|
///
|
||||||
/// @brief forward register data to HyperionDaemon
|
/// @brief forward register data to HyperionDaemon
|
||||||
@ -138,6 +141,9 @@ private:
|
|||||||
///
|
///
|
||||||
void sendErrorReply(const std::string & error);
|
void sendErrorReply(const std::string & error);
|
||||||
|
|
||||||
|
void processRawImage(const hyperionnet::RawImageT& raw_image, int bytesPerPixel, ImageResampler& resampler, Image<ColorRgb>& outputImage);
|
||||||
|
void processNV12Image(const hyperionnet::NV12ImageT& nv12_image, ImageResampler& resampler, Image<ColorRgb>& outputImage);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Logger *_log;
|
Logger *_log;
|
||||||
QTcpSocket *_socket;
|
QTcpSocket *_socket;
|
||||||
@ -148,6 +154,8 @@ private:
|
|||||||
|
|
||||||
QByteArray _receiveBuffer;
|
QByteArray _receiveBuffer;
|
||||||
|
|
||||||
|
ImageResampler _imageResampler;
|
||||||
|
|
||||||
// Flatbuffers builder
|
// Flatbuffers builder
|
||||||
flatbuffers::FlatBufferBuilder _builder;
|
flatbuffers::FlatBufferBuilder _builder;
|
||||||
};
|
};
|
||||||
|
@ -62,6 +62,12 @@ void FlatBufferServer::handleSettingsUpdate(settings::type type, const QJsonDocu
|
|||||||
_timeout = obj["timeout"].toInt(5000);
|
_timeout = obj["timeout"].toInt(5000);
|
||||||
// enable check
|
// enable check
|
||||||
obj["enable"].toBool(true) ? startServer() : stopServer();
|
obj["enable"].toBool(true) ? startServer() : stopServer();
|
||||||
|
|
||||||
|
_pixelDecimation = obj["pixelDecimation"].toInt(1);
|
||||||
|
for (const auto& client : _openConnections)
|
||||||
|
{
|
||||||
|
client->setPixelDecimation(_pixelDecimation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,6 +81,9 @@ void FlatBufferServer::newConnection()
|
|||||||
{
|
{
|
||||||
Debug(_log, "New connection from %s", QSTRING_CSTR(socket->peerAddress().toString()));
|
Debug(_log, "New connection from %s", QSTRING_CSTR(socket->peerAddress().toString()));
|
||||||
FlatBufferClient *client = new FlatBufferClient(socket, _timeout, this);
|
FlatBufferClient *client = new FlatBufferClient(socket, _timeout, this);
|
||||||
|
|
||||||
|
client->setPixelDecimation(_pixelDecimation);
|
||||||
|
|
||||||
// internal
|
// internal
|
||||||
connect(client, &FlatBufferClient::clientDisconnected, this, &FlatBufferServer::clientDisconnected);
|
connect(client, &FlatBufferClient::clientDisconnected, this, &FlatBufferServer::clientDisconnected);
|
||||||
connect(client, &FlatBufferClient::registerGlobalInput, GlobalSignals::getInstance(), &GlobalSignals::registerGlobalInput);
|
connect(client, &FlatBufferClient::registerGlobalInput, GlobalSignals::getInstance(), &GlobalSignals::registerGlobalInput);
|
||||||
|
@ -12,9 +12,17 @@ table RawImage {
|
|||||||
height:int = -1;
|
height:int = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
union ImageType {RawImage}
|
table NV12Image {
|
||||||
|
data_y:[ubyte];
|
||||||
|
data_uv:[ubyte];
|
||||||
|
width:int;
|
||||||
|
height:int;
|
||||||
|
stride_y:int = 0;
|
||||||
|
stride_uv:int = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
union ImageType {RawImage, NV12Image}
|
||||||
|
|
||||||
// Either RGB or RGBA data can be transferred
|
|
||||||
table Image {
|
table Image {
|
||||||
data:ImageType (required);
|
data:ImageType (required);
|
||||||
duration:int = -1;
|
duration:int = -1;
|
||||||
|
@ -1,35 +1,41 @@
|
|||||||
{
|
{
|
||||||
"type" : "object",
|
"type" : "object",
|
||||||
"title" : "edt_conf_fbs_heading_title",
|
"title" : "edt_conf_fbs_heading_title",
|
||||||
"properties" :
|
"properties": {
|
||||||
{
|
"enable": {
|
||||||
"enable" :
|
"type": "boolean",
|
||||||
{
|
"required": true,
|
||||||
"type" : "boolean",
|
"title": "edt_conf_general_enable_title",
|
||||||
"required" : true,
|
"default": true,
|
||||||
"title" : "edt_conf_general_enable_title",
|
"propertyOrder": 1
|
||||||
"default" : true,
|
|
||||||
"propertyOrder" : 1
|
|
||||||
},
|
},
|
||||||
"port" :
|
"port": {
|
||||||
{
|
"type": "integer",
|
||||||
"type" : "integer",
|
"required": true,
|
||||||
"required" : true,
|
"title": "edt_conf_general_port_title",
|
||||||
"title" : "edt_conf_general_port_title",
|
"minimum": 1024,
|
||||||
"minimum" : 1024,
|
"maximum": 65535,
|
||||||
"maximum" : 65535,
|
"default": 19400,
|
||||||
"default" : 19400,
|
"propertyOrder": 2
|
||||||
"propertyOrder" : 2
|
|
||||||
},
|
},
|
||||||
"timeout" :
|
"timeout": {
|
||||||
{
|
"type": "integer",
|
||||||
"type" : "integer",
|
"required": true,
|
||||||
"required" : true,
|
"title": "edt_conf_fbs_timeout_title",
|
||||||
"title" : "edt_conf_fbs_timeout_title",
|
"append": "edt_append_s",
|
||||||
"append" : "edt_append_s",
|
"minimum": 1,
|
||||||
"minimum" : 1,
|
"default": 5,
|
||||||
"default" : 5,
|
"propertyOrder": 3
|
||||||
"propertyOrder" : 3
|
},
|
||||||
|
"pixelDecimation": {
|
||||||
|
"type": "integer",
|
||||||
|
"title": "edt_conf_fg_pixelDecimation_title",
|
||||||
|
"minimum": 1,
|
||||||
|
"maximum": 30,
|
||||||
|
"default": 1,
|
||||||
|
"required": false,
|
||||||
|
"access": "advanced",
|
||||||
|
"propertyOrder": 4
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties" : false
|
"additionalProperties" : false
|
||||||
|
Loading…
x
Reference in New Issue
Block a user