git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@8318 75d07b2b-3a1a-0410-a2c5-0572b91ccdca3.0
parent
3f95a0ca2f
commit
b1e46de5ee
@ -1,43 +0,0 @@ |
||||
/* |
||||
* Copyright (c) 2009-2010 jMonkeyEngine |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* |
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.jme3.video; |
||||
|
||||
@Deprecated |
||||
public interface Clock { |
||||
|
||||
public static final long MILLIS_TO_NANOS = 1000000; |
||||
public static final long SECONDS_TO_NANOS = 1000000000; |
||||
|
||||
public long getTime(); |
||||
public double getTimeSeconds(); |
||||
} |
@ -1,177 +0,0 @@ |
||||
/* |
||||
* Copyright (c) 2009-2010 jMonkeyEngine |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* |
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.jme3.video; |
||||
|
||||
@Deprecated |
||||
public final class RingBuffer { |
||||
|
||||
private final int bufSize; |
||||
private final byte[] buf; |
||||
private final Object lock = new Object(); |
||||
|
||||
private volatile int writePos; |
||||
private volatile int readPos; |
||||
|
||||
// private volatile boolean eof;
|
||||
private volatile long totalRead = 0, |
||||
totalWritten = 0; |
||||
|
||||
public RingBuffer(int size) { |
||||
bufSize = size; |
||||
buf = new byte[size]; |
||||
} |
||||
|
||||
public int remainingForWrite() { |
||||
if (writePos < readPos) return readPos - writePos - 1; |
||||
if (writePos == readPos) return bufSize - 1; |
||||
return bufSize - (writePos - readPos) - 1; |
||||
} |
||||
|
||||
public void write(byte[] data, int offset, int length) { |
||||
if (length == 0) return; |
||||
|
||||
synchronized (lock) { |
||||
while (remainingForWrite() < length) { |
||||
System.out.println("Warning: Audio decoder starved, waiting for player"); |
||||
try { |
||||
lock.wait(); |
||||
} catch (InterruptedException ex) { |
||||
} |
||||
} |
||||
|
||||
// copy data
|
||||
if (writePos >= readPos) { |
||||
int l = Math.min(length, bufSize - writePos); |
||||
System.arraycopy(data, offset, buf, writePos, l); |
||||
writePos += l; |
||||
if (writePos >= bufSize) writePos = 0; |
||||
if (length > l) write(data, offset + l, length - l); |
||||
} else { |
||||
int l = Math.min(length, readPos - writePos - 1); |
||||
System.arraycopy(data, offset, buf, writePos, l); |
||||
writePos += l; |
||||
if (writePos >= bufSize) writePos = 0; |
||||
} |
||||
|
||||
totalWritten += length; |
||||
} |
||||
} |
||||
|
||||
public int remainingForRead() { |
||||
if (writePos < readPos) return bufSize - (readPos - writePos); |
||||
if (writePos == readPos) return 0; |
||||
return writePos - readPos; |
||||
} |
||||
|
||||
public int skip(int amount){ |
||||
if (amount <= 0) return 0; |
||||
int dataLen = 0; |
||||
|
||||
synchronized (lock){ |
||||
if (remainingForRead() <= 0) |
||||
return 0; |
||||
|
||||
amount = Math.min(amount, remainingForRead()); |
||||
|
||||
// copy data
|
||||
if (readPos < writePos) { |
||||
int l = Math.min(amount, writePos - readPos); |
||||
readPos += l; |
||||
if (readPos >= bufSize) readPos = 0; |
||||
dataLen = l; |
||||
} else { |
||||
int l = Math.min(amount, bufSize - readPos); |
||||
readPos += l; |
||||
if (readPos >= bufSize) readPos = 0; |
||||
dataLen = l; |
||||
if (amount > l) dataLen += skip(amount - l); |
||||
} |
||||
lock.notifyAll(); |
||||
} |
||||
|
||||
totalRead += dataLen; |
||||
return dataLen; |
||||
} |
||||
|
||||
public int read(byte[] data, int offset, int len) { |
||||
if (len == 0) return 0; |
||||
int dataLen = 0; |
||||
|
||||
synchronized (lock) { |
||||
// see if we have enough data
|
||||
if (remainingForRead() <= 0){ |
||||
System.out.println("Warning: Audio starved. Not enough data."); |
||||
return 0; |
||||
} |
||||
|
||||
len = Math.min(len, remainingForRead()); |
||||
|
||||
// copy data
|
||||
if (readPos < writePos) { |
||||
int l = Math.min(len, writePos - readPos); |
||||
System.arraycopy(buf, readPos, data, offset, l); |
||||
readPos += l; |
||||
if (readPos >= bufSize) readPos = 0; |
||||
dataLen = l; |
||||
} else { |
||||
int l = Math.min(len, bufSize - readPos); |
||||
System.arraycopy(buf, readPos, data, offset, l); |
||||
readPos += l; |
||||
if (readPos >= bufSize) readPos = 0; |
||||
dataLen = l; |
||||
if (len > l) dataLen += read(data, offset + l, len - l); |
||||
} |
||||
lock.notifyAll(); |
||||
} |
||||
|
||||
totalRead += dataLen; |
||||
return dataLen; |
||||
} |
||||
|
||||
public long getTotalRead(){ |
||||
return totalRead; |
||||
} |
||||
|
||||
public long getTotalWritten(){ |
||||
return totalWritten; |
||||
} |
||||
|
||||
// public boolean isEOF() {
|
||||
// return eof;
|
||||
// }
|
||||
//
|
||||
// public void setEOF(boolean eof) {
|
||||
// this.eof = eof;
|
||||
// }
|
||||
|
||||
} |
@ -1,59 +0,0 @@ |
||||
/* |
||||
* Copyright (c) 2009-2010 jMonkeyEngine |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* |
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.jme3.video; |
||||
|
||||
@Deprecated |
||||
public class SystemClock implements Clock { |
||||
|
||||
private long startTime = 0; |
||||
|
||||
public SystemClock(){ |
||||
} |
||||
|
||||
public boolean needReset(){ |
||||
return startTime == 0; |
||||
} |
||||
|
||||
public void reset(){ |
||||
startTime = System.nanoTime(); |
||||
} |
||||
|
||||
public long getTime() { |
||||
return System.nanoTime() - startTime; |
||||
} |
||||
|
||||
public double getTimeSeconds(){ |
||||
return (double) getTime() / Clock.SECONDS_TO_NANOS; |
||||
} |
||||
|
||||
} |
@ -1,203 +0,0 @@ |
||||
/* |
||||
* Copyright (c) 2009-2010 jMonkeyEngine |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* |
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.jme3.video; |
||||
|
||||
import com.jme3.app.SimpleApplication; |
||||
import com.jme3.audio.AudioNode; |
||||
import com.jme3.system.AppSettings; |
||||
import com.jme3.texture.Image; |
||||
import com.jme3.ui.Picture; |
||||
import com.jme3.video.plugins.jheora.AVThread; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.net.URL; |
||||
|
||||
@Deprecated |
||||
public class TestVideoPlayer extends SimpleApplication { |
||||
|
||||
private Picture picture; |
||||
private AVThread decoder; |
||||
private Thread videoThread; |
||||
private VQueue videoQueue; |
||||
|
||||
private long lastFrameTime = 0; |
||||
private Clock masterClock; |
||||
private AudioNode source; |
||||
|
||||
private float waitTime = 0; |
||||
private VFrame frameToDraw = null; |
||||
|
||||
public static void main(String[] args){ |
||||
TestVideoPlayer app = new TestVideoPlayer(); |
||||
AppSettings settings = new AppSettings(true); |
||||
settings.setFrameRate(60); |
||||
app.setSettings(settings); |
||||
app.start(); |
||||
} |
||||
|
||||
private void createVideo(){ |
||||
try { |
||||
// uncomment to play video from harddrive
|
||||
// FileInputStream fis = new FileInputStream("E:\\bunny.ogg");
|
||||
InputStream fis = new URL("http://mirrorblender.top-ix.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_stereo.ogg").openStream(); |
||||
|
||||
// increasing queued frames value from 5 will make web streamed
|
||||
// playback smoother at the cost of memory.
|
||||
videoQueue = new VQueue(5); |
||||
decoder = new AVThread(fis, videoQueue); |
||||
videoThread = new Thread(decoder, "Jheora Video Decoder"); |
||||
videoThread.setDaemon(true); |
||||
videoThread.start(); |
||||
masterClock = decoder.getMasterClock(); |
||||
} catch (IOException ex) { |
||||
ex.printStackTrace(); |
||||
} |
||||
} |
||||
|
||||
public void simpleInitApp() { |
||||
picture = new Picture("VideoPicture", true); |
||||
picture.setPosition(0, 0); |
||||
picture.setWidth(settings.getWidth()); |
||||
picture.setHeight(settings.getHeight()); |
||||
picture.setImage(assetManager, "Interface/Logo/Monkey.jpg", false); |
||||
|
||||
// attach geometry to orthoNode
|
||||
rootNode.attachChild(picture); |
||||
|
||||
// start video playback
|
||||
createVideo(); |
||||
} |
||||
|
||||
private void drawFrame(VFrame frame){ |
||||
Image image = frame.getImage(); |
||||
frame.setImage(image); |
||||
picture.setTexture(assetManager, frame, false); |
||||
|
||||
// note: this forces renderer to upload frame immediately,
|
||||
// since it is going to be returned to the video queue pool
|
||||
// it could be used again.
|
||||
renderer.setTexture(0, frame); |
||||
videoQueue.returnFrame(frame); |
||||
lastFrameTime = frame.getTime(); |
||||
} |
||||
|
||||
private void waitNanos(long time){ |
||||
long millis = (long) (time / Clock.MILLIS_TO_NANOS); |
||||
int nanos = (int) (time - (millis * Clock.MILLIS_TO_NANOS)); |
||||
|
||||
try { |
||||
Thread.sleep(millis, nanos); |
||||
}catch (InterruptedException ex){ |
||||
stop(); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void simpleUpdate(float tpf){ |
||||
if (source == null){ |
||||
if (decoder.getAudioStream() != null){ |
||||
source = new AudioNode(audioRenderer, decoder.getAudioStream(), null); |
||||
source.setPositional(false); |
||||
source.setReverbEnabled(false); |
||||
audioRenderer.playSource(source); |
||||
}else{ |
||||
// uncomment this statement to be able to play videos
|
||||
// without audio.
|
||||
return; |
||||
} |
||||
} |
||||
|
||||
if (waitTime > 0){ |
||||
waitTime -= tpf; |
||||
if (waitTime > 0) |
||||
return; |
||||
else{ |
||||
waitTime = 0; |
||||
drawFrame(frameToDraw); |
||||
frameToDraw = null; |
||||
} |
||||
}else{ |
||||
VFrame frame; |
||||
try { |
||||
frame = videoQueue.take(); |
||||
} catch (InterruptedException ex){ |
||||
stop(); |
||||
return; |
||||
} |
||||
if (frame.getTime() < lastFrameTime){ |
||||
videoQueue.returnFrame(frame); |
||||
return; |
||||
} |
||||
|
||||
if (frame.getTime() == -2){ |
||||
// end of stream
|
||||
System.out.println("End of stream"); |
||||
stop(); |
||||
return; |
||||
} |
||||
|
||||
long AV_SYNC_THRESHOLD = 1 * Clock.MILLIS_TO_NANOS; |
||||
|
||||
long delay = frame.getTime() - lastFrameTime; |
||||
// delay -= tpf * Clock.SECONDS_TO_NANOS;
|
||||
long diff = frame.getTime() - masterClock.getTime(); |
||||
long syncThresh = delay > AV_SYNC_THRESHOLD ? delay : AV_SYNC_THRESHOLD; |
||||
|
||||
// if difference is more than 1 second, synchronize.
|
||||
if (Math.abs(diff) < Clock.SECONDS_TO_NANOS){ |
||||
if(diff <= -syncThresh) { |
||||
delay = 0; |
||||
} else if(diff >= syncThresh) { |
||||
delay = 2 * delay; |
||||
} |
||||
} |
||||
// delay = diff;
|
||||
|
||||
System.out.println("M: "+decoder.getSystemClock().getTimeSeconds()+ |
||||
", V: "+decoder.getVideoClock().getTimeSeconds()+ |
||||
", A: "+decoder.getAudioClock().getTimeSeconds()); |
||||
|
||||
if (delay > 0){ |
||||
waitNanos(delay); |
||||
drawFrame(frame); |
||||
// waitTime = (float) ((double) delay / Clock.SECONDS_TO_NANOS);
|
||||
// frameToDraw = frame;
|
||||
}else{ |
||||
videoQueue.returnFrame(frame); |
||||
lastFrameTime = frame.getTime(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
@ -1,62 +0,0 @@ |
||||
/* |
||||
* Copyright (c) 2009-2010 jMonkeyEngine |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* |
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.jme3.video; |
||||
|
||||
import com.jme3.texture.Image.Format; |
||||
import com.jme3.texture.Texture2D; |
||||
import com.jme3.util.BufferUtils; |
||||
|
||||
@Deprecated |
||||
public class VFrame extends Texture2D { |
||||
|
||||
private long time; |
||||
|
||||
public VFrame(int width, int height){ |
||||
super(width, height, Format.RGBA8); |
||||
getImage().setData(BufferUtils.createByteBuffer(width*height*4)); |
||||
} |
||||
|
||||
public long getTime(){ |
||||
return time; |
||||
} |
||||
|
||||
public void setTime(long time){ |
||||
this.time = time; |
||||
} |
||||
|
||||
@Override |
||||
public String toString(){ |
||||
return super.toString() + "[Time="+time+"]"; |
||||
} |
||||
|
||||
} |
@ -1,82 +0,0 @@ |
||||
/* |
||||
* Copyright (c) 2009-2010 jMonkeyEngine |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* |
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.jme3.video; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.concurrent.ArrayBlockingQueue; |
||||
import java.util.logging.Level; |
||||
import java.util.logging.Logger; |
||||
|
||||
@Deprecated |
||||
public class VQueue extends ArrayBlockingQueue<VFrame> { |
||||
|
||||
// private final ArrayList<VFrame> returnedFrames;
|
||||
private final ArrayBlockingQueue<VFrame> returnedFrames; |
||||
|
||||
public VQueue(int bufferedFrames){ |
||||
super(bufferedFrames); |
||||
// returnedFrames = new ArrayList<VFrame>(remainingCapacity());
|
||||
returnedFrames = new ArrayBlockingQueue<VFrame>(bufferedFrames * 3); |
||||
} |
||||
|
||||
public VFrame nextReturnedFrame(boolean waitForIt){ |
||||
// synchronized (returnedFrames){
|
||||
// while (returnedFrames.size() == 0){
|
||||
// if (!waitForIt)
|
||||
// return null;
|
||||
//
|
||||
// try {
|
||||
// returnedFrames.wait();
|
||||
// } catch (InterruptedException ex) {
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
try { |
||||
return returnedFrames.take(); |
||||
} catch (InterruptedException ex) { |
||||
ex.printStackTrace(); |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
public void returnFrame(VFrame frame){ |
||||
returnedFrames.add(frame); |
||||
|
||||
// synchronized (returnedFrames){
|
||||
// returnedFrames.add(frame);
|
||||
// returnedFrames.notifyAll();
|
||||
// }
|
||||
} |
||||
} |
@ -1,278 +0,0 @@ |
||||
/* |
||||
* Copyright (c) 2009-2010 jMonkeyEngine |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* |
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.jme3.video.plugins.jheora; |
||||
|
||||
import com.jcraft.jogg.Packet; |
||||
import com.jcraft.jorbis.Block; |
||||
import com.jcraft.jorbis.Comment; |
||||
import com.jcraft.jorbis.DspState; |
||||
import com.jcraft.jorbis.Info; |
||||
import com.jme3.audio.AudioStream; |
||||
import com.jme3.video.Clock; |
||||
import com.jme3.video.RingBuffer; |
||||
import com.jme3.video.SystemClock; |
||||
import java.io.InputStream; |
||||
|
||||
@Deprecated |
||||
public class ADecoder extends InputStream implements Clock { |
||||
|
||||
private int packetIndex = 0; |
||||
|
||||
private final DspState dsp; |
||||
private Block block; |
||||
|
||||
private Info info; |
||||
private Comment comment; |
||||
|
||||
private float[][][] pcmAll = new float[1][][]; |
||||
private int[] index; |
||||
|
||||
private AudioStream stream; |
||||
private RingBuffer ringBuffer = new RingBuffer(48000 * 2 * 2 * 2); |
||||
|
||||
private int UNCOMP_BUFSIZE = 4096; |
||||
private byte[] uncompBuf = new byte[UNCOMP_BUFSIZE]; |
||||
|
||||
private long lastPts = 0; |
||||
private long lastWritten = 0; |
||||
private long lastRead = 0; |
||||
private long lastPtsRead = 0; |
||||
private long lastPtsWrite = 0; |
||||
|
||||
private long timeDiffSum = 0; |
||||
private int timesDesynced = 0; |
||||
private Clock masterClock; |
||||
|
||||
public ADecoder(){ |
||||
info = new Info(); |
||||
info.init(); |
||||
|
||||
comment = new Comment(); |
||||
comment.init(); |
||||
|
||||
dsp = new DspState(); |
||||
block = new Block(dsp); |
||||
} |
||||
|
||||
public void setMasterClock(Clock masterClock) { |
||||
this.masterClock = masterClock; |
||||
} |
||||
|
||||
public AudioStream getAudioStream(){ |
||||
return stream; |
||||
} |
||||
|
||||
public long getTime(){ |
||||
long bytesRead = ringBuffer.getTotalRead(); |
||||
if (bytesRead == 0) |
||||
return 0; |
||||
|
||||
//long diff = bytesRead - lastWritten;
|
||||
long diff = bytesRead; |
||||
long diffNs = (diff * Clock.SECONDS_TO_NANOS) / (2 * info.channels * info.rate); |
||||
long timeSinceLastRead = System.nanoTime() - lastPtsRead; |
||||
return /*lastPts +*/ diffNs + timeSinceLastRead; |
||||
} |
||||
|
||||
public double getTimeSeconds(){ |
||||
return (double) getTime() / Clock.SECONDS_TO_NANOS; |
||||
} |
||||
|
||||
public int read(){ |
||||
byte[] buf = new byte[1]; |
||||
int read = read(buf, 0, 1); |
||||
if (read < 0) |
||||
return -1; |
||||
else |
||||
return buf[0] & 0xff; |
||||
} |
||||
|
||||
private static final long NOSYNC_THRESH = 3 * Clock.SECONDS_TO_NANOS, |
||||
AUDIO_DIFF_THRESH = Clock.SECONDS_TO_NANOS / 2; |
||||
|
||||
private static final int NUM_DIFFS_FOR_SYNC = 5; |
||||
private static final double PRODUCT_FOR_PREV = 6.0 / 10.0, |
||||
PRODUCT_FOR_PREV_INV = 4.0 / 10.0; |
||||
|
||||
private int needToSkip = 0; |
||||
|
||||
/** |
||||
* Only useful if audio is synced to something else. |
||||
*/ |
||||
private void sync(){ |
||||
if (needToSkip > 0){ |
||||
int skipped = ringBuffer.skip(needToSkip); |
||||
System.out.println("Skipped: "+skipped); |
||||
needToSkip -= skipped; |
||||
} |
||||
|
||||
long masterTime = masterClock.getTime(); |
||||
long audioTime = getTime(); |
||||
long diff = audioTime - masterTime; |
||||
if (diff < NOSYNC_THRESH){ |
||||
timeDiffSum = diff + (long) (timeDiffSum * PRODUCT_FOR_PREV); |
||||
if (timesDesynced < NUM_DIFFS_FOR_SYNC){ |
||||
timesDesynced ++; |
||||
}else{ |
||||
long avgDiff = (long) (timeDiffSum * PRODUCT_FOR_PREV_INV); |
||||
if (Math.abs(avgDiff) >= AUDIO_DIFF_THRESH){ |
||||
if (diff < 0){ |
||||
int toSkip = (int) ((-diff * 2 * info.channels * info.rate) / Clock.SECONDS_TO_NANOS); |
||||
int skipped = ringBuffer.skip(toSkip); |
||||
System.out.println("Skipped: "+skipped); |
||||
if (skipped < toSkip) |
||||
needToSkip = toSkip - skipped; |
||||
|
||||
timeDiffSum = 0; |
||||
timesDesynced = 0; |
||||
} |
||||
} |
||||
} |
||||
}else{ |
||||
timesDesynced = 0; |
||||
timeDiffSum = 0; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public int read(byte[] buf, int offset, int length){ |
||||
// int diff = (int) (ringBuffer.getTotalWritten() - ringBuffer.getTotalRead());
|
||||
// if ( diff > info.rate * info.channels * 2){
|
||||
// System.out.println("Warning: more than 1 second lag for audio. Adjusting..");
|
||||
// ringBuffer.skip( diff );
|
||||
// }
|
||||
|
||||
|
||||
// if (masterClock != null)
|
||||
// sync();
|
||||
|
||||
int r = ringBuffer.read(buf, offset, length); |
||||
if (r <= 0){ |
||||
// // put silence
|
||||
for (int i = 0; i < length; i++){ |
||||
buf[offset + i] = 0x0; |
||||
} |
||||
return length; |
||||
}else{ |
||||
lastPtsRead = System.nanoTime(); |
||||
} |
||||
return r; |
||||
} |
||||
|
||||
public void decodeDsp(Packet packet){ |
||||
if (block.synthesis(packet) == 0) { |
||||
dsp.synthesis_blockin(block); |
||||
} |
||||
|
||||
int samplesAvail; |
||||
int channels = info.channels; |
||||
while ((samplesAvail = dsp.synthesis_pcmout(pcmAll, index)) > 0) { |
||||
float[][] pcm = pcmAll[0]; |
||||
int samplesCanRead = UNCOMP_BUFSIZE / (channels*2); |
||||
int samplesToRead = (samplesAvail < samplesCanRead ? samplesAvail : samplesCanRead); |
||||
|
||||
// convert floats to 16 bit signed ints and interleave
|
||||
for (int i = 0; i < channels; i++) { |
||||
// each sample is two bytes, the sample for the 2nd
|
||||
// channel is at index 2, etc.
|
||||
int writeOff = i * 2; |
||||
int readOff = index[i]; |
||||
for (int j = 0; j < samplesToRead; j++) { |
||||
int val = (int) (pcm[i][readOff + j] * 32767.0); |
||||
// guard against clipping
|
||||
if (val > 32767) { |
||||
val = 32767; |
||||
}if (val < -32768) { |
||||
val = -32768; |
||||
} |
||||
uncompBuf[writeOff] = (byte) (val); |
||||
uncompBuf[writeOff + 1] = (byte) (val >> 8); |
||||
|
||||
writeOff += 2 * channels; // each sample is 2 bytes
|
||||
} |
||||
} |
||||
|
||||
ringBuffer.write(uncompBuf, 0, samplesToRead * channels * 2); |
||||
|
||||
// tell vorbis how many samples were actualy consumed
|
||||
dsp.synthesis_read(samplesToRead); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void close(){ |
||||
} |
||||
|
||||
public void decode(Packet packet){ |
||||
if (packetIndex < 3) { |
||||
if (info.synthesis_headerin(comment, packet) < 0) { |
||||
// error case; not a Vorbis header
|
||||
System.err.println("does not contain Vorbis audio data."); |
||||
return; |
||||
} |
||||
if (packetIndex == 2) { |
||||
dsp.synthesis_init(info); |
||||
block.init(dsp); |
||||
System.out.println("vorbis: "+info); |
||||
System.out.println(comment.toString()); |
||||
index = new int[info.channels]; |
||||
|
||||
if (stream == null){ |
||||
stream = new AudioStream(); |
||||
stream.setupFormat(info.channels, 16, info.rate); |
||||
stream.updateData(this, -1); |
||||
} |
||||
|
||||
if (masterClock instanceof SystemClock){ |
||||
SystemClock clock = (SystemClock) masterClock; |
||||
if (clock.needReset()){ |
||||
clock.reset(); |
||||
System.out.println("Note: master clock was reset by audio"); |
||||
} |
||||
} |
||||
} |
||||
} else { |
||||
long gp = packet.granulepos; |
||||
if (gp != -1){ |
||||
lastPts = (gp * Clock.SECONDS_TO_NANOS) / info.rate; |
||||
lastWritten = ringBuffer.getTotalWritten(); |
||||
lastRead = ringBuffer.getTotalRead(); |
||||
lastPtsWrite = System.nanoTime(); |
||||
} |
||||
|
||||
decodeDsp(packet); |
||||
} |
||||
packetIndex++; |
||||
} |
||||
|
||||
} |
@ -1,223 +0,0 @@ |
||||
/* |
||||
* Copyright (c) 2009-2010 jMonkeyEngine |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* |
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.jme3.video.plugins.jheora; |
||||
|
||||
import com.jcraft.jogg.Packet; |
||||
import com.jcraft.jogg.Page; |
||||
import com.jcraft.jogg.StreamState; |
||||
import com.jcraft.jogg.SyncState; |
||||
import com.jme3.audio.AudioStream; |
||||
import com.jme3.util.IntMap; |
||||
import com.jme3.video.Clock; |
||||
import com.jme3.video.SystemClock; |
||||
import com.jme3.video.VQueue; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.util.concurrent.atomic.AtomicBoolean; |
||||
import java.util.logging.Level; |
||||
import java.util.logging.Logger; |
||||
|
||||
@Deprecated |
||||
public class AVThread implements Runnable { |
||||
|
||||
private static final Logger logger = Logger.getLogger(AVThread.class.getName()); |
||||
|
||||
private static final int BUFFSIZE = 8192; |
||||
|
||||
/** |
||||
* OggPage. |
||||
*/ |
||||
private Page page; |
||||
|
||||
/** |
||||
* OggPacket, constructed from OggPages. |
||||
*/ |
||||
private Packet packet; |
||||
|
||||
/** |
||||
* SyncState. |
||||
*/ |
||||
private SyncState syncState; |
||||
|
||||
/** |
||||
* Stream of .ogg file. |
||||
*/ |
||||
private InputStream oggStream; |
||||
|
||||
private AtomicBoolean cancel = new AtomicBoolean(false); |
||||
|
||||
private IntMap<StreamState> streams = new IntMap<StreamState>(); |
||||
private int theoraSerial, vorbisSerial; |
||||
private ADecoder audioDecoder; |
||||
private VDecoder videoDecoder; |
||||
private Clock masterClock; |
||||
private Clock systemClock; |
||||
|
||||
public AVThread(InputStream oggStream, VQueue videoQueue){ |
||||
this.oggStream = oggStream; |
||||
videoDecoder = new VDecoder(videoQueue); |
||||
audioDecoder = new ADecoder(); |
||||
systemClock = new SystemClock(); |
||||
// masterClock = systemClock;//audioDecoder;
|
||||
masterClock = audioDecoder; |
||||
audioDecoder.setMasterClock(masterClock); |
||||
videoDecoder.setMasterClock(masterClock); |
||||
// masterClock = videoDecoder;
|
||||
// masterClock = systemClock;
|
||||
// audioDecoder.setMasterClock(masterClock);
|
||||
} |
||||
|
||||
public AudioStream getAudioStream(){ |
||||
return audioDecoder.getAudioStream(); |
||||
} |
||||
|
||||
public void stop(){ |
||||
cancel.set(true); |
||||
} |
||||
|
||||
private void done(){ |
||||
videoDecoder.close(); |
||||
audioDecoder.close(); |
||||
try { |
||||
oggStream.close(); |
||||
} catch (IOException ex) { |
||||
logger.log(Level.SEVERE, "Error while closing Ogg Video", ex); |
||||
} |
||||
} |
||||
|
||||
public Clock getMasterClock(){ |
||||
return masterClock; |
||||
} |
||||
|
||||
public Clock getSystemClock(){ |
||||
return systemClock; |
||||
} |
||||
|
||||
public Clock getVideoClock(){ |
||||
return videoDecoder; |
||||
} |
||||
|
||||
public Clock getAudioClock(){ |
||||
return audioDecoder; |
||||
} |
||||
|
||||
public void run(){ |
||||
page = new Page(); |
||||
packet = new Packet(); |
||||
syncState = new SyncState(); |
||||
|
||||
while (!cancel.get()) { |
||||
int index = syncState.buffer(BUFFSIZE); |
||||
|
||||
// Read from stream into syncState's buffer.
|
||||
int read; |
||||
try { |
||||
read = oggStream.read(syncState.data, index, BUFFSIZE); |
||||
} catch (IOException ex){ |
||||
logger.log(Level.SEVERE, "Error while decoding Ogg Video", ex); |
||||
return; |
||||
} |
||||
|
||||
if (read < 0){ |
||||
// EOF
|
||||
break; |
||||
} |
||||
|
||||
syncState.wrote(read); |
||||
|
||||
while (!cancel.get()) { |
||||
// Acquire page from syncState
|
||||
int res = syncState.pageout(page); |
||||
if (res == 0) |
||||
break; // need more data
|
||||
|
||||
if (res == -1) { |
||||
// missing or corrupt data at this page position
|
||||
// no reason to complain; already complained above
|
||||
} else { |
||||
int serial = page.serialno(); |
||||
StreamState state = streams.get(serial); |
||||
boolean newStream = false; |
||||
if (state == null){ |
||||
state = new StreamState(); |
||||
state.init(serial); |
||||
state.reset(); |
||||
streams.put(serial, state); |
||||
newStream = true; |
||||
} |
||||
|
||||
// Give StreamState the page
|
||||
res = state.pagein(page); |
||||
if (res < 0) { |
||||
// error; stream version mismatch perhaps
|
||||
System.err.println("Error reading first page of Ogg bitstream data."); |
||||
return; |
||||
} |
||||
while (!cancel.get()) { |
||||
// Get a packet out of the stream state
|
||||
res = state.packetout(packet); |
||||
if (res == 0) |
||||
break; |
||||
|
||||
if (res == -1) { |
||||
// missing or corrupt data at this page position
|
||||
// no reason to complain; already complained above
|
||||
} else { |
||||
// Packet acquired!
|
||||
if (newStream) { |
||||
// typefind
|
||||
int packetId = packet.packet; |
||||
byte[] packetBase = packet.packet_base; |
||||
if (packetBase[packetId + 1] == 0x76) { |
||||
vorbisSerial = serial; |
||||
} else if (packet.packet_base[packet.packet + 1] == 0x73) { |
||||
// smoke video! ignored
|
||||
logger.log(Level.WARNING, "Smoke video detected. Unsupported!"); |
||||
} else if (packet.packet_base[packet.packet + 1] == 0x74) { |
||||
theoraSerial = serial; |
||||
} |
||||
} |
||||
if (serial == theoraSerial){ |
||||
videoDecoder.decode(packet); |
||||
}else if (serial == vorbisSerial){ |
||||
audioDecoder.decode(packet); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
done(); |
||||
} |
||||
|
||||
} |
@ -1,184 +0,0 @@ |
||||
/* |
||||
* Copyright (c) 2009-2010 jMonkeyEngine |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* |
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.jme3.video.plugins.jheora; |
||||
|
||||
import com.fluendo.jheora.Comment; |
||||
import com.fluendo.jheora.Info; |
||||
import com.fluendo.jheora.State; |
||||
import com.fluendo.jheora.YUVBuffer; |
||||
import com.jcraft.jogg.Packet; |
||||
import com.jme3.video.Clock; |
||||
import com.jme3.video.SystemClock; |
||||
import com.jme3.video.VFrame; |
||||
import com.jme3.video.VQueue; |
||||
import java.nio.ByteBuffer; |
||||
|
||||
@Deprecated |
||||
public class VDecoder implements Clock { |
||||
|
||||
private int packetIndex = 0; |
||||
|
||||
private Info info; |
||||
private Comment comment; |
||||
|
||||
private State state; |
||||
private YUVBuffer yuv; |
||||
|
||||
private int xOff, yOff, width, height; |
||||
private YUVConv conv = new YUVConv(); |
||||
|
||||
private VQueue videoQueue; |
||||
|
||||
private long lastTs = -1; |
||||
private long lastUpdateTime = 0; |
||||
private Clock masterClock; |
||||
|
||||
public VDecoder(VQueue queue) { |
||||
info = new Info(); |
||||
comment = new Comment(); |
||||
state = new State(); |
||||
yuv = new YUVBuffer(); |
||||
videoQueue = queue; |
||||
} |
||||
|
||||
public void setMasterClock(Clock masterClock) { |
||||
this.masterClock = masterClock; |
||||
} |
||||
|
||||
public long getTime(){ |
||||
if (lastTs == -1) |
||||
return 0; |
||||
|
||||
long timeDiff = System.nanoTime() - lastUpdateTime; |
||||
return lastTs + timeDiff; |
||||
} |
||||
|
||||
public double getTimeSeconds(){ |
||||
return (double) getTime() / Clock.SECONDS_TO_NANOS; |
||||
} |
||||
|
||||
private void initializeFrames(){ |
||||
for (int i = 0; i < videoQueue.remainingCapacity(); i++){ |
||||
videoQueue.returnFrame(new VFrame(width, height)); |
||||
} |
||||
} |
||||
|
||||
private void decodeRgbFromBuffer(long time){ |
||||
VFrame frame = videoQueue.nextReturnedFrame(true); |
||||
conv.convert(yuv, xOff, yOff, width, height); |
||||
int[] rgb = conv.getRGBData(); |
||||
|
||||
frame.setTime(time); |
||||
ByteBuffer data = frame.getImage().getData(0); |
||||
data.clear(); |
||||
data.asIntBuffer().put(rgb); |
||||
|
||||
try { |
||||
// if it throws an exception someone
|
||||
// else modified it. "unknown error"..
|
||||
videoQueue.put(frame); |
||||
} catch (InterruptedException ex) { |
||||
} |
||||
} |
||||
|
||||
public void close(){ |
||||
// enqueue a frame with time == -2 to indicate end of stream
|
||||
VFrame frame = videoQueue.nextReturnedFrame(true); |
||||
frame.setTime(-2); |
||||
try { |
||||
videoQueue.put(frame); |
||||
} catch (InterruptedException ex) { |
||||
} |
||||
} |
||||
|
||||
public void decode(Packet packet) { |
||||
//System.out.println ("creating packet");
|
||||
if (packetIndex < 3) { |
||||
//System.out.println ("decoding header");
|
||||
if (info.decodeHeader(comment, packet) < 0) { |
||||
// error case; not a theora header
|
||||
System.err.println("does not contain Theora video data."); |
||||
return; |
||||
} |
||||
if (packetIndex == 2) { |
||||
state.decodeInit(info); |
||||
|
||||
System.out.println("theora frame: " + info.frame_width + "x" + info.frame_height); |
||||
System.out.println("theora resolution: " + info.width + "x" + info.height); |
||||
System.out.println("theora aspect: " + info.aspect_numerator + "x" + info.aspect_denominator); |
||||
System.out.println("theora framerate: " + info.fps_numerator + "x" + info.fps_denominator); |
||||
|
||||
xOff = info.offset_x; |
||||
yOff = info.offset_y; |
||||
width = info.frame_width; |
||||
height = info.frame_height; |
||||
initializeFrames(); |
||||
|
||||
if (masterClock instanceof SystemClock){ |
||||
SystemClock clock = (SystemClock) masterClock; |
||||
if (clock.needReset()){ |
||||
clock.reset(); |
||||
System.out.println("Note: master clock was reset by video"); |
||||
} |
||||
} |
||||
} |
||||
} else { |
||||
// convert to nanos
|
||||
long granulePos = packet.granulepos; |
||||
long time = (long) (state.granuleTime(granulePos) * Clock.SECONDS_TO_NANOS); |
||||
long oneFrameTime = (long) ((Clock.SECONDS_TO_NANOS * info.fps_denominator) / info.fps_numerator); |
||||
if (time >= 0){ |
||||
lastTs = time; |
||||
}else{ |
||||
lastTs += oneFrameTime; |
||||
time = lastTs; |
||||
} |
||||
lastUpdateTime = System.nanoTime(); |
||||
|
||||
if (state.decodePacketin(packet) != 0) { |
||||
System.err.println("Error Decoding Theora."); |
||||
return; |
||||
} |
||||
|
||||
// if (time >= 0){
|
||||
if (state.decodeYUVout(yuv) != 0) { |
||||
System.err.println("Error getting the picture."); |
||||
return; |
||||
} |
||||
decodeRgbFromBuffer( time ); |
||||
// }
|
||||
} |
||||
packetIndex++; |
||||
} |
||||
|
||||
} |
@ -1,143 +0,0 @@ |
||||
/* |
||||
* Copyright (c) 2009-2010 jMonkeyEngine |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* |
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.jme3.video.plugins.jheora; |
||||
|
||||
import com.fluendo.jheora.YUVBuffer; |
||||
|
||||
@Deprecated |
||||
public final class YUVConv { |
||||
|
||||
private int[] pixels; |
||||
|
||||
private static final int VAL_RANGE = 256; |
||||
private static final int SHIFT = 16; |
||||
|
||||
private static final int CR_FAC = (int) (1.402 * (1 << SHIFT)); |
||||
private static final int CB_FAC = (int) (1.772 * (1 << SHIFT)); |
||||
private static final int CR_DIFF_FAC = (int) (0.71414 * (1 << SHIFT)); |
||||
private static final int CB_DIFF_FAC = (int) (0.34414 * (1 << SHIFT)); |
||||
|
||||
private static int[] r_tab = new int[VAL_RANGE * 3]; |
||||
private static int[] g_tab = new int[VAL_RANGE * 3]; |
||||
private static int[] b_tab = new int[VAL_RANGE * 3]; |
||||
|
||||
static { |
||||
setupRgbYuvAccelerators(); |
||||
} |
||||
|
||||
private static final short clamp255(int val) { |
||||
val -= 255; |
||||
val = -(255 + ((val >> (31)) & val)); |
||||
return (short) -((val >> 31) & val); |
||||
} |
||||
|
||||
private static void setupRgbYuvAccelerators() { |
||||
for (int i = 0; i < VAL_RANGE * 3; i++) { |
||||
r_tab[i] = clamp255(i - VAL_RANGE); |
||||
g_tab[i] = clamp255(i - VAL_RANGE) << 8; |
||||
b_tab[i] = clamp255(i - VAL_RANGE) << 16; |
||||
} |
||||
} |
||||
|
||||
public YUVConv(){ |
||||
} |
||||
|
||||
public int[] getRGBData(){ |
||||
return pixels; |
||||
} |
||||
|
||||
public void convert(YUVBuffer yuv, int xOff, int yOff, int width, int height) { |
||||
if (pixels == null){ |
||||
pixels = new int[width*height]; |
||||
} |
||||
// Set up starting values for YUV pointers
|
||||
int YPtr = yuv.y_offset + xOff + yOff * (yuv.y_stride); |
||||
int YPtr2 = YPtr + yuv.y_stride; |
||||
int UPtr = yuv.u_offset + xOff/2 + (yOff/2)*(yuv.uv_stride); |
||||
int VPtr = yuv.v_offset + xOff/2 + (yOff/2)*(yuv.uv_stride); |
||||
int RGBPtr = 0; |
||||
int RGBPtr2 = width; |
||||
int width2 = width / 2; |
||||
int height2 = height / 2; |
||||
|
||||
// Set the line step for the Y and UV planes and YPtr2
|
||||
int YStep = yuv.y_stride * 2 - (width2) * 2; |
||||
int UVStep = yuv.uv_stride - (width2); |
||||
int RGBStep = width; |
||||
|
||||
for (int i = 0; i < height2; i++) { |
||||
for (int j = 0; j < width2; j++) { |
||||
// groups of four pixels
|
||||
int UFactor = yuv.data[UPtr++] - 128; |
||||
int VFactor = yuv.data[VPtr++] - 128; |
||||
int GFactor = UFactor * CR_DIFF_FAC + VFactor * CB_DIFF_FAC - (VAL_RANGE<<SHIFT); |
||||
|
||||
UFactor = UFactor * CR_FAC + (VAL_RANGE<<SHIFT); |
||||
VFactor = VFactor * CB_FAC + (VAL_RANGE<<SHIFT); |
||||
|
||||
int YVal = yuv.data[YPtr] << SHIFT; |
||||
pixels[RGBPtr] = r_tab[(YVal + VFactor)>>SHIFT] | |
||||
b_tab[(YVal + UFactor)>>SHIFT] | |
||||
g_tab[(YVal - GFactor)>>SHIFT]; |
||||
|
||||
YVal = yuv.data[YPtr+1] << SHIFT; |
||||
pixels[RGBPtr+1] = r_tab[(YVal + VFactor)>>SHIFT] | |
||||
b_tab[(YVal + UFactor)>>SHIFT] | |
||||
g_tab[(YVal - GFactor)>>SHIFT]; |
||||
|
||||
YVal = yuv.data[YPtr2] << SHIFT; |
||||
pixels[RGBPtr2] = r_tab[(YVal + VFactor)>>SHIFT] | |
||||
b_tab[(YVal + UFactor)>>SHIFT] | |
||||
g_tab[(YVal - GFactor)>>SHIFT]; |
||||
|
||||
YVal = yuv.data[YPtr2+1] << SHIFT; |
||||
pixels[RGBPtr2+1] = r_tab[(YVal + VFactor)>>SHIFT] | |
||||
b_tab[(YVal + UFactor)>>SHIFT] | |
||||
g_tab[(YVal - GFactor)>>SHIFT]; |
||||
|
||||
YPtr += 2; |
||||
YPtr2 += 2; |
||||
RGBPtr += 2; |
||||
RGBPtr2 += 2; |
||||
} |
||||
|
||||
// Increment the various pointers
|
||||
YPtr += YStep; |
||||
YPtr2 += YStep; |
||||
UPtr += UVStep; |
||||
VPtr += UVStep; |
||||
RGBPtr += RGBStep; |
||||
RGBPtr2 += RGBStep; |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue