awawa-dev / HyperHDR

Highly optimized open source ambient lighting implementation based on modern digital video and audio stream analysis for Windows, macOS and Linux (x86 and Raspberry Pi / ARM).
http://www.hyperhdr.eu/
MIT License
1.13k stars 118 forks source link

SDR colours incorrect with HDR mapping enabled #56

Closed EverythingSmartHome closed 3 years ago

EverythingSmartHome commented 3 years ago

Feature request

I'm not sure if this is even possible or if it would even be a feature, perhaps I'm even doing something wrong (definitely a possibility!) but is there a way to detect HDR content playing and have the HDR to SDR tone mapping feature auto-toggle? Or if this isn't possible, would there be away to integrate this feature into the API so that it would be possible to toggle it with something like Home Assistant?

The problem I have is that HDR content looks nice using the LUT and having the HDR to SDR tone mapping feature enabled, but when playing SDR content (which often happens) then the colours are off. Is there a way around this that you can think of?

What problem does this feature solve?

SDR content would look normal when HDR to SDR tone mapping is enabled.

What does the proposed API look like?

How should this be implemented in your opinion?

Are you willing to work on this yourself?

awawa-dev commented 3 years ago

Hi There is no reliable way to auto-detect HDR from the image that was capture by the grabber as SDR. There are approaches to detect bleak colors that come with limited usage of luminescence. But I doubt it will work for every grabber with every factory settings of brightness/contrast/saturation. And it would take some time to switch HDR on/off because otherwise the screen would switching on/off on dark scenes where there is no way to distinguish for sure SDR from HDR.

However if you have AVR like Denon it can inform us about detected stream. Some TV and other amplifiers can share similar info via API.

Thanks to user @Puck from hyperion-project forum below is sample integration for Denon & HA but similar approach can be used for other systems:

In order to get the signal state I use the following sensor:

- platform: scrape
name: denon_signal_hdr
resource: https://{IP_OF_DENON_AVR}:1234/ajax/general/get_config?type=12
verify_ssl: false
select: "Information Video HDMISignalInfo HDR"
scan_interval: 10


The following switch toggles the HyperHDR tone mapping:

- platform: command_line
switches:
hyperion_toggle_hdr:
command_on: 'curl -X POST -i "http://{IP_OF_HYPERHDR}:8090/json-rpc" -d ''{"command":"videomodehdr","HDR":1}'''
command_off: 'curl -X POST -i "http://{IP_OF_HYPERHDR}:8090/json-rpc" -d ''{"command":"videomodehdr","HDR":0}'''
command_state: "curl -k http://{IP_OF_HYPERHDR}:8090/json-rpc -H 'Content-Type: application/json' -d '{\"command\":\"serverinfo\"}'"
value_template: >
{% if value_json.info.videomodehdr == 1 %}
{{ true }}
{% else %}
{{ false }}
{% endif %}

The following automation toggles the HyperHDR tone mapping based on the Denon AVR state:

# HDR off: ' --- -> --- '
# HDR on: 'HDR10 -> HDR10'
- id: ambilight_toggle_tone_mapping
alias: Ambilight - Toggle tone-mapping based on HDR/SDR input signal
trigger:
- platform: state
entity_id: sensor.denon_signal_hdr
action:
service_template: >
{% if is_state('sensor.denon_signal_hdr', 'HDR10 -> HDR10') %}
switch.turn_on
{% else %}
switch.turn_off
{% endif %}
entity_id: switch.hyperion_toggle_hdr
EverythingSmartHome commented 3 years ago

Thanks for the quick response, especially on the weekend!

Your explanation makes perfect sense and something I kinda figured. I didn't know about using json-rpc to toggle it, I managed to get that setup in Home Assistant and works well. Unfortunately I don't have a way of getting the HDR status through my current setup, but having the switch in Home Assistant is a big help and I can work with that.

Thanks for all the great work, appreciate it!

awawa-dev commented 3 years ago

There is a new method to turn on/off HDR tone mapping but still it's not an automatic process and requires Raspberry Pi with CEC to control it with a TV remote: https://github.com/awawa-dev/HyperHDR/releases/tag/v17.0.0.0beta Maybe some future devices/grabbers/TV's API will provide us some meta information about the stream or will do HDR tone mapping on their own but for now can't solve it in a different way.

dawiinci commented 2 years ago

Will there be any progress on this topic in 18.0.0.0?

I am trying to get the information of the HDR status from Panasonic Viera or the Onkyo Receiver, but no success until now. Do you have any ideas regarding these devices?

awawa-dev commented 2 years ago

Nope. Only Denons and not updated LG's TV.

dawiinci commented 2 years ago

So what is the best way to handle this? Will this ever be automatic?

Should I always enable HDR?

awawa-dev commented 2 years ago

For my video system I have HDR always enabled (SDR content is "upgraded" to HDR by the video player).

pandel commented 2 years ago

Nope. Only Denons and not updated LG's TV.

I can say that also Marantz, in my case a 5015, supports the same URL to receive HDR status.

awawa-dev commented 2 years ago

Good to know they unified API with Denon. As a curiosity: the AV ACCESS 4KVC00 grabber also provides information about the video stream (including HDR status) on the COM port.

pandel commented 2 years ago

Interesting! I am using a WisFox (2109) grabber and this one does not give any further information.

I am using the URL method in combination with ioBroker as my home automation. I use the following ioBroker JavaScript. It is quite hacky but does its job. Perhaps someone finds it useful:

// create some global vars
var run;
var reso;
var hdr;
var hdr_state = "false";
const receiver = '192.168.178.49:10443';
const hyperhdr = 'mediapc.fritz.box:8090';

on({id:"denon.0.zoneMain.powerZone"}, function (obj) {
    if (obj.state.val === true || obj.state.val === "true") {
        log("Interval gestartet",'info');
        run = setInterval(function() {
            setHDRMode();
        }, 30000);
    } else {
        log("Interval gestoppt",'info');
        clearInterval(run)
    }
});

function setHDRMode() {
    const request = require('request');
    var parseString = require('xml2js').parseString;

    const options = {
        url: 'https://'+receiver+'/ajax/general/get_config?type=12',
        agentOptions: {
            strictSSL: false,
            rejectUnauthorized: false
        }
    };

    request.get(options, function (error, response, body) {
        if (error) log(error, 'error'); // Print the error if one occurred
        //log('statusCode:'+ response && response.statusCode, 'debug'); // Print the response status code if a response was received
        //log(body, 'debug');
        parseString(body, function(err, result) {
            //log(result, 'info');
            reso = result.Information.Video[0].HDMISignalInfo[0].Resolution[0];
            hdr = result.Information.Video[0].HDMISignalInfo[0].HDR[0];
            log('Current resolution: ' + reso, 'debug');
            log('Current HDR status: ' + hdr, 'debug');
            // HDR off: ' --- -> --- '
            // HDR on: 'HDR10 -> HDR10'
            if (hdr.includes("HDR")) {
                switchHDR("true");
            } else {
                switchHDR("false");
            }
        });
    });
};

function switchHDR(mode) {
    if (mode !== hdr_state ) {
        try {
            require("request")('http://'+hyperhdr+'/json-rpc?request=%7B%22command%22:%22componentstate%22,%22componentstate%22:%7B%22component%22:%22HDR%22,%22state%22:'+mode+'%7D%7D').on("error", function (e) {console.error(e);});
            hdr_state = mode;
            log("Switched HDR mode to:"+hdr_state, 'info');
        } catch (e) { console.error(e); }
    }
};

(Please ignore the reso(lution) stuff, I thought it might be useful sometime...)