package fr.unistra.pelican.algorithms.io; import java.awt.image.BufferedImage; import java.io.File; import com.xuggle.mediatool.IMediaReader; import com.xuggle.mediatool.MediaListenerAdapter; import com.xuggle.mediatool.ToolFactory; import com.xuggle.mediatool.event.IVideoPictureEvent; import com.xuggle.xuggler.IContainer; import com.xuggle.xuggler.IStream; import com.xuggle.xuggler.IStreamCoder; import com.xuggle.xuggler.ICodec; import fr.unistra.pelican.Algorithm; import fr.unistra.pelican.AlgorithmException; import fr.unistra.pelican.ByteImage; import fr.unistra.pelican.Image; import fr.unistra.pelican.PelicanException; import fr.unistra.pelican.algorithms.io.ImageLoader; import fr.unistra.pelican.algorithms.visualisation.ViewerVideo; /** * Video loader using Xuggle library * It load the whole video uncompressed, it isn't memory-wise. * * Possibility to reduce frame number by selecting one frame every ratio frames. * * You can also select first frame and last frame * * TODO : Improves efficiency of loading. Too slow for now. * TODO : Deal with timestamp ? * * @author Jonathan Weber */ public class VideoLoader extends Algorithm { /** * Input image. */ public String filename; /** * Output image. */ public ByteImage outputImage; //optional parameters /** * Ratio of frames */ public Integer ratio = 1; /** * Beginning of the selection */ public Integer firstFrame = 0; /** * End of the selection */ public Integer lastFrame = null; /** * Constructor * */ public VideoLoader() { super(); super.inputs = "filename"; super.options= "ratio,firstFrame,lastFrame"; super.outputs = "outputImage"; } /* * (non-Javadoc) * * @see fr.unistra.pelican.Algorithm#launch() */ public void launch() throws AlgorithmException { long t= System.currentTimeMillis(); // Get info about the video (size and # of frames) IContainer container = IContainer.make(); if (container.open(filename, IContainer.Type.READ, null) < 0) throw new PelicanException("Could not open file: " + filename); int numStreams = container.getNumStreams(); int xDim=-1; int yDim=-1; int tDim=-1; for(int i = 0; i < numStreams; i++) { IStream stream = container.getStream(i); IStreamCoder coder = stream.getStreamCoder(); if (coder.getCodecType() == ICodec.Type.CODEC_TYPE_VIDEO) { xDim = coder.getWidth(); yDim = coder.getHeight(); tDim = (int) stream.getNumFrames(); System.out.println(new File(filename).getName()+" => Height: "+yDim+" | Width: "+xDim+" | # Frames: "+tDim+" || "+(xDim*yDim*tDim)+" pixels => "+(xDim*yDim*tDim*3)+" bytes"); if(lastFrame==null) lastFrame=tDim-1; if(ratio!=1||firstFrame!=0||lastFrame!=tDim-1) System.out.println("With ratio="+ratio+";firstFrame="+firstFrame+";lastFrame="+lastFrame+" => # Frames: "+(((lastFrame-firstFrame+1)/ratio)+1)+" || "+(xDim*yDim*(((lastFrame-firstFrame+1)/ratio)+1))+" pixels => "+(xDim*yDim*(((lastFrame-firstFrame+1)/ratio)+1)*3)+" bytes"); break; } } // Instantiate video output outputImage = new ByteImage(xDim,yDim, 1, ((lastFrame-firstFrame+1)/ratio)+1,3); // Read video and write it to outputImage via the listener IMediaReader reader = ToolFactory.makeReader(filename); reader.setBufferedImageTypeToGenerate(BufferedImage.TYPE_3BYTE_BGR); reader.addListener(new VideoListener()); // Read the video file while (reader.readPacket() == null) do {} while(false); outputImage.setColor(true); System.out.println("Loaded in "+(System.currentTimeMillis()-t)+" ms."); } private class VideoListener extends MediaListenerAdapter { int currentOutputFrame=0; int currentInputFrame=0; public VideoListener() { currentInputFrame = firstFrame.intValue(); } public void onVideoPicture(IVideoPictureEvent event) { if(currentInputFrame>=firstFrame&¤tInputFrame<=lastFrame&&(currentInputFrame-firstFrame)%ratio==0) { Image tmp = ImageLoader.convertFromJAI(event.getImage(),false); outputImage.setImage4D(tmp, currentOutputFrame, Image.T); currentOutputFrame++; } currentInputFrame++; } } /** * Experimental video loader. * * @param filename * Directory of the video * @return the loaded video */ public static ByteImage exec(String filename) { return (ByteImage) new VideoLoader().process(filename); } /** * Experimental video loader. * * @param filename * Directory of the video * @param ratio * number of frames divided by the number of selected frames * @return the loaded video */ public static ByteImage exec(String filename,Integer ratio) { return (ByteImage) new VideoLoader().process(filename,ratio); } /** * Experimental video loader. * * @param filename * Directory of the video * @param ratio * number of frames divided by the number of selected frames * @param firstFrame * number of the first frame which will be selected * @return the loaded video */ public static ByteImage exec(String filename,Integer ratio,Integer firstFrame) { return (ByteImage) new VideoLoader().process(filename,ratio,firstFrame); } /** * Experimental video loader. * * @param filename * Directory of the video * @param ratio * number of frames divided by the number of selected frames * @param firstFrame * number of the first frame which will be selected * @param lastFrame * number of the last frame of the selection * @return the loaded video */ public static ByteImage exec(String filename,Integer ratio,Integer firstFrame,Integer lastFrame) { return (ByteImage) new VideoLoader().process(filename,ratio,firstFrame,lastFrame); } }