Skip to content

Commit 6e3357e

Browse files
authored
Support NV12 format on Flatbuffer (#1806)
1 parent bc1bfbc commit 6e3357e

File tree

7 files changed

+157
-52
lines changed

7 files changed

+157
-52
lines changed

include/flatbufserver/FlatBufferServer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,5 +71,7 @@ private slots:
7171
quint16 _port;
7272
const QJsonDocument _config;
7373

74+
int _pixelDecimation;
75+
7476
QVector<FlatBufferClient*> _openConnections;
7577
};

include/utils/ImageResampler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class ImageResampler
1313

1414
void setHorizontalPixelDecimation(int decimator) { _horizontalDecimation = decimator; }
1515
void setVerticalPixelDecimation(int decimator) { _verticalDecimation = decimator; }
16+
void setPixelDecimation(int decimator) { _horizontalDecimation = decimator; _verticalDecimation = decimator;}
1617
void setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom);
1718
void setVideoMode(VideoMode mode) { _videoMode = mode; }
1819
void setFlipMode(FlipMode mode) { _flipMode = mode; }

libsrc/flatbufserver/FlatBufferClient.cpp

Lines changed: 94 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "FlatBufferClient.h"
2+
#include <utils/PixelFormat.h>
23

34
// qt
45
#include <QTcpSocket>
@@ -15,6 +16,8 @@ FlatBufferClient::FlatBufferClient(QTcpSocket* socket, int timeout, QObject *par
1516
, _timeout(timeout * 1000)
1617
, _priority()
1718
{
19+
_imageResampler.setPixelDecimation(1);
20+
1821
// timer setup
1922
_timeoutTimer->setSingleShot(true);
2023
_timeoutTimer->setInterval(_timeout);
@@ -25,6 +28,11 @@ FlatBufferClient::FlatBufferClient(QTcpSocket* socket, int timeout, QObject *par
2528
connect(_socket, &QTcpSocket::disconnected, this, &FlatBufferClient::disconnected);
2629
}
2730

31+
void FlatBufferClient::setPixelDecimation(int decimator)
32+
{
33+
_imageResampler.setPixelDecimation(decimator);
34+
}
35+
2836
void FlatBufferClient::readyRead()
2937
{
3038
_timeoutTimer->start();
@@ -141,55 +149,71 @@ void FlatBufferClient::handleRegisterCommand(const hyperionnet::Register *regReq
141149

142150
void FlatBufferClient::handleImageCommand(const hyperionnet::Image *image)
143151
{
152+
Image<ColorRgb> imageRGB;
153+
144154
// extract parameters
145155
int duration = image->duration();
146-
147156
const void* reqPtr;
148157
if ((reqPtr = image->data_as_RawImage()) != nullptr)
149158
{
150-
const auto *img = static_cast<const hyperionnet::RawImage*>(reqPtr);
151-
const auto & imageData = img->data();
152-
const int width = img->width();
153-
const int height = img->height();
159+
const auto* img = static_cast<const hyperionnet::RawImage*>(reqPtr);
160+
161+
hyperionnet::RawImageT rawImageNative;
162+
img->UnPackTo(&rawImageNative);
154163

155-
if (width <= 0 || height <= 0)
164+
const int width = rawImageNative.width;
165+
const int height = rawImageNative.height;
166+
167+
if (width <= 0 || height <= 0 || rawImageNative.data.empty())
156168
{
157-
sendErrorReply("Size of image data does not match with the width and height");
169+
sendErrorReply("Invalid width and/or height or no raw image data provided");
158170
return;
159171
}
160172

161173
// check consistency of the size of the received data
162-
int channelCount = (int)imageData->size()/(width*height);
163-
if (channelCount != 3 && channelCount != 4)
174+
int bytesPerPixel = rawImageNative.data.size() / (width * height);
175+
if (bytesPerPixel != 3 && bytesPerPixel != 4)
164176
{
165177
sendErrorReply("Size of image data does not match with the width and height");
166178
return;
167179
}
168180

169-
// create ImageRgb
170-
Image<ColorRgb> imageRGB(width, height);
171-
if (channelCount == 3)
172-
{
173-
memmove(imageRGB.memptr(), imageData->data(), imageData->size());
174-
}
181+
imageRGB.resize(width, height);
182+
processRawImage(rawImageNative, bytesPerPixel, _imageResampler, imageRGB);
183+
}
184+
else if ((reqPtr = image->data_as_NV12Image()) != nullptr)
185+
{
186+
const auto* img = static_cast<const hyperionnet::NV12Image*>(reqPtr);
175187

176-
if (channelCount == 4)
188+
hyperionnet::NV12ImageT nv12ImageNative;
189+
img->UnPackTo(&nv12ImageNative);
190+
191+
const int width = nv12ImageNative.width;
192+
const int height = nv12ImageNative.height;
193+
194+
if (width <= 0 || height <= 0 || nv12ImageNative.data_y.empty() || nv12ImageNative.data_uv.empty())
177195
{
178-
for (int source=0, destination=0; source < width * height * static_cast<int>(sizeof(ColorRgb)); source+=sizeof(ColorRgb), destination+=sizeof(ColorRgba))
179-
{
180-
memmove((uint8_t*)imageRGB.memptr() + source, imageData->data() + destination, sizeof(ColorRgb));
181-
}
196+
sendErrorReply("Invalid width and/or height or no complete NV12 image data provided");
197+
return;
182198
}
183199

184-
emit setGlobalInputImage(_priority, imageRGB, duration);
185-
emit setBufferImage("FlatBuffer", imageRGB);
200+
imageRGB.resize(width, height);
201+
processNV12Image(nv12ImageNative, _imageResampler, imageRGB);
202+
203+
}
204+
else
205+
{
206+
sendErrorReply("No or unknown image data provided");
207+
return;
186208
}
187209

210+
emit setGlobalInputImage(_priority, imageRGB, duration);
211+
emit setBufferImage("FlatBuffer", imageRGB);
212+
188213
// send reply
189214
sendSuccessReply();
190215
}
191216

192-
193217
void FlatBufferClient::handleClearCommand(const hyperionnet::Clear *clear)
194218
{
195219
// extract parameters
@@ -242,3 +266,50 @@ void FlatBufferClient::sendErrorReply(const std::string &error)
242266

243267
_builder.Clear();
244268
}
269+
270+
inline void FlatBufferClient::processRawImage(const hyperionnet::RawImageT& raw_image, int bytesPerPixel, ImageResampler& resampler, Image<ColorRgb>& outputImage) {
271+
272+
int width = raw_image.width;
273+
int height = raw_image.height;
274+
275+
int lineLength = width * bytesPerPixel;
276+
PixelFormat pixelFormat = (bytesPerPixel == 4) ? PixelFormat::RGB32 : PixelFormat::RGB24;
277+
278+
// Process the image
279+
resampler.processImage(
280+
raw_image.data.data(), // Raw RGB/RGBA buffer
281+
width, // Image width
282+
height, // Image height
283+
lineLength, // Line length
284+
pixelFormat, // Pixel format (RGB24/RGB32)
285+
outputImage // Output image
286+
);
287+
}
288+
289+
inline void FlatBufferClient::processNV12Image(const hyperionnet::NV12ImageT& nv12_image, ImageResampler& resampler, Image<ColorRgb>& outputImage) {
290+
// Combine data_y and data_uv into a single buffer
291+
int width = nv12_image.width;
292+
int height = nv12_image.height;
293+
294+
size_t y_size = nv12_image.data_y.size();
295+
size_t uv_size = nv12_image.data_uv.size();
296+
std::vector<uint8_t> combined_buffer(y_size + uv_size);
297+
298+
std::memcpy(combined_buffer.data(), nv12_image.data_y.data(), y_size);
299+
std::memcpy(combined_buffer.data() + y_size, nv12_image.data_uv.data(), uv_size);
300+
301+
// Determine line length (stride_y)
302+
int lineLength = nv12_image.stride_y > 0 ? nv12_image.stride_y : width;
303+
304+
PixelFormat pixelFormat = PixelFormat::NV12;
305+
306+
// Process the image
307+
resampler.processImage(
308+
combined_buffer.data(), // Combined NV12 buffer
309+
width, // Image width
310+
height, // Image height
311+
lineLength, // Line length for Y plane
312+
pixelFormat, // Pixel format (NV12)
313+
outputImage // Output image
314+
);
315+
}

libsrc/flatbufserver/FlatBufferClient.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <utils/ColorRgb.h>
77
#include <utils/ColorRgba.h>
88
#include <utils/Components.h>
9+
#include "utils/ImageResampler.h"
910

1011
// flatbuffer FBS
1112
#include "hyperion_reply_generated.h"
@@ -33,6 +34,8 @@ class FlatBufferClient : public QObject
3334
///
3435
explicit FlatBufferClient(QTcpSocket* socket, int timeout, QObject *parent = nullptr);
3536

37+
void setPixelDecimation(int decimator);
38+
3639
signals:
3740
///
3841
/// @brief forward register data to HyperionDaemon
@@ -138,6 +141,9 @@ private slots:
138141
///
139142
void sendErrorReply(const std::string & error);
140143

144+
void processRawImage(const hyperionnet::RawImageT& raw_image, int bytesPerPixel, ImageResampler& resampler, Image<ColorRgb>& outputImage);
145+
void processNV12Image(const hyperionnet::NV12ImageT& nv12_image, ImageResampler& resampler, Image<ColorRgb>& outputImage);
146+
141147
private:
142148
Logger *_log;
143149
QTcpSocket *_socket;
@@ -148,6 +154,8 @@ private slots:
148154

149155
QByteArray _receiveBuffer;
150156

157+
ImageResampler _imageResampler;
158+
151159
// Flatbuffers builder
152160
flatbuffers::FlatBufferBuilder _builder;
153161
};

libsrc/flatbufserver/FlatBufferServer.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ void FlatBufferServer::handleSettingsUpdate(settings::type type, const QJsonDocu
6262
_timeout = obj["timeout"].toInt(5000);
6363
// enable check
6464
obj["enable"].toBool(true) ? startServer() : stopServer();
65+
66+
_pixelDecimation = obj["pixelDecimation"].toInt(1);
67+
for (const auto& client : _openConnections)
68+
{
69+
client->setPixelDecimation(_pixelDecimation);
70+
}
6571
}
6672
}
6773

@@ -75,6 +81,9 @@ void FlatBufferServer::newConnection()
7581
{
7682
Debug(_log, "New connection from %s", QSTRING_CSTR(socket->peerAddress().toString()));
7783
FlatBufferClient *client = new FlatBufferClient(socket, _timeout, this);
84+
85+
client->setPixelDecimation(_pixelDecimation);
86+
7887
// internal
7988
connect(client, &FlatBufferClient::clientDisconnected, this, &FlatBufferServer::clientDisconnected);
8089
connect(client, &FlatBufferClient::registerGlobalInput, GlobalSignals::getInstance(), &GlobalSignals::registerGlobalInput);

libsrc/flatbufserver/hyperion_request.fbs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,17 @@ table RawImage {
1212
height:int = -1;
1313
}
1414

15-
union ImageType {RawImage}
15+
table NV12Image {
16+
data_y:[ubyte];
17+
data_uv:[ubyte];
18+
width:int;
19+
height:int;
20+
stride_y:int = 0;
21+
stride_uv:int = 0;
22+
}
23+
24+
union ImageType {RawImage, NV12Image}
1625

17-
// Either RGB or RGBA data can be transferred
1826
table Image {
1927
data:ImageType (required);
2028
duration:int = -1;

libsrc/hyperion/schema/schema-flatbufServer.json

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,41 @@
11
{
22
"type" : "object",
33
"title" : "edt_conf_fbs_heading_title",
4-
"properties" :
5-
{
6-
"enable" :
7-
{
8-
"type" : "boolean",
9-
"required" : true,
10-
"title" : "edt_conf_general_enable_title",
11-
"default" : true,
12-
"propertyOrder" : 1
4+
"properties": {
5+
"enable": {
6+
"type": "boolean",
7+
"required": true,
8+
"title": "edt_conf_general_enable_title",
9+
"default": true,
10+
"propertyOrder": 1
1311
},
14-
"port" :
15-
{
16-
"type" : "integer",
17-
"required" : true,
18-
"title" : "edt_conf_general_port_title",
19-
"minimum" : 1024,
20-
"maximum" : 65535,
21-
"default" : 19400,
22-
"propertyOrder" : 2
12+
"port": {
13+
"type": "integer",
14+
"required": true,
15+
"title": "edt_conf_general_port_title",
16+
"minimum": 1024,
17+
"maximum": 65535,
18+
"default": 19400,
19+
"propertyOrder": 2
2320
},
24-
"timeout" :
25-
{
26-
"type" : "integer",
27-
"required" : true,
28-
"title" : "edt_conf_fbs_timeout_title",
29-
"append" : "edt_append_s",
30-
"minimum" : 1,
31-
"default" : 5,
32-
"propertyOrder" : 3
21+
"timeout": {
22+
"type": "integer",
23+
"required": true,
24+
"title": "edt_conf_fbs_timeout_title",
25+
"append": "edt_append_s",
26+
"minimum": 1,
27+
"default": 5,
28+
"propertyOrder": 3
29+
},
30+
"pixelDecimation": {
31+
"type": "integer",
32+
"title": "edt_conf_fg_pixelDecimation_title",
33+
"minimum": 1,
34+
"maximum": 30,
35+
"default": 1,
36+
"required": false,
37+
"access": "advanced",
38+
"propertyOrder": 4
3339
}
3440
},
3541
"additionalProperties" : false

0 commit comments

Comments
 (0)