Skip to content
Snippets Groups Projects
Commit 838a80d5 authored by bodzsoaa's avatar bodzsoaa
Browse files

Merge remote-tracking branch 'origin/develop' into develop

parents b33ca888 ab894fd8
Branches develop
No related tags found
No related merge requests found
......@@ -45,6 +45,8 @@ class LIBMUEB_EXPORT MuebTransmitter final : public QObject {
explicit MuebTransmitter(QObject* parent = nullptr);
~MuebTransmitter();
void SendPacket(QByteArray reduced_compressed_frame);
};
} // namespace libmueb
......
......@@ -15,10 +15,14 @@ color_depth=4
; Network protocol specific constants.
[network]
animation_port=50001
; Could be any valid IP(v4/v6) address: broadcast, multicast, unicast, localhost etc.
; Could be any valid IPv4 address: broadcast, multicast, unicast, localhost etc.
; Multicast example
;multicast_interface=ethernet_32776
;target_address=239.6.0.1
; Broadcast example
target_address=10.6.255.255
; The number of windows divided by max_windows_per_datagram must be an integer.
; max_windows_per_datagram must be less than the number of windows.
; max_windows_per_datagram must be less than or equal to the number of windows.
; Packet size must be less than 1472 bytes to avoid IPv4 fragmentation.
; Assuming 1500 MTU, 1500-20(IPv4 header)-8(UDP header) = 1472 bytes.
max_windows_per_datagram=208
\ No newline at end of file
......@@ -34,8 +34,8 @@ Configuration::Configuration() {
quint32 pixels_per_window = vertical_pixel_unit_ * horizontal_pixel_unit_;
window_per_floor_ = rooms_per_floor * windows_per_room;
quint32 windows = floors_ * window_per_floor_;
pixels_ = windows * pixels_per_window;
windows_ = floors_ * window_per_floor_;
pixels_ = windows_ * pixels_per_window;
// Alpha channel is not supported by hardware
// The image is stored using a 24-bit RGB format (8-8-8)
frame_ = QImage(window_per_floor_ * horizontal_pixel_unit_,
......@@ -56,7 +56,7 @@ Configuration::Configuration() {
}
quint32 max_windows_per_datagram =
settings.value("max_windows_per_datagram", windows).toUInt();
settings.value("max_windows_per_datagram", windows_).toUInt();
packet_header_size_ = 2;
packet_size_ =
packet_header_size_ + max_windows_per_datagram * window_byte_size;
......@@ -65,13 +65,13 @@ Configuration::Configuration() {
frame_fragment_size_ =
max_windows_per_datagram * pixels_per_window * kRgbByteSize;
max_packet_number_ =
qCeil(static_cast<qreal>(windows) / max_windows_per_datagram);
qCeil(static_cast<qreal>(windows_) / max_windows_per_datagram);
settings.endGroup();
if (settings.status() != QSettings::NoError ||
vertical_pixel_unit_ % 2 != 0 || horizontal_pixel_unit_ % 2 != 0 ||
color_depth_ < 3 || color_depth_ > 8 || animation_port_ < 0 ||
windows % max_windows_per_datagram != 0 || packet_size_ > 1472 ||
windows_ % max_windows_per_datagram != 0 || packet_size_ > 1472 ||
(target_address_.isMulticast() && !multicast_interface_.isValid())) {
if (target_address_.isMulticast()) {
qInfo() << "[Configuration] Possible multicast interfaces:"
......
#include "muebtransmitter.h"
#include <QList>
#include "muebtransmitter_p.h"
namespace libmueb {
struct CompressedColorsWrapper {
QByteArray compressed_colors;
bool msb{true};
};
MuebTransmitter::MuebTransmitter(QObject* parent)
: QObject(parent), d_ptr_(new MuebTransmitterPrivate(this)) {}
......@@ -26,62 +33,52 @@ void MuebTransmitter::SendFrame(libmueb::Frame frame) {
}
frame.convertTo(QImage::Format_RGB888);
QList<uchar> frame_bytes(frame.constBits(),
frame.constBits() + frame.sizeInBytes());
// Frame color reduction and compression
QByteArray reduced_compressed_frame;
if (d->configuration_.color_depth() < 5) {
reduced_compressed_frame = QtConcurrent::blockingMappedReduced<QByteArray>(
frame.constBits(), frame.constBits() + frame.sizeInBytes(),
auto result = QtConcurrent::mappedReduced<CompressedColorsWrapper>(
frame_bytes,
// Reference:
// http://threadlocalmutex.com/?p=48
// http://threadlocalmutex.com/?page_id=60
[d](const uchar& color) -> uchar {
[this](const uchar& color) -> uchar {
Q_D(MuebTransmitter);
uchar u_color = static_cast<uchar>(color);
if (d->configuration_.color_depth() == 3) {
return (color * 225 + 4096) >> 13;
return (u_color * 225 + 4096) >> 13;
} else if (d->configuration_.color_depth() == 4) {
return (color * 15 + 135) >> 8;
return (u_color * 15 + 135) >> 8;
}
return color;
return u_color;
},
[d](QByteArray& compressed_colors, const uchar& color) {
static bool msb{true};
[](CompressedColorsWrapper& compressed_colors_wrapper,
const uchar& color) {
// Compress 2 color components into 1 byte
if (msb) {
compressed_colors.append(color << Configuration::kFactor);
if (compressed_colors_wrapper.msb) {
compressed_colors_wrapper.compressed_colors.append(
color << Configuration::kFactor);
} else {
compressed_colors.back() = compressed_colors.back() | color;
compressed_colors_wrapper.compressed_colors.back() =
compressed_colors_wrapper.compressed_colors.back() | color;
}
msb = !msb;
compressed_colors_wrapper.msb = !compressed_colors_wrapper.msb;
},
QtConcurrent::OrderedReduce | QtConcurrent::SequentialReduce);
result.then(this,
[this](CompressedColorsWrapper compressed_colors_wrapper) {
SendPacket(compressed_colors_wrapper.compressed_colors);
});
}
// No compression
else {
reduced_compressed_frame.setRawData(
reinterpret_cast<const char*>(frame.bits()), frame.sizeInBytes());
}
if (d->configuration_.max_packet_number() == 1) {
reduced_compressed_frame.insert(0, d->configuration_.protocol_type())
.insert(1, static_cast<char>(0) /*packet number*/);
d->datagram_.setData(reduced_compressed_frame);
d->socket_.writeDatagram(d->datagram_);
} else {
for (std::uint8_t i = 0; i < d->configuration_.max_packet_number(); ++i) {
QByteArray data;
data.append(d->configuration_.protocol_type())
.append(i /*packet number*/)
.append(reduced_compressed_frame.sliced(
i * d->configuration_.packet_payload_size(),
d->configuration_.packet_payload_size()));
d->datagram_.setData(data);
d->socket_.writeDatagram(d->datagram_);
}
SendPacket(QByteArray(reinterpret_cast<const char*>(frame.bits()),
frame.sizeInBytes()));
}
}
......@@ -144,4 +141,28 @@ libmueb::Frame MuebTransmitter::frame() const {
return d->configuration_.frame();
}
void MuebTransmitter::SendPacket(QByteArray reduced_compressed_frame) {
Q_D(MuebTransmitter);
if (d->configuration_.max_packet_number() == 1) {
reduced_compressed_frame.insert(0, d->configuration_.protocol_type())
.insert(1, static_cast<char>(0) /*packet number*/);
d->datagram_.setData(reduced_compressed_frame);
d->socket_.writeDatagram(d->datagram_);
} else {
for (std::uint8_t i = 0; i < d->configuration_.max_packet_number(); ++i) {
QByteArray data;
data.append(d->configuration_.protocol_type())
.append(i /*packet number*/)
.append(reduced_compressed_frame.sliced(
i * d->configuration_.packet_payload_size(),
d->configuration_.packet_payload_size()));
d->datagram_.setData(data);
d->socket_.writeDatagram(d->datagram_);
}
}
}
} // namespace libmueb
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment