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 <array>
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#ifdef __cpp_lib_ranges_contains
92 return std::ranges::contains(m_rates, rate);
93#else
94 auto result = std::ranges::find(m_rates, rate);
95 return result != m_rates.end();
96#endif
97}
98
100{
101 if (m_rates.empty())
102 return 48000;
103 return m_rates.back();
104}
105
107{
108 if (m_rates.empty())
109 return 48000;
110
111 // Assume rates vector is sorted
112 auto it = std::ranges::find_if(m_rates,
113 [rate](const auto entry){ return entry >= rate; } );
114 if (it != m_rates.end())
115 return *it;
116
117 // Not found, so return highest available rate
118 return m_rates.back();
119}
120
122{
123 if (m_sfIt == kStdFormats.end())
124 {
125 m_sfIt = kStdFormats.begin();
126 return FORMAT_NONE;
127 }
128
129 return *m_sfIt++;
130}
131
133{
134 LOG(VB_AUDIO, LOG_INFO, LOC +
135 QString("Format %1 is supported").arg(FormatToString(format)));
136 m_formats.push_back(format);
137}
138
140{
141 if (m_formats.empty() && format == FORMAT_S16)
142 return true;
143
144#ifdef __cpp_lib_ranges_contains
145 return std::ranges::contains(m_formats, format);
146#else
147 auto result = std::ranges::find(m_formats, format);
148 return result != m_formats.end();
149#endif
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#ifdef __cpp_lib_ranges_contains
259 return std::ranges::contains(m_channels, channels);
260#else
261 return std::ranges::any_of(m_channels,
262 [channels](const auto entry)
263 { return entry == channels; } );
264#endif
265}
266
268{
269 if (m_channels.empty())
270 return 2;
271 SortSupportedChannels(); // ensure last element is the best supported channel
272 return m_channels.back();
273}
274
276{
277 if (m_channels.empty())
278 return;
279 std::ranges::sort(m_channels);
280}
281
283{
284 if (m_channels.empty())
285 {
286 m_channels.push_back(channels);
287 return;
288 }
289
290 std::vector<int>tmp;
291 std::ranges::copy_if(m_channels,
292 std::back_inserter(tmp),
293 [channels](int value){ return channels > value; } );
294 m_channels = tmp;
295 m_channels.push_back(channels);
296}
297
298void AudioOutputSettings::setFeature(bool val, int arg)
299{
300 if (val)
301 m_features |= arg;
302 else
303 m_features &= ~arg;
304};
305
307{
308 setFeature(val, (int) arg);
309};
310
318{
319 AudioOutputSettings* aosettings = this;
320
321 if (newcopy)
322 {
323 aosettings = new AudioOutputSettings;
324 *aosettings = *this;
325 }
326
327 if (m_invalid)
328 return aosettings;
329
331 {
332 aosettings->setFeature(FEATURE_LPCM);
333 }
334
336 {
337 // E-AC3 is transferred as stereo PCM at 4 times the rates
338 // assume all amplifier supporting E-AC3 also supports 7.1 LPCM
339 // as it's mandatory under the bluray standard
340//#if LIBAVFORMAT_VERSION_INT > AV_VERSION_INT( 52, 83, 0 )
341 if (m_passthrough >= 0 && IsSupportedChannels(8) &&
342 IsSupportedRate(192000))
345//#endif
346 if (m_passthrough >= 0)
347 {
348 if (BestSupportedChannels() == 2)
349 {
350 LOG(VB_AUDIO, LOG_INFO, LOC + "may be AC3 or DTS capable");
351 aosettings->AddSupportedChannels(6);
352 }
353 aosettings->setFeature(FEATURE_AC3 | FEATURE_DTS);
354 }
355 }
356 else
357 {
358 // Can't do digital passthrough without 16 bits audio
359 aosettings->setPassthrough(-1);
360 aosettings->setFeature(false,
363 }
364
365 return aosettings;
366}
367
375{
376 AudioOutputSettings* aosettings = this;
377
378 if (newcopy)
379 aosettings = GetCleaned(newcopy);
380
381 if (aosettings->m_invalid)
382 return aosettings;
383
384 int cur_channels = gCoreContext->GetNumSetting("MaxChannels", 2);
385 int max_channels = aosettings->BestSupportedChannels();
386
387 bool bAC3 = aosettings->canFeature(FEATURE_AC3) &&
388 gCoreContext->GetBoolSetting("AC3PassThru", false);
389
390 bool bDTS = aosettings->canFeature(FEATURE_DTS) &&
391 gCoreContext->GetBoolSetting("DTSPassThru", false);
392
393 bool bLPCM = aosettings->canFeature(FEATURE_LPCM) &&
394 !gCoreContext->GetBoolSetting("StereoPCM", false);
395
396 bool bEAC3 = aosettings->canFeature(FEATURE_EAC3) &&
397 gCoreContext->GetBoolSetting("EAC3PassThru", false) &&
398 !gCoreContext->GetBoolSetting("Audio48kOverride", false);
399
400 // TrueHD requires HBR support.
401 bool bTRUEHD = aosettings->canFeature(FEATURE_TRUEHD) &&
402 gCoreContext->GetBoolSetting("TrueHDPassThru", false) &&
403 !gCoreContext->GetBoolSetting("Audio48kOverride", false) &&
404 gCoreContext->GetBoolSetting("HBRPassthru", true);
405
406 bool bDTSHD = aosettings->canFeature(FEATURE_DTSHD) &&
407 gCoreContext->GetBoolSetting("DTSHDPassThru", false) &&
408 !gCoreContext->GetBoolSetting("Audio48kOverride", false);
409
410 if (max_channels > 2 && !bLPCM)
411 max_channels = 2;
412 if (max_channels == 2 && (bAC3 || bDTS))
413 max_channels = 6;
414
415 cur_channels = std::min(cur_channels, max_channels);
416
417 aosettings->SetBestSupportedChannels(cur_channels);
418 aosettings->setFeature(bAC3, FEATURE_AC3);
419 aosettings->setFeature(bDTS, FEATURE_DTS);
420 aosettings->setFeature(bLPCM, FEATURE_LPCM);
421 aosettings->setFeature(bEAC3, FEATURE_EAC3);
422 aosettings->setFeature(bTRUEHD, FEATURE_TRUEHD);
423 aosettings->setFeature(bDTSHD, FEATURE_DTSHD);
424
425 return aosettings;
426}
427
429{
431 return 0;
432
433 // If no HBR or no LPCM, limit bitrate to 6.144Mbit/s
434 if (!gCoreContext->GetBoolSetting("HBRPassthru", true) ||
436 {
437 return 192000; // E-AC3/DTS-HD High Res: 192k, 16 bits, 2 ch
438 }
439 return 768000; // TrueHD or DTS-HD MA: 192k, 16 bits, 8 ch
440}
441
443{
445 const std::string name;
446};
447static const std::array<featureStruct,7> feature {{
448 { .flag=FEATURE_AC3, .name="AC3"},
449 { .flag=FEATURE_DTS, .name="DTS"},
450 { .flag=FEATURE_LPCM, .name="LPCM"},
451 { .flag=FEATURE_EAC3, .name="EAC3"},
452 { .flag=FEATURE_TRUEHD, .name="TRUEHD"},
453 { .flag=FEATURE_DTSHD, .name="DTSHD"},
454 { .flag=FEATURE_AAC, .name="AAC"},
455}};
456
458{
459 QStringList tmp;
460 // cppcheck-suppress unassignedVariable
461 for (const auto & [flag, name] : feature)
462 {
463 if (arg & flag)
464 tmp += QString::fromStdString(name);
465 }
466 return tmp.join(",");
467}
468
469QString AudioOutputSettings::GetPassthroughParams(int codec, int codec_profile,
470 int &samplerate,
471 int &channels,
472 bool canDTSHDMA)
473{
474 QString log;
475
476 channels = 2;
477
478 switch (codec)
479 {
480 case AV_CODEC_ID_AC3:
481 log = "AC3";
482 break;
483 case AV_CODEC_ID_EAC3:
484 samplerate = samplerate * 4;
485 log = "Dolby Digital Plus (E-AC3)";
486 break;
487 case AV_CODEC_ID_DTS:
488 switch(codec_profile)
489 {
490 case AV_PROFILE_DTS_ES:
491 log = "DTS-ES";
492 break;
493 case AV_PROFILE_DTS_96_24:
494 log = "DTS 96/24";
495 break;
496 case AV_PROFILE_DTS_HD_HRA:
497 samplerate = 192000;
498 log = "DTS-HD High-Res";
499 break;
500 case AV_PROFILE_DTS_HD_MA:
501 samplerate = 192000;
502 if (canDTSHDMA)
503 {
504 log = "DTS-HD MA";
505 channels = 8;
506 }
507 else
508 {
509 log = "DTS-HD High-Res";
510 }
511 break;
512 case AV_PROFILE_DTS:
513 default:
514 log = "DTS Core";
515 break;
516 }
517 break;
518 case AV_CODEC_ID_TRUEHD:
519 channels = 8;
520 log = "TrueHD";
521 switch(samplerate)
522 {
523 case 48000:
524 case 96000:
525 case 192000:
526 samplerate = 192000;
527 break;
528 case 44100:
529 case 88200:
530 case 176400:
531 samplerate = 176400;
532 break;
533 default:
534 log = "TrueHD: Unsupported samplerate";
535 break;
536 }
537 break;
538 default:
539 break;
540 }
541 return log;
542}
543
545{
546 return m_hasEld && m_eld.isValid();
547};
548
550{
551 return m_hasEld;
552};
553
554void AudioOutputSettings::setELD(QByteArray *ba)
555{
556 m_hasEld = true;
557 m_eld = eld(ba->constData(), ba->size());
558 m_eld.show();
559}
560
562{
564 if (!hasValidELD())
565 return chan;
566 int eldc = m_eld.maxChannels();
567 return eldc < chan ? eldc : chan;
568}
569
571{
573 if (!hasValidELD())
574 return chan;
575 int eldc = m_eld.maxLPCMChannels();
576 return eldc < chan ? eldc : chan;
577}
#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:416
int maxChannels()
Definition: eldutils.cpp:464
bool isValid() const
Definition: eldutils.cpp:411
int maxLPCMChannels()
Definition: eldutils.cpp:450
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)
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