Skip to content

Commit b7f5b75

Browse files
committed
Automatic tone mapping control: add timeout option for turning tone mapping off
1 parent e7aa8ef commit b7f5b75

8 files changed

Lines changed: 70 additions & 31 deletions

File tree

include/base/AutomaticToneMapping.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class AutomaticToneMapping
4141

4242
AutomaticToneMapping* prepare();
4343
void finilize();
44-
void setConfig(bool enabled, const ToneMappingThresholds& newConfig, int timeInSec);
44+
void setConfig(bool enabled, const ToneMappingThresholds& newConfig, int timeInSec, int timeToDisableInMSec);
4545
void setToneMapping(bool enabled);
4646

4747
constexpr uint8_t checkY(uint8_t y)
@@ -71,12 +71,13 @@ class AutomaticToneMapping
7171
private:
7272
bool _enabled;
7373
int _timeInSec;
74+
int _timeToDisableInMSec;
7475

7576
ToneMappingThresholds _config, _running;
7677

7778
bool _modeSDR;
7879
long _startedTime;
79-
int _gracefulTimeout;
80+
long _endingTime;
8081
Logger* _log;
8182

8283
};

include/base/Grabber.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ class Grabber : public DetectionAutomatic, public DetectionManual, protected Lut
126126

127127
QString getConfigurationPath();
128128

129-
void setAutomaticToneMappingConfig(bool enabled, const AutomaticToneMapping::ToneMappingThresholds& newConfig, int timeInSec);
129+
void setAutomaticToneMappingConfig(bool enabled, const AutomaticToneMapping::ToneMappingThresholds& newConfig, int timeInSec, int timeToDisableInMSec);
130130
void setAutoToneMappingCurrentStateEnabled(bool enabled);
131131

132132
struct DevicePropertiesItem

sources/base/AutomaticToneMapping.cpp

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,12 @@
3737
AutomaticToneMapping::AutomaticToneMapping() :
3838
_enabled(false),
3939
_timeInSec(30),
40+
_timeToDisableInMSec(500),
4041
_config{},
4142
_running{},
4243
_modeSDR(true),
4344
_startedTime(0),
44-
_gracefulTimeout(DEFAULT_GRACEFUL_TIMEOUT),
45+
_endingTime(0),
4546
_log(Logger::getInstance(QString("AUTOTONEMAPPING")))
4647
{
4748
}
@@ -64,20 +65,28 @@ void AutomaticToneMapping::finilize()
6465
{
6566
bool triggered = (_config.y != _running.y || _config.u != _running.u || _config.v != _running.v);
6667

67-
if (triggered && !_modeSDR && _gracefulTimeout-- <= 0)
68+
if (triggered && !_modeSDR)
6869
{
69-
QString message = "Tone mapping OFF triggered by: ";
70-
if (_config.y != _running.y)
71-
message += QString(" Y threshold (%1), ").arg(_running.y);
72-
if (_config.u != _running.u)
73-
message += QString(" U threshold (%1), ").arg(_running.u);
74-
if (_config.v != _running.v)
75-
message += QString(" V threshold (%1), ").arg(_running.v);
76-
Info(_log, "%s", QSTRING_CSTR(message));
77-
78-
_modeSDR = true;
79-
_startedTime = 0;
80-
GlobalSignals::getInstance()->SignalRequestComponent(hyperhdr::Components::COMP_HDR, -1, false);
70+
auto now = InternalClock::now();
71+
if (_endingTime == 0 || _endingTime > now)
72+
{
73+
_endingTime = now;
74+
}
75+
else if (_endingTime + _timeToDisableInMSec <= now)
76+
{
77+
QString message = "Tone mapping OFF triggered by: ";
78+
if (_config.y != _running.y)
79+
message += QString(" Y threshold (%1), ").arg(_running.y);
80+
if (_config.u != _running.u)
81+
message += QString(" U threshold (%1), ").arg(_running.u);
82+
if (_config.v != _running.v)
83+
message += QString(" V threshold (%1), ").arg(_running.v);
84+
Info(_log, "%s after %i ms", QSTRING_CSTR(message), now - _endingTime);
85+
86+
87+
_modeSDR = true;
88+
GlobalSignals::getInstance()->SignalRequestComponent(hyperhdr::Components::COMP_HDR, -1, false);
89+
}
8190
}
8291
else if (!triggered && _modeSDR)
8392
{
@@ -86,35 +95,43 @@ void AutomaticToneMapping::finilize()
8695
{
8796
_startedTime = now;
8897
}
89-
else if (_startedTime + _timeInSec < now)
98+
else if (_startedTime + _timeInSec <= now)
9099
{
91100
_modeSDR = false;
92-
Info(_log, "Tone mapping ON triggered by configured time");
101+
Info(_log, "Tone mapping ON triggered after %i sec", now - _startedTime);
93102
GlobalSignals::getInstance()->SignalRequestComponent(hyperhdr::Components::COMP_HDR, -1, true);
94103
}
95104
}
96105

97106
if (!triggered)
98-
_gracefulTimeout = DEFAULT_GRACEFUL_TIMEOUT;
107+
{
108+
_endingTime = 0;
109+
}
110+
else
111+
{
112+
_startedTime = 0;
113+
}
99114

100115
_running = _config;
101116
}
102117
}
103118

104-
void AutomaticToneMapping::setConfig(bool enabled, const ToneMappingThresholds& newConfig, int timeInSec)
119+
void AutomaticToneMapping::setConfig(bool enabled, const ToneMappingThresholds& newConfig, int timeInSec, int timeToDisableInMSec)
105120
{
106121
_enabled = enabled;
107122
_config = newConfig;
108123
_timeInSec = timeInSec;
124+
_timeToDisableInMSec = timeToDisableInMSec;
109125
_running = _config;
110-
Info(_log, "Enabled: %s, Time: %i, Thresholds: %i, %i, %i", (enabled) ? "yes" : "no", timeInSec, _config.y, _config.u, _config.v);
126+
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);
111127
}
112128

113129
void AutomaticToneMapping::setToneMapping(bool enabled)
114130
{
131+
Info(_log, "Tone mapping is currently: %s", (enabled) ? "enabled" : "disabled");
115132
_modeSDR = !enabled;
116133
_startedTime = 0;
117-
_gracefulTimeout = DEFAULT_GRACEFUL_TIMEOUT;
134+
_endingTime = 0;
118135
}
119136

120137

sources/base/Grabber.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -967,9 +967,9 @@ void Grabber::signalSetLutHandler(MemoryBuffer<uint8_t>* lut)
967967
Error(_log, "Could not set LUT: current size = %i, incoming size = %i", _lut.size(), (lut != nullptr) ? lut->size() : 0);
968968
}
969969

970-
void Grabber::setAutomaticToneMappingConfig(bool enabled, const AutomaticToneMapping::ToneMappingThresholds& newConfig, int timeInSec)
970+
void Grabber::setAutomaticToneMappingConfig(bool enabled, const AutomaticToneMapping::ToneMappingThresholds& newConfig, int timeInSec, int timeToDisableInMSec)
971971
{
972-
_automaticToneMapping.setConfig(enabled, newConfig, timeInSec);
972+
_automaticToneMapping.setConfig(enabled, newConfig, timeInSec, timeToDisableInMSec);
973973
if (_automaticToneMapping.prepare() && !_qframe)
974974
Error(_log, "Automatic tone mapping requires 'Quarter of frame' mode enabled");
975975
if (_automaticToneMapping.prepare() && (_enc != PixelFormat::YUYV && _enc != PixelFormat::NV12 && _enc != PixelFormat::P010 ))

sources/base/GrabberWrapper.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -589,8 +589,9 @@ void GrabberWrapper::handleSettingsUpdate(settings::type type, const QJsonDocume
589589
t.y = obj["tone_mapping_y_threshold"].toInt(155);
590590
t.u = obj["tone_mapping_u_threshold"].toInt(175);
591591
t.v = obj["tone_mapping_v_threshold"].toInt(160);
592-
auto time = obj["time_to_tone_mapping"].toInt(30);
593-
_grabber->setAutomaticToneMappingConfig(enabled, t, time);
592+
auto timeToEnableInSec = obj["time_to_tone_mapping"].toInt(30);
593+
auto timeToDisableInMSec = obj["time_to_disable_tone_mapping"].toInt(500);
594+
_grabber->setAutomaticToneMappingConfig(enabled, t, timeToEnableInSec, timeToDisableInMSec);
594595
}
595596
}
596597

sources/base/schema/schema-automaticToneMapping.json

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,25 @@
8080
}
8181
},
8282
"propertyOrder" : 5
83-
}
83+
},
84+
"time_to_disable_tone_mapping" :
85+
{
86+
"type" : "integer",
87+
"format": "stepper",
88+
"step" : 100,
89+
"title" : "edt_automatic_tone_mapping_disable_time_title",
90+
"minimum" : 0,
91+
"maximum": 5000,
92+
"default" : 500,
93+
"append" : "edt_append_ms",
94+
"required" : true,
95+
"options": {
96+
"dependencies": {
97+
"enable": true
98+
}
99+
},
100+
"propertyOrder" : 6
101+
}
84102
},
85103
"additionalProperties" : false
86104
}

sources/lut-calibrator/LutCalibrator.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1852,7 +1852,7 @@ void LutCalibrator::CreateDefaultLut(QString filepath)
18521852
bestResult.signal.downYLimit = 0.062745;
18531853
bestResult.signal.yShift = 0.062745;
18541854
bestResult.signal.isSourceP010 = 0;
1855-
bestResult.minError = 212.883333;
1855+
bestResult.minError = 212;
18561856

18571857
auto worker = new DefaultLutCreatorWorker(bestResult, filepath);
18581858
QThreadPool::globalInstance()->start(worker);

www/i18n/en.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1253,13 +1253,15 @@
12531253
"chk_lchCorrection": "LCH color correction",
12541254
"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.",
12551255
"edt_automatic_tone_mapping_title" : "Automatic tone mapping",
1256-
"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.",
1256+
"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).",
12571257
"edt_automatic_tone_mapping_y_threshold_title" : "Brightness threshold (Y)",
12581258
"edt_automatic_tone_mapping_y_threshold_expl" : "The brightness level that separates raw dark HDR material from the SDR signal",
12591259
"edt_automatic_tone_mapping_u_threshold_title" : "Blue chroma threshold (U)",
12601260
"edt_automatic_tone_mapping_u_threshold_expl" : "Blue chroma level that separates raw pale HDR material from the SDR signal",
12611261
"edt_automatic_tone_mapping_v_threshold_title" : "Red chroma threshold (V)",
12621262
"edt_automatic_tone_mapping_v_threshold_expl" : "Red chroma level that separates raw pale HDR material from the SDR signal",
12631263
"edt_automatic_tone_mapping_time_title" : "Time to turn on tone mapping",
1264-
"edt_automatic_tone_mapping_time_expl" : "Time to turn on tone mapping if the signal does not exceed the configured threshold levels"
1264+
"edt_automatic_tone_mapping_time_expl" : "Time to turn on tone mapping if the signal does not exceed the configured threshold levels",
1265+
"edt_automatic_tone_mapping_disable_time_title" : "Time to turn off tone mapping",
1266+
"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."
12651267
}

0 commit comments

Comments
 (0)