Boolean MPEG2TransportStreamIndexFile::rewindToVSH(unsigned long&ixFound) {
  Boolean success = False;

  while (ixFound > 0) {
    if (!readIndexRecord(ixFound)) break;

    u_int8_t recordType = recordTypeFromBuf();
    if ((recordType&0x80) != 0 && (recordType&0x7F) <= 2/*GOP*/) {
      if ((recordType&0x7F) == 2) {
	// This is a GOP.  Hack: If the preceding record is for a Video Sequence Header,
	// then use it instead:
	unsigned long newIxFound = ixFound;

	while (--newIxFound > 0) {
	  if (!readIndexRecord(newIxFound)) break;
	  recordType = recordTypeFromBuf();
	  if ((recordType&0x7F) != 1) break; // not a Video Sequence Header
	  if ((recordType&0x80) != 0) { // this is the start of the VSH; use it
	    ixFound = newIxFound;
	    break;
	  }
	}
      }
      // Record 'ixFound' as appropriate to return:
      success = True;
      break;
    }
    --ixFound;
  }
  if (ixFound == 0) success = True; // use record 0 anyway

  return success;
}
Boolean MPEG2TransportStreamIndexFile::rewindToCleanPoint(unsigned long&ixFound) {
  Boolean success = False; // until we learn otherwise

  while (ixFound > 0) {
    if (!readIndexRecord(ixFound)) break;

    u_int8_t recordType = recordTypeFromBuf();
    setMPEGVersionFromRecordType(recordType);

    // A 'clean point' is the start of a 'frame' from which a decoder can cleanly resume
    // handling the stream.  For H.264, this is a SPS.  For H.265, this is a VPS.
    // For MPEG-2, this is a Video Sequence Header, or a GOP. 

    if ((recordType&0x80) != 0) { // This is the start of a 'frame'
      recordType &=~ 0x80; // remove the 'start of frame' bit
      if (fMPEGVersion == 5) { // H.264
        if (recordType == 5/*SPS*/) {
          success = True;
          break;
        }
      } else if (fMPEGVersion == 6) { // H.265
        if (recordType == 11/*VPS*/) {
          success = True;
          break;
        }
      } else { // MPEG-1, 2, or 4
        if (recordType == 1/*VSH*/) {
          success = True;
          break;
        } else if (recordType == 2/*GOP*/) {
          // Hack: If the preceding record is for a Video Sequence Header, then use it instead:
          unsigned long newIxFound = ixFound;

          while (--newIxFound > 0) {
            if (!readIndexRecord(newIxFound)) break;
            recordType = recordTypeFromBuf();
            if ((recordType&0x7F) != 1) break; // not a Video Sequence Header
            if ((recordType&0x80) != 0) { // this is the start of the VSH; use it
              ixFound = newIxFound;
              break;
            }
          }
        }
        success = True;
        break;
      }
    }

    // Keep checking, from the previous record:
    --ixFound;
  }
  if (ixFound == 0) success = True; // use record 0 anyway

  return success;
}
int MPEG2TransportStreamIndexFile::mpegVersion() {
  if (fMPEGVersion != 0) return fMPEGVersion; // we already know it

  // Read the first index record, and figure out the MPEG version from its type:
  if (!readOneIndexRecord(0)) return 0; // unknown; perhaps the indecx file is empty?        

  setMPEGVersionFromRecordType(recordTypeFromBuf());
  return fMPEGVersion;
}
Boolean MPEG2TransportStreamIndexFile
::readIndexRecordValues(unsigned long indexRecordNum,
                        unsigned long& transportPacketNum, u_int8_t& offset,
                        u_int8_t& size, float& pcr, u_int8_t& recordType) {
  if (!readIndexRecord(indexRecordNum)) return False;

  transportPacketNum = tsPacketNumFromBuf();
  offset = offsetFromBuf();
  size = sizeFromBuf();
  pcr = pcrFromBuf();
  recordType = recordTypeFromBuf();
  return True;
}