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-2012 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 50000
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   delete fInputSources;
00103 }
00104 
00105 void MPEG2TransportStreamFromESSource::doStopGettingFrames() {
00106   // Stop each input source:
00107   for (InputESSourceRecord* sourceRec = fInputSources; sourceRec != NULL;
00108        sourceRec = sourceRec->next()) {
00109     sourceRec->inputSource()->stopGettingFrames();
00110   }
00111 }
00112 
00113 void MPEG2TransportStreamFromESSource
00114 ::awaitNewBuffer(unsigned char* oldBuffer) {
00115   InputESSourceRecord* sourceRec;
00116   // Begin by resetting the old buffer:
00117   if (oldBuffer != NULL) {
00118     for (sourceRec = fInputSources; sourceRec != NULL;
00119          sourceRec = sourceRec->next()) {
00120       if (sourceRec->buffer() == oldBuffer) {
00121         sourceRec->reset();
00122         break;
00123       }
00124     }
00125   }
00126 
00127   if (isCurrentlyAwaitingData()) {
00128     // Try to deliver one filled-in buffer to the client:
00129     for (sourceRec = fInputSources; sourceRec != NULL;
00130          sourceRec = sourceRec->next()) {
00131       if (sourceRec->deliverBufferToClient()) break;
00132     }
00133   }
00134 
00135   // No filled-in buffers are available. Ask each of our inputs for data:
00136   for (sourceRec = fInputSources; sourceRec != NULL;
00137        sourceRec = sourceRec->next()) {
00138     sourceRec->askForNewData();
00139   }
00140 
00141 }
00142 
00143 void MPEG2TransportStreamFromESSource
00144 ::addNewInputSource(FramedSource* inputSource,
00145                     u_int8_t streamId, int mpegVersion) {
00146   if (inputSource == NULL) return;
00147   fInputSources = new InputESSourceRecord(*this, inputSource, streamId,
00148                                           mpegVersion, fInputSources);
00149 }
00150 
00151 
00153 
00154 InputESSourceRecord
00155 ::InputESSourceRecord(MPEG2TransportStreamFromESSource& parent,
00156                       FramedSource* inputSource,
00157                       u_int8_t streamId, int mpegVersion,
00158                       InputESSourceRecord* next)
00159   : fNext(next), fParent(parent), fInputSource(inputSource),
00160     fStreamId(streamId), fMPEGVersion(mpegVersion) {
00161   fInputBuffer = new unsigned char[INPUT_BUFFER_SIZE];
00162   reset();
00163 }
00164 
00165 InputESSourceRecord::~InputESSourceRecord() {
00166   Medium::close(fInputSource);
00167   delete[] fInputBuffer;
00168   delete fNext;
00169 }
00170 
00171 void InputESSourceRecord::askForNewData() {
00172   if (fInputBufferInUse) return;
00173 
00174   if (fInputBufferBytesAvailable == 0) {
00175     // Reset our buffer, by adding a simple PES header at the start:
00176     fInputBuffer[0] = 0; fInputBuffer[1] = 0; fInputBuffer[2] = 1;
00177     fInputBuffer[3] = fStreamId;
00178     fInputBuffer[4] = 0; fInputBuffer[5] = 0; // fill in later with the length
00179     fInputBuffer[6] = 0x80;
00180     fInputBuffer[7] = 0x80; // include a PTS
00181     fInputBuffer[8] = 5; // PES_header_data_length (enough for a PTS)
00182     // fInputBuffer[9..13] will be the PTS; fill this in later
00183     fInputBufferBytesAvailable = SIMPLE_PES_HEADER_SIZE;
00184   }
00185   if (fInputBufferBytesAvailable < LOW_WATER_MARK &&
00186       !fInputSource->isCurrentlyAwaitingData()) {
00187     // We don't yet have enough data in our buffer.  Arrange to read more:
00188     fInputSource->getNextFrame(&fInputBuffer[fInputBufferBytesAvailable],
00189                                INPUT_BUFFER_SIZE-fInputBufferBytesAvailable,
00190                                afterGettingFrame, this,
00191                                FramedSource::handleClosure, &fParent);
00192   }
00193 }
00194 
00195 Boolean InputESSourceRecord::deliverBufferToClient() {
00196   if (fInputBufferInUse || fInputBufferBytesAvailable < LOW_WATER_MARK) return False;
00197 
00198   // Fill in the PES_packet_length field that we left unset before:
00199   unsigned PES_packet_length = fInputBufferBytesAvailable - 6;
00200   if (PES_packet_length > 0xFFFF) {
00201     // Set the PES_packet_length field to 0.  This indicates an unbounded length (see ISO 13818-1, 2.4.3.7)
00202     PES_packet_length = 0;
00203   }
00204   fInputBuffer[4] = PES_packet_length>>8;
00205   fInputBuffer[5] = PES_packet_length;
00206 
00207   // Fill in the PES PTS (from our SCR):
00208   fInputBuffer[9] = 0x20|(fSCR.highBit<<3)|(fSCR.remainingBits>>29)|0x01;
00209   fInputBuffer[10] = fSCR.remainingBits>>22;
00210   fInputBuffer[11] = (fSCR.remainingBits>>14)|0x01;
00211   fInputBuffer[12] = fSCR.remainingBits>>7;
00212   fInputBuffer[13] = (fSCR.remainingBits<<1)|0x01;
00213 
00214   fInputBufferInUse = True;
00215 
00216   // Do the delivery:
00217   fParent.handleNewBuffer(fInputBuffer, fInputBufferBytesAvailable,
00218                          fMPEGVersion, fSCR);
00219 
00220   return True;
00221 }
00222 
00223 void InputESSourceRecord
00224 ::afterGettingFrame(void* clientData, unsigned frameSize,
00225                     unsigned numTruncatedBytes,
00226                     struct timeval presentationTime,
00227                     unsigned /*durationInMicroseconds*/) {
00228   InputESSourceRecord* source = (InputESSourceRecord*)clientData;
00229   source->afterGettingFrame1(frameSize, numTruncatedBytes, presentationTime);
00230 }
00231 void InputESSourceRecord
00232 ::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes,
00233                      struct timeval presentationTime) {
00234   if (numTruncatedBytes > 0) {
00235     fParent.envir() << "MPEG2TransportStreamFromESSource: input buffer too small; increase \"MAX_INPUT_ES_FRAME_SIZE\" in \"MPEG2TransportStreamFromESSource\" by at least "
00236                     << numTruncatedBytes << " bytes!\n";
00237   }
00238 
00239   if (fInputBufferBytesAvailable == SIMPLE_PES_HEADER_SIZE) {
00240     // Use this presentationTime for our SCR:
00241     fSCR.highBit
00242       = ((presentationTime.tv_sec*45000 + (presentationTime.tv_usec*9)/200)&
00243          0x80000000) != 0;
00244     fSCR.remainingBits
00245       = presentationTime.tv_sec*90000 + (presentationTime.tv_usec*9)/100;
00246     fSCR.extension = (presentationTime.tv_usec*9)%100;
00247 #ifdef DEBUG_SCR
00248     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);
00249 #endif
00250   }
00251 
00252   fInputBufferBytesAvailable += frameSize;
00253 
00254   fParent.fPresentationTime = presentationTime;
00255 
00256   // Now that we have new input data, check if we can deliver to the client:
00257   fParent.awaitNewBuffer(NULL);
00258 }

Generated on Thu May 17 07:11:46 2012 for live by  doxygen 1.5.2