函数原型如下:
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;}新闻热点
疑难解答