rlm@3: package com.aurellem.capture; rlm@3: rlm@3: import java.awt.image.BufferedImage; rlm@3: import java.io.File; rlm@3: import java.io.IOException; rlm@3: import java.nio.ByteBuffer; rlm@3: rlm@3: import com.jme3.app.Application; rlm@3: import com.jme3.app.state.AppState; rlm@3: import com.jme3.app.state.AppStateManager; rlm@3: import com.jme3.post.SceneProcessor; rlm@3: import com.jme3.renderer.Camera; rlm@3: import com.jme3.renderer.RenderManager; rlm@3: import com.jme3.renderer.ViewPort; rlm@3: import com.jme3.renderer.queue.RenderQueue; rlm@3: import com.jme3.texture.FrameBuffer; rlm@3: import com.jme3.util.BufferUtils; rlm@3: import com.jme3.util.Screenshots; rlm@3: rlm@3: /** rlm@3: * VideoProcessor copies the frames it receives to video. rlm@3: * To ensure smooth video at a constant framerate, you should set your rlm@3: * application's timer to a new {@link IsoTimer}. This class will rlm@3: * auto-determine the framerate of the video based on the time difference rlm@3: * between the first two frames it receives, although you can manually set rlm@3: * the framerate by calling setFps(newFramerate). Be sure to rlm@3: * place this processor *after* any other processors whose effects you want rlm@3: * to be included in the output video. You can attach multiple rlm@3: * VideoProcessors to the same ViewPort. rlm@3: * rlm@3: * For example, rlm@3: * rlm@3: * someViewPort.addProcessor(new VideoProcessor(file1)); rlm@3: * someViewPort.addProcessor(someShadowRenderer); rlm@3: * someViewPort.addProcessor(new VideoProcessor(file2)); rlm@3: * rlm@3: * rlm@3: * will output a video without shadows to file1 and a video rlm@3: * with shadows to file2 rlm@3: * rlm@3: * @author Robert McIntyre rlm@3: * rlm@3: */ rlm@3: rlm@3: public abstract class AbstractVideoRecorder rlm@3: implements SceneProcessor, IVideoRecorder, AppState{ rlm@3: rlm@3: final File output; rlm@3: Camera camera; rlm@3: int width; rlm@3: int height; rlm@3: String targetFileName; rlm@3: FrameBuffer frameBuffer; rlm@3: Double fps = null; rlm@3: RenderManager renderManager; rlm@3: ByteBuffer byteBuffer; rlm@3: BufferedImage rawFrame; rlm@3: boolean isInitilized = false; rlm@3: boolean paused = false; rlm@3: rlm@3: public AbstractVideoRecorder(File output) throws IOException { rlm@3: this.output = output; rlm@3: this.targetFileName = this.output.getCanonicalPath(); rlm@3: } rlm@3: rlm@3: rlm@3: public double getFps() {return this.fps;} rlm@3: rlm@3: public AbstractVideoRecorder setFps(double fps) { rlm@3: this.fps = fps; rlm@3: return this; rlm@3: } rlm@3: rlm@3: public void initialize(RenderManager rm, ViewPort viewPort) { rlm@3: Camera camera = viewPort.getCamera(); rlm@3: this.width = camera.getWidth(); rlm@3: this.height = camera.getHeight(); rlm@3: rlm@3: rawFrame = new BufferedImage(width, height, rlm@3: BufferedImage.TYPE_4BYTE_ABGR); rlm@3: byteBuffer = BufferUtils.createByteBuffer(width * height * 4 ); rlm@3: this.renderManager = rm; rlm@3: this.isInitilized = true; rlm@3: } rlm@3: rlm@3: public void reshape(ViewPort vp, int w, int h) {} rlm@3: rlm@3: public boolean isInitialized() {return this.isInitilized;} rlm@3: rlm@3: public void preFrame(float tpf) { rlm@3: if (null == this.fps){ rlm@3: this.setFps(1.0 / tpf);} rlm@3: } rlm@3: rlm@3: public void postQueue(RenderQueue rq) {} rlm@3: rlm@3: public void postFrame(FrameBuffer out) { rlm@3: if (!this.paused){ rlm@3: byteBuffer.clear(); rlm@3: renderManager.getRenderer().readFrameBuffer(out, byteBuffer); rlm@3: Screenshots.convertScreenShot(byteBuffer, rawFrame); rlm@3: record(rawFrame); rlm@3: } rlm@3: } rlm@3: rlm@3: public void cleanup(){ rlm@3: this.pause(); rlm@3: this.finish(); rlm@3: }; rlm@3: rlm@3: public void pause(){ rlm@3: this.paused = true; rlm@3: } rlm@3: rlm@3: public void start(){ rlm@3: this.paused = false; rlm@3: } rlm@3: rlm@3: // methods from AppState rlm@3: public void initialize(AppStateManager stateManager, Application app) {} rlm@3: rlm@3: public void setEnabled(boolean active) { rlm@3: if (active) {this.start();} rlm@3: else {this.pause();} rlm@3: } rlm@3: rlm@3: public boolean isEnabled() { rlm@3: return this.paused; rlm@3: } rlm@3: rlm@3: public void stateAttached(AppStateManager stateManager) {} rlm@3: rlm@3: rlm@3: public void stateDetached(AppStateManager stateManager) { rlm@3: this.pause(); rlm@3: this.finish(); rlm@3: } rlm@3: rlm@3: public void update(float tpf) {} rlm@3: public void render(RenderManager rm) {} rlm@3: public void postRender() {} rlm@3: rlm@3: }