private void parseHeader() throws IOException {
    LOGGER.trace("Parsing AVI stream");
    String id = getString(stream, 4);
    getBytes(stream, 4);
    String type = getString(stream, 4);

    if (!"RIFF".equalsIgnoreCase(id) || !"AVI ".equalsIgnoreCase(type)) {
      throw new IOException("Not AVI file");
    }

    byte[] hdrl = null;

    while (true) {
      String command = getString(stream, 4);
      int length = (readBytes(stream, 4) + 1) & ~1;

      if ("LIST".equalsIgnoreCase(command)) {
        command = getString(stream, 4);
        length -= 4;

        if ("movi".equalsIgnoreCase(command)) {
          break;
        }

        if ("hdrl".equalsIgnoreCase(command)) {
          hdrl = getBytes(stream, length);
        }

        if ("idx1".equalsIgnoreCase(command)) {
          /*idx = */ getBytes(stream, length);
        }

        if ("iddx".equalsIgnoreCase(command)) {
          /*idx = */ getBytes(stream, length);
        }
      } else {
        getBytes(stream, length);
      }
    }

    int streamNumber = 0;
    int lastTagID = 0;

    for (int i = 0; i < hdrl.length; ) {
      String command = new String(hdrl, i, 4);
      int size = str2ulong(hdrl, i + 4);

      if ("LIST".equalsIgnoreCase(command)) {
        i += 12;
        continue;
      }

      String command2 = new String(hdrl, i + 8, 4);

      if ("strh".equalsIgnoreCase(command)) {
        lastTagID = 0;

        if ("vids".equalsIgnoreCase(command2)) {
          String compressor = new String(hdrl, i + 12, 4);
          int scale = str2ulong(hdrl, i + 28);
          int rate = str2ulong(hdrl, i + 32);
          track[0] = new Track(compressor, scale, rate, -1);
          streamVideoTag =
              new String(
                  new char[] {
                    (char) ((streamNumber / 10) + '0'), (char) ((streamNumber % 10) + '0'), 'd', 'b'
                  });
          streamNumber++;
          lastTagID = 1;
        }

        if ("auds".equalsIgnoreCase(command2)) {
          int scale = str2ulong(hdrl, i + 28);
          int rate = str2ulong(hdrl, i + 32);
          int sampleSize = str2ulong(hdrl, i + 52);
          track[1 + numberOfAudioChannels++] = new Track(null, scale, rate, sampleSize);

          streamNumber++;
          lastTagID = 2;
        }
      }

      if ("strf".equalsIgnoreCase(command)) {
        if (lastTagID == 1) {

          byte[] information = new byte[size]; // formerly size-4
          System.arraycopy(hdrl, i + 8, information, 0, information.length); // formerly i+4
          track[0].setBih(information);
        }

        if (lastTagID == 2) {
          byte[] information = new byte[size]; // formerly size-4
          System.arraycopy(hdrl, i + 8, information, 0, information.length); // formerly i+4
          Track aud = track[1 + numberOfAudioChannels - 1];
          aud.setBih(information);
          int bitsPerSample = str2ushort(information, 14);
          aud.setBitsPerSample(bitsPerSample);
          int nbAudio = str2ushort(information, 2);
          aud.setNbAudio(nbAudio);
          long fileLength = 100;

          if (params.losslessaudio) {
            aOut = new PCMAudioOutputStream(aOut, nbAudio, 48000, bitsPerSample);
          }

          if (!params.lossyaudio && params.losslessaudio) {
            writePCMHeader(
                aOut, fileLength, nbAudio, aud.getRate(), aud.getSampleSize(), bitsPerSample);
          }
        }
      }

      if (size % 2 != 0) {
        size++;
      }

      i += size + 8;
    }

    LOGGER.trace("Found " + streamNumber + " stream(s)");
    boolean init = false;

    while (true) {
      String command;

      try {
        command = getString(stream, 4);
      } catch (Exception e) {
        LOGGER.trace("Error reading stream: " + e.getMessage());
        break;
      }

      if (command == null) {
        break;
      }

      command = command.toUpperCase();
      int size = readBytes(stream, 4);
      boolean framed = false;

      while ("LIST".equals(command) || "RIFF".equals(command) || "JUNK".equals(command)) {
        if (size < 0) {
          size = 4;
        }

        getBytes(stream, "RIFF".equals(command) ? 4 : size);
        command = getString(stream, 4).toUpperCase();
        size = readBytes(stream, 4);

        if (("LIST".equals(command) || "RIFF".equals(command) || "JUNK".equals(command))
            && (size % 2 != 0)) {
          readByte(stream);
        }
      }

      String videoTag = streamVideoTag.substring(0, 3);

      if (command.substring(0, 3).equalsIgnoreCase(videoTag)
          && (command.charAt(3) == 'B' || command.charAt(3) == 'C')) {
        byte[] buffer = getBytes(stream, size);

        if (!command.equalsIgnoreCase("IDX1")) {
          vOut.write(buffer);
          videosize += size;
        }

        framed = true;
      }

      if (!framed) {
        for (int i = 0; i < numberOfAudioChannels; i++) {
          byte[] buffer = getBytes(stream, size);

          if (!command.equalsIgnoreCase("IDX1")) {
            aOut.write(buffer, init ? 4 : 0, init ? (size - 4) : size);
            init = false;
            audiosize += size;
          }

          framed = true;
        }
      }

      if (!framed) {
        throw new IOException("Not header: " + command);
      }

      if (size % 2 != 0) {
        readByte(stream);
      }
    }

    LOGGER.trace("output pipes closed");
    aOut.close();
    vOut.close();
  }