diff options
author | Sven Gothel <[email protected]> | 2014-02-16 06:12:45 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2014-02-16 06:12:45 +0100 |
commit | e685f79ec7071e266a1bd3d3ce3e742397b5372e (patch) | |
tree | 7328960c34c3083e91ec47793993c686359e0015 | |
parent | a6acce1be19060a6a4801582f0534e0d6887467a (diff) |
Bug 927: Fix minor MT issues w/ libav/ffmpeg
Issue:
[NULL @ 0x35bde60] insufficient thread locking around avcodec_open/close()
Decorating said libav functions w/ mutex lock/release.
Abstract impl. to either use pthread or JNI Monitor,
but using the latter to reduce dependencies (ming64 windows).
FFMPEGNatives is now an abstract class containing the
'static final Object mutex_avcodec_openclose'
7 files changed, 152 insertions, 92 deletions
diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index 9365a6bce..f6e3ab244 100644 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -367,8 +367,8 @@ function testawtswt() { # av demos # #testnoawt jogamp.opengl.openal.av.ALDummyUsage $* -testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.av.MovieCube $* -#testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.av.MovieSimple $* +#testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.av.MovieCube $* +testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.av.MovieSimple $* # # performance tests diff --git a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGNatives.java b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGNatives.java index bc0865aa9..c3fc2898f 100644 --- a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGNatives.java +++ b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGNatives.java @@ -29,17 +29,23 @@ package jogamp.opengl.util.av.impl; import com.jogamp.opengl.util.texture.TextureSequence.TextureFrame; -interface FFMPEGNatives { +/* pp */ abstract class FFMPEGNatives { - boolean initSymbols0(long[] symbols, int count); - int getAvUtilMajorVersionCC0(); - int getAvFormatMajorVersionCC0(); - int getAvCodecMajorVersionCC0(); - int getAvResampleMajorVersionCC0(); - int getSwResampleMajorVersionCC0(); + private static final Object mutex_avcodec_openclose = new Object(); - long createInstance0(FFMPEGMediaPlayer upstream, boolean verbose); - void destroyInstance0(long moviePtr); + abstract boolean initSymbols0(long[] symbols, int count); + abstract int getAvUtilMajorVersionCC0(); + abstract int getAvFormatMajorVersionCC0(); + abstract int getAvCodecMajorVersionCC0(); + abstract int getAvResampleMajorVersionCC0(); + abstract int getSwResampleMajorVersionCC0(); + + final long createInstance0(FFMPEGMediaPlayer upstream, boolean verbose) { + return createInstance0(mutex_avcodec_openclose, upstream, verbose); + } + abstract long createInstance0(Object mutex_avcodec_openclose, FFMPEGMediaPlayer upstream, boolean verbose); + + abstract void destroyInstance0(long moviePtr); /** * Issues {@link #updateAttributes(int, int, int, int, int, int, int, float, int, int, String, String)} @@ -56,24 +62,24 @@ interface FFMPEGNatives { * @param aPrefSampleRate * @param aPrefChannelCount */ - void setStream0(long moviePtr, String url, boolean isCameraInput, - int vid, String sizes, int vWidth, int vHeight, - int vRate, int aid, int aMaxChannelCount, int aPrefSampleRate); + abstract void setStream0(long moviePtr, String url, boolean isCameraInput, + int vid, String sizes, int vWidth, int vHeight, + int vRate, int aid, int aMaxChannelCount, int aPrefSampleRate); - void setGLFuncs0(long moviePtr, long procAddrGLTexSubImage2D, long procAddrGLGetError, long procAddrGLFlush, long procAddrGLFinish); + abstract void setGLFuncs0(long moviePtr, long procAddrGLTexSubImage2D, long procAddrGLGetError, long procAddrGLFlush, long procAddrGLFinish); - int getVideoPTS0(long moviePtr); + abstract int getVideoPTS0(long moviePtr); - int getAudioPTS0(long moviePtr); + abstract int getAudioPTS0(long moviePtr); /** * @return resulting current video PTS, or {@link TextureFrame#INVALID_PTS} */ - int readNextPacket0(long moviePtr, int texTarget, int texFmt, int texType); + abstract int readNextPacket0(long moviePtr, int texTarget, int texFmt, int texType); - int play0(long moviePtr); - int pause0(long moviePtr); - int seek0(long moviePtr, int position); + abstract int play0(long moviePtr); + abstract int pause0(long moviePtr); + abstract int seek0(long moviePtr, int position); /** FFMPEG/libAV Audio Sample Format */ public static enum SampleFormat { diff --git a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGv08Natives.java b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGv08Natives.java index 4b013c1b3..6ca0ea311 100644 --- a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGv08Natives.java +++ b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGv08Natives.java @@ -27,52 +27,52 @@ */ package jogamp.opengl.util.av.impl; -class FFMPEGv08Natives implements FFMPEGNatives { +class FFMPEGv08Natives extends FFMPEGNatives { @Override - public native boolean initSymbols0(long[] symbols, int count); + native boolean initSymbols0(long[] symbols, int count); @Override - public native int getAvUtilMajorVersionCC0(); + native int getAvUtilMajorVersionCC0(); @Override - public native int getAvFormatMajorVersionCC0(); + native int getAvFormatMajorVersionCC0(); @Override - public native int getAvCodecMajorVersionCC0(); + native int getAvCodecMajorVersionCC0(); @Override - public native int getAvResampleMajorVersionCC0(); + native int getAvResampleMajorVersionCC0(); @Override - public native int getSwResampleMajorVersionCC0(); + native int getSwResampleMajorVersionCC0(); @Override - public native long createInstance0(FFMPEGMediaPlayer upstream, boolean verbose); + native long createInstance0(Object mutex_avcodec_openclose, FFMPEGMediaPlayer upstream, boolean verbose); @Override - public native void destroyInstance0(long moviePtr); + native void destroyInstance0(long moviePtr); @Override - public native void setStream0(long moviePtr, String url, boolean isCameraInput, int vid, String sizes, int vWidth, int vHeight, int vRate, int aid, int aMaxChannelCount, int aPrefSampleRate); + native void setStream0(long moviePtr, String url, boolean isCameraInput, int vid, String sizes, int vWidth, int vHeight, int vRate, int aid, int aMaxChannelCount, int aPrefSampleRate); @Override - public native void setGLFuncs0(long moviePtr, long procAddrGLTexSubImage2D, long procAddrGLGetError, long procAddrGLFlush, long procAddrGLFinish); + native void setGLFuncs0(long moviePtr, long procAddrGLTexSubImage2D, long procAddrGLGetError, long procAddrGLFlush, long procAddrGLFinish); @Override - public native int getVideoPTS0(long moviePtr); + native int getVideoPTS0(long moviePtr); @Override - public native int getAudioPTS0(long moviePtr); + native int getAudioPTS0(long moviePtr); @Override - public native int readNextPacket0(long moviePtr, int texTarget, int texFmt, int texType); + native int readNextPacket0(long moviePtr, int texTarget, int texFmt, int texType); @Override - public native int play0(long moviePtr); + native int play0(long moviePtr); @Override - public native int pause0(long moviePtr); + native int pause0(long moviePtr); @Override - public native int seek0(long moviePtr, int position); + native int seek0(long moviePtr, int position); } diff --git a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGv09Natives.java b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGv09Natives.java index d69763287..1d9f7f5fa 100644 --- a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGv09Natives.java +++ b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGv09Natives.java @@ -27,52 +27,52 @@ */ package jogamp.opengl.util.av.impl; -class FFMPEGv09Natives implements FFMPEGNatives { +class FFMPEGv09Natives extends FFMPEGNatives { @Override - public native boolean initSymbols0(long[] symbols, int count); + native boolean initSymbols0(long[] symbols, int count); @Override - public native int getAvUtilMajorVersionCC0(); + native int getAvUtilMajorVersionCC0(); @Override - public native int getAvFormatMajorVersionCC0(); + native int getAvFormatMajorVersionCC0(); @Override - public native int getAvCodecMajorVersionCC0(); + native int getAvCodecMajorVersionCC0(); @Override - public native int getAvResampleMajorVersionCC0(); + native int getAvResampleMajorVersionCC0(); @Override - public native int getSwResampleMajorVersionCC0(); + native int getSwResampleMajorVersionCC0(); @Override - public native long createInstance0(FFMPEGMediaPlayer upstream, boolean verbose); + native long createInstance0(Object mutex_avcodec_openclose, FFMPEGMediaPlayer upstream, boolean verbose); @Override - public native void destroyInstance0(long moviePtr); + native void destroyInstance0(long moviePtr); @Override - public native void setStream0(long moviePtr, String url, boolean isCameraInput, int vid, String sizes, int vWidth, int vHeight, int vRate, int aid, int aMaxChannelCount, int aPrefSampleRate); + native void setStream0(long moviePtr, String url, boolean isCameraInput, int vid, String sizes, int vWidth, int vHeight, int vRate, int aid, int aMaxChannelCount, int aPrefSampleRate); @Override - public native void setGLFuncs0(long moviePtr, long procAddrGLTexSubImage2D, long procAddrGLGetError, long procAddrGLFlush, long procAddrGLFinish); + native void setGLFuncs0(long moviePtr, long procAddrGLTexSubImage2D, long procAddrGLGetError, long procAddrGLFlush, long procAddrGLFinish); @Override - public native int getVideoPTS0(long moviePtr); + native int getVideoPTS0(long moviePtr); @Override - public native int getAudioPTS0(long moviePtr); + native int getAudioPTS0(long moviePtr); @Override - public native int readNextPacket0(long moviePtr, int texTarget, int texFmt, int texType); + native int readNextPacket0(long moviePtr, int texTarget, int texFmt, int texType); @Override - public native int play0(long moviePtr); + native int play0(long moviePtr); @Override - public native int pause0(long moviePtr); + native int pause0(long moviePtr); @Override - public native int seek0(long moviePtr, int position); + native int seek0(long moviePtr, int position); } diff --git a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGv10Natives.java b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGv10Natives.java index 0b5f70d7c..19bc10f5f 100644 --- a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGv10Natives.java +++ b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGv10Natives.java @@ -27,52 +27,52 @@ */ package jogamp.opengl.util.av.impl; -class FFMPEGv10Natives implements FFMPEGNatives { +class FFMPEGv10Natives extends FFMPEGNatives { @Override - public native boolean initSymbols0(long[] symbols, int count); + native boolean initSymbols0(long[] symbols, int count); @Override - public native int getAvUtilMajorVersionCC0(); + native int getAvUtilMajorVersionCC0(); @Override - public native int getAvFormatMajorVersionCC0(); + native int getAvFormatMajorVersionCC0(); @Override - public native int getAvCodecMajorVersionCC0(); + native int getAvCodecMajorVersionCC0(); @Override - public native int getAvResampleMajorVersionCC0(); + native int getAvResampleMajorVersionCC0(); @Override - public native int getSwResampleMajorVersionCC0(); + native int getSwResampleMajorVersionCC0(); @Override - public native long createInstance0(FFMPEGMediaPlayer upstream, boolean verbose); + native long createInstance0(Object mutex_avcodec_openclose, FFMPEGMediaPlayer upstream, boolean verbose); @Override - public native void destroyInstance0(long moviePtr); + native void destroyInstance0(long moviePtr); @Override - public native void setStream0(long moviePtr, String url, boolean isCameraInput, int vid, String sizes, int vWidth, int vHeight, int vRate, int aid, int aMaxChannelCount, int aPrefSampleRate); + native void setStream0(long moviePtr, String url, boolean isCameraInput, int vid, String sizes, int vWidth, int vHeight, int vRate, int aid, int aMaxChannelCount, int aPrefSampleRate); @Override - public native void setGLFuncs0(long moviePtr, long procAddrGLTexSubImage2D, long procAddrGLGetError, long procAddrGLFlush, long procAddrGLFinish); + native void setGLFuncs0(long moviePtr, long procAddrGLTexSubImage2D, long procAddrGLGetError, long procAddrGLFlush, long procAddrGLFinish); @Override - public native int getVideoPTS0(long moviePtr); + native int getVideoPTS0(long moviePtr); @Override - public native int getAudioPTS0(long moviePtr); + native int getAudioPTS0(long moviePtr); @Override - public native int readNextPacket0(long moviePtr, int texTarget, int texFmt, int texType); + native int readNextPacket0(long moviePtr, int texTarget, int texFmt, int texType); @Override - public native int play0(long moviePtr); + native int play0(long moviePtr); @Override - public native int pause0(long moviePtr); + native int pause0(long moviePtr); @Override - public native int seek0(long moviePtr, int position); + native int seek0(long moviePtr, int position); } diff --git a/src/jogl/native/libav/ffmpeg_impl_template.c b/src/jogl/native/libav/ffmpeg_impl_template.c index e86b2a542..274eb37a5 100644 --- a/src/jogl/native/libav/ffmpeg_impl_template.c +++ b/src/jogl/native/libav/ffmpeg_impl_template.c @@ -344,6 +344,14 @@ static void _setIsGLOriented(JNIEnv *env, FFMPEGToolBasicAV_t* pAV) { } } +#ifdef USE_PTHREAD_LOCKING + #define MY_MUTEX_LOCK(e,s) pthread_mutex_lock(&(s)) + #define MY_MUTEX_UNLOCK(e,s) pthread_mutex_unlock(&(s)) +#else + #define MY_MUTEX_LOCK(e,s) (*e)->MonitorEnter(e, s) + #define MY_MUTEX_UNLOCK(e,s) (*e)->MonitorExit(e, s) +#endif + static void freeInstance(JNIEnv *env, FFMPEGToolBasicAV_t* pAV) { int i; if(NULL != pAV) { @@ -361,19 +369,23 @@ static void freeInstance(JNIEnv *env, FFMPEGToolBasicAV_t* pAV) { pAV->aResampleBuffer = NULL; } - // Close the V codec - if(NULL != pAV->pVCodecCtx) { - sp_avcodec_close(pAV->pVCodecCtx); - pAV->pVCodecCtx = NULL; - } - pAV->pVCodec=NULL; + MY_MUTEX_LOCK(env, pAV->mutex_avcodec_openclose); + { + // Close the V codec + if(NULL != pAV->pVCodecCtx) { + sp_avcodec_close(pAV->pVCodecCtx); + pAV->pVCodecCtx = NULL; + } + pAV->pVCodec=NULL; - // Close the A codec - if(NULL != pAV->pACodecCtx) { - sp_avcodec_close(pAV->pACodecCtx); - pAV->pACodecCtx = NULL; + // Close the A codec + if(NULL != pAV->pACodecCtx) { + sp_avcodec_close(pAV->pACodecCtx); + pAV->pACodecCtx = NULL; + } + pAV->pACodec=NULL; } - pAV->pACodec=NULL; + MY_MUTEX_UNLOCK(env, pAV->mutex_avcodec_openclose); // Close the frames if(NULL != pAV->pVFrame) { @@ -421,6 +433,14 @@ static void freeInstance(JNIEnv *env, FFMPEGToolBasicAV_t* pAV) { (*env)->DeleteGlobalRef(env, pAV->ffmpegMediaPlayer); pAV->ffmpegMediaPlayer = NULL; } + + #ifdef USE_PTHREAD_LOCKING + pthread_mutex_unlock(&pAV->mutex_avcodec_openclose); + pthread_mutex_destroy(&pAV->mutex_avcodec_openclose); + #else + (*env)->DeleteGlobalRef(env, pAV->mutex_avcodec_openclose); + #endif + free(pAV); } } @@ -488,8 +508,11 @@ JNIEXPORT jint JNICALL FF_FUNC(getSwResampleMajorVersionCC0) } JNIEXPORT jlong JNICALL FF_FUNC(createInstance0) - (JNIEnv *env, jobject instance, jobject ffmpegMediaPlayer, jboolean verbose) + (JNIEnv *env, jobject instance, jobject mutex_avcodec_openclose, jobject ffmpegMediaPlayer, jboolean verbose) { + #ifdef USE_PTHREAD_LOCKING + pthread_mutexattr_t renderLockAttr; + #endif FFMPEGToolBasicAV_t * pAV = calloc(1, sizeof(FFMPEGToolBasicAV_t)); if(NULL==pAV) { JoglCommon_throwNewRuntimeException(env, "Couldn't alloc instance"); @@ -524,6 +547,14 @@ JNIEXPORT jlong JNICALL FF_FUNC(createInstance0) pAV->vid=AV_STREAM_ID_AUTO; pAV->aid=AV_STREAM_ID_AUTO; + #ifdef USE_PTHREAD_LOCKING + pthread_mutexattr_init(&renderLockAttr); + pthread_mutexattr_settype(&renderLockAttr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&pAV->mutex_avcodec_openclose, &renderLockAttr); // recursive + #else + pAV->mutex_avcodec_openclose = (*env)->NewGlobalRef(env, mutex_avcodec_openclose); + #endif + if(pAV->verbose) { fprintf(stderr, "Info: Use avresample %d, swresample %d, device %d, refCount %d\n", AV_HAS_API_AVRESAMPLE(pAV), AV_HAS_API_SWRESAMPLE(pAV), HAS_FUNC(sp_avdevice_register_all), pAV->useRefCountedFrames); @@ -824,10 +855,14 @@ JNIEXPORT void JNICALL FF_FUNC(setStream0) } // Open codec - #if LIBAVCODEC_VERSION_MAJOR >= 55 - pAV->pACodecCtx->refcounted_frames = pAV->useRefCountedFrames; - #endif - res = sp_avcodec_open2(pAV->pACodecCtx, pAV->pACodec, NULL); + MY_MUTEX_LOCK(env, pAV->mutex_avcodec_openclose); + { + #if LIBAVCODEC_VERSION_MAJOR >= 55 + pAV->pACodecCtx->refcounted_frames = pAV->useRefCountedFrames; + #endif + res = sp_avcodec_open2(pAV->pACodecCtx, pAV->pACodec, NULL); + } + MY_MUTEX_UNLOCK(env, pAV->mutex_avcodec_openclose); if(res<0) { JoglCommon_throwNewRuntimeException(env, "Couldn't open audio codec %d, %s", pAV->pACodecCtx->codec_id, pAV->acodec); return; @@ -982,10 +1017,14 @@ JNIEXPORT void JNICALL FF_FUNC(setStream0) } // Open codec - #if LIBAVCODEC_VERSION_MAJOR >= 55 - pAV->pVCodecCtx->refcounted_frames = pAV->useRefCountedFrames; - #endif - res = sp_avcodec_open2(pAV->pVCodecCtx, pAV->pVCodec, NULL); + MY_MUTEX_LOCK(env, pAV->mutex_avcodec_openclose); + { + #if LIBAVCODEC_VERSION_MAJOR >= 55 + pAV->pVCodecCtx->refcounted_frames = pAV->useRefCountedFrames; + #endif + res = sp_avcodec_open2(pAV->pVCodecCtx, pAV->pVCodec, NULL); + } + MY_MUTEX_UNLOCK(env, pAV->mutex_avcodec_openclose); if(res<0) { JoglCommon_throwNewRuntimeException(env, "Couldn't open video codec %d, %s", pAV->pVCodecCtx->codec_id, pAV->vcodec); return; diff --git a/src/jogl/native/libav/ffmpeg_tool.h b/src/jogl/native/libav/ffmpeg_tool.h index 97e60afce..66c3519e6 100644 --- a/src/jogl/native/libav/ffmpeg_tool.h +++ b/src/jogl/native/libav/ffmpeg_tool.h @@ -64,6 +64,15 @@ typedef struct SwrContext SwrContext; #include <stdio.h> #include <stdlib.h> +// We use JNI Monitor Locking, since this removes the need +// to statically link-in pthreads on window .. +// #define USE_PTHREAD_LOCKING 1 +// +#ifdef USE_PTHREAD_LOCKING + #include <pthread.h> + #error PTHREAD path not tested yet +#endif + #include <GL/gl.h> typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); @@ -148,6 +157,12 @@ typedef struct { PFNGLFLUSH procAddrGLFlush; PFNGLFINISH procAddrGLFinish; + #ifdef USE_PTHREAD_LOCKING + pthread_mutex_t mutex_avcodec_openclose; + #else + jobject mutex_avcodec_openclose; + #endif + AVFormatContext* pFormatCtx; int32_t vid; AVStream* pVStream; |