changeset 68:302d5e9ad120

adjust format
author Robert McIntyre <rlm@mit.edu>
date Thu, 19 Jul 2012 12:28:55 -0500
parents 30cea3f0f30a
children ddb300c5335f 2c50a0c99715
files build.xml src/ca/randelshofer/AVIOutputStream.java src/ca/randelshofer/ImageOutputStreamAdapter.java src/ca/randelshofer/SeekableByteArrayOutputStream.java src/com/aurellem/capture/Capture.java src/com/aurellem/capture/audio/WaveFileWriter.java src/com/aurellem/capture/video/XuggleVideoRecorder.java
diffstat 7 files changed, 141 insertions(+), 112 deletions(-) [+]
line wrap: on
line diff
     1.1 --- a/build.xml	Tue Feb 28 11:17:04 2012 -0600
     1.2 +++ b/build.xml	Thu Jul 19 12:28:55 2012 -0500
     1.3 @@ -16,10 +16,12 @@
     1.4      <pathelement path="${lib}/jME3-core.jar"/>
     1.5      <pathelement path="${lib}/jME3-desktop.jar"/>
     1.6      <pathelement path="${lib}/jME3-lwjgl.jar"/>
     1.7 +    <pathelement path="${lib}/lwjgl.jar"/>
     1.8 +<!--
     1.9      <pathelement path="${lib}/logback-classic.jar"/>
    1.10      <pathelement path="${lib}/logback-core.jar"/>
    1.11 -    <pathelement path="${lib}/lwjgl.jar"/>
    1.12      <pathelement path="${lib}/slf4j-api.jar"/>
    1.13 +-->
    1.14      <pathelement path="${lib}/xuggle-xuggler.jar"/>
    1.15      <pathelement path="${lib}/tritonus_aos-0.3.6.jar"/>
    1.16      <pathelement path="${lib}/tritonus_share-0.3.6.jar"/>
    1.17 @@ -54,6 +56,9 @@
    1.18      
    1.19    </target>
    1.20  
    1.21 +
    1.22 +  <target name="all" depends="dist"/>
    1.23 +
    1.24    <target name="clean"> 
    1.25      <delete dir="${build}"/> 
    1.26      <delete dir="${dist}"/> 
     2.1 --- a/src/ca/randelshofer/AVIOutputStream.java	Tue Feb 28 11:17:04 2012 -0600
     2.2 +++ b/src/ca/randelshofer/AVIOutputStream.java	Thu Jul 19 12:28:55 2012 -0500
     2.3 @@ -1,7 +1,7 @@
     2.4  /**
     2.5   * @(#)AVIOutputStream.java  1.5.1  2011-01-17
     2.6   *
     2.7 - * Copyright (c) 2008-2011 Werner Randelshofer, Immensee, Switzerland.
     2.8 +* Copyright (c) 2008-2011 Werner Randelshofer, Immensee, Switzerland.
     2.9   * All rights reserved.
    2.10   *
    2.11   * You may not use, copy or modify this file, except in compliance with the
    2.12 @@ -1337,7 +1337,7 @@
    2.13          // Specifies an indicator of the quality of the data in the stream.
    2.14          // Quality is represented as a number between 0 and 10,000.
    2.15          // For compressed data, this typically represents the value of the
    2.16 -        // quality parameter passed to the compression software. If set to –1,
    2.17 +        // quality parameter passed to the compression software. If set to -1,
    2.18          // drivers use the default quality value.
    2.19  
    2.20          d.writeUInt(0); // dwSampleSize
     3.1 --- a/src/ca/randelshofer/ImageOutputStreamAdapter.java	Tue Feb 28 11:17:04 2012 -0600
     3.2 +++ b/src/ca/randelshofer/ImageOutputStreamAdapter.java	Thu Jul 19 12:28:55 2012 -0500
     3.3 @@ -1,7 +1,7 @@
     3.4  /*
     3.5   * @(#)ImageOutputStreamAdapter.java  1.1  2011-01-07
     3.6   *
     3.7 - * Copyright © 2010 Werner Randelshofer, Immensee, Switzerland.
     3.8 + * Copyright (c) 2010 Werner Randelshofer, Immensee, Switzerland.
     3.9   * All rights reserved.
    3.10   *
    3.11   * You may not use, copy or modify this file, except in compliance with the
     4.1 --- a/src/ca/randelshofer/SeekableByteArrayOutputStream.java	Tue Feb 28 11:17:04 2012 -0600
     4.2 +++ b/src/ca/randelshofer/SeekableByteArrayOutputStream.java	Thu Jul 19 12:28:55 2012 -0500
     4.3 @@ -1,7 +1,7 @@
     4.4  /*
     4.5   * @(#)SeekableByteArrayOutputStream.java  1.0  2010-12-27
     4.6   * 
     4.7 - * Copyright © 2010 Werner Randelshofer, Immensee, Switzerland.
     4.8 + * Copyright (c) 2010 Werner Randelshofer, Immensee, Switzerland.
     4.9   * All rights reserved.
    4.10   * 
    4.11   * You may not use, copy or modify this file, except in compliance with the
     5.1 --- a/src/com/aurellem/capture/Capture.java	Tue Feb 28 11:17:04 2012 -0600
     5.2 +++ b/src/com/aurellem/capture/Capture.java	Thu Jul 19 12:28:55 2012 -0500
     5.3 @@ -18,19 +18,21 @@
     5.4  import com.jme3.system.JmeSystem;
     5.5  
     5.6  /**
     5.7 - * Use the methods in this class for capturing consistent, high quality video
     5.8 - * and audio from a jMonkeyEngine3 application.  To capture audio or video do
     5.9 - * the following:
    5.10 + * Use the methods in this class for capturing consistent,
    5.11 + * high quality video and audio from a jMonkeyEngine3
    5.12 + * application.  To capture audio or video do the following:
    5.13   * 
    5.14 - * 1.) Set your application's timer to an IsoTimer. Create the IsoTimer with the
    5.15 - *     desired video frames-per-second.
    5.16 + * 1.) Set your application's timer to an IsoTimer. Create
    5.17 + *     the IsoTimer with the desired video
    5.18 + *     frames-per-second.
    5.19   *
    5.20 - * 2.) Call captureAudio and/or captureVideo on the Application as desired
    5.21 - *     before starting the Application.
    5.22 + * 2.) Call captureAudio and/or captureVideo on the
    5.23 + *     Application as desired before starting the
    5.24 + *     Application.
    5.25   * 
    5.26 - * See the Basic and Advanced demos in the examples section for more
    5.27 - * information.  If you have any trouble, please PM me on the jMonkeyEngine
    5.28 - * forums.  My username is bortreb.
    5.29 + * See the Basic and Advanced demos in the examples section
    5.30 + * for more information.  If you have any trouble, please PM
    5.31 + * me on the jMonkeyEngine forums.  My username is bortreb.
    5.32   * 
    5.33   * @author Robert McIntyre
    5.34   */
    5.35 @@ -38,57 +40,69 @@
    5.36  public class Capture {
    5.37  
    5.38      /**
    5.39 -     * Use this function to capture video from your application.  You
    5.40 -     * specify the framerate at which the video will be recording by setting
    5.41 -     * the Application's timer to an IsoTimer created with the desired
    5.42 +     * Use this function to capture video from your
    5.43 +     * application.  You specify the framerate at which the
    5.44 +     * video will be recording by setting the Application's
    5.45 +     * timer to an IsoTimer created with the desired
    5.46       * frames-per-second.
    5.47       * 
    5.48 -     * There are three ways to record and they are selected by the
    5.49 -     * properties of the file that you specify.
    5.50 +     * There are three ways to record and they are selected
    5.51 +     * by the properties of the file that you specify.
    5.52       * 
    5.53 -     * 1.) (Preferred) If you supply an empty directory as the file, then
    5.54 -     *     the video will be saved as a sequence of .png files, one file per
    5.55 -     *     frame.  The files start at 0000000.png and increment from there.
    5.56 -     *     You can then combine the frames into your preferred
    5.57 -     *     container/codec. If the directory is not empty, then writing
    5.58 -     *     video frames to it will fail, and nothing will be written.
    5.59 +     * 1.) (Preferred) If you supply an empty directory as
    5.60 +     *     the file, then the video will be saved as a
    5.61 +     *     sequence of .png files, one file per frame.  The
    5.62 +     *     files start at 0000000.png and increment from
    5.63 +     *     there.  You can then combine the frames into your
    5.64 +     *     preferred container/codec. If the directory is
    5.65 +     *     not empty, then writing video frames to it will
    5.66 +     *     fail, and nothing will be written.
    5.67       *     
    5.68 -     * 2.) If the filename ends in ".avi" then the frames will be encoded as
    5.69 -     *     a RAW stream inside an AVI 1.0 container.  The resulting file
    5.70 -     *     will be quite large and you will probably want to re-encode it to
    5.71 -     *     your preferred container/codec format.  Be advised that some
    5.72 -     *     video payers cannot process AVI with a RAW stream, and that AVI
    5.73 -     *     1.0 files generated by this method that exceed 2.0GB are invalid
    5.74 -     *     according to the AVI 1.0 spec (but many programs can still deal
    5.75 -     *     with them.)  Thanks to Werner Randelshofer for his excellent work
    5.76 -     *     which made AVI file writer option possible.
    5.77 +     * 2.) If the filename ends in ".avi" then the frames
    5.78 +     *     will be encoded as a RAW stream inside an AVI 1.0
    5.79 +     *     container.  The resulting file will be quite
    5.80 +     *     large and you will probably want to re-encode it
    5.81 +     *     to your preferred container/codec format.  Be
    5.82 +     *     advised that some video payers cannot process AVI
    5.83 +     *     with a RAW stream, and that AVI 1.0 files
    5.84 +     *     generated by this method that exceed 2.0GB are
    5.85 +     *     invalid according to the AVI 1.0 spec (but many
    5.86 +     *     programs can still deal with them.)  Thanks to
    5.87 +     *     Werner Randelshofer for his excellent work which
    5.88 +     *     made AVI file writer option possible.
    5.89       *  
    5.90 -     * 3.) Any non-directory file ending in anything other than ".avi" will
    5.91 -     *     be processed through Xuggle.  Xuggle provides the option to use
    5.92 -     *     many codecs/containers, but you will have to install it on your
    5.93 -     *     system yourself in order to use this option. Please visit
    5.94 -     *     http://www.xuggle.com/ to learn how to do this.
    5.95 +     * 3.) Any non-directory file ending in anything other
    5.96 +     *     than ".avi" will be processed through Xuggle.
    5.97 +     *     Xuggle provides the option to use many
    5.98 +     *     codecs/containers, but you will have to install
    5.99 +     *     it on your system yourself in order to use this
   5.100 +     *     option. Please visit http://www.xuggle.com/ to
   5.101 +     *     learn how to do this.
   5.102       * 
   5.103       * @param app The Application from which you wish to record Video.
   5.104       * @param file The file to which the video will be captured. 
   5.105       * @throws IOException
   5.106       */
   5.107  	
   5.108 -    public static void captureVideo(final Application app, final File file) throws IOException{
   5.109 +    public static void captureVideo
   5.110 +	(final Application app, final File file) throws IOException{
   5.111  	final AbstractVideoRecorder videoRecorder;
   5.112  
   5.113  	if (file.getCanonicalPath().endsWith(".avi")){
   5.114  	    videoRecorder = new AVIVideoRecorder(file);}
   5.115  	else if (file.isDirectory()){
   5.116  	    videoRecorder = new FileVideoRecorder(file);}
   5.117 -	else { videoRecorder = new XuggleVideoRecorder(file);}
   5.118 +	else { 
   5.119 +	    videoRecorder = new XuggleVideoRecorder(file);
   5.120 +	}
   5.121  
   5.122  	Callable<Object> thunk = new Callable<Object>(){
   5.123  	    public Object call(){
   5.124  
   5.125  		ViewPort viewPort = 
   5.126  		app.getRenderManager()
   5.127 -		.createPostView("aurellem video record", app.getCamera());
   5.128 +		.createPostView("aurellem video record", 
   5.129 +				app.getCamera());
   5.130  
   5.131  		viewPort.setClearFlags(false, false, false);
   5.132  
   5.133 @@ -107,28 +121,34 @@
   5.134  
   5.135  
   5.136      /**
   5.137 -     * Use this function to capture audio from your application.  Audio data
   5.138 -     * will be saved in linear PCM format at 44,100 hertz in the wav container
   5.139 -     * format to the file that you specify.
   5.140 +     * Use this function to capture audio from your
   5.141 +     * application.  Audio data will be saved in linear PCM
   5.142 +     * format at 44,100 hertz in the wav container format to
   5.143 +     * the file that you specify.
   5.144       * 
   5.145 -     * Note that you *have* to use an IsoTimer for your Application's timer
   5.146 -     * while recording audio or the recording will fail. Also ensure that your
   5.147 -     * IsoTimer obeys the following constraints:
   5.148 +     * Note that you *have* to use an IsoTimer for your
   5.149 +     * Application's timer while recording audio or the
   5.150 +     * recording will fail. Also ensure that your IsoTimer
   5.151 +     * obeys the following constraints:
   5.152       * 
   5.153 -     *  1.) The frames-per-second value of the IsoTimer cannot be lower than 10
   5.154 -     *   frames-per-second.
   5.155 +     *  1.) The frames-per-second value of the IsoTimer
   5.156 +     *   cannot be lower than 10 frames-per-second.
   5.157       *
   5.158 -     *  2.) The frames-per-second value of the IsoTimer must evenly divide
   5.159 -     *   44,100.
   5.160 +     *  2.) The frames-per-second value of the IsoTimer must
   5.161 +     *   evenly divide 44,100.
   5.162       * 
   5.163 -     * @param app The Application from which you wish to record Audio.
   5.164 -     * @param file the target file to which you want to record audio data.
   5.165 +     * @param app The Application from which you wish to
   5.166 +     * record Audio.
   5.167 +     * @param file the target file to which you want to
   5.168 +     * record audio data.
   5.169       * @throws IOException
   5.170       */
   5.171  	
   5.172 -    public static void captureAudio(final Application app, final File file) throws IOException{
   5.173 +    public static void captureAudio
   5.174 +	(final Application app, final File file) throws IOException{
   5.175  	AppSettings settings = null;
   5.176 -	if (app.getContext() != null){settings = app.getContext().getSettings();}
   5.177 +	if (app.getContext() != null){
   5.178 +	    settings = app.getContext().getSettings();}
   5.179  	if (settings == null){settings = new AppSettings(true);}
   5.180  	settings.setAudioRenderer("Send");
   5.181  	app.setSettings(settings);
     6.1 --- a/src/com/aurellem/capture/audio/WaveFileWriter.java	Tue Feb 28 11:17:04 2012 -0600
     6.2 +++ b/src/com/aurellem/capture/audio/WaveFileWriter.java	Thu Jul 19 12:28:55 2012 -0500
     6.3 @@ -21,37 +21,38 @@
     6.4  
     6.5  public class WaveFileWriter implements SoundProcessor {
     6.6  
     6.7 -	public File targetFile;
     6.8 -	private WaveAudioOutputStream wao;
     6.9 -	private TDataOutputStream tos;
    6.10 -	private boolean initialized = false;
    6.11 +    public File targetFile;
    6.12 +    private WaveAudioOutputStream wao;
    6.13 +    private TDataOutputStream tos;
    6.14 +    private boolean initialized = false;
    6.15  	
    6.16 -	public WaveFileWriter(File targetFile) throws FileNotFoundException{
    6.17 -		tos = new TNonSeekableDataOutputStream(
    6.18 -				new FileOutputStream(targetFile));
    6.19 -	}
    6.20 +    public WaveFileWriter(File targetFile) 
    6.21 +	throws FileNotFoundException{
    6.22 +	tos = new TNonSeekableDataOutputStream
    6.23 +	    (new FileOutputStream(targetFile));
    6.24 +    }
    6.25  
    6.26 -	public void init(AudioFormat format){
    6.27 -		wao = new WaveAudioOutputStream(format,AudioSystem.NOT_SPECIFIED, tos);
    6.28 +    public void init(AudioFormat format){
    6.29 +	wao = new WaveAudioOutputStream(format,AudioSystem.NOT_SPECIFIED, tos);
    6.30 +    }
    6.31 +		
    6.32 +    public void process(ByteBuffer audioSamples, int numSamples, AudioFormat format) {
    6.33 +	audioSamples.clear();
    6.34 +	if (!initialized){
    6.35 +	    init(format);
    6.36 +	    initialized = true;
    6.37  	}
    6.38  		
    6.39 -	public void process(ByteBuffer audioSamples, int numSamples, AudioFormat format) {
    6.40 -		audioSamples.clear();
    6.41 -		if (!initialized){
    6.42 -			init(format);
    6.43 -			initialized = true;
    6.44 -		}
    6.45 -		
    6.46 -		byte[] data = new byte[numSamples];
    6.47 -		audioSamples.get(data, 0, numSamples);
    6.48 -		try {wao.write(data, 0, numSamples);}
    6.49 -		catch (IOException e) {e.printStackTrace();}
    6.50 -	}
    6.51 +	byte[] data = new byte[numSamples];
    6.52 +	audioSamples.get(data, 0, numSamples);
    6.53 +	try {wao.write(data, 0, numSamples);}
    6.54 +	catch (IOException e) {e.printStackTrace();}
    6.55 +    }
    6.56  
    6.57 -	public void cleanup() {
    6.58 -		try {wao.close();}
    6.59 -		catch (IOException e) {e.printStackTrace();}
    6.60 -	}
    6.61 +    public void cleanup() {
    6.62 +	try {wao.close();}
    6.63 +	catch (IOException e) {e.printStackTrace();}
    6.64 +    }
    6.65  
    6.66  
    6.67  }
     7.1 --- a/src/com/aurellem/capture/video/XuggleVideoRecorder.java	Tue Feb 28 11:17:04 2012 -0600
     7.2 +++ b/src/com/aurellem/capture/video/XuggleVideoRecorder.java	Thu Jul 19 12:28:55 2012 -0500
     7.3 @@ -19,40 +19,43 @@
     7.4  
     7.5  public  class XuggleVideoRecorder extends AbstractVideoRecorder{
     7.6  
     7.7 -	IMediaWriter writer;
     7.8 -	BufferedImage frame;
     7.9 -	int videoChannel = 0;
    7.10 -	long currentTimeStamp = 0;
    7.11 -	boolean videoReady = false;
    7.12 +    
    7.13 +    IMediaWriter writer;
    7.14 +    BufferedImage frame;
    7.15 +    int videoChannel = 0;
    7.16 +    long currentTimeStamp = 0;
    7.17 +    boolean videoReady = false;
    7.18 +    
    7.19  	
    7.20 +    public XuggleVideoRecorder(File output) 
    7.21 +	throws IOException {super(output);}
    7.22  	
    7.23 -	public XuggleVideoRecorder(File output) throws IOException {super(output);}
    7.24 +    public void initVideo(){
    7.25 +	this.frame = new BufferedImage(
    7.26 +				       width, height,
    7.27 +				       BufferedImage.TYPE_3BYTE_BGR);
    7.28 +	this.writer = ToolFactory.makeWriter(this.targetFileName);
    7.29 +	writer.addVideoStream(videoChannel, 
    7.30 +			      0, IRational.make(fps), 
    7.31 +			      width, height);
    7.32 +	this.videoReady = true;
    7.33 +    }
    7.34  	
    7.35 -	public void initVideo(){
    7.36 -		this.frame = new BufferedImage(
    7.37 -				width, height,
    7.38 -				BufferedImage.TYPE_3BYTE_BGR);
    7.39 -		this.writer = ToolFactory.makeWriter(this.targetFileName);
    7.40 -		writer.addVideoStream(videoChannel, 
    7.41 -				0, IRational.make(fps), 
    7.42 -				width, height);
    7.43 -		this.videoReady = true;
    7.44 -	}
    7.45 -	
    7.46 -	public void record(BufferedImage rawFrame) {
    7.47 -		if (!this.videoReady){initVideo();}
    7.48 -		// convert the Image into the form that Xuggle likes.
    7.49 -		this.frame.getGraphics().drawImage(rawFrame, 0, 0, null);
    7.50 -		writer.encodeVideo(videoChannel, 
    7.51 -			frame,
    7.52 -			currentTimeStamp, TimeUnit.NANOSECONDS);
    7.53 +    public void record(BufferedImage rawFrame) {
    7.54 +	if (!this.videoReady){initVideo();}
    7.55 +	// convert the Image into the form that Xuggle likes.
    7.56 +	this.frame.getGraphics().drawImage(rawFrame, 0, 0, null);
    7.57 +	writer.encodeVideo(videoChannel, 
    7.58 +			   frame,
    7.59 +			   currentTimeStamp, TimeUnit.NANOSECONDS);
    7.60  		
    7.61 -		currentTimeStamp += (long) (1000000000.0 / fps);
    7.62 -	}
    7.63 +	currentTimeStamp += (long) (1000000000.0 / fps);
    7.64 +    }
    7.65  
    7.66 -	public void finish() {
    7.67 -		writer.close();
    7.68 -	}
    7.69 +    public void finish() {
    7.70 +	writer.close();
    7.71 +    }
    7.72 +    
    7.73  	
    7.74  }
    7.75