dst_config.sample_rate = m_internalFormat.m_sampleRate;
dst_config.fmt = CActiveAEResample::GetAVSampleFormat(m_internalFormat.m_dataFormat);
dst_config.bits_per_sample = CAEUtil::DataFormatToUsedBits(m_internalFormat.m_dataFormat);
+ dst_config.dither_bits = CAEUtil::DataFormatToDitherBits(m_internalFormat.m_dataFormat);
CActiveAEResample *resampler = new CActiveAEResample();
resampler->Init(dst_config.channel_layout,
dst_config.sample_rate,
dst_config.fmt,
dst_config.bits_per_sample,
+ dst_config.dither_bits,
orig_config.channel_layout,
orig_config.channels,
orig_config.sample_rate,
orig_config.fmt,
orig_config.bits_per_sample,
+ orig_config.dither_bits,
false,
true,
NULL,
SampleConfig config;
config.fmt = CActiveAEResample::GetAVSampleFormat(m_format.m_dataFormat);
config.bits_per_sample = CAEUtil::DataFormatToUsedBits(m_format.m_dataFormat);
+ config.dither_bits = CAEUtil::DataFormatToDitherBits(m_format.m_dataFormat);
config.channels = m_format.m_channelLayout.Count();
config.sample_rate = m_format.m_sampleRate;
config.channel_layout = CActiveAEResample::GetAVChannelLayout(m_format.m_channelLayout);
m_format.m_sampleRate,
CActiveAEResample::GetAVSampleFormat(m_format.m_dataFormat),
CAEUtil::DataFormatToUsedBits(m_format.m_dataFormat),
+ CAEUtil::DataFormatToDitherBits(m_format.m_dataFormat),
CActiveAEResample::GetAVChannelLayout(m_inputFormat.m_channelLayout),
m_inputFormat.m_channelLayout.Count(),
m_inputFormat.m_sampleRate,
CActiveAEResample::GetAVSampleFormat(m_inputFormat.m_dataFormat),
CAEUtil::DataFormatToUsedBits(m_inputFormat.m_dataFormat),
+ CAEUtil::DataFormatToDitherBits(m_format.m_dataFormat),
upmix,
m_normalize,
remap ? &m_format.m_channelLayout : NULL,
m_format.m_sampleRate,
CActiveAEResample::GetAVSampleFormat(m_format.m_dataFormat),
CAEUtil::DataFormatToUsedBits(m_format.m_dataFormat),
+ CAEUtil::DataFormatToDitherBits(m_format.m_dataFormat),
CActiveAEResample::GetAVChannelLayout(m_inputFormat.m_channelLayout),
m_inputFormat.m_channelLayout.Count(),
m_inputFormat.m_sampleRate,
CActiveAEResample::GetAVSampleFormat(m_inputFormat.m_dataFormat),
CAEUtil::DataFormatToUsedBits(m_inputFormat.m_dataFormat),
+ CAEUtil::DataFormatToDitherBits(m_format.m_dataFormat),
m_stereoUpmix,
m_normalize,
NULL,
int channels;
int sample_rate;
int bits_per_sample;
+ int dither_bits;
};
/**
swr_free(&m_pContext);
}
-bool CActiveAEResample::Init(uint64_t dst_chan_layout, int dst_channels, int dst_rate, AVSampleFormat dst_fmt, int dst_bits, uint64_t src_chan_layout, int src_channels, int src_rate, AVSampleFormat src_fmt, int src_bits, bool upmix, bool normalize, CAEChannelInfo *remapLayout, AEQuality quality)
+bool CActiveAEResample::Init(uint64_t dst_chan_layout, int dst_channels, int dst_rate, AVSampleFormat dst_fmt, int dst_bits, int dst_dither, uint64_t src_chan_layout, int src_channels, int src_rate, AVSampleFormat src_fmt, int src_bits, int src_dither, bool upmix, bool normalize, CAEChannelInfo *remapLayout, AEQuality quality)
{
if (!m_loaded)
return false;
m_dst_rate = dst_rate;
m_dst_fmt = dst_fmt;
m_dst_bits = dst_bits;
+ m_dst_dither_bits = dst_dither;
m_src_chan_layout = src_chan_layout;
m_src_channels = src_channels;
m_src_rate = src_rate;
m_src_fmt = src_fmt;
m_src_bits = src_bits;
+ m_src_dither_bits = src_dither;
if (m_dst_chan_layout == 0)
m_dst_chan_layout = av_get_default_channel_layout(m_dst_channels);
CLog::Log(LOGERROR, "CActiveAEResample::Resample - resample failed");
return 0;
}
+
+ // shift bits if destination format requires it, swr_resamples aligns to the left
+ if (m_dst_fmt == AV_SAMPLE_FMT_S32 || m_dst_fmt == AV_SAMPLE_FMT_S32P)
+ {
+ if (m_dst_bits != 32 && (m_dst_dither_bits + m_dst_bits) != 32)
+ {
+ int planes = av_sample_fmt_is_planar(m_dst_fmt) ? m_dst_channels : 1;
+ int samples = ret * m_dst_channels / planes;
+ for (int i=0; i<planes; i++)
+ {
+ uint32_t* buf = (uint32_t*)dst_buffer[i];
+ for (int j=0; j<samples; j++)
+ {
+ *buf = *buf >> m_dst_dither_bits;
+ }
+ }
+ }
+ }
return ret;
}
else if (format == AE_FMT_S16NE) return AV_SAMPLE_FMT_S16;
else if (format == AE_FMT_S32NE) return AV_SAMPLE_FMT_S32;
else if (format == AE_FMT_S24NE4) return AV_SAMPLE_FMT_S32;
+ else if (format == AE_FMT_S24NE4MSB)return AV_SAMPLE_FMT_S32;
else if (format == AE_FMT_FLOAT) return AV_SAMPLE_FMT_FLT;
else if (format == AE_FMT_DOUBLE) return AV_SAMPLE_FMT_DBL;
else if (format == AE_FMT_S16NEP) return AV_SAMPLE_FMT_S16P;
else if (format == AE_FMT_S32NEP) return AV_SAMPLE_FMT_S32P;
else if (format == AE_FMT_S24NE4P) return AV_SAMPLE_FMT_S32P;
+ else if (format == AE_FMT_S24NE4MSBP)return AV_SAMPLE_FMT_S32P;
else if (format == AE_FMT_FLOATP) return AV_SAMPLE_FMT_FLTP;
else if (format == AE_FMT_DOUBLEP) return AV_SAMPLE_FMT_DBLP;
public:
CActiveAEResample();
virtual ~CActiveAEResample();
- bool Init(uint64_t dst_chan_layout, int dst_channels, int dst_rate, AVSampleFormat dst_fmt, int dst_bits, uint64_t src_chan_layout, int src_channels, int src_rate, AVSampleFormat src_fmt, int src_bits, bool upmix, bool normalize, CAEChannelInfo *remapLayout, AEQuality quality);
+ bool Init(uint64_t dst_chan_layout, int dst_channels, int dst_rate, AVSampleFormat dst_fmt, int dst_bits, int dst_dither, uint64_t src_chan_layout, int src_channels, int src_rate, AVSampleFormat src_fmt, int src_bits, int src_dither, bool upmix, bool normalize, CAEChannelInfo *remapLayout, AEQuality quality);
int Resample(uint8_t **dst_buffer, int dst_samples, uint8_t **src_buffer, int src_samples, double ratio);
int64_t GetDelay(int64_t base);
int GetBufferedSamples();
int m_src_channels, m_dst_channels;
AVSampleFormat m_src_fmt, m_dst_fmt;
int m_src_bits, m_dst_bits;
+ int m_src_dither_bits, m_dst_dither_bits;
SwrContext *m_pContext;
double m_rematrix[AE_CH_MAX][AE_CH_MAX];
};
SampleConfig config;
config.fmt = CActiveAEResample::GetAVSampleFormat(m_sinkFormat.m_dataFormat);
config.bits_per_sample = CAEUtil::DataFormatToUsedBits(m_sinkFormat.m_dataFormat);
+ config.dither_bits = CAEUtil::DataFormatToDitherBits(m_sinkFormat.m_dataFormat);
config.channel_layout = CActiveAEResample::GetAVChannelLayout(m_sinkFormat.m_channelLayout);
config.channels = m_sinkFormat.m_channelLayout.Count();
config.sample_rate = m_sinkFormat.m_sampleRate;
SampleConfig config;
config.fmt = CActiveAEResample::GetAVSampleFormat(m_sinkFormat.m_dataFormat);
config.bits_per_sample = CAEUtil::DataFormatToUsedBits(m_sinkFormat.m_dataFormat);
+ config.dither_bits = CAEUtil::DataFormatToDitherBits(m_sinkFormat.m_dataFormat);
config.channel_layout = CActiveAEResample::GetAVChannelLayout(m_sinkFormat.m_channelLayout);
config.channels = m_sinkFormat.m_channelLayout.Count();
config.sample_rate = m_sinkFormat.m_sampleRate;
m_format.m_sampleRate,
CActiveAEResample::GetAVSampleFormat(m_format.m_dataFormat),
CAEUtil::DataFormatToUsedBits(m_format.m_dataFormat),
+ CAEUtil::DataFormatToDitherBits(m_format.m_dataFormat),
avLayout,
m_format.m_channelLayout.Count(),
m_format.m_sampleRate,
CActiveAEResample::GetAVSampleFormat(m_format.m_dataFormat),
CAEUtil::DataFormatToUsedBits(m_format.m_dataFormat),
+ CAEUtil::DataFormatToDitherBits(m_format.m_dataFormat),
false,
false,
&remapLayout,
AE_FMT_S24BE4,
AE_FMT_S24LE4,
- AE_FMT_S24NE4, /* S24 in 4 bytes */
+ AE_FMT_S24NE4, // 24 bits in lower 3 bytes
+ AE_FMT_S24NE4MSB, // S32 with bits_per_sample < 32
AE_FMT_S24BE3,
AE_FMT_S24LE3,
AE_FMT_S16NEP,
AE_FMT_S32NEP,
AE_FMT_S24NE4P,
+ AE_FMT_S24NE4MSBP,
AE_FMT_S24NE3P,
AE_FMT_DOUBLEP,
AE_FMT_FLOATP,
32, /* S24BE */
32, /* S24LE */
32, /* S24NE */
+ 32, /* S24NER */
24, /* S24BE3 */
24, /* S24LE3 */
16, /* S16NEP */
32, /* S32NEP */
32, /* S24NEP */
+ 32, /* S24NERP*/
24, /* S24NE3P*/
sizeof(double) << 3, /* DOUBLEP */
sizeof(float ) << 3 /* FLOATP */
const unsigned int CAEUtil::DataFormatToUsedBits(const enum AEDataFormat dataFormat)
{
- if (dataFormat == AE_FMT_S24BE4 || dataFormat == AE_FMT_S24LE4 || dataFormat == AE_FMT_S24NE4)
+ if (dataFormat == AE_FMT_S24BE4 || dataFormat == AE_FMT_S24LE4 ||
+ dataFormat == AE_FMT_S24NE4 || dataFormat == AE_FMT_S24NE4MSB)
return 24;
else
return DataFormatToBits(dataFormat);
}
+const unsigned int CAEUtil::DataFormatToDitherBits(const enum AEDataFormat dataFormat)
+{
+ if (dataFormat == AE_FMT_S24NE4MSB)
+ return 8;
+ else
+ return 0;
+}
+
const char* CAEUtil::DataFormatToStr(const enum AEDataFormat dataFormat)
{
if (dataFormat < 0 || dataFormat >= AE_FMT_MAX)
"AE_FMT_S24BE4",
"AE_FMT_S24LE4",
"AE_FMT_S24NE4", /* S24 in 4 bytes */
+ "AE_FMT_S24NE4MSB",
"AE_FMT_S24BE3",
"AE_FMT_S24LE3",
"AE_FMT_S16NEP",
"AE_FMT_S32NEP",
"AE_FMT_S24NE4P",
+ "AE_FMT_S24NE4MSBP",
"AE_FMT_S24NE3P",
"AE_FMT_DOUBLEP",
"AE_FMT_FLOATP"
static const char* GetStdChLayoutName(const enum AEStdChLayout layout);
static const unsigned int DataFormatToBits (const enum AEDataFormat dataFormat);
static const unsigned int DataFormatToUsedBits (const enum AEDataFormat dataFormat);
+ static const unsigned int DataFormatToDitherBits(const enum AEDataFormat dataFormat);
static const char* DataFormatToStr (const enum AEDataFormat dataFormat);
/*! \brief convert a volume percentage (as a proportion) to a dB gain