diff --git a/include/libmueb/muebtransmitter.h b/include/libmueb/muebtransmitter.h index f12ea3c61bc7a78a1272ccf86b914335bab474e8..48b27089cce9aa2ef305298b7fc5afb512c6689f 100644 --- a/include/libmueb/muebtransmitter.h +++ b/include/libmueb/muebtransmitter.h @@ -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 diff --git a/libmueb.ini b/libmueb.ini index d7ab61197d9b415bff145a4a40c145a3e750828f..db6b6fd85095b9ca32812c51f882bab6af6075a6 100644 --- a/libmueb.ini +++ b/libmueb.ini @@ -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 diff --git a/src/configuration.cc b/src/configuration.cc index aaf9958e6e0f9fc422d3d93a54e47a4323650f87..c17245bf42a0165f7b1e04309446fe76f63e0b2c 100644 --- a/src/configuration.cc +++ b/src/configuration.cc @@ -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:" diff --git a/src/muebtransmitter.cc b/src/muebtransmitter.cc index e6b679c0f59e9055129a80f74363ef2f7d099772..77ad1c5415335980c1b9e656b10fb9f1063bb0e3 100644 --- a/src/muebtransmitter.cc +++ b/src/muebtransmitter.cc @@ -1,9 +1,16 @@ #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