/** @param args the command line arguments */
  public static void main(String[] args) throws IOException {
    final ArrayList<BufferedImage> frames = new ArrayList<BufferedImage>();
    final File f =
        new File(
            "/Users/Shared/Developer/Java/MonteMedia/current/trunk/MonteMedia/avidemo-tscc8.avi");
    MovieReader in = Registry.getInstance().getReader(f);
    try {
      Format format =
          new Format(VideoFormatKeys.EncodingKey, VideoFormatKeys.ENCODING_BUFFERED_IMAGE);
      int track = in.findTrack(0, new Format(FormatKeys.MediaTypeKey, MediaType.VIDEO));
      if (track == -1) {
        throw new IOException("Movie has no video track.");
      }
      Codec codec = Registry.getInstance().getCodec(in.getFormat(track), format);
      if (codec == null) {
        throw new IOException("Can not decode video track.");
      }
      Buffer inBuf = new Buffer();
      Buffer codecBuf = new Buffer();
      do {
        in.read(track, inBuf);
        if (codec.process(inBuf, codecBuf) == Codec.CODEC_FAILED) {
          System.out.println("Can not decode buffer " + inBuf);
        }
        if (!codecBuf.isFlag(BufferFlag.DISCARD)) {
          frames.add(Images.cloneImage((BufferedImage) codecBuf.data));
        }
      } while (!inBuf.isFlag(BufferFlag.END_OF_MEDIA));
    } finally {
      in.close();
    }

    SwingUtilities.invokeLater(
        new Runnable() {
          @Override
          public void run() {
            JFrame fr = new JFrame(f.getName());
            fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            final JLabel label = new JLabel(new ImageIcon(frames.get(0)));
            final JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, frames.size() - 1, 0);

            slider.addChangeListener(
                new ChangeListener() {

                  @Override
                  public void stateChanged(ChangeEvent e) {
                    label.setIcon(new ImageIcon(frames.get(slider.getValue())));
                  }
                });

            fr.add(BorderLayout.CENTER, label);
            fr.add(BorderLayout.SOUTH, slider);
            fr.pack();
            fr.setVisible(true);
          }
        });
  }
 @Override
 public void read(Buffer buf) {
   if (position < demux.getFrameCount()) {
     buf.setFlagsTo(KEYFRAME);
     if (!(buf.data instanceof BitmapImage)) {
       buf.data = demux.createCompatibleBitmap();
     }
     demux.readFrame((int) position, (BitmapImage) buf.data);
     buf.sampleDuration = new Rational(demux.getDuration((int) position), demux.getJiffies());
     position++;
   } else {
     buf.setFlagsTo(DISCARD);
   }
 }
  @Override
  public void write(int track, Buffer buf) throws IOException {
    VideoTrack t = tracks.get(track);
    if (buf.isFlag(DISCARD)) {
      return;
    }

    File file = new File(t.dir, String.format(t.nameFormat, t.count + 1));

    if (buf.data instanceof byte[]) {
      FileOutputStream out = new FileOutputStream(file);
      try {
        out.write((byte[]) buf.data, buf.offset, buf.length);
      } finally {
        out.close();
      }
    } else if (buf.data instanceof File) {
      FileInputStream in = new FileInputStream((File) buf.data);
      try {
        FileOutputStream out = new FileOutputStream(file);
        try {
          byte[] b = new byte[2048];
          int len;
          while ((len = in.read(b)) != -1) {
            out.write(b, 0, len);
          }
        } finally {
          out.close();
        }
      } finally {
        in.close();
      }
    } else {
      throw new IllegalArgumentException("Can't process buffer data:" + buf.data);
    }

    t.count++;
  }
  public int process(Buffer in, Buffer out) {
    out.setMetaTo(in);
    if (in.isFlag(DISCARD)) {
      return CODEC_OK;
    }
    out.format = outputFormat;

    SeekableByteArrayOutputStream tmp;
    if (out.data instanceof byte[]) {
      tmp = new SeekableByteArrayOutputStream((byte[]) out.data);
    } else {
      tmp = new SeekableByteArrayOutputStream();
    }
    Format vf = outputFormat;

    // Handle sub-image
    Rectangle r;
    int scanlineStride;
    if (in.data instanceof BufferedImage) {
      BufferedImage image = (BufferedImage) in.data;
      WritableRaster raster = image.getRaster();
      scanlineStride = raster.getSampleModel().getWidth();
      r = raster.getBounds();
      r.x -= raster.getSampleModelTranslateX();
      r.y -= raster.getSampleModelTranslateY();
    } else {
      r = new Rectangle(0, 0, vf.get(WidthKey), vf.get(HeightKey));
      scanlineStride = vf.get(WidthKey);
    }

    try {
      switch (vf.get(DepthKey)) {
        case 8:
          {
            writeKey8(
                tmp,
                getIndexed8(in),
                r.width,
                r.height,
                r.x + r.y * scanlineStride,
                scanlineStride);
            break;
          }
        case 16:
          {
            writeKey16(
                tmp, getRGB15(in), r.width, r.height, r.x + r.y * scanlineStride, scanlineStride);
            break;
          }
        case 24:
          {
            writeKey24(
                tmp, getRGB24(in), r.width, r.height, r.x + r.y * scanlineStride, scanlineStride);
            break;
          }
        case 32:
          {
            writeKey24(
                tmp, getARGB32(in), r.width, r.height, r.x + r.y * scanlineStride, scanlineStride);
            break;
          }
        default:
          {
            out.setFlag(DISCARD);
            return CODEC_FAILED;
          }
      }

      out.format = outputFormat;
      out.sampleCount = 1;
      out.setFlag(KEYFRAME);
      out.data = tmp.getBuffer();
      out.offset = 0;
      out.length = (int) tmp.getStreamPosition();
      return CODEC_OK;
    } catch (IOException ex) {
      ex.printStackTrace();
      out.setFlag(DISCARD);
      return CODEC_FAILED;
    }
  }