diff --git a/src/app/basicMP4Writer.cpp b/src/app/basicMP4Writer.cpp index 42c2c33..057f8cf 100644 --- a/src/app/basicMP4Writer.cpp +++ b/src/app/basicMP4Writer.cpp @@ -105,7 +105,12 @@ int BasicMP4Writer::finishFile (const unsigned avgBitrate, const unsigned maxBit const uint32_t stscAtomSize = STSX_BSIZE + (numFramesFinalPeriod == 0 ? 12 : 24); const uint32_t stcoAtomSize = STSX_BSIZE + (uint32_t) m_rndAccOffsets.size () * 4; #ifndef NO_FIX_FOR_ISSUE_1 - const uint32_t stssAtomSize = STSX_BSIZE; +# ifndef NO_FIX_FOR_ISSUE_13 + const uint32_t chunkCount = (m_frameCount + m_rndAccPeriod - 1) / m_rndAccPeriod; + const uint32_t stssAtomSize = STSX_BSIZE + chunkCount * 4; +# else + const uint32_t stssAtomSize = STSX_BSIZE + 4; +# endif // The following code creates a 'prol' sample group with a repeating pattern of membership, // indicating that the first sample in each increment of m_rndAccPeriod samples is a member // and therefore an independent frame (IF), and the remainder are not. @@ -244,8 +249,24 @@ int BasicMP4Writer::finishFile (const unsigned avgBitrate, const unsigned maxBit m_dynamicHeader.push_back (0x73); m_dynamicHeader.push_back (0x73); // stss m_dynamicHeader.push_back (0x00); m_dynamicHeader.push_back (0x00); m_dynamicHeader.push_back (0x00); m_dynamicHeader.push_back (0x00); +# ifndef NO_FIX_FOR_ISSUE_13 + m_dynamicHeader.push_back ((chunkCount >> 24) & UCHAR_MAX); + m_dynamicHeader.push_back ((chunkCount >> 16) & UCHAR_MAX); + m_dynamicHeader.push_back ((chunkCount >> 8) & UCHAR_MAX); + m_dynamicHeader.push_back ( chunkCount & UCHAR_MAX); + for (uint32_t i = 1; i <= m_frameCount; i += m_rndAccPeriod) + { + m_dynamicHeader.push_back ((i >> 24) & UCHAR_MAX); + m_dynamicHeader.push_back ((i >> 16) & UCHAR_MAX); + m_dynamicHeader.push_back ((i >> 8) & UCHAR_MAX); + m_dynamicHeader.push_back ( i & UCHAR_MAX); + } +# else m_dynamicHeader.push_back (0x00); m_dynamicHeader.push_back (0x00); + m_dynamicHeader.push_back (0x00); m_dynamicHeader.push_back (0x01); // 1 entry m_dynamicHeader.push_back (0x00); m_dynamicHeader.push_back (0x00); + m_dynamicHeader.push_back (0x00); m_dynamicHeader.push_back (0x01); // 1st AU +# endif m_dynamicHeader.push_back ((sgpdAtomSize >> 24) & UCHAR_MAX); m_dynamicHeader.push_back ((sgpdAtomSize >> 16) & UCHAR_MAX); m_dynamicHeader.push_back ((sgpdAtomSize >> 8) & UCHAR_MAX); @@ -372,7 +393,11 @@ int BasicMP4Writer::initHeader (const uint32_t audioLength) // reserve bytes for const unsigned finalChunk = (frameCount <= m_rndAccPeriod ? 0 : frameCount % m_rndAccPeriod); #ifndef NO_FIX_FOR_ISSUE_1 const unsigned smpGrpSize = 10 /*sgpd*/ + (m_rndAccPeriod > UINT8_MAX ? 10 : 9) + ((m_rndAccPeriod + 1) >> 1) /*csgp*/; - const int estimHeaderSize = STAT_HEADER_SIZE + m_ascSizeM5 + 6+4 + frameCount * 4 /*stsz*/ + STSX_BSIZE * 6 + smpGrpSize + +# ifndef NO_FIX_FOR_ISSUE_13 + const int estimHeaderSize = STAT_HEADER_SIZE + m_ascSizeM5 + 6+4 + frameCount * 4 /*stsz*/ + STSX_BSIZE * 6 + smpGrpSize + chunkCount * 4 /*stss*/ + +# else + const int estimHeaderSize = STAT_HEADER_SIZE + m_ascSizeM5 + 6+4 + frameCount * 4 /*stsz*/ + STSX_BSIZE * 6 + smpGrpSize + 4 /*stss*/ + +# endif #else const int estimHeaderSize = STAT_HEADER_SIZE + m_ascSizeM5 + 6+4 + frameCount * 4 /*stsz*/ + STSX_BSIZE * 3 + #endif diff --git a/src/lib/bitAllocation.cpp b/src/lib/bitAllocation.cpp index ea9fc63..7b57618 100644 --- a/src/lib/bitAllocation.cpp +++ b/src/lib/bitAllocation.cpp @@ -432,6 +432,9 @@ unsigned BitAllocator::imprSfbStepSizes (const SfbGroupData* const groupData[USA const SfbGroupData& grpData = *groupData[ch]; const uint32_t maxSfbInCh = __min (MAX_NUM_SWB_LONG, grpData.sfbsPerGroup); const bool eightShorts = (grpData.numWindowGroups != 1); +#if 1 + const bool lowRateTuning = (samplingRate >= 27713) && (sfm[ch] <= (SCHAR_MAX >> 1)); +#endif const uint32_t* rms = grpData.sfbRmsValues; uint32_t* stepSizes = &sfbStepSizes[ch * numSwbShort * NUM_WINDOW_GROUPS]; @@ -450,7 +453,25 @@ unsigned BitAllocator::imprSfbStepSizes (const SfbGroupData* const groupData[USA uint64_t s = (eightShorts ? (nSamplesInFrame * grpData.windowGroupLength[gr]) >> 1 : nSamplesInFrame << 2); memset (m_tempSfbValue, UCHAR_MAX, maxSfbInCh * sizeof (uint8_t)); +#if 1 + if ((m_rateIndex == 0) && lowRateTuning && (maxSfbInCh > 0) && !eightShorts) + { + uint32_t numRedBands = nSamplesInFrame; // final result lies between 1/4 and 1/2 + if ((nChannels == 2) && commonWindow && (grpSte != nullptr)) + { + for (b = 0; b < maxSfbInCh; b++) if (grpSte[b] == 0) numRedBands += grpOff[b + 1] - grpOff[b]; + } + b = MAX_NUM_SWB_LONG - ((numRedBands * ((SCHAR_MAX >> 1) + 1 - sfm[ch]) + (1 << 11)) >> 12); + + while ((b < maxSfbInCh) && (grpRms[b] > grpRms[b - 1])) b++; // start after peak + + for (b += ((nChannels == 2) && commonWindow ? b & 1 : 0); b < maxSfbInCh; b++) + { + grpStepSizes[b] = __max (grpStepSizes[b], grpRms[b] >= (UINT_MAX >> 1) ? UINT_MAX : (grpRms[b] + 1) << 1); + } + } +#endif // undercoding reduction for case where large number of coefs is quantized to zero for (b = 0; b < maxSfbInCh; b++) { @@ -470,7 +491,7 @@ unsigned BitAllocator::imprSfbStepSizes (const SfbGroupData* const groupData[USA } if (grpRms[b] < grpRmsMin) grpRmsMin = grpRms[b]; #if 1 - if ((m_rateIndex > 0) || (samplingRate >= 27713 && sfm[ch] <= (SCHAR_MAX >> 1))) + if ((m_rateIndex > 0) || lowRateTuning) #endif if (rmsComp >= rmsRef9 && (rmsComp < (grpStepSizes[b] >> 1))) // zero-quantized { @@ -484,7 +505,7 @@ unsigned BitAllocator::imprSfbStepSizes (const SfbGroupData* const groupData[USA const uint32_t rmsRef9 = (commonWindow ? refRms[b] >> 9 : rmsComp); const uint8_t sfbWidth = grpOff[maxSfbL16k] - grpOff[b]; #if 1 - if ((m_rateIndex > 0) || (samplingRate >= 27713 && sfm[ch] <= (SCHAR_MAX >> 1))) + if ((m_rateIndex > 0) || lowRateTuning) #endif if (rmsComp >= rmsRef9) // check only first SFB above max_sfb for simplification { @@ -499,6 +520,12 @@ unsigned BitAllocator::imprSfbStepSizes (const SfbGroupData* const groupData[USA { grpStepSizes[b] = uint32_t ((__max (grpRmsMin, grpStepSizes[b]) * s * (m_tempSfbValue[b] + 1u) + (1u << 14)) >> 15); if (grpStepSizes[b] <= (grpRms[b] >> 11)) grpStepSizes[b] = __max (BA_EPS, grpRms[b] >> 11); +#if 1 + if ((m_rateIndex == 0) && lowRateTuning) + { + if ((grpStepSizes[b] > grpRms[b]) && ((grpStepSizes[b] >> 1) <= grpRms[b])) grpStepSizes[b] = grpRms[b]; + } +#endif } } // for gr } // for ch diff --git a/src/lib/exhaleEnc.cpp b/src/lib/exhaleEnc.cpp index b2488ee..2904b32 100644 --- a/src/lib/exhaleEnc.cpp +++ b/src/lib/exhaleEnc.cpp @@ -2076,7 +2076,7 @@ unsigned ExhaleEncoder::initEncoder (unsigned char* const audioConfigBuffer, uin // initialize coder class memory m_tempIntBuf = m_timeSignals[0]; - if (m_bitAllocator.initAllocMemory (&m_linPredictor, numSwbOffsetL[m_swbTableIdx] - 1, m_bitRateMode >> ((nChannels - 1) >> 1)) > 0 || + if (m_bitAllocator.initAllocMemory (&m_linPredictor, numSwbOffsetL[m_swbTableIdx] - 1, m_bitRateMode >> ((nChannels - 1) >> 2)) > 0 || #if EC_TRELLIS_OPT_CODING m_sfbQuantizer.initQuantMemory (nSamplesInFrame, numSwbOffsetL[m_swbTableIdx] - 1, m_bitRateMode, toSamplingRate (m_frequencyIdx)) > 0 || #else diff --git a/src/lib/specGapFilling.cpp b/src/lib/specGapFilling.cpp index 59ed2c6..491d18d 100644 --- a/src/lib/specGapFilling.cpp +++ b/src/lib/specGapFilling.cpp @@ -42,7 +42,7 @@ uint8_t SpecGapFiller::getSpecGapFillParams (const SfbQuantizer& sfbQuantizer, c const uint16_t sfbsPerGrp = grpData.sfbsPerGroup; const uint16_t windowNfso = noiseFillingStartOffset[grpData.numWindowGroups == 1 ? 0 : 1][nSamplesInFrame >> 10]; const bool saveRate = (samplingRate >= sampRateBitSave); - uint8_t scaleFacLim = 0; // limit range + uint8_t scaleFacLim = 0; uint16_t u = 0; short diff = 0, s = 0; double magnSum = 0.0; @@ -181,7 +181,7 @@ uint8_t SpecGapFiller::getSpecGapFillParams (const SfbQuantizer& sfbQuantizer, c u = __max (1, u - int (specFlat >> 5)); // SFM-adaptive reduction magnSum = pow (2.0, (14 - u) / 3.0); // noiseVal^-1, 23003-3, 7.2 - magnSum *= 1.25 - specFlat * 0.0009765625; // zero-quant increase + magnSum *= 1.25 - specFlat * 0.0009765625; // --- calculate gap-fill scale factors for zero quantized SFBs, then determine noise_offset u <<= 5; // left-shift for bit-stream @@ -236,6 +236,7 @@ uint8_t SpecGapFiller::getSpecGapFillParams (const SfbQuantizer& sfbQuantizer, c #if SGF_SF_PEAK_SMOOTHING else if (saveRate) lastNonZeroSfb = b; #endif + if ((b > m_1stGapFillSfb) && (((grpRms[b - 1] >> 16) > 0) ^ ((grpRms[b - 2] >> 16) > 0))) { diff += (int) grpScFacs[b - 1] - (int) grpScFacs[b - 2]; // sum up transition deltas @@ -248,7 +249,7 @@ uint8_t SpecGapFiller::getSpecGapFillParams (const SfbQuantizer& sfbQuantizer, c const int32_t start = lastNonZeroSfb + 1; const int32_t size = sfbsPerGrp - start - 1; const int32_t xSum = (size * (size + 1)) >> 1; - int32_t ySum = 0, a = 0, b = 0; + int32_t ySum = 0, a = 0, b = 0, y = 0; uint16_t x; for (x = start + 1; x < sfbsPerGrp; x++) ySum += grpScFacs[x]; // size * (mean factor) @@ -256,11 +257,14 @@ uint8_t SpecGapFiller::getSpecGapFillParams (const SfbQuantizer& sfbQuantizer, c for (x = start + 1; x < sfbsPerGrp; x++) { const int32_t xZ = size * (x - start) - xSum; // zero-mean + const int32_t yZ = size * grpScFacs[x] - ySum; a += xZ * xZ; - b += xZ * (size * grpScFacs[x] - ySum); + b += xZ * yZ; + y += yZ * yZ; } - if (a > 0) // complete line and adjust gap-fill scale factors + + if ((a > 0) && (b * b > ((a * y) >> 3))) // factor smoothing { unsigned countOld = 0, countNew = 0; @@ -270,7 +274,7 @@ uint8_t SpecGapFiller::getSpecGapFillParams (const SfbQuantizer& sfbQuantizer, c ySum = grpScFacs[start]; for (x = start + 1; x < sfbsPerGrp; x++) { - const int32_t y = CLIP_UCHAR ((a + b * (x - start) - SCHAR_MIN) >> 8); + y = CLIP_UCHAR ((a + b * (x - start) - SCHAR_MIN) >> 8); countOld += huffBitCountEstimate ((int) grpScFacs[x] - grpScFacs[x - 1]); countNew += huffBitCountEstimate (y - ySum); @@ -307,7 +311,7 @@ uint8_t SpecGapFiller::getSpecGapFillParams (const SfbQuantizer& sfbQuantizer, c if (grpScFacs[b] > scaleFacLim) grpScFacs[b] = scaleFacLim; } - } // for b + } // repeat first significant scale factor downwards to save bits memset (grpScFacs, grpScFacs[m_1stNonZeroSfb[gr]], m_1stNonZeroSfb[gr] * sizeof (uint8_t));