00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "MPEG2TransportStreamIndexFile.hh"
00025 #include "InputFile.hh"
00026
00027 MPEG2TransportStreamIndexFile
00028 ::MPEG2TransportStreamIndexFile(UsageEnvironment& env, char const* indexFileName)
00029 : Medium(env),
00030 fFileName(strDup(indexFileName)), fFid(NULL), fMPEGVersion(0), fCurrentIndexRecordNum(0),
00031 fCachedPCR(0.0f), fCachedTSPacketNumber(0), fNumIndexRecords(0) {
00032
00033 u_int64_t indexFileSize = GetFileSize(indexFileName, NULL);
00034 if (indexFileSize % INDEX_RECORD_SIZE != 0) {
00035 env << "Warning: Size of the index file \"" << indexFileName
00036 << "\" (" << (unsigned)indexFileSize
00037 << ") is not a multiple of the index record size ("
00038 << INDEX_RECORD_SIZE << ")\n";
00039 }
00040 fNumIndexRecords = (unsigned long)(indexFileSize/INDEX_RECORD_SIZE);
00041 }
00042
00043 MPEG2TransportStreamIndexFile* MPEG2TransportStreamIndexFile
00044 ::createNew(UsageEnvironment& env, char const* indexFileName) {
00045 if (indexFileName == NULL) return NULL;
00046 MPEG2TransportStreamIndexFile* indexFile
00047 = new MPEG2TransportStreamIndexFile(env, indexFileName);
00048
00049
00050 if (indexFile->getPlayingDuration() == 0.0f) {
00051 delete indexFile;
00052 indexFile = NULL;
00053 }
00054
00055 return indexFile;
00056 }
00057
00058 MPEG2TransportStreamIndexFile::~MPEG2TransportStreamIndexFile() {
00059 closeFid();
00060 delete[] fFileName;
00061 }
00062
00063 void MPEG2TransportStreamIndexFile
00064 ::lookupTSPacketNumFromNPT(float& npt, unsigned long& tsPacketNumber,
00065 unsigned long& indexRecordNumber) {
00066 if (npt <= 0.0 || fNumIndexRecords == 0) {
00067 npt = 0.0f;
00068 tsPacketNumber = indexRecordNumber = 0;
00069 return;
00070 }
00071
00072
00073 if (npt == fCachedPCR) {
00074 tsPacketNumber = fCachedTSPacketNumber;
00075 indexRecordNumber = fCachedIndexRecordNumber;
00076 return;
00077 }
00078
00079
00080
00081 Boolean success = False;
00082 unsigned long ixFound = 0;
00083 do {
00084 unsigned long ixLeft = 0, ixRight = fNumIndexRecords-1;
00085 float pcrLeft = 0.0f, pcrRight;
00086 if (!readIndexRecord(ixRight)) break;
00087 pcrRight = pcrFromBuf();
00088 if (npt > pcrRight) npt = pcrRight;
00089
00090
00091 while (ixRight-ixLeft > 1 && pcrLeft < npt && npt <= pcrRight) {
00092 unsigned long ixNew = ixLeft
00093 + (unsigned long)(((npt-pcrLeft)/(pcrRight-pcrLeft))*(ixRight-ixLeft));
00094 if (ixNew == ixLeft || ixNew == ixRight) {
00095
00096 ixNew = (ixLeft+ixRight)/2;
00097 }
00098 if (!readIndexRecord(ixNew)) break;
00099 float pcrNew = pcrFromBuf();
00100 if (pcrNew < npt) {
00101 pcrLeft = pcrNew;
00102 ixLeft = ixNew;
00103 } else {
00104 pcrRight = pcrNew;
00105 ixRight = ixNew;
00106 }
00107 }
00108 if (ixRight-ixLeft > 1 || npt <= pcrLeft || npt > pcrRight) break;
00109
00110 ixFound = ixRight;
00111
00112 success = rewindToCleanPoint(ixFound);
00113 } while (0);
00114
00115 if (success && readIndexRecord(ixFound)) {
00116
00117 npt = fCachedPCR = pcrFromBuf();
00118 tsPacketNumber = fCachedTSPacketNumber = tsPacketNumFromBuf();
00119 indexRecordNumber = fCachedIndexRecordNumber = ixFound;
00120 } else {
00121
00122 npt = 0.0f;
00123 tsPacketNumber = indexRecordNumber = 0;
00124 }
00125 closeFid();
00126 }
00127
00128 void MPEG2TransportStreamIndexFile
00129 ::lookupPCRFromTSPacketNum(unsigned long& tsPacketNumber, Boolean reverseToPreviousCleanPoint,
00130 float& pcr, unsigned long& indexRecordNumber) {
00131 if (tsPacketNumber == 0 || fNumIndexRecords == 0) {
00132 pcr = 0.0f;
00133 indexRecordNumber = 0;
00134 return;
00135 }
00136
00137
00138 if (tsPacketNumber == fCachedTSPacketNumber) {
00139 pcr = fCachedPCR;
00140 indexRecordNumber = fCachedIndexRecordNumber;
00141 return;
00142 }
00143
00144
00145
00146 Boolean success = False;
00147 unsigned long ixFound = 0;
00148 do {
00149 unsigned long ixLeft = 0, ixRight = fNumIndexRecords-1;
00150 unsigned long tsLeft = 0, tsRight;
00151 if (!readIndexRecord(ixRight)) break;
00152 tsRight = tsPacketNumFromBuf();
00153 if (tsPacketNumber > tsRight) tsPacketNumber = tsRight;
00154
00155
00156 while (ixRight-ixLeft > 1 && tsLeft < tsPacketNumber && tsPacketNumber <= tsRight) {
00157 unsigned long ixNew = ixLeft
00158 + (unsigned long)(((tsPacketNumber-tsLeft)/(tsRight-tsLeft))*(ixRight-ixLeft));
00159 if (ixNew == ixLeft || ixNew == ixRight) {
00160
00161 ixNew = (ixLeft+ixRight)/2;
00162 }
00163 if (!readIndexRecord(ixNew)) break;
00164 unsigned long tsNew = tsPacketNumFromBuf();
00165 if (tsNew < tsPacketNumber) {
00166 tsLeft = tsNew;
00167 ixLeft = ixNew;
00168 } else {
00169 tsRight = tsNew;
00170 ixRight = ixNew;
00171 }
00172 }
00173 if (ixRight-ixLeft > 1 || tsPacketNumber <= tsLeft || tsPacketNumber > tsRight) break;
00174
00175 ixFound = ixRight;
00176 if (reverseToPreviousCleanPoint) {
00177
00178 success = rewindToCleanPoint(ixFound);
00179 } else {
00180 success = True;
00181 }
00182 } while (0);
00183
00184 if (success && readIndexRecord(ixFound)) {
00185
00186 pcr = fCachedPCR = pcrFromBuf();
00187 fCachedTSPacketNumber = tsPacketNumFromBuf();
00188 if (reverseToPreviousCleanPoint) tsPacketNumber = fCachedTSPacketNumber;
00189 indexRecordNumber = fCachedIndexRecordNumber = ixFound;
00190 } else {
00191
00192 pcr = 0.0f;
00193 indexRecordNumber = 0;
00194 }
00195 closeFid();
00196 }
00197
00198 Boolean MPEG2TransportStreamIndexFile
00199 ::readIndexRecordValues(unsigned long indexRecordNum,
00200 unsigned long& transportPacketNum, u_int8_t& offset,
00201 u_int8_t& size, float& pcr, u_int8_t& recordType) {
00202 if (!readIndexRecord(indexRecordNum)) return False;
00203
00204 transportPacketNum = tsPacketNumFromBuf();
00205 offset = offsetFromBuf();
00206 size = sizeFromBuf();
00207 pcr = pcrFromBuf();
00208 recordType = recordTypeFromBuf();
00209 return True;
00210 }
00211
00212 float MPEG2TransportStreamIndexFile::getPlayingDuration() {
00213 if (fNumIndexRecords == 0 || !readOneIndexRecord(fNumIndexRecords-1)) return 0.0f;
00214
00215 return pcrFromBuf();
00216 }
00217
00218 int MPEG2TransportStreamIndexFile::mpegVersion() {
00219 if (fMPEGVersion != 0) return fMPEGVersion;
00220
00221
00222 if (!readOneIndexRecord(0)) return 0;
00223
00224 setMPEGVersionFromRecordType(recordTypeFromBuf());
00225 return fMPEGVersion;
00226 }
00227
00228 Boolean MPEG2TransportStreamIndexFile::openFid() {
00229 if (fFid == NULL && fFileName != NULL) {
00230 if ((fFid = OpenInputFile(envir(), fFileName)) != NULL) {
00231 fCurrentIndexRecordNum = 0;
00232 }
00233 }
00234
00235 return fFid != NULL;
00236 }
00237
00238 Boolean MPEG2TransportStreamIndexFile::seekToIndexRecord(unsigned long indexRecordNumber) {
00239 if (!openFid()) return False;
00240
00241 if (indexRecordNumber == fCurrentIndexRecordNum) return True;
00242
00243 if (SeekFile64(fFid, (int64_t)(indexRecordNumber*INDEX_RECORD_SIZE), SEEK_SET) != 0) return False;
00244 fCurrentIndexRecordNum = indexRecordNumber;
00245 return True;
00246 }
00247
00248 Boolean MPEG2TransportStreamIndexFile::readIndexRecord(unsigned long indexRecordNum) {
00249 do {
00250 if (!seekToIndexRecord(indexRecordNum)) break;
00251 if (fread(fBuf, INDEX_RECORD_SIZE, 1, fFid) != 1) break;
00252 ++fCurrentIndexRecordNum;
00253
00254 return True;
00255 } while (0);
00256
00257 return False;
00258 }
00259
00260 Boolean MPEG2TransportStreamIndexFile::readOneIndexRecord(unsigned long indexRecordNum) {
00261 Boolean result = readIndexRecord(indexRecordNum);
00262 closeFid();
00263
00264 return result;
00265 }
00266
00267 void MPEG2TransportStreamIndexFile::closeFid() {
00268 if (fFid != NULL) {
00269 CloseInputFile(fFid);
00270 fFid = NULL;
00271 }
00272 }
00273
00274 float MPEG2TransportStreamIndexFile::pcrFromBuf() {
00275 unsigned pcr_int = (fBuf[5]<<16) | (fBuf[4]<<8) | fBuf[3];
00276 u_int8_t pcr_frac = fBuf[6];
00277 return pcr_int + pcr_frac/256.0f;
00278 }
00279
00280 unsigned long MPEG2TransportStreamIndexFile::tsPacketNumFromBuf() {
00281 return (fBuf[10]<<24) | (fBuf[9]<<16) | (fBuf[8]<<8) | fBuf[7];
00282 }
00283
00284 void MPEG2TransportStreamIndexFile::setMPEGVersionFromRecordType(u_int8_t recordType) {
00285 if (fMPEGVersion != 0) return;
00286
00287 u_int8_t const recordTypeWithoutStartBit = recordType&~0x80;
00288 if (recordTypeWithoutStartBit >= 1 && recordTypeWithoutStartBit <= 4) fMPEGVersion = 2;
00289 else if (recordTypeWithoutStartBit >= 5 && recordTypeWithoutStartBit <= 10) fMPEGVersion = 5;
00290 }
00291
00292 Boolean MPEG2TransportStreamIndexFile::rewindToCleanPoint(unsigned long&ixFound) {
00293 Boolean success = False;
00294
00295 while (ixFound > 0) {
00296 if (!readIndexRecord(ixFound)) break;
00297
00298 u_int8_t recordType = recordTypeFromBuf();
00299 setMPEGVersionFromRecordType(recordType);
00300
00301
00302
00303
00304 if ((recordType&0x80) != 0) {
00305 recordType &=~ 0x80;
00306 if (fMPEGVersion == 5) {
00307 if (recordType == 5) {
00308 success = True;
00309 break;
00310 }
00311 } else {
00312 if (recordType == 1) {
00313 success = True;
00314 break;
00315 } else if (recordType == 2) {
00316
00317 unsigned long newIxFound = ixFound;
00318
00319 while (--newIxFound > 0) {
00320 if (!readIndexRecord(newIxFound)) break;
00321 recordType = recordTypeFromBuf();
00322 if ((recordType&0x7F) != 1) break;
00323 if ((recordType&0x80) != 0) {
00324 ixFound = newIxFound;
00325 break;
00326 }
00327 }
00328 }
00329 success = True;
00330 break;
00331 }
00332 }
00333
00334
00335 --ixFound;
00336 }
00337 if (ixFound == 0) success = True;
00338
00339 return success;
00340 }