private void parse(InputStream fin) throws IOException {
    inputStream = fin;
    bitRateAndFrameSizeTable = new int[19][2][3][2];
    stts = new LinkedList<TimeToSampleBox.Entry>();
    initBitRateAndFrameSizeTable();
    if (!readVariables()) {
      throw new IOException();
    }

    sampleDescriptionBox = new SampleDescriptionBox();
    AudioSampleEntry audioSampleEntry = new AudioSampleEntry("ac-3");
    audioSampleEntry.setChannelCount(2); // According to  ETSI TS 102 366 Annex F
    audioSampleEntry.setSampleRate(samplerate);
    audioSampleEntry.setDataReferenceIndex(1);
    audioSampleEntry.setSampleSize(16);

    AC3SpecificBox ac3 = new AC3SpecificBox();
    ac3.setAcmod(acmod);
    ac3.setBitRateCode(frmsizecod >> 1);
    ac3.setBsid(bsid);
    ac3.setBsmod(bsmod);
    ac3.setFscod(fscod);
    ac3.setLfeon(lfeon);
    ac3.setReserved(0);

    audioSampleEntry.addBox(ac3);
    sampleDescriptionBox.addBox(audioSampleEntry);

    trackMetaData.setCreationTime(new Date());
    trackMetaData.setModificationTime(new Date());
    trackMetaData.setLanguage(lang);
    trackMetaData.setTimescale(samplerate); // Audio tracks always use samplerate as timescale

    samples = new LinkedList<ByteBuffer>();
    if (!readSamples()) {
      throw new IOException();
    }
  }
  /**
   * Gets an array of sample numbers that are meant to be the first sample of each chunk or
   * fragment.
   *
   * @param track concerned track
   * @param movie the context of the track
   * @return an array containing the ordinal of each fragment's first sample
   */
  public long[] sampleNumbers(Track track, Movie movie) {
    if ("vide".equals(track.getHandler())) {
      if (track.getSyncSamples() != null && track.getSyncSamples().length > 0) {
        List<long[]> times = getSyncSamplesTimestamps(movie, track);
        return getCommonIndices(
            track.getSyncSamples(),
            getTimes(movie, track),
            times.toArray(new long[times.size()][]));
      } else {
        throw new RuntimeException(
            "Video Tracks need sync samples. Only tracks other than video may have no sync samples.");
      }
    } else if ("soun".equals(track.getHandler())) {
      Track referenceTrack = null;
      for (Track candidate : movie.getTracks()) {
        if (candidate.getSyncSamples() != null
            && "vide".equals(candidate.getHandler())
            && candidate.getSyncSamples().length > 0) {
          referenceTrack = candidate;
        }
      }
      if (referenceTrack != null) {

        // Gets the reference track's fra
        long[] refSyncSamples = sampleNumbers(referenceTrack, movie);

        int refSampleCount = referenceTrack.getSamples().size();

        long[] syncSamples = new long[refSyncSamples.length];
        long minSampleRate = 192000;
        for (Track testTrack : movie.getTracks()) {
          if ("soun".equals(testTrack.getHandler())) {
            AudioSampleEntry ase =
                (AudioSampleEntry) testTrack.getSampleDescriptionBox().getSampleEntry();
            if (ase.getSampleRate() < minSampleRate) {
              minSampleRate = ase.getSampleRate();
              long sc = testTrack.getSamples().size();
              double stretch = (double) sc / refSampleCount;

              for (int i = 0; i < syncSamples.length; i++) {
                int start = (int) Math.ceil(stretch * (refSyncSamples[i] - 1)) + 1;
                syncSamples[i] = start;
                // The Stretch makes sure that there are as much audio and video chunks!
              }
            }
          }
        }
        AudioSampleEntry ase = (AudioSampleEntry) track.getSampleDescriptionBox().getSampleEntry();
        double factor = (double) ase.getSampleRate() / (double) minSampleRate;
        if (factor != Math.rint(factor)) { // Not an integer
          throw new RuntimeException(
              "Sample rates must be a multiple of the lowest sample rate to create a correct file!");
        }
        for (int i = 1; i < syncSamples.length; i++) {
          syncSamples[i] = (int) (1 + (syncSamples[i] - 1) * factor);
        }
        return syncSamples;
      }
      throw new RuntimeException(
          "There was absolutely no Track with sync samples. I can't work with that!");
    } else {
      // Ok, my track has no sync samples - let's find one with sync samples.
      for (Track candidate : movie.getTracks()) {
        if (candidate.getSyncSamples() != null && candidate.getSyncSamples().length > 0) {
          long[] refSyncSamples = sampleNumbers(candidate, movie);
          int refSampleCount = candidate.getSamples().size();

          long[] syncSamples = new long[refSyncSamples.length];
          long sc = track.getSamples().size();
          double stretch = (double) sc / refSampleCount;

          for (int i = 0; i < syncSamples.length; i++) {
            int start = (int) Math.ceil(stretch * (refSyncSamples[i] - 1)) + 1;
            syncSamples[i] = start;
            // The Stretch makes sure that there are as much audio and video chunks!
          }
          return syncSamples;
        }
      }
      throw new RuntimeException(
          "There was absolutely no Track with sync samples. I can't work with that!");
    }
  }