1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2024-12-23 12:43:46 +02:00

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.

Originally committed as revision 19025 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
Andreas Öman 2009-05-31 06:51:18 +00:00
parent b8df8d0d1c
commit f988ce6cad
3 changed files with 75 additions and 1 deletions

View File

@ -12,6 +12,14 @@ libavutil: 2009-03-08
API changes, most recent first: 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 2009-04-30 - r18719 - lavc 52.28.0 - av_free_packet
av_free_packet() is no longer an inline function. It is now exported. av_free_packet() is no longer an inline function. It is now exported.

View File

@ -30,7 +30,7 @@
#include "libavutil/avutil.h" #include "libavutil/avutil.h"
#define LIBAVCODEC_VERSION_MAJOR 52 #define LIBAVCODEC_VERSION_MAJOR 52
#define LIBAVCODEC_VERSION_MINOR 29 #define LIBAVCODEC_VERSION_MINOR 30
#define LIBAVCODEC_VERSION_MICRO 1 #define LIBAVCODEC_VERSION_MICRO 1
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ #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); 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 */ #endif /* AVCODEC_AVCODEC_H */

View File

@ -65,6 +65,8 @@ const uint8_t ff_reverse[256]={
}; };
static int volatile entangled_thread_counter=0; 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) 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; 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++; entangled_thread_counter++;
if(entangled_thread_counter != 1){ if(entangled_thread_counter != 1){
av_log(avctx, AV_LOG_ERROR, "insufficient thread locking around avcodec_open/close()\n"); 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; ret=0;
end: end:
entangled_thread_counter--; entangled_thread_counter--;
/* Release any user-supplied mutex. */
if (ff_lockmgr_cb) {
(*ff_lockmgr_cb)(&codec_mutex, AV_LOCK_RELEASE);
}
return ret; return ret;
} }
@ -642,6 +655,12 @@ int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub,
int avcodec_close(AVCodecContext *avctx) 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++; entangled_thread_counter++;
if(entangled_thread_counter != 1){ if(entangled_thread_counter != 1){
av_log(avctx, AV_LOG_ERROR, "insufficient thread locking around avcodec_open/close()\n"); 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); av_freep(&avctx->priv_data);
avctx->codec = NULL; avctx->codec = NULL;
entangled_thread_counter--; entangled_thread_counter--;
/* Release any user-supplied mutex. */
if (ff_lockmgr_cb) {
(*ff_lockmgr_cb)(&codec_mutex, AV_LOCK_RELEASE);
}
return 0; return 0;
} }
@ -1213,3 +1237,19 @@ AVHWAccel *ff_find_hwaccel(enum CodecID codec_id, enum PixelFormat pix_fmt)
} }
return NULL; 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;
}