aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil-cisco@xs4all.nl>2020-02-27 15:39:14 +0100
committerHans Verkuil <hverkuil-cisco@xs4all.nl>2020-02-27 15:39:14 +0100
commit0219ae832f8559868f5e5ffbea9b207e10fab2d8 (patch)
tree50aed77210911f6e68e81921da19bcfe6b488860
parent70c168e4b3dc16f7637d3610715614206ff92b49 (diff)
edid-decode: correctly report YCbCr 4:2:0 timings
These formats transmit two lines as if it was one line. So the pixelclock is actually running at half the speed, and the same is true for the horizontal frequency. This incorrect reporting caused incorrect display range checks as well. Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
-rw-r--r--edid-decode.cpp20
-rw-r--r--edid-decode.h5
-rw-r--r--parse-base-block.cpp13
-rw-r--r--parse-cta-block.cpp27
4 files changed, 46 insertions, 19 deletions
diff --git a/edid-decode.cpp b/edid-decode.cpp
index 0473bbf..94ea330 100644
--- a/edid-decode.cpp
+++ b/edid-decode.cpp
@@ -394,6 +394,9 @@ bool edid_state::print_timings(const char *prefix, const struct timings *t,
if (t->interlaced)
vact /= 2;
+ if (t->ycbcr420)
+ hor_freq_khz /= 2;
+
double vtotal = vact + vbl;
bool ok = true;
@@ -427,6 +430,7 @@ bool edid_state::print_timings(const char *prefix, const struct timings *t,
add_str(s, std::to_string(t->hsize_mm) + " mm x " + std::to_string(t->vsize_mm) + " mm");
if (!s.empty())
s = " (" + s + ")";
+ unsigned pixclk_khz = t->pixclk_khz / (t->ycbcr420 ? 2 : 1);
char buf[10];
@@ -437,16 +441,16 @@ bool edid_state::print_timings(const char *prefix, const struct timings *t,
refresh,
t->hratio, t->vratio,
hor_freq_khz,
- t->pixclk_khz / 1000.0,
+ pixclk_khz / 1000.0,
s.c_str());
unsigned len = strlen(prefix) + 2;
- if (detailed && options[OptXModeLineTimings])
+ if (!t->ycbcr420 && detailed && options[OptXModeLineTimings])
print_modeline(len, t, refresh);
- else if (detailed && options[OptFBModeTimings])
+ else if (!t->ycbcr420 && detailed && options[OptFBModeTimings])
print_fbmode(len, t, refresh, hor_freq_khz);
- else if (detailed && options[OptV4L2Timings])
+ else if (!t->ycbcr420 && detailed && options[OptV4L2Timings])
print_v4l2_timing(t, refresh, type);
else if (detailed)
print_detailed_timing(len + strlen(type) + 6, t);
@@ -475,10 +479,10 @@ bool edid_state::print_timings(const char *prefix, const struct timings *t,
min_vert_freq_hz = min(min_vert_freq_hz, refresh);
max_vert_freq_hz = max(max_vert_freq_hz, refresh);
}
- if (t->pixclk_khz && (t->hact + hbl)) {
- min_hor_freq_hz = min(min_hor_freq_hz, (t->pixclk_khz * 1000) / (t->hact + hbl));
- max_hor_freq_hz = max(max_hor_freq_hz, (t->pixclk_khz * 1000) / (t->hact + hbl));
- max_pixclk_khz = max(max_pixclk_khz, t->pixclk_khz);
+ if (pixclk_khz && (t->hact + hbl)) {
+ min_hor_freq_hz = min(min_hor_freq_hz, (pixclk_khz * 1000) / (t->hact + hbl));
+ max_hor_freq_hz = max(max_hor_freq_hz, (pixclk_khz * 1000) / (t->hact + hbl));
+ max_pixclk_khz = max(max_pixclk_khz, pixclk_khz);
}
return ok;
}
diff --git a/edid-decode.h b/edid-decode.h
index c26774a..b72b9eb 100644
--- a/edid-decode.h
+++ b/edid-decode.h
@@ -53,6 +53,7 @@ struct timings {
bool even_vtotal; // special for VIC 39
bool no_pol_vsync; // digital composite signals have no vsync polarity
unsigned hsize_mm, vsize_mm;
+ bool ycbcr420; // YCbCr 4:2:0 encoding
};
struct edid_state {
@@ -182,8 +183,8 @@ struct edid_state {
void detailed_block(const unsigned char *x);
void parse_base_block(const unsigned char *x);
- void print_vic_index(const char *prefix, unsigned idx, const char *suffix);
- void cta_svd(const unsigned char *x, unsigned n, int for_ycbcr420);
+ void print_vic_index(const char *prefix, unsigned idx, const char *suffix, bool ycbcr420 = false);
+ void cta_svd(const unsigned char *x, unsigned n, bool for_ycbcr420);
void cta_y420cmdb(const unsigned char *x, unsigned length);
void cta_vfpdb(const unsigned char *x, unsigned length);
void cta_hdmi_block(const unsigned char *x, unsigned length);
diff --git a/parse-base-block.cpp b/parse-base-block.cpp
index f842264..bd5ad37 100644
--- a/parse-base-block.cpp
+++ b/parse-base-block.cpp
@@ -982,6 +982,19 @@ void edid_state::detailed_display_range_limits(const unsigned char *x)
range_class.c_str(),
x[5] + v_min_offset, x[6] + v_max_offset,
x[7] + h_min_offset, x[8] + h_max_offset);
+
+ // For EDID 1.3 the horizontal frequency maxes out at 255 kHz.
+ // So to avoid false range-check warnings due to this limitation,
+ // just double the max_display_hor_freq_hz in this case.
+ if (edid_minor < 4 && x[8] == 0xff)
+ max_display_hor_freq_hz *= 2;
+
+ // For EDID 1.3 the vertical frequency maxes out at 255 Hz.
+ // So to avoid false range-check warnings due to this limitation,
+ // just double the max_display_vert_freq_hz in this case.
+ if (edid_minor < 4 && x[6] == 0xff)
+ max_display_vert_freq_hz *= 2;
+
if (x[9]) {
max_display_pixclk_khz = x[9] * 10000;
printf(", max dotclock %d MHz\n", x[9] * 10);
diff --git a/parse-cta-block.cpp b/parse-cta-block.cpp
index 2a2837b..8f4026d 100644
--- a/parse-cta-block.cpp
+++ b/parse-cta-block.cpp
@@ -342,7 +342,7 @@ static void cta_audio_block(const unsigned char *x, unsigned length)
}
}
-void edid_state::cta_svd(const unsigned char *x, unsigned n, int for_ycbcr420)
+void edid_state::cta_svd(const unsigned char *x, unsigned n, bool for_ycbcr420)
{
unsigned i;
@@ -387,7 +387,13 @@ void edid_state::cta_svd(const unsigned char *x, unsigned n, int for_ycbcr420)
sprintf(type, "VIC %3u", vic);
const char *flags = native ? "native" : "";
- print_timings(" ", t, type, flags);
+ if (for_ycbcr420) {
+ struct timings tmp = *t;
+ tmp.ycbcr420 = true;
+ print_timings(" ", &tmp, type, flags);
+ } else {
+ print_timings(" ", t, type, flags);
+ }
if (override_pref) {
preferred_timings = *t;
preferred_type = type;
@@ -408,7 +414,7 @@ void edid_state::cta_svd(const unsigned char *x, unsigned n, int for_ycbcr420)
}
}
-void edid_state::print_vic_index(const char *prefix, unsigned idx, const char *suffix)
+void edid_state::print_vic_index(const char *prefix, unsigned idx, const char *suffix, bool ycbcr420)
{
if (!suffix)
suffix = "";
@@ -419,11 +425,14 @@ void edid_state::print_vic_index(const char *prefix, unsigned idx, const char *s
sprintf(buf, "VIC %3u", vic);
- if (t)
- print_timings(prefix, t, buf, suffix);
- else
+ if (t) {
+ struct timings tmp = *t;
+ tmp.ycbcr420 = ycbcr420;
+ print_timings(prefix, &tmp, buf, suffix);
+ } else {
printf("%sUnknown (%s%s%s)\n", prefix, buf,
*suffix ? ", " : "", suffix);
+ }
} else {
// Should not happen!
printf("%sSVD Index %u is out of range", prefix, idx + 1);
@@ -457,7 +466,7 @@ void edid_state::cta_y420cmdb(const unsigned char *x, unsigned length)
if (!(v & (1 << j)))
continue;
- print_vic_index(" ", i * 8 + j, "");
+ print_vic_index(" ", i * 8 + j, "", true);
max_idx = i * 8 + j;
if (max_idx < preparsed_svds[0].size()) {
unsigned vic = preparsed_svds[0][max_idx];
@@ -1682,7 +1691,7 @@ void edid_state::cta_ext_block(const unsigned char *x, unsigned length)
case 0x06: cta_hdr_static_metadata_block(x + 1, length); return;
case 0x07: cta_hdr_dyn_metadata_block(x + 1, length); return;
case 0x0d: cta_vfpdb(x + 1, length); return;
- case 0x0e: cta_svd(x + 1, length, 1); return;
+ case 0x0e: cta_svd(x + 1, length, true); return;
case 0x0f: cta_y420cmdb(x + 1, length); return;
case 0x12: cta_hdmi_audio_block(x + 1, length); return;
case 0x13: cta_rcdb(x + 1, length); return;
@@ -1725,7 +1734,7 @@ void edid_state::cta_block(const unsigned char *x)
case 0x02:
data_block = "Video Data Block";
printf(" %s:\n", data_block.c_str());
- cta_svd(x + 1, length, 0);
+ cta_svd(x + 1, length, false);
break;
case 0x03:
oui = (x[3] << 16) + (x[2] << 8) + x[1];

Privacy Policy