mirror of
https://gitlab.freedesktop.org/emersion/libdisplay-info.git
synced 2024-11-16 19:48:30 +01:00
cta: add support for InfoFrame Data Block
Signed-off-by: Sebastian Wick <sebastian.wick@redhat.com>
This commit is contained in:
parent
23be3830c0
commit
506925a66b
9 changed files with 321 additions and 1 deletions
134
cta.c
134
cta.c
|
@ -1101,12 +1101,128 @@ parse_ycbcr420_cap_map(struct di_edid_cta *cta,
|
|||
memcpy(ycbcr420_cap_map->svd_bitmap, data, size);
|
||||
}
|
||||
|
||||
static struct di_cta_infoframe_descriptor *
|
||||
parse_infoframe(struct di_edid_cta *cta, uint8_t type,
|
||||
const uint8_t *data, size_t size)
|
||||
{
|
||||
struct di_cta_infoframe_descriptor infoframe = {0};
|
||||
struct di_cta_infoframe_descriptor *ifp;
|
||||
|
||||
if (type >= 8 && type <= 0x1f) {
|
||||
add_failure(cta, "InfoFrame Data Block: Type code %u is reserved.",
|
||||
type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (type >= 0x20) {
|
||||
add_failure(cta, "InfoFrame Data Block: Type code %u is forbidden.",
|
||||
type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (type == 1) {
|
||||
/* No known vendor specific InfoFrames, yet */
|
||||
return NULL;
|
||||
} else {
|
||||
switch (type) {
|
||||
case 0x02:
|
||||
infoframe.type = DI_CTA_INFOFRAME_TYPE_AUXILIARY_VIDEO_INFORMATION;
|
||||
break;
|
||||
case 0x03:
|
||||
infoframe.type = DI_CTA_INFOFRAME_TYPE_SOURCE_PRODUCT_DESCRIPTION;
|
||||
break;
|
||||
case 0x04:
|
||||
infoframe.type = DI_CTA_INFOFRAME_TYPE_AUDIO;
|
||||
break;
|
||||
case 0x05:
|
||||
infoframe.type = DI_CTA_INFOFRAME_TYPE_MPEG_SOURCE;
|
||||
break;
|
||||
case 0x06:
|
||||
infoframe.type = DI_CTA_INFOFRAME_TYPE_NTSC_VBI;
|
||||
break;
|
||||
case 0x07:
|
||||
infoframe.type = DI_CTA_INFOFRAME_TYPE_DYNAMIC_RANGE_AND_MASTERING;
|
||||
break;
|
||||
default:
|
||||
abort(); /* unreachable */
|
||||
}
|
||||
}
|
||||
|
||||
ifp = calloc(1, sizeof(*ifp));
|
||||
if (!ifp)
|
||||
return NULL;
|
||||
|
||||
*ifp = infoframe;
|
||||
return ifp;
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_infoframe_block(struct di_edid_cta *cta,
|
||||
struct di_cta_infoframe_block_priv *ifb,
|
||||
const uint8_t *data, size_t size)
|
||||
{
|
||||
size_t index = 0, length;
|
||||
uint8_t type;
|
||||
struct di_cta_infoframe_descriptor *infoframe;
|
||||
|
||||
if (size < 2) {
|
||||
add_failure(cta, "InfoFrame Data Block: Empty Data Block with length %u.",
|
||||
size);
|
||||
return false;
|
||||
}
|
||||
|
||||
ifb->block.num_simultaneous_vsifs = data[1] + 1;
|
||||
ifb->block.infoframes = (const struct di_cta_infoframe_descriptor *const *)ifb->infoframes;
|
||||
|
||||
index = get_bit_range(data[0], 7, 5) + 2;
|
||||
if (get_bit_range(data[0], 4, 0) != 0)
|
||||
add_failure(cta, "InfoFrame Data Block: InfoFrame Processing "
|
||||
"Descriptor Header bits F14-F10 shall be 0.");
|
||||
|
||||
while (true) {
|
||||
if (index == size)
|
||||
break;
|
||||
if (index > size) {
|
||||
add_failure(cta, "InfoFrame Data Block: Payload length exceeds block size.");
|
||||
return false;
|
||||
}
|
||||
|
||||
length = get_bit_range(data[index], 7, 5);
|
||||
type = get_bit_range(data[index], 4, 0);
|
||||
|
||||
if (type == 0) {
|
||||
add_failure(cta, "InfoFrame Data Block: Short InfoFrame Descriptor with type 0 is forbidden.");
|
||||
return false;
|
||||
} else if (type == 1) {
|
||||
length += 4;
|
||||
} else {
|
||||
length += 1;
|
||||
}
|
||||
|
||||
if (index + length > size) {
|
||||
add_failure(cta, "InfoFrame Data Block: Payload length exceeds block size.");
|
||||
return false;
|
||||
}
|
||||
|
||||
infoframe = parse_infoframe(cta, type, &data[index], length);
|
||||
if (infoframe) {
|
||||
assert(ifb->infoframes_len < EDID_CTA_INFOFRAME_BLOCK_ENTRIES);
|
||||
ifb->infoframes[ifb->infoframes_len++] = infoframe;
|
||||
}
|
||||
|
||||
index += length;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_data_block(struct di_cta_data_block *data_block)
|
||||
{
|
||||
size_t i;
|
||||
struct di_cta_video_block *video;
|
||||
struct di_cta_audio_block *audio;
|
||||
struct di_cta_infoframe_block_priv *infoframe;
|
||||
|
||||
switch (data_block->tag) {
|
||||
case DI_CTA_DATA_BLOCK_VIDEO:
|
||||
|
@ -1124,6 +1240,11 @@ destroy_data_block(struct di_cta_data_block *data_block)
|
|||
for (i = 0; i < audio->sads_len; i++)
|
||||
free(audio->sads[i]);
|
||||
break;
|
||||
case DI_CTA_DATA_BLOCK_INFOFRAME:
|
||||
infoframe = &data_block->infoframe;
|
||||
for (i = 0; i < infoframe->infoframes_len; i++)
|
||||
free(infoframe->infoframes[i]);
|
||||
break;
|
||||
default:
|
||||
break; /* Nothing to do */
|
||||
}
|
||||
|
@ -1248,6 +1369,10 @@ parse_data_block(struct di_edid_cta *cta, uint8_t raw_tag, const uint8_t *data,
|
|||
break;
|
||||
case 32:
|
||||
tag = DI_CTA_DATA_BLOCK_INFOFRAME;
|
||||
if (!parse_infoframe_block(cta,
|
||||
&data_block->infoframe,
|
||||
data, size))
|
||||
goto skip;
|
||||
break;
|
||||
case 34:
|
||||
tag = DI_CTA_DATA_BLOCK_DISPLAYID_VIDEO_TIMING_VII;
|
||||
|
@ -1530,6 +1655,15 @@ di_cta_data_block_get_ycbcr420_cap_map(const struct di_cta_data_block *block)
|
|||
return &block->ycbcr420_cap_map;
|
||||
}
|
||||
|
||||
const struct di_cta_infoframe_block *
|
||||
di_cta_data_block_get_infoframe(const struct di_cta_data_block *block)
|
||||
{
|
||||
if (block->tag != DI_CTA_DATA_BLOCK_INFOFRAME) {
|
||||
return NULL;
|
||||
}
|
||||
return &block->infoframe.block;
|
||||
}
|
||||
|
||||
const struct di_edid_detailed_timing_def *const *
|
||||
di_edid_cta_get_detailed_timing_defs(const struct di_edid_cta *cta)
|
||||
{
|
||||
|
|
|
@ -669,6 +669,39 @@ print_ycbcr420_cap_map(const struct di_edid_cta *cta,
|
|||
}
|
||||
}
|
||||
|
||||
static const char *
|
||||
cta_infoframe_type_name(enum di_cta_infoframe_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case DI_CTA_INFOFRAME_TYPE_AUXILIARY_VIDEO_INFORMATION:
|
||||
return "Auxiliary Video Information InfoFrame (2)";
|
||||
case DI_CTA_INFOFRAME_TYPE_SOURCE_PRODUCT_DESCRIPTION:
|
||||
return "Source Product Description InfoFrame (3)";
|
||||
case DI_CTA_INFOFRAME_TYPE_AUDIO:
|
||||
return "Audio InfoFrame (4)";
|
||||
case DI_CTA_INFOFRAME_TYPE_MPEG_SOURCE:
|
||||
return "MPEG Source InfoFrame (5)";
|
||||
case DI_CTA_INFOFRAME_TYPE_NTSC_VBI:
|
||||
return "NTSC VBI InfoFrame (6)";
|
||||
case DI_CTA_INFOFRAME_TYPE_DYNAMIC_RANGE_AND_MASTERING:
|
||||
return "Dynamic Range and Mastering InfoFrame (7)";
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
static void
|
||||
print_infoframes(const struct di_cta_infoframe_descriptor *const *infoframes)
|
||||
{
|
||||
size_t i;
|
||||
const struct di_cta_infoframe_descriptor *infoframe;
|
||||
|
||||
for (i = 0; infoframes[i] != NULL; i++) {
|
||||
infoframe = infoframes[i];
|
||||
printf(" %s\n",
|
||||
cta_infoframe_type_name(infoframe->type));
|
||||
}
|
||||
}
|
||||
|
||||
static const char *
|
||||
cta_data_block_tag_name(enum di_cta_data_block_tag tag)
|
||||
{
|
||||
|
@ -757,6 +790,7 @@ print_cta(const struct di_edid_cta *cta)
|
|||
const struct di_cta_vesa_transfer_characteristics *transfer_characteristics;
|
||||
const struct di_cta_sad *const *sads;
|
||||
const struct di_cta_ycbcr420_cap_map *ycbcr420_cap_map;
|
||||
const struct di_cta_infoframe_block *infoframe;
|
||||
size_t i;
|
||||
const struct di_edid_detailed_timing_def *const *detailed_timing_defs;
|
||||
|
||||
|
@ -897,6 +931,11 @@ print_cta(const struct di_edid_cta *cta)
|
|||
ycbcr420_cap_map = di_cta_data_block_get_ycbcr420_cap_map(data_block);
|
||||
print_ycbcr420_cap_map(cta, ycbcr420_cap_map);
|
||||
break;
|
||||
case DI_CTA_DATA_BLOCK_INFOFRAME:
|
||||
infoframe = di_cta_data_block_get_infoframe(data_block);
|
||||
printf(" VSIFs: %d\n", infoframe->num_simultaneous_vsifs - 1);
|
||||
print_infoframes(infoframe->infoframes);
|
||||
break;
|
||||
default:
|
||||
break; /* Ignore */
|
||||
}
|
||||
|
|
|
@ -48,6 +48,15 @@
|
|||
* is 63 bytes, and each Capability Bit Map uses 1 byte.
|
||||
*/
|
||||
#define EDID_CTA_MAX_YCBCR420_CAP_MAP_BLOCK_ENTRIES 63
|
||||
/**
|
||||
* The maximum number of Short InfoFrame Descriptor or Short Vendor-Specific
|
||||
* InfoFrame Descriptor entries in a InfoFrame data block.
|
||||
*
|
||||
* Each data block has its size described in a 5-bit field, so its maximum size
|
||||
* is 63 bytes, the header takes up at least 2 bytes and the smallest Short
|
||||
* InfoFrame Descriptor is 1 byte.
|
||||
*/
|
||||
#define EDID_CTA_INFOFRAME_BLOCK_ENTRIES 61
|
||||
|
||||
struct di_edid_cta {
|
||||
int revision;
|
||||
|
@ -113,6 +122,12 @@ struct di_cta_ycbcr420_cap_map {
|
|||
uint8_t svd_bitmap[EDID_CTA_MAX_YCBCR420_CAP_MAP_BLOCK_ENTRIES];
|
||||
};
|
||||
|
||||
struct di_cta_infoframe_block_priv {
|
||||
struct di_cta_infoframe_block block;
|
||||
struct di_cta_infoframe_descriptor *infoframes[EDID_CTA_INFOFRAME_BLOCK_ENTRIES + 1];
|
||||
size_t infoframes_len;
|
||||
};
|
||||
|
||||
struct di_cta_data_block {
|
||||
enum di_cta_data_block_tag tag;
|
||||
|
||||
|
@ -138,6 +153,8 @@ struct di_cta_data_block {
|
|||
struct di_cta_vesa_transfer_characteristics vesa_transfer_characteristics;
|
||||
/* Used for DI_CTA_DATA_BLOCK_YCBCR420_CAP_MAP */
|
||||
struct di_cta_ycbcr420_cap_map ycbcr420_cap_map;
|
||||
/* Used for DI_CTA_DATA_BLOCK_INFOFRAME */
|
||||
struct di_cta_infoframe_block_priv infoframe;
|
||||
};
|
||||
|
||||
extern const struct di_cta_video_format _di_cta_video_formats[];
|
||||
|
|
|
@ -877,6 +877,53 @@ di_cta_ycbcr420_cap_map_supported(const struct di_cta_ycbcr420_cap_map *cap_map,
|
|||
const struct di_cta_ycbcr420_cap_map *
|
||||
di_cta_data_block_get_ycbcr420_cap_map(const struct di_cta_data_block *block);
|
||||
|
||||
/**
|
||||
* InfoFrame types, defined in table 7.
|
||||
*
|
||||
* Note, the enum values don't match the specification.
|
||||
*/
|
||||
enum di_cta_infoframe_type {
|
||||
/* Auxiliary Video Information, defined in section 6.4. */
|
||||
DI_CTA_INFOFRAME_TYPE_AUXILIARY_VIDEO_INFORMATION,
|
||||
/* Source Product Description, defined in section 6.5. */
|
||||
DI_CTA_INFOFRAME_TYPE_SOURCE_PRODUCT_DESCRIPTION,
|
||||
/* Audio, defined in section 6.6. */
|
||||
DI_CTA_INFOFRAME_TYPE_AUDIO,
|
||||
/* MPEG Source, defined in section 6.7. */
|
||||
DI_CTA_INFOFRAME_TYPE_MPEG_SOURCE,
|
||||
/* NTSC VBI, defined in section 6.8. */
|
||||
DI_CTA_INFOFRAME_TYPE_NTSC_VBI,
|
||||
/* Dynamic Range and Mastering, defined in section 6.9. */
|
||||
DI_CTA_INFOFRAME_TYPE_DYNAMIC_RANGE_AND_MASTERING,
|
||||
};
|
||||
|
||||
/**
|
||||
* CTA InfoFrame descriptor, defined in section 7.5.9.
|
||||
*/
|
||||
struct di_cta_infoframe_descriptor {
|
||||
/* Type of InfoFrame */
|
||||
enum di_cta_infoframe_type type;
|
||||
};
|
||||
|
||||
/**
|
||||
* CTA InfoFrame processing, defined in section 7.5.9.
|
||||
*/
|
||||
struct di_cta_infoframe_block {
|
||||
/* Number of Vendor-specific InfoFrames that can be received
|
||||
* simultaneously */
|
||||
int num_simultaneous_vsifs;
|
||||
/* Supported InfoFrames. The array is NULL-terminated. */
|
||||
const struct di_cta_infoframe_descriptor *const *infoframes;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the InfoFrame information from a CTA data block.
|
||||
*
|
||||
* Returns NULL if the data block tag is not DI_CTA_DATA_BLOCK_INFOFRAME.
|
||||
*/
|
||||
const struct di_cta_infoframe_block *
|
||||
di_cta_data_block_get_infoframe(const struct di_cta_data_block *block);
|
||||
|
||||
/**
|
||||
* Get a list of EDID detailed timing definitions.
|
||||
*
|
||||
|
|
|
@ -14,6 +14,7 @@ samsung-s27a950d-dp | ./Digital/Samsung/SAM079F/6D343EDB39F8 | cff7fe4d44
|
|||
sun-gh19ps-dvi | ./Digital/Sun/SUN058C/34B2E3B9A052 | cff7fe4d44
|
||||
viewsonic-vp2768-dp | ./Digital/ViewSonic/VSC2034/6B81BEA28A1E | cff7fe4d44
|
||||
philips-ftv-490 | ./Digital/Philips/PHL01EA/03A4224323A6 | cff7fe4d44
|
||||
hitachi-55r6+ | ./Digital/Hitachi/HEC0000/58C711CBA787 | cff7fe4d44
|
||||
|
||||
The following blobs originate from the [edid-decode] repository and are under
|
||||
the same license as the rest of the libdisplay-info project:
|
||||
|
|
78
test/data/hitachi-55r6+.diff
Normal file
78
test/data/hitachi-55r6+.diff
Normal file
|
@ -0,0 +1,78 @@
|
|||
--- ref
|
||||
+++ di
|
||||
@@ -102,26 +102,6 @@
|
||||
Colorimetry Data Block:
|
||||
BT2020YCC
|
||||
BT2020RGB
|
||||
- Vendor-Specific Data Block (HDMI), OUI 00-0C-03:
|
||||
- Source physical address: 3.0.0.0
|
||||
- Supports_AI
|
||||
- DC_36bit
|
||||
- DC_30bit
|
||||
- DC_Y444
|
||||
- Maximum TMDS clock: 300 MHz
|
||||
- Extended HDMI video details:
|
||||
- Base EDID image size is in units of 1 cm
|
||||
- HDMI VICs:
|
||||
- HDMI VIC 1: 3840x2160 30.000000 Hz 16:9 67.500 kHz 297.000000 MHz
|
||||
- HDMI VIC 3: 3840x2160 24.000000 Hz 16:9 54.000 kHz 297.000000 MHz
|
||||
- HDMI VIC 4: 4096x2160 24.000000 Hz 256:135 54.000 kHz 297.000000 MHz
|
||||
- Vendor-Specific Data Block (HDMI Forum), OUI C4-5D-D8:
|
||||
- Version: 1
|
||||
- Maximum TMDS Character Rate: 600 MHz
|
||||
- SCDC Present
|
||||
- Supports 12-bits/component Deep Color 4:2:0 Pixel Encoding
|
||||
- Supports 10-bits/component Deep Color 4:2:0 Pixel Encoding
|
||||
- Supports Auto Low-Latency Mode
|
||||
HDR Static Metadata Data Block:
|
||||
Electro optical transfer functions:
|
||||
Traditional gamma - SDR luminance range
|
||||
@@ -129,23 +109,6 @@
|
||||
Hybrid Log-Gamma
|
||||
Supported static metadata descriptors:
|
||||
Static metadata type 1
|
||||
- Vendor-Specific Video Data Block (Dolby), OUI 00-D0-46:
|
||||
- Version: 2 (12 bytes)
|
||||
- Supports global dimming
|
||||
- DM Version: 3.x
|
||||
- Backlt Min Luma: 100 cd/m^2
|
||||
- Interface: Standard + Low-Latency
|
||||
- Supports 10b 12b 444: Not supported
|
||||
- Target Min PQ v2: 200 (0.05768953 cd/m^2)
|
||||
- Target Max PQ v2: 2445 (245 cd/m^2)
|
||||
- Unique Rx, Ry: 0.62500000, 0.33203125
|
||||
- Unique Gx, Gy: 0.30468750, 0.61328125
|
||||
- Unique Bx, By: 0.15234375, 0.05078125
|
||||
- Vendor-Specific Audio Data Block (Dolby), OUI 00-D0-46:
|
||||
- Version: 1 (7 bytes)
|
||||
- Height speaker zone present
|
||||
- Surround speaker zone present
|
||||
- Center speaker zone present
|
||||
YCbCr 4:2:0 Capability Map Data Block:
|
||||
VIC 97: 3840x2160 60.000000 Hz 16:9 135.000 kHz 594.000000 MHz
|
||||
VIC 102: 4096x2160 60.000000 Hz 256:135 135.000 kHz 594.000000 MHz
|
||||
@@ -156,22 +119,8 @@
|
||||
DTD 3: 1360x768 60.015162 Hz 85:48 47.712 kHz 85.500000 MHz
|
||||
Hfront 64 Hsync 112 Hback 256 Hpol P
|
||||
Vfront 3 Vsync 6 Vback 18 Vpol P
|
||||
-Checksum: 0x4d Unused space in Extension Block: 10 bytes
|
||||
+Checksum: 0x4d
|
||||
|
||||
----------------
|
||||
|
||||
-Warnings:
|
||||
-
|
||||
-Block 1, CTA-861 Extension Block:
|
||||
- IT Video Formats are overscanned by default, but normally this should be underscanned.
|
||||
- Colorimetry Data Block: Set the sRGB colorimetry bit to avoid interop issues.
|
||||
-
|
||||
-Failures:
|
||||
-
|
||||
-Block 0, Base EDID:
|
||||
- Detailed Timing Descriptor #1: Mismatch of image size 800x450 mm vs display size 1220x680 mm.
|
||||
- Detailed Timing Descriptor #2: Mismatch of image size 800x450 mm vs display size 1220x680 mm.
|
||||
-Block 1, CTA-861 Extension Block:
|
||||
- Detailed Timing Descriptor #3: Mismatch of image size vs display size: image size is not set, but display size is.
|
||||
-
|
||||
-EDID conformity: FAIL
|
||||
+EDID conformity: PASS
|
BIN
test/data/hitachi-55r6+.edid
Normal file
BIN
test/data/hitachi-55r6+.edid
Normal file
Binary file not shown.
3
test/data/hitachi-55r6+.print
Normal file
3
test/data/hitachi-55r6+.print
Normal file
|
@ -0,0 +1,3 @@
|
|||
make: Hisense Electric Co., Ltd.
|
||||
model: 55R6+
|
||||
serial: 0x000001D8
|
|
@ -30,7 +30,8 @@ test_cases = [
|
|||
'cvt',
|
||||
'philips-ftv-490',
|
||||
'samsung-q800t-hdmi2.0',
|
||||
'cta-timings'
|
||||
'cta-timings',
|
||||
'hitachi-55r6+',
|
||||
]
|
||||
|
||||
test_env = [
|
||||
|
|
Loading…
Reference in a new issue