|
MythTV
0.26-pre
|
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 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00015 **********/ 00016 // "liveMedia" 00017 // Copyright (c) 1996-2005 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 | (fVideoSourceCounter++&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 fInputBuffer[4] = PES_packet_length>>8; 00201 fInputBuffer[5] = PES_packet_length; 00202 00203 // Fill in the PES PTS (from our SCR): 00204 fInputBuffer[9] = 0x20|(fSCR.highBit<<3)|(fSCR.remainingBits>>29)|0x01; 00205 fInputBuffer[10] = fSCR.remainingBits>>22; 00206 fInputBuffer[11] = (fSCR.remainingBits>>14)|0x01; 00207 fInputBuffer[12] = fSCR.remainingBits>>7; 00208 fInputBuffer[13] = (fSCR.remainingBits<<1)|0x01; 00209 00210 fInputBufferInUse = True; 00211 00212 // Do the delivery: 00213 fParent.handleNewBuffer(fInputBuffer, fInputBufferBytesAvailable, 00214 fMPEGVersion, fSCR); 00215 00216 return True; 00217 } 00218 00219 void InputESSourceRecord 00220 ::afterGettingFrame(void* clientData, unsigned frameSize, 00221 unsigned numTruncatedBytes, 00222 struct timeval presentationTime, 00223 unsigned /*durationInMicroseconds*/) { 00224 InputESSourceRecord* source = (InputESSourceRecord*)clientData; 00225 source->afterGettingFrame1(frameSize, numTruncatedBytes, presentationTime); 00226 } 00227 void InputESSourceRecord 00228 ::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes, 00229 struct timeval presentationTime) { 00230 if (numTruncatedBytes > 0) { 00231 fParent.envir() << "MPEG2TransportStreamFromESSource: input buffer too small; increase \"MAX_INPUT_ES_FRAME_SIZE\" in \"MPEG2TransportStreamFromESSource\" by at least " 00232 << numTruncatedBytes << " bytes!\n"; 00233 } 00234 00235 if (fInputBufferBytesAvailable == SIMPLE_PES_HEADER_SIZE) { 00236 // Use this presentationTime for our SCR: 00237 fSCR.highBit 00238 = ((presentationTime.tv_sec*45000 + (presentationTime.tv_usec*9)/200)& 00239 0x80000000) != 0; 00240 fSCR.remainingBits 00241 = presentationTime.tv_sec*90000 + (presentationTime.tv_usec*9)/100; 00242 fSCR.extension = (presentationTime.tv_usec*9)%100; 00243 #ifdef DEBUG_SCR 00244 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); 00245 #endif 00246 } 00247 00248 fInputBufferBytesAvailable += frameSize; 00249 00250 // Now that we have new input data, check if we can deliver to the client: 00251 fParent.awaitNewBuffer(NULL); 00252 }
1.7.6.1