Program: 110399
Project: 110399
Buggy source:
/** 
 * Parses an stbl atom (defined in 14496-12).
 * @param track Track to which this sample table corresponds.
 * @param stblAtom stbl (sample table) atom to parse.
 * @return Sample table described by the stbl atom.
 * @throws ParserException If the resulting sample sequence does not contain a sync sample.
 */
public static TrackSampleTable parseStbl(Track track,Atom.ContainerAtom stblAtom) throws ParserException {
  ParsableByteArray stsz=stblAtom.getLeafAtomOfType(Atom.TYPE_stsz).data;
  ParsableByteArray chunkOffsets;
  Atom.LeafAtom chunkOffsetsAtom=stblAtom.getLeafAtomOfType(Atom.TYPE_stco);
  if (chunkOffsetsAtom == null) {
    chunkOffsetsAtom=stblAtom.getLeafAtomOfType(Atom.TYPE_co64);
  }
  chunkOffsets=chunkOffsetsAtom.data;
  ParsableByteArray stsc=stblAtom.getLeafAtomOfType(Atom.TYPE_stsc).data;
  ParsableByteArray stts=stblAtom.getLeafAtomOfType(Atom.TYPE_stts).data;
  Atom.LeafAtom stssAtom=stblAtom.getLeafAtomOfType(Atom.TYPE_stss);
  ParsableByteArray stss=stssAtom != null ? stssAtom.data : null;
  Atom.LeafAtom cttsAtom=stblAtom.getLeafAtomOfType(Atom.TYPE_ctts);
  ParsableByteArray ctts=cttsAtom != null ? cttsAtom.data : null;
  stsz.setPosition(Atom.FULL_HEADER_SIZE);
  int fixedSampleSize=stsz.readUnsignedIntToInt();
  int sampleCount=stsz.readUnsignedIntToInt();
  long[] offsets=new long[sampleCount];
  int[] sizes=new int[sampleCount];
  int maximumSize=0;
  long[] timestamps=new long[sampleCount];
  int[] flags=new int[sampleCount];
  if (sampleCount == 0) {
    return new TrackSampleTable(offsets,sizes,maximumSize,timestamps,flags);
  }
  chunkOffsets.setPosition(Atom.FULL_HEADER_SIZE);
  int chunkCount=chunkOffsets.readUnsignedIntToInt();
  stsc.setPosition(Atom.FULL_HEADER_SIZE);
  int remainingSamplesPerChunkChanges=stsc.readUnsignedIntToInt() - 1;
  Assertions.checkState(stsc.readInt() == 1,"String_Node_Str");
  int samplesPerChunk=stsc.readUnsignedIntToInt();
  stsc.skipBytes(4);
  int nextSamplesPerChunkChangeChunkIndex=-1;
  if (remainingSamplesPerChunkChanges > 0) {
    nextSamplesPerChunkChangeChunkIndex=stsc.readUnsignedIntToInt() - 1;
  }
  int chunkIndex=0;
  int remainingSamplesInChunk=samplesPerChunk;
  stts.setPosition(Atom.FULL_HEADER_SIZE);
  int remainingTimestampDeltaChanges=stts.readUnsignedIntToInt() - 1;
  int remainingSamplesAtTimestampDelta=stts.readUnsignedIntToInt();
  int timestampDeltaInTimeUnits=stts.readUnsignedIntToInt();
  int remainingSamplesAtTimestampOffset=0;
  int remainingTimestampOffsetChanges=0;
  int timestampOffset=0;
  if (ctts != null) {
    ctts.setPosition(Atom.FULL_HEADER_SIZE);
    remainingTimestampOffsetChanges=ctts.readUnsignedIntToInt() - 1;
    remainingSamplesAtTimestampOffset=ctts.readUnsignedIntToInt();
    timestampOffset=ctts.readInt();
  }
  int nextSynchronizationSampleIndex=-1;
  int remainingSynchronizationSamples=0;
  if (stss != null) {
    stss.setPosition(Atom.FULL_HEADER_SIZE);
    remainingSynchronizationSamples=stss.readUnsignedIntToInt();
    nextSynchronizationSampleIndex=stss.readUnsignedIntToInt() - 1;
  }
  long offsetBytes;
  if (chunkOffsetsAtom.type == Atom.TYPE_stco) {
    offsetBytes=chunkOffsets.readUnsignedInt();
  }
 else {
    offsetBytes=chunkOffsets.readUnsignedLongToLong();
  }
  long timestampTimeUnits=0;
  for (int i=0; i < sampleCount; i++) {
    offsets[i]=offsetBytes;
    sizes[i]=fixedSampleSize == 0 ? stsz.readUnsignedIntToInt() : fixedSampleSize;
    if (sizes[i] > maximumSize) {
      maximumSize=sizes[i];
    }
    timestamps[i]=timestampTimeUnits + timestampOffset;
    flags[i]=stss == null ? C.SAMPLE_FLAG_SYNC : 0;
    if (i == nextSynchronizationSampleIndex) {
      flags[i]=C.SAMPLE_FLAG_SYNC;
      remainingSynchronizationSamples--;
      if (remainingSynchronizationSamples > 0) {
        nextSynchronizationSampleIndex=stss.readUnsignedIntToInt() - 1;
      }
    }
    timestampTimeUnits+=timestampDeltaInTimeUnits;
    remainingSamplesAtTimestampDelta--;
    if (remainingSamplesAtTimestampDelta == 0 && remainingTimestampDeltaChanges > 0) {
      remainingSamplesAtTimestampDelta=stts.readUnsignedIntToInt();
      timestampDeltaInTimeUnits=stts.readUnsignedIntToInt();
      remainingTimestampDeltaChanges--;
    }
    if (ctts != null) {
      remainingSamplesAtTimestampOffset--;
      if (remainingSamplesAtTimestampOffset == 0 && remainingTimestampOffsetChanges > 0) {
        remainingSamplesAtTimestampOffset=ctts.readUnsignedIntToInt();
        timestampOffset=ctts.readInt();
        remainingTimestampOffsetChanges--;
      }
    }
    remainingSamplesInChunk--;
    if (remainingSamplesInChunk == 0) {
      chunkIndex++;
      if (chunkIndex < chunkCount) {
        if (chunkOffsetsAtom.type == Atom.TYPE_stco) {
          offsetBytes=chunkOffsets.readUnsignedInt();
        }
 else {
          offsetBytes=chunkOffsets.readUnsignedLongToLong();
        }
      }
      if (chunkIndex == nextSamplesPerChunkChangeChunkIndex) {
        samplesPerChunk=stsc.readUnsignedIntToInt();
        stsc.skipBytes(4);
        remainingSamplesPerChunkChanges--;
        if (remainingSamplesPerChunkChanges > 0) {
          nextSamplesPerChunkChangeChunkIndex=stsc.readUnsignedIntToInt() - 1;
        }
      }
      if (chunkIndex < chunkCount) {
        remainingSamplesInChunk=samplesPerChunk;
      }
    }
 else {
      offsetBytes+=sizes[i];
    }
  }
  Assertions.checkArgument(remainingSynchronizationSamples == 0);
  Assertions.checkArgument(remainingSamplesAtTimestampDelta == 0);
  Assertions.checkArgument(remainingSamplesInChunk == 0);
  Assertions.checkArgument(remainingTimestampDeltaChanges == 0);
  Assertions.checkArgument(remainingTimestampOffsetChanges == 0);
  if (track.editListDurations == null) {
    Util.scaleLargeTimestampsInPlace(timestamps,C.MICROS_PER_SECOND,track.timescale);
    return new TrackSampleTable(offsets,sizes,maximumSize,timestamps,flags);
  }
  if (track.editListDurations.length == 1 && track.editListDurations[0] == 0) {
    for (int i=0; i < timestamps.length; i++) {
      timestamps[i]=Util.scaleLargeTimestamp(timestamps[i] - track.editListMediaTimes[0],C.MICROS_PER_SECOND,track.timescale);
    }
    return new TrackSampleTable(offsets,sizes,maximumSize,timestamps,flags);
  }
  int editedSampleCount=0;
  int nextSampleIndex=0;
  boolean copyMetadata=false;
  for (int i=0; i < track.editListDurations.length; i++) {
    long mediaTime=track.editListMediaTimes[i];
    if (mediaTime != -1) {
      long duration=Util.scaleLargeTimestamp(track.editListDurations[i],track.timescale,track.movieTimescale);
      int startIndex=Util.binarySearchCeil(timestamps,mediaTime,true,true);
      int endIndex=Util.binarySearchCeil(timestamps,mediaTime + duration,true,false);
      editedSampleCount+=endIndex - startIndex;
      copyMetadata|=nextSampleIndex != startIndex;
      nextSampleIndex=endIndex;
    }
  }
  copyMetadata|=editedSampleCount != sampleCount;
  long[] editedOffsets=copyMetadata ? new long[editedSampleCount] : offsets;
  int[] editedSizes=copyMetadata ? new int[editedSampleCount] : sizes;
  int editedMaximumSize=copyMetadata ? 0 : maximumSize;
  int[] editedFlags=copyMetadata ? new int[editedSampleCount] : flags;
  long[] editedTimestamps=new long[editedSampleCount];
  long pts=0;
  int sampleIndex=0;
  for (int i=0; i < track.editListDurations.length; i++) {
    long mediaTime=track.editListMediaTimes[i];
    long duration=track.editListDurations[i];
    if (mediaTime != -1) {
      long endMediaTime=mediaTime + Util.scaleLargeTimestamp(duration,track.timescale,track.movieTimescale);
      int startIndex=Util.binarySearchCeil(timestamps,mediaTime,true,true);
      int endIndex=Util.binarySearchCeil(timestamps,endMediaTime,true,false);
      if (copyMetadata) {
        int count=endIndex - startIndex;
        System.arraycopy(offsets,startIndex,editedOffsets,sampleIndex,count);
        System.arraycopy(sizes,startIndex,editedSizes,sampleIndex,count);
        System.arraycopy(flags,startIndex,editedFlags,sampleIndex,count);
      }
      for (int j=startIndex; j < endIndex; j++) {
        long ptsUs=Util.scaleLargeTimestamp(pts,C.MICROS_PER_SECOND,track.movieTimescale);
        long timeInSegmentUs=Util.scaleLargeTimestamp(timestamps[j] - mediaTime,C.MICROS_PER_SECOND,track.timescale);
        editedTimestamps[sampleIndex]=ptsUs + timeInSegmentUs;
        if (copyMetadata && editedSizes[sampleIndex] > editedMaximumSize) {
          editedMaximumSize=sizes[j];
        }
        sampleIndex++;
      }
    }
    pts+=duration;
  }
  boolean hasSyncSample=false;
  for (int i=0; i < editedFlags.length && !hasSyncSample; i++) {
    hasSyncSample|=(editedFlags[i] & C.SAMPLE_FLAG_SYNC) != 0;
  }
  if (!hasSyncSample) {
    throw new ParserException("String_Node_Str");
  }
  return new TrackSampleTable(editedOffsets,editedSizes,editedMaximumSize,editedTimestamps,editedFlags);
}

Fixed version (ground truth):
/** 
 * Parses an stbl atom (defined in 14496-12).
 * @param track Track to which this sample table corresponds.
 * @param stblAtom stbl (sample table) atom to parse.
 * @return Sample table described by the stbl atom.
 * @throws ParserException If the resulting sample sequence does not contain a sync sample.
 */
public static TrackSampleTable parseStbl(Track track,Atom.ContainerAtom stblAtom) throws ParserException {
  ParsableByteArray stsz=stblAtom.getLeafAtomOfType(Atom.TYPE_stsz).data;
  ParsableByteArray chunkOffsets;
  Atom.LeafAtom chunkOffsetsAtom=stblAtom.getLeafAtomOfType(Atom.TYPE_stco);
  if (chunkOffsetsAtom == null) {
    chunkOffsetsAtom=stblAtom.getLeafAtomOfType(Atom.TYPE_co64);
  }
  chunkOffsets=chunkOffsetsAtom.data;
  ParsableByteArray stsc=stblAtom.getLeafAtomOfType(Atom.TYPE_stsc).data;
  ParsableByteArray stts=stblAtom.getLeafAtomOfType(Atom.TYPE_stts).data;
  Atom.LeafAtom stssAtom=stblAtom.getLeafAtomOfType(Atom.TYPE_stss);
  ParsableByteArray stss=stssAtom != null ? stssAtom.data : null;
  Atom.LeafAtom cttsAtom=stblAtom.getLeafAtomOfType(Atom.TYPE_ctts);
  ParsableByteArray ctts=cttsAtom != null ? cttsAtom.data : null;
  stsz.setPosition(Atom.FULL_HEADER_SIZE);
  int fixedSampleSize=stsz.readUnsignedIntToInt();
  int sampleCount=stsz.readUnsignedIntToInt();
  long[] offsets=new long[sampleCount];
  int[] sizes=new int[sampleCount];
  int maximumSize=0;
  long[] timestamps=new long[sampleCount];
  int[] flags=new int[sampleCount];
  if (sampleCount == 0) {
    return new TrackSampleTable(offsets,sizes,maximumSize,timestamps,flags);
  }
  chunkOffsets.setPosition(Atom.FULL_HEADER_SIZE);
  int chunkCount=chunkOffsets.readUnsignedIntToInt();
  stsc.setPosition(Atom.FULL_HEADER_SIZE);
  int remainingSamplesPerChunkChanges=stsc.readUnsignedIntToInt() - 1;
  Assertions.checkState(stsc.readInt() == 1,"String_Node_Str");
  int samplesPerChunk=stsc.readUnsignedIntToInt();
  stsc.skipBytes(4);
  int nextSamplesPerChunkChangeChunkIndex=-1;
  if (remainingSamplesPerChunkChanges > 0) {
    nextSamplesPerChunkChangeChunkIndex=stsc.readUnsignedIntToInt() - 1;
  }
  int chunkIndex=0;
  int remainingSamplesInChunk=samplesPerChunk;
  stts.setPosition(Atom.FULL_HEADER_SIZE);
  int remainingTimestampDeltaChanges=stts.readUnsignedIntToInt() - 1;
  int remainingSamplesAtTimestampDelta=stts.readUnsignedIntToInt();
  int timestampDeltaInTimeUnits=stts.readUnsignedIntToInt();
  int remainingSamplesAtTimestampOffset=0;
  int remainingTimestampOffsetChanges=0;
  int timestampOffset=0;
  if (ctts != null) {
    ctts.setPosition(Atom.FULL_HEADER_SIZE);
    remainingTimestampOffsetChanges=ctts.readUnsignedIntToInt();
  }
  int nextSynchronizationSampleIndex=-1;
  int remainingSynchronizationSamples=0;
  if (stss != null) {
    stss.setPosition(Atom.FULL_HEADER_SIZE);
    remainingSynchronizationSamples=stss.readUnsignedIntToInt();
    nextSynchronizationSampleIndex=stss.readUnsignedIntToInt() - 1;
  }
  long offsetBytes;
  if (chunkOffsetsAtom.type == Atom.TYPE_stco) {
    offsetBytes=chunkOffsets.readUnsignedInt();
  }
 else {
    offsetBytes=chunkOffsets.readUnsignedLongToLong();
  }
  long timestampTimeUnits=0;
  for (int i=0; i < sampleCount; i++) {
    if (ctts != null) {
      while (remainingSamplesAtTimestampOffset == 0 && remainingTimestampOffsetChanges > 0) {
        remainingSamplesAtTimestampOffset=ctts.readUnsignedIntToInt();
        timestampOffset=ctts.readInt();
        remainingTimestampOffsetChanges--;
      }
      remainingSamplesAtTimestampOffset--;
    }
    offsets[i]=offsetBytes;
    sizes[i]=fixedSampleSize == 0 ? stsz.readUnsignedIntToInt() : fixedSampleSize;
    if (sizes[i] > maximumSize) {
      maximumSize=sizes[i];
    }
    timestamps[i]=timestampTimeUnits + timestampOffset;
    flags[i]=stss == null ? C.SAMPLE_FLAG_SYNC : 0;
    if (i == nextSynchronizationSampleIndex) {
      flags[i]=C.SAMPLE_FLAG_SYNC;
      remainingSynchronizationSamples--;
      if (remainingSynchronizationSamples > 0) {
        nextSynchronizationSampleIndex=stss.readUnsignedIntToInt() - 1;
      }
    }
    timestampTimeUnits+=timestampDeltaInTimeUnits;
    remainingSamplesAtTimestampDelta--;
    if (remainingSamplesAtTimestampDelta == 0 && remainingTimestampDeltaChanges > 0) {
      remainingSamplesAtTimestampDelta=stts.readUnsignedIntToInt();
      timestampDeltaInTimeUnits=stts.readUnsignedIntToInt();
      remainingTimestampDeltaChanges--;
    }
    remainingSamplesInChunk--;
    if (remainingSamplesInChunk == 0) {
      chunkIndex++;
      if (chunkIndex < chunkCount) {
        if (chunkOffsetsAtom.type == Atom.TYPE_stco) {
          offsetBytes=chunkOffsets.readUnsignedInt();
        }
 else {
          offsetBytes=chunkOffsets.readUnsignedLongToLong();
        }
      }
      if (chunkIndex == nextSamplesPerChunkChangeChunkIndex) {
        samplesPerChunk=stsc.readUnsignedIntToInt();
        stsc.skipBytes(4);
        remainingSamplesPerChunkChanges--;
        if (remainingSamplesPerChunkChanges > 0) {
          nextSamplesPerChunkChangeChunkIndex=stsc.readUnsignedIntToInt() - 1;
        }
      }
      if (chunkIndex < chunkCount) {
        remainingSamplesInChunk=samplesPerChunk;
      }
    }
 else {
      offsetBytes+=sizes[i];
    }
  }
  Assertions.checkArgument(remainingSynchronizationSamples == 0);
  Assertions.checkArgument(remainingSamplesAtTimestampDelta == 0);
  Assertions.checkArgument(remainingSamplesInChunk == 0);
  Assertions.checkArgument(remainingTimestampDeltaChanges == 0);
  Assertions.checkArgument(remainingTimestampOffsetChanges == 0);
  if (track.editListDurations == null) {
    Util.scaleLargeTimestampsInPlace(timestamps,C.MICROS_PER_SECOND,track.timescale);
    return new TrackSampleTable(offsets,sizes,maximumSize,timestamps,flags);
  }
  if (track.editListDurations.length == 1 && track.editListDurations[0] == 0) {
    for (int i=0; i < timestamps.length; i++) {
      timestamps[i]=Util.scaleLargeTimestamp(timestamps[i] - track.editListMediaTimes[0],C.MICROS_PER_SECOND,track.timescale);
    }
    return new TrackSampleTable(offsets,sizes,maximumSize,timestamps,flags);
  }
  int editedSampleCount=0;
  int nextSampleIndex=0;
  boolean copyMetadata=false;
  for (int i=0; i < track.editListDurations.length; i++) {
    long mediaTime=track.editListMediaTimes[i];
    if (mediaTime != -1) {
      long duration=Util.scaleLargeTimestamp(track.editListDurations[i],track.timescale,track.movieTimescale);
      int startIndex=Util.binarySearchCeil(timestamps,mediaTime,true,true);
      int endIndex=Util.binarySearchCeil(timestamps,mediaTime + duration,true,false);
      editedSampleCount+=endIndex - startIndex;
      copyMetadata|=nextSampleIndex != startIndex;
      nextSampleIndex=endIndex;
    }
  }
  copyMetadata|=editedSampleCount != sampleCount;
  long[] editedOffsets=copyMetadata ? new long[editedSampleCount] : offsets;
  int[] editedSizes=copyMetadata ? new int[editedSampleCount] : sizes;
  int editedMaximumSize=copyMetadata ? 0 : maximumSize;
  int[] editedFlags=copyMetadata ? new int[editedSampleCount] : flags;
  long[] editedTimestamps=new long[editedSampleCount];
  long pts=0;
  int sampleIndex=0;
  for (int i=0; i < track.editListDurations.length; i++) {
    long mediaTime=track.editListMediaTimes[i];
    long duration=track.editListDurations[i];
    if (mediaTime != -1) {
      long endMediaTime=mediaTime + Util.scaleLargeTimestamp(duration,track.timescale,track.movieTimescale);
      int startIndex=Util.binarySearchCeil(timestamps,mediaTime,true,true);
      int endIndex=Util.binarySearchCeil(timestamps,endMediaTime,true,false);
      if (copyMetadata) {
        int count=endIndex - startIndex;
        System.arraycopy(offsets,startIndex,editedOffsets,sampleIndex,count);
        System.arraycopy(sizes,startIndex,editedSizes,sampleIndex,count);
        System.arraycopy(flags,startIndex,editedFlags,sampleIndex,count);
      }
      for (int j=startIndex; j < endIndex; j++) {
        long ptsUs=Util.scaleLargeTimestamp(pts,C.MICROS_PER_SECOND,track.movieTimescale);
        long timeInSegmentUs=Util.scaleLargeTimestamp(timestamps[j] - mediaTime,C.MICROS_PER_SECOND,track.timescale);
        editedTimestamps[sampleIndex]=ptsUs + timeInSegmentUs;
        if (copyMetadata && editedSizes[sampleIndex] > editedMaximumSize) {
          editedMaximumSize=sizes[j];
        }
        sampleIndex++;
      }
    }
    pts+=duration;
  }
  boolean hasSyncSample=false;
  for (int i=0; i < editedFlags.length && !hasSyncSample; i++) {
    hasSyncSample|=(editedFlags[i] & C.SAMPLE_FLAG_SYNC) != 0;
  }
  if (!hasSyncSample) {
    throw new ParserException("String_Node_Str");
  }
  return new TrackSampleTable(editedOffsets,editedSizes,editedMaximumSize,editedTimestamps,editedFlags);
}