liveMedia/MPEG2TransportStreamFromESSource.cpp

Go to the documentation of this file.
00001 /**********
00002 This library is free software; you can redistribute it and/or modify it under
00003 the terms of the GNU Lesser General Public License as published by the
00004 Free Software Foundation; either version 2.1 of the License, or (at your
00005 option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
00006 
00007 This library is distributed in the hope that it will be useful, but WITHOUT
00008 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00009 FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
00010 more details.
00011 
00012 You should have received a copy of the GNU Lesser General Public License
00013 along with this library; if not, write to the Free Software Foundation, Inc.,
00014 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
00015 **********/
00016 // "liveMedia"
00017 // Copyright (c) 1996-2013 Live Networks, Inc.  All rights reserved.
00018 // A filter for converting one or more MPEG Elementary Streams
00019 // to a MPEG-2 Transport Stream
00020 // Implementation
00021 
00022 #include "MPEG2TransportStreamFromESSource.hh"
00023 
00024 #define MAX_INPUT_ES_FRAME_SIZE 100000
00025 #define SIMPLE_PES_HEADER_SIZE 14
00026 #define LOW_WATER_MARK 1000 // <= MAX_INPUT_ES_FRAME_SIZE
00027 #define INPUT_BUFFER_SIZE (SIMPLE_PES_HEADER_SIZE + 2*MAX_INPUT_ES_FRAME_SIZE)
00028 
00030 
00031 class InputESSourceRecord {
00032 public:
00033   InputESSourceRecord(MPEG2TransportStreamFromESSource& parent,
00034                       FramedSource* inputSource,
00035                       u_int8_t streamId, int mpegVersion,
00036                       InputESSourceRecord* next);
00037   virtual ~InputESSourceRecord();
00038 
00039   InputESSourceRecord* next() const { return fNext; }
00040   FramedSource* inputSource() const { return fInputSource; }
00041 
00042   void askForNewData();
00043   Boolean deliverBufferToClient();
00044 
00045   unsigned char* buffer() const { return fInputBuffer; }
00046   void reset() {
00047     // Reset the buffer for future use:
00048     fInputBufferBytesAvailable = 0;
00049     fInputBufferInUse = False;
00050   }
00051 
00052 private:
00053   static void afterGettingFrame(void* clientData, unsigned frameSize,
00054                                 unsigned numTruncatedBytes,
00055                                 struct timeval presentationTime,
00056                                 unsigned durationInMicroseconds);
00057   void afterGettingFrame1(unsigned frameSize,
00058                           unsigned numTruncatedBytes,
00059                           struct timeval presentationTime);
00060 
00061 private:
00062   InputESSourceRecord* fNext;
00063   MPEG2TransportStreamFromESSource& fParent;
00064   FramedSource* fInputSource;
00065   u_int8_t fStreamId;
00066   int fMPEGVersion;
00067   unsigned char* fInputBuffer;
00068   unsigned fInputBufferBytesAvailable;
00069   Boolean fInputBufferInUse;
00070   MPEG1or2Demux::SCR fSCR;
00071 };
00072 
00073 
00075 
00076 MPEG2TransportStreamFromESSource* MPEG2TransportStreamFromESSource
00077 ::createNew(UsageEnvironment& env) {
00078   return new MPEG2TransportStreamFromESSource(env);
00079 }
00080 
00081 void MPEG2TransportStreamFromESSource
00082 ::addNewVideoSource(FramedSource* inputSource, int mpegVersion) {
00083   u_int8_t streamId = 0xE0 | (fVideoSourceCounter++&0x0F);
00084   addNewInputSource(inputSource, streamId, mpegVersion);
00085   fHaveVideoStreams = True;
00086 }
00087 
00088 void MPEG2TransportStreamFromESSource
00089 ::addNewAudioSource(FramedSource* inputSource, int mpegVersion) {
00090   u_int8_t streamId = 0xC0 | (fAudioSourceCounter++&0x0F);
00091   addNewInputSource(inputSource, streamId, mpegVersion);
00092 }
00093 
00094 MPEG2TransportStreamFromESSource
00095 ::MPEG2TransportStreamFromESSource(UsageEnvironment& env)
00096   : MPEG2TransportStreamMultiplexor(env),
00097     fInputSources(NULL), fVideoSourceCounter(0), fAudioSourceCounter(0) {
00098   fHaveVideoStreams = False; // unless we add a video source
00099 }
00100 
00101 MPEG2TransportStreamFromESSource::~MPEG2TransportStreamFromESSource() {
00102   doStopGettingFrames();
00103   delete fInputSources;
00104 }
00105 
00106 void MPEG2TransportStreamFromESSource::doStopGettingFrames() {
00107   // Stop each input source:
00108   for (InputESSourceRecord* sourceRec = fInputSources; sourceRec != NULL;
00109        sourceRec = sourceRec->next()) {
00110     sourceRec->inputSource()->stopGettingFrames();
00111   }
00112 }
00113 
00114 void MPEG2TransportStreamFromESSource
00115 ::awaitNewBuffer(unsigned char* oldBuffer) {
00116   InputESSourceRecord* sourceRec;
00117   // Begin by resetting the old buffer:
00118   if (oldBuffer != NULL) {
00119     for (sourceRec = fInputSources; sourceRec != NULL;
00120          sourceRec = sourceRec->next()) {
00121       if (sourceRec->buffer() == oldBuffer) {
00122         sourceRec->reset();
00123         break;
00124       }
00125     }
00126   }
00127 
00128   if (isCurrentlyAwaitingData()) {
00129     // Try to deliver one filled-in buffer to the client:
00130     for (sourceRec = fInputSources; sourceRec != NULL;
00131          sourceRec = sourceRec->next()) {
00132       if (sourceRec->deliverBufferToClient()) break;
00133     }
00134   }
00135 
00136   // No filled-in buffers are available. Ask each of our inputs for data:
00137   for (sourceRec = fInputSources; sourceRec != NULL;
00138        sourceRec = sourceRec->next()) {
00139     sourceRec->askForNewData();
00140   }
00141 
00142 }
00143 
00144 void MPEG2TransportStreamFromESSource
00145 ::addNewInputSource(FramedSource* inputSource,
00146                     u_int8_t streamId, int mpegVersion) {
00147   if (inputSource == NULL) return;
00148   fInputSources = new InputESSourceRecord(*this, inputSource, streamId,
00149                                           mpegVersion, fInputSources);
00150 }
00151 
00152 
00154 
00155 InputESSourceRecord
00156 ::InputESSourceRecord(MPEG2TransportStreamFromESSource& parent,
00157                       FramedSource* inputSource,
00158                       u_int8_t streamId, int mpegVersion,
00159                       InputESSourceRecord* next)
00160   : fNext(next), fParent(parent), fInputSource(inputSource),
00161     fStreamId(streamId), fMPEGVersion(mpegVersion) {
00162   fInputBuffer = new unsigned char[INPUT_BUFFER_SIZE];
00163   reset();
00164 }
00165 
00166 InputESSourceRecord::~InputESSourceRecord() {
00167   Medium::close(fInputSource);
00168   delete[] fInputBuffer;
00169   delete fNext;
00170 }
00171 
00172 void InputESSourceRecord::askForNewData() {
00173   if (fInputBufferInUse) return;
00174 
00175   if (fInputBufferBytesAvailable == 0) {
00176     // Reset our buffer, by adding a simple PES header at the start:
00177     fInputBuffer[0] = 0; fInputBuffer[1] = 0; fInputBuffer[2] = 1;
00178     fInputBuffer[3] = fStreamId;
00179     fInputBuffer[4] = 0; fInputBuffer[5] = 0; // fill in later with the length
00180     fInputBuffer[6] = 0x80;
00181     fInputBuffer[7] = 0x80; // include a PTS
00182     fInputBuffer[8] = 5; // PES_header_data_length (enough for a PTS)
00183     // fInputBuffer[9..13] will be the PTS; fill this in later
00184     fInputBufferBytesAvailable = SIMPLE_PES_HEADER_SIZE;
00185   }
00186   if (fInputBufferBytesAvailable < LOW_WATER_MARK &&
00187       !fInputSource->isCurrentlyAwaitingData()) {
00188     // We don't yet have enough data in our buffer.  Arrange to read more:
00189     fInputSource->getNextFrame(&fInputBuffer[fInputBufferBytesAvailable],
00190                                INPUT_BUFFER_SIZE-fInputBufferBytesAvailable,
00191                                afterGettingFrame, this,
00192                                FramedSource::handleClosure, &fParent);
00193   }
00194 }
00195 
00196 Boolean InputESSourceRecord::deliverBufferToClient() {
00197   if (fInputBufferInUse || fInputBufferBytesAvailable < LOW_WATER_MARK) return False;
00198 
00199   // Fill in the PES_packet_length field that we left unset before:
00200   unsigned PES_packet_length = fInputBufferBytesAvailable - 6;
00201   if (PES_packet_length > 0xFFFF) {
00202     // Set the PES_packet_length field to 0.  This indicates an unbounded length (see ISO 13818-1, 2.4.3.7)
00203     PES_packet_length = 0;
00204   }
00205   fInputBuffer[4] = PES_packet_length>>8;
00206   fInputBuffer[5] = PES_packet_length;
00207 
00208   // Fill in the PES PTS (from our SCR):
00209   fInputBuffer[9] = 0x20|(fSCR.highBit<<3)|(fSCR.remainingBits>>29)|0x01;
00210   fInputBuffer[10] = fSCR.remainingBits>>22;
00211   fInputBuffer[11] = (fSCR.remainingBits>>14)|0x01;
00212   fInputBuffer[12] = fSCR.remainingBits>>7;
00213   fInputBuffer[13] = (fSCR.remainingBits<<1)|0x01;
00214 
00215   fInputBufferInUse = True;
00216 
00217   // Do the delivery:
00218   fParent.handleNewBuffer(fInputBuffer, fInputBufferBytesAvailable,
00219                          fMPEGVersion, fSCR);
00220 
00221   return True;
00222 }
00223 
00224 void InputESSourceRecord
00225 ::afterGettingFrame(void* clientData, unsigned frameSize,
00226                     unsigned numTruncatedBytes,
00227                     struct timeval presentationTime,
00228                     unsigned /*durationInMicroseconds*/) {
00229   InputESSourceRecord* source = (InputESSourceRecord*)clientData;
00230   source->afterGettingFrame1(frameSize, numTruncatedBytes, presentationTime);
00231 }
00232 void InputESSourceRecord
00233 ::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes,
00234                      struct timeval presentationTime) {
00235   if (numTruncatedBytes > 0) {
00236     fParent.envir() << "MPEG2TransportStreamFromESSource: input buffer too small; increase \"MAX_INPUT_ES_FRAME_SIZE\" in \"MPEG2TransportStreamFromESSource\" by at least "
00237                     << numTruncatedBytes << " bytes!\n";
00238   }
00239 
00240   if (fInputBufferBytesAvailable == SIMPLE_PES_HEADER_SIZE) {
00241     // Use this presentationTime for our SCR:
00242     fSCR.highBit
00243       = ((presentationTime.tv_sec*45000 + (presentationTime.tv_usec*9)/200)&
00244          0x80000000) != 0;
00245     fSCR.remainingBits
00246       = presentationTime.tv_sec*90000 + (presentationTime.tv_usec*9)/100;
00247     fSCR.extension = (presentationTime.tv_usec*9)%100;
00248 #ifdef DEBUG_SCR
00249     fprintf(stderr, "PES header: stream_id 0x%02x, pts: %u.%06u => SCR 0x%x%08x:%03x\n", fStreamId, (unsigned)presentationTime.tv_sec, (unsigned)presentationTime.tv_usec, fSCR.highBit, fSCR.remainingBits, fSCR.extension);
00250 #endif
00251   }
00252 
00253   fInputBufferBytesAvailable += frameSize;
00254 
00255   fParent.fPresentationTime = presentationTime;
00256 
00257   // Now that we have new input data, check if we can deliver to the client:
00258   fParent.awaitNewBuffer(NULL);
00259 }

Generated on Mon Apr 29 13:28:02 2013 for live by  doxygen 1.5.2