Guest User

MPEG2TransportStreamFromESSource4iOS.cpp

a guest
Dec 23rd, 2011
90
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.52 KB | None | 0 0
  1. /**********
  2. This library is free software; you can redistribute it and/or modify it under
  3. the terms of the GNU Lesser General Public License as published by the
  4. Free Software Foundation; either version 2.1 of the License, or (at your
  5. option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
  6.  
  7. This library is distributed in the hope that it will be useful, but WITHOUT
  8. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  9. FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
  10. more details.
  11.  
  12. You should have received a copy of the GNU Lesser General Public License
  13. along with this library; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
  15. **********/
  16. // "liveMedia"
  17. // Copyright (c) 1996-2011 Live Networks, Inc.  All rights reserved.
  18. // A filter for converting one or more MPEG Elementary Streams
  19. // to a MPEG-2 Transport Stream
  20. // Implementation
  21.  
  22. #include <Media/MPEG2TransportStreamFromESSource4iOS.hh>
  23.  
  24. #define MAX_INPUT_ES_FRAME_SIZE 50000
  25. //#define SIMPLE_PES_HEADER_SIZE 14
  26. #define SIMPLE_PES_HEADER_SIZE 19 //JFS ipad tweaks
  27. #define LOW_WATER_MARK 128 // <= MAX_INPUT_ES_FRAME_SIZE
  28. #define INPUT_BUFFER_SIZE (SIMPLE_PES_HEADER_SIZE + 2*MAX_INPUT_ES_FRAME_SIZE)
  29.  
  30. ////////// InputESSourceRecord4iOS definition //////////
  31.  
  32. class InputESSourceRecord4iOS {
  33. public:
  34.   InputESSourceRecord4iOS(MPEG2TransportStreamFromESSource4iOS& parent,
  35.               FramedSource* inputSource,
  36.               u_int8_t streamId, int mpegVersion,
  37.               InputESSourceRecord4iOS* next);
  38.   virtual ~InputESSourceRecord4iOS();
  39.  
  40.   InputESSourceRecord4iOS* next() const { return fNext; }
  41.   FramedSource* inputSource() const { return fInputSource; }
  42.  
  43.   void askForNewData();
  44.   Boolean deliverBufferToClient();
  45.  
  46.   unsigned char* buffer() const { return fInputBuffer; }
  47.   void reset() {
  48.     // Reset the buffer for future use:
  49.     fInputBufferBytesAvailable = 0;
  50.     fInputBufferInUse = False;
  51.   }
  52.  
  53. private:
  54.   static void afterGettingFrame(void* clientData, unsigned frameSize,
  55.                                 unsigned numTruncatedBytes,
  56.                                 struct timeval presentationTime,
  57.                                 unsigned durationInMicroseconds);
  58.   void afterGettingFrame1(unsigned frameSize,
  59.                           unsigned numTruncatedBytes,
  60.                           struct timeval presentationTime);
  61.  
  62. private:
  63.   InputESSourceRecord4iOS* fNext;
  64.   MPEG2TransportStreamFromESSource4iOS& fParent;
  65.   FramedSource* fInputSource;
  66.   u_int8_t fStreamId;
  67.   int fMPEGVersion;
  68.   unsigned char* fInputBuffer;
  69.   unsigned fInputBufferBytesAvailable;
  70.   Boolean fInputBufferInUse;
  71.   MPEG1or2Demux::SCR fSCR;
  72. };
  73.  
  74.  
  75. ////////// MPEG2TransportStreamFromESSource4iOS implementation //////////
  76.  
  77. MPEG2TransportStreamFromESSource4iOS* MPEG2TransportStreamFromESSource4iOS
  78. ::createNew(UsageEnvironment& env) {
  79.   return new MPEG2TransportStreamFromESSource4iOS(env);
  80. }
  81.  
  82. void MPEG2TransportStreamFromESSource4iOS
  83. ::addNewVideoSource(FramedSource* inputSource, int mpegVersion) {
  84.   u_int8_t streamId = 0xE0 | (fVideoSourceCounter++&0x0F);
  85.   addNewInputSource(inputSource, streamId, mpegVersion);
  86.   fHaveVideoStreams = True;
  87. }
  88.  
  89. void MPEG2TransportStreamFromESSource4iOS
  90. ::addNewAudioSource(FramedSource* inputSource, int mpegVersion) {
  91.   u_int8_t streamId = 0xC0 | (fAudioSourceCounter++&0x0F);
  92.   addNewInputSource(inputSource, streamId, mpegVersion);
  93. }
  94.  
  95. MPEG2TransportStreamFromESSource4iOS
  96. ::MPEG2TransportStreamFromESSource4iOS(UsageEnvironment& env)
  97.   : MPEG2TransportStreamMultiplexor4iOS(env),
  98.     fInputSources(NULL), fVideoSourceCounter(0), fAudioSourceCounter(0) {
  99.   fHaveVideoStreams = False; // unless we add a video source
  100. }
  101.  
  102. MPEG2TransportStreamFromESSource4iOS::~MPEG2TransportStreamFromESSource4iOS() {
  103.   delete fInputSources;
  104. }
  105.  
  106. void MPEG2TransportStreamFromESSource4iOS::doStopGettingFrames() {
  107.   // Stop each input source:
  108.   for (InputESSourceRecord4iOS* sourceRec = fInputSources; sourceRec != NULL;
  109.        sourceRec = sourceRec->next()) {
  110.     sourceRec->inputSource()->stopGettingFrames();
  111.   }
  112. }
  113.  
  114. void MPEG2TransportStreamFromESSource4iOS
  115. ::awaitNewBuffer(unsigned char* oldBuffer) {
  116.   InputESSourceRecord4iOS* sourceRec;
  117.   // Begin by resetting the old buffer:
  118.   if (oldBuffer != NULL) {
  119.     for (sourceRec = fInputSources; sourceRec != NULL;
  120.      sourceRec = sourceRec->next()) {
  121.       if (sourceRec->buffer() == oldBuffer) {
  122.     sourceRec->reset();
  123.     break;
  124.       }
  125.     }
  126.   }
  127.  
  128.   if (isCurrentlyAwaitingData()) {
  129.     // Try to deliver one filled-in buffer to the client:
  130.     for (sourceRec = fInputSources; sourceRec != NULL;
  131.      sourceRec = sourceRec->next()) {
  132.       if (sourceRec->deliverBufferToClient()) break;
  133.     }
  134.   }
  135.  
  136.   // No filled-in buffers are available. Ask each of our inputs for data:
  137.   for (sourceRec = fInputSources; sourceRec != NULL;
  138.        sourceRec = sourceRec->next()) {
  139.     sourceRec->askForNewData();
  140.   }
  141.  
  142. }
  143.  
  144. void MPEG2TransportStreamFromESSource4iOS
  145. ::addNewInputSource(FramedSource* inputSource,
  146.             u_int8_t streamId, int mpegVersion) {
  147.   if (inputSource == NULL) return;
  148.   fInputSources = new InputESSourceRecord4iOS(*this, inputSource, streamId,
  149.                       mpegVersion, fInputSources);
  150. }
  151.  
  152.  
  153. ////////// InputESSourceRecord4iOS implementation //////////
  154.  
  155. InputESSourceRecord4iOS
  156. ::InputESSourceRecord4iOS(MPEG2TransportStreamFromESSource4iOS& parent,
  157.               FramedSource* inputSource,
  158.               u_int8_t streamId, int mpegVersion,
  159.               InputESSourceRecord4iOS* next)
  160.   : fNext(next), fParent(parent), fInputSource(inputSource),
  161.     fStreamId(streamId), fMPEGVersion(mpegVersion) {
  162.   fInputBuffer = new unsigned char[INPUT_BUFFER_SIZE];
  163.   reset();
  164. }
  165.  
  166. InputESSourceRecord4iOS::~InputESSourceRecord4iOS() {
  167.   Medium::close(fInputSource);
  168.   delete[] fInputBuffer;
  169.   delete fNext;
  170. }
  171.  
  172. void InputESSourceRecord4iOS::askForNewData() {
  173.   if (fInputBufferInUse) return;
  174.  
  175.   if (fInputBufferBytesAvailable == 0) {
  176.     // Reset our buffer, by adding a simple PES header at the start:
  177.     fInputBuffer[0] = 0; fInputBuffer[1] = 0; fInputBuffer[2] = 1;
  178.     fInputBuffer[3] = fStreamId;
  179.     fInputBuffer[4] = 0; fInputBuffer[5] = 0; // fill in later with the length
  180.  
  181.     //original
  182.     //fInputBuffer[6] = 0x80;
  183.     //fInputBuffer[7] = 0x80; // include a PTS
  184.     //fInputBuffer[8] = 10; // PES_header_data_length (enough for a PTS)
  185.     //// fInputBuffer[9..13] will be the PTS; fill this in later
  186.  
  187.     fInputBuffer[6] = 0x84; //JFS enable data_alignment bit
  188.     fInputBuffer[7] = 0xC0; // include a PTS and DTS
  189.     fInputBuffer[8] = 10; // PES_header_data_length (enough for a PTS)
  190.     // fInputBuffer[9..13] will be the PTS; fill this in later
  191.     // fInputBuffer[14..18] will be the PTS; fill this in later
  192.     fInputBufferBytesAvailable = SIMPLE_PES_HEADER_SIZE;
  193.   }
  194.  // if (fInputBufferBytesAvailable < LOW_WATER_MARK &&
  195.   //    !fInputSource->isCurrentlyAwaitingData()) {
  196.  
  197.     if (!fInputSource->isCurrentlyAwaitingData()) {
  198.     // We don't yet have enough data in our buffer.  Arrange to read more:
  199.     fInputSource->getNextFrame(&fInputBuffer[fInputBufferBytesAvailable],
  200.                                INPUT_BUFFER_SIZE-fInputBufferBytesAvailable,
  201.                                afterGettingFrame, this,
  202.                                FramedSource::handleClosure, &fParent);
  203.   }
  204. }
  205.  
  206. Boolean InputESSourceRecord4iOS::deliverBufferToClient() {
  207.   if (fInputBufferInUse || fInputBufferBytesAvailable < LOW_WATER_MARK) return False;
  208.    // if (fInputBufferInUse) return False;
  209.  
  210.   // Fill in the PES_packet_length field that we left unset before:
  211.   unsigned PES_packet_length = fInputBufferBytesAvailable - 6;
  212.   if (PES_packet_length > 0xFFFF) {
  213.     // Set the PES_packet_length field to 0.  This indicates an unbounded length (see ISO 13818-1, 2.4.3.7)
  214.     PES_packet_length = 0;
  215.   }
  216.   fInputBuffer[4] = PES_packet_length>>8;
  217.   fInputBuffer[5] = PES_packet_length;
  218.  
  219.   // it is allowed to be zero, lets try that in case error in PES size breaks ipad
  220.   //fInputBuffer[4] = 0;
  221.   //fInputBuffer[5] = 0;
  222.  
  223.   // Fill in the PES PTS (from our SCR):
  224.   fInputBuffer[9] = 0x30|(fSCR.highBit<<3)|(fSCR.remainingBits>>29)|0x01;
  225.   fInputBuffer[10] = fSCR.remainingBits>>22;
  226.   fInputBuffer[11] = (fSCR.remainingBits>>14)|0x01;
  227.   fInputBuffer[12] = fSCR.remainingBits>>7;
  228.   fInputBuffer[13] = (fSCR.remainingBits<<1)|0x01;
  229.  
  230.    // Fill in the PES DTS (from our SCR):
  231.   fInputBuffer[14] = 0x10|(fSCR.highBit<<3)|(fSCR.remainingBits>>29)|0x01;
  232.   fInputBuffer[15] = fSCR.remainingBits>>22;
  233.   fInputBuffer[16] = (fSCR.remainingBits>>14)|0x01;
  234.   fInputBuffer[17] = fSCR.remainingBits>>7;
  235.   fInputBuffer[18] = (fSCR.remainingBits<<1)|0x01;
  236.  
  237.   fInputBufferInUse = True;
  238.  
  239.   // Do the delivery:
  240.   fParent.handleNewBuffer(fInputBuffer, fInputBufferBytesAvailable,
  241.              fMPEGVersion, fSCR);
  242.  
  243.   return True;
  244. }
  245.  
  246. void InputESSourceRecord4iOS
  247. ::afterGettingFrame(void* clientData, unsigned frameSize,
  248.             unsigned numTruncatedBytes,
  249.             struct timeval presentationTime,
  250.             unsigned /*durationInMicroseconds*/) {
  251.   InputESSourceRecord4iOS* source = (InputESSourceRecord4iOS*)clientData;
  252.   source->afterGettingFrame1(frameSize, numTruncatedBytes, presentationTime);
  253. }
  254. void InputESSourceRecord4iOS
  255. ::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes,
  256.              struct timeval presentationTime) {
  257.   if (numTruncatedBytes > 0) {
  258.     fParent.envir() << "MPEG2TransportStreamFromESSource4iOS: input buffer too small; increase \"MAX_INPUT_ES_FRAME_SIZE\" in \"MPEG2TransportStreamFromESSource4iOS\" by at least "
  259.             << numTruncatedBytes << " bytes!\n";
  260.   }
  261.  
  262.   if (fInputBufferBytesAvailable == SIMPLE_PES_HEADER_SIZE) {
  263.     // Use this presentationTime for our SCR:
  264.     fSCR.highBit
  265.       = ((presentationTime.tv_sec*45000 + (presentationTime.tv_usec*9)/200)&
  266.      0x80000000) != 0;
  267.     fSCR.remainingBits
  268.       = presentationTime.tv_sec*90000 + (presentationTime.tv_usec*9)/100;
  269.     fSCR.extension = (presentationTime.tv_usec*9)%100;
  270. #ifdef DEBUG_SCR
  271.     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);
  272. #endif
  273.   }
  274.  
  275.   fInputBufferBytesAvailable += frameSize;
  276.  
  277.   fParent.fPresentationTime = presentationTime;
  278.  
  279.   // Now that we have new input data, check if we can deliver to the client:
  280.   fParent.awaitNewBuffer(NULL);
  281. }
Add Comment
Please, Sign In to add comment