MythTV  master
audiooutputsettings.cpp
Go to the documentation of this file.
1 /* -*- Mode: c++ -*-
2  *
3  * Copyright (C) 2010 foobum@gmail.com and jyavenard@gmail.com
4  *
5  * Licensed under the GPL v2 or a later version at your choosing.
6  */
7 
8 #include <algorithm>
9 #include <vector>
10 
11 using namespace std;
12 
13 #include "audiooutputsettings.h"
14 #include "mythlogging.h"
15 #include "mythcorecontext.h"
16 
17 extern "C" {
18 #include "libavutil/avutil.h" // to check version of libavformat
19 }
20 #include "eldutils.h"
21 
22 #define LOC QString("AOS: ")
23 
25  m_invalid(invalid), m_eld(ELD())
26 {
27  m_sr.assign(srs, srs +
28  sizeof(srs) / sizeof(int));
29  m_sf.assign(fmts, fmts +
30  sizeof(fmts) / sizeof(AudioFormat));
31  m_sr_it = m_sr.begin();
32  m_sf_it = m_sf.begin();
33 }
34 
36 {
37  m_sr.clear();
38  m_rates.clear();
39  m_sf.clear();
40  m_formats.clear();
41  m_channels.clear();
42 }
43 
45  const AudioOutputSettings &rhs)
46 {
47  if (this == &rhs)
48  return *this;
49  m_sr = rhs.m_sr;
50  m_rates = rhs.m_rates;
51  m_sf = rhs.m_sf;
52  m_formats = rhs.m_formats;
53  m_channels = rhs.m_channels;
55  m_features = rhs.m_features;
56  m_invalid = rhs.m_invalid;
57  m_has_eld = rhs.m_has_eld;
58  m_eld = rhs.m_eld;
59  m_sr_it = m_sr.begin() + (rhs.m_sr_it - rhs.m_sr.begin());
60  m_sf_it = m_sf.begin() + (rhs.m_sf_it - rhs.m_sf.begin());
61  return *this;
62 }
63 
65 {
66  if (m_sr_it == m_sr.end())
67  {
68  m_sr_it = m_sr.begin();
69  return 0;
70  }
71 
72  return *m_sr_it++;
73 }
74 
76 {
77  m_rates.push_back(rate);
78  LOG(VB_AUDIO, LOG_INFO, LOC +
79  QString("Sample rate %1 is supported").arg(rate));
80 }
81 
83 {
84  if (m_rates.empty() && rate == 48000)
85  return true;
86 
87  vector<int>::iterator it;
88 
89  for (it = m_rates.begin(); it != m_rates.end(); ++it)
90  if (*it == rate)
91  return true;
92 
93  return false;
94 }
95 
97 {
98  if (m_rates.empty())
99  return 48000;
100  return m_rates.back();
101 }
102 
104 {
105  if (m_rates.empty())
106  return 48000;
107 
108  vector<int>::iterator it;
109 
110  // Assume rates vector is sorted
111  for (it = m_rates.begin(); it != m_rates.end(); ++it)
112  {
113  if (*it >= rate)
114  return *it;
115  }
116  // Not found, so return highest available rate
117  return m_rates.back();
118 }
119 
121 {
122  if (m_sf_it == m_sf.end())
123  {
124  m_sf_it = m_sf.begin();
125  return FORMAT_NONE;
126  }
127 
128  return *m_sf_it++;
129 }
130 
132 {
133  LOG(VB_AUDIO, LOG_INFO, LOC +
134  QString("Format %1 is supported").arg(FormatToString(format)));
135  m_formats.push_back(format);
136 }
137 
139 {
140  if (m_formats.empty() && format == FORMAT_S16)
141  return true;
142 
143  vector<AudioFormat>::iterator it;
144 
145  for (it = m_formats.begin(); it != m_formats.end(); ++it)
146  if (*it == format)
147  return true;
148 
149  return false;
150 }
151 
153 {
154  if (m_formats.empty())
155  return FORMAT_S16;
156  return m_formats.back();
157 }
158 
160 {
161  switch (format)
162  {
163  case FORMAT_U8: return 8;
164  case FORMAT_S16: return 16;
165  case FORMAT_S24LSB:
166  case FORMAT_S24: return 24;
167  case FORMAT_S32:
168  case FORMAT_FLT: return 32;
169  case FORMAT_NONE:
170  default: return -1;
171  }
172 }
173 
175 {
176  switch (format)
177  {
178  case FORMAT_U8: return "unsigned 8 bit";
179  case FORMAT_S16: return "signed 16 bit";
180  case FORMAT_S24: return "signed 24 bit MSB";
181  case FORMAT_S24LSB: return "signed 24 bit LSB";
182  case FORMAT_S32: return "signed 32 bit";
183  case FORMAT_FLT: return "32 bit floating point";
184  case FORMAT_NONE: return "none";
185  default: return "unknown";
186  }
187 }
188 
190 {
191  switch (format)
192  {
193  case FORMAT_U8: return 1;
194  case FORMAT_S16: return 2;
195  case FORMAT_S24:
196  case FORMAT_S24LSB:
197  case FORMAT_S32:
198  case FORMAT_FLT: return 4;
199  case FORMAT_NONE:
200  default: return 0;
201  }
202 }
203 
208 {
209  switch (av_get_packed_sample_fmt(format))
210  {
211  case AV_SAMPLE_FMT_U8: return FORMAT_U8;
212  case AV_SAMPLE_FMT_S16: return FORMAT_S16;
213  case AV_SAMPLE_FMT_FLT: return FORMAT_FLT;
214  case AV_SAMPLE_FMT_DBL: return FORMAT_NONE;
215  case AV_SAMPLE_FMT_S32:
216  switch (bits)
217  {
218  case 0: return FORMAT_S32;
219  case 24: return FORMAT_S24;
220  case 32: return FORMAT_S32;
221  default: return FORMAT_NONE;
222  }
223  default: return FORMAT_NONE;
224  }
225 }
226 
233 {
234  switch (format)
235  {
236  case FORMAT_U8: return AV_SAMPLE_FMT_U8;
237  case FORMAT_S16: return AV_SAMPLE_FMT_S16;
238  case FORMAT_FLT: return AV_SAMPLE_FMT_FLT;
239  case FORMAT_S32:
240  case FORMAT_S24:
241  case FORMAT_S24LSB: return AV_SAMPLE_FMT_S32;
242  default: return AV_SAMPLE_FMT_NONE;
243  }
244 }
245 
247 {
248  m_channels.push_back(channels);
249  LOG(VB_AUDIO, LOG_INFO, LOC + QString("%1 channel(s) are supported")
250  .arg(channels));
251 }
252 
254 {
255  if (m_channels.empty() && channels == 2)
256  return true;
257 
258  vector<int>::iterator it;
259 
260  for (it = m_channels.begin(); it != m_channels.end(); ++it)
261  if (*it == channels)
262  return true;
263 
264  return false;
265 }
266 
268 {
269  if (m_channels.empty())
270  return 2;
271  return m_channels.back();
272 }
273 
275 {
276  if (m_channels.empty())
277  return;
278  sort(m_channels.begin(), m_channels.end());
279 }
280 
282 {
283  if (m_channels.empty())
284  {
285  m_channels.push_back(channels);
286  return;
287  }
288 
289  vector<int>::reverse_iterator it;
290 
291  for (it = m_channels.rbegin();
292  it != m_channels.rend() && *it >= channels;
293  ++it)
294  {
295  m_channels.pop_back();
296  }
297  m_channels.push_back(channels);
298 }
299 
300 void AudioOutputSettings::setFeature(bool val, int arg)
301 {
302  if (val)
303  m_features |= arg;
304  else
305  m_features &= ~arg;
306 };
307 
309 {
310  setFeature(val, (int) arg);
311 };
312 
320 {
321  AudioOutputSettings* aosettings = this;
322 
323  if (newcopy)
324  {
325  aosettings = new AudioOutputSettings;
326  *aosettings = *this;
327  }
328 
329  if (m_invalid)
330  return aosettings;
331 
332  if (BestSupportedPCMChannelsELD() > 2)
333  {
334  aosettings->setFeature(FEATURE_LPCM);
335  }
336 
338  {
339  // E-AC3 is transferred as stereo PCM at 4 times the rates
340  // assume all amplifier supporting E-AC3 also supports 7.1 LPCM
341  // as it's mandatory under the bluray standard
342 //#if LIBAVFORMAT_VERSION_INT > AV_VERSION_INT( 52, 83, 0 )
343  if (m_passthrough >= 0 && IsSupportedChannels(8) &&
344  IsSupportedRate(192000))
345  aosettings->setFeature(FEATURE_TRUEHD | FEATURE_DTSHD |
346  FEATURE_EAC3);
347 //#endif
348  if (m_passthrough >= 0)
349  {
350  if (BestSupportedChannels() == 2)
351  {
352  LOG(VB_AUDIO, LOG_INFO, LOC + "may be AC3 or DTS capable");
353  aosettings->AddSupportedChannels(6);
354  }
355  aosettings->setFeature(FEATURE_AC3 | FEATURE_DTS);
356  }
357  }
358  else
359  {
360  // Can't do digital passthrough without 16 bits audio
361  aosettings->setPassthrough(-1);
362  aosettings->setFeature(false,
365  }
366 
367  return aosettings;
368 }
369 
377 {
378  AudioOutputSettings* aosettings = this;
379 
380  if (newcopy)
381  aosettings = GetCleaned(newcopy);
382 
383  if (aosettings->m_invalid)
384  return aosettings;
385 
386  int cur_channels = gCoreContext->GetNumSetting("MaxChannels", 2);
387  int max_channels = aosettings->BestSupportedChannels();
388 
389  bool bAC3 = aosettings->canFeature(FEATURE_AC3) &&
390  gCoreContext->GetBoolSetting("AC3PassThru", false);
391 
392  bool bDTS = aosettings->canFeature(FEATURE_DTS) &&
393  gCoreContext->GetBoolSetting("DTSPassThru", false);
394 
395  bool bLPCM = aosettings->canFeature(FEATURE_LPCM) &&
396  !gCoreContext->GetBoolSetting("StereoPCM", false);
397 
398  bool bEAC3 = aosettings->canFeature(FEATURE_EAC3) &&
399  gCoreContext->GetBoolSetting("EAC3PassThru", false) &&
400  !gCoreContext->GetBoolSetting("Audio48kOverride", false);
401 
402  // TrueHD requires HBR support.
403  bool bTRUEHD = aosettings->canFeature(FEATURE_TRUEHD) &&
404  gCoreContext->GetBoolSetting("TrueHDPassThru", false) &&
405  !gCoreContext->GetBoolSetting("Audio48kOverride", false) &&
406  gCoreContext->GetBoolSetting("HBRPassthru", true);
407 
408  bool bDTSHD = aosettings->canFeature(FEATURE_DTSHD) &&
409  gCoreContext->GetBoolSetting("DTSHDPassThru", false) &&
410  !gCoreContext->GetBoolSetting("Audio48kOverride", false);
411 
412  if (max_channels > 2 && !bLPCM)
413  max_channels = 2;
414  if (max_channels == 2 && (bAC3 || bDTS))
415  max_channels = 6;
416 
417  if (cur_channels > max_channels)
418  cur_channels = max_channels;
419 
420  aosettings->SetBestSupportedChannels(cur_channels);
421  aosettings->setFeature(bAC3, FEATURE_AC3);
422  aosettings->setFeature(bDTS, FEATURE_DTS);
423  aosettings->setFeature(bLPCM, FEATURE_LPCM);
424  aosettings->setFeature(bEAC3, FEATURE_EAC3);
425  aosettings->setFeature(bTRUEHD, FEATURE_TRUEHD);
426  aosettings->setFeature(bDTSHD, FEATURE_DTSHD);
427 
428  return aosettings;
429 }
430 
432 {
434  return 0;
435 
436  // If no HBR or no LPCM, limit bitrate to 6.144Mbit/s
437  if (!gCoreContext->GetBoolSetting("HBRPassthru", true) ||
439  {
440  return 192000; // E-AC3/DTS-HD High Res: 192k, 16 bits, 2 ch
441  }
442  return 768000; // TrueHD or DTS-HD MA: 192k, 16 bits, 8 ch
443 }
444 
445 #define ARG(x) ((tmp.isEmpty() ? "" : ",") + QString(x))
446 
448 {
449  QString tmp;
450  DigitalFeature feature[] = {
451  FEATURE_AC3,
452  FEATURE_DTS,
453  FEATURE_LPCM,
454  FEATURE_EAC3,
457  FEATURE_AAC,
458  (DigitalFeature)-1
459  };
460  const char *feature_str[] = {
461  "AC3",
462  "DTS",
463  "LPCM",
464  "EAC3",
465  "TRUEHD",
466  "DTSHD",
467  "AAC",
468  nullptr
469  };
470 
471  for (unsigned int i = 0; feature[i] != (DigitalFeature)-1; i++)
472  {
473  if (arg & feature[i])
474  tmp += ARG(feature_str[i]);
475  }
476  return tmp;
477 }
478 
479 QString AudioOutputSettings::GetPassthroughParams(int codec, int codec_profile,
480  int &samplerate,
481  int &channels,
482  bool canDTSHDMA)
483 {
484  QString log;
485 
486  channels = 2;
487 
488  switch (codec)
489  {
490  case AV_CODEC_ID_AC3:
491  log = "AC3";
492  break;
493  case AV_CODEC_ID_EAC3:
494  samplerate = samplerate * 4;
495  log = "Dolby Digital Plus (E-AC3)";
496  break;
497  case AV_CODEC_ID_DTS:
498  switch(codec_profile)
499  {
500  case FF_PROFILE_DTS_ES:
501  log = "DTS-ES";
502  break;
503  case FF_PROFILE_DTS_96_24:
504  log = "DTS 96/24";
505  break;
506  case FF_PROFILE_DTS_HD_HRA:
507  samplerate = 192000;
508  log = "DTS-HD High-Res";
509  break;
510  case FF_PROFILE_DTS_HD_MA:
511  samplerate = 192000;
512  if (canDTSHDMA)
513  {
514  log = "DTS-HD MA";
515  channels = 8;
516  }
517  else
518  {
519  log = "DTS-HD High-Res";
520  }
521  break;
522  case FF_PROFILE_DTS:
523  default:
524  log = "DTS Core";
525  break;
526  }
527  break;
528  case AV_CODEC_ID_TRUEHD:
529  channels = 8;
530  log = "TrueHD";
531  switch(samplerate)
532  {
533  case 48000:
534  case 96000:
535  case 192000:
536  samplerate = 192000;
537  break;
538  case 44100:
539  case 88200:
540  case 176400:
541  samplerate = 176400;
542  break;
543  default:
544  log = "TrueHD: Unsupported samplerate";
545  break;
546  }
547  break;
548  default:
549  break;
550  }
551  return log;
552 }
553 
555 {
556  return m_has_eld && m_eld.isValid();
557 };
558 
560 {
561  return m_has_eld;
562 };
563 
564 void AudioOutputSettings::setELD(QByteArray *ba)
565 {
566  m_has_eld = true;
567  m_eld = ELD(ba->constData(), ba->size());
568  m_eld.show();
569 }
570 
572 {
574  if (!hasValidELD())
575  return chan;
576  int eldc = m_eld.maxChannels();
577  return eldc < chan ? eldc : chan;
578 }
579 
581 {
583  if (!hasValidELD())
584  return chan;
585  int eldc = m_eld.maxLPCMChannels();
586  return eldc < chan ? eldc : chan;
587 }
int NearestSupportedRate(int rate)
static const AudioFormat fmts[]
bool IsSupportedChannels(int channels)
void setELD(QByteArray *ba)
set ELD data
Definition: eldutils.h:39
bool IsSupportedFormat(AudioFormat format)
int BestSupportedPCMChannelsELD()
Reports best supported PCM channel number, restricted to ELD.
void setPassthrough(int val)
void SetBestSupportedChannels(int channels)
Force set the greatest number of channels supported by the audio device.
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
int BestSupportedChannelsELD()
Reports best supported channel number, restricted to ELD range.
static const char * FormatToString(AudioFormat format)
static int FormatToBits(AudioFormat format)
static guint32 * tmp
Definition: goom_core.c:35
static QString GetPassthroughParams(int codec, int codec_profile, int &samplerate, int &channels, bool canDTSHDMA)
Setup samplerate and number of channels for passthrough.
std::vector< AudioFormat > m_formats
static const int srs[]
std::vector< int >::iterator m_sr_it
AudioFormat BestSupportedFormat()
std::vector< AudioFormat > m_sf
AudioOutputSettings(bool invalid=false)
void setFeature(DigitalFeature arg)
set the provided digital feature possible values are:
#define LOC
static int SampleSize(AudioFormat format)
QString FeaturesToString(void)
int maxChannels()
Definition: eldutils.cpp:482
int maxLPCMChannels()
Definition: eldutils.cpp:467
def log(debug, txt)
Definition: utilities.py:5
bool canFeature(DigitalFeature arg)
return DigitalFeature mask.
bool m_has_eld
will be set to true if we were able to retrieve the device ELD (EDID like Data).
std::vector< int > m_channels
void show()
Definition: eldutils.cpp:432
AudioOutputSettings & operator=(const AudioOutputSettings &)
int GetNumSetting(const QString &key, int defaultval=0)
std::vector< int > m_sr
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
AudioOutputSettings * GetCleaned(bool newcopy=false)
Returns capabilities supported by the audio device amended to take into account the digital audio opt...
std::vector< AudioFormat >::iterator m_sf_it
bool GetBoolSetting(const QString &key, bool defaultval=false)
void AddSupportedRate(int rate)
#define ARG(x)
bool IsSupportedRate(int rate)
int GetMaxHDRate()
return the highest iec958 rate supported.
bool isValid()
Definition: eldutils.cpp:427
std::vector< int > m_rates
AudioOutputSettings * GetUsers(bool newcopy=false)
Returns capabilities supported by the audio device amended to take into account the digital audio opt...
DigitalFeature
void AddSupportedFormat(AudioFormat format)
bool hasELD()
get the ELD flag
static AudioFormat AVSampleFormatToFormat(AVSampleFormat format, int bits=0)
Return AVSampleFormat closest equivalent to AudioFormat.
int m_passthrough
passthrough status -1 : no 0: unknown 1: yes
void AddSupportedChannels(int channels)
static AVSampleFormat FormatToAVSampleFormat(AudioFormat format)
Return AudioFormat closest equivalent to AVSampleFormat Note that FORMAT_S24LSB and FORMAT_S24 have n...