2 * Copyright (C) 2012 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
22 #include "AEELDParser.h"
23 #include "utils/EndianSwap.h"
28 #define GRAB_BITS(buf, byte, lowbit, bits) ((buf[byte] >> (lowbit)) & ((1 << (bits)) - 1))
33 uint8_t baseline_eid_len;
35 uint8_t monitor_name_length;
40 uint8_t audio_sync_delay;
41 bool rlrc; /* rear left and right of center */
42 bool flrc; /* front left and right of center */
43 bool rc; /* rear center */
44 bool rlr; /* rear left and right */
45 bool fc; /* front center */
47 bool flr; /* front left and right */
50 uint16_t product_code;
51 std::string monitor_name;
54 #define ELD_VER_CEA_816D 2
55 #define ELD_VER_PARTIAL 31
57 #define ELD_EDID_VER_NONE 0
58 #define ELD_EDID_VER_CEA_861 1
59 #define ELD_EDID_VER_CEA_861_A 2
60 #define ELD_EDID_VER_CEA_861_BCD 3
62 #define ELD_CONN_TYPE_HDMI 0
63 #define ELD_CONN_TYPE_DP 1
64 #define ELD_CONN_TYPE_RESERVED1 2
65 #define ELD_CONN_TYPE_RESERVED2 3
67 #define CEA_861_FORMAT_RESERVED1 0
68 #define CEA_861_FORMAT_LPCM 1
69 #define CEA_861_FORMAT_AC3 2
70 #define CEA_861_FORMAT_MPEG1 3
71 #define CEA_861_FORMAT_MP3 4
72 #define CEA_861_FORMAT_MPEG2 5
73 #define CEA_861_FORMAT_AAC 6
74 #define CEA_861_FORMAT_DTS 7
75 #define CEA_861_FORMAT_ATRAC 8
76 #define CEA_861_FORMAT_SACD 9
77 #define CEA_861_FORMAT_EAC3 10
78 #define CEA_861_FORMAT_DTSHD 11
79 #define CEA_861_FORMAT_MLP 12
80 #define CEA_861_FORMAT_DST 13
81 #define CEA_861_FORMAT_WMAPRO 14
82 #define CEA_861_FORMAT_RESERVED2 15
84 #define rtrim(s) s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end())
86 void CAEELDParser::Parse(const uint8_t *data, size_t length, CAEDeviceInfo& info)
89 header.eld_ver = (data[0 ] & 0xF8) >> 3;
90 if (header.eld_ver != ELD_VER_CEA_816D && header.eld_ver != ELD_VER_PARTIAL)
93 header.baseline_eid_len = data[2 ];
94 header.cea_edid_ver = (data[4 ] & 0xE0) >> 5;
95 header.monitor_name_length = data[4 ] & 0x1F;
96 header.sad_count = (data[5 ] & 0xF0) >> 4;
97 header.conn_type = (data[5 ] & 0x0C) >> 2;
98 header.s_ai = (data[5 ] & 0x02) == 0x02;
99 header.hdcp = (data[5 ] & 0x01) == 0x01;
100 header.audio_sync_delay = data[6 ];
101 header.rlrc = (data[7 ] & 0x40) == 0x40;
102 header.flrc = (data[7 ] & 0x20) == 0x20;
103 header.rc = (data[7 ] & 0x10) == 0x10;
104 header.rlr = (data[7 ] & 0x08) == 0x08;
105 header.fc = (data[7 ] & 0x04) == 0x04;
106 header.lfe = (data[7 ] & 0x02) == 0x02;
107 header.flr = (data[7 ] & 0x01) == 0x01;
108 header.port_id = Endian_SwapLE64(*((uint64_t*)(data + 8)));
109 header.mfg_name[0] = 'A' + ((data[16] >> 2) & 0x1F) - 1;
110 header.mfg_name[1] = 'A' + (((data[16] << 3) | (data[17] >> 5)) & 0x1F) - 1;
111 header.mfg_name[2] = 'A' + (data[17] & 0x1F) - 1;
112 header.mfg_name[3] = '\0';
113 header.product_code = Endian_SwapLE16(*((uint16_t*)(data + 18)));
115 switch (header.conn_type)
117 case ELD_CONN_TYPE_HDMI: info.m_deviceType = AE_DEVTYPE_HDMI; break;
118 case ELD_CONN_TYPE_DP : info.m_deviceType = AE_DEVTYPE_DP ; break;
121 info.m_displayNameExtra = header.mfg_name;
122 if (header.monitor_name_length <= 16)
124 header.monitor_name.assign((const char *)(data + 20), header.monitor_name_length);
125 rtrim(header.monitor_name);
126 if (header.monitor_name.length() > 0)
128 info.m_displayNameExtra.append(" ");
129 info.m_displayNameExtra.append(header.monitor_name);
130 if (header.conn_type == ELD_CONN_TYPE_HDMI)
131 info.m_displayNameExtra.append(" on HDMI" );
133 info.m_displayNameExtra.append(" on DisplayPort");
139 if (!info.m_channels.HasChannel(AE_CH_FL))
140 info.m_channels += AE_CH_FL;
141 if (!info.m_channels.HasChannel(AE_CH_FR))
142 info.m_channels += AE_CH_FR;
146 if (!info.m_channels.HasChannel(AE_CH_LFE))
147 info.m_channels += AE_CH_LFE;
150 if (!info.m_channels.HasChannel(AE_CH_FC))
151 info.m_channels += AE_CH_FC;
155 if (!info.m_channels.HasChannel(AE_CH_BL))
156 info.m_channels += AE_CH_BL;
157 if (!info.m_channels.HasChannel(AE_CH_BR))
158 info.m_channels += AE_CH_BR;
162 if (!info.m_channels.HasChannel(AE_CH_BC))
163 info.m_channels += AE_CH_BC;
167 if (!info.m_channels.HasChannel(AE_CH_FLOC))
168 info.m_channels += AE_CH_FLOC;
169 if (!info.m_channels.HasChannel(AE_CH_FROC))
170 info.m_channels += AE_CH_FROC;
175 if (!info.m_channels.HasChannel(AE_CH_BLOC))
176 info.m_channels += AE_CH_BLOC;
177 if (!info.m_channels.HasChannel(AE_CH_BROC))
178 info.m_channels += AE_CH_BROC;
181 const uint8_t *sad = data + 20 + header.monitor_name_length;
182 for(uint8_t i = 0; i < header.sad_count; ++i)
184 uint8_t offset = i * 3;
185 uint8_t formatCode = (sad[offset + 0] >> 3) & 0xF;
186 //uint8_t channelCount = (sad[offset + 0] & 0x7) + 1;
187 //uint8_t sampleRates = sad[offset + 1];
189 AEDataFormat fmt = AE_FMT_INVALID;
192 case CEA_861_FORMAT_AAC : fmt = AE_FMT_AAC ; break;
193 case CEA_861_FORMAT_AC3 : fmt = AE_FMT_AC3 ; break;
194 case CEA_861_FORMAT_DTS : fmt = AE_FMT_DTS ; break;
195 case CEA_861_FORMAT_DTSHD: fmt = AE_FMT_DTSHD ; break;
196 case CEA_861_FORMAT_EAC3 : fmt = AE_FMT_EAC3 ; break;
197 case CEA_861_FORMAT_LPCM : fmt = AE_FMT_LPCM ; break;
198 case CEA_861_FORMAT_MLP : fmt = AE_FMT_TRUEHD; break;
201 if (fmt == AE_FMT_INVALID)
204 if (std::find(info.m_dataFormats.begin(), info.m_dataFormats.end(), fmt) == info.m_dataFormats.end())
205 info.m_dataFormats.push_back(fmt);