aboutsummaryrefslogtreecommitdiffstats
path: root/monitor-parse-edid
diff options
context:
space:
mode:
authorPascal Rigaux <pixel@mandriva.com>2005-02-28 19:38:39 +0000
committerPascal Rigaux <pixel@mandriva.com>2005-02-28 19:38:39 +0000
commit8973906ea8dea0fe7712b2475a85b8f37a3b3452 (patch)
tree8de319ee14dd83cc36d65ec74a072ac178ed5f13 /monitor-parse-edid
parente72d2748a9d22228dcbd1cff755fb412f2928a78 (diff)
downloadmonitor-edid-8973906ea8dea0fe7712b2475a85b8f37a3b3452.tar
monitor-edid-8973906ea8dea0fe7712b2475a85b8f37a3b3452.tar.gz
monitor-edid-8973906ea8dea0fe7712b2475a85b8f37a3b3452.tar.bz2
monitor-edid-8973906ea8dea0fe7712b2475a85b8f37a3b3452.tar.xz
monitor-edid-8973906ea8dea0fe7712b2475a85b8f37a3b3452.zip
- handle "Manufacturer's Specified Range Timing"
- recognise more flag from feature_support - try to have a more precise max_size and ratio using the detailed_timing size in mm - try to name the ratio
Diffstat (limited to 'monitor-parse-edid')
-rwxr-xr-xmonitor-parse-edid127
1 files changed, 118 insertions, 9 deletions
diff --git a/monitor-parse-edid b/monitor-parse-edid
index edf7623..596017f 100755
--- a/monitor-parse-edid
+++ b/monitor-parse-edid
@@ -1,5 +1,8 @@
#!/usr/bin/perl
+my @CVT_ratios = qw(5/4 4/3 3/2 16/10 15/9 16/9);
+my @known_ratios = @CVT_ratios;
+
my @edid_info = group_by2(
a8 => '_header',
a2 => 'manufacturer_name',
@@ -12,8 +15,8 @@ my @edid_info = group_by2(
C => 'edid_revision',
a => 'video_input_definition',
- C => 'max_size_horizontal', # in cm
- C => 'max_size_vertical', # in cm
+ C => 'max_size_horizontal', # in cm, 0 on projectors
+ C => 'max_size_vertical', # in cm, 0 on projectors
C => 'gamma',
a => 'feature_support',
a10 => '_color_characteristics',
@@ -45,9 +48,13 @@ my %subfields = (
feature_support => [ group_by2(
1 => 'DPMS_standby',
1 => 'DPMS_suspend',
- 1 => 'DPMS_active_off',
- 1 => '',
+ 1 => 'DPMS_active_off',
1 => 'rgb',
+
+ 1 => '',
+ 1 => 'sRGB_compliance',
+ 1 => 'has_prefered_timing',
+ 1 => 'GTF_compliance',
) ],
detailed_timing => [ group_by2(
@@ -89,6 +96,24 @@ my %subfields = (
8 => 'horizontal_max',
8 => 'pixel_clock_max',
) ],
+
+ manufacturer_specified_range_timing => [ group_by2(
+ # http://www.spwg.org/salisbury_march_19_2002.pdf
+ # for the glossary: http://www.vesa.org/Public/PSWG/PSWG15v1.pdf
+ 8 => 'horizontal_sync_pulse_width_min', # HSPW (Horizontal Sync Pulse Width)
+ 8 => 'horizontal_sync_pulse_width_max',
+ 8 => 'horizontal_back_porch_min', # t_hbp
+ 8 => 'horizontal_back_porch_max',
+ 8 => 'vertical_sync_pulse_width_min', # VSPW (Vertical Sync Pulse Width)
+ 8 => 'vertical_sync_pulse_width_max',
+ 8 => 'vertical_back_porch_min', # t_vbp (Vertical Back Porch)
+ 8 => 'vertical_back_porch_max',
+ 8 => 'horizontal_blanking_min', # t_hp (Horizontal Period)
+ 8 => 'horizontal_blanking_max',
+ 8 => 'vertical_blanking_min', # t_vp
+ 8 => 'vertical_blanking_max',
+ 8 => 'module_revision',
+ ) ],
);
sub get_many_bits {
@@ -169,6 +194,32 @@ sub parse_edid {
} else {
$edid{monitor_range}{pixel_clock_max} *= 10; #- to have it in MHz
}
+ } elsif ($flag == 0xf) {
+ my $range = get_many_bits($vv, 'manufacturer_specified_range_timing');
+
+ my $e = $edid{detailed_timings}[0];
+ my $valid = 1;
+ foreach my $m ('min', 'max') {
+ my %total;
+ foreach my $dir ('horizontal', 'vertical') {
+ $range->{$dir . '_sync_pulse_width_' . $m} *= 2;
+ $range->{$dir . '_back_porch_' . $m} *= 2;
+ $range->{$dir . '_blanking_' . $m} *= 2;
+ if ($e && $e->{$dir . '_active'}) {
+ $total{$dir} = $e->{$dir . '_active'} + $range->{$dir . '_blanking_' . $m};
+ }
+ }
+ if ($total{horizontal} && $total{vertical}) {
+ my $hfreq = $e->{pixel_clock} * 1000 / $total{horizontal};
+ my $vfreq = $hfreq * 1000 / $total{vertical};
+ $range->{'horizontal_' . ($m eq 'min' ? 'max' : 'min')} = round($hfreq);
+ $range->{'vertical_' . ($m eq 'min' ? 'max' : 'min')} = round($vfreq);
+ } else {
+ $valid = 0;
+ }
+ }
+ $edid{$valid ? 'monitor_range' : 'manufacturer_specified_range_timing'} = $range;
+
} elsif ($flag == 0xfc) {
my $prev = $edid{monitor_name};
$edid{monitor_name} = ($prev ? "$prev " : '') . unpack('A13', $vv);
@@ -186,17 +237,15 @@ sub parse_edid {
$edid{$field} = $v if $field && $field !~ /^_/;
}
+ $edid{max_size_precision} = 'cm';
$edid{EISA_ID} = $edid{manufacturer_name} . sprintf('%x', $edid{product_code});
if ($edid{monitor_range}) {
$edid{HorizSync} = $edid{monitor_range}{horizontal_min} . '-' . $edid{monitor_range}{horizontal_max};
$edid{VertRefresh} = $edid{monitor_range}{vertical_min} . '-' . $edid{monitor_range}{vertical_max};
}
- $edid{diagonal_size} = sqrt(sqr($edid{max_size_horizontal}) +
- sqr($edid{max_size_vertical})) / 2.54;
foreach my $h (@{$edid{detailed_timings}}) {
-
my $horizontal_total = $h->{horizontal_active} + $h->{horizontal_blanking};
my $vertical_total = $h->{vertical_active} + $h->{vertical_blanking};
@@ -216,17 +265,76 @@ sub parse_edid {
$h->{vertical_active} + $h->{vertical_sync_offset},
$h->{vertical_active} + $h->{vertical_sync_offset} + $h->{vertical_sync_pulse_width},
$vertical_total;
- }
+
+ # if the mm size given in the detailed_timing is not far from the cm size
+ # put it as a more precise cm size
+ my %in_cm = map { $_ => $h->{$_ . '_image_size'} / 10 } ('horizontal', 'vertical');
+ my ($error) = sort { $b <=> $a } map { abs($edid{'max_size_' . $_} - $in_cm{$_}) } keys %in_cm;
+ if ($error <= 0.5) {
+ $edid{'max_size_' . $_} = $in_cm{$_} foreach keys %in_cm;
+ $edid{max_size_precision} = 'mm';
+ }
+ if ($error < 1 && $in_cm{vertical}) {
+ # using it for the ratio
+ $edid{ratio} = $in_cm{horizontal} / $in_cm{vertical};
+ $edid{ratio_name} = ratio_name($in_cm{horizontal}, $in_cm{vertical}, 'mm');
+ $edid{ratio_precision} = 'mm';
+ }
+ }
+
+ $edid{diagonal_size} = sqrt(sqr($edid{max_size_horizontal}) +
+ sqr($edid{max_size_vertical})) / 2.54;
+
+ if (!$edid{ratio} && $edid{max_size_vertical}) {
+ $edid{ratio} = $edid{max_size_horizontal} / $edid{max_size_vertical};
+ $edid{ratio_name} = ratio_name($edid{max_size_horizontal}, $edid{max_size_vertical}, 'cm');
+ $edid{ratio_precision} = 'cm';
+ }
\%edid;
}
+sub nearest_ratio {
+ my ($ratio, $max_error) = @_;
+ my @sorted =
+ sort { $a->[1] <=> $b->[1] }
+ map {
+ my $error = abs($ratio - eval($_));
+ $error > $max_error ? () : [ $_, $error ];
+ } @known_ratios;
+ $sorted[0][0];
+}
+
+sub ratio_name {
+ my ($horizontal, $vertical, $precision) = @_;
+
+ if ($precision eq 'mm') {
+ nearest_ratio($horizontal / $vertical, 0.1);
+ } else {
+ my $error = 0.5;
+ my $ratio1 = nearest_ratio(($horizontal + $error) / ($vertical - $error), 0.2);
+ my $ratio2 = nearest_ratio(($horizontal - $error) / ($vertical + $error), 0.2);
+ $ratio1 && $ratio2 or return;
+ if ($ratio1 eq $ratio2) {
+ $ratio1;
+ } else {
+ my $ratio = nearest_ratio($horizontal / $vertical, 0.2);
+ join(' or ', $ratio, $ratio eq $ratio1 ? $ratio2 : $ratio1);
+ }
+ }
+}
+
sub print_edid {
my ($edid) = @_;
print "Name: $edid->{monitor_name}\n";
print "EISA ID: $edid->{EISA_ID}\n";
- printf "Screen size: %d cm x %d cm (%3.2f inches)\n", $edid->{max_size_horizontal}, $edid->{max_size_vertical}, $edid->{diagonal_size};
+ printf "Screen size: %.1f cm x %.1f cm (%3.2f inches%s)\n",
+ $edid->{max_size_horizontal},
+ $edid->{max_size_vertical},
+ $edid->{diagonal_size},
+ $edid->{ratio_name} ? sprintf(", aspect ratio %s = %.2f", $edid->{ratio_name}, $edid->{ratio}) :
+ $edid->{ratio} ? sprintf(", aspect ratio %.2f", $edid->{ratio}) : '';
print "Gamma: ", $edid->{gamma} / 100 + 1, "\n";
printf "%s signal\n", $edid->{video_input_definition}{digital} ? 'Digital' : 'Analog';
@@ -285,6 +393,7 @@ if ($raw_perl) {
sub sqr { $_[0] * $_[0] }
+sub round { int($_[0] + 0.5) }
sub group_by2 {
my @l;
for (my $i = 0; $i < @_; $i += 2) {