annotate src/com/aurellem/capture/Capture.java @ 63:df4a2d12ea13

added new timer for debugging purposes
author Robert McIntyre <rlm@mit.edu>
date Sun, 15 Jan 2012 04:10:37 -0700
parents afc437f637bd
children 302d5e9ad120
rev   line source
rlm@3 1 package com.aurellem.capture;
rlm@3 2
rlm@3 3 import java.io.File;
rlm@3 4 import java.io.IOException;
rlm@12 5 import java.util.concurrent.Callable;
rlm@3 6
rlm@12 7 import com.aurellem.capture.audio.MultiListener;
rlm@12 8 import com.aurellem.capture.audio.WaveFileWriter;
rlm@9 9 import com.aurellem.capture.video.AVIVideoRecorder;
rlm@10 10 import com.aurellem.capture.video.AbstractVideoRecorder;
rlm@39 11 import com.aurellem.capture.video.FileVideoRecorder;
rlm@10 12 import com.aurellem.capture.video.XuggleVideoRecorder;
rlm@3 13 import com.jme3.app.Application;
rlm@12 14 import com.jme3.audio.AudioRenderer;
rlm@12 15 import com.jme3.renderer.ViewPort;
rlm@12 16 import com.jme3.scene.Spatial;
rlm@49 17 import com.jme3.system.AppSettings;
rlm@44 18 import com.jme3.system.JmeSystem;
rlm@3 19
rlm@53 20 /**
rlm@56 21 * Use the methods in this class for capturing consistent, high quality video
rlm@56 22 * and audio from a jMonkeyEngine3 application. To capture audio or video do
rlm@56 23 * the following:
rlm@53 24 *
rlm@56 25 * 1.) Set your application's timer to an IsoTimer. Create the IsoTimer with the
rlm@56 26 * desired video frames-per-second.
rlm@56 27 *
rlm@56 28 * 2.) Call captureAudio and/or captureVideo on the Application as desired
rlm@56 29 * before starting the Application.
rlm@55 30 *
rlm@56 31 * See the Basic and Advanced demos in the examples section for more
rlm@56 32 * information. If you have any trouble, please PM me on the jMonkeyEngine
rlm@56 33 * forums. My username is bortreb.
rlm@55 34 *
rlm@53 35 * @author Robert McIntyre
rlm@53 36 */
rlm@53 37
rlm@3 38 public class Capture {
rlm@3 39
rlm@56 40 /**
rlm@56 41 * Use this function to capture video from your application. You
rlm@56 42 * specify the framerate at which the video will be recording by setting
rlm@56 43 * the Application's timer to an IsoTimer created with the desired
rlm@56 44 * frames-per-second.
rlm@56 45 *
rlm@56 46 * There are three ways to record and they are selected by the
rlm@56 47 * properties of the file that you specify.
rlm@56 48 *
rlm@56 49 * 1.) (Preferred) If you supply an empty directory as the file, then
rlm@56 50 * the video will be saved as a sequence of .png files, one file per
rlm@56 51 * frame. The files start at 0000000.png and increment from there.
rlm@56 52 * You can then combine the frames into your preferred
rlm@56 53 * container/codec. If the directory is not empty, then writing
rlm@56 54 * video frames to it will fail, and nothing will be written.
rlm@56 55 *
rlm@56 56 * 2.) If the filename ends in ".avi" then the frames will be encoded as
rlm@56 57 * a RAW stream inside an AVI 1.0 container. The resulting file
rlm@56 58 * will be quite large and you will probably want to re-encode it to
rlm@56 59 * your preferred container/codec format. Be advised that some
rlm@56 60 * video payers cannot process AVI with a RAW stream, and that AVI
rlm@56 61 * 1.0 files generated by this method that exceed 2.0GB are invalid
rlm@56 62 * according to the AVI 1.0 spec (but many programs can still deal
rlm@56 63 * with them.) Thanks to Werner Randelshofer for his excellent work
rlm@56 64 * which made AVI file writer option possible.
rlm@56 65 *
rlm@56 66 * 3.) Any non-directory file ending in anything other than ".avi" will
rlm@56 67 * be processed through Xuggle. Xuggle provides the option to use
rlm@56 68 * many codecs/containers, but you will have to install it on your
rlm@56 69 * system yourself in order to use this option. Please visit
rlm@56 70 * http://www.xuggle.com/ to learn how to do this.
rlm@56 71 *
rlm@56 72 * @param app The Application from which you wish to record Video.
rlm@56 73 * @param file The file to which the video will be captured.
rlm@56 74 * @throws IOException
rlm@56 75 */
rlm@54 76
rlm@56 77 public static void captureVideo(final Application app, final File file) throws IOException{
rlm@56 78 final AbstractVideoRecorder videoRecorder;
rlm@12 79
rlm@56 80 if (file.getCanonicalPath().endsWith(".avi")){
rlm@56 81 videoRecorder = new AVIVideoRecorder(file);}
rlm@56 82 else if (file.isDirectory()){
rlm@56 83 videoRecorder = new FileVideoRecorder(file);}
rlm@56 84 else { videoRecorder = new XuggleVideoRecorder(file);}
rlm@12 85
rlm@56 86 Callable<Object> thunk = new Callable<Object>(){
rlm@56 87 public Object call(){
rlm@12 88
rlm@56 89 ViewPort viewPort =
rlm@56 90 app.getRenderManager()
rlm@56 91 .createPostView("aurellem video record", app.getCamera());
rlm@12 92
rlm@56 93 viewPort.setClearFlags(false, false, false);
rlm@12 94
rlm@56 95 // get GUI node stuff
rlm@56 96 for (Spatial s : app.getGuiViewPort().getScenes()){
rlm@56 97 viewPort.attachScene(s);
rlm@56 98 }
rlm@12 99
rlm@56 100 app.getStateManager().attach(videoRecorder);
rlm@56 101 viewPort.addProcessor(videoRecorder);
rlm@56 102 return null;
rlm@56 103 }
rlm@56 104 };
rlm@56 105 app.enqueue(thunk);
rlm@56 106 }
rlm@12 107
rlm@54 108
rlm@56 109 /**
rlm@56 110 * Use this function to capture audio from your application. Audio data
rlm@56 111 * will be saved in linear PCM format at 44,100 hertz in the wav container
rlm@56 112 * format to the file that you specify.
rlm@56 113 *
rlm@56 114 * Note that you *have* to use an IsoTimer for your Application's timer
rlm@56 115 * while recording audio or the recording will fail. Also ensure that your
rlm@56 116 * IsoTimer obeys the following constraints:
rlm@56 117 *
rlm@56 118 * 1.) The frames-per-second value of the IsoTimer cannot be lower than 10
rlm@56 119 * frames-per-second.
rlm@56 120 *
rlm@56 121 * 2.) The frames-per-second value of the IsoTimer must evenly divide
rlm@56 122 * 44,100.
rlm@56 123 *
rlm@56 124 * @param app The Application from which you wish to record Audio.
rlm@56 125 * @param file the target file to which you want to record audio data.
rlm@56 126 * @throws IOException
rlm@56 127 */
rlm@12 128
rlm@56 129 public static void captureAudio(final Application app, final File file) throws IOException{
rlm@56 130 AppSettings settings = null;
rlm@56 131 if (app.getContext() != null){settings = app.getContext().getSettings();}
rlm@56 132 if (settings == null){settings = new AppSettings(true);}
rlm@56 133 settings.setAudioRenderer("Send");
rlm@56 134 app.setSettings(settings);
rlm@49 135
rlm@56 136 JmeSystem.setSystemDelegate(new AurellemSystemDelegate());
rlm@49 137
rlm@56 138 final WaveFileWriter writer = new WaveFileWriter(file);
rlm@12 139
rlm@56 140 Callable<Object> thunk = new Callable<Object>(){
rlm@56 141 public Object call(){
rlm@56 142 AudioRenderer ar = app.getAudioRenderer();
rlm@56 143 if (ar instanceof MultiListener){
rlm@56 144 MultiListener ml = (MultiListener)ar;
rlm@56 145 ml.registerSoundProcessor(writer);
rlm@56 146 }
rlm@56 147 return null;
rlm@56 148 }
rlm@56 149 };
rlm@56 150 app.enqueue(thunk);
rlm@56 151 }
rlm@3 152 }