00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "MPEG2TransportStreamFramer.hh"
00024 #include <GroupsockHelper.hh>
00025
00026 #define TRANSPORT_PACKET_SIZE 188
00027 #define NEW_DURATION_WEIGHT 0.5
00028
00029 #define TIME_ADJUSTMENT_FACTOR 0.8
00030
00031
00032
00033
00034 #define MAX_PLAYOUT_BUFFER_DURATION 0.1 // (seconds)
00035 #define PCR_PERIOD_VARIATION_RATIO 0.5
00036
00038
00039 class PIDStatus {
00040 public:
00041 PIDStatus(double _firstClock, double _firstRealTime)
00042 : firstClock(_firstClock), lastClock(_firstClock),
00043 firstRealTime(_firstRealTime), lastRealTime(_firstRealTime),
00044 lastPacketNum(0) {
00045 }
00046
00047 double firstClock, lastClock, firstRealTime, lastRealTime;
00048 unsigned lastPacketNum;
00049 };
00050
00051
00053
00054 MPEG2TransportStreamFramer* MPEG2TransportStreamFramer
00055 ::createNew(UsageEnvironment& env, FramedSource* inputSource) {
00056 return new MPEG2TransportStreamFramer(env, inputSource);
00057 }
00058
00059 MPEG2TransportStreamFramer
00060 ::MPEG2TransportStreamFramer(UsageEnvironment& env, FramedSource* inputSource)
00061 : FramedFilter(env, inputSource),
00062 fTSPacketCount(0), fTSPacketDurationEstimate(0.0), fTSPCRCount(0) {
00063 fPIDStatusTable = HashTable::create(ONE_WORD_HASH_KEYS);
00064 }
00065
00066 MPEG2TransportStreamFramer::~MPEG2TransportStreamFramer() {
00067 clearPIDStatusTable();
00068 delete fPIDStatusTable;
00069 }
00070
00071 void MPEG2TransportStreamFramer::clearPIDStatusTable() {
00072 PIDStatus* pidStatus;
00073 while ((pidStatus = (PIDStatus*)fPIDStatusTable->RemoveNext()) != NULL) {
00074 delete pidStatus;
00075 }
00076 }
00077
00078 void MPEG2TransportStreamFramer::doGetNextFrame() {
00079
00080 fFrameSize = 0;
00081 fInputSource->getNextFrame(fTo, fMaxSize,
00082 afterGettingFrame, this,
00083 FramedSource::handleClosure, this);
00084 }
00085
00086 void MPEG2TransportStreamFramer::doStopGettingFrames() {
00087 FramedFilter::doStopGettingFrames();
00088 fTSPacketCount = 0;
00089
00090 clearPIDStatusTable();
00091 }
00092
00093 void MPEG2TransportStreamFramer
00094 ::afterGettingFrame(void* clientData, unsigned frameSize,
00095 unsigned ,
00096 struct timeval presentationTime,
00097 unsigned ) {
00098 MPEG2TransportStreamFramer* framer = (MPEG2TransportStreamFramer*)clientData;
00099 framer->afterGettingFrame1(frameSize, presentationTime);
00100 }
00101
00102 #define TRANSPORT_SYNC_BYTE 0x47
00103
00104 void MPEG2TransportStreamFramer::afterGettingFrame1(unsigned frameSize,
00105 struct timeval presentationTime) {
00106 fFrameSize += frameSize;
00107 unsigned const numTSPackets = fFrameSize/TRANSPORT_PACKET_SIZE;
00108 fFrameSize = numTSPackets*TRANSPORT_PACKET_SIZE;
00109 if (fFrameSize == 0) {
00110
00111 handleClosure(this);
00112 return;
00113 }
00114
00115
00116 unsigned syncBytePosition;
00117 for (syncBytePosition = 0; syncBytePosition < fFrameSize; ++syncBytePosition) {
00118 if (fTo[syncBytePosition] == TRANSPORT_SYNC_BYTE) break;
00119 }
00120 if (syncBytePosition == fFrameSize) {
00121 envir() << "No Transport Stream sync byte in data.";
00122 handleClosure(this);
00123 return;
00124 } else if (syncBytePosition > 0) {
00125
00126
00127 memmove(fTo, &fTo[syncBytePosition], fFrameSize - syncBytePosition);
00128 fFrameSize -= syncBytePosition;
00129 fInputSource->getNextFrame(&fTo[fFrameSize], syncBytePosition,
00130 afterGettingFrame, this,
00131 FramedSource::handleClosure, this);
00132 return;
00133 }
00134
00135 fPresentationTime = presentationTime;
00136
00137
00138
00139 struct timeval tvNow;
00140 gettimeofday(&tvNow, NULL);
00141 double timeNow = tvNow.tv_sec + tvNow.tv_usec/1000000.0;
00142 for (unsigned i = 0; i < numTSPackets; ++i) {
00143 updateTSPacketDurationEstimate(&fTo[i*TRANSPORT_PACKET_SIZE], timeNow);
00144 }
00145
00146 fDurationInMicroseconds
00147 = numTSPackets * (unsigned)(fTSPacketDurationEstimate*1000000);
00148
00149
00150 afterGetting(this);
00151 }
00152
00153 void MPEG2TransportStreamFramer
00154 ::updateTSPacketDurationEstimate(unsigned char* pkt, double timeNow) {
00155
00156 if (pkt[0] != TRANSPORT_SYNC_BYTE) {
00157 envir() << "Missing sync byte!\n";
00158 return;
00159 }
00160
00161 ++fTSPacketCount;
00162
00163
00164 u_int8_t const adaptation_field_control = (pkt[3]&0x30)>>4;
00165 if (adaptation_field_control != 2 && adaptation_field_control != 3) return;
00166
00167
00168 u_int8_t const adaptation_field_length = pkt[4];
00169 if (adaptation_field_length == 0) return;
00170
00171 u_int8_t const discontinuity_indicator = pkt[5]&0x80;
00172 u_int8_t const pcrFlag = pkt[5]&0x10;
00173 if (pcrFlag == 0) return;
00174
00175
00176 ++fTSPCRCount;
00177 u_int32_t pcrBaseHigh = (pkt[6]<<24)|(pkt[7]<<16)|(pkt[8]<<8)|pkt[9];
00178 double clock = pcrBaseHigh/45000.0;
00179 if ((pkt[10]&0x80) != 0) clock += 1/90000.0;
00180 unsigned short pcrExt = ((pkt[10]&0x01)<<8) | pkt[11];
00181 clock += pcrExt/27000000.0;
00182
00183 unsigned pid = ((pkt[1]&0x1F)<<8) | pkt[2];
00184
00185
00186 PIDStatus* pidStatus = (PIDStatus*)(fPIDStatusTable->Lookup((char*)pid));
00187
00188 if (pidStatus == NULL) {
00189
00190 pidStatus = new PIDStatus(clock, timeNow);
00191 fPIDStatusTable->Add((char*)pid, pidStatus);
00192 #ifdef DEBUG_PCR
00193 fprintf(stderr, "PID 0x%x, FIRST PCR 0x%08x+%d:%03x == %f @ %f, pkt #%lu\n", pid, pcrBaseHigh, pkt[10]>>7, pcrExt, clock, timeNow, fTSPacketCount);
00194 #endif
00195 } else {
00196
00197 double durationPerPacket
00198 = (clock - pidStatus->lastClock)/(fTSPacketCount - pidStatus->lastPacketNum);
00199
00200
00201
00202 double meanPCRPeriod = 0.0;
00203 if (fTSPCRCount > 0) {
00204 meanPCRPeriod=(double)fTSPacketCount/fTSPCRCount;
00205 if (fTSPacketCount - pidStatus->lastPacketNum < meanPCRPeriod*PCR_PERIOD_VARIATION_RATIO) return;
00206 }
00207
00208 if (fTSPacketDurationEstimate == 0.0) {
00209 fTSPacketDurationEstimate = durationPerPacket;
00210 } else if (discontinuity_indicator == 0 && durationPerPacket >= 0.0) {
00211 fTSPacketDurationEstimate
00212 = durationPerPacket*NEW_DURATION_WEIGHT
00213 + fTSPacketDurationEstimate*(1-NEW_DURATION_WEIGHT);
00214
00215
00216
00217 double transmitDuration = timeNow - pidStatus->firstRealTime;
00218 double playoutDuration = clock - pidStatus->firstClock;
00219 if (transmitDuration > playoutDuration) {
00220 fTSPacketDurationEstimate *= TIME_ADJUSTMENT_FACTOR;
00221 } else if (transmitDuration + MAX_PLAYOUT_BUFFER_DURATION < playoutDuration) {
00222 fTSPacketDurationEstimate /= TIME_ADJUSTMENT_FACTOR;
00223 }
00224 } else {
00225
00226
00227 pidStatus->firstClock = clock;
00228 pidStatus->firstRealTime = timeNow;
00229 }
00230 #ifdef DEBUG_PCR
00231 fprintf(stderr, "PID 0x%x, PCR 0x%08x+%d:%03x == %f @ %f (diffs %f @ %f), pkt #%lu, discon %d => this duration %f, new estimate %f, mean PCR period=%f\n", pid, pcrBaseHigh, pkt[10]>>7, pcrExt, clock, timeNow, clock - pidStatus->firstClock, timeNow - pidStatus->firstRealTime, fTSPacketCount, discontinuity_indicator != 0, durationPerPacket, fTSPacketDurationEstimate, meanPCRPeriod );
00232 #endif
00233 }
00234
00235 pidStatus->lastClock = clock;
00236 pidStatus->lastRealTime = timeNow;
00237 pidStatus->lastPacketNum = fTSPacketCount;
00238 }