From 8e35bdc4d3d7398396ff6a023a0867b89633f8e2 Mon Sep 17 00:00:00 2001 From: b1rdhous3 Date: Thu, 22 Aug 2019 09:40:12 +0200 Subject: [PATCH 1/4] Update 3rd party license (roboto font) Add Roboto Font License --- 3RD_PARTY_LICENSES | 208 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 207 insertions(+), 1 deletion(-) diff --git a/3RD_PARTY_LICENSES b/3RD_PARTY_LICENSES index e6d6f278..46e9495f 100644 --- a/3RD_PARTY_LICENSES +++ b/3RD_PARTY_LICENSES @@ -501,6 +501,212 @@ of the input file used when generating it. This code is not standalone and requires a support library to be linked with it. This support library is itself covered by the above license. +====== +Roboto +====== + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ========== rpi_ws281x ========== @@ -537,4 +743,4 @@ Copyright (C) 2012-2013 Matthias Bolte Copyright (C) 2011 Olaf Lüke Redistribution and use in source and binary forms of this file, -with or without modification, are permitted. \ No newline at end of file +with or without modification, are permitted. From 24495bbc65bfbe72179a3e641437884570f98e7b Mon Sep 17 00:00:00 2001 From: Paulchen Panther <16664240+Paulchen-Panther@users.noreply.github.com> Date: Sat, 24 Aug 2019 22:53:30 +0200 Subject: [PATCH 2/4] Fix #604, #605 ... (#607) * Fix #604 and #605 Signed-off-by: Paulchen-Panther * clear current prio on color command Signed-off-by: Paulchen-Panther * Fix QTimer threading issues * Call QTimer start() stop() from QEvent Signed-off-by: Paulchen-Panther * send initial color/image to WebUI hide error message when opening webbrowser Signed-off-by: Paulchen-Panther * added streaming timer to update WebUI Preview Signed-off-by: Paulchen-Panther * remove QMetaObject::invokeMethod() Signed-off-by: Paulchen-Panther * added parent to streaming timers Signed-off-by: Paulchen-Panther * header cleanup --- include/api/JsonAPI.h | 43 +++--- include/utils/Image.h | 11 ++ .../api/JSONRPC_schema/schema-ledcolors.json | 4 +- libsrc/api/JsonAPI.cpp | 127 +++++++++++------- libsrc/hyperion/Hyperion.cpp | 3 + libsrc/hyperion/LinearColorSmoothing.cpp | 9 +- libsrc/hyperion/PriorityMuxer.cpp | 2 + src/hyperiond/systray.cpp | 25 ++++ 8 files changed, 150 insertions(+), 74 deletions(-) diff --git a/include/api/JsonAPI.h b/include/api/JsonAPI.h index 6b869966..08a6f181 100644 --- a/include/api/JsonAPI.h +++ b/include/api/JsonAPI.h @@ -2,21 +2,17 @@ // hyperion includes #include -#include #include #include +#include // qt includes #include -#include #include -// HyperionInstanceManager -#include - +class QTimer; class JsonCB; class AuthManager; -class HyperionIManager; class JsonAPI : public QObject { @@ -43,15 +39,20 @@ public: public slots: /// - /// @brief is called whenever the current Hyperion instance pushes new led raw values (if enabled) - /// @param ledColors The current ledColors + /// @brief Is called whenever the current Hyperion instance pushes new led raw values (if enabled) + /// @param ledColors The current led colors /// void streamLedcolorsUpdate(const std::vector& ledColors); - /// push images whenever hyperion emits (if enabled) + /// + /// @brief Push images whenever hyperion emits (if enabled) + /// @param image The current image + /// void setImage(const Image & image); - /// process and push new log messages from logger (if enabled) + /// + /// @brief Process and push new log messages from logger (if enabled) + /// void incommingLogMessage(const Logger::T_LOG_MESSAGE&); private slots: @@ -128,17 +129,23 @@ private: /// flag to determine state of log streaming bool _streaming_logging_activated; - /// mutex to determine state of image streaming - QMutex _image_stream_mutex; + /// timer for live video refresh + QTimer* _imageStreamTimer; - /// mutex to determine state of led streaming - QMutex _led_stream_mutex; + /// image stream connection handle + QMetaObject::Connection _imageStreamConnection; - /// timeout for live video refresh - volatile qint64 _image_stream_timeout; + /// the current streaming image + Image _currentImage; - /// timeout for led color refresh - volatile qint64 _led_stream_timeout; + /// timer for led color refresh + QTimer* _ledStreamTimer; + + /// led stream connection handle + QMetaObject::Connection _ledStreamConnection; + + /// the current streaming led values + std::vector _currentLedValues; /// /// @brief Handle the switches of Hyperion instances diff --git a/include/utils/Image.h b/include/utils/Image.h index a883cc2f..0c5c8456 100644 --- a/include/utils/Image.h +++ b/include/utils/Image.h @@ -245,6 +245,17 @@ public: return (ssize_t) _width * _height * sizeof(Pixel_T); } + /// Clear the image + // + void clear() + { + _width = 1; + _height = 1; + _pixels = new Pixel_T[2]; + _endOfPixels = _pixels + 1; + memset(_pixels, 0, _width * _height * sizeof(Pixel_T)); + } + private: /// diff --git a/libsrc/api/JSONRPC_schema/schema-ledcolors.json b/libsrc/api/JSONRPC_schema/schema-ledcolors.json index 93d5e95a..b1bda0a3 100644 --- a/libsrc/api/JSONRPC_schema/schema-ledcolors.json +++ b/libsrc/api/JSONRPC_schema/schema-ledcolors.json @@ -19,7 +19,9 @@ "type" : "bool" }, "interval": { - "type" : "integer" + "type" : "integer", + "required" : false, + "minimum": 50 } }, diff --git a/libsrc/api/JsonAPI.cpp b/libsrc/api/JsonAPI.cpp index 17e43859..83127145 100644 --- a/libsrc/api/JsonAPI.cpp +++ b/libsrc/api/JsonAPI.cpp @@ -12,17 +12,16 @@ #include #include #include -#include -#include -#include +#include // hyperion includes -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include #include #include @@ -53,8 +52,8 @@ JsonAPI::JsonAPI(QString peerAddress, Logger* log, const bool& localConnection, , _hyperion(nullptr) , _jsonCB(nullptr) , _streaming_logging_activated(false) - , _image_stream_timeout(0) - , _led_stream_timeout(0) + , _imageStreamTimer(new QTimer(this)) + , _ledStreamTimer(new QTimer(this)) { Q_INIT_RESOURCE(JSONRPC_schemas); @@ -1018,28 +1017,68 @@ void JsonAPI::handleLedColorsCommand(const QJsonObject& message, const QString & // create result QString subcommand = message["subcommand"].toString(""); + // max 20 Hz (50ms) interval for streaming (default: 10 Hz (100ms)) + qint64 streaming_interval = qMax(message["interval"].toInt(100), 50); + if (subcommand == "ledstream-start") { _streaming_leds_reply["success"] = true; _streaming_leds_reply["command"] = command+"-ledstream-update"; _streaming_leds_reply["tan"] = tan; - connect(_hyperion, &Hyperion::rawLedColors, this, &JsonAPI::streamLedcolorsUpdate, Qt::UniqueConnection); + + connect(_hyperion, &Hyperion::rawLedColors, this, [=](const std::vector& ledValues) + { + _currentLedValues = ledValues; + + // necessary because Qt::UniqueConnection for lambdas does not work until 5.9 + // see: https://bugreports.qt.io/browse/QTBUG-52438 + if (!_ledStreamConnection) + _ledStreamConnection = connect(_ledStreamTimer, &QTimer::timeout, this, [=]() + { + emit streamLedcolorsUpdate(_currentLedValues); + }, Qt::UniqueConnection); + + // start the timer + if (!_ledStreamTimer->isActive() || _ledStreamTimer->interval() != streaming_interval) + _ledStreamTimer->start(streaming_interval); + }, Qt::UniqueConnection); } else if (subcommand == "ledstream-stop") { - disconnect(_hyperion, &Hyperion::rawLedColors, this, &JsonAPI::streamLedcolorsUpdate); + disconnect(_hyperion, &Hyperion::rawLedColors, this, 0); + _ledStreamTimer->stop(); + disconnect(_ledStreamConnection); } else if (subcommand == "imagestream-start") { _streaming_image_reply["success"] = true; _streaming_image_reply["command"] = command+"-imagestream-update"; _streaming_image_reply["tan"] = tan; - connect(_hyperion, &Hyperion::currentImage, this, &JsonAPI::setImage, Qt::UniqueConnection); + + connect(_hyperion, &Hyperion::currentImage, this, [=](const Image& image) + { + _currentImage = image; + + // necessary because Qt::UniqueConnection for lambdas does not work until 5.9 + // see: https://bugreports.qt.io/browse/QTBUG-52438 + if (!_imageStreamConnection) + _imageStreamConnection = connect(_imageStreamTimer, &QTimer::timeout, this, [=]() + { + emit setImage(_currentImage); + }, Qt::UniqueConnection); + + // start timer + if (!_imageStreamTimer->isActive() || _imageStreamTimer->interval() != streaming_interval) + _imageStreamTimer->start(streaming_interval); + }, Qt::UniqueConnection); + _hyperion->update(); } else if (subcommand == "imagestream-stop") { - disconnect(_hyperion, &Hyperion::currentImage, this, &JsonAPI::setImage); + disconnect(_hyperion, &Hyperion::currentImage, this, 0); + _imageStreamTimer->stop(); + disconnect(_imageStreamConnection); } else { @@ -1420,52 +1459,40 @@ void JsonAPI::sendErrorReply(const QString &error, const QString &command, const emit callbackMessage(reply); } - void JsonAPI::streamLedcolorsUpdate(const std::vector& ledColors) { - QMutexLocker lock(&_led_stream_mutex); - if ( (_led_stream_timeout+100) < QDateTime::currentMSecsSinceEpoch() ) + QJsonObject result; + QJsonArray leds; + + for(auto color = ledColors.begin(); color != ledColors.end(); ++color) { - _led_stream_timeout = QDateTime::currentMSecsSinceEpoch(); - QJsonObject result; - QJsonArray leds; - - for(auto color = ledColors.begin(); color != ledColors.end(); ++color) - { - QJsonObject item; - item["index"] = int(color - ledColors.begin()); - item["red"] = color->red; - item["green"] = color->green; - item["blue"] = color->blue; - leds.append(item); - } - - result["leds"] = leds; - _streaming_leds_reply["result"] = result; - - // send the result - emit callbackMessage(_streaming_leds_reply); + QJsonObject item; + item["index"] = int(color - ledColors.begin()); + item["red"] = color->red; + item["green"] = color->green; + item["blue"] = color->blue; + leds.append(item); } + + result["leds"] = leds; + _streaming_leds_reply["result"] = result; + + // send the result + emit callbackMessage(_streaming_leds_reply); } void JsonAPI::setImage(const Image & image) { - QMutexLocker lock(&_image_stream_mutex); - if ( (_image_stream_timeout+100) < QDateTime::currentMSecsSinceEpoch() ) - { - _image_stream_timeout = QDateTime::currentMSecsSinceEpoch(); + QImage jpgImage((const uint8_t *) image.memptr(), image.width(), image.height(), 3*image.width(), QImage::Format_RGB888); + QByteArray ba; + QBuffer buffer(&ba); + buffer.open(QIODevice::WriteOnly); + jpgImage.save(&buffer, "jpg"); - QImage jpgImage((const uint8_t *) image.memptr(), image.width(), image.height(), 3*image.width(), QImage::Format_RGB888); - QByteArray ba; - QBuffer buffer(&ba); - buffer.open(QIODevice::WriteOnly); - jpgImage.save(&buffer, "jpg"); - - QJsonObject result; - result["image"] = "data:image/jpg;base64,"+QString(ba.toBase64()); - _streaming_image_reply["result"] = result; - emit callbackMessage(_streaming_image_reply); - } + QJsonObject result; + result["image"] = "data:image/jpg;base64,"+QString(ba.toBase64()); + _streaming_image_reply["result"] = result; + emit callbackMessage(_streaming_image_reply); } void JsonAPI::incommingLogMessage(const Logger::T_LOG_MESSAGE &msg) diff --git a/libsrc/hyperion/Hyperion.cpp b/libsrc/hyperion/Hyperion.cpp index fb735143..3995cb2f 100644 --- a/libsrc/hyperion/Hyperion.cpp +++ b/libsrc/hyperion/Hyperion.cpp @@ -368,6 +368,9 @@ void Hyperion::setColor(const int priority, const ColorRgb &color, const int tim // create led vector from single color std::vector ledColors(_ledString.leds().size(), color); + if (getPriorityInfo(priority).componentId != hyperion::COMP_COLOR) + clear(priority); + // register color registerInput(priority, hyperion::COMP_COLOR, origin); diff --git a/libsrc/hyperion/LinearColorSmoothing.cpp b/libsrc/hyperion/LinearColorSmoothing.cpp index d49e0c4b..0acaf127 100644 --- a/libsrc/hyperion/LinearColorSmoothing.cpp +++ b/libsrc/hyperion/LinearColorSmoothing.cpp @@ -72,7 +72,7 @@ int LinearColorSmoothing::write(const std::vector &ledValues) _previousTime = QDateTime::currentMSecsSinceEpoch(); _previousValues = ledValues; - _timer->start(); + QMetaObject::invokeMethod(_timer, "start", Qt::QueuedConnection, Q_ARG(int, _updateInterval)); } else { @@ -182,7 +182,7 @@ void LinearColorSmoothing::setEnable(bool enable) { if (!enable) { - _timer->stop(); + QMetaObject::invokeMethod(_timer, "stop", Qt::QueuedConnection); _previousValues.clear(); } // update comp register @@ -218,10 +218,9 @@ bool LinearColorSmoothing::selectConfig(unsigned cfg, const bool& force) if (_cfgList[cfg].updateInterval != _updateInterval) { - _timer->stop(); + QMetaObject::invokeMethod(_timer, "stop", Qt::QueuedConnection); _updateInterval = _cfgList[cfg].updateInterval; - _timer->setInterval(_updateInterval); - _timer->start(); + QMetaObject::invokeMethod(_timer, "start", Qt::QueuedConnection, Q_ARG(int, _updateInterval)); } _currentConfigId = cfg; //DebugIf( enabled() && !_pause, _log, "set smoothing cfg: %d, interval: %d ms, settlingTime: %d ms, updateDelay: %d frames", _currentConfigId, _updateInterval, _settlingTime, _outputDelay ); diff --git a/libsrc/hyperion/PriorityMuxer.cpp b/libsrc/hyperion/PriorityMuxer.cpp index b833e59d..d9a112b4 100644 --- a/libsrc/hyperion/PriorityMuxer.cpp +++ b/libsrc/hyperion/PriorityMuxer.cpp @@ -185,6 +185,7 @@ bool PriorityMuxer::setInput(const int priority, const std::vector& le // update input input.timeoutTime_ms = timeout_ms; input.ledColors = ledColors; + input.image.clear(); // emit active change if(activeChange) @@ -224,6 +225,7 @@ bool PriorityMuxer::setInputImage(const int priority, const Image& ima // update input input.timeoutTime_ms = timeout_ms; input.image = image; + input.ledColors.clear(); // emit active change if(activeChange) diff --git a/src/hyperiond/systray.cpp b/src/hyperiond/systray.cpp index 066527f2..994966b2 100644 --- a/src/hyperiond/systray.cpp +++ b/src/hyperiond/systray.cpp @@ -1,5 +1,6 @@ #include +#include #include #include @@ -128,7 +129,31 @@ void SysTray::closeEvent(QCloseEvent *event) void SysTray::settings() { + // Hide error messages when opening webbrowser + + int out_pipe[2]; + int saved_stdout; + int saved_stderr; + + // saving stdout and stderr file descriptor + saved_stdout = ::dup( STDOUT_FILENO ); + saved_stderr = ::dup( STDERR_FILENO ); + + if(::pipe(out_pipe) == 0) + { + // redirecting stdout to pipe + ::dup2(out_pipe[1], STDOUT_FILENO); + ::close(out_pipe[1]); + // redirecting stderr to stdout + ::dup2(STDOUT_FILENO, STDERR_FILENO); + } + QDesktopServices::openUrl(QUrl("http://localhost:"+QString::number(_webPort)+"/", QUrl::TolerantMode)); + + // restoring stdout + ::dup2(saved_stdout, STDOUT_FILENO); + // restoring stderr + ::dup2(saved_stderr, STDERR_FILENO); } void SysTray::setEffect() From b1fa085d64cb3a2851c60e55711a9600850d377d Mon Sep 17 00:00:00 2001 From: brindosch Date: Sun, 25 Aug 2019 16:32:19 +0200 Subject: [PATCH 3/4] Breaking Change: ledLayout, ledColorsStream (#614) * Remove clone & index in ledConfig * Additional index correction * Rename ledsConfig maximum and minimum in max and min * Rename ledsConfig hscan and vscan with h and v * Optimize ledColorsStream * tiny correction --- assets/webconfig/js/content_leds.js | 144 +++++----- assets/webconfig/js/ledsim.js | 20 +- assets/webconfig/js/wizard.js | 50 ++-- config/hyperion.config.json.commented | 350 +++++++++++------------- config/hyperion.config.json.default | 338 +++++++++++------------ include/hyperion/Hyperion.h | 3 - include/hyperion/LedString.h | 5 - include/utils/hyperion.h | 130 +++------ libsrc/api/JsonAPI.cpp | 9 +- libsrc/hyperion/Hyperion.cpp | 19 +- libsrc/hyperion/schema/schema-leds.json | 22 +- 11 files changed, 466 insertions(+), 624 deletions(-) diff --git a/assets/webconfig/js/content_leds.js b/assets/webconfig/js/content_leds.js index c032f0e9..88ca8cd9 100644 --- a/assets/webconfig/js/content_leds.js +++ b/assets/webconfig/js/content_leds.js @@ -24,12 +24,12 @@ function createLedPreview(leds, origin){ $('#previewcreator').html($.i18n('conf_leds_layout_preview_originMA')); $('#leds_preview').css("padding-top", "100%"); } - + $('#previewledcount').html($.i18n('conf_leds_layout_preview_totalleds', leds.length)); $('#previewledpower').html($.i18n('conf_leds_layout_preview_ledpower', ((leds.length * 0.06)*1.1).toFixed(1))); - + $('.st_helper').css("border", "8px solid grey"); - + var canvas_height = $('#leds_preview').innerHeight(); var canvas_width = $('#leds_preview').innerWidth(); @@ -39,17 +39,17 @@ function createLedPreview(leds, origin){ var led = leds[idx]; var led_id='ledc_'+[idx]; var bgcolor = "background-color:hsl("+(idx*360/leds.length)+",100%,50%);"; - var pos = "left:"+(led.hscan.minimum * canvas_width)+"px;"+ - "top:"+(led.vscan.minimum * canvas_height)+"px;"+ - "width:"+((led.hscan.maximum-led.hscan.minimum) * (canvas_width-1))+"px;"+ - "height:"+((led.vscan.maximum-led.vscan.minimum) * (canvas_height-1))+"px;"; - leds_html += '
'+led.index+'
'; + var pos = "left:"+(led.h.min * canvas_width)+"px;"+ + "top:"+(led.v.min * canvas_height)+"px;"+ + "width:"+((led.h.max-led.h.min) * (canvas_width-1))+"px;"+ + "height:"+((led.v.max-led.v.min) * (canvas_height-1))+"px;"; + leds_html += '
'+idx+'
'; } $('#leds_preview').html(leds_html); $('#ledc_0').css({"background-color":"black","z-index":"12"}); $('#ledc_1').css({"background-color":"grey","z-index":"11"}); $('#ledc_2').css({"background-color":"#A9A9A9","z-index":"10"}); - + if($('#leds_prev_toggle_num').hasClass('btn-success')) $('.led_prev_num').css("display", "inline"); @@ -65,14 +65,14 @@ function createClassicLeds(){ var ledsgpos = parseInt($("#ip_cl_gpos").val()); var position = parseInt($("#ip_cl_position").val()); var reverse = $("#ip_cl_reverse").is(":checked"); - + //advanced values var ledsVDepth = parseInt($("#ip_cl_vdepth").val())/100; var ledsHDepth = parseInt($("#ip_cl_hdepth").val())/100; var edgeVGap = parseInt($("#ip_cl_edgegap").val())/100/2; //var cornerVGap = parseInt($("#ip_cl_cornergap").val())/100/2; var overlap = $("#ip_cl_overlap").val()/4000; - + //helper var edgeHGap = edgeVGap/(16/9); //var cornerHGap = cornerVGap/(16/9); @@ -83,15 +83,15 @@ function createClassicLeds(){ var Hdiff = Hmax-Hmin; var Vdiff = Vmax-Vmin; var ledArray = []; - + function createFinalArray(array){ finalLedArray = []; for(var i = 0; i 1) @@ -120,7 +120,7 @@ function createClassicLeds(){ return 0; return val; } - + function ovl(scan,val) { if(scan == "+") @@ -128,15 +128,15 @@ function createClassicLeds(){ else return valScan(val -= overlap); } - + function createLedArray(hmin, hmax, vmin, vmax){ hmin = round(hmin); hmax = round(hmax); vmin = round(vmin); vmax = round(vmax); - ledArray.push( { "hscan" : { "minimum" : hmin, "maximum" : hmax }, "vscan": { "minimum": vmin, "maximum": vmax }} ); + ledArray.push( { "h" : { "min" : hmin, "max" : hmax }, "v": { "min": vmin, "max": vmax }} ); } - + function createTopLeds(){ var step=(Hmax-Hmin)/ledstop; //if(cornerVGap != '0') @@ -148,9 +148,9 @@ function createClassicLeds(){ var hmin = ovl("-",(Hdiff/ledstop*Number([i]))+edgeHGap); var hmax = ovl("+",(Hdiff/ledstop*Number([i]))+step+edgeHGap); createLedArray(hmin, hmax, vmin, vmax); - } + } } - + function createLeftLeds(){ var step=(Vmax-Vmin)/ledsleft; //if(cornerVGap != '0') @@ -164,7 +164,7 @@ function createClassicLeds(){ createLedArray(hmin, hmax, vmin, vmax); } } - + function createRightLeds(){ var step=(Vmax-Vmin)/ledsright; //if(cornerVGap != '0') @@ -175,15 +175,15 @@ function createClassicLeds(){ for (var i = 0; i-1; i--){ @@ -192,7 +192,7 @@ function createClassicLeds(){ createLedArray(hmin, hmax, vmin, vmax); } } - + createTopLeds(); createRightLeds(); createBottomLeds(); @@ -205,25 +205,25 @@ function createClassicLeds(){ $('#ip_cl_ledsgpos').val(mpos); ledsgpos = mpos; } - + //check led gap length if(ledsglength >= ledArray.length) { $('#ip_cl_ledsglength').val(ledArray.length-1); ledsglength = ledArray.length-ledsglength-1; } - + if(ledsglength != 0){ ledArray.splice(ledsgpos, ledsglength); } - + if (position != 0){ rotateArray(ledArray, position); } if (reverse) ledArray.reverse(); - + createFinalArray(ledArray); } @@ -239,7 +239,6 @@ function createMatrixLeds(){ var start = $("#ip_ma_start").val(); var parallel = false - var index = 0 var leds = [] var hblock = 1.0 / ledshoriz var vblock = 1.0 / ledsvert @@ -250,11 +249,10 @@ function createMatrixLeds(){ /** * Adds led to the hyperion config led array - * @param {Number} index Index of the led * @param {Number} x Horizontal position in matrix * @param {Number} y Vertical position in matrix */ - function addLed (index, x, y) { + function addLed (x, y) { var hscanMin = x * hblock var hscanMax = (x + 1) * hblock var vscanMin = y * vblock @@ -264,16 +262,15 @@ function createMatrixLeds(){ hscanMax = round(hscanMax); vscanMin = round(vscanMin); vscanMax = round(vscanMax); - + leds.push({ - index: index, - hscan: { - minimum: hscanMin, - maximum: hscanMax + h: { + min: hscanMin, + max: hscanMax }, - vscan: { - minimum: vscanMin, - maximum: vscanMax + v: { + min: vscanMin, + max: vscanMax } }) } @@ -291,8 +288,7 @@ function createMatrixLeds(){ for (y = startY; downward && y <= endY || !downward && y >= endY; y += downward ? 1 : -1) { for (x = startX; forward && x <= endX || !forward && x >= endX; x += forward ? 1 : -1) { - addLed(index, x, y) - index++ + addLed(x, y) } if (!parallel) { forward = !forward @@ -309,7 +305,7 @@ function createMatrixLeds(){ $(document).ready(function() { // translate performTranslation(); - + //add intros if(window.showOptHelp) { @@ -317,9 +313,9 @@ $(document).ready(function() { createHintH("intro", $.i18n('conf_leds_layout_intro'), "layout_intro"); $('#led_vis_help').html('
'+$.i18n('conf_leds_layout_preview_l1')+'
'+$.i18n('conf_leds_layout_preview_l2')+'
'); } - + var slConfig = window.serverConfig.ledConfig; - + //restore ledConfig for(var key in slConfig) { @@ -343,7 +339,7 @@ $(document).ready(function() { } setTimeout(requestWriteConfig, 100, {ledConfig}); } - + // check access level and adjust ui if(storedAccess == "default") { @@ -357,10 +353,10 @@ $(document).ready(function() { $('#btn_ma_save').toggle(false); $('#btn_cl_save').toggle(false); } - + //Wiki link $('#leds_wl').append('

'+$.i18n('general_wiki_moreto',$.i18n('conf_leds_nav_label_ledlayout'))+buildWL("user/moretopics/ledarea","Wiki")+'

'); - + // bind change event to all inputs $('.ledCLconstr').bind("change", function() { valValue(this.id,this.value,this.min,this.max); @@ -373,7 +369,7 @@ $(document).ready(function() { }); // v4 of json schema with diff required assignment - remove when hyperion schema moved to v4 - var ledschema = {"items":{"additionalProperties":false,"required":["hscan","vscan","index"],"properties":{"clone":{"type":"integer"},"colorOrder":{"enum":["rgb","bgr","rbg","brg","gbr","grb"],"type":"string"},"hscan":{"additionalProperties":false,"properties":{"maximum":{"maximum":1,"minimum":0,"type":"number"},"minimum":{"maximum":1,"minimum":0,"type":"number"}},"type":"object"},"index":{"type":"integer"},"vscan":{"additionalProperties":false,"properties":{"maximum":{"maximum":1,"minimum":0,"type":"number"},"minimum":{"maximum":1,"minimum":0,"type":"number"}},"type":"object"}},"type":"object"},"type":"array"}; + var ledschema = {"items":{"additionalProperties":false,"required":["h","v"],"properties":{"colorOrder":{"enum":["rgb","bgr","rbg","brg","gbr","grb"],"type":"string"},"h":{"additionalProperties":false,"properties":{"max":{"maximum":1,"minimum":0,"type":"number"},"min":{"maximum":1,"minimum":0,"type":"number"}},"type":"object"},"v":{"additionalProperties":false,"properties":{"max":{"maximum":1,"minimum":0,"type":"number"},"min":{"maximum":1,"minimum":0,"type":"number"}},"type":"object"}},"type":"object"},"type":"array"}; //create jsonace editor var aceEdt = new JSONACEEditor(document.getElementById("aceedit"),{ mode: 'code', @@ -387,7 +383,7 @@ $(document).ready(function() { { success = false; } - + if(success) { $('#leds_custom_updsim').attr("disabled", false); @@ -400,7 +396,7 @@ $(document).ready(function() { } } }, window.serverConfig.leds); - + //TODO: HACK! No callback for schema validation - Add it! setInterval(function(){ if($('#aceedit table').hasClass('jsoneditor-text-errors')) @@ -409,23 +405,23 @@ $(document).ready(function() { $('#leds_custom_save').attr("disabled", true); } },1000); - + $('.jsoneditor-menu').toggle(); - + // leds to finalLedArray finalLedArray = window.serverConfig.leds; - + // cl/ma leds push to textfield $('#btn_cl_generate, #btn_ma_generate').off().on("click", function(e) { if(e.currentTarget.id == "btn_cl_generate") $('#collapse1').collapse('hide'); else $('#collapse2').collapse('hide'); - + aceEdt.set(finalLedArray); $('#collapse4').collapse('show'); }); - + // create and update editor $("#leddevices").off().on("change", function() { var generalOptions = window.serverSchema.properties.device; @@ -437,7 +433,7 @@ $(document).ready(function() { generalOptions : generalOptions, specificOptions : specificOptions, }); - + var values_general = {}; var values_specific = {}; var isCurrentDevice = (window.serverInfo.ledDevices.active == $(this).val()); @@ -457,10 +453,10 @@ $(document).ready(function() { conf_editor.getEditor("root.specificOptions").setValue( values_specific ); }; - + // change save button state based on validation result conf_editor.validate().length ? $('#btn_submit_controller').attr('disabled', true) : $('#btn_submit_controller').attr('disabled', false); - + // led controller sepecific wizards if($(this).val() == "philipshue") { @@ -473,7 +469,7 @@ $(document).ready(function() { $('#btn_led_device_wiz').off(); } }); - + // create led device selection var ledDevices = window.serverInfo.ledDevices.available; var devRPiSPI = ['apa102', 'apa104', 'ws2801', 'lpd6803', 'lpd8806', 'p9813', 'sk6812spi', 'sk6822spi', 'ws2812spi']; @@ -481,14 +477,14 @@ $(document).ready(function() { var devRPiGPIO = ['piblaster']; var devNET = ['atmoorb', 'fadecandy', 'philipshue', 'nanoleaf', 'tinkerforge', 'tpm2net', 'udpe131', 'udpartnet', 'udph801', 'udpraw']; var devUSB = ['adalight', 'dmx', 'atmo', 'hyperionusbasp', 'lightpack', 'multilightpack', 'paintpack', 'rawhid', 'sedu', 'tpm2', 'karate']; - + var optArr = [[]]; optArr[1]=[]; optArr[2]=[]; optArr[3]=[]; optArr[4]=[]; optArr[5]=[]; - + for (var idx=0; idx= maxLedId ) + + const QJsonObject& hscanConfig = ledConfigArray[i].toObject()["h"].toObject(); + const QJsonObject& vscanConfig = ledConfigArray[i].toObject()["v"].toObject(); + led.minX_frac = qMax(0.0, qMin(1.0, hscanConfig["min"].toDouble())); + led.maxX_frac = qMax(0.0, qMin(1.0, hscanConfig["max"].toDouble())); + led.minY_frac = qMax(0.0, qMin(1.0, vscanConfig["min"].toDouble())); + led.maxY_frac = qMax(0.0, qMin(1.0, vscanConfig["max"].toDouble())); + // Fix if the user swapped min and max + if (led.minX_frac > led.maxX_frac) { - //Warning(_log, "LED %d: clone index of %d is out of range, clone ignored", led.index, led.clone); - led.clone = -1; + std::swap(led.minX_frac, led.maxX_frac); + } + if (led.minY_frac > led.maxY_frac) + { + std::swap(led.minY_frac, led.maxY_frac); } - if ( led.clone < 0 ) - { - const QJsonObject& hscanConfig = ledConfigArray[i].toObject()["hscan"].toObject(); - const QJsonObject& vscanConfig = ledConfigArray[i].toObject()["vscan"].toObject(); - led.minX_frac = qMax(0.0, qMin(1.0, hscanConfig["minimum"].toDouble())); - led.maxX_frac = qMax(0.0, qMin(1.0, hscanConfig["maximum"].toDouble())); - led.minY_frac = qMax(0.0, qMin(1.0, vscanConfig["minimum"].toDouble())); - led.maxY_frac = qMax(0.0, qMin(1.0, vscanConfig["maximum"].toDouble())); - // Fix if the user swapped min and max - if (led.minX_frac > led.maxX_frac) - { - std::swap(led.minX_frac, led.maxX_frac); - } - if (led.minY_frac > led.maxY_frac) - { - std::swap(led.minY_frac, led.maxY_frac); - } - - // Get the order of the rgb channels for this led (default is device order) - led.colorOrder = stringToColorOrder(index["colorOrder"].toString(deviceOrderStr)); - ledString.leds().push_back(led); - } + // Get the order of the rgb channels for this led (default is device order) + led.colorOrder = stringToColorOrder(index["colorOrder"].toString(deviceOrderStr)); + ledString.leds().push_back(led); } - - // Make sure the leds are sorted (on their indices) - std::sort(ledString.leds().begin(), ledString.leds().end(), [](const Led& lhs, const Led& rhs){ return lhs.index < rhs.index; }); - return ledString; - } - - LedString createLedStringClone(const QJsonArray& ledConfigArray, const ColorOrder deviceOrder) - { - LedString ledString; - const QString deviceOrderStr = colorOrderToString(deviceOrder); - int maxLedId = ledConfigArray.size(); - - for (signed i = 0; i < ledConfigArray.size(); ++i) - { - const QJsonObject& index = ledConfigArray[i].toObject(); - - Led led; - led.index = index["index"].toInt(); - led.clone = index["clone"].toInt(-1); - if ( led.clone < -1 || led.clone >= maxLedId ) - { - //Warning(_log, "LED %d: clone index of %d is out of range, clone ignored", led.index, led.clone); - led.clone = -1; - } - - if ( led.clone >= 0 ) - { - //Debug(_log, "LED %d: clone from led %d", led.index, led.clone); - led.minX_frac = 0; - led.maxX_frac = 0; - led.minY_frac = 0; - led.maxY_frac = 0; - // Get the order of the rgb channels for this led (default is device order) - led.colorOrder = stringToColorOrder(index["colorOrder"].toString(deviceOrderStr)); - - ledString.leds().push_back(led); - } - - } - - // Make sure the leds are sorted (on their indices) - std::sort(ledString.leds().begin(), ledString.leds().end(), [](const Led& lhs, const Led& rhs){ return lhs.index < rhs.index; }); return ledString; } @@ -282,30 +228,26 @@ namespace hyperion { for (signed i = 0; i < ledConfigArray.size(); ++i) { - const QJsonObject& index = ledConfigArray[i].toObject(); - - if (index["clone"].toInt(-1) < 0 ) + const QJsonObject& hscanConfig = ledConfigArray[i].toObject()["h"].toObject(); + const QJsonObject& vscanConfig = ledConfigArray[i].toObject()["v"].toObject(); + double minX_frac = qMax(0.0, qMin(1.0, hscanConfig["min"].toDouble())); + double maxX_frac = qMax(0.0, qMin(1.0, hscanConfig["max"].toDouble())); + double minY_frac = qMax(0.0, qMin(1.0, vscanConfig["min"].toDouble())); + double maxY_frac = qMax(0.0, qMin(1.0, vscanConfig["max"].toDouble())); + // Fix if the user swapped min and max + if (minX_frac > maxX_frac) { - const QJsonObject& hscanConfig = ledConfigArray[i].toObject()["hscan"].toObject(); - const QJsonObject& vscanConfig = ledConfigArray[i].toObject()["vscan"].toObject(); - double minX_frac = qMax(0.0, qMin(1.0, hscanConfig["minimum"].toDouble())); - double maxX_frac = qMax(0.0, qMin(1.0, hscanConfig["maximum"].toDouble())); - double minY_frac = qMax(0.0, qMin(1.0, vscanConfig["minimum"].toDouble())); - double maxY_frac = qMax(0.0, qMin(1.0, vscanConfig["maximum"].toDouble())); - // Fix if the user swapped min and max - if (minX_frac > maxX_frac) - { - std::swap(minX_frac, maxX_frac); - } - if (minY_frac > maxY_frac) - { - std::swap(minY_frac, maxY_frac); - } - - // calculate mid point and make grid calculation - midPointsX.push_back( int(1000.0*(minX_frac + maxX_frac) / 2.0) ); - midPointsY.push_back( int(1000.0*(minY_frac + maxY_frac) / 2.0) ); + std::swap(minX_frac, maxX_frac); } + if (minY_frac > maxY_frac) + { + std::swap(minY_frac, maxY_frac); + } + + // calculate mid point and make grid calculation + midPointsX.push_back( int(1000.0*(minX_frac + maxX_frac) / 2.0) ); + midPointsY.push_back( int(1000.0*(minY_frac + maxY_frac) / 2.0) ); + } // remove duplicates @@ -315,7 +257,7 @@ namespace hyperion { midPointsY.erase(std::unique(midPointsY.begin(), midPointsY.end()), midPointsY.end()); QSize gridSize( midPointsX.size(), midPointsY.size() ); - //Debug(_log, "led layout grid: %dx%d", gridSize.width(), gridSize.height()); + //Debug(_log, "LED layout grid size: %dx%d", gridSize.width(), gridSize.height()); return gridSize; } diff --git a/libsrc/api/JsonAPI.cpp b/libsrc/api/JsonAPI.cpp index 83127145..66395dc9 100644 --- a/libsrc/api/JsonAPI.cpp +++ b/libsrc/api/JsonAPI.cpp @@ -1464,14 +1464,9 @@ void JsonAPI::streamLedcolorsUpdate(const std::vector& ledColors) QJsonObject result; QJsonArray leds; - for(auto color = ledColors.begin(); color != ledColors.end(); ++color) + for(const auto & color : ledColors) { - QJsonObject item; - item["index"] = int(color - ledColors.begin()); - item["red"] = color->red; - item["green"] = color->green; - item["blue"] = color->blue; - leds.append(item); + leds << QJsonValue(color.red) << QJsonValue(color.green) << QJsonValue(color.blue); } result["leds"] = leds; diff --git a/libsrc/hyperion/Hyperion.cpp b/libsrc/hyperion/Hyperion.cpp index 3995cb2f..f91b8e60 100644 --- a/libsrc/hyperion/Hyperion.cpp +++ b/libsrc/hyperion/Hyperion.cpp @@ -46,7 +46,6 @@ Hyperion::Hyperion(const quint8& instance) , _settingsManager(new SettingsManager(instance, this)) , _componentRegister(this) , _ledString(hyperion::createLedString(getSetting(settings::LEDS).array(), hyperion::createColorOrder(getSetting(settings::DEVICE).object()))) - , _ledStringClone(hyperion::createLedStringClone(getSetting(settings::LEDS).array(), hyperion::createColorOrder(getSetting(settings::DEVICE).object()))) , _imageProcessor(new ImageProcessor(_ledString, this)) , _muxer(_ledString.leds().size()) , _raw2ledAdjustment(hyperion::createLedColorsAdjustment(_ledString.leds().size(), getSetting(settings::COLOR).object())) @@ -87,10 +86,6 @@ void Hyperion::start() { _ledStringColorOrder.push_back(led.colorOrder); } - for (Led& led : _ledStringClone.leds()) - { - _ledStringColorOrder.insert(_ledStringColorOrder.begin() + led.index, led.colorOrder); - } // connect Hyperion::update with Muxer visible priority changes as muxer updates independent connect(&_muxer, &PriorityMuxer::visiblePriorityChanged, this, &Hyperion::update); @@ -202,9 +197,8 @@ void Hyperion::handleSettingsUpdate(const settings::type& type, const QJsonDocum // stop and cache all running effects, as effects depend heavily on ledlayout _effectEngine->cacheRunningEffects(); - // ledstring, clone, img processor, muxer, ledGridSize (eff engine image based effects), _ledBuffer and ByteOrder of ledstring + // ledstring, img processor, muxer, ledGridSize (eff engine image based effects), _ledBuffer and ByteOrder of ledstring _ledString = hyperion::createLedString(leds, hyperion::createColorOrder(getSetting(settings::DEVICE).object())); - _ledStringClone = hyperion::createLedStringClone(leds, hyperion::createColorOrder(getSetting(settings::DEVICE).object())); _imageProcessor->setLedString(_ledString); _muxer.updateLedColorsLength(_ledString.leds().size()); _ledGridSize = hyperion::getLedLayoutGridSize(leds); @@ -217,10 +211,6 @@ void Hyperion::handleSettingsUpdate(const settings::type& type, const QJsonDocum { _ledStringColorOrder.push_back(led.colorOrder); } - for (Led& led : _ledStringClone.leds()) - { - _ledStringColorOrder.insert(_ledStringColorOrder.begin() + led.index, led.colorOrder); - } // handle hwLedCount update _hwLedCount = qMax(unsigned(getSetting(settings::DEVICE).object()["hardwareLedCount"].toInt(getLedCount())), getLedCount()); @@ -244,7 +234,6 @@ void Hyperion::handleSettingsUpdate(const settings::type& type, const QJsonDocum if(_ledDeviceWrapper->getColorOrder() != dev["colorOrder"].toString("rgb")) { _ledString = hyperion::createLedString(getSetting(settings::LEDS).array(), hyperion::createColorOrder(dev)); - _ledStringClone = hyperion::createLedStringClone(getSetting(settings::LEDS).array(), hyperion::createColorOrder(dev)); _imageProcessor->setLedString(_ledString); } @@ -542,12 +531,6 @@ void Hyperion::update() _raw2ledAdjustment->applyAdjustment(_ledBuffer); - // insert cloned leds into buffer - for (Led& led : _ledStringClone.leds()) - { - _ledBuffer.insert(_ledBuffer.begin() + led.index, _ledBuffer.at(led.clone)); - } - int i = 0; for (ColorRgb& color : _ledBuffer) { diff --git a/libsrc/hyperion/schema/schema-leds.json b/libsrc/hyperion/schema/schema-leds.json index c4557e74..c2f23f94 100644 --- a/libsrc/hyperion/schema/schema-leds.json +++ b/libsrc/hyperion/schema/schema-leds.json @@ -8,23 +8,13 @@ "required" : true, "properties": { - "index": - { - "type":"integer", - "required":true, - "default" : 0 - }, - "clone": - { - "type":"integer" - }, - "hscan": + "h": { "type":"object", "required" : true, "properties": { - "minimum": + "min": { "type":"number", "minimum" : 0, @@ -32,7 +22,7 @@ "required":true, "default" : 0 }, - "maximum": + "max": { "type":"number", "minimum" : 0, @@ -43,13 +33,13 @@ }, "additionalProperties" : false }, - "vscan": + "v": { "type":"object", "required" : true, "properties": { - "minimum": + "min": { "type":"number", "minimum" : 0, @@ -57,7 +47,7 @@ "required":true, "default" : 0 }, - "maximum": + "max": { "type":"number", "minimum" : 0, From 782d44b81b62271929844c6fd939edd940222983 Mon Sep 17 00:00:00 2001 From: Paulchen Panther <16664240+Paulchen-Panther@users.noreply.github.com> Date: Wed, 28 Aug 2019 22:20:49 +0200 Subject: [PATCH 4/4] [Bugfix] V4L2 used screen resolution for fallback https://hyperion-project.org/threads/ng-hyperion-v4l2-capture-resolution-issue.3684/#post-15959 --- libsrc/grabber/v4l2/V4L2Grabber.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libsrc/grabber/v4l2/V4L2Grabber.cpp b/libsrc/grabber/v4l2/V4L2Grabber.cpp index ae6047f1..43db07c3 100644 --- a/libsrc/grabber/v4l2/V4L2Grabber.cpp +++ b/libsrc/grabber/v4l2/V4L2Grabber.cpp @@ -617,8 +617,16 @@ void V4L2Grabber::init_device(VideoStandard videoStandard, int input) } // set the settings - fmt.fmt.pix.width = max_width; - fmt.fmt.pix.height = max_height; + if (max_width != 0 || max_height != 0) + { + fmt.fmt.pix.width = max_width; + fmt.fmt.pix.height = max_height; + } + else + { + fmt.fmt.pix.width = _width; + fmt.fmt.pix.height = _height; + } if (-1 == xioctl(VIDIOC_S_FMT, &fmt)) {