Permalink
Browse files

Merge pull request #973 from anssih/fix/AE-byteswap

[AE] Fix issues related to endianness in passthrough

Conflicts:
	xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.cpp
  • Loading branch information...
anssih committed Jul 10, 2012
2 parents 2de2058 + 941eae2 commit 55e2317d7d87f81d47154c7637f00bcaaa783482
@@ -90,7 +90,9 @@ const char* StreamDescriptionToString(AudioStreamBasicDescription desc, std::str
case kAudioFormat60958AC3:
sstr << "["
<< fourCC
- << "] AC-3/DTS for S/PDIF ("
+ << "] AC-3/DTS for S/PDIF "
+ << ((desc.mFormatFlags & kAudioFormatFlagIsBigEndian) ? "BE" : "LE")
+ << " ("
<< (UInt32)desc.mSampleRate
<< "Hz)";
str = sstr.str();
@@ -27,6 +27,7 @@
#include "utils/log.h"
#include "utils/TimeUtils.h"
#include "utils/MathUtils.h"
+#include "utils/EndianSwap.h"
#include "threads/SingleLock.h"
#include "settings/GUISettings.h"
#include "settings/Settings.h"
@@ -884,6 +885,16 @@ void CSoftAE::Run()
}
}
+void CSoftAE::AllocateConvIfNeeded(size_t convertedSize)
+{
+ if (m_convertedSize < convertedSize)
+ {
+ _aligned_free(m_converted);
+ m_converted = (uint8_t *)_aligned_malloc(convertedSize, 16);
+ m_convertedSize = convertedSize;
+ }
+}
+
void CSoftAE::MixSounds(float *buffer, unsigned int samples)
{
SoundStateList::iterator itt;
@@ -982,12 +993,7 @@ void CSoftAE::RunOutputStage()
if (m_convertFn)
{
const unsigned int convertedBytes = m_sinkFormat.m_frames * m_sinkFormat.m_frameSize;
- if (m_convertedSize < convertedBytes)
- {
- _aligned_free(m_converted);
- m_converted = (uint8_t *)_aligned_malloc(convertedBytes, 16);
- m_convertedSize = convertedBytes;
- }
+ AllocateConvIfNeeded(convertedBytes);
m_convertFn((float*)data, needSamples, m_converted);
data = m_converted;
}
@@ -1010,7 +1016,26 @@ void CSoftAE::RunRawOutputStage()
if(m_buffer.Used() < m_sinkBlockSize)
return;
- int wroteFrames = m_sink->AddPackets((uint8_t*)m_buffer.Raw(m_sinkBlockSize), m_sinkFormat.m_frames);
+ void *data = m_buffer.Raw(m_sinkBlockSize);
+
+ if (CAEUtil::S16NeedsByteSwap(AE_FMT_S16NE, m_sinkFormat.m_dataFormat))
+ {
+ /*
+ * It would really be preferable to handle this at packing stage, so that
+ * it could byteswap the data efficiently without wasting CPU time on
+ * swapping the huge IEC 61937 zero padding between frames (or not
+ * byteswap at all, if there are two byteswaps).
+ *
+ * Unfortunately packing is done on a higher level and we can't easily
+ * tell it the needed format from here, so do it here for now (better than
+ * nothing)...
+ */
+ AllocateConvIfNeeded(m_sinkBlockSize);
+ Endian_Swap16_buf((uint16_t *)m_converted, (uint16_t *)data, m_sinkBlockSize / 2);
+ data = m_converted;
+ }
+
+ int wroteFrames = m_sink->AddPackets((uint8_t *)data, m_sinkFormat.m_frames);
/* Return value of INT_MAX signals error in sink - restart */
if (wroteFrames == INT_MAX)
@@ -192,6 +192,8 @@ class CSoftAE : public IThreadedAE
uint8_t *m_converted;
size_t m_convertedSize;
+ void AllocateConvIfNeeded(size_t convertedSize);
+
/* thread run stages */
void MixSounds (float *buffer, unsigned int samples);
void FinalizeSamples (float *buffer, unsigned int samples);
@@ -214,13 +214,15 @@ bool CAESinkALSA::IsCompatible(const AEAudioFormat format, const std::string dev
snd_pcm_format_t CAESinkALSA::AEFormatToALSAFormat(const enum AEDataFormat format)
{
if (AE_IS_RAW(format))
- return SND_PCM_FORMAT_S16_LE;
+ return SND_PCM_FORMAT_S16;
switch (format)
{
case AE_FMT_S8 : return SND_PCM_FORMAT_S8;
case AE_FMT_U8 : return SND_PCM_FORMAT_U8;
case AE_FMT_S16NE : return SND_PCM_FORMAT_S16;
+ case AE_FMT_S16LE : return SND_PCM_FORMAT_S16_LE;
+ case AE_FMT_S16BE : return SND_PCM_FORMAT_S16_BE;
case AE_FMT_S24NE4: return SND_PCM_FORMAT_S24;
#ifdef __BIG_ENDIAN__
case AE_FMT_S24NE3: return SND_PCM_FORMAT_S24_3BE;
@@ -279,6 +281,10 @@ bool CAESinkALSA::InitializeHW(AEAudioFormat &format)
{
if (AE_IS_RAW(i) || i == AE_FMT_MAX)
continue;
+
+ if (m_passthrough && i != AE_FMT_S16BE && i != AE_FMT_S16LE)
+ continue;
+
fmt = AEFormatToALSAFormat(i);
if (fmt == SND_PCM_FORMAT_UNKNOWN || snd_pcm_hw_params_set_format(m_pcm, hw_params, fmt) < 0)
@@ -20,6 +20,7 @@
*/
#include "AEBitstreamPacker.h"
+#include "AEPackIEC61937.h"
#include <stdint.h>
#include <stddef.h>
#include <string.h>
@@ -56,6 +57,18 @@ void CAEBitstreamPacker::Pack(CAEStreamInfo &info, uint8_t* data, int size)
PackDTSHD (info, data, size);
break;
+ case CAEStreamInfo::STREAM_TYPE_DTS_512:
+ m_dataSize = CAEPackIEC61937::PackDTS_512(data, size, m_packedBuffer, info.IsLittleEndian());
+ break;
+
+ case CAEStreamInfo::STREAM_TYPE_DTS_1024:
+ m_dataSize = CAEPackIEC61937::PackDTS_1024(data, size, m_packedBuffer, info.IsLittleEndian());
+ break;
+
+ case CAEStreamInfo::STREAM_TYPE_DTS_2048:
+ m_dataSize = CAEPackIEC61937::PackDTS_2048(data, size, m_packedBuffer, info.IsLittleEndian());
+ break;
+
default:
/* pack the data into an IEC61937 frame */
CAEPackIEC61937::PackFunc pack = info.GetPackFunc();
@@ -23,8 +23,6 @@
#include <stdint.h>
#include "../AEAudioFormat.h"
-/* note: always converts to machine byte endian */
-
class CAEConvert{
private:
static unsigned int U8_Float (uint8_t *data, const unsigned int samples, float *dest);
@@ -19,8 +19,6 @@
*
*/
-/* DTS spec shows it suppors both BE and LE, we should not need to convert */
-
#include <cassert>
#include "system.h"
#include "AEPackIEC61937.h"
@@ -85,73 +83,19 @@ int CAEPackIEC61937::PackEAC3(uint8_t *data, unsigned int size, uint8_t *dest)
return OUT_FRAMESTOBYTES(EAC3_FRAME_SIZE);
}
-int CAEPackIEC61937::PackDTS_512(uint8_t *data, unsigned int size, uint8_t *dest)
+int CAEPackIEC61937::PackDTS_512(uint8_t *data, unsigned int size, uint8_t *dest, bool littleEndian)
{
- assert(size <= OUT_FRAMESTOBYTES(DTS1_FRAME_SIZE));
- struct IEC61937Packet *packet = (struct IEC61937Packet*)dest;
- packet->m_preamble1 = IEC61937_PREAMBLE1;
- packet->m_preamble2 = IEC61937_PREAMBLE2;
- packet->m_type = IEC61937_TYPE_DTS1;
- packet->m_length = size << 3;
-
- if (data == NULL)
- data = packet->m_data;
-#ifdef __BIG_ENDIAN__
- else
- memcpy(packet->m_data, data, size);
-#else
- size += size & 0x1;
- SwapEndian((uint16_t*)packet->m_data, (uint16_t*)data, size >> 1);
-#endif
-
- memset(packet->m_data + size, 0, OUT_FRAMESTOBYTES(DTS1_FRAME_SIZE) - IEC61937_DATA_OFFSET - size);
- return OUT_FRAMESTOBYTES(DTS1_FRAME_SIZE);
+ return PackDTS(data, size, dest, littleEndian, OUT_FRAMESTOBYTES(DTS1_FRAME_SIZE), IEC61937_TYPE_DTS1);
}
-int CAEPackIEC61937::PackDTS_1024(uint8_t *data, unsigned int size, uint8_t *dest)
+int CAEPackIEC61937::PackDTS_1024(uint8_t *data, unsigned int size, uint8_t *dest, bool littleEndian)
{
- assert(size <= OUT_FRAMESTOBYTES(DTS2_FRAME_SIZE));
- struct IEC61937Packet *packet = (struct IEC61937Packet*)dest;
- packet->m_preamble1 = IEC61937_PREAMBLE1;
- packet->m_preamble2 = IEC61937_PREAMBLE2;
- packet->m_type = IEC61937_TYPE_DTS2;
- packet->m_length = size << 3;
-
- if (data == NULL)
- data = packet->m_data;
-#ifdef __BIG_ENDIAN__
- else
- memcpy(packet->m_data, data, size);
-#else
- size += size & 0x1;
- SwapEndian((uint16_t*)packet->m_data, (uint16_t*)data, size >> 1);
-#endif
-
- memset(packet->m_data + size, 0, OUT_FRAMESTOBYTES(DTS2_FRAME_SIZE) - IEC61937_DATA_OFFSET - size);
- return OUT_FRAMESTOBYTES(DTS2_FRAME_SIZE);
+ return PackDTS(data, size, dest, littleEndian, OUT_FRAMESTOBYTES(DTS2_FRAME_SIZE), IEC61937_TYPE_DTS2);
}
-int CAEPackIEC61937::PackDTS_2048(uint8_t *data, unsigned int size, uint8_t *dest)
+int CAEPackIEC61937::PackDTS_2048(uint8_t *data, unsigned int size, uint8_t *dest, bool littleEndian)
{
- assert(size <= OUT_FRAMESTOBYTES(DTS3_FRAME_SIZE));
- struct IEC61937Packet *packet = (struct IEC61937Packet*)dest;
- packet->m_preamble1 = IEC61937_PREAMBLE1;
- packet->m_preamble2 = IEC61937_PREAMBLE2;
- packet->m_type = IEC61937_TYPE_DTS3;
- packet->m_length = size << 3;
-
- if (data == NULL)
- data = packet->m_data;
-#ifdef __BIG_ENDIAN__
- else
- memcpy(packet->m_data, data, size);
-#else
- size += size & 0x1;
- SwapEndian((uint16_t*)packet->m_data, (uint16_t*)data, size >> 1);
-#endif
-
- memset(packet->m_data + size, 0, OUT_FRAMESTOBYTES(DTS3_FRAME_SIZE) - IEC61937_DATA_OFFSET - size);
- return OUT_FRAMESTOBYTES(DTS3_FRAME_SIZE);
+ return PackDTS(data, size, dest, littleEndian, OUT_FRAMESTOBYTES(DTS3_FRAME_SIZE), IEC61937_TYPE_DTS3);
}
int CAEPackIEC61937::PackTrueHD(uint8_t *data, unsigned int size, uint8_t *dest)
@@ -220,3 +164,56 @@ int CAEPackIEC61937::PackDTSHD(uint8_t *data, unsigned int size, uint8_t *dest,
return burstsize;
}
+int CAEPackIEC61937::PackDTS(uint8_t *data, unsigned int size, uint8_t *dest, bool littleEndian,
+ unsigned int frameSize, uint16_t type)
+{
+ assert(size <= frameSize);
+
+ /* BE is the standard endianness, byteswap needed if LE */
+ bool byteSwapNeeded = littleEndian;
+
+#ifndef __BIG_ENDIAN__
+ /* on LE systems we want LE output, byteswap needed */
+ byteSwapNeeded ^= true;
+#endif
+
+ struct IEC61937Packet *packet = (struct IEC61937Packet*)dest;
+ uint8_t *dataTo;
+
+ if (size == frameSize)
+ {
+ /* No packing possible or needed, DTS stream is suitable for direct output */
+ dataTo = dest;
+ }
+ else if (size <= frameSize - IEC61937_DATA_OFFSET)
+ {
+ /* Fits to IEC61937, perform packing */
+ packet->m_preamble1 = IEC61937_PREAMBLE1;
+ packet->m_preamble2 = IEC61937_PREAMBLE2;
+ packet->m_type = type;
+ packet->m_length = size << 3;
+
+ dataTo = packet->m_data;
+ }
+ else
+ {
+ /* Stream is unsuitable for both packing and direct output */
+ return 0;
+ }
+
+ if (data == NULL)
+ data = dataTo;
+ else if (!byteSwapNeeded)
+ memcpy(dataTo, data, size);
+
+ if (byteSwapNeeded)
+ {
+ size += size & 0x1;
+ SwapEndian((uint16_t*)dataTo, (uint16_t*)data, size >> 1);
+ }
+
+ if (size != frameSize)
+ memset(packet->m_data + size, 0, frameSize - IEC61937_DATA_OFFSET - size);
+
+ return frameSize;
+}
@@ -52,12 +52,16 @@ class CAEPackIEC61937
static int PackAC3 (uint8_t *data, unsigned int size, uint8_t *dest);
static int PackEAC3 (uint8_t *data, unsigned int size, uint8_t *dest);
- static int PackDTS_512 (uint8_t *data, unsigned int size, uint8_t *dest);
- static int PackDTS_1024(uint8_t *data, unsigned int size, uint8_t *dest);
- static int PackDTS_2048(uint8_t *data, unsigned int size, uint8_t *dest);
+ static int PackDTS_512 (uint8_t *data, unsigned int size, uint8_t *dest, bool littleEndian);
+ static int PackDTS_1024(uint8_t *data, unsigned int size, uint8_t *dest, bool littleEndian);
+ static int PackDTS_2048(uint8_t *data, unsigned int size, uint8_t *dest, bool littleEndian);
static int PackTrueHD (uint8_t *data, unsigned int size, uint8_t *dest);
static int PackDTSHD (uint8_t *data, unsigned int size, uint8_t *dest, unsigned int period);
private:
+
+ static int PackDTS(uint8_t *data, unsigned int size, uint8_t *dest, bool littleEndian,
+ unsigned int frameSize, uint16_t type);
+
enum IEC61937DataType
{
IEC61937_TYPE_NULL = 0x00,
@@ -504,9 +504,9 @@ unsigned int CAEStreamInfo::SyncDTS(uint8_t *data, unsigned int size)
DataType dataType;
switch (dtsBlocks << 5)
{
- case 512 : dataType = STREAM_TYPE_DTS_512 ; m_packFunc = &CAEPackIEC61937::PackDTS_512 ; break;
- case 1024: dataType = STREAM_TYPE_DTS_1024; m_packFunc = &CAEPackIEC61937::PackDTS_1024; break;
- case 2048: dataType = STREAM_TYPE_DTS_2048; m_packFunc = &CAEPackIEC61937::PackDTS_2048; break;
+ case 512 : dataType = STREAM_TYPE_DTS_512 ; break;
+ case 1024: dataType = STREAM_TYPE_DTS_1024; break;
+ case 2048: dataType = STREAM_TYPE_DTS_2048; break;
default:
invalid = true;
break;
@@ -455,3 +455,20 @@ void CAEUtil::FloatRand4(const float min, const float max, float result[4], __m1
result[3] = ((float)(m_seed = (214013 * m_seed + 2531011)) * factor) - delta;
#endif
}
+
+bool CAEUtil::S16NeedsByteSwap(AEDataFormat in, AEDataFormat out)
+{
+ const AEDataFormat nativeFormat =
+#ifdef WORDS_BIGENDIAN
+ AE_FMT_S16BE;
+#else
+ AE_FMT_S16LE;
+#endif
+
+ if (in == AE_FMT_S16NE || AE_IS_RAW(in))
+ in = nativeFormat;
+ if (out == AE_FMT_S16NE || AE_IS_RAW(out))
+ out = nativeFormat;
+
+ return in != out;
+}
@@ -90,4 +90,6 @@ class CAEUtil
*/
static float FloatRand1(const float min, const float max);
static void FloatRand4(const float min, const float max, float result[4], __m128 *sseresult = NULL);
+
+ static bool S16NeedsByteSwap(AEDataFormat in, AEDataFormat out);
};
Oops, something went wrong.

4 comments on commit 55e2317

Contributor

Giftie replied Jul 16, 2012

This commit breaks DTS Core audio playback in movies with DTS MA-HD track(BD Rips) Movies with DTS only tracks work fine.

Member

anssih replied Jul 16, 2012

Thanks for the info, I'll try to test and investigate tomorrow.

Member

anssih replied Jul 21, 2012

Sorry for the delay, fixed now in 8e94e27. Thanks for the report.

Contributor

Giftie replied Jul 21, 2012

No problem... Thanks for fixing it...

Please sign in to comment.