package fr.unistra.pelican; import java.awt.image.BufferedImage; import java.awt.image.WritableRaster; import java.io.File; import java.io.IOException; import java.io.NotSerializableException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.URL; import java.util.HashMap; import javax.media.Buffer; import javax.media.Duration; import javax.media.Manager; import javax.media.Player; import javax.media.Time; import javax.media.control.FrameGrabbingControl; import javax.media.control.FramePositioningControl; import javax.media.format.VideoFormat; import javax.media.util.BufferToImage; import fr.unistra.pelican.util.largeImages.ByteUnit; import fr.unistra.pelican.util.largeImages.LargeImageInterface; import fr.unistra.pelican.util.largeImages.LargeImageMemoryManager; import fr.unistra.pelican.util.largeImages.LargeImageUtil; import fr.unistra.pelican.util.largeImages.Unit; /** * JMFVideos are used to open and read from videos supported by JMF (yes, such * video exists ...) */ public class JMFVideo extends LargeByteImage implements LargeImageInterface { /** * Serial */ private static final long serialVersionUID = -7585583132719664934L; /** * Player used to read the video */ private transient Player p; /** * BufferedImage to access to the frames of the video */ private transient BufferedImage bim; /** * VideoFormat */ private VideoFormat vf; /** * Frame positioner */ private transient FramePositioningControl fpc; /** * Frame grabber */ private transient FrameGrabbingControl fg; /** * BufferToImage */ private transient BufferToImage bufferToImage; /** * Buffer */ private transient Buffer buf; /** * Number of pixels in each frames */ public int frameSize; /** * Constructs a new JMF Video with the file at the given address. * * @param filename * path to the Video */ public JMFVideo(String filename) { this(filename, 0); } /** * Constructs a new JMF Video with the file at the given address and with * the specified unitSize. * * @param filename * path to the Video * @param unitSize * Max unit size in bytes */ public JMFVideo(String filename, int unitSize) { super(); this.setFile(new File(filename)); int bands; initializePlayer(); // convert the buffer to an image bim = (BufferedImage) bufferToImage.createImage(buf); int width = bim.getWidth(null); int height = bim.getHeight(null); switch (bim.getType()) { case BufferedImage.TYPE_BYTE_GRAY: case BufferedImage.TYPE_USHORT_GRAY: bands = 1; break; case BufferedImage.TYPE_INT_RGB: case BufferedImage.TYPE_INT_BGR: bands = 3; break; default: throw new AlgorithmException("Unsupported pixel organization"); } if (bands == 3) { this.setColor(true); } this.setDim(width, height, 1, this.getTDim(), bands); this.setUnitLength(-1); this.computeUnitSize(unitSize); this.calculate(); } @Override public void calculate() { this.frameSize = this.getXDim() * this.getYDim() * this.getBDim(); this.computeUnitDim(); this.setSize((long) this.getXDim() * (long) this.getYDim() * (long) this.getZDim() * (long) this.getTDim() * (long) this.getBDim()); } @Override public void createFile() { throw new PelicanException("A JMFVideo should not create a file"); } @Override public void setUnit(Unit currentUnit, int currentId, boolean modified) { if (modified) { throw new PelicanException("A JMFVideo should not be modified"); } LargeImageUtil.setUnit(this, currentUnit, currentId, modified); } @Override public ByteUnit loadAnUnit(int id) { if (p == null) { this.initializePlayer(); } ByteUnit currentUnit = new ByteUnit(this.getUnitSize()); if (id >= this.getUnitDim()) { throw new AlgorithmException("there is no " + id + "th unit in this video"); } byte[] newPixels = new byte[this.getUnitSize()]; int firstFrame = (int) ((((long) id) << this.getUnitPowerSize()) / ((long) this.frameSize)); int lastFrame = (int) ((((long) (id + 1)) << this.getUnitPowerSize()) / ((long) this.frameSize)); int nbFrame = lastFrame - firstFrame + 1; int firstPixelInFirstFrame = (int) ((((long) id) << this .getUnitPowerSize()) % ((long) this.frameSize)); int arrayOffset = -firstPixelInFirstFrame; for (int i = 0; i < nbFrame; i++) { fpc.seek(i + firstFrame + 1); buf = fg.grabFrame(); bim = (BufferedImage) bufferToImage.createImage(buf); WritableRaster r = bim.getRaster(); for (int y = 0; y < this.getYDim(); y++) { for (int x = 0; x < this.getXDim(); x++) { for (int b = 0; b < this.getBDim(); b++) { int pos = arrayOffset + b + this.getBDim() * (x + this.getXDim() * (y + this.getYDim() * (i))); if ((pos >= 0) && (pos < newPixels.length)) { newPixels[arrayOffset + b + this.getBDim() * (x + this.getXDim() * (y + this.getYDim() * (i)))] = (byte) ((byte) r .getSample(x, y, b) + Byte.MIN_VALUE); } } } } } currentUnit.setPixels(newPixels); this.setUnit(currentUnit, id, false); return currentUnit; } @Override public void fillFile() { throw new PelicanException("A JMFVideo should not be modified"); } @Override public void close() { p.close(); } @Override public long getUnitLength() { if (this.unitLength == -1) { this.computeUnitLength(); } return this.unitLength; } @Override public String getWorkingFileSuffix() { return ".avi"; } /** * Initialize the player so you can read in the file. */ private void initializePlayer() { p = null; try { URL url = new URL("file:" + this.getFile().getAbsolutePath()); p = Manager.createRealizedPlayer(url); } catch (Exception e) { e.printStackTrace(); } // create a frame positioner fpc = (FramePositioningControl) p .getControl("javax.media.control.FramePositioningControl"); // create a frame grabber fg = (FrameGrabbingControl) p .getControl("javax.media.control.FrameGrabbingControl"); // request that the player changes to a 'prefetched' state p.prefetch(); // wait until the player is in that state... Time duration = p.getDuration(); if (duration != Duration.DURATION_UNKNOWN) { this.setTDim(fpc.mapTimeToFrame(duration)); } else { throw new AlgorithmException("Duration unknown"); } // move to the first frame fpc.seek(1); // take a snap of the current frame buf = fg.grabFrame(); // get its video format details vf = (VideoFormat) buf.getFormat(); // initialize BufferToImage with video format bufferToImage = new BufferToImage(vf); } /** * You already have a copy of the file don't need a new since there was no modifications * @param out * @throws NotSerializableException */ private void writeObject(ObjectOutputStream out) throws NotSerializableException{ throw new NotSerializableException("JMFVideo can not be serialized"); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); this.unitMap = new HashMap<Integer, Unit>(); this.memoryId = LargeImageMemoryManager.getInstance().addImage(this); } }