summaryrefslogtreecommitdiffstats
path: root/src/jogl/classes/jogamp/opengl/av
diff options
context:
space:
mode:
Diffstat (limited to 'src/jogl/classes/jogamp/opengl/av')
-rw-r--r--src/jogl/classes/jogamp/opengl/av/EGLMediaPlayerImpl.java109
-rw-r--r--src/jogl/classes/jogamp/opengl/av/GLMediaPlayerImpl.java307
2 files changed, 416 insertions, 0 deletions
diff --git a/src/jogl/classes/jogamp/opengl/av/EGLMediaPlayerImpl.java b/src/jogl/classes/jogamp/opengl/av/EGLMediaPlayerImpl.java
new file mode 100644
index 000000000..ef3d5072c
--- /dev/null
+++ b/src/jogl/classes/jogamp/opengl/av/EGLMediaPlayerImpl.java
@@ -0,0 +1,109 @@
+package jogamp.opengl.av;
+
+import javax.media.opengl.GLContext;
+
+import com.jogamp.opengl.util.texture.Texture;
+
+import jogamp.opengl.egl.EGL;
+import jogamp.opengl.egl.EGLContext;
+import jogamp.opengl.egl.EGLDrawable;
+import jogamp.opengl.egl.EGLExt;
+
+public abstract class EGLMediaPlayerImpl extends GLMediaPlayerImpl {
+ TextureType texType;
+ boolean useKHRSync;
+
+ public enum TextureType {
+ GL(0), KHRImage(1);
+
+ public final int id;
+
+ TextureType(int id){
+ this.id = id;
+ }
+ }
+
+ public static class EGLTextureFrame extends TextureFrame {
+
+ public EGLTextureFrame(Texture t, long khrImage, long khrSync) {
+ super(t);
+ this.image = khrImage;
+ this.sync = khrSync;
+ }
+
+ public final long getImage() { return image; }
+ public final long getSync() { return sync; }
+
+ public String toString() {
+ return "EGLTextureFrame[" + texture + ", img "+ image + ", sync "+ sync+"]";
+ }
+ protected final long image;
+ protected final long sync;
+ }
+
+
+ protected EGLMediaPlayerImpl() {
+ this(TextureType.GL, false);
+ }
+
+ protected EGLMediaPlayerImpl(TextureType texType, boolean useKHRSync) {
+ super();
+ this.texType = texType;
+ this.useKHRSync = useKHRSync;
+ }
+
+ @Override
+ protected TextureFrame createTexImage(GLContext ctx, int idx, int[] tex) {
+ final Texture texture = super.createTexImageImpl(ctx, idx, tex, true);
+ final long image;
+ final long sync;
+
+ final EGLContext eglCtx = (EGLContext) ctx;
+ final EGLExt eglExt = eglCtx.getEGLExt();
+ final EGLDrawable eglDrawable = (EGLDrawable) eglCtx.getGLDrawable();
+ int[] tmp = new int[1];
+
+ if(TextureType.KHRImage == texType) {
+ // create EGLImage from texture
+ tmp[0] = EGL.EGL_NONE;
+ image = eglExt.eglCreateImageKHR( eglDrawable.getDisplay(), eglCtx.getHandle(),
+ EGLExt.EGL_GL_TEXTURE_2D_KHR,
+ tex[idx], tmp, 0);
+ if (0==image) {
+ throw new RuntimeException("EGLImage creation failed: "+EGL.eglGetError()+", ctx "+eglCtx+", tex "+tex[idx]+", err "+toHexString(EGL.eglGetError()));
+ }
+ } else {
+ image = 0;
+ }
+
+ if(useKHRSync) {
+ // Create sync object so that we can be sure that gl has finished
+ // rendering the EGLImage texture before we tell OpenMAX to fill
+ // it with a new frame.
+ tmp[0] = EGL.EGL_NONE;
+ sync = eglExt.eglCreateSyncKHR(eglDrawable.getDisplay(), EGLExt.EGL_SYNC_FENCE_KHR, tmp, 0);
+ if (0==sync) {
+ throw new RuntimeException("EGLSync creation failed: "+EGL.eglGetError()+", ctx "+eglCtx+", err "+toHexString(EGL.eglGetError()));
+ }
+ } else {
+ sync = 0;
+ }
+ return new EGLTextureFrame(texture, image, sync);
+ }
+
+ @Override
+ protected void destroyTexImage(GLContext ctx, TextureFrame imgTex) {
+ final EGLContext eglCtx = (EGLContext) ctx;
+ final EGLExt eglExt = eglCtx.getEGLExt();
+ final EGLDrawable eglDrawable = (EGLDrawable) eglCtx.getGLDrawable();
+ final EGLTextureFrame eglTex = (EGLTextureFrame) imgTex;
+
+ if(0!=eglTex.getImage()) {
+ eglExt.eglDestroyImageKHR(eglDrawable.getDisplay(), eglTex.getImage());
+ }
+ if(0!=eglTex.getSync()) {
+ eglExt.eglDestroySyncKHR(eglDrawable.getDisplay(), eglTex.getSync());
+ }
+ super.destroyTexImage(ctx, imgTex);
+ }
+}
diff --git a/src/jogl/classes/jogamp/opengl/av/GLMediaPlayerImpl.java b/src/jogl/classes/jogamp/opengl/av/GLMediaPlayerImpl.java
new file mode 100644
index 000000000..826bb6953
--- /dev/null
+++ b/src/jogl/classes/jogamp/opengl/av/GLMediaPlayerImpl.java
@@ -0,0 +1,307 @@
+package jogamp.opengl.av;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLDrawable;
+import javax.media.opengl.GLES2;
+
+import com.jogamp.opengl.av.GLMediaPlayer;
+import com.jogamp.opengl.av.GLMediaEventListener;
+import com.jogamp.opengl.util.texture.Texture;
+
+/**
+ * After object creation an implementation may customize the behavior:
+ * <ul>
+ * <li>{@link #setTextureCount(int)}</li>
+ * <li>{@link #setTextureTarget(int)}</li>
+ * <li>{@link EGLMediaPlayerImpl#setEGLTexImageAttribs(boolean, boolean)}.</li>
+ * </ul>
+ *
+ * <p>
+ * See {@link GLMediaPlayer}.
+ * </p>
+ */
+public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
+
+ protected int textureCount;
+ protected int textureTarget;
+
+ private int sWidth = 0;
+ private int sHeight = 0;
+ protected URL url = null;
+
+ protected Texture texture = null;
+ protected float playSpeed = 1.0f;
+
+ /** Shall be set by the {@link #setStreamImpl()} method implementation. */
+ protected int width = 0;
+ /** Shall be set by the {@link #setStreamImpl()} method implementation. */
+ protected int height = 0;
+ /** Shall be set by the {@link #setStreamImpl()} method implementation. */
+ protected int fps = 0;
+ /** Shall be set by the {@link #setStreamImpl()} method implementation. */
+ protected long bps = 0;
+ /** Shall be set by the {@link #setStreamImpl()} method implementation. */
+ protected long totalFrames = 0;
+ /** Shall be set by the {@link #setStreamImpl()} method implementation. */
+ protected String acodec = null;
+ /** Shall be set by the {@link #setStreamImpl()} method implementation. */
+ protected String vcodec = null;
+
+ protected long frameNumber = 0;
+
+ private TextureFrame[] texFrames = null;
+ protected HashMap<Integer, TextureFrame> texFrameMap = new HashMap<Integer, TextureFrame>();
+ private ArrayList<GLMediaEventListener> eventListeners = new ArrayList<GLMediaEventListener>();
+
+ protected GLMediaPlayerImpl() {
+ this.textureCount=3;
+ this.textureTarget=GL.GL_TEXTURE_2D;
+ }
+
+ protected final void setTextureCount(int textureCount) {
+ this.textureCount=textureCount;
+ }
+ protected final void setTextureTarget(int textureTarget) {
+ this.textureTarget=textureTarget;
+ }
+
+ @Override
+ public final void setStream(GL gl, URL url) throws IOException {
+ this.url = url;
+ if (this.url == null) {
+ System.out.println("setURL (null)");
+ stop();
+ return;
+ }
+ setStreamImpl();
+ init(gl);
+ }
+
+ /**
+ * Implementation shall set the following set of data:
+ * @see #width
+ * @see #height
+ * @see #fps
+ * @see #bps
+ * @see #totalFrames
+ * @see #acodec
+ * @see #vcodec
+ */
+ protected abstract void setStreamImpl() throws IOException;
+
+ protected final void init(GL gl) {
+ final GLContext ctx = gl.getContext();
+ if(!ctx.isCurrent()) {
+ throw new RuntimeException("Not current: "+ctx);
+ }
+
+ final GLDrawable drawable = ctx.getGLDrawable();
+ sWidth = drawable.getWidth();
+ sHeight = drawable.getHeight();
+ System.out.println("surface size: "+sWidth+"x"+sHeight);
+ System.out.println("Platform Extensions : "+ctx.getPlatformExtensionsString());
+
+ if(null!=texFrames) {
+ removeAllImageTextures(ctx);
+ } else {
+ texFrames = new TextureFrame[textureCount];
+ }
+
+ final int[] tex = new int[textureCount];
+ {
+ gl.glGenTextures(textureCount, tex, 0);
+ final int err = gl.glGetError();
+ if( GL.GL_NO_ERROR != err ) {
+ throw new RuntimeException("TextureNames creation failed (num: "+textureCount+"): err "+toHexString(err));
+ }
+ }
+
+ for(int i=0; i<textureCount; i++) {
+ final TextureFrame tf = createTexImage(ctx, i, tex);
+ texFrames[i] = tf;
+ texFrameMap.put(tex[i], tf);
+ }
+ }
+
+ protected TextureFrame createTexImage(GLContext ctx, int idx, int[] tex) {
+ return new TextureFrame( createTexImageImpl(ctx, idx, tex, true) );
+ }
+
+ protected Texture createTexImageImpl(GLContext ctx, int idx, int[] tex, boolean mustFlipVertically) {
+ final GL gl = ctx.getGL();
+ if( 0 > tex[idx] ) {
+ throw new RuntimeException("TextureName "+toHexString(tex[idx])+" invalid.");
+ }
+ gl.glBindTexture(textureTarget, tex[idx]);
+ {
+ final int err = gl.glGetError();
+ if( GL.GL_NO_ERROR != err ) {
+ throw new RuntimeException("Couldn't bind textureName "+toHexString(tex[idx])+" to 2D target, err "+toHexString(err));
+ }
+ }
+
+ // create space for buffer with a texture
+ gl.glTexImage2D(
+ textureTarget, // target
+ 0, // level
+ GL.GL_RGBA, // internal format
+ width, // width
+ height, // height
+ 0, // border
+ GL.GL_RGBA, // format
+ GL.GL_UNSIGNED_BYTE, // type
+ null); // pixels -- will be provided later
+ {
+ final int err = gl.glGetError();
+ if( GL.GL_NO_ERROR != err ) {
+ throw new RuntimeException("Couldn't create TexImage2D RGBA "+width+"x"+height+", err "+toHexString(err));
+ }
+ }
+ gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST);
+ gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST);
+ // Clamp to edge is only option.
+ gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE);
+ gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE);
+
+ return com.jogamp.opengl.util.texture.TextureIO.newTexture(tex[idx],
+ textureTarget,
+ width, height,
+ width, height,
+ mustFlipVertically);
+ }
+
+ protected void destroyTexImage(GLContext ctx, TextureFrame imgTex) {
+ imgTex.getTexture().destroy(ctx.getGL());
+ }
+
+ protected void removeAllImageTextures(GLContext ctx) {
+ texture = null;
+ for(int i=0; i<textureCount; i++) {
+ final TextureFrame imgTex = texFrames[i];
+ destroyTexImage(ctx, imgTex);
+ texFrames[i] = null;
+ }
+ texFrameMap.clear();
+ }
+
+ protected void attributesUpdated(int event_mask) {
+ synchronized(eventListenersLock) {
+ for(Iterator<GLMediaEventListener> i = eventListeners.iterator(); i.hasNext(); ) {
+ i.next().attributesChanges(this, event_mask);
+ }
+ }
+ }
+ protected void newFrameAvailable(TextureFrame frame) {
+ synchronized(eventListenersLock) {
+ for(Iterator<GLMediaEventListener> i = eventListeners.iterator(); i.hasNext(); ) {
+ i.next().newFrameAvailable(this, frame);
+ }
+ }
+ }
+
+ @Override
+ public synchronized float getPlaySpeed() {
+ return playSpeed;
+ }
+
+ @Override
+ public synchronized Texture getLastTextureID() {
+ return texture;
+ }
+
+ @Override
+ public synchronized void destroy(GL gl) {
+ destroyImpl(gl);
+ removeAllImageTextures(gl.getContext());
+ }
+ protected abstract void destroyImpl(GL gl);
+
+ @Override
+ public synchronized URL getURL() {
+ return url;
+ }
+
+ @Override
+ public synchronized String getVideoCodec() {
+ return vcodec;
+ }
+
+ @Override
+ public synchronized String getAudioCodec() {
+ return acodec;
+ }
+
+ @Override
+ public synchronized long getTotalFrames() {
+ return totalFrames;
+ }
+
+ @Override
+ public synchronized long getBitrate() {
+ return bps;
+ }
+
+ @Override
+ public synchronized int getFramerate() {
+ return fps;
+ }
+
+ @Override
+ public synchronized int getWidth() {
+ return width;
+ }
+
+ @Override
+ public synchronized int getHeight() {
+ return height;
+ }
+
+ @Override
+ public synchronized String toString() {
+ return "GLMediaPlayer [ stream [ video [ "+vcodec+", "+width+"x"+height+", "+fps+"fps, "+bps+"bsp, "+totalFrames+"f ] ] ]";
+ }
+
+ @Override
+ public void addEventListener(GLMediaEventListener l) {
+ if(l == null) {
+ return;
+ }
+ synchronized(eventListenersLock) {
+ eventListeners.add(l);
+ }
+ }
+
+ @Override
+ public void removeEventListener(GLMediaEventListener l) {
+ if (l == null) {
+ return;
+ }
+ synchronized(eventListenersLock) {
+ eventListeners.remove(l);
+ }
+ }
+
+ @Override
+ public synchronized GLMediaEventListener[] getEventListeners() {
+ synchronized(eventListenersLock) {
+ return eventListeners.toArray(new GLMediaEventListener[eventListeners.size()]);
+ }
+ }
+
+ private Object eventListenersLock = new Object();
+
+ protected static final String toHexString(long v) {
+ return "0x"+Long.toHexString(v);
+ }
+ protected static final String toHexString(int v) {
+ return "0x"+Integer.toHexString(v);
+ }
+
+} \ No newline at end of file