Mercurial > cortex
diff org/capture-video.org @ 275:da4de661c5d9
I changed Capture Video\!
author | Dylan Holmes <ocsenave@gmail.com> |
---|---|
date | Wed, 15 Feb 2012 01:15:15 -0600 |
parents | ecafe87ffddc |
children | 301e91a6c2d1 |
line wrap: on
line diff
1.1 --- a/org/capture-video.org Tue Feb 14 23:12:56 2012 -0600 1.2 +++ b/org/capture-video.org Wed Feb 15 01:15:15 2012 -0600 1.3 @@ -24,35 +24,70 @@ 1.4 smooth video output at a constant framerate. 1.5 1.6 1.7 -* Game-time vs. User-time vs. Video-time 1.8 +* Video recording requires a steady framerate 1.9 +** The built-in =Timer= rushes to keep up. 1.10 +#* Game-time vs. User-time vs. Video-time 1.11 1.12 -A standard JME3 application that extends =SimpleApplication= or 1.13 -=Application= tries as hard as it can to keep in sync with 1.14 -/user-time/. If a ball is rolling at 1 game-mile per game-hour in the 1.15 -game, and you wait for one user-hour as measured by the clock on your 1.16 -wall, then the ball should have traveled exactly one game-mile. In 1.17 -order to keep sync with the real world, the game throttles its physics 1.18 -engine and graphics display. If the computations involved in running 1.19 -the game are too intense, then the game will first skip frames, then 1.20 -sacrifice physics accuracy. If there are particuraly demanding 1.21 -computations, then you may only get 1 fps, and the ball may tunnel 1.22 -through the floor or obstacles due to inaccurate physics simulation, 1.23 -but after the end of one user-hour, that ball will have traveled one 1.24 -game-mile. 1.25 +Standard JME3 applications use a =Timer= object to manage time 1.26 +in the simulated world. Because most JME3 applications (e.g. games) 1.27 +are supposed to happen \ldquo{}live\rdquo{}, the built-in =Timer= 1.28 +requires simulated time to match real time. This means that the 1.29 +application must rush to finish all of its calculations on 1.30 +schedule: the more complicated the calculations, the more the 1.31 +application is obligated to rush. And if the workload becomes too 1.32 +much to handle on schedule, =Timer= forces the application to cut 1.33 +corners: it demands fast, approximate answers instead of careful, 1.34 +accurate ones. Although this policy sometimes causes physically impossible 1.35 +glitches and choppy framerates, it ensures that the user will never be 1.36 +kept waiting while the computer stops to make a complicated 1.37 +calculation. 1.38 1.39 -When we're recording video, we don't care if the game-time syncs with 1.40 -user-time, but instead whether the time in the recorded video 1.41 -(video-time) syncs with user-time. To continue the analogy, if we 1.42 -recorded the ball rolling at 1 game-mile per game-hour and watched the 1.43 -video later, we would want to see 30 fps video of the ball rolling at 1.44 -1 video-mile per /user-hour/. It doesn't matter how much user-time it 1.45 -took to simulate that hour of game-time to make the high-quality 1.46 -recording. 1.47 +Now, the built-in =Timer= values speed over accuracy because real-time 1.48 +applications require it. On the other hand, if your goal is to record a 1.49 +glitch-free video, you need a =Timer= that will take its time to 1.50 +ensure that all calculations are accurate, even if they take a long time. In the next section, we 1.51 +will create a new kind of =Timer=\mdash{}called =IsoTimer=\mdash{}which 1.52 +slows down to let the computer finish all its calculations. The result 1.53 +is a perfectly steady framerate and a flawless physical simulation. 1.54 1.55 -* COMMENT Two examples to clarify the point: 1.56 -** Recording from a Simple Simulation 1.57 +# are supposed to happen \ldquo live \rdquo, this =Timer= requires the 1.58 +# application to update in real-time. In order to keep up with the real world, JME applications cannot 1.59 +# afford to take too much time on expensive computations. Whenever the 1.60 +# workload becomes too much for the computer to handle on schedule, 1.61 +# =Timer= forces the computer to cut corners, giving fast, approximate 1.62 +# answers instead of careful, accurate ones. Although physical accuracy sometimes 1.63 +# suffers as a result, this policy ensures that the user will never be 1.64 +# kept waiting while the computer stops to make a complicated 1.65 +# calculation. 1.66 1.67 -*** Without a Special Timer 1.68 +#fast answers are more important than accurate ones. 1.69 + 1.70 +# A standard JME3 application that extends =SimpleApplication= or 1.71 +# =Application= tries as hard as it can to keep in sync with 1.72 +# /user-time/. If a ball is rolling at 1 game-mile per game-hour in the 1.73 +# game, and you wait for one user-hour as measured by the clock on your 1.74 +# wall, then the ball should have traveled exactly one game-mile. In 1.75 +# order to keep sync with the real world, the game throttles its physics 1.76 +# engine and graphics display. If the computations involved in running 1.77 +# the game are too intense, then the game will first skip frames, then 1.78 +# sacrifice physics accuracy. If there are particuraly demanding 1.79 +# computations, then you may only get 1 fps, and the ball may tunnel 1.80 +# through the floor or obstacles due to inaccurate physics simulation, 1.81 +# but after the end of one user-hour, that ball will have traveled one 1.82 +# game-mile. 1.83 + 1.84 +# When we're recording video, we don't care if the game-time syncs with 1.85 +# user-time, but instead whether the time in the recorded video 1.86 +# (video-time) syncs with user-time. To continue the analogy, if we 1.87 +# recorded the ball rolling at 1 game-mile per game-hour and watched the 1.88 +# video later, we would want to see 30 fps video of the ball rolling at 1.89 +# 1 video-mile per /user-hour/. It doesn't matter how much user-time it 1.90 +# took to simulate that hour of game-time to make the high-quality 1.91 +# recording. 1.92 +** COMMENT Two examples to clarify the point: 1.93 +*** Recording from a Simple Simulation 1.94 + 1.95 +**** Without a Special Timer 1.96 You have a simulation of a ball rolling on an infinite empty plane at 1.97 one game-mile per game-hour, and a really good computer. Normally, 1.98 JME3 will throttle the physics engine and graphics display to sync the 1.99 @@ -66,7 +101,7 @@ 1.100 frames per user-second. 1.101 1.102 1.103 -*** With a Special Timer 1.104 +**** With a Special Timer 1.105 Then, you change the game's timer so that user-time will be synced to 1.106 video-time. Assume that encoding a single frame takes 0 seconds 1.107 user-time to complete. 1.108 @@ -85,7 +120,7 @@ 1.109 will take exactly one hour user-time (and one hour video-time) for the 1.110 ball in the video to travel one video-mile. 1.111 1.112 -** Recording from a Complex Simulation 1.113 +*** Recording from a Complex Simulation 1.114 1.115 *** Without a Special Timer 1.116 You have a simulation of a ball rolling on an infinite empty plane at 1.117 @@ -122,7 +157,7 @@ 1.118 will have an hour long video at 60 fps. 1.119 1.120 1.121 -* COMMENT proposed names for the new timer 1.122 +** COMMENT proposed names for the new timer 1.123 # METRONOME 1.124 # IsoTimer 1.125 # EvenTimer 1.126 @@ -136,7 +171,7 @@ 1.127 # SteadyTimer 1.128 1.129 1.130 -* =IsoTimer= records time like a metronome 1.131 +** =IsoTimer= records time like a metronome 1.132 1.133 The easiest way to achieve this special timing is to create a new 1.134 timer that always reports the same framerate to JME3 every time it is 1.135 @@ -150,15 +185,18 @@ 1.136 can be sure that every call to =simpleUpdate=, for example, corresponds 1.137 to exactly $(\frac{1}{fps})$ seconds of game-time. 1.138 1.139 -* Encoding to Video 1.140 +* =VideoRecorder= manages video feeds in JMonkeyEngine. 1.141 + 1.142 + 1.143 +** =AbstractVideoRecorder= provides a general framework for managing videos. 1.144 1.145 Now that the issue of time is solved, we just need a function that 1.146 writes each frame to a video. We can put this function somewhere 1.147 -where it will be called exactly one per frame. 1.148 +where it will be called exactly once per frame. 1.149 1.150 The basic functions that a =VideoRecorder= should support are 1.151 -recording, starting, stopping, and possibly a final finishing step 1.152 -there it finilizes the recording (such as writing headers for a video 1.153 +recording, starting, stopping, and possibly a cleanup step 1.154 +where it finalizes the recording (e.g. by writing headers for a video 1.155 file). 1.156 1.157 An appropiate interface describing this behaviour could look like 1.158 @@ -186,10 +224,13 @@ 1.159 =./src/com/aurellem/capture/video/AbstractVideoRecorder.java= 1.160 #+include ../../jmeCapture/src/com/aurellem/capture/video/AbstractVideoRecorder.java src java 1.161 1.162 + 1.163 +** There are many options for handling video files in Java 1.164 + 1.165 If you want to generate video from Java, a great option is [[http://www.xuggle.com/][Xuggle]]. It 1.166 takes care of everything related to video encoding and decoding and 1.167 runs on Windows, Linux and Mac. Out of all the video frameworks for 1.168 -Java I personally like this one the best. 1.169 +Java, I personally like this one the best. 1.170 1.171 Here is a =VideoRecorder= that uses [[http://www.xuggle.com/][Xuggle]] to write each frame to a 1.172 video file. 1.173 @@ -199,8 +240,7 @@ 1.174 1.175 With this, we are able to record video! 1.176 1.177 -However, it can be hard to properly install Xuggle. For those of you 1.178 -who would rather not use Xuggle, here is an alternate class that uses 1.179 +However, it can be hard to properly install Xuggle. If you would rather not use Xuggle, here is an alternate class that uses 1.180 [[http://www.randelshofer.ch/blog/2008/08/writing-avi-videos-in-pure-java/][Werner Randelshofer's]] excellent pure Java AVI file writer. 1.181 1.182 =./src/com/aurellem/capture/video/AVIVideoRecorder.java= 1.183 @@ -219,11 +259,19 @@ 1.184 #+include ../../jmeCapture/src/com/aurellem/capture/video/FileVideoRecorder.java src java 1.185 1.186 1.187 -* /Really/ Simple Video Recording 1.188 1.189 -The most common case for recording a video is probably to just capture 1.190 -whatever is on your screen exactly as you see it. In this case, this 1.191 -method will do. 1.192 + 1.193 +* How to record videos yourself 1.194 + 1.195 +** Include this code. 1.196 + 1.197 + No matter how complicated your application is, it's easy to add 1.198 + support for video output with just a few lines of code. 1.199 +# You can also record from multiple ViewPorts as the above example shows. 1.200 + 1.201 +And although you can use =VideoRecorder= to record advanced split-screen videos with multiple views, in the simplest case, you want to capture a single view\mdash{} 1.202 +exactly what's on screen. In this case, the following simple =captureVideo= 1.203 +method will do the job: 1.204 1.205 #+begin_src java 1.206 public static void captureVideo(final Application app, 1.207 @@ -254,13 +302,37 @@ 1.208 } 1.209 #+end_src 1.210 1.211 -This will select the appropiate backend =VideoRecorder= class 1.212 -depending on the file name you specify, and insturment your 1.213 -application to record video to the file. You should still set the 1.214 -game's timer to an =IsoTimer= with the desired fps. 1.215 +This method selects the appropriate =VideoRecorder= class 1.216 +for the file type you specify, and instructs your 1.217 +application to record video to the file. 1.218 + 1.219 + 1.220 + 1.221 + 1.222 +Now that you have a =captureVideo= method, you use it like this: 1.223 + 1.224 + - Establish an =Isotimer= and set its framerate :: For example, if 1.225 + you want to record video with a framerate of 30 fps, include 1.226 + the following line of code somewhere in the initializtion of 1.227 + your application: 1.228 +#+begin_src java :exports code 1.229 +this.setTimer(new IsoTimer(30)); 1.230 +#+end_src 1.231 + 1.232 + - Choose the output file :: If you want to record from the game's 1.233 + main =ViewPort= to a file called =/home/r/record.flv=, then 1.234 + include the following line of code somewhere before you call =app.start()=; 1.235 + 1.236 + #+begin_src java :exports code 1.237 +Capture.captureVideo(app, new File("/home/r/record.flv")); 1.238 + #+end_src 1.239 + 1.240 + 1.241 +** Simple example 1.242 + 1.243 1.244 This example will record video from the ocean scene from the 1.245 -jMonkeyEngine test suite. 1.246 +JMonkeyEngine test suite. 1.247 #+begin_src java 1.248 File video = File.createTempFile("JME-water-video", ".avi"); 1.249 captureVideo(app, video); 1.250 @@ -273,7 +345,7 @@ 1.251 =com.aurellem.capture.Capture=. You can get it [[http://hg.bortreb.com/jmeCapture/][here]]. 1.252 1.253 1.254 -* Hello Video! 1.255 +** Hello Video! example 1.256 1.257 I've taken [[http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/helloworld/HelloLoop.java][=./jme3/src/test/jme3test/helloworld/HelloLoop.java=]] and 1.258 augmented it with video output as follows: 1.259 @@ -310,32 +382,7 @@ 1.260 #+END_HTML 1.261 1.262 1.263 -* Summary 1.264 -It's quite easy to augment your own application to record video, 1.265 -almost regardless of how complicated the actual application is. You 1.266 -can also record from multiple ViewPorts as the above example shows. 1.267 - 1.268 -The process for adding video recording to your application is as 1.269 -follows: 1.270 - 1.271 -Assuming you want to record at 30 fps, add: 1.272 - 1.273 -#+begin_src java :exports code 1.274 -this.setTimer(new IsoTimer(30)); 1.275 -#+end_src 1.276 - 1.277 -Somewhere in the initialization of your Application. 1.278 - 1.279 -If you want to record from the game's main =ViewPort= to a file called 1.280 -=/home/r/record.flv=, then add: 1.281 - 1.282 -#+begin_src java :exports code 1.283 -Capture.captureVideo(app, new File("/home/r/record.flv")); 1.284 -#+end_src 1.285 - 1.286 -Before you call =app.start()=; 1.287 - 1.288 -* More Examples 1.289 +* COMMENT More Examples 1.290 ** COMMENT Hello Physics 1.291 =HelloVideo= is boring. Let's add some video capturing to =HelloPhysics= 1.292 and create something fun! 1.293 @@ -535,7 +582,7 @@ 1.294 JME3 Xuggle Aurellem video capture 1.295 1.296 1.297 -* Sample Videos 1.298 +* Showcase of recorded videos 1.299 I encoded most of the original JME3 Hello demos for your viewing 1.300 pleasure, all using the =Capture= and =IsoTimer= classes. 1.301