diff options
author | Kenneth Russel <[email protected]> | 2009-06-15 22:57:38 +0000 |
---|---|---|
committer | Kenneth Russel <[email protected]> | 2009-06-15 22:57:38 +0000 |
commit | a959c53b7ac91e489bf0959391e892790b9ff248 (patch) | |
tree | 4664742a4f9f6daa694364292e376ad2e6ee97d1 /src/jogl/native/openmax/omx_tool.c | |
parent | 506b634b780dcd23aa61015c2ceba3e687196abf (diff) |
Copied JOGL_2_SANDBOX r1957 on to trunk; JOGL_2_SANDBOX branch is now closed
git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1959 232f8b59-042b-4e1e-8c03-345bb8c30851
Diffstat (limited to 'src/jogl/native/openmax/omx_tool.c')
-rw-r--r-- | src/jogl/native/openmax/omx_tool.c | 1713 |
1 files changed, 1713 insertions, 0 deletions
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 + |