aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil-cisco@xs4all.nl>2021-10-01 11:15:04 +0200
committerHans Verkuil <hverkuil-cisco@xs4all.nl>2021-10-01 11:15:04 +0200
commit46a55672e67541886c55830260e90924c7ecd94f (patch)
treeff697960a77d8db5ed2cf3267aed5f8d1474518b
parent4993146962b86550a982993b8f660f0a16e4e7b2 (diff)
edid-decode: rework the -n option
Improve the native resolution reporting: include DisplayID native resolutions in the report, and if all the listed native resolutions are all the same, then just report that. Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
-rw-r--r--edid-decode.111
-rw-r--r--edid-decode.cpp180
-rw-r--r--edid-decode.h3
-rw-r--r--parse-displayid-block.cpp50
4 files changed, 183 insertions, 61 deletions
diff --git a/edid-decode.1 b/edid-decode.1
index 5bb69d1..4a20993 100644
--- a/edid-decode.1
+++ b/edid-decode.1
@@ -179,13 +179,16 @@ reported at the end.
Check if the EDID conforms to the standards. Warnings and failures are
reported as they happen.
.TP
-\fB\-n\fR, \fB\-\-native\-timings\fR
-Report the native timings at the end. There may be multiple native timing reports
+\fB\-n\fR, \fB\-\-native\-resolution\fR
+Report the native resolution at the end. There may be multiple native resolution reports
depending on whether the Source only parses Block 0 (e.g. DVI outputs) or Block 0
-and the CTA-861 Extension Blocks (HDMI).
+and the CTA-861 Extension Blocks (HDMI), or just the DisplayID Extension Blocks
+(typical for DisplayPort). If all blocks contain the same native resolution, then
+only that resolution is reported. For older displays there may be two separate native
+resolutions: progressive and interlaced.
.TP
\fB\-p\fR, \fB\-\-preferred\-timings\fR
-Report the preferred timings at the end. There may be multiple native timing reports
+Report the preferred timings at the end. There may be multiple preferred timing reports
depending on whether the Source only parses Block 0 (e.g. DVI outputs), or Block 0
and the CTA-861 Extension Blocks (HDMI), or Block 0 and the DisplayID Extension Blocks
(typical for DisplayPort).
diff --git a/edid-decode.cpp b/edid-decode.cpp
index c58139e..c274121 100644
--- a/edid-decode.cpp
+++ b/edid-decode.cpp
@@ -46,7 +46,7 @@ enum Option {
OptHelp = 'h',
OptOnlyHexDump = 'H',
OptLongTimings = 'L',
- OptNativeTimings = 'n',
+ OptNativeResolution = 'n',
OptOutputFormat = 'o',
OptPreferredTimings = 'p',
OptPhysicalAddress = 'P',
@@ -75,7 +75,7 @@ static char options[OptLast];
static struct option long_options[] = {
{ "help", no_argument, 0, OptHelp },
{ "output-format", required_argument, 0, OptOutputFormat },
- { "native-timings", no_argument, 0, OptNativeTimings },
+ { "native-resolution", no_argument, 0, OptNativeResolution },
{ "preferred-timings", no_argument, 0, OptPreferredTimings },
{ "physical-address", no_argument, 0, OptPhysicalAddress },
{ "skip-hex-dump", no_argument, 0, OptSkipHexDump },
@@ -1286,6 +1286,138 @@ void edid_state::parse_extension(const unsigned char *x)
do_checksum("", x, EDID_PAGE_SIZE);
}
+void edid_state::print_preferred_timings()
+{
+ if (base.preferred_timing.is_valid()) {
+ printf("\n----------------\n");
+ printf("\nPreferred Video Timing if only Block 0 is parsed:\n");
+ print_timings(" ", base.preferred_timing, true, false);
+ }
+
+ if (!cta.preferred_timings.empty()) {
+ printf("\n----------------\n");
+ printf("\nPreferred Video Timing%s if Block 0 and CTA-861 Blocks are parsed:\n",
+ cta.preferred_timings.size() > 1 ? "s" : "");
+ for (vec_timings_ext::iterator iter = cta.preferred_timings.begin();
+ iter != cta.preferred_timings.end(); ++iter)
+ print_timings(" ", *iter, true, false);
+ }
+
+ if (!dispid.preferred_timings.empty()) {
+ printf("\n----------------\n");
+ printf("\nPreferred Video Timing%s if Block 0 and DisplayID Blocks are parsed:\n",
+ dispid.preferred_timings.size() > 1 ? "s" : "");
+ for (vec_timings_ext::iterator iter = dispid.preferred_timings.begin();
+ iter != dispid.preferred_timings.end(); ++iter)
+ print_timings(" ", *iter, true, false);
+ }
+}
+
+void edid_state::print_native_res()
+{
+ typedef std::pair<unsigned, unsigned> resolution;
+ typedef std::set<resolution> resolution_set;
+ resolution_set native_prog, native_int;
+ unsigned native_width = 0, native_height = 0;
+ unsigned native_width_int = 0, native_height_int = 0;
+
+ // Note: it is also a mismatch if Block 0 does not define a
+ // native resolution, but other blocks do.
+ bool native_mismatch = false;
+ bool native_int_mismatch = false;
+
+ if (base.preferred_timing.is_valid() && base.preferred_is_also_native) {
+ if (base.preferred_timing.t.interlaced) {
+ native_width_int = base.preferred_timing.t.hact;
+ native_height_int = base.preferred_timing.t.vact;
+ } else {
+ native_width = base.preferred_timing.t.hact;
+ native_height = base.preferred_timing.t.vact;
+ }
+ }
+
+ if (!native_width && dispid.native_width) {
+ native_width = dispid.native_width;
+ native_height = dispid.native_height;
+ native_mismatch = true;
+ } else if (dispid.native_width && native_width &&
+ (dispid.native_width != native_width ||
+ dispid.native_height != native_height)) {
+ native_mismatch = true;
+ }
+
+ for (vec_timings_ext::iterator iter = cta.native_timings.begin();
+ iter != cta.native_timings.end(); ++iter) {
+ if (iter->t.interlaced) {
+ native_int.insert(std::pair<unsigned, unsigned>(iter->t.hact, iter->t.vact));
+ if (!native_width_int) {
+ native_width_int = iter->t.hact;
+ native_height_int = iter->t.vact;
+ native_int_mismatch = true;
+ } else if (native_width_int &&
+ (iter->t.hact != native_width_int ||
+ iter->t.vact != native_height_int)) {
+ native_int_mismatch = true;
+ }
+ } else {
+ native_prog.insert(std::pair<unsigned, unsigned>(iter->t.hact, iter->t.vact));
+ if (!native_width) {
+ native_width = iter->t.hact;
+ native_height = iter->t.vact;
+ native_mismatch = true;
+ } else if (native_width &&
+ (iter->t.hact != native_width ||
+ iter->t.vact != native_height)) {
+ native_mismatch = true;
+ }
+ }
+ }
+
+ if (native_width == 0 && native_width_int == 0) {
+ printf("\n----------------\n");
+ printf("\nNo Native Video Resolution was defined.\n");
+ return;
+ }
+
+ if ((native_width || native_width_int) &&
+ !native_mismatch && !native_int_mismatch) {
+ printf("\n----------------\n");
+ printf("\nNative Video Resolution%s:\n",
+ native_width && native_width_int ? "s" : "");
+ if (native_width)
+ printf(" %ux%u\n", native_width, native_height);
+ if (native_width_int)
+ printf(" %ux%ui\n", native_width_int, native_height_int);
+ return;
+ }
+
+ if (base.preferred_timing.is_valid() && base.preferred_is_also_native) {
+ printf("\n----------------\n");
+ printf("\nNative Video Resolution if only Block 0 is parsed:\n");
+ printf(" %ux%u%s\n",
+ base.preferred_timing.t.hact, base.preferred_timing.t.vact,
+ base.preferred_timing.t.interlaced ? "i" : "");
+ }
+
+ if (!cta.native_timings.empty()) {
+ printf("\n----------------\n");
+ printf("\nNative Video Resolution%s if Block 0 and CTA-861 Blocks are parsed:\n",
+ native_prog.size() + native_int.size() > 1 ? "s" : "");
+ for (resolution_set::iterator iter = native_prog.begin();
+ iter != native_prog.end(); ++iter)
+ printf(" %ux%u\n", iter->first, iter->second);
+ for (resolution_set::iterator iter = native_int.begin();
+ iter != native_int.end(); ++iter)
+ printf(" %ux%ui\n", iter->first, iter->second);
+ }
+
+ if (dispid.native_width) {
+ printf("\n----------------\n");
+ printf("\nNative Video Resolution if the DisplayID Blocks are parsed:\n");
+ printf(" %ux%u\n", dispid.native_width, dispid.native_height);
+ }
+}
+
int edid_state::parse_edid()
{
hide_serial_numbers = options[OptHideSerialNumbers];
@@ -1329,45 +1461,11 @@ int edid_state::parse_edid()
if (has_cta)
cta_resolve_svrs();
- if (options[OptPreferredTimings] && base.preferred_timing.is_valid()) {
- printf("\n----------------\n");
- printf("\nPreferred Video Timing if only Block 0 is parsed:\n");
- print_timings(" ", base.preferred_timing, true, false);
- }
-
- if (options[OptNativeTimings] &&
- base.preferred_timing.is_valid() && base.preferred_is_also_native) {
- printf("\n----------------\n");
- printf("\nNative Video Timing if only Block 0 is parsed:\n");
- print_timings(" ", base.preferred_timing, true, false);
- }
-
- if (options[OptPreferredTimings] && !cta.preferred_timings.empty()) {
- printf("\n----------------\n");
- printf("\nPreferred Video Timing%s if Block 0 and CTA-861 Blocks are parsed:\n",
- cta.preferred_timings.size() > 1 ? "s" : "");
- for (vec_timings_ext::iterator iter = cta.preferred_timings.begin();
- iter != cta.preferred_timings.end(); ++iter)
- print_timings(" ", *iter, true, false);
- }
-
- if (options[OptNativeTimings] && !cta.native_timings.empty()) {
- printf("\n----------------\n");
- printf("\nNative Video Timing%s if Block 0 and CTA-861 Blocks are parsed:\n",
- cta.native_timings.size() > 1 ? "s" : "");
- for (vec_timings_ext::iterator iter = cta.native_timings.begin();
- iter != cta.native_timings.end(); ++iter)
- print_timings(" ", *iter, true, false);
- }
+ if (options[OptPreferredTimings])
+ print_preferred_timings();
- if (options[OptPreferredTimings] && !dispid.preferred_timings.empty()) {
- printf("\n----------------\n");
- printf("\nPreferred Video Timing%s if Block 0 and DisplayID Blocks are parsed:\n",
- dispid.preferred_timings.size() > 1 ? "s" : "");
- for (vec_timings_ext::iterator iter = dispid.preferred_timings.begin();
- iter != dispid.preferred_timings.end(); ++iter)
- print_timings(" ", *iter, true, false);
- }
+ if (options[OptNativeResolution])
+ print_native_res();
if (!options[OptCheck] && !options[OptCheckInline])
return 0;
@@ -1861,7 +1959,7 @@ extern "C" int parse_edid(const char *input)
}
options[OptCheck] = 1;
options[OptPreferredTimings] = 1;
- options[OptNativeTimings] = 1;
+ options[OptNativeResolution] = 1;
state = edid_state();
int ret = edid_from_file(input, stderr);
return ret ? ret : state.parse_edid();
diff --git a/edid-decode.h b/edid-decode.h
index 738c95f..548f563 100644
--- a/edid-decode.h
+++ b/edid-decode.h
@@ -361,6 +361,7 @@ struct edid_state {
void cta_list_vics();
void cta_list_hdmi_vics();
+ void set_displayid_native_res(unsigned w, unsigned h);
void parse_digital_interface(const unsigned char *x);
void parse_display_device(const unsigned char *x);
void parse_display_caps(const unsigned char *x);
@@ -413,6 +414,8 @@ struct edid_state {
void preparse_extension(const unsigned char *x);
void parse_extension(const unsigned char *x);
+ void print_preferred_timings();
+ void print_native_res();
int parse_edid();
};
diff --git a/parse-displayid-block.cpp b/parse-displayid-block.cpp
index c8cea53..f4b8ca5 100644
--- a/parse-displayid-block.cpp
+++ b/parse-displayid-block.cpp
@@ -130,6 +130,26 @@ static void print_flag_lines(const char *indent, const char *label,
}
}
+void edid_state::set_displayid_native_res(unsigned w, unsigned h)
+{
+ if (dispid.native_width &&
+ (dispid.native_width != w || dispid.native_height != h)) {
+ fail("Native resolution mismatch: %ux%u -> %ux%u.\n",
+ dispid.native_width, dispid.native_height, w, h);
+ return;
+ }
+
+ if (!w && !h)
+ return;
+
+ if (!w ^ !h) {
+ fail("Invalid Native Pixel Format %ux%u.\n", w, h);
+ } else {
+ dispid.native_width = w;
+ dispid.native_height = h;
+ }
+}
+
void edid_state::parse_displayid_parameters(const unsigned char *x)
{
check_displayid_datablock_revision(x[1]);
@@ -141,8 +161,10 @@ void edid_state::parse_displayid_parameters(const unsigned char *x)
printf(" Image size: %.1f mm x %.1f mm\n",
((x[4] << 8) + x[3]) / 10.0,
((x[6] << 8) + x[5]) / 10.0);
- printf(" Pixels: %d x %d\n",
- (x[8] << 8) + x[7], (x[10] << 8) + x[9]);
+ unsigned w = (x[8] << 8) + x[7];
+ unsigned h = (x[10] << 8) + x[9];
+ printf(" Display native pixel format: %ux%u\n", w, h);
+ set_displayid_native_res(w, h);
print_flag_lines(" ", " Feature support flags:",
x[11], feature_support_flags);
@@ -591,13 +613,12 @@ void edid_state::parse_displayid_display_device(const unsigned char *x)
printf(" The backlight's intensity can be controlled\n");
unsigned w = x[5] | (x[6] << 8);
unsigned h = x[7] | (x[8] << 8);
- if (w && h) {
- printf(" Display native pixel format: %ux%u\n", w + 1, h + 1);
- dispid.native_width = w + 1;
- dispid.native_height = h + 1;
- } else if (w || h) {
- fail("Invalid Native Pixel Format %ux%u.\n", w, h);
- }
+
+ if (w) w++;
+ if (h) h++;
+
+ printf(" Display native pixel format: %ux%u\n", w, h);
+ set_displayid_native_res(w, h);
printf(" Aspect ratio and orientation:\n");
printf(" Aspect Ratio: %.2f\n", (100 + x[9]) / 100.0);
unsigned char v = x[0x0a];
@@ -1122,13 +1143,10 @@ void edid_state::parse_displayid_parameters_v2(const unsigned char *x,
hor_size / 10.0, vert_size / 10.0);
unsigned w = (x[8] << 8) + x[7];
unsigned h = (x[10] << 8) + x[9];
- if (w && h) {
- printf(" Native Format: %ux%u\n", w, h);
- dispid.native_width = w;
- dispid.native_height = h;
- } else if (w || h) {
- fail("Invalid Native Format %ux%u.\n", w, h);
- }
+
+ printf(" Display native pixel format: %ux%u\n", w, h);
+ set_displayid_native_res(w, h);
+
unsigned char v = x[11];
printf(" Scan Orientation: ");
switch (v & 0x07) {

Privacy Policy