aboutsummaryrefslogtreecommitdiffstats
path: root/src/jogl
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2012-04-16 20:50:06 +0200
committerSven Gothel <[email protected]>2012-04-16 20:50:06 +0200
commit10935e1ec0d8ed677bc3fddfaa8cd73898a3bcbf (patch)
tree6d453f72b3024670a6ed5c03454ef54ad4a04ba0 /src/jogl
parent62e5686fb583ad991d5811baf242d40d21952e27 (diff)
Add native tests for libav/ffmpeg and gst
Diffstat (limited to 'src/jogl')
-rw-r--r--src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGDynamicLibraryBundleInfo.java219
-rw-r--r--src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java503
2 files changed, 722 insertions, 0 deletions
diff --git a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGDynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGDynamicLibraryBundleInfo.java
new file mode 100644
index 000000000..4c4870545
--- /dev/null
+++ b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGDynamicLibraryBundleInfo.java
@@ -0,0 +1,219 @@
+/**
+ * Copyright 2012 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``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 JogAmp Community 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.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package jogamp.opengl.util.av.impl;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.media.opengl.GLProfile;
+
+import com.jogamp.common.os.DynamicLibraryBundle;
+import com.jogamp.common.os.DynamicLibraryBundleInfo;
+import com.jogamp.common.util.RunnableExecutor;
+
+class FFMPEGDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo {
+ private static List<String> glueLibNames = new ArrayList<String>(); // none
+
+ private static final int symbolCount = 29;
+ private static String[] symbolNames = {
+ "avcodec_version",
+ "avformat_version",
+/* 3 */ "avutil_version",
+
+ // libavcodec
+ "avcodec_close",
+ "avcodec_string",
+ "avcodec_find_decoder",
+ "avcodec_open2", // 53.6.0 (opt)
+ "avcodec_open",
+ "avcodec_alloc_frame",
+ "avcodec_default_get_buffer",
+ "avcodec_default_release_buffer",
+ "av_free_packet",
+ "avcodec_decode_audio4", // 53.25.0 (opt)
+ "avcodec_decode_audio3", // 52.23.0
+/* 15 */ "avcodec_decode_video2", // 52.23.0
+
+ // libavutil
+ "av_pix_fmt_descriptors",
+ "av_free",
+/* 18 */ "av_get_bits_per_pixel",
+
+ // libavformat
+ "avformat_close_input", // 53.17.0 (opt)
+ "av_close_input_file",
+ "av_register_all",
+ "avformat_open_input",
+ "av_dump_format",
+ "av_read_frame",
+ "av_seek_frame",
+ "avformat_network_init", // 53.13.0 (opt)
+ "avformat_network_deinit", // 53.13.0 (opt)
+ "avformat_find_stream_info", // 53.3.0 (opt)
+/* 29 */ "av_find_stream_info"
+ };
+
+ private static String[] optionalSymbolNames = {
+ "avcodec_open2", // 53.6.0 (opt)
+ "avcodec_decode_audio4", // 53.25.0 (opt)
+ "avformat_close_input", // 53.17.0 (opt)
+ "avformat_network_init", // 53.13.0 (opt)
+ "avformat_network_deinit", // 53.13.0 (opt)
+ "avformat_find_stream_info" // 53.3.0 (opt)
+ };
+
+ private static long[] symbolAddr;
+ private static final boolean ready;
+
+ static {
+ // native ffmpeg media player implementation is included in jogl_desktop and jogl_mobile
+ GLProfile.initSingleton();
+ boolean _ready = false;
+ try {
+ _ready = initSymbols();
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ ready = _ready;
+ if(!ready) {
+ System.err.println("FFMPEG: Not Available");
+ }
+ }
+
+ static boolean initSingleton() { return ready; }
+
+ private static boolean initSymbols() {
+ final DynamicLibraryBundle dl = new DynamicLibraryBundle(new FFMPEGDynamicLibraryBundleInfo());
+ final boolean avutilLoaded = dl.isToolLibLoaded(0);
+ final boolean avformatLoaded = dl.isToolLibLoaded(1);
+ final boolean avcodecLoaded = dl.isToolLibLoaded(2);
+ if(!avutilLoaded || !avformatLoaded || !avcodecLoaded) {
+ throw new RuntimeException("FFMPEG Tool library incomplete: [ avutil "+avutilLoaded+", avformat "+avformatLoaded+", avcodec "+avcodecLoaded+"]");
+ }
+ if(!dl.isToolLibComplete()) {
+ throw new RuntimeException("FFMPEG Tool libraries incomplete");
+ }
+ symbolAddr = new long[symbolCount];
+
+ final Set<String> optionalSet = new HashSet<String>();
+ optionalSet.addAll(Arrays.asList(optionalSymbolNames));
+
+ if(!lookupSymbols(dl, symbolNames, optionalSet, symbolAddr, symbolCount)) {
+ return false;
+ }
+ return initSymbols0(symbolAddr, symbolAddr.length);
+ }
+
+ private static boolean lookupSymbols(DynamicLibraryBundle dl,
+ String[] symbols, Set<String> optionalSymbols,
+ long[] addresses, int symbolCount) {
+ for(int i = 0; i<symbolCount; i++) {
+ final long addr = dl.dynamicLookupFunction(symbols[i]);
+ if( 0 == addr ) {
+ if(!optionalSymbols.contains(symbols[i])) {
+ System.err.println("Could not resolve mandatory symbol <"+symbols[i]+">");
+ return false;
+ } else if(true || DEBUG ) { // keep it verbose per default for now ..
+ System.err.println("Could not resolve optional symbol <"+symbols[i]+">");
+ }
+ }
+ addresses[i] = addr;
+ }
+ return true;
+ }
+
+ protected FFMPEGDynamicLibraryBundleInfo() {
+ }
+
+ @Override
+ public boolean shallLinkGlobal() { return true; }
+
+ @Override
+ public boolean shallLookupGlobal() { return true; }
+
+ @Override
+ public final List<String> getGlueLibNames() {
+ return glueLibNames;
+ }
+
+ @Override
+ public List<List<String>> getToolLibNames() {
+ List<List<String>> libsList = new ArrayList<List<String>>();
+
+ final List<String> avutil = new ArrayList<String>();
+ avutil.add("avutil"); // default
+ avutil.add("avutil-52"); // dummy future proof
+ avutil.add("avutil-51"); // 0.8
+ avutil.add("avutil-50"); // 0.7
+ libsList.add(avutil);
+
+ final List<String> avformat = new ArrayList<String>();
+ avformat.add("avformat"); // default
+ avformat.add("avformat-55"); // dummy future proof
+ avformat.add("avformat-54"); // 0.?
+ avformat.add("avformat-53"); // 0.8
+ avformat.add("avformat-52"); // 0.7
+ libsList.add(avformat);
+
+ final List<String> avcodec = new ArrayList<String>();
+ avcodec.add("avcodec"); // default
+ avcodec.add("avcodec-55"); // dummy future proof
+ avcodec.add("avcodec-54"); // 0.?
+ avcodec.add("avcodec-53"); // 0.8
+ avcodec.add("avcodec-52"); // 0.7
+ libsList.add(avcodec);
+
+ return libsList;
+ }
+
+ @Override
+ public final List<String> getToolGetProcAddressFuncNameList() {
+ return null;
+ }
+
+ @Override
+ public final long toolGetProcAddress(long toolGetProcAddressHandle, String funcName) {
+ return 0;
+ }
+
+ @Override
+ public boolean useToolGetProcAdressFirst(String funcName) {
+ return false;
+ }
+
+ @Override
+ public RunnableExecutor getLibLoaderExecutor() {
+ return DynamicLibraryBundle.getDefaultRunnableExecutor();
+ }
+
+ private static native boolean initSymbols0(long[] symbols, int count);
+}
diff --git a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java
new file mode 100644
index 000000000..d24961b68
--- /dev/null
+++ b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java
@@ -0,0 +1,503 @@
+/**
+ * Copyright 2012 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``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 JogAmp Community 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.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package jogamp.opengl.util.av.impl;
+
+import java.io.IOException;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLException;
+
+import com.jogamp.common.util.VersionNumber;
+import com.jogamp.gluegen.runtime.ProcAddressTable;
+import com.jogamp.opengl.util.GLPixelStorageModes;
+import com.jogamp.opengl.util.texture.Texture;
+import com.jogamp.opengl.util.texture.TextureSequence;
+
+import jogamp.opengl.GLContextImpl;
+import jogamp.opengl.es1.GLES1ProcAddressTable;
+import jogamp.opengl.es2.GLES2ProcAddressTable;
+import jogamp.opengl.gl4.GL4bcProcAddressTable;
+import jogamp.opengl.util.av.EGLMediaPlayerImpl;
+
+/***
+ * Currently only YUV420P and the usual packed RGB formats are supported.
+ * <p>
+ * Check tag 'FIXME: Add more planar formats !'
+ * here and in the corresponding native code
+ * <code>jogl/src/jogl/native/ffmpeg/jogamp_opengl_util_av_impl_FFMPEGMediaPlayer.c</code>
+ * </p>
+ * <p>
+ * TODO: Audio Output
+ * </p>
+ */
+public class FFMPEGMediaPlayer extends EGLMediaPlayerImpl {
+ public static final VersionNumber avUtilVersion;
+ public static final VersionNumber avFormatVersion;
+ public static final VersionNumber avCodecVersion;
+ static final boolean available;
+
+ static {
+ if(FFMPEGDynamicLibraryBundleInfo.initSingleton()) {
+ avUtilVersion = getAVVersion(getAvUtilVersion0());
+ avFormatVersion = getAVVersion(getAvFormatVersion0());
+ avCodecVersion = getAVVersion(getAvCodecVersion0());
+ System.err.println("LIB_AV Util : "+avUtilVersion);
+ System.err.println("LIB_AV Format: "+avFormatVersion);
+ System.err.println("LIB_AV Codec : "+avCodecVersion);
+ available = initIDs0();
+ } else {
+ avUtilVersion = null;
+ avFormatVersion = null;
+ avCodecVersion = null;
+ available = false;
+ }
+ }
+
+ public static final boolean isAvailable() { return available; }
+
+ private static VersionNumber getAVVersion(int vers) {
+ return new VersionNumber( ( vers >> 16 ) & 0xFF,
+ ( vers >> 8 ) & 0xFF,
+ ( vers >> 0 ) & 0xFF );
+ }
+
+ protected long moviePtr = 0;
+ protected long procAddrGLTexSubImage2D = 0;
+ protected EGLMediaPlayerImpl.EGLTextureFrame lastTex = null;
+ protected GLPixelStorageModes psm;
+ protected PixelFormat vPixelFmt = null;
+ protected int vPlanes = 0;
+ protected int vBitsPerPixel = 0;
+ protected int vBytesPerPixelPerPlane = 0;
+ protected int[] vLinesize = { 0, 0, 0 }; // per plane
+ protected int[] vTexWidth = { 0, 0, 0 }; // per plane
+ protected int texWidth, texHeight; // overall (stuffing planes in one texture)
+ protected ByteBuffer texCopy;
+
+ public FFMPEGMediaPlayer() {
+ super(TextureType.GL, false);
+ if(!available) {
+ throw new RuntimeException("FFMPEGMediaPlayer not available");
+ }
+ setTextureCount(1);
+ moviePtr = createInstance0(true);
+ if(0==moviePtr) {
+ throw new GLException("Couldn't create FFMPEGInstance");
+ }
+ psm = new GLPixelStorageModes();
+ }
+
+ @Override
+ protected TextureSequence.TextureFrame createTexImage(GL gl, int idx, int[] tex) {
+ if(TextureType.GL == texType) {
+ final Texture texture = super.createTexImageImpl(gl, idx, tex, texWidth, texHeight, true);
+ lastTex = new EGLTextureFrame(null, texture, 0, 0);
+ } else {
+ throw new InternalError("n/a");
+ }
+ return lastTex;
+ }
+
+ @Override
+ protected void destroyTexImage(GL gl, TextureSequence.TextureFrame imgTex) {
+ lastTex = null;
+ super.destroyTexImage(gl, imgTex);
+ }
+
+ @Override
+ protected void destroyImpl(GL gl) {
+ if (moviePtr != 0) {
+ destroyInstance0(moviePtr);
+ moviePtr = 0;
+ }
+ }
+
+ @Override
+ protected void initGLStreamImpl(GL gl, int[] texNames) throws IOException {
+ if(0==moviePtr) {
+ throw new GLException("FFMPEG native instance null");
+ }
+ final String urlS=urlConn.getURL().toExternalForm();
+
+ System.out.println("setURL: p1 "+this);
+ setStream0(moviePtr, urlS, -1, -1);
+ System.out.println("setURL: p2 "+this);
+ int tf;
+ switch(vBytesPerPixelPerPlane) {
+ case 1: tf = GL2ES2.GL_RED; break;
+ case 3: tf = GL2ES2.GL_RGB; break;
+ case 4: tf = GL2ES2.GL_RGBA; break;
+ default: throw new RuntimeException("Unsupported bytes-per-pixel / plane "+vBytesPerPixelPerPlane);
+ }
+ setTextureFormat(tf);
+ setTextureType(GL.GL_UNSIGNED_BYTE);
+ GLContextImpl ctx = (GLContextImpl)gl.getContext();
+ ProcAddressTable pt = ctx.getGLProcAddressTable();
+ if(pt instanceof GLES2ProcAddressTable) {
+ procAddrGLTexSubImage2D = ((GLES2ProcAddressTable)pt)._addressof_glTexSubImage2D;
+ } else if(pt instanceof GLES1ProcAddressTable) {
+ procAddrGLTexSubImage2D = ((GLES1ProcAddressTable)pt)._addressof_glTexSubImage2D;
+ } else if(pt instanceof GL4bcProcAddressTable) {
+ procAddrGLTexSubImage2D = ((GL4bcProcAddressTable)pt)._addressof_glTexSubImage2D;
+ } else {
+ throw new InternalError("Unknown ProcAddressTable: "+pt.getClass().getName()+" of "+ctx.getClass().getName());
+ }
+ }
+ private void updateAttributes2(int pixFmt, int planes, int bitsPerPixel, int bytesPerPixelPerPlane,
+ int lSz0, int lSz1, int lSz2,
+ int tWd0, int tWd1, int tWd2) {
+ vPixelFmt = PixelFormat.valueOf(pixFmt);
+ vPlanes = planes;
+ vBitsPerPixel = bitsPerPixel;
+ vBytesPerPixelPerPlane = bytesPerPixelPerPlane;
+ vLinesize[0] = lSz0; vLinesize[1] = lSz1; vLinesize[2] = lSz2;
+ vTexWidth[0] = tWd0; vTexWidth[1] = tWd1; vTexWidth[2] = tWd2;
+
+ switch(vPixelFmt) {
+ case YUV420P:
+ // YUV420P: Adding U+V on right side of fixed height texture,
+ // since width is already aligned by decoder.
+ // Y=w*h, Y=w/2*h/2, U=w/2*h/2
+ // w*h + 2 ( w/2 * h/2 )
+ // w*h + w*h/2
+ // 2*w/2 * h
+ texWidth = vTexWidth[0] + vTexWidth[1]; texHeight = height;
+ break;
+ // case PIX_FMT_YUYV422:
+ case RGB24:
+ case BGR24:
+ case ARGB:
+ case RGBA:
+ case ABGR:
+ case BGRA:
+ texWidth = vTexWidth[0]; texHeight = height;
+ break;
+ default: // FIXME: Add more planar formats !
+ throw new RuntimeException("Unsupported pixelformat: "+vPixelFmt);
+ }
+ if(DEBUG) {
+ System.err.println("XXX0: fmt "+vPixelFmt+", planes "+vPlanes+", bpp "+vBitsPerPixel+"/"+vBytesPerPixelPerPlane);
+ for(int i=0; i<3; i++) {
+ System.err.println("XXX0 "+i+": "+vTexWidth[i]+"/"+vLinesize[i]);
+ }
+ System.err.println("XXX0 total tex "+texWidth+"x"+texHeight);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * If this implementation generates a specialized shader,
+ * it allows the user to override the default function name <code>ffmpegTexture2D</code>.
+ * Otherwise the call is delegated to it's super class.
+ */
+ @Override
+ public String getTextureLookupFunctionName(String desiredFuncName) throws IllegalStateException {
+ if(State.Uninitialized == state) {
+ throw new IllegalStateException("Instance not initialized: "+this);
+ }
+ if(PixelFormat.YUV420P == vPixelFmt) {
+ if(null != desiredFuncName && desiredFuncName.length()>0) {
+ textureLookupFunctionName = desiredFuncName;
+ }
+ return textureLookupFunctionName;
+ }
+ return super.getTextureLookupFunctionName(desiredFuncName);
+ }
+ private String textureLookupFunctionName = "ffmpegTexture2D";
+
+ /**
+ * {@inheritDoc}
+ *
+ * Depending on the pixelformat, a specific conversion shader is being created,
+ * e.g. YUV420P to RGB. Otherwise the call is delegated to it's super class.
+ */
+ @Override
+ public String getTextureLookupFragmentShaderImpl() throws IllegalStateException {
+ if(State.Uninitialized == state) {
+ throw new IllegalStateException("Instance not initialized: "+this);
+ }
+ final float tc_w_1 = (float)getWidth() / (float)texWidth;
+ switch(vPixelFmt) {
+ case YUV420P:
+ return
+ "vec4 "+textureLookupFunctionName+"(in "+getTextureSampler2DType()+" image, in vec2 texCoord) {\n"+
+ " vec2 u_off = vec2("+tc_w_1+", 0.0);\n"+
+ " vec2 v_off = vec2("+tc_w_1+", 0.5);\n"+
+ " vec2 tc_half = texCoord*0.5;\n"+
+ " float y,u,v,r,g,b;\n"+
+ " y = texture2D(image, texCoord).r;\n"+
+ " u = texture2D(image, u_off+tc_half).r;\n"+
+ " v = texture2D(image, v_off+tc_half).r;\n"+
+ " y = 1.1643*(y-0.0625);\n"+
+ " u = u-0.5;\n"+
+ " v = v-0.5;\n"+
+ " r = y+1.5958*v;\n"+
+ " g = y-0.39173*u-0.81290*v;\n"+
+ " b = y+2.017*u;\n"+
+ " return vec4(r, g, b, 1);\n"+
+ "}\n"
+ ;
+ default: // FIXME: Add more planar formats !
+ return super.getTextureLookupFragmentShaderImpl();
+ }
+ }
+
+ @Override
+ protected synchronized int getCurrentPositionImpl() {
+ return 0!=moviePtr ? getVideoPTS0(moviePtr) : 0;
+ }
+
+ @Override
+ protected synchronized boolean setPlaySpeedImpl(float rate) {
+ return true;
+ }
+
+ @Override
+ public synchronized boolean startImpl() {
+ if(0==moviePtr) {
+ return false;
+ }
+ return true;
+ }
+
+ /** @return time position after issuing the command */
+ @Override
+ public synchronized boolean pauseImpl() {
+ if(0==moviePtr) {
+ return false;
+ }
+ return true;
+ }
+
+ /** @return time position after issuing the command */
+ @Override
+ public synchronized boolean stopImpl() {
+ if(0==moviePtr) {
+ return false;
+ }
+ return true;
+ }
+
+ /** @return time position after issuing the command */
+ @Override
+ protected synchronized int seekImpl(int msec) {
+ if(0==moviePtr) {
+ throw new GLException("FFMPEG native instance null");
+ }
+ int pts0 = getVideoPTS0(moviePtr);
+ int pts1 = seek0(moviePtr, msec);
+ System.err.println("Seek: "+pts0+" -> "+msec+" : "+pts1);
+ return pts1;
+ }
+
+ @Override
+ protected TextureSequence.TextureFrame getLastTextureImpl() {
+ return lastTex;
+ }
+
+ private long lastVideoTime = 0;
+ private int lastVideoPTS = 0;
+ private static final int dt_d = 9;
+
+ @Override
+ protected TextureSequence.TextureFrame getNextTextureImpl(GL gl, boolean blocking) {
+ if(0==moviePtr) {
+ throw new GLException("FFMPEG native instance null");
+ }
+ if(null != lastTex) {
+ psm.setUnpackAlignment(gl, 1); // RGBA ? 4 : 1
+ try {
+ final Texture tex = lastTex.getTexture();
+ gl.glActiveTexture(GL.GL_TEXTURE0+getTextureUnit());
+ tex.enable(gl);
+ tex.bind(gl);
+ readNextPacket0(moviePtr, procAddrGLTexSubImage2D, textureTarget, textureFormat, textureType);
+ } finally {
+ psm.restore(gl);
+ }
+ final int pts = getVideoPTS0(moviePtr); // this frame
+ if(blocking) {
+ // poor mans video sync .. TODO: off thread 'readNextPackage0(..)' on shared GLContext and multi textures/unit!
+ final long now = System.currentTimeMillis();
+ final long now_d = now - lastVideoTime;
+ final long pts_d = pts - lastVideoPTS;
+ final long dt = (long) ( (float) ( pts_d - now_d ) / getPlaySpeed() ) ;
+ lastVideoTime = now;
+ // System.err.println("s: pts-v "+pts+", pts-d "+pts_d+", now_d "+now_d+", dt "+dt);
+ if(dt>dt_d) {
+ try {
+ Thread.sleep(dt-dt_d);
+ } catch (InterruptedException e) { }
+ } /* else if(0>pts_d) {
+ System.err.println("s: pts-v "+pts+", pts-d "+pts_d+", now_d "+now_d+", dt "+dt);
+ } */
+ }
+ lastVideoPTS = pts;
+ }
+ return lastTex;
+ }
+
+ private void consumeAudio(int len) {
+
+ }
+
+ private static native int getAvUtilVersion0();
+ private static native int getAvFormatVersion0();
+ private static native int getAvCodecVersion0();
+ private static native boolean initIDs0();
+ private native long createInstance0(boolean verbose);
+ private native void destroyInstance0(long moviePtr);
+
+ private native void setStream0(long moviePtr, String url, int vid, int aid);
+
+ private native int getVideoPTS0(long moviePtr);
+
+ private native int getAudioPTS0(long moviePtr);
+ private native Buffer getAudioBuffer0(long moviePtr, int plane);
+
+ private native int readNextPacket0(long moviePtr, long procAddrGLTexSubImage2D, int texTarget, int texFmt, int texType);
+
+ private native int seek0(long moviePtr, int position);
+
+ public static enum PixelFormat {
+ // NONE= -1,
+ YUV420P, ///< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
+ YUYV422, ///< packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr
+ RGB24, ///< packed RGB 8:8:8, 24bpp, RGBRGB...
+ BGR24, ///< packed RGB 8:8:8, 24bpp, BGRBGR...
+ YUV422P, ///< planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
+ YUV444P, ///< planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
+ YUV410P, ///< planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
+ YUV411P, ///< planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
+ GRAY8, ///< Y , 8bpp
+ MONOWHITE, ///< Y , 1bpp, 0 is white, 1 is black, in each byte pixels are ordered from the msb to the lsb
+ MONOBLACK, ///< Y , 1bpp, 0 is black, 1 is white, in each byte pixels are ordered from the msb to the lsb
+ PAL8, ///< 8 bit with RGB32 palette
+ YUVJ420P, ///< planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of YUV420P and setting color_range
+ YUVJ422P, ///< planar YUV 4:2:2, 16bpp, full scale (JPEG), deprecated in favor of YUV422P and setting color_range
+ YUVJ444P, ///< planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of YUV444P and setting color_range
+ XVMC_MPEG2_MC,///< XVideo Motion Acceleration via common packet passing
+ XVMC_MPEG2_IDCT,
+ UYVY422, ///< packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1
+ UYYVYY411, ///< packed YUV 4:1:1, 12bpp, Cb Y0 Y1 Cr Y2 Y3
+ BGR8, ///< packed RGB 3:3:2, 8bpp, (msb)2B 3G 3R(lsb)
+ BGR4, ///< packed RGB 1:2:1 bitstream, 4bpp, (msb)1B 2G 1R(lsb), a byte contains two pixels, the first pixel in the byte is the one composed by the 4 msb bits
+ BGR4_BYTE, ///< packed RGB 1:2:1, 8bpp, (msb)1B 2G 1R(lsb)
+ RGB8, ///< packed RGB 3:3:2, 8bpp, (msb)2R 3G 3B(lsb)
+ RGB4, ///< packed RGB 1:2:1 bitstream, 4bpp, (msb)1R 2G 1B(lsb), a byte contains two pixels, the first pixel in the byte is the one composed by the 4 msb bits
+ RGB4_BYTE, ///< packed RGB 1:2:1, 8bpp, (msb)1R 2G 1B(lsb)
+ NV12, ///< planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (first byte U and the following byte V)
+ NV21, ///< as above, but U and V bytes are swapped
+
+ ARGB, ///< packed ARGB 8:8:8:8, 32bpp, ARGBARGB...
+ RGBA, ///< packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
+ ABGR, ///< packed ABGR 8:8:8:8, 32bpp, ABGRABGR...
+ BGRA, ///< packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
+
+ GRAY16BE, ///< Y , 16bpp, big-endian
+ GRAY16LE, ///< Y , 16bpp, little-endian
+ YUV440P, ///< planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples)
+ YUVJ440P, ///< planar YUV 4:4:0 full scale (JPEG), deprecated in favor of YUV440P and setting color_range
+ YUVA420P, ///< planar YUV 4:2:0, 20bpp, (1 Cr & Cb sample per 2x2 Y & A samples)
+ VDPAU_H264,///< H.264 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers
+ VDPAU_MPEG1,///< MPEG-1 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers
+ VDPAU_MPEG2,///< MPEG-2 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers
+ VDPAU_WMV3,///< WMV3 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers
+ VDPAU_VC1, ///< VC-1 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers
+ RGB48BE, ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, the 2-byte value for each R/G/B component is stored as big-endian
+ RGB48LE, ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, the 2-byte value for each R/G/B component is stored as little-endian
+
+ RGB565BE, ///< packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), big-endian
+ RGB565LE, ///< packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), little-endian
+ RGB555BE, ///< packed RGB 5:5:5, 16bpp, (msb)1A 5R 5G 5B(lsb), big-endian, most significant bit to 0
+ RGB555LE, ///< packed RGB 5:5:5, 16bpp, (msb)1A 5R 5G 5B(lsb), little-endian, most significant bit to 0
+
+ BGR565BE, ///< packed BGR 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), big-endian
+ BGR565LE, ///< packed BGR 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), little-endian
+ BGR555BE, ///< packed BGR 5:5:5, 16bpp, (msb)1A 5B 5G 5R(lsb), big-endian, most significant bit to 1
+ BGR555LE, ///< packed BGR 5:5:5, 16bpp, (msb)1A 5B 5G 5R(lsb), little-endian, most significant bit to 1
+
+ VAAPI_MOCO, ///< HW acceleration through VA API at motion compensation entry-point, Picture.data[3] contains a vaapi_render_state struct which contains macroblocks as well as various fields extracted from headers
+ VAAPI_IDCT, ///< HW acceleration through VA API at IDCT entry-point, Picture.data[3] contains a vaapi_render_state struct which contains fields extracted from headers
+ VAAPI_VLD, ///< HW decoding through VA API, Picture.data[3] contains a vaapi_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers
+
+ YUV420P16LE, ///< planar YUV 4:2:0, 24bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian
+ YUV420P16BE, ///< planar YUV 4:2:0, 24bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian
+ YUV422P16LE, ///< planar YUV 4:2:2, 32bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian
+ YUV422P16BE, ///< planar YUV 4:2:2, 32bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian
+ YUV444P16LE, ///< planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian
+ YUV444P16BE, ///< planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian
+ VDPAU_MPEG4, ///< MPEG4 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers
+ DXVA2_VLD, ///< HW decoding through DXVA2, Picture.data[3] contains a LPDIRECT3DSURFACE9 pointer
+
+ RGB444LE, ///< packed RGB 4:4:4, 16bpp, (msb)4A 4R 4G 4B(lsb), little-endian, most significant bits to 0
+ RGB444BE, ///< packed RGB 4:4:4, 16bpp, (msb)4A 4R 4G 4B(lsb), big-endian, most significant bits to 0
+ BGR444LE, ///< packed BGR 4:4:4, 16bpp, (msb)4A 4B 4G 4R(lsb), little-endian, most significant bits to 1
+ BGR444BE, ///< packed BGR 4:4:4, 16bpp, (msb)4A 4B 4G 4R(lsb), big-endian, most significant bits to 1
+ Y400A, ///< 8bit gray, 8bit alpha
+ BGR48BE, ///< packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as big-endian
+ BGR48LE, ///< packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as little-endian
+ YUV420P9BE, ///< planar YUV 4:2:0, 13.5bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian
+ YUV420P9LE, ///< planar YUV 4:2:0, 13.5bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian
+ YUV420P10BE,///< planar YUV 4:2:0, 15bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian
+ YUV420P10LE,///< planar YUV 4:2:0, 15bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian
+ YUV422P10BE,///< planar YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian
+ YUV422P10LE,///< planar YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian
+ YUV444P9BE, ///< planar YUV 4:4:4, 27bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian
+ YUV444P9LE, ///< planar YUV 4:4:4, 27bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian
+ YUV444P10BE,///< planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian
+ YUV444P10LE,///< planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian
+ YUV422P9BE, ///< planar YUV 4:2:2, 18bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian
+ YUV422P9LE, ///< planar YUV 4:2:2, 18bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian
+ VDA_VLD, ///< hardware decoding through VDA
+ GBRP, ///< planar GBR 4:4:4 24bpp
+ GBRP9BE, ///< planar GBR 4:4:4 27bpp, big endian
+ GBRP9LE, ///< planar GBR 4:4:4 27bpp, little endian
+ GBRP10BE, ///< planar GBR 4:4:4 30bpp, big endian
+ GBRP10LE, ///< planar GBR 4:4:4 30bpp, little endian
+ GBRP16BE, ///< planar GBR 4:4:4 48bpp, big endian
+ GBRP16LE, ///< planar GBR 4:4:4 48bpp, little endian
+ COUNT ///< number of pixel formats in this list
+ ;
+ public static PixelFormat valueOf(int i) {
+ for (PixelFormat fmt : PixelFormat.values()) {
+ if(fmt.ordinal() == i) {
+ return fmt;
+ }
+ }
+ return null;
+ }
+ }
+
+}
+