⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mp3adu.cpp

📁 流媒体传输协议的实现代码,非常有用.可以支持rtsp mms等流媒体传输协议
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/**********This library is free software; you can redistribute it and/or modify it underthe terms of the GNU Lesser General Public License as published by theFree Software Foundation; either version 2.1 of the License, or (at youroption) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)This library is distributed in the hope that it will be useful, but WITHOUTANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESSFOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License formore details.You should have received a copy of the GNU Lesser General Public Licensealong with this library; if not, write to the Free Software Foundation, Inc.,59 Temple Place, Suite 330, Boston, MA  02111-1307  USA**********/// "liveMedia"// Copyright (c) 1996-2004 Live Networks, Inc.  All rights reserved.// 'ADU' MP3 streams (for improved loss-tolerance)// Implementation#include "MP3ADU.hh"#include "MP3ADUdescriptor.hh"#include "MP3Internals.hh"#include <string.h>#ifdef TEST_LOSS#include "GroupsockHelper.hh"#endif// Segment data structures, used in the implementation below:#define SegmentBufSize 2000	/* conservatively high */class Segment {public:  unsigned char buf[SegmentBufSize];  unsigned char* dataStart() { return &buf[descriptorSize]; }  unsigned frameSize; // if it's a non-ADU frame  unsigned dataHere(); // if it's a non-ADU frame  unsigned descriptorSize;  static unsigned const headerSize;  unsigned sideInfoSize, aduSize;  unsigned backpointer;  struct timeval presentationTime;  unsigned durationInMicroseconds;};unsigned const Segment::headerSize = 4;#define SegmentQueueSize 10class SegmentQueue {public:  SegmentQueue(Boolean directionIsToADU, Boolean includeADUdescriptors)    : fDirectionIsToADU(directionIsToADU),      fIncludeADUdescriptors(includeADUdescriptors) {    reset();  }  Segment s[SegmentQueueSize];  unsigned headIndex() {return fHeadIndex;}  Segment& headSegment() {return s[fHeadIndex];}  unsigned nextFreeIndex() {return fNextFreeIndex;}  Segment& nextFreeSegment() {return s[fNextFreeIndex];}  Boolean isEmpty() {return isEmptyOrFull() && totalDataSize() == 0;}  Boolean isFull() {return isEmptyOrFull() && totalDataSize() > 0;}  static unsigned nextIndex(unsigned ix) {return (ix+1)%SegmentQueueSize;}  static unsigned prevIndex(unsigned ix) {return (ix+SegmentQueueSize-1)%SegmentQueueSize;}  unsigned totalDataSize() {return fTotalDataSize;}  void enqueueNewSegment(FramedSource* inputSource, FramedSource* usingSource);  Boolean dequeue();  Boolean insertDummyBeforeTail(unsigned backpointer);  void reset() { fHeadIndex = fNextFreeIndex = fTotalDataSize = 0; }private:  static void sqAfterGettingSegment(void* clientData,				    unsigned numBytesRead,				    unsigned numTruncatedBytes,				    struct timeval presentationTime,				    unsigned durationInMicroseconds);  Boolean sqAfterGettingCommon(Segment& seg, unsigned numBytesRead);   Boolean isEmptyOrFull() {return headIndex() == nextFreeIndex();}  unsigned fHeadIndex, fNextFreeIndex, fTotalDataSize;  // The following is used for asynchronous reads:  FramedSource* fUsingSource;  // This tells us whether the direction in which we're being used  // is MP3->ADU, or vice-versa.  (This flag is used for debugging output.)  Boolean fDirectionIsToADU;  // The following is true iff we're used to enqueue incoming  // ADU frames, and these have an ADU descriptor in front  Boolean fIncludeADUdescriptors;};////////// ADUFromMP3Source //////////ADUFromMP3Source::ADUFromMP3Source(UsageEnvironment& env,				   FramedSource* inputSource,				   Boolean includeADUdescriptors)  : FramedFilter(env, inputSource),    fAreEnqueueingMP3Frame(False),    fSegments(new SegmentQueue(True /* because we're MP3->ADU */,			       False /*no descriptors in incoming frames*/)),    fIncludeADUdescriptors(includeADUdescriptors),    fTotalDataSizeBeforePreviousRead(0), fScale(1), fFrameCounter(0) {}ADUFromMP3Source::~ADUFromMP3Source() {  delete fSegments;}char const* ADUFromMP3Source::MIMEtype() const {  return "audio/MPA-ROBUST";}ADUFromMP3Source* ADUFromMP3Source::createNew(UsageEnvironment& env,                                              FramedSource* inputSource,                                              Boolean includeADUdescriptors) {  // The source must be a MPEG audio source:  if (strcmp(inputSource->MIMEtype(), "audio/MPEG") != 0) {    env.setResultMsg(inputSource->name(), " is not an MPEG audio source");    return NULL;  }  return new ADUFromMP3Source(env, inputSource, includeADUdescriptors);}void ADUFromMP3Source::resetInput() {  fSegments->reset();}Boolean ADUFromMP3Source::setScaleFactor(int scale) {  if (scale < 1) return False;  fScale = scale;  return True;}void ADUFromMP3Source::doGetNextFrame() {  if (!fAreEnqueueingMP3Frame) {    // Arrange to enqueue a new MP3 frame:    fTotalDataSizeBeforePreviousRead = fSegments->totalDataSize();    fAreEnqueueingMP3Frame = True;    fSegments->enqueueNewSegment(fInputSource, this);  } else {    // Deliver an ADU from a previously-read MP3 frame:    fAreEnqueueingMP3Frame = False;    if (!doGetNextFrame1()) {      // An internal error occurred; act as if our source went away:      FramedSource::handleClosure(this);    }  }}Boolean ADUFromMP3Source::doGetNextFrame1() {  // First, check whether we have enough previously-read data to output an  // ADU for the last-read MP3 frame:  unsigned tailIndex;  Segment* tailSeg;  Boolean needMoreData;  if (fSegments->isEmpty()) {    needMoreData = True;    tailSeg = NULL; tailIndex = 0; // unneeded, but stops compiler warnings  } else {    tailIndex = SegmentQueue::prevIndex(fSegments->nextFreeIndex());    tailSeg = &(fSegments->s[tailIndex]);    needMoreData	  = fTotalDataSizeBeforePreviousRead < tailSeg->backpointer // bp points back too far      || tailSeg->backpointer + tailSeg->dataHere() < tailSeg->aduSize; // not enough data  }  if (needMoreData) {    // We don't have enough data to output an ADU from the last-read MP3    // frame, so need to read another one and try again:    doGetNextFrame();    return True;  }  // Output an ADU from the tail segment:  fFrameSize = tailSeg->headerSize+tailSeg->sideInfoSize+tailSeg->aduSize;  fPresentationTime = tailSeg->presentationTime;  fDurationInMicroseconds = tailSeg->durationInMicroseconds;  unsigned descriptorSize    = fIncludeADUdescriptors ? ADUdescriptor::computeSize(fFrameSize) : 0;#ifdef DEBUG  fprintf(stderr, "m->a:outputting ADU %d<-%d, nbr:%d, sis:%d, dh:%d, (descriptor size: %d)\n", tailSeg->aduSize, tailSeg->backpointer, fFrameSize, tailSeg->sideInfoSize, tailSeg->dataHere(), descriptorSize);#endif  if (descriptorSize + fFrameSize > fMaxSize) {    envir() << "ADUFromMP3Source::doGetNextFrame1(): not enough room ("	    << descriptorSize + fFrameSize << ">"	    << fMaxSize << ")\n";    fFrameSize = 0;    return False;  }  unsigned char* toPtr = fTo;  // output the ADU descriptor:  if (fIncludeADUdescriptors) {    fFrameSize += ADUdescriptor::generateDescriptor(toPtr, fFrameSize);  }  // output header and side info:  memmove(toPtr, tailSeg->dataStart(),	  tailSeg->headerSize + tailSeg->sideInfoSize);  toPtr += tailSeg->headerSize + tailSeg->sideInfoSize;  // go back to the frame that contains the start of our data:  unsigned offset = 0;  unsigned i = tailIndex;  unsigned prevBytes = tailSeg->backpointer;  while (prevBytes > 0) {    i = SegmentQueue::prevIndex(i);    unsigned dataHere = fSegments->s[i].dataHere();    if (dataHere < prevBytes) {      prevBytes -= dataHere;    } else {      offset = dataHere - prevBytes;      break;    }  }  // dequeue any segments that we no longer need:  while (fSegments->headIndex() != i) {    fSegments->dequeue(); // we're done with it  }  unsigned bytesToUse = tailSeg->aduSize;  while (bytesToUse > 0) {    Segment& seg = fSegments->s[i];    unsigned char* fromPtr      = &seg.dataStart()[seg.headerSize + seg.sideInfoSize + offset];    unsigned dataHere = seg.dataHere() - offset;    unsigned bytesUsedHere = dataHere < bytesToUse ? dataHere : bytesToUse;    memmove(toPtr, fromPtr, bytesUsedHere);    bytesToUse -= bytesUsedHere;    toPtr += bytesUsedHere;    offset = 0;    i = SegmentQueue::nextIndex(i);  }  if (fFrameCounter++%fScale == 0) {    // 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 {    // Don't use this frame; get another one:    doGetNextFrame();  }  return True;}////////// MP3FromADUSource //////////MP3FromADUSource::MP3FromADUSource(UsageEnvironment& env,				   FramedSource* inputSource,				   Boolean includeADUdescriptors)  : FramedFilter(env, inputSource),    fAreEnqueueingADU(False),    fSegments(new SegmentQueue(False /* because we're ADU->MP3 */,			       includeADUdescriptors)),    fIncludeADUdescriptors(includeADUdescriptors) {}MP3FromADUSource::~MP3FromADUSource() {  delete fSegments;}char const* MP3FromADUSource::MIMEtype() const {  return "audio/MPEG";}MP3FromADUSource* MP3FromADUSource::createNew(UsageEnvironment& env,					      FramedSource* inputSource,					      Boolean includeADUdescriptors) {  // The source must be an MP3 ADU source:  if (strcmp(inputSource->MIMEtype(), "audio/MPA-ROBUST") != 0) {    env.setResultMsg(inputSource->name(), " is not an MP3 ADU source");    return NULL;  }  return new MP3FromADUSource(env, inputSource, includeADUdescriptors);}void MP3FromADUSource::doGetNextFrame() {  if (fAreEnqueueingADU) insertDummyADUsIfNecessary();  fAreEnqueueingADU = False;  if (needToGetAnADU()) {    // Before returning a frame, we must enqueue at least one ADU:#ifdef TEST_LOSS  NOTE: This code no longer works, because it uses synchronous reads,  which are no longer supported.    static unsigned const framesPerPacket = 10;    static unsigned const frameCount = 0;    static Boolean packetIsLost;    while (1) {      if ((frameCount++)%framesPerPacket == 0) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -