# HG changeset patch # User Robert McIntyre # Date 1329327111 25200 # Node ID 301e91a6c2d116193b4c1a2f8fa93a4795f7c3b6 # Parent d8ff1a293b8c82b6f912a975e5c6ac7aad3adafb correct formating for capture-video.org diff -r d8ff1a293b8c -r 301e91a6c2d1 org/capture-video.org --- a/org/capture-video.org Wed Feb 15 10:26:05 2012 -0700 +++ b/org/capture-video.org Wed Feb 15 10:31:51 2012 -0700 @@ -12,8 +12,7 @@ create a demo video to show off your hard work. Screen capturing is the most straightforward way to do this, but it can slow down your game and produce low-quality video as a result. A better way is to -record a video feed directly from the game while it is -running. +record a video feed directly from the game while it is running. In this post, I'll explain how you can alter your JMonkeyEngine3 game to output video while it is running. The main trick is to alter the @@ -28,62 +27,62 @@ ** The built-in =Timer= rushes to keep up. #* Game-time vs. User-time vs. Video-time -Standard JME3 applications use a =Timer= object to manage time -in the simulated world. Because most JME3 applications (e.g. games) -are supposed to happen \ldquo{}live\rdquo{}, the built-in =Timer= -requires simulated time to match real time. This means that the -application must rush to finish all of its calculations on -schedule: the more complicated the calculations, the more the -application is obligated to rush. And if the workload becomes too -much to handle on schedule, =Timer= forces the application to cut -corners: it demands fast, approximate answers instead of careful, -accurate ones. Although this policy sometimes causes physically impossible -glitches and choppy framerates, it ensures that the user will never be -kept waiting while the computer stops to make a complicated -calculation. +Standard JME3 applications use a =Timer= object to manage time in the +simulated world. Because most JME3 applications (e.g. games) are +supposed to happen \ldquo{}live\rdquo{}, the built-in =Timer= requires +simulated time to match real time. This means that the application +must rush to finish all of its calculations on schedule: the more +complicated the calculations, the more the application is obligated to +rush. And if the workload becomes too much to handle on schedule, +=Timer= forces the application to cut corners: it demands fast, +approximate answers instead of careful, accurate ones. Although this +policy sometimes causes physically impossible glitches and choppy +framerates, it ensures that the user will never be kept waiting while +the computer stops to make a complicated calculation. Now, the built-in =Timer= values speed over accuracy because real-time -applications require it. On the other hand, if your goal is to record a -glitch-free video, you need a =Timer= that will take its time to -ensure that all calculations are accurate, even if they take a long time. In the next section, we -will create a new kind of =Timer=\mdash{}called =IsoTimer=\mdash{}which -slows down to let the computer finish all its calculations. The result -is a perfectly steady framerate and a flawless physical simulation. +applications require it. On the other hand, if your goal is to record +a glitch-free video, you need a =Timer= that will take its time to +ensure that all calculations are accurate, even if they take a long +time. In the next section, we will create a new kind of +=Timer=\mdash{}called =IsoTimer=\mdash{}which slows down to let the +computer finish all its calculations. The result is a perfectly steady +framerate and a flawless physical simulation. # are supposed to happen \ldquo live \rdquo, this =Timer= requires the -# application to update in real-time. In order to keep up with the real world, JME applications cannot -# afford to take too much time on expensive computations. Whenever the -# workload becomes too much for the computer to handle on schedule, -# =Timer= forces the computer to cut corners, giving fast, approximate -# answers instead of careful, accurate ones. Although physical accuracy sometimes -# suffers as a result, this policy ensures that the user will never be -# kept waiting while the computer stops to make a complicated -# calculation. +# application to update in real-time. In order to keep up with the +# real world, JME applications cannot afford to take too much time on +# expensive computations. Whenever the workload becomes too much for +# the computer to handle on schedule, =Timer= forces the computer to +# cut corners, giving fast, approximate answers instead of careful, +# accurate ones. Although physical accuracy sometimes suffers as a +# result, this policy ensures that the user will never be kept waiting +# while the computer stops to make a complicated calculation. #fast answers are more important than accurate ones. # A standard JME3 application that extends =SimpleApplication= or # =Application= tries as hard as it can to keep in sync with -# /user-time/. If a ball is rolling at 1 game-mile per game-hour in the -# game, and you wait for one user-hour as measured by the clock on your -# wall, then the ball should have traveled exactly one game-mile. In -# order to keep sync with the real world, the game throttles its physics -# engine and graphics display. If the computations involved in running -# the game are too intense, then the game will first skip frames, then -# sacrifice physics accuracy. If there are particuraly demanding -# computations, then you may only get 1 fps, and the ball may tunnel -# through the floor or obstacles due to inaccurate physics simulation, -# but after the end of one user-hour, that ball will have traveled one -# game-mile. +# /user-time/. If a ball is rolling at 1 game-mile per game-hour in +# the game, and you wait for one user-hour as measured by the clock on +# your wall, then the ball should have traveled exactly one +# game-mile. In order to keep sync with the real world, the game +# throttles its physics engine and graphics display. If the +# computations involved in running the game are too intense, then the +# game will first skip frames, then sacrifice physics accuracy. If +# there are particuraly demanding computations, then you may only get +# 1 fps, and the ball may tunnel through the floor or obstacles due to +# inaccurate physics simulation, but after the end of one user-hour, +# that ball will have traveled one game-mile. -# When we're recording video, we don't care if the game-time syncs with -# user-time, but instead whether the time in the recorded video +# When we're recording video, we don't care if the game-time syncs +# with user-time, but instead whether the time in the recorded video # (video-time) syncs with user-time. To continue the analogy, if we -# recorded the ball rolling at 1 game-mile per game-hour and watched the -# video later, we would want to see 30 fps video of the ball rolling at -# 1 video-mile per /user-hour/. It doesn't matter how much user-time it -# took to simulate that hour of game-time to make the high-quality -# recording. +# recorded the ball rolling at 1 game-mile per game-hour and watched +# the video later, we would want to see 30 fps video of the ball +# rolling at 1 video-mile per /user-hour/. It doesn't matter how much +# user-time it took to simulate that hour of game-time to make the +# high-quality recording. ** COMMENT Two examples to clarify the point: *** Recording from a Simple Simulation @@ -151,10 +150,10 @@ the screen, and an additional $\frac{1}{60}$ to encode the video and write the frame to disk. This is a total of $\frac{1}{24}$ user-seconds for each $\frac{1}{60}$ game-seconds. It will take -$(\frac{60}{24} = 2.5)$ user-hours to record one game-hour and game-time -will appear to flow two-fifths as fast as user time while the game is -running. However, just as in example one, when all is said and done we -will have an hour long video at 60 fps. +$(\frac{60}{24} = 2.5)$ user-hours to record one game-hour and +game-time will appear to flow two-fifths as fast as user time while +the game is running. However, just as in example one, when all is said +and done we will have an hour long video at 60 fps. ** COMMENT proposed names for the new timer @@ -182,8 +181,8 @@ #+include ../../jmeCapture/src/com/aurellem/capture/IsoTimer.java src java If an Application uses this =IsoTimer= instead of the normal one, we -can be sure that every call to =simpleUpdate=, for example, corresponds -to exactly $(\frac{1}{fps})$ seconds of game-time. +can be sure that every call to =simpleUpdate=, for example, +corresponds to exactly $(\frac{1}{fps})$ seconds of game-time. * =VideoRecorder= manages video feeds in JMonkeyEngine. @@ -240,8 +239,9 @@ With this, we are able to record video! -However, it can be hard to properly install Xuggle. If you would rather not use Xuggle, here is an alternate class that uses -[[http://www.randelshofer.ch/blog/2008/08/writing-avi-videos-in-pure-java/][Werner Randelshofer's]] excellent pure Java AVI file writer. +However, it can be hard to properly install Xuggle. If you would +rather not use Xuggle, here is an alternate class that uses [[http://www.randelshofer.ch/blog/2008/08/writing-avi-videos-in-pure-java/][Werner +Randelshofer's]] excellent pure Java AVI file writer. =./src/com/aurellem/capture/video/AVIVideoRecorder.java= #+include ../../jmeCapture/src/com/aurellem/capture/video/AVIVideoRecorder.java src java @@ -265,13 +265,14 @@ ** Include this code. - No matter how complicated your application is, it's easy to add - support for video output with just a few lines of code. +No matter how complicated your application is, it's easy to add +support for video output with just a few lines of code. # You can also record from multiple ViewPorts as the above example shows. -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{} -exactly what's on screen. In this case, the following simple =captureVideo= -method will do the job: +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{} exactly what's on screen. In +this case, the following simple =captureVideo= method will do the job: #+begin_src java public static void captureVideo(final Application app, @@ -302,12 +303,9 @@ } #+end_src -This method selects the appropriate =VideoRecorder= class -for the file type you specify, and instructs your -application to record video to the file. - - - +This method selects the appropriate =VideoRecorder= class for the file +type you specify, and instructs your application to record video to +the file. Now that you have a =captureVideo= method, you use it like this: @@ -321,7 +319,8 @@ - Choose the output file :: If you want to record from the game's main =ViewPort= to a file called =/home/r/record.flv=, then - include the following line of code somewhere before you call =app.start()=; + include the following line of code somewhere before you call + =app.start()=; #+begin_src java :exports code Capture.captureVideo(app, new File("/home/r/record.flv")); @@ -384,8 +383,9 @@ * COMMENT More Examples ** COMMENT Hello Physics -=HelloVideo= is boring. Let's add some video capturing to =HelloPhysics= -and create something fun! + +=HelloVideo= is boring. Let's add some video capturing to +=HelloPhysics= and create something fun! This example is a modified version of =HelloPhysics= that creates four simultaneous views of the same scene of cannonballs careening into a @@ -579,7 +579,7 @@ four points of view are simultaneously recorded and then glued together later. - JME3 Xuggle Aurellem video capture +JME3 Xuggle Aurellem video capture * Showcase of recorded videos