rlm@9
|
1 package com.aurellem.capture.video;
|
rlm@9
|
2
|
rlm@9
|
3 import java.awt.image.BufferedImage;
|
rlm@9
|
4 import java.io.File;
|
rlm@9
|
5 import java.io.IOException;
|
rlm@9
|
6 import java.nio.ByteBuffer;
|
rlm@9
|
7
|
rlm@9
|
8 import com.aurellem.capture.IsoTimer;
|
rlm@9
|
9 import com.jme3.app.Application;
|
rlm@9
|
10 import com.jme3.app.state.AppState;
|
rlm@9
|
11 import com.jme3.app.state.AppStateManager;
|
rlm@9
|
12 import com.jme3.post.SceneProcessor;
|
rlm@9
|
13 import com.jme3.renderer.Camera;
|
rlm@9
|
14 import com.jme3.renderer.RenderManager;
|
rlm@9
|
15 import com.jme3.renderer.ViewPort;
|
rlm@9
|
16 import com.jme3.renderer.queue.RenderQueue;
|
rlm@9
|
17 import com.jme3.texture.FrameBuffer;
|
rlm@9
|
18 import com.jme3.util.BufferUtils;
|
rlm@9
|
19 import com.jme3.util.Screenshots;
|
rlm@9
|
20
|
rlm@9
|
21 /**
|
rlm@39
|
22 * <code>VideoRecorder</code> copies the frames it receives to video.
|
rlm@9
|
23 * To ensure smooth video at a constant framerate, you should set your
|
rlm@39
|
24 * application's timer to a new <code>IsoTimer</code>. This class will
|
rlm@9
|
25 * auto-determine the framerate of the video based on the time difference
|
rlm@9
|
26 * between the first two frames it receives, although you can manually set
|
rlm@9
|
27 * the framerate by calling <code>setFps(newFramerate)</code>. Be sure to
|
rlm@9
|
28 * place this processor *after* any other processors whose effects you want
|
rlm@9
|
29 * to be included in the output video. You can attach multiple
|
rlm@9
|
30 * <code>VideoProcessor</code>s to the same <code>ViewPort</code>.
|
rlm@9
|
31 *
|
rlm@9
|
32 * For example,
|
rlm@9
|
33 * <code>
|
rlm@9
|
34 * someViewPort.addProcessor(new VideoProcessor(file1));
|
rlm@9
|
35 * someViewPort.addProcessor(someShadowRenderer);
|
rlm@9
|
36 * someViewPort.addProcessor(new VideoProcessor(file2));
|
rlm@9
|
37 * </code>
|
rlm@9
|
38 *
|
rlm@9
|
39 * will output a video without shadows to <code>file1</code> and a video
|
rlm@9
|
40 * with shadows to <code>file2</code>
|
rlm@9
|
41 *
|
rlm@9
|
42 * @author Robert McIntyre
|
rlm@9
|
43 *
|
rlm@9
|
44 */
|
rlm@9
|
45
|
rlm@9
|
46 public abstract class AbstractVideoRecorder
|
rlm@39
|
47 implements SceneProcessor, VideoRecorder, AppState{
|
rlm@9
|
48
|
rlm@9
|
49 final File output;
|
rlm@9
|
50 Camera camera;
|
rlm@9
|
51 int width;
|
rlm@9
|
52 int height;
|
rlm@9
|
53 String targetFileName;
|
rlm@9
|
54 FrameBuffer frameBuffer;
|
rlm@9
|
55 Double fps = null;
|
rlm@9
|
56 RenderManager renderManager;
|
rlm@9
|
57 ByteBuffer byteBuffer;
|
rlm@9
|
58 BufferedImage rawFrame;
|
rlm@9
|
59 boolean isInitilized = false;
|
rlm@9
|
60 boolean paused = false;
|
rlm@9
|
61
|
rlm@9
|
62 public AbstractVideoRecorder(File output) throws IOException {
|
rlm@9
|
63 this.output = output;
|
rlm@9
|
64 this.targetFileName = this.output.getCanonicalPath();
|
rlm@9
|
65 }
|
rlm@9
|
66
|
rlm@9
|
67
|
rlm@9
|
68 public double getFps() {return this.fps;}
|
rlm@9
|
69
|
rlm@9
|
70 public AbstractVideoRecorder setFps(double fps) {
|
rlm@9
|
71 this.fps = fps;
|
rlm@9
|
72 return this;
|
rlm@9
|
73 }
|
rlm@9
|
74
|
rlm@9
|
75 public void initialize(RenderManager rm, ViewPort viewPort) {
|
rlm@9
|
76 Camera camera = viewPort.getCamera();
|
rlm@9
|
77 this.width = camera.getWidth();
|
rlm@9
|
78 this.height = camera.getHeight();
|
rlm@9
|
79
|
rlm@9
|
80 rawFrame = new BufferedImage(width, height,
|
rlm@9
|
81 BufferedImage.TYPE_4BYTE_ABGR);
|
rlm@9
|
82 byteBuffer = BufferUtils.createByteBuffer(width * height * 4 );
|
rlm@9
|
83 this.renderManager = rm;
|
rlm@9
|
84 this.isInitilized = true;
|
rlm@9
|
85 }
|
rlm@9
|
86
|
rlm@9
|
87 public void reshape(ViewPort vp, int w, int h) {}
|
rlm@9
|
88
|
rlm@9
|
89 public boolean isInitialized() {return this.isInitilized;}
|
rlm@9
|
90
|
rlm@9
|
91 public void preFrame(float tpf) {
|
rlm@9
|
92 if (null == this.fps){
|
rlm@9
|
93 this.setFps(1.0 / tpf);}
|
rlm@9
|
94 }
|
rlm@9
|
95
|
rlm@9
|
96 public void postQueue(RenderQueue rq) {}
|
rlm@9
|
97
|
rlm@9
|
98 public void postFrame(FrameBuffer out) {
|
rlm@9
|
99 if (!this.paused){
|
rlm@9
|
100 byteBuffer.clear();
|
rlm@9
|
101 renderManager.getRenderer().readFrameBuffer(out, byteBuffer);
|
rlm@9
|
102 Screenshots.convertScreenShot(byteBuffer, rawFrame);
|
rlm@9
|
103 record(rawFrame);
|
rlm@9
|
104 }
|
rlm@9
|
105 }
|
rlm@9
|
106
|
rlm@9
|
107 public void cleanup(){
|
rlm@9
|
108 this.pause();
|
rlm@9
|
109 this.finish();
|
rlm@9
|
110 };
|
rlm@9
|
111
|
rlm@9
|
112 public void pause(){
|
rlm@9
|
113 this.paused = true;
|
rlm@9
|
114 }
|
rlm@9
|
115
|
rlm@9
|
116 public void start(){
|
rlm@9
|
117 this.paused = false;
|
rlm@9
|
118 }
|
rlm@9
|
119
|
rlm@9
|
120 // methods from AppState
|
rlm@9
|
121 public void initialize(AppStateManager stateManager, Application app) {}
|
rlm@9
|
122
|
rlm@9
|
123 public void setEnabled(boolean active) {
|
rlm@9
|
124 if (active) {this.start();}
|
rlm@9
|
125 else {this.pause();}
|
rlm@9
|
126 }
|
rlm@9
|
127
|
rlm@9
|
128 public boolean isEnabled() {
|
rlm@9
|
129 return this.paused;
|
rlm@9
|
130 }
|
rlm@9
|
131
|
rlm@9
|
132 public void stateAttached(AppStateManager stateManager) {}
|
rlm@9
|
133
|
rlm@9
|
134
|
rlm@9
|
135 public void stateDetached(AppStateManager stateManager) {
|
rlm@9
|
136 this.pause();
|
rlm@9
|
137 this.finish();
|
rlm@9
|
138 }
|
rlm@9
|
139
|
rlm@9
|
140 public void update(float tpf) {}
|
rlm@9
|
141 public void render(RenderManager rm) {}
|
rlm@9
|
142 public void postRender() {}
|
rlm@9
|
143
|
rlm@9
|
144 }
|