|
|
|
@ -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<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() { |
|
|
|
|
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++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|