From 11b5a1395d02290b49d3fa937a66bccfdd95f8a0 Mon Sep 17 00:00:00 2001 From: "nor..67" Date: Thu, 17 Nov 2011 02:17:35 +0000 Subject: [PATCH] - make timer of VideoRecorderAppState actually throttle fps if actual fps is greater than target fps, threaded file writing git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@8709 75d07b2b-3a1a-0410-a2c5-0572b91ccdca --- .../jme3/app/state/VideoRecorderAppState.java | 65 ++++++++++++++++--- 1 file changed, 56 insertions(+), 9 deletions(-) diff --git a/engine/src/desktop/com/jme3/app/state/VideoRecorderAppState.java b/engine/src/desktop/com/jme3/app/state/VideoRecorderAppState.java index e35adddd3..7b7f35318 100644 --- a/engine/src/desktop/com/jme3/app/state/VideoRecorderAppState.java +++ b/engine/src/desktop/com/jme3/app/state/VideoRecorderAppState.java @@ -14,6 +14,12 @@ import java.awt.image.BufferedImage; import java.io.*; import java.nio.ByteBuffer; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ThreadFactory; import java.util.logging.Level; import java.util.logging.Logger; @@ -28,9 +34,20 @@ public class VideoRecorderAppState extends AbstractAppState { private MjpegFileWriter writer; private File file; private Application app; + private ExecutorService executor; + private Future fut; public VideoRecorderAppState(File file) { this.file = file; + executor = Executors.newSingleThreadExecutor(new ThreadFactory() { + + public Thread newThread(Runnable r) { + Thread th = new Thread(r); + th.setName("jME Video processing Thread"); + th.setDaemon(true); + return th; + } + }); } public File getFile() { @@ -40,7 +57,7 @@ public class VideoRecorderAppState extends AbstractAppState { public void setFile(File file) { this.file = file; } - + @Override public void initialize(AppStateManager stateManager, Application app) { super.initialize(stateManager, app); @@ -99,19 +116,39 @@ public class VideoRecorderAppState extends AbstractAppState { } public void postFrame(FrameBuffer out) { + try { + if (fut != null) { + fut.get(); + } + fut = null; + } catch (InterruptedException ex) { + } catch (ExecutionException ex) { + } byteBuffer.clear(); renderManager.getRenderer().readFrameBuffer(out, byteBuffer); - synchronized (rawFrame) { - Screenshots.convertScreenShot(byteBuffer, rawFrame); - try { - writer.addImage(rawFrame); - } catch (Exception ex) { - Logger.getLogger(VideoRecorderAppState.class.getName()).log(Level.SEVERE, "Error writing frame: {0}", ex); + fut = executor.submit(new Callable() { + + public Void call() throws Exception { + Screenshots.convertScreenShot(byteBuffer, rawFrame); + try { + writer.addImage(rawFrame); + } catch (Exception ex) { + Logger.getLogger(VideoRecorderAppState.class.getName()).log(Level.SEVERE, "Error writing frame: {0}", ex); + } + return null; } - } + }); } public void cleanup() { + try { + if (fut != null) { + fut.get(); + fut = null; + } + } catch (InterruptedException ex) { + } catch (ExecutionException ex) { + } app.setTimer(new NanoTimer()); try { writer.finishAVI(); @@ -125,6 +162,7 @@ public class VideoRecorderAppState extends AbstractAppState { private float framerate; private int ticks; + private long lastTime = 0; public IsoTimer(float framerate) { this.framerate = framerate; @@ -132,7 +170,7 @@ public class VideoRecorderAppState extends AbstractAppState { } public long getTime() { - return (long) (this.ticks * (1.0f / this.framerate)); + return (long) (this.ticks * (1.0f / this.framerate) * 1000f); } public long getResolution() { @@ -148,6 +186,15 @@ public class VideoRecorderAppState extends AbstractAppState { } public void update() { + long time = System.currentTimeMillis(); + long difference = time - lastTime; + lastTime = time; + if (difference < (1.0f / this.framerate) * 1000.0f) { + try { + Thread.sleep(difference); + } catch (InterruptedException ex) { + } + } this.ticks++; }