Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add support for E-AC3, TrueHD and DTS-HD digital passthrough.

A big thank you to Anssi Hannulafor his changes to FFmpeg and working with me to get this up and running.
Thanks to foobum for his code review

Details on some of the changes included in this commit are:
- When creating the AudioOutput instance, only open the audio device and set all parameters when we have valid configuration information. This seriously reduces the amount of noise in the logs
- Simplify locking code in audioplayer, in particular do not create more locking than necessary
- E-AC3 , DTS-HD hi-res can be enabled on any platform supporting stereo 192kHz, so change the test to see if hardware supports that mode
- Add ability to play audio-only files with default player. Set -O AudioOnlyPlayback=1
- Add support for 6.144Mbit/s bitrate passthrough. This allows the use of DTS-HD passthrough for card not supporting HBR (ION, 9400M or nvidia GT2xx).
- Make audiooutputsettings digital features more generic and future-proof
- Change digital passthrough auto-configuration:
  Open device with settings:
  AES0=6 AES1=0x82 AES2=0x00 AES3=0x01.

  AES0 = NON_AUDIO | PRO_MODE
  AES1 = original stream, original PCM coder
  AES2 = source and channel unspecified
  AES3 = sample rate unspecified

  by default, ALSA uses AES3=0x02 which force the sampling rate to 48kHz. This break 44.1kHz passthrough with some audio cards.
  On the other hand, with some cards, you need to set 48kHz sample rate to get 44.1kHz passthrough. As the later case is obviously a bug, we do the right thing and set it as it should by default.
  For people finding that they no longer get multi-channel AC3/DTS audio, they need to go into the Advanced Option and check the SPDIF 48k override option
-Up to now, if the user had overriden the passthrough device, we assumed he knew what he was doing and it would disable all consistency tests.
  We now handle errors should the passthrough device not be valid. In the settings screen, an error message will now be shown.
  We also now handle two different AudioOutputSettings type one for PCM output, the other for passthrough. Previously capabilities would only be checked on the main audio device.
-Fix some segfault should the upmixer failed to be initialised properly. Fix timestretch.
-Mythmusic seems to happily supply audio frames to AudioOutput even when audio initialisation fail. As some fields weren't initialised, this could result with some division by zero error
-Audio framework: Main function member will now return an error if called without audio framework properly initialised
-Add an OutputSettings(bool digital) method in AudioOutputBase, get rid of alternation in Reconfigure()
-Check for FORMAT_S16 support for passthru support, use canFeature instead of canAC3 / canLPCM in AO
-Rewrite support for the various DTS streams.
  Can now properly distinguish between the various DTS types:
  - DTS Core
  - DTS-ES
  - DTS 96/24
  - DTS-HD High-Res
  - DTS-HD MA
 Note that if not using-passthrough, only the DTS Core stream can be decoded
-Change in the audio stream can now be properly monitored such as changing DTS audio type.
-Move SPDIF/IEC958 encapsulation within the audio class so avfd doesn't depends directly on any of the audio code.
-Fixes timestamp estimation when timestamps are missing or frames are dropped
  • Loading branch information...
commit 649fa85cb41f128606038a9789693657a11cd178 1 parent 8b8b128
@jyavenard jyavenard authored
Showing with 1,066 additions and 700 deletions.
  1. +2 −5 mythplugins/mythmusic/mythmusic/musicplayer.cpp
  2. +7 −4 mythtv/libs/libmyth/audio/audiooutput.h
  3. +42 −26 mythtv/libs/libmyth/audio/audiooutputalsa.cpp
  4. +1 −2  mythtv/libs/libmyth/audio/audiooutputalsa.h
  5. +288 −117 mythtv/libs/libmyth/audio/audiooutputbase.cpp
  6. +44 −15 mythtv/libs/libmyth/audio/audiooutputbase.h
  7. +4 −3 mythtv/libs/libmyth/audio/audiooutputdigitalencoder.cpp
  8. +9 −7 mythtv/libs/libmyth/audio/audiooutputdx.cpp
  9. +1 −1  mythtv/libs/libmyth/audio/audiooutputdx.h
  10. +105 −33 mythtv/libs/libmyth/audio/audiooutputsettings.cpp
  11. +79 −23 mythtv/libs/libmyth/audio/audiooutputsettings.h
  12. +2 −2 mythtv/libs/libmyth/audio/audiooutpututil.cpp
  13. +2 −2 mythtv/libs/libmyth/audio/audiooutpututil.h
  14. +7 −1 mythtv/libs/libmyth/audio/audiosettings.cpp
  15. +14 −1 mythtv/libs/libmyth/audio/audiosettings.h
  16. +35 −27 mythtv/libs/libmyth/audio/spdifencoder.cpp
  17. +6 −3 mythtv/libs/libmyth/audio/spdifencoder.h
  18. +161 −146 mythtv/libs/libmythtv/audioplayer.cpp
  19. +16 −10 mythtv/libs/libmythtv/audioplayer.h
  20. +83 −189 mythtv/libs/libmythtv/avformatdecoder.cpp
  21. +17 −14 mythtv/libs/libmythtv/avformatdecoder.h
  22. +7 −6 mythtv/libs/libmythtv/mythplayer.cpp
  23. +115 −54 mythtv/programs/mythfrontend/audiogeneralsettings.cpp
  24. +4 −1 mythtv/programs/mythfrontend/audiogeneralsettings.h
  25. +15 −8 mythtv/programs/mythtranscode/transcode.cpp
View
7 mythplugins/mythmusic/mythmusic/musicplayer.cpp
@@ -303,11 +303,8 @@ void MusicPlayer::openOutputDevice(void)
else
adevice = gCoreContext->GetSetting("MusicAudioDevice");
- pdevice = gCoreContext->GetNumSetting("AdvancedAudioSettings",
- false) &&
- gCoreContext->GetNumSetting("PassThruDeviceOverride",
- false) ?
- gCoreContext->GetSetting("PassThruOutputDevice") : QString::null;
+ pdevice = gCoreContext->GetNumSetting("PassThruDeviceOverride", false) ?
+ gCoreContext->GetSetting("PassThruOutputDevice") : "auto";
// TODO: Error checking that device is opened correctly!
m_output = AudioOutput::OpenAudio(
View
11 mythtv/libs/libmyth/audio/audiooutput.h
@@ -64,18 +64,21 @@ class MPUBLIC AudioOutput : public VolumeBase, public OutputListeners
virtual AudioFormat GetFormat(void) const { return FORMAT_S16; };
virtual int GetBytesPerFrame(void) const { return 4; };
- virtual AudioOutputSettings* GetOutputSettingsCleaned(void)
+ virtual AudioOutputSettings* GetOutputSettingsCleaned(bool digital = true)
{ return new AudioOutputSettings; }
- virtual AudioOutputSettings* GetOutputSettingsUsers(void)
+ virtual AudioOutputSettings* GetOutputSettingsUsers(bool digital = true)
{ return new AudioOutputSettings; }
- virtual bool CanPassthrough(int samplerate, int channels) const = 0;
+ virtual bool CanPassthrough(int samplerate, int channels, int codec) const
+ { return false; }
// dsprate is in 100 * samples/second
virtual void SetEffDsp(int dsprate) = 0;
virtual void Reset(void) = 0;
- virtual bool AddFrames(void *buffer, int samples, int64_t timecode) = 0;
+ virtual bool AddFrames(void *buffer, int frames, int64_t timecode) = 0;
+ virtual bool AddData(void *buffer, int len, int64_t timecode) = 0;
+ virtual int64_t LengthLastData(void) { return 0; }
virtual void SetTimecode(int64_t timecode) = 0;
virtual bool IsPaused(void) const = 0;
View
68 mythtv/libs/libmyth/audio/audiooutputalsa.cpp
@@ -36,8 +36,7 @@ AudioOutputALSA::AudioOutputALSA(const AudioSettings &settings) :
pbufsize(-1),
m_card(-1),
m_device(-1),
- m_subdevice(-1),
- m_autopassthrough(false)
+ m_subdevice(-1)
{
m_mixer.handle = NULL;
m_mixer.elem = NULL;
@@ -45,17 +44,29 @@ AudioOutputALSA::AudioOutputALSA(const AudioSettings &settings) :
// Set everything up
if (passthru_device == "auto")
{
- m_autopassthrough = true;
passthru_device = main_device;
- /* to set the non-audio bit, use AES0=6 */
int len = passthru_device.length();
int args = passthru_device.indexOf(":");
+ /*
+ * AES description:
+ * AES0=6 AES1=0x82 AES2=0x00 AES3=0x01.
+ * AES0 = NON_AUDIO | PRO_MODE
+ * AES1 = original stream, original PCM coder
+ * AES2 = source and channel unspecified
+ * AES3 = sample rate unspecified
+ */
+ bool s48k = gCoreContext->GetNumSetting("SPDIFRateOverride", false);
+ QString iecarg = QString("AES0=6,AES1=0x82,AES2=0x00") +
+ (s48k ? QString() : QString(",AES3=0x01"));
+ QString iecarg2 = QString("AES0=6 AES1=0x82 AES2=0x00") +
+ (s48k ? QString() : QString(" AES3=0x01"));
+
if (args < 0)
{
/* no existing parameters: add it behind device name */
- passthru_device += ":AES0=6"; //,AES1=0x82,AES2=0x00,AES3=0x01";
+ passthru_device += ":" + iecarg;
}
else
{
@@ -66,12 +77,12 @@ AudioOutputALSA::AudioOutputALSA(const AudioSettings &settings) :
if (args == passthru_device.length())
{
/* ":" but no parameters */
- passthru_device += "AES0=6"; //,AES1=0x82,AES2=0x00,AES3=0x01";
+ passthru_device += iecarg;
}
else if (passthru_device[args] != '{')
{
/* a simple list of parameters: add it at the end of the list */
- passthru_device += ",AES0=6"; //,AES1=0x82,AES2=0x00,AES3=0x01";
+ passthru_device += "," + iecarg;
}
else
{
@@ -80,13 +91,15 @@ AudioOutputALSA::AudioOutputALSA(const AudioSettings &settings) :
--len;
while (len > 0 && passthru_device[len].isSpace());
if (passthru_device[len] == '}')
- passthru_device = passthru_device.insert(
- len, " AES0=6"); // AES1=0x82 AES2=0x00 AES3=0x01");
+ passthru_device =
+ passthru_device.insert(len, " " + iecarg2);
}
}
}
else if (passthru_device.toLower() == "default")
passthru_device = main_device;
+ else
+ m_discretedigital = true;
InitSettings(settings);
if (settings.init)
@@ -110,9 +123,12 @@ int AudioOutputALSA::TryOpenDevice(int open_mode, int try_ac3)
VBAUDIO(QString("OpenDevice %1 for passthrough").arg(passthru_device));
err = snd_pcm_open(&pcm_handle, dev_ba.constData(),
SND_PCM_STREAM_PLAYBACK, open_mode);
+
m_lastdevice = passthru_device;
- if (!m_autopassthrough)
+
+ if (m_discretedigital)
return err;
+
if (err < 0)
{
VBAUDIO(QString("Auto setting passthrough failed (%1), defaulting "
@@ -266,7 +282,7 @@ bool AudioOutputALSA::IncPreallocBufferSize(int requested, int buffer_time)
return ret;
}
-AudioOutputSettings* AudioOutputALSA::GetOutputSettings()
+AudioOutputSettings* AudioOutputALSA::GetOutputSettings(bool passthrough)
{
snd_pcm_hw_params_t *params;
snd_pcm_format_t afmt = SND_PCM_FORMAT_UNKNOWN;
@@ -282,7 +298,7 @@ AudioOutputSettings* AudioOutputALSA::GetOutputSettings()
pcm_handle = NULL;
}
- if((err = TryOpenDevice(OPEN_FLAGS, passthru || enc)) < 0)
+ if ((err = TryOpenDevice(OPEN_FLAGS, passthrough)) < 0)
{
AERROR(QString("snd_pcm_open(\"%1\")").arg(m_lastdevice));
delete settings;
@@ -294,7 +310,7 @@ AudioOutputSettings* AudioOutputALSA::GetOutputSettings()
if ((err = snd_pcm_hw_params_any(pcm_handle, params)) < 0)
{
snd_pcm_close(pcm_handle);
- if((err = TryOpenDevice(OPEN_FLAGS&FILTER_FLAGS, passthru || enc)) < 0)
+ if ((err = TryOpenDevice(OPEN_FLAGS&FILTER_FLAGS, passthrough)) < 0)
{
AERROR(QString("snd_pcm_open(\"%1\")").arg(m_lastdevice));
delete settings;
@@ -337,12 +353,13 @@ AudioOutputSettings* AudioOutputALSA::GetOutputSettings()
snd_pcm_close(pcm_handle);
pcm_handle = NULL;
- // Check if name or description contains information
- // to know if device can accept passthrough or not
+
+ /* Check if name or description contains information
+ to know if device can accept passthrough or not */
QMap<QString, QString> *alsadevs = GetALSADevices("pcm");
while(1)
{
- QString real_device = (((passthru || enc) && !m_autopassthrough) ?
+ QString real_device = (((passthru || enc) && m_discretedigital) ?
passthru_device : main_device);
QString desc = alsadevs->value(real_device);
@@ -386,7 +403,7 @@ bool AudioOutputALSA::OpenDevice()
if (pcm_handle != NULL)
CloseDevice();
- if ((err = TryOpenDevice(0, passthru || enc)) < 0)
+ if ((err = TryOpenDevice(0, passthru || enc)) < 0)
{
AERROR(QString("snd_pcm_open(\"%1\")").arg(m_lastdevice));
if (pcm_handle)
@@ -448,7 +465,7 @@ void AudioOutputALSA::CloseDevice()
template <class AudioDataType>
static inline void _ReorderSmpteToAlsa(AudioDataType *buf, uint frames,
- uint extrach)
+ uint extrach)
{
AudioDataType tmpC, tmpLFE, *buf2;
@@ -467,7 +484,7 @@ static inline void _ReorderSmpteToAlsa(AudioDataType *buf, uint frames,
}
static inline void ReorderSmpteToAlsa(void *buf, uint frames,
- AudioFormat format, uint extrach)
+ AudioFormat format, uint extrach)
{
switch(AudioOutputSettings::FormatToBits(format))
{
@@ -489,11 +506,11 @@ void AudioOutputALSA::WriteAudio(uchar *aubuf, int size)
return;
}
- /* Audio received is using SMPTE channel ordering
- * ALSA uses its own channel order.
- * Do not re-order passthu audio */
+ //Audio received is in SMPTE channel order, reorder to ALSA unless passthru
if (!passthru && (channels == 6 || channels == 8))
+ {
ReorderSmpteToAlsa(aubuf, frames, output_format, channels - 6);
+ }
VERBOSE(VB_AUDIO+VB_TIMESTAMP,
QString("WriteAudio: Preparing %1 bytes (%2 frames)")
@@ -589,7 +606,7 @@ int AudioOutputALSA::GetBufferedOnSoundcard(void) const
return delay;
}
-/*
+/**
* Set the various ALSA audio parameters.
* Returns:
* < 0 : an error occurred
@@ -667,9 +684,8 @@ int AudioOutputALSA::SetParameters(snd_pcm_t *handle, snd_pcm_format_t format,
&buffer_time, &dir);
CHECKERR(QString("Unable to set buffer time %1").arg(buffer_time));
- // See if we need to increase the prealloc'd buffer size
- // If buffer_time is too small we could underrun
- // Make 10% leeway okay
+ /* See if we need to increase the prealloc'd buffer size
+ If buffer_time is too small we could underrun - make 10% difference ok */
if ((buffer_time * 1.10f < (float)original_buffer_time) && pbufsize < 0)
{
VBAUDIO(QString("Requested %1us got %2 buffer time")
View
3  mythtv/libs/libmyth/audio/audiooutputalsa.h
@@ -28,7 +28,7 @@ class AudioOutputALSA : public AudioOutputBase
virtual void CloseDevice(void);
virtual void WriteAudio(uchar *aubuf, int size);
virtual int GetBufferedOnSoundcard(void) const;
- AudioOutputSettings* GetOutputSettings(void);
+ AudioOutputSettings* GetOutputSettings(bool passthrough = false);
private:
int TryOpenDevice(int open_mode, int try_ac3);
@@ -46,7 +46,6 @@ class AudioOutputALSA : public AudioOutputBase
int pbufsize;
int m_card, m_device, m_subdevice;
QMutex killAudioLock;
- bool m_autopassthrough;
QString m_lastdevice;
struct {
View
405 mythtv/libs/libmyth/audio/audiooutputbase.cpp
@@ -17,6 +17,7 @@
#include "audiooutputdownmix.h"
#include "SoundTouch.h"
#include "freesurround.h"
+#include "spdifencoder.h"
#define LOC QString("AO: ")
#define LOC_ERR QString("AO, ERROR: ")
@@ -53,7 +54,7 @@ AudioOutputBase::AudioOutputBase(const AudioSettings &settings) :
main_device(settings.GetMainDevice()),
passthru_device(settings.GetPassthruDevice()),
- passthru(false),
+ m_discretedigital(false), passthru(false),
enc(false), reenc(false),
stretchfactor(1.0f),
eff_stretchfactor(100000),
@@ -68,6 +69,7 @@ AudioOutputBase::AudioOutputBase(const AudioSettings &settings) :
// private
output_settingsraw(NULL), output_settings(NULL),
+ output_settingsdigitalraw(NULL), output_settingsdigital(NULL),
need_resampler(false), src_ctx(NULL),
pSoundStretch(NULL),
@@ -95,7 +97,9 @@ AudioOutputBase::AudioOutputBase(const AudioSettings &settings) :
memory_corruption_test1(0xdeadbeef),
src_out(NULL), kAudioSRCOutputSize(0),
memory_corruption_test2(0xdeadbeef),
- memory_corruption_test3(0xdeadbeef)
+ memory_corruption_test3(0xdeadbeef),
+ m_configure_succeeded(true),m_length_last_data(0),
+ m_spdifenc(NULL)
{
src_in = (float *)AOALIGN(src_in_buf);
memset(&src_data, 0, sizeof(SRC_DATA));
@@ -131,6 +135,11 @@ AudioOutputBase::~AudioOutputBase()
// We got this from a subclass, delete it
delete output_settings;
delete output_settingsraw;
+ if (output_settings != output_settingsdigital)
+ {
+ delete output_settingsdigital;
+ delete output_settingsdigitalraw;
+ }
if (kAudioSRCOutputSize > 0)
delete[] src_out;
@@ -149,13 +158,15 @@ void AudioOutputBase::InitSettings(const AudioSettings &settings)
// this was likely provided by the AudioTest utility
output_settings = new AudioOutputSettings;
*output_settings = *settings.custom;
+ output_settingsdigital = output_settings;
max_channels = output_settings->BestSupportedChannels();
configured_channels = max_channels;
return;
}
// Ask the subclass what we can send to the device
- output_settings = GetOutputSettingsUsers();
+ output_settings = GetOutputSettingsUsers(false);
+ output_settingsdigital = GetOutputSettingsUsers(true);
max_channels = output_settings->BestSupportedChannels();
configured_channels = max_channels;
@@ -174,21 +185,29 @@ void AudioOutputBase::InitSettings(const AudioSettings &settings)
* amended to take into account the digital audio
* options (AC3, DTS, E-AC3 and TrueHD)
*/
-AudioOutputSettings* AudioOutputBase::GetOutputSettingsCleaned(void)
+AudioOutputSettings* AudioOutputBase::GetOutputSettingsCleaned(bool digital)
{
// If we've already checked the port, use the cache
// version instead
- if (output_settingsraw)
- return output_settingsraw;
-
- AudioOutputSettings* aosettings = GetOutputSettings();
+ if (!m_discretedigital || !digital)
+ {
+ digital = false;
+ if (output_settingsraw)
+ return output_settingsraw;
+ }
+ else if (output_settingsdigitalraw)
+ return output_settingsdigitalraw;
+ AudioOutputSettings* aosettings = GetOutputSettings(digital);
if (aosettings)
aosettings->GetCleaned();
else
aosettings = new AudioOutputSettings(true);
- return (output_settingsraw = aosettings);
+ if (digital)
+ return (output_settingsdigitalraw = aosettings);
+ else
+ return (output_settingsraw = aosettings);
}
/**
@@ -196,36 +215,46 @@ AudioOutputSettings* AudioOutputBase::GetOutputSettingsCleaned(void)
* amended to take into account the digital audio
* options (AC3, DTS, E-AC3 and TrueHD) as well as the user settings
*/
-AudioOutputSettings* AudioOutputBase::GetOutputSettingsUsers(void)
+AudioOutputSettings* AudioOutputBase::GetOutputSettingsUsers(bool digital)
{
- if (output_settings)
- return output_settings;
+ if (!m_discretedigital || !digital)
+ {
+ digital = false;
+ if (output_settings)
+ return output_settings;
+ }
+ else if (output_settingsdigital)
+ return output_settingsdigital;
AudioOutputSettings* aosettings = new AudioOutputSettings;
- *aosettings = *GetOutputSettingsCleaned();
+ *aosettings = *GetOutputSettingsCleaned(digital);
aosettings->GetUsers();
- return (output_settings = aosettings);
+ if (digital)
+ return (output_settingsdigital = aosettings);
+ else
+ return (output_settings = aosettings);
}
/**
* Test if we can output digital audio and if sample rate is supported
*/
-bool AudioOutputBase::CanPassthrough(int samplerate, int channels) const
+bool AudioOutputBase::CanPassthrough(int samplerate, int channels,
+ int codec) const
{
bool ret = false;
- ret = output_settings->IsSupportedFormat(FORMAT_S16);
- ret &= output_settings->IsSupportedRate(samplerate);
+ ret = output_settingsdigital->IsSupportedFormat(FORMAT_S16);
+ ret &= output_settingsdigital->IsSupportedRate(samplerate);
// Don't know any cards that support spdif clocked at < 44100
// Some US cable transmissions have 2ch 32k AC-3 streams
ret &= samplerate >= 44100;
// Will passthrough if surround audio was defined. Amplifier will
// do the downmix if required
- ret &= max_channels >= 6;
+ ret &= max_channels >= 6 && channels > 2;
// Stereo content will always be decoded so it can later be upmixed
// unless audio is configured for stereoo
- ret |= channels == 2 && max_channels == 2;
+ ret |= max_channels == 2;
return ret;
}
@@ -239,7 +268,7 @@ void AudioOutputBase::SetSourceBitrate(int rate)
source_bitrate = rate;
}
-/*
+/**
* Set the timestretch factor
*
* You must hold the audio_buflock to call this safely
@@ -313,6 +342,119 @@ bool AudioOutputBase::ToggleUpmix(void)
return configured_channels == max_channels;
}
+/*
+ * Setup samplerate and number of channels for passthrough
+ * Create SPDIF encoder and true if successful
+ */
+bool AudioOutputBase::SetupPassthrough(int codec, int codec_profile,
+ int &samplerate_tmp, int &channels_tmp)
+{
+ channels_tmp = 2;
+ QString log;
+
+ switch (codec)
+ {
+ case CODEC_ID_AC3:
+ log = "AC3";
+ break;
+ case CODEC_ID_EAC3:
+ samplerate_tmp = samplerate_tmp * 4;
+ log = "Dolby Digital Plus (E-AC3)";
+ break;
+ case CODEC_ID_DTS:
+ switch(codec_profile)
+ {
+ case FF_PROFILE_DTS_ES:
+ log = "DTS-ES";
+ break;
+ case FF_PROFILE_DTS_96_24:
+ log = "DTS 96/24";
+ break;
+ case FF_PROFILE_DTS_HD_HRA:
+ case FF_PROFILE_DTS_HD_MA:
+ samplerate_tmp = 192000;
+ if (output_settingsdigital->GetMaxHDRate() == 768000)
+ {
+ log = "DTS-HD MA";
+ channels_tmp = 8;
+ }
+ else
+ {
+ log = "DTS-HD High-Res";
+ }
+ break;
+ case FF_PROFILE_DTS:
+ default:
+ log = "DTS Core";
+ break;
+ }
+ break;
+ case CODEC_ID_TRUEHD:
+ channels_tmp = 8;
+ log = "TrueHD";
+ switch(samplerate_tmp)
+ {
+ case 48000:
+ case 96000:
+ case 192000:
+ samplerate_tmp = 192000;
+ break;
+ case 44100:
+ case 88200:
+ case 176400:
+ samplerate_tmp = 176400;
+ break;
+ default:
+ VBAUDIO("TrueHD: Unsupported samplerate");
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ VBAUDIO("Setting " + log + " passthrough");
+
+ if (m_spdifenc)
+ {
+ delete m_spdifenc;
+ }
+
+ m_spdifenc = new SPDIFEncoder("spdif", codec);
+ if (m_spdifenc->Succeeded() && codec == CODEC_ID_DTS)
+ {
+ switch(codec_profile)
+ {
+ case FF_PROFILE_DTS:
+ case FF_PROFILE_DTS_ES:
+ case FF_PROFILE_DTS_96_24:
+ m_spdifenc->SetMaxHDRate(0);
+ break;
+ case FF_PROFILE_DTS_HD_HRA:
+ m_spdifenc->SetMaxHDRate(
+ OutputSettings(true)->canFeature(FEATURE_DTSHD) ?
+ 192000 : 0);
+ break;
+ case FF_PROFILE_DTS_HD_MA:
+ m_spdifenc->SetMaxHDRate(OutputSettings(true)->GetMaxHDRate());
+ }
+ }
+
+ if (!m_spdifenc->Succeeded())
+ {
+ delete m_spdifenc;
+ m_spdifenc = NULL;
+ return false;
+ }
+ return true;
+}
+
+AudioOutputSettings *AudioOutputBase::OutputSettings(bool digital)
+{
+ if (digital)
+ return output_settingsdigital;
+ return output_settings;
+}
+
/**
* (Re)Configure AudioOutputBase
*
@@ -353,7 +495,7 @@ void AudioOutputBase::Reconfigure(const AudioSettings &orig_settings)
/* Might we reencode a bitstream that's been decoded for timestretch?
If the device doesn't support the number of channels - see below */
- if (output_settings->canAC3() &&
+ if (output_settingsdigital->canFeature(FEATURE_AC3) &&
(settings.codec == CODEC_ID_AC3 || settings.codec == CODEC_ID_DTS))
{
lreenc = true;
@@ -380,13 +522,27 @@ void AudioOutputBase::Reconfigure(const AudioSettings &orig_settings)
ClearError();
+ bool general_deps = true;
+
+ /* Set samplerate_tmp and channels_tmp to appropriate values
+ if passing through */
+ int samplerate_tmp, channels_tmp;
+ if (settings.use_passthru)
+ {
+ samplerate_tmp = settings.samplerate;
+ SetupPassthrough(settings.codec, settings.codec_profile,
+ samplerate_tmp, channels_tmp);
+ general_deps = samplerate == samplerate_tmp && channels == channels_tmp;
+ }
+
// Check if anything has changed
- bool general_deps = settings.format == format &&
- settings.samplerate == source_samplerate &&
- settings.use_passthru == passthru &&
- lneeds_upmix == needs_upmix && lreenc == reenc &&
- lsource_channels == source_channels &&
- lneeds_downmix == needs_downmix;
+ general_deps &=
+ settings.format == format &&
+ settings.samplerate == source_samplerate &&
+ settings.use_passthru == passthru &&
+ lneeds_upmix == needs_upmix && lreenc == reenc &&
+ lsource_channels == source_channels &&
+ lneeds_downmix == needs_downmix;
if (general_deps)
{
@@ -437,20 +593,16 @@ void AudioOutputBase::Reconfigure(const AudioSettings &orig_settings)
and we have more than 2 channels but multichannel PCM is not supported
or if the device just doesn't support the number of channels */
enc = (!passthru &&
- output_settings->IsSupportedFormat(FORMAT_S16) &&
- output_settings->canAC3() &&
- ((!output_settings->canLPCM() && configured_channels > 2) ||
+ output_settingsdigital->canFeature(FEATURE_AC3) &&
+ ((!output_settings->canFeature(FEATURE_LPCM) &&
+ configured_channels > 2) ||
!output_settings->IsSupportedChannels(channels)));
- VBAUDIO(QString("enc(%1), passthru(%2), canAC3(%3), canDTS(%4), canHD(%5), "
- "canHDLL(%6), canLPCM(%7), "
- "configured_channels(%8), %9 channels supported(%10)")
+
+ VBAUDIO(QString("enc(%1), passthru(%2), features (%3) "
+ "configured_channels(%4), %5 channels supported(%6)")
.arg(enc)
.arg(passthru)
- .arg(output_settings->canAC3())
- .arg(output_settings->canDTS())
- .arg(output_settings->canHD())
- .arg(output_settings->canHDLL())
- .arg(output_settings->canLPCM())
+ .arg(output_settingsdigital->FeaturesToString())
.arg(configured_channels)
.arg(channels)
.arg(output_settings->IsSupportedChannels(channels)));
@@ -461,7 +613,7 @@ void AudioOutputBase::Reconfigure(const AudioSettings &orig_settings)
// or if 48k override was checked in settings
if ((samplerate != 48000 &&
gCoreContext->GetNumSetting("Audio48kOverride", false)) ||
- (enc && (samplerate > 48000 || (need_resampler && dest_rate > 48000))))
+ (enc && (samplerate > 48000 || (need_resampler && dest_rate > 48000))))
{
VBAUDIO("Forcing resample to 48 kHz");
if (src_quality < 0)
@@ -469,8 +621,11 @@ void AudioOutputBase::Reconfigure(const AudioSettings &orig_settings)
need_resampler = true;
dest_rate = 48000;
}
- else if ((need_resampler = !output_settings->IsSupportedRate(samplerate)))
- dest_rate = output_settings->NearestSupportedRate(samplerate);
+ else if (
+ (need_resampler = !OutputSettings(enc)->IsSupportedRate(samplerate)))
+ {
+ dest_rate = OutputSettings(enc)->NearestSupportedRate(samplerate);
+ }
if (need_resampler && src_quality > QUALITY_DISABLED)
{
@@ -525,40 +680,16 @@ void AudioOutputBase::Reconfigure(const AudioSettings &orig_settings)
delete encoder;
encoder = NULL;
enc = false;
+ // upmixing will fail if we needed the encoder
+ needs_upmix = false;
}
}
if (passthru)
{
- switch (settings.codec)
- {
- case CODEC_ID_EAC3:
- samplerate *= 4;
- case CODEC_ID_AC3:
- case CODEC_ID_DTS:
- channels = 2;
- break;
- case CODEC_ID_TRUEHD:
- channels = 8;
- switch(samplerate)
- {
- case 48000:
- case 96000:
- case 192000:
- samplerate = 192000;
- break;
- case 44100:
- case 88200:
- case 176400:
- samplerate = 176400;
- break;
- default:
- VBAUDIO("TrueHD: Unsupported samplerate");
- break;
- }
- break;
- }
- //AC3, DTS, DTS-HD MA and TrueHD use 16 bits samples
+ //AC3, DTS, DTS-HD MA and TrueHD all use 16 bits samples
+ channels = channels_tmp;
+ samplerate = samplerate_tmp;
format = output_format = FORMAT_S16;
source_bytes_per_frame = channels *
output_settings->SampleSize(format);
@@ -573,7 +704,7 @@ void AudioOutputBase::Reconfigure(const AudioSettings &orig_settings)
if (need_resampler || needs_upmix || needs_downmix ||
stretchfactor != 1.0f || (internal_vol && SWVolume()) ||
(enc && output_format != FORMAT_S16) ||
- !output_settings->IsSupportedFormat(output_format))
+ !OutputSettings(enc)->IsSupportedFormat(output_format))
{
VBAUDIO("Audio processing enabled");
processing = true;
@@ -597,6 +728,10 @@ void AudioOutputBase::Reconfigure(const AudioSettings &orig_settings)
.arg(main_device).arg(channels).arg(source_channels).arg(samplerate)
.arg(output_settings->FormatToString(output_format)).arg(reenc));
+ audbuf_timecode = audiotime = frames_buffered = 0;
+ current_seconds = source_bitrate = -1;
+ effdsp = samplerate * 100;
+
// Actually do the device specific open call
if (!OpenDevice())
{
@@ -604,9 +739,12 @@ void AudioOutputBase::Reconfigure(const AudioSettings &orig_settings)
Error("Aborting reconfigure");
else
VBGENERAL("Aborting reconfigure");
+ m_configure_succeeded = false;
return;
}
+ VBAUDIO(QString("Audio fragment size: %1").arg(fragment_size));
+
// Only used for software volume
if (set_initial_vol && internal_vol && SWVolume())
{
@@ -620,12 +758,6 @@ void AudioOutputBase::Reconfigure(const AudioSettings &orig_settings)
VolumeBase::SyncVolume();
VolumeBase::UpdateVolume();
- VBAUDIO(QString("Audio fragment size: %1").arg(fragment_size));
-
- audbuf_timecode = audiotime = frames_buffered = 0;
- current_seconds = source_bitrate = -1;
- effdsp = samplerate * 100;
-
// Upmix Stereo to 5.1
if (needs_upmix && source_channels == 2 && configured_channels > 2)
{
@@ -650,6 +782,8 @@ void AudioOutputBase::Reconfigure(const AudioSettings &orig_settings)
if (unpause_when_ready)
pauseaudio = actually_paused = true;
+ m_configure_succeeded = true;
+
StartOutputThread();
VBAUDIO("Ending Reconfigure()");
@@ -761,12 +895,12 @@ void AudioOutputBase::Reset()
* Set the timecode of the samples most recently added to the audiobuffer
*
* Used by mythmusic for seeking since it doesn't provide timecodes to
- * AddFrames()
+ * AddData()
*/
void AudioOutputBase::SetTimecode(int64_t timecode)
{
audbuf_timecode = audiotime = timecode;
- frames_buffered = (timecode * (int64_t)source_samplerate) / 1000LL;
+ frames_buffered = (timecode * source_samplerate) / 1000;
}
/**
@@ -823,10 +957,10 @@ int AudioOutputBase::audioready()
*/
int64_t AudioOutputBase::GetAudiotime(void)
{
- if (audbuf_timecode == 0LL)
- return 0LL;
+ if (audbuf_timecode == 0 || !m_configure_succeeded)
+ return 0;
- int64_t obpf = (int64_t)output_bytes_per_frame;
+ int obpf = output_bytes_per_frame;
int64_t oldaudiotime;
/* We want to calculate 'audiotime', which is the timestamp of the audio
@@ -845,21 +979,21 @@ int64_t AudioOutputBase::GetAudiotime(void)
QMutexLocker lockav(&avsync_lock);
- int64_t soundcard_buffer = (int64_t)GetBufferedOnSoundcard(); // bytes
- int64_t main_buffer =(int64_t)audioready();
+ int soundcard_buffer = GetBufferedOnSoundcard(); // bytes
/* audioready tells us how many bytes are in audiobuffer
scaled appropriately if output format != internal format */
+ int main_buffer = audioready();
oldaudiotime = audiotime;
/* timecode is the stretch adjusted version
of major post-stretched buffer contents
- processing latencies are catered for in AddFrames/SetAudiotime
+ processing latencies are catered for in AddData/SetAudiotime
to eliminate race */
audiotime = audbuf_timecode - (
- ((main_buffer + soundcard_buffer) * (int64_t)eff_stretchfactor ) /
- ((int64_t)effdsp * obpf));
+ ((int64_t)(main_buffer + soundcard_buffer) * eff_stretchfactor) /
+ (effdsp * obpf));
/* audiotime should never go backwards, but we might get a negative
value if GetBufferedOnSoundcard() isn't updated by the driver very
@@ -885,43 +1019,43 @@ int64_t AudioOutputBase::GetAudiotime(void)
/**
* Set the timecode of the top of the ringbuffer
* Exclude all other processing elements as they dont vary
- * between AddFrames calls
+ * between AddData calls
*/
void AudioOutputBase::SetAudiotime(int frames, int64_t timecode)
{
- int64_t processframes_stretched = 0LL;
- int64_t processframes_unstretched = 0LL;
- int64_t old_audbuf_timecode = audbuf_timecode;
+ int64_t processframes_stretched = 0;
+ int64_t processframes_unstretched = 0;
+ int64_t old_audbuf_timecode = audbuf_timecode;
+
+ if (!m_configure_succeeded)
+ return;
if (needs_upmix && upmixer)
- processframes_unstretched -= (int64_t)upmixer->frameLatency();
+ processframes_unstretched -= upmixer->frameLatency();
if (pSoundStretch)
{
- processframes_unstretched -=
- (int64_t)pSoundStretch->numUnprocessedSamples();
- processframes_stretched -=
- (int64_t)pSoundStretch->numSamples();
+ processframes_unstretched -= pSoundStretch->numUnprocessedSamples();
+ processframes_stretched -= pSoundStretch->numSamples();
}
if (encoder)
{
// the input buffered data is still in audio_bytes_per_sample format
processframes_stretched -=
- (int64_t)(encoder->Buffered() / output_bytes_per_frame);
+ encoder->Buffered() / output_bytes_per_frame;
}
audbuf_timecode =
- timecode + (
- ((int64_t)frames + processframes_unstretched * 100000LL) +
- (processframes_stretched * (int64_t)eff_stretchfactor)
- ) / (int64_t)effdsp;
+ timecode + ((frames + processframes_unstretched * 100000) +
+ (processframes_stretched * eff_stretchfactor)
+ ) / effdsp;
// check for timecode wrap and reset audiotime if detected
// timecode will always be monotonic asc if not seeked and reset
// happens if seek or pause happens
if (audbuf_timecode < old_audbuf_timecode)
- audiotime = 0LL;
+ audiotime = 0;
VBAUDIOTS(QString("SetAudiotime atc=%1 tc=%2 f=%3 pfu=%4 pfs=%5")
.arg(audbuf_timecode)
@@ -941,10 +1075,10 @@ void AudioOutputBase::SetAudiotime(int frames, int64_t timecode)
*/
int64_t AudioOutputBase::GetAudioBufferedTime(void)
{
- int64_t ret = audbuf_timecode - (int64_t)GetAudiotime();
+ int64_t ret = audbuf_timecode - GetAudiotime();
// Pulse can give us values that make this -ve
- if (ret < 0LL)
- return 0LL;
+ if (ret < 0)
+ return 0;
return ret;
}
@@ -1003,7 +1137,7 @@ int AudioOutputBase::CheckFreeSpace(int &frames)
return len;
}
-/*
+/**
* Copy frames into the audiobuffer, upmixing en route if necessary
*
* Returns the number of frames written, which may be less than requested
@@ -1095,19 +1229,34 @@ int AudioOutputBase::CopyWithUpmix(char *buffer, int frames, int &org_waud)
bool AudioOutputBase::AddFrames(void *in_buffer, int in_frames,
int64_t timecode)
{
- int org_waud = waud, afree = audiofree();
- int frames = in_frames;
+ return AddData(in_buffer, in_frames * source_bytes_per_frame, timecode);
+}
+
+/**
+ * Add data to the audiobuffer and perform any required processing
+ *
+ * Returns false if there's not enough space right now
+ */
+bool AudioOutputBase::AddData(void *in_buffer, int in_len,
+ int64_t timecode)
+{
+ int org_waud = waud;
+ int afree = audiofree();
+ int frames = in_len / source_bytes_per_frame;
void *buffer = in_buffer;
int bpf = bytes_per_frame;
- int len = frames * source_bytes_per_frame;
+ int len = in_len;
int used = kAudioRingBufferSize - afree;
bool music = false;
int bdiff;
- VBAUDIOTS(QString("AddFrames frames=%1, bytes=%2, used=%3, free=%4, "
- "timecode=%5 needsupmix=%6")
- .arg(frames).arg(len).arg(used).arg(afree).arg(timecode)
- .arg(needs_upmix));
+ if (!m_configure_succeeded)
+ {
+ VERBOSE(VB_IMPORTANT, LOC + "AddData called with audio framework not "
+ "initialised");
+ m_length_last_data = 0;
+ return false;
+ }
/* See if we're waiting for new samples to be buffered before we unpause
post channel change, seek, etc. Wait for 4 fragments to be buffered */
@@ -1117,6 +1266,28 @@ bool AudioOutputBase::AddFrames(void *in_buffer, int in_frames,
Pause(false);
}
+ if (passthru && m_spdifenc)
+ {
+ // mux into an IEC958 packet
+ m_spdifenc->WriteFrame((unsigned char *)in_buffer, len);
+ len = m_spdifenc->GetProcessedSize();
+ if (len > 0)
+ {
+ buffer = in_buffer = m_spdifenc->GetProcessedBuffer();
+ m_spdifenc->Reset();
+ frames = len / source_bytes_per_frame;
+ }
+ else
+ frames = 0;
+ }
+ m_length_last_data = (int64_t)
+ ((double)(len * 1000) / (source_samplerate * source_bytes_per_frame));
+
+ VBAUDIOTS(QString("AddData frames=%1, bytes=%2, used=%3, free=%4, "
+ "timecode=%5 needsupmix=%6")
+ .arg(frames).arg(len).arg(used).arg(afree).arg(timecode)
+ .arg(needs_upmix));
+
// Don't write new samples if we're resetting the buffer or reconfiguring
QMutexLocker lock(&audio_buflock);
@@ -1124,8 +1295,8 @@ bool AudioOutputBase::AddFrames(void *in_buffer, int in_frames,
if (timecode < 0)
{
// Send original samples to mythmusic visualisation
- timecode = (frames_buffered * 1000LL) / (int64_t)source_samplerate;
- frames_buffered += (int64_t)frames;
+ timecode = (frames_buffered * 1000) / source_samplerate;
+ frames_buffered += frames;
dispatchVisual((uchar *)in_buffer, len, timecode, source_channels,
output_settings->FormatToBits(format));
music = true;
@@ -1158,11 +1329,11 @@ bool AudioOutputBase::AddFrames(void *in_buffer, int in_frames,
if (len > afree)
{
- VBAUDIOTS("Buffer is full, AddFrames returning false");
+ VBAUDIOTS("Buffer is full, AddData returning false");
return false; // would overflow
}
- int frames_remaining = in_frames;
+ int frames_remaining = frames;
int frames_final = 0;
int maxframes = (kAudioSRCInputSize /
(passthru ? channels : source_channels)) & ~0xf;
View
59 mythtv/libs/libmyth/audio/audiooutputbase.h
@@ -43,14 +43,17 @@ class AsyncLooseLock
int tail;
};
+// Forward declaration of SPDIF encoder
+class SPDIFEncoder;
+
class AudioOutputBase : public AudioOutput, public QThread
{
public:
AudioOutputBase(const AudioSettings &settings);
virtual ~AudioOutputBase();
- AudioOutputSettings* GetOutputSettingsCleaned(void);
- AudioOutputSettings* GetOutputSettingsUsers(void);
+ AudioOutputSettings* GetOutputSettingsCleaned(bool digital = true);
+ AudioOutputSettings* GetOutputSettingsUsers(bool digital = false);
// reconfigure sound out for new params
virtual void Reconfigure(const AudioSettings &settings);
@@ -65,7 +68,7 @@ class AudioOutputBase : public AudioOutput, public QThread
virtual AudioFormat GetFormat(void) const { return format; };
virtual int GetBytesPerFrame(void) const { return source_bytes_per_frame; };
- virtual bool CanPassthrough(int samplerate, int channels) const;
+ virtual bool CanPassthrough(int samplerate, int channels, int codec) const;
virtual bool ToggleUpmix(void);
virtual void Reset(void);
@@ -75,6 +78,8 @@ class AudioOutputBase : public AudioOutput, public QThread
// timecode is in milliseconds.
virtual bool AddFrames(void *buffer, int frames, int64_t timecode);
+ virtual bool AddData(void *buffer, int len, int64_t timecode);
+ virtual int64_t LengthLastData(void) { return m_length_last_data; }
virtual void SetTimecode(int64_t timecode);
virtual bool IsPaused(void) const { return actually_paused; }
@@ -111,15 +116,15 @@ class AudioOutputBase : public AudioOutput, public QThread
virtual bool OpenDevice(void) = 0;
virtual void CloseDevice(void) = 0;
virtual void WriteAudio(uchar *aubuf, int size) = 0;
- /*
+ /**
* Return the size in bytes of frames currently in the audio buffer adjusted
* with the audio playback latency
*/
virtual int GetBufferedOnSoundcard(void) const = 0;
// Default implementation only supports 2ch s16le at 48kHz
- virtual AudioOutputSettings* GetOutputSettings(void)
+ virtual AudioOutputSettings* GetOutputSettings(bool digital = false)
{ return new AudioOutputSettings; }
- /// You need to call this from any implementation in the dtor.
+ // You need to call this from any implementation in the dtor.
void KillAudio(void);
// The following functions may be overridden, but don't need to be
@@ -153,11 +158,13 @@ class AudioOutputBase : public AudioOutput, public QThread
AudioFormat format;
AudioFormat output_format;
int samplerate;
+ int bitrate;
int effdsp; // from the recorded stream (NuppelVideo)
int fragment_size;
long soundcard_buffer_size;
QString main_device, passthru_device;
+ bool m_discretedigital;
bool passthru, enc, reenc;
@@ -176,10 +183,15 @@ class AudioOutputBase : public AudioOutput, public QThread
int src_quality;
private:
+ bool SetupPassthrough(int codec, int codec_profile,
+ int &samplerate_tmp, int &channels_tmp);
+ AudioOutputSettings* OutputSettings(bool digital = true);
int CopyWithUpmix(char *buffer, int frames, int &org_waud);
void SetAudiotime(int frames, int64_t timecode);
AudioOutputSettings *output_settingsraw;
AudioOutputSettings *output_settings;
+ AudioOutputSettings *output_settingsdigitalraw;
+ AudioOutputSettings *output_settingsdigital;
bool need_resampler;
SRC_STATE *src_ctx;
soundtouch::SoundTouch *pSoundStretch;
@@ -203,20 +215,30 @@ class AudioOutputBase : public AudioOutput, public QThread
bool audio_thread_exists;
- /* Writes to the audiobuffer, reconfigures and audiobuffer resets can only
- take place while holding this lock */
+ /**
+ * Writes to the audiobuffer, reconfigures and audiobuffer resets can only
+ * take place while holding this lock
+ */
QMutex audio_buflock;
- /** must hold avsync_lock to read or write 'audiotime' and
- 'audiotime_updated' */
+ /**
+ * must hold avsync_lock to read or write 'audiotime' and
+ * 'audiotime_updated'
+ */
QMutex avsync_lock;
- // timecode of audio leaving the soundcard (same units as timecodes)
+ /**
+ * timecode of audio leaving the soundcard (same units as timecodes)
+ */
int64_t audiotime;
- /* Audio circular buffer */
- int raud, waud; /* read and write positions */
- // timecode of audio most recently placed into buffer
+ /**
+ * Audio circular buffer
+ */
+ int raud, waud; // read and write positions
+ /**
+ * timecode of audio most recently placed into buffer
+ */
int64_t audbuf_timecode;
AsyncLooseLock reset_active;
@@ -235,9 +257,16 @@ class AudioOutputBase : public AudioOutput, public QThread
float *src_out;
int kAudioSRCOutputSize;
uint memory_corruption_test2;
- /** main audio buffer */
+ /**
+ * main audio buffer
+ */
uchar audiobuffer[kAudioRingBufferSize];
uint memory_corruption_test3;
+ uint m_configure_succeeded;
+ int64_t m_length_last_data;
+
+ // SPDIF Encoder for digital passthrough
+ SPDIFEncoder *m_spdifenc;
};
#endif
View
7 mythtv/libs/libmyth/audio/audiooutputdigitalencoder.cpp
@@ -94,11 +94,12 @@ bool AudioOutputDigitalEncoder::Init(
delete m_spdifenc;
}
- m_spdifenc = new SPDIFEncoder("spdif", av_context);
+ m_spdifenc = new SPDIFEncoder("spdif", CODEC_ID_AC3);
if (!m_spdifenc->Succeeded())
{
Dispose();
- delete m_spdifenc;
+ VERBOSE(VB_IMPORTANT, LOC_ERR +
+ "Could not create spdif muxer");
return false;
}
@@ -143,7 +144,7 @@ size_t AudioOutputDigitalEncoder::Encode(void *buf, int len, bool isFloat)
if (!m_spdifenc)
{
- m_spdifenc = new SPDIFEncoder("spdif", av_context);
+ m_spdifenc = new SPDIFEncoder("spdif", CODEC_ID_AC3);
}
m_spdifenc->WriteFrame(m_encodebuffer, outsize);
m_spdifenc->GetData(out + outlen, data_size);
View
16 mythtv/libs/libmyth/audio/audiooutputdx.cpp
@@ -77,7 +77,7 @@ class AudioOutputDXPrivate
FreeLibrary(dsound_dll);
}
- int InitDirectSound(void);
+ int InitDirectSound(bool passthrough = false);
void ResetDirectSound(void);
void DestroyDSBuffer(void);
void FillBuffer(unsigned char *buffer, int size);
@@ -110,6 +110,8 @@ AudioOutputDX::AudioOutputDX(const AudioSettings &settings) :
InitSettings(settings);
if (passthru_device == "auto" || passthru_device.toLower() == "default")
passthru_device = main_device;
+ else
+ m_discretedigital = true;
if (settings.init)
Reconfigure(settings);
}
@@ -179,7 +181,7 @@ void AudioOutputDXPrivate::ResetDirectSound(void)
device_list.clear();
}
-int AudioOutputDXPrivate::InitDirectSound(void)
+int AudioOutputDXPrivate::InitDirectSound(bool passthrough)
{
LPFNDSC OurDirectSoundCreate;
LPFNDSE OurDirectSoundEnumerate;
@@ -195,7 +197,7 @@ int AudioOutputDXPrivate::InitDirectSound(void)
}
if (parent) // parent can be NULL only when called from GetDXDevices()
- device_name = parent->m_UseSPDIF ?
+ device_name = passthrough ?
parent->passthru_device : parent->main_device;
device_name = device_name.section(':', 1);
device_num = device_name.toInt(&ok, 10);
@@ -378,13 +380,13 @@ bool AudioOutputDXPrivate::StartPlayback(void)
return true;
}
-AudioOutputSettings* AudioOutputDX::GetOutputSettings(void)
+AudioOutputSettings* AudioOutputDX::GetOutputSettings(bool passthrough)
{
AudioOutputSettings *settings = new AudioOutputSettings();
DSCAPS devcaps;
devcaps.dwSize = sizeof(DSCAPS);
- m_priv->InitDirectSound();
+ m_priv->InitDirectSound(passthrough);
if ((!m_priv->dsobject || !m_priv->dsound_dll) ||
FAILED(IDirectSound_GetCaps(m_priv->dsobject, &devcaps)) )
{
@@ -431,7 +433,7 @@ bool AudioOutputDX::OpenDevice(void)
CloseDevice();
m_UseSPDIF = passthru || enc;
- m_priv->InitDirectSound();
+ m_priv->InitDirectSound(m_UseSPDIF);
if (!m_priv->dsobject || !m_priv->dsound_dll)
{
Error("DirectSound initialization failed");
@@ -607,7 +609,7 @@ void AudioOutputDX::SetVolumeChannel(int channel, int volume)
QMap<int, QString> *AudioOutputDX::GetDXDevices(void)
{
AudioOutputDXPrivate *tmp_priv = new AudioOutputDXPrivate(NULL);
- tmp_priv->InitDirectSound();
+ tmp_priv->InitDirectSound(false);
QMap<int, QString> *dxdevs = new QMap<int, QString>(tmp_priv->device_list);
delete tmp_priv;
return dxdevs;
View
2  mythtv/libs/libmyth/audio/audiooutputdx.h
@@ -25,7 +25,7 @@ class AudioOutputDX : public AudioOutputBase
virtual void CloseDevice(void);
virtual void WriteAudio(unsigned char *buffer, int size);
virtual int GetBufferedOnSoundcard(void) const;
- AudioOutputSettings* GetOutputSettings(void);
+ AudioOutputSettings* GetOutputSettings(bool passthrough = false);
protected:
AudioOutputDXPrivate *m_priv;
View
138 mythtv/libs/libmyth/audio/audiooutputsettings.cpp
@@ -15,14 +15,14 @@ using namespace std;
#include "mythcorecontext.h"
extern "C" {
-#include "libavutil/avutil.h" // to check version of libavformat
+#include "libavutil/avutil.h" // to check version of libavformat
}
#define LOC QString("AO: ")
AudioOutputSettings::AudioOutputSettings(bool invalid) :
- m_passthrough(-1), m_AC3(false), m_DTS(false), m_LPCM(false),
- m_HD(false) , m_HDLL(false), m_invalid(invalid)
+ m_passthrough(-1), m_features(FEATURE_NONE),
+ m_invalid(invalid), m_has_eld(false)
{
m_sr.assign(srs, srs +
sizeof(srs) / sizeof(int));
@@ -52,11 +52,8 @@ AudioOutputSettings& AudioOutputSettings::operator=(
m_formats = rhs.m_formats;
m_channels = rhs.m_channels;
m_passthrough = rhs.m_passthrough;
- m_AC3 = rhs.m_AC3;
- m_DTS = rhs.m_DTS;
- m_LPCM = rhs.m_LPCM;
- m_HD = rhs.m_HD;
- m_HDLL = rhs.m_HDLL;
+ m_features = rhs.m_features;
+ m_has_eld = rhs.m_has_eld;
m_invalid = rhs.m_invalid;
m_sr_it = m_sr.begin() + (rhs.m_sr_it - rhs.m_sr.begin());
m_sf_it = m_sf.begin() + (rhs.m_sf_it - rhs.m_sf.begin());
@@ -251,6 +248,14 @@ void AudioOutputSettings::SetBestSupportedChannels(int channels)
m_channels.push_back(channels);
}
+void AudioOutputSettings::setFeature(bool val, DigitalFeature arg)
+{
+ if (val)
+ m_features |= arg;
+ else
+ m_features &= ~arg;
+};
+
/**
* Returns capabilities supported by the audio device
* amended to take into account the digital audio
@@ -274,20 +279,30 @@ AudioOutputSettings* AudioOutputSettings::GetCleaned(bool newcopy)
int mchannels = BestSupportedChannels();
- aosettings->m_LPCM = (mchannels > 2);
- // E-AC3 is transferred as sterep PCM at 4 times the rates
- // assume all amplifier supporting E-AC3 also supports 7.1 LPCM
- // as it's required under the bluray standard
-#if LIBAVFORMAT_VERSION_INT > AV_VERSION_INT( 52, 83, 0 )
- aosettings->m_HD = (mchannels == 8 && BestSupportedRate() == 192000);
- aosettings->m_HDLL = (mchannels == 8 && BestSupportedRate() == 192000);
-#endif
- if (mchannels == 2 && m_passthrough >= 0)
+ if (mchannels > 2)
{
- VERBOSE(VB_AUDIO, LOC + QString("may be AC3 or DTS capable"));
- aosettings->AddSupportedChannels(6);
+ aosettings->setFeature(FEATURE_LPCM);
+ }
+
+ if (IsSupportedFormat(FORMAT_S16))
+ {
+ // E-AC3 is transferred as stereo PCM at 4 times the rates
+ // assume all amplifier supporting E-AC3 also supports 7.1 LPCM
+ // as it's mandatory under the bluray standard
+//#if LIBAVFORMAT_VERSION_INT > AV_VERSION_INT( 52, 83, 0 )
+ if (IsSupportedChannels(8) && IsSupportedRate(192000))
+ aosettings->setFeature(FEATURE_TRUEHD | FEATURE_DTSHD | FEATURE_EAC3);
+//#endif
+ if (m_passthrough >= 0)
+ {
+ if (mchannels == 2)
+ {
+ VERBOSE(VB_AUDIO, LOC + QString("may be AC3 or DTS capable"));
+ aosettings->AddSupportedChannels(6);
+ }
+ aosettings->setFeature(FEATURE_AC3 | FEATURE_DTS);
+ }
}
- aosettings->m_DTS = aosettings->m_AC3 = (m_passthrough >= 0);
return aosettings;
}
@@ -312,19 +327,28 @@ AudioOutputSettings* AudioOutputSettings::GetUsers(bool newcopy)
int cur_channels = gCoreContext->GetNumSetting("MaxChannels", 2);
int max_channels = aosettings->BestSupportedChannels();
- bool bForceDigital = gCoreContext->GetNumSetting(
- "PassThruDeviceOverride", false);
- bool bAC3 = (aosettings->m_AC3 || bForceDigital) &&
+
+ bool bAC3 = aosettings->canFeature(FEATURE_AC3) &&
gCoreContext->GetNumSetting("AC3PassThru", false);
- bool bDTS = (aosettings->m_DTS || bForceDigital) &&
+
+ bool bDTS = aosettings->canFeature(FEATURE_DTS) &&
gCoreContext->GetNumSetting("DTSPassThru", false);
- bool bLPCM = aosettings->m_LPCM &&
+
+ bool bLPCM = aosettings->canFeature(FEATURE_LPCM) &&
!gCoreContext->GetNumSetting("StereoPCM", false);
- bool bHD = bLPCM && aosettings->m_HD &&
+
+ bool bEAC3 = aosettings->canFeature(FEATURE_EAC3) &&
gCoreContext->GetNumSetting("EAC3PassThru", false) &&
!gCoreContext->GetNumSetting("Audio48kOverride", false);
- bool bHDLL = bLPCM && aosettings->m_HD &&
+
+ // TrueHD requires HBR support.
+ bool bTRUEHD = aosettings->canFeature(FEATURE_TRUEHD) &&
gCoreContext->GetNumSetting("TrueHDPassThru", false) &&
+ !gCoreContext->GetNumSetting("Audio48kOverride", false) &&
+ gCoreContext->GetNumSetting("HBRPassthru", true);
+
+ bool bDTSHD = aosettings->canFeature(FEATURE_DTSHD) &&
+ gCoreContext->GetNumSetting("DTSHDPassThru", false) &&
!gCoreContext->GetNumSetting("Audio48kOverride", false);
if (max_channels > 2 && !bLPCM)
@@ -336,12 +360,60 @@ AudioOutputSettings* AudioOutputSettings::GetUsers(bool newcopy)
cur_channels = max_channels;
aosettings->SetBestSupportedChannels(cur_channels);
- aosettings->m_AC3 = bAC3;
- aosettings->m_DTS = bDTS;
- aosettings->m_HD = bHD;
- aosettings->m_HDLL = bHDLL;
-
- aosettings->m_LPCM = bLPCM;
+ aosettings->setFeature(bAC3, FEATURE_AC3);
+ aosettings->setFeature(bDTS, FEATURE_DTS);
+ aosettings->setFeature(bLPCM, FEATURE_LPCM);
+ aosettings->setFeature(bEAC3, FEATURE_EAC3);
+ aosettings->setFeature(bTRUEHD, FEATURE_TRUEHD);
+ aosettings->setFeature(bDTSHD, FEATURE_DTSHD);
return aosettings;
}
+
+int AudioOutputSettings::GetMaxHDRate()
+{
+ if (!canFeature(FEATURE_DTSHD))
+ return 0;
+
+ // If no HBR or no LPCM, limit bitrate to 6.144Mbit/s
+ if (!gCoreContext->GetNumSetting("HBRPassthru", true) ||
+ !canFeature(FEATURE_LPCM))
+ {
+ return 192000; // E-AC3/DTS-HD High Res: 192k, 16 bits, 2 ch
+ }
+ return 768000; // TrueHD or DTS-HD MA: 192k, 16 bits, 8 ch
+}
+
+#define ARG(x) ((tmp.isEmpty() ? "" : ",") + QString(x))
+
+QString AudioOutputSettings::FeaturesToString(DigitalFeature arg)
+{
+ QString tmp;
+ DigitalFeature feature[] = {
+ FEATURE_AC3,
+ FEATURE_DTS,
+ FEATURE_LPCM,
+ FEATURE_EAC3,
+ FEATURE_TRUEHD,
+ FEATURE_DTSHD,
+ FEATURE_AAC,
+ (DigitalFeature)-1
+ };
+ const char *feature_str[] = {
+ "AC3",
+ "DTS",
+ "LPCM",
+ "EAC3",
+ "TRUEHD",
+ "DTSHD",
+ "AAC",
+ NULL
+ };
+
+ for (unsigned int i = 0; feature[i] != (DigitalFeature)-1; i++)
+ {
+ if (arg & feature[i])
+ tmp += ARG(feature_str[i]);
+ }
+ return tmp;
+}
View
102 mythtv/libs/libmyth/audio/audiooutputsettings.h
@@ -1,6 +1,7 @@
/* -*- Mode: c++ -*-
*
* Copyright (C) foobum@gmail.com 2010
+ * Copyright (C) Jean-Yves Avenard 2010
*
* Licensed under the GPL v2 or a later version at your choosing.
*/
@@ -11,6 +12,11 @@
#include <vector>
#include "mythexp.h"
+#include <QString>
+
+extern "C" {
+#include "libavcodec/avcodec.h" // to get codec id
+}
using namespace std;
@@ -24,6 +30,17 @@ typedef enum {
FORMAT_FLT
} AudioFormat;
+typedef enum {
+ FEATURE_NONE = 0,
+ FEATURE_AC3 = 1 << 0,
+ FEATURE_DTS = 1 << 1,
+ FEATURE_LPCM = 1 << 2,
+ FEATURE_EAC3 = 1 << 3,
+ FEATURE_TRUEHD = 1 << 4,
+ FEATURE_DTSHD = 1 << 5,
+ FEATURE_AAC = 1 << 6,
+} DigitalFeature;
+
static const int srs[] = { 8000, 11025, 16000, 22050, 32000, 44100,
48000, 64000, 88200, 96000, 176400, 192000 };
@@ -58,61 +75,100 @@ class MPUBLIC AudioOutputSettings
void setPassthrough(int val) { m_passthrough = val; };
int canPassthrough() { return m_passthrough; };
/**
+ * return DigitalFeature mask.
+ * possible values are:
+ * - FEATURE_AC3
+ * - FEATURE_DTS
+ * - FEATURE_LPCM
+ * - FEATURE_EAC3
+ * - FEATURE_TRUEHD
+ * - FEATURE_DTSHD
+ */
+ unsigned int canFeature(DigitalFeature arg)
+ { return m_features & arg; };
+ unsigned int canFeature(unsigned int arg)
+ { return m_features & arg; };
+
+ /**
* return true if device can or may support AC3
+ * (deprecated, see canFeature())
*/
- bool canAC3() { return m_AC3; };
+ bool canAC3() { return m_features & FEATURE_AC3; };
/**
* return true if device can or may support DTS
+ * (deprecated, see canFeature())
*/
- bool canDTS() { return m_DTS; };
+ bool canDTS() { return m_features & FEATURE_DTS; };
/**
* return true if device supports multichannels PCM
+ * (deprecated, see canFeature())
*/
- bool canLPCM() { return m_LPCM; };
- /**
- * return true if device supports E-AC3 or DTS-HD passthrough
- */
- bool canHD() { return m_HD; };
- /**
- * return true if device supports TrueHD or DTS-HD passthrough
- */
- bool canHDLL() { return m_HDLL; };
+ bool canLPCM() { return m_features & FEATURE_LPCM; };
/**
* return true if class instance is marked invalid.
* if true, you can not assume any of the other method returned
* values are valid
*/
bool IsInvalid() { return m_invalid; };
+
/**
- * return true if device supports TrueHD or DTS-HD passthrough
+ * set the provided digital feature
+ * possible values are:
+ * - FEATURE_AC3
+ * - FEATURE_DTS
+ * - FEATURE_LPCM
+ * - FEATURE_EAC3
+ * - FEATURE_TRUEHD
+ * - FEATURE_DTSHD
*/
- void setAC3(bool b) { m_AC3 = b; };
- void setDTS(bool b) { m_DTS = b; };
- void setLPCM(bool b) { m_LPCM = b; };
- void setHD(bool b) { m_HD = b; };
- void setHDLL(bool b) { m_HDLL = b; };
+ void setFeature(DigitalFeature arg) { m_features |= arg; };
+ void setFeature(unsigned int arg) { m_features |= arg; };
+
+ /**
+ * clear or set digital feature internal mask
+ */
+ void setFeature(bool val, DigitalFeature arg);
+
/**
* Force set the greatest number of channels supported by the audio
* device
*/
void SetBestSupportedChannels(int channels);
+ /**
+ * return the highest iec958 rate supported.
+ * return 0 if no HD rate are supported
+ */
+ int GetMaxHDRate();
+
+ /**
+ * Display in human readable form the digital features
+ * supported by the output device
+ */
+ QString FeaturesToString(DigitalFeature arg);
+ QString FeaturesToString(void)
+ { return FeaturesToString((DigitalFeature)m_features); };
+
private:
void SortSupportedChannels();
- /* passthrough status
+ /** passthrough status
* -1 : no
* 0: unknown
* 1: yes
*/
int m_passthrough;
- bool m_AC3;
- bool m_DTS;
- bool m_LPCM;
- bool m_HD;
- bool m_HDLL;
+
+ unsigned int m_features;
bool m_invalid;
+ /**
+ * will be set to true if we were able to retrieve the device ELD
+ * (EDID like Data). ELD contains information about the audio
+ * processing capabilities of the device connected to the audio card
+ * ELD is usually retrieve from EDID CEA-861-E extension.
+ */
+ bool m_has_eld;
vector<int> m_sr, m_rates, m_channels;
vector<AudioFormat> m_sf, m_formats;
View
4 mythtv/libs/libmyth/audio/audiooutpututil.cpp
@@ -650,8 +650,8 @@ void AudioOutputUtil::MuteChannel(int obits, int channels, int ch,
#define LE_INT(v) (v)
#endif
-char *AudioOutputUtil::GeneratePinkSamples(char *frames, int channels,
- int channel, int count, int bits)
+char *AudioOutputUtil::GeneratePinkFrames(char *frames, int channels,
+ int channel, int count, int bits)
{
pink_noise_t pink;
View
4 mythtv/libs/libmyth/audio/audiooutpututil.h
@@ -18,8 +18,8 @@ class MPUBLIC AudioOutputUtil
bool music, bool upmix);
static void MuteChannel(int obits, int channels, int ch,
void *buffer, int bytes);
- static char *GeneratePinkSamples(char *frames, int channels,
- int channel, int count, int bits = 16);
+ static char *GeneratePinkFrames(char *frames, int channels,
+ int channel, int count, int bits = 16);
};
#endif
View
8 mythtv/libs/libmyth/audio/audiosettings.cpp
@@ -14,6 +14,7 @@ AudioSettings::AudioSettings() :
format(FORMAT_NONE),
channels(-1),
codec(0),
+ codec_profile(-1),
samplerate(-1),
set_initial_vol(false),
use_passthru(false),
@@ -30,6 +31,7 @@ AudioSettings::AudioSettings(const AudioSettings &other) :
format(other.format),
channels(other.channels),
codec(other.codec),
+ codec_profile(other.codec_profile),
samplerate(other.samplerate),
set_initial_vol(other.set_initial_vol),
use_passthru(other.use_passthru),
@@ -64,6 +66,7 @@ AudioSettings::AudioSettings(
format(format),
channels(channels),
codec(codec),
+ codec_profile(-1),
samplerate(samplerate),
set_initial_vol(set_initial_vol),
use_passthru(use_passthru),
@@ -87,12 +90,14 @@ AudioSettings::AudioSettings(
int codec,
int samplerate,
bool use_passthru,
- int upmixer_startup) :
+ int upmixer_startup,
+ int codec_profile) :
main_device(QString::null),
passthru_device(QString::null),
format(format),
channels(channels),
codec(codec),
+ codec_profile(codec_profile),
samplerate(samplerate),
set_initial_vol(false),
use_passthru(use_passthru),
@@ -111,6 +116,7 @@ AudioSettings::AudioSettings(
format(FORMAT_NONE),
channels(-1),
codec(0),
+ codec_profile(-1),
samplerate(-1),
set_initial_vol(false),
use_passthru(false),
View
15 mythtv/libs/libmyth/audio/audiosettings.h
@@ -1,6 +1,7 @@
/* -*- Mode: c++ -*-
*
* Copyright (C) Daniel Kristjansson 2008
+ * Copyright (C) Jean-Yves Avenard 2010
*
* Licensed under the GPL v2 or a later version at your choosing.
*/
@@ -43,7 +44,8 @@ class MPUBLIC AudioSettings
int codec,
int samplerate,
bool use_passthru,
- int upmixer_startup = 0);
+ int upmixer_startup = 0,
+ int codec_profile = 0);
AudioSettings(const QString &main_device,
const QString &passthru_device = QString::null);
@@ -61,12 +63,23 @@ class MPUBLIC AudioSettings
AudioFormat format;
int channels;
int codec;
+ int codec_profile;
int samplerate;
bool set_initial_vol;
bool use_passthru;
AudioOutputSource source;
int upmixer;
+ /**
+ * If set to false, AudioOutput instance will not try to initially open
+ * the audio device
+ */
bool init;
+ /**
+ * custom contains a pointer to the audio device capabilities
+ * if defined, AudioOutput will not try to automatically discover them.
+ * This is used by the AudioTest setting screen where the user can
+ * manually override and immediately use them.
+ */
AudioOutputSettings *custom;
};
View
62 mythtv/libs/libmyth/audio/spdifencoder.cpp
@@ -1,5 +1,7 @@
#include "config.h"
+#include "mythcorecontext.h"
+
#include "compat.h"
#include "spdifencoder.h"
#include "mythverbose.h"
@@ -7,7 +9,7 @@
#define LOC QString("SPDIFEncoder: ")
#define LOC_ERR QString("SPDIFEncoder, Error: ")
-/*
+/**
* SPDIFEncoder constructor
* Args:
* QString muxer : name of the muxer.
@@ -16,15 +18,13 @@
* Use "adts" for ADTS encpsulation (AAC)
* AVCodecContext *ctx : CodecContext to be encaspulated
*/
-
-SPDIFEncoder::SPDIFEncoder(QString muxer, AVCodecContext *ctx)
+SPDIFEncoder::SPDIFEncoder(QString muxer, int codec_id)
: m_complete(false), m_oc(NULL), m_stream(NULL), m_size(0)
{
QByteArray dev_ba = muxer.toAscii();
- AVOutputFormat *fmt =
- av_guess_format(dev_ba.constData(), NULL, NULL);
+ AVOutputFormat *fmt;
- if (!(av_guess_format && avformat_alloc_context &&
+ if (!(av_register_all && av_guess_format && avformat_alloc_context &&
av_new_stream && av_write_header && av_write_frame &&
av_write_trailer && av_set_parameters))
{
@@ -44,6 +44,11 @@ SPDIFEncoder::SPDIFEncoder(QString muxer, AVCodecContext *ctx)
return;
}
+ avcodeclock->lock();
+ av_register_all();
+ avcodeclock->unlock();
+
+ fmt = av_guess_format(dev_ba.constData(), NULL, NULL);
if (!fmt)
{
VERBOSE(VB_AUDIO, LOC_ERR + "av_guess_format");
@@ -97,21 +102,11 @@ SPDIFEncoder::SPDIFEncoder(QString muxer, AVCodecContext *ctx)
AVCodecContext *codec = m_stream->codec;
- codec->codec_type = ctx->codec_type;
- codec->codec_id = ctx->codec_id;
- codec->sample_rate = ctx->sample_rate;
- codec->sample_fmt = ctx->sample_fmt;
- codec->channels = ctx->channels;
- codec->bit_rate = ctx->bit_rate;
- codec->extradata = new uint8_t[ctx->extradata_size];
- codec->extradata_size = ctx->extradata_size;
- memcpy(codec->extradata, ctx->extradata, ctx->extradata_size);
-
+ codec->codec_id = (CodecID)codec_id;
av_write_header(m_oc);
- VERBOSE(VB_AUDIO, LOC + QString("Creating %1 encoder (%2, %3Hz)")
- .arg(muxer).arg(ff_codec_id_string((CodecID)codec->codec_type))
- .arg(codec->sample_rate));
+ VERBOSE(VB_AUDIO, LOC + QString("Creating %1 encoder (for %2)")
+ .arg(muxer).arg(ff_codec_id_string((CodecID)codec_id)));
m_complete = true;
}
@@ -121,12 +116,11 @@ SPDIFEncoder::~SPDIFEncoder(void)
Destroy();
}
-/*
+/**
* Encode data through created muxer
* unsigned char data: pointer to data to encode
* int size: size of data to encode
*/
-
void SPDIFEncoder::WriteFrame(unsigned char *data, int size)
{
AVPacket packet;
@@ -141,7 +135,7 @@ void SPDIFEncoder::WriteFrame(unsigned char *data, int size)
}
}
-/*
+/**
* Retrieve encoded data and copy it in the provided buffer.
* Return -1 if there is no data to retrieve.
* On return, dest_size will contain the length of the data copied
@@ -159,7 +153,7 @@ int SPDIFEncoder::GetData(unsigned char *buffer, int &dest_size)
return -1;
}
-/*
+/**
* Reset the internal encoder buffer
*/
void SPDIFEncoder::Reset()
@@ -167,10 +161,25 @@ void SPDIFEncoder::Reset()
m_size = 0;
}
-/*
- * funcIO: Internal callback function that will receive encoded frames
+/**
+ * Set the maximum HD rate.
+ * If playing DTS-HD content, setting a HD rate of 0 will only use the DTS-Core
+ * and the HD stream be stripped out before encoding
+ * Input: rate = maximum HD rate in Hz
*/
+bool SPDIFEncoder::SetMaxHDRate(int rate)
+{
+ if (!m_oc)
+ {
+ return false;
+ }
+ av_set_int(m_oc->priv_data, "dtshd_rate", rate);
+ return true;
+}
+/**
+ * funcIO: Internal callback function that will receive encoded frames
+ */
int SPDIFEncoder::funcIO(void *opaque, unsigned char *buf, int size)
{
SPDIFEncoder *enc = (SPDIFEncoder *)opaque;
@@ -180,10 +189,9 @@ int SPDIFEncoder::funcIO(void *opaque, unsigned char *buf, int size)
return size;
}
-/*
+/**
* Destroy and free all allocated memory
*/
-
void SPDIFEncoder::Destroy()
{
Reset();
View
9 mythtv/libs/libmyth/audio/spdifencoder.h
@@ -9,19 +9,22 @@ extern "C" {
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavcodec/audioconvert.h"
+#include "libavcodec/opt.h"
}
class MPUBLIC SPDIFEncoder
{
-
public:
- SPDIFEncoder(QString muxer, AVCodecContext *ctx);
+ SPDIFEncoder(QString muxer, int codec_id);
~SPDIFEncoder();
void WriteFrame(unsigned char *data, int size);
int GetData(unsigned char *buffer, int &dest_size);
+ int GetProcessedSize() { return m_size; };
+ unsigned char *GetProcessedBuffer() { return m_buffer; };
void Reset();
bool Succeeded() { return m_complete; };
-
+ bool SetMaxHDRate(int rate);
+
private:
static int funcIO(void *opaque, unsigned char *buf, int size);
void Destroy();
View
307 mythtv/libs/libmythtv/audioplayer.cpp
@@ -5,12 +5,13 @@
#define LOC QString("AudioPlayer: ")
AudioPlayer::AudioPlayer(MythPlayer *parent, bool muted)
- : m_parent(parent), m_audioOutput(NULL), m_channels(-1),
- m_orig_channels(-1), m_codec(0), m_format(FORMAT_NONE),
- m_samplerate(44100), m_stretchfactor(1.0f), m_passthru(false),
+ : m_parent(parent), m_audioOutput(NULL), m_channels(-1),
+ m_orig_channels(-1), m_codec(0), m_format(FORMAT_NONE),
+ m_samplerate(44100), m_codec_profile(0),
+ m_stretchfactor(1.0f),m_passthru(false),
m_lock(QMutex::Recursive), m_muted_on_creation(muted),
m_main_device(QString::null), m_passthru_device(QString::null),
- no_audio_in(false), no_audio_out(false)
+ m_no_audio_in(false), m_no_audio_out(false)
{
}
@@ -21,10 +22,11 @@ AudioPlayer::~AudioPlayer()
void AudioPlayer::Reset(void)
{
- m_lock.lock();
- if (m_audioOutput)
- m_audioOutput->Reset();
- m_lock.unlock();
+ if (!m_audioOutput)
+ return;
+
+ QMutexLocker lock(&m_lock);
+ m_audioOutput->Reset();
}
void AudioPlayer::DeleteOutput(void)
@@ -35,14 +37,14 @@ void AudioPlayer::DeleteOutput(void)
delete m_audioOutput;
m_audioOutput = NULL;
}
- no_audio_out = true;
+ m_no_audio_out = true;
}
QString AudioPlayer::ReinitAudio(void)
{
bool want_audio = m_parent->IsAudioNeeded();
- QMutexLocker lock(&m_lock);
QString errMsg = QString::null;
+ QMutexLocker lock(&m_lock);
bool firstinit = (m_format == FORMAT_NONE &&
m_channels < 0 &&
@@ -52,102 +54,97 @@ QString AudioPlayer::ReinitAudio(void)
(m_channels <= 0) ||
(m_samplerate <= 0))
{
- if (!firstinit)
- {
- VERBOSE(VB_IMPORTANT, LOC +
- QString("Disabling Audio, params(%1,%2,%3)")
- .arg(m_format).arg(m_channels).arg(m_samplerate));
- }
- no_audio_in = no_audio_out = true;
+ m_no_audio_in = m_no_audio_out = true;
}
else
- no_audio_in = false;
+ m_no_audio_in = false;
- if (no_audio_out && want_audio)
+ if (want_audio && !m_audioOutput)
{
- if (m_audioOutput)
- DeleteOutput();
-
+ // AudioOutput has never been created and we will want audio
bool setVolume = gCoreContext->GetNumSetting("MythControlsVolume", 1);
- m_audioOutput = AudioOutput::OpenAudio(m_main_device,
- m_passthru_device,
- m_format, m_channels,
- m_codec, m_samplerate,
- AUDIOOUTPUT_VIDEO,
- setVolume, m_passthru);
+ AudioSettings aos = AudioSettings(m_main_device,
+ m_passthru_device,
+ m_format, m_channels,
+ m_codec, m_samplerate,
+ AUDIOOUTPUT_VIDEO,
+ setVolume, m_passthru);
+ if (m_no_audio_in)
+ aos.init = false;
+
+ m_audioOutput = AudioOutput::OpenAudio(aos);
if (!m_audioOutput)
- errMsg = QObject::tr("Unable to create AudioOutput.");
- else
- errMsg = m_audioOutput->GetError();
-
- if (!errMsg.isEmpty())
- {
- if (!firstinit)
- {
- VERBOSE(VB_IMPORTANT, LOC + "Disabling Audio" +
- QString(", reason is: %1").arg(errMsg));
- }
- no_audio_out = true;
- }
- else if (no_audio_out)
{
- VERBOSE(VB_IMPORTANT, LOC + "Enabling Audio");
- no_audio_out = false;
+ errMsg = QObject::tr("Unable to create AudioOutput.");
}
- if (m_muted_on_creation)
+ else
{
- SetMuteState(kMuteAll);
- m_muted_on_creation = false;
+ errMsg = m_audioOutput->GetError();
}
}
-
- if (m_audioOutput && !no_audio_out)
+ else if (want_audio && !m_no_audio_in)
{
const AudioSettings settings(m_format, m_channels, m_codec,
- m_samplerate, m_passthru);
+ m_samplerate, m_passthru, 0,
+ m_codec_profile);
m_audioOutput->Reconfigure(settings);
errMsg = m_audioOutput->GetError();
SetStretchFactor(m_stretchfactor);
}
+ if (!errMsg.isEmpty())
+ {
+ if (!firstinit)
+ {
+ VERBOSE(VB_IMPORTANT, LOC + "Disabling Audio" +
+ QString(", reason is: %1").arg(errMsg));
+ }
+ m_no_audio_out = true;
+ }
+ else if (m_no_audio_out)
+ {
+ VERBOSE(VB_IMPORTANT, LOC + "Enabling Audio");
+ m_no_audio_out = false;
+ }
+ if (m_muted_on_creation)
+ {
+ SetMuteState(kMuteAll);
+ m_muted_on_creation = false;
+ }
+
return errMsg;
}
void AudioPlayer::CheckFormat(void)
{
if (m_format == FORMAT_NONE)
- no_audio_in = no_audio_out = true;
+ m_no_audio_in = m_no_audio_out = true;
}
bool AudioPlayer::Pause(bool pause)
{
- bool result = false;
- m_lock.lock();
- if (m_audioOutput && !no_audio_out)
- {
- m_audioOutput->Pause(pause);
- result = true;
- }
- m_lock.unlock();
- return result;
+ if (!m_audioOutput || m_no_audio_out)
+ return false;
+
+ QMutexLocker lock(&m_lock);
+ m_audioOutput->Pause(pause);
+ return true;
}
bool AudioPlayer::IsPaused(void)
{
- bool paused = false;
- m_lock.lock();
- if (m_audioOutput && !no_audio_out)
- paused = m_audioOutput->IsPaused();
- m_lock.unlock();
- return paused;
+ if (!m_audioOutput || m_no_audio_out)
+ return false;
+ QMutexLocker lock(&m_lock);
+ return m_audioOutput->IsPaused();
}
void AudioPlayer::PauseAudioUntilBuffered()
{
- m_lock.lock();
- if (m_audioOutput && !no_audio_out)
- m_audioOutput->PauseUntilBuffered();
- m_lock.unlock();
+ if (!m_audioOutput || m_no_audio_out)
+ return;
+ QMutexLocker lock(&m_lock);
+ m_audioOutput->PauseUntilBuffered();
}
void AudioPlayer::SetAudioOutput(AudioOutput *ao)
@@ -159,17 +156,20 @@ void AudioPlayer::SetAudioOutput(AudioOutput *ao)
uint AudioPlayer::GetVolume(void)
{
- uint res = 0;
- m_lock.lock();
- if (m_audioOutput && !no_audio_out)
- res = m_audioOutput->GetCurrentVolume();
- m_lock.unlock();
- return res;
+ if (!m_audioOutput || m_no_audio_out)
+ return 0;
+ QMutexLocker lock(&m_lock);
+ return m_audioOutput->GetCurrentVolume();
}
+/**
+ * Set audio output device parameters.
+ * codec_profile is currently only used for DTS
+ */
void AudioPlayer::SetAudioInfo(const QString &main_device,
const QString &passthru_device,
- uint samplerate)
+ uint samplerate,
+ int codec_profile)