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