MP3AudioMatroskaFileServerMediaSubsession
::MP3AudioMatroskaFileServerMediaSubsession(MatroskaFileServerDemux& demux, MatroskaTrack* track,
					    Boolean generateADUs, Interleaving* interleaving)
  : MP3AudioFileServerMediaSubsession(demux.envir(), demux.fileName(), False, generateADUs, interleaving),
    fOurDemux(demux), fTrackNumber(track->trackNumber) {
  fFileDuration = fOurDemux.fileDuration();
}
H264VideoMatroskaFileServerMediaSubsession
::H264VideoMatroskaFileServerMediaSubsession(MatroskaFileServerDemux& demux, unsigned trackNumber)
  : H264VideoFileServerMediaSubsession(demux.envir(), demux.fileName(), False),
    fOurDemux(demux), fTrackNumber(trackNumber),
    fSPSSize(0), fSPS(NULL), fPPSSize(0), fPPS(NULL) {
  // Use our track's 'Codec Private' data: Byte 4 contains the size of NAL unit lengths,
  // and bytes 5 and beyond contain SPS and PPSs:
  MatroskaTrack* track = fOurDemux.lookup(fTrackNumber);
  if (track->codecPrivateSize >= 5) track->subframeSizeSize = (track->codecPrivate[4])&0x3 + 1;

  unsigned numSPSandPPSBytes;
  u_int8_t* SPSandPPSBytes;
  if (track->codecPrivateSize >= 6) {
    numSPSandPPSBytes = track->codecPrivateSize - 5;
    track->codecPrivate[5] &=~ 0xE0; // mask out the top 3 (reserved) bits from the 'numSPSs' byte
    SPSandPPSBytes = &track->codecPrivate[5];
  } else {
    numSPSandPPSBytes = 0;
    SPSandPPSBytes = NULL;
  }

  // Extract, from "SPSandPPSBytes", one SPS NAL unit, and one PPS NAL unit.  (I hope one is all we need of each.)
  do {
    if (numSPSandPPSBytes == 0 || SPSandPPSBytes == NULL) break; // sanity check
    u_int8_t* ptr = SPSandPPSBytes;
    u_int8_t* limit = &SPSandPPSBytes[numSPSandPPSBytes];

    unsigned numSPSs = *ptr++; checkPtr;
    unsigned i;
    for (i = 0; i < numSPSs; ++i) {
      unsigned spsSize = (*ptr++)<<8; checkPtr;
      spsSize |= *ptr++; checkPtr;

      if (spsSize > numBytesRemaining) return;
      if (i == 0) { // save the first one
	fSPSSize = spsSize;
	fSPS = new u_int8_t[spsSize];
	memmove(fSPS, ptr, spsSize);
      }
      ptr += spsSize;
    }

    unsigned numPPSs = *ptr++; checkPtr;
    for (i = 0; i < numPPSs; ++i) {
      unsigned ppsSize = (*ptr++)<<8; checkPtr;
      ppsSize |= *ptr++; checkPtr;

      if (ppsSize > numBytesRemaining) return;
      if (i == 0) { // save the first one
	fPPSSize = ppsSize;
	fPPS = new u_int8_t[ppsSize];
	memmove(fPPS, ptr, ppsSize);
      }
      ptr += ppsSize;
    }
  } while (0);
}
AACAudioMatroskaFileServerMediaSubsession
::AACAudioMatroskaFileServerMediaSubsession(MatroskaFileServerDemux& demux, unsigned trackNumber)
  : FileServerMediaSubsession(demux.envir(), demux.fileName(), False),
    fOurDemux(demux), fTrackNumber(trackNumber) {
  // The Matroska file's 'Codec Private' data is assumed to be the AAC configuration information.
  // Use this to generate a 'config string':
  MatroskaTrack* track = fOurDemux.lookup(fTrackNumber);
  fConfigStr = new char[2*track->codecPrivateSize + 1]; // 2 hex digits per byte, plus the trailing '\0'
  for (unsigned i = 0; i < track->codecPrivateSize; ++i) sprintf(&fConfigStr[2*i], "%02X", track->codecPrivate[i]);
}
T140TextMatroskaFileServerMediaSubsession
::T140TextMatroskaFileServerMediaSubsession(MatroskaFileServerDemux& demux, unsigned trackNumber)
  : FileServerMediaSubsession(demux.envir(), demux.fileName(), False),
    fOurDemux(demux), fTrackNumber(trackNumber) {
}
MatroskaFileServerMediaSubsession
::MatroskaFileServerMediaSubsession(MatroskaFileServerDemux& demux, MatroskaTrack* track)
  : FileServerMediaSubsession(demux.envir(), demux.fileName(), False),
    fOurDemux(demux), fTrack(track), fNumFiltersInFrontOfTrack(0) {
}
VorbisAudioMatroskaFileServerMediaSubsession
::VorbisAudioMatroskaFileServerMediaSubsession(MatroskaFileServerDemux& demux, unsigned trackNumber)
  : FileServerMediaSubsession(demux.envir(), demux.fileName(), False),
    fOurDemux(demux), fTrackNumber(trackNumber),
    fIdentificationHeader(NULL), fIdentificationHeaderSize(0),
    fCommentHeader(NULL), fCommentHeaderSize(0),
    fSetupHeader(NULL), fSetupHeaderSize(0),
    fEstBitrate(96/* kbps, default guess */) {
  MatroskaTrack* track = fOurDemux.lookup(fTrackNumber);

  // The Matroska file's 'Codec Private' data is assumed to be the Vorbis configuration information,
  // containing the "Identification", "Comment", and "Setup" headers.  Extract these headers now:
  do {
    u_int8_t* p = track->codecPrivate;
    unsigned n = track->codecPrivateSize;
    if (n == 0 || p == NULL) break; // we have no 'Codec Private' data

    u_int8_t numHeaders;
    getPrivByte(numHeaders);
    unsigned headerSize[3]; // we don't handle any more than 2+1 headers

    // Extract the sizes of each of these headers:
    unsigned sizesSum = 0;
    Boolean success = True;
    unsigned i;
    for (i = 0; i < numHeaders && i < 3; ++i) {
      unsigned len = 0;
      u_int8_t c;

      do {
	success = False;
	getPrivByte(c);
	success = True;

	len += c;
      } while (c == 255);
      if (!success || len == 0) break;

      headerSize[i] = len;
      sizesSum += len;
    }
    if (!success) break;

    // Compute the implicit size of the final header:
    if (numHeaders < 3) {
      int finalHeaderSize = n - sizesSum;
      if (finalHeaderSize <= 0) break; // error in data; give up

      headerSize[numHeaders] = (unsigned)finalHeaderSize;
      ++numHeaders; // include the final header now
    } else {
      numHeaders = 3; // The maximum number of headers that we handle
    }

    // Then, extract and classify each header:
    for (i = 0; i < numHeaders; ++i) {
      success = False;
      unsigned newHeaderSize = headerSize[i];
      u_int8_t* newHeader = new u_int8_t[newHeaderSize];
      if (newHeader == NULL) break;
      
      u_int8_t* hdr = newHeader;
      while (newHeaderSize-- > 0) {
	success = False;
	getPrivByte(*hdr++);
	success = True;
      }
      if (!success) {
	delete[] newHeader;
	break;
      }

      u_int8_t headerType = newHeader[0];
      if (headerType == 1) {
	delete[] fIdentificationHeader; fIdentificationHeader = newHeader;
	fIdentificationHeaderSize = headerSize[i];

	if (fIdentificationHeaderSize >= 28) {
	  // Get the 'bitrate' values from this header, and use them to set "fEstBitrate":
	  u_int32_t val;
	  u_int8_t* p;

	  p = &fIdentificationHeader[16];
	  val = ((p[3]*256 + p[2])*256 + p[1])*256 + p[0]; // i.e., little-endian
	  int bitrate_maximum = (int)val;
	  if (bitrate_maximum < 0) bitrate_maximum = 0;

	  p = &fIdentificationHeader[20];
	  val = ((p[3]*256 + p[2])*256 + p[1])*256 + p[0]; // i.e., little-endian
	  int bitrate_nominal = (int)val;
	  if (bitrate_nominal < 0) bitrate_nominal = 0;

	  p = &fIdentificationHeader[24];
	  val = ((p[3]*256 + p[2])*256 + p[1])*256 + p[0]; // i.e., little-endian
	  int bitrate_minimum = (int)val;
	  if (bitrate_minimum < 0) bitrate_minimum = 0;

	  int bitrate
	    = bitrate_nominal>0 ? bitrate_nominal : bitrate_maximum>0 ? bitrate_maximum : bitrate_minimum>0 ? bitrate_minimum : 0;
	  if (bitrate > 0) fEstBitrate = ((unsigned)bitrate)/1000;
	}
      } else if (headerType == 3) {
	delete[] fCommentHeader; fCommentHeader = newHeader;
	fCommentHeaderSize = headerSize[i];
      } else if (headerType == 5) {
	delete[] fSetupHeader; fSetupHeader = newHeader;
	fSetupHeaderSize = headerSize[i];
      } else {
	delete[] newHeader; // because it was a header type that we don't understand
      }
    }
    if (!success) break;
  } while (0);
}