Allows an application to register a callback that manages mutexes on behalf of FFmpeg. With this callback registered FFmpeg is fully thread safe. Originally committed as revision 19025 to svn://svn.ffmpeg.org/ffmpeg/trunktags/v0.6
| @@ -12,6 +12,14 @@ libavutil: 2009-03-08 | |||
| API changes, most recent first: | |||
| 2009-06-01 - r19025 - lavc 52.30.0 - av_lockmgr_register() | |||
| av_lockmgr_register() can be used to register a callback function | |||
| that lavc (and in the future, libraries that depend on lavc) can use | |||
| to implement mutexes. The application should provide a callback function | |||
| the implements the AV_LOCK_* operations described in avcodec.h. | |||
| When the lock manager is registered FFmpeg is guaranteed to behave | |||
| correct also in a multi-threaded application. | |||
| 2009-04-30 - r18719 - lavc 52.28.0 - av_free_packet | |||
| av_free_packet() is no longer an inline function. It is now exported. | |||
| @@ -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 @@ void av_register_hwaccel(AVHWAccel *hwaccel); | |||
| */ | |||
| 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 */ | |||
| @@ -65,6 +65,8 @@ const uint8_t ff_reverse[256]={ | |||
| }; | |||
| 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 attribute_align_arg avcodec_open(AVCodecContext *avctx, AVCodec *codec) | |||
| { | |||
| 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 @@ int attribute_align_arg avcodec_open(AVCodecContext *avctx, AVCodec *codec) | |||
| 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_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub, | |||
| 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 @@ int avcodec_close(AVCodecContext *avctx) | |||
| 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 @@ AVHWAccel *ff_find_hwaccel(enum CodecID codec_id, enum PixelFormat pix_fmt) | |||
| } | |||
| 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; | |||
| } | |||