void MPEG2TransportFileServerMediaSubsession
::startStream(unsigned clientSessionId, void *streamToken, TaskFunc *rtcpRRHandler,
              void *rtcpRRHandlerClientData, unsigned short &rtpSeqNum,
              unsigned &rtpTimestamp,
              ServerRequestAlternativeByteHandler *serverRequestAlternativeByteHandler,
              void *serverRequestAlternativeByteHandlerClientData)
{
    if (fIndexFile != NULL)   // we support 'trick play'
    {
        ClientTrickPlayState *client = lookupClient(clientSessionId);
        if (client != NULL && client->areChangingScale())
        {
            // First, handle this like a "PAUSE", except that we back up to the previous VSH
            client->updateStateOnPlayChange(True);
            OnDemandServerMediaSubsession::pauseStream(clientSessionId, streamToken);

            // Then, adjust for the change of scale:
            client->updateStateOnScaleChange();
        }
    }

    // Call the original, default version of this routine:
    OnDemandServerMediaSubsession::startStream(clientSessionId, streamToken,
            rtcpRRHandler, rtcpRRHandlerClientData,
            rtpSeqNum, rtpTimestamp,
            serverRequestAlternativeByteHandler, serverRequestAlternativeByteHandlerClientData);
}
FramedSource* MPEG2TransportFileServerMediaSubsession
::createNewStreamSource(unsigned clientSessionId, unsigned& estBitrate) {
  // Create the video source:
  unsigned const inputDataChunkSize
    = TRANSPORT_PACKETS_PER_NETWORK_PACKET*TRANSPORT_PACKET_SIZE;
  ByteStreamFileSource* fileSource
    = ByteStreamFileSource::createNew(envir(), fFileName, inputDataChunkSize);
  if (fileSource == NULL) return NULL;
  fFileSize = fileSource->fileSize();

  // Use the file size and the duration to estimate the stream's bitrate:
  if (fFileSize > 0 && fDuration > 0.0) {
    estBitrate = (unsigned)((int64_t)fFileSize/(125*fDuration) + 0.5); // kbps, rounded
  } else {
    estBitrate = 5000; // kbps, estimate
  }


  // Create a framer for the Transport Stream:
  MPEG2TransportStreamFramer* framer
    = MPEG2TransportStreamFramer::createNew(envir(), fileSource);

  if (fIndexFile != NULL) { // we support 'trick play'
    // Keep state for this client (if we don't already have it):
    ClientTrickPlayState* client = lookupClient(clientSessionId);
    if (client == NULL) {
      client = newClientTrickPlayState();
      fClientSessionHashTable->Add((char const*)clientSessionId, client);
    }
    client->setSource(framer);
  }

  return framer;
}
void MPEG2TransportFileServerMediaSubsession
::pauseStream(unsigned clientSessionId, void* streamToken) {
  if (fIndexFile != NULL) { // we support 'trick play'
    ClientTrickPlayState* client = lookupClient(clientSessionId);
    if (client != NULL) {
      client->updateStateOnPlayChange(False);
    }
  }

  // Call the original, default version of this routine:
  OnDemandServerMediaSubsession::pauseStream(clientSessionId, streamToken);
}
void MPEG2TransportFileServerMediaSubsession
::setStreamScale(unsigned clientSessionId, void* streamToken, float scale) {
  if (fIndexFile != NULL) { // we support 'trick play'
    ClientTrickPlayState* client = lookupClient(clientSessionId);
    if (client != NULL) {
      client->setNextScale(scale); // scale won't take effect until the next "PLAY"
    }
  }

  // Call the original, default version of this routine:
  OnDemandServerMediaSubsession::setStreamScale(clientSessionId, streamToken, scale);
}
void MPEG2TransportFileServerMediaSubsession
::seekStream(unsigned clientSessionId, void* streamToken, double seekNPT) {
  if (fIndexFile != NULL) { // we support 'trick play'
    ClientTrickPlayState* client = lookupClient(clientSessionId);
    if (client != NULL) {
      client->updateStateFromNPT(seekNPT);
    }
  }

  // Call the original, default version of this routine:
  OnDemandServerMediaSubsession::seekStream(clientSessionId, streamToken, seekNPT);
}
void MPEG2TransportFileServerMediaSubsession
::seekStream(unsigned clientSessionId, void* streamToken, double& seekNPT, double streamDuration, u_int64_t& numBytes) {
  // Begin by calling the original, default version of this routine:
  OnDemandServerMediaSubsession::seekStream(clientSessionId, streamToken, seekNPT, streamDuration, numBytes);

  // Then, special handling specific to indexed Transport Stream files:
  if (fIndexFile != NULL) { // we support 'trick play'
    ClientTrickPlayState* client = lookupClient(clientSessionId);
    if (client != NULL) {
      unsigned long numTSPacketsToStream = client->updateStateFromNPT(seekNPT, streamDuration);
      numBytes = numTSPacketsToStream*TRANSPORT_PACKET_SIZE;
    }
  }
}