# HG changeset patch # User Robert McIntyre # Date 1320361246 25200 # Node ID 784a3f4e6202d99bb0e08d3a6ba7533f2d84bd13 # Parent adeb887876458ea94e63d19ff81e48141723ad77 updating capture-video diff -r adeb88787645 -r 784a3f4e6202 .hgignore --- a/.hgignore Mon Oct 31 07:43:44 2011 -0700 +++ b/.hgignore Thu Nov 03 16:00:46 2011 -0700 @@ -8,5 +8,5 @@ dist* lib* .ant* +output/* - diff -r adeb88787645 -r 784a3f4e6202 src/ca/randelshofer/AVIOutputStream.java --- a/src/ca/randelshofer/AVIOutputStream.java Mon Oct 31 07:43:44 2011 -0700 +++ b/src/ca/randelshofer/AVIOutputStream.java Thu Nov 03 16:00:46 2011 -0700 @@ -627,7 +627,7 @@ } /** - * Sets the state of the QuickTimeOutpuStream to started. + * Sets the state of the AVIOutputStream to 'started'. *

* If the state is changed by this method, the prolog is * written. diff -r adeb88787645 -r 784a3f4e6202 src/com/aurellem/capture/Capture.java --- a/src/com/aurellem/capture/Capture.java Mon Oct 31 07:43:44 2011 -0700 +++ b/src/com/aurellem/capture/Capture.java Thu Nov 03 16:00:46 2011 -0700 @@ -8,6 +8,7 @@ import com.aurellem.capture.audio.WaveFileWriter; import com.aurellem.capture.video.AVIVideoRecorder; import com.aurellem.capture.video.AbstractVideoRecorder; +import com.aurellem.capture.video.FileVideoRecorder; import com.aurellem.capture.video.XuggleVideoRecorder; import com.jme3.app.Application; import com.jme3.audio.AudioRenderer; @@ -27,6 +28,8 @@ if (file.getCanonicalPath().endsWith(".avi")){ videoRecorder = new AVIVideoRecorder(file);} + else if (file.isDirectory()){ + videoRecorder = new FileVideoRecorder(file);} else { videoRecorder = new XuggleVideoRecorder(file);} Callable thunk = new Callable(){ diff -r adeb88787645 -r 784a3f4e6202 src/com/aurellem/capture/audio/AudioSendRenderer.java --- a/src/com/aurellem/capture/audio/AudioSendRenderer.java Mon Oct 31 07:43:44 2011 -0700 +++ b/src/com/aurellem/capture/audio/AudioSendRenderer.java Thu Nov 03 16:00:46 2011 -0700 @@ -136,8 +136,7 @@ this.audioSend = new AudioSend(this.deviceID); this.outFormat = audioSend.getAudioFormat(); initBuffer(); - System.out.println(outFormat); - + // The LWJGL context must be established as the master context before // any other listeners can be created on this device. audioSend.initDevice(); @@ -173,22 +172,14 @@ } - //public final static int BYTES_PER_SAMPLE = 4; - - private ByteBuffer buffer;; - private byte[] debug0; - private byte[] debug1; - + public static final int MIN_FRAMERATE = 10; private void initBuffer(){ int bufferSize = (int)(this.outFormat.getSampleRate() / ((float)MIN_FRAMERATE)) * this.outFormat.getFrameSize(); this.buffer = BufferUtils.createByteBuffer(bufferSize); - debug0 = new byte[4096]; - debug1 = new byte[4096]; - } /* @@ -196,33 +187,19 @@ public void dispatchAudio(float tpf){ int samplesToGet = (int) (tpf * outFormat.getSampleRate()); - System.out.println("want " + samplesToGet + " samples"); try {latch.await();} catch (InterruptedException e) {e.printStackTrace();} audioSend.step(samplesToGet); updateAllListeners(); - + for (int i = 0; i < this.listeners.size(); i++){ buffer.clear(); audioSend.getSamples(buffer, samplesToGet, i); - if (i == 0 ) buffer.get(debug0); - if (i == 1 ) buffer.get(debug1); SoundProcessor sp = - this.soundProcessorMap.get(this.listeners.get(i)); + this.soundProcessorMap.get(this.listeners.get(i)); if (null != sp){sp.process(buffer, samplesToGet*outFormat.getFrameSize(), outFormat);} } - - for (int i = 0; i < samplesToGet; i++){ - if (debug1[i] != debug0[i]){ - System.out.println("inconsistency detected @ sample " + i); - System.out.println("main : " + debug0[i]); - System.out.println("aux : " + debug1[i]); - - break; - } - - } - + } public void update(float tpf){ diff -r adeb88787645 -r 784a3f4e6202 src/com/aurellem/capture/audio/SoundProcessor.java --- a/src/com/aurellem/capture/audio/SoundProcessor.java Mon Oct 31 07:43:44 2011 -0700 +++ b/src/com/aurellem/capture/audio/SoundProcessor.java Thu Nov 03 16:00:46 2011 -0700 @@ -6,8 +6,25 @@ public interface SoundProcessor { - void cleanup(); + /** + * Called when the SoundProcessor is being destroyed, and + * there are no more samples to process. This happens at the + * latest when the Application is shutting down. + * + */ + void cleanup(); - void process(ByteBuffer audioSamples, int numSamples, AudioFormat format); + /** + * + * Called whenever there are new audio samples to process. The + * audioSamples ByteBuffer contains 3D audio data rendered by + * OpenAL. + * + * @param audioSamples a ByteBuffer containing processed audio + * samples + * @param numSamples the number of samples, in bytes, that are valid + * @param format the format of the audio samples in audioSamples + */ + void process(ByteBuffer audioSamples, int numSamples, AudioFormat format); } diff -r adeb88787645 -r 784a3f4e6202 src/com/aurellem/capture/examples/AdvancedAudio.java --- a/src/com/aurellem/capture/examples/AdvancedAudio.java Mon Oct 31 07:43:44 2011 -0700 +++ b/src/com/aurellem/capture/examples/AdvancedAudio.java Thu Nov 03 16:00:46 2011 -0700 @@ -19,7 +19,6 @@ import com.aurellem.capture.audio.WaveFileWriter; import com.jme3.app.SimpleApplication; import com.jme3.audio.AudioNode; -import com.jme3.audio.AudioParam; import com.jme3.audio.Listener; import com.jme3.audio.ListenerParam; import com.jme3.cinematic.MotionPath; @@ -34,7 +33,6 @@ import com.jme3.math.Vector3f; import com.jme3.scene.Geometry; import com.jme3.scene.Node; -import com.jme3.scene.Spatial; import com.jme3.scene.shape.Box; import com.jme3.scene.shape.Sphere; import com.jme3.system.AppSettings; @@ -69,16 +67,18 @@ app.setSettings(settings); app.setShowSettings(false); app.setPauseOnLostFocus(false); - org.lwjgl.input.Mouse.setGrabbed(false); - //try {Capture.captureVideo(app, new File("/home/r/tmp/out.avi"));} - //catch (IOException e) {e.printStackTrace();} + + try {Capture.captureVideo(app, new File("/home/r/tmp/out")); + Capture.captureAudio(app, new File("/home/r/tmp/main.wav"));} + catch (IOException e) {e.printStackTrace();} app.start(); + } private MotionTrack motionControl; - private Spatial makeEar(Node root, Vector3f position){ + private Geometry makeEar(Node root, Vector3f position){ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); Geometry ear = new Geometry("ear", new Box(1.0f, 1.0f, 1.0f)); ear.setLocalTranslation(position); @@ -90,10 +90,10 @@ private Geometry bell; - private Spatial ear1; - //private Spatial ear2; - //private Spatial ear3; - //private Spatial ear4; + private Geometry ear1; + private Geometry ear2; + private Geometry ear3; + private Vector3f[] path = new Vector3f[]{ @@ -160,9 +160,9 @@ rootNode.addLight(light); ear1 = makeEar(rootNode, new Vector3f(0, 0 ,-20)); - //ear2 = makeEar(rootNode, new Vector3f(0, 0 ,-20)); - //ear3 = makeEar(rootNode, new Vector3f(20, 0 ,0)); - //ear4 = makeEar(rootNode, new Vector3f(-20, 0 ,0)); + ear2 = makeEar(rootNode, new Vector3f(0, 0 ,20)); + ear3 = makeEar(rootNode, new Vector3f(20, 0 ,0)); + MotionPath track = new MotionPath(); @@ -204,7 +204,7 @@ private void initAudio() { - + org.lwjgl.input.Mouse.setGrabbed(false); music = new AudioNode(assetManager, "Sound/Environment/sqr-1kHz.wav", false); rootNode.attachChild(music); @@ -234,14 +234,10 @@ public class Dancer implements SoundProcessor { - - Spatial entity; - + Geometry entity; float scale = 2; - String debug; - public Dancer(Spatial entity, String debug){ + public Dancer(Geometry entity){ this.entity = entity; - this.debug = debug; } /** @@ -265,10 +261,9 @@ float max = Float.NEGATIVE_INFINITY; for (float f : out){if (f > max) max = f;} audioSamples.clear(); - System.out.println(debug); - System.out.println(max); - + if (max > 0.1){entity.getMaterial().setColor("Color", ColorRGBA.Green);} + else {entity.getMaterial().setColor("Color", ColorRGBA.Gray);} //entity.scale(this.scale); //if (this.scale == 2f){this.scale = 0.5f;} @@ -280,38 +275,35 @@ + private void prepareEar(Geometry ear, int n){ + if (this.audioRenderer instanceof MultiListener){ + MultiListener rf = (MultiListener)this.audioRenderer; + + auxListener = new Listener(); + auxListener.setLocation(ear.getLocalTranslation()); + + rf.addListener(auxListener); + WaveFileWriter aux = null; + + try {aux = new WaveFileWriter(new File("/home/r/tmp/ear"+n+".wav"));} + catch (FileNotFoundException e) {e.printStackTrace();} + + rf.registerSoundProcessor(auxListener, + new CompositeSoundProcessor(new Dancer(ear), aux)); + + } + } + public void simpleInitApp() { this.setTimer(new IsoTimer(60)); initAudio(); initKeys(); createScene(); - listener.setLocation(ear1.getLocalTranslation()); - listener.setRotation(new Quaternion().fromAngleAxis(0, Vector3f.UNIT_Y)); - if (this.audioRenderer instanceof MultiListener){ - MultiListener rf = (MultiListener)this.audioRenderer; - - - auxListener = new Listener(listener); - - rf.addListener(auxListener); - WaveFileWriter aux = null; - WaveFileWriter main = null; - - - try {aux = new WaveFileWriter(new File("/home/r/tmp/aux.wav"));} - catch (FileNotFoundException e) {e.printStackTrace();} - - try {main = new WaveFileWriter(new File("/home/r/tmp/main.wav"));} - catch (FileNotFoundException e) {e.printStackTrace();} - - rf.registerSoundProcessor(auxListener, - new CompositeSoundProcessor(new Dancer(ear1, "aux"), aux)); - - rf.registerSoundProcessor( - new CompositeSoundProcessor(new Dancer(ear1, "--------\nmain"), main)); - } + prepareEar(ear1, 1); + prepareEar(ear2, 1); + prepareEar(ear3, 1); motionControl.play(); } @@ -350,15 +342,15 @@ if (countdown == 0){ music.play(); } - //Vector3f loc = cam.getLocation(); - //Quaternion rot = cam.getRotation(); - //listener.setLocation(loc); - listener.setRotation(new Quaternion().fromAngleAxis(0, music.getLocalTranslation().subtract(listener.getLocation()))); + Vector3f loc = cam.getLocation(); + Quaternion rot = cam.getRotation(); + listener.setLocation(loc); + listener.setRotation(rot); audioRenderer.updateListenerParam(listener, ListenerParam.Rotation); - System.out.println(countdown); + //System.out.println(countdown); - if (countdown++ == 300) { this.requestClose(false);} + //if (countdown++ == 300) { this.requestClose(false);} //System.out.println("channel "+ music.getChannel()); //listener.setLocation(cam.getLocation()); @@ -378,8 +370,8 @@ music.setLocalTranslation(bell.getLocalTranslation()); - System.out.println("distance: " + - music.getLocalTranslation().subtract(listener.getLocation()).length()); + //System.out.println("distance: " + + // music.getLocalTranslation().subtract(listener.getLocation()).length()); //music.setVelocity(bellVelocity); diff -r adeb88787645 -r 784a3f4e6202 src/com/aurellem/capture/examples/HelloVideo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/com/aurellem/capture/examples/HelloVideo.java Thu Nov 03 16:00:46 2011 -0700 @@ -0,0 +1,22 @@ +package com.aurellem.capture.examples; + +import java.io.File; +import java.io.IOException; + +import jme3test.helloworld.HelloLoop; + +import com.aurellem.capture.IsoTimer; +import com.aurellem.capture.Capture; +import com.jme3.app.SimpleApplication; + +public class HelloVideo { + + public static void main(String[] ignore) throws IOException { + SimpleApplication app = new HelloLoop(); + File video = File.createTempFile("helloVideo", ".avi"); + app.setTimer(new IsoTimer(60)); + Capture.captureVideo(app, video); + app.start(); + System.out.println(video.getCanonicalPath()); + } +} diff -r adeb88787645 -r 784a3f4e6202 src/com/aurellem/capture/video/AVIVideoRecorder.java --- a/src/com/aurellem/capture/video/AVIVideoRecorder.java Mon Oct 31 07:43:44 2011 -0700 +++ b/src/com/aurellem/capture/video/AVIVideoRecorder.java Thu Nov 03 16:00:46 2011 -0700 @@ -9,38 +9,38 @@ public class AVIVideoRecorder extends AbstractVideoRecorder{ - AVIOutputStream out = null; - boolean videoReady = false; - BufferedImage frame; + AVIOutputStream out = null; + boolean videoReady = false; + BufferedImage frame; - public AVIVideoRecorder(File output) throws IOException { - super(output); - this.out = new AVIOutputStream(output, AVIOutputStream.VideoFormat.PNG, 24); - this.out.setVideoCompressionQuality(1.0f); - } - + public AVIVideoRecorder(File output) throws IOException { + super(output); + this.out = new + AVIOutputStream(output, AVIOutputStream.VideoFormat.RAW, 24); + this.out.setFrameRate(60); + } - public void initVideo (){ - frame = new BufferedImage( - width, height, - BufferedImage.TYPE_INT_RGB); - out.setFrameRate((int) Math.round(this.fps)); - out.setTimeScale(1); - out.setVideoDimension(width, height); - this.videoReady = true; - } + public void initVideo (){ + frame = new BufferedImage( + width, height, + BufferedImage.TYPE_INT_RGB); + out.setFrameRate((int) Math.round(this.fps)); + out.setTimeScale(1); + out.setVideoDimension(width, height); + this.videoReady = true; + } - public void record(BufferedImage rawFrame) { - if (!videoReady){initVideo();} - this.frame.getGraphics().drawImage(rawFrame, 0, 0, null); - try {out.writeFrame(frame);} - catch (IOException e){e.printStackTrace();} - } + public void record(BufferedImage rawFrame) { + if (!videoReady){initVideo();} + this.frame.getGraphics().drawImage(rawFrame, 0, 0, null); + try {out.writeFrame(frame);} + catch (IOException e){e.printStackTrace();} + } - public void finish() { - try {out.close();} - catch (IOException e) {e.printStackTrace();} - } + public void finish() { + try {out.close();} + catch (IOException e) {e.printStackTrace();} + } diff -r adeb88787645 -r 784a3f4e6202 src/com/aurellem/capture/video/AbstractVideoRecorder.java --- a/src/com/aurellem/capture/video/AbstractVideoRecorder.java Mon Oct 31 07:43:44 2011 -0700 +++ b/src/com/aurellem/capture/video/AbstractVideoRecorder.java Thu Nov 03 16:00:46 2011 -0700 @@ -19,9 +19,9 @@ import com.jme3.util.Screenshots; /** - * VideoProcessor copies the frames it receives to video. + * VideoRecorder copies the frames it receives to video. * To ensure smooth video at a constant framerate, you should set your - * application's timer to a new {@link IsoTimer}. This class will + * application's timer to a new IsoTimer. This class will * auto-determine the framerate of the video based on the time difference * between the first two frames it receives, although you can manually set * the framerate by calling setFps(newFramerate). Be sure to @@ -44,7 +44,7 @@ */ public abstract class AbstractVideoRecorder - implements SceneProcessor, IVideoRecorder, AppState{ + implements SceneProcessor, VideoRecorder, AppState{ final File output; Camera camera; diff -r adeb88787645 -r 784a3f4e6202 src/com/aurellem/capture/video/FileVideoRecorder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/com/aurellem/capture/video/FileVideoRecorder.java Thu Nov 03 16:00:46 2011 -0700 @@ -0,0 +1,41 @@ +package com.aurellem.capture.video; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import javax.imageio.ImageIO; + +public class FileVideoRecorder extends AbstractVideoRecorder{ + int current; + File outDir; + String formatName = "png"; + + public FileVideoRecorder(File output) throws IOException { + super(output); + if (output.exists() + && output.isDirectory() + && (0 == output.listFiles().length)){ + // good + } + else if (!output.exists()){ + output.mkdir(); + } + else { + throw new IOException("argument must be either an empty " + + "directory or a nonexistent one."); + } + this.outDir = output; + } + + public void record(BufferedImage rawFrame) { + String name = String.format("%07d.%s" , current++, formatName); + File target = new File(output, name); + try {ImageIO.write(rawFrame, formatName, target);} + catch (IOException e) {e.printStackTrace();} + } + + public void finish() {} +} + + + diff -r adeb88787645 -r 784a3f4e6202 src/com/aurellem/capture/video/IVideoRecorder.java --- a/src/com/aurellem/capture/video/IVideoRecorder.java Mon Oct 31 07:43:44 2011 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ -package com.aurellem.capture.video; - -import java.awt.image.BufferedImage; - -public interface IVideoRecorder{ - - void record(BufferedImage image); - - void pause(); - - void start(); - - /** - * closes the video file, writing appropriate headers, trailers, etc. - * After this is called, no more recording can be done. - */ - void finish(); - -} - - diff -r adeb88787645 -r 784a3f4e6202 src/com/aurellem/capture/video/VideoRecorder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/com/aurellem/capture/video/VideoRecorder.java Thu Nov 03 16:00:46 2011 -0700 @@ -0,0 +1,29 @@ +package com.aurellem.capture.video; + +import java.awt.image.BufferedImage; + +public interface VideoRecorder{ + + /** + * Write this image to video, disk, etc. + * @param image the image to write + */ + void record(BufferedImage image); + + /** + * stop recording temporarally. The recording can be started again + * with start() + */ + void pause(); + + /** + * start the recording. + */ + void start(); + + /** + * closes the video file, writing appropriate headers, trailers, etc. + * After this is called, no more recording can be done. + */ + void finish(); +} \ No newline at end of file