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