00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "MPEG2TransportStreamMultiplexor.hh"
00023
00024 #define TRANSPORT_PACKET_SIZE 188
00025
00026 #define PAT_FREQUENCY 100 // # of packets between Program Association Tables
00027 #define PMT_FREQUENCY 500 // # of packets between Program Map Tables
00028
00029 #define PID_TABLE_SIZE 256
00030
00031 MPEG2TransportStreamMultiplexor
00032 ::MPEG2TransportStreamMultiplexor(UsageEnvironment& env)
00033 : FramedSource(env),
00034 fHaveVideoStreams(True),
00035 fOutgoingPacketCounter(0), fProgramMapVersion(0),
00036 fPreviousInputProgramMapVersion(0xFF), fCurrentInputProgramMapVersion(0xFF),
00037 fPCR_PID(0), fCurrentPID(0),
00038 fInputBuffer(NULL), fInputBufferSize(0), fInputBufferBytesUsed(0),
00039 fIsFirstAdaptationField(True) {
00040 for (unsigned i = 0; i < PID_TABLE_SIZE; ++i) {
00041 fPIDState[i].counter = 0;
00042 fPIDState[i].streamType = 0;
00043 }
00044 }
00045
00046 MPEG2TransportStreamMultiplexor::~MPEG2TransportStreamMultiplexor() {
00047 }
00048
00049 void MPEG2TransportStreamMultiplexor::doGetNextFrame() {
00050 if (fInputBufferBytesUsed >= fInputBufferSize) {
00051
00052
00053 awaitNewBuffer(fInputBuffer);
00054 return;
00055 }
00056
00057 do {
00058
00059 if (fOutgoingPacketCounter++ % PAT_FREQUENCY == 0) {
00060 deliverPATPacket();
00061 break;
00062 }
00063
00064
00065 Boolean programMapHasChanged = fPIDState[fCurrentPID].counter == 0
00066 || fCurrentInputProgramMapVersion != fPreviousInputProgramMapVersion;
00067 if (fOutgoingPacketCounter % PMT_FREQUENCY == 0 || programMapHasChanged) {
00068 if (programMapHasChanged) {
00069 fPIDState[fCurrentPID].counter = 1;
00070 fPreviousInputProgramMapVersion = fCurrentInputProgramMapVersion;
00071 }
00072 deliverPMTPacket(programMapHasChanged);
00073 break;
00074 }
00075
00076
00077 deliverDataToClient(fCurrentPID, fInputBuffer, fInputBufferSize,
00078 fInputBufferBytesUsed);
00079 } while (0);
00080
00081
00082
00083 afterGetting(this);
00084 }
00085
00086 void MPEG2TransportStreamMultiplexor
00087 ::handleNewBuffer(unsigned char* buffer, unsigned bufferSize,
00088 int mpegVersion, MPEG1or2Demux::SCR scr) {
00089 if (bufferSize < 4) return;
00090 fInputBuffer = buffer;
00091 fInputBufferSize = bufferSize;
00092 fInputBufferBytesUsed = 0;
00093
00094 u_int8_t stream_id = fInputBuffer[3];
00095
00096
00097 if (stream_id == 0xBE) {
00098 fInputBufferSize = 0;
00099 } else if (stream_id == 0xBC) {
00100 setProgramStreamMap(fInputBufferSize);
00101 fInputBufferSize = 0;
00102 } else {
00103 fCurrentPID = stream_id;
00104
00105
00106 u_int8_t& streamType = fPIDState[fCurrentPID].streamType;
00107
00108 if (streamType == 0) {
00109
00110
00111 if ((stream_id&0xF0) == 0xE0) {
00112 streamType = mpegVersion == 1 ? 1 : mpegVersion == 2 ? 2 : mpegVersion == 4 ? 0x10 : 0x1B;
00113 } else if ((stream_id&0xE0) == 0xC0) {
00114 streamType = mpegVersion == 1 ? 3 : mpegVersion == 2 ? 4 : 0xF;
00115 } else if (stream_id == 0xBD) {
00116 streamType = 0x06;
00117 } else {
00118 streamType = 0x81;
00119 }
00120 }
00121
00122 if (fPCR_PID == 0) {
00123 if ((!fHaveVideoStreams && (streamType == 3 || streamType == 4 || streamType == 0xF)) ||
00124 (streamType == 1 || streamType == 2 || streamType == 0x10 || streamType == 0x1B)) {
00125 fPCR_PID = fCurrentPID;
00126 }
00127 }
00128 if (fCurrentPID == fPCR_PID) {
00129
00130 fPCR = scr;
00131 }
00132 }
00133
00134
00135 doGetNextFrame();
00136 }
00137
00138 void MPEG2TransportStreamMultiplexor
00139 ::deliverDataToClient(u_int8_t pid, unsigned char* buffer, unsigned bufferSize,
00140 unsigned& startPositionInBuffer) {
00141
00142 if (fMaxSize < TRANSPORT_PACKET_SIZE) {
00143 fFrameSize = 0;
00144 fNumTruncatedBytes = TRANSPORT_PACKET_SIZE;
00145 } else {
00146 fFrameSize = TRANSPORT_PACKET_SIZE;
00147 Boolean willAddPCR = pid == fPCR_PID && startPositionInBuffer == 0
00148 && !(fPCR.highBit == 0 && fPCR.remainingBits == 0 && fPCR.extension == 0);
00149 unsigned const numBytesAvailable = bufferSize - startPositionInBuffer;
00150 unsigned numHeaderBytes = 4;
00151 unsigned numPCRBytes = 0;
00152 unsigned numPaddingBytes = 0;
00153 unsigned numDataBytes;
00154 u_int8_t adaptation_field_control;
00155 if (willAddPCR) {
00156 adaptation_field_control = 0x30;
00157 numHeaderBytes += 2;
00158 numPCRBytes = 6;
00159 if (numBytesAvailable >= TRANSPORT_PACKET_SIZE - numHeaderBytes - numPCRBytes) {
00160 numDataBytes = TRANSPORT_PACKET_SIZE - numHeaderBytes - numPCRBytes;
00161 } else {
00162 numDataBytes = numBytesAvailable;
00163 numPaddingBytes
00164 = TRANSPORT_PACKET_SIZE - numHeaderBytes - numPCRBytes - numDataBytes;
00165 }
00166 } else if (numBytesAvailable >= TRANSPORT_PACKET_SIZE - numHeaderBytes) {
00167
00168 adaptation_field_control = 0x10;
00169 numDataBytes = TRANSPORT_PACKET_SIZE - numHeaderBytes;
00170 } else {
00171 adaptation_field_control = 0x30;
00172 ++numHeaderBytes;
00173
00174 numDataBytes = numBytesAvailable;
00175 if (numDataBytes < TRANSPORT_PACKET_SIZE - numHeaderBytes) {
00176 ++numHeaderBytes;
00177 numPaddingBytes = TRANSPORT_PACKET_SIZE - numHeaderBytes - numDataBytes;
00178 }
00179 }
00180
00181
00182
00183
00184 unsigned char* header = fTo;
00185 *header++ = 0x47;
00186 *header++ = (startPositionInBuffer == 0) ? 0x40 : 0x00;
00187
00188
00189 *header++ = pid;
00190
00191 unsigned& continuity_counter = fPIDState[pid].counter;
00192 *header++ = adaptation_field_control|(continuity_counter&0x0F);
00193
00194 ++continuity_counter;
00195 if (adaptation_field_control == 0x30) {
00196
00197 u_int8_t adaptation_field_length
00198 = (numHeaderBytes == 5) ? 0 : 1 + numPCRBytes + numPaddingBytes;
00199 *header++ = adaptation_field_length;
00200 if (numHeaderBytes > 5) {
00201 u_int8_t flags = willAddPCR ? 0x10 : 0x00;
00202 if (fIsFirstAdaptationField) {
00203 flags |= 0x80;
00204 fIsFirstAdaptationField = False;
00205 }
00206 *header++ = flags;
00207 if (willAddPCR) {
00208 u_int32_t pcrHigh32Bits = (fPCR.highBit<<31) | (fPCR.remainingBits>>1);
00209 u_int8_t pcrLowBit = fPCR.remainingBits&1;
00210 u_int8_t extHighBit = (fPCR.extension&0x100)>>8;
00211 *header++ = pcrHigh32Bits>>24;
00212 *header++ = pcrHigh32Bits>>16;
00213 *header++ = pcrHigh32Bits>>8;
00214 *header++ = pcrHigh32Bits;
00215 *header++ = (pcrLowBit<<7)|0x7E|extHighBit;
00216 *header++ = (u_int8_t)fPCR.extension;
00217 }
00218 }
00219 }
00220
00221
00222 for (unsigned i = 0; i < numPaddingBytes; ++i) *header++ = 0xFF;
00223
00224
00225 memmove(header, &buffer[startPositionInBuffer], numDataBytes);
00226 startPositionInBuffer += numDataBytes;
00227 }
00228 }
00229
00230 static u_int32_t calculateCRC(u_int8_t* data, unsigned dataLength);
00231
00232 #define PAT_PID 0
00233 #define OUR_PROGRAM_NUMBER 1
00234 #define OUR_PROGRAM_MAP_PID 0x30
00235
00236 void MPEG2TransportStreamMultiplexor::deliverPATPacket() {
00237
00238 unsigned const patSize = TRANSPORT_PACKET_SIZE - 4;
00239 unsigned char* patBuffer = new unsigned char[patSize];
00240
00241
00242 unsigned char* pat = patBuffer;
00243 *pat++ = 0;
00244 *pat++ = 0;
00245 *pat++ = 0xB0;
00246 *pat++ = 13;
00247 *pat++ = 0; *pat++ = 1;
00248 *pat++ = 0xC3;
00249 *pat++ = 0;
00250 *pat++ = 0;
00251 *pat++ = OUR_PROGRAM_NUMBER>>8; *pat++ = OUR_PROGRAM_NUMBER;
00252 *pat++ = 0xE0|(OUR_PROGRAM_MAP_PID>>8);
00253 *pat++ = OUR_PROGRAM_MAP_PID;
00254
00255
00256 u_int32_t crc = calculateCRC(patBuffer+1, pat - (patBuffer+1));
00257 *pat++ = crc>>24; *pat++ = crc>>16; *pat++ = crc>>8; *pat++ = crc;
00258
00259
00260 while (pat < &patBuffer[patSize]) *pat++ = 0xFF;
00261
00262
00263 unsigned startPosition = 0;
00264 deliverDataToClient(PAT_PID, patBuffer, patSize, startPosition);
00265
00266
00267 delete[] patBuffer;
00268 }
00269
00270 void MPEG2TransportStreamMultiplexor::deliverPMTPacket(Boolean hasChanged) {
00271 if (hasChanged) ++fProgramMapVersion;
00272
00273
00274 unsigned const pmtSize = TRANSPORT_PACKET_SIZE - 4;
00275 unsigned char* pmtBuffer = new unsigned char[pmtSize];
00276
00277
00278 unsigned char* pmt = pmtBuffer;
00279 *pmt++ = 0;
00280 *pmt++ = 2;
00281 *pmt++ = 0xB0;
00282 unsigned char* section_lengthPtr = pmt;
00283 *pmt++ = 0;
00284 *pmt++ = OUR_PROGRAM_NUMBER>>8; *pmt++ = OUR_PROGRAM_NUMBER;
00285 *pmt++ = 0xC1|((fProgramMapVersion&0x1F)<<1);
00286 *pmt++ = 0;
00287 *pmt++ = 0;
00288 *pmt++ = 0xE0;
00289 *pmt++ = fPCR_PID;
00290 *pmt++ = 0xF0;
00291 *pmt++ = 0;
00292 for (int pid = 0; pid < PID_TABLE_SIZE; ++pid) {
00293 if (fPIDState[pid].streamType != 0) {
00294
00295 *pmt++ = fPIDState[pid].streamType;
00296 *pmt++ = 0xE0;
00297 *pmt++ = pid;
00298 *pmt++ = 0xF0;
00299 *pmt++ = 0;
00300 }
00301 }
00302 unsigned section_length = pmt - (section_lengthPtr+1) + 4 ;
00303 *section_lengthPtr = section_length;
00304
00305
00306 u_int32_t crc = calculateCRC(pmtBuffer+1, pmt - (pmtBuffer+1));
00307 *pmt++ = crc>>24; *pmt++ = crc>>16; *pmt++ = crc>>8; *pmt++ = crc;
00308
00309
00310 while (pmt < &pmtBuffer[pmtSize]) *pmt++ = 0xFF;
00311
00312
00313 unsigned startPosition = 0;
00314 deliverDataToClient(OUR_PROGRAM_MAP_PID, pmtBuffer, pmtSize, startPosition);
00315
00316
00317 delete[] pmtBuffer;
00318 }
00319
00320 void MPEG2TransportStreamMultiplexor::setProgramStreamMap(unsigned frameSize) {
00321 if (frameSize <= 16) return;
00322 if (frameSize > 0xFF) return;
00323
00324 u_int16_t program_stream_map_length = (fInputBuffer[4]<<8) | fInputBuffer[5];
00325 if ((u_int16_t)frameSize > 6+program_stream_map_length) {
00326 frameSize = 6+program_stream_map_length;
00327 }
00328
00329 u_int8_t versionByte = fInputBuffer[6];
00330 if ((versionByte&0x80) == 0) return;
00331 fCurrentInputProgramMapVersion = versionByte&0x1F;
00332
00333 u_int16_t program_stream_info_length = (fInputBuffer[8]<<8) | fInputBuffer[9];
00334 unsigned offset = 10 + program_stream_info_length;
00335
00336 u_int16_t elementary_stream_map_length
00337 = (fInputBuffer[offset]<<8) | fInputBuffer[offset+1];
00338 offset += 2;
00339 frameSize -= 4;
00340 if (frameSize > offset + elementary_stream_map_length) {
00341 frameSize = offset + elementary_stream_map_length;
00342 }
00343
00344 while (offset + 4 <= frameSize) {
00345 u_int8_t stream_type = fInputBuffer[offset];
00346 u_int8_t elementary_stream_id = fInputBuffer[offset+1];
00347
00348 fPIDState[elementary_stream_id].streamType = stream_type;
00349
00350 u_int16_t elementary_stream_info_length
00351 = (fInputBuffer[offset+2]<<8) | fInputBuffer[offset+3];
00352 offset += 4 + elementary_stream_info_length;
00353 }
00354 }
00355
00356 static u_int32_t const CRC32[256] = {
00357 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
00358 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
00359 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
00360 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
00361 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
00362 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
00363 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
00364 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
00365 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
00366 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
00367 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
00368 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
00369 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
00370 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
00371 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
00372 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
00373 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
00374 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
00375 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
00376 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
00377 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
00378 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
00379 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
00380 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
00381 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
00382 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
00383 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
00384 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
00385 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
00386 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
00387 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
00388 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
00389 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
00390 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
00391 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
00392 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
00393 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
00394 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
00395 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
00396 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
00397 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
00398 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
00399 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
00400 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
00401 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
00402 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
00403 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
00404 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
00405 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
00406 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
00407 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
00408 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
00409 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
00410 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
00411 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
00412 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
00413 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
00414 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
00415 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
00416 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
00417 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
00418 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
00419 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
00420 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
00421 };
00422
00423 static u_int32_t calculateCRC(u_int8_t* data, unsigned dataLength) {
00424 u_int32_t crc = 0xFFFFFFFF;
00425
00426 while (dataLength-- > 0) {
00427 crc = (crc<<8) ^ CRC32[(crc>>24) ^ (u_int32_t)(*data++)];
00428 }
00429
00430 return crc;
00431 }