diff --git a/libavcodec/frame_thread_encoder.c b/libavcodec/frame_thread_encoder.c index 9e176985ee..6eae8b5733 100644 --- a/libavcodec/frame_thread_encoder.c +++ b/libavcodec/frame_thread_encoder.c @@ -142,8 +142,16 @@ int ff_frame_thread_encoder_init(AVCodecContext *avctx, AVDictionary *options){ if (avctx->codec_id == AV_CODEC_ID_HUFFYUV || avctx->codec_id == AV_CODEC_ID_FFVHUFF) { + int warn = 0; + if (avctx->flags & CODEC_FLAG_PASS1) + warn = 1; + else if(avctx->context_model > 0) { + AVDictionaryEntry *t = av_dict_get(options, "non_deterministic", + NULL, AV_DICT_MATCH_CASE); + warn = !t || !t->value || !atoi(t->value) ? 1 : 0; + } // huffyuv does not support these with multiple frame threads currently - if (avctx->context_model > 0 || (avctx->flags & CODEC_FLAG_PASS1)) { + if (warn) { av_log(avctx, AV_LOG_WARNING, "Forcing thread count to 1 for huffyuv encoding with first pass or context 1\n"); avctx->thread_count = 1; diff --git a/libavcodec/huffyuv.h b/libavcodec/huffyuv.h index 2b3a1b33eb..c18247ed0f 100644 --- a/libavcodec/huffyuv.h +++ b/libavcodec/huffyuv.h @@ -52,6 +52,7 @@ typedef enum Predictor { } Predictor; typedef struct HYuvContext { + AVClass *class; AVCodecContext *avctx; Predictor predictor; GetBitContext gb; @@ -88,6 +89,7 @@ typedef struct HYuvContext { HuffYUVDSPContext hdsp; HuffYUVEncDSPContext hencdsp; LLVidDSPContext llviddsp; + int non_determ; // non-deterministic, multi-threaded encoder allowed } HYuvContext; void ff_huffyuv_common_init(AVCodecContext *s); diff --git a/libavcodec/huffyuvenc.c b/libavcodec/huffyuvenc.c index 8d72b6328e..fd6f570e66 100644 --- a/libavcodec/huffyuvenc.c +++ b/libavcodec/huffyuvenc.c @@ -34,6 +34,7 @@ #include "huffyuvencdsp.h" #include "internal.h" #include "put_bits.h" +#include "libavutil/opt.h" #include "libavutil/pixdesc.h" static inline void diff_bytes(HYuvContext *s, uint8_t *dst, @@ -990,6 +991,27 @@ static av_cold int encode_end(AVCodecContext *avctx) return 0; } +static const AVOption options[] = { + { "non_deterministic", "Allow multithreading for e.g. context=1 at the expense of determinism", + offsetof(HYuvContext, non_determ), AV_OPT_TYPE_INT, { .i64 = 1 }, + 0, 1, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM }, + { NULL }, +}; + +static const AVClass normal_class = { + .class_name = "huffyuv", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const AVClass ff_class = { + .class_name = "ffvhuff", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVCodec ff_huffyuv_encoder = { .name = "huffyuv", .long_name = NULL_IF_CONFIG_SMALL("Huffyuv / HuffYUV"), @@ -1000,6 +1022,7 @@ AVCodec ff_huffyuv_encoder = { .encode2 = encode_frame, .close = encode_end, .capabilities = CODEC_CAP_FRAME_THREADS | CODEC_CAP_INTRA_ONLY, + .priv_class = &normal_class, .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV422P, AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE @@ -1017,6 +1040,7 @@ AVCodec ff_ffvhuff_encoder = { .encode2 = encode_frame, .close = encode_end, .capabilities = CODEC_CAP_FRAME_THREADS | CODEC_CAP_INTRA_ONLY, + .priv_class = &ff_class, .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV440P,