realign and clean

This commit is contained in:
Christian R. Helmrich
2021-03-21 00:00:00 +01:00
parent 5bfcbaca3e
commit ab91fd8f9c
5 changed files with 96 additions and 90 deletions

View File

@@ -316,16 +316,9 @@ int BasicMP4Writer::finishFile (const unsigned avgBitrate, const unsigned maxBit
return bytesWritten; return bytesWritten;
} }
int BasicMP4Writer::initHeader (const uint32_t audioLength) // reserve bytes for header in file int BasicMP4Writer::initHeader (const uint32_t audioLength, const unsigned extraDelay)
{ {
/* NOTE: the following condition is, as far as I can tell, correct, but some decoders with DRC processing const unsigned frameCount = (audioLength + m_pregapLength - extraDelay + m_sampleRate / 200u + m_frameLength - 1u) / m_frameLength;
may decode too few samples with it. Hence, I disabled it. See also corresponding NOTE in exhaleApp.cpp */
const bool flushFrameUsed = true; // ((audioLength + m_pregapLength) % m_frameLength) > 0;
#ifdef NO_PREROLL_DATA
const unsigned frameCount = ((audioLength + m_frameLength - 1) / m_frameLength) + (flushFrameUsed ? 2 : 1);
#else
const unsigned frameCount = ((audioLength + m_frameLength - 1) / m_frameLength) + (flushFrameUsed ? 1 : 0);
#endif
const unsigned chunkCount = ((frameCount + m_rndAccPeriod - 1) / m_rndAccPeriod); const unsigned chunkCount = ((frameCount + m_rndAccPeriod - 1) / m_rndAccPeriod);
const unsigned numFramesFirstPeriod = __min (frameCount, m_rndAccPeriod); const unsigned numFramesFirstPeriod = __min (frameCount, m_rndAccPeriod);
const unsigned numFramesFinalPeriod = (frameCount <= m_rndAccPeriod ? 0 : frameCount % m_rndAccPeriod); const unsigned numFramesFinalPeriod = (frameCount <= m_rndAccPeriod ? 0 : frameCount % m_rndAccPeriod);
@@ -366,7 +359,7 @@ unsigned BasicMP4Writer::open (const int mp4FileHandle, const unsigned sampleRat
} }
m_fileHandle = mp4FileHandle; m_fileHandle = mp4FileHandle;
reset (frameLength, pregapLength, __min (USHRT_MAX, raPeriod)); reset (frameLength, pregapLength, __min (USHRT_MAX, raPeriod), sampleRate);
// create fixed-length 576-byte part of MPEG-4 file header // create fixed-length 576-byte part of MPEG-4 file header
memcpy (m_staticHeader, staticHeaderTemplate, STAT_HEADER_SIZE * sizeof (uint8_t)); memcpy (m_staticHeader, staticHeaderTemplate, STAT_HEADER_SIZE * sizeof (uint8_t));
@@ -427,7 +420,7 @@ unsigned BasicMP4Writer::open (const int mp4FileHandle, const unsigned sampleRat
return 0; // correct operation return 0; // correct operation
} }
void BasicMP4Writer::reset (const unsigned frameLength /*= 0*/, const unsigned pregapLength /*= 0*/, const unsigned raPeriod /*= 0*/) void BasicMP4Writer::reset (const unsigned frameLength, const unsigned pregapLength, const unsigned raPeriod, const unsigned sampleRate)
{ {
m_ascSizeM5 = 0; m_ascSizeM5 = 0;
m_frameCount = 0; m_frameCount = 0;
@@ -436,7 +429,7 @@ void BasicMP4Writer::reset (const unsigned frameLength /*= 0*/, const unsigned p
m_mediaSize = 0; // total length of 'mdat' (access unit) payload in file m_mediaSize = 0; // total length of 'mdat' (access unit) payload in file
m_pregapLength = pregapLength; m_pregapLength = pregapLength;
m_rndAccPeriod = raPeriod; m_rndAccPeriod = raPeriod;
m_sampleRate = 0; m_sampleRate = sampleRate;
m_dynamicHeader.clear (); m_dynamicHeader.clear ();
m_rndAccOffsets.clear (); m_rndAccOffsets.clear ();
#ifndef NO_PREROLL_DATA #ifndef NO_PREROLL_DATA

View File

@@ -53,7 +53,7 @@ private:
public: public:
// constructor // constructor
BasicMP4Writer () { m_fileHandle = -1; reset (); } BasicMP4Writer () { m_fileHandle = -1; reset (0, 0, 0, 0); }
// destructor // destructor
#ifdef NO_PREROLL_DATA #ifdef NO_PREROLL_DATA
~BasicMP4Writer() { m_dynamicHeader.clear (); m_rndAccOffsets.clear (); } ~BasicMP4Writer() { m_dynamicHeader.clear (); m_rndAccOffsets.clear (); }
@@ -65,12 +65,12 @@ public:
int finishFile (const unsigned avgBitrate, const unsigned maxBitrate, const uint32_t audioLength, int finishFile (const unsigned avgBitrate, const unsigned maxBitrate, const uint32_t audioLength,
const uint32_t modifTime = 0, const uint8_t* ascBuf = nullptr); const uint32_t modifTime = 0, const uint8_t* ascBuf = nullptr);
unsigned getFrameCount () const { return m_frameCount; } unsigned getFrameCount () const { return m_frameCount; }
int initHeader (const uint32_t audioLength); int initHeader (const uint32_t audioLength, const unsigned extraDelay);
unsigned open (const int mp4FileHandle, const unsigned sampleRate, const unsigned numChannels, unsigned open (const int mp4FileHandle, const unsigned sampleRate, const unsigned numChannels,
const unsigned bitDepth, const unsigned frameLength, const unsigned pregapLength, const unsigned bitDepth, const unsigned frameLength, const unsigned pregapLength,
const unsigned raPeriod, const uint8_t* ascBuf, const unsigned ascSize, const unsigned raPeriod, const uint8_t* ascBuf, const unsigned ascSize,
const uint32_t creatTime = 0, const char vbrQuality = 0); const uint32_t creatTime = 0, const char vbrQuality = 0);
void reset (const unsigned frameLength = 0, const unsigned pregapLength = 0, const unsigned raPeriod = 0); void reset (const unsigned frameLength, const unsigned pregapLength, const unsigned raPeriod, const unsigned sampleRate);
#ifndef NO_PREROLL_DATA #ifndef NO_PREROLL_DATA
int updateIPFs (const uint8_t* ascUcBuf, const uint32_t ascUcLength, const uint32_t ucOffset); int updateIPFs (const uint8_t* ascUcBuf, const uint32_t ascUcLength, const uint32_t ucOffset);
#endif #endif

View File

@@ -118,9 +118,10 @@ unsigned BasicWavReader::readDataFloat16 (const int fileHandle, int32_t* frameBu
const unsigned chanCount, void* tempBuf) const unsigned chanCount, void* tempBuf)
{ {
#if BWR_BUFFERED_READ #if BWR_BUFFERED_READ
const unsigned rest = ((frameCount >> (BWR_READ_FRACT - 1)) << (BWR_READ_FRACT - 1)) < frameCount ? 1 : 0;
unsigned framesRead = 0; unsigned framesRead = 0;
for (unsigned fract = 0; fract < (1 << BWR_READ_FRACT); fract++) for (unsigned fract = 0; fract < (1 << BWR_READ_FRACT) + rest; fract++)
{ {
const int16_t* fBuf = (const int16_t*) tempBuf; // words const int16_t* fBuf = (const int16_t*) tempBuf; // words
const unsigned size = (frameCount + ((fract & 1) > 0 ? 1 << (BWR_READ_FRACT - 1) : 0)) >> BWR_READ_FRACT; const unsigned size = (frameCount + ((fract & 1) > 0 ? 1 << (BWR_READ_FRACT - 1) : 0)) >> BWR_READ_FRACT;
@@ -168,9 +169,10 @@ unsigned BasicWavReader::readDataFloat32 (const int fileHandle, int32_t* frameBu
const unsigned chanCount, void* tempBuf) const unsigned chanCount, void* tempBuf)
{ {
#if BWR_BUFFERED_READ #if BWR_BUFFERED_READ
const unsigned rest = ((frameCount >> (BWR_READ_FRACT - 1)) << (BWR_READ_FRACT - 1)) < frameCount ? 1 : 0;
unsigned framesRead = 0; unsigned framesRead = 0;
for (unsigned fract = 0; fract < (1 << BWR_READ_FRACT); fract++) for (unsigned fract = 0; fract < (1 << BWR_READ_FRACT) + rest; fract++)
{ {
const float* fBuf = (const float*) tempBuf; // 4 bytes const float* fBuf = (const float*) tempBuf; // 4 bytes
const unsigned size = (frameCount + ((fract & 1) > 0 ? 1 << (BWR_READ_FRACT - 1) : 0)) >> BWR_READ_FRACT; const unsigned size = (frameCount + ((fract & 1) > 0 ? 1 << (BWR_READ_FRACT - 1) : 0)) >> BWR_READ_FRACT;
@@ -216,9 +218,10 @@ unsigned BasicWavReader::readDataLnPcm08 (const int fileHandle, int32_t* frameBu
const unsigned chanCount, void* tempBuf) const unsigned chanCount, void* tempBuf)
{ {
#if BWR_BUFFERED_READ #if BWR_BUFFERED_READ
const unsigned rest = ((frameCount >> (BWR_READ_FRACT - 1)) << (BWR_READ_FRACT - 1)) < frameCount ? 1 : 0;
unsigned framesRead = 0; unsigned framesRead = 0;
for (unsigned fract = 0; fract < (1 << BWR_READ_FRACT); fract++) for (unsigned fract = 0; fract < (1 << BWR_READ_FRACT) + rest; fract++)
{ {
const uint8_t* iBuf = (const uint8_t*) tempBuf; // 1b const uint8_t* iBuf = (const uint8_t*) tempBuf; // 1b
const unsigned size = (frameCount + ((fract & 1) > 0 ? 1 << (BWR_READ_FRACT - 1) : 0)) >> BWR_READ_FRACT; const unsigned size = (frameCount + ((fract & 1) > 0 ? 1 << (BWR_READ_FRACT - 1) : 0)) >> BWR_READ_FRACT;
@@ -254,9 +257,10 @@ unsigned BasicWavReader::readDataLnPcm16 (const int fileHandle, int32_t* frameBu
const unsigned chanCount, void* tempBuf) const unsigned chanCount, void* tempBuf)
{ {
#if BWR_BUFFERED_READ #if BWR_BUFFERED_READ
const unsigned rest = ((frameCount >> (BWR_READ_FRACT - 1)) << (BWR_READ_FRACT - 1)) < frameCount ? 1 : 0;
unsigned framesRead = 0; unsigned framesRead = 0;
for (unsigned fract = 0; fract < (1 << BWR_READ_FRACT); fract++) for (unsigned fract = 0; fract < (1 << BWR_READ_FRACT) + rest; fract++)
{ {
const int16_t* iBuf = (const int16_t*) tempBuf; // words const int16_t* iBuf = (const int16_t*) tempBuf; // words
const unsigned size = (frameCount + ((fract & 1) > 0 ? 1 << (BWR_READ_FRACT - 1) : 0)) >> BWR_READ_FRACT; const unsigned size = (frameCount + ((fract & 1) > 0 ? 1 << (BWR_READ_FRACT - 1) : 0)) >> BWR_READ_FRACT;
@@ -292,9 +296,10 @@ unsigned BasicWavReader::readDataLnPcm24 (const int fileHandle, int32_t* frameBu
const unsigned chanCount, void* tempBuf) const unsigned chanCount, void* tempBuf)
{ {
#if BWR_BUFFERED_READ #if BWR_BUFFERED_READ
const unsigned rest = ((frameCount >> (BWR_READ_FRACT - 1)) << (BWR_READ_FRACT - 1)) < frameCount ? 1 : 0;
unsigned framesRead = 0; unsigned framesRead = 0;
for (unsigned fract = 0; fract < (1 << BWR_READ_FRACT); fract++) for (unsigned fract = 0; fract < (1 << BWR_READ_FRACT) + rest; fract++)
{ {
const uint8_t* iBuf = (const uint8_t*) tempBuf; // 3b const uint8_t* iBuf = (const uint8_t*) tempBuf; // 3b
const unsigned size = (frameCount + ((fract & 1) > 0 ? 1 << (BWR_READ_FRACT - 1) : 0)) >> BWR_READ_FRACT; const unsigned size = (frameCount + ((fract & 1) > 0 ? 1 << (BWR_READ_FRACT - 1) : 0)) >> BWR_READ_FRACT;
@@ -332,9 +337,10 @@ unsigned BasicWavReader::readDataLnPcm32 (const int fileHandle, int32_t* frameBu
const unsigned chanCount, void* tempBuf) const unsigned chanCount, void* tempBuf)
{ {
#if BWR_BUFFERED_READ #if BWR_BUFFERED_READ
const unsigned rest = ((frameCount >> (BWR_READ_FRACT - 1)) << (BWR_READ_FRACT - 1)) < frameCount ? 1 : 0;
unsigned framesRead = 0; unsigned framesRead = 0;
for (unsigned fract = 0; fract < (1 << BWR_READ_FRACT); fract++) for (unsigned fract = 0; fract < (1 << BWR_READ_FRACT) + rest; fract++)
{ {
const int32_t* iBuf = (const int32_t*) tempBuf; // dword const int32_t* iBuf = (const int32_t*) tempBuf; // dword
const unsigned size = (frameCount + ((fract & 1) > 0 ? 1 << (BWR_READ_FRACT - 1) : 0)) >> BWR_READ_FRACT; const unsigned size = (frameCount + ((fract & 1) > 0 ? 1 << (BWR_READ_FRACT - 1) : 0)) >> BWR_READ_FRACT;

View File

@@ -54,11 +54,10 @@
#define EA_PEAK_NORM -96.33f // 20 * log10(2^-16), 16-bit normalization #define EA_PEAK_NORM -96.33f // 20 * log10(2^-16), 16-bit normalization
#define EA_PEAK_MIN 0.262f // 20 * log10() + EA_PEAK_NORM = -108 dbFS #define EA_PEAK_MIN 0.262f // 20 * log10() + EA_PEAK_NORM = -108 dbFS
#define ENABLE_RESAMPLING 1 // 1: automatic input up- and downsampling #define ENABLE_RESAMPLING 1 // 1: automatic input up- and downsampling
#define ENABLE_SIMPLE_SBR 1 // 1: basic 2:1 low-rate SBR functionality
#define IGNORE_WAV_LENGTH 0 // 1: ignore input size indicators (nasty)
#define XHE_AAC_LOW_DELAY 0 // 1: allow encoding with 768 frame length #define XHE_AAC_LOW_DELAY 0 // 1: allow encoding with 768 frame length
#if ENABLE_RESAMPLING #if ENABLE_RESAMPLING
#define FULL_FRM_LOOKAHEAD // on: encoder delay = zero or frame length
static const int16_t usfc2x[32] = { // 2x upsampling filter coefficients static const int16_t usfc2x[32] = { // 2x upsampling filter coefficients
(83359-65536), -27563, 16273, -11344, 8541, -6708, 5403, -4419, 3647, -3025, 2514, -2088, 1730, (83359-65536), -27563, 16273, -11344, 8541, -6708, 5403, -4419, 3647, -3025, 2514, -2088, 1730,
-1428, 1173, -957, 775, -622, 494, -388, 300, -230, 172, -127, 91, -63, 43, -27, 16, -9, 4, -1 -1428, 1173, -957, 775, -622, 494, -388, 300, -230, 172, -127, 91, -63, 43, -27, 16, -9, 4, -1
@@ -382,14 +381,14 @@ int main (const int argc, char* argv[])
fprintf_s (stdout, " preset\t= # (0-9) low-complexity standard compliant xHE-AAC at 16<31>#+48 kbit/s\n"); fprintf_s (stdout, " preset\t= # (0-9) low-complexity standard compliant xHE-AAC at 16<31>#+48 kbit/s\n");
# if XHE_AAC_LOW_DELAY # if XHE_AAC_LOW_DELAY
fprintf_s (stdout, " \t (A-J) 41ms low-delay compatible xHE-AAC with BE at 16<31>#+48 kbit/s\n"); fprintf_s (stdout, " \t (A-J) 41ms low-delay compatible xHE-AAC with BE at 16<31>#+48 kbit/s\n");
# elif ENABLE_SIMPLE_SBR # else
fprintf_s (stdout, " \t (a-g) low-complexity compliant xHE-AAC with SBR at 12<31>#+36 kbit/s\n"); fprintf_s (stdout, " \t (a-g) low-complexity compliant xHE-AAC with SBR at 12<31>#+36 kbit/s\n");
# endif # endif
#else #else
fprintf_s (stdout, " preset\t= # (0-9) low-complexity standard compliant xHE-AAC at 16*#+48 kbit/s\n"); fprintf_s (stdout, " preset\t= # (0-9) low-complexity standard compliant xHE-AAC at 16*#+48 kbit/s\n");
# if XHE_AAC_LOW_DELAY # if XHE_AAC_LOW_DELAY
fprintf_s (stdout, " \t (A-J) 41ms low-delay compatible xHE-AAC with BE at 16*#+48 kbit/s\n"); fprintf_s (stdout, " \t (A-J) 41ms low-delay compatible xHE-AAC with BE at 16*#+48 kbit/s\n");
# elif ENABLE_SIMPLE_SBR # else
fprintf_s (stdout, " \t (a-g) low-complexity compliant xHE-AAC with SBR at 12*#+36 kbit/s\n"); fprintf_s (stdout, " \t (a-g) low-complexity compliant xHE-AAC with SBR at 12*#+36 kbit/s\n");
# endif # endif
#endif #endif
@@ -420,19 +419,13 @@ int main (const int argc, char* argv[])
// check preset mode, derive coder config // check preset mode, derive coder config
#if XHE_AAC_LOW_DELAY #if XHE_AAC_LOW_DELAY
if ((*argv[1] >= '0' && *argv[1] <= '9') || (*argv[1] >= 'A' && *argv[1] <= 'J')) if ((*argv[1] >= '0' && *argv[1] <= '9') || (*argv[1] >= 'A' && *argv[1] <= 'J'))
#elif ENABLE_SIMPLE_SBR
if ((*argv[1] >= '0' && *argv[1] <= '9') || (*argv[1] >= 'a' && *argv[1] <= 'g'))
#else #else
if (*argv[1] >= '0' && *argv[1] <= '9') if ((*argv[1] >= '0' && *argv[1] <= '9') || (*argv[1] >= 'a' && *argv[1] <= 'g'))
#endif #endif
{ {
i = (uint16_t) argv[1][0]; i = (uint16_t) argv[1][0];
compatibleExtensionFlag = (i & 0x40) >> 6; compatibleExtensionFlag = (i & 0x40) >> 6;
#if ENABLE_SIMPLE_SBR
coreSbrFrameLengthIndex = (i > 0x60 ? 5 : (i & 0x20) >> 5); coreSbrFrameLengthIndex = (i > 0x60 ? 5 : (i & 0x20) >> 5);
#else
coreSbrFrameLengthIndex = (i & 0x20) >> 5;
#endif
variableCoreBitRateMode = (i & 0x0F) - (i >> 6); variableCoreBitRateMode = (i & 0x0F) - (i >> 6);
} }
else if (*argv[1] == '#') // default mode else if (*argv[1] == '#') // default mode
@@ -447,18 +440,12 @@ int main (const int argc, char* argv[])
# else # else
fprintf_s (stderr, " ERROR reading preset mode: character %s is not supported! Use 0-9 or A-J.\n\n", argv[1]); fprintf_s (stderr, " ERROR reading preset mode: character %s is not supported! Use 0-9 or A-J.\n\n", argv[1]);
# endif # endif
#elif ENABLE_SIMPLE_SBR #else
# ifdef EXHALE_APP_WCHAR # ifdef EXHALE_APP_WCHAR
fwprintf_s (stderr, L" ERROR reading preset mode: character %s is not supported! Use 0-9 or a-g.\n\n", argv[1]); fwprintf_s (stderr, L" ERROR reading preset mode: character %s is not supported! Use 0-9 or a-g.\n\n", argv[1]);
# else # else
fprintf_s (stderr, " ERROR reading preset mode: character %s is not supported! Use 0-9 or a-g.\n\n", argv[1]); fprintf_s (stderr, " ERROR reading preset mode: character %s is not supported! Use 0-9 or a-g.\n\n", argv[1]);
# endif # endif
#else
# ifdef EXHALE_APP_WCHAR
fwprintf_s (stderr, L" ERROR reading preset mode: character %s is not supported! Please use 0-9.\n\n", argv[1]);
# else
fprintf_s (stderr, " ERROR reading preset mode: character %s is not supported! Please use 0-9.\n\n", argv[1]);
# endif
#endif #endif
return 16384; // preset isn't supported return 16384; // preset isn't supported
} }
@@ -542,18 +529,14 @@ int main (const int argc, char* argv[])
#else // Linux, MacOS, Unix #else // Linux, MacOS, Unix
if ((wavReader.open (inFileHandle, startLength, readStdin ? LLONG_MAX : lseek (inFileHandle, 0, 2 /*SEEK_END*/)) != 0) || if ((wavReader.open (inFileHandle, startLength, readStdin ? LLONG_MAX : lseek (inFileHandle, 0, 2 /*SEEK_END*/)) != 0) ||
#endif #endif
#if ENABLE_SIMPLE_SBR (wavReader.getSampleRate () >= 1000 && wavReader.getSampleRate () < 24000 && coreSbrFrameLengthIndex >= 3) || (wavReader.getNumChannels () >= 7))
(wavReader.getSampleRate () >= 1000 && wavReader.getSampleRate () < 24000 && coreSbrFrameLengthIndex >= 3) ||
#endif
(wavReader.getNumChannels () >= 7))
{ {
fprintf_s (stderr, " ERROR while trying to open WAVE file: invalid or unsupported audio format!\n\n"); fprintf_s (stderr, " ERROR while trying to open WAVE file: invalid or unsupported audio format!\n\n");
#if ENABLE_SIMPLE_SBR
if (wavReader.getSampleRate () >= 1000 && wavReader.getSampleRate () < 24000 && coreSbrFrameLengthIndex >= 3) if (wavReader.getSampleRate () >= 1000 && wavReader.getSampleRate () < 24000 && coreSbrFrameLengthIndex >= 3)
{ {
fprintf_s (stderr, " The sampling rate is %d kHz but xHE-AAC with SBR requires at least 24 kHz.\n\n", wavReader.getSampleRate () / 1000); fprintf_s (stderr, " The sampling rate is %d kHz but xHE-AAC with SBR requires at least 24 kHz.\n\n", wavReader.getSampleRate () / 1000);
} }
#endif
i = 8192; // return value i = 8192; // return value
goto mainFinish; // audio format invalid goto mainFinish; // audio format invalid
@@ -582,14 +565,11 @@ int main (const int argc, char* argv[])
goto mainFinish; // bad output string goto mainFinish; // bad output string
} }
if (wavReader.getSampleRate () > 32100 + (unsigned) variableCoreBitRateMode * 12000 + (variableCoreBitRateMode >> 2) * 3900 if ((wavReader.getSampleRate () > 32100 + (unsigned) variableCoreBitRateMode * 12000 + (variableCoreBitRateMode >> 2) * 3900) &&
#if ENABLE_SIMPLE_SBR
&& (coreSbrFrameLengthIndex < 3)
#endif
#if ENABLE_RESAMPLING #if ENABLE_RESAMPLING
&& (variableCoreBitRateMode > 1 || wavReader.getSampleRate () != 48000) (variableCoreBitRateMode > 1 || wavReader.getSampleRate () != 48000) &&
#endif #endif
) (coreSbrFrameLengthIndex < 3))
{ {
i = (variableCoreBitRateMode > 4 ? 96 : __min (64, 32 + variableCoreBitRateMode * 12)); i = (variableCoreBitRateMode > 4 ? 96 : __min (64, 32 + variableCoreBitRateMode * 12));
fprintf_s (stderr, " ERROR during encoding! Input sample rate must be <=%d kHz for preset mode %d!\n\n", i, variableCoreBitRateMode); fprintf_s (stderr, " ERROR during encoding! Input sample rate must be <=%d kHz for preset mode %d!\n\n", i, variableCoreBitRateMode);
@@ -597,11 +577,7 @@ int main (const int argc, char* argv[])
goto mainFinish; // ask for resampling goto mainFinish; // ask for resampling
} }
#if ENABLE_SIMPLE_SBR if ((wavReader.getSampleRate () > 32000) && (coreSbrFrameLengthIndex < 3) && (variableCoreBitRateMode <= 1))
if (wavReader.getSampleRate () > 32000 && coreSbrFrameLengthIndex < 3 && variableCoreBitRateMode <= 1)
#else
if (wavReader.getSampleRate () > 32000 && variableCoreBitRateMode <= 1)
#endif
{ {
#if ENABLE_RESAMPLING #if ENABLE_RESAMPLING
if (wavReader.getSampleRate () == 48000) if (wavReader.getSampleRate () == 48000)
@@ -658,18 +634,19 @@ int main (const int argc, char* argv[])
{ {
const unsigned numChannels = wavReader.getNumChannels (); const unsigned numChannels = wavReader.getNumChannels ();
const unsigned inSampDepth = wavReader.getBitDepth (); const unsigned inSampDepth = wavReader.getBitDepth ();
const unsigned sbrEncDelay = (coreSbrFrameLengthIndex >= 3 ? 962 : 0);
#if ENABLE_RESAMPLING #if ENABLE_RESAMPLING
const bool enableUpsampler = eaInitUpsampler2x (&inPcmRsmp, variableCoreBitRateMode, i, frameLength, numChannels); const bool enableUpsampler = eaInitUpsampler2x (&inPcmRsmp, variableCoreBitRateMode, i, frameLength, numChannels);
# if ENABLE_SIMPLE_SBR
const bool enableResampler = (coreSbrFrameLengthIndex >= 3 ? false : // no 3:2 downsampling needed when using SBR const bool enableResampler = (coreSbrFrameLengthIndex >= 3 ? false : // no 3:2 downsampling needed when using SBR
eaInitDownsampler (&inPcmRsmp, variableCoreBitRateMode, i, frameLength, numChannels)); eaInitDownsampler (&inPcmRsmp, variableCoreBitRateMode, i, frameLength, numChannels));
# else
const bool enableResampler = eaInitDownsampler (&inPcmRsmp, variableCoreBitRateMode, i, frameLength, numChannels);
# endif
const uint16_t firstLength = uint16_t (enableUpsampler ? (frameLength >> 1) + 32 : (enableResampler ? startLength : frameLength)); const uint16_t firstLength = uint16_t (enableUpsampler ? (frameLength >> 1) + 32 : (enableResampler ? startLength : frameLength));
const unsigned inFrameSize = (enableResampler ? startLength : frameLength) * sizeof (int32_t); // max buffer size const unsigned inFrameSize = (enableResampler ? startLength : frameLength) * sizeof (int32_t); // max buffer size
const unsigned resampRatio = (enableResampler ? 3 : 1); // for resampling ratio const unsigned resampRatio = (enableResampler ? 3 : 1); // for resampling ratio
const unsigned resampShift = (enableResampler || enableUpsampler ? 1 : 0); const unsigned resampShift = (enableResampler || enableUpsampler ? 1 : 0);
# ifdef FULL_FRM_LOOKAHEAD
const uint16_t inPadLength = uint16_t ((((frameLength << 1) - startLength) * resampRatio) >> resampShift)
+ (coreSbrFrameLengthIndex >= 3 ? firstLength - (sbrEncDelay >> resampShift) : 0);
# endif
const int64_t expectLength = (wavReader.getDataBytesLeft () << resampShift) / int64_t ((numChannels * inSampDepth * resampRatio) >> 3); const int64_t expectLength = (wavReader.getDataBytesLeft () << resampShift) / int64_t ((numChannels * inSampDepth * resampRatio) >> 3);
if (enableUpsampler) // notify by printf if (enableUpsampler) // notify by printf
@@ -696,7 +673,13 @@ int main (const int argc, char* argv[])
} }
#if ENABLE_RESAMPLING #if ENABLE_RESAMPLING
# ifdef FULL_FRM_LOOKAHEAD
memset (inPcmData, 0, inPadLength * numChannels * sizeof (int32_t)); // padding
if (inPadLength + wavReader.read (inPcmData + inPadLength * numChannels, firstLength - inPadLength) != firstLength)
# else
if (wavReader.read (inPcmData, firstLength) != firstLength) // full first frame if (wavReader.read (inPcmData, firstLength) != firstLength) // full first frame
# endif
#else #else
if (wavReader.read (inPcmData, frameLength) != frameLength) // full first frame if (wavReader.read (inPcmData, frameLength) != frameLength) // full first frame
#endif #endif
@@ -737,11 +720,16 @@ int main (const int argc, char* argv[])
// init encoder, generate UsacConfig() // init encoder, generate UsacConfig()
memset (outAuData, 0, 108 * sizeof (uint8_t)); // max. allowed ASC + UC size memset (outAuData, 0, 108 * sizeof (uint8_t)); // max. allowed ASC + UC size
#ifdef FULL_FRM_LOOKAHEAD
outAuData[0] = 1; // to skip 1st frame
#endif
i = exhaleEnc.initEncoder (outAuData, &bw); // bw stores actual ASC + UC size i = exhaleEnc.initEncoder (outAuData, &bw); // bw stores actual ASC + UC size
if ((i |= mp4Writer.open (outFileHandle, sampleRate, numChannels, inSampDepth, frameLength, startLength if ((i |= mp4Writer.open (outFileHandle, sampleRate, numChannels, inSampDepth, frameLength,
#if ENABLE_SIMPLE_SBR #ifdef FULL_FRM_LOOKAHEAD
+ (coreSbrFrameLengthIndex >= 3 ? 962 : 0) (frameLength << (coreSbrFrameLengthIndex >= 3 ? 1 : 0))
#else
startLength + sbrEncDelay
#endif #endif
#ifndef NO_PREROLL_DATA #ifndef NO_PREROLL_DATA
- frameLength - frameLength
@@ -759,12 +747,8 @@ int main (const int argc, char* argv[])
if (*argv[1] != '#') // user-def. mode if (*argv[1] != '#') // user-def. mode
{ {
fprintf_s (stdout, " Encoding %d-kHz %d-channel %d-bit WAVE to low-complexity xHE-AAC at %d kbit/s\n\n", fprintf_s (stdout, " Encoding %d-kHz %d-channel %d-bit WAVE to low-complexity xHE-AAC at %d kbit/s\n\n",
#if ENABLE_SIMPLE_SBR
sampleRate / 1000, numChannels, inSampDepth, __min (5, numChannels) * (((24 + variableCoreBitRateMode * 8) * sampleRate / 1000, numChannels, inSampDepth, __min (5, numChannels) * (((24 + variableCoreBitRateMode * 8) *
(coreSbrFrameLengthIndex >= 3 ? 3 : 4)) >> 2)); (coreSbrFrameLengthIndex >= 3 ? 3 : 4)) >> 2));
#else
sampleRate / 1000, numChannels, inSampDepth, __min (5, numChannels) * (24 + variableCoreBitRateMode * 8));
#endif
} }
if (!readStdin && (mod3Percent > 0)) if (!readStdin && (mod3Percent > 0))
{ {
@@ -777,20 +761,20 @@ int main (const int argc, char* argv[])
fprintf_s (stdout, EXHALE_TEXT_BLUE " Progress: " EXHALE_TEXT_INIT "-"); fflush (stdout); fprintf_s (stdout, EXHALE_TEXT_BLUE " Progress: " EXHALE_TEXT_INIT "-"); fflush (stdout);
#endif #endif
} }
#if !IGNORE_WAV_LENGTH
if (!readStdin) // reserve space for MP4 file header. TODO: nasty, avoid this if (!readStdin) // reserve space for MP4 file header. TODO: nasty, avoid this
{ {
if ((headerRes = (uint32_t) mp4Writer.initHeader (uint32_t (__min (UINT_MAX - startLength, expectLength)))) < 666) if ((headerRes = (uint32_t) mp4Writer.initHeader (uint32_t (__min (UINT_MAX - startLength, expectLength)), sbrEncDelay)) < 666)
{ {
fprintf_s (stderr, "\n ERROR while trying to write MPEG-4 bit-stream header: stopped after %d bytes!\n\n", headerRes); fprintf_s (stderr, "\n ERROR while trying to write MPEG-4 bit-stream header: stopped after %d bytes!\n\n", headerRes);
i = 3; // return value i = 3; // return value
# if USE_EXHALELIB_DLL #if USE_EXHALELIB_DLL
exhaleDelete (&exhaleEnc); exhaleDelete (&exhaleEnc);
# endif #endif
goto mainFinish; // writeout error goto mainFinish; // writeout error
} }
} }
#endif
i = 1; // for progress bar i = 1; // for progress bar
#if ENABLE_RESAMPLING #if ENABLE_RESAMPLING
@@ -809,6 +793,25 @@ int main (const int argc, char* argv[])
#endif #endif
goto mainFinish; // coder-time error goto mainFinish; // coder-time error
} }
#ifdef FULL_FRM_LOOKAHEAD
wavReader.read (inPcmData, (frameLength * resampRatio) >> resampShift); // discard the initial look-ahead AU
// resample leading frame if necessary
if (enableUpsampler) eaApplyUpsampler2x (inPcmData, inPcmRsmp, frameLength, numChannels);
else
if (enableResampler) eaApplyDownsampler (inPcmData, inPcmRsmp, frameLength, numChannels);
// leading frame, actual look-ahead AU
if ((bw = exhaleEnc.encodeFrame ()) < 3)
{
fprintf_s (stderr, "\n ERROR while trying to create first xHE-AAC frame: error value %d was returned!\n\n", bw);
i = 2; // return value
# if USE_EXHALELIB_DLL
exhaleDelete (&exhaleEnc);
# endif
goto mainFinish; // coder-time error
}
#endif
#ifdef NO_PREROLL_DATA #ifdef NO_PREROLL_DATA
if (bwMax < bw) bwMax = bw; if (bwMax < bw) bwMax = bw;
// write first AU, add frame to header // write first AU, add frame to header
@@ -864,11 +867,7 @@ int main (const int argc, char* argv[])
if (!readStdin && (mod3Percent > 0) && !(mp4Writer.getFrameCount () % mod3Percent)) if (!readStdin && (mod3Percent > 0) && !(mp4Writer.getFrameCount () % mod3Percent))
{ {
#if ENABLE_SIMPLE_SBR
if ((i++) < (coreSbrFrameLengthIndex >= 3 ? 17 : 34)) // with short files if ((i++) < (coreSbrFrameLengthIndex >= 3 ? 17 : 34)) // with short files
#else
if ((i++) < 34) // for short files
#endif
{ {
fprintf_s (stdout, "-"); fflush (stdout); fprintf_s (stdout, "-"); fflush (stdout);
} }
@@ -904,13 +903,22 @@ int main (const int argc, char* argv[])
#if ENABLE_RESAMPLING #if ENABLE_RESAMPLING
const int64_t actualLength = (wavReader.getDataBytesRead () << resampShift) / int64_t ((numChannels * inSampDepth * resampRatio) >> 3); const int64_t actualLength = (wavReader.getDataBytesRead () << resampShift) / int64_t ((numChannels * inSampDepth * resampRatio) >> 3);
const int64_t inFileLength = wavReader.getDataBytesRead () / int64_t ((numChannels * inSampDepth) >> 3);
const unsigned inFrmLength = (frameLength * resampRatio) >> resampShift;
# ifdef FULL_FRM_LOOKAHEAD
const unsigned flushLength = (inFileLength - (enableUpsampler ? 32 : 0) + inPadLength) % inFrmLength;
# else
const unsigned flushLength = (inFileLength - (enableUpsampler ? 32 : 0)) % inFrmLength;
# endif
if ((flushLength == 0) || (flushLength + ((startLength * resampRatio) >> resampShift) - inFrmLength // flush
+ (enableUpsampler ? 32 : 0) + wavReader.getSampleRate () / 200 > inFrmLength))
#else #else
const int64_t actualLength = wavReader.getDataBytesRead () / int64_t ((numChannels * inSampDepth) >> 3); const int64_t actualLength = wavReader.getDataBytesRead () / int64_t ((numChannels * inSampDepth) >> 3);
const unsigned flushLength = actualLength % frameLength;
if ((flushLength == 0) || (flushLength + startLength - frameLength + sampleRate/200 > frameLength)) // flush
#endif #endif
/* NOTE: the following "if" is, as far as I can tell, correct, but some decoders {
with DRC processing may decode too few samples with it. Hence, I disabled it.
if (((actualLength + startLength) % frameLength) > 0) // flush trailing audio
*/ {
memset (inPcmData, 0, inFrameSize * numChannels); memset (inPcmData, 0, inFrameSize * numChannels);
#if ENABLE_RESAMPLING #if ENABLE_RESAMPLING
// resample flush frame if necessary // resample flush frame if necessary
@@ -940,13 +948,11 @@ int main (const int argc, char* argv[])
byteCount += bw; byteCount += bw;
} // trailing frame } // trailing frame
#if !IGNORE_WAV_LENGTH
if (readStdin) // reserve space for MP4 file header (is there an easier way?) if (readStdin) // reserve space for MP4 file header (is there an easier way?)
#endif
{ {
int64_t pos = _SEEK (outFileHandle, 0, 1 /*SEEK_CUR*/); int64_t pos = _SEEK (outFileHandle, 0, 1 /*SEEK_CUR*/);
if ((headerRes = (uint32_t) mp4Writer.initHeader (uint32_t (__min (UINT_MAX - startLength, actualLength)))) < 666) if ((headerRes = (uint32_t) mp4Writer.initHeader (uint32_t (__min (UINT_MAX - startLength, actualLength)), sbrEncDelay)) < 666)
{ {
fprintf_s (stderr, "\n ERROR while trying to write MPEG-4 bit-stream header: stopped after %d bytes!\n\n", headerRes); fprintf_s (stderr, "\n ERROR while trying to write MPEG-4 bit-stream header: stopped after %d bytes!\n\n", headerRes);
i = 3; // return value i = 3; // return value
@@ -990,7 +996,7 @@ int main (const int argc, char* argv[])
if (i == 0) if (i == 0)
{ {
i = __min (USHRT_MAX, wavReader.getSampleRate ()); i = __min (USHRT_MAX, wavReader.getSampleRate ());
i = (uint16_t) mp4Writer.updateIPFs (outAuData, bw, (i == 57600 || i == 38400 || i == 19200 /*BL USAC*/ ? 6 : 3)); i = (uint16_t) mp4Writer.updateIPFs (outAuData, bw, (i == 57600 || i == 38400 || i == 28800 || i == 19200 /*BL USAC*/ ? 6 : 3));
} }
#endif #endif
} }
@@ -1000,14 +1006,14 @@ int main (const int argc, char* argv[])
bw = mp4Writer.finishFile (br, bw, uint32_t (__min (UINT_MAX - startLength, actualLength)), (time (nullptr) + 2082844800) & UINT_MAX, bw = mp4Writer.finishFile (br, bw, uint32_t (__min (UINT_MAX - startLength, actualLength)), (time (nullptr) + 2082844800) & UINT_MAX,
(i == 0) && (numChannels < 7) ? outAuData : nullptr); (i == 0) && (numChannels < 7) ? outAuData : nullptr);
// print out collected file statistics // print out collected file statistics
#if ENABLE_SIMPLE_SBR
if (coreSbrFrameLengthIndex >= 3) if (coreSbrFrameLengthIndex >= 3)
{ {
fprintf_s (stdout, " Done, actual average incl. SBR data %.2f kbit/s\n\n", (float) br * 0.001f); fprintf_s (stdout, " Done, actual average incl. SBR data %.2f kbit/s\n\n", (float) br * 0.001f);
} }
else else
#endif {
fprintf_s (stdout, " Done, actual average %.1f kbit/s\n\n", (float) br * 0.001f); fprintf_s (stdout, " Done, actual average %.1f kbit/s\n\n", (float) br * 0.001f);
}
if (numChannels < 7) if (numChannels < 7)
{ {
fprintf_s (stdout, " Input statistics: File loudness %.2f LUFS,\tsample peak level %.2f dBFS\n\n", fprintf_s (stdout, " Input statistics: File loudness %.2f LUFS,\tsample peak level %.2f dBFS\n\n",

View File

@@ -1691,7 +1691,6 @@ unsigned ExhaleEncoder::temporalProcessing () // determine time-domain aspects o
tsCurr[ch] = (m_tempAnaCurr[ci] /*R*/) & UCHAR_MAX; tsCurr[ch] = (m_tempAnaCurr[ci] /*R*/) & UCHAR_MAX;
tsNext[ch] = (m_tempAnaNext[ci] >> 8) & UCHAR_MAX; tsNext[ch] = (m_tempAnaNext[ci] >> 8) & UCHAR_MAX;
// save maximum spectral flatness of current and neighboring frames for quantization // save maximum spectral flatness of current and neighboring frames for quantization
// m_specFlatPrev[ci] = __max (m_specFlatPrev[ci], (m_specAnaCurr[ci] >> 16) & UCHAR_MAX);
m_tempAnaCurr [ci] = (m_tempAnaCurr[ci] & 0xFFFFFF) | (__max (sfCurr, __max (m_specFlatPrev[ci], sfNext)) << 24); m_tempAnaCurr [ci] = (m_tempAnaCurr[ci] & 0xFFFFFF) | (__max (sfCurr, __max (m_specFlatPrev[ci], sfNext)) << 24);
m_specFlatPrev[ci] = (uint8_t) sfCurr; m_specFlatPrev[ci] = (uint8_t) sfCurr;
@@ -2155,7 +2154,9 @@ unsigned ExhaleEncoder::initEncoder (unsigned char* const audioConfigBuffer, uin
if ((errorValue == 0) && (audioConfigBuffer != nullptr)) // save UsacConfig() for writeout if ((errorValue == 0) && (audioConfigBuffer != nullptr)) // save UsacConfig() for writeout
{ {
const uint32_t loudnessInfo = (audioConfigBytes ? *audioConfigBytes : 0); const uint32_t loudnessInfo = (audioConfigBytes ? *audioConfigBytes : 0);
#if 1 //FULL_FRM_LOOKAHEAD
if (*audioConfigBuffer > 0) m_frameCount--; // to skip 1 frame
#endif
errorValue = m_outStream.createAudioConfig (m_frequencyIdx, m_frameLength != CCFL_1024, chConf, m_numElements, errorValue = m_outStream.createAudioConfig (m_frequencyIdx, m_frameLength != CCFL_1024, chConf, m_numElements,
elementTypeConfig[chConf], loudnessInfo, elementTypeConfig[chConf], loudnessInfo,
#if !RESTRICT_TO_AAC #if !RESTRICT_TO_AAC