2 * Copyright (C) 2012-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "AEELDParser.h"
11 #include "AEDeviceInfo.h"
12 #include "utils/EndianSwap.h"
19 #define GRAB_BITS(buf, byte, lowbit, bits) ((buf[byte] >> (lowbit)) & ((1 << (bits)) - 1))
24 uint8_t baseline_eid_len
;
26 uint8_t monitor_name_length
;
31 uint8_t audio_sync_delay
;
32 bool rlrc
; /* rear left and right of center */
33 bool flrc
; /* front left and right of center */
34 bool rc
; /* rear center */
35 bool rlr
; /* rear left and right */
36 bool fc
; /* front center */
38 bool flr
; /* front left and right */
41 uint16_t product_code
;
42 std::string monitor_name
;
45 #define ELD_VER_CEA_816D 2
46 #define ELD_VER_PARTIAL 31
48 #define ELD_EDID_VER_NONE 0
49 #define ELD_EDID_VER_CEA_861 1
50 #define ELD_EDID_VER_CEA_861_A 2
51 #define ELD_EDID_VER_CEA_861_BCD 3
53 #define ELD_CONN_TYPE_HDMI 0
54 #define ELD_CONN_TYPE_DP 1
55 #define ELD_CONN_TYPE_RESERVED1 2
56 #define ELD_CONN_TYPE_RESERVED2 3
58 #define CEA_861_FORMAT_RESERVED1 0
59 #define CEA_861_FORMAT_LPCM 1
60 #define CEA_861_FORMAT_AC3 2
61 #define CEA_861_FORMAT_MPEG1 3
62 #define CEA_861_FORMAT_MP3 4
63 #define CEA_861_FORMAT_MPEG2 5
64 #define CEA_861_FORMAT_AAC 6
65 #define CEA_861_FORMAT_DTS 7
66 #define CEA_861_FORMAT_ATRAC 8
67 #define CEA_861_FORMAT_SACD 9
68 #define CEA_861_FORMAT_EAC3 10
69 #define CEA_861_FORMAT_DTSHD 11
70 #define CEA_861_FORMAT_MLP 12
71 #define CEA_861_FORMAT_DST 13
72 #define CEA_861_FORMAT_WMAPRO 14
73 #define CEA_861_FORMAT_RESERVED2 15
75 void CAEELDParser::Parse(const uint8_t *data
, size_t length
, CAEDeviceInfo
& info
)
78 header
.eld_ver
= (data
[0 ] & 0xF8) >> 3;
79 if (header
.eld_ver
!= ELD_VER_CEA_816D
&& header
.eld_ver
!= ELD_VER_PARTIAL
)
82 header
.baseline_eid_len
= data
[2 ];
83 header
.cea_edid_ver
= (data
[4 ] & 0xE0) >> 5;
84 header
.monitor_name_length
= data
[4 ] & 0x1F;
85 header
.sad_count
= (data
[5 ] & 0xF0) >> 4;
86 header
.conn_type
= (data
[5 ] & 0x0C) >> 2;
87 header
.s_ai
= (data
[5 ] & 0x02) == 0x02;
88 header
.hdcp
= (data
[5 ] & 0x01) == 0x01;
89 header
.audio_sync_delay
= data
[6 ];
90 header
.rlrc
= (data
[7 ] & 0x40) == 0x40;
91 header
.flrc
= (data
[7 ] & 0x20) == 0x20;
92 header
.rc
= (data
[7 ] & 0x10) == 0x10;
93 header
.rlr
= (data
[7 ] & 0x08) == 0x08;
94 header
.fc
= (data
[7 ] & 0x04) == 0x04;
95 header
.lfe
= (data
[7 ] & 0x02) == 0x02;
96 header
.flr
= (data
[7 ] & 0x01) == 0x01;
97 header
.port_id
= Endian_SwapLE64(*((const uint64_t*)(data
+ 8)));
98 header
.mfg_name
[0] = 'A' + ((data
[16] >> 2) & 0x1F) - 1;
99 header
.mfg_name
[1] = 'A' + (((data
[16] << 3) | (data
[17] >> 5)) & 0x1F) - 1;
100 header
.mfg_name
[2] = 'A' + (data
[17] & 0x1F) - 1;
101 header
.mfg_name
[3] = '\0';
102 header
.product_code
= Endian_SwapLE16(*((const uint16_t*)(data
+ 18)));
104 switch (header
.conn_type
)
106 case ELD_CONN_TYPE_HDMI
: info
.m_deviceType
= AE_DEVTYPE_HDMI
; break;
107 case ELD_CONN_TYPE_DP
: info
.m_deviceType
= AE_DEVTYPE_DP
; break;
110 info
.m_displayNameExtra
= header
.mfg_name
;
111 if (header
.monitor_name_length
<= 16)
113 header
.monitor_name
.assign((const char *)(data
+ 20), header
.monitor_name_length
);
114 header
.monitor_name
.erase(std::find_if(header
.monitor_name
.rbegin(), header
.monitor_name
.rend(),
115 [](char c
) { return !std::isspace(c
); })
117 header
.monitor_name
.end());
118 if (header
.monitor_name
.length() > 0)
120 info
.m_displayNameExtra
.append(" ");
121 info
.m_displayNameExtra
.append(header
.monitor_name
);
122 if (header
.conn_type
== ELD_CONN_TYPE_HDMI
)
123 info
.m_displayNameExtra
.append(" on HDMI" );
125 info
.m_displayNameExtra
.append(" on DisplayPort");
131 if (!info
.m_channels
.HasChannel(AE_CH_FL
))
132 info
.m_channels
+= AE_CH_FL
;
133 if (!info
.m_channels
.HasChannel(AE_CH_FR
))
134 info
.m_channels
+= AE_CH_FR
;
138 if (!info
.m_channels
.HasChannel(AE_CH_LFE
))
139 info
.m_channels
+= AE_CH_LFE
;
142 if (!info
.m_channels
.HasChannel(AE_CH_FC
))
143 info
.m_channels
+= AE_CH_FC
;
147 if (!info
.m_channels
.HasChannel(AE_CH_BL
))
148 info
.m_channels
+= AE_CH_BL
;
149 if (!info
.m_channels
.HasChannel(AE_CH_BR
))
150 info
.m_channels
+= AE_CH_BR
;
154 if (!info
.m_channels
.HasChannel(AE_CH_BC
))
155 info
.m_channels
+= AE_CH_BC
;
159 if (!info
.m_channels
.HasChannel(AE_CH_FLOC
))
160 info
.m_channels
+= AE_CH_FLOC
;
161 if (!info
.m_channels
.HasChannel(AE_CH_FROC
))
162 info
.m_channels
+= AE_CH_FROC
;
167 if (!info
.m_channels
.HasChannel(AE_CH_BLOC
))
168 info
.m_channels
+= AE_CH_BLOC
;
169 if (!info
.m_channels
.HasChannel(AE_CH_BROC
))
170 info
.m_channels
+= AE_CH_BROC
;
173 const uint8_t *sad
= data
+ 20 + header
.monitor_name_length
;
174 for(uint8_t i
= 0; i
< header
.sad_count
; ++i
)
176 uint8_t offset
= i
* 3;
177 uint8_t formatCode
= (sad
[offset
+ 0] >> 3) & 0xF;
178 //uint8_t channelCount = (sad[offset + 0] & 0x7) + 1;
179 //uint8_t sampleRates = sad[offset + 1];
181 AEDataFormat fmt
= AE_FMT_INVALID
;
185 case CEA_861_FORMAT_AC3
: fmt
= AE_FMT_RAW
; break;
186 case CEA_861_FORMAT_DTS
: fmt
= AE_FMT_RAW
; break;
187 case CEA_861_FORMAT_DTSHD
: fmt
= AE_FMT_RAW
; break;
188 case CEA_861_FORMAT_EAC3
: fmt
= AE_FMT_RAW
; break;
189 case CEA_861_FORMAT_LPCM
: fmt
= AE_FMT_RAW
; break;
190 case CEA_861_FORMAT_MLP
: fmt
= AE_FMT_RAW
; break;
193 if (fmt
== AE_FMT_INVALID
)
196 if (std::find(info
.m_dataFormats
.begin(), info
.m_dataFormats
.end(), fmt
) == info
.m_dataFormats
.end())
197 info
.m_dataFormats
.push_back(fmt
);