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 "libavutil/avutil.h" // to check version of libavformat
20}
21
22#define LOC QString("AOS: ")
23
25{
26 5512, 8000, 11025, 16000, 22050, 32000, 44100,
27 48000, 88200, 96000, 176400, 192000
28};
29
31{
33};
34
36 m_invalid(invalid),
37 m_srIt(kStdRates.begin()),
38 m_sfIt(kStdFormats.begin())
39{
40}
41
43{
44 m_rates.clear();
45 m_formats.clear();
46 m_channels.clear();
47}
48
50 const AudioOutputSettings &rhs)
51{
52 if (this == &rhs)
53 return *this;
54 m_rates = rhs.m_rates;
55 m_formats = rhs.m_formats;
59 m_invalid = rhs.m_invalid;
60 m_hasEld = rhs.m_hasEld;
61 m_eld = rhs.m_eld;
62 m_srIt = kStdRates.begin() + (rhs.m_srIt - kStdRates.begin());
63 m_sfIt = kStdFormats.begin() + (rhs.m_sfIt - kStdFormats.begin());
64 return *this;
65}
66
68{
69 if (m_srIt == kStdRates.end())
70 {
71 m_srIt = kStdRates.begin();
72 return 0;
73 }
74
75 return *m_srIt++;
76}
77
79{
80 m_rates.push_back(rate);
81 LOG(VB_AUDIO, LOG_INFO, LOC +
82 QString("Sample rate %1 is supported").arg(rate));
83}
84
86{
87 if (m_rates.empty() && rate == 48000)
88 return true;
89
90 auto result = std::find(m_rates.cbegin(), m_rates.cend(), rate);
91 return result != m_rates.end();
92}
93
95{
96 if (m_rates.empty())
97 return 48000;
98 return m_rates.back();
99}
100
102{
103 if (m_rates.empty())
104 return 48000;
105
106 // Assume rates vector is sorted
107 auto it = std::find_if(m_rates.cbegin(), m_rates.cend(),
108 [rate](const auto entry){ return entry >= rate; } );
109 if (it != m_rates.cend())
110 return *it;
111
112 // Not found, so return highest available rate
113 return m_rates.back();
114}
115
117{
118 if (m_sfIt == kStdFormats.end())
119 {
120 m_sfIt = kStdFormats.begin();
121 return FORMAT_NONE;
122 }
123
124 return *m_sfIt++;
125}
126
128{
129 LOG(VB_AUDIO, LOG_INFO, LOC +
130 QString("Format %1 is supported").arg(FormatToString(format)));
131 m_formats.push_back(format);
132}
133
135{
136 if (m_formats.empty() && format == FORMAT_S16)
137 return true;
138
139 auto result = std::find(m_formats.cbegin(), m_formats.cend(), format);
140 return result != m_formats.end();
141}
142
144{
145 if (m_formats.empty())
146 return FORMAT_S16;
147 return m_formats.back();
148}
149
151{
152 switch (format)
153 {
154 case FORMAT_U8: return 8;
155 case FORMAT_S16: return 16;
156 case FORMAT_S24LSB:
157 case FORMAT_S24: return 24;
158 case FORMAT_S32:
159 case FORMAT_FLT: return 32;
160 case FORMAT_NONE:
161 default: return -1;
162 }
163}
164
166{
167 switch (format)
168 {
169 case FORMAT_U8: return "unsigned 8 bit";
170 case FORMAT_S16: return "signed 16 bit";
171 case FORMAT_S24: return "signed 24 bit MSB";
172 case FORMAT_S24LSB: return "signed 24 bit LSB";
173 case FORMAT_S32: return "signed 32 bit";
174 case FORMAT_FLT: return "32 bit floating point";
175 case FORMAT_NONE: return "none";
176 default: return "unknown";
177 }
178}
179
181{
182 switch (format)
183 {
184 case FORMAT_U8: return 1;
185 case FORMAT_S16: return 2;
186 case FORMAT_S24:
187 case FORMAT_S24LSB:
188 case FORMAT_S32:
189 case FORMAT_FLT: return 4;
190 case FORMAT_NONE:
191 default: return 0;
192 }
193}
194
199{
200 switch (av_get_packed_sample_fmt(format))
201 {
202 case AV_SAMPLE_FMT_U8: return FORMAT_U8;
203 case AV_SAMPLE_FMT_S16: return FORMAT_S16;
204 case AV_SAMPLE_FMT_FLT: return FORMAT_FLT;
205 case AV_SAMPLE_FMT_DBL: return FORMAT_NONE;
206 case AV_SAMPLE_FMT_S32:
207 switch (bits)
208 {
209 case 0: return FORMAT_S32;
210 case 24: return FORMAT_S24;
211 case 32: return FORMAT_S32;
212 default: return FORMAT_NONE;
213 }
214 default: return FORMAT_NONE;
215 }
216}
217
224{
225 switch (format)
226 {
227 case FORMAT_U8: return AV_SAMPLE_FMT_U8;
228 case FORMAT_S16: return AV_SAMPLE_FMT_S16;
229 case FORMAT_FLT: return AV_SAMPLE_FMT_FLT;
230 case FORMAT_S32:
231 case FORMAT_S24:
232 case FORMAT_S24LSB: return AV_SAMPLE_FMT_S32;
233 default: return AV_SAMPLE_FMT_NONE;
234 }
235}
236
238{
239 m_channels.push_back(channels);
240 LOG(VB_AUDIO, LOG_INFO, LOC + QString("%1 channel(s) are supported")
241 .arg(channels));
242}
243
245{
246 if (m_channels.empty() && channels == 2)
247 return true;
248
249 return std::any_of(m_channels.cbegin(), m_channels.cend(),
250 [channels](const auto entry)
251 { return entry == channels; } );
252}
253
255{
256 if (m_channels.empty())
257 return 2;
258 SortSupportedChannels(); // ensure last element is the best supported channel
259 return m_channels.back();
260}
261
263{
264 if (m_channels.empty())
265 return;
266 sort(m_channels.begin(), m_channels.end());
267}
268
270{
271 if (m_channels.empty())
272 {
273 m_channels.push_back(channels);
274 return;
275 }
276
277 std::vector<int>tmp;
278 std::copy_if(m_channels.cbegin(), m_channels.cend(),
279 std::back_inserter(tmp),
280 [channels](int value){ return channels > value; } );
281 m_channels = tmp;
282 m_channels.push_back(channels);
283}
284
285void AudioOutputSettings::setFeature(bool val, int arg)
286{
287 if (val)
288 m_features |= arg;
289 else
290 m_features &= ~arg;
291};
292
294{
295 setFeature(val, (int) arg);
296};
297
305{
306 AudioOutputSettings* aosettings = this;
307
308 if (newcopy)
309 {
310 aosettings = new AudioOutputSettings;
311 *aosettings = *this;
312 }
313
314 if (m_invalid)
315 return aosettings;
316
318 {
319 aosettings->setFeature(FEATURE_LPCM);
320 }
321
323 {
324 // E-AC3 is transferred as stereo PCM at 4 times the rates
325 // assume all amplifier supporting E-AC3 also supports 7.1 LPCM
326 // as it's mandatory under the bluray standard
327//#if LIBAVFORMAT_VERSION_INT > AV_VERSION_INT( 52, 83, 0 )
328 if (m_passthrough >= 0 && IsSupportedChannels(8) &&
329 IsSupportedRate(192000))
332//#endif
333 if (m_passthrough >= 0)
334 {
335 if (BestSupportedChannels() == 2)
336 {
337 LOG(VB_AUDIO, LOG_INFO, LOC + "may be AC3 or DTS capable");
338 aosettings->AddSupportedChannels(6);
339 }
340 aosettings->setFeature(FEATURE_AC3 | FEATURE_DTS);
341 }
342 }
343 else
344 {
345 // Can't do digital passthrough without 16 bits audio
346 aosettings->setPassthrough(-1);
347 aosettings->setFeature(false,
350 }
351
352 return aosettings;
353}
354
362{
363 AudioOutputSettings* aosettings = this;
364
365 if (newcopy)
366 aosettings = GetCleaned(newcopy);
367
368 if (aosettings->m_invalid)
369 return aosettings;
370
371 int cur_channels = gCoreContext->GetNumSetting("MaxChannels", 2);
372 int max_channels = aosettings->BestSupportedChannels();
373
374 bool bAC3 = aosettings->canFeature(FEATURE_AC3) &&
375 gCoreContext->GetBoolSetting("AC3PassThru", false);
376
377 bool bDTS = aosettings->canFeature(FEATURE_DTS) &&
378 gCoreContext->GetBoolSetting("DTSPassThru", false);
379
380 bool bLPCM = aosettings->canFeature(FEATURE_LPCM) &&
381 !gCoreContext->GetBoolSetting("StereoPCM", false);
382
383 bool bEAC3 = aosettings->canFeature(FEATURE_EAC3) &&
384 gCoreContext->GetBoolSetting("EAC3PassThru", false) &&
385 !gCoreContext->GetBoolSetting("Audio48kOverride", false);
386
387 // TrueHD requires HBR support.
388 bool bTRUEHD = aosettings->canFeature(FEATURE_TRUEHD) &&
389 gCoreContext->GetBoolSetting("TrueHDPassThru", false) &&
390 !gCoreContext->GetBoolSetting("Audio48kOverride", false) &&
391 gCoreContext->GetBoolSetting("HBRPassthru", true);
392
393 bool bDTSHD = aosettings->canFeature(FEATURE_DTSHD) &&
394 gCoreContext->GetBoolSetting("DTSHDPassThru", false) &&
395 !gCoreContext->GetBoolSetting("Audio48kOverride", false);
396
397 if (max_channels > 2 && !bLPCM)
398 max_channels = 2;
399 if (max_channels == 2 && (bAC3 || bDTS))
400 max_channels = 6;
401
402 cur_channels = std::min(cur_channels, max_channels);
403
404 aosettings->SetBestSupportedChannels(cur_channels);
405 aosettings->setFeature(bAC3, FEATURE_AC3);
406 aosettings->setFeature(bDTS, FEATURE_DTS);
407 aosettings->setFeature(bLPCM, FEATURE_LPCM);
408 aosettings->setFeature(bEAC3, FEATURE_EAC3);
409 aosettings->setFeature(bTRUEHD, FEATURE_TRUEHD);
410 aosettings->setFeature(bDTSHD, FEATURE_DTSHD);
411
412 return aosettings;
413}
414
416{
418 return 0;
419
420 // If no HBR or no LPCM, limit bitrate to 6.144Mbit/s
421 if (!gCoreContext->GetBoolSetting("HBRPassthru", true) ||
423 {
424 return 192000; // E-AC3/DTS-HD High Res: 192k, 16 bits, 2 ch
425 }
426 return 768000; // TrueHD or DTS-HD MA: 192k, 16 bits, 8 ch
427}
428
430{
432 const std::string name;
433};
434static const std::array<featureStruct,7> feature {{
435 { FEATURE_AC3, "AC3"},
436 { FEATURE_DTS, "DTS"},
437 { FEATURE_LPCM, "LPCM"},
438 { FEATURE_EAC3, "EAC3"},
439 { FEATURE_TRUEHD, "TRUEHD"},
440 { FEATURE_DTSHD, "DTSHD"},
441 { FEATURE_AAC, "AAC"},
442}};
443
445{
446 QStringList tmp;
447 // cppcheck-suppress unassignedVariable
448 for (const auto & [flag, name] : feature)
449 {
450 if (arg & flag)
451 tmp += QString::fromStdString(name);
452 }
453 return tmp.join(",");
454}
455
456QString AudioOutputSettings::GetPassthroughParams(int codec, int codec_profile,
457 int &samplerate,
458 int &channels,
459 bool canDTSHDMA)
460{
461 QString log;
462
463 channels = 2;
464
465 switch (codec)
466 {
467 case AV_CODEC_ID_AC3:
468 log = "AC3";
469 break;
470 case AV_CODEC_ID_EAC3:
471 samplerate = samplerate * 4;
472 log = "Dolby Digital Plus (E-AC3)";
473 break;
474 case AV_CODEC_ID_DTS:
475 switch(codec_profile)
476 {
477 case FF_PROFILE_DTS_ES:
478 log = "DTS-ES";
479 break;
480 case FF_PROFILE_DTS_96_24:
481 log = "DTS 96/24";
482 break;
483 case FF_PROFILE_DTS_HD_HRA:
484 samplerate = 192000;
485 log = "DTS-HD High-Res";
486 break;
487 case FF_PROFILE_DTS_HD_MA:
488 samplerate = 192000;
489 if (canDTSHDMA)
490 {
491 log = "DTS-HD MA";
492 channels = 8;
493 }
494 else
495 {
496 log = "DTS-HD High-Res";
497 }
498 break;
499 case FF_PROFILE_DTS:
500 default:
501 log = "DTS Core";
502 break;
503 }
504 break;
505 case AV_CODEC_ID_TRUEHD:
506 channels = 8;
507 log = "TrueHD";
508 switch(samplerate)
509 {
510 case 48000:
511 case 96000:
512 case 192000:
513 samplerate = 192000;
514 break;
515 case 44100:
516 case 88200:
517 case 176400:
518 samplerate = 176400;
519 break;
520 default:
521 log = "TrueHD: Unsupported samplerate";
522 break;
523 }
524 break;
525 default:
526 break;
527 }
528 return log;
529}
530
532{
533 return m_hasEld && m_eld.isValid();
534};
535
537{
538 return m_hasEld;
539};
540
541void AudioOutputSettings::setELD(QByteArray *ba)
542{
543 m_hasEld = true;
544 m_eld = eld(ba->constData(), ba->size());
545 m_eld.show();
546}
547
549{
551 if (!hasValidELD())
552 return chan;
553 int eldc = m_eld.maxChannels();
554 return eldc < chan ? eldc : chan;
555}
556
558{
560 if (!hasValidELD())
561 return chan;
562 int eldc = m_eld.maxLPCMChannels();
563 return eldc < chan ? eldc : chan;
564}
#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:38
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 guint32 * tmp
Definition: goom_core.cpp:26
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