From 8973906ea8dea0fe7712b2475a85b8f37a3b3452 Mon Sep 17 00:00:00 2001 From: Pascal Rigaux Date: Mon, 28 Feb 2005 19:38:39 +0000 Subject: - 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 --- monitor-parse-edid | 127 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 118 insertions(+), 9 deletions(-) (limited to 'monitor-parse-edid') 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) { -- cgit v1.2.1