Browse Source

- 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
nor..67 14 years ago
parent
commit
11b5a1395d
1 changed files with 56 additions and 9 deletions
  1. 56 9
      engine/src/desktop/com/jme3/app/state/VideoRecorderAppState.java

+ 56 - 9
engine/src/desktop/com/jme3/app/state/VideoRecorderAppState.java

@@ -14,6 +14,12 @@ import java.awt.image.BufferedImage;
 import java.io.*;
 import java.io.*;
 import java.nio.ByteBuffer;
 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.Level;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
 
 
@@ -28,9 +34,20 @@ public class VideoRecorderAppState extends AbstractAppState {
     private MjpegFileWriter writer;
     private MjpegFileWriter writer;
     private File file;
     private File file;
     private Application app;
     private Application app;
+    private ExecutorService executor;
+    private Future fut;
 
 
     public VideoRecorderAppState(File file) {
     public VideoRecorderAppState(File file) {
         this.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() {
     public File getFile() {
@@ -40,7 +57,7 @@ public class VideoRecorderAppState extends AbstractAppState {
     public void setFile(File file) {
     public void setFile(File file) {
         this.file = file;
         this.file = file;
     }
     }
-    
+
     @Override
     @Override
     public void initialize(AppStateManager stateManager, Application app) {
     public void initialize(AppStateManager stateManager, Application app) {
         super.initialize(stateManager, app);
         super.initialize(stateManager, app);
@@ -99,19 +116,39 @@ public class VideoRecorderAppState extends AbstractAppState {
         }
         }
 
 
         public void postFrame(FrameBuffer out) {
         public void postFrame(FrameBuffer out) {
+            try {
+                if (fut != null) {
+                    fut.get();
+                }
+                fut = null;
+            } catch (InterruptedException ex) {
+            } catch (ExecutionException ex) {
+            }
             byteBuffer.clear();
             byteBuffer.clear();
             renderManager.getRenderer().readFrameBuffer(out, byteBuffer);
             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<Void>() {
+
+                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() {
         public void cleanup() {
+            try {
+                if (fut != null) {
+                    fut.get();
+                    fut = null;
+                }
+            } catch (InterruptedException ex) {
+            } catch (ExecutionException ex) {
+            }
             app.setTimer(new NanoTimer());
             app.setTimer(new NanoTimer());
             try {
             try {
                 writer.finishAVI();
                 writer.finishAVI();
@@ -125,6 +162,7 @@ public class VideoRecorderAppState extends AbstractAppState {
 
 
         private float framerate;
         private float framerate;
         private int ticks;
         private int ticks;
+        private long lastTime = 0;
 
 
         public IsoTimer(float framerate) {
         public IsoTimer(float framerate) {
             this.framerate = framerate;
             this.framerate = framerate;
@@ -132,7 +170,7 @@ public class VideoRecorderAppState extends AbstractAppState {
         }
         }
 
 
         public long getTime() {
         public long getTime() {
-            return (long) (this.ticks * (1.0f / this.framerate));
+            return (long) (this.ticks * (1.0f / this.framerate) * 1000f);
         }
         }
 
 
         public long getResolution() {
         public long getResolution() {
@@ -148,6 +186,15 @@ public class VideoRecorderAppState extends AbstractAppState {
         }
         }
 
 
         public void update() {
         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++;
             this.ticks++;
         }
         }