diff options
Diffstat (limited to 'src/jogl/native')
-rw-r--r-- | src/jogl/native/GLXGetProcAddressARB.c | 53 | ||||
-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, 3210 insertions, 0 deletions
diff --git a/src/jogl/native/GLXGetProcAddressARB.c b/src/jogl/native/GLXGetProcAddressARB.c new file mode 100644 index 000000000..6e9f6c3c2 --- /dev/null +++ b/src/jogl/native/GLXGetProcAddressARB.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2003-2009 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. + */ + +#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 */ + |