MythTV  master
eldutils.cpp
Go to the documentation of this file.
1 /*
2  * eldutils.cpp (c) Jean-Yves Avenard <jyavenard@mythtv.org>
3  * a utility class to decode EDID Like Data (ELD) byte stream
4  *
5  * Based on ALSA hda_eld.c
6  * Copyright(c) 2008 Intel Corporation.
7  *
8  * Authors:
9  * Wu Fengguang <wfg@linux.intel.com>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 #include "eldutils.h"
26 
27 #include <cinttypes>
28 #include <limits> // workaround QTBUG-90395
29 #include <sys/types.h>
30 
31 #include <QString>
32 #include <QtEndian>
33 
34 #include "audiooutputbase.h"
35 
36 #define LOC QString("ELDUTILS: ")
37 
39 {
42 };
43 
45 {
51 };
52 
53 static const std::array<const QString,11> cea_speaker_allocation_names {
54  /* 0 */ "FL/FR",
55  /* 1 */ "LFE",
56  /* 2 */ "FC",
57  /* 3 */ "RL/RR",
58  /* 4 */ "RC",
59  /* 5 */ "FLC/FRC",
60  /* 6 */ "RLC/RRC",
61  /* 7 */ "FLW/FRW",
62  /* 8 */ "FLH/FRH",
63  /* 9 */ "TC",
64  /* 10 */ "FCH",
65 };
66 
67 static const std::array<const QString,4> eld_connection_type_names {
68  "HDMI",
69  "DisplayPort",
70  "2-reserved",
71  "3-reserved"
72 };
73 
75 {
81 };
82 
83 static const std::array<const QString,18> audiotype_names {
84  /* 0 */ "undefined",
85  /* 1 */ "LPCM",
86  /* 2 */ "AC3",
87  /* 3 */ "MPEG1",
88  /* 4 */ "MP3",
89  /* 5 */ "MPEG2",
90  /* 6 */ "AAC-LC",
91  /* 7 */ "DTS",
92  /* 8 */ "ATRAC",
93  /* 9 */ "DSD (One Bit Audio)",
94  /* 10 */ "E-AC3",
95  /* 11 */ "DTS-HD",
96  /* 12 */ "TrueHD",
97  /* 13 */ "DST",
98  /* 14 */ "WMAPro",
99  /* 15 */ "HE-AAC",
100  /* 16 */ "HE-AACv2",
101  /* 17 */ "MPEG Surround",
102 };
103 
104 /*
105  * The following two lists are shared between
106  * - HDMI audio InfoFrame (source to sink)
107  * - CEA E-EDID Extension (sink to source)
108  */
109 
110 /*
111  * SF2:SF1:SF0 index => sampling frequency
112  */
113 #define SNDRV_PCM_RATE_5512 (1<<0) /* 5512Hz */
114 #define SNDRV_PCM_RATE_8000 (1<<1) /* 8000Hz */
115 #define SNDRV_PCM_RATE_11025 (1<<2) /* 11025Hz */
116 #define SNDRV_PCM_RATE_16000 (1<<3) /* 16000Hz */
117 #define SNDRV_PCM_RATE_22050 (1<<4) /* 22050Hz */
118 #define SNDRV_PCM_RATE_32000 (1<<5) /* 32000Hz */
119 #define SNDRV_PCM_RATE_44100 (1<<6) /* 44100Hz */
120 #define SNDRV_PCM_RATE_48000 (1<<7) /* 48000Hz */
121 #define SNDRV_PCM_RATE_64000 (1<<8) /* 64000Hz */
122 #define SNDRV_PCM_RATE_88200 (1<<9) /* 88200Hz */
123 #define SNDRV_PCM_RATE_96000 (1<<10) /* 96000Hz */
124 #define SNDRV_PCM_RATE_176400 (1<<11) /* 176400Hz */
125 #define SNDRV_PCM_RATE_192000 (1<<12) /* 192000Hz */
126 
127 static const std::array<const int,8> cea_sampling_frequencies {
128  0, /* 0: Refer to Stream Header */
129  SNDRV_PCM_RATE_32000, /* 1: 32000Hz */
130  SNDRV_PCM_RATE_44100, /* 2: 44100Hz */
131  SNDRV_PCM_RATE_48000, /* 3: 48000Hz */
132  SNDRV_PCM_RATE_88200, /* 4: 88200Hz */
133  SNDRV_PCM_RATE_96000, /* 5: 96000Hz */
134  SNDRV_PCM_RATE_176400, /* 6: 176400Hz */
135  SNDRV_PCM_RATE_192000, /* 7: 192000Hz */
136 };
137 
138 static inline int
139 GRAB_BITS(const char* buf, size_t byte, uint8_t lowbit, uint8_t bits)
140  { return (buf[byte] >> lowbit) & ((1 << bits) - 1); };
141 
142 eld::eld(const char *buf, int size)
143 {
144  m_e.formats = 0LL;
145  update_eld(buf, size);
146 }
147 
149 {
150  m_e.formats = 0LL;
151  m_e.eld_valid = false;
152 }
153 
154 eld& eld::operator=(const eld &rhs)
155 {
156  if (this == &rhs)
157  return *this;
158  m_e = rhs.m_e;
159  return *this;
160 }
161 
162 void eld::update_sad(int index,
163  const char *buf)
164 {
165  cea_sad *a = m_e.sad + index;
166 
167  int val = GRAB_BITS(buf, 1, 0, 7);
168  a->rates = 0;
169  for (int i = 0; i < 7; i++)
170  if ((val & (1 << i)) != 0)
171  a->rates |= cea_sampling_frequencies[i + 1];
172 
173  a->channels = GRAB_BITS(buf, 0, 0, 3);
174  a->channels++;
175 
176  a->sample_bits = 0;
177  a->max_bitrate = 0;
178 
179  a->format = GRAB_BITS(buf, 0, 3, 4);
180  m_e.formats |= 1 << a->format;
181  switch (a->format)
182  {
184  VBAUDIO("audio coding type 0 not expected");
185  break;
186 
187  case TYPE_LPCM:
188  a->sample_bits = GRAB_BITS(buf, 2, 0, 3);
189  break;
190 
191  case TYPE_AC3:
192  case TYPE_MPEG1:
193  case TYPE_MP3:
194  case TYPE_MPEG2:
195  case TYPE_AACLC:
196  case TYPE_DTS:
197  case TYPE_ATRAC:
198  a->max_bitrate = GRAB_BITS(buf, 2, 0, 8);
199  a->max_bitrate *= 8000;
200  break;
201 
202  case TYPE_SACD:
203  case TYPE_EAC3:
204  case TYPE_DTS_HD:
205  case TYPE_MLP:
206  case TYPE_DST:
207  break;
208 
209  case TYPE_WMAPRO:
210  a->profile = GRAB_BITS(buf, 2, 0, 3);
211  break;
212 
213  case TYPE_REF_CXT:
214  a->format = GRAB_BITS(buf, 2, 3, 5);
215  if (a->format == XTYPE_HE_REF_CT ||
217  {
218  VBAUDIO(QString("audio coding xtype %1 not expected")
219  .arg(a->format));
220  a->format = 0;
221  }
222  else
223  {
225  }
226  break;
227  }
228 }
229 
230 int eld::update_eld(const char *buf, int size)
231 {
232  int mnl = 0;
233 
234  m_e.eld_ver = GRAB_BITS(buf, 0, 3, 5);
235  if (m_e.eld_ver != ELD_VER_CEA_861D &&
237  {
238  VBAUDIO(QString("Unknown ELD version %1").arg(m_e.eld_ver));
239  goto out_fail;
240  }
241 
242  m_e.eld_size = size;
243  m_e.baseline_len = GRAB_BITS(buf, 2, 0, 8);
244  mnl = GRAB_BITS(buf, 4, 0, 5);
245  m_e.cea_edid_ver = GRAB_BITS(buf, 4, 5, 3);
246 
247  m_e.support_hdcp = GRAB_BITS(buf, 5, 0, 1);
248  m_e.support_ai = GRAB_BITS(buf, 5, 1, 1);
249  m_e.conn_type = GRAB_BITS(buf, 5, 2, 2);
250  m_e.sad_count = GRAB_BITS(buf, 5, 4, 4);
251 
252  m_e.aud_synch_delay = GRAB_BITS(buf, 6, 0, 8) * 2;
253  m_e.spk_alloc = GRAB_BITS(buf, 7, 0, 7);
254 
255  m_e.port_id = qFromLittleEndian<quint64>(buf + 8);
256 
257  /* not specified, but the spec's tendency is little endian */
258  m_e.manufacture_id = qFromLittleEndian<quint16>(buf + 16);
259  m_e.product_id = qFromLittleEndian<quint16>(buf + 18);
260 
261  if (ELD_FIXED_BYTES + mnl > size)
262  {
263  VBAUDIO(QString("out of range MNL %1").arg(mnl));
264  goto out_fail;
265  }
266  else
267  {
268  std::string tmp(buf + ELD_FIXED_BYTES, mnl);
269  m_e.monitor_name = QString::fromStdString(tmp);
270  }
271 
272  for (int i = 0; i < m_e.sad_count; i++)
273  {
274  if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size)
275  {
276  VBAUDIO(QString("out of range SAD %1").arg(i));
277  goto out_fail;
278  }
279  update_sad(i, buf + ELD_FIXED_BYTES + mnl + 3 * static_cast<ptrdiff_t>(i));
280  }
281 
282  /*
283  * Assume the highest speakers configuration
284  */
285  if (!m_e.spk_alloc)
286  m_e.spk_alloc = 0xffff;
287 
288  m_e.eld_valid = true;
289  return 0;
290 
291  out_fail:
292  m_e.eld_valid = false;
293  return -1;
294 }
295 
300 QString eld::print_pcm_rates(int pcm)
301 {
302  static const std::array<const uint32_t,12> rates {
303  5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200,
304  96000, 176400, 192000 };
305  QString result = QString();
306 
307  for (size_t i = 0; i < rates.size(); i++)
308  {
309  if ((pcm & (1 << i)) != 0)
310  {
311  result += QString(" %1").arg(rates[i]);
312  }
313  }
314  return result;
315 }
316 
321 QString eld::print_pcm_bits(int pcm)
322 {
323  static const std::array<const uint8_t,3> bits { 16, 20, 24 };
324  QString result = QString();
325 
326  for (size_t i = 0; i < bits.size(); i++)
327  {
328  if ((pcm & (1 << i)) != 0)
329  {
330  result += QString(" %1").arg(bits[i]);
331  }
332  }
333  return result;
334 }
335 
336 QString eld::sad_desc(int index)
337 {
338  cea_sad *a = m_e.sad + index;
339  if (!a->format)
340  return "";
341 
342  QString buf = print_pcm_rates(a->rates);
343  QString buf2 = ", bits =";
344 
345  if (a->format == TYPE_LPCM)
346  buf2 += print_pcm_bits(a->sample_bits);
347  else if (a->max_bitrate)
348  buf2 = QString(", max bitrate = %1").arg(a->max_bitrate);
349  else
350  buf2 = "";
351 
352  return QString("supports coding type %1:"
353  " channels = %2, rates =%3%4")
354  .arg(audiotype_names[a->format], QString::number(a->channels),
355  buf, buf2);
356 }
357 
359 {
360  QString result = QString();
361 
362  for (size_t i = 0; i < cea_speaker_allocation_names.size(); i++)
363  {
364  if ((m_e.spk_alloc & (1 << i)) != 0)
365  {
366  result += QString(" %1").arg(cea_speaker_allocation_names[i]);
367  }
368  }
369  return result;
370 }
371 
372 QString eld::eld_version_name() const
373 {
374  switch (m_e.eld_ver)
375  {
376  case 2: return "CEA-861D or below";
377  case 31: return "partial";
378  default: return "reserved";
379  }
380 }
381 
382 QString eld::edid_version_name() const
383 {
384  switch (m_e.cea_edid_ver)
385  {
386  case 0: return "no CEA EDID Timing Extension block present";
387  case 1: return "CEA-861";
388  case 2: return "CEA-861-A";
389  case 3: return "CEA-861-B, C or D";
390  default: return "reserved";
391  }
392 }
393 
394 QString eld::info_desc() const
395 {
396  QString result = QString("manufacture_id\t\t0x%1\n")
397  .arg(m_e.manufacture_id, 0, 16);
398  result += QString("product_id\t\t0x%1\n").arg(m_e.product_id, 0, 16);
399  result += QString("port_id\t\t\t0x%1\n").arg((long long)m_e.port_id);
400  result += QString("support_hdcp\t\t%1\n").arg(m_e.support_hdcp);
401  result += QString("support_ai\t\t%1\n").arg(m_e.support_ai);
402  result += QString("audio_sync_delay\t%1\n").arg(m_e.aud_synch_delay);
403  result += QString("sad_count\t\t%1\n").arg(m_e.sad_count);
404  return result;
405 }
406 
407 bool eld::isValid() const
408 {
409  return m_e.eld_valid;
410 }
411 
412 void eld::show()
413 {
414  if (!isValid())
415  {
416  VBAUDIO("Invalid ELD");
417  return;
418  }
419  VBAUDIO(QString("Detected monitor %1 at connection type %2")
420  .arg(product_name().simplified(), connection_name()));
421 
422  if (m_e.spk_alloc)
423  {
424  VBAUDIO(QString("available speakers:%1")
425  .arg(channel_allocation_desc()));
426  }
427  VBAUDIO(QString("max LPCM channels = %1").arg(maxLPCMChannels()));
428  VBAUDIO(QString("max channels = %1").arg(maxChannels()));
429  VBAUDIO(QString("supported codecs = %1").arg(codecs_desc()));
430  for (int i = 0; i < m_e.sad_count; i++)
431  {
432  VBAUDIO(sad_desc(i));
433  }
434 }
435 
436 QString eld::product_name() const
437 {
438  return m_e.monitor_name;
439 }
440 
441 QString eld::connection_name() const
442 {
444 }
445 
447 {
448  int channels = 2; // assume stereo at the minimum
449  for (int i = 0; i < m_e.sad_count; i++)
450  {
451  struct cea_sad *a = m_e.sad + i;
452  if (a->format == TYPE_LPCM)
453  {
454  if (a->channels > channels)
455  channels = a->channels;
456  }
457  }
458  return channels;
459 }
460 
462 {
463  int channels = 2; // assume stereo at the minimum
464  for (int i = 0; i < m_e.sad_count; i++)
465  {
466  struct cea_sad *a = m_e.sad + i;
467  if (a->channels > channels)
468  channels = a->channels;
469  }
470  return channels;
471 }
472 
473 QString eld::codecs_desc() const
474 {
475  QString result = QString();
476  bool found_one = false;
477  for (size_t i = 0; i < audiotype_names.size(); i++)
478  {
479  if ((m_e.formats & (1 << i)) != 0)
480  {
481  if (found_one)
482  result += ", ";
483  result += audiotype_names[i];
484  found_one = true;
485  }
486  }
487  return result;
488 }
eld::TYPE_HE_AAC
@ TYPE_HE_AAC
Definition: eldutils.h:75
eld::eld_data::spk_alloc
int spk_alloc
Definition: eldutils.h:119
eld_versions
eld_versions
Definition: eldutils.cpp:38
eld::TYPE_WMAPRO
@ TYPE_WMAPRO
Definition: eldutils.h:72
VBAUDIO
#define VBAUDIO(str)
Definition: audiooutputbase.h:20
eld::TYPE_MLP
@ TYPE_MLP
Definition: eldutils.h:70
XTYPE_MPEG_SURROUND
@ XTYPE_MPEG_SURROUND
Definition: eldutils.cpp:79
SNDRV_PCM_RATE_176400
#define SNDRV_PCM_RATE_176400
Definition: eldutils.cpp:124
ELD_FIXED_BYTES
static constexpr uint8_t ELD_FIXED_BYTES
Definition: eldutils.h:30
eld::show
void show()
Definition: eldutils.cpp:412
eld::eld_data::conn_type
int conn_type
Definition: eldutils.h:117
eld::connection_name
QString connection_name() const
Definition: eldutils.cpp:441
eld::cea_sad::profile
int profile
Definition: eldutils.h:98
eld
Definition: eldutils.h:37
CEA_EDID_VER_CEA861BCD
@ CEA_EDID_VER_CEA861BCD
Definition: eldutils.cpp:49
eld::eld_data::sad_count
int sad_count
Definition: eldutils.h:120
CEA_EDID_VER_CEA861
@ CEA_EDID_VER_CEA861
Definition: eldutils.cpp:47
eld::TYPE_EAC3
@ TYPE_EAC3
Definition: eldutils.h:68
SNDRV_PCM_RATE_88200
#define SNDRV_PCM_RATE_88200
Definition: eldutils.cpp:122
eld::cea_sad::format
int format
Definition: eldutils.h:94
eld::m_e
eld_data m_e
Definition: eldutils.h:125
eld::maxLPCMChannels
int maxLPCMChannels()
Definition: eldutils.cpp:446
eld::TYPE_SACD
@ TYPE_SACD
Definition: eldutils.h:67
eld::TYPE_ATRAC
@ TYPE_ATRAC
Definition: eldutils.h:66
eld::print_pcm_rates
static QString print_pcm_rates(int pcm)
SNDRV_PCM_RATE_* and AC_PAR_PCM values don't match, print correct rates with hdmi-specific routine.
Definition: eldutils.cpp:300
eld::TYPE_MPEG2
@ TYPE_MPEG2
Definition: eldutils.h:63
XTYPE_FIRST_RESERVED
@ XTYPE_FIRST_RESERVED
Definition: eldutils.cpp:80
GRAB_BITS
static int GRAB_BITS(const char *buf, size_t byte, uint8_t lowbit, uint8_t bits)
Definition: eldutils.cpp:139
eld::eld_data::support_ai
int support_ai
Definition: eldutils.h:116
eld::TYPE_REF_STREAM_HEADER
@ TYPE_REF_STREAM_HEADER
Definition: eldutils.h:58
cea_audio_coding_xtypes
cea_audio_coding_xtypes
Definition: eldutils.cpp:74
eldutils.h
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
ELD_VER_PARTIAL
@ ELD_VER_PARTIAL
Definition: eldutils.cpp:41
eld::TYPE_MPEG1
@ TYPE_MPEG1
Definition: eldutils.h:61
eld::cea_sad::rates
int rates
Definition: eldutils.h:95
eld::update_eld
int update_eld(const char *buf, int size)
Definition: eldutils.cpp:230
eld::update_sad
void update_sad(int index, const char *buf)
Definition: eldutils.cpp:162
cea_sampling_frequencies
static const std::array< const int, 8 > cea_sampling_frequencies
Definition: eldutils.cpp:127
eld::eld
eld()
Definition: eldutils.cpp:148
eld::eld_data::eld_ver
int eld_ver
Definition: eldutils.h:108
eld::cea_sad::sample_bits
int sample_bits
Definition: eldutils.h:96
eld::operator=
eld & operator=(const eld &)
Definition: eldutils.cpp:154
SNDRV_PCM_RATE_48000
#define SNDRV_PCM_RATE_48000
Definition: eldutils.cpp:120
CEA_EDID_VER_RESERVED
@ CEA_EDID_VER_RESERVED
Definition: eldutils.cpp:50
eld::eld_data::manufacture_id
int manufacture_id
Definition: eldutils.h:111
eld::TYPE_DTS
@ TYPE_DTS
Definition: eldutils.h:65
eld::eld_data::formats
uint64_t formats
Definition: eldutils.h:114
cea_edid_versions
cea_edid_versions
Definition: eldutils.cpp:44
eld::maxChannels
int maxChannels()
Definition: eldutils.cpp:461
eld::product_name
QString product_name() const
Definition: eldutils.cpp:436
SNDRV_PCM_RATE_32000
#define SNDRV_PCM_RATE_32000
Definition: eldutils.cpp:118
eld::eld_data::port_id
uint64_t port_id
Definition: eldutils.h:113
eld::eld_data::baseline_len
int baseline_len
Definition: eldutils.h:107
eld::print_pcm_bits
static QString print_pcm_bits(int pcm)
Print the supported PCM fmt bits to the string buffer.
Definition: eldutils.cpp:321
eld::channel_allocation_desc
QString channel_allocation_desc() const
Definition: eldutils.cpp:358
eld::edid_version_name
QString edid_version_name() const
Definition: eldutils.cpp:382
eld::eld_data::eld_valid
bool eld_valid
Definition: eldutils.h:105
eld::TYPE_DTS_HD
@ TYPE_DTS_HD
Definition: eldutils.h:69
XTYPE_HE_REF_CT
@ XTYPE_HE_REF_CT
Definition: eldutils.cpp:76
eld_connection_type_names
static const std::array< const QString, 4 > eld_connection_type_names
Definition: eldutils.cpp:67
SNDRV_PCM_RATE_44100
#define SNDRV_PCM_RATE_44100
Definition: eldutils.cpp:119
eld::TYPE_AC3
@ TYPE_AC3
Definition: eldutils.h:60
audiooutputbase.h
ELD_VER_CEA_861D
@ ELD_VER_CEA_861D
Definition: eldutils.cpp:40
XTYPE_HE_AAC2
@ XTYPE_HE_AAC2
Definition: eldutils.cpp:78
SNDRV_PCM_RATE_192000
#define SNDRV_PCM_RATE_192000
Definition: eldutils.cpp:125
CEA_EDID_VER_NONE
@ CEA_EDID_VER_NONE
Definition: eldutils.cpp:46
eld::TYPE_MP3
@ TYPE_MP3
Definition: eldutils.h:62
eld::eld_data::eld_size
int eld_size
Definition: eldutils.h:106
eld::TYPE_AACLC
@ TYPE_AACLC
Definition: eldutils.h:64
CEA_EDID_VER_CEA861A
@ CEA_EDID_VER_CEA861A
Definition: eldutils.cpp:48
cea_speaker_allocation_names
static const std::array< const QString, 11 > cea_speaker_allocation_names
Definition: eldutils.cpp:53
eld::eld_version_name
QString eld_version_name() const
Definition: eldutils.cpp:372
XTYPE_HE_AAC
@ XTYPE_HE_AAC
Definition: eldutils.cpp:77
eld::eld_data::monitor_name
QString monitor_name
Definition: eldutils.h:110
eld::eld_data::support_hdcp
int support_hdcp
Definition: eldutils.h:115
eld::cea_sad
Definition: eldutils.h:92
eld::TYPE_DST
@ TYPE_DST
Definition: eldutils.h:71
audiotype_names
static const std::array< const QString, 18 > audiotype_names
Definition: eldutils.cpp:83
eld::TYPE_LPCM
@ TYPE_LPCM
Definition: eldutils.h:59
eld::eld_data::product_id
int product_id
Definition: eldutils.h:112
eld::cea_sad::max_bitrate
int max_bitrate
Definition: eldutils.h:97
eld::eld_data::cea_edid_ver
int cea_edid_ver
Definition: eldutils.h:109
eld::codecs_desc
QString codecs_desc() const
Definition: eldutils.cpp:473
eld::eld_data::aud_synch_delay
int aud_synch_delay
Definition: eldutils.h:118
eld::isValid
bool isValid() const
Definition: eldutils.cpp:407
eld::sad_desc
QString sad_desc(int index)
Definition: eldutils.cpp:336
SNDRV_PCM_RATE_96000
#define SNDRV_PCM_RATE_96000
Definition: eldutils.cpp:123
eld::TYPE_REF_CXT
@ TYPE_REF_CXT
Definition: eldutils.h:73
eld::info_desc
QString info_desc() const
Definition: eldutils.cpp:394
eld::eld_data::sad
struct cea_sad sad[ELD_MAX_SAD]
Definition: eldutils.h:122
eld::cea_sad::channels
int channels
Definition: eldutils.h:93