EDID (VESA Enhanced Extended Display Identification Data): Perl 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.

Perl source code to parse EDID (VESA Enhanced Extended Display Identification Data)

Edid.pm

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

use strict;
use warnings;
use IO::KaitaiStruct 0.009_000;
use Encode;

########################################################################
package Edid;

our @ISA = 'IO::KaitaiStruct::Struct';

sub from_file {
    my ($class, $filename) = @_;
    my $fd;

    open($fd, '<', $filename) or return undef;
    binmode($fd);
    return new($class, IO::KaitaiStruct::Stream->new($fd));
}

sub new {
    my ($class, $_io, $_parent, $_root) = @_;
    my $self = IO::KaitaiStruct::Struct->new($_io);

    bless $self, $class;
    $self->{_parent} = $_parent;
    $self->{_root} = $_root || $self;;

    $self->_read();

    return $self;
}

sub _read {
    my ($self) = @_;

    $self->{magic} = $self->{_io}->read_bytes(8);
    $self->{mfg_bytes} = $self->{_io}->read_u2be();
    $self->{product_code} = $self->{_io}->read_u2le();
    $self->{serial} = $self->{_io}->read_u4le();
    $self->{mfg_week} = $self->{_io}->read_u1();
    $self->{mfg_year_mod} = $self->{_io}->read_u1();
    $self->{edid_version_major} = $self->{_io}->read_u1();
    $self->{edid_version_minor} = $self->{_io}->read_u1();
    $self->{input_flags} = $self->{_io}->read_u1();
    $self->{screen_size_h} = $self->{_io}->read_u1();
    $self->{screen_size_v} = $self->{_io}->read_u1();
    $self->{gamma_mod} = $self->{_io}->read_u1();
    $self->{features_flags} = $self->{_io}->read_u1();
    $self->{chromacity} = Edid::ChromacityInfo->new($self->{_io}, $self, $self->{_root});
    $self->{est_timings} = Edid::EstTimingsInfo->new($self->{_io}, $self, $self->{_root});
    $self->{_raw_std_timings} = ();
    $self->{std_timings} = ();
    my $n_std_timings = 8;
    for (my $i = 0; $i < $n_std_timings; $i++) {
        push @{$self->{_raw_std_timings}}, $self->{_io}->read_bytes(2);
        my $io__raw_std_timings = IO::KaitaiStruct::Stream->new($self->{_raw_std_timings}[$i]);
        push @{$self->{std_timings}}, Edid::StdTiming->new($io__raw_std_timings, $self, $self->{_root});
    }
}

sub mfg_year {
    my ($self) = @_;
    return $self->{mfg_year} if ($self->{mfg_year});
    $self->{mfg_year} = ($self->mfg_year_mod() + 1990);
    return $self->{mfg_year};
}

sub mfg_id_ch1 {
    my ($self) = @_;
    return $self->{mfg_id_ch1} if ($self->{mfg_id_ch1});
    $self->{mfg_id_ch1} = (($self->mfg_bytes() & 31744) >> 10);
    return $self->{mfg_id_ch1};
}

sub mfg_id_ch3 {
    my ($self) = @_;
    return $self->{mfg_id_ch3} if ($self->{mfg_id_ch3});
    $self->{mfg_id_ch3} = ($self->mfg_bytes() & 31);
    return $self->{mfg_id_ch3};
}

sub gamma {
    my ($self) = @_;
    return $self->{gamma} if ($self->{gamma});
    if ($self->gamma_mod() != 255) {
        $self->{gamma} = (($self->gamma_mod() + 100) / 100.0);
    }
    return $self->{gamma};
}

sub mfg_str {
    my ($self) = @_;
    return $self->{mfg_str} if ($self->{mfg_str});
    $self->{mfg_str} = Encode::decode("ASCII", pack('C*', (($self->mfg_id_ch1() + 64), ($self->mfg_id_ch2() + 64), ($self->mfg_id_ch3() + 64))));
    return $self->{mfg_str};
}

sub mfg_id_ch2 {
    my ($self) = @_;
    return $self->{mfg_id_ch2} if ($self->{mfg_id_ch2});
    $self->{mfg_id_ch2} = (($self->mfg_bytes() & 992) >> 5);
    return $self->{mfg_id_ch2};
}

sub magic {
    my ($self) = @_;
    return $self->{magic};
}

sub mfg_bytes {
    my ($self) = @_;
    return $self->{mfg_bytes};
}

sub product_code {
    my ($self) = @_;
    return $self->{product_code};
}

sub serial {
    my ($self) = @_;
    return $self->{serial};
}

sub mfg_week {
    my ($self) = @_;
    return $self->{mfg_week};
}

sub mfg_year_mod {
    my ($self) = @_;
    return $self->{mfg_year_mod};
}

sub edid_version_major {
    my ($self) = @_;
    return $self->{edid_version_major};
}

sub edid_version_minor {
    my ($self) = @_;
    return $self->{edid_version_minor};
}

sub input_flags {
    my ($self) = @_;
    return $self->{input_flags};
}

sub screen_size_h {
    my ($self) = @_;
    return $self->{screen_size_h};
}

sub screen_size_v {
    my ($self) = @_;
    return $self->{screen_size_v};
}

sub gamma_mod {
    my ($self) = @_;
    return $self->{gamma_mod};
}

sub features_flags {
    my ($self) = @_;
    return $self->{features_flags};
}

sub chromacity {
    my ($self) = @_;
    return $self->{chromacity};
}

sub est_timings {
    my ($self) = @_;
    return $self->{est_timings};
}

sub std_timings {
    my ($self) = @_;
    return $self->{std_timings};
}

sub _raw_std_timings {
    my ($self) = @_;
    return $self->{_raw_std_timings};
}

########################################################################
package Edid::ChromacityInfo;

our @ISA = 'IO::KaitaiStruct::Struct';

sub from_file {
    my ($class, $filename) = @_;
    my $fd;

    open($fd, '<', $filename) or return undef;
    binmode($fd);
    return new($class, IO::KaitaiStruct::Stream->new($fd));
}

sub new {
    my ($class, $_io, $_parent, $_root) = @_;
    my $self = IO::KaitaiStruct::Struct->new($_io);

    bless $self, $class;
    $self->{_parent} = $_parent;
    $self->{_root} = $_root || $self;;

    $self->_read();

    return $self;
}

sub _read {
    my ($self) = @_;

    $self->{red_x_1_0} = $self->{_io}->read_bits_int_be(2);
    $self->{red_y_1_0} = $self->{_io}->read_bits_int_be(2);
    $self->{green_x_1_0} = $self->{_io}->read_bits_int_be(2);
    $self->{green_y_1_0} = $self->{_io}->read_bits_int_be(2);
    $self->{blue_x_1_0} = $self->{_io}->read_bits_int_be(2);
    $self->{blue_y_1_0} = $self->{_io}->read_bits_int_be(2);
    $self->{white_x_1_0} = $self->{_io}->read_bits_int_be(2);
    $self->{white_y_1_0} = $self->{_io}->read_bits_int_be(2);
    $self->{_io}->align_to_byte();
    $self->{red_x_9_2} = $self->{_io}->read_u1();
    $self->{red_y_9_2} = $self->{_io}->read_u1();
    $self->{green_x_9_2} = $self->{_io}->read_u1();
    $self->{green_y_9_2} = $self->{_io}->read_u1();
    $self->{blue_x_9_2} = $self->{_io}->read_u1();
    $self->{blue_y_9_2} = $self->{_io}->read_u1();
    $self->{white_x_9_2} = $self->{_io}->read_u1();
    $self->{white_y_9_2} = $self->{_io}->read_u1();
}

sub green_x_int {
    my ($self) = @_;
    return $self->{green_x_int} if ($self->{green_x_int});
    $self->{green_x_int} = (($self->green_x_9_2() << 2) | $self->green_x_1_0());
    return $self->{green_x_int};
}

sub red_y {
    my ($self) = @_;
    return $self->{red_y} if ($self->{red_y});
    $self->{red_y} = ($self->red_y_int() / 1024.0);
    return $self->{red_y};
}

sub green_y_int {
    my ($self) = @_;
    return $self->{green_y_int} if ($self->{green_y_int});
    $self->{green_y_int} = (($self->green_y_9_2() << 2) | $self->green_y_1_0());
    return $self->{green_y_int};
}

sub white_y {
    my ($self) = @_;
    return $self->{white_y} if ($self->{white_y});
    $self->{white_y} = ($self->white_y_int() / 1024.0);
    return $self->{white_y};
}

sub red_x {
    my ($self) = @_;
    return $self->{red_x} if ($self->{red_x});
    $self->{red_x} = ($self->red_x_int() / 1024.0);
    return $self->{red_x};
}

sub white_x {
    my ($self) = @_;
    return $self->{white_x} if ($self->{white_x});
    $self->{white_x} = ($self->white_x_int() / 1024.0);
    return $self->{white_x};
}

sub blue_x {
    my ($self) = @_;
    return $self->{blue_x} if ($self->{blue_x});
    $self->{blue_x} = ($self->blue_x_int() / 1024.0);
    return $self->{blue_x};
}

sub white_x_int {
    my ($self) = @_;
    return $self->{white_x_int} if ($self->{white_x_int});
    $self->{white_x_int} = (($self->white_x_9_2() << 2) | $self->white_x_1_0());
    return $self->{white_x_int};
}

sub white_y_int {
    my ($self) = @_;
    return $self->{white_y_int} if ($self->{white_y_int});
    $self->{white_y_int} = (($self->white_y_9_2() << 2) | $self->white_y_1_0());
    return $self->{white_y_int};
}

sub green_x {
    my ($self) = @_;
    return $self->{green_x} if ($self->{green_x});
    $self->{green_x} = ($self->green_x_int() / 1024.0);
    return $self->{green_x};
}

sub red_x_int {
    my ($self) = @_;
    return $self->{red_x_int} if ($self->{red_x_int});
    $self->{red_x_int} = (($self->red_x_9_2() << 2) | $self->red_x_1_0());
    return $self->{red_x_int};
}

sub red_y_int {
    my ($self) = @_;
    return $self->{red_y_int} if ($self->{red_y_int});
    $self->{red_y_int} = (($self->red_y_9_2() << 2) | $self->red_y_1_0());
    return $self->{red_y_int};
}

sub blue_x_int {
    my ($self) = @_;
    return $self->{blue_x_int} if ($self->{blue_x_int});
    $self->{blue_x_int} = (($self->blue_x_9_2() << 2) | $self->blue_x_1_0());
    return $self->{blue_x_int};
}

sub blue_y {
    my ($self) = @_;
    return $self->{blue_y} if ($self->{blue_y});
    $self->{blue_y} = ($self->blue_y_int() / 1024.0);
    return $self->{blue_y};
}

sub green_y {
    my ($self) = @_;
    return $self->{green_y} if ($self->{green_y});
    $self->{green_y} = ($self->green_y_int() / 1024.0);
    return $self->{green_y};
}

sub blue_y_int {
    my ($self) = @_;
    return $self->{blue_y_int} if ($self->{blue_y_int});
    $self->{blue_y_int} = (($self->blue_y_9_2() << 2) | $self->blue_y_1_0());
    return $self->{blue_y_int};
}

sub red_x_1_0 {
    my ($self) = @_;
    return $self->{red_x_1_0};
}

sub red_y_1_0 {
    my ($self) = @_;
    return $self->{red_y_1_0};
}

sub green_x_1_0 {
    my ($self) = @_;
    return $self->{green_x_1_0};
}

sub green_y_1_0 {
    my ($self) = @_;
    return $self->{green_y_1_0};
}

sub blue_x_1_0 {
    my ($self) = @_;
    return $self->{blue_x_1_0};
}

sub blue_y_1_0 {
    my ($self) = @_;
    return $self->{blue_y_1_0};
}

sub white_x_1_0 {
    my ($self) = @_;
    return $self->{white_x_1_0};
}

sub white_y_1_0 {
    my ($self) = @_;
    return $self->{white_y_1_0};
}

sub red_x_9_2 {
    my ($self) = @_;
    return $self->{red_x_9_2};
}

sub red_y_9_2 {
    my ($self) = @_;
    return $self->{red_y_9_2};
}

sub green_x_9_2 {
    my ($self) = @_;
    return $self->{green_x_9_2};
}

sub green_y_9_2 {
    my ($self) = @_;
    return $self->{green_y_9_2};
}

sub blue_x_9_2 {
    my ($self) = @_;
    return $self->{blue_x_9_2};
}

sub blue_y_9_2 {
    my ($self) = @_;
    return $self->{blue_y_9_2};
}

sub white_x_9_2 {
    my ($self) = @_;
    return $self->{white_x_9_2};
}

sub white_y_9_2 {
    my ($self) = @_;
    return $self->{white_y_9_2};
}

########################################################################
package Edid::EstTimingsInfo;

our @ISA = 'IO::KaitaiStruct::Struct';

sub from_file {
    my ($class, $filename) = @_;
    my $fd;

    open($fd, '<', $filename) or return undef;
    binmode($fd);
    return new($class, IO::KaitaiStruct::Stream->new($fd));
}

sub new {
    my ($class, $_io, $_parent, $_root) = @_;
    my $self = IO::KaitaiStruct::Struct->new($_io);

    bless $self, $class;
    $self->{_parent} = $_parent;
    $self->{_root} = $_root || $self;;

    $self->_read();

    return $self;
}

sub _read {
    my ($self) = @_;

    $self->{can_720x400px_70hz} = $self->{_io}->read_bits_int_be(1);
    $self->{can_720x400px_88hz} = $self->{_io}->read_bits_int_be(1);
    $self->{can_640x480px_60hz} = $self->{_io}->read_bits_int_be(1);
    $self->{can_640x480px_67hz} = $self->{_io}->read_bits_int_be(1);
    $self->{can_640x480px_72hz} = $self->{_io}->read_bits_int_be(1);
    $self->{can_640x480px_75hz} = $self->{_io}->read_bits_int_be(1);
    $self->{can_800x600px_56hz} = $self->{_io}->read_bits_int_be(1);
    $self->{can_800x600px_60hz} = $self->{_io}->read_bits_int_be(1);
    $self->{can_800x600px_72hz} = $self->{_io}->read_bits_int_be(1);
    $self->{can_800x600px_75hz} = $self->{_io}->read_bits_int_be(1);
    $self->{can_832x624px_75hz} = $self->{_io}->read_bits_int_be(1);
    $self->{can_1024x768px_87hz_i} = $self->{_io}->read_bits_int_be(1);
    $self->{can_1024x768px_60hz} = $self->{_io}->read_bits_int_be(1);
    $self->{can_1024x768px_70hz} = $self->{_io}->read_bits_int_be(1);
    $self->{can_1024x768px_75hz} = $self->{_io}->read_bits_int_be(1);
    $self->{can_1280x1024px_75hz} = $self->{_io}->read_bits_int_be(1);
    $self->{can_1152x870px_75hz} = $self->{_io}->read_bits_int_be(1);
    $self->{reserved} = $self->{_io}->read_bits_int_be(7);
}

sub can_720x400px_70hz {
    my ($self) = @_;
    return $self->{can_720x400px_70hz};
}

sub can_720x400px_88hz {
    my ($self) = @_;
    return $self->{can_720x400px_88hz};
}

sub can_640x480px_60hz {
    my ($self) = @_;
    return $self->{can_640x480px_60hz};
}

sub can_640x480px_67hz {
    my ($self) = @_;
    return $self->{can_640x480px_67hz};
}

sub can_640x480px_72hz {
    my ($self) = @_;
    return $self->{can_640x480px_72hz};
}

sub can_640x480px_75hz {
    my ($self) = @_;
    return $self->{can_640x480px_75hz};
}

sub can_800x600px_56hz {
    my ($self) = @_;
    return $self->{can_800x600px_56hz};
}

sub can_800x600px_60hz {
    my ($self) = @_;
    return $self->{can_800x600px_60hz};
}

sub can_800x600px_72hz {
    my ($self) = @_;
    return $self->{can_800x600px_72hz};
}

sub can_800x600px_75hz {
    my ($self) = @_;
    return $self->{can_800x600px_75hz};
}

sub can_832x624px_75hz {
    my ($self) = @_;
    return $self->{can_832x624px_75hz};
}

sub can_1024x768px_87hz_i {
    my ($self) = @_;
    return $self->{can_1024x768px_87hz_i};
}

sub can_1024x768px_60hz {
    my ($self) = @_;
    return $self->{can_1024x768px_60hz};
}

sub can_1024x768px_70hz {
    my ($self) = @_;
    return $self->{can_1024x768px_70hz};
}

sub can_1024x768px_75hz {
    my ($self) = @_;
    return $self->{can_1024x768px_75hz};
}

sub can_1280x1024px_75hz {
    my ($self) = @_;
    return $self->{can_1280x1024px_75hz};
}

sub can_1152x870px_75hz {
    my ($self) = @_;
    return $self->{can_1152x870px_75hz};
}

sub reserved {
    my ($self) = @_;
    return $self->{reserved};
}

########################################################################
package Edid::StdTiming;

our @ISA = 'IO::KaitaiStruct::Struct';

sub from_file {
    my ($class, $filename) = @_;
    my $fd;

    open($fd, '<', $filename) or return undef;
    binmode($fd);
    return new($class, IO::KaitaiStruct::Stream->new($fd));
}

our $ASPECT_RATIOS_RATIO_16_10 = 0;
our $ASPECT_RATIOS_RATIO_4_3 = 1;
our $ASPECT_RATIOS_RATIO_5_4 = 2;
our $ASPECT_RATIOS_RATIO_16_9 = 3;

sub new {
    my ($class, $_io, $_parent, $_root) = @_;
    my $self = IO::KaitaiStruct::Struct->new($_io);

    bless $self, $class;
    $self->{_parent} = $_parent;
    $self->{_root} = $_root || $self;;

    $self->_read();

    return $self;
}

sub _read {
    my ($self) = @_;

    $self->{horiz_active_pixels_mod} = $self->{_io}->read_u1();
    $self->{aspect_ratio} = $self->{_io}->read_bits_int_be(2);
    $self->{refresh_rate_mod} = $self->{_io}->read_bits_int_be(6);
}

sub bytes_lookahead {
    my ($self) = @_;
    return $self->{bytes_lookahead} if ($self->{bytes_lookahead});
    my $_pos = $self->{_io}->pos();
    $self->{_io}->seek(0);
    $self->{bytes_lookahead} = $self->{_io}->read_bytes(2);
    $self->{_io}->seek($_pos);
    return $self->{bytes_lookahead};
}

sub is_used {
    my ($self) = @_;
    return $self->{is_used} if ($self->{is_used});
    $self->{is_used} = $self->bytes_lookahead() ne pack('C*', (1, 1));
    return $self->{is_used};
}

sub horiz_active_pixels {
    my ($self) = @_;
    return $self->{horiz_active_pixels} if ($self->{horiz_active_pixels});
    if ($self->is_used()) {
        $self->{horiz_active_pixels} = (($self->horiz_active_pixels_mod() + 31) * 8);
    }
    return $self->{horiz_active_pixels};
}

sub refresh_rate {
    my ($self) = @_;
    return $self->{refresh_rate} if ($self->{refresh_rate});
    if ($self->is_used()) {
        $self->{refresh_rate} = ($self->refresh_rate_mod() + 60);
    }
    return $self->{refresh_rate};
}

sub horiz_active_pixels_mod {
    my ($self) = @_;
    return $self->{horiz_active_pixels_mod};
}

sub aspect_ratio {
    my ($self) = @_;
    return $self->{aspect_ratio};
}

sub refresh_rate_mod {
    my ($self) = @_;
    return $self->{refresh_rate_mod};
}

1;