# HG changeset patch # User andoma # Date 1243752678 0 # Node ID 0d6f887d91fb3c4918bcfd5a845ee34ee9147c55 # Parent e52891e48ceb64a05065db117d07f496a9bbc727 Add a lock manager API to libavcodec. Allows an application to register a callback that manages mutexes on behalf of FFmpeg. With this callback registered FFmpeg is fully thread safe. diff -r e52891e48ceb -r 0d6f887d91fb avcodec.h --- a/avcodec.h Sun May 31 06:33:58 2009 +0000 +++ b/avcodec.h Sun May 31 06:51:18 2009 +0000 @@ -30,7 +30,7 @@ #include "libavutil/avutil.h" #define LIBAVCODEC_VERSION_MAJOR 52 -#define LIBAVCODEC_VERSION_MINOR 29 +#define LIBAVCODEC_VERSION_MINOR 30 #define LIBAVCODEC_VERSION_MICRO 1 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ @@ -3711,4 +3711,30 @@ */ AVHWAccel *av_hwaccel_next(AVHWAccel *hwaccel); + +/** + * Lock operation used by lockmgr + */ +enum AVLockOp { + AV_LOCK_CREATE, ///< Create a mutex + AV_LOCK_OBTAIN, ///< Lock the mutex + AV_LOCK_RELEASE, ///< Unlock the mutex + AV_LOCK_DESTROY, ///< Free mutex resources +}; + +/** + * Register a user provided lock manager supporting the operations + * specified by AVLockOp. \p mutex points to a (void *) where the + * lockmgr should store/get a pointer to a user allocated mutex. It's + * NULL upon AV_LOCK_CREATE and != NULL for all other ops. + * + * @param cb User defined callback. Note: FFmpeg may invoke calls to this + * callback during the call to av_lockmgr_register(). + * Thus, the application must be prepared to handle that. + * If cb is set to NULL the lockmgr will be unregistered. + * Also note that during unregistration the previously registered + * lockmgr callback may also be invoked. + */ +int av_lockmgr_register(int (*cb)(void **mutex, enum AVLockOp op)); + #endif /* AVCODEC_AVCODEC_H */ diff -r e52891e48ceb -r 0d6f887d91fb utils.c --- a/utils.c Sun May 31 06:33:58 2009 +0000 +++ b/utils.c Sun May 31 06:51:18 2009 +0000 @@ -65,6 +65,8 @@ }; static int volatile entangled_thread_counter=0; +int (*ff_lockmgr_cb)(void **mutex, enum AVLockOp op); +static void *codec_mutex; void *av_fast_realloc(void *ptr, unsigned int *size, unsigned int min_size) { @@ -439,6 +441,12 @@ { int ret= -1; + /* If there is a user-supplied mutex locking routine, call it. */ + if (ff_lockmgr_cb) { + if ((*ff_lockmgr_cb)(&codec_mutex, AV_LOCK_OBTAIN)) + return -1; + } + entangled_thread_counter++; if(entangled_thread_counter != 1){ av_log(avctx, AV_LOG_ERROR, "insufficient thread locking around avcodec_open/close()\n"); @@ -483,6 +491,11 @@ ret=0; end: entangled_thread_counter--; + + /* Release any user-supplied mutex. */ + if (ff_lockmgr_cb) { + (*ff_lockmgr_cb)(&codec_mutex, AV_LOCK_RELEASE); + } return ret; } @@ -642,6 +655,12 @@ int avcodec_close(AVCodecContext *avctx) { + /* If there is a user-supplied mutex locking routine, call it. */ + if (ff_lockmgr_cb) { + if ((*ff_lockmgr_cb)(&codec_mutex, AV_LOCK_OBTAIN)) + return -1; + } + entangled_thread_counter++; if(entangled_thread_counter != 1){ av_log(avctx, AV_LOG_ERROR, "insufficient thread locking around avcodec_open/close()\n"); @@ -657,6 +676,11 @@ av_freep(&avctx->priv_data); avctx->codec = NULL; entangled_thread_counter--; + + /* Release any user-supplied mutex. */ + if (ff_lockmgr_cb) { + (*ff_lockmgr_cb)(&codec_mutex, AV_LOCK_RELEASE); + } return 0; } @@ -1213,3 +1237,19 @@ } return NULL; } + +int av_lockmgr_register(int (*cb)(void **mutex, enum AVLockOp op)) +{ + if (ff_lockmgr_cb) { + if (ff_lockmgr_cb(&codec_mutex, AV_LOCK_DESTROY)) + return -1; + } + + ff_lockmgr_cb = cb; + + if (ff_lockmgr_cb) { + if (ff_lockmgr_cb(&codec_mutex, AV_LOCK_CREATE)) + return -1; + } + return 0; +}