EDID (VESA Enhanced Extended Display Identification Data): C++11/STL parsing library

KS implementation details

License: CC0-1.0

References

This page hosts a formal specification of EDID (VESA Enhanced Extended Display Identification Data) using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Usage

Runtime library

All parsing code for C++11/STL generated by Kaitai Struct depends on the C++/STL runtime library. You have to install it before you can parse data.

For C++, the easiest way is to clone the runtime library sources and build them along with your project.

Code

Using Kaitai Struct in C++/STL usually consists of 3 steps.

  1. We need to create an STL input stream (std::istream). One can open local file for that, or use existing std::string or char* buffer.
    #include <fstream>
    
    std::ifstream is("path/to/local/file.bin", std::ifstream::binary);
    
    #include <sstream>
    
    std::istringstream is(str);
    
    #include <sstream>
    
    const char buf[] = { ... };
    std::string str(buf, sizeof buf);
    std::istringstream is(str);
    
  2. We need to wrap our input stream into Kaitai stream:
    #include "kaitai/kaitaistream.h"
    
    kaitai::kstream ks(&is);
    
  3. And finally, we can invoke the parsing:
    edid_t data(&ks);
    

After that, one can get various attributes from the structure by invoking getter methods like:

data.product_code() // => Manufacturer product code

C++11/STL source code to parse EDID (VESA Enhanced Extended Display Identification Data)

edid.h

#pragma once

// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

class edid_t;

#include "kaitai/kaitaistruct.h"
#include <stdint.h>
#include <memory>
#include <vector>
#include <set>

#if KAITAI_STRUCT_VERSION < 11000L
#error "Incompatible Kaitai Struct C++/STL API: version 0.11 or later is required"
#endif

class edid_t : public kaitai::kstruct {

public:
    class chromacity_info_t;
    class est_timings_info_t;
    class std_timing_t;

    edid_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, edid_t* p__root = nullptr);

private:
    void _read();
    void _clean_up();

public:
    ~edid_t();

    /**
     * Chromaticity information: colorimetry and white point
     * coordinates. All coordinates are stored as fixed precision
     * 10-bit numbers, bits are shuffled for compactness.
     */

    class chromacity_info_t : public kaitai::kstruct {

    public:

        chromacity_info_t(kaitai::kstream* p__io, edid_t* p__parent = nullptr, edid_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~chromacity_info_t();

    private:
        bool f_blue_x;
        double m_blue_x;

    public:

        /**
         * Blue X coordinate
         */
        double blue_x();

    private:
        bool f_blue_x_int;
        int32_t m_blue_x_int;

    public:
        int32_t blue_x_int();

    private:
        bool f_blue_y;
        double m_blue_y;

    public:

        /**
         * Blue Y coordinate
         */
        double blue_y();

    private:
        bool f_blue_y_int;
        int32_t m_blue_y_int;

    public:
        int32_t blue_y_int();

    private:
        bool f_green_x;
        double m_green_x;

    public:

        /**
         * Green X coordinate
         */
        double green_x();

    private:
        bool f_green_x_int;
        int32_t m_green_x_int;

    public:
        int32_t green_x_int();

    private:
        bool f_green_y;
        double m_green_y;

    public:

        /**
         * Green Y coordinate
         */
        double green_y();

    private:
        bool f_green_y_int;
        int32_t m_green_y_int;

    public:
        int32_t green_y_int();

    private:
        bool f_red_x;
        double m_red_x;

    public:

        /**
         * Red X coordinate
         */
        double red_x();

    private:
        bool f_red_x_int;
        int32_t m_red_x_int;

    public:
        int32_t red_x_int();

    private:
        bool f_red_y;
        double m_red_y;

    public:

        /**
         * Red Y coordinate
         */
        double red_y();

    private:
        bool f_red_y_int;
        int32_t m_red_y_int;

    public:
        int32_t red_y_int();

    private:
        bool f_white_x;
        double m_white_x;

    public:

        /**
         * White X coordinate
         */
        double white_x();

    private:
        bool f_white_x_int;
        int32_t m_white_x_int;

    public:
        int32_t white_x_int();

    private:
        bool f_white_y;
        double m_white_y;

    public:

        /**
         * White Y coordinate
         */
        double white_y();

    private:
        bool f_white_y_int;
        int32_t m_white_y_int;

    public:
        int32_t white_y_int();

    private:
        uint64_t m_red_x_1_0;
        uint64_t m_red_y_1_0;
        uint64_t m_green_x_1_0;
        uint64_t m_green_y_1_0;
        uint64_t m_blue_x_1_0;
        uint64_t m_blue_y_1_0;
        uint64_t m_white_x_1_0;
        uint64_t m_white_y_1_0;
        uint8_t m_red_x_9_2;
        uint8_t m_red_y_9_2;
        uint8_t m_green_x_9_2;
        uint8_t m_green_y_9_2;
        uint8_t m_blue_x_9_2;
        uint8_t m_blue_y_9_2;
        uint8_t m_white_x_9_2;
        uint8_t m_white_y_9_2;
        edid_t* m__root;
        edid_t* m__parent;

    public:

        /**
         * Red X, bits 1..0
         */
        uint64_t red_x_1_0() const { return m_red_x_1_0; }

        /**
         * Red Y, bits 1..0
         */
        uint64_t red_y_1_0() const { return m_red_y_1_0; }

        /**
         * Green X, bits 1..0
         */
        uint64_t green_x_1_0() const { return m_green_x_1_0; }

        /**
         * Green Y, bits 1..0
         */
        uint64_t green_y_1_0() const { return m_green_y_1_0; }

        /**
         * Blue X, bits 1..0
         */
        uint64_t blue_x_1_0() const { return m_blue_x_1_0; }

        /**
         * Blue Y, bits 1..0
         */
        uint64_t blue_y_1_0() const { return m_blue_y_1_0; }

        /**
         * White X, bits 1..0
         */
        uint64_t white_x_1_0() const { return m_white_x_1_0; }

        /**
         * White Y, bits 1..0
         */
        uint64_t white_y_1_0() const { return m_white_y_1_0; }

        /**
         * Red X, bits 9..2
         */
        uint8_t red_x_9_2() const { return m_red_x_9_2; }

        /**
         * Red Y, bits 9..2
         */
        uint8_t red_y_9_2() const { return m_red_y_9_2; }

        /**
         * Green X, bits 9..2
         */
        uint8_t green_x_9_2() const { return m_green_x_9_2; }

        /**
         * Green Y, bits 9..2
         */
        uint8_t green_y_9_2() const { return m_green_y_9_2; }

        /**
         * Blue X, bits 9..2
         */
        uint8_t blue_x_9_2() const { return m_blue_x_9_2; }

        /**
         * Blue Y, bits 9..2
         */
        uint8_t blue_y_9_2() const { return m_blue_y_9_2; }

        /**
         * White X, bits 9..2
         */
        uint8_t white_x_9_2() const { return m_white_x_9_2; }

        /**
         * White Y, bits 9..2
         */
        uint8_t white_y_9_2() const { return m_white_y_9_2; }
        edid_t* _root() const { return m__root; }
        edid_t* _parent() const { return m__parent; }
    };

    class est_timings_info_t : public kaitai::kstruct {

    public:

        est_timings_info_t(kaitai::kstream* p__io, edid_t* p__parent = nullptr, edid_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~est_timings_info_t();

    private:
        bool m_can_720x400px_70hz;
        bool m_can_720x400px_88hz;
        bool m_can_640x480px_60hz;
        bool m_can_640x480px_67hz;
        bool m_can_640x480px_72hz;
        bool m_can_640x480px_75hz;
        bool m_can_800x600px_56hz;
        bool m_can_800x600px_60hz;
        bool m_can_800x600px_72hz;
        bool m_can_800x600px_75hz;
        bool m_can_832x624px_75hz;
        bool m_can_1024x768px_87hz_i;
        bool m_can_1024x768px_60hz;
        bool m_can_1024x768px_70hz;
        bool m_can_1024x768px_75hz;
        bool m_can_1280x1024px_75hz;
        bool m_can_1152x870px_75hz;
        uint64_t m_reserved;
        edid_t* m__root;
        edid_t* m__parent;

    public:

        /**
         * Supports 720 x 400 @ 70Hz
         */
        bool can_720x400px_70hz() const { return m_can_720x400px_70hz; }

        /**
         * Supports 720 x 400 @ 88Hz
         */
        bool can_720x400px_88hz() const { return m_can_720x400px_88hz; }

        /**
         * Supports 640 x 480 @ 60Hz
         */
        bool can_640x480px_60hz() const { return m_can_640x480px_60hz; }

        /**
         * Supports 640 x 480 @ 67Hz
         */
        bool can_640x480px_67hz() const { return m_can_640x480px_67hz; }

        /**
         * Supports 640 x 480 @ 72Hz
         */
        bool can_640x480px_72hz() const { return m_can_640x480px_72hz; }

        /**
         * Supports 640 x 480 @ 75Hz
         */
        bool can_640x480px_75hz() const { return m_can_640x480px_75hz; }

        /**
         * Supports 800 x 600 @ 56Hz
         */
        bool can_800x600px_56hz() const { return m_can_800x600px_56hz; }

        /**
         * Supports 800 x 600 @ 60Hz
         */
        bool can_800x600px_60hz() const { return m_can_800x600px_60hz; }

        /**
         * Supports 800 x 600 @ 72Hz
         */
        bool can_800x600px_72hz() const { return m_can_800x600px_72hz; }

        /**
         * Supports 800 x 600 @ 75Hz
         */
        bool can_800x600px_75hz() const { return m_can_800x600px_75hz; }

        /**
         * Supports 832 x 624 @ 75Hz
         */
        bool can_832x624px_75hz() const { return m_can_832x624px_75hz; }

        /**
         * Supports 1024 x 768 @ 87Hz(I)
         */
        bool can_1024x768px_87hz_i() const { return m_can_1024x768px_87hz_i; }

        /**
         * Supports 1024 x 768 @ 60Hz
         */
        bool can_1024x768px_60hz() const { return m_can_1024x768px_60hz; }

        /**
         * Supports 1024 x 768 @ 70Hz
         */
        bool can_1024x768px_70hz() const { return m_can_1024x768px_70hz; }

        /**
         * Supports 1024 x 768 @ 75Hz
         */
        bool can_1024x768px_75hz() const { return m_can_1024x768px_75hz; }

        /**
         * Supports 1280 x 1024 @ 75Hz
         */
        bool can_1280x1024px_75hz() const { return m_can_1280x1024px_75hz; }

        /**
         * Supports 1152 x 870 @ 75Hz
         */
        bool can_1152x870px_75hz() const { return m_can_1152x870px_75hz; }
        uint64_t reserved() const { return m_reserved; }
        edid_t* _root() const { return m__root; }
        edid_t* _parent() const { return m__parent; }
    };

    class std_timing_t : public kaitai::kstruct {

    public:

        enum aspect_ratios_t {
            ASPECT_RATIOS_RATIO_16_10 = 0,
            ASPECT_RATIOS_RATIO_4_3 = 1,
            ASPECT_RATIOS_RATIO_5_4 = 2,
            ASPECT_RATIOS_RATIO_16_9 = 3
        };
        static bool _is_defined_aspect_ratios_t(aspect_ratios_t v);

    private:
        static const std::set<aspect_ratios_t> _values_aspect_ratios_t;

    public:

        std_timing_t(kaitai::kstream* p__io, edid_t* p__parent = nullptr, edid_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~std_timing_t();

    private:
        bool f_bytes_lookahead;
        std::string m_bytes_lookahead;

    public:
        std::string bytes_lookahead();

    private:
        bool f_horiz_active_pixels;
        int32_t m_horiz_active_pixels;
        bool n_horiz_active_pixels;

    public:
        bool _is_null_horiz_active_pixels() { horiz_active_pixels(); return n_horiz_active_pixels; };

    private:

    public:

        /**
         * Range of horizontal active pixels.
         */
        int32_t horiz_active_pixels();

    private:
        bool f_is_used;
        bool m_is_used;

    public:
        bool is_used();

    private:
        bool f_refresh_rate;
        int32_t m_refresh_rate;
        bool n_refresh_rate;

    public:
        bool _is_null_refresh_rate() { refresh_rate(); return n_refresh_rate; };

    private:

    public:

        /**
         * Vertical refresh rate, Hz.
         */
        int32_t refresh_rate();

    private:
        uint8_t m_horiz_active_pixels_mod;
        aspect_ratios_t m_aspect_ratio;
        uint64_t m_refresh_rate_mod;
        edid_t* m__root;
        edid_t* m__parent;

    public:

        /**
         * Range of horizontal active pixels, written in modified form:
         * `(horiz_active_pixels / 8) - 31`. This yields an effective
         * range of 256..2288, with steps of 8 pixels.
         */
        uint8_t horiz_active_pixels_mod() const { return m_horiz_active_pixels_mod; }

        /**
         * Aspect ratio of the image. Can be used to calculate number
         * of vertical pixels.
         */
        aspect_ratios_t aspect_ratio() const { return m_aspect_ratio; }

        /**
         * Refresh rate in Hz, written in modified form: `refresh_rate
         * - 60`. This yields an effective range of 60..123 Hz.
         */
        uint64_t refresh_rate_mod() const { return m_refresh_rate_mod; }
        edid_t* _root() const { return m__root; }
        edid_t* _parent() const { return m__parent; }
    };

private:
    bool f_gamma;
    double m_gamma;
    bool n_gamma;

public:
    bool _is_null_gamma() { gamma(); return n_gamma; };

private:

public:
    double gamma();

private:
    bool f_mfg_id_ch1;
    int32_t m_mfg_id_ch1;

public:
    int32_t mfg_id_ch1();

private:
    bool f_mfg_id_ch2;
    int32_t m_mfg_id_ch2;

public:
    int32_t mfg_id_ch2();

private:
    bool f_mfg_id_ch3;
    int32_t m_mfg_id_ch3;

public:
    int32_t mfg_id_ch3();

private:
    bool f_mfg_str;
    std::string m_mfg_str;

public:
    std::string mfg_str();

private:
    bool f_mfg_year;
    int32_t m_mfg_year;

public:
    int32_t mfg_year();

private:
    std::string m_magic;
    uint16_t m_mfg_bytes;
    uint16_t m_product_code;
    uint32_t m_serial;
    uint8_t m_mfg_week;
    uint8_t m_mfg_year_mod;
    uint8_t m_edid_version_major;
    uint8_t m_edid_version_minor;
    uint8_t m_input_flags;
    uint8_t m_screen_size_h;
    uint8_t m_screen_size_v;
    uint8_t m_gamma_mod;
    uint8_t m_features_flags;
    std::unique_ptr<chromacity_info_t> m_chromacity;
    std::unique_ptr<est_timings_info_t> m_est_timings;
    std::unique_ptr<std::vector<std::unique_ptr<std_timing_t>>> m_std_timings;
    edid_t* m__root;
    kaitai::kstruct* m__parent;
    std::unique_ptr<std::vector<std::string>> m__raw_std_timings;
    std::unique_ptr<std::vector<std::unique_ptr<kaitai::kstream>>> m__io__raw_std_timings;

public:
    std::string magic() const { return m_magic; }
    uint16_t mfg_bytes() const { return m_mfg_bytes; }

    /**
     * Manufacturer product code
     */
    uint16_t product_code() const { return m_product_code; }

    /**
     * Serial number
     */
    uint32_t serial() const { return m_serial; }

    /**
     * Week of manufacture. Week numbering is not consistent between manufacturers.
     */
    uint8_t mfg_week() const { return m_mfg_week; }

    /**
     * Year of manufacture, less 1990. (1990-2245). If week=255, it is the model year instead.
     */
    uint8_t mfg_year_mod() const { return m_mfg_year_mod; }

    /**
     * EDID version, usually 1 (for 1.3)
     */
    uint8_t edid_version_major() const { return m_edid_version_major; }

    /**
     * EDID revision, usually 3 (for 1.3)
     */
    uint8_t edid_version_minor() const { return m_edid_version_minor; }
    uint8_t input_flags() const { return m_input_flags; }

    /**
     * Maximum horizontal image size, in centimetres (max 292 cm/115 in at 16:9 aspect ratio)
     */
    uint8_t screen_size_h() const { return m_screen_size_h; }

    /**
     * Maximum vertical image size, in centimetres. If either byte is 0, undefined (e.g. projector)
     */
    uint8_t screen_size_v() const { return m_screen_size_v; }

    /**
     * Display gamma, datavalue = (gamma*100)-100 (range 1.00-3.54)
     */
    uint8_t gamma_mod() const { return m_gamma_mod; }
    uint8_t features_flags() const { return m_features_flags; }

    /**
     * Phosphor or filter chromaticity structure, which provides info on colorimetry and white point
     * \sa Standard, section 3.7
     */
    chromacity_info_t* chromacity() const { return m_chromacity.get(); }

    /**
     * Block of bit flags that indicates support of so called
     * "established timings", which is a commonly used subset of VESA
     * DMT (Discrete Monitor Timings) modes.
     * \sa Standard, section 3.8
     */
    est_timings_info_t* est_timings() const { return m_est_timings.get(); }

    /**
     * Array of descriptions of so called "standard timings", which are
     * used to specify up to 8 additional timings not included in
     * "established timings".
     */
    std::vector<std::unique_ptr<std_timing_t>>* std_timings() const { return m_std_timings.get(); }
    edid_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
    std::vector<std::string>* _raw_std_timings() const { return m__raw_std_timings.get(); }
    std::vector<std::unique_ptr<kaitai::kstream>>* _io__raw_std_timings() const { return m__io__raw_std_timings.get(); }
};

edid.cpp

// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

#include "edid.h"
#include "kaitai/exceptions.h"

edid_t::edid_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, edid_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root ? p__root : this;
    m_chromacity = nullptr;
    m_est_timings = nullptr;
    m_std_timings = nullptr;
    m__raw_std_timings = nullptr;
    m__io__raw_std_timings = nullptr;
    f_gamma = false;
    f_mfg_id_ch1 = false;
    f_mfg_id_ch2 = false;
    f_mfg_id_ch3 = false;
    f_mfg_str = false;
    f_mfg_year = false;
    _read();
}

void edid_t::_read() {
    m_magic = m__io->read_bytes(8);
    if (!(m_magic == std::string("\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00", 8))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00", 8), m_magic, m__io, std::string("/seq/0"));
    }
    m_mfg_bytes = m__io->read_u2be();
    m_product_code = m__io->read_u2le();
    m_serial = m__io->read_u4le();
    m_mfg_week = m__io->read_u1();
    m_mfg_year_mod = m__io->read_u1();
    m_edid_version_major = m__io->read_u1();
    m_edid_version_minor = m__io->read_u1();
    m_input_flags = m__io->read_u1();
    m_screen_size_h = m__io->read_u1();
    m_screen_size_v = m__io->read_u1();
    m_gamma_mod = m__io->read_u1();
    m_features_flags = m__io->read_u1();
    m_chromacity = std::unique_ptr<chromacity_info_t>(new chromacity_info_t(m__io, this, m__root));
    m_est_timings = std::unique_ptr<est_timings_info_t>(new est_timings_info_t(m__io, this, m__root));
    m__raw_std_timings = std::unique_ptr<std::vector<std::string>>(new std::vector<std::string>());
    m__io__raw_std_timings = std::unique_ptr<std::vector<std::unique_ptr<kaitai::kstream>>>(new std::vector<std::unique_ptr<kaitai::kstream>>());
    m_std_timings = std::unique_ptr<std::vector<std::unique_ptr<std_timing_t>>>(new std::vector<std::unique_ptr<std_timing_t>>());
    const int l_std_timings = 8;
    for (int i = 0; i < l_std_timings; i++) {
        m__raw_std_timings->push_back(std::move(m__io->read_bytes(2)));
        kaitai::kstream* io__raw_std_timings = new kaitai::kstream(m__raw_std_timings->at(m__raw_std_timings->size() - 1));
        m__io__raw_std_timings->emplace_back(io__raw_std_timings);
        m_std_timings->push_back(std::move(std::unique_ptr<std_timing_t>(new std_timing_t(io__raw_std_timings, this, m__root))));
    }
}

edid_t::~edid_t() {
    _clean_up();
}

void edid_t::_clean_up() {
}

edid_t::chromacity_info_t::chromacity_info_t(kaitai::kstream* p__io, edid_t* p__parent, edid_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    f_blue_x = false;
    f_blue_x_int = false;
    f_blue_y = false;
    f_blue_y_int = false;
    f_green_x = false;
    f_green_x_int = false;
    f_green_y = false;
    f_green_y_int = false;
    f_red_x = false;
    f_red_x_int = false;
    f_red_y = false;
    f_red_y_int = false;
    f_white_x = false;
    f_white_x_int = false;
    f_white_y = false;
    f_white_y_int = false;
    _read();
}

void edid_t::chromacity_info_t::_read() {
    m_red_x_1_0 = m__io->read_bits_int_be(2);
    m_red_y_1_0 = m__io->read_bits_int_be(2);
    m_green_x_1_0 = m__io->read_bits_int_be(2);
    m_green_y_1_0 = m__io->read_bits_int_be(2);
    m_blue_x_1_0 = m__io->read_bits_int_be(2);
    m_blue_y_1_0 = m__io->read_bits_int_be(2);
    m_white_x_1_0 = m__io->read_bits_int_be(2);
    m_white_y_1_0 = m__io->read_bits_int_be(2);
    m__io->align_to_byte();
    m_red_x_9_2 = m__io->read_u1();
    m_red_y_9_2 = m__io->read_u1();
    m_green_x_9_2 = m__io->read_u1();
    m_green_y_9_2 = m__io->read_u1();
    m_blue_x_9_2 = m__io->read_u1();
    m_blue_y_9_2 = m__io->read_u1();
    m_white_x_9_2 = m__io->read_u1();
    m_white_y_9_2 = m__io->read_u1();
}

edid_t::chromacity_info_t::~chromacity_info_t() {
    _clean_up();
}

void edid_t::chromacity_info_t::_clean_up() {
}

double edid_t::chromacity_info_t::blue_x() {
    if (f_blue_x)
        return m_blue_x;
    f_blue_x = true;
    m_blue_x = blue_x_int() / 1024.0;
    return m_blue_x;
}

int32_t edid_t::chromacity_info_t::blue_x_int() {
    if (f_blue_x_int)
        return m_blue_x_int;
    f_blue_x_int = true;
    m_blue_x_int = blue_x_9_2() << 2 | blue_x_1_0();
    return m_blue_x_int;
}

double edid_t::chromacity_info_t::blue_y() {
    if (f_blue_y)
        return m_blue_y;
    f_blue_y = true;
    m_blue_y = blue_y_int() / 1024.0;
    return m_blue_y;
}

int32_t edid_t::chromacity_info_t::blue_y_int() {
    if (f_blue_y_int)
        return m_blue_y_int;
    f_blue_y_int = true;
    m_blue_y_int = blue_y_9_2() << 2 | blue_y_1_0();
    return m_blue_y_int;
}

double edid_t::chromacity_info_t::green_x() {
    if (f_green_x)
        return m_green_x;
    f_green_x = true;
    m_green_x = green_x_int() / 1024.0;
    return m_green_x;
}

int32_t edid_t::chromacity_info_t::green_x_int() {
    if (f_green_x_int)
        return m_green_x_int;
    f_green_x_int = true;
    m_green_x_int = green_x_9_2() << 2 | green_x_1_0();
    return m_green_x_int;
}

double edid_t::chromacity_info_t::green_y() {
    if (f_green_y)
        return m_green_y;
    f_green_y = true;
    m_green_y = green_y_int() / 1024.0;
    return m_green_y;
}

int32_t edid_t::chromacity_info_t::green_y_int() {
    if (f_green_y_int)
        return m_green_y_int;
    f_green_y_int = true;
    m_green_y_int = green_y_9_2() << 2 | green_y_1_0();
    return m_green_y_int;
}

double edid_t::chromacity_info_t::red_x() {
    if (f_red_x)
        return m_red_x;
    f_red_x = true;
    m_red_x = red_x_int() / 1024.0;
    return m_red_x;
}

int32_t edid_t::chromacity_info_t::red_x_int() {
    if (f_red_x_int)
        return m_red_x_int;
    f_red_x_int = true;
    m_red_x_int = red_x_9_2() << 2 | red_x_1_0();
    return m_red_x_int;
}

double edid_t::chromacity_info_t::red_y() {
    if (f_red_y)
        return m_red_y;
    f_red_y = true;
    m_red_y = red_y_int() / 1024.0;
    return m_red_y;
}

int32_t edid_t::chromacity_info_t::red_y_int() {
    if (f_red_y_int)
        return m_red_y_int;
    f_red_y_int = true;
    m_red_y_int = red_y_9_2() << 2 | red_y_1_0();
    return m_red_y_int;
}

double edid_t::chromacity_info_t::white_x() {
    if (f_white_x)
        return m_white_x;
    f_white_x = true;
    m_white_x = white_x_int() / 1024.0;
    return m_white_x;
}

int32_t edid_t::chromacity_info_t::white_x_int() {
    if (f_white_x_int)
        return m_white_x_int;
    f_white_x_int = true;
    m_white_x_int = white_x_9_2() << 2 | white_x_1_0();
    return m_white_x_int;
}

double edid_t::chromacity_info_t::white_y() {
    if (f_white_y)
        return m_white_y;
    f_white_y = true;
    m_white_y = white_y_int() / 1024.0;
    return m_white_y;
}

int32_t edid_t::chromacity_info_t::white_y_int() {
    if (f_white_y_int)
        return m_white_y_int;
    f_white_y_int = true;
    m_white_y_int = white_y_9_2() << 2 | white_y_1_0();
    return m_white_y_int;
}

edid_t::est_timings_info_t::est_timings_info_t(kaitai::kstream* p__io, edid_t* p__parent, edid_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void edid_t::est_timings_info_t::_read() {
    m_can_720x400px_70hz = m__io->read_bits_int_be(1);
    m_can_720x400px_88hz = m__io->read_bits_int_be(1);
    m_can_640x480px_60hz = m__io->read_bits_int_be(1);
    m_can_640x480px_67hz = m__io->read_bits_int_be(1);
    m_can_640x480px_72hz = m__io->read_bits_int_be(1);
    m_can_640x480px_75hz = m__io->read_bits_int_be(1);
    m_can_800x600px_56hz = m__io->read_bits_int_be(1);
    m_can_800x600px_60hz = m__io->read_bits_int_be(1);
    m_can_800x600px_72hz = m__io->read_bits_int_be(1);
    m_can_800x600px_75hz = m__io->read_bits_int_be(1);
    m_can_832x624px_75hz = m__io->read_bits_int_be(1);
    m_can_1024x768px_87hz_i = m__io->read_bits_int_be(1);
    m_can_1024x768px_60hz = m__io->read_bits_int_be(1);
    m_can_1024x768px_70hz = m__io->read_bits_int_be(1);
    m_can_1024x768px_75hz = m__io->read_bits_int_be(1);
    m_can_1280x1024px_75hz = m__io->read_bits_int_be(1);
    m_can_1152x870px_75hz = m__io->read_bits_int_be(1);
    m_reserved = m__io->read_bits_int_be(7);
}

edid_t::est_timings_info_t::~est_timings_info_t() {
    _clean_up();
}

void edid_t::est_timings_info_t::_clean_up() {
}
const std::set<edid_t::std_timing_t::aspect_ratios_t> edid_t::std_timing_t::_values_aspect_ratios_t{
    edid_t::std_timing_t::ASPECT_RATIOS_RATIO_16_10,
    edid_t::std_timing_t::ASPECT_RATIOS_RATIO_4_3,
    edid_t::std_timing_t::ASPECT_RATIOS_RATIO_5_4,
    edid_t::std_timing_t::ASPECT_RATIOS_RATIO_16_9,
};
bool edid_t::std_timing_t::_is_defined_aspect_ratios_t(edid_t::std_timing_t::aspect_ratios_t v) {
    return edid_t::std_timing_t::_values_aspect_ratios_t.find(v) != edid_t::std_timing_t::_values_aspect_ratios_t.end();
}

edid_t::std_timing_t::std_timing_t(kaitai::kstream* p__io, edid_t* p__parent, edid_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    f_bytes_lookahead = false;
    f_horiz_active_pixels = false;
    f_is_used = false;
    f_refresh_rate = false;
    _read();
}

void edid_t::std_timing_t::_read() {
    m_horiz_active_pixels_mod = m__io->read_u1();
    m_aspect_ratio = static_cast<edid_t::std_timing_t::aspect_ratios_t>(m__io->read_bits_int_be(2));
    m_refresh_rate_mod = m__io->read_bits_int_be(6);
}

edid_t::std_timing_t::~std_timing_t() {
    _clean_up();
}

void edid_t::std_timing_t::_clean_up() {
    if (f_bytes_lookahead) {
    }
}

std::string edid_t::std_timing_t::bytes_lookahead() {
    if (f_bytes_lookahead)
        return m_bytes_lookahead;
    f_bytes_lookahead = true;
    std::streampos _pos = m__io->pos();
    m__io->seek(0);
    m_bytes_lookahead = m__io->read_bytes(2);
    m__io->seek(_pos);
    return m_bytes_lookahead;
}

int32_t edid_t::std_timing_t::horiz_active_pixels() {
    if (f_horiz_active_pixels)
        return m_horiz_active_pixels;
    f_horiz_active_pixels = true;
    n_horiz_active_pixels = true;
    if (is_used()) {
        n_horiz_active_pixels = false;
        m_horiz_active_pixels = (horiz_active_pixels_mod() + 31) * 8;
    }
    return m_horiz_active_pixels;
}

bool edid_t::std_timing_t::is_used() {
    if (f_is_used)
        return m_is_used;
    f_is_used = true;
    m_is_used = bytes_lookahead() != std::string("\x01\x01", 2);
    return m_is_used;
}

int32_t edid_t::std_timing_t::refresh_rate() {
    if (f_refresh_rate)
        return m_refresh_rate;
    f_refresh_rate = true;
    n_refresh_rate = true;
    if (is_used()) {
        n_refresh_rate = false;
        m_refresh_rate = refresh_rate_mod() + 60;
    }
    return m_refresh_rate;
}

double edid_t::gamma() {
    if (f_gamma)
        return m_gamma;
    f_gamma = true;
    n_gamma = true;
    if (gamma_mod() != 255) {
        n_gamma = false;
        m_gamma = (gamma_mod() + 100) / 100.0;
    }
    return m_gamma;
}

int32_t edid_t::mfg_id_ch1() {
    if (f_mfg_id_ch1)
        return m_mfg_id_ch1;
    f_mfg_id_ch1 = true;
    m_mfg_id_ch1 = (mfg_bytes() & 31744) >> 10;
    return m_mfg_id_ch1;
}

int32_t edid_t::mfg_id_ch2() {
    if (f_mfg_id_ch2)
        return m_mfg_id_ch2;
    f_mfg_id_ch2 = true;
    m_mfg_id_ch2 = (mfg_bytes() & 992) >> 5;
    return m_mfg_id_ch2;
}

int32_t edid_t::mfg_id_ch3() {
    if (f_mfg_id_ch3)
        return m_mfg_id_ch3;
    f_mfg_id_ch3 = true;
    m_mfg_id_ch3 = mfg_bytes() & 31;
    return m_mfg_id_ch3;
}

std::string edid_t::mfg_str() {
    if (f_mfg_str)
        return m_mfg_str;
    f_mfg_str = true;
    m_mfg_str = kaitai::kstream::bytes_to_str(std::string({static_cast<char>(mfg_id_ch1() + 64), static_cast<char>(mfg_id_ch2() + 64), static_cast<char>(mfg_id_ch3() + 64)}), "ASCII");
    return m_mfg_str;
}

int32_t edid_t::mfg_year() {
    if (f_mfg_year)
        return m_mfg_year;
    f_mfg_year = true;
    m_mfg_year = mfg_year_mod() + 1990;
    return m_mfg_year;
}