简介
函数原型如下:
int av_lockmgr_register (int(*cb)(void **mutex, enum AVLockOp op));
其作用是注册一个用户自定义的lock manager, 其中cb可定义如下(ffplay.c):
static int lockmgr(void **mtx, enum AVLockOp op)
{
switch(op) {
case AV_LOCK_CREATE:
*mtx = SDL_CreateMutex();
if(!*mtx) {
av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());
return 1;
}
return 0;
case AV_LOCK_OBTAIN:
return !!SDL_LockMutex(*mtx);
case AV_LOCK_RELEASE:
return !!SDL_UnlockMutex(*mtx);
case AV_LOCK_DESTROY:
SDL_DestroyMutex(*mtx);
return 0;
}
return 1;
}
通过传入的op参数来创建、加锁、解锁以及销毁操作。
作用
当多个线程调用avcodec_open2、avcodec_close的时可能导致失败。 从ffmpeg源码可知,失败的主要原因是在调用此函数时为确保函数为原子操作,在函数的开头和结尾处使用了一个变量entangled_thread_counter来记录当前函数是否已经有其他线程进入,如果有其他线程正在函数内运行,则会调用失败。其解释如下:
- 在avcodec_open2函数开头有如下判断, 当返回值小于0时返回。
ret = ff_lock_avcodec(avctx);
if (ret < 0)
return ret;
- ff_lock_avcodec定义如下,当lockmgr_cb不为空时调用该函数加锁。当entangled_thread_counter大于1时,则返回AVERROR(EINVAL),说明有多个线程在该函数中运行。
int ff_lock_avcodec(AVCodecContext *log_ctx, const AVCodec *codec)
{
if (codec->caps_internal & FF_CODEC_CAP_INIT_THREADSAFE || !codec->init)
return 0;
if (lockmgr_cb) {
if ((*lockmgr_cb)(&codec_mutex, AV_LOCK_OBTAIN))
return -1;
}
if (avpriv_atomic_int_add_and_fetch(&entangled_thread_counter, 1) != 1) {
av_log(log_ctx, AV_LOG_ERROR,
"Insufficient thread locking. At least %d threads are "
"calling avcodec_open2() at the same time right now.\n",
entangled_thread_counter);
if (!lockmgr_cb)
av_log(log_ctx, AV_LOG_ERROR, "No lock manager is set, please see av_lockmgr_register()\n");
ff_avcodec_locked = 1;
ff_unlock_avcodec(codec);
return AVERROR(EINVAL);
}
av_assert0(!ff_avcodec_locked);
ff_avcodec_locked = 1;
return 0;
}