Mercurial > jmeCapture
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