diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/classes/com/sun/javafx/media/video/openmax/OMXMoviePlayerImpl.java | 548 | ||||
-rw-r--r-- | src/classes/com/sun/opengl/impl/NativeLibLoader.java | 4 | ||||
-rw-r--r-- | src/classes/javax/media/opengl/GLArrayDataServer.java | 4 | ||||
-rw-r--r-- | src/native/openmax/com_sun_javafx_media_video_openmax_OMXMoviePlayerImpl.c | 363 | ||||
-rw-r--r-- | src/native/openmax/omx_tool.c | 1597 | ||||
-rw-r--r-- | src/native/openmax/omx_tool.h | 145 |
6 files changed, 2658 insertions, 3 deletions
diff --git a/src/classes/com/sun/javafx/media/video/openmax/OMXMoviePlayerImpl.java b/src/classes/com/sun/javafx/media/video/openmax/OMXMoviePlayerImpl.java new file mode 100644 index 000000000..eefd02402 --- /dev/null +++ b/src/classes/com/sun/javafx/media/video/openmax/OMXMoviePlayerImpl.java @@ -0,0 +1,548 @@ + +package com.sun.javafx.media.video.openmax; + +import javax.media.opengl.*; +import javax.media.opengl.glu.GLU; +import com.sun.opengl.util.texture.*; + +import com.sun.opengl.impl.egl.EGL; +import com.sun.opengl.impl.egl.EGLContext; +import com.sun.opengl.impl.egl.EGLDrawable; +import com.sun.opengl.impl.egl.EGLExt; + +import java.net.URL; +import java.nio.ByteBuffer; +import java.io.File; +import java.io.FileNotFoundException; +import java.util.*; + +public class OMXMoviePlayerImpl /* extends MoviePlayerImpl */ { + + static final public int PREVIOUS = -1; + static final public int NEXT = 1; + + public boolean isTransparent() { + return false; + } + + long totalFrames = 0; + int width = 0; + int height = 0; + float fps = 0.0f; + + int pixelBytes = 0; + int pixelType = 0; + + EGLExt eglExt = null; + long eglSurface=0; + long eglDisplay=0; + long eglContext=0; + int sWidth=0, sHeight=0; + int textureNum = 4; + + static class EGLImageTexture { + public EGLImageTexture(com.sun.opengl.util.texture.Texture t, long i, long s) { + System.out.println("EGLImageTexture " + t + ", image " + i + ", sync "+s); + texture = t; image = i; sync = s; + } + protected com.sun.opengl.util.texture.Texture texture; + protected long image; + protected long sync; + } + EGLImageTexture[] eglImgTexs=null; + HashMap eglImgTexsMap = new HashMap(); + + long moviePtr = 0; + String path = null; + URL url; + String name = null; + String nameClean = null; + int loopCount = 0; + long position = 0; + float volume = 1.0f; + float rate = 1.0f; + boolean playing = false; + boolean paused = false; + + native long _createInstance(int numTextures); + native void _setStream(long moviePtr, String path); + native void _updateStreamInfo(long moviePtr); + native void _setEGLImageTexture2D(long moviePtr, int i, int tex, long image, long sync); + native void _activateInstance(long moviePtr); + native void _deactivateInstance(long moviePtr); + + native void _play(long moviePtr, long position, float rate, int loopCount); + native long _stop(long moviePtr); + native void _setVolume(long moviePtr, float volume); + native long _getCurrentPosition(long moviePtr); + native long _setCurrentPosition(long moviePtr, long position); + native long _getCurrentLoaded(long moviePtr); + native long _step(long moviePtr, int direction, long position); + native void _setRate(long moviePtr, float rate); + native int _getTextureID(long moviePtr); + native int _getWidth(long moviePtr); + native int _getHeight(long moviePtr); + native long _getDuration(long moviePtr); + + native void _destroyInstance(long moviePtr); + + public OMXMoviePlayerImpl() { + System.out.println("OMXMoviePlayerImpl (null)"); + } + + public OMXMoviePlayerImpl(URL url) { + System.out.println("OMXMoviePlayerImpl ("+url+")"); + setURL(url); + } + + public void update() { + update(null); + } + + /** + public int moduleTest() { + return _moduleTest(); + } + native int _moduleTest(); + */ + + public void update(GL gl) { + if (moviePtr == 0) { + return; + } + System.out.println("update: totalFrames "+totalFrames); + totalFrames = _getDuration(moviePtr); + int w = _getWidth(moviePtr); + int h = _getHeight(moviePtr); + if (h != height || w!=width) { + System.out.println("update: size change "+width+"x"+height+" -> "+w+"x"+h); + width = w; + height = h; + // FIXME: TODO + // [1] EventListener model to notify clients of dimension change + // [2] Reallocate ressources (Textures, EGLImage, ..) + if(null==gl) { + gl = GLU.getCurrentGL(); + } + try { + setAllEGLImageTexture2D(gl); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } else { + System.out.println("update: none"); + } + } + + private String replaceAll(String orig, String search, String repl) { + String dest=null; + // In case replaceAll / java.util.regex.* is not supported (-> CVM) + int i=0,j; + dest = new String(); + while((j=orig.indexOf(search, i))>=0) { + dest=dest.concat(orig.substring(i, j)); + dest=dest.concat(repl); + i=j+1; + } + return dest.concat(orig.substring(i, orig.length())); + } + + public synchronized void setURL(URL u) { + url = u; + if (url == null) { + System.out.println("setURL (null)"); + stop(); + return; + } + path=null; + if (url.getProtocol() == null || "file".equals(url.getProtocol())) { + // CV only accepts absolute paths + try { + File file = new File(url.getPath()); + if (!file.exists()) { + throw new RuntimeException(new FileNotFoundException(file.toString())); + } + path = file.getCanonicalPath(); + System.out.println("setURL: path "+path); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + path = replaceAll(path, "\\", "/").trim(); + if(null==path) { + throw new RuntimeException("Couldn't parse stream URL: "+url); + } + System.out.println("setURL: clean path "+path); + + GL gl = initGLData(); + + if(0!=moviePtr) { + dispose(); + } + moviePtr = _createInstance(textureNum); + if (moviePtr == 0) { + throw new RuntimeException("Couldn't establish native playback: "+url); + } + _setStream(moviePtr, path); + width = _getWidth(moviePtr); + height = _getHeight(moviePtr); + if(width==0 || height==0) { + throw new RuntimeException("Illegal media dimension "+width+"x"+height); + } + System.out.println("movie size: "+width+"x"+height); + + setAllEGLImageTexture2D(gl); + + _activateInstance(moviePtr); + + position = 0; + } + + private GL initGLData() { + GL gl = GLU.getCurrentGL(); + if(null==gl) { + throw new RuntimeException("No current GL"); + } + /* + if(gl.isGLES2()) { + GLES2 gles2 = gl.getGLES2(); + + // Debug .. + //DebugGLES2 gldbg = new DebugGLES2(gles2); + //gles2.getContext().setGL(gldbg); + //gles2 = gldbg; + + // Trace .. + TraceGLES2 gltrace = new TraceGLES2(gles2, System.out); + gles2.getContext().setGL(gltrace); + gl = gltrace; + }*/ + EGLContext eglCtx = (EGLContext) gl.getContext(); + if(null==eglCtx) { + throw new RuntimeException("No current EGL context"); + } + EGLDrawable eglDrawable = (EGLDrawable) eglCtx.getGLDrawable(); + if(null==eglDrawable) { + throw new RuntimeException("No valid drawable"); + } + eglContext = eglCtx.getContext(); + eglDisplay = eglDrawable.getDisplay(); + eglSurface = eglDrawable.getSurface(); + eglExt = eglCtx.getEGLExt(); + if(null==eglExt) { + throw new RuntimeException("No valid EGLExt"); + } + + int iTmp[] = new int[1]; + EGL.eglQuerySurface(eglDisplay, eglSurface, EGL.EGL_WIDTH, iTmp, 0); + sWidth=iTmp[0]; + EGL.eglQuerySurface(eglDisplay, eglSurface, EGL.EGL_HEIGHT, iTmp, 0); + sHeight=iTmp[0]; + System.out.println("surface size: "+width+"x"+height); + System.out.println(eglDrawable); + System.out.println(eglCtx); + System.out.println("EGL Extensions : "+EGL.eglQueryString(eglDisplay, EGL.EGL_EXTENSIONS)); + System.out.println("EGL CLIENT APIs: "+EGL.eglQueryString(eglDisplay, EGL.EGL_CLIENT_APIS)); + return gl; + } + + private void removeAllEGLImageTexture2D() { + System.out.println("removeAllEGLImg: mp "+moviePtr+", textureNum "+textureNum); + if (moviePtr != 0) { + texture = null; + for(int i=0; i<textureNum; i++) { + eglExt.eglDestroyImage( + eglDisplay, + eglImgTexs[i].image); + eglExt.eglDestroySync(eglImgTexs[i].sync); + // JAU eglImgTexs[i].texture.dispose(); + eglImgTexs[i]=null; + } + eglImgTexsMap.clear(); + } + } + + private void errorCheckGL(GL gl, String s) { + int e; + if( (e=gl.glGetError()) != GL.GL_NO_ERROR ) { + System.out.println("GL Error: ("+s+"): "+e); + } + } + + private void errorCheckEGL(String s) { + int e; + if( (e=EGL.eglGetError()) != EGL.EGL_SUCCESS ) { + System.out.println("EGL Error: ("+s+"): "+e); + } + } + + private void setAllEGLImageTexture2D(GL gl) { + if (moviePtr == 0) { + return; + } + if(null!=eglImgTexs) { + removeAllEGLImageTexture2D(); + } else { + eglImgTexs = new EGLImageTexture[textureNum]; + } + + int[] tmp = new int[1]; + int tex, e; + + gl.glEnable(gl.GL_TEXTURE_2D); + errorCheckGL(gl, "i.2"); + + for(int i=0; i<textureNum; i++) { + String s0 = String.valueOf(i); + gl.glGenTextures(1, tmp, 0); + tex=tmp[0]; + if( (e=gl.glGetError()) != GL.GL_NO_ERROR || 0>tex ) { + throw new RuntimeException("TextureName creation failed: "+e); + } + gl.glBindTexture(gl.GL_TEXTURE_2D, tex); + + // create space for buffer with a texture + gl.glTexImage2D( + gl.GL_TEXTURE_2D, // 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 + gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_NEAREST); + gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_NEAREST); + + long image=0, sync=0; + + // create EGLImage from texture + tmp[0] = EGL.EGL_NONE; + image = eglExt.eglCreateImage( + eglDisplay, + eglContext, + eglExt.EGL_GL_TEXTURE_2D, + tex, + tmp, 0); + if (0==image) { + throw new RuntimeException("EGLImage creation failed: "+EGL.eglGetError()); + } + + // 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.eglCreateFenceSync( + eglDisplay, + eglExt.EGL_SYNC_PRIOR_COMMANDS_COMPLETE, tmp, 0); + + _setEGLImageTexture2D(moviePtr, i, tex, image, sync); + + eglImgTexs[i] = new EGLImageTexture( + com.sun.opengl.util.texture.TextureIO.newTexture(tex, + javax.media.opengl.GL2.GL_TEXTURE_2D, + width, + height, + width, + height, + true), + image, sync); + eglImgTexsMap.put(new Integer(tex), eglImgTexs[i]); + } + } + + public boolean isValid() { + return (moviePtr != 0); + } + + public String getPath() { + return path; + } + + public URL getURL() { + return url; + } + + // start playing from the beginning (user frame) + public void play() { + paused = false; + if (moviePtr == 0) { + return; + } + playing = true; + _play(moviePtr, position, rate, loopCount); + } + + public boolean isPlaying() { + return playing; + } + + public long pause() { + paused = true; + if (moviePtr == 0) { + return 0; + } + if (height != 0 && width != 0) { + position = stop(); + } + return position; + } + + // returns the last played frame + public long stop() { + if (moviePtr == 0) { + return 0; + } + playing = false; + position = _stop(moviePtr); + return position; + } + + public long step(int direction) { + if (moviePtr == 0) { + return 0; + } + if (isPlaying()) { + stop(); + } + position = _step(moviePtr, direction, position); + return position; + } + + // 0 (no volume) to 1 (max volume) + public void setVolume(float volume) { + if (moviePtr == 0) { + return; + } + + if (volume < 0.0f) { + volume = 0.0f; + } + volume = volume; + _setVolume(moviePtr, volume); + } + + public float getVolume() { + return volume; + } + + public void setLoopCount(int loopCount) { + loopCount = loopCount; + } + + public int getLoopCount() { + return loopCount; + } + + // in frames + public void setPosition(long position) { + if (position < 0) { + position = 0; + } else if (position <= totalFrames) { + position = position; + } + else { + position = 0; + } + _setCurrentPosition(moviePtr, position); + } + + public long getLoaded() { + if (moviePtr == 0) { + return 0; + } + return _getCurrentLoaded(moviePtr); + } + + public long getPosition() { + if (moviePtr == 0) { + position = 0; + } else if (playing == true) { + long pos = _getCurrentPosition(moviePtr); + //System.out.println("getPosition " + pos + " " + position); + position = pos; + } + return position; + } + + public long getEndPosition() { + return totalFrames; + } + + public void setRate(float rate) { + setPlaybackRate(rate); + } + + public float getRate() { + return getPlaybackRate(); + } + + // -1.0f - backwards normal speed + // 0.5f - 1/2x speed + // 1.0f - normal speed + // 2.0f - 2x speed + public void setPlaybackRate(float r) { + if (moviePtr == 0) { + return; + } + rate = r; + _setRate(moviePtr, rate); + } + + public float getPlaybackRate() { + return rate; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + + public synchronized void dispose() { + removeAllEGLImageTexture2D(); + if (moviePtr != 0) { + long ptr = moviePtr; + moviePtr = 0; + _destroyInstance(ptr); + + eglExt=null; + eglSurface=0; + eglDisplay=0; + eglContext=0; + } + } + + protected synchronized void finalize() { + if (moviePtr != 0) { + dispose(); + } + } + + // *** Texture impl + + com.sun.opengl.util.texture.Texture texture = null; // holds the last fetched texture + + public void unlockTexture() { + // FIXME: EGLSync notification ? + } + + public Texture lockTexture() { + texture=null; + if (moviePtr == 0) { + return null; + } + EGLImageTexture eglImgTex = (EGLImageTexture) eglImgTexsMap.get(new Integer(_getTextureID(moviePtr))); + if(null!=eglImgTex) { + texture = eglImgTex.texture; + } + return texture; + } +} + diff --git a/src/classes/com/sun/opengl/impl/NativeLibLoader.java b/src/classes/com/sun/opengl/impl/NativeLibLoader.java index 6327c17d2..851099daf 100644 --- a/src/classes/com/sun/opengl/impl/NativeLibLoader.java +++ b/src/classes/com/sun/opengl/impl/NativeLibLoader.java @@ -109,7 +109,7 @@ public class NativeLibLoader { public static void loadNEWT() { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { - loadLibrary("newt", null, false, false); + loadLibrary("newt", null, false, false); // JAU return null; } }); @@ -137,6 +137,8 @@ public class NativeLibLoader { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { loadLibrary("jogl_es2", null, false, false); + // JAU loadLibrary("jogl_es2", null, false, false); // JAU + // JAU loadLibrary("jfxFramework", null, false, false); // JAU return null; } }); diff --git a/src/classes/javax/media/opengl/GLArrayDataServer.java b/src/classes/javax/media/opengl/GLArrayDataServer.java index 53b5b896a..ead0b58f2 100644 --- a/src/classes/javax/media/opengl/GLArrayDataServer.java +++ b/src/classes/javax/media/opengl/GLArrayDataServer.java @@ -186,8 +186,8 @@ public class GLArrayDataServer extends GLArrayDataClient implements GLArrayDataE if( ! (GLProfile.isGL2ES2() && vboBufferUsage==GL2ES2.GL_STREAM_DRAW) ) { switch(vboBufferUsage) { case -1: // nop - case GL2ES1.GL_STATIC_DRAW: - case GL2ES1.GL_DYNAMIC_DRAW: + case GL.GL_STATIC_DRAW: + case GL.GL_DYNAMIC_DRAW: break; default: throw new GLException("invalid vboBufferUsage: "+vboBufferUsage+":\n\t"+this); diff --git a/src/native/openmax/com_sun_javafx_media_video_openmax_OMXMoviePlayerImpl.c b/src/native/openmax/com_sun_javafx_media_video_openmax_OMXMoviePlayerImpl.c new file mode 100644 index 000000000..6800246fc --- /dev/null +++ b/src/native/openmax/com_sun_javafx_media_video_openmax_OMXMoviePlayerImpl.c @@ -0,0 +1,363 @@ +/* + * javafx_media_video_Movie.c + * JFXFramework + * + * Created by sun on 17/02/08. + * Copyright 2007 __MyCompanyName__. All rights reserved. + * + */ + +// http://developer.apple.com/technotes/tn2005/tn2140.html +// http://developer.apple.com/qa/qa2005/qa1443.html +// http://developer.apple.com/documentation/QuickTime/Conceptual/QT7UpdateGuide/Chapter03/chapter_3_section_1.html#//apple_ref/doc/c_ref/NewMovieFromProperties +// http://developer.apple.com/qa/qa2001/qa1149.html +// http://developer.apple.com/qa/qa2001/qa1262.html + +#include "com_sun_javafx_media_video_openmax_OMXMoviePlayerImpl.h" +#include "omx_tool.h" +#include <stdarg.h> + +static const char * const ClazzNameRuntimeException = + "java/lang/RuntimeException"; +static jclass runtimeExceptionClz=NULL; +#ifdef _WIN32_WCE + #define STDOUT_FILE "\\Storage Card\\javafx_demos\\stdout.txt" + #define STDERR_FILE "\\Storage Card\\javafx_demos\\stderr.txt" +#endif + +static void _initStatics(JNIEnv *env) +{ + jclass c; +#ifdef _WIN32_WCE + _wfreopen(TEXT(STDOUT_FILE),L"w",stdout); + _wfreopen(TEXT(STDERR_FILE),L"w",stderr); +#endif + fprintf(stdout, "_initstatics ..\n"); fflush(stdout); // JAU + if (runtimeExceptionClz != NULL) { + return; + } + + c = (*env)->FindClass(env, ClazzNameRuntimeException); + if(NULL==c) { + fprintf(stdout, "FatalError: can't find %s\n", ClazzNameRuntimeException); + (*env)->FatalError(env, ClazzNameRuntimeException); + } + runtimeExceptionClz = (jclass)(*env)->NewGlobalRef(env, c); + if(NULL==runtimeExceptionClz) { + fprintf(stdout, "FatalError: can't use %s\n", ClazzNameRuntimeException); + (*env)->FatalError(env, ClazzNameRuntimeException); + } +} + +static JNIEnv *_env = NULL; +void java_throwNewRuntimeException(JNIEnv *env, const char* format, ...) +{ + va_list ap; + char buffer[255]; + va_start(ap, format); + if(env!=NULL) { + _env=env; + } + #ifdef _WIN32 + _vsnprintf(buffer, sizeof(buffer)-1, format, ap); + #else + vsnprintf(buffer, sizeof(buffer)-1, format, ap); + #endif + va_end(ap); + buffer[sizeof(buffer)-1]=0; + fprintf(stderr, "RuntimeException: %s\n", buffer); fflush(stderr); + if(_env!=NULL) { + (*env)->ThrowNew(_env, runtimeExceptionClz, buffer); + } +} + +JNIEXPORT jlong JNICALL Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1createInstance + (JNIEnv *env, jobject instance, jint vBufferNum) +{ + OMXToolBasicAV_t * pOMXAV; + + _initStatics(env); + _env = env; + + pOMXAV = OMXToolBasicAV_CreateInstance(vBufferNum); + + return (jlong)((intptr_t)((void *)pOMXAV)); +} + +JNIEXPORT void JNICALL Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1setStream + (JNIEnv *env, jobject instance, jlong ptr, jstring jpath) +{ + jboolean iscopy; + OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); + + _env = env; + + fprintf(stdout, "setStream 1 ..\n"); fflush(stdout); // JAU + if (pOMXAV != NULL) { + const char *filePath = (*env)->GetStringUTFChars(env, jpath, &iscopy); + fprintf(stdout, "setStream 2 %s..\n", filePath); fflush(stdout); // JAU + OMXToolBasicAV_SetStream(pOMXAV, filePath); + (*env)->ReleaseStringChars(env, jpath, (const jchar *)filePath); + } + fprintf(stdout, "setStream 3 ..\n"); fflush(stdout); // JAU +} + +JNIEXPORT void JNICALL Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1updateStreamInfo + (JNIEnv *env, jobject instance, jlong ptr) +{ + OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); + + _env = env; + + if (pOMXAV != NULL) { + OMXToolBasicAV_UpdateStreamInfo(pOMXAV); + } +} + +JNIEXPORT void JNICALL Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1setEGLImageTexture2D + (JNIEnv *env, jobject instance, jlong ptr, jint i, jint tex, jlong image, jlong sync) +{ + OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); + _env = env; + if (pOMXAV != NULL) { + OMXToolBasicAV_SetEGLImageTexture2D( pOMXAV, i, (GLuint) tex, + (EGLImageKHR)(intptr_t)image, + (EGLSyncKHR)(intptr_t)sync); + } +} + +JNIEXPORT void JNICALL Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1activateInstance + (JNIEnv *env, jobject instance, jlong ptr) +{ + OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); + + _env = env; + + if (pOMXAV != NULL) { + OMXToolBasicAV_ActivateInstance(pOMXAV); + } +} + +/* + * Class: com_sun_javafx_media_video_openmax_OMXMovieImpl + * Method: _play + * Signature: (ILjava/nio/ByteBuffer;JFI)V + */ +JNIEXPORT void JNICALL Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1play + (JNIEnv *env, jobject instance, jlong ptr, jlong position, jfloat rate, jint loopCount) +{ +//fprintf(stdout, "Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1play\n"); + OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); + _env = env; + if (pOMXAV != NULL) { + if(OMXToolBasicAV_PlayStart(pOMXAV)) { + java_throwNewRuntimeException(env, "Couldn't start play %p p:%ld r:%f l%d", + pOMXAV, position, rate, loopCount); + } + } +} + +/* + * Class: com_sun_javafx_media_video_openmax_OMXMovieImpl + * Method: _stop + * Signature: (I)I + */ +JNIEXPORT jlong JNICALL Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1stop + (JNIEnv *env, jobject instance, jlong ptr) +{ + jlong frame = 0; + _env = env; + return frame; +} + +/* + * Class: com_sun_javafx_media_video_openmax_OMXMovieImpl + * Method: _setVolume + * Signature: (IF)V + */ +JNIEXPORT void JNICALL Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1setVolume + (JNIEnv *env, jobject instance, jlong ptr, jfloat volume) +{ + _env = env; +} + +/* + * Class: com_sun_javafx_media_video_openmax_OMXMovieImpl + * Method: _getCurrentPosition + * Signature: (I)I + */ +JNIEXPORT jlong JNICALL Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1getCurrentPosition + (JNIEnv *env, jobject instance, jlong ptr) +{ + jlong frame = 0; + _env = env; + return frame; +} + +/* + * Class: com_sun_javafx_media_video_openmax_OMXMovieImpl + * Method: _getCurrentPosition + * Signature: (I)I + */ +JNIEXPORT jlong JNICALL Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1getCurrentLoaded + (JNIEnv *env, jobject instance, jlong ptr) +{ + jlong frame = 0; + _env = env; + return frame; +} + +JNIEXPORT jlong JNICALL Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1getDuration + (JNIEnv *env, jobject instance, jlong ptr) +{ + jlong frame = 0; + _env = env; + return frame; +} +/* + * Class: com_sun_javafx_media_video_openmax_OMXMovieImpl + * Method: _step + * Signature: (IIJ)V + */ +JNIEXPORT jlong JNICALL Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1step + (JNIEnv *env, jobject instance, jlong ptr, jint direction, jlong position) +{ +//fprintf(stdout, "Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1step\n"); + jlong frame = position; + _env = env; + return frame; +} + +/* + * Class: com_sun_javafx_media_video_openmax_OMXMovieImpl + * Method: _setRate + * Signature: (IF)V + */ +JNIEXPORT void JNICALL Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1setRate + (JNIEnv *env, jobject instance, jlong ptr, jfloat rate) +{ +//fprintf(stdout, "Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1setRate\n"); + _env = env; +} + +/* + * Class: com_sun_javafx_media_video_openmax_OMXMovieImpl + * Method: _setRate + * Signature: (IF)V + */ +JNIEXPORT jlong JNICALL Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1setCurrentPosition + (JNIEnv *env, jobject obj, jlong ptr, jlong position) +{ +//fprintf(stdout, "Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1setRate\n"); + _env = env; + return position; +} + +/* + * Class: com_sun_javafx_media_video_openmax_OMXMovieImpl + * Method: _lock + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1lock + (JNIEnv *env, jobject instance, jlong ptr) +{ +//fprintf(stdout, "Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1lock\n"); + _env = env; +} + +/* + * Class: com_sun_javafx_media_video_openmax_OMXMovieImpl + * Method: _unlock + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1unlock + (JNIEnv *env, jobject instance, jlong ptr) +{ +//fprintf(stdout, "Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1unlock\n"); + _env = env; +} + +/* + * Class: com_sun_javafx_media_video_openmax_OMXMovieImpl + * Method: _getTextureID + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1getTextureID + (JNIEnv *env, jobject instance, jlong ptr) +{ +//fprintf(stdout, "Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1getTextureID\n"); + jint textureID = 0xffffffff; + OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); + _env = env; + if (pOMXAV != NULL) { + textureID = OMXToolBasicAV_GetTexture(pOMXAV); + } + return textureID; +} + +/* + * Class: com_sun_javafx_media_video_openmax_OMXMovieImpl + * Method: _getWidth + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1getWidth + (JNIEnv *env, jobject instance, jlong ptr) +{ +//fprintf(stdout, "Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1getWidth\n"); + jint width = 0; + + OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); + _env = env; + if (pOMXAV != NULL) { + width = pOMXAV->width; + } + return width; +} + +/* + * Class: com_sun_javafx_media_video_openmax_OMXMovieImpl + * Method: _getHeight + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1getHeight + (JNIEnv *env, jobject instance, jlong ptr) +{ +//fprintf(stdout, "Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1getHeight\n"); + jint height = 0; + + OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); + _env = env; + if (pOMXAV != NULL) { + height = pOMXAV->height; + } + return height; +} + +/* + * Class: com_sun_javafx_media_video_openmax_OMXMovieImpl + * Method: _task + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1task + (JNIEnv *env, jobject instance, jlong ptr) +{ + _env = env; +} + +/* + * Class: com_sun_javafx_media_video_openmax_OMXMovieImpl + * Method: _destroy + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1destroyInstance + (JNIEnv *env, jobject instance, jlong ptr) +{ +//fprintf(stdout, "Java_com_sun_javafx_media_video_openmax_OMXMovieImpl__1destroy\n"); + OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); + _env = env; + if (pOMXAV != NULL) { + OMXToolBasicAV_DestroyInstance(pOMXAV); + } +} + + diff --git a/src/native/openmax/omx_tool.c b/src/native/openmax/omx_tool.c new file mode 100644 index 000000000..a727996b4 --- /dev/null +++ b/src/native/openmax/omx_tool.c @@ -0,0 +1,1597 @@ + +#include "omx_tool.h" + +#include <NVOMX_IndexExtensions.h> +#if !defined(SELF_TEST) + #include <jni.h> +#endif + +#define NOTSET_U8 ((OMX_U8)0xDE) +#define NOTSET_U16 ((OMX_U16)0xDEDE) +#define NOTSET_U32 ((OMX_U32)0xDEDEDEDE) +#define INIT_PARAM(_X_) (memset(&(_X_), NOTSET_U8, sizeof(_X_)), ((_X_).nSize = sizeof (_X_)), (_X_).nVersion = vOMX) + +#if !defined(SELF_TEST) +void java_throwNewRuntimeException(JNIEnv *env, const char* format, ...); +#else +#include <stdarg.h> +void java_throwNewRuntimeException(void *env, const char* format, ...) { + va_list ap; + char buffer[255]; + va_start(ap, format); + #ifdef _WIN32 + _vsnprintf(buffer, sizeof(buffer)-1, format, ap); + #else + vsnprintf(buffer, sizeof(buffer)-1, format, ap); + #endif + va_end(ap); + buffer[sizeof(buffer)-1]=0; + fprintf(stderr, "RuntimeException: %s\n", buffer); fflush(stderr); + exit(1); +} +#endif +static void DestroyInstanceUnlock(OMXToolBasicAV_t * pOMXAV); + +#define OMXSAFE(x) \ +do { \ + OMX_ERRORTYPE err = (x); \ + if (err != OMX_ErrorNone) { \ + java_throwNewRuntimeException(NULL, "FAILED at %s:%d, Error: 0x%x\n", __FILE__, __LINE__, err); \ + if(NULL!=pOMXAV) { \ + DestroyInstanceUnlock(pOMXAV); \ + } \ + return -1; \ + } \ +} while (0); + +#define OMXSAFEERR(x) \ +do { \ + OMX_ERRORTYPE err = (x); \ + if (err != OMX_ErrorNone) { \ + java_throwNewRuntimeException(NULL, "FAILED at %s:%d, Error: 0x%x\n", __FILE__, __LINE__, err); \ + if(NULL!=pOMXAV) { \ + DestroyInstanceUnlock(pOMXAV); \ + } \ + return err; \ + } \ +} while (0); + +static PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR; +static PFNEGLCREATEFENCESYNCKHRPROC eglCreateFenceSyncKHR; +static PFNEGLFENCEKHRPROC eglFenceKHR; +static PFNEGLGETSYNCATTRIBKHRPROC eglGetSyncAttribKHR; +static PFNEGLSIGNALSYNCKHRPROC eglSignalSyncKHR; +static int _hasEGLSync = 0; + +#define GETEXTENSION(type, ext) \ +do \ +{ \ + ext = (type) eglGetProcAddress(#ext); \ + if (!ext) \ + { \ + fprintf(stderr, "ERROR getting proc addr of " #ext "\n"); \ + } \ +} while (0); + +int USE_OPENGL = 1; +int USE_HWAUDIOOUT = 1; +int USE_AUDIOBUFFERING = 0; +const int PORT_VRENDERER = 6; + +static OMX_VERSIONTYPE vOMX; + +static int _initialized = 0; +static void InitStatic() +{ + if(_initialized) return; + _initialized = 1; + + vOMX.s.nVersionMajor = 1; + vOMX.s.nVersionMinor = 1; + vOMX.s.nRevision = 0; + vOMX.s.nStep = 0; + + GETEXTENSION(PFNEGLCREATEIMAGEKHRPROC, eglCreateImageKHR); + GETEXTENSION(PFNEGLCREATEFENCESYNCKHRPROC, eglCreateFenceSyncKHR); + GETEXTENSION(PFNEGLFENCEKHRPROC, eglFenceKHR); + GETEXTENSION(PFNEGLGETSYNCATTRIBKHRPROC, eglGetSyncAttribKHR); + GETEXTENSION(PFNEGLSIGNALSYNCKHRPROC, eglSignalSyncKHR); + if(NULL==eglFenceKHR||NULL==eglGetSyncAttribKHR||NULL==eglSignalSyncKHR) { + _hasEGLSync = 0; + } else { + _hasEGLSync = 1; + } + _hasEGLSync = 0; // JAU + + OMX_Init(); +} + +static void Invalidate(OMXToolBasicAV_t * pOMXAV) +{ + printf("INVALIDATE\n"); fflush(stdout); + pOMXAV->status=OMXAV_INVALID; +} + +static void GetComponentName(OMX_HANDLETYPE hComponent, KDchar *pName, int nameMaxLen) +{ + OMX_VERSIONTYPE v1, v2; + OMX_UUIDTYPE uuid; + + OMX_GetComponentVersion(hComponent, pName, &v1, &v2, &uuid); +} + +static OMX_ERRORTYPE EventHandler( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, + OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData) +{ + OMXToolBasicAV_t * pOMXAV = (OMXToolBasicAV_t *) pAppData; + KDchar name[128]; + + GetComponentName(hComponent, name, 128); + + switch (eEvent) + { + case OMX_EventCmdComplete: + { + printf("event complete: cmd 0x%X, s:0x%X, component: %p - %s\n", (unsigned)nData1, (unsigned)nData2, hComponent, name); + if (nData1 == OMX_CommandStateSet && pOMXAV->status == OMXAV_INVALID) + { + if (nData2 > OMX_StateLoaded) { + printf("\t state -> StateLoaded\n"); + // Transition the component down to StateLoaded + OMX_SendCommand(hComponent, OMX_CommandStateSet, OMX_StateLoaded, 0); + } + } + else if (nData1 == OMX_CommandFlush && nData2 == OMX_ALL) + { + printf("\t flush\n"); + kdThreadSemPost(pOMXAV->flushSem); + } + break; + } + case OMX_EventBufferFlag: + if (nData2 & OMX_BUFFERFLAG_EOS) + { + printf("event buffer EOS: component: %p - %s\n", hComponent, name); + if (pOMXAV->endComponent == hComponent) + { + printf("\t end component - FIN\n"); + pOMXAV->status = OMXAV_FIN; + } + } + break; + case OMX_EventError: + { + if (nData1 == OMX_ErrorIncorrectStateTransition) + { + printf("event error: 0x%X IncorrectTransition, component: %p - %s\n", (unsigned int) nData1, hComponent, name); + // We are shutting down, just continue with that process + OMX_SendCommand(hComponent, OMX_CommandStateSet, OMX_StateIdle, 0); + } + else if(nData1 == OMX_ErrorSameState) + { + printf("event error: Same State 0x%X, component: %p - %s\n", (unsigned int) nData2, hComponent, name); + } + else + { + printf("event error: 0x%X, component: %p - %s\n", (unsigned int) nData1, hComponent, name); + Invalidate(pOMXAV); + } + } + break; + default: + break; + } + + return OMX_ErrorNone; +} + + +static OMX_ERRORTYPE EmptyBufferDone( + OMX_OUT OMX_HANDLETYPE hComponent, + OMX_OUT OMX_PTR pAppData, + OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer) +{ + return OMX_ErrorNone; +} + +static OMX_ERRORTYPE FillBufferDone( + OMX_OUT OMX_HANDLETYPE hComponent, + OMX_OUT OMX_PTR pAppData, + OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer) +{ + OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *) pAppData; + + if (pBuffer->nFlags & OMX_BUFFERFLAG_EOS) + { + pOMXAV->status = OMXAV_FIN; + } + pOMXAV->available++; + fprintf(stdout, "FillBufferDone avail %d\n", pOMXAV->available); fflush(stdout); + + return OMX_ErrorNone; +} + +#define STATE_SLEEP 10 // ms +#define STATE_TIMEOUT 1000 // ms +#define STATE_TIMEOUT_LOOP (STATE_TIMEOUT/STATE_SLEEP) + +static OMX_ERRORTYPE WaitForState(OMX_HANDLETYPE hComponent, + OMX_STATETYPE eTestState, + OMX_STATETYPE eTestState2, + OMX_STATETYPE *currentState) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_STATETYPE eState; + int loop=STATE_TIMEOUT_LOOP; + + fprintf(stdout, "WaitForState p1 c:%p s1:0x%X s2:0x%X\n", hComponent, eTestState, eTestState2); fflush(stdout); // JAU + eError = OMX_GetState(hComponent, &eState); + fprintf(stdout, "WaitForState p2 s:0x%X e:0x%X\n", eState, eError); fflush(stdout); // JAU + + while (loop>0 && + OMX_ErrorNone == eError && + eState != eTestState && + eState != eTestState2) + { + usleep(STATE_SLEEP*1000); + loop--; + + eError = OMX_GetState(hComponent, &eState); + fprintf(stdout, "WaitForState p3 s:0x%X e:0x%X\n", eState, eError); fflush(stdout); // JAU + } + + if(NULL!=currentState) *currentState=eState; + + return eError; +} + +static KDint SyncOnState(OMX_HANDLETYPE hComponent, OMX_STATETYPE state) +{ + OMX_STATETYPE currentState; + OMX_ERRORTYPE eError = WaitForState(hComponent, state, OMX_StateInvalid, ¤tState); + return ( OMX_ErrorNone != eError ) ? -1 : ( currentState!=state ) ? -2 : 0 ; +} + +static KDint CheckState(OMX_HANDLETYPE hComponent, OMX_STATETYPE state) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_STATETYPE eState; + + eError = OMX_GetState(hComponent, &eState); + + return ( OMX_ErrorNone != eError ) ? -1 : ( eState!=state ) ? -2 : 0 ; +} + +KDint OMXToolBasicAV_IsFileValid(const KDchar * file) +{ + #ifdef _WIN32 + KDchar cvtdPath[_MAX_PATH]; + + if(NULL==file) return -1; + + kdStrcpy_s(cvtdPath, _MAX_PATH, file); + while(kdStrchr(cvtdPath,'/')) + *kdStrchr(cvtdPath,'/')='\\'; + + { + #ifdef UNICODE + wchar_t properfilename[_MAX_PATH]; + mbstowcs( properfilename, cvtdPath, _MAX_PATH ); + #else + char *properfilename = cvtdPath; + #endif + + if (INVALID_FILE_ATTRIBUTES==GetFileAttributes(properfilename)) + { + fprintf(stderr, "!>Input file (%s) does not exist! EXITING.", file); + return -2; + } + } + #else + if(NULL==file) return -1; + #endif + + return 0; +} + +KDint OMXToolBasicAV_CheckState(OMXToolBasicAV_t * pOMXAV, OMX_STATETYPE state) +{ + KDint i, res; + if(NULL==pOMXAV) return -1; + + for(i=0; i<OMXAV_H_NUMBER; i++) { + if(0!=pOMXAV->comp[i]) { + if( 0!=(res=CheckState(pOMXAV->comp[i], state)) ) { + return res-(i*10); + } + } + } + return 0; +} + +KDint OMXToolBasicAV_WaitForState(OMXToolBasicAV_t * pOMXAV, OMX_STATETYPE state) +{ + KDint res, i; + fprintf(stdout, "OMXToolBasicAV_WaitForState %p s:%d\n", pOMXAV, state); fflush(stdout); // JAU + if(NULL==pOMXAV) { + fprintf(stdout, "OMXToolBasicAV_WaitForState p1\n"); fflush(stdout); // JAU + return -1; + } + + for(i=0; i<OMXAV_H_NUMBER; i++) { + if(0!=pOMXAV->comp[i]) { + fprintf(stdout, "OMXToolBasicAV_WaitForState p4 %d c:%p\n", i, pOMXAV->comp[i]); fflush(stdout); // JAU + if( 0!=(res=SyncOnState(pOMXAV->comp[i], state)) ) { + KDchar name[128]; + GetComponentName(pOMXAV->comp[i], name, 128); + fprintf(stdout, "OMXToolBasicAV_WaitForState Failed (Wait) %d c:%p - %s, s:0x%X\n", + i, pOMXAV->comp[i], name, state); + fflush(stdout); // JAU + return res-(i*10); + } + } + } + + return 0; +} + +static OMX_ERRORTYPE RequestState(OMX_HANDLETYPE hComponent, OMX_STATETYPE state, KDboolean wait) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_STATETYPE eState; + eError = OMX_GetState(hComponent, &eState); + fprintf(stdout, "RequestState p2 c:%p, e:0x%X, s:0x%X\n", + hComponent, eError, eState); fflush(stdout); // JAU + // Skip StateSet in case the state is already reached .. + if(OMX_ErrorNone != eError || eState!=state) { + eError = OMX_SendCommand(hComponent, OMX_CommandStateSet, state, 0); + fprintf(stdout, "RequestState p3 c:%p e:0x%X s: 0x%X -> 0x%X\n", + hComponent, eError, eState, state); fflush(stdout); // JAU + if(wait) { + OMX_STATETYPE currentState; + eError = WaitForState(hComponent, state, OMX_StateInvalid, ¤tState); + if ( OMX_ErrorNone==eError && currentState!=state ) eError=OMX_StateInvalid; + } + } + return eError; +} + +KDint OMXToolBasicAV_RequestState(OMXToolBasicAV_t * pOMXAV, OMX_STATETYPE state, KDboolean wait) +{ + KDint i; + fprintf(stdout, "OMXToolBasicAV_RequestState %p s:%d, w:%d\n", pOMXAV, state, wait); fflush(stdout); // JAU + if(NULL==pOMXAV) { + fprintf(stdout, "OMXToolBasicAV_RequestState p1\n"); fflush(stdout); // JAU + return -1; + } + + for(i=0; i<OMXAV_H_NUMBER; i++) { + if(0!=pOMXAV->comp[i]) { + OMXSAFE(RequestState(pOMXAV->comp[i], state, KD_FALSE)); + } + } + + if (wait) + { + return OMXToolBasicAV_WaitForState(pOMXAV, state); + } + + return 0; +} + +static KDint SendCommand(OMXToolBasicAV_t * pOMXAV, OMX_COMMANDTYPE cmd, OMX_U32 nParam1, OMX_PTR pCmdData) +{ + KDint i; + if(NULL==pOMXAV) return -1; + + for(i=0; i<OMXAV_H_NUMBER; i++) { + if(0!=pOMXAV->comp[i]) { + if(OMX_ErrorNone!=OMX_SendCommand(pOMXAV->comp[i], cmd, nParam1, pCmdData)) { + return -1; + } + if(OMX_CommandFlush==cmd) { + kdThreadSemWait(pOMXAV->flushSem); + } + } + } + return 0; +} + +static KDint PlayStop(OMXToolBasicAV_t * pOMXAV); +static int DetachVideoRenderer(OMXToolBasicAV_t * pOMXAV); + +static void DestroyInstanceUnlock(OMXToolBasicAV_t * pOMXAV) +{ + // 0: Stop + // 1: X -> idle + // 2: Disable all ports + // 3: DetachVideoRenderer + // 3: X -> loaded + // 4: Free Handle + // 5: Free mutex/semaphores/struct + int i, res1=0, res2=0; + if(NULL==pOMXAV) return; + + fprintf(stderr, "Destroy p1\n"); fflush(stderr); + PlayStop(pOMXAV); + + fprintf(stderr, "Destroy p2\n"); fflush(stderr); + if(0!=(res1=OMXToolBasicAV_RequestState(pOMXAV, OMX_StateIdle, KD_TRUE))) + { + java_throwNewRuntimeException(NULL, "Destroy - Wait for Idle Failed (%d)", res1); + } + + fprintf(stderr, "Destroy p3\n"); fflush(stderr); + SendCommand(pOMXAV, OMX_CommandPortDisable, OMX_ALL, 0); // Ignore error .. + + fprintf(stderr, "Destroy p3\n"); fflush(stderr); + DetachVideoRenderer(pOMXAV); + + fprintf(stderr, "Destroy p4\n"); fflush(stderr); + if(0!=(res2=OMXToolBasicAV_RequestState(pOMXAV, OMX_StateLoaded, KD_TRUE))) + { + if(!res1) { + java_throwNewRuntimeException(NULL, "Destroy - Wait for Loaded Failed (%d)", res2); + } + } + + fprintf(stderr, "Destroy p5\n"); fflush(stderr); + for(i=0; i<OMXAV_H_NUMBER; i++) { + if(0!=pOMXAV->comp[i]) { + OMX_FreeHandle(pOMXAV->comp[i]); + pOMXAV->comp[i]=0; + } + } + + if(0!=pOMXAV->flushSem) { + fprintf(stderr, "Destroy p6\n"); fflush(stderr); + kdThreadSemFree(pOMXAV->flushSem); + pOMXAV->flushSem=0; + } + if(0!=pOMXAV->mutex) { + fprintf(stderr, "Destroy p7\n"); fflush(stderr); + kdThreadMutexUnlock(pOMXAV->mutex); + fprintf(stderr, "Destroy p8\n"); fflush(stderr); + kdThreadMutexFree(pOMXAV->mutex); + pOMXAV->mutex=0; + } + + fprintf(stderr, "Destroy DONE\n"); fflush(stderr); + + free(pOMXAV); +} + +static OMX_ERRORTYPE AddFile(OMXToolBasicAV_t * pOMXAV, const KDchar* filename) +{ + // FIXME: Non NV case .. + OMX_ERRORTYPE eError; + NVX_PARAM_FILENAME oFilenameParam; + OMX_INDEXTYPE eIndexParamFilename; + + eError = OMX_GetExtensionIndex(pOMXAV->comp[OMXAV_H_READER], NVX_INDEX_PARAM_FILENAME, + &eIndexParamFilename); + if (eError != OMX_ErrorNone) + return eError; + + INIT_PARAM(oFilenameParam); + oFilenameParam.pFilename = (char*) filename; + + eError = OMX_SetParameter(pOMXAV->comp[OMXAV_H_READER], eIndexParamFilename, &oFilenameParam); + if (eError != OMX_ErrorNone) + return eError; + + return OMX_ErrorNone; +} + +static OMX_ERRORTYPE ProbePort(OMXToolBasicAV_t * pOMXAV, int port, KDchar* component) +{ + // FIXME: Non NV case .. + KDchar codec[256]; + OMX_U32 roles = 1; + OMX_ERRORTYPE err = OMX_ErrorNone; + OMX_INDEXTYPE eParam; + NVX_PARAM_STREAMTYPE oStreamType; + OMX_PARAM_PORTDEFINITIONTYPE oPortDef; + + INIT_PARAM(oStreamType); + INIT_PARAM(oPortDef); + OMXSAFEERR(OMX_GetExtensionIndex(pOMXAV->comp[OMXAV_H_READER], NVX_INDEX_PARAM_STREAMTYPE, &eParam)); + + oPortDef.nPortIndex = port; + OMXSAFEERR(OMX_GetParameter(pOMXAV->comp[OMXAV_H_READER], OMX_IndexParamPortDefinition, &oPortDef)); + + oStreamType.nPort = port; + OMXSAFEERR(OMX_GetParameter(pOMXAV->comp[OMXAV_H_READER], eParam, &oStreamType)); + + if (oPortDef.eDomain == OMX_PortDomainVideo) + kdStrcpy_s(codec, 128, "video_decoder."); + else if (oPortDef.eDomain == OMX_PortDomainAudio) + kdStrcpy_s(codec, 128, "audio_decoder."); + else + return OMX_ErrorNotImplemented; + + switch (oStreamType.eStreamType) + { +#define CODEC(a, b) case a: kdStrncat_s(codec, 128, b, kdStrlen(b)); break + CODEC(NvxStreamType_MPEG4, "mpeg4"); + CODEC(NvxStreamType_H264, "avc"); + CODEC(NvxStreamType_H263, "mpeg4"); + CODEC(NvxStreamType_WMV, "vc1"); + CODEC(NvxStreamType_MP3, "mp3"); + CODEC(NvxStreamType_AAC, "aac"); + CODEC(NvxStreamType_AACSBR, "eaacplus"); + CODEC(NvxStreamType_BSAC, "bsac"); + CODEC(NvxStreamType_WMA, "wma"); + CODEC(NvxStreamType_WMAPro, "wmapro"); + CODEC(NvxStreamType_WMALossless, "wmalossless"); + CODEC(NvxStreamType_AMRWB, "amrwb"); + CODEC(NvxStreamType_AMRNB, "amrnb"); + CODEC(NvxStreamType_VORBIS, "vorbis"); +#undef CODEC + default: + return OMX_ErrorNotImplemented; + } + + { + OMX_U8 *tmp = (OMX_U8*) kdMalloc(OMX_MAX_STRINGNAME_SIZE + 1); + kdMemset(tmp, 0, sizeof(OMX_U8) * (OMX_MAX_STRINGNAME_SIZE + 1)); + + err = OMX_GetComponentsOfRole(codec, &roles, &tmp); + kdStrcpy_s(component, 256, (KDchar*) tmp); + kdFree(tmp); + } + + printf("%s -> %s\n", codec, component); + return err != OMX_ErrorNone ? err : roles ? OMX_ErrorNone : OMX_ErrorComponentNotFound; +} + +static OMX_ERRORTYPE UpdateStreamInfo(OMXToolBasicAV_t * pOMXAV) +{ + OMX_PARAM_PORTDEFINITIONTYPE oPortDef; + kdMemset(&oPortDef, 0, sizeof(oPortDef)); + oPortDef.nSize = sizeof(oPortDef); + oPortDef.nVersion.s.nVersionMajor = 1; + oPortDef.nVersion.s.nVersionMinor = 1; + oPortDef.nPortIndex = 0; + OMXSAFEERR(OMX_GetParameter(pOMXAV->comp[OMXAV_H_READER], OMX_IndexParamPortDefinition, &oPortDef)); + + if (oPortDef.eDomain != OMX_PortDomainVideo) + { + kdMemset(&oPortDef, 0, sizeof(oPortDef)); + oPortDef.nSize = sizeof(oPortDef); + oPortDef.nVersion.s.nVersionMajor = 1; + oPortDef.nVersion.s.nVersionMinor = 1; + + oPortDef.nPortIndex = 1; + OMXSAFEERR(OMX_GetParameter(pOMXAV->comp[OMXAV_H_READER], OMX_IndexParamPortDefinition, &oPortDef)); + } + pOMXAV->width = oPortDef.format.video.nFrameWidth; + pOMXAV->height = oPortDef.format.video.nFrameHeight; + + return OMX_ErrorNone; +} + +static int StartClock(OMXToolBasicAV_t * pOMXAV, KDboolean start, KDfloat32 time) { + OMX_TIME_CONFIG_CLOCKSTATETYPE oClockState; + OMX_ERRORTYPE eError = OMX_ErrorNone; + int loop=STATE_TIMEOUT_LOOP; + INIT_PARAM(oClockState); + oClockState.nOffset = 0; + oClockState.nStartTime = (KD_TRUE==start)? (OMX_TICKS) (time * 1000.0 * 1000.0) : 0; + oClockState.nWaitMask = 0; + oClockState.eState = (KD_TRUE==start)?OMX_TIME_ClockStateRunning:OMX_TIME_ClockStateStopped; + + eError = OMX_SetConfig(pOMXAV->comp[OMXAV_H_CLOCK], OMX_IndexConfigTimeClockState, &oClockState); + while (loop>0 && OMX_ErrorNotReady == eError) + { + fprintf(stdout, "Play 3.2\n"); fflush(stdout); // JAU + usleep(STATE_SLEEP*1000); + loop--; + eError = OMX_SetConfig(pOMXAV->comp[OMXAV_H_CLOCK], OMX_IndexConfigTimeClockState, + &oClockState); + } + return (OMX_ErrorNotReady == eError)?-1:0; +} + +static KDint SetClockScale(OMXToolBasicAV_t * pOMXAV, KDfloat32 scale) +{ + OMX_TIME_CONFIG_SCALETYPE pScale; + INIT_PARAM(pScale); + pScale.xScale = (int) (scale * (1<<16)); + + OMX_SetConfig(pOMXAV->comp[OMXAV_H_CLOCK], OMX_IndexConfigTimeScale, &pScale); + return 0; +} + +static int AttachAudioRenderer(OMXToolBasicAV_t * pOMXAV) +{ + int res=0; + // Configure audio port + + if (USE_AUDIOBUFFERING) + { + // FIXME: proper audio buffering .. + OMXSAFE(OMX_GetHandle(&pOMXAV->comp[OMXAV_H_ABUFFERING], "OMX.Nvidia.audio.visualization", pOMXAV, &pOMXAV->callbacks)); + if(0!=(res=SyncOnState(pOMXAV->comp[OMXAV_H_ABUFFERING], OMX_StateLoaded))) { + java_throwNewRuntimeException(NULL, "Loading AudioBuffering Failed (%d)", res); + return res; + } + /** + if (m_settings.m_avsync) + { + // Tweak the avsync parameter + NVX_CONFIG_VISU conf; + INIT_PARAM(conf); + conf.nAVSyncOffset = m_settings.m_avsync; + + OMX_INDEXTYPE idx; + OMX_GetExtensionIndex(pOMXAV->comp[OMXAV_H_ABUFFERING], NVX_INDEX_PARAM_VISUDATA, &idx); + OMX_SetConfig(pOMXAV->comp[OMXAV_H_ABUFFERING], idx, &conf); + }*/ + } + + OMXSAFE(OMX_GetHandle(&pOMXAV->comp[OMXAV_H_ARENDERER], "OMX.Nvidia.audio.render",pOMXAV, &pOMXAV->callbacks)); + pOMXAV->endComponent = pOMXAV->comp[OMXAV_H_ARENDERER]; + + // mandatory before SetupTunnel + if(0!=(res=SyncOnState(pOMXAV->comp[OMXAV_H_ARENDERER], OMX_StateLoaded))) { + java_throwNewRuntimeException(NULL, "Loading AudioRenderer Failed (%d)", res); + return res; + } + + { + OMX_INDEXTYPE eIndexConfigOutputType; + NVX_CONFIG_AUDIOOUTPUT ao; + OMX_ERRORTYPE eError; + + INIT_PARAM(ao); + + eError = OMX_GetExtensionIndex(pOMXAV->comp[OMXAV_H_ARENDERER], NVX_INDEX_CONFIG_AUDIO_OUTPUT, + &eIndexConfigOutputType); + if (eError != OMX_ErrorNoMore) + { + /** FIXME: HDMI configuration .. + // for now, only put audio out hdmi if the settings say to, regardless of the hdmi-video flag. + // if (// m_settings.m_hdmiVideo || // m_settings.m_hdmiAudio) + // ao.eOutputType = NVX_AUDIO_OutputHdmi; + else */ + ao.eOutputType = NVX_AUDIO_OutputI2S; + + OMX_SetConfig(pOMXAV->comp[OMXAV_H_ARENDERER], eIndexConfigOutputType, &ao); + } + } + + OMXSAFE(OMX_SendCommand(pOMXAV->comp[OMXAV_H_CLOCK], OMX_CommandPortEnable, pOMXAV->audioPort, 0)); + OMXSAFE(OMX_SendCommand(pOMXAV->comp[OMXAV_H_ARENDERER], OMX_CommandPortEnable, 1, 0)); + + if (USE_AUDIOBUFFERING) + { + OMXSAFE(OMX_SetupTunnel(pOMXAV->comp[OMXAV_H_ADECODER], 1, pOMXAV->comp[OMXAV_H_ABUFFERING], 0)); + OMXSAFE(OMX_SetupTunnel(pOMXAV->comp[OMXAV_H_ABUFFERING], 1, pOMXAV->comp[OMXAV_H_ARENDERER], 0)); + } + else + { + OMXSAFE(OMX_SetupTunnel(pOMXAV->comp[OMXAV_H_ADECODER], 1, pOMXAV->comp[OMXAV_H_ARENDERER], 0)); + } + + OMXSAFE(OMX_SetupTunnel(pOMXAV->comp[OMXAV_H_CLOCK], pOMXAV->audioPort, pOMXAV->comp[OMXAV_H_ARENDERER], 1)); + + return OMX_ErrorNone; +} + +static int AttachVideoRenderer(OMXToolBasicAV_t * pOMXAV) +{ + int i, res=0; + if(KD_NULL!=pOMXAV->comp[OMXAV_H_VSCHEDULER]) { + java_throwNewRuntimeException(NULL, "Detach Video first"); + return -1; + } + OMXSAFE(OMX_GetHandle(&pOMXAV->comp[OMXAV_H_VSCHEDULER], "OMX.Nvidia.video.scheduler", pOMXAV, &pOMXAV->callbacks)); + pOMXAV->endComponent = pOMXAV->comp[OMXAV_H_VSCHEDULER]; + + // mandatory before SetupTunnel + if(0!=(res=SyncOnState(pOMXAV->comp[OMXAV_H_VSCHEDULER], OMX_StateLoaded))) { + java_throwNewRuntimeException(NULL, "Loading VideoScheduler Failed (%d)", res); + return res; + } + // mandatory before EGLUseImage + OMXSAFE(RequestState(pOMXAV->comp[OMXAV_H_VSCHEDULER], OMX_StateIdle, KD_FALSE)); + + fprintf(stdout, "Attach VR %p c:%p\n", pOMXAV, pOMXAV->comp[OMXAV_H_VSCHEDULER]); fflush(stdout); // JAU + OMXSAFE(UpdateStreamInfo(pOMXAV)); + + fprintf(stdout, "UseEGLImg port enable/tunneling %p\n", pOMXAV); + OMXSAFE(OMX_SendCommand(pOMXAV->comp[OMXAV_H_CLOCK], OMX_CommandPortEnable, PORT_VRENDERER, 0)); + OMXSAFE(OMX_SendCommand(pOMXAV->comp[OMXAV_H_VDECODER], OMX_CommandPortEnable, 1, 0)); + OMXSAFE(OMX_SendCommand(pOMXAV->comp[OMXAV_H_VSCHEDULER], OMX_CommandPortEnable, 0, 0)); + OMXSAFE(OMX_SendCommand(pOMXAV->comp[OMXAV_H_VSCHEDULER], OMX_CommandPortEnable, 2, 0)); + OMXSAFE(OMX_SetupTunnel(pOMXAV->comp[OMXAV_H_VDECODER], 1, pOMXAV->comp[OMXAV_H_VSCHEDULER], 0)); + OMXSAFE(OMX_SetupTunnel(pOMXAV->comp[OMXAV_H_CLOCK], PORT_VRENDERER, pOMXAV->comp[OMXAV_H_VSCHEDULER], 2)); + + for (i = 0; i < pOMXAV->vBufferNum; i++) { + OMXToolImageBuffer_t *pBuf = &pOMXAV->buffers[i]; + // The Texture, EGLImage and EGLSync was created by the Java client, + // and registered using the OMXToolBasicAV_SetEGLImageTexture2D command. + + fprintf(stdout, "UseEGLImg %p #%d t:%d i:%p s:%p p1\n", pOMXAV, i, pBuf->tex, pBuf->image, pBuf->sync); fflush(stdout); // JAU + + if(NULL==pBuf->image) { + java_throwNewRuntimeException(NULL, "AttachVideoRenderer: User didn't set buffer %d/%d\n", i, pOMXAV->vBufferNum); + return -1; + } else { + // tell decoder output port that it will be using EGLImage + OMXSAFE(OMX_UseEGLImage( + pOMXAV->comp[OMXAV_H_VSCHEDULER], + &pBuf->omxBufferHeader, + 1, // The port to use the EGLImage for + pOMXAV, // app private data + pBuf->image)); + } + fprintf(stdout, "UseEGLImg %p #%d t:%d i:%p s:%p b:%p - p2\n", + pOMXAV, i, pBuf->tex, pBuf->image, pBuf->sync, pBuf->omxBufferHeader); fflush(stdout); // JAU + } + + fprintf(stdout, "UseEGLImg %p #%d DONE\n", pOMXAV, i); fflush(stdout); // JAU + return 0; +} + +static int DetachVideoRenderer(OMXToolBasicAV_t * pOMXAV) +{ + int i; + if(NULL==pOMXAV) return -1; + + if(KD_NULL==pOMXAV->comp[OMXAV_H_VSCHEDULER]) { + java_throwNewRuntimeException(NULL, "Attach Video first"); + return -1; + } + fprintf(stderr, "DetachVideoRenderer p0\n"); fflush(stderr); + if(0==CheckState(pOMXAV->comp[OMXAV_H_VSCHEDULER], OMX_StateLoaded)) { + fprintf(stderr, "DetachVideoRenderer DONE (already state loaded)\n"); fflush(stderr); + return 0; + } + OMXSAFE(RequestState(pOMXAV->comp[OMXAV_H_VSCHEDULER], OMX_StateIdle, KD_TRUE)); + + fprintf(stderr, "DetachVideoRenderer p1\n"); fflush(stderr); + OMXSAFE(OMX_SendCommand(pOMXAV->comp[OMXAV_H_CLOCK], OMX_CommandPortDisable, PORT_VRENDERER, 0)); + OMXSAFE(OMX_SendCommand(pOMXAV->comp[OMXAV_H_VDECODER], OMX_CommandPortDisable, 1, 0)); + OMXSAFE(OMX_SendCommand(pOMXAV->comp[OMXAV_H_VSCHEDULER], OMX_CommandPortDisable, 0, 0)); + OMXSAFE(OMX_SendCommand(pOMXAV->comp[OMXAV_H_VSCHEDULER], OMX_CommandPortDisable, 2, 0)); + fprintf(stderr, "DetachVideoRenderer p2\n"); fflush(stderr); + + for (i = 0; i < pOMXAV->vBufferNum; i++) { + OMXToolImageBuffer_t *pBuf = &pOMXAV->buffers[i]; + + // tell decoder output port to stop using EGLImage + if (NULL!=pBuf->omxBufferHeader) { + OMX_FreeBuffer( + pOMXAV->comp[OMXAV_H_VSCHEDULER], + 1, + pBuf->omxBufferHeader); + pBuf->omxBufferHeader=NULL; + } + } + + OMXSAFE(RequestState(pOMXAV->comp[OMXAV_H_VSCHEDULER], OMX_StateLoaded, KD_TRUE)); + fprintf(stderr, "DetachVideoRenderer p3\n"); fflush(stderr); + + OMX_FreeHandle(pOMXAV->comp[OMXAV_H_VSCHEDULER]); + pOMXAV->comp[OMXAV_H_VSCHEDULER]=NULL; + fprintf(stderr, "DetachVideoRenderer DONE\n"); fflush(stderr); + return 0; +} + +OMXToolBasicAV_t * OMXToolBasicAV_CreateInstance(int vBufferNum) +{ + int i; + OMXToolBasicAV_t * pOMXAV = NULL; + InitStatic(); + + if(vBufferNum>EGLIMAGE_MAX_BUFFERS) { + fprintf(stderr, "buffer number %d > MAX(%d)\n", vBufferNum, EGLIMAGE_MAX_BUFFERS); + return NULL; + } + pOMXAV = malloc(sizeof(OMXToolBasicAV_t)); + if(NULL==pOMXAV) { + fprintf(stderr, "Init struct failed!\n"); + return NULL; + } + memset(pOMXAV, 0, sizeof(OMXToolBasicAV_t)); + + pOMXAV->audioPort=-1; + pOMXAV->videoPort=-1; + + for(i=0; i<OMXAV_H_NUMBER; i++) { + pOMXAV->comp[i] = KD_NULL; + } + + pOMXAV->callbacks.EventHandler = EventHandler; + pOMXAV->callbacks.EmptyBufferDone = EmptyBufferDone; + pOMXAV->callbacks.FillBufferDone = FillBufferDone; + + pOMXAV->mutex = kdThreadMutexCreate(KD_NULL); + pOMXAV->flushSem = kdThreadSemCreate(0); + + pOMXAV->vBufferNum = vBufferNum; + + pOMXAV->status=OMXAV_INIT; + + return pOMXAV; +} + +int OMXToolBasicAV_SetStream(OMXToolBasicAV_t * pOMXAV, const KDchar * stream) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + + fprintf(stdout, "SetStream 1 %s ..\n", stream); fflush(stdout); // JAU + + // FIXME: verify player state .. ie stop ! + if(pOMXAV->status!=OMXAV_INIT) { + java_throwNewRuntimeException(NULL, "Player instance in use\n"); + return -1; + } + + kdThreadMutexLock(pOMXAV->mutex); + + fprintf(stdout, "SetStream 3\n"); fflush(stdout); // JAU + + // Use the "super parser" :) FIXME: Non NV case .. + eError = OMX_GetHandle(&pOMXAV->comp[OMXAV_H_READER], "OMX.Nvidia.reader", pOMXAV, &pOMXAV->callbacks); + + eError = AddFile(pOMXAV, stream); + if(eError!=OMX_ErrorNone) { + java_throwNewRuntimeException(NULL, "Couldn't open or handle stream: %s\n", stream); + kdThreadMutexUnlock(pOMXAV->mutex); + return -1; + } + + fprintf(stdout, "SetStream 4\n"); fflush(stdout); // JAU + + // Auto detect codecs + { + OMX_PARAM_PORTDEFINITIONTYPE oPortDef; + INIT_PARAM(oPortDef); + oPortDef.nPortIndex = 0; + pOMXAV->videoPort = -1; + pOMXAV->audioPort = -1; + OMXSAFE(OMX_GetParameter(pOMXAV->comp[OMXAV_H_READER], OMX_IndexParamPortDefinition, &oPortDef)); + + if (oPortDef.eDomain == OMX_PortDomainAudio) + pOMXAV->audioPort = oPortDef.nPortIndex; + else if (oPortDef.eDomain == OMX_PortDomainVideo) + pOMXAV->videoPort = oPortDef.nPortIndex; + else + OMXSAFE(OMX_ErrorNotImplemented); + + INIT_PARAM(oPortDef); + oPortDef.nPortIndex = 1; + if (OMX_GetParameter(pOMXAV->comp[OMXAV_H_READER], OMX_IndexParamPortDefinition, &oPortDef) == OMX_ErrorNone) + { + if (oPortDef.eDomain == OMX_PortDomainAudio) + pOMXAV->audioPort = oPortDef.nPortIndex; + else if (oPortDef.eDomain == OMX_PortDomainVideo) + pOMXAV->videoPort = oPortDef.nPortIndex; + else + OMXSAFE(OMX_ErrorNotImplemented); + } + if (pOMXAV->audioPort != -1) + { + if (ProbePort(pOMXAV, pOMXAV->audioPort, pOMXAV->audioCodec) != OMX_ErrorNone) + { + printf("disabling audio port\n"); + OMXSAFE(OMX_SendCommand(pOMXAV->comp[OMXAV_H_READER], OMX_CommandPortDisable, pOMXAV->audioPort, 0)); + pOMXAV->audioPort = -1; + } + } + if (pOMXAV->videoPort != -1) + if (ProbePort(pOMXAV, pOMXAV->videoPort, pOMXAV->videoCodec) != OMX_ErrorNone) + { + printf("disabling video port\n"); + OMXSAFE(OMX_SendCommand(pOMXAV->comp[OMXAV_H_READER], OMX_CommandPortDisable, pOMXAV->videoPort, 0)); + pOMXAV->videoPort = -1; + } + + if (pOMXAV->audioPort == -1 && pOMXAV->videoPort == -1) + { + java_throwNewRuntimeException(NULL, "Neither audioport or videoport could be played back!\n"); + kdThreadMutexUnlock(pOMXAV->mutex); + return -1; + } + } + fprintf(stdout, "SetStream 5 ; audioPort %d, videoPort %d\n", pOMXAV->audioPort, pOMXAV->videoPort); fflush(stdout); // JAU + + OMXSAFE(OMX_GetHandle(&pOMXAV->comp[OMXAV_H_CLOCK], "OMX.Nvidia.clock.component", pOMXAV, &pOMXAV->callbacks)); + + fprintf(stdout, "Configuring comp[OMXAV_H_CLOCK]\n"); + { + + OMX_TIME_CONFIG_ACTIVEREFCLOCKTYPE oActiveClockType; + INIT_PARAM(oActiveClockType); + oActiveClockType.eClock = (pOMXAV->audioPort != -1) ? + OMX_TIME_RefClockAudio : OMX_TIME_RefClockVideo; + OMXSAFE(OMX_SetConfig(pOMXAV->comp[OMXAV_H_CLOCK], OMX_IndexConfigTimeActiveRefClock, + &oActiveClockType)); + } + OMXSAFE(OMX_SendCommand(pOMXAV->comp[OMXAV_H_CLOCK], OMX_CommandPortDisable, (OMX_U32) -1, 0)); + + OMXSAFE(UpdateStreamInfo(pOMXAV)); + + kdThreadMutexUnlock(pOMXAV->mutex); + + fprintf(stdout, "SetStream X\n"); fflush(stdout); // JAU + + return 0; +} + +int OMXToolBasicAV_UpdateStreamInfo(OMXToolBasicAV_t * pOMXAV) { + if(NULL==pOMXAV) return -1; + kdThreadMutexLock(pOMXAV->mutex); + OMXSAFE(UpdateStreamInfo(pOMXAV)); + kdThreadMutexUnlock(pOMXAV->mutex); + return 0; +} + +int OMXToolBasicAV_SetEGLImageTexture2D(OMXToolBasicAV_t * pOMXAV, KDint i, GLuint tex, EGLImageKHR image, EGLSyncKHR sync) +{ + if(NULL==pOMXAV) return -1; + fprintf(stdout, "SetEGLImg %p #%d/%d t:%d i:%p s:%p..\n", pOMXAV, i, pOMXAV->vBufferNum, tex, image, sync); fflush(stdout); // JAU + if(i<0||i>=pOMXAV->vBufferNum) return -1; + + + kdThreadMutexLock(pOMXAV->mutex); + { + OMXToolImageBuffer_t *pBuf = &pOMXAV->buffers[i]; + pBuf->tex=tex; + pBuf->image=image; + pBuf->sync=sync; + + } + kdThreadMutexUnlock(pOMXAV->mutex); + + return 0; +} + +int OMXToolBasicAV_ActivateInstance(OMXToolBasicAV_t * pOMXAV) { + int res; + if(NULL==pOMXAV) return -1; + fprintf(stdout, "ActivateInstance 1\n"); fflush(stdout); // JAU + + kdThreadMutexLock(pOMXAV->mutex); + + if (pOMXAV->audioPort != -1) + { + OMXSAFE(OMX_GetHandle(&pOMXAV->comp[OMXAV_H_ADECODER], pOMXAV->audioCodec, pOMXAV, &pOMXAV->callbacks)); + } + + if (pOMXAV->videoPort != -1) + { + OMXSAFE(OMX_GetHandle(&pOMXAV->comp[OMXAV_H_VDECODER], pOMXAV->videoCodec, pOMXAV, &pOMXAV->callbacks)); + } + + // + // mandatory: before SetupTunnel (->Activate), wait until all devices are ready .. + // arender/vrender must wait as well .. + if(0!=(res=OMXToolBasicAV_WaitForState(pOMXAV, OMX_StateLoaded))) { + java_throwNewRuntimeException(NULL, "Loaded Failed (%d)", res); + kdThreadMutexUnlock(pOMXAV->mutex); + return res; + } + + if (pOMXAV->audioPort != -1) + { + if(0!=(res=AttachAudioRenderer(pOMXAV))) { + kdThreadMutexUnlock(pOMXAV->mutex); + return res; + } + } + + if (pOMXAV->videoPort != -1) + { + if(0!=(res=AttachVideoRenderer(pOMXAV))) { + kdThreadMutexUnlock(pOMXAV->mutex); + return res; + } + } + + fprintf(stdout, "Setup tunneling\n"); fflush(stdout); // JAU + { + // do tunneling + if (pOMXAV->audioPort != -1) + { + fprintf(stdout, "Setup tunneling audio\n"); fflush(stdout); // JAU + OMXSAFE(OMX_SetupTunnel(pOMXAV->comp[OMXAV_H_READER], pOMXAV->audioPort, pOMXAV->comp[OMXAV_H_ADECODER], 0)); + // The rest of the audio port is configured in AttachAudioRenderer + } + + if (pOMXAV->videoPort != -1) + { + fprintf(stdout, "Setup tunneling video\n"); fflush(stdout); // JAU + OMXSAFE(OMX_SetupTunnel(pOMXAV->comp[OMXAV_H_READER], pOMXAV->videoPort, pOMXAV->comp[OMXAV_H_VDECODER], 0)); + // The rest of the video port is configured in AttachVideoRenderer + } + } + fprintf(stdout, "ActivateInstance .. %p\n", pOMXAV); fflush(stdout); + + // + // mandatory: wait until all devices are idle + // failure means not all necessary ports/buffer are set. + // + if(0!=(res=OMXToolBasicAV_RequestState(pOMXAV, OMX_StateIdle, KD_TRUE))) + { + java_throwNewRuntimeException(NULL, "Wait for Idle Failed (%d)", res); + kdThreadMutexUnlock(pOMXAV->mutex); + return res; + } + pOMXAV->status=OMXAV_STOPPED; + kdThreadMutexUnlock(pOMXAV->mutex); + fprintf(stdout, "ActivateInstance done %p\n", pOMXAV); fflush(stdout); + return 0; +} + +int OMXToolBasicAV_DetachVideoRenderer(OMXToolBasicAV_t * pOMXAV) { + int res; + if(NULL==pOMXAV) return -1; + if(pOMXAV->status<=OMXAV_INIT) { + fprintf(stderr, "Err: DetachVideoRenderer invalid"); + return -1; + } + + kdThreadMutexLock(pOMXAV->mutex); + + res = DetachVideoRenderer(pOMXAV); + + kdThreadMutexUnlock(pOMXAV->mutex); + return res; +} + +int OMXToolBasicAV_AttachVideoRenderer(OMXToolBasicAV_t * pOMXAV) { + int res; + if(NULL==pOMXAV) return -1; + if(pOMXAV->status<=OMXAV_INIT) { + fprintf(stderr, "Err: AttachVideoRenderer invalid"); + return -1; + } + + kdThreadMutexLock(pOMXAV->mutex); + + res = AttachVideoRenderer(pOMXAV); + + kdThreadMutexUnlock(pOMXAV->mutex); + return res; +} + +int OMXToolBasicAV_SetClockScale(OMXToolBasicAV_t * pOMXAV, KDfloat32 scale) +{ + int res; + if(NULL==pOMXAV) return -1; + if(pOMXAV->status<=OMXAV_INIT) { + fprintf(stderr, "Err: SetClockScale invalid"); + return -1; + } + + kdThreadMutexLock(pOMXAV->mutex); + + res = SetClockScale(pOMXAV, scale); + + kdThreadMutexUnlock(pOMXAV->mutex); + return res; +} + + +int OMXToolBasicAV_PlayStart(OMXToolBasicAV_t * pOMXAV) +{ + int res; + if(NULL==pOMXAV) return -1; + if(pOMXAV->status<=OMXAV_INIT) { + fprintf(stderr, "Err: Play invalid"); fflush(stderr); + return -1; + } + if(pOMXAV->status==OMXAV_PLAYING) { + return 0; + } + + fprintf(stdout, "Play 1\n"); fflush(stdout); // JAU + kdThreadMutexLock(pOMXAV->mutex); + fprintf(stdout, "Play 2\n"); fflush(stdout); // JAU + + if(OMXToolBasicAV_CheckState(pOMXAV, OMX_StateIdle)) { + if(0!=(res=OMXToolBasicAV_RequestState(pOMXAV, OMX_StateIdle, KD_TRUE))) { + java_throwNewRuntimeException(NULL, "Idle Failed (%d)", res); + kdThreadMutexUnlock(pOMXAV->mutex); + return res; + } + } + if(pOMXAV->status==OMXAV_PAUSED) { + fprintf(stdout, "Play 3.0\n"); fflush(stdout); // JAU + SetClockScale(pOMXAV, 1); + } + fprintf(stdout, "Play 3.1\n"); fflush(stdout); // JAU + if(0!=(res=OMXToolBasicAV_RequestState(pOMXAV, OMX_StateExecuting, KD_TRUE))) { + java_throwNewRuntimeException(NULL, "Play Execute Failed (%d)", res); + kdThreadMutexUnlock(pOMXAV->mutex); + return res; + } + if(pOMXAV->status==OMXAV_STOPPED || pOMXAV->status==OMXAV_FIN) { + fprintf(stdout, "Play 3.2\n"); fflush(stdout); // JAU + if(StartClock(pOMXAV, KD_TRUE, 0.0)) { + java_throwNewRuntimeException(NULL, "Play StartClock Failed"); + kdThreadMutexUnlock(pOMXAV->mutex); + return -1; + } + fprintf(stdout, "Play 3.3\n"); fflush(stdout); // JAU + } + fprintf(stdout, "Play 4.0\n"); fflush(stdout); // JAU + + kdThreadMutexUnlock(pOMXAV->mutex); + pOMXAV->status=OMXAV_PLAYING; + fprintf(stdout, "Play DONE\n"); fflush(stdout); // JAU + return 0; +} + +static int PlayStop(OMXToolBasicAV_t * pOMXAV) +{ + int res; + if(NULL==pOMXAV) return -1; + + if(pOMXAV->status<=OMXAV_INIT) { + fprintf(stderr, "Err: Stop invalid"); + return -1; + } + if( pOMXAV->status!=OMXAV_PLAYING && pOMXAV->status!=OMXAV_PAUSED ) { + fprintf(stderr, "Err: Stop not playing nor paused"); + return -1; + } + + if(OMXToolBasicAV_CheckState(pOMXAV, OMX_StateLoaded)) { + if(StartClock(pOMXAV, KD_FALSE, 0.0)) { + java_throwNewRuntimeException(NULL, "Stop StopClock Failed"); + kdThreadMutexUnlock(pOMXAV->mutex); + return -1; + } + if(OMXToolBasicAV_CheckState(pOMXAV, OMX_StateIdle)) { + if(0!=(res=OMXToolBasicAV_RequestState(pOMXAV, OMX_StateIdle, KD_TRUE))) { + java_throwNewRuntimeException(NULL, "Stop Idle Failed (%d)", res); + kdThreadMutexUnlock(pOMXAV->mutex); + return res; + } + } + } + pOMXAV->status=OMXAV_STOPPED; + return 0; +} + +int OMXToolBasicAV_PlayStop(OMXToolBasicAV_t * pOMXAV) +{ + int res; + if(NULL==pOMXAV) return -1; + + kdThreadMutexLock(pOMXAV->mutex); + res=PlayStop(pOMXAV); + kdThreadMutexUnlock(pOMXAV->mutex); + return res; +} + +int OMXToolBasicAV_PlayPause(OMXToolBasicAV_t * pOMXAV) +{ + int res; + if(NULL==pOMXAV) return -1; + if(pOMXAV->status<=OMXAV_INIT) { + fprintf(stderr, "Err: Pause invalid"); + return -1; + } + if(pOMXAV->status==OMXAV_PAUSED) { + return 0; + } + if(pOMXAV->status!=OMXAV_PLAYING) { + fprintf(stderr, "Err: Pause not playing"); + return -1; + } + + kdThreadMutexLock(pOMXAV->mutex); + SetClockScale(pOMXAV, 0); + if(0!=(res=OMXToolBasicAV_RequestState(pOMXAV, OMX_StatePause, KD_TRUE))) { + fprintf(stderr, "Err: Pause Pause Failed (%d)", res); + kdThreadMutexUnlock(pOMXAV->mutex); + return res; + } + pOMXAV->status=OMXAV_PAUSED; + kdThreadMutexUnlock(pOMXAV->mutex); + return 0; +} + +int OMXToolBasicAV_PlaySeek(OMXToolBasicAV_t * pOMXAV, KDfloat32 time) +{ + int res; + OMX_ERRORTYPE eError = OMX_ErrorNotReady; + + if(NULL==pOMXAV) return -1; + if(pOMXAV->status<=OMXAV_INIT) { + fprintf(stderr, "Err: Seek invalid"); + return -1; + } + + kdThreadMutexLock(pOMXAV->mutex); + + // 1. Pause the component through the use of OMX_SendCommand requesting a + // state transition to OMX_StatePause. + if(pOMXAV->status!=OMXAV_PAUSED) { + if(0!=(res=OMXToolBasicAV_RequestState(pOMXAV, OMX_StatePause, KD_TRUE))) { + fprintf(stderr, "Err: Seek Pause Failed (%d)", res); + kdThreadMutexUnlock(pOMXAV->mutex); + return res; + } + } + + // 2. Stop the comp[OMXAV_H_CLOCK] components media comp[OMXAV_H_CLOCK] through the use of OMX_SetConfig + // on OMX_TIME_CONFIG_CLOCKSTATETYPE requesting a transition to + // OMX_TIME_ClockStateStopped. + if(StartClock(pOMXAV, KD_FALSE, 0.0)) { + java_throwNewRuntimeException(NULL, "Seek StopClock Failed"); + kdThreadMutexUnlock(pOMXAV->mutex); + return -1; + } + + // 3. Seek to the desired location through the use of OMX_SetConfig on + // OMX_IndexConfigTimePosition requesting the desired timestamp. + { + OMX_TIME_CONFIG_TIMESTAMPTYPE timestamp; + int loop=STATE_TIMEOUT_LOOP; + INIT_PARAM(timestamp); + timestamp.nPortIndex = 0; + timestamp.nTimestamp = (OMX_TICKS) (time * 1000.0 * 1000.0); + + eError = OMX_SetConfig(pOMXAV->comp[OMXAV_H_READER], OMX_IndexConfigTimePosition, ×tamp); + while (loop>0 && OMX_ErrorNotReady == eError) + { + usleep(STATE_SLEEP*1000); + loop--; + eError = OMX_SetConfig(pOMXAV->comp[OMXAV_H_READER], OMX_IndexConfigTimePosition, ×tamp); + } + if (OMX_ErrorNotReady == eError) { + java_throwNewRuntimeException(NULL, "Seek position Failed"); + kdThreadMutexUnlock(pOMXAV->mutex); + return -1; + } + } + + // 4. Flush all components. + if(SendCommand(pOMXAV, OMX_CommandFlush, OMX_ALL, 0)) { + fprintf(stderr, "Err: Seek Flush Failed"); + kdThreadMutexUnlock(pOMXAV->mutex); + return -1; + } + + // 5. Start the comp[OMXAV_H_CLOCK] components media comp[OMXAV_H_CLOCK] through the use of OMX_SetConfig + // on OMX_TIME_CONFIG_CLOCKSTATETYPE requesting a transition to either + // OMX_TIME_ClockStateRunning or + // OMX_TIME_ClockStateWaitingForStartTime. + if(StartClock(pOMXAV, KD_TRUE, time)) { + java_throwNewRuntimeException(NULL, "Seek StartClock Failed"); + kdThreadMutexUnlock(pOMXAV->mutex); + return -1; + } + + // 6. Un-pause the component through the use of OMX_SendCommand requesting a + // state transition to OMX_StateExecuting. + if(pOMXAV->status!=OMXAV_PLAYING) { + if(0!=(res=OMXToolBasicAV_RequestState(pOMXAV, OMX_StateExecuting, KD_TRUE))) { + fprintf(stderr, "Err: Seek Execute Failed (%d)", res); + kdThreadMutexUnlock(pOMXAV->mutex); + return res; + } + } + kdThreadMutexUnlock(pOMXAV->mutex); + return 0; +} + +GLuint OMXToolBasicAV_GetTexture(OMXToolBasicAV_t * pOMXAV) { + GLuint texID = 0; + int ret = pOMXAV->glPos; + kdThreadMutexLock(pOMXAV->mutex); + + if(pOMXAV->status==OMXAV_PLAYING) { + int next = (pOMXAV->omxPos + 1) % pOMXAV->vBufferNum; + + // fprintf(stdout, "GetTexture A avail %d, filled %d, pos o:%d g:%d\n", + // pOMXAV->available, pOMXAV->filled, pOMXAV->omxPos, pOMXAV->glPos); fflush(stdout); + + while (pOMXAV->filled < pOMXAV->vBufferNum) + { + int attr; + if ( !_hasEGLSync || ( + eglGetSyncAttribKHR(pOMXAV->buffers[pOMXAV->omxPos].sync, EGL_SYNC_STATUS_KHR, &attr) && + attr == EGL_SIGNALED_KHR ) + ) + { + // fprintf(stdout, "GetTexture p2.1 attr 0x%X\n", attr); fflush(stdout); + // OpenGL has finished rendering with this texture, so we are free + // to make OpenMAX IL fill it with new data. + OMX_FillThisBuffer(pOMXAV->comp[OMXAV_H_VSCHEDULER], pOMXAV->buffers[pOMXAV->omxPos].omxBufferHeader); + // fprintf(stdout, "GetTexture p2.2\n", attr); fflush(stdout); + pOMXAV->omxPos = next; + next = (pOMXAV->omxPos + 1) % pOMXAV->vBufferNum; + pOMXAV->filled++; + } + else + { + // fprintf(stdout, "GetTexture p2.3\n", attr); fflush(stdout); + break; + } + } + } + if (pOMXAV->available > 1) + { + // fprintf(stdout, "GetTexture p3.1\n"); fflush(stdout); + // We want to make sure that the previous eglImage + // has finished, so insert a fence command into the + // command stream to make sure that any rendering using + // the previous eglImage has finished. + // + // Only move on to rendering the next image if the insertion + // was successfull. + if (!_hasEGLSync || eglFenceKHR(pOMXAV->buffers[pOMXAV->glPos].sync)) + { + // fprintf(stdout, "GetTexture p3.2\n"); fflush(stdout); + pOMXAV->available--; + pOMXAV->filled--; + pOMXAV->glPos = (pOMXAV->glPos + 1) % pOMXAV->vBufferNum; + ret = pOMXAV->glPos; + } + } + + texID = pOMXAV->available ? pOMXAV->buffers[ret].tex : 0; + // fprintf(stdout, "GetTexture B avail %d, filled %d, pos o:%d g:%d t:%d\n", + // pOMXAV->available, pOMXAV->filled, pOMXAV->omxPos, pOMXAV->glPos, texID); fflush(stdout); + + kdThreadMutexUnlock(pOMXAV->mutex); + return texID; +} + +void OMXToolBasicAV_DestroyInstance(OMXToolBasicAV_t * pOMXAV) +{ + if(NULL==pOMXAV) return; + + kdThreadMutexLock(pOMXAV->mutex); + DestroyInstanceUnlock(pOMXAV); +} + +#if defined(SELF_TEST) + +#include <KD/NV_extwindowprops.h> + +static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR; + +#ifdef _WIN32_WCE + #define STDOUT_FILE "\\Storage Card\\stdout.txt" + #define STDERR_FILE "\\Storage Card\\stderr.txt" +#endif + +int ModuleTest() +{ + int i; + OMXToolBasicAV_t * pOMXAV = NULL; + GLuint tex; EGLImageKHR image; EGLSyncKHR sync; + KDchar file[512]; + EGLint attrib = EGL_NONE; + +#if 0 + const EGLint s_configAttribs[] = { + EGL_RED_SIZE, 1, + EGL_GREEN_SIZE, 1, + EGL_BLUE_SIZE, 1, + EGL_ALPHA_SIZE, EGL_DONT_CARE, + EGL_DEPTH_SIZE, 1, + EGL_STENCIL_SIZE, EGL_DONT_CARE, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_NONE + }; +#else + const EGLint s_configAttribs[] = { + EGL_RED_SIZE, 5, + EGL_GREEN_SIZE, 6, + EGL_BLUE_SIZE, 5, + EGL_ALPHA_SIZE, EGL_DONT_CARE, + EGL_DEPTH_SIZE, 16, + EGL_STENCIL_SIZE, EGL_DONT_CARE, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_NONE + }; +#endif + + const EGLint contextAttrs[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + + EGLint numConfigs; + EGLint majorVersion; + EGLint minorVersion; + + EGLint sWidth, sHeight; + + EGLDisplay eglDisplay; + EGLConfig eglConfig; + EGLContext eglContext; + EGLSurface eglWindowSurface; + KDWindow *kdWindow; + NativeWindowType ntWindow; + +// KDint wSize[2]; + +#ifdef _WIN32_WCE + _wfreopen(TEXT(STDOUT_FILE),L"w",stdout); + _wfreopen(TEXT(STDERR_FILE),L"w",stderr); +#endif + + /* + * EGL initialisation. + */ + + eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + eglInitialize(eglDisplay, &majorVersion, &minorVersion); + eglChooseConfig(eglDisplay, s_configAttribs, &eglConfig, 1, &numConfigs); + kdWindow = kdCreateWindow(eglDisplay, eglConfig, KD_NULL); + + { + /* Set fullscreen mode */ + KDboolean fullscreen = KD_TRUE; + kdSetWindowPropertybv(kdWindow, + KD_WINDOWPROPERTY_FULLSCREEN_NV, &fullscreen); + } + + kdRealizeWindow(kdWindow, &ntWindow); + + eglContext = eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, contextAttrs); + + eglWindowSurface = eglCreateWindowSurface(eglDisplay, eglConfig, ntWindow, KD_NULL); + eglMakeCurrent(eglDisplay, eglWindowSurface, eglWindowSurface, eglContext); + + printf("EGL Extensions : %s\n",eglQueryString(eglDisplay, EGL_EXTENSIONS)); + printf("EGL CLIENT APIs: %s\n",eglQueryString(eglDisplay, EGL_CLIENT_APIS)); + + eglQuerySurface(eglDisplay, eglWindowSurface, EGL_WIDTH , &sWidth); + eglQuerySurface(eglDisplay, eglWindowSurface, EGL_HEIGHT , &sHeight); + + /* Set up the viewport and perspective. */ + printf("screen dim %dx%d\n", sWidth, sHeight); + glViewport(0, 0, sWidth, sHeight); + + /* + if (argc == 2) + kdStrcpy_s(file, 512, argv[1]); + else */ + kdStrcpy_s(file, 512, "/Storage Card/resources/videoplayer/Luna_800x480_1_5M_H264.mp4"); + + if( OMXToolBasicAV_IsFileValid(file) ) { + fprintf(stderr, "File is invalid"); + return -1; + } + + GETEXTENSION(PFNEGLDESTROYIMAGEKHRPROC, eglDestroyImageKHR); + + pOMXAV = OMXToolBasicAV_CreateInstance(3); + if(OMXToolBasicAV_SetStream(pOMXAV, file)) { + return -1; + } + printf("movie dim %dx%d\n", pOMXAV->width, pOMXAV->height); + + glActiveTexture(GL_TEXTURE0); + printf("i1: 0x%X\n", glGetError()); + glEnable(GL_TEXTURE_2D); + printf("i2: 0x%X\n", glGetError()); + + for (i = 0; i < 3; i++) + { + printf("0: 0x%X\n", glGetError()); + glGenTextures(1, &tex); + printf("1: tex: %d, e 0x%X\n", tex, glGetError()); + glBindTexture(GL_TEXTURE_2D, tex); + printf("2: 0x%X\n", glGetError()); + + // create space for buffer with a texture + glTexImage2D( + GL_TEXTURE_2D, // target + 0, // level + GL_RGBA, // internal format + pOMXAV->width, // width + pOMXAV->height, // height + 0, // border + GL_RGBA, // format + GL_UNSIGNED_BYTE, // type + NULL); // pixels -- will be provided later + printf("3: 0x%X\n", glGetError()); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + printf("4: 0x%X\n", glGetError()); + + // create EGLImage from texture + image = eglCreateImageKHR( + eglDisplay, + eglContext, + EGL_GL_TEXTURE_2D_KHR, + (EGLClientBuffer)(tex), + &attrib); + if (!image) + { + printf("eglGetError: 0x%x\n", eglGetError()); + printf("ERROR creating EglImage\n"); + return -1; + } + printf("5 eglGetError: 0x%x\n", eglGetError()); + + sync = eglCreateFenceSyncKHR( + eglDisplay, EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR, &attrib); + + printf("6 eglGetError: 0x%x\n", eglGetError()); + + if(OMXToolBasicAV_SetEGLImageTexture2D(pOMXAV, i, tex, image, sync)) { + return -1; + } + } + + printf("7\n"); fflush(stdout); + if( OMXToolBasicAV_ActivateInstance(pOMXAV) ) { + return -1; + } + + printf("8\n"); fflush(stdout); + if( OMXToolBasicAV_PlayStart(pOMXAV) ) { + return -1; + } + + printf("8.2\n"); fflush(stdout); + + i = 0; + while (i++ < 10) { + glClear(GL_COLOR_BUFFER_BIT); + // set uniforms + // set attributes + // draw arrays .. + eglSwapBuffers(eglDisplay, eglWindowSurface); + printf("Sleep %d\n", i); fflush(stdout); + usleep(1000); + } + + printf("9\n"); + if( OMXToolBasicAV_PlayStop(pOMXAV) ) { + fprintf(stderr, "Err: Stop"); + return -1; + } + printf("A1\n"); + OMXToolBasicAV_DetachVideoRenderer(pOMXAV); // Stop before .. + + printf("A2\n"); + OMXToolBasicAV_AttachVideoRenderer(pOMXAV); // DetachVideoRenderer before .. + + printf("B\n"); + OMXToolBasicAV_DestroyInstance(pOMXAV); + + printf("C\n"); + eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(eglDisplay, eglWindowSurface); + eglDestroyContext(eglDisplay, eglContext); + + printf("D\n"); + kdDestroyWindow(kdWindow); + + printf("E\n"); + eglTerminate(eglDisplay); + printf("F\n"); + eglReleaseThread(); + + return 0; +} + +KDint kdMain(KDint argc, const KDchar *const *argv) +// int main(int argc, const char *const *argv) +{ + return ModuleTest(); +} +#endif + diff --git a/src/native/openmax/omx_tool.h b/src/native/openmax/omx_tool.h new file mode 100644 index 000000000..abfe09eff --- /dev/null +++ b/src/native/openmax/omx_tool.h @@ -0,0 +1,145 @@ + +#ifndef _OMX_TOOL_H +#define _OMX_TOOL_H + +#ifdef _WIN32 + #include <windows.h> + // __declspec(dllimport) void __stdcall Sleep(unsigned long dwMilliseconds); + + #define usleep(t) Sleep((t) / 1000) + + #ifdef _MSC_VER + /* This typedef is apparently needed for Microsoft compilers before VC8, + and on Windows CE */ + #if (_MSC_VER < 1400) || defined(UNDER_CE) + #ifdef _WIN64 + typedef long long intptr_t; + #else + typedef int intptr_t; + #endif + #endif + #else + #include <inttypes.h> + #endif +#else + #include <unistd.h> + #include <inttypes.h> +#endif + +#include <OMX_Core.h> +#include <OMX_Index.h> +#include <OMX_Video.h> +#include <OMX_Audio.h> +#include <OMX_Other.h> +#include <OMX_Image.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> +#include <EGL/eglext.h> +#include <KD/kd.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define EGLIMAGE_MAX_BUFFERS 4 + +extern int USE_OPENGL; +extern int USE_HWAUDIOOUT; +extern int USE_AUDIOBUFFERING; +extern const int PORT_VRENDERER; + +typedef struct { + EGLSyncKHR sync; + EGLImageKHR image; + GLuint tex; + OMX_BUFFERHEADERTYPE *omxBufferHeader; +} OMXToolImageBuffer_t; + +typedef enum +{ + OMXAV_INVALID=0, + OMXAV_INIT, + OMXAV_STOPPED, + OMXAV_PLAYING, + OMXAV_PAUSED, + OMXAV_FIN, +} OMXToolStatus; + +typedef enum +{ + OMXAV_H_READER=0, + OMXAV_H_CLOCK, + OMXAV_H_ADECODER, + OMXAV_H_ABUFFERING, + OMXAV_H_ARENDERER, + OMXAV_H_VDECODER, + OMXAV_H_VRENDERER, + OMXAV_H_VSCHEDULER, + OMXAV_H_NUMBER, +} OMXToolHandleIdx; + + +typedef struct { + OMX_VERSIONTYPE version; + OMX_HANDLETYPE comp[OMXAV_H_NUMBER]; + OMX_HANDLETYPE endComponent; + OMX_CALLBACKTYPE callbacks; + + KDchar audioCodec[256]; + KDchar videoCodec[256]; + int audioPort; + int videoPort; + int width; + int height; + + KDThreadMutex * mutex; + KDThreadSem * flushSem; + + OMXToolImageBuffer_t buffers[EGLIMAGE_MAX_BUFFERS]; + int vBufferNum; + int glPos; + int omxPos; + int filled; + int available; + + int status; +} OMXToolBasicAV_t ; + +// +// more internal stuff .. +// +KDint OMXToolBasicAV_IsFileValid(const KDchar * file); + +// +// OMX state control .. +// +KDint OMXToolBasicAV_CheckState(OMXToolBasicAV_t * pOMXAV, OMX_STATETYPE state); +KDint OMXToolBasicAV_SetState(OMXToolBasicAV_t * pOMXAV, OMX_STATETYPE state, KDboolean wait); + +// +// User related functionality, mutex managed +// +OMXToolBasicAV_t * OMXToolBasicAV_CreateInstance(int vBufferNum); // #1 +int OMXToolBasicAV_SetStream(OMXToolBasicAV_t * pOMXAV, const KDchar * stream); // #3 +int OMXToolBasicAV_UpdateStreamInfo(OMXToolBasicAV_t * pOMXAV); +int OMXToolBasicAV_SetEGLImageTexture2D(OMXToolBasicAV_t * pOMXAV, KDint i, GLuint tex, EGLImageKHR image, EGLSyncKHR sync); // #2.. +int OMXToolBasicAV_ActivateInstance(OMXToolBasicAV_t * pOMXAV); + +int OMXToolBasicAV_AttachVideoRenderer(OMXToolBasicAV_t * pOMXAV); // DetachVideoRenderer before .. +int OMXToolBasicAV_DetachVideoRenderer(OMXToolBasicAV_t * pOMXAV); // Stop before .. + +int OMXToolBasicAV_SetClockScale(OMXToolBasicAV_t * pOMXAV, KDfloat32 scale); +int OMXToolBasicAV_PlayStart(OMXToolBasicAV_t * pOMXAV); +int OMXToolBasicAV_PlayPause(OMXToolBasicAV_t * pOMXAV); +int OMXToolBasicAV_PlayStop(OMXToolBasicAV_t * pOMXAV); +int OMXToolBasicAV_PlaySeek(OMXToolBasicAV_t * pOMXAV, KDfloat32 time); +GLuint OMXToolBasicAV_GetTexture(OMXToolBasicAV_t * pOMXAV); + +void OMXToolBasicAV_DestroyInstance(OMXToolBasicAV_t * pOMXAV); +int ModuleTest(); + + + + +#endif /* _OMX_TOOL_H */ + |