mirror of
https://gitlab.freedesktop.org/emersion/libdisplay-info.git
synced 2024-12-25 21:59:08 +01:00
di-edid-decode: split into multiple files
di-edid-decode.c is getting bit and messy. Use one file per spec. Signed-off-by: Simon Ser <contact@emersion.fr>
This commit is contained in:
parent
f2d6819f04
commit
97a8f16d1f
6 changed files with 780 additions and 716 deletions
277
di-edid-decode/cta.c
Normal file
277
di-edid-decode/cta.c
Normal file
|
@ -0,0 +1,277 @@
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <libdisplay-info/cta.h>
|
||||||
|
|
||||||
|
#include "di-edid-decode.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
printf_cta_svds(const struct di_cta_svd *const *svds)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
const struct di_cta_svd *svd;
|
||||||
|
|
||||||
|
for (i = 0; svds[i] != NULL; i++) {
|
||||||
|
svd = svds[i];
|
||||||
|
|
||||||
|
printf(" VIC %3" PRIu8, svd->vic);
|
||||||
|
if (svd->native)
|
||||||
|
printf(" (native)");
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
// TODO: print detailed mode info
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t
|
||||||
|
encode_max_luminance(float max)
|
||||||
|
{
|
||||||
|
if (max == 0)
|
||||||
|
return 0;
|
||||||
|
return (uint8_t) (log2f(max / 50) * 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t
|
||||||
|
encode_min_luminance(float min, float max)
|
||||||
|
{
|
||||||
|
if (min == 0)
|
||||||
|
return 0;
|
||||||
|
return (uint8_t) (255 * sqrtf(min / max * 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_cta_hdr_static_metadata(const struct di_cta_hdr_static_metadata_block *metadata)
|
||||||
|
{
|
||||||
|
printf(" Electro optical transfer functions:\n");
|
||||||
|
if (metadata->eotfs->traditional_sdr)
|
||||||
|
printf(" Traditional gamma - SDR luminance range\n");
|
||||||
|
if (metadata->eotfs->traditional_hdr)
|
||||||
|
printf(" Traditional gamma - HDR luminance range\n");
|
||||||
|
if (metadata->eotfs->pq)
|
||||||
|
printf(" SMPTE ST2084\n");
|
||||||
|
if (metadata->eotfs->hlg)
|
||||||
|
printf(" Hybrid Log-Gamma\n");
|
||||||
|
|
||||||
|
printf(" Supported static metadata descriptors:\n");
|
||||||
|
if (metadata->descriptors->type1)
|
||||||
|
printf(" Static metadata type 1\n");
|
||||||
|
|
||||||
|
/* TODO: figure out a way to print raw values? */
|
||||||
|
if (metadata->desired_content_max_luminance != 0)
|
||||||
|
printf(" Desired content max luminance: %" PRIu8 " (%.3f cd/m^2)\n",
|
||||||
|
encode_max_luminance(metadata->desired_content_max_luminance),
|
||||||
|
metadata->desired_content_max_luminance);
|
||||||
|
if (metadata->desired_content_max_frame_avg_luminance != 0)
|
||||||
|
printf(" Desired content max frame-average luminance: %" PRIu8 " (%.3f cd/m^2)\n",
|
||||||
|
encode_max_luminance(metadata->desired_content_max_frame_avg_luminance),
|
||||||
|
metadata->desired_content_max_frame_avg_luminance);
|
||||||
|
if (metadata->desired_content_min_luminance != 0)
|
||||||
|
printf(" Desired content min luminance: %" PRIu8 " (%.3f cd/m^2)\n",
|
||||||
|
encode_min_luminance(metadata->desired_content_min_luminance,
|
||||||
|
metadata->desired_content_max_luminance),
|
||||||
|
metadata->desired_content_min_luminance);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_cta_vesa_transfer_characteristics(const struct di_cta_vesa_transfer_characteristics *tf)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
switch (tf->usage) {
|
||||||
|
case DI_CTA_VESA_TRANSFER_CHARACTERISTIC_USAGE_WHITE:
|
||||||
|
printf(" White");
|
||||||
|
break;
|
||||||
|
case DI_CTA_VESA_TRANSFER_CHARACTERISTIC_USAGE_RED:
|
||||||
|
printf(" Red");
|
||||||
|
break;
|
||||||
|
case DI_CTA_VESA_TRANSFER_CHARACTERISTIC_USAGE_GREEN:
|
||||||
|
printf(" Green");
|
||||||
|
break;
|
||||||
|
case DI_CTA_VESA_TRANSFER_CHARACTERISTIC_USAGE_BLUE:
|
||||||
|
printf(" Blue");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(" transfer characteristics:");
|
||||||
|
for (i = 0; i < tf->points_len; i++)
|
||||||
|
printf(" %u", (uint16_t) (tf->points[i] * 1023.0f));
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
uncommon_features.cta_transfer_characteristics = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
cta_data_block_tag_name(enum di_cta_data_block_tag tag)
|
||||||
|
{
|
||||||
|
switch (tag) {
|
||||||
|
case DI_CTA_DATA_BLOCK_AUDIO:
|
||||||
|
return "Audio Data Block";
|
||||||
|
case DI_CTA_DATA_BLOCK_VIDEO:
|
||||||
|
return "Video Data Block";
|
||||||
|
case DI_CTA_DATA_BLOCK_SPEAKER_ALLOC:
|
||||||
|
return "Speaker Allocation Data Block";
|
||||||
|
case DI_CTA_DATA_BLOCK_VESA_DISPLAY_TRANSFER_CHARACTERISTIC:
|
||||||
|
return "VESA Display Transfer Characteristic Data Block";
|
||||||
|
case DI_CTA_DATA_BLOCK_VIDEO_CAP:
|
||||||
|
return "Video Capability Data Block";
|
||||||
|
case DI_CTA_DATA_BLOCK_VESA_DISPLAY_DEVICE:
|
||||||
|
return "VESA Display Device Data Block";
|
||||||
|
case DI_CTA_DATA_BLOCK_COLORIMETRY:
|
||||||
|
return "Colorimetry Data Block";
|
||||||
|
case DI_CTA_DATA_BLOCK_HDR_STATIC_METADATA:
|
||||||
|
return "HDR Static Metadata Data Block";
|
||||||
|
case DI_CTA_DATA_BLOCK_HDR_DYNAMIC_METADATA:
|
||||||
|
return "HDR Dynamic Metadata Data Block";
|
||||||
|
case DI_CTA_DATA_BLOCK_VIDEO_FORMAT_PREF:
|
||||||
|
return "Video Format Preference Data Block";
|
||||||
|
case DI_CTA_DATA_BLOCK_YCBCR420:
|
||||||
|
return "YCbCr 4:2:0 Video Data Block";
|
||||||
|
case DI_CTA_DATA_BLOCK_YCBCR420_CAP_MAP:
|
||||||
|
return "YCbCr 4:2:0 Capability Map Data Block";
|
||||||
|
case DI_CTA_DATA_BLOCK_HDMI_AUDIO:
|
||||||
|
return "HDMI Audio Data Block";
|
||||||
|
case DI_CTA_DATA_BLOCK_ROOM_CONFIG:
|
||||||
|
return "Room Configuration Data Block";
|
||||||
|
case DI_CTA_DATA_BLOCK_SPEAKER_LOCATION:
|
||||||
|
return "Speaker Location Data Block";
|
||||||
|
case DI_CTA_DATA_BLOCK_INFOFRAME:
|
||||||
|
return "InfoFrame Data Block";
|
||||||
|
case DI_CTA_DATA_BLOCK_DISPLAYID_VIDEO_TIMING_VII:
|
||||||
|
return "DisplayID Type VII Video Timing Data Block";
|
||||||
|
case DI_CTA_DATA_BLOCK_DISPLAYID_VIDEO_TIMING_VIII:
|
||||||
|
return "DisplayID Type VIII Video Timing Data Block";
|
||||||
|
case DI_CTA_DATA_BLOCK_DISPLAYID_VIDEO_TIMING_X:
|
||||||
|
return "DisplayID Type X Video Timing Data Block";
|
||||||
|
case DI_CTA_DATA_BLOCK_HDMI_EDID_EXT_OVERRIDE :
|
||||||
|
return "HDMI Forum EDID Extension Override Data Block";
|
||||||
|
case DI_CTA_DATA_BLOCK_HDMI_SINK_CAP:
|
||||||
|
return "HDMI Forum Sink Capability Data Block";
|
||||||
|
}
|
||||||
|
return "Unknown CTA-861 Data Block";
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
video_cap_over_underscan_name(enum di_cta_video_cap_over_underscan over_underscan,
|
||||||
|
const char *unknown)
|
||||||
|
{
|
||||||
|
switch (over_underscan) {
|
||||||
|
case DI_CTA_VIDEO_CAP_UNKNOWN_OVER_UNDERSCAN:
|
||||||
|
return unknown;
|
||||||
|
case DI_CTA_VIDEO_CAP_ALWAYS_OVERSCAN:
|
||||||
|
return "Always Overscanned";
|
||||||
|
case DI_CTA_VIDEO_CAP_ALWAYS_UNDERSCAN:
|
||||||
|
return "Always Underscanned";
|
||||||
|
case DI_CTA_VIDEO_CAP_BOTH_OVER_UNDERSCAN:
|
||||||
|
return "Supports both over- and underscan";
|
||||||
|
}
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
print_cta(const struct di_edid_cta *cta)
|
||||||
|
{
|
||||||
|
const struct di_edid_cta_flags *cta_flags;
|
||||||
|
const struct di_cta_data_block *const *data_blocks;
|
||||||
|
const struct di_cta_data_block *data_block;
|
||||||
|
enum di_cta_data_block_tag data_block_tag;
|
||||||
|
const struct di_cta_svd *const *svds;
|
||||||
|
const struct di_cta_video_cap_block *video_cap;
|
||||||
|
const struct di_cta_colorimetry_block *colorimetry;
|
||||||
|
const struct di_cta_hdr_static_metadata_block *hdr_static_metadata;
|
||||||
|
const struct di_cta_vesa_transfer_characteristics *transfer_characteristics;
|
||||||
|
size_t i;
|
||||||
|
const struct di_edid_detailed_timing_def *const *detailed_timing_defs;
|
||||||
|
|
||||||
|
printf(" Revision: %d\n", di_edid_cta_get_revision(cta));
|
||||||
|
|
||||||
|
cta_flags = di_edid_cta_get_flags(cta);
|
||||||
|
if (cta_flags->it_underscan) {
|
||||||
|
printf(" Underscans IT Video Formats by default\n");
|
||||||
|
}
|
||||||
|
if (cta_flags->basic_audio) {
|
||||||
|
printf(" Basic audio support\n");
|
||||||
|
}
|
||||||
|
if (cta_flags->ycc444) {
|
||||||
|
printf(" Supports YCbCr 4:4:4\n");
|
||||||
|
}
|
||||||
|
if (cta_flags->ycc422) {
|
||||||
|
printf(" Supports YCbCr 4:2:2\n");
|
||||||
|
}
|
||||||
|
printf(" Native detailed modes: %d\n", cta_flags->native_dtds);
|
||||||
|
|
||||||
|
data_blocks = di_edid_cta_get_data_blocks(cta);
|
||||||
|
for (i = 0; data_blocks[i] != NULL; i++) {
|
||||||
|
data_block = data_blocks[i];
|
||||||
|
|
||||||
|
data_block_tag = di_cta_data_block_get_tag(data_block);
|
||||||
|
printf(" %s:\n", cta_data_block_tag_name(data_block_tag));
|
||||||
|
|
||||||
|
switch (data_block_tag) {
|
||||||
|
case DI_CTA_DATA_BLOCK_VIDEO:
|
||||||
|
svds = di_cta_data_block_get_svds(data_block);
|
||||||
|
printf_cta_svds(svds);
|
||||||
|
break;
|
||||||
|
case DI_CTA_DATA_BLOCK_VIDEO_CAP:
|
||||||
|
video_cap = di_cta_data_block_get_video_cap(data_block);
|
||||||
|
printf(" YCbCr quantization: %s\n",
|
||||||
|
video_cap->selectable_ycc_quantization_range ?
|
||||||
|
"Selectable (via AVI YQ)" : "No Data");
|
||||||
|
printf(" RGB quantization: %s\n",
|
||||||
|
video_cap->selectable_ycc_quantization_range ?
|
||||||
|
"Selectable (via AVI Q)" : "No Data");
|
||||||
|
printf(" PT scan behavior: %s\n",
|
||||||
|
video_cap_over_underscan_name(video_cap->pt_over_underscan,
|
||||||
|
"No Data"));
|
||||||
|
printf(" IT scan behavior: %s\n",
|
||||||
|
video_cap_over_underscan_name(video_cap->it_over_underscan,
|
||||||
|
"IT video formats not supported"));
|
||||||
|
printf(" CE scan behavior: %s\n",
|
||||||
|
video_cap_over_underscan_name(video_cap->ce_over_underscan,
|
||||||
|
"CE video formats not supported"));
|
||||||
|
break;
|
||||||
|
case DI_CTA_DATA_BLOCK_COLORIMETRY:
|
||||||
|
colorimetry = di_cta_data_block_get_colorimetry(data_block);
|
||||||
|
if (colorimetry->xvycc_601)
|
||||||
|
printf(" xvYCC601\n");
|
||||||
|
if (colorimetry->xvycc_709)
|
||||||
|
printf(" xvYCC709\n");
|
||||||
|
if (colorimetry->sycc_601)
|
||||||
|
printf(" sYCC601\n");
|
||||||
|
if (colorimetry->opycc_601)
|
||||||
|
printf(" opYCC601\n");
|
||||||
|
if (colorimetry->oprgb)
|
||||||
|
printf(" opRGB\n");
|
||||||
|
if (colorimetry->bt2020_cycc)
|
||||||
|
printf(" BT2020cYCC\n");
|
||||||
|
if (colorimetry->bt2020_ycc)
|
||||||
|
printf(" BT2020YCC\n");
|
||||||
|
if (colorimetry->bt2020_rgb)
|
||||||
|
printf(" BT2020RGB\n");
|
||||||
|
if (colorimetry->ictcp)
|
||||||
|
printf(" ICtCp\n");
|
||||||
|
if (colorimetry->st2113_rgb)
|
||||||
|
printf(" ST2113RGB\n");
|
||||||
|
break;
|
||||||
|
case DI_CTA_DATA_BLOCK_HDR_STATIC_METADATA:
|
||||||
|
hdr_static_metadata = di_cta_data_block_get_hdr_static_metadata(data_block);
|
||||||
|
print_cta_hdr_static_metadata(hdr_static_metadata);
|
||||||
|
break;
|
||||||
|
case DI_CTA_DATA_BLOCK_VESA_DISPLAY_TRANSFER_CHARACTERISTIC:
|
||||||
|
transfer_characteristics = di_cta_data_block_get_vesa_transfer_characteristics(data_block);
|
||||||
|
print_cta_vesa_transfer_characteristics(transfer_characteristics);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break; /* Ignore */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
detailed_timing_defs = di_edid_cta_get_detailed_timing_defs(cta);
|
||||||
|
if (detailed_timing_defs[0]) {
|
||||||
|
printf(" Detailed Timing Descriptors:\n");
|
||||||
|
}
|
||||||
|
for (i = 0; detailed_timing_defs[i] != NULL; i++) {
|
||||||
|
print_detailed_timing_def(detailed_timing_defs[i]);
|
||||||
|
}
|
||||||
|
}
|
276
di-edid-decode/displayid.c
Normal file
276
di-edid-decode/displayid.c
Normal file
|
@ -0,0 +1,276 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <libdisplay-info/displayid.h>
|
||||||
|
|
||||||
|
#include "di-edid-decode.h"
|
||||||
|
|
||||||
|
static bool is_displayid_base_block = true;
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_displayid_display_params(const struct di_displayid_display_params *params)
|
||||||
|
{
|
||||||
|
printf(" Image size: %.1f mm x %.1f mm\n",
|
||||||
|
params->horiz_image_mm, params->vert_image_mm);
|
||||||
|
printf(" Display native pixel format: %dx%d\n",
|
||||||
|
params->horiz_pixels, params->vert_pixels);
|
||||||
|
|
||||||
|
printf(" Feature support flags:\n");
|
||||||
|
if (params->features->audio)
|
||||||
|
printf(" Audio support on video interface\n");
|
||||||
|
if (params->features->separate_audio_inputs)
|
||||||
|
printf(" Separate audio inputs provided\n");
|
||||||
|
if (params->features->audio_input_override)
|
||||||
|
printf(" Audio input override\n");
|
||||||
|
if (params->features->power_management)
|
||||||
|
printf(" Power management (DPM)\n");
|
||||||
|
if (params->features->fixed_timing)
|
||||||
|
printf(" Fixed timing\n");
|
||||||
|
if (params->features->fixed_pixel_format)
|
||||||
|
printf(" Fixed pixel format\n");
|
||||||
|
if (params->features->ai)
|
||||||
|
printf(" Support ACP, ISRC1, or ISRC2packets\n");
|
||||||
|
if (params->features->deinterlacing)
|
||||||
|
printf(" De-interlacing\n");
|
||||||
|
|
||||||
|
if (params->gamma != 0)
|
||||||
|
printf(" Gamma: %.2f\n", params->gamma);
|
||||||
|
printf(" Aspect ratio: %.2f\n", params->aspect_ratio);
|
||||||
|
printf(" Dynamic bpc native: %d\n", params->bits_per_color_native);
|
||||||
|
printf(" Dynamic bpc overall: %d\n", params->bits_per_color_overall);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
get_displayid_type_i_timing_aspect_ratio(enum di_displayid_type_i_timing_aspect_ratio ratio,
|
||||||
|
int *horiz, int *vert)
|
||||||
|
{
|
||||||
|
switch (ratio) {
|
||||||
|
case DI_DISPLAYID_TYPE_I_TIMING_ASPECT_RATIO_1_1:
|
||||||
|
*horiz = *vert = 1;
|
||||||
|
return;
|
||||||
|
case DI_DISPLAYID_TYPE_I_TIMING_ASPECT_RATIO_5_4:
|
||||||
|
*horiz = 5;
|
||||||
|
*vert = 4;
|
||||||
|
return;
|
||||||
|
case DI_DISPLAYID_TYPE_I_TIMING_ASPECT_RATIO_4_3:
|
||||||
|
*horiz = 4;
|
||||||
|
*vert = 3;
|
||||||
|
return;
|
||||||
|
case DI_DISPLAYID_TYPE_I_TIMING_ASPECT_RATIO_15_9:
|
||||||
|
*horiz = 15;
|
||||||
|
*vert = 9;
|
||||||
|
return;
|
||||||
|
case DI_DISPLAYID_TYPE_I_TIMING_ASPECT_RATIO_16_9:
|
||||||
|
*horiz = 16;
|
||||||
|
*vert = 9;
|
||||||
|
return;
|
||||||
|
case DI_DISPLAYID_TYPE_I_TIMING_ASPECT_RATIO_16_10:
|
||||||
|
*horiz = 16;
|
||||||
|
*vert = 10;
|
||||||
|
return;
|
||||||
|
case DI_DISPLAYID_TYPE_I_TIMING_ASPECT_RATIO_64_27:
|
||||||
|
*horiz = 64;
|
||||||
|
*vert = 27;
|
||||||
|
return;
|
||||||
|
case DI_DISPLAYID_TYPE_I_TIMING_ASPECT_RATIO_256_135:
|
||||||
|
*horiz = 256;
|
||||||
|
*vert = 135;
|
||||||
|
return;
|
||||||
|
case DI_DISPLAYID_TYPE_I_TIMING_ASPECT_RATIO_UNDEFINED:
|
||||||
|
*horiz = *vert = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
abort(); /* Unreachable */
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
displayid_type_i_timing_stereo_3d_name(enum di_displayid_type_i_timing_stereo_3d stereo_3d)
|
||||||
|
{
|
||||||
|
switch (stereo_3d) {
|
||||||
|
case DI_DISPLAYID_TYPE_I_TIMING_STEREO_3D_NEVER:
|
||||||
|
return "no 3D stereo";
|
||||||
|
case DI_DISPLAYID_TYPE_I_TIMING_STEREO_3D_ALWAYS:
|
||||||
|
return "3D stereo";
|
||||||
|
case DI_DISPLAYID_TYPE_I_TIMING_STEREO_3D_USER:
|
||||||
|
return "3D stereo depends on user action";
|
||||||
|
}
|
||||||
|
abort(); /* Unreachable */
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
displayid_type_i_timing_sync_polarity_name(enum di_displayid_type_i_timing_sync_polarity pol)
|
||||||
|
{
|
||||||
|
switch (pol) {
|
||||||
|
case DI_DISPLAYID_TYPE_I_TIMING_SYNC_NEGATIVE:
|
||||||
|
return "N";
|
||||||
|
case DI_DISPLAYID_TYPE_I_TIMING_SYNC_POSITIVE:
|
||||||
|
return "P";
|
||||||
|
}
|
||||||
|
abort(); /* Unreachable */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_displayid_type_i_timing(const struct di_displayid_type_i_timing *t)
|
||||||
|
{
|
||||||
|
int horiz_total, vert_total;
|
||||||
|
int horiz_back_porch, vert_back_porch;
|
||||||
|
int horiz_ratio, vert_ratio;
|
||||||
|
double pixel_clock_hz, refresh, horiz_freq_hz;
|
||||||
|
|
||||||
|
get_displayid_type_i_timing_aspect_ratio(t->aspect_ratio,
|
||||||
|
&horiz_ratio, &vert_ratio);
|
||||||
|
|
||||||
|
horiz_total = t->horiz_active + t->horiz_blank;
|
||||||
|
vert_total = t->vert_active + t->vert_blank;
|
||||||
|
pixel_clock_hz = t->pixel_clock_mhz * 1000 * 1000;
|
||||||
|
refresh = pixel_clock_hz / (horiz_total * vert_total);
|
||||||
|
horiz_freq_hz = pixel_clock_hz / horiz_total;
|
||||||
|
|
||||||
|
printf(" DTD:");
|
||||||
|
printf(" %5dx%-5d", t->horiz_active, t->vert_active);
|
||||||
|
if (t->interlaced) {
|
||||||
|
printf("i");
|
||||||
|
}
|
||||||
|
printf(" %10.6f Hz", refresh);
|
||||||
|
printf(" %3d:%-3d", horiz_ratio, vert_ratio);
|
||||||
|
printf(" %8.3f kHz %13.6f MHz", horiz_freq_hz / 1000,
|
||||||
|
t->pixel_clock_mhz);
|
||||||
|
printf(" (aspect ");
|
||||||
|
if (t->aspect_ratio == DI_DISPLAYID_TYPE_I_TIMING_ASPECT_RATIO_UNDEFINED)
|
||||||
|
printf("undefined");
|
||||||
|
else
|
||||||
|
printf("%d:%d", horiz_ratio, vert_ratio);
|
||||||
|
printf(", %s", displayid_type_i_timing_stereo_3d_name(t->stereo_3d));
|
||||||
|
if (t->preferred)
|
||||||
|
printf(", preferred");
|
||||||
|
printf(")\n");
|
||||||
|
|
||||||
|
horiz_back_porch = t->horiz_blank - t->horiz_sync_width - t->horiz_offset;
|
||||||
|
printf(" Hfront %4d Hsync %3d Hback %4d Hpol %s",
|
||||||
|
t->horiz_offset, t->horiz_sync_width, horiz_back_porch,
|
||||||
|
displayid_type_i_timing_sync_polarity_name(t->horiz_sync_polarity));
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
vert_back_porch = t->vert_blank - t->vert_sync_width - t->vert_offset;
|
||||||
|
printf(" Vfront %4d Vsync %3d Vback %4d Vpol %s",
|
||||||
|
t->vert_offset, t->vert_sync_width, vert_back_porch,
|
||||||
|
displayid_type_i_timing_sync_polarity_name(t->vert_sync_polarity));
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_displayid_type_i_timing_block(const struct di_displayid_data_block *data_block)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
const struct di_displayid_type_i_timing *const *timings;
|
||||||
|
|
||||||
|
timings = di_displayid_data_block_get_type_i_timings(data_block);
|
||||||
|
for (i = 0; timings[i] != NULL; i++)
|
||||||
|
print_displayid_type_i_timing(timings[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
displayid_product_type_name(enum di_displayid_product_type type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case DI_DISPLAYID_PRODUCT_TYPE_EXTENSION:
|
||||||
|
return "Extension Section";
|
||||||
|
case DI_DISPLAYID_PRODUCT_TYPE_TEST:
|
||||||
|
return "Test Structure; test equipment only";
|
||||||
|
case DI_DISPLAYID_PRODUCT_TYPE_DISPLAY_PANEL:
|
||||||
|
return "Display panel or other transducer, LCD or PDP module, etc.";
|
||||||
|
case DI_DISPLAYID_PRODUCT_TYPE_STANDALONE_DISPLAY:
|
||||||
|
return "Standalone display device";
|
||||||
|
case DI_DISPLAYID_PRODUCT_TYPE_TV_RECEIVER:
|
||||||
|
return "Television receiver";
|
||||||
|
case DI_DISPLAYID_PRODUCT_TYPE_REPEATER:
|
||||||
|
return "Repeater/translator";
|
||||||
|
case DI_DISPLAYID_PRODUCT_TYPE_DIRECT_DRIVE:
|
||||||
|
return "DIRECT DRIVE monitor";
|
||||||
|
}
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
displayid_data_block_tag_name(enum di_displayid_data_block_tag tag)
|
||||||
|
{
|
||||||
|
switch (tag) {
|
||||||
|
case DI_DISPLAYID_DATA_BLOCK_PRODUCT_ID:
|
||||||
|
return "Product Identification Data Block (0x00)";
|
||||||
|
case DI_DISPLAYID_DATA_BLOCK_DISPLAY_PARAMS:
|
||||||
|
return "Display Parameters Data Block (0x01)";
|
||||||
|
case DI_DISPLAYID_DATA_BLOCK_COLOR_CHARACT:
|
||||||
|
return "Color Characteristics Data Block";
|
||||||
|
case DI_DISPLAYID_DATA_BLOCK_TYPE_I_TIMING:
|
||||||
|
return "Video Timing Modes Type 1 - Detailed Timings Data Block";
|
||||||
|
case DI_DISPLAYID_DATA_BLOCK_TYPE_II_TIMING:
|
||||||
|
return "Video Timing Modes Type 2 - Detailed Timings Data Block";
|
||||||
|
case DI_DISPLAYID_DATA_BLOCK_TYPE_III_TIMING:
|
||||||
|
return "Video Timing Modes Type 3 - Short Timings Data Block";
|
||||||
|
case DI_DISPLAYID_DATA_BLOCK_TYPE_IV_TIMING:
|
||||||
|
return "Video Timing Modes Type 4 - DMT Timings Data Block";
|
||||||
|
case DI_DISPLAYID_DATA_BLOCK_VESA_TIMING:
|
||||||
|
return "Supported Timing Modes Type 1 - VESA DMT Timings Data Block";
|
||||||
|
case DI_DISPLAYID_DATA_BLOCK_CEA_TIMING:
|
||||||
|
return "Supported Timing Modes Type 2 - CTA-861 Timings Data Block";
|
||||||
|
case DI_DISPLAYID_DATA_BLOCK_TIMING_RANGE_LIMITS:
|
||||||
|
return "Video Timing Range Data Block";
|
||||||
|
case DI_DISPLAYID_DATA_BLOCK_PRODUCT_SERIAL:
|
||||||
|
return "Product Serial Number Data Block";
|
||||||
|
case DI_DISPLAYID_DATA_BLOCK_ASCII_STRING:
|
||||||
|
return "GP ASCII String Data Block";
|
||||||
|
case DI_DISPLAYID_DATA_BLOCK_DISPLAY_DEVICE_DATA:
|
||||||
|
return "Display Device Data Data Block";
|
||||||
|
case DI_DISPLAYID_DATA_BLOCK_INTERFACE_POWER_SEQ:
|
||||||
|
return "Interface Power Sequencing Data Block";
|
||||||
|
case DI_DISPLAYID_DATA_BLOCK_TRANSFER_CHARACT:
|
||||||
|
return "Transfer Characteristics Data Block";
|
||||||
|
case DI_DISPLAYID_DATA_BLOCK_DISPLAY_INTERFACE:
|
||||||
|
return "Display Interface Data Block";
|
||||||
|
case DI_DISPLAYID_DATA_BLOCK_STEREO_DISPLAY_INTERFACE:
|
||||||
|
return "Stereo Display Interface Data Block (0x10)";
|
||||||
|
case DI_DISPLAYID_DATA_BLOCK_TYPE_V_TIMING:
|
||||||
|
return "Video Timing Modes Type 5 - Short Timings Data Block";
|
||||||
|
case DI_DISPLAYID_DATA_BLOCK_TILED_DISPLAY_TOPO:
|
||||||
|
return "Tiled Display Topology Data Block (0x12)";
|
||||||
|
case DI_DISPLAYID_DATA_BLOCK_TYPE_VI_TIMING:
|
||||||
|
return "Video Timing Modes Type 6 - Detailed Timings Data Block";
|
||||||
|
}
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
print_displayid(const struct di_displayid *displayid)
|
||||||
|
{
|
||||||
|
const struct di_displayid_data_block *const *data_blocks;
|
||||||
|
const struct di_displayid_data_block *data_block;
|
||||||
|
enum di_displayid_data_block_tag tag;
|
||||||
|
size_t i;
|
||||||
|
const struct di_displayid_display_params *display_params;
|
||||||
|
|
||||||
|
printf(" Version: %d.%d\n", di_displayid_get_version(displayid),
|
||||||
|
di_displayid_get_revision(displayid));
|
||||||
|
|
||||||
|
if (is_displayid_base_block)
|
||||||
|
printf(" Display Product Type: %s\n",
|
||||||
|
displayid_product_type_name(di_displayid_get_product_type(displayid)));
|
||||||
|
is_displayid_base_block = false;
|
||||||
|
|
||||||
|
data_blocks = di_displayid_get_data_blocks(displayid);
|
||||||
|
for (i = 0; data_blocks[i] != NULL; i++) {
|
||||||
|
data_block = data_blocks[i];
|
||||||
|
tag = di_displayid_data_block_get_tag(data_block);
|
||||||
|
printf(" %s:\n", displayid_data_block_tag_name(tag));
|
||||||
|
switch (tag) {
|
||||||
|
case DI_DISPLAYID_DATA_BLOCK_DISPLAY_PARAMS:
|
||||||
|
display_params = di_displayid_data_block_get_display_params(data_block);
|
||||||
|
print_displayid_display_params(display_params);
|
||||||
|
break;
|
||||||
|
case DI_DISPLAYID_DATA_BLOCK_TYPE_I_TIMING:
|
||||||
|
print_displayid_type_i_timing_block(data_block);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break; /* Ignore */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,38 +3,14 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <getopt.h>
|
|
||||||
|
|
||||||
#include <libdisplay-info/cta.h>
|
|
||||||
#include <libdisplay-info/displayid.h>
|
|
||||||
#include <libdisplay-info/dmt.h>
|
#include <libdisplay-info/dmt.h>
|
||||||
#include <libdisplay-info/edid.h>
|
#include <libdisplay-info/edid.h>
|
||||||
#include <libdisplay-info/gtf.h>
|
#include <libdisplay-info/gtf.h>
|
||||||
#include <libdisplay-info/info.h>
|
|
||||||
|
|
||||||
static struct {
|
#include "di-edid-decode.h"
|
||||||
bool color_point_descriptor;
|
|
||||||
bool color_management_data;
|
|
||||||
bool cta_transfer_characteristics;
|
|
||||||
} contains_uncommon_feature;
|
|
||||||
|
|
||||||
static size_t num_detailed_timing_defs = 0;
|
static size_t num_detailed_timing_defs = 0;
|
||||||
static bool is_displayid_base_block = true;
|
|
||||||
|
|
||||||
static const struct option long_options[] = {
|
|
||||||
{ "help", no_argument, 0, 'h' },
|
|
||||||
{ 0, 0, 0, 0 }
|
|
||||||
};
|
|
||||||
|
|
||||||
static void usage(void)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Usage: di-edid-decode <options> [in]\n"
|
|
||||||
" [in]: EDID file to parse. Read from standard input (stdin),\n"
|
|
||||||
" if none given.\n"
|
|
||||||
"Example : di-edid-decode /sys/class/drm/card0-DP-2/edid \n"
|
|
||||||
"\nOptions:\n"
|
|
||||||
"-h, --help display the help message\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
standard_timing_aspect_ratio_name(enum di_edid_standard_timing_aspect_ratio aspect_ratio)
|
standard_timing_aspect_ratio_name(enum di_edid_standard_timing_aspect_ratio aspect_ratio)
|
||||||
|
@ -261,7 +237,7 @@ detailed_timing_def_sync_polarity_name(enum di_edid_detailed_timing_def_sync_pol
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
print_detailed_timing_def(const struct di_edid_detailed_timing_def *def)
|
print_detailed_timing_def(const struct di_edid_detailed_timing_def *def)
|
||||||
{
|
{
|
||||||
int hbl, vbl, horiz_total, vert_total;
|
int hbl, vbl, horiz_total, vert_total;
|
||||||
|
@ -556,7 +532,7 @@ print_display_desc(const struct di_edid *edid,
|
||||||
print_color_point(color_points[i]);
|
print_color_point(color_points[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
contains_uncommon_feature.color_point_descriptor = true;
|
uncommon_features.color_point_descriptor = true;
|
||||||
break;
|
break;
|
||||||
case DI_EDID_DISPLAY_DESCRIPTOR_ESTABLISHED_TIMINGS_III:
|
case DI_EDID_DISPLAY_DESCRIPTOR_ESTABLISHED_TIMINGS_III:
|
||||||
established_timings_iii = di_edid_display_descriptor_get_established_timings_iii(desc);
|
established_timings_iii = di_edid_display_descriptor_get_established_timings_iii(desc);
|
||||||
|
@ -578,37 +554,12 @@ print_display_desc(const struct di_edid *edid,
|
||||||
printf(" Blue a3 : %.2f\n", color_management_data->blue_a3);
|
printf(" Blue a3 : %.2f\n", color_management_data->blue_a3);
|
||||||
printf(" Blue a2 : %.2f\n", color_management_data->blue_a2);
|
printf(" Blue a2 : %.2f\n", color_management_data->blue_a2);
|
||||||
|
|
||||||
contains_uncommon_feature.color_management_data = true;
|
uncommon_features.color_management_data = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printf("\n");
|
printf("\n");
|
||||||
break; /* TODO: print other tags */
|
break; /* TODO: print other tags */
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
ext_tag_name(enum di_edid_ext_tag tag)
|
|
||||||
{
|
|
||||||
switch (tag) {
|
|
||||||
case DI_EDID_EXT_CEA:
|
|
||||||
return "CTA-861 Extension Block";
|
|
||||||
case DI_EDID_EXT_VTB:
|
|
||||||
return "Video Timing Extension Block";
|
|
||||||
case DI_EDID_EXT_DI:
|
|
||||||
return "Display Information Extension Block";
|
|
||||||
case DI_EDID_EXT_LS:
|
|
||||||
return "Localized String Extension Block";
|
|
||||||
case DI_EDID_EXT_DPVL:
|
|
||||||
return "Digital Packet Video Link Extension";
|
|
||||||
case DI_EDID_EXT_BLOCK_MAP:
|
|
||||||
return "Block Map Extension Block";
|
|
||||||
case DI_EDID_EXT_VENDOR:
|
|
||||||
return "Manufacturer-Specific Extension Block";
|
|
||||||
case DI_EDID_EXT_DISPLAYID:
|
|
||||||
return "DisplayID Extension Block";
|
|
||||||
}
|
|
||||||
abort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
|
@ -663,578 +614,9 @@ display_color_type_name(enum di_edid_display_color_type type)
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
printf_cta_svds(const struct di_cta_svd *const *svds)
|
print_edid(const struct di_edid *edid)
|
||||||
{
|
{
|
||||||
size_t i;
|
|
||||||
const struct di_cta_svd *svd;
|
|
||||||
|
|
||||||
for (i = 0; svds[i] != NULL; i++) {
|
|
||||||
svd = svds[i];
|
|
||||||
|
|
||||||
printf(" VIC %3" PRIu8, svd->vic);
|
|
||||||
if (svd->native)
|
|
||||||
printf(" (native)");
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
// TODO: print detailed mode info
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t
|
|
||||||
encode_max_luminance(float max)
|
|
||||||
{
|
|
||||||
if (max == 0)
|
|
||||||
return 0;
|
|
||||||
return (uint8_t) (log2f(max / 50) * 32);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t
|
|
||||||
encode_min_luminance(float min, float max)
|
|
||||||
{
|
|
||||||
if (min == 0)
|
|
||||||
return 0;
|
|
||||||
return (uint8_t) (255 * sqrtf(min / max * 100));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
print_cta_hdr_static_metadata(const struct di_cta_hdr_static_metadata_block *metadata)
|
|
||||||
{
|
|
||||||
printf(" Electro optical transfer functions:\n");
|
|
||||||
if (metadata->eotfs->traditional_sdr)
|
|
||||||
printf(" Traditional gamma - SDR luminance range\n");
|
|
||||||
if (metadata->eotfs->traditional_hdr)
|
|
||||||
printf(" Traditional gamma - HDR luminance range\n");
|
|
||||||
if (metadata->eotfs->pq)
|
|
||||||
printf(" SMPTE ST2084\n");
|
|
||||||
if (metadata->eotfs->hlg)
|
|
||||||
printf(" Hybrid Log-Gamma\n");
|
|
||||||
|
|
||||||
printf(" Supported static metadata descriptors:\n");
|
|
||||||
if (metadata->descriptors->type1)
|
|
||||||
printf(" Static metadata type 1\n");
|
|
||||||
|
|
||||||
/* TODO: figure out a way to print raw values? */
|
|
||||||
if (metadata->desired_content_max_luminance != 0)
|
|
||||||
printf(" Desired content max luminance: %" PRIu8 " (%.3f cd/m^2)\n",
|
|
||||||
encode_max_luminance(metadata->desired_content_max_luminance),
|
|
||||||
metadata->desired_content_max_luminance);
|
|
||||||
if (metadata->desired_content_max_frame_avg_luminance != 0)
|
|
||||||
printf(" Desired content max frame-average luminance: %" PRIu8 " (%.3f cd/m^2)\n",
|
|
||||||
encode_max_luminance(metadata->desired_content_max_frame_avg_luminance),
|
|
||||||
metadata->desired_content_max_frame_avg_luminance);
|
|
||||||
if (metadata->desired_content_min_luminance != 0)
|
|
||||||
printf(" Desired content min luminance: %" PRIu8 " (%.3f cd/m^2)\n",
|
|
||||||
encode_min_luminance(metadata->desired_content_min_luminance,
|
|
||||||
metadata->desired_content_max_luminance),
|
|
||||||
metadata->desired_content_min_luminance);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
print_cta_vesa_transfer_characteristics(const struct di_cta_vesa_transfer_characteristics *tf)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
switch (tf->usage) {
|
|
||||||
case DI_CTA_VESA_TRANSFER_CHARACTERISTIC_USAGE_WHITE:
|
|
||||||
printf(" White");
|
|
||||||
break;
|
|
||||||
case DI_CTA_VESA_TRANSFER_CHARACTERISTIC_USAGE_RED:
|
|
||||||
printf(" Red");
|
|
||||||
break;
|
|
||||||
case DI_CTA_VESA_TRANSFER_CHARACTERISTIC_USAGE_GREEN:
|
|
||||||
printf(" Green");
|
|
||||||
break;
|
|
||||||
case DI_CTA_VESA_TRANSFER_CHARACTERISTIC_USAGE_BLUE:
|
|
||||||
printf(" Blue");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf(" transfer characteristics:");
|
|
||||||
for (i = 0; i < tf->points_len; i++)
|
|
||||||
printf(" %u", (uint16_t) (tf->points[i] * 1023.0f));
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
contains_uncommon_feature.cta_transfer_characteristics = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
cta_data_block_tag_name(enum di_cta_data_block_tag tag)
|
|
||||||
{
|
|
||||||
switch (tag) {
|
|
||||||
case DI_CTA_DATA_BLOCK_AUDIO:
|
|
||||||
return "Audio Data Block";
|
|
||||||
case DI_CTA_DATA_BLOCK_VIDEO:
|
|
||||||
return "Video Data Block";
|
|
||||||
case DI_CTA_DATA_BLOCK_SPEAKER_ALLOC:
|
|
||||||
return "Speaker Allocation Data Block";
|
|
||||||
case DI_CTA_DATA_BLOCK_VESA_DISPLAY_TRANSFER_CHARACTERISTIC:
|
|
||||||
return "VESA Display Transfer Characteristic Data Block";
|
|
||||||
case DI_CTA_DATA_BLOCK_VIDEO_CAP:
|
|
||||||
return "Video Capability Data Block";
|
|
||||||
case DI_CTA_DATA_BLOCK_VESA_DISPLAY_DEVICE:
|
|
||||||
return "VESA Display Device Data Block";
|
|
||||||
case DI_CTA_DATA_BLOCK_COLORIMETRY:
|
|
||||||
return "Colorimetry Data Block";
|
|
||||||
case DI_CTA_DATA_BLOCK_HDR_STATIC_METADATA:
|
|
||||||
return "HDR Static Metadata Data Block";
|
|
||||||
case DI_CTA_DATA_BLOCK_HDR_DYNAMIC_METADATA:
|
|
||||||
return "HDR Dynamic Metadata Data Block";
|
|
||||||
case DI_CTA_DATA_BLOCK_VIDEO_FORMAT_PREF:
|
|
||||||
return "Video Format Preference Data Block";
|
|
||||||
case DI_CTA_DATA_BLOCK_YCBCR420:
|
|
||||||
return "YCbCr 4:2:0 Video Data Block";
|
|
||||||
case DI_CTA_DATA_BLOCK_YCBCR420_CAP_MAP:
|
|
||||||
return "YCbCr 4:2:0 Capability Map Data Block";
|
|
||||||
case DI_CTA_DATA_BLOCK_HDMI_AUDIO:
|
|
||||||
return "HDMI Audio Data Block";
|
|
||||||
case DI_CTA_DATA_BLOCK_ROOM_CONFIG:
|
|
||||||
return "Room Configuration Data Block";
|
|
||||||
case DI_CTA_DATA_BLOCK_SPEAKER_LOCATION:
|
|
||||||
return "Speaker Location Data Block";
|
|
||||||
case DI_CTA_DATA_BLOCK_INFOFRAME:
|
|
||||||
return "InfoFrame Data Block";
|
|
||||||
case DI_CTA_DATA_BLOCK_DISPLAYID_VIDEO_TIMING_VII:
|
|
||||||
return "DisplayID Type VII Video Timing Data Block";
|
|
||||||
case DI_CTA_DATA_BLOCK_DISPLAYID_VIDEO_TIMING_VIII:
|
|
||||||
return "DisplayID Type VIII Video Timing Data Block";
|
|
||||||
case DI_CTA_DATA_BLOCK_DISPLAYID_VIDEO_TIMING_X:
|
|
||||||
return "DisplayID Type X Video Timing Data Block";
|
|
||||||
case DI_CTA_DATA_BLOCK_HDMI_EDID_EXT_OVERRIDE :
|
|
||||||
return "HDMI Forum EDID Extension Override Data Block";
|
|
||||||
case DI_CTA_DATA_BLOCK_HDMI_SINK_CAP:
|
|
||||||
return "HDMI Forum Sink Capability Data Block";
|
|
||||||
}
|
|
||||||
return "Unknown CTA-861 Data Block";
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
video_cap_over_underscan_name(enum di_cta_video_cap_over_underscan over_underscan,
|
|
||||||
const char *unknown)
|
|
||||||
{
|
|
||||||
switch (over_underscan) {
|
|
||||||
case DI_CTA_VIDEO_CAP_UNKNOWN_OVER_UNDERSCAN:
|
|
||||||
return unknown;
|
|
||||||
case DI_CTA_VIDEO_CAP_ALWAYS_OVERSCAN:
|
|
||||||
return "Always Overscanned";
|
|
||||||
case DI_CTA_VIDEO_CAP_ALWAYS_UNDERSCAN:
|
|
||||||
return "Always Underscanned";
|
|
||||||
case DI_CTA_VIDEO_CAP_BOTH_OVER_UNDERSCAN:
|
|
||||||
return "Supports both over- and underscan";
|
|
||||||
}
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
print_cta(const struct di_edid_cta *cta)
|
|
||||||
{
|
|
||||||
const struct di_edid_cta_flags *cta_flags;
|
|
||||||
const struct di_cta_data_block *const *data_blocks;
|
|
||||||
const struct di_cta_data_block *data_block;
|
|
||||||
enum di_cta_data_block_tag data_block_tag;
|
|
||||||
const struct di_cta_svd *const *svds;
|
|
||||||
const struct di_cta_video_cap_block *video_cap;
|
|
||||||
const struct di_cta_colorimetry_block *colorimetry;
|
|
||||||
const struct di_cta_hdr_static_metadata_block *hdr_static_metadata;
|
|
||||||
const struct di_cta_vesa_transfer_characteristics *transfer_characteristics;
|
|
||||||
size_t i;
|
|
||||||
const struct di_edid_detailed_timing_def *const *detailed_timing_defs;
|
|
||||||
|
|
||||||
printf(" Revision: %d\n", di_edid_cta_get_revision(cta));
|
|
||||||
|
|
||||||
cta_flags = di_edid_cta_get_flags(cta);
|
|
||||||
if (cta_flags->it_underscan) {
|
|
||||||
printf(" Underscans IT Video Formats by default\n");
|
|
||||||
}
|
|
||||||
if (cta_flags->basic_audio) {
|
|
||||||
printf(" Basic audio support\n");
|
|
||||||
}
|
|
||||||
if (cta_flags->ycc444) {
|
|
||||||
printf(" Supports YCbCr 4:4:4\n");
|
|
||||||
}
|
|
||||||
if (cta_flags->ycc422) {
|
|
||||||
printf(" Supports YCbCr 4:2:2\n");
|
|
||||||
}
|
|
||||||
printf(" Native detailed modes: %d\n", cta_flags->native_dtds);
|
|
||||||
|
|
||||||
data_blocks = di_edid_cta_get_data_blocks(cta);
|
|
||||||
for (i = 0; data_blocks[i] != NULL; i++) {
|
|
||||||
data_block = data_blocks[i];
|
|
||||||
|
|
||||||
data_block_tag = di_cta_data_block_get_tag(data_block);
|
|
||||||
printf(" %s:\n", cta_data_block_tag_name(data_block_tag));
|
|
||||||
|
|
||||||
switch (data_block_tag) {
|
|
||||||
case DI_CTA_DATA_BLOCK_VIDEO:
|
|
||||||
svds = di_cta_data_block_get_svds(data_block);
|
|
||||||
printf_cta_svds(svds);
|
|
||||||
break;
|
|
||||||
case DI_CTA_DATA_BLOCK_VIDEO_CAP:
|
|
||||||
video_cap = di_cta_data_block_get_video_cap(data_block);
|
|
||||||
printf(" YCbCr quantization: %s\n",
|
|
||||||
video_cap->selectable_ycc_quantization_range ?
|
|
||||||
"Selectable (via AVI YQ)" : "No Data");
|
|
||||||
printf(" RGB quantization: %s\n",
|
|
||||||
video_cap->selectable_ycc_quantization_range ?
|
|
||||||
"Selectable (via AVI Q)" : "No Data");
|
|
||||||
printf(" PT scan behavior: %s\n",
|
|
||||||
video_cap_over_underscan_name(video_cap->pt_over_underscan,
|
|
||||||
"No Data"));
|
|
||||||
printf(" IT scan behavior: %s\n",
|
|
||||||
video_cap_over_underscan_name(video_cap->it_over_underscan,
|
|
||||||
"IT video formats not supported"));
|
|
||||||
printf(" CE scan behavior: %s\n",
|
|
||||||
video_cap_over_underscan_name(video_cap->ce_over_underscan,
|
|
||||||
"CE video formats not supported"));
|
|
||||||
break;
|
|
||||||
case DI_CTA_DATA_BLOCK_COLORIMETRY:
|
|
||||||
colorimetry = di_cta_data_block_get_colorimetry(data_block);
|
|
||||||
if (colorimetry->xvycc_601)
|
|
||||||
printf(" xvYCC601\n");
|
|
||||||
if (colorimetry->xvycc_709)
|
|
||||||
printf(" xvYCC709\n");
|
|
||||||
if (colorimetry->sycc_601)
|
|
||||||
printf(" sYCC601\n");
|
|
||||||
if (colorimetry->opycc_601)
|
|
||||||
printf(" opYCC601\n");
|
|
||||||
if (colorimetry->oprgb)
|
|
||||||
printf(" opRGB\n");
|
|
||||||
if (colorimetry->bt2020_cycc)
|
|
||||||
printf(" BT2020cYCC\n");
|
|
||||||
if (colorimetry->bt2020_ycc)
|
|
||||||
printf(" BT2020YCC\n");
|
|
||||||
if (colorimetry->bt2020_rgb)
|
|
||||||
printf(" BT2020RGB\n");
|
|
||||||
if (colorimetry->ictcp)
|
|
||||||
printf(" ICtCp\n");
|
|
||||||
if (colorimetry->st2113_rgb)
|
|
||||||
printf(" ST2113RGB\n");
|
|
||||||
break;
|
|
||||||
case DI_CTA_DATA_BLOCK_HDR_STATIC_METADATA:
|
|
||||||
hdr_static_metadata = di_cta_data_block_get_hdr_static_metadata(data_block);
|
|
||||||
print_cta_hdr_static_metadata(hdr_static_metadata);
|
|
||||||
break;
|
|
||||||
case DI_CTA_DATA_BLOCK_VESA_DISPLAY_TRANSFER_CHARACTERISTIC:
|
|
||||||
transfer_characteristics = di_cta_data_block_get_vesa_transfer_characteristics(data_block);
|
|
||||||
print_cta_vesa_transfer_characteristics(transfer_characteristics);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break; /* Ignore */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
detailed_timing_defs = di_edid_cta_get_detailed_timing_defs(cta);
|
|
||||||
if (detailed_timing_defs[0]) {
|
|
||||||
printf(" Detailed Timing Descriptors:\n");
|
|
||||||
}
|
|
||||||
for (i = 0; detailed_timing_defs[i] != NULL; i++) {
|
|
||||||
print_detailed_timing_def(detailed_timing_defs[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
print_displayid_display_params(const struct di_displayid_display_params *params)
|
|
||||||
{
|
|
||||||
printf(" Image size: %.1f mm x %.1f mm\n",
|
|
||||||
params->horiz_image_mm, params->vert_image_mm);
|
|
||||||
printf(" Display native pixel format: %dx%d\n",
|
|
||||||
params->horiz_pixels, params->vert_pixels);
|
|
||||||
|
|
||||||
printf(" Feature support flags:\n");
|
|
||||||
if (params->features->audio)
|
|
||||||
printf(" Audio support on video interface\n");
|
|
||||||
if (params->features->separate_audio_inputs)
|
|
||||||
printf(" Separate audio inputs provided\n");
|
|
||||||
if (params->features->audio_input_override)
|
|
||||||
printf(" Audio input override\n");
|
|
||||||
if (params->features->power_management)
|
|
||||||
printf(" Power management (DPM)\n");
|
|
||||||
if (params->features->fixed_timing)
|
|
||||||
printf(" Fixed timing\n");
|
|
||||||
if (params->features->fixed_pixel_format)
|
|
||||||
printf(" Fixed pixel format\n");
|
|
||||||
if (params->features->ai)
|
|
||||||
printf(" Support ACP, ISRC1, or ISRC2packets\n");
|
|
||||||
if (params->features->deinterlacing)
|
|
||||||
printf(" De-interlacing\n");
|
|
||||||
|
|
||||||
if (params->gamma != 0)
|
|
||||||
printf(" Gamma: %.2f\n", params->gamma);
|
|
||||||
printf(" Aspect ratio: %.2f\n", params->aspect_ratio);
|
|
||||||
printf(" Dynamic bpc native: %d\n", params->bits_per_color_native);
|
|
||||||
printf(" Dynamic bpc overall: %d\n", params->bits_per_color_overall);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
get_displayid_type_i_timing_aspect_ratio(enum di_displayid_type_i_timing_aspect_ratio ratio,
|
|
||||||
int *horiz, int *vert)
|
|
||||||
{
|
|
||||||
switch (ratio) {
|
|
||||||
case DI_DISPLAYID_TYPE_I_TIMING_ASPECT_RATIO_1_1:
|
|
||||||
*horiz = *vert = 1;
|
|
||||||
return;
|
|
||||||
case DI_DISPLAYID_TYPE_I_TIMING_ASPECT_RATIO_5_4:
|
|
||||||
*horiz = 5;
|
|
||||||
*vert = 4;
|
|
||||||
return;
|
|
||||||
case DI_DISPLAYID_TYPE_I_TIMING_ASPECT_RATIO_4_3:
|
|
||||||
*horiz = 4;
|
|
||||||
*vert = 3;
|
|
||||||
return;
|
|
||||||
case DI_DISPLAYID_TYPE_I_TIMING_ASPECT_RATIO_15_9:
|
|
||||||
*horiz = 15;
|
|
||||||
*vert = 9;
|
|
||||||
return;
|
|
||||||
case DI_DISPLAYID_TYPE_I_TIMING_ASPECT_RATIO_16_9:
|
|
||||||
*horiz = 16;
|
|
||||||
*vert = 9;
|
|
||||||
return;
|
|
||||||
case DI_DISPLAYID_TYPE_I_TIMING_ASPECT_RATIO_16_10:
|
|
||||||
*horiz = 16;
|
|
||||||
*vert = 10;
|
|
||||||
return;
|
|
||||||
case DI_DISPLAYID_TYPE_I_TIMING_ASPECT_RATIO_64_27:
|
|
||||||
*horiz = 64;
|
|
||||||
*vert = 27;
|
|
||||||
return;
|
|
||||||
case DI_DISPLAYID_TYPE_I_TIMING_ASPECT_RATIO_256_135:
|
|
||||||
*horiz = 256;
|
|
||||||
*vert = 135;
|
|
||||||
return;
|
|
||||||
case DI_DISPLAYID_TYPE_I_TIMING_ASPECT_RATIO_UNDEFINED:
|
|
||||||
*horiz = *vert = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
abort(); /* Unreachable */
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
displayid_type_i_timing_stereo_3d_name(enum di_displayid_type_i_timing_stereo_3d stereo_3d)
|
|
||||||
{
|
|
||||||
switch (stereo_3d) {
|
|
||||||
case DI_DISPLAYID_TYPE_I_TIMING_STEREO_3D_NEVER:
|
|
||||||
return "no 3D stereo";
|
|
||||||
case DI_DISPLAYID_TYPE_I_TIMING_STEREO_3D_ALWAYS:
|
|
||||||
return "3D stereo";
|
|
||||||
case DI_DISPLAYID_TYPE_I_TIMING_STEREO_3D_USER:
|
|
||||||
return "3D stereo depends on user action";
|
|
||||||
}
|
|
||||||
abort(); /* Unreachable */
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
displayid_type_i_timing_sync_polarity_name(enum di_displayid_type_i_timing_sync_polarity pol)
|
|
||||||
{
|
|
||||||
switch (pol) {
|
|
||||||
case DI_DISPLAYID_TYPE_I_TIMING_SYNC_NEGATIVE:
|
|
||||||
return "N";
|
|
||||||
case DI_DISPLAYID_TYPE_I_TIMING_SYNC_POSITIVE:
|
|
||||||
return "P";
|
|
||||||
}
|
|
||||||
abort(); /* Unreachable */
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
print_displayid_type_i_timing(const struct di_displayid_type_i_timing *t)
|
|
||||||
{
|
|
||||||
int horiz_total, vert_total;
|
|
||||||
int horiz_back_porch, vert_back_porch;
|
|
||||||
int horiz_ratio, vert_ratio;
|
|
||||||
double pixel_clock_hz, refresh, horiz_freq_hz;
|
|
||||||
|
|
||||||
get_displayid_type_i_timing_aspect_ratio(t->aspect_ratio,
|
|
||||||
&horiz_ratio, &vert_ratio);
|
|
||||||
|
|
||||||
horiz_total = t->horiz_active + t->horiz_blank;
|
|
||||||
vert_total = t->vert_active + t->vert_blank;
|
|
||||||
pixel_clock_hz = t->pixel_clock_mhz * 1000 * 1000;
|
|
||||||
refresh = pixel_clock_hz / (horiz_total * vert_total);
|
|
||||||
horiz_freq_hz = pixel_clock_hz / horiz_total;
|
|
||||||
|
|
||||||
printf(" DTD:");
|
|
||||||
printf(" %5dx%-5d", t->horiz_active, t->vert_active);
|
|
||||||
if (t->interlaced) {
|
|
||||||
printf("i");
|
|
||||||
}
|
|
||||||
printf(" %10.6f Hz", refresh);
|
|
||||||
printf(" %3d:%-3d", horiz_ratio, vert_ratio);
|
|
||||||
printf(" %8.3f kHz %13.6f MHz", horiz_freq_hz / 1000,
|
|
||||||
t->pixel_clock_mhz);
|
|
||||||
printf(" (aspect ");
|
|
||||||
if (t->aspect_ratio == DI_DISPLAYID_TYPE_I_TIMING_ASPECT_RATIO_UNDEFINED)
|
|
||||||
printf("undefined");
|
|
||||||
else
|
|
||||||
printf("%d:%d", horiz_ratio, vert_ratio);
|
|
||||||
printf(", %s", displayid_type_i_timing_stereo_3d_name(t->stereo_3d));
|
|
||||||
if (t->preferred)
|
|
||||||
printf(", preferred");
|
|
||||||
printf(")\n");
|
|
||||||
|
|
||||||
horiz_back_porch = t->horiz_blank - t->horiz_sync_width - t->horiz_offset;
|
|
||||||
printf(" Hfront %4d Hsync %3d Hback %4d Hpol %s",
|
|
||||||
t->horiz_offset, t->horiz_sync_width, horiz_back_porch,
|
|
||||||
displayid_type_i_timing_sync_polarity_name(t->horiz_sync_polarity));
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
vert_back_porch = t->vert_blank - t->vert_sync_width - t->vert_offset;
|
|
||||||
printf(" Vfront %4d Vsync %3d Vback %4d Vpol %s",
|
|
||||||
t->vert_offset, t->vert_sync_width, vert_back_porch,
|
|
||||||
displayid_type_i_timing_sync_polarity_name(t->vert_sync_polarity));
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
print_displayid_type_i_timing_block(const struct di_displayid_data_block *data_block)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
const struct di_displayid_type_i_timing *const *timings;
|
|
||||||
|
|
||||||
timings = di_displayid_data_block_get_type_i_timings(data_block);
|
|
||||||
for (i = 0; timings[i] != NULL; i++)
|
|
||||||
print_displayid_type_i_timing(timings[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
displayid_product_type_name(enum di_displayid_product_type type)
|
|
||||||
{
|
|
||||||
switch (type) {
|
|
||||||
case DI_DISPLAYID_PRODUCT_TYPE_EXTENSION:
|
|
||||||
return "Extension Section";
|
|
||||||
case DI_DISPLAYID_PRODUCT_TYPE_TEST:
|
|
||||||
return "Test Structure; test equipment only";
|
|
||||||
case DI_DISPLAYID_PRODUCT_TYPE_DISPLAY_PANEL:
|
|
||||||
return "Display panel or other transducer, LCD or PDP module, etc.";
|
|
||||||
case DI_DISPLAYID_PRODUCT_TYPE_STANDALONE_DISPLAY:
|
|
||||||
return "Standalone display device";
|
|
||||||
case DI_DISPLAYID_PRODUCT_TYPE_TV_RECEIVER:
|
|
||||||
return "Television receiver";
|
|
||||||
case DI_DISPLAYID_PRODUCT_TYPE_REPEATER:
|
|
||||||
return "Repeater/translator";
|
|
||||||
case DI_DISPLAYID_PRODUCT_TYPE_DIRECT_DRIVE:
|
|
||||||
return "DIRECT DRIVE monitor";
|
|
||||||
}
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
displayid_data_block_tag_name(enum di_displayid_data_block_tag tag)
|
|
||||||
{
|
|
||||||
switch (tag) {
|
|
||||||
case DI_DISPLAYID_DATA_BLOCK_PRODUCT_ID:
|
|
||||||
return "Product Identification Data Block (0x00)";
|
|
||||||
case DI_DISPLAYID_DATA_BLOCK_DISPLAY_PARAMS:
|
|
||||||
return "Display Parameters Data Block (0x01)";
|
|
||||||
case DI_DISPLAYID_DATA_BLOCK_COLOR_CHARACT:
|
|
||||||
return "Color Characteristics Data Block";
|
|
||||||
case DI_DISPLAYID_DATA_BLOCK_TYPE_I_TIMING:
|
|
||||||
return "Video Timing Modes Type 1 - Detailed Timings Data Block";
|
|
||||||
case DI_DISPLAYID_DATA_BLOCK_TYPE_II_TIMING:
|
|
||||||
return "Video Timing Modes Type 2 - Detailed Timings Data Block";
|
|
||||||
case DI_DISPLAYID_DATA_BLOCK_TYPE_III_TIMING:
|
|
||||||
return "Video Timing Modes Type 3 - Short Timings Data Block";
|
|
||||||
case DI_DISPLAYID_DATA_BLOCK_TYPE_IV_TIMING:
|
|
||||||
return "Video Timing Modes Type 4 - DMT Timings Data Block";
|
|
||||||
case DI_DISPLAYID_DATA_BLOCK_VESA_TIMING:
|
|
||||||
return "Supported Timing Modes Type 1 - VESA DMT Timings Data Block";
|
|
||||||
case DI_DISPLAYID_DATA_BLOCK_CEA_TIMING:
|
|
||||||
return "Supported Timing Modes Type 2 - CTA-861 Timings Data Block";
|
|
||||||
case DI_DISPLAYID_DATA_BLOCK_TIMING_RANGE_LIMITS:
|
|
||||||
return "Video Timing Range Data Block";
|
|
||||||
case DI_DISPLAYID_DATA_BLOCK_PRODUCT_SERIAL:
|
|
||||||
return "Product Serial Number Data Block";
|
|
||||||
case DI_DISPLAYID_DATA_BLOCK_ASCII_STRING:
|
|
||||||
return "GP ASCII String Data Block";
|
|
||||||
case DI_DISPLAYID_DATA_BLOCK_DISPLAY_DEVICE_DATA:
|
|
||||||
return "Display Device Data Data Block";
|
|
||||||
case DI_DISPLAYID_DATA_BLOCK_INTERFACE_POWER_SEQ:
|
|
||||||
return "Interface Power Sequencing Data Block";
|
|
||||||
case DI_DISPLAYID_DATA_BLOCK_TRANSFER_CHARACT:
|
|
||||||
return "Transfer Characteristics Data Block";
|
|
||||||
case DI_DISPLAYID_DATA_BLOCK_DISPLAY_INTERFACE:
|
|
||||||
return "Display Interface Data Block";
|
|
||||||
case DI_DISPLAYID_DATA_BLOCK_STEREO_DISPLAY_INTERFACE:
|
|
||||||
return "Stereo Display Interface Data Block (0x10)";
|
|
||||||
case DI_DISPLAYID_DATA_BLOCK_TYPE_V_TIMING:
|
|
||||||
return "Video Timing Modes Type 5 - Short Timings Data Block";
|
|
||||||
case DI_DISPLAYID_DATA_BLOCK_TILED_DISPLAY_TOPO:
|
|
||||||
return "Tiled Display Topology Data Block (0x12)";
|
|
||||||
case DI_DISPLAYID_DATA_BLOCK_TYPE_VI_TIMING:
|
|
||||||
return "Video Timing Modes Type 6 - Detailed Timings Data Block";
|
|
||||||
}
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
print_displayid(const struct di_displayid *displayid)
|
|
||||||
{
|
|
||||||
const struct di_displayid_data_block *const *data_blocks;
|
|
||||||
const struct di_displayid_data_block *data_block;
|
|
||||||
enum di_displayid_data_block_tag tag;
|
|
||||||
size_t i;
|
|
||||||
const struct di_displayid_display_params *display_params;
|
|
||||||
|
|
||||||
printf(" Version: %d.%d\n", di_displayid_get_version(displayid),
|
|
||||||
di_displayid_get_revision(displayid));
|
|
||||||
|
|
||||||
if (is_displayid_base_block)
|
|
||||||
printf(" Display Product Type: %s\n",
|
|
||||||
displayid_product_type_name(di_displayid_get_product_type(displayid)));
|
|
||||||
is_displayid_base_block = false;
|
|
||||||
|
|
||||||
data_blocks = di_displayid_get_data_blocks(displayid);
|
|
||||||
for (i = 0; data_blocks[i] != NULL; i++) {
|
|
||||||
data_block = data_blocks[i];
|
|
||||||
tag = di_displayid_data_block_get_tag(data_block);
|
|
||||||
printf(" %s:\n", displayid_data_block_tag_name(tag));
|
|
||||||
switch (tag) {
|
|
||||||
case DI_DISPLAYID_DATA_BLOCK_DISPLAY_PARAMS:
|
|
||||||
display_params = di_displayid_data_block_get_display_params(data_block);
|
|
||||||
print_displayid_display_params(display_params);
|
|
||||||
break;
|
|
||||||
case DI_DISPLAYID_DATA_BLOCK_TYPE_I_TIMING:
|
|
||||||
print_displayid_type_i_timing_block(data_block);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break; /* Ignore */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
print_ext(const struct di_edid_ext *ext, size_t ext_index)
|
|
||||||
{
|
|
||||||
const char *tag_name;
|
|
||||||
|
|
||||||
tag_name = ext_tag_name(di_edid_ext_get_tag(ext));
|
|
||||||
printf("\n----------------\n\n");
|
|
||||||
printf("Block %zu, %s:\n", ext_index + 1, tag_name);
|
|
||||||
|
|
||||||
switch (di_edid_ext_get_tag(ext)) {
|
|
||||||
case DI_EDID_EXT_CEA:
|
|
||||||
print_cta(di_edid_ext_get_cta(ext));
|
|
||||||
break;
|
|
||||||
case DI_EDID_EXT_DISPLAYID:
|
|
||||||
print_displayid(di_edid_ext_get_displayid(ext));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break; /* Ignore */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t
|
|
||||||
edid_checksum_index(size_t block_index)
|
|
||||||
{
|
|
||||||
return 128 * (block_index + 1) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
FILE *in;
|
|
||||||
static uint8_t raw[32 * 1024];
|
|
||||||
size_t size = 0;
|
|
||||||
const struct di_edid *edid;
|
|
||||||
struct di_info *info;
|
|
||||||
const struct di_edid_vendor_product *vendor_product;
|
const struct di_edid_vendor_product *vendor_product;
|
||||||
const struct di_edid_video_input_analog *video_input_analog;
|
const struct di_edid_video_input_analog *video_input_analog;
|
||||||
const struct di_edid_video_input_digital *video_input_digital;
|
const struct di_edid_video_input_digital *video_input_digital;
|
||||||
|
@ -1249,56 +631,7 @@ main(int argc, char *argv[])
|
||||||
const struct di_edid_standard_timing *const *standard_timings;
|
const struct di_edid_standard_timing *const *standard_timings;
|
||||||
const struct di_edid_detailed_timing_def *const *detailed_timing_defs;
|
const struct di_edid_detailed_timing_def *const *detailed_timing_defs;
|
||||||
const struct di_edid_display_descriptor *const *display_descs;
|
const struct di_edid_display_descriptor *const *display_descs;
|
||||||
const struct di_edid_ext *const *exts;
|
|
||||||
const char *failure_msg;
|
|
||||||
size_t i;
|
size_t i;
|
||||||
int opt;
|
|
||||||
|
|
||||||
in = stdin;
|
|
||||||
while (1) {
|
|
||||||
int option_index = 0;
|
|
||||||
opt = getopt_long(argc, argv, "h", long_options, &option_index);
|
|
||||||
if (opt == -1)
|
|
||||||
break;
|
|
||||||
|
|
||||||
switch (opt) {
|
|
||||||
case 'h':
|
|
||||||
usage();
|
|
||||||
return -1;
|
|
||||||
default:
|
|
||||||
usage();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argc > 1) {
|
|
||||||
in = fopen(argv[1], "r");
|
|
||||||
if (!in) {
|
|
||||||
perror("failed to open input file");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!feof(in)) {
|
|
||||||
size += fread(&raw[size], 1, sizeof(raw) - size, in);
|
|
||||||
if (ferror(in)) {
|
|
||||||
perror("fread failed");
|
|
||||||
return 1;
|
|
||||||
} else if (size >= sizeof(raw)) {
|
|
||||||
fprintf(stderr, "input too large\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(in);
|
|
||||||
|
|
||||||
info = di_info_parse_edid(raw, size);
|
|
||||||
if (!info) {
|
|
||||||
perror("di_edid_parse failed");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
edid = di_info_get_edid(info);
|
|
||||||
|
|
||||||
printf("Block 0, Base EDID:\n");
|
printf("Block 0, Base EDID:\n");
|
||||||
printf(" EDID Structure Version & Revision: %d.%d\n",
|
printf(" EDID Structure Version & Revision: %d.%d\n",
|
||||||
|
@ -1515,46 +848,4 @@ main(int argc, char *argv[])
|
||||||
for (i = 0; display_descs[i] != NULL; i++) {
|
for (i = 0; display_descs[i] != NULL; i++) {
|
||||||
print_display_desc(edid, display_descs[i]);
|
print_display_desc(edid, display_descs[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
exts = di_edid_get_extensions(edid);
|
|
||||||
|
|
||||||
for (i = 0; exts[i] != NULL; i++);
|
|
||||||
if (i > 0) {
|
|
||||||
printf(" Extension blocks: %zu\n", i);
|
|
||||||
}
|
|
||||||
printf("Checksum: 0x%02hhx\n", raw[edid_checksum_index(0)]);
|
|
||||||
|
|
||||||
for (i = 0; exts[i] != NULL; i++) {
|
|
||||||
print_ext(exts[i], i);
|
|
||||||
printf("Checksum: 0x%02hhx\n", raw[edid_checksum_index(i + 1)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("\n----------------\n\n");
|
|
||||||
|
|
||||||
failure_msg = di_info_get_failure_msg(info);
|
|
||||||
if (failure_msg) {
|
|
||||||
printf("Failures:\n\n%s", failure_msg);
|
|
||||||
printf("EDID conformity: FAIL\n");
|
|
||||||
} else {
|
|
||||||
printf("EDID conformity: PASS\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (contains_uncommon_feature.color_point_descriptor) {
|
|
||||||
fprintf(stderr, "The EDID blob contains an uncommon Color "
|
|
||||||
"Point Descriptor. Please share the EDID blob "
|
|
||||||
"with upstream!\n");
|
|
||||||
}
|
|
||||||
if (contains_uncommon_feature.color_management_data) {
|
|
||||||
fprintf(stderr, "The EDID blob contains an uncommon Color "
|
|
||||||
"Management Data Descriptor. Please share the "
|
|
||||||
"EDID blob with upstream!\n");
|
|
||||||
}
|
|
||||||
if (contains_uncommon_feature.cta_transfer_characteristics) {
|
|
||||||
fprintf(stderr, "The EDID blob contains an uncommon CTA VESA "
|
|
||||||
"Display Transfer Characteristic data block. "
|
|
||||||
"Please share the EDID blob with upstream!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
di_info_destroy(info);
|
|
||||||
return failure_msg ? 254 : 0;
|
|
||||||
}
|
}
|
184
di-edid-decode/main.c
Normal file
184
di-edid-decode/main.c
Normal file
|
@ -0,0 +1,184 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
|
||||||
|
#include <libdisplay-info/displayid.h>
|
||||||
|
#include <libdisplay-info/edid.h>
|
||||||
|
#include <libdisplay-info/info.h>
|
||||||
|
|
||||||
|
#include "di-edid-decode.h"
|
||||||
|
|
||||||
|
struct uncommon_features uncommon_features = {0};
|
||||||
|
|
||||||
|
static const struct option long_options[] = {
|
||||||
|
{ "help", no_argument, 0, 'h' },
|
||||||
|
{ 0, 0, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static void usage(void)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Usage: di-edid-decode <options> [in]\n"
|
||||||
|
" [in]: EDID file to parse. Read from standard input (stdin),\n"
|
||||||
|
" if none given.\n"
|
||||||
|
"Example : di-edid-decode /sys/class/drm/card0-DP-2/edid \n"
|
||||||
|
"\nOptions:\n"
|
||||||
|
"-h, --help display the help message\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
ext_tag_name(enum di_edid_ext_tag tag)
|
||||||
|
{
|
||||||
|
switch (tag) {
|
||||||
|
case DI_EDID_EXT_CEA:
|
||||||
|
return "CTA-861 Extension Block";
|
||||||
|
case DI_EDID_EXT_VTB:
|
||||||
|
return "Video Timing Extension Block";
|
||||||
|
case DI_EDID_EXT_DI:
|
||||||
|
return "Display Information Extension Block";
|
||||||
|
case DI_EDID_EXT_LS:
|
||||||
|
return "Localized String Extension Block";
|
||||||
|
case DI_EDID_EXT_DPVL:
|
||||||
|
return "Digital Packet Video Link Extension";
|
||||||
|
case DI_EDID_EXT_BLOCK_MAP:
|
||||||
|
return "Block Map Extension Block";
|
||||||
|
case DI_EDID_EXT_VENDOR:
|
||||||
|
return "Manufacturer-Specific Extension Block";
|
||||||
|
case DI_EDID_EXT_DISPLAYID:
|
||||||
|
return "DisplayID Extension Block";
|
||||||
|
}
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_ext(const struct di_edid_ext *ext, size_t ext_index)
|
||||||
|
{
|
||||||
|
const char *tag_name;
|
||||||
|
|
||||||
|
tag_name = ext_tag_name(di_edid_ext_get_tag(ext));
|
||||||
|
printf("\n----------------\n\n");
|
||||||
|
printf("Block %zu, %s:\n", ext_index + 1, tag_name);
|
||||||
|
|
||||||
|
switch (di_edid_ext_get_tag(ext)) {
|
||||||
|
case DI_EDID_EXT_CEA:
|
||||||
|
print_cta(di_edid_ext_get_cta(ext));
|
||||||
|
break;
|
||||||
|
case DI_EDID_EXT_DISPLAYID:
|
||||||
|
print_displayid(di_edid_ext_get_displayid(ext));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break; /* Ignore */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
edid_checksum_index(size_t block_index)
|
||||||
|
{
|
||||||
|
return 128 * (block_index + 1) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
FILE *in;
|
||||||
|
static uint8_t raw[32 * 1024];
|
||||||
|
size_t size = 0;
|
||||||
|
const struct di_edid *edid;
|
||||||
|
struct di_info *info;
|
||||||
|
const struct di_edid_ext *const *exts;
|
||||||
|
const char *failure_msg;
|
||||||
|
size_t i;
|
||||||
|
int opt;
|
||||||
|
|
||||||
|
in = stdin;
|
||||||
|
while (1) {
|
||||||
|
int option_index = 0;
|
||||||
|
opt = getopt_long(argc, argv, "h", long_options, &option_index);
|
||||||
|
if (opt == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (opt) {
|
||||||
|
case 'h':
|
||||||
|
usage();
|
||||||
|
return -1;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc > 1) {
|
||||||
|
in = fopen(argv[1], "r");
|
||||||
|
if (!in) {
|
||||||
|
perror("failed to open input file");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!feof(in)) {
|
||||||
|
size += fread(&raw[size], 1, sizeof(raw) - size, in);
|
||||||
|
if (ferror(in)) {
|
||||||
|
perror("fread failed");
|
||||||
|
return 1;
|
||||||
|
} else if (size >= sizeof(raw)) {
|
||||||
|
fprintf(stderr, "input too large\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(in);
|
||||||
|
|
||||||
|
info = di_info_parse_edid(raw, size);
|
||||||
|
if (!info) {
|
||||||
|
perror("di_edid_parse failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
edid = di_info_get_edid(info);
|
||||||
|
print_edid(edid);
|
||||||
|
|
||||||
|
exts = di_edid_get_extensions(edid);
|
||||||
|
|
||||||
|
for (i = 0; exts[i] != NULL; i++);
|
||||||
|
if (i > 0) {
|
||||||
|
printf(" Extension blocks: %zu\n", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Checksum: 0x%02hhx\n", raw[edid_checksum_index(0)]);
|
||||||
|
|
||||||
|
for (i = 0; exts[i] != NULL; i++) {
|
||||||
|
print_ext(exts[i], i);
|
||||||
|
printf("Checksum: 0x%02hhx\n", raw[edid_checksum_index(i + 1)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n----------------\n\n");
|
||||||
|
|
||||||
|
failure_msg = di_info_get_failure_msg(info);
|
||||||
|
if (failure_msg) {
|
||||||
|
printf("Failures:\n\n%s", failure_msg);
|
||||||
|
printf("EDID conformity: FAIL\n");
|
||||||
|
} else {
|
||||||
|
printf("EDID conformity: PASS\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uncommon_features.color_point_descriptor) {
|
||||||
|
fprintf(stderr, "The EDID blob contains an uncommon Color "
|
||||||
|
"Point Descriptor. Please share the EDID blob "
|
||||||
|
"with upstream!\n");
|
||||||
|
}
|
||||||
|
if (uncommon_features.color_management_data) {
|
||||||
|
fprintf(stderr, "The EDID blob contains an uncommon Color "
|
||||||
|
"Management Data Descriptor. Please share the "
|
||||||
|
"EDID blob with upstream!\n");
|
||||||
|
}
|
||||||
|
if (uncommon_features.cta_transfer_characteristics) {
|
||||||
|
fprintf(stderr, "The EDID blob contains an uncommon CTA VESA "
|
||||||
|
"Display Transfer Characteristic data block. "
|
||||||
|
"Please share the EDID blob with upstream!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
di_info_destroy(info);
|
||||||
|
return failure_msg ? 254 : 0;
|
||||||
|
}
|
31
include/di-edid-decode.h
Normal file
31
include/di-edid-decode.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#ifndef DI_EDID_DECODE_H
|
||||||
|
#define DI_EDID_DECODE_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
struct uncommon_features {
|
||||||
|
bool color_point_descriptor;
|
||||||
|
bool color_management_data;
|
||||||
|
bool cta_transfer_characteristics;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct uncommon_features uncommon_features;
|
||||||
|
|
||||||
|
struct di_edid;
|
||||||
|
struct di_edid_detailed_timing_def;
|
||||||
|
struct di_edid_cta;
|
||||||
|
struct di_displayid;
|
||||||
|
|
||||||
|
void
|
||||||
|
print_edid(const struct di_edid *edid);
|
||||||
|
|
||||||
|
void
|
||||||
|
print_detailed_timing_def(const struct di_edid_detailed_timing_def *def);
|
||||||
|
|
||||||
|
void
|
||||||
|
print_cta(const struct di_edid_cta *cta);
|
||||||
|
|
||||||
|
void
|
||||||
|
print_displayid(const struct di_displayid *displayid);
|
||||||
|
|
||||||
|
#endif
|
|
@ -68,7 +68,12 @@ di_dep = declare_dependency(
|
||||||
|
|
||||||
di_edid_decode = executable(
|
di_edid_decode = executable(
|
||||||
'di-edid-decode',
|
'di-edid-decode',
|
||||||
'di-edid-decode.c',
|
[
|
||||||
|
'di-edid-decode/cta.c',
|
||||||
|
'di-edid-decode/displayid.c',
|
||||||
|
'di-edid-decode/edid.c',
|
||||||
|
'di-edid-decode/main.c',
|
||||||
|
],
|
||||||
dependencies: [di_dep, math],
|
dependencies: [di_dep, math],
|
||||||
install: true,
|
install: true,
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue