unsigned H264or5VideoStreamParser::parse() {
    static int aaaa = 0  ;
    aaaa++;
    qDebug()<<"H264or5VideoStreamParser::parse() {  868   aaaa" <<aaaa;
  try {
    // The stream must start with a 0x00000001:
    if (!fHaveSeenFirstStartCode) {
      // Skip over any input bytes that precede the first 0x00000001:
      u_int32_t first4Bytes;
      while ((first4Bytes = test4Bytes()) != 0x00000001) {
	get1Byte(); setParseState(); // ensures that we progress over bad data
      }
      skipBytes(4); // skip this initial code
      
      setParseState();
      fHaveSeenFirstStartCode = True; // from now on
    }
    
    if (fOutputStartCodeSize > 0 && curFrameSize() == 0 && !haveSeenEOF()) {
      // Include a start code in the output:
      save4Bytes(0x00000001);
    }

    // Then save everything up until the next 0x00000001 (4 bytes) or 0x000001 (3 bytes), or we hit EOF.
    // Also make note of the first byte, because it contains the "nal_unit_type": 
    if (haveSeenEOF()) {
      // We hit EOF the last time that we tried to parse this data, so we know that any remaining unparsed data
      // forms a complete NAL unit, and that there's no 'start code' at the end:
      unsigned remainingDataSize = totNumValidBytes() - curOffset();
#ifdef DEBUG
      unsigned const trailingNALUnitSize = remainingDataSize;
#endif
      while (remainingDataSize > 0) {
	u_int8_t nextByte = get1Byte();
	if (!fHaveSeenFirstByteOfNALUnit) {
	  fFirstByteOfNALUnit = nextByte;
	  fHaveSeenFirstByteOfNALUnit = True;
	}
	saveByte(nextByte);
	--remainingDataSize;
      }

#ifdef DEBUG
      if (fHNumber == 264) {
	u_int8_t nal_ref_idc = (fFirstByteOfNALUnit&0x60)>>5;
	u_int8_t nal_unit_type = fFirstByteOfNALUnit&0x1F;
	fprintf(stderr, "Parsed trailing %d-byte NAL-unit (nal_ref_idc: %d, nal_unit_type: %d (\"%s\"))\n",
		trailingNALUnitSize, nal_ref_idc, nal_unit_type, nal_unit_type_description_h264[nal_unit_type]);
      } else { // 265
	u_int8_t nal_unit_type = (fFirstByteOfNALUnit&0x7E)>>1;
	fprintf(stderr, "Parsed trailing %d-byte NAL-unit (nal_unit_type: %d (\"%s\"))\n",
		trailingNALUnitSize, nal_unit_type, nal_unit_type_description_h265[nal_unit_type]);
      }
#endif

      (void)get1Byte(); // forces another read, which will cause EOF to get handled for real this time
      return 0;
    } else {
unsigned MPEG1or2VideoStreamParser
::parseVideoSequenceHeader(Boolean haveSeenStartCode) {
#ifdef DEBUG
  fprintf(stderr, "parsing video sequence header\n");
#endif
  unsigned first4Bytes;
  if (!haveSeenStartCode) {
    while ((first4Bytes = test4Bytes()) != VIDEO_SEQUENCE_HEADER_START_CODE) {
#ifdef DEBUG
      fprintf(stderr, "ignoring non video sequence header: 0x%08x\n", first4Bytes);
#endif
      get1Byte(); setParseState(PARSING_VIDEO_SEQUENCE_HEADER);
          // ensures we progress over bad data
    }
    first4Bytes = get4Bytes();
  } else {
    // We've already seen the start code
    first4Bytes = VIDEO_SEQUENCE_HEADER_START_CODE;
  }
  save4Bytes(first4Bytes);

  // Next, extract the size and rate parameters from the next 8 bytes
  unsigned paramWord1 = get4Bytes();
  save4Bytes(paramWord1);
  unsigned next4Bytes = get4Bytes();
#ifdef DEBUG
  unsigned short horizontal_size_value   = (paramWord1&0xFFF00000)>>(32-12);
  unsigned short vertical_size_value     = (paramWord1&0x000FFF00)>>8;
  unsigned char aspect_ratio_information = (paramWord1&0x000000F0)>>4;
#endif
  unsigned char frame_rate_code          = (paramWord1&0x0000000F);
  usingSource()->fFrameRate = frameRateFromCode[frame_rate_code];
#ifdef DEBUG
  unsigned bit_rate_value                = (next4Bytes&0xFFFFC000)>>(32-18);
  unsigned vbv_buffer_size_value         = (next4Bytes&0x00001FF8)>>3;
  fprintf(stderr, "horizontal_size_value: %d, vertical_size_value: %d, aspect_ratio_information: %d, frame_rate_code: %d (=>%f fps), bit_rate_value: %d (=>%d bps), vbv_buffer_size_value: %d\n", horizontal_size_value, vertical_size_value, aspect_ratio_information, frame_rate_code, usingSource()->fFrameRate, bit_rate_value, bit_rate_value*400, vbv_buffer_size_value);
#endif

  // Now, copy all bytes that we see, up until we reach a GROUP_START_CODE
  // or a PICTURE_START_CODE:
  do {
    saveToNextCode(next4Bytes);
  } while (next4Bytes != GROUP_START_CODE && next4Bytes != PICTURE_START_CODE);

  setParseState((next4Bytes == GROUP_START_CODE)
		? PARSING_GOP_HEADER_SEEN_CODE : PARSING_PICTURE_HEADER);

  // Compute this frame's timestamp by noting how many pictures we've seen
  // since the last GOP header:
  usingSource()->computePresentationTime(fPicturesSinceLastGOP);

  // Save this video_sequence_header, in case we need to insert a copy
  // into the stream later:
  saveCurrentVSH();

  return curFrameSize();
}
void MatroskaFileParser::deliverFrameBytes() {
  do {
    MatroskaTrack* track = fOurFile.lookup(fBlockTrackNumber);
    if (track == NULL) break; // shouldn't happen

    MatroskaDemuxedTrack* demuxedTrack = fOurDemux->lookupDemuxedTrack(fBlockTrackNumber);
    if (demuxedTrack == NULL) break; // shouldn't happen

    unsigned const BANK_SIZE = bankSize();
    while (fCurFrameNumBytesToGet > 0) {
      // Hack: We can get no more than BANK_SIZE bytes at a time:
      unsigned numBytesToGet = fCurFrameNumBytesToGet > BANK_SIZE ? BANK_SIZE : fCurFrameNumBytesToGet;
      getBytes(fCurFrameTo, numBytesToGet);
      fCurFrameTo += numBytesToGet;
      fCurFrameNumBytesToGet -= numBytesToGet;
      fCurOffsetWithinFrame += numBytesToGet;
      setParseState();
    }
    while (fCurFrameNumBytesToSkip > 0) {
      // Hack: We can skip no more than BANK_SIZE bytes at a time:
      unsigned numBytesToSkip = fCurFrameNumBytesToSkip > BANK_SIZE ? BANK_SIZE : fCurFrameNumBytesToSkip;
      skipBytes(numBytesToSkip);
      fCurFrameNumBytesToSkip -= numBytesToSkip;
      fCurOffsetWithinFrame += numBytesToSkip;
      setParseState();
    }
#ifdef DEBUG
    fprintf(stderr, "\tdelivered frame #%d: %d bytes", fNextFrameNumberToDeliver, demuxedTrack->frameSize());
    if (track->haveSubframes()) fprintf(stderr, "[offset %d]", fCurOffsetWithinFrame - track->subframeSizeSize - demuxedTrack->frameSize() - demuxedTrack->numTruncatedBytes());
    if (demuxedTrack->numTruncatedBytes() > 0) fprintf(stderr, " (%d bytes truncated)", demuxedTrack->numTruncatedBytes());
    fprintf(stderr, " @%u.%06u (%.06f from start); duration %u us\n", demuxedTrack->presentationTime().tv_sec, demuxedTrack->presentationTime().tv_usec, demuxedTrack->presentationTime().tv_sec+demuxedTrack->presentationTime().tv_usec/1000000.0-fPresentationTimeOffset, demuxedTrack->durationInMicroseconds());
#endif

    if (!track->haveSubframes()
	|| fCurOffsetWithinFrame + track->subframeSizeSize >= fFrameSizesWithinBlock[fNextFrameNumberToDeliver]) {
      // Either we don't have subframes, or there's no more room for another subframe => We're completely done with this frame now:
      ++fNextFrameNumberToDeliver;
      fCurOffsetWithinFrame = 0;
    }
    if (fNextFrameNumberToDeliver == fNumFramesInBlock) {
      // We've delivered all of the frames from this block.  Look for another block next:
      fCurrentParseState = LOOKING_FOR_BLOCK;
    } else {
      fCurrentParseState = DELIVERING_FRAME_WITHIN_BLOCK;
    }

    setParseState();
    FramedSource::afterGetting(demuxedTrack); // completes delivery
    return;
  } while (0);

  // An error occurred.  Try to recover:
#ifdef DEBUG
  fprintf(stderr, "deliverFrameBytes(): Error parsing data; trying to recover...\n");
#endif
  fCurrentParseState = LOOKING_FOR_BLOCK;
}
Beispiel #4
0
void MPEGProgramStreamParser::parsePackHeader() {
#ifdef DEBUG
  fprintf(stderr, "parsing pack header\n"); fflush(stderr);
#endif
  unsigned first4Bytes;
  while (1) {
    first4Bytes = test4Bytes();

    // We're supposed to have a pack header here, but check also for
    // a system header or a PES packet, just in case:
    if (first4Bytes == PACK_START_CODE) {
      skipBytes(4);
      break;
    } else if (first4Bytes == SYSTEM_HEADER_START_CODE) {
#ifdef DEBUG
      fprintf(stderr, "found system header instead of pack header\n");
#endif
      setParseState(PARSING_SYSTEM_HEADER);
      return;
    } else if (isPacketStartCode(first4Bytes)) {
#ifdef DEBUG
      fprintf(stderr, "found packet start code 0x%02x instead of pack header\n", first4Bytes);
#endif
      setParseState(PARSING_PES_PACKET);
      return;
    }

    setParseState(PARSING_PACK_HEADER); // ensures we progress over bad data
    if ((first4Bytes&0xFF) > 1) { // a system code definitely doesn't start here
      skipBytes(4);
    } else {
      skipBytes(1);
    }
  }

  // The size of the pack header differs depending on whether it's
  // MPEG-1 or MPEG-2.  The next byte tells us this:
  unsigned char nextByte = get1Byte();
  MPEG1or2Demux::SCR& scr = fUsingSource->fLastSeenSCR; // alias
  if ((nextByte&0xF0) == 0x20) { // MPEG-1
    fUsingSource->fMPEGversion = 1;
    scr.highBit =  (nextByte&0x08)>>3;
    scr.remainingBits = (nextByte&0x06)<<29;
    unsigned next4Bytes = get4Bytes();
    scr.remainingBits |= (next4Bytes&0xFFFE0000)>>2;
    scr.remainingBits |= (next4Bytes&0x0000FFFE)>>1;
    scr.extension = 0;
    scr.isValid = True;
    skipBits(24);

#if defined(DEBUG_TIMESTAMPS) || defined(DEBUG_SCR_TIMESTAMPS)
    fprintf(stderr, "pack hdr system_clock_reference_base: 0x%x",
	    scr.highBit);
    fprintf(stderr, "%08x\n", scr.remainingBits);
#endif
  } else if ((nextByte&0xC0) == 0x40) { // MPEG-2
void MPEG1or2VideoStreamParser::flushInput() {
  reset();
  StreamParser::flushInput();
  if (fCurrentParseState != PARSING_VIDEO_SEQUENCE_HEADER) {
    setParseState(PARSING_GOP_HEADER); // start from the next GOP
  }
}
Boolean MatroskaFileParser::parseEBMLNumber(EBMLNumber& num) {
  unsigned i;
  u_int8_t bitmask = 0x80;
  for (i = 0; i < EBML_NUMBER_MAX_LEN; ++i) {
    while (1) {
      if (fLimitOffsetInFile > 0 && fCurOffsetInFile > fLimitOffsetInFile) return False; // We've hit our pre-set limit
      num.data[i] = get1Byte();
      ++fCurOffsetInFile;

      // If we're looking for an id, skip any leading bytes that don't contain a '1' in the first 4 bits:
      if (i == 0/*we're a leading byte*/ && !num.stripLeading1/*we're looking for an id*/ && (num.data[i]&0xF0) == 0) {
	setParseState(); // ensures that we make forward progress if the parsing gets interrupted
	continue;
      }
      break;
    }
    if ((num.data[0]&bitmask) != 0) {
      // num[i] is the last byte of the id
      if (num.stripLeading1) num.data[0] &=~ bitmask;
      break;
    }
    bitmask >>= 1;
  }
  if (i == EBML_NUMBER_MAX_LEN) return False;

  num.len = i+1;
  return True;
}
unsigned MPEG4VideoStreamParser
::parseVisualObjectSequence(Boolean haveSeenStartCode) {
#ifdef DEBUG
  fprintf(stderr, "parsing VisualObjectSequence\n");
#endif
  usingSource()->startNewConfig();
  u_int32_t first4Bytes;
  if (!haveSeenStartCode) {
    while ((first4Bytes = test4Bytes()) != VISUAL_OBJECT_SEQUENCE_START_CODE) {
#ifdef DEBUG
      fprintf(stderr, "ignoring non VS header: 0x%08x\n", first4Bytes);
#endif
      get1Byte(); setParseState(PARSING_VISUAL_OBJECT_SEQUENCE);
          // ensures we progress over bad data
    }
    first4Bytes = get4Bytes();
  } else {
    // We've already seen the start code
    first4Bytes = VISUAL_OBJECT_SEQUENCE_START_CODE;
  }
  save4Bytes(first4Bytes);

  // The next byte is the "profile_and_level_indication":
  u_int8_t pali = get1Byte();
#ifdef DEBUG
  fprintf(stderr, "profile_and_level_indication: %02x\n", pali);
#endif
  saveByte(pali);
  usingSource()->fProfileAndLevelIndication = pali;

  // Now, copy all bytes that we see, up until we reach
  // a VISUAL_OBJECT_START_CODE:
  u_int32_t next4Bytes = get4Bytes();
  while (next4Bytes != VISUAL_OBJECT_START_CODE) {
    saveToNextCode(next4Bytes);
  }

  setParseState(PARSING_VISUAL_OBJECT);

  // Compute this frame's presentation time:
  usingSource()->computePresentationTime(fTotalTicksSinceLastTimeCode);

  // This header forms part of the 'configuration' information:
  usingSource()->appendToNewConfig(fStartOfFrame, curFrameSize());

  return curFrameSize();
}
void MatroskaFileParser::lookForNextBlock() {
#ifdef DEBUG
  fprintf(stderr, "looking for Block\n");
#endif
  // Read and skip over each Matroska header, until we get to a 'Cluster':
  EBMLId id;
  EBMLDataSize size;
  while (fCurrentParseState == LOOKING_FOR_BLOCK) {
    while (!parseEBMLIdAndSize(id, size)) {}
#ifdef DEBUG
    fprintf(stderr, "MatroskaFileParser::lookForNextBlock(): Parsed id 0x%s (%s), size: %lld\n", id.hexString(), id.stringName(), size.val());
#endif
    switch (id.val()) {
      case MATROSKA_ID_SEGMENT: { // 'Segment' header: enter this
	break;
      }
      case MATROSKA_ID_CLUSTER: { // 'Cluster' header: enter this
	break;
      }
      case MATROSKA_ID_TIMECODE: { // 'Timecode' header: get this value
	unsigned timecode;
	if (parseEBMLVal_unsigned(size, timecode)) {
	  fClusterTimecode = timecode;
#ifdef DEBUG
	  fprintf(stderr, "\tCluster timecode: %d (== %f seconds)\n", fClusterTimecode, fClusterTimecode*(fOurFile.fTimecodeScale/1000000000.0));
#endif
	}
	break;
      }
      case MATROSKA_ID_BLOCK_GROUP: { // 'Block Group' header: enter this
	break;
      }
      case MATROSKA_ID_SIMPLEBLOCK:
      case MATROSKA_ID_BLOCK: { // 'SimpleBlock' or 'Block' header: enter this (and we're done)
	fBlockSize = (unsigned)size.val();
	fCurrentParseState = PARSING_BLOCK;
	break;
      }
      case MATROSKA_ID_BLOCK_DURATION: { // 'Block Duration' header: get this value (but we currently don't do anything with it)
	unsigned blockDuration;
	if (parseEBMLVal_unsigned(size, blockDuration)) {
#ifdef DEBUG
	  fprintf(stderr, "\tblock duration: %d (== %f ms)\n", blockDuration, (float)(blockDuration*fOurFile.fTimecodeScale/1000000.0));
#endif
	}
	break;
      }
      default: { // skip over this header
	skipHeader(size);
#ifdef DEBUG
	fprintf(stderr, "\tskipped %lld bytes\n", size.val());
#endif
	break;
      }
    }
    setParseState();
  }
}
unsigned MPEG1or2VideoStreamParser::parsePictureHeader()
{
#ifdef DEBUG
    fprintf(stderr, "parsing picture header\n");
#endif
    // Note that we've already read the PICTURE_START_CODE
    // Next, extract the temporal reference from the next 4 bytes:
    unsigned next4Bytes = get4Bytes();
    unsigned short temporal_reference = (next4Bytes & 0xFFC00000) >> (32 - 10);
    unsigned char picture_coding_type = (next4Bytes & 0x00380000) >> 19;
#ifdef DEBUG
    unsigned short vbv_delay          = (next4Bytes & 0x0007FFF8) >> 3;
    fprintf(stderr, "temporal_reference: %d, picture_coding_type: %d, vbv_delay: %d\n", temporal_reference, picture_coding_type, vbv_delay);
#endif

    fSkippingCurrentPicture = fIFramesOnly && picture_coding_type != 1;
    if (fSkippingCurrentPicture)
    {
        // Skip all bytes that we see, up until we reach a slice_start_code:
        do
        {
            skipToNextCode(next4Bytes);
        }
        while (!isSliceStartCode(next4Bytes));
    }
    else
    {
        // Save the PICTURE_START_CODE that we've already read:
        save4Bytes(PICTURE_START_CODE);

        // Copy all bytes that we see, up until we reach a slice_start_code:
        do
        {
            saveToNextCode(next4Bytes);
        }
        while (!isSliceStartCode(next4Bytes));
    }

    setParseState(PARSING_SLICE);

    fCurrentSliceNumber = next4Bytes & 0xFF;

    // Record the temporal reference:
    fCurPicTemporalReference = temporal_reference;

    // Compute this frame's timestamp:
    usingSource()->computePresentationTime(fCurPicTemporalReference);

    if (fSkippingCurrentPicture)
    {
        return parse(); // try again, until we get a non-skipped frame
    }
    else
    {
        return curFrameSize();
    }
}
void MPEG4VideoStreamParser::flushInput() {
  fSecondsSinceLastTimeCode = 0;
  fTotalTicksSinceLastTimeCode = 0;
  fPrevNewTotalTicks = 0;
  fPrevPictureCountDelta = 1;

  StreamParser::flushInput();
  if (fCurrentParseState != PARSING_VISUAL_OBJECT_SEQUENCE) {
    setParseState(PARSING_VISUAL_OBJECT_SEQUENCE); // later, change to GOV or VOP? #####
  }
}
unsigned H264VideoStreamParser::parseStartSequence()
{

    u_int32_t test = test4Bytes();

    while (test != 0x00000001)
    {
        skipBytes(1);
        test = test4Bytes();
    }
    setParseState(PARSING_START_SEQUENCE);
    skipBytes(4);
    return parseNALUnit();


}
unsigned H264VideoStreamParser::parse() {
  try {
    // The stream must start with a 0x00000001:
    if (!fHaveSeenFirstStartCode) {
      // Skip over any input bytes that precede the first 0x00000001:
      u_int32_t first4Bytes;
      while ((first4Bytes = test4Bytes()) != 0x00000001) {
	get1Byte(); setParseState(); // ensures that we progress over bad data
      }
      skipBytes(4); // skip this initial code
      
      setParseState();
      fHaveSeenFirstStartCode = True; // from now on
    }
    
    if (fOutputStartCodeSize > 0 && curFrameSize() == 0 && !haveSeenEOF()) {
      // Include a start code in the output:
      save4Bytes(0x00000001);
    }

    // Then save everything up until the next 0x00000001 (4 bytes) or 0x000001 (3 bytes), or we hit EOF.
    // Also make note of the first byte, because it contains the "nal_unit_type": 
    if (haveSeenEOF()) {
      // We hit EOF the last time that we tried to parse this data, so we know that any remaining unparsed data
      // forms a complete NAL unit, and that there's no 'start code' at the end:
      unsigned remainingDataSize = totNumValidBytes() - curOffset();
#ifdef DEBUG
      unsigned const trailingNALUnitSize = remainingDataSize;
#endif
      while (remainingDataSize > 0) {
	u_int8_t nextByte = get1Byte();
	if (!fHaveSeenFirstByteOfNALUnit) {
	  fFirstByteOfNALUnit = nextByte;
	  fHaveSeenFirstByteOfNALUnit = True;
	}
	saveByte(nextByte);
	--remainingDataSize;
      }

#ifdef DEBUG
      u_int8_t nal_ref_idc = (fFirstByteOfNALUnit&0x60)>>5;
      u_int8_t nal_unit_type = fFirstByteOfNALUnit&0x1F;
      fprintf(stderr, "Parsed trailing %d-byte NAL-unit (nal_ref_idc: %d, nal_unit_type: %d (\"%s\"))\n",
	      trailingNALUnitSize, nal_ref_idc, nal_unit_type, nal_unit_type_description[nal_unit_type]);
#endif

      (void)get1Byte(); // forces another read, which will cause EOF to get handled for real this time
      return 0;
    } else {
      u_int32_t next4Bytes = test4Bytes();
      if (!fHaveSeenFirstByteOfNALUnit) {
	fFirstByteOfNALUnit = next4Bytes>>24;
	fHaveSeenFirstByteOfNALUnit = True;
      }
      while (next4Bytes != 0x00000001 && (next4Bytes&0xFFFFFF00) != 0x00000100) {
	// We save at least some of "next4Bytes".
	if ((unsigned)(next4Bytes&0xFF) > 1) {
	  // Common case: 0x00000001 or 0x000001 definitely doesn't begin anywhere in "next4Bytes", so we save all of it:
	  save4Bytes(next4Bytes);
	  skipBytes(4);
	} else {
	  // Save the first byte, and continue testing the rest:
	  saveByte(next4Bytes>>24);
	  skipBytes(1);
	}
	setParseState(); // ensures forward progress
	next4Bytes = test4Bytes();
      }
      // Assert: next4Bytes starts with 0x00000001 or 0x000001, and we've saved all previous bytes (forming a complete NAL unit).
      // Skip over these remaining bytes, up until the start of the next NAL unit:
      if (next4Bytes == 0x00000001) {
	skipBytes(4);
      } else {
	skipBytes(3);
      }
    }
Boolean MatroskaFileParser::deliverFrameWithinBlock() {
#ifdef DEBUG
  fprintf(stderr, "delivering frame within SimpleBlock or Block\n");
#endif
  do {
    MatroskaTrack* track = fOurFile.lookup(fBlockTrackNumber);
    if (track == NULL) break; // shouldn't happen

    MatroskaDemuxedTrack* demuxedTrack = fOurDemux->lookupDemuxedTrack(fBlockTrackNumber);
    if (demuxedTrack == NULL) break; // shouldn't happen
    if (!demuxedTrack->isCurrentlyAwaitingData()) {
      // Someone has been reading this stream, but isn't right now.
      // We can't deliver this frame until he asks for it, so punt for now.
      // The next time he asks for a frame, he'll get it.
#ifdef DEBUG
      fprintf(stderr, "\tdeferring delivery of frame #%d (%d bytes)", fNextFrameNumberToDeliver, fFrameSizesWithinBlock[fNextFrameNumberToDeliver]);
      if (track->haveSubframes()) fprintf(stderr, "[offset %d]", fCurOffsetWithinFrame);
      fprintf(stderr, "\n");
#endif
      restoreSavedParserState(); // so we read from the beginning next time
      return False;
    }

    unsigned frameSize = fFrameSizesWithinBlock[fNextFrameNumberToDeliver];
    if (track->haveSubframes()) {
      // The next "track->subframeSizeSize" bytes contain the length of a 'subframe':
      if (fCurOffsetWithinFrame + track->subframeSizeSize > frameSize) break; // sanity check
      unsigned subframeSize = 0;
      for (unsigned i = 0; i < track->subframeSizeSize; ++i) {
	u_int8_t c;
	getCommonFrameBytes(track, &c, 1, 0);
	if (fCurFrameNumBytesToGet > 0) { // it'll be 1
	  c = get1Byte();
	  ++fCurOffsetWithinFrame;
	}
	subframeSize = subframeSize*256 + c;
      }
      if (subframeSize == 0 || fCurOffsetWithinFrame + subframeSize > frameSize) break; // sanity check
      frameSize = subframeSize;
    }

    // Compute the presentation time of this frame (from the cluster timecode, the block timecode, and the default duration):
    double pt = (fClusterTimecode+fBlockTimecode)*(fOurFile.fTimecodeScale/1000000000.0)
      + fNextFrameNumberToDeliver*(track->defaultDuration/1000000000.0);
    if (fPresentationTimeOffset == 0.0) {
      // This is the first time we've computed a presentation time.  Compute an offset to make the presentation times aligned
      // with 'wall clock' time:
      struct timeval timeNow;
      gettimeofday(&timeNow, NULL);
      double ptNow = timeNow.tv_sec + timeNow.tv_usec/1000000.0;
      fPresentationTimeOffset = ptNow - pt;
    }
    pt += fPresentationTimeOffset;
    struct timeval presentationTime;
    presentationTime.tv_sec = (unsigned)pt;
    presentationTime.tv_usec = (unsigned)((pt - presentationTime.tv_sec)*1000000);
    unsigned durationInMicroseconds = track->defaultDuration/1000;
    if (track->haveSubframes()) {
      // If this is a 'subframe', use a duration of 0 instead (unless it's the last 'subframe'):
      if (fCurOffsetWithinFrame + frameSize + track->subframeSizeSize < fFrameSizesWithinBlock[fNextFrameNumberToDeliver]) {
	// There's room for at least one more subframe after this, so give this subframe a duration of 0
	durationInMicroseconds = 0;
      }
    }

    if (track->defaultDuration == 0) {
      // Adjust the frame duration to keep the sum of frame durations aligned with presentation times.
      if (track->prevPresentationTime.tv_sec != 0) { // not the first time for this track
	track->durationImbalance
	  += (presentationTime.tv_sec - track->prevPresentationTime.tv_sec)*1000000
	  + (presentationTime.tv_usec - track->prevPresentationTime.tv_usec);
      }
      int adjustment = 0;
      if (track->durationImbalance > 0) {
	// The duration needs to be increased.
	int const adjustmentThreshold = 100000; // don't increase the duration by more than this amount (in case there's a mistake)
	adjustment = track->durationImbalance > adjustmentThreshold ? adjustmentThreshold : track->durationImbalance;
      } else if (track->durationImbalance < 0) {
	// The duration needs to be decreased.
	adjustment
	  = (unsigned)(-track->durationImbalance) < durationInMicroseconds ? track->durationImbalance : -(int)durationInMicroseconds;
      }
      durationInMicroseconds += adjustment;
      track->durationImbalance -= durationInMicroseconds; // for next time
      track->prevPresentationTime = presentationTime; // for next time
    }

    demuxedTrack->presentationTime() = presentationTime;
    demuxedTrack->durationInMicroseconds() = durationInMicroseconds;

    // Deliver the next block now:
    if (frameSize > demuxedTrack->maxSize()) {
      demuxedTrack->numTruncatedBytes() = frameSize - demuxedTrack->maxSize();
      demuxedTrack->frameSize() = demuxedTrack->maxSize();
    } else { // normal case
      demuxedTrack->numTruncatedBytes() = 0;
      demuxedTrack->frameSize() = frameSize;
    }
    getCommonFrameBytes(track, demuxedTrack->to(), demuxedTrack->frameSize(), demuxedTrack->numTruncatedBytes());

    // Next, deliver (and/or skip) bytes from the input file:
    fCurrentParseState = DELIVERING_FRAME_BYTES;
    setParseState();
    return True;
  } while (0);

  // An error occurred.  Try to recover:
#ifdef DEBUG
  fprintf(stderr, "deliverFrameWithinBlock(): Error parsing data; trying to recover...\n");
#endif
  fCurrentParseState = LOOKING_FOR_BLOCK;
  return True;
}
void MatroskaFileParser::parseBlock() {
#ifdef DEBUG
  fprintf(stderr, "parsing SimpleBlock or Block\n");
#endif
  do {
    unsigned blockStartPos = curOffset();

    // The block begins with the track number:
    EBMLNumber trackNumber;
    if (!parseEBMLNumber(trackNumber)) break;
    fBlockTrackNumber = (unsigned)trackNumber.val();

    // If this track is not being read, then skip the rest of this block, and look for another one:
    if (fOurDemux->lookupDemuxedTrack(fBlockTrackNumber) == NULL) {
      unsigned headerBytesSeen = curOffset() - blockStartPos;
      if (headerBytesSeen < fBlockSize) {
	skipBytes(fBlockSize - headerBytesSeen);
      }
#ifdef DEBUG
      fprintf(stderr, "\tSkipped block for unused track number %d\n", fBlockTrackNumber);
#endif
      fCurrentParseState = LOOKING_FOR_BLOCK;
      setParseState();
      return;
    }

    MatroskaTrack* track = fOurFile.lookup(fBlockTrackNumber);
    if (track == NULL) break; // shouldn't happen

    // The next two bytes are the block's timecode (relative to the cluster timecode)
    fBlockTimecode = (get1Byte()<<8)|get1Byte();

    // The next byte indicates the type of 'lacing' used:
    u_int8_t c = get1Byte();
    c &= 0x6; // we're interested in bits 5-6 only
    MatroskaLacingType lacingType = (c==0x0)?NoLacing : (c==0x02)?XiphLacing : (c==0x04)?FixedSizeLacing : EBMLLacing;
#ifdef DEBUG
    fprintf(stderr, "\ttrack number %d, timecode %d (=> %f seconds), %s lacing\n", fBlockTrackNumber, fBlockTimecode, (fClusterTimecode+fBlockTimecode)*(fOurFile.fTimecodeScale/1000000000.0), (lacingType==NoLacing)?"no" : (lacingType==XiphLacing)?"Xiph" : (lacingType==FixedSizeLacing)?"fixed-size" : "EBML");
#endif

    if (lacingType == NoLacing) {
      fNumFramesInBlock = 1;
    } else {
      // The next byte tells us how many frames are present in this block
      fNumFramesInBlock = get1Byte() + 1;
    }
    delete[] fFrameSizesWithinBlock; fFrameSizesWithinBlock = new unsigned[fNumFramesInBlock];
    if (fFrameSizesWithinBlock == NULL) break;
  
    if (lacingType == NoLacing) {
      unsigned headerBytesSeen = curOffset() - blockStartPos;
      if (headerBytesSeen > fBlockSize) break;

      fFrameSizesWithinBlock[0] = fBlockSize - headerBytesSeen;
    } else if (lacingType == FixedSizeLacing) {
      unsigned headerBytesSeen = curOffset() - blockStartPos;
      if (headerBytesSeen > fBlockSize) break;

      unsigned frameBytesAvailable = fBlockSize - headerBytesSeen;
      unsigned constantFrameSize = frameBytesAvailable/fNumFramesInBlock;

      for (unsigned i = 0; i < fNumFramesInBlock; ++i) {
	fFrameSizesWithinBlock[i] = constantFrameSize;
      }
      // If there are any bytes left over, assign them to the last frame:
      fFrameSizesWithinBlock[fNumFramesInBlock-1] += frameBytesAvailable%fNumFramesInBlock;
    } else { // EBML or Xiph lacing
      unsigned curFrameSize = 0;
      unsigned frameSizesTotal = 0;
      unsigned i;

      for (i = 0; i < fNumFramesInBlock-1; ++i) {
	if (lacingType == EBMLLacing) {
	  EBMLNumber frameSize;
	  if (!parseEBMLNumber(frameSize)) break;
	  unsigned fsv = (unsigned)frameSize.val();

	  if (i == 0) {
	    curFrameSize = fsv;
	  } else {
	    // The value we read is a signed value, that's added to the previous frame size, to get the current frame size:
	    unsigned toSubtract = (fsv>0xFFFFFF)?0x07FFFFFF : (fsv>0xFFFF)?0x0FFFFF : (fsv>0xFF)?0x1FFF : 0x3F;
	    int fsv_signed = fsv - toSubtract;
	    curFrameSize += fsv_signed;
	    if ((int)curFrameSize < 0) break;
	  }
	} else { // Xiph lacing
	  curFrameSize = 0;
	  u_int8_t c;
	  do {
	    c = get1Byte();
	    curFrameSize += c;
	  } while (c == 0xFF);
	}
	fFrameSizesWithinBlock[i] = curFrameSize;
	frameSizesTotal += curFrameSize;
      }
      if (i != fNumFramesInBlock-1) break; // an error occurred within the "for" loop

      // Compute the size of the final frame within the block (from the block's size, and the frame sizes already computed):)
      unsigned headerBytesSeen = curOffset() - blockStartPos;
      if (headerBytesSeen + frameSizesTotal > fBlockSize) break;
      fFrameSizesWithinBlock[i] = fBlockSize - (headerBytesSeen + frameSizesTotal);
    }

    // We're done parsing headers within the block, and (as a result) we now know the sizes of all frames within the block.
    // If we have 'stripped bytes' that are common to (the front of) all frames, then count them now:
    if (track->headerStrippedBytesSize != 0) {
      for (unsigned i = 0; i < fNumFramesInBlock; ++i) fFrameSizesWithinBlock[i] += track->headerStrippedBytesSize;
    }
#ifdef DEBUG
    fprintf(stderr, "\tThis block contains %d frame(s); size(s):", fNumFramesInBlock);
    unsigned frameSizesTotal = 0;
    for (unsigned i = 0; i < fNumFramesInBlock; ++i) {
      fprintf(stderr, " %d", fFrameSizesWithinBlock[i]);
      frameSizesTotal += fFrameSizesWithinBlock[i];
    }
    if (fNumFramesInBlock > 1) fprintf(stderr, " (total: %u)", frameSizesTotal);
    fprintf(stderr, " bytes\n");
#endif
    // Next, start delivering these frames:
    fCurrentParseState = DELIVERING_FRAME_WITHIN_BLOCK;
    fCurOffsetWithinFrame = fNextFrameNumberToDeliver = 0;
    setParseState();
    return;
  } while (0);

  // An error occurred.  Try to recover:
#ifdef DEBUG
  fprintf(stderr, "parseBlock(): Error parsing data; trying to recover...\n");
#endif
  fCurrentParseState = LOOKING_FOR_BLOCK;
}
Boolean MatroskaFileParser::parseCues() {
#if defined(DEBUG) || defined(DEBUG_CUES)
  fprintf(stderr, "parsing Cues\n");
#endif
  EBMLId id;
  EBMLDataSize size;

  // Read the next header, which should be MATROSKA_ID_CUES:
  if (!parseEBMLIdAndSize(id, size) || id != MATROSKA_ID_CUES) return True; // The header wasn't what we expected, so we're done
  fLimitOffsetInFile = fCurOffsetInFile + size.val(); // Make sure we don't read past the end of this header

  double currentCueTime = 0.0;
  u_int64_t currentClusterOffsetInFile = 0;

  while (fCurOffsetInFile < fLimitOffsetInFile) {
    while (!parseEBMLIdAndSize(id, size)) {}
#ifdef DEBUG_CUES
    if (id == MATROSKA_ID_CUE_POINT) fprintf(stderr, "\n"); // makes debugging output easier to read
    fprintf(stderr, "MatroskaFileParser::parseCues(): Parsed id 0x%s (%s), size: %lld\n", id.hexString(), id.stringName(), size.val());
#endif
    switch (id.val()) {
      case MATROSKA_ID_CUE_POINT: { // 'Cue Point' header: enter this
	break;
      }
      case MATROSKA_ID_CUE_TIME: { // 'Cue Time' header: get this value
	unsigned cueTime;
	if (parseEBMLVal_unsigned(size, cueTime)) {
	  currentCueTime = cueTime*(fOurFile.fTimecodeScale/1000000000.0);
#ifdef DEBUG_CUES
	  fprintf(stderr, "\tCue Time %d (== %f seconds)\n", cueTime, currentCueTime);
#endif
	}
	break;
      }
      case MATROSKA_ID_CUE_TRACK_POSITIONS: { // 'Cue Track Positions' header: enter this
	break;
      }
      case MATROSKA_ID_CUE_TRACK: { // 'Cue Track' header: get this value (but only for debugging; we don't do anything with it)
	unsigned cueTrack;
	if (parseEBMLVal_unsigned(size, cueTrack)) {
#ifdef DEBUG_CUES
	  fprintf(stderr, "\tCue Track %d\n", cueTrack);
#endif
	}
	break;
      }
      case MATROSKA_ID_CUE_CLUSTER_POSITION: { // 'Cue Cluster Position' header: get this value
	u_int64_t cueClusterPosition;
	if (parseEBMLVal_unsigned64(size, cueClusterPosition)) {
	  currentClusterOffsetInFile = fOurFile.fSegmentDataOffset + cueClusterPosition;
#ifdef DEBUG_CUES
	  fprintf(stderr, "\tCue Cluster Position %llu (=> offset within the file: %llu (0x%llx))\n", cueClusterPosition, currentClusterOffsetInFile, currentClusterOffsetInFile);
#endif
	  // Record this cue point:
	  fOurFile.addCuePoint(currentCueTime, currentClusterOffsetInFile, 1/*default block number within cluster*/);
	}
	break;
      }
      case MATROSKA_ID_CUE_BLOCK_NUMBER: { // 'Cue Block Number' header: get this value
	unsigned cueBlockNumber;
	if (parseEBMLVal_unsigned(size, cueBlockNumber) && cueBlockNumber != 0) {
#ifdef DEBUG_CUES
	  fprintf(stderr, "\tCue Block Number %d\n", cueBlockNumber);
#endif
	  // Record this cue point (overwriting any existing entry for this cue time):
	  fOurFile.addCuePoint(currentCueTime, currentClusterOffsetInFile, cueBlockNumber);
	}
	break;
      }
      default: { // We don't process this header, so just skip over it:
	skipHeader(size);
#ifdef DEBUG_CUES
	fprintf(stderr, "\tskipped %lld bytes\n", size.val());
#endif
	break;
      }
    }
    setParseState();
  }

  fLimitOffsetInFile = 0; // reset
#if defined(DEBUG) || defined(DEBUG_CUES)
  fprintf(stderr, "done parsing Cues\n");
#endif
#ifdef DEBUG_CUES
  fprintf(stderr, "Cue Point tree: ");
  fOurFile.printCuePoints(stderr);
  fprintf(stderr, "\n");
#endif
  return True; // we're done parsing Cues
}
Boolean MatroskaFileParser::parseTrack() {
#ifdef DEBUG
  fprintf(stderr, "parsing Track\n");
#endif
  // Read and process each Matroska header, until we get to the end of the Track:
  MatroskaTrack* track = NULL;
  EBMLId id;
  EBMLDataSize size;
  while (fCurOffsetInFile < fLimitOffsetInFile) {
    while (!parseEBMLIdAndSize(id, size)) {}
#ifdef DEBUG
    if (id == MATROSKA_ID_TRACK_ENTRY) fprintf(stderr, "\n"); // makes debugging output easier to read
    fprintf(stderr, "MatroskaFileParser::parseTrack(): Parsed id 0x%s (%s), size: %lld\n", id.hexString(), id.stringName(), size.val());
#endif
    switch (id.val()) {
      case MATROSKA_ID_TRACK_ENTRY: { // 'Track Entry' header: enter this
	// Create a new "MatroskaTrack" object for this entry:
	if (track != NULL && track->trackNumber == 0) delete track; // We had a previous "MatroskaTrack" object that was never used
	track = new MatroskaTrack;
	break;
      }
      case MATROSKA_ID_TRACK_NUMBER: {
	unsigned trackNumber;
	if (parseEBMLVal_unsigned(size, trackNumber)) {
#ifdef DEBUG
	  fprintf(stderr, "\tTrack Number %d\n", trackNumber);
#endif
	  if (track != NULL && trackNumber != 0) {
	    track->trackNumber = trackNumber;
	    fOurFile.fTracks.add(track, trackNumber);
	  }
	}
	break;
      }
      case MATROSKA_ID_TRACK_TYPE: {
	unsigned trackType;
	if (parseEBMLVal_unsigned(size, trackType) && track != NULL) {
	  // We convert the Matroska 'track type' code into our own code (which we can use as a bitmap):
	  track->trackType
	    = trackType == 1 ? MATROSKA_TRACK_TYPE_VIDEO : trackType == 2 ? MATROSKA_TRACK_TYPE_AUDIO
	    : trackType == 0x11 ? MATROSKA_TRACK_TYPE_SUBTITLE : MATROSKA_TRACK_TYPE_OTHER;
#ifdef DEBUG
	  fprintf(stderr, "\tTrack Type 0x%02x (%s)\n", trackType,
		  track->trackType == MATROSKA_TRACK_TYPE_VIDEO ? "video" :
		  track->trackType == MATROSKA_TRACK_TYPE_AUDIO ? "audio" :
		  track->trackType == MATROSKA_TRACK_TYPE_SUBTITLE ? "subtitle" :
		  "<other>");
#endif
	}
	break;
      }
      case MATROSKA_ID_FLAG_ENABLED: {
	unsigned flagEnabled;
	if (parseEBMLVal_unsigned(size, flagEnabled)) {
#ifdef DEBUG
	  fprintf(stderr, "\tTrack is Enabled: %d\n", flagEnabled);
#endif
	  if (track != NULL) track->isEnabled = flagEnabled != 0;
	}
	break;
      }
      case MATROSKA_ID_FLAG_DEFAULT: {
	unsigned flagDefault;
	if (parseEBMLVal_unsigned(size, flagDefault)) {
#ifdef DEBUG
	  fprintf(stderr, "\tTrack is Default: %d\n", flagDefault);
#endif
	  if (track != NULL) track->isDefault = flagDefault != 0;
	}
	break;
      }
      case MATROSKA_ID_FLAG_FORCED: {
	unsigned flagForced;
	if (parseEBMLVal_unsigned(size, flagForced)) {
#ifdef DEBUG
	  fprintf(stderr, "\tTrack is Forced: %d\n", flagForced);
#endif
	  if (track != NULL) track->isForced = flagForced != 0;
	}
	break;
      }
      case MATROSKA_ID_DEFAULT_DURATION: {
	unsigned defaultDuration;
	if (parseEBMLVal_unsigned(size, defaultDuration)) {
#ifdef DEBUG
	  fprintf(stderr, "\tDefault duration %f ms\n", defaultDuration/1000000.0);
#endif
	  if (track != NULL) track->defaultDuration = defaultDuration;
	}
	break;
      }
      case MATROSKA_ID_MAX_BLOCK_ADDITION_ID: {
	unsigned maxBlockAdditionID;
	if (parseEBMLVal_unsigned(size, maxBlockAdditionID)) {
#ifdef DEBUG
	  fprintf(stderr, "\tMax Block Addition ID: %u\n", maxBlockAdditionID);
#endif
	}
	break;
      }
      case MATROSKA_ID_NAME: {
	char* name;
	if (parseEBMLVal_string(size, name)) {
#ifdef DEBUG
	  fprintf(stderr, "\tName: %s\n", name);
#endif
	  if (track != NULL) {
	    delete[] track->name; track->name = name;
	  } else {
	    delete[] name;
	  }
	}
	break;
      }
      case MATROSKA_ID_LANGUAGE: {
	char* language;
	if (parseEBMLVal_string(size, language)) {
#ifdef DEBUG
	  fprintf(stderr, "\tLanguage: %s\n", language);
#endif
	  if (track != NULL) {
	    delete[] track->language; track->language = language;
	  } else {
	    delete[] language;
	  }
	}
	break;
      }
      case MATROSKA_ID_CODEC: {
	char* codecID;
	if (parseEBMLVal_string(size, codecID)) {
#ifdef DEBUG
	  fprintf(stderr, "\tCodec ID: %s\n", codecID);
#endif
	  if (track != NULL) {
	    delete[] track->codecID; track->codecID = codecID;
	  } else {
	    delete[] codecID;
	  }
	}
	break;
      }
      case MATROSKA_ID_CODEC_PRIVATE: {
	u_int8_t* codecPrivate;
	unsigned codecPrivateSize;
	if (parseEBMLVal_binary(size, codecPrivate)) {
	  codecPrivateSize = (unsigned)size.val();
#ifdef DEBUG
	  fprintf(stderr, "\tCodec Private: ");
	  for (unsigned i = 0; i < codecPrivateSize; ++i) fprintf(stderr, "%02x:", codecPrivate[i]);
	  fprintf(stderr, "\n");
#endif
	  if (track != NULL) {
	    delete[] track->codecPrivate; track->codecPrivate = codecPrivate;
	    track->codecPrivateSize = codecPrivateSize;
	  } else {
	    delete[] codecPrivate;
	  }
	}
	break;
      }
      case MATROSKA_ID_VIDEO: { // 'Video settings' header: enter this
	break;
      }
      case MATROSKA_ID_PIXEL_WIDTH: {
	unsigned pixelWidth;
	if (parseEBMLVal_unsigned(size, pixelWidth)) {
#ifdef DEBUG
	  fprintf(stderr, "\tPixel Width %d\n", pixelWidth);
#endif
	}
	break;
      }
      case MATROSKA_ID_PIXEL_HEIGHT: {
	unsigned pixelHeight;
	if (parseEBMLVal_unsigned(size, pixelHeight)) {
#ifdef DEBUG
	  fprintf(stderr, "\tPixel Height %d\n", pixelHeight);
#endif
	}
	break;
      }
      case MATROSKA_ID_DISPLAY_WIDTH: {
	unsigned displayWidth;
	if (parseEBMLVal_unsigned(size, displayWidth)) {
#ifdef DEBUG
	  fprintf(stderr, "\tDisplay Width %d\n", displayWidth);
#endif
	}
	break;
      }
      case MATROSKA_ID_DISPLAY_HEIGHT: {
	unsigned displayHeight;
	if (parseEBMLVal_unsigned(size, displayHeight)) {
#ifdef DEBUG
	  fprintf(stderr, "\tDisplay Height %d\n", displayHeight);
#endif
	}
	break;
      }
      case MATROSKA_ID_AUDIO: { // 'Audio settings' header: enter this
	break;
      }
      case MATROSKA_ID_SAMPLING_FREQUENCY: {
	float samplingFrequency;
	if (parseEBMLVal_float(size, samplingFrequency)) {
	  if (track != NULL) {
	    track->samplingFrequency = (unsigned)samplingFrequency;
#ifdef DEBUG
	    fprintf(stderr, "\tSampling frequency %f (->%d)\n", samplingFrequency, track->samplingFrequency);
#endif
	  }
	}
	break;
      }
      case MATROSKA_ID_OUTPUT_SAMPLING_FREQUENCY: {
	float outputSamplingFrequency;
	if (parseEBMLVal_float(size, outputSamplingFrequency)) {
#ifdef DEBUG
	  fprintf(stderr, "\tOutput sampling frequency %f\n", outputSamplingFrequency);
#endif
	}
	break;
      }
      case MATROSKA_ID_CHANNELS: {
	unsigned numChannels;
	if (parseEBMLVal_unsigned(size, numChannels)) {
#ifdef DEBUG
	  fprintf(stderr, "\tChannels %d\n", numChannels);
#endif
	  if (track != NULL) track->numChannels = numChannels;
	}
	break;
      }
      case MATROSKA_ID_CONTENT_ENCODINGS:
      case MATROSKA_ID_CONTENT_ENCODING: { // 'Content Encodings' or 'Content Encoding' header: enter this
	break;
      }
      case MATROSKA_ID_CONTENT_COMPRESSION: { // 'Content Compression' header: enter this
	// Note: We currently support only 'Header Stripping' compression, not 'zlib' compression (the default algorithm).
	// Therefore, we disable this track, unless/until we later see that 'Header Stripping' is supported:
	if (track != NULL) track->isEnabled = False;
	break;
      }
      case MATROSKA_ID_CONTENT_COMP_ALGO: {
	unsigned contentCompAlgo;
	if (parseEBMLVal_unsigned(size, contentCompAlgo)) {
#ifdef DEBUG
	  fprintf(stderr, "\tContent Compression Algorithm %d (%s)\n", contentCompAlgo,
		  contentCompAlgo == 0 ? "zlib" : contentCompAlgo == 3 ? "Header Stripping" : "<unknown>");
#endif
	  // The only compression algorithm that we support is #3: Header Stripping; disable the track otherwise
	  if (track != NULL) track->isEnabled = contentCompAlgo == 3;
	}
	break;
      }
      case MATROSKA_ID_CONTENT_COMP_SETTINGS: {
	u_int8_t* headerStrippedBytes;
	unsigned headerStrippedBytesSize;
	if (parseEBMLVal_binary(size, headerStrippedBytes)) {
	  headerStrippedBytesSize = (unsigned)size.val();
#ifdef DEBUG
	  fprintf(stderr, "\tHeader Stripped Bytes: ");
	  for (unsigned i = 0; i < headerStrippedBytesSize; ++i) fprintf(stderr, "%02x:", headerStrippedBytes[i]);
	  fprintf(stderr, "\n");
#endif
	  if (track != NULL) {
	    delete[] track->headerStrippedBytes; track->headerStrippedBytes = headerStrippedBytes;
	    track->headerStrippedBytesSize = headerStrippedBytesSize;
	  } else {
	    delete[] headerStrippedBytes;
	  }
	}
	break;
      }
      case MATROSKA_ID_CONTENT_ENCRYPTION: { // 'Content Encrpytion' header: skip this
	// Note: We don't currently support encryption at all.  Therefore, we disable this track:
	if (track != NULL) track->isEnabled = False;
	// Fall through to...
      }
      default: { // We don't process this header, so just skip over it:
	skipHeader(size);
#ifdef DEBUG
	fprintf(stderr, "\tskipped %lld bytes\n", size.val());
#endif
	break;
      }
    }
    setParseState();
  }

  fLimitOffsetInFile = 0; // reset
  if (track != NULL && track->trackNumber == 0) delete track; // We had a previous "MatroskaTrack" object that was never used
  return True; // we're done parsing track entries
}
void MatroskaFileParser::lookForNextTrack() {
#ifdef DEBUG
  fprintf(stderr, "looking for Track\n");
#endif
  EBMLId id;
  EBMLDataSize size;

  // Read and skip over (or enter) each Matroska header, until we get to a 'Track'.
  while (fCurrentParseState == LOOKING_FOR_TRACKS) {
    while (!parseEBMLIdAndSize(id, size)) {}
#ifdef DEBUG
    fprintf(stderr, "MatroskaFileParser::lookForNextTrack(): Parsed id 0x%s (%s), size: %lld\n", id.hexString(), id.stringName(), size.val());
#endif
    switch (id.val()) {
      case MATROSKA_ID_SEGMENT: { // 'Segment' header: enter this
	// Remember the position, within the file, of the start of Segment data, because Seek Positions are relative to this:
	fOurFile.fSegmentDataOffset = fCurOffsetInFile;
	break;
      }
      case MATROSKA_ID_SEEK_HEAD: { // 'Seek Head' header: enter this
	break;
      }
      case MATROSKA_ID_SEEK: { // 'Seek' header: enter this
	break;
      }
      case MATROSKA_ID_SEEK_ID: { // 'Seek ID' header: get this value
	if (parseEBMLNumber(fLastSeekId)) {
#ifdef DEBUG
	  fprintf(stderr, "\tSeek ID 0x%s:\t%s\n", fLastSeekId.hexString(), fLastSeekId.stringName());
#endif
	}
	break;
      }
      case MATROSKA_ID_SEEK_POSITION: { // 'Seek Position' header: get this value
	u_int64_t seekPosition;
	if (parseEBMLVal_unsigned64(size, seekPosition)) {
	  u_int64_t offsetInFile = fOurFile.fSegmentDataOffset + seekPosition;
#ifdef DEBUG
	  fprintf(stderr, "\tSeek Position %llu (=> offset within the file: %llu (0x%llx))\n", seekPosition, offsetInFile, offsetInFile);
#endif
	  // The only 'Seek Position's that we care about are for 'Cluster' and 'Cues':
	  if (fLastSeekId == MATROSKA_ID_CLUSTER) {
	    fOurFile.fClusterOffset = offsetInFile;
	  } else if (fLastSeekId == MATROSKA_ID_CUES) {
	    fOurFile.fCuesOffset = offsetInFile;
	  }
	}
	break;
      }
      case MATROSKA_ID_INFO: { // 'Segment Info' header: enter this
	break;
      }
      case MATROSKA_ID_TIMECODE_SCALE: { // 'Timecode Scale' header: get this value
        unsigned timecodeScale;
	if (parseEBMLVal_unsigned(size, timecodeScale) && timecodeScale > 0) {
	  fOurFile.fTimecodeScale = timecodeScale;
#ifdef DEBUG
	  fprintf(stderr, "\tTimecode Scale %u ns (=> Segment Duration == %f seconds)\n", fOurFile.timecodeScale(), fOurFile.fileDuration());
#endif
	}
	break;
      }
      case MATROSKA_ID_DURATION: { // 'Segment Duration' header: get this value
	if (parseEBMLVal_float(size, fOurFile.fSegmentDuration)) {
#ifdef DEBUG
	  fprintf(stderr, "\tSegment Duration %f (== %f seconds)\n", fOurFile.segmentDuration(), fOurFile.fileDuration());
#endif
	}
	break;
      }
      case MATROSKA_ID_TRACKS: { // enter this, and move on to parsing 'Tracks'
	fLimitOffsetInFile = fCurOffsetInFile + size.val(); // Make sure we don't read past the end of this header
	fCurrentParseState = PARSING_TRACK;
	break;
      }
      default: { // skip over this header
	skipHeader(size);
#ifdef DEBUG
	fprintf(stderr, "\tskipped %lld bytes\n", size.val());
#endif
	break;
      }
    }
    setParseState();
  }
}
unsigned MPEG1or2VideoStreamParser::parseGOPHeader(Boolean haveSeenStartCode)
{
    // First check whether we should insert a previously-saved
    // 'video_sequence_header' here:
    if (needToUseSavedVSH()) return useSavedVSH();

#ifdef DEBUG
    fprintf(stderr, "parsing GOP header\n");
#endif
    unsigned first4Bytes;
    if (!haveSeenStartCode)
    {
        while ((first4Bytes = test4Bytes()) != GROUP_START_CODE)
        {
#ifdef DEBUG
            fprintf(stderr, "ignoring non GOP start code: 0x%08x\n", first4Bytes);
#endif
            get1Byte();
            setParseState(PARSING_GOP_HEADER);
            // ensures we progress over bad data
        }
        first4Bytes = get4Bytes();
    }
    else
    {
        // We've already seen the GROUP_START_CODE
        first4Bytes = GROUP_START_CODE;
    }
    save4Bytes(first4Bytes);

    // Next, extract the (25-bit) time code from the next 4 bytes:
    unsigned next4Bytes = get4Bytes();
    unsigned time_code = (next4Bytes & 0xFFFFFF80) >> (32 - 25);
#if defined(DEBUG) || defined(DEBUG_TIMESTAMPS)
    Boolean drop_frame_flag     = (time_code & 0x01000000) != 0;
#endif
    unsigned time_code_hours    = (time_code & 0x00F80000) >> 19;
    unsigned time_code_minutes  = (time_code & 0x0007E000) >> 13;
    unsigned time_code_seconds  = (time_code & 0x00000FC0) >> 6;
    unsigned time_code_pictures = (time_code & 0x0000003F);
#if defined(DEBUG) || defined(DEBUG_TIMESTAMPS)
    fprintf(stderr, "time_code: 0x%07x, drop_frame %d, hours %d, minutes %d, seconds %d, pictures %d\n", time_code, drop_frame_flag, time_code_hours, time_code_minutes, time_code_seconds, time_code_pictures);
#endif
#ifdef DEBUG
    Boolean closed_gop  = (next4Bytes & 0x00000040) != 0;
    Boolean broken_link = (next4Bytes & 0x00000020) != 0;
    fprintf(stderr, "closed_gop: %d, broken_link: %d\n", closed_gop, broken_link);
#endif

    // Now, copy all bytes that we see, up until we reach a PICTURE_START_CODE:
    do
    {
        saveToNextCode(next4Bytes);
    }
    while (next4Bytes != PICTURE_START_CODE);

    // Record the time code:
    usingSource()->setTimeCode(time_code_hours, time_code_minutes,
                               time_code_seconds, time_code_pictures,
                               fPicturesSinceLastGOP);

    fPicturesSinceLastGOP = 0;

    // Compute this frame's timestamp:
    usingSource()->computePresentationTime(0);

    setParseState(PARSING_PICTURE_HEADER);

    return curFrameSize();
}
unsigned H264VideoStreamParser::parse() {
  try {
    // The stream must start with a 0x00000001:
    if (!fHaveSeenFirstStartCode) {
      // Skip over any input bytes that precede the first 0x00000001:
      u_int32_t first4Bytes;
      while ((first4Bytes = test4Bytes()) != 0x00000001) {
	get1Byte(); setParseState(); // ensures that we progress over bad data
      }
      skipBytes(4); // skip this initial code
      
      setParseState();
      fHaveSeenFirstStartCode = True; // from now on
    }
    
    if (fOutputStartCodeSize > 0) {
      // Include a start code in the output:
      save4Bytes(0x00000001);
    }

    // Then save everything up until the next 0x00000001 (4 bytes) or 0x000001 (3 bytes), or we hit EOF.
    // Also make note of the first byte, because it contains the "nal_unit_type": 
    if (haveSeenEOF()) {
      // We hit EOF the last time that we tried to parse this data, so we know that any remaining unparsed data
      // forms a complete NAL unit, and that there's no 'start code' at the end:
      unsigned remainingDataSize = totNumValidBytes() - curOffset();
      while (remainingDataSize > 0) {
	saveByte(get1Byte());
	--remainingDataSize;
      }

      if (!fHaveSeenFirstByteOfNALUnit) {
	// There's no remaining NAL unit.
	(void)get1Byte(); // forces another read, which will cause EOF to get handled for real this time
	return 0;
      }
#ifdef DEBUG
      fprintf(stderr, "This NAL unit (%d bytes) ends with EOF\n", curFrameSize()-fOutputStartCodeSize);
#endif
    } else {
      u_int32_t next4Bytes = test4Bytes();
      if (!fHaveSeenFirstByteOfNALUnit) {
	fFirstByteOfNALUnit = next4Bytes>>24;
	fHaveSeenFirstByteOfNALUnit = True;
      }
      while (next4Bytes != 0x00000001 && (next4Bytes&0xFFFFFF00) != 0x00000100) {
	// We save at least some of "next4Bytes".
	if ((unsigned)(next4Bytes&0xFF) > 1) {
	  // Common case: 0x00000001 or 0x000001 definitely doesn't begin anywhere in "next4Bytes", so we save all of it:
	  save4Bytes(next4Bytes);
	  skipBytes(4);
	} else {
	  // Save the first byte, and continue testing the rest:
	  saveByte(next4Bytes>>24);
	  skipBytes(1);
	}
	setParseState(); // ensures forward progress
	next4Bytes = test4Bytes();
      }
      // Assert: next4Bytes starts with 0x00000001 or 0x000001, and we've saved all previous bytes (forming a complete NAL unit).
      // Skip over these remaining bytes, up until the start of the next NAL unit:
      if (next4Bytes == 0x00000001) {
	skipBytes(4);
      } else {
	skipBytes(3);
      }
    }

    u_int8_t nal_ref_idc = (fFirstByteOfNALUnit&0x60)>>5;
    u_int8_t nal_unit_type = fFirstByteOfNALUnit&0x1F;
    fHaveSeenFirstByteOfNALUnit = False; // for the next NAL unit that we parse
#ifdef DEBUG
    fprintf(stderr, "Parsed %d-byte NAL-unit (nal_ref_idc: %d, nal_unit_type: %d (\"%s\"))\n",
	    curFrameSize()-fOutputStartCodeSize, nal_ref_idc, nal_unit_type, nal_unit_type_description[nal_unit_type]);
#endif

    switch (nal_unit_type) {
      case 6: { // Supplemental enhancement information (SEI)
	analyze_sei_data();
	// Later, perhaps adjust "fPresentationTime" if we saw a "pic_timing" SEI payload??? #####
	break;
      }
      case 7: { // Sequence parameter set
	// First, save a copy of this NAL unit, in case the downstream object wants to see it:
	usingSource()->saveCopyOfSPS(fStartOfFrame + fOutputStartCodeSize, fTo - fStartOfFrame - fOutputStartCodeSize);

	// Parse this NAL unit to check whether frame rate information is present:
	unsigned num_units_in_tick, time_scale, fixed_frame_rate_flag;
	analyze_seq_parameter_set_data(num_units_in_tick, time_scale, fixed_frame_rate_flag);
	if (time_scale > 0 && num_units_in_tick > 0) {
	  usingSource()->fFrameRate = time_scale/(2.0*num_units_in_tick);
#ifdef DEBUG
	  fprintf(stderr, "Set frame rate to %f fps\n", usingSource()->fFrameRate);
	  if (fixed_frame_rate_flag == 0) {
	    fprintf(stderr, "\tWARNING: \"fixed_frame_rate_flag\" was not set\n");
	  }
#endif
	} else {
#ifdef DEBUG
	  fprintf(stderr, "\tThis \"Sequence Parameter Set\" NAL unit contained no frame rate information, so we use a default frame rate of %f fps\n", usingSource()->fFrameRate);
#endif
	}
	break;
      }
      case 8: { // Picture parameter set
	// Save a copy of this NAL unit, in case the downstream object wants to see it:
	usingSource()->saveCopyOfPPS(fStartOfFrame + fOutputStartCodeSize, fTo - fStartOfFrame - fOutputStartCodeSize);
      }
    }

    usingSource()->setPresentationTime();
#ifdef DEBUG
    unsigned long secs = (unsigned long)usingSource()->fPresentationTime.tv_sec;
    unsigned uSecs = (unsigned)usingSource()->fPresentationTime.tv_usec;
    fprintf(stderr, "\tPresentation time: %lu.%06u\n", secs, uSecs);
#endif

    // If this NAL unit is a VCL NAL unit, we also scan the start of the next NAL unit, to determine whether this NAL unit
    // ends the current 'access unit'.  We need this information to figure out when to increment "fPresentationTime".
    // (RTP streamers also need to know this in order to figure out whether or not to set the "M" bit.)
    Boolean thisNALUnitEndsAccessUnit = False; // until we learn otherwise 
    if (haveSeenEOF()) {
      // There is no next NAL unit, so we assume that this one ends the current 'access unit':
      thisNALUnitEndsAccessUnit = True;
    } else {
      Boolean const isVCL = nal_unit_type <= 5 && nal_unit_type > 0; // Would need to include type 20 for SVC and MVC #####
      if (isVCL) {
	u_int32_t first4BytesOfNextNALUnit = test4Bytes();
	u_int8_t firstByteOfNextNALUnit = first4BytesOfNextNALUnit>>24;
	u_int8_t next_nal_ref_idc = (firstByteOfNextNALUnit&0x60)>>5;
	u_int8_t next_nal_unit_type = firstByteOfNextNALUnit&0x1F;
	if (next_nal_unit_type >= 6) {
	  // The next NAL unit is not a VCL; therefore, we assume that this NAL unit ends the current 'access unit':
#ifdef DEBUG
	  fprintf(stderr, "\t(The next NAL unit is not a VCL)\n");
#endif
	  thisNALUnitEndsAccessUnit = True;
	} else {
	  // The next NAL unit is also a VCL.  We need to examine it a little to figure out if it's a different 'access unit'.
	  // (We use many of the criteria described in section 7.4.1.2.4 of the H.264 specification.)
	  Boolean IdrPicFlag = nal_unit_type == 5;
	  Boolean next_IdrPicFlag = next_nal_unit_type == 5;
	  if (next_IdrPicFlag != IdrPicFlag) {
	    // IdrPicFlag differs in value
#ifdef DEBUG
	    fprintf(stderr, "\t(IdrPicFlag differs in value)\n");
#endif
	    thisNALUnitEndsAccessUnit = True;
	  } else if (next_nal_ref_idc != nal_ref_idc && next_nal_ref_idc*nal_ref_idc == 0) {
	    // nal_ref_idc differs in value with one of the nal_ref_idc values being equal to 0
#ifdef DEBUG
	    fprintf(stderr, "\t(nal_ref_idc differs in value with one of the nal_ref_idc values being equal to 0)\n");
#endif
	    thisNALUnitEndsAccessUnit = True;
	  } else if ((nal_unit_type == 1 || nal_unit_type == 2 || nal_unit_type == 5)
		     && (next_nal_unit_type == 1 || next_nal_unit_type == 2 || next_nal_unit_type == 5)) {
	    // Both this and the next NAL units begin with a "slice_header".
	    // Parse this (for each), to get parameters that we can compare:
	    
	    // Current NAL unit's "slice_header":
	    unsigned frame_num, pic_parameter_set_id, idr_pic_id;
	    Boolean field_pic_flag, bottom_field_flag;
	    analyze_slice_header(fStartOfFrame + fOutputStartCodeSize, fTo, nal_unit_type,
				 frame_num, pic_parameter_set_id, idr_pic_id, field_pic_flag, bottom_field_flag);
	    
	    // Next NAL unit's "slice_header":
#ifdef DEBUG
	    fprintf(stderr, "    Next NAL unit's slice_header:\n");
#endif
	    u_int8_t next_slice_header[NUM_NEXT_SLICE_HEADER_BYTES_TO_ANALYZE];
	    testBytes(next_slice_header, sizeof next_slice_header);
	    unsigned next_frame_num, next_pic_parameter_set_id, next_idr_pic_id;
	    Boolean next_field_pic_flag, next_bottom_field_flag;
	    analyze_slice_header(next_slice_header, &next_slice_header[sizeof next_slice_header], next_nal_unit_type,
				 next_frame_num, next_pic_parameter_set_id, next_idr_pic_id, next_field_pic_flag, next_bottom_field_flag);
	    
	    if (next_frame_num != frame_num) {
	      // frame_num differs in value
#ifdef DEBUG
	      fprintf(stderr, "\t(frame_num differs in value)\n");
#endif
	      thisNALUnitEndsAccessUnit = True;
	    } else if (next_pic_parameter_set_id != pic_parameter_set_id) {
	      // pic_parameter_set_id differs in value
#ifdef DEBUG
	      fprintf(stderr, "\t(pic_parameter_set_id differs in value)\n");
#endif
	      thisNALUnitEndsAccessUnit = True;
	    } else if (next_field_pic_flag != field_pic_flag) {
	      // field_pic_flag differs in value
#ifdef DEBUG
	      fprintf(stderr, "\t(field_pic_flag differs in value)\n");
#endif
	      thisNALUnitEndsAccessUnit = True;
	    } else if (next_bottom_field_flag != bottom_field_flag) {
	      // bottom_field_flag differs in value
#ifdef DEBUG
	      fprintf(stderr, "\t(bottom_field_flag differs in value)\n");
#endif
	      thisNALUnitEndsAccessUnit = True;
	    } else if (next_IdrPicFlag == 1 && next_idr_pic_id != idr_pic_id) {
	      // IdrPicFlag is equal to 1 for both and idr_pic_id differs in value
	      // Note: We already know that IdrPicFlag is the same for both.
#ifdef DEBUG
	      fprintf(stderr, "\t(IdrPicFlag is equal to 1 for both and idr_pic_id differs in value)\n");
#endif
	      thisNALUnitEndsAccessUnit = True;
	    }
	  }
	}
      }
    }
	
    if (thisNALUnitEndsAccessUnit) {
#ifdef DEBUG
      fprintf(stderr, "*****This NAL unit ends the current access unit*****\n");
#endif
      usingSource()->fPictureEndMarker = True;
      ++usingSource()->fPictureCount;

      // Note that the presentation time for the next NAL unit will be different:
      struct timeval& nextPT = usingSource()->fNextPresentationTime; // alias
      nextPT = usingSource()->fPresentationTime;
      double nextFraction = nextPT.tv_usec/1000000.0 + 1/usingSource()->fFrameRate;
      unsigned nextSecsIncrement = (long)nextFraction;
      nextPT.tv_sec += (long)nextSecsIncrement;
      nextPT.tv_usec = (long)((nextFraction - nextSecsIncrement)*1000000);
    }
    setParseState();

    return curFrameSize();
  } catch (int /*e*/) {
unsigned MPEG1or2VideoStreamParser::parseSlice()
{
    // Note that we've already read the slice_start_code:
    unsigned next4Bytes = PICTURE_START_CODE | fCurrentSliceNumber;
#ifdef DEBUG_SLICE
    fprintf(stderr, "parsing slice: 0x%08x\n", next4Bytes);
#endif

    if (fSkippingCurrentPicture)
    {
        // Skip all bytes that we see, up until we reach a code of some sort:
        skipToNextCode(next4Bytes);
    }
    else
    {
        // Copy all bytes that we see, up until we reach a code of some sort:
        saveToNextCode(next4Bytes);
    }

    // The next thing to parse depends on the code that we just saw:
    if (isSliceStartCode(next4Bytes))   // common case
    {
        setParseState(PARSING_SLICE);
        fCurrentSliceNumber = next4Bytes & 0xFF;
    }
    else
    {
        // Because we don't see any more slices, we are assumed to have ended
        // the current picture:
        ++fPicturesSinceLastGOP;
        ++usingSource()->fPictureCount;
        usingSource()->fPictureEndMarker = True; // HACK #####

        switch (next4Bytes)
        {
        case SEQUENCE_END_CODE:
        {
            setParseState(PARSING_VIDEO_SEQUENCE_HEADER);
            break;
        }
        case VIDEO_SEQUENCE_HEADER_START_CODE:
        {
            setParseState(PARSING_VIDEO_SEQUENCE_HEADER_SEEN_CODE);
            break;
        }
        case GROUP_START_CODE:
        {
            setParseState(PARSING_GOP_HEADER_SEEN_CODE);
            break;
        }
        case PICTURE_START_CODE:
        {
            setParseState(PARSING_PICTURE_HEADER);
            break;
        }
        default:
        {
            usingSource()->envir() << "MPEG1or2VideoStreamParser::parseSlice(): Saw unexpected code "
                                   << (void *)next4Bytes << "\n";
            setParseState(PARSING_SLICE); // the safest way to recover...
            break;
        }
        }
    }

    // Compute this frame's timestamp:
    usingSource()->computePresentationTime(fCurPicTemporalReference);

    if (fSkippingCurrentPicture)
    {
        return parse(); // try again, until we get a non-skipped frame
    }
    else
    {
        return curFrameSize();
    }
}