Extrair o n-ésimo frame de um MPEG

Olás,

alguém já conseguiu realizar essa façanha?

Em particular, o seguinte código não funciona.

Se utilizarmos mp.setMediaTime o código funciona parcialmente.

Por exemplo, para frameNumber variando de 1 a 18, obtemos (surpreendentemente?) o 1º frame como resposta. A partir do frame 19 até (37?) obtemos o frame 19 como resposta. Estou esquecendo algo aqui ou o JMF está morto mesmo, cheio de bugs e inutilizável?

package main;

import javax.imageio.ImageIO;
import javax.media.*;
import javax.media.control.FrameGrabbingControl;
import javax.media.control.FramePositioningControl;
import javax.media.control.FrameRateControl;
import javax.media.format.VideoFormat;
import javax.media.util.BufferToImage;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

/**
 * Date: 06/05/2005
 * Time: 16:56:49
 *
 * @author Filipe Silva
 */
public class Main implements ControllerListener {
  private FrameGrabbingControl grabber;
  private FrameRateControl fps;
  private FramePositioningControl fpc;
  private Player mp;
  private BooleanLocker lock;
  private boolean firstTime;

  public Main() {
    try {
      Manager.setHint(Manager.PLUGIN_PLAYER, new Boolean(true));
      mp = Manager.createPlayer(new MediaLocator("file:///vid1.mpg"));
    } catch (NoPlayerException npe) {
      npe.printStackTrace();
    } catch (IOException ioe) {
      ioe.printStackTrace();
    }
    grabber = null;
    fps = null;
    fpc = null;
    lock = new BooleanLocker();
    firstTime = true;
    mp.addControllerListener(this);
    mp.realize();
    mp.prefetch();
  }

  public static void main(String[] args) {
    new Main();
  }

  public void controllerUpdate(ControllerEvent event) {
    if (event instanceof PrefetchCompleteEvent) {
      if (firstTime) {
        if (grabber == null) {
          grabber = (FrameGrabbingControl) mp.getControl("javax.media.control.FrameGrabbingControl");
          if (grabber == null) {
            System.out.println("Num tem grabber");
            System.exit(-1);
          }
        }

        if (fps == null) {
          fps = (FrameRateControl) mp.getControl("javax.media.control.FrameRateControl");
          if (fps == null) {
            System.out.println("num tem fps");
            System.exit(-1);
          }
        }

        if (fpc == null) {
          fpc = (FramePositioningControl) mp.getControl("javax.media.control.FramePositioningControl");
          if (fpc == null) {
            System.out.println("num tem framePositioning");
            System.exit(-1);
          }
        }
        firstTime = false;
        new FrameGrabberThread(grabber, fps, fpc, mp, lock).start();
      } else {
        synchronized (lock) {
          lock.canGrab = true;
        }
      }
    }
  }
}

class BooleanLocker {
  public boolean canGrab;

  public BooleanLocker() {
    canGrab = false;
  }
}

class FrameGrabberThread extends Thread {
  private FrameGrabbingControl grabber;
  private FrameRateControl fps;
  private FramePositioningControl fpc;
  private Player mp;
  private Buffer buffer;
  private VideoFormat vFormat;
  private BufferToImage bToImage;
  private BufferedImage image;
  private BooleanLocker lock;
  private static final long WAIT = 100;

  public FrameGrabberThread(FrameGrabbingControl grabber, FrameRateControl fps, FramePositioningControl fpc, Player mp, BooleanLocker lock) {
    this.grabber = grabber;
    this.fps = fps;
    this.mp = mp;
    this.lock = lock;
    this.fpc = fpc;
  }

  public void run() {
    int frameNumber = 19;

    synchronized (lock) {
      lock.canGrab = false;
    }

    fpc.seek(frameNumber);
    mp.prefetch();

    long t = System.currentTimeMillis();
    synchronized (lock) {
      while (!lock.canGrab && System.currentTimeMillis() < t + WAIT)
        try {
          lock.wait(1);
        } catch (InterruptedException ie) {
          ie.printStackTrace();
        }
      if (System.currentTimeMillis() >= t + WAIT) {
        System.out.println("deadlock ou sei lá ta demorando muito");
        System.exit(-1);
      }
    }

    synchronized (lock) {
      if (!lock.canGrab) {
        System.out.println("O lock não foi locado. Abortando");
        System.exit(-1);
      }
    }

    buffer = grabber.grabFrame();
    vFormat = (VideoFormat) buffer.getFormat();
    bToImage = new BufferToImage(vFormat);
    image = (BufferedImage) bToImage.createImage(buffer);
    File f;

    if (frameNumber < 10)
      f = new File("c:" + File.separator + "teste" + File.separator + "frame0" + frameNumber + ".jpg");
    else
      f = new File("c:" + File.separator + "teste" + File.separator + "frame" + frameNumber + ".jpg");
    try {
      ImageIO.write(image, "jpeg", f);
    } catch (IOException ioe) {
      ioe.printStackTrace();
    }

    mp.close();
  }
}