changeset 42:ecafe87ffddc

updating capture video with new examples
author Robert McIntyre <rlm@mit.edu>
date Thu, 03 Nov 2011 16:01:14 -0700
parents cce471a4108a
children 117eb477d0a7
files org/capture-video.org
diffstat 1 files changed, 115 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
     1.1 --- a/org/capture-video.org	Thu Nov 03 10:42:28 2011 -0700
     1.2 +++ b/org/capture-video.org	Thu Nov 03 16:01:14 2011 -0700
     1.3 @@ -143,53 +143,147 @@
     1.4  called.
     1.5  
     1.6  
     1.7 -=./jme3/src/core/com/jme3/system/IsoTimer.java=
     1.8 -#+include ./jme3/src/core/com/jme3/system/IsoTimer.java src java
     1.9 +=./src/com/aurellem/capture/IsoTimer.java=
    1.10 +#+include ../../jmeCapture/src/com/aurellem/capture/IsoTimer.java src java
    1.11  
    1.12  If an Application uses this =IsoTimer= instead of the normal one, we
    1.13  can be sure that every call to =simpleUpdate=, for example, corresponds
    1.14  to exactly $(\frac{1}{fps})$ seconds of game-time.
    1.15  
    1.16 -In order to facilitate setting the =Timer= in user code, I added
    1.17 -getter and setter methods to =Application.java=.
    1.18 -
    1.19 -In =./jme3/src/core/com/jme3/app/Application.java= I added:
    1.20 -#+include ./jme3/src/core/com/jme3/app/Application.java src java :lines "340-356"
    1.21 -
    1.22  * Encoding to Video
    1.23  
    1.24  Now that the issue of time is solved, we just need a function that
    1.25  writes each frame to a video.  We can put this function somewhere
    1.26  where it will be called exactly one per frame.
    1.27  
    1.28 +The basic functions that a =VideoRecorder= should support are
    1.29 +recording, starting, stopping, and possibly a final finishing step
    1.30 +there it finilizes the recording (such as writing headers for a video
    1.31 +file).
    1.32 +
    1.33 +An appropiate interface describing this behaviour could look like
    1.34 +this:
    1.35 +
    1.36 +=./src/com/aurellem/capture/video/VideoRecorder.java=
    1.37 +#+include ../../jmeCapture/src/com/aurellem/capture/video/VideoRecorder.java src java
    1.38 +
    1.39 +
    1.40  JME3 already provides exactly the class we need: the =SceneProcessor=
    1.41  class can be attached to any viewport and the methods defined therein
    1.42  will be called at the appropriate points in the rendering process.
    1.43  
    1.44 +However, it is also important to properly close the video stream and
    1.45 +write headers and such, and even though =SceneProcessor= has a
    1.46 +=.cleanup()= method, it is only called when the =SceneProcessor= is
    1.47 +removed from the =RenderManager=, not when the game is shutting down
    1.48 +when the user pressed ESC, for example. To obtain reliable shutdown
    1.49 +behaviour, we also have to implement =AppState=, which provides a
    1.50 +=.cleanup()= method that /is/ called on shutdown.
    1.51 +
    1.52 +Here is an AbstractVideoRecorder class that takes care of the details
    1.53 +of setup and teardown.
    1.54 +
    1.55 +=./src/com/aurellem/capture/video/AbstractVideoRecorder.java=
    1.56 +#+include ../../jmeCapture/src/com/aurellem/capture/video/AbstractVideoRecorder.java src java
    1.57 +
    1.58  If you want to generate video from Java, a great option is [[http://www.xuggle.com/][Xuggle]]. It
    1.59  takes care of everything related to video encoding and decoding and
    1.60  runs on Windows, Linux and Mac.  Out of all the video frameworks for
    1.61  Java I personally like this one the best.
    1.62  
    1.63 -Here is a =SceneProcessor= that uses [[http://www.xuggle.com/][Xuggle]] to write each frame to a
    1.64 +Here is a =VideoRecorder= that uses [[http://www.xuggle.com/][Xuggle]] to write each frame to a
    1.65  video file.
    1.66  
    1.67 -=./jme3/src/core/com/jme3/app/VideoProcessor.java=
    1.68 -#+include ./jme3/src/core/com/jme3/app/VideoProcessor.java src java
    1.69 +=./src/com/aurellem/capture/video/XuggleVideoRecorder.java=
    1.70 +#+include ../../jmeCapture/src/com/aurellem/capture/video/XuggleVideoRecorder.java src java
    1.71  
    1.72  With this, we are able to record video!
    1.73  
    1.74 +However, it can be hard to properly install Xuggle. For those of you
    1.75 +who would rather not use Xuggle, here is an alternate class that uses
    1.76 +[[http://www.randelshofer.ch/blog/2008/08/writing-avi-videos-in-pure-java/][Werner Randelshofer's]] excellent pure Java AVI file writer.
    1.77 +
    1.78 +=./src/com/aurellem/capture/video/AVIVideoRecorder.java=
    1.79 +#+include ../../jmeCapture/src/com/aurellem/capture/video/AVIVideoRecorder.java src java
    1.80 +
    1.81 +This =AVIVideoRecorder= is more limited than the
    1.82 +=XuggleVideoRecorder=, but requires less external dependencies.
    1.83 +
    1.84 +Finally, for those of you who prefer to create the final video from a
    1.85 +sequence of images, there is the =FileVideoRecorder=, which records
    1.86 +each frame to a folder as a sequentially numbered image file. Note
    1.87 +that you have to remember the FPS at which you recorded the video, as
    1.88 +this information is lost when saving each frame to a file.
    1.89 +
    1.90 +=./src/com/aurellem/capture/video/FileVideoRecorder.java=
    1.91 +#+include ../../jmeCapture/src/com/aurellem/capture/video/FileVideoRecorder.java src java
    1.92 +
    1.93 +
    1.94 +* /Really/ Simple Video Recording
    1.95 +
    1.96 +The most common case for recording a video is probably to just capture
    1.97 +whatever is on your screen exactly as you see it.  In this case, this
    1.98 +method will do.
    1.99 +
   1.100 +#+begin_src java
   1.101 +public static void captureVideo(final Application app, 
   1.102 +				final File file) throws IOException{
   1.103 +    final AbstractVideoRecorder videoRecorder;
   1.104 +    if (file.getCanonicalPath().endsWith(".avi")){
   1.105 +	videoRecorder = new AVIVideoRecorder(file);}
   1.106 +    else if (file.isDirectory()){
   1.107 +	videoRecorder = new FileVideoRecorder(file);}
   1.108 +    else { videoRecorder = new XuggleVideoRecorder(file);}
   1.109 +    
   1.110 +    Callable<Object> thunk = new Callable<Object>(){
   1.111 +	public Object call(){
   1.112 +	    ViewPort viewPort = 
   1.113 +	    app.getRenderManager()
   1.114 +	    .createPostView("aurellem record", app.getCamera());
   1.115 +	    viewPort.setClearFlags(false, false, false);
   1.116 +	    // get GUI node stuff
   1.117 +	    for (Spatial s : app.getGuiViewPort().getScenes()){
   1.118 +		viewPort.attachScene(s);
   1.119 +	    }
   1.120 +	    app.getStateManager().attach(videoRecorder);
   1.121 +	    viewPort.addProcessor(videoRecorder);
   1.122 +	    return null;
   1.123 +	}
   1.124 +    };
   1.125 +    app.enqueue(thunk);
   1.126 +}
   1.127 +#+end_src
   1.128 +
   1.129 +This will select the appropiate backend =VideoRecorder= class
   1.130 +depending on the file name you specify, and insturment your
   1.131 +application to record video to the file.  You should still set the
   1.132 +game's timer to an =IsoTimer= with the desired fps.
   1.133 +
   1.134 +This example will record video from the ocean scene from the
   1.135 +jMonkeyEngine test suite.
   1.136 +#+begin_src java
   1.137 +File video = File.createTempFile("JME-water-video", ".avi");
   1.138 +captureVideo(app, video);
   1.139 +app.start();
   1.140 +System.out.println(video.getCanonicalPath());
   1.141 +#+end_src
   1.142 +
   1.143 +
   1.144 +I've added support for this under a class called
   1.145 +=com.aurellem.capture.Capture=. You can get it [[http://hg.bortreb.com/jmeCapture/][here]].
   1.146 +
   1.147 +
   1.148  * Hello Video!
   1.149  
   1.150  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.151  augmented it with video output as follows:
   1.152  
   1.153 -=./jme3/src/test/jme3test/helloworld/HelloVideo.java=
   1.154 -#+include ./jme3/src/test/jme3test/helloworld/HelloVideo.java src java
   1.155 +=./src/com/aurellem/capture/examples/HelloVideo.java=
   1.156 +#+include ../../src/com/aurellem/capture/examples/HelloVideo.java src java
   1.157  
   1.158  The videos are created in the =hello-video= directory
   1.159  
   1.160 -#+begin_src sh :results verbatim
   1.161 +#+begin_src sh :results verbatim :exports both
   1.162  du -h hello-video/*
   1.163  #+end_src
   1.164  
   1.165 @@ -216,7 +310,6 @@
   1.166  #+END_HTML
   1.167  
   1.168    
   1.169 -
   1.170  * Summary 
   1.171  It's quite easy to augment your own application to record video,
   1.172  almost regardless of how complicated the actual application is.  You
   1.173 @@ -231,26 +324,19 @@
   1.174  this.setTimer(new IsoTimer(30));
   1.175  #+end_src
   1.176  
   1.177 -Somewhere in the initialization of your Application.  Right now, you
   1.178 -will have to add the =setTimer= method to =Application=, but hopefully
   1.179 -this method will be included soon by the JMonkeyEngine3 team.
   1.180 -
   1.181 -Then, you create a =VideoProcessor= object and attach it to the
   1.182 -=ViewPort= from which you want to record.
   1.183 +Somewhere in the initialization of your Application.
   1.184  
   1.185  If you want to record from the game's main =ViewPort= to a file called
   1.186  =/home/r/record.flv=, then add:
   1.187  
   1.188  #+begin_src java :exports code
   1.189 -viewPort.addProcessor(new VideoProcessor(new File("/home/r/record.flv")));
   1.190 +Capture.captureVideo(app, new File("/home/r/record.flv"));
   1.191  #+end_src
   1.192  
   1.193 -Do this for each =ViewPort= from which you want to record.  The more
   1.194 -ViewPorts from which you record, the slower the game will run, but
   1.195 -this slowness will not affect the final video output.
   1.196 +Before you call =app.start()=;
   1.197  
   1.198  * More Examples
   1.199 -** Hello Physics
   1.200 +** COMMENT Hello Physics
   1.201  =HelloVideo= is boring. Let's add some video capturing to =HelloPhysics=
   1.202  and create something fun!
   1.203  
   1.204 @@ -341,7 +427,7 @@
   1.205  Thats a terribly large size!
   1.206  Let's compress it:
   1.207  
   1.208 -** Compressing the HelloPhysics Video
   1.209 +** COMMENT Compressing the HelloPhysics Video
   1.210  First, we'll scale the video, then, we'll decrease it's bitrate. The
   1.211  end result will be perfect for upload to YouTube.
   1.212  
   1.213 @@ -451,7 +537,7 @@
   1.214   
   1.215  * Sample Videos
   1.216  I encoded most of the original JME3 Hello demos for your viewing
   1.217 -pleasure, all using the =VideoProcessor= and =IsoTimer= classes.
   1.218 +pleasure, all using the =Capture= and =IsoTimer= classes.
   1.219  
   1.220  ** HelloTerrain
   1.221  [[http://youtu.be/5_4wyDFwrVQ][HelloTerrain.avi]]
   1.222 @@ -651,3 +737,4 @@
   1.223  
   1.224  
   1.225  
   1.226 +