/********** This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. (See .) This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA **********/ // "liveMedia" // Copyright (c) 1996-2020 Live Networks, Inc. All rights reserved. // A filter that breaks up an AC3 audio elementary stream into frames // Implementation #include "AC3AudioStreamFramer.hh" #include "StreamParser.hh" #include ////////// AC3AudioStreamParser definition ////////// class AC3FrameParams { public: AC3FrameParams() : samplingFreq(0) {} // 8-byte header at the start of each frame: // u_int32_t hdr0, hdr1; unsigned hdr0, hdr1; // parameters derived from the headers unsigned kbps, samplingFreq, frameSize; void setParamsFromHeader(); }; class AC3AudioStreamParser: public StreamParser { public: AC3AudioStreamParser(AC3AudioStreamFramer* usingSource, FramedSource* inputSource); virtual ~AC3AudioStreamParser(); public: void testStreamCode(unsigned char ourStreamCode, unsigned char* ptr, unsigned size); unsigned parseFrame(unsigned& numTruncatedBytes); // returns the size of the frame that was acquired, or 0 if none was void registerReadInterest(unsigned char* to, unsigned maxSize); AC3FrameParams const& currentFrame() const { return fCurrentFrame; } Boolean haveParsedAFrame() const { return fHaveParsedAFrame; } void readAndSaveAFrame(); private: static void afterGettingSavedFrame(void* clientData, unsigned frameSize, unsigned numTruncatedBytes, struct timeval presentationTime, unsigned durationInMicroseconds); void afterGettingSavedFrame1(unsigned frameSize); static void onSavedFrameClosure(void* clientData); void onSavedFrameClosure1(); private: AC3AudioStreamFramer* fUsingSource; unsigned char* fTo; unsigned fMaxSize; Boolean fHaveParsedAFrame; unsigned char* fSavedFrame; unsigned fSavedFrameSize; char fSavedFrameFlag; // Parameters of the most recently read frame: AC3FrameParams fCurrentFrame; }; ////////// AC3AudioStreamFramer implementation ////////// AC3AudioStreamFramer::AC3AudioStreamFramer(UsageEnvironment& env, FramedSource* inputSource, unsigned char streamCode) : FramedFilter(env, inputSource), fOurStreamCode(streamCode) { // Use the current wallclock time as the initial 'presentation time': gettimeofday(&fNextFramePresentationTime, NULL); fParser = new AC3AudioStreamParser(this, inputSource); } AC3AudioStreamFramer::~AC3AudioStreamFramer() { delete fParser; } AC3AudioStreamFramer* AC3AudioStreamFramer::createNew(UsageEnvironment& env, FramedSource* inputSource, unsigned char streamCode) { // Need to add source type checking here??? ##### return new AC3AudioStreamFramer(env, inputSource, streamCode); } unsigned AC3AudioStreamFramer::samplingRate() { if (!fParser->haveParsedAFrame()) { // Because we haven't yet parsed a frame, we don't yet know the input // stream's sampling rate. So, we first need to read a frame // (into a special buffer that we keep around for later use). fParser->readAndSaveAFrame(); } return fParser->currentFrame().samplingFreq; } void AC3AudioStreamFramer::flushInput() { fParser->flushInput(); } void AC3AudioStreamFramer::doGetNextFrame() { fParser->registerReadInterest(fTo, fMaxSize); parseNextFrame(); } #define MILLION 1000000 struct timeval AC3AudioStreamFramer::currentFramePlayTime() const { AC3FrameParams const& fr = fParser->currentFrame(); unsigned const numSamples = 1536; unsigned const freq = fr.samplingFreq; // result is numSamples/freq unsigned const uSeconds = (freq == 0) ? 0 : ((numSamples*2*MILLION)/freq + 1)/2; // rounds to nearest integer struct timeval result; result.tv_sec = uSeconds/MILLION; result.tv_usec = uSeconds%MILLION; return result; } void AC3AudioStreamFramer ::handleNewData(void* clientData, unsigned char* ptr, unsigned size, struct timeval /*presentationTime*/) { AC3AudioStreamFramer* framer = (AC3AudioStreamFramer*)clientData; framer->handleNewData(ptr, size); } void AC3AudioStreamFramer ::handleNewData(unsigned char* ptr, unsigned size) { fParser->testStreamCode(fOurStreamCode, ptr, size); parseNextFrame(); } void AC3AudioStreamFramer::parseNextFrame() { unsigned acquiredFrameSize = fParser->parseFrame(fNumTruncatedBytes); if (acquiredFrameSize > 0) { // We were able to acquire a frame from the input. // It has already been copied to the reader's space. fFrameSize = acquiredFrameSize; // Also set the presentation time, and increment it for next time, // based on the length of this frame: fPresentationTime = fNextFramePresentationTime; struct timeval framePlayTime = currentFramePlayTime(); fDurationInMicroseconds = framePlayTime.tv_sec*MILLION + framePlayTime.tv_usec; fNextFramePresentationTime.tv_usec += framePlayTime.tv_usec; fNextFramePresentationTime.tv_sec += framePlayTime.tv_sec + fNextFramePresentationTime.tv_usec/MILLION; fNextFramePresentationTime.tv_usec %= MILLION; // Call our own 'after getting' function. Because we're not a 'leaf' // source, we can call this directly, without risking infinite recursion. afterGetting(this); } else { // We were unable to parse a complete frame from the input, because: // - we had to read more data from the source stream, or // - the source stream has ended. } } ////////// AC3AudioStreamParser implementation ////////// static int const kbpsTable[] = {32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 576, 640}; void AC3FrameParams::setParamsFromHeader() { unsigned char byte4 = hdr1 >> 24; unsigned char kbpsIndex = (byte4&0x3E) >> 1; if (kbpsIndex > 18) kbpsIndex = 18; kbps = kbpsTable[kbpsIndex]; unsigned char samplingFreqIndex = (byte4&0xC0) >> 6; switch (samplingFreqIndex) { case 0: samplingFreq = 48000; frameSize = 4*kbps; break; case 1: samplingFreq = 44100; frameSize = 2*(320*kbps/147 + (byte4&1)); break; case 2: case 3: // not legal? samplingFreq = 32000; frameSize = 6*kbps; } } AC3AudioStreamParser ::AC3AudioStreamParser(AC3AudioStreamFramer* usingSource, FramedSource* inputSource) : StreamParser(inputSource, FramedSource::handleClosure, usingSource, &AC3AudioStreamFramer::handleNewData, usingSource), fUsingSource(usingSource), fHaveParsedAFrame(False), fSavedFrame(NULL), fSavedFrameSize(0) { } AC3AudioStreamParser::~AC3AudioStreamParser() { } void AC3AudioStreamParser::registerReadInterest(unsigned char* to, unsigned maxSize) { fTo = to; fMaxSize = maxSize; } void AC3AudioStreamParser ::testStreamCode(unsigned char ourStreamCode, unsigned char* ptr, unsigned size) { if (ourStreamCode == 0) return; // we assume that there's no stream code at the beginning of the data if (size < 4) return; unsigned char streamCode = *ptr; if (streamCode == ourStreamCode) { // Remove the first 4 bytes from the stream: memmove(ptr, ptr + 4, size - 4); totNumValidBytes() = totNumValidBytes() - 4; } else { // Discard all of the data that was just read: totNumValidBytes() = totNumValidBytes() - size; } } unsigned AC3AudioStreamParser::parseFrame(unsigned& numTruncatedBytes) { if (fSavedFrameSize > 0) { // We've already read and parsed a frame. Use it instead: memmove(fTo, fSavedFrame, fSavedFrameSize); delete[] fSavedFrame; fSavedFrame = NULL; unsigned frameSize = fSavedFrameSize; fSavedFrameSize = 0; return frameSize; } try { saveParserState(); // We expect an AC3 audio header (first 2 bytes == 0x0B77) at the start: while (1) { unsigned next4Bytes = test4Bytes(); if (next4Bytes>>16 == 0x0B77) break; skipBytes(1); saveParserState(); } fCurrentFrame.hdr0 = get4Bytes(); fCurrentFrame.hdr1 = test4Bytes(); fCurrentFrame.setParamsFromHeader(); fHaveParsedAFrame = True; // Copy the frame to the requested destination: unsigned frameSize = fCurrentFrame.frameSize; if (frameSize > fMaxSize) { numTruncatedBytes = frameSize - fMaxSize; frameSize = fMaxSize; } else { numTruncatedBytes = 0; } fTo[0] = fCurrentFrame.hdr0 >> 24; fTo[1] = fCurrentFrame.hdr0 >> 16; fTo[2] = fCurrentFrame.hdr0 >> 8; fTo[3] = fCurrentFrame.hdr0; getBytes(&fTo[4], frameSize-4); skipBytes(numTruncatedBytes); return frameSize; } catch (int /*e*/) { #ifdef DEBUG fUsingSource->envir() << "AC3AudioStreamParser::parseFrame() EXCEPTION (This is normal behavior - *not* an error)\n"; #endif return 0; // the parsing got interrupted } } void AC3AudioStreamParser::readAndSaveAFrame() { unsigned const maxAC3FrameSize = 4000; fSavedFrame = new unsigned char[maxAC3FrameSize]; fSavedFrameSize = 0; fSavedFrameFlag = 0; fUsingSource->getNextFrame(fSavedFrame, maxAC3FrameSize, afterGettingSavedFrame, this, onSavedFrameClosure, this); fUsingSource->envir().taskScheduler().doEventLoop(&fSavedFrameFlag); } void AC3AudioStreamParser ::afterGettingSavedFrame(void* clientData, unsigned frameSize, unsigned /*numTruncatedBytes*/, struct timeval /*presentationTime*/, unsigned /*durationInMicroseconds*/) { AC3AudioStreamParser* parser = (AC3AudioStreamParser*)clientData; parser->afterGettingSavedFrame1(frameSize); } void AC3AudioStreamParser ::afterGettingSavedFrame1(unsigned frameSize) { fSavedFrameSize = frameSize; fSavedFrameFlag = ~0; } void AC3AudioStreamParser::onSavedFrameClosure(void* clientData) { AC3AudioStreamParser* parser = (AC3AudioStreamParser*)clientData; parser->onSavedFrameClosure1(); } void AC3AudioStreamParser::onSavedFrameClosure1() { delete[] fSavedFrame; fSavedFrame = NULL; fSavedFrameSize = 0; fSavedFrameFlag = ~0; }