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 <array>
9#include <algorithm>
10#include <vector>
11
14
15#include "audiooutputsettings.h"
16#include "eldutils.h"
17
18extern "C" {
19#include "libavcodec/defs.h"
20#include "libavutil/avutil.h" // to check version of libavformat
21}
22
23#define LOC QString("AOS: ")
24
26{
27 5512, 8000, 11025, 16000, 22050, 32000, 44100,
28 48000, 88200, 96000, 176400, 192000
29};
30
32{
34};
35
37 m_invalid(invalid),
38 m_srIt(kStdRates.begin()),
39 m_sfIt(kStdFormats.begin())
40{
41}
42
44{
45 m_rates.clear();
46 m_formats.clear();
47 m_channels.clear();
48}
49
51 const AudioOutputSettings &rhs)
52{
53 if (this == &rhs)
54 return *this;
55 m_rates = rhs.m_rates;
56 m_formats = rhs.m_formats;
60 m_invalid = rhs.m_invalid;
61 m_hasEld = rhs.m_hasEld;
62 m_eld = rhs.m_eld;
63 m_srIt = kStdRates.begin() + (rhs.m_srIt - kStdRates.begin());
64 m_sfIt = kStdFormats.begin() + (rhs.m_sfIt - kStdFormats.begin());
65 return *this;
66}
67
69{
70 if (m_srIt == kStdRates.end())
71 {
72 m_srIt = kStdRates.begin();
73 return 0;
74 }
75
76 return *m_srIt++;
77}
78
80{
81 m_rates.push_back(rate);
82 LOG(VB_AUDIO, LOG_INFO, LOC +
83 QString("Sample rate %1 is supported").arg(rate));
84}
85
87{
88 if (m_rates.empty() && rate == 48000)
89 return true;
90
91 auto result = std::find(m_rates.cbegin(), m_rates.cend(), rate);
92 return result != m_rates.end();
93}
94
96{
97 if (m_rates.empty())
98 return 48000;
99 return m_rates.back();
100}
101
103{
104 if (m_rates.empty())
105 return 48000;
106
107 // Assume rates vector is sorted
108 auto it = std::find_if(m_rates.cbegin(), m_rates.cend(),
109 [rate](const auto entry){ return entry >= rate; } );
110 if (it != m_rates.cend())
111 return *it;
112
113 // Not found, so return highest available rate
114 return m_rates.back();
115}
116
118{
119 if (m_sfIt == kStdFormats.end())
120 {
121 m_sfIt = kStdFormats.begin();
122 return FORMAT_NONE;
123 }
124
125 return *m_sfIt++;
126}
127
129{
130 LOG(VB_AUDIO, LOG_INFO, LOC +
131 QString("Format %1 is supported").arg(FormatToString(format)));
132 m_formats.push_back(format);
133}
134
136{
137 if (m_formats.empty() && format == FORMAT_S16)
138 return true;
139
140 auto result = std::find(m_formats.cbegin(), m_formats.cend(), format);
141 return result != m_formats.end();
142}
143
145{
146 if (m_formats.empty())
147 return FORMAT_S16;
148 return m_formats.back();
149}
150
152{
153 switch (format)
154 {
155 case FORMAT_U8: return 8;
156 case FORMAT_S16: return 16;
157 case FORMAT_S24LSB:
158 case FORMAT_S24: return 24;
159 case FORMAT_S32:
160 case FORMAT_FLT: return 32;
161 case FORMAT_NONE:
162 default: return -1;
163 }
164}
165
167{
168 switch (format)
169 {
170 case FORMAT_U8: return "unsigned 8 bit";
171 case FORMAT_S16: return "signed 16 bit";
172 case FORMAT_S24: return "signed 24 bit MSB";
173 case FORMAT_S24LSB: return "signed 24 bit LSB";
174 case FORMAT_S32: return "signed 32 bit";
175 case FORMAT_FLT: return "32 bit floating point";
176 case FORMAT_NONE: return "none";
177 default: return "unknown";
178 }
179}
180
182{
183 switch (format)
184 {
185 case FORMAT_U8: return 1;
186 case FORMAT_S16: return 2;
187 case FORMAT_S24:
188 case FORMAT_S24LSB:
189 case FORMAT_S32:
190 case FORMAT_FLT: return 4;
191 case FORMAT_NONE:
192 default: return 0;
193 }
194}
195
200{
201 switch (av_get_packed_sample_fmt(format))
202 {
203 case AV_SAMPLE_FMT_U8: return FORMAT_U8;
204 case AV_SAMPLE_FMT_S16: return FORMAT_S16;
205 case AV_SAMPLE_FMT_FLT: return FORMAT_FLT;
206 case AV_SAMPLE_FMT_DBL: return FORMAT_NONE;
207 case AV_SAMPLE_FMT_S32:
208 switch (bits)
209 {
210 case 0: return FORMAT_S32;
211 case 24: return FORMAT_S24;
212 case 32: return FORMAT_S32;
213 default: return FORMAT_NONE;
214 }
215 default: return FORMAT_NONE;
216 }
217}
218
225{
226 switch (format)
227 {
228 case FORMAT_U8: return AV_SAMPLE_FMT_U8;
229 case FORMAT_S16: return AV_SAMPLE_FMT_S16;
230 case FORMAT_FLT: return AV_SAMPLE_FMT_FLT;
231 case FORMAT_S32:
232 case FORMAT_S24:
233 case FORMAT_S24LSB: return AV_SAMPLE_FMT_S32;
234 default: return AV_SAMPLE_FMT_NONE;
235 }
236}
237
239{
240 m_channels.push_back(channels);
241 LOG(VB_AUDIO, LOG_INFO, LOC + QString("%1 channel(s) are supported")
242 .arg(channels));
243}
244
246{
247 if (m_channels.empty() && channels == 2)
248 return true;
249
250 return std::any_of(m_channels.cbegin(), m_channels.cend(),
251 [channels](const auto entry)
252 { return entry == channels; } );
253}
254
256{
257 if (m_channels.empty())
258 return 2;
259 SortSupportedChannels(); // ensure last element is the best supported channel
260 return m_channels.back();
261}
262
264{
265 if (m_channels.empty())
266 return;
267 sort(m_channels.begin(), m_channels.end());
268}
269
271{
272 if (m_channels.empty())
273 {
274 m_channels.push_back(channels);
275 return;
276 }
277
278 std::vector<int>tmp;
279 std::copy_if(m_channels.cbegin(), m_channels.cend(),
280 std::back_inserter(tmp),
281 [channels](int value){ return channels > value; } );
282 m_channels = tmp;
283 m_channels.push_back(channels);
284}
285
286void AudioOutputSettings::setFeature(bool val, int arg)
287{
288 if (val)
289 m_features |= arg;
290 else
291 m_features &= ~arg;
292};
293
295{
296 setFeature(val, (int) arg);
297};
298
306{
307 AudioOutputSettings* aosettings = this;
308
309 if (newcopy)
310 {
311 aosettings = new AudioOutputSettings;
312 *aosettings = *this;
313 }
314
315 if (m_invalid)
316 return aosettings;
317
319 {
320 aosettings->setFeature(FEATURE_LPCM);
321 }
322
324 {
325 // E-AC3 is transferred as stereo PCM at 4 times the rates
326 // assume all amplifier supporting E-AC3 also supports 7.1 LPCM
327 // as it's mandatory under the bluray standard
328//#if LIBAVFORMAT_VERSION_INT > AV_VERSION_INT( 52, 83, 0 )
329 if (m_passthrough >= 0 && IsSupportedChannels(8) &&
330 IsSupportedRate(192000))
333//#endif
334 if (m_passthrough >= 0)
335 {
336 if (BestSupportedChannels() == 2)
337 {
338 LOG(VB_AUDIO, LOG_INFO, LOC + "may be AC3 or DTS capable");
339 aosettings->AddSupportedChannels(6);
340 }
341 aosettings->setFeature(FEATURE_AC3 | FEATURE_DTS);
342 }
343 }
344 else
345 {
346 // Can't do digital passthrough without 16 bits audio
347 aosettings->setPassthrough(-1);
348 aosettings->setFeature(false,
351 }
352
353 return aosettings;
354}
355
363{
364 AudioOutputSettings* aosettings = this;
365
366 if (newcopy)
367 aosettings = GetCleaned(newcopy);
368
369 if (aosettings->m_invalid)
370 return aosettings;
371
372 int cur_channels = gCoreContext->GetNumSetting("MaxChannels", 2);
373 int max_channels = aosettings->BestSupportedChannels();
374
375 bool bAC3 = aosettings->canFeature(FEATURE_AC3) &&
376 gCoreContext->GetBoolSetting("AC3PassThru", false);
377
378 bool bDTS = aosettings->canFeature(FEATURE_DTS) &&
379 gCoreContext->GetBoolSetting("DTSPassThru", false);
380
381 bool bLPCM = aosettings->canFeature(FEATURE_LPCM) &&
382 !gCoreContext->GetBoolSetting("StereoPCM", false);
383
384 bool bEAC3 = aosettings->canFeature(FEATURE_EAC3) &&
385 gCoreContext->GetBoolSetting("EAC3PassThru", false) &&
386 !gCoreContext->GetBoolSetting("Audio48kOverride", false);
387
388 // TrueHD requires HBR support.
389 bool bTRUEHD = aosettings->canFeature(FEATURE_TRUEHD) &&
390 gCoreContext->GetBoolSetting("TrueHDPassThru", false) &&
391 !gCoreContext->GetBoolSetting("Audio48kOverride", false) &&
392 gCoreContext->GetBoolSetting("HBRPassthru", true);
393
394 bool bDTSHD = aosettings->canFeature(FEATURE_DTSHD) &&
395 gCoreContext->GetBoolSetting("DTSHDPassThru", false) &&
396 !gCoreContext->GetBoolSetting("Audio48kOverride", false);
397
398 if (max_channels > 2 && !bLPCM)
399 max_channels = 2;
400 if (max_channels == 2 && (bAC3 || bDTS))
401 max_channels = 6;
402
403 cur_channels = std::min(cur_channels, max_channels);
404
405 aosettings->SetBestSupportedChannels(cur_channels);
406 aosettings->setFeature(bAC3, FEATURE_AC3);
407 aosettings->setFeature(bDTS, FEATURE_DTS);
408 aosettings->setFeature(bLPCM, FEATURE_LPCM);
409 aosettings->setFeature(bEAC3, FEATURE_EAC3);
410 aosettings->setFeature(bTRUEHD, FEATURE_TRUEHD);
411 aosettings->setFeature(bDTSHD, FEATURE_DTSHD);
412
413 return aosettings;
414}
415
417{
419 return 0;
420
421 // If no HBR or no LPCM, limit bitrate to 6.144Mbit/s
422 if (!gCoreContext->GetBoolSetting("HBRPassthru", true) ||
424 {
425 return 192000; // E-AC3/DTS-HD High Res: 192k, 16 bits, 2 ch
426 }
427 return 768000; // TrueHD or DTS-HD MA: 192k, 16 bits, 8 ch
428}
429
431{
433 const std::string name;
434};
435static const std::array<featureStruct,7> feature {{
436 { FEATURE_AC3, "AC3"},
437 { FEATURE_DTS, "DTS"},
438 { FEATURE_LPCM, "LPCM"},
439 { FEATURE_EAC3, "EAC3"},
440 { FEATURE_TRUEHD, "TRUEHD"},
441 { FEATURE_DTSHD, "DTSHD"},
442 { FEATURE_AAC, "AAC"},
443}};
444
446{
447 QStringList tmp;
448 // cppcheck-suppress unassignedVariable
449 for (const auto & [flag, name] : feature)
450 {
451 if (arg & flag)
452 tmp += QString::fromStdString(name);
453 }
454 return tmp.join(",");
455}
456
457QString AudioOutputSettings::GetPassthroughParams(int codec, int codec_profile,
458 int &samplerate,
459 int &channels,
460 bool canDTSHDMA)
461{
462 QString log;
463
464 channels = 2;
465
466 switch (codec)
467 {
468 case AV_CODEC_ID_AC3:
469 log = "AC3";
470 break;
471 case AV_CODEC_ID_EAC3:
472 samplerate = samplerate * 4;
473 log = "Dolby Digital Plus (E-AC3)";
474 break;
475 case AV_CODEC_ID_DTS:
476 switch(codec_profile)
477 {
478 case AV_PROFILE_DTS_ES:
479 log = "DTS-ES";
480 break;
481 case AV_PROFILE_DTS_96_24:
482 log = "DTS 96/24";
483 break;
484 case AV_PROFILE_DTS_HD_HRA:
485 samplerate = 192000;
486 log = "DTS-HD High-Res";
487 break;
488 case AV_PROFILE_DTS_HD_MA:
489 samplerate = 192000;
490 if (canDTSHDMA)
491 {
492 log = "DTS-HD MA";
493 channels = 8;
494 }
495 else
496 {
497 log = "DTS-HD High-Res";
498 }
499 break;
500 case AV_PROFILE_DTS:
501 default:
502 log = "DTS Core";
503 break;
504 }
505 break;
506 case AV_CODEC_ID_TRUEHD:
507 channels = 8;
508 log = "TrueHD";
509 switch(samplerate)
510 {
511 case 48000:
512 case 96000:
513 case 192000:
514 samplerate = 192000;
515 break;
516 case 44100:
517 case 88200:
518 case 176400:
519 samplerate = 176400;
520 break;
521 default:
522 log = "TrueHD: Unsupported samplerate";
523 break;
524 }
525 break;
526 default:
527 break;
528 }
529 return log;
530}
531
533{
534 return m_hasEld && m_eld.isValid();
535};
536
538{
539 return m_hasEld;
540};
541
542void AudioOutputSettings::setELD(QByteArray *ba)
543{
544 m_hasEld = true;
545 m_eld = eld(ba->constData(), ba->size());
546 m_eld.show();
547}
548
550{
552 if (!hasValidELD())
553 return chan;
554 int eldc = m_eld.maxChannels();
555 return eldc < chan ? eldc : chan;
556}
557
559{
561 if (!hasValidELD())
562 return chan;
563 int eldc = m_eld.maxLPCMChannels();
564 return eldc < chan ? eldc : chan;
565}
#define LOC
static const std::array< featureStruct, 7 > feature
std::array< const int, 12 > rate_array
std::array< const AudioFormat, 6 > format_array
@ FORMAT_U8
@ FORMAT_S32
@ FORMAT_S24
@ FORMAT_NONE
@ FORMAT_FLT
@ FORMAT_S16
@ FORMAT_S24LSB
DigitalFeature
@ FEATURE_DTS
@ FEATURE_AC3
@ FEATURE_DTSHD
@ FEATURE_EAC3
@ FEATURE_LPCM
@ FEATURE_TRUEHD
@ FEATURE_AAC
bool IsSupportedChannels(int channels)
QString FeaturesToString(void) const
AudioOutputSettings * GetUsers(bool newcopy=false)
Returns capabilities supported by the audio device amended to take into account the digital audio opt...
static int SampleSize(AudioFormat format)
AudioFormat BestSupportedFormat()
void setELD(QByteArray *ba)
set ELD data
bool canFeature(DigitalFeature arg) const
return DigitalFeature mask.
std::vector< AudioFormat > m_formats
int BestSupportedChannelsELD()
Reports best supported channel number, restricted to ELD range.
static const format_array kStdFormats
void AddSupportedRate(int rate)
rate_array::iterator m_srIt
int GetMaxHDRate() const
return the highest iec958 rate supported.
static AVSampleFormat FormatToAVSampleFormat(AudioFormat format)
Return AudioFormat closest equivalent to AVSampleFormat Note that FORMAT_S24LSB and FORMAT_S24 have n...
bool IsSupportedRate(int rate)
format_array::iterator m_sfIt
std::vector< int > m_rates
AudioOutputSettings(bool invalid=false)
bool hasELD() const
get the ELD flag
void SetBestSupportedChannels(int channels)
Force set the greatest number of channels supported by the audio device.
int NearestSupportedRate(int rate)
AudioOutputSettings * GetCleaned(bool newcopy=false)
Returns capabilities supported by the audio device amended to take into account the digital audio opt...
static AudioFormat AVSampleFormatToFormat(AVSampleFormat format, int bits=0)
Return AVSampleFormat closest equivalent to AudioFormat.
std::vector< int > m_channels
void setPassthrough(int val)
static const char * FormatToString(AudioFormat format)
static int FormatToBits(AudioFormat format)
int BestSupportedPCMChannelsELD()
Reports best supported PCM channel number, restricted to ELD.
void AddSupportedChannels(int channels)
void setFeature(DigitalFeature arg)
set the provided digital feature possible values are:
static QString GetPassthroughParams(int codec, int codec_profile, int &samplerate, int &channels, bool canDTSHDMA)
Setup samplerate and number of channels for passthrough.
void AddSupportedFormat(AudioFormat format)
static const rate_array kStdRates
bool IsSupportedFormat(AudioFormat format)
bool m_hasEld
will be set to true if we were able to retrieve the device ELD (EDID like Data).
AudioOutputSettings & operator=(const AudioOutputSettings &)
int m_passthrough
passthrough status -1 : no 0: unknown 1: yes
int GetNumSetting(const QString &key, int defaultval=0)
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: eldutils.h:39
void show()
Definition: eldutils.cpp:412
int maxChannels()
Definition: eldutils.cpp:460
bool isValid() const
Definition: eldutils.cpp:407
int maxLPCMChannels()
Definition: eldutils.cpp:446
static pid_list_t::iterator find(const PIDInfoMap &map, pid_list_t &list, pid_list_t::iterator begin, pid_list_t::iterator end, bool find_open)
static uint32_t * tmp
Definition: goom_core.cpp:28
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
None log(str msg, int level=LOGDEBUG)
Definition: xbmc.py:9
const DigitalFeature flag
const std::string name