diff options
author | Sven Gothel <[email protected]> | 2009-03-16 14:38:27 +0000 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2009-03-16 14:38:27 +0000 |
commit | 24fcece997ba911b0270033a357bbd83258d4f1a (patch) | |
tree | 4d01034154734897724d6a3b7738bf22693a8d36 /src/jogl/native | |
parent | 9517d52c18bfa93d78e03f4c212757eda421afb6 (diff) |
JOGL refactoring:
Refactored JOGL into 3 independent components.
1 NWI - Native windowing interface
Abstracts the the general NativeWindow interface and it's factory,
incl the basic JAWT and Xlib toolkit.
The latter was motivated to clean up the JOGL workspace,
and to allow other to reuse this part.
The generic core is nwi.core.jar, the AWT add-on is nwi.awt.jar.
2 JOGL - The OpenGL mapping
Further cleanup of the SPEC.
All non OpenGL toolkits are relocated to NWI and NEWT.
There is still openmax and the windows audio layer ..
Another cleanup of the fixed function pipeline emulation.
Moved utilities and implementations where they belong ..
Removed GLUnsupportedException.
Misc .. changes
3 NEWT - The new windowing toolkit
The generic NEWT, newt.core.jar.
The JOGL and AWT modules are seperate, newt.ogl.jar newt.awt.jar.
Their build can be switched off.
The modules source and builds resides in their own directory.
Because of their nature, they share the stub_includes, etc.
Each module has it's own ant build script
- build-nwi.xml
- build-jogl.xml
- build-newt.xml
They can be build at once using build.xml as ususal,
which just invokes the seperate build tasks.
if rootrel.build=build, then the build location is
jogl/build-nwi
jogl/build-jogl
jogl/build-newt
and the sources are under
jogl/src/nwi
jogl/src/jogl
jogl/src/newt
Tested: jogl-demos, d4; Linux, MacOsX; Nvidia
git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/branches/JOGL_2_SANDBOX@1868 232f8b59-042b-4e1e-8c03-345bb8c30851
Diffstat (limited to 'src/jogl/native')
-rw-r--r-- | src/jogl/native/InternalBufferUtils.c | 78 | ||||
-rwxr-xr-x | src/jogl/native/audio/Mixer.cpp | 199 | ||||
-rw-r--r-- | src/jogl/native/macosx/ContextUpdater.h | 40 | ||||
-rw-r--r-- | src/jogl/native/macosx/ContextUpdater.m | 83 | ||||
-rw-r--r-- | src/jogl/native/macosx/MacOSXWindowSystemInterface.m | 702 | ||||
-rw-r--r-- | src/jogl/native/openmax/com_sun_openmax_OMXInstance.c | 255 | ||||
-rw-r--r-- | src/jogl/native/openmax/omx_tool.c | 1713 | ||||
-rw-r--r-- | src/jogl/native/openmax/omx_tool.h | 165 |
8 files changed, 3235 insertions, 0 deletions
diff --git a/src/jogl/native/InternalBufferUtils.c b/src/jogl/native/InternalBufferUtils.c new file mode 100644 index 000000000..4b2001a34 --- /dev/null +++ b/src/jogl/native/InternalBufferUtils.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + * + * Sun gratefully acknowledges that this software was originally authored + * and developed by Kenneth Bradley Russell and Christopher John Kline. + */ + +#include <jni.h> + +#ifdef _WIN32 + #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 <inttypes.h> +#endif + +JNIEXPORT jobject JNICALL +Java_com_sun_opengl_impl_InternalBufferUtils_newDirectByteBuffer(JNIEnv* env, jclass unused, jlong address, jint capacity) { + return (*env)->NewDirectByteBuffer(env, (void*) (intptr_t) address, capacity); +} + +#if defined(__sun) || defined(_HPUX) +#include <dlfcn.h> + +/* HP-UX doesn't define RTLD_DEFAULT. */ +#if defined(_HPUX) && !defined(RTLD_DEFAULT) +#define RTLD_DEFAULT NULL +#endif + +/* Sun's GLX implementation doesn't have glXGetProcAddressARB (or + glXGetProcAddress) so we implement it here */ +void (*glXGetProcAddressARB(const char *procname))() { + return (void (*)()) dlsym(RTLD_DEFAULT, procname); +} +#endif /* __ sun || _HPUX */ diff --git a/src/jogl/native/audio/Mixer.cpp b/src/jogl/native/audio/Mixer.cpp new file mode 100755 index 000000000..8843c00ec --- /dev/null +++ b/src/jogl/native/audio/Mixer.cpp @@ -0,0 +1,199 @@ +#include <windows.h> +#include <stdlib.h> +#include <mmsystem.h> +#include <mmreg.h> +#include "com_sun_javafx_audio_windows_waveout_Mixer.h" + +static HANDLE event = NULL; +static HWAVEOUT output = NULL; +// We use only two buffers to keep latency down +#define NUM_BUFFERS 2 +//#define NUM_BUFFERS 4 +// This is about 20 ms of data for WAVE_FORMAT_PCM: +// (44100 samples / sec) * (20 ms / 1000 ms) * (2 bytes / sample) * (2 channels) +//#define BUFFER_SIZE 3528 + +// This is about 50 ms of data for WAVE_FORMAT_PCM: +// (44100 samples / sec) * (50 ms / 1000 ms) * (2 bytes / sample) * (1 channel) +//#define BUFFER_SIZE 4410 + +// This is about 200 ms of data for WAVE_FORMAT_PCM: +// (44100 samples / sec) * (200 ms / 1000 ms) * (2 bytes / sample) * (1 channel) +//#define BUFFER_SIZE 17640 + +// This is about 200 ms of data for WAVE_FORMAT_PCM: +// (44100 samples / sec) * (200 ms / 1000 ms) * (2 bytes / sample) * (2 channel) +//#define BUFFER_SIZE 35280 + +// This is about 1000 ms of data for WAVE_FORMAT_PCM: +// (44100 samples / sec) * (1000 ms / 1000 ms) * (2 bytes / sample) * (1 channel) +//#define BUFFER_SIZE 88200 + +// This is about 50 ms of data for WAVE_FORMAT_PCM: +// (44100 samples / sec) * (50 ms / 1000 ms) * (2 bytes / sample) * (2 channels) +//#define BUFFER_SIZE 8820 + +// This is about 50 ms of data for WAVE_FORMAT_IEEE_FLOAT: +// (44100 samples / sec) * (50 ms / 1000 ms) * (4 bytes / sample) * (2 channels) +//#define BUFFER_SIZE 17640 + +// This is about 200 ms of data for WAVE_FORMAT_PCM: +// (11025 samples / sec) * (200 ms / 1000 ms) * (2 bytes / sample) * (2 channel) +#define BUFFER_SIZE 8820 + +//#define BUFFER_SIZE 8192 +static WAVEHDR** buffers = NULL; + +void CALLBACK playbackCallback(HWAVEOUT output, + UINT msg, + DWORD_PTR userData, + DWORD_PTR param1, + DWORD_PTR param2) +{ + if (msg == WOM_DONE) { + WAVEHDR* hdr = (WAVEHDR*) param1; + hdr->dwFlags |= WHDR_DONE; + SetEvent(event); + } +} + +JNIEXPORT jboolean JNICALL Java_com_sun_javafx_audio_windows_waveout_Mixer_initializeWaveOut + (JNIEnv *env, jclass unused, jlong eventObject) +{ + event = (HANDLE) eventObject; + + // Note the hard requirements on the RawSoundConverter's output format + WAVEFORMATEX format; + format.wFormatTag = WAVE_FORMAT_PCM; + // format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; + format.nChannels = 2; + // format.nChannels = 1; + // format.nSamplesPerSec = 44100; + format.nSamplesPerSec = 11025; + format.wBitsPerSample = 16; + // format.wBitsPerSample = 32; + format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8; + format.nAvgBytesPerSec = format.nBlockAlign * format.nSamplesPerSec; + format.cbSize = 0; + MMRESULT res = waveOutOpen(&output, + WAVE_MAPPER, + &format, + /* NULL, */ (DWORD_PTR) &playbackCallback, + NULL, // No user data right now + /* CALLBACK_NULL */ CALLBACK_FUNCTION); + if (res != MMSYSERR_NOERROR) { + return JNI_FALSE; + } + + buffers = (WAVEHDR**) calloc(NUM_BUFFERS, sizeof(WAVEHDR)); + for (int i = 0; i < NUM_BUFFERS; i++) { + char* data = (char*) calloc(BUFFER_SIZE, 1); + WAVEHDR* hdr = (WAVEHDR*) calloc(1, sizeof(WAVEHDR)); + hdr->lpData = data; + hdr->dwBufferLength = BUFFER_SIZE; + hdr->dwFlags |= WHDR_DONE; + buffers[i] = hdr; + } + + return JNI_TRUE; +} + +JNIEXPORT void JNICALL Java_com_sun_javafx_audio_windows_waveout_Mixer_shutdownWaveOut + (JNIEnv *env, jclass unused) +{ + // writeString("Pausing\n"); + waveOutPause(output); + // writeString("Resetting\n"); + waveOutReset(output); + // writeString("Closing output\n"); + waveOutClose(output); +} + +JNIEXPORT jlong JNICALL Java_com_sun_javafx_audio_windows_waveout_Mixer_getNextMixerBuffer + (JNIEnv *env, jclass unused) +{ + WAVEHDR* hdr = NULL; + for (int i = 0; i < NUM_BUFFERS; i++) { + if (buffers[i] != NULL && ((buffers[i]->dwFlags & WHDR_DONE) != 0)) { + hdr = buffers[i]; + hdr->dwFlags &= ~WHDR_DONE; + break; + } + } + return (jlong) hdr; +} + +JNIEXPORT jobject JNICALL Java_com_sun_javafx_audio_windows_waveout_Mixer_getMixerBufferData + (JNIEnv *env, jclass unused, jlong mixerBuffer) +{ + WAVEHDR* hdr = (WAVEHDR*) mixerBuffer; + return env->NewDirectByteBuffer(hdr->lpData, hdr->dwBufferLength); +} + +JNIEXPORT jlong JNICALL Java_com_sun_javafx_audio_windows_waveout_Mixer_getMixerBufferDataAddress + (JNIEnv *env, jclass unused, jlong mixerBuffer) +{ + WAVEHDR* hdr = (WAVEHDR*) mixerBuffer; + return (jlong) hdr->lpData; +} + +JNIEXPORT jint JNICALL Java_com_sun_javafx_audio_windows_waveout_Mixer_getMixerBufferDataCapacity + (JNIEnv *env, jclass unused, jlong mixerBuffer) +{ + WAVEHDR* hdr = (WAVEHDR*) mixerBuffer; + return (jint) hdr->dwBufferLength; +} + +JNIEXPORT jboolean JNICALL Java_com_sun_javafx_audio_windows_waveout_Mixer_prepareMixerBuffer + (JNIEnv *env, jclass unused, jlong mixerBuffer) +{ + MMRESULT res = waveOutPrepareHeader(output, + (WAVEHDR*) mixerBuffer, + sizeof(WAVEHDR)); + if (res == MMSYSERR_NOERROR) { + return JNI_TRUE; + } + return JNI_FALSE; +} + +JNIEXPORT jboolean JNICALL Java_com_sun_javafx_audio_windows_waveout_Mixer_writeMixerBuffer + (JNIEnv *env, jclass unused, jlong mixerBuffer) +{ + MMRESULT res = waveOutWrite(output, + (WAVEHDR*) mixerBuffer, + sizeof(WAVEHDR)); + if (res == MMSYSERR_NOERROR) { + waveOutRestart(output); + + return JNI_TRUE; + } + return JNI_FALSE; +} + +JNIEXPORT jlong JNICALL Java_com_sun_javafx_audio_windows_waveout_Mixer_CreateEvent + (JNIEnv *env, jclass unused) +{ + return (jlong) CreateEvent(NULL, FALSE, TRUE, NULL); +} + +JNIEXPORT jboolean JNICALL Java_com_sun_javafx_audio_windows_waveout_Mixer_WaitForSingleObject + (JNIEnv *env, jclass unused, jlong eventObject) +{ + DWORD res = WaitForSingleObject((HANDLE) eventObject, INFINITE); + if (res == WAIT_OBJECT_0) { + return JNI_TRUE; + } + return JNI_FALSE; +} + +JNIEXPORT void JNICALL Java_com_sun_javafx_audio_windows_waveout_Mixer_SetEvent + (JNIEnv *env, jclass unused, jlong eventObject) +{ + SetEvent((HANDLE) eventObject); +} + +JNIEXPORT void JNICALL Java_com_sun_javafx_audio_windows_waveout_Mixer_CloseHandle + (JNIEnv *env, jclass unused, jlong eventObject) +{ + CloseHandle((HANDLE) eventObject); +} diff --git a/src/jogl/native/macosx/ContextUpdater.h b/src/jogl/native/macosx/ContextUpdater.h new file mode 100644 index 000000000..e8b757fac --- /dev/null +++ b/src/jogl/native/macosx/ContextUpdater.h @@ -0,0 +1,40 @@ +/* + +Listens to NSViewGlobalFrameDidChangeNotification + +This notification is sent whenever an NSView that has an attached NSSurface changes size or changes screens (thus potentially changing graphics hardware drivers.) + +*/ + +#import <Cocoa/Cocoa.h> +#import <Foundation/Foundation.h> +#import <AppKit/NSView.h> +#import <OpenGL/OpenGL.h> +#import <OpenGL/gl.h> + +//#define DEBUG_GL_LOCKS + +#ifdef DEBUG_GL_LOCKS + #define LOCK_GL(func, line) [ContextUpdater lockInFunction:func atLine:line]; + #define UNLOCK_GL(func, line) [ContextUpdater unlockInFunction:func atLine:line]; +#else + #define LOCK_GL(func, line) [ContextUpdater lock]; + #define UNLOCK_GL(func, line) [ContextUpdater unlock]; +#endif + +// gznote: OpenGL NOT thread safe - need to sync on update and paints + +@interface ContextUpdater : NSObject +{ +} + ++ (void) lock; ++ (void) lockInFunction:(char *)func atLine:(int)line; ++ (void) unlock; ++ (void) unlockInFunction:(char *)func atLine:(int)line; + +- (void) registerFor:(NSOpenGLContext *)context with: (NSView *)window; + +- (void) update:(NSNotification *)notification; + +@end diff --git a/src/jogl/native/macosx/ContextUpdater.m b/src/jogl/native/macosx/ContextUpdater.m new file mode 100644 index 000000000..587782c98 --- /dev/null +++ b/src/jogl/native/macosx/ContextUpdater.m @@ -0,0 +1,83 @@ +#import "ContextUpdater.h" +#import <pthread.h> + +@implementation ContextUpdater +{ +} + +static NSOpenGLContext *theContext; +static pthread_mutex_t resourceLock = PTHREAD_MUTEX_INITIALIZER; + +static void printLockDebugInfo(char *message, char *func, int line) +{ + fprintf(stderr, "%s in function: \"%s\" at line: %d\n", message, func, line); + fflush(stderr); +} + ++ (void) lock +{ + if (theContext != NULL) + { + pthread_mutex_lock(&resourceLock); + } +} + ++ (void) lockInFunction:(char *)func atLine:(int)line +{ + if (theContext != NULL) + { + printLockDebugInfo("locked ", func, line); + [self lock]; + } +} + ++ (void) unlock +{ + if (theContext != NULL) + { + pthread_mutex_unlock(&resourceLock); + } +} + ++ (void) unlockInFunction:(char *)func atLine:(int)line +{ + if (theContext != NULL) + { + printLockDebugInfo("unlocked", func, line); + [self unlock]; + } +} + +- (void) registerFor:(NSOpenGLContext *)context with: (NSView *)view +{ + if (view != NULL) + { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(update:) name:NSViewGlobalFrameDidChangeNotification object: view]; + theContext = context; + } +} + +- (void) update:(NSNotification *)notification +{ + [ContextUpdater lock]; + + [theContext update]; + + [ContextUpdater unlock]; +} + +- (id) init +{ + theContext = NULL; + + return [super init]; +} + +- (void) dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + [super dealloc]; +} + +@end
\ No newline at end of file diff --git a/src/jogl/native/macosx/MacOSXWindowSystemInterface.m b/src/jogl/native/macosx/MacOSXWindowSystemInterface.m new file mode 100644 index 000000000..350f6152f --- /dev/null +++ b/src/jogl/native/macosx/MacOSXWindowSystemInterface.m @@ -0,0 +1,702 @@ +/* Note: usage of AvailabilityMacros.h to detect whether we're + building on OS X 10.3 does not work because the header #defines + MAC_OS_X_VERSION_10_4 even though the machine is a 10.3 machine + +#include <AvailabilityMacros.h> + +#ifndef MAC_OS_X_VERSION_10_3 + #error building JOGL requires Mac OS X 10.3 or greater +#endif + +#ifndef MAC_OS_X_VERSION_10_4 + #define NSOpenGLPFAColorFloat kCGLPFAColorFloat + #define kCGLNoError 0 +#endif +*/ + +#import <Cocoa/Cocoa.h> +#import <OpenGL/gl.h> +#import <OpenGL/CGLTypes.h> +#import <jni.h> +#import "ContextUpdater.h" + +#import "macosx-window-system.h" + +// see MacOSXPbufferGLContext.java createPbuffer +#define USE_GL_TEXTURE_RECTANGLE_EXT + +#ifdef USE_GL_TEXTURE_RECTANGLE_EXT + #ifndef GL_TEXTURE_RECTANGLE_EXT + #define GL_TEXTURE_RECTANGLE_EXT 0x84F5 + #endif +#endif + +// Workarounds for compiling on 10.3 +#ifndef kCGLRGBA16161616Bit +#define kCGLRGBA16161616Bit 0x00800000 /* 64 argb bit/pixel, R=63:48, G=47:32, B=31:16, A=15:0 */ +#define kCGLRGBFloat64Bit 0x01000000 /* 64 rgb bit/pixel, half float */ +#define kCGLRGBAFloat64Bit 0x02000000 /* 64 argb bit/pixel, half float */ +#define kCGLRGBFloat128Bit 0x04000000 /* 128 rgb bit/pixel, ieee float */ +#define kCGLRGBAFloat128Bit 0x08000000 /* 128 argb bit/pixel, ieee float */ +#define kCGLRGBFloat256Bit 0x10000000 /* 256 rgb bit/pixel, ieee double */ +#define kCGLRGBAFloat256Bit 0x20000000 /* 256 argb bit/pixel, ieee double */ +#endif + +struct _RendererInfo +{ + long id; // kCGLRPRendererID + long displayMask; // kCGLRPDisplayMask + + long accelerated; // kCGLRPAccelerated + + long window; // kCGLRPWindow + long fullscreen; // kCGLRPFullScreen + long multiscreen; // kCGLRPMultiScreen + long offscreen; // kCGLRPOffScreen + long floatPixels; // see kCGLRPColorModes + long stereo; // kCGLRPBufferModes + + long auxBuffers; // kCGLRPMaxAuxBuffers + long sampleBuffers; // kCGLRPMaxSampleBuffers + long samples; // kCGLRPMaxSamples + long samplesModes; // kCGLRPSampleModes + long multiSample; // see kCGLRPSampleModes + long superSample; // see kCGLRPSampleModes + long alphaSample; // kCGLRPSampleAlpha + + long colorModes; // kCGLRPColorModes + long colorRGBSizeMAX; + long colorASizeMAX; + long colorFloatRGBSizeMAX; + long colorFloatASizeMAX; + long colorFloatRGBSizeMIN; + long colorFloatASizeMIN; + long colorModesCount; + long colorFloatModesCount; + long depthModes; // kCGLRPDepthModes + long depthSizeMAX; + long depthModesCount; + long stencilModes; // kCGLRPStencilModes + long stencilSizeMAX; + long stencilModesCount; + long accumModes; // kCGLRPAccumModes + long accumRGBSizeMAX; + long accumASizeMAX; + long accumModesCount; +} +typedef RendererInfo; + +RendererInfo *gRenderers = NULL; +long gRenderersCount = 0; + +long depthModes[] = { + kCGL0Bit, + kCGL1Bit, + kCGL2Bit, + kCGL3Bit, + kCGL4Bit, + kCGL5Bit, + kCGL6Bit, + kCGL8Bit, + kCGL10Bit, + kCGL12Bit, + kCGL16Bit, + kCGL24Bit, + kCGL32Bit, + kCGL48Bit, + kCGL64Bit, + kCGL96Bit, + kCGL128Bit, + 0 + }; +long depthModesBits[] = {0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 24, 32, 48, 64, 96, 128}; +long colorModes[] = { + kCGLRGB444Bit, + kCGLARGB4444Bit, + kCGLRGB444A8Bit, + kCGLRGB555Bit, + kCGLARGB1555Bit, + kCGLRGB555A8Bit, + kCGLRGB565Bit, + kCGLRGB565A8Bit, + kCGLRGB888Bit, + kCGLARGB8888Bit, + kCGLRGB888A8Bit, + kCGLRGB101010Bit, + kCGLARGB2101010Bit, + kCGLRGB101010_A8Bit, + kCGLRGB121212Bit, + kCGLARGB12121212Bit, + kCGLRGB161616Bit, + kCGLRGBA16161616Bit, + kCGLRGBFloat64Bit, + kCGLRGBAFloat64Bit, + kCGLRGBFloat128Bit, + kCGLRGBAFloat128Bit, + kCGLRGBFloat256Bit, + kCGLRGBAFloat256Bit, + 0 + }; +long colorModesBitsRGB[] = {4, 4, 4, 5, 5, 5, 5, 5, 8, 8, 8, 10, 10, 10, 12, 12, 16, 16, 16, 16, 32, 32, 64, 64}; +long colorModesBitsA[] = {0, 4, 8, 0, 1, 8, 0, 8, 0, 8, 8, 0, 2, 8, 0, 12, 0, 16, 0, 16, 0, 32, 0, 64}; + +void getRendererInfo() +{ + if (gRenderersCount == 0) + { + CGLRendererInfoObj info; + CGLError err = CGLQueryRendererInfo(CGDisplayIDToOpenGLDisplayMask(kCGDirectMainDisplay), &info, &gRenderersCount); + if (err == 0 /* kCGLNoError */) + { + // how many renderers are available? + CGLDescribeRenderer(info, 0, kCGLRPRendererCount, &gRenderersCount); + + // allocate our global renderers info + gRenderers = (RendererInfo*)malloc(gRenderersCount*sizeof(RendererInfo)); + memset(gRenderers, 0x00, gRenderersCount*sizeof(RendererInfo)); + + // iterate through the renderers checking for their features + long j; + for (j=0; j<gRenderersCount; j++) + { + RendererInfo *renderer = &gRenderers[j]; + int i; + + CGLDescribeRenderer(info, j, kCGLRPRendererID, &(renderer->id)); + CGLDescribeRenderer(info, j, kCGLRPDisplayMask, &(renderer->displayMask)); + + CGLDescribeRenderer(info, j, kCGLRPAccelerated, &(renderer->accelerated)); + + CGLDescribeRenderer(info, j, kCGLRPWindow, &(renderer->window)); + CGLDescribeRenderer(info, j, kCGLRPFullScreen, &(renderer->fullscreen)); + CGLDescribeRenderer(info, j, kCGLRPMultiScreen, &(renderer->multiscreen)); + CGLDescribeRenderer(info, j, kCGLRPOffScreen, &(renderer->offscreen)); + CGLDescribeRenderer(info, j, kCGLRPColorModes, &(renderer->floatPixels)); + if ((renderer->floatPixels >= kCGLRGBFloat64Bit) != 0) + { + renderer->floatPixels = 1; + } + else + { + renderer->floatPixels = 0; + } + CGLDescribeRenderer(info, j, kCGLRPBufferModes, &(renderer->stereo)); + if ((renderer->stereo & kCGLStereoscopicBit) != 0) + { + renderer->stereo = 1; + } + else + { + renderer->stereo = 0; + } + + CGLDescribeRenderer(info, j, kCGLRPMaxAuxBuffers, &(renderer->auxBuffers)); + CGLDescribeRenderer(info, j, kCGLRPMaxSampleBuffers, &(renderer->sampleBuffers)); + CGLDescribeRenderer(info, j, kCGLRPMaxSamples, &(renderer->samples)); + // The following queries are only legal on 10.4 + // FIXME: should figure out a way to enable them dynamically +#ifdef kCGLRPSampleModes + CGLDescribeRenderer(info, j, kCGLRPSampleModes, &(renderer->samplesModes)); + if ((renderer->samplesModes & kCGLSupersampleBit) != 0) + { + renderer->multiSample = 1; + } + if ((renderer->samplesModes & kCGLMultisampleBit) != 0) + { + renderer->superSample = 1; + } + CGLDescribeRenderer(info, j, kCGLRPSampleAlpha, &(renderer->alphaSample)); +#endif + CGLDescribeRenderer(info, j, kCGLRPColorModes, &(renderer->colorModes)); + i=0; + int floatPixelFormatInitialized = 0; + while (colorModes[i] != 0) + { + if ((renderer->colorModes & colorModes[i]) != 0) + { + // non-float color model + if (colorModes[i] < kCGLRGBFloat64Bit) + { + // look for max color and alpha values - prefer color models that have alpha + if ((colorModesBitsRGB[i] >= renderer->colorRGBSizeMAX) && (colorModesBitsA[i] >= renderer->colorASizeMAX)) + { + renderer->colorRGBSizeMAX = colorModesBitsRGB[i]; + renderer->colorASizeMAX = colorModesBitsA[i]; + } + renderer->colorModesCount++; + } + // float-color model + if (colorModes[i] >= kCGLRGBFloat64Bit) + { + if (floatPixelFormatInitialized == 0) + { + floatPixelFormatInitialized = 1; + + renderer->colorFloatASizeMAX = colorModesBitsA[i]; + renderer->colorFloatRGBSizeMAX = colorModesBitsRGB[i]; + renderer->colorFloatASizeMIN = colorModesBitsA[i]; + renderer->colorFloatRGBSizeMIN = colorModesBitsRGB[i]; + } + // look for max color and alpha values - prefer color models that have alpha + if ((colorModesBitsRGB[i] >= renderer->colorFloatRGBSizeMAX) && (colorModesBitsA[i] >= renderer->colorFloatASizeMAX)) + { + renderer->colorFloatRGBSizeMAX = colorModesBitsRGB[i]; + renderer->colorFloatASizeMAX = colorModesBitsA[i]; + } + // find min color + if (colorModesBitsA[i] < renderer->colorFloatASizeMIN) + { + renderer->colorFloatASizeMIN = colorModesBitsA[i]; + } + // find min alpha color + if (colorModesBitsA[i] < renderer->colorFloatRGBSizeMIN) + { + renderer->colorFloatRGBSizeMIN = colorModesBitsRGB[i]; + } + renderer->colorFloatModesCount++; + } + } + i++; + } + CGLDescribeRenderer(info, j, kCGLRPDepthModes, &(renderer->depthModes)); + i=0; + while (depthModes[i] != 0) + { + if ((renderer->depthModes & depthModes[i]) != 0) + { + renderer->depthSizeMAX = depthModesBits[i]; + renderer->depthModesCount++; + } + i++; + } + CGLDescribeRenderer(info, j, kCGLRPStencilModes, &(renderer->stencilModes)); + i=0; + while (depthModes[i] != 0) + { + if ((renderer->stencilModes & depthModes[i]) != 0) + { + renderer->stencilSizeMAX = depthModesBits[i]; + renderer->stencilModesCount++; + } + i++; + } + CGLDescribeRenderer(info, j, kCGLRPAccumModes, &(renderer->accumModes)); + i=0; + while (colorModes[i] != 0) + { + if ((renderer->accumModes & colorModes[i]) != 0) + { + if ((colorModesBitsRGB[i] >= renderer->accumRGBSizeMAX) && (colorModesBitsA[i] >= renderer->accumASizeMAX)) + { + renderer->accumRGBSizeMAX = colorModesBitsRGB[i]; + renderer->accumASizeMAX = colorModesBitsA[i]; + } + renderer->accumModesCount++; + } + i++; + } + } + } + CGLDestroyRendererInfo (info); + } + +#if 0 + fprintf(stderr, "gRenderersCount=%ld\n", gRenderersCount); + int j; + for (j=0; j<gRenderersCount; j++) + { + RendererInfo *renderer = &gRenderers[j]; + fprintf(stderr, " id=%ld\n", renderer->id); + fprintf(stderr, " displayMask=%ld\n", renderer->displayMask); + + fprintf(stderr, " accelerated=%ld\n", renderer->accelerated); + + fprintf(stderr, " window=%ld\n", renderer->window); + fprintf(stderr, " fullscreen=%ld\n", renderer->fullscreen); + fprintf(stderr, " multiscreen=%ld\n", renderer->multiscreen); + fprintf(stderr, " offscreen=%ld\n", renderer->offscreen); + fprintf(stderr, " floatPixels=%ld\n", renderer->floatPixels); + fprintf(stderr, " stereo=%ld\n", renderer->stereo); + + fprintf(stderr, " auxBuffers=%ld\n", renderer->auxBuffers); + fprintf(stderr, " sampleBuffers=%ld\n", renderer->sampleBuffers); + fprintf(stderr, " samples=%ld\n", renderer->samples); + fprintf(stderr, " samplesModes=%ld\n", renderer->samplesModes); + fprintf(stderr, " multiSample=%ld\n", renderer->superSample); + fprintf(stderr, " superSample=%ld\n", renderer->superSample); + fprintf(stderr, " alphaSample=%ld\n", renderer->alphaSample); + + fprintf(stderr, " colorModes=%ld\n", renderer->colorModes); + fprintf(stderr, " colorRGBSizeMAX=%ld\n", renderer->colorRGBSizeMAX); + fprintf(stderr, " colorASizeMAX=%ld\n", renderer->colorASizeMAX); + fprintf(stderr, " colorFloatRGBSizeMAX=%ld\n", renderer->colorFloatRGBSizeMAX); + fprintf(stderr, " colorFloatASizeMAX=%ld\n", renderer->colorFloatASizeMAX); + fprintf(stderr, " colorFloatRGBSizeMIN=%ld\n", renderer->colorFloatRGBSizeMIN); + fprintf(stderr, " colorFloatASizeMIN=%ld\n", renderer->colorFloatASizeMIN); + fprintf(stderr, " colorModesCount=%ld\n", renderer->colorModesCount); + fprintf(stderr, " colorFloatModesCount=%ld\n", renderer->colorFloatModesCount); + fprintf(stderr, " depthModes=%ld\n", renderer->depthModes); + fprintf(stderr, " depthSizeMAX=%ld\n", renderer->depthSizeMAX); + fprintf(stderr, " depthModesCount=%ld\n", renderer->depthModesCount); + fprintf(stderr, " stencilModes=%ld\n", renderer->stencilModes); + fprintf(stderr, " stencilSizeMAX=%ld\n", renderer->stencilSizeMAX); + fprintf(stderr, " stencilModesCount=%ld\n", renderer->stencilModesCount); + fprintf(stderr, " accumModes=%ld\n", renderer->accumModes); + fprintf(stderr, " accumRGBSizeMAX=%ld\n", renderer->accumRGBSizeMAX); + fprintf(stderr, " accumASizeMAX=%ld\n", renderer->accumASizeMAX); + fprintf(stderr, " accumModesCount=%ld\n", renderer->accumModesCount); + fprintf(stderr, "\n"); + } +#endif +} + +long validateParameter(NSOpenGLPixelFormatAttribute attribute, long value) +{ + int i; + for (i=0; i<gRenderersCount; i++) { + RendererInfo* renderer = &gRenderers[i]; + if (renderer->accelerated != 0) { + switch (attribute) { + case NSOpenGLPFAStereo: + return renderer->stereo; + + case NSOpenGLPFAStencilSize: + return MIN(value, renderer->stencilSizeMAX); + + default: + break; + } + } + } + + return value; +} + +void* createPixelFormat(int* iattrs, int niattrs, int* ivalues) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + getRendererInfo(); + + // http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/ObjC_classic/Classes/NSOpenGLPixelFormat.html + NSOpenGLPixelFormatAttribute attribs[256]; + + int idx = 0; + int i; + for (i = 0; i < niattrs; i++) { + int attr = iattrs[i]; + switch (attr) { + case NSOpenGLPFAPixelBuffer: + if (ivalues[i] != 0) { + attribs[idx++] = NSOpenGLPFAPixelBuffer; + } + break; + + case kCGLPFAColorFloat: + if (ivalues[i] != 0) { + attribs[idx++] = kCGLPFAColorFloat; + } + break; + + case NSOpenGLPFADoubleBuffer: + if (ivalues[i] != 0) { + attribs[idx++] = NSOpenGLPFADoubleBuffer; + } + break; + + case NSOpenGLPFAStereo: + if (ivalues[i] != 0 && (validateParameter(NSOpenGLPFAStereo, 0 /* dummy */) != 0)) { + attribs[idx++] = NSOpenGLPFAStereo; + } + break; + + case NSOpenGLPFAColorSize: + case NSOpenGLPFAAlphaSize: + case NSOpenGLPFADepthSize: + case NSOpenGLPFAAccumSize: + case NSOpenGLPFASampleBuffers: + case NSOpenGLPFASamples: + attribs[idx++] = attr; + attribs[idx++] = ivalues[i]; + break; + + case NSOpenGLPFAStencilSize: + attribs[idx++] = attr; + attribs[idx++] = validateParameter(NSOpenGLPFAStencilSize, ivalues[i]); + break; + + default: + // Need better way to signal to caller + return nil; + } + } + + // Zero-terminate + attribs[idx++] = 0; + + NSOpenGLPixelFormat* fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; + if (fmt == nil) { + // should we fallback to defaults or not? + fmt = [NSOpenGLView defaultPixelFormat]; + } + + [pool release]; + return fmt; +} + +void queryPixelFormat(void* pixelFormat, int* iattrs, int niattrs, int* ivalues) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSOpenGLPixelFormat* fmt = (NSOpenGLPixelFormat*) pixelFormat; + long tmp; + // FIXME: think about how specifying this might affect the API + int virtualScreen = 0; + + int i; + for (i = 0; i < niattrs; i++) { + [fmt getValues: &tmp + forAttribute: (NSOpenGLPixelFormatAttribute) iattrs[i] + forVirtualScreen: virtualScreen]; + ivalues[i] = (int) tmp; + } + [pool release]; +} + +void deletePixelFormat(void* pixelFormat) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSOpenGLPixelFormat* fmt = (NSOpenGLPixelFormat*) pixelFormat; + [fmt release]; + [pool release]; +} + +void* createContext(void* shareContext, + void* view, + void* pixelFormat, + int* viewNotReady) +{ + getRendererInfo(); + + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + NSView *nsView = (NSView*)view; + + if (nsView != NULL) + { + Bool viewReady = true; + + if ([nsView lockFocusIfCanDraw] == NO) + { + viewReady = false; + } + else + { + NSRect frame = [nsView frame]; + if ((frame.size.width == 0) || (frame.size.height == 0)) + { + [nsView unlockFocus]; + viewReady = false; + } + } + + if (!viewReady) + { + if (viewNotReady != NULL) + { + *viewNotReady = 1; + } + + // the view is not ready yet + [pool release]; + return NULL; + } + } + + NSOpenGLContext* nsContext = [[NSOpenGLContext alloc] + initWithFormat: (NSOpenGLPixelFormat*) pixelFormat + shareContext: (NSOpenGLContext*) shareContext]; + + if (nsContext != nil) { + if (nsView != nil) { + [nsContext setView:nsView]; + [nsView unlockFocus]; + } + } + + [pool release]; + return nsContext; +} + +Bool makeCurrentContext(void* context) { + NSOpenGLContext *nsContext = (NSOpenGLContext*)context; + + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [nsContext makeCurrentContext]; + [pool release]; + return true; +} + +Bool clearCurrentContext(void* context) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [NSOpenGLContext clearCurrentContext]; + [pool release]; + return true; +} + +Bool deleteContext(void* context) { + NSOpenGLContext *nsContext = (NSOpenGLContext*)context; + + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [nsContext clearDrawable]; + [nsContext release]; + [pool release]; + return true; +} + +Bool flushBuffer(void* context) { + NSOpenGLContext *nsContext = (NSOpenGLContext*)context; + + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [nsContext flushBuffer]; + [pool release]; + return true; +} + +void setContextOpacity(void* context, int opacity) { + NSOpenGLContext *nsContext = (NSOpenGLContext*)context; + + [nsContext setValues:&opacity forParameter:NSOpenGLCPSurfaceOpacity]; +} + +void updateContext(void* context) { + NSOpenGLContext *nsContext = (NSOpenGLContext*)context; + + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [nsContext update]; + [pool release]; +} + +void copyContext(void* destContext, void* srcContext, int mask) { + NSOpenGLContext *src = (NSOpenGLContext*) srcContext; + NSOpenGLContext *dst = (NSOpenGLContext*) destContext; + [dst copyAttributesFromContext: src withMask: mask]; +} + +void* updateContextRegister(void* context, void* view) { + NSOpenGLContext *nsContext = (NSOpenGLContext*)context; + NSView *nsView = (NSView*)view; + + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + ContextUpdater *contextUpdater = [[ContextUpdater alloc] init]; + [contextUpdater registerFor:nsContext with:nsView]; + [pool release]; + return NULL; +} + +void updateContextUnregister(void* context, void* view, void* updater) { + ContextUpdater *contextUpdater = (ContextUpdater *)updater; + + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [contextUpdater release]; + [pool release]; +} + +void* createPBuffer(int renderTarget, int internalFormat, int width, int height) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSOpenGLPixelBuffer* pBuffer = [[NSOpenGLPixelBuffer alloc] + initWithTextureTarget:renderTarget + textureInternalFormat:internalFormat + textureMaxMipMapLevel:0 + pixelsWide:width + pixelsHigh:height]; + [pool release]; + return pBuffer; +} + +Bool destroyPBuffer(void* context, void* buffer) { + /* FIXME: not clear whether we need to perform the clearDrawable below */ + /* FIXME: remove the context argument -- don't need it any more */ + /* NSOpenGLContext *nsContext = (NSOpenGLContext*)context; */ + NSOpenGLPixelBuffer *pBuffer = (NSOpenGLPixelBuffer*)buffer; + + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + /* + if (nsContext != NULL) { + [nsContext clearDrawable]; + } + */ + [pBuffer release]; + [pool release]; + + return true; +} + +void setContextPBuffer(void* context, void* buffer) { + NSOpenGLContext *nsContext = (NSOpenGLContext*)context; + NSOpenGLPixelBuffer *pBuffer = (NSOpenGLPixelBuffer*)buffer; + + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [nsContext setPixelBuffer: pBuffer + cubeMapFace: 0 + mipMapLevel: 0 + currentVirtualScreen: [nsContext currentVirtualScreen]]; + [pool release]; +} + +void setContextTextureImageToPBuffer(void* context, void* buffer, int colorBuffer) { + NSOpenGLContext *nsContext = (NSOpenGLContext*)context; + NSOpenGLPixelBuffer *pBuffer = (NSOpenGLPixelBuffer*)buffer; + + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [nsContext setTextureImageToPixelBuffer: pBuffer + colorBuffer: (unsigned long) colorBuffer]; + [pool release]; +} + +#include <mach-o/dyld.h> +Bool imagesInitialized = false; +static char libGLStr[] = "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"; +static char libGLUStr[] = "/System/Library/Frameworks/OpenGL.framework/Libraries/libGLU.dylib"; +static const struct mach_header *libGLImage; +static const struct mach_header *libGLUImage; +void* getProcAddress(const char *procname) { + if (imagesInitialized == false) { + imagesInitialized = true; + unsigned long options = NSADDIMAGE_OPTION_RETURN_ON_ERROR; + libGLImage = NSAddImage(libGLStr, options); + libGLUImage = NSAddImage(libGLUStr, options); + } + + unsigned long options = NSLOOKUPSYMBOLINIMAGE_OPTION_BIND | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR; + char underscoreName[512] = "_"; + strcat(underscoreName, procname); + + if (NSIsSymbolNameDefinedInImage(libGLImage, underscoreName) == YES) { + NSSymbol sym = NSLookupSymbolInImage(libGLImage, underscoreName, options); + return NSAddressOfSymbol(sym); + } + + if (NSIsSymbolNameDefinedInImage(libGLUImage, underscoreName) == YES) { + NSSymbol sym = NSLookupSymbolInImage(libGLUImage, underscoreName, options); + return NSAddressOfSymbol(sym); + } + + if (NSIsSymbolNameDefinedWithHint(underscoreName, "GL")) { + NSSymbol sym = NSLookupAndBindSymbol(underscoreName); + return NSAddressOfSymbol(sym); + } + + return NULL; +} + +void setSwapInterval(void* context, int interval) { + NSOpenGLContext *nsContext = (NSOpenGLContext*)context; + long swapInterval = interval; + [nsContext setValues: &swapInterval forParameter: NSOpenGLCPSwapInterval]; +} + +Bool setGammaRamp(int tableSize, float* redRamp, float* greenRamp, float* blueRamp) { + CGDisplayErr err = CGSetDisplayTransferByTable(kCGDirectMainDisplay, tableSize, redRamp, greenRamp, blueRamp); + return (err == CGDisplayNoErr); +} + +void resetGammaRamp() { + CGDisplayRestoreColorSyncSettings(); +} diff --git a/src/jogl/native/openmax/com_sun_openmax_OMXInstance.c b/src/jogl/native/openmax/com_sun_openmax_OMXInstance.c new file mode 100644 index 000000000..c763b0dd6 --- /dev/null +++ b/src/jogl/native/openmax/com_sun_openmax_OMXInstance.c @@ -0,0 +1,255 @@ +/* + * 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_openmax_OMXInstance.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); + } +} + +void java_throwNewRuntimeException(intptr_t jni_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); + if(jni_env!=0) { + (*((JNIEnv *)jni_env))->ThrowNew((JNIEnv *)jni_env, runtimeExceptionClz, buffer); + } +} + +void OMXInstance_SaveJavaAttributes(OMXToolBasicAV_t *pOMXAV, KDboolean issueJavaCallback) +{ + if(NULL==pOMXAV || 0==pOMXAV->jni_env || 0==pOMXAV->jni_instance) { + fprintf(stderr, "OMXInstance_SaveJavaAttributes failed"); + return; + } else if(issueJavaCallback==KD_TRUE) { + JNIEnv * env = (JNIEnv *)pOMXAV->jni_env; + jobject instance = (jobject)pOMXAV->jni_instance; + (*env)->CallVoidMethod(env, instance, (jmethodID)pOMXAV->jni_mid_saveAttributes); + } +} + +void OMXInstance_UpdateJavaAttributes(OMXToolBasicAV_t *pOMXAV, KDboolean issueJavaCallback) +{ + if(NULL==pOMXAV || 0==pOMXAV->jni_env || 0==pOMXAV->jni_instance) { + fprintf(stderr, "OMXInstance_UpdateJavaAttributes failed"); + return; + } else { + JNIEnv * env = (JNIEnv *)pOMXAV->jni_env; + jobject instance = (jobject)pOMXAV->jni_instance; + (*env)->SetIntField(env, instance, (jfieldID)pOMXAV->jni_fid_width, (jint)pOMXAV->width); + (*env)->SetIntField(env, instance, (jfieldID)pOMXAV->jni_fid_height, (jint)pOMXAV->height); + (*env)->SetIntField(env, instance, (jfieldID)pOMXAV->jni_fid_fps, (jint)pOMXAV->framerate); + (*env)->SetLongField(env, instance, (jfieldID)pOMXAV->jni_fid_bps, (jlong)pOMXAV->bitrate); + (*env)->SetLongField(env, instance, (jfieldID)pOMXAV->jni_fid_totalFrames, (jlong)(pOMXAV->length*pOMXAV->framerate)); + if(issueJavaCallback==KD_TRUE) { + (*env)->CallVoidMethod(env, instance, (jmethodID)pOMXAV->jni_mid_attributesUpdated); + } else { + if(strlen(pOMXAV->videoCodec)>0) { + (*env)->SetObjectField(env, instance, (jfieldID)pOMXAV->jni_fid_vcodec, (*env)->NewStringUTF(env, pOMXAV->videoCodec)); + } + if(strlen(pOMXAV->audioCodec)>0) { + (*env)->SetObjectField(env, instance, (jfieldID)pOMXAV->jni_fid_acodec, (*env)->NewStringUTF(env, pOMXAV->audioCodec)); + } + } + } +} + +JNIEXPORT jlong JNICALL Java_com_sun_openmax_OMXInstance__1createInstance + (JNIEnv *env, jobject instance) +{ + OMXToolBasicAV_t * pOMXAV; + + _initStatics(env); + + pOMXAV->jni_env=(intptr_t)env; + pOMXAV->jni_instance=(intptr_t)instance; + + pOMXAV = OMXToolBasicAV_CreateInstance((intptr_t)env, (intptr_t)instance); + if(NULL!=pOMXAV) { + jclass cls = (*env)->GetObjectClass(env, instance); + pOMXAV->jni_mid_saveAttributes = (intptr_t) (*env)->GetMethodID(env, cls, "saveAttributes", "()V"); + pOMXAV->jni_mid_attributesUpdated = (intptr_t) (*env)->GetMethodID(env, cls, "attributesUpdated", "()V"); + pOMXAV->jni_fid_width = (intptr_t) (*env)->GetFieldID(env, cls, "width", "I"); + pOMXAV->jni_fid_height = (intptr_t) (*env)->GetFieldID(env, cls, "height", "I"); + pOMXAV->jni_fid_fps = (intptr_t) (*env)->GetFieldID(env, cls, "fps", "I"); + pOMXAV->jni_fid_bps = (intptr_t) (*env)->GetFieldID(env, cls, "bps", "J"); + pOMXAV->jni_fid_totalFrames = (intptr_t) (*env)->GetFieldID(env, cls, "totalFrames", "J"); + pOMXAV->jni_fid_acodec = (intptr_t) (*env)->GetFieldID(env, cls, "acodec", "Ljava/lang/String;"); + pOMXAV->jni_fid_vcodec = (intptr_t) (*env)->GetFieldID(env, cls, "vcodec", "Ljava/lang/String;"); + } + + return (jlong) (intptr_t) (void *)pOMXAV; +} + +JNIEXPORT void JNICALL Java_com_sun_openmax_OMXInstance__1setStream + (JNIEnv *env, jobject instance, jlong ptr, jint vBufferNum, jstring jpath) +{ + jboolean iscopy; + OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); + + 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 + pOMXAV->jni_env=(intptr_t)env; + pOMXAV->jni_instance=(intptr_t)instance; + OMXToolBasicAV_SetStream(pOMXAV, vBufferNum, filePath); + (*env)->ReleaseStringChars(env, jpath, (const jchar *)filePath); + } + fprintf(stdout, "setStream 3 ..\n"); fflush(stdout); // JAU +} + +JNIEXPORT void JNICALL Java_com_sun_openmax_OMXInstance__1setStreamEGLImageTexture2D + (JNIEnv *env, jobject instance, jlong ptr, jint i, jint tex, jlong image, jlong sync) +{ + OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); + if (pOMXAV != NULL) { + OMXToolBasicAV_SetStreamEGLImageTexture2D( pOMXAV, i, (GLuint) tex, + (EGLImageKHR)(intptr_t)image, + (EGLSyncKHR)(intptr_t)sync); + } +} + +JNIEXPORT void JNICALL Java_com_sun_openmax_OMXInstance__1activateStream + (JNIEnv *env, jobject instance, jlong ptr) +{ + OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); + + if (pOMXAV != NULL) { + OMXToolBasicAV_ActivateStream(pOMXAV); + } +} + +JNIEXPORT void JNICALL Java_com_sun_openmax_OMXInstance__1attachVideoRenderer + (JNIEnv *env, jobject instance, jlong ptr) +{ + OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); + OMXToolBasicAV_AttachVideoRenderer(pOMXAV); +} + +JNIEXPORT void JNICALL Java_com_sun_openmax_OMXInstance__1detachVideoRenderer + (JNIEnv *env, jobject instance, jlong ptr) +{ + OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); + OMXToolBasicAV_DetachVideoRenderer(pOMXAV); +} + +JNIEXPORT void JNICALL Java_com_sun_openmax_OMXInstance__1setPlaySpeed + (JNIEnv *env, jobject instance, jlong ptr, jfloat scale) +{ + OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); + OMXToolBasicAV_SetPlaySpeed(pOMXAV, scale); +} + +JNIEXPORT jfloat JNICALL Java_com_sun_openmax_OMXInstance__1play + (JNIEnv *env, jobject instance, jlong ptr) +{ + OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); + OMXToolBasicAV_PlayStart(pOMXAV); + return OMXToolBasicAV_GetCurrentPosition(pOMXAV); +} + +JNIEXPORT jfloat JNICALL Java_com_sun_openmax_OMXInstance__1pause + (JNIEnv *env, jobject instance, jlong ptr) +{ + OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); + OMXToolBasicAV_PlayPause(pOMXAV); + return OMXToolBasicAV_GetCurrentPosition(pOMXAV); +} + +JNIEXPORT jfloat JNICALL Java_com_sun_openmax_OMXInstance__1stop + (JNIEnv *env, jobject instance, jlong ptr) +{ + OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); + OMXToolBasicAV_PlayStop(pOMXAV); + return OMXToolBasicAV_GetCurrentPosition(pOMXAV); +} + +JNIEXPORT jfloat JNICALL Java_com_sun_openmax_OMXInstance__1seek + (JNIEnv *env, jobject instance, jlong ptr, jfloat pos) +{ + OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); + OMXToolBasicAV_PlaySeek(pOMXAV, pos); + return OMXToolBasicAV_GetCurrentPosition(pOMXAV); +} + +JNIEXPORT jint JNICALL Java_com_sun_openmax_OMXInstance__1getNextTextureID + (JNIEnv *env, jobject instance, jlong ptr) +{ + jint textureID = 0xffffffff; + OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); + if (pOMXAV != NULL) { + textureID = OMXToolBasicAV_GetNextTextureID(pOMXAV); + } + return textureID; +} + +JNIEXPORT jfloat JNICALL Java_com_sun_openmax_OMXInstance__1getCurrentPosition + (JNIEnv *env, jobject instance, jlong ptr) +{ + OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); + return OMXToolBasicAV_GetCurrentPosition(pOMXAV); +} + + +JNIEXPORT void JNICALL Java_com_sun_openmax_OMXInstance__1destroyInstance + (JNIEnv *env, jobject instance, jlong ptr) +{ + OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); + if (pOMXAV != NULL) { + OMXToolBasicAV_DestroyInstance(pOMXAV); + } +} + + diff --git a/src/jogl/native/openmax/omx_tool.c b/src/jogl/native/openmax/omx_tool.c new file mode 100644 index 000000000..e9633af1b --- /dev/null +++ b/src/jogl/native/openmax/omx_tool.c @@ -0,0 +1,1713 @@ + +#include "omx_tool.h" + +#define VERBOSE_ON 1 +#define VERBOSE2_ON 1 + +#ifdef VERBOSE_ON + #define DBG_PRINT(...) fprintf(stdout, __VA_ARGS__) +#else + #define DBG_PRINT(...) +#endif + +#if defined(VERBOSE_ON) && defined(VERBOSE2_ON) + #define DBG_PRINT2(...) fprintf(stdout, __VA_ARGS__) +#else + #define DBG_PRINT2(...) +#endif + +#ifdef VERBOSE_ON + #ifdef _WIN32_WCE + #define STDOUT_FILE "\\Storage Card\\stdout.txt" + #define STDERR_FILE "\\Storage Card\\stderr.txt" + #endif +#endif + +#include <NVOMX_IndexExtensions.h> + +#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) + +void OMXInstance_SaveJavaAttributes(OMXToolBasicAV_t *pOMXAV, KDboolean issueJavaCallback); +void OMXInstance_UpdateJavaAttributes(OMXToolBasicAV_t *pOMXAV, KDboolean issueJavaCallback); + +#if !defined(SELF_TEST) +void java_throwNewRuntimeException(intptr_t jni_env, const char* format, ...); +#else +#include <stdarg.h> +void java_throwNewRuntimeException(intptr_t jni_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; + DBG_PRINT( "RuntimeException: %s\n", buffer); + exit(1); +} +#endif +static void DestroyInstanceUnlock(OMXToolBasicAV_t * pOMXAV); + +#define OMXSAFEVOID(x) \ +do { \ + OMX_ERRORTYPE err = (x); \ + if (err != OMX_ErrorNone) { \ + java_throwNewRuntimeException((NULL!=pOMXAV)?pOMXAV->jni_env:0, "FAILED at %s:%d, Error: 0x%x\n", __FILE__, __LINE__, err); \ + if(NULL!=pOMXAV) { \ + DestroyInstanceUnlock(pOMXAV); \ + } \ + return; \ + } \ +} while (0); + +#define OMXSAFE(x) \ +do { \ + OMX_ERRORTYPE err = (x); \ + if (err != OMX_ErrorNone) { \ + java_throwNewRuntimeException((NULL!=pOMXAV)?pOMXAV->jni_env:0, "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!=pOMXAV)?pOMXAV->jni_env:0, "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; + +#ifdef VERBOSE_ON + #ifdef _WIN32_WCE + _wfreopen(TEXT(STDOUT_FILE),L"w",stdout); + _wfreopen(TEXT(STDERR_FILE),L"w",stderr); + #endif +#endif + + _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; + } + + OMX_Init(); +} + +static void Invalidate(OMXToolBasicAV_t * pOMXAV) +{ + DBG_PRINT("INVALIDATE\n"); + 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 UpdateStreamInfo(OMXToolBasicAV_t * pOMXAV, KDboolean issueCallback); + +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: + { + DBG_PRINT("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) { + DBG_PRINT("\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) + { + DBG_PRINT("\t flush\n"); + kdThreadSemPost(pOMXAV->flushSem); + } + break; + } + case OMX_EventBufferFlag: + if (nData2 & OMX_BUFFERFLAG_EOS) + { + DBG_PRINT("event buffer EOS: component: %p - %s\n", hComponent, name); + if (pOMXAV->endComponent == hComponent) + { + DBG_PRINT("\t end component - FIN\n"); + pOMXAV->status = OMXAV_FIN; + } + } + break; + case OMX_EventError: + { + if (nData1 == OMX_ErrorIncorrectStateTransition) + { + DBG_PRINT("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) + { + DBG_PRINT("event error: Same State 0x%X, component: %p - %s\n", (unsigned int) nData2, hComponent, name); + } + else + { + DBG_PRINT("event error: 0x%X, component: %p - %s\n", (unsigned int) nData1, hComponent, name); + Invalidate(pOMXAV); + } + } + break; + case OMX_EventPortSettingsChanged: + { + (void) UpdateStreamInfo(pOMXAV, (pOMXAV->status>OMXAV_INIT)?KD_TRUE:KD_FALSE); + } + 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++; + DBG_PRINT("FillBufferDone avail %d\n", pOMXAV->available); + + 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; + + DBG_PRINT( "WaitForState p1 c:%p s1:0x%X s2:0x%X\n", hComponent, eTestState, eTestState2); + eError = OMX_GetState(hComponent, &eState); + DBG_PRINT( "WaitForState p2 s:0x%X e:0x%X\n", eState, eError); + + while (loop>0 && + OMX_ErrorNone == eError && + eState != eTestState && + eState != eTestState2) + { + usleep(STATE_SLEEP*1000); + loop--; + + eError = OMX_GetState(hComponent, &eState); + DBG_PRINT( "WaitForState p3 s:0x%X e:0x%X\n", eState, eError); + } + + 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; + DBG_PRINT( "OMXToolBasicAV_WaitForState %p s:%d\n", pOMXAV, state); + if(NULL==pOMXAV) { + DBG_PRINT( "OMXToolBasicAV_WaitForState p1\n"); + return -1; + } + + for(i=0; i<OMXAV_H_NUMBER; i++) { + if(0!=pOMXAV->comp[i]) { + DBG_PRINT( "OMXToolBasicAV_WaitForState p4 %d c:%p\n", i, pOMXAV->comp[i]); + if( 0!=(res=SyncOnState(pOMXAV->comp[i], state)) ) { + KDchar name[128]; + GetComponentName(pOMXAV->comp[i], name, 128); + DBG_PRINT( "OMXToolBasicAV_WaitForState Failed (Wait) %d c:%p - %s, s:0x%X\n", + i, pOMXAV->comp[i], name, state); + 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); + DBG_PRINT( "RequestState p2 c:%p, e:0x%X, s:0x%X\n", + hComponent, eError, eState); + // Skip StateSet in case the state is already reached .. + if(OMX_ErrorNone != eError || eState!=state) { + eError = OMX_SendCommand(hComponent, OMX_CommandStateSet, state, 0); + DBG_PRINT( "RequestState p3 c:%p e:0x%X s: 0x%X -> 0x%X\n", + hComponent, eError, eState, state); + 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; + DBG_PRINT( "OMXToolBasicAV_RequestState %p s:%d, w:%d\n", pOMXAV, state, wait); + if(NULL==pOMXAV) { + DBG_PRINT( "OMXToolBasicAV_RequestState p1\n"); + 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; + + DBG_PRINT( "Destroy p1\n"); + PlayStop(pOMXAV); + + DBG_PRINT( "Destroy p2\n"); + if(0!=(res1=OMXToolBasicAV_RequestState(pOMXAV, OMX_StateIdle, KD_TRUE))) + { + java_throwNewRuntimeException(pOMXAV->jni_env, "Destroy - Wait for Idle Failed (%d)", res1); + } + + DBG_PRINT( "Destroy p3\n"); + SendCommand(pOMXAV, OMX_CommandPortDisable, OMX_ALL, 0); // Ignore error .. + + DBG_PRINT( "Destroy p3\n"); + DetachVideoRenderer(pOMXAV); + + DBG_PRINT( "Destroy p4\n"); + if(0!=(res2=OMXToolBasicAV_RequestState(pOMXAV, OMX_StateLoaded, KD_TRUE))) + { + if(!res1) { + java_throwNewRuntimeException(pOMXAV->jni_env, "Destroy - Wait for Loaded Failed (%d)", res2); + } + } + + DBG_PRINT( "Destroy p5\n"); + 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) { + DBG_PRINT( "Destroy p6\n"); + kdThreadSemFree(pOMXAV->flushSem); + pOMXAV->flushSem=0; + } + if(0!=pOMXAV->mutex) { + DBG_PRINT( "Destroy p7\n"); + kdThreadMutexUnlock(pOMXAV->mutex); + DBG_PRINT( "Destroy p8\n"); + kdThreadMutexFree(pOMXAV->mutex); + pOMXAV->mutex=0; + } + + DBG_PRINT( "Destroy DONE\n"); + + 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 *codec, KDchar* component) +{ + // FIXME: Non NV case .. + 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 && + oPortDef.eDomain != OMX_PortDomainAudio) { + 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; + } + + { + KDchar ocodec[256]; + OMX_U8 *tmp = (OMX_U8*) kdMalloc(OMX_MAX_STRINGNAME_SIZE + 1); + kdMemset(tmp, 0, sizeof(OMX_U8) * (OMX_MAX_STRINGNAME_SIZE + 1)); + + if (oPortDef.eDomain == OMX_PortDomainVideo) + kdStrcpy_s(ocodec, 128, "video_decoder."); + else if (oPortDef.eDomain == OMX_PortDomainAudio) + kdStrcpy_s(ocodec, 128, "audio_decoder."); + kdStrncat_s(ocodec, 128, codec, kdStrlen(codec)); + + err = OMX_GetComponentsOfRole(codec, &roles, &tmp); + kdStrcpy_s(component, 256, (KDchar*) tmp); + kdFree(tmp); + printf("%s(%s) -> %s\n", ocodec, codec, component); + } + + return err != OMX_ErrorNone ? err : roles ? OMX_ErrorNone : OMX_ErrorComponentNotFound; +} + +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) + { + DBG_PRINT( "Play 3.2\n"); + usleep(STATE_SLEEP*1000); + loop--; + eError = OMX_SetConfig(pOMXAV->comp[OMXAV_H_CLOCK], OMX_IndexConfigTimeClockState, + &oClockState); + } + return (OMX_ErrorNotReady == eError)?-1:0; +} + +static KDfloat32 GetClockPosition(OMXToolBasicAV_t * pOMXAV) +{ + OMX_TIME_CONFIG_TIMESTAMPTYPE stamp; + INIT_PARAM(stamp); + stamp.nPortIndex = 0; + + OMX_GetConfig(pOMXAV->comp[OMXAV_H_CLOCK], OMX_IndexConfigTimeCurrentMediaTime, &stamp); + return (KDfloat32) (stamp.nTimestamp * (1.0f/(1000.0f*1000.0f))); +} + +static KDfloat32 GetClockScale(OMXToolBasicAV_t * pOMXAV) +{ + OMX_TIME_CONFIG_SCALETYPE pScale; + INIT_PARAM(pScale); + + OMX_GetConfig(pOMXAV->comp[OMXAV_H_CLOCK], OMX_IndexConfigTimeScale, &pScale); + return (pScale.xScale / 65536.0f); +} + +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 SetMediaPosition(OMXToolBasicAV_t * pOMXAV, KDfloat32 time) { + OMX_ERRORTYPE eError = OMX_ErrorNone; + 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); + } + return (OMX_ErrorNotReady == eError)?-1:0; +} + +static KDfloat32 GetMediaLength(OMXToolBasicAV_t * pOMXAV) +{ + NVX_PARAM_DURATION oDuration; + OMX_INDEXTYPE eParam; + + if (OMX_ErrorNone != OMX_GetExtensionIndex(pOMXAV->comp[OMXAV_H_READER], NVX_INDEX_PARAM_DURATION, &eParam)) + return -1.0f; + + if (OMX_ErrorNone != OMX_GetParameter(pOMXAV->comp[OMXAV_H_READER], eParam, &oDuration)) + return -1.0f; + + return (KDfloat32) (oDuration.nDuration * (1.0f/(1000.0f*1000.0f))); +} + +static OMX_ERRORTYPE UpdateStreamInfo(OMXToolBasicAV_t * pOMXAV, KDboolean issueCallback) +{ + OMX_ERRORTYPE err = OMX_ErrorNone; + OMX_PARAM_PORTDEFINITIONTYPE oPortDef; + + DBG_PRINT( "Update StreamInfo p0\n" ); + + kdMemset(&oPortDef, 0, sizeof(oPortDef)); + oPortDef.nSize = sizeof(oPortDef); + oPortDef.nVersion.s.nVersionMajor = 1; + oPortDef.nVersion.s.nVersionMinor = 1; + oPortDef.nPortIndex = 0; + err = OMX_GetParameter(pOMXAV->comp[OMXAV_H_READER], OMX_IndexParamPortDefinition, &oPortDef); + if(OMX_ErrorNone!=err) { + fprintf(stderr, "UpdateStreamInfo failed - p1 0x%X", err); + return err; + } + + 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; + err = OMX_GetParameter(pOMXAV->comp[OMXAV_H_READER], OMX_IndexParamPortDefinition, &oPortDef); + if(OMX_ErrorNone!=err) { + fprintf(stderr, "UpdateStreamInfo failed - p2 0x%X", err); + return err; + } + } + + DBG_PRINT( "Update StreamInfo p1\n" ); + OMXInstance_SaveJavaAttributes(pOMXAV, issueCallback); + + pOMXAV->width = oPortDef.format.video.nFrameWidth; + pOMXAV->height = oPortDef.format.video.nFrameHeight; + /* pOMXAV->stride = oPortDef.format.video.nStride; + pOMXAV->sliceHeight = oPortDef.format.video.nSliceHeight; */ + pOMXAV->framerate = oPortDef.format.video.xFramerate; + pOMXAV->bitrate = oPortDef.format.video.nBitrate; + DBG_PRINT( "Update StreamInfo p2 %dx%d, fps %d, bps %d\n", pOMXAV->width, pOMXAV->height, pOMXAV->framerate, pOMXAV->bitrate ); + pOMXAV->length = GetMediaLength(pOMXAV); + pOMXAV->speed = GetClockScale(pOMXAV); + + OMXInstance_UpdateJavaAttributes(pOMXAV, issueCallback); + + return err; +} + +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(pOMXAV->jni_env, "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(pOMXAV->jni_env, "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(pOMXAV->jni_env, "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(pOMXAV->jni_env, "Loading VideoScheduler Failed (%d)", res); + return res; + } + // mandatory before EGLUseImage + OMXSAFE(RequestState(pOMXAV->comp[OMXAV_H_VSCHEDULER], OMX_StateIdle, KD_FALSE)); + + DBG_PRINT( "Attach VR %p c:%p\n", pOMXAV, pOMXAV->comp[OMXAV_H_VSCHEDULER]); + OMXSAFE(UpdateStreamInfo(pOMXAV, KD_FALSE)); + + DBG_PRINT( "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_SetStreamEGLImageTexture2D command. + + DBG_PRINT( "UseEGLImg %p #%d t:%d i:%p s:%p p1\n", pOMXAV, i, pBuf->tex, pBuf->image, pBuf->sync); + + if(NULL==pBuf->image) { + java_throwNewRuntimeException(pOMXAV->jni_env, "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)); + } + DBG_PRINT( "UseEGLImg %p #%d t:%d i:%p s:%p b:%p - p2\n", + pOMXAV, i, pBuf->tex, pBuf->image, pBuf->sync, pBuf->omxBufferHeader); + } + + DBG_PRINT( "UseEGLImg %p #%d DONE\n", pOMXAV, i); + 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(pOMXAV->jni_env, "Attach Video first"); + return -1; + } + DBG_PRINT( "DetachVideoRenderer p0\n"); + if(0==CheckState(pOMXAV->comp[OMXAV_H_VSCHEDULER], OMX_StateLoaded)) { + DBG_PRINT( "DetachVideoRenderer DONE (already state loaded)\n"); + return 0; + } + OMXSAFE(RequestState(pOMXAV->comp[OMXAV_H_VSCHEDULER], OMX_StateIdle, KD_TRUE)); + + DBG_PRINT( "DetachVideoRenderer p1\n"); + 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)); + DBG_PRINT( "DetachVideoRenderer p2\n"); + + 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)); + DBG_PRINT( "DetachVideoRenderer p3\n"); + + OMX_FreeHandle(pOMXAV->comp[OMXAV_H_VSCHEDULER]); + pOMXAV->comp[OMXAV_H_VSCHEDULER]=NULL; + DBG_PRINT( "DetachVideoRenderer DONE\n"); + return 0; +} + +OMXToolBasicAV_t * OMXToolBasicAV_CreateInstance() +{ + int i; + OMXToolBasicAV_t * pOMXAV = NULL; + InitStatic(); + + pOMXAV = malloc(sizeof(OMXToolBasicAV_t)); + if(NULL==pOMXAV) { + DBG_PRINT( "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->play_speed = 1.0f; + pOMXAV->status=OMXAV_INIT; + + return pOMXAV; +} + +void OMXToolBasicAV_SetStream(OMXToolBasicAV_t * pOMXAV, int vBufferNum, const KDchar * stream) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + + DBG_PRINT( "SetStream 1 %s ..\n", stream); + + // FIXME: verify player state .. ie stop ! + if(pOMXAV->status!=OMXAV_INIT) { + java_throwNewRuntimeException(pOMXAV->jni_env, "Player instance in use\n"); + return; + } + if(vBufferNum>EGLIMAGE_MAX_BUFFERS) { + java_throwNewRuntimeException(pOMXAV->jni_env, "buffer number %d > MAX(%d)\n", vBufferNum, EGLIMAGE_MAX_BUFFERS); + return; + } + + kdThreadMutexLock(pOMXAV->mutex); + + DBG_PRINT( "SetStream 3\n"); + + pOMXAV->vBufferNum = vBufferNum; + + // 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(pOMXAV->jni_env, "Couldn't open or handle stream: %s\n", stream); + kdThreadMutexUnlock(pOMXAV->mutex); + return; + } + + DBG_PRINT( "SetStream 4\n"); + + // Auto detect codecs + { + OMX_PARAM_PORTDEFINITIONTYPE oPortDef; + INIT_PARAM(oPortDef); + oPortDef.nPortIndex = 0; + pOMXAV->videoPort = -1; + pOMXAV->audioPort = -1; + OMXSAFEVOID(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 + OMXSAFEVOID(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 + OMXSAFEVOID(OMX_ErrorNotImplemented); + } + if (pOMXAV->audioPort != -1) + { + if (ProbePort(pOMXAV, pOMXAV->audioPort, pOMXAV->audioCodec, pOMXAV->audioCodecComponent) != OMX_ErrorNone) + { + printf("disabling audio port\n"); + OMXSAFEVOID(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, pOMXAV->videoCodecComponent) != OMX_ErrorNone) + { + printf("disabling video port\n"); + OMXSAFEVOID(OMX_SendCommand(pOMXAV->comp[OMXAV_H_READER], OMX_CommandPortDisable, pOMXAV->videoPort, 0)); + pOMXAV->videoPort = -1; + } + + if (pOMXAV->audioPort == -1 && pOMXAV->videoPort == -1) + { + java_throwNewRuntimeException(pOMXAV->jni_env, "Neither audioport or videoport could be played back!\n"); + kdThreadMutexUnlock(pOMXAV->mutex); + return; + } + } + DBG_PRINT( "SetStream 5 ; audioPort %d, videoPort %d\n", pOMXAV->audioPort, pOMXAV->videoPort); + + OMXSAFEVOID(OMX_GetHandle(&pOMXAV->comp[OMXAV_H_CLOCK], "OMX.Nvidia.clock.component", pOMXAV, &pOMXAV->callbacks)); + + DBG_PRINT( "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; + OMXSAFEVOID(OMX_SetConfig(pOMXAV->comp[OMXAV_H_CLOCK], OMX_IndexConfigTimeActiveRefClock, + &oActiveClockType)); + } + OMXSAFEVOID(OMX_SendCommand(pOMXAV->comp[OMXAV_H_CLOCK], OMX_CommandPortDisable, (OMX_U32) -1, 0)); + + OMXSAFEVOID(UpdateStreamInfo(pOMXAV, KD_FALSE)); + + kdThreadMutexUnlock(pOMXAV->mutex); + + DBG_PRINT( "SetStream X\n"); +} + +void OMXToolBasicAV_SetStreamEGLImageTexture2D(OMXToolBasicAV_t * pOMXAV, KDint i, GLuint tex, EGLImageKHR image, EGLSyncKHR sync) +{ + if(NULL==pOMXAV) { + java_throwNewRuntimeException(0, "OMX instance null\n"); + return; + } + DBG_PRINT( "SetStreamEGLImg %p #%d/%d t:%d i:%p s:%p..\n", pOMXAV, i, pOMXAV->vBufferNum, tex, image, sync); + if(i<0||i>=pOMXAV->vBufferNum) { + java_throwNewRuntimeException(pOMXAV->jni_env, "Buffer index out of range: %d\n", i); + return; + } + + kdThreadMutexLock(pOMXAV->mutex); + { + OMXToolImageBuffer_t *pBuf = &pOMXAV->buffers[i]; + pBuf->tex=tex; + pBuf->image=image; + pBuf->sync=sync; + + } + kdThreadMutexUnlock(pOMXAV->mutex); +} + +void OMXToolBasicAV_ActivateStream(OMXToolBasicAV_t * pOMXAV) { + int res; + if(NULL==pOMXAV) { + java_throwNewRuntimeException(0, "OMX instance null\n"); + return; + } + DBG_PRINT( "ActivateStream 1\n"); + + kdThreadMutexLock(pOMXAV->mutex); + + if (pOMXAV->audioPort != -1) + { + OMXSAFEVOID(OMX_GetHandle(&pOMXAV->comp[OMXAV_H_ADECODER], pOMXAV->audioCodecComponent, pOMXAV, &pOMXAV->callbacks)); + } + + if (pOMXAV->videoPort != -1) + { + OMXSAFEVOID(OMX_GetHandle(&pOMXAV->comp[OMXAV_H_VDECODER], pOMXAV->videoCodecComponent, 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(pOMXAV->jni_env, "Loaded Failed (%d)", res); + kdThreadMutexUnlock(pOMXAV->mutex); + return; + } + + if (pOMXAV->audioPort != -1) + { + if(0!=(res=AttachAudioRenderer(pOMXAV))) { + kdThreadMutexUnlock(pOMXAV->mutex); + return; // exception thrown + } + } + + if (pOMXAV->videoPort != -1) + { + if(0!=(res=AttachVideoRenderer(pOMXAV))) { + kdThreadMutexUnlock(pOMXAV->mutex); + return; // exception thrown + } + } + + DBG_PRINT( "Setup tunneling\n"); + { + // do tunneling + if (pOMXAV->audioPort != -1) + { + DBG_PRINT( "Setup tunneling audio\n"); + OMXSAFEVOID(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) + { + DBG_PRINT( "Setup tunneling video\n"); + OMXSAFEVOID(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 + } + } + DBG_PRINT( "ActivateStream .. %p\n", pOMXAV); + + // + // 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(pOMXAV->jni_env, "Wait for Idle Failed (%d)", res); + kdThreadMutexUnlock(pOMXAV->mutex); + return; + } + pOMXAV->status=OMXAV_STOPPED; + kdThreadMutexUnlock(pOMXAV->mutex); + DBG_PRINT( "ActivateStream done %p\n", pOMXAV); +} + +void OMXToolBasicAV_DetachVideoRenderer(OMXToolBasicAV_t * pOMXAV) { + if(NULL==pOMXAV) { + java_throwNewRuntimeException(0, "OMX instance null\n"); + return; + } + if(pOMXAV->status<=OMXAV_INIT) { + java_throwNewRuntimeException(pOMXAV->jni_env, "OMX invalid status: %d <= INIT\n", pOMXAV->status); + return; + } + kdThreadMutexLock(pOMXAV->mutex); + + (void) DetachVideoRenderer(pOMXAV); + + kdThreadMutexUnlock(pOMXAV->mutex); +} + +void OMXToolBasicAV_AttachVideoRenderer(OMXToolBasicAV_t * pOMXAV) { + if(NULL==pOMXAV) { + java_throwNewRuntimeException(0, "OMX instance null\n"); + return; + } + if(pOMXAV->status<=OMXAV_INIT) { + java_throwNewRuntimeException(pOMXAV->jni_env, "OMX invalid status: %d <= INIT\n", pOMXAV->status); + return; + } + kdThreadMutexLock(pOMXAV->mutex); + + (void) AttachVideoRenderer(pOMXAV); + + kdThreadMutexUnlock(pOMXAV->mutex); +} + +void OMXToolBasicAV_SetPlaySpeed(OMXToolBasicAV_t * pOMXAV, KDfloat32 scale) +{ + if(NULL==pOMXAV) { + java_throwNewRuntimeException(0, "OMX instance null\n"); + return; + } + if(pOMXAV->status<=OMXAV_INIT) { + java_throwNewRuntimeException(pOMXAV->jni_env, "OMX invalid status: %d <= INIT\n", pOMXAV->status); + return; + } + kdThreadMutexLock(pOMXAV->mutex); + + if(!SetClockScale(pOMXAV, scale)) { + pOMXAV->play_speed=scale; + } + + kdThreadMutexUnlock(pOMXAV->mutex); +} + + +void OMXToolBasicAV_PlayStart(OMXToolBasicAV_t * pOMXAV) +{ + int res; + if(NULL==pOMXAV) { + java_throwNewRuntimeException(0, "OMX instance null\n"); + return; + } + if(pOMXAV->status<=OMXAV_INIT) { + java_throwNewRuntimeException(pOMXAV->jni_env, "OMX invalid status: %d <= INIT\n", pOMXAV->status); + return; + } + if(pOMXAV->status==OMXAV_PLAYING) { + return; + } + + kdThreadMutexLock(pOMXAV->mutex); + DBG_PRINT( "Play 2\n"); + + SetClockScale(pOMXAV, pOMXAV->play_speed); + + DBG_PRINT( "Play 3.1\n"); + if(0!=(res=OMXToolBasicAV_RequestState(pOMXAV, OMX_StateExecuting, KD_TRUE))) { + java_throwNewRuntimeException(pOMXAV->jni_env, "Play Execute Failed (%d)", res); + kdThreadMutexUnlock(pOMXAV->mutex); + return; + } + if(pOMXAV->status==OMXAV_STOPPED || pOMXAV->status==OMXAV_FIN) { + DBG_PRINT( "Play 3.2\n"); + if(StartClock(pOMXAV, KD_TRUE, 0.0)) { + java_throwNewRuntimeException(pOMXAV->jni_env, "Play StartClock Failed"); + kdThreadMutexUnlock(pOMXAV->mutex); + return; + } + } + DBG_PRINT( "Play 4.0\n"); + + kdThreadMutexUnlock(pOMXAV->mutex); + pOMXAV->status=OMXAV_PLAYING; + DBG_PRINT( "Play DONE\n"); +} + +static int PlayStop(OMXToolBasicAV_t * pOMXAV) +{ + int res; + if(NULL==pOMXAV || pOMXAV->status<=OMXAV_INIT) { + return -1; + } + if( pOMXAV->status!=OMXAV_PLAYING && pOMXAV->status!=OMXAV_PAUSED ) { + return -1; + } + + if(OMXToolBasicAV_CheckState(pOMXAV, OMX_StateLoaded)) { + if(StartClock(pOMXAV, KD_FALSE, 0.0)) { + java_throwNewRuntimeException(pOMXAV->jni_env, "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(pOMXAV->jni_env, "Stop Idle Failed (%d)", res); + kdThreadMutexUnlock(pOMXAV->mutex); + return res; + } + } + } + pOMXAV->status=OMXAV_STOPPED; + return 0; +} + +void OMXToolBasicAV_PlayStop(OMXToolBasicAV_t * pOMXAV) +{ + if(NULL==pOMXAV) { + java_throwNewRuntimeException(0, "OMX instance null\n"); + return; + } + if(pOMXAV->status<=OMXAV_INIT) { + java_throwNewRuntimeException(pOMXAV->jni_env, "OMX invalid status: %d <= INIT\n", pOMXAV->status); + return; + } + kdThreadMutexLock(pOMXAV->mutex); + + (void) PlayStop(pOMXAV); + + kdThreadMutexUnlock(pOMXAV->mutex); +} + +void OMXToolBasicAV_PlayPause(OMXToolBasicAV_t * pOMXAV) +{ + int res; + if(NULL==pOMXAV) { + java_throwNewRuntimeException(0, "OMX instance null\n"); + return; + } + if(pOMXAV->status<=OMXAV_INIT) { + java_throwNewRuntimeException(pOMXAV->jni_env, "OMX invalid status: %d <= INIT\n", pOMXAV->status); + return; + } + if(pOMXAV->status==OMXAV_PAUSED || pOMXAV->status!=OMXAV_PLAYING) { + return; + } + + 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; + } + pOMXAV->status=OMXAV_PAUSED; + kdThreadMutexUnlock(pOMXAV->mutex); +} + +void OMXToolBasicAV_PlaySeek(OMXToolBasicAV_t * pOMXAV, KDfloat32 time) +{ + int res; + + if(NULL==pOMXAV) { + java_throwNewRuntimeException(0, "OMX instance null\n"); + return; + } + if(pOMXAV->status<=OMXAV_INIT) { + java_throwNewRuntimeException(pOMXAV->jni_env, "OMX invalid status: %d <= INIT\n", pOMXAV->status); + return; + } + kdThreadMutexLock(pOMXAV->mutex); + + pOMXAV->length = GetMediaLength(pOMXAV); + if(pOMXAV->length<=time) { + (void) PlayStop(pOMXAV); + kdThreadMutexUnlock(pOMXAV->mutex); + return; + } + + // 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))) { + java_throwNewRuntimeException(pOMXAV->jni_env, "Seek Pause Failed (%d)", res); + kdThreadMutexUnlock(pOMXAV->mutex); + return; + } + } + + // 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(pOMXAV->jni_env, "Seek StopClock Failed"); + kdThreadMutexUnlock(pOMXAV->mutex); + return; + } + + // 3. Seek to the desired location through the use of OMX_SetConfig on + // OMX_IndexConfigTimePosition requesting the desired timestamp. + if(SetMediaPosition(pOMXAV, time)) { + java_throwNewRuntimeException(pOMXAV->jni_env, "Seek position Failed"); + kdThreadMutexUnlock(pOMXAV->mutex); + return; + } + + // 4. Flush all components. + if(SendCommand(pOMXAV, OMX_CommandFlush, OMX_ALL, 0)) { + java_throwNewRuntimeException(pOMXAV->jni_env, "Seek Flush Failed"); + kdThreadMutexUnlock(pOMXAV->mutex); + return; + } + + // 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(pOMXAV->jni_env, "Seek StartClock Failed"); + kdThreadMutexUnlock(pOMXAV->mutex); + return; + } + + // 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))) { + java_throwNewRuntimeException(pOMXAV->jni_env, "Seek Execute Failed (%d)", res); + kdThreadMutexUnlock(pOMXAV->mutex); + return; + } + } + kdThreadMutexUnlock(pOMXAV->mutex); +} + +GLuint OMXToolBasicAV_GetNextTextureID(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; + + DBG_PRINT2("GetNextTexture A avail %d, filled %d, pos o:%d g:%d\n", + pOMXAV->available, pOMXAV->filled, pOMXAV->omxPos, pOMXAV->glPos); + + while (pOMXAV->filled < pOMXAV->vBufferNum) + { + int attr; + if ( !_hasEGLSync || ( + eglGetSyncAttribKHR(pOMXAV->buffers[pOMXAV->omxPos].sync, EGL_SYNC_STATUS_KHR, &attr) && + attr == EGL_SIGNALED_KHR ) + ) + { + DBG_PRINT2( "GetNextTexture p2.1 attr 0x%X\n", attr); + // 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); + DBG_PRINT2( "GetNextTexture p2.2\n"); + pOMXAV->omxPos = next; + next = (pOMXAV->omxPos + 1) % pOMXAV->vBufferNum; + pOMXAV->filled++; + } + else + { + DBG_PRINT2( "GetNextTexture p2.3\n"); + break; + } + } + } + if (pOMXAV->available > 1) + { + DBG_PRINT2("GetNextTexture p3.1\n"); + // 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)) + { + DBG_PRINT2( "GetNextTexture p3.2\n"); + pOMXAV->available--; + pOMXAV->filled--; + pOMXAV->glPos = (pOMXAV->glPos + 1) % pOMXAV->vBufferNum; + ret = pOMXAV->glPos; + } + } + + texID = pOMXAV->available ? pOMXAV->buffers[ret].tex : 0; + DBG_PRINT2( "GetNextTexture B avail %d, filled %d, pos o:%d g:%d t:%d\n", + pOMXAV->available, pOMXAV->filled, pOMXAV->omxPos, pOMXAV->glPos, texID); + + kdThreadMutexUnlock(pOMXAV->mutex); + return texID; +} + +KDfloat32 OMXToolBasicAV_GetCurrentPosition(OMXToolBasicAV_t * pOMXAV) { + KDfloat32 res = -1.0f; + if(NULL==pOMXAV) { + java_throwNewRuntimeException(0, "OMX instance null\n"); + return res; + } + if(pOMXAV->status<=OMXAV_INIT) { + java_throwNewRuntimeException(pOMXAV->jni_env, "OMX invalid status: %d <= INIT\n", pOMXAV->status); + return res; + } + kdThreadMutexLock(pOMXAV->mutex); + + res = GetClockPosition(pOMXAV); + + kdThreadMutexUnlock(pOMXAV->mutex); + + return res; +} + +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; + +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]; + + /* + * 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_SetStreamEGLImageTexture2D(pOMXAV, i, tex, image, sync)) { + return -1; + } + } + + printf("7\n"); + if( OMXToolBasicAV_ActivateStream(pOMXAV) ) { + return -1; + } + + printf("8\n"); + if( OMXToolBasicAV_PlayStart(pOMXAV) ) { + return -1; + } + + printf("8.2\n"); + + i = 0; + while (i++ < 10) { + glClear(GL_COLOR_BUFFER_BIT); + // set uniforms + // set attributes + // draw arrays .. + eglSwapBuffers(eglDisplay, eglWindowSurface); + printf("Sleep %d\n", i); + 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/jogl/native/openmax/omx_tool.h b/src/jogl/native/openmax/omx_tool.h new file mode 100644 index 000000000..9c0df93b3 --- /dev/null +++ b/src/jogl/native/openmax/omx_tool.h @@ -0,0 +1,165 @@ + +#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 audioCodecComponent[256]; + KDchar videoCodec[256]; + KDchar videoCodecComponent[256]; + int audioPort; + int videoPort; + KDuint32 width; + KDuint32 height; + KDuint32 bitrate; // per seconds + KDuint32 framerate; // per seconds + KDfloat32 length; // seconds + KDfloat32 speed; // current clock scale + KDfloat32 play_speed; // current play clock scale + + KDThreadMutex * mutex; + KDThreadSem * flushSem; + + OMXToolImageBuffer_t buffers[EGLIMAGE_MAX_BUFFERS]; + int vBufferNum; + int glPos; + int omxPos; + int filled; + int available; + + int status; + + intptr_t jni_env; + intptr_t jni_instance; + intptr_t jni_mid_saveAttributes; + intptr_t jni_mid_attributesUpdated; + intptr_t jni_fid_width; + intptr_t jni_fid_height; + intptr_t jni_fid_fps; + intptr_t jni_fid_bps; + intptr_t jni_fid_totalFrames; + intptr_t jni_fid_acodec; + intptr_t jni_fid_vcodec; +} 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(); // #1 +void OMXToolBasicAV_SetStream(OMXToolBasicAV_t * pOMXAV, int vBufferNum, const KDchar * stream); // #2 +void OMXToolBasicAV_SetStreamEGLImageTexture2D(OMXToolBasicAV_t * pOMXAV, KDint i, GLuint tex, EGLImageKHR image, EGLSyncKHR sync); // #3 +void OMXToolBasicAV_ActivateStream(OMXToolBasicAV_t * pOMXAV); // #4 + +void OMXToolBasicAV_AttachVideoRenderer(OMXToolBasicAV_t * pOMXAV); // Stop, DetachVideoRenderer, SetEGLImageTexture2D .. before .. +void OMXToolBasicAV_DetachVideoRenderer(OMXToolBasicAV_t * pOMXAV); // Stop before .. + +void OMXToolBasicAV_SetPlaySpeed(OMXToolBasicAV_t * pOMXAV, KDfloat32 scale); +void OMXToolBasicAV_PlayStart(OMXToolBasicAV_t * pOMXAV); // #5 +void OMXToolBasicAV_PlayPause(OMXToolBasicAV_t * pOMXAV); +void OMXToolBasicAV_PlayStop(OMXToolBasicAV_t * pOMXAV); +void OMXToolBasicAV_PlaySeek(OMXToolBasicAV_t * pOMXAV, KDfloat32 time); +GLuint OMXToolBasicAV_GetNextTextureID(OMXToolBasicAV_t * pOMXAV); + +KDfloat32 OMXToolBasicAV_GetCurrentPosition(OMXToolBasicAV_t * pOMXAV); + +void OMXToolBasicAV_DestroyInstance(OMXToolBasicAV_t * pOMXAV); + +#if defined(SELF_TEST) + int ModuleTest(); +#endif + +#endif /* _OMX_TOOL_H */ + |