Skip to content

Commit

Permalink
Automatic tone mapping control: add timeout option for turning tone m…
Browse files Browse the repository at this point in the history
…apping off
  • Loading branch information
awawa-dev committed Nov 30, 2024
1 parent e7aa8ef commit b7f5b75
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 31 deletions.
5 changes: 3 additions & 2 deletions include/base/AutomaticToneMapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class AutomaticToneMapping

AutomaticToneMapping* prepare();
void finilize();
void setConfig(bool enabled, const ToneMappingThresholds& newConfig, int timeInSec);
void setConfig(bool enabled, const ToneMappingThresholds& newConfig, int timeInSec, int timeToDisableInMSec);
void setToneMapping(bool enabled);

constexpr uint8_t checkY(uint8_t y)
Expand Down Expand Up @@ -71,12 +71,13 @@ class AutomaticToneMapping
private:
bool _enabled;
int _timeInSec;
int _timeToDisableInMSec;

ToneMappingThresholds _config, _running;

bool _modeSDR;
long _startedTime;
int _gracefulTimeout;
long _endingTime;
Logger* _log;

};
2 changes: 1 addition & 1 deletion include/base/Grabber.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ class Grabber : public DetectionAutomatic, public DetectionManual, protected Lut

QString getConfigurationPath();

void setAutomaticToneMappingConfig(bool enabled, const AutomaticToneMapping::ToneMappingThresholds& newConfig, int timeInSec);
void setAutomaticToneMappingConfig(bool enabled, const AutomaticToneMapping::ToneMappingThresholds& newConfig, int timeInSec, int timeToDisableInMSec);
void setAutoToneMappingCurrentStateEnabled(bool enabled);

struct DevicePropertiesItem
Expand Down
57 changes: 37 additions & 20 deletions sources/base/AutomaticToneMapping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,12 @@
AutomaticToneMapping::AutomaticToneMapping() :
_enabled(false),
_timeInSec(30),
_timeToDisableInMSec(500),
_config{},
_running{},
_modeSDR(true),
_startedTime(0),
_gracefulTimeout(DEFAULT_GRACEFUL_TIMEOUT),
_endingTime(0),
_log(Logger::getInstance(QString("AUTOTONEMAPPING")))
{
}
Expand All @@ -64,20 +65,28 @@ void AutomaticToneMapping::finilize()
{
bool triggered = (_config.y != _running.y || _config.u != _running.u || _config.v != _running.v);

if (triggered && !_modeSDR && _gracefulTimeout-- <= 0)
if (triggered && !_modeSDR)
{
QString message = "Tone mapping OFF triggered by: ";
if (_config.y != _running.y)
message += QString(" Y threshold (%1), ").arg(_running.y);
if (_config.u != _running.u)
message += QString(" U threshold (%1), ").arg(_running.u);
if (_config.v != _running.v)
message += QString(" V threshold (%1), ").arg(_running.v);
Info(_log, "%s", QSTRING_CSTR(message));

_modeSDR = true;
_startedTime = 0;
GlobalSignals::getInstance()->SignalRequestComponent(hyperhdr::Components::COMP_HDR, -1, false);
auto now = InternalClock::now();
if (_endingTime == 0 || _endingTime > now)
{
_endingTime = now;
}
else if (_endingTime + _timeToDisableInMSec <= now)
{
QString message = "Tone mapping OFF triggered by: ";
if (_config.y != _running.y)
message += QString(" Y threshold (%1), ").arg(_running.y);
if (_config.u != _running.u)
message += QString(" U threshold (%1), ").arg(_running.u);
if (_config.v != _running.v)
message += QString(" V threshold (%1), ").arg(_running.v);
Info(_log, "%s after %i ms", QSTRING_CSTR(message), now - _endingTime);


_modeSDR = true;
GlobalSignals::getInstance()->SignalRequestComponent(hyperhdr::Components::COMP_HDR, -1, false);
}
}
else if (!triggered && _modeSDR)
{
Expand All @@ -86,35 +95,43 @@ void AutomaticToneMapping::finilize()
{
_startedTime = now;
}
else if (_startedTime + _timeInSec < now)
else if (_startedTime + _timeInSec <= now)
{
_modeSDR = false;
Info(_log, "Tone mapping ON triggered by configured time");
Info(_log, "Tone mapping ON triggered after %i sec", now - _startedTime);
GlobalSignals::getInstance()->SignalRequestComponent(hyperhdr::Components::COMP_HDR, -1, true);
}
}

if (!triggered)
_gracefulTimeout = DEFAULT_GRACEFUL_TIMEOUT;
{
_endingTime = 0;
}
else
{
_startedTime = 0;
}

_running = _config;
}
}

void AutomaticToneMapping::setConfig(bool enabled, const ToneMappingThresholds& newConfig, int timeInSec)
void AutomaticToneMapping::setConfig(bool enabled, const ToneMappingThresholds& newConfig, int timeInSec, int timeToDisableInMSec)
{
_enabled = enabled;
_config = newConfig;
_timeInSec = timeInSec;
_timeToDisableInMSec = timeToDisableInMSec;
_running = _config;
Info(_log, "Enabled: %s, Time: %i, Thresholds: %i, %i, %i", (enabled) ? "yes" : "no", timeInSec, _config.y, _config.u, _config.v);
Info(_log, "Enabled: %s, time to enable: %is, time to disable: %ims, thresholds: { %i, %i, %i}", (enabled) ? "yes" : "no", _timeInSec, _timeToDisableInMSec, _config.y, _config.u, _config.v);
}

void AutomaticToneMapping::setToneMapping(bool enabled)
{
Info(_log, "Tone mapping is currently: %s", (enabled) ? "enabled" : "disabled");
_modeSDR = !enabled;
_startedTime = 0;
_gracefulTimeout = DEFAULT_GRACEFUL_TIMEOUT;
_endingTime = 0;
}


4 changes: 2 additions & 2 deletions sources/base/Grabber.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -967,9 +967,9 @@ void Grabber::signalSetLutHandler(MemoryBuffer<uint8_t>* lut)
Error(_log, "Could not set LUT: current size = %i, incoming size = %i", _lut.size(), (lut != nullptr) ? lut->size() : 0);
}

void Grabber::setAutomaticToneMappingConfig(bool enabled, const AutomaticToneMapping::ToneMappingThresholds& newConfig, int timeInSec)
void Grabber::setAutomaticToneMappingConfig(bool enabled, const AutomaticToneMapping::ToneMappingThresholds& newConfig, int timeInSec, int timeToDisableInMSec)
{
_automaticToneMapping.setConfig(enabled, newConfig, timeInSec);
_automaticToneMapping.setConfig(enabled, newConfig, timeInSec, timeToDisableInMSec);
if (_automaticToneMapping.prepare() && !_qframe)
Error(_log, "Automatic tone mapping requires 'Quarter of frame' mode enabled");
if (_automaticToneMapping.prepare() && (_enc != PixelFormat::YUYV && _enc != PixelFormat::NV12 && _enc != PixelFormat::P010 ))
Expand Down
5 changes: 3 additions & 2 deletions sources/base/GrabberWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -589,8 +589,9 @@ void GrabberWrapper::handleSettingsUpdate(settings::type type, const QJsonDocume
t.y = obj["tone_mapping_y_threshold"].toInt(155);
t.u = obj["tone_mapping_u_threshold"].toInt(175);
t.v = obj["tone_mapping_v_threshold"].toInt(160);
auto time = obj["time_to_tone_mapping"].toInt(30);
_grabber->setAutomaticToneMappingConfig(enabled, t, time);
auto timeToEnableInSec = obj["time_to_tone_mapping"].toInt(30);
auto timeToDisableInMSec = obj["time_to_disable_tone_mapping"].toInt(500);
_grabber->setAutomaticToneMappingConfig(enabled, t, timeToEnableInSec, timeToDisableInMSec);
}
}

Expand Down
20 changes: 19 additions & 1 deletion sources/base/schema/schema-automaticToneMapping.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,25 @@
}
},
"propertyOrder" : 5
}
},
"time_to_disable_tone_mapping" :
{
"type" : "integer",
"format": "stepper",
"step" : 100,
"title" : "edt_automatic_tone_mapping_disable_time_title",
"minimum" : 0,
"maximum": 5000,
"default" : 500,
"append" : "edt_append_ms",
"required" : true,
"options": {
"dependencies": {
"enable": true
}
},
"propertyOrder" : 6
}
},
"additionalProperties" : false
}
2 changes: 1 addition & 1 deletion sources/lut-calibrator/LutCalibrator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1852,7 +1852,7 @@ void LutCalibrator::CreateDefaultLut(QString filepath)
bestResult.signal.downYLimit = 0.062745;
bestResult.signal.yShift = 0.062745;
bestResult.signal.isSourceP010 = 0;
bestResult.minError = 212.883333;
bestResult.minError = 212;

auto worker = new DefaultLutCreatorWorker(bestResult, filepath);
QThreadPool::globalInstance()->start(worker);
Expand Down
6 changes: 4 additions & 2 deletions www/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1253,13 +1253,15 @@
"chk_lchCorrection": "LCH color correction",
"grabber_calibration_expl": "This tool allows you to create a new calibrated HDR LUT for your grabber (or external flatbuffers source) as close to the actual input colors as possible.<br/>You need an HDR10 video source that can display this web page, for example: Windows 10 with HDR enabled in the properties of the graphics driver.<br/>The screen may flicker during calibration. The process typically takes about few minutes on a Intel 7 Windows PC (depending on the host CPU resources and the video capturing framerate).<br/><b>The calculations are very intensive and put a strain on your equipment <svg data-src='svg/performance_undervoltage.svg' class='svg4hyperhdr ms-1'></svg></b>You can disable LCH color correction to reduce the load a bit<br/>You can monitor the progress in HyperHDR logs using the browser from other device.<br/><br/><br/><b>1</b> If everything is properly connected, this page should be displayed on the TV screen (as HDR content) and live preview in HyperHDR (captured by the grabber).</br><b>2</b> Absolute minimum capturing resolution is 1280x720 (we will verify this). Recommended is 1920x1080 YUV/NV12. Aspect 1920/1080 must be preserved.<br/><b>3</b> You must disable 'Quarter of frame mode' in your grabber properties if it's enabled.<br/><b>4</b> You must set the grabber's video format to MJPEG/YUV/NV12/P010.<br/><b>5</b> Before you run the process please put your WWW browser in the full-screen mode (F11 key, we will verify this).</br><b>6</b> <b>If you are calibrating using Windows 11, turn off features such as 'Night light', 'Automatic manage color for apps' and 'Auto-HDR'. Do not change the color balance in the graphics driver. The GFX output should support e.g. 10 or 12 bit RGB in full PC range.</b><br/><br/>After completing the calibration, your new LUT table file (lut_lin_tables.3d) will be created in the user's HyperHDR home directory and is immediately ready to use when you just enable HDR tone mapping. Please verify HyperHDR logs for details.",
"edt_automatic_tone_mapping_title" : "Automatic tone mapping",
"edt_automatic_tone_mapping_enable_explain" : "Automatic tone mapping control is only available for <span style='color:red;'>'YUV/NV12/P010'</span> video formats with <span style='color:red;'>'Quarter of frame'</span> mode enabled. Please configure them in the USB grabber settings.<br/>The component will automatically enable tone mapping if the signal does not exceed the configured threshold levels for a certain period of time, and will disable it immediately after exceeding them.",
"edt_automatic_tone_mapping_enable_explain" : "Automatic tone mapping control is only available for <span style='color:red;'>'YUV/NV12/P010'</span> video formats with <span style='color:red;'>'Quarter of frame'</span> mode enabled. Please configure them in the USB grabber settings.<br/>The component will automatically enable tone mapping if the signal does not exceed the configured threshold levels for a certain period of time, and will disable it immediately after exceeding them.<br/>Then later you can check what was the value that exceeded any of the thresholds, which actually caused tone mapping to be disabled in HyperHDR logs. And then possibly adjust the configuration if it generates false events of tone mapping disabling (threshold too low) or generates unnecessary tone mapping enabling in dark SDR scenes (threshold too high).",
"edt_automatic_tone_mapping_y_threshold_title" : "Brightness threshold (Y)",
"edt_automatic_tone_mapping_y_threshold_expl" : "The brightness level that separates raw dark HDR material from the SDR signal",
"edt_automatic_tone_mapping_u_threshold_title" : "Blue chroma threshold (U)",
"edt_automatic_tone_mapping_u_threshold_expl" : "Blue chroma level that separates raw pale HDR material from the SDR signal",
"edt_automatic_tone_mapping_v_threshold_title" : "Red chroma threshold (V)",
"edt_automatic_tone_mapping_v_threshold_expl" : "Red chroma level that separates raw pale HDR material from the SDR signal",
"edt_automatic_tone_mapping_time_title" : "Time to turn on tone mapping",
"edt_automatic_tone_mapping_time_expl" : "Time to turn on tone mapping if the signal does not exceed the configured threshold levels"
"edt_automatic_tone_mapping_time_expl" : "Time to turn on tone mapping if the signal does not exceed the configured threshold levels",
"edt_automatic_tone_mapping_disable_time_title" : "Time to turn off tone mapping",
"edt_automatic_tone_mapping_disable_time_expl" : "In an ideal world this value should be zero, because tone mapping should be disabled immediately after crossing one of the thresholds. But it happens, for example: when starting or switching resolution, the grabber can generate junk frames, which can disable tone mapping unnecessarily."
}

0 comments on commit b7f5b75

Please sign in to comment.