diff --git a/src/app/basicMP4Writer.cpp b/src/app/basicMP4Writer.cpp index ae5941a..5558a10 100644 --- a/src/app/basicMP4Writer.cpp +++ b/src/app/basicMP4Writer.cpp @@ -87,6 +87,20 @@ int BasicMP4Writer::addFrameAU (const uint8_t* byteBuf, const uint32_t byteCount if (((m_frameCount++) % m_rndAccPeriod) == 0) // add RAP to list (stco) { m_rndAccOffsets.push_back (m_mediaSize); +#ifndef NO_PREROLL_DATA + if (((m_frameCount - 1u) % (m_rndAccPeriod << 1)) == 0) // every 2nd + { + if ((byteBuf[0] & 0xE0) == 0xC0) // IPF? + { + // byte-offset of UsacConfig() in AU (excl. first 5 config bits!) + m_ipfCfgOffsets.push_back (byteBuf[0] == 0xDF && (byteBuf[1] & 0xE0) == 0xE0 ? 5 : 3); + } + else // 3-bit ID is missing, not an IPF! + { + m_ipfCfgOffsets.push_back (0); + } + } +#endif } m_mediaSize += byteCount; @@ -425,6 +439,37 @@ void BasicMP4Writer::reset (const unsigned frameLength /*= 0*/, const unsigned p m_sampleRate = 0; m_dynamicHeader.clear (); m_rndAccOffsets.clear (); +#ifndef NO_PREROLL_DATA + m_ipfCfgOffsets.clear (); +#endif if (m_fileHandle != -1) _SEEK (m_fileHandle, 0, 0 /*SEEK_SET*/); } + +#ifndef NO_PREROLL_DATA +int BasicMP4Writer::updateIPFs (const uint8_t* ascUcBuf, const uint32_t ascUcLength, const uint32_t ucOffset) +{ + const uint8_t bw = uint8_t (ascUcLength - ucOffset); + int bytesWritten = 0, configsWritten = 0; + + if ((m_fileHandle == -1) || (ascUcBuf == nullptr) || (ascUcLength == 0) || (ascUcLength <= ucOffset)) + { + return 1; // invalid file handle or IPF config parameter + } + + // write updated UsacConfig() to AudioPreRoll() extensions + for (uint32_t i = 0; i < (uint32_t) m_ipfCfgOffsets.size (); i++) + { + const uint32_t configOffset = m_ipfCfgOffsets.at (i); + + if (configOffset > 0) // this AU is an IPF + { + _SEEK (m_fileHandle, m_rndAccOffsets.at (i << 1) + m_mediaOffset + configOffset, 0 /*SEEK_SET*/); + bytesWritten += _WRITE (m_fileHandle, &ascUcBuf[ucOffset], bw); + configsWritten++; + } + } + + return (bytesWritten != configsWritten * bw ? 1 : 0); +} +#endif diff --git a/src/app/basicMP4Writer.h b/src/app/basicMP4Writer.h index 9c91cad..95d1110 100755 --- a/src/app/basicMP4Writer.h +++ b/src/app/basicMP4Writer.h @@ -43,6 +43,9 @@ private: uint8_t m_staticHeader[STAT_HEADER_SIZE]; // fixed-size std::vector m_dynamicHeader; // variable-sized std::vector m_rndAccOffsets; // random access +#ifndef NO_PREROLL_DATA + std::vector m_ipfCfgOffsets; // IPF UsacConfig +#endif // helper function void push32BitValue (const uint32_t value); // to header @@ -52,7 +55,11 @@ public: // constructor BasicMP4Writer () { m_fileHandle = -1; reset (); } // destructor +#ifdef NO_PREROLL_DATA ~BasicMP4Writer() { m_dynamicHeader.clear (); m_rndAccOffsets.clear (); } +#else + ~BasicMP4Writer() { m_dynamicHeader.clear (); m_rndAccOffsets.clear (); m_ipfCfgOffsets.clear (); } +#endif // public functions int addFrameAU (const uint8_t* byteBuf, const uint32_t byteCount); int finishFile (const unsigned avgBitrate, const unsigned maxBitrate, const uint32_t audioLength, @@ -64,6 +71,9 @@ public: const unsigned raPeriod, const uint8_t* ascBuf, const unsigned ascSize, const uint32_t creatTime = 0, const char vbrQuality = 0); void reset (const unsigned frameLength = 0, const unsigned pregapLength = 0, const unsigned raPeriod = 0); +#ifndef NO_PREROLL_DATA + int updateIPFs (const uint8_t* ascUcBuf, const uint32_t ascUcLength, const uint32_t ucOffset); +#endif }; // BasicMP4Writer #endif // _BASIC_MP4_WRITER_H_ diff --git a/src/app/exhaleApp.cpp b/src/app/exhaleApp.cpp index ff19d6a..23384a9 100644 --- a/src/app/exhaleApp.cpp +++ b/src/app/exhaleApp.cpp @@ -1016,6 +1016,13 @@ int main (const int argc, char* argv[]) bw = EA_LOUD_INIT | (qPeak << 18) | (qLoud << 6) | 11u; memset (outAuData, 0, 108 * sizeof (uint8_t)); // max allowed ASC + UC size i = exhaleEnc.initEncoder (outAuData, &bw); // with finished loudnessInfo() +#ifndef NO_PREROLL_DATA + if (i == 0) + { + i = __min (USHRT_MAX, wavReader.getSampleRate ()); + i = (uint16_t) mp4Writer.updateIPFs (outAuData, bw, (i == 57600 || i == 38400 || i == 19200 /*BL USAC*/ ? 6 : 3)); + } +#endif } // mean & max. bit-rate of encoded AUs br = uint32_t (((actualLength >> 1) + 8 * (byteCount + 4 * (int64_t) mp4Writer.getFrameCount ()) * sampleRate) / actualLength);