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), 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 = rewindToVSH(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 reverseToPreviousVSH,
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 (reverseToPreviousVSH) {
00177
00178 success = rewindToVSH(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 (reverseToPreviousVSH) 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 Boolean MPEG2TransportStreamIndexFile::openFid() {
00219 if (fFid == NULL && fFileName != NULL) {
00220 if ((fFid = OpenInputFile(envir(), fFileName)) != NULL) {
00221 fCurrentIndexRecordNum = 0;
00222 }
00223 }
00224
00225 return fFid != NULL;
00226 }
00227
00228 Boolean MPEG2TransportStreamIndexFile::seekToIndexRecord(unsigned long indexRecordNumber) {
00229 if (!openFid()) return False;
00230
00231 if (indexRecordNumber == fCurrentIndexRecordNum) return True;
00232
00233 if (SeekFile64(fFid, (int64_t)(indexRecordNumber*INDEX_RECORD_SIZE), SEEK_SET) != 0) return False;
00234 fCurrentIndexRecordNum = indexRecordNumber;
00235 return True;
00236 }
00237
00238 Boolean MPEG2TransportStreamIndexFile::readIndexRecord(unsigned long indexRecordNum) {
00239 do {
00240 if (!seekToIndexRecord(indexRecordNum)) break;
00241 if (fread(fBuf, INDEX_RECORD_SIZE, 1, fFid) != 1) break;
00242 ++fCurrentIndexRecordNum;
00243
00244 return True;
00245 } while (0);
00246
00247 return False;
00248 }
00249
00250 Boolean MPEG2TransportStreamIndexFile::readOneIndexRecord(unsigned long indexRecordNum) {
00251 Boolean result = readIndexRecord(indexRecordNum);
00252 closeFid();
00253
00254 return result;
00255 }
00256
00257 void MPEG2TransportStreamIndexFile::closeFid() {
00258 if (fFid != NULL) {
00259 CloseInputFile(fFid);
00260 fFid = NULL;
00261 }
00262 }
00263
00264 float MPEG2TransportStreamIndexFile::pcrFromBuf() {
00265 unsigned pcr_int = (fBuf[5]<<16) | (fBuf[4]<<8) | fBuf[3];
00266 u_int8_t pcr_frac = fBuf[6];
00267 return pcr_int + pcr_frac/256.0f;
00268 }
00269
00270 unsigned long MPEG2TransportStreamIndexFile::tsPacketNumFromBuf() {
00271 return (fBuf[10]<<24) | (fBuf[9]<<16) | (fBuf[8]<<8) | fBuf[7];
00272 }
00273
00274 Boolean MPEG2TransportStreamIndexFile::rewindToVSH(unsigned long&ixFound) {
00275 Boolean success = False;
00276
00277 while (ixFound > 0) {
00278 if (!readIndexRecord(ixFound)) break;
00279
00280 u_int8_t recordType = recordTypeFromBuf();
00281 if ((recordType&0x80) != 0 && (recordType&0x7F) <= 2) {
00282 if ((recordType&0x7F) == 2) {
00283
00284
00285 unsigned long newIxFound = ixFound;
00286
00287 while (--newIxFound > 0) {
00288 if (!readIndexRecord(newIxFound)) break;
00289 recordType = recordTypeFromBuf();
00290 if ((recordType&0x7F) != 1) break;
00291 if ((recordType&0x80) != 0) {
00292 ixFound = newIxFound;
00293 break;
00294 }
00295 }
00296 }
00297
00298 success = True;
00299 break;
00300 }
00301 --ixFound;
00302 }
00303 if (ixFound == 0) success = True;
00304
00305 return success;
00306 }