diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index a9dbff7235..8572a7be07 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -3262,6 +3262,11 @@ typedef struct AVCodec { * Will be called when seeking */ void (*flush)(AVCodecContext *); + /** + * Internal codec capabilities. + * See FF_CODEC_CAP_* in internal.h + */ + int caps_internal; } AVCodec; int av_codec_get_max_lowres(const AVCodec *codec); diff --git a/libavcodec/internal.h b/libavcodec/internal.h index f4e12e8084..3d0cd5b582 100644 --- a/libavcodec/internal.h +++ b/libavcodec/internal.h @@ -33,6 +33,16 @@ #include "avcodec.h" #include "config.h" +/** + * Codec is thread safe. + */ +#define FF_CODEC_CAP_INIT_THREADSAFE (1 << 0) +/** + * Codec cleans up memory on init failure. + */ +#define FF_CODEC_CAP_INIT_CLEANUP (1 << 1) + + #define FF_SANE_NB_CHANNELS 63U #define FF_SIGNBIT(x) ((x) >> CHAR_BIT * sizeof(x) - 1) @@ -157,7 +167,7 @@ int ff_init_buffer_info(AVCodecContext *s, AVFrame *frame); void avpriv_color_frame(AVFrame *frame, const int color[4]); extern volatile int ff_avcodec_locked; -int ff_lock_avcodec(AVCodecContext *log_ctx); +int ff_lock_avcodec(AVCodecContext *log_ctx, AVCodec *codec); int ff_unlock_avcodec(void); int avpriv_lock_avformat(void); diff --git a/libavcodec/utils.c b/libavcodec/utils.c index b3749af340..14a4d7b6c5 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -1318,7 +1318,7 @@ int attribute_align_arg ff_codec_open2_recursive(AVCodecContext *avctx, const AV ret = avcodec_open2(avctx, codec, options); - ff_lock_avcodec(avctx); + ff_lock_avcodec(avctx, codec); return ret; } @@ -1348,7 +1348,7 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code if (options) av_dict_copy(&tmp, *options, 0); - ret = ff_lock_avcodec(avctx); + ret = ff_lock_avcodec(avctx, codec); if (ret < 0) return ret; @@ -1477,7 +1477,7 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code if (CONFIG_FRAME_THREAD_ENCODER) { ff_unlock_avcodec(); //we will instanciate a few encoders thus kick the counter to prevent false detection of a problem ret = ff_frame_thread_encoder_init(avctx, options ? *options : NULL); - ff_lock_avcodec(avctx); + ff_lock_avcodec(avctx, codec); if (ret < 0) goto free_and_end; } @@ -1704,6 +1704,10 @@ end: return ret; free_and_end: + if (avctx->codec && + (avctx->codec->caps_internal & FF_CODEC_CAP_INIT_CLEANUP)) + avctx->codec->close(avctx); + av_dict_free(&tmp); if (codec->priv_class && codec->priv_data_size) av_opt_free(avctx->priv_data); @@ -3600,14 +3604,15 @@ int av_lockmgr_register(int (*cb)(void **mutex, enum AVLockOp op)) return 0; } -int ff_lock_avcodec(AVCodecContext *log_ctx) +int ff_lock_avcodec(AVCodecContext *log_ctx, AVCodec *codec) { if (lockmgr_cb) { if ((*lockmgr_cb)(&codec_mutex, AV_LOCK_OBTAIN)) return -1; } entangled_thread_counter++; - if (entangled_thread_counter != 1) { + if (entangled_thread_counter != 1 && + !(codec->caps_internal & FF_CODEC_CAP_INIT_THREADSAFE)) { 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",