diff mbox

[FFmpeg-devel,v15,1/2] lavc/svt_hevc: add libsvt hevc encoder wrapper

Message ID 1564386636-3287-1-git-send-email-jing.a.sun@intel.com
State Superseded
Headers show

Commit Message

Jing SUN July 29, 2019, 7:50 a.m. UTC
Signed-off-by: Zhengxu Huang <zhengxu.huang@intel.com>
Signed-off-by: Hassene Tmar <hassene.tmar@intel.com>
Signed-off-by: Jun Zhao <jun.zhao@intel.com>
Signed-off-by: Jing Sun <jing.a.sun@intel.com>
---
 configure                |   4 +
 libavcodec/Makefile      |   1 +
 libavcodec/allcodecs.c   |   1 +
 libavcodec/libsvt_hevc.c | 501 +++++++++++++++++++++++++++++++++++++++++++++++
 libavcodec/version.h     |   2 +-
 5 files changed, 508 insertions(+), 1 deletion(-)
 create mode 100644 libavcodec/libsvt_hevc.c

Comments

Jing SUN July 29, 2019, 6:49 a.m. UTC | #1
The just updated one fixed such typo:
      .pix_fmts       = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P,
                                                      AV_PIX_FMT_YUV420P10,
                                                      AV_PIX_FMT_YUV422P,
-                                                     AV_PIX_FMT_YUV420P10,
+                                                    AV_PIX_FMT_YUV422P10,
                                                      AV_PIX_FMT_YUV444P,
                                                      AV_PIX_FMT_YUV444P10,
                                                      AV_PIX_FMT_NONE },

Regards,
Sun, Jing
Lance Wang July 30, 2019, 5:59 a.m. UTC | #2
On Mon, Jul 29, 2019 at 03:50:36PM +0800, Jing Sun wrote:
> Signed-off-by: Zhengxu Huang <zhengxu.huang@intel.com>
> Signed-off-by: Hassene Tmar <hassene.tmar@intel.com>
> Signed-off-by: Jun Zhao <jun.zhao@intel.com>
> Signed-off-by: Jing Sun <jing.a.sun@intel.com>
> ---
>  configure                |   4 +
>  libavcodec/Makefile      |   1 +
>  libavcodec/allcodecs.c   |   1 +
>  libavcodec/libsvt_hevc.c | 501 +++++++++++++++++++++++++++++++++++++++++++++++
>  libavcodec/version.h     |   2 +-
>  5 files changed, 508 insertions(+), 1 deletion(-)
>  create mode 100644 libavcodec/libsvt_hevc.c
> 
> diff --git a/configure b/configure
> index 7cea9d4..8f2f065 100755
> --- a/configure
> +++ b/configure
> @@ -264,6 +264,7 @@ External library support:
>    --enable-libspeex        enable Speex de/encoding via libspeex [no]
>    --enable-libsrt          enable Haivision SRT protocol via libsrt [no]
>    --enable-libssh          enable SFTP protocol via libssh [no]
> +  --enable-libsvthevc      enable HEVC encoding via svt [no]
>    --enable-libtensorflow   enable TensorFlow as a DNN module backend
>                             for DNN based filters like sr [no]
>    --enable-libtesseract    enable Tesseract, needed for ocr filter [no]
> @@ -1787,6 +1788,7 @@ EXTERNAL_LIBRARY_LIST="
>      libspeex
>      libsrt
>      libssh
> +    libsvthevc
>      libtensorflow
>      libtesseract
>      libtheora
> @@ -3180,6 +3182,7 @@ libshine_encoder_select="audio_frame_queue"
>  libspeex_decoder_deps="libspeex"
>  libspeex_encoder_deps="libspeex"
>  libspeex_encoder_select="audio_frame_queue"
> +libsvt_hevc_encoder_deps="libsvthevc"
>  libtheora_encoder_deps="libtheora"
>  libtwolame_encoder_deps="libtwolame"
>  libvo_amrwbenc_encoder_deps="libvo_amrwbenc"
> @@ -6226,6 +6229,7 @@ enabled libsoxr           && require libsoxr soxr.h soxr_create -lsoxr
>  enabled libssh            && require_pkg_config libssh libssh libssh/sftp.h sftp_init
>  enabled libspeex          && require_pkg_config libspeex speex speex/speex.h speex_decoder_init
>  enabled libsrt            && require_pkg_config libsrt "srt >= 1.3.0" srt/srt.h srt_socket
> +enabled libsvthevc        && require_pkg_config libsvthevc SvtHevcEnc EbApi.h EbInitHandle
>  enabled libtensorflow     && require libtensorflow tensorflow/c/c_api.h TF_Version -ltensorflow
>  enabled libtesseract      && require_pkg_config libtesseract tesseract tesseract/capi.h TessBaseAPICreate
>  enabled libtheora         && require libtheora theora/theoraenc.h th_info_init -ltheoraenc -ltheoradec -logg
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index edccd73..7eb13de 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -991,6 +991,7 @@ OBJS-$(CONFIG_LIBOPUS_ENCODER)            += libopusenc.o libopus.o     \
>  OBJS-$(CONFIG_LIBSHINE_ENCODER)           += libshine.o
>  OBJS-$(CONFIG_LIBSPEEX_DECODER)           += libspeexdec.o
>  OBJS-$(CONFIG_LIBSPEEX_ENCODER)           += libspeexenc.o
> +OBJS-$(CONFIG_LIBSVT_HEVC_ENCODER)        += libsvt_hevc.o
>  OBJS-$(CONFIG_LIBTHEORA_ENCODER)          += libtheoraenc.o
>  OBJS-$(CONFIG_LIBTWOLAME_ENCODER)         += libtwolame.o
>  OBJS-$(CONFIG_LIBVO_AMRWBENC_ENCODER)     += libvo-amrwbenc.o
> diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
> index d2f9a39..d8788a7 100644
> --- a/libavcodec/allcodecs.c
> +++ b/libavcodec/allcodecs.c
> @@ -707,6 +707,7 @@ extern AVCodec ff_librsvg_decoder;
>  extern AVCodec ff_libshine_encoder;
>  extern AVCodec ff_libspeex_encoder;
>  extern AVCodec ff_libspeex_decoder;
> +extern AVCodec ff_libsvt_hevc_encoder;
>  extern AVCodec ff_libtheora_encoder;
>  extern AVCodec ff_libtwolame_encoder;
>  extern AVCodec ff_libvo_amrwbenc_encoder;
> diff --git a/libavcodec/libsvt_hevc.c b/libavcodec/libsvt_hevc.c
> new file mode 100644
> index 0000000..d9ac04c
> --- /dev/null
> +++ b/libavcodec/libsvt_hevc.c
> @@ -0,0 +1,501 @@
> +/*
> +* Scalable Video Technology for HEVC encoder library plugin
> +*
> +* Copyright (c) 2019 Intel Corporation
> +*
> +* This file is part of FFmpeg.
> +*
> +* FFmpeg is free software; you can redistribute it and/or
> +* modify it under the terms of the GNU Lesser General Public
> +* License as published by the Free Software Foundation; either
> +* version 2.1 of the License, or (at your option) any later version.
> +*
> +* FFmpeg is distributed in the hope that it will be useful,
> +* but WITHOUT ANY WARRANTY; without even the implied warranty of
> +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +* Lesser General Public License for more details.
> +*
> +* You should have received a copy of the GNU Lesser General Public
> +* License along with this program; if not, write to the Free Software
> +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> +*/
> +
> +#include "EbErrorCodes.h"
> +#include "EbTime.h"
> +#include "EbApi.h"
> +
> +#include "libavutil/common.h"
> +#include "libavutil/frame.h"
> +#include "libavutil/opt.h"
> +
> +#include "internal.h"
> +#include "avcodec.h"
> +
> +typedef enum eos_status {
> +    EOS_NOT_REACHED = 0,
> +    EOS_SENT,
> +    EOS_RECEIVED
> +}EOS_STATUS;
> +
> +typedef struct SvtContext {
> +    AVClass *class;
> +
> +    EB_H265_ENC_CONFIGURATION enc_params;
> +    EB_COMPONENTTYPE *svt_handle;
> +    EB_BUFFERHEADERTYPE in_buf;
> +    EOS_STATUS eos_flag;
> +
> +    // User options.
> +    int profile;
> +    int hierarchical_level;
> +    int enc_mode;
> +    int tier;
> +    int level;
> +    int rc_mode;
> +    int scd;
> +    int tune;
> +    int base_layer_switch_mode;
> +    int qp;
> +    int aud;
> +    int asm_type;
> +    int forced_idr;
> +    int la_depth;
> +} SvtContext;
> +
> +static int error_mapping(EB_ERRORTYPE svt_ret)
> +{
> +    switch (svt_ret) {
> +    case EB_ErrorInsufficientResources:
> +        return AVERROR(ENOMEM);
> +
> +    case EB_ErrorUndefined:
> +    case EB_ErrorInvalidComponent:
> +    case EB_ErrorBadParameter:
> +        return AVERROR(EINVAL);
> +
> +    case EB_ErrorDestroyThreadFailed:
> +    case EB_ErrorSemaphoreUnresponsive:
> +    case EB_ErrorDestroySemaphoreFailed:
> +    case EB_ErrorCreateMutexFailed:
> +    case EB_ErrorMutexUnresponsive:
> +    case EB_ErrorDestroyMutexFailed:
> +        return AVERROR_EXTERNAL;
> +
> +    case EB_NoErrorEmptyQueue:
> +        return AVERROR(EAGAIN);
> +
> +    case EB_ErrorNone:
> +        return 0;
> +
> +    default:
> +        return AVERROR_UNKNOWN;
> +    }
> +}
> +
> +static void free_buffer(SvtContext *svt_enc)
> +{
> +    uint8_t *in_data = svt_enc->in_buf.pBuffer;
> +
> +    av_freep(&in_data);
> +}
> +
> +static EB_ERRORTYPE alloc_buffer(SvtContext *svt_enc)
> +{
> +    EB_BUFFERHEADERTYPE *in_buf = &svt_enc->in_buf;
> +    EB_H265_ENC_INPUT *in_data = NULL;
> +
> +    memset(in_buf, 0, sizeof(*in_buf));
> +    in_buf->nSize = sizeof(*in_buf);
> +    in_buf->sliceType = EB_INVALID_PICTURE;
> +
> +    in_data = (EB_H265_ENC_INPUT *)av_mallocz(sizeof(*in_data));
> +    if (in_data) {
> +        in_buf->pBuffer = (uint8_t *)in_data;
> +        return EB_ErrorNone;
> +    } else {
> +        return EB_ErrorInsufficientResources;
> +    }
> +}
> +
> +static int config_enc_params(EB_H265_ENC_CONFIGURATION *param,
> +                             AVCodecContext *avctx)
> +{
> +    SvtContext *svt_enc = avctx->priv_data;
> +
> +    param->sourceWidth = avctx->width;
> +    param->sourceHeight = avctx->height;
> +
> +    if ((avctx->pix_fmt == AV_PIX_FMT_YUV420P10) ||
> +        (avctx->pix_fmt == AV_PIX_FMT_YUV422P10) ||
> +        (avctx->pix_fmt == AV_PIX_FMT_YUV444P10)) {
> +        av_log(avctx, AV_LOG_DEBUG, "Set 10 bits depth input\n");
> +        param->encoderBitDepth = 10;
> +    } else {
> +        av_log(avctx, AV_LOG_DEBUG, "Set 8 bits depth input\n");
> +        param->encoderBitDepth = 8;
> +    }
> +
> +    if ((avctx->pix_fmt == AV_PIX_FMT_YUV420P) ||
> +        (avctx->pix_fmt == AV_PIX_FMT_YUV420P10))
> +        param->encoderColorFormat = EB_YUV420;
> +    else if ((avctx->pix_fmt == AV_PIX_FMT_YUV422P) ||
> +             (avctx->pix_fmt == AV_PIX_FMT_YUV422P10))
> +        param->encoderColorFormat = EB_YUV422;
> +    else
> +        param->encoderColorFormat = EB_YUV444;
> +
> +    param->profile = svt_enc->profile;
> +
> +    if (FF_PROFILE_HEVC_MAIN_STILL_PICTURE == param->profile) {
> +        av_log(avctx, AV_LOG_ERROR, "Main Still Picture Profile not supported\n");
> +        return EB_ErrorBadParameter;
> +    }
> +
> +    if ((param->encoderColorFormat >= EB_YUV422) &&
> +        (param->profile != FF_PROFILE_HEVC_REXT)) {
> +        av_log(avctx, AV_LOG_WARNING, "Rext Profile forced for 422 or 444\n");
> +        param->profile = FF_PROFILE_HEVC_REXT;
> +    }
> +
> +    if ((FF_PROFILE_HEVC_MAIN == param->profile) &&
> +        (param->encoderBitDepth > 8)) {
> +        av_log(avctx, AV_LOG_WARNING, "Main10 Profile forced for 10 bits\n");
> +        param->profile = FF_PROFILE_HEVC_MAIN_10;
> +    }
> +
> +    param->targetBitRate = avctx->bit_rate;
> +
> +    if (avctx->gop_size > 0)
> +        param->intraPeriodLength = avctx->gop_size - 1;
> +
> +    if ((avctx->framerate.num > 0) && (avctx->framerate.den > 0)) {
> +        param->frameRateNumerator = avctx->framerate.num;
> +        param->frameRateDenominator =
> +            avctx->framerate.den * avctx->ticks_per_frame;
> +    } else {
> +        param->frameRateNumerator = avctx->time_base.den;
> +        param->frameRateDenominator =
> +            avctx->time_base.num * avctx->ticks_per_frame;
> +    }
> +
> +    if (param->rateControlMode) {
> +        param->maxQpAllowed = avctx->qmax;
> +        param->minQpAllowed = avctx->qmin;
> +    }
> +
> +    param->hierarchicalLevels = svt_enc->hierarchical_level;
> +    param->encMode = svt_enc->enc_mode;
> +    param->tier = svt_enc->tier;
> +    param->level = svt_enc->level;
> +    param->rateControlMode = svt_enc->rc_mode;
> +    param->sceneChangeDetection = svt_enc->scd;
> +    param->tune = svt_enc->tune;
> +    param->baseLayerSwitchMode = svt_enc->base_layer_switch_mode;
> +    param->qp = svt_enc->qp;
> +    param->accessUnitDelimiter = svt_enc->aud;
> +    param->asmType = svt_enc->asm_type;
> +
> +    param->intraRefreshType =  svt_enc->forced_idr + 1;
> +
> +    if (svt_enc->la_depth != -1)
> +        param->lookAheadDistance = svt_enc->la_depth;
> +
> +    if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)
> +        param->codeVpsSpsPps = 0;
> +    else
> +        param->codeVpsSpsPps = 1;
> +
> +    param->codeEosNal = 1;
> +
> +    return EB_ErrorNone;
> +}
> +
> +static void read_in_data(EB_H265_ENC_CONFIGURATION *config,
> +                         const AVFrame *frame,
> +                         EB_BUFFERHEADERTYPE *header_ptr)
> +{
> +    uint8_t is16bit;
> +    uint64_t frame_size;
> +    EB_H265_ENC_INPUT *in_data = (EB_H265_ENC_INPUT *)header_ptr->pBuffer;
> +
> +    is16bit = config->encoderBitDepth > 8;
> +    frame_size = (uint64_t)(config->sourceWidth * config->sourceHeight) << is16bit;

frame size is better to use defined as int or uint32_t

> +
> +    in_data->luma = frame->data[0];
> +    in_data->cb = frame->data[1];
> +    in_data->cr = frame->data[2];
> +
> +    in_data->yStride = frame->linesize[0] >> is16bit;
> +    in_data->cbStride = frame->linesize[1] >> is16bit;
> +    in_data->crStride = frame->linesize[2] >> is16bit;
> +
> +    if (config->encoderColorFormat == EB_YUV420)
> +        frame_size *= 3/2u;
> +    else if (config->encoderColorFormat == EB_YUV422)
> +        frame_size *= 2u;
> +    else
> +        frame_size *= 3u;
> +
> +    header_ptr->nFilledLen += frame_size;

nFilledLen is uint32_t, frame_size is uint64_t

> +}
> +
> +static av_cold int eb_enc_init(AVCodecContext *avctx)
> +{
> +    SvtContext *svt_enc = avctx->priv_data;
> +    EB_ERRORTYPE svt_ret;
> +
> +    svt_enc->eos_flag = EOS_NOT_REACHED;
> +
> +    svt_ret = EbInitHandle(&svt_enc->svt_handle, svt_enc, &svt_enc->enc_params);
> +    if (svt_ret != EB_ErrorNone) {
> +        av_log(avctx, AV_LOG_ERROR, "Failed to init handle\n");
> +        return error_mapping(svt_ret);
> +    }
> +
> +    svt_ret = config_enc_params(&svt_enc->enc_params, avctx);
> +    if (svt_ret != EB_ErrorNone) {
> +        av_log(avctx, AV_LOG_ERROR, "Failed to config parameters\n");
> +        goto failed_init_handle;
> +    }
> +
> +    svt_ret = EbH265EncSetParameter(svt_enc->svt_handle, &svt_enc->enc_params);
> +    if (svt_ret != EB_ErrorNone) {
> +        av_log(avctx, AV_LOG_ERROR, "Failed to set parameters\n");
> +        goto failed_init_handle;
> +    }
> +
> +    svt_ret = EbInitEncoder(svt_enc->svt_handle);
> +    if (svt_ret != EB_ErrorNone) {
> +        av_log(avctx, AV_LOG_ERROR, "Failed to init encoder\n");
> +        goto failed_init_handle;
> +    }
> +
> +    if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
> +        EB_BUFFERHEADERTYPE *header_ptr = NULL;
> +
> +        svt_ret = EbH265EncStreamHeader(svt_enc->svt_handle, &header_ptr);
> +        if (svt_ret != EB_ErrorNone) {
> +            av_log(avctx, AV_LOG_ERROR, "Failed to build stream header\n");
> +            goto failed_init_encoder;
> +        }
> +
> +        avctx->extradata_size = header_ptr->nFilledLen;
> +        avctx->extradata = av_malloc(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
It's preferalbe to use av_mallocz

> +        if (!avctx->extradata) {
> +            av_log(avctx, AV_LOG_ERROR, "Failed to allocate extradata\n");
> +            svt_ret = EB_ErrorInsufficientResources;
> +            goto failed_init_encoder;
> +        }
> +        memcpy(avctx->extradata, header_ptr->pBuffer, avctx->extradata_size);
> +        memset((void *)(avctx->extradata+avctx->extradata_size), 0, AV_INPUT_BUFFER_PADDING_SIZE);
Don't need it if use av_mallocz

> +    }
> +
> +    svt_ret = alloc_buffer(svt_enc);
> +    if (svt_ret != EB_ErrorNone) {
> +        av_log(avctx, AV_LOG_ERROR, "Failed to alloc data buffer\n");
> +        goto failed_init_encoder;
> +    }
> +    return 0;
> +
> +failed_init_encoder:
> +    EbDeinitEncoder(svt_enc->svt_handle);
> +failed_init_handle:
> +    EbDeinitHandle(svt_enc->svt_handle);
> +    svt_enc->svt_handle = NULL;
> +    svt_enc = NULL;
> +    return error_mapping(svt_ret);
> +}
> +
> +static int eb_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
> +                           const AVFrame *frame, int *got_packet)
> +{
> +    SvtContext *svt_enc = avctx->priv_data;
> +    EB_BUFFERHEADERTYPE *header_ptr = &svt_enc->in_buf;
> +    EB_ERRORTYPE svt_ret;
> +    int av_ret;
> +
> +    if (EOS_RECEIVED == svt_enc->eos_flag) {
> +        *got_packet = 0;
> +        return 0;
> +    }
> +
> +    if (!frame) {
> +        if (!svt_enc->eos_flag) {
> +            svt_enc->eos_flag = EOS_SENT;
> +
> +            header_ptr->nAllocLen = 0;
> +            header_ptr->nFilledLen = 0;
> +            header_ptr->nTickCount = 0;
> +            header_ptr->pBuffer = NULL;
> +            header_ptr->nFlags = EB_BUFFERFLAG_EOS;
> +
> +            EbH265EncSendPicture(svt_enc->svt_handle, header_ptr);
> +
> +            av_log(avctx, AV_LOG_DEBUG, "Sent EOS\n");
> +        }
> +    } else {
> +        read_in_data(&svt_enc->enc_params, frame, header_ptr);
> +        header_ptr->pts = frame->pts;
> +
> +        EbH265EncSendPicture(svt_enc->svt_handle, header_ptr);
> +
> +        av_log(avctx, AV_LOG_DEBUG, "Sent PTS %"PRId64"\n", header_ptr->pts);
> +    }
> +
> +    header_ptr = NULL;
> +    svt_ret = EbH265GetPacket(svt_enc->svt_handle, &header_ptr, svt_enc->eos_flag);
> +
> +    if (svt_ret == EB_NoErrorEmptyQueue) {
> +        *got_packet = 0;
> +        av_log(avctx, AV_LOG_DEBUG, "Received none\n");
> +        return 0;
> +    }
> +
> +    av_log(avctx, AV_LOG_DEBUG, "Received PTS %"PRId64" packet\n", header_ptr->pts);
> +
> +    av_ret = ff_alloc_packet2(avctx, pkt, header_ptr->nFilledLen, 0);
> +    if (av_ret) {
> +        av_log(avctx, AV_LOG_ERROR, "Failed to allocate a packet\n");
> +        EbH265ReleaseOutBuffer(&header_ptr);
> +        return av_ret;
> +    }
> +
> +    memcpy(pkt->data, header_ptr->pBuffer, header_ptr->nFilledLen);
> +    pkt->size = header_ptr->nFilledLen;
> +    pkt->pts  = header_ptr->pts;
> +    pkt->dts  = header_ptr->dts;
> +
> +    if ((header_ptr->sliceType == EB_IDR_PICTURE) ||
> +        (header_ptr->sliceType == EB_I_PICTURE))
> +        pkt->flags |= AV_PKT_FLAG_KEY;

Can we think EB_I_PICTURE is keyframe?


> +    if (header_ptr->sliceType == EB_NON_REF_PICTURE)
> +        pkt->flags |= AV_PKT_FLAG_DISPOSABLE;
> +
> +    EbH265ReleaseOutBuffer(&header_ptr);
> +
> +    *got_packet = 1;
> +
> +    if (EB_BUFFERFLAG_EOS == header_ptr->nFlags)
> +       svt_enc->eos_flag = EOS_RECEIVED;
> +
> +    return 0;
> +}
> +
> +static av_cold int eb_enc_close(AVCodecContext *avctx)
> +{
> +    SvtContext *svt_enc = avctx->priv_data;
> +
> +    if (svt_enc) {
> +        free_buffer(svt_enc);
> +
> +        if (svt_enc->svt_handle) {
> +            EbDeinitEncoder(svt_enc->svt_handle);
> +            EbDeinitHandle(svt_enc->svt_handle);
> +            svt_enc->svt_handle = NULL;
> +        }
> +
> +        svt_enc = NULL;
> +    }
> +
> +    return 0;
> +}
> +
> +#define OFFSET(x) offsetof(SvtContext, x)
> +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
> +static const AVOption options[] = {
> +    { "asm_type", "Assembly instruction set type [0: C Only, 1: Auto]", OFFSET(asm_type),
> +      AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE },
> +
> +    { "aud", "Include Access Unit Delimiter", OFFSET(aud),
> +      AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE },
> +
> +    { "bl_mode", "Random Access Prediction Structure type setting", OFFSET(base_layer_switch_mode),
> +      AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE },
> +
> +    { "forced-idr", "If forcing keyframes, force them as IDR frames.", OFFSET(forced_idr),
> +      AV_OPT_TYPE_BOOL,   { .i64 = 0 }, 0, 1, VE },
> +
> +    { "hielevel", "Hierarchical prediction levels setting", OFFSET(hierarchical_level),
> +      AV_OPT_TYPE_INT, { .i64 = 3 }, 0, 3, VE , "hielevel"},
> +        { "flat",   NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 },  INT_MIN, INT_MAX, VE, "hielevel" },
> +        { "1 level", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 },  INT_MIN, INT_MAX, VE, "hielevel" },
> +        { "2 level", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 2 },  INT_MIN, INT_MAX, VE, "hielevel" },
> +        { "3 level", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 3 },  INT_MIN, INT_MAX, VE, "hielevel" },
> +
> +    { "la_depth", "Look ahead distance [0, 256]", OFFSET(la_depth),
> +      AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 256, VE },
> +
> +    { "level", "Set level (level_idc)", OFFSET(level),
> +      AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 0xff, VE, "level" },
> +
> +    { "preset", "Encoding preset [0, 12]",
> +      OFFSET(enc_mode), AV_OPT_TYPE_INT, { .i64 = 9 }, 0, 12, VE },

12 is report as deprecated for the latest library?

> +
> +    { "profile", "Profile setting, Main Still Picture Profile not supported", OFFSET(profile),
> +      AV_OPT_TYPE_INT, { .i64 = FF_PROFILE_HEVC_MAIN }, FF_PROFILE_HEVC_MAIN, FF_PROFILE_HEVC_REXT, VE, "profile"},

How about to add profile with string support like below:
+    { "main",         "",  0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_HEVC_MAIN },    0, 0, VE, "profile" },
+    { "main10",       "",  0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_HEVC_MAIN_10 }, 0, 0, VE, "profile" },
+    { "rext",         "",  0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_HEVC_REXT },    0, 0, VE, "profile" },

> +
> +    { "qp", "QP value for intra frames", OFFSET(qp),
> +      AV_OPT_TYPE_INT, { .i64 = 32 }, 0, 51, VE },
> + 

I think qp is used to force constant QP in cqp rate control mode.

> +    { "rc", "Bit rate control mode", OFFSET(rc_mode),
> +      AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE , "rc"},
> +        { "cqp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 },  INT_MIN, INT_MAX, VE, "rc" },
> +        { "vbr", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 },  INT_MIN, INT_MAX, VE, "rc" },
> +
> +    { "sc_detection", "Scene change detection", OFFSET(scd),
> +      AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE },
> +
> +    { "tier", "Set tier (general_tier_flag)", OFFSET(tier),
> +      AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE, "tier" },
> +        { "main", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, VE, "tier" },
> +        { "high", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, VE, "tier" },
> +
> +    { "tune", "Quality tuning mode", OFFSET(tune), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 2, VE, "tune" },
> +        { "sq", "Visually optimized mode", 0,
> +          AV_OPT_TYPE_CONST, { .i64 = 0 },  INT_MIN, INT_MAX, VE, "tune" },

It seems that the latest library support 1 only.

    if (config->tune != 1) {
        SVT_LOG("SVT [WARNING]: -tune is deprecated.\n");
        config->tune = 1;
    }

> +        { "oq",  "PSNR / SSIM optimized mode",  0,
> +          AV_OPT_TYPE_CONST, { .i64 = 1 },  INT_MIN, INT_MAX, VE, "tune" },
> +        { "vmaf", "VMAF optimized mode", 0,
> +          AV_OPT_TYPE_CONST, { .i64 = 2 },  INT_MIN, INT_MAX, VE, "tune" },
> +
> +    {NULL},
> +};
> +
> +static const AVClass class = {
> +    .class_name = "libsvt_hevc",
> +    .item_name  = av_default_item_name,
> +    .option     = options,
> +    .version    = LIBAVUTIL_VERSION_INT,
> +};
> +
> +static const AVCodecDefault eb_enc_defaults[] = {
> +    { "b",         "7M"    },
> +    { "flags",     "+cgop" },
> +    { "qmin",      "10"    },
> +    { "qmax",      "48"    },
> +    { "g",         "-2"    },

gop_size default to -1 is preferable although -2 is OK in the function.

> +    { NULL },
> +};
> +
> +AVCodec ff_libsvt_hevc_encoder = {
> +    .name           = "libsvt_hevc",
> +    .long_name      = NULL_IF_CONFIG_SMALL("SVT-HEVC(Scalable Video Technology for HEVC) encoder"),
> +    .priv_data_size = sizeof(SvtContext),
> +    .type           = AVMEDIA_TYPE_VIDEO,
> +    .id             = AV_CODEC_ID_HEVC,
> +    .init           = eb_enc_init,
> +    .encode2        = eb_encode_frame,
> +    .close          = eb_enc_close,
> +    .capabilities   = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS,

The code don't support to configure thread_count, so I think you'll get the same result without AV_CODEC_CAP_AUTO_THREADS.
 
> +    .pix_fmts       = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P,
> +                                                    AV_PIX_FMT_YUV420P10,
> +                                                    AV_PIX_FMT_YUV422P,
> +                                                    AV_PIX_FMT_YUV422P10,
> +                                                    AV_PIX_FMT_YUV444P,
> +                                                    AV_PIX_FMT_YUV444P10,
> +                                                    AV_PIX_FMT_NONE },
> +    .priv_class     = &class,
> +    .defaults       = eb_enc_defaults,
> +    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
> +    .wrapper_name   = "libsvt_hevc",
> +};
> diff --git a/libavcodec/version.h b/libavcodec/version.h
> index 2709163..3331d47 100644
> --- a/libavcodec/version.h
> +++ b/libavcodec/version.h
> @@ -28,7 +28,7 @@
>  #include "libavutil/version.h"
>  
>  #define LIBAVCODEC_VERSION_MAJOR  58
> -#define LIBAVCODEC_VERSION_MINOR  53
> +#define LIBAVCODEC_VERSION_MINOR  54

failed to apply for master is updated to 55 already

>  #define LIBAVCODEC_VERSION_MICRO 100
>  
>  #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
> -- 
> 1.8.3.1
> 
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
Zhong Li July 30, 2019, 7:49 a.m. UTC | #3
> > +AVCodec ff_libsvt_hevc_encoder = {

> > +    .name           = "libsvt_hevc",

> > +    .long_name      = NULL_IF_CONFIG_SMALL("SVT-HEVC(Scalable

> Video Technology for HEVC) encoder"),

> > +    .priv_data_size = sizeof(SvtContext),

> > +    .type           = AVMEDIA_TYPE_VIDEO,

> > +    .id             = AV_CODEC_ID_HEVC,

> > +    .init           = eb_enc_init,

> > +    .encode2        = eb_encode_frame,

> > +    .close          = eb_enc_close,

> > +    .capabilities   = AV_CODEC_CAP_DELAY |

> AV_CODEC_CAP_AUTO_THREADS,

> 

> The code don't support to configure thread_count, so I think you'll get the

> same result without AV_CODEC_CAP_AUTO_THREADS.


This was pointed out by Mark Thompson on patch V4. 
It is a problem how comment can be well addressed and avoid to be pointed out again and again.
James Almer July 30, 2019, 1:20 p.m. UTC | #4
On 7/30/2019 2:59 AM, Limin Wang wrote:
>> +    if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
>> +        EB_BUFFERHEADERTYPE *header_ptr = NULL;
>> +
>> +        svt_ret = EbH265EncStreamHeader(svt_enc->svt_handle, &header_ptr);
>> +        if (svt_ret != EB_ErrorNone) {
>> +            av_log(avctx, AV_LOG_ERROR, "Failed to build stream header\n");
>> +            goto failed_init_encoder;
>> +        }
>> +
>> +        avctx->extradata_size = header_ptr->nFilledLen;
>> +        avctx->extradata = av_malloc(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
> It's preferalbe to use av_mallocz

He was asked to do it this way as it's faster. No need to zero the whole
buffer if it's going to be written to immediately afterwards. Only the
trailing padding bytes needs to be zeroed.
Carl Eugen Hoyos July 30, 2019, 5:48 p.m. UTC | #5
Am Di., 30. Juli 2019 um 15:20 Uhr schrieb James Almer <jamrial@gmail.com>:
>
> On 7/30/2019 2:59 AM, Limin Wang wrote:
> >> +    if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
> >> +        EB_BUFFERHEADERTYPE *header_ptr = NULL;
> >> +
> >> +        svt_ret = EbH265EncStreamHeader(svt_enc->svt_handle, &header_ptr);
> >> +        if (svt_ret != EB_ErrorNone) {
> >> +            av_log(avctx, AV_LOG_ERROR, "Failed to build stream header\n");
> >> +            goto failed_init_encoder;
> >> +        }
> >> +
> >> +        avctx->extradata_size = header_ptr->nFilledLen;
> >> +        avctx->extradata = av_malloc(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
> > It's preferalbe to use av_mallocz
>
> He was asked to do it this way as it's faster. No need to zero the whole
> buffer if it's going to be written to immediately afterwards. Only the
> trailing padding bytes needs to be zeroed.

In this case I suspect there is an unneeded cast in the next line.

Carl Eugen
Lance Wang July 30, 2019, 11:05 p.m. UTC | #6
On Tue, Jul 30, 2019 at 07:48:43PM +0200, Carl Eugen Hoyos wrote:
> Am Di., 30. Juli 2019 um 15:20 Uhr schrieb James Almer <jamrial@gmail.com>:
> >
> > On 7/30/2019 2:59 AM, Limin Wang wrote:
> > >> +    if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
> > >> +        EB_BUFFERHEADERTYPE *header_ptr = NULL;
> > >> +
> > >> +        svt_ret = EbH265EncStreamHeader(svt_enc->svt_handle, &header_ptr);
> > >> +        if (svt_ret != EB_ErrorNone) {
> > >> +            av_log(avctx, AV_LOG_ERROR, "Failed to build stream header\n");
> > >> +            goto failed_init_encoder;
> > >> +        }
> > >> +
> > >> +        avctx->extradata_size = header_ptr->nFilledLen;
> > >> +        avctx->extradata = av_malloc(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
> > > It's preferalbe to use av_mallocz
> >
> > He was asked to do it this way as it's faster. No need to zero the whole
> > buffer if it's going to be written to immediately afterwards. Only the
> > trailing padding bytes needs to be zeroed.
> 
> In this case I suspect there is an unneeded cast in the next line.

It's very confusing to allocate with extra padding size, then memcpy the
actual data size, then zero the padding data.

IMO, the padding size is used for the bitstream optimized buffer read(32 or 64
bit for minimal at least). If it's memcpy, do we need malloc with extra 
AV_INPUT_BUFFER_PADDING_SIZE?


> 
> Carl Eugen
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
Lance Wang July 30, 2019, 11:24 p.m. UTC | #7
On Tue, Jul 30, 2019 at 07:48:43PM +0200, Carl Eugen Hoyos wrote:
> Am Di., 30. Juli 2019 um 15:20 Uhr schrieb James Almer <jamrial@gmail.com>:
> >
> > On 7/30/2019 2:59 AM, Limin Wang wrote:
> > >> +    if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
> > >> +        EB_BUFFERHEADERTYPE *header_ptr = NULL;
> > >> +
> > >> +        svt_ret = EbH265EncStreamHeader(svt_enc->svt_handle, &header_ptr);
> > >> +        if (svt_ret != EB_ErrorNone) {
> > >> +            av_log(avctx, AV_LOG_ERROR, "Failed to build stream header\n");
> > >> +            goto failed_init_encoder;
> > >> +        }
> > >> +
> > >> +        avctx->extradata_size = header_ptr->nFilledLen;
> > >> +        avctx->extradata = av_malloc(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
> > > It's preferalbe to use av_mallocz
> >
> > He was asked to do it this way as it's faster. No need to zero the whole
> > buffer if it's going to be written to immediately afterwards. Only the
> > trailing padding bytes needs to be zeroed.
> 
> In this case I suspect there is an unneeded cast in the next line.

FYI:
libavcodec/avcodec.h comments for the extradata_size
      * The allocated memory should be AV_INPUT_BUFFER_PADDING_SIZE bytes larger
      * than extradata_size to avoid problems if it is read with the bitstream reader.
      * The bytewise contents of extradata must not depend on the architecture or CPU endianness.
      * Must be allocated with the av_malloc() family of functions.


> 
> Carl Eugen
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
Jing SUN July 31, 2019, 2:15 a.m. UTC | #8
-----Original Message-----
From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf Of Li, Zhong

Sent: Tuesday, July 30, 2019 3:49 PM
To: FFmpeg development discussions and patches <ffmpeg-devel@ffmpeg.org>
Subject: Re: [FFmpeg-devel] [PATCH v15 1/2] lavc/svt_hevc: add libsvt hevc encoder wrapper

> > +AVCodec ff_libsvt_hevc_encoder = {

> > +    .name           = "libsvt_hevc",

> > +    .long_name      = NULL_IF_CONFIG_SMALL("SVT-HEVC(Scalable

> Video Technology for HEVC) encoder"),

> > +    .priv_data_size = sizeof(SvtContext),

> > +    .type           = AVMEDIA_TYPE_VIDEO,

> > +    .id             = AV_CODEC_ID_HEVC,

> > +    .init           = eb_enc_init,

> > +    .encode2        = eb_encode_frame,

> > +    .close          = eb_enc_close,

> > +    .capabilities   = AV_CODEC_CAP_DELAY |

> AV_CODEC_CAP_AUTO_THREADS,

> 

> The code don't support to configure thread_count, so I think you'll 

> get the same result without AV_CODEC_CAP_AUTO_THREADS.


> This was pointed out by Mark Thompson on patch V4. 

> It is a problem how comment can be well addressed and avoid to be pointed out again and again. 


I got started based on V5 and V6 is my first submission. Thanks for showing me the information. I am looking into it. 

Regards,
Sun, Jing
Jing SUN July 31, 2019, 2:18 a.m. UTC | #9
-----Original Message-----
From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf Of Limin Wang

Sent: Wednesday, July 31, 2019 7:05 AM
To: FFmpeg development discussions and patches <ffmpeg-devel@ffmpeg.org>
Subject: Re: [FFmpeg-devel] [PATCH v15 1/2] lavc/svt_hevc: add libsvt hevc encoder wrapper

On Tue, Jul 30, 2019 at 07:48:43PM +0200, Carl Eugen Hoyos wrote:
> Am Di., 30. Juli 2019 um 15:20 Uhr schrieb James Almer <jamrial@gmail.com>:

> >

> > On 7/30/2019 2:59 AM, Limin Wang wrote:

> > >> +    if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {

> > >> +        EB_BUFFERHEADERTYPE *header_ptr = NULL;

> > >> +

> > >> +        svt_ret = EbH265EncStreamHeader(svt_enc->svt_handle, &header_ptr);

> > >> +        if (svt_ret != EB_ErrorNone) {

> > >> +            av_log(avctx, AV_LOG_ERROR, "Failed to build stream header\n");

> > >> +            goto failed_init_encoder;

> > >> +        }

> > >> +

> > >> +        avctx->extradata_size = header_ptr->nFilledLen;

> > >> +        avctx->extradata = av_malloc(avctx->extradata_size + 

> > >> + AV_INPUT_BUFFER_PADDING_SIZE);

> > > It's preferalbe to use av_mallocz

> >

> > He was asked to do it this way as it's faster. No need to zero the 

> > whole buffer if it's going to be written to immediately afterwards. 

> > Only the trailing padding bytes needs to be zeroed.

> 

> In this case I suspect there is an unneeded cast in the next line.


> It's very confusing to allocate with extra padding size, then memcpy the actual data size, then zero the padding data.


> IMO, the padding size is used for the bitstream optimized buffer read(32 or 64 bit for minimal at least). If it's memcpy, do we need malloc with extra AV_INPUT_BUFFER_PADDING_SIZE?


Thanks for everyone's advices and I am considering on how to make this not confusing. Will update the patch later.
BTW, it's a "she" :-).

Regards,
Sun, Jing
Zhong Li July 31, 2019, 3:33 a.m. UTC | #10
> From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf

> Of Sun, Jing A

> Sent: Wednesday, July 31, 2019 10:16 AM

> To: FFmpeg development discussions and patches

> <ffmpeg-devel@ffmpeg.org>

> Subject: Re: [FFmpeg-devel] [PATCH v15 1/2] lavc/svt_hevc: add libsvt hevc

> encoder wrapper

> 

> -----Original Message-----

> From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf

> Of Li, Zhong

> Sent: Tuesday, July 30, 2019 3:49 PM

> To: FFmpeg development discussions and patches

> <ffmpeg-devel@ffmpeg.org>

> Subject: Re: [FFmpeg-devel] [PATCH v15 1/2] lavc/svt_hevc: add libsvt hevc

> encoder wrapper

> 

> > > +AVCodec ff_libsvt_hevc_encoder = {

> > > +    .name           = "libsvt_hevc",

> > > +    .long_name      =

> NULL_IF_CONFIG_SMALL("SVT-HEVC(Scalable

> > Video Technology for HEVC) encoder"),

> > > +    .priv_data_size = sizeof(SvtContext),

> > > +    .type           = AVMEDIA_TYPE_VIDEO,

> > > +    .id             = AV_CODEC_ID_HEVC,

> > > +    .init           = eb_enc_init,

> > > +    .encode2        = eb_encode_frame,

> > > +    .close          = eb_enc_close,

> > > +    .capabilities   = AV_CODEC_CAP_DELAY |

> > AV_CODEC_CAP_AUTO_THREADS,

> >

> > The code don't support to configure thread_count, so I think you'll

> > get the same result without AV_CODEC_CAP_AUTO_THREADS.

> 

> > This was pointed out by Mark Thompson on patch V4.

> > It is a problem how comment can be well addressed and avoid to be

> pointed out again and again.

> 

> I got started based on V5 and V6 is my first submission. Thanks for showing

> me the information. I am looking into it.


It was also mentioned in svt-av1 patch https://patchwork.ffmpeg.org/patch/13912/:
* Expose threads setting since AV_CODEC_CAP_AUTO_THREADS declared
James Almer July 31, 2019, 3:39 a.m. UTC | #11
On 7/30/2019 11:18 PM, Sun, Jing A wrote:
> -----Original Message-----
> From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf Of Limin Wang
> Sent: Wednesday, July 31, 2019 7:05 AM
> To: FFmpeg development discussions and patches <ffmpeg-devel@ffmpeg.org>
> Subject: Re: [FFmpeg-devel] [PATCH v15 1/2] lavc/svt_hevc: add libsvt hevc encoder wrapper
> 
> On Tue, Jul 30, 2019 at 07:48:43PM +0200, Carl Eugen Hoyos wrote:
>> Am Di., 30. Juli 2019 um 15:20 Uhr schrieb James Almer <jamrial@gmail.com>:
>>>
>>> On 7/30/2019 2:59 AM, Limin Wang wrote:
>>>>> +    if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
>>>>> +        EB_BUFFERHEADERTYPE *header_ptr = NULL;
>>>>> +
>>>>> +        svt_ret = EbH265EncStreamHeader(svt_enc->svt_handle, &header_ptr);
>>>>> +        if (svt_ret != EB_ErrorNone) {
>>>>> +            av_log(avctx, AV_LOG_ERROR, "Failed to build stream header\n");
>>>>> +            goto failed_init_encoder;
>>>>> +        }
>>>>> +
>>>>> +        avctx->extradata_size = header_ptr->nFilledLen;
>>>>> +        avctx->extradata = av_malloc(avctx->extradata_size + 
>>>>> + AV_INPUT_BUFFER_PADDING_SIZE);
>>>> It's preferalbe to use av_mallocz
>>>
>>> He was asked to do it this way as it's faster. No need to zero the 
>>> whole buffer if it's going to be written to immediately afterwards. 
>>> Only the trailing padding bytes needs to be zeroed.
>>
>> In this case I suspect there is an unneeded cast in the next line.
> 
>> It's very confusing to allocate with extra padding size, then memcpy the actual data size, then zero the padding data.
> 
>> IMO, the padding size is used for the bitstream optimized buffer read(32 or 64 bit for minimal at least). If it's memcpy, do we need malloc with extra AV_INPUT_BUFFER_PADDING_SIZE?
> 
> Thanks for everyone's advices and I am considering on how to make this not confusing. Will update the patch later.
> BTW, it's a "she" :-).
> 
> Regards,
> Sun, Jing

Simply remove the void* cast in the memset() line. "avctx->extradata +
avctx->extradata_size" is acceptable as an argument.
Jing SUN July 31, 2019, 8:24 a.m. UTC | #12
-----Original Message-----
From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf Of Li, Zhong

Sent: Wednesday, July 31, 2019 11:33 AM
To: FFmpeg development discussions and patches <ffmpeg-devel@ffmpeg.org>
Subject: Re: [FFmpeg-devel] [PATCH v15 1/2] lavc/svt_hevc: add libsvt hevc encoder wrapper
 
> > > > +AVCodec ff_libsvt_hevc_encoder = {

> > > > +    .name           = "libsvt_hevc",

> > > > +    .long_name      =

> > NULL_IF_CONFIG_SMALL("SVT-HEVC(Scalable

> > > Video Technology for HEVC) encoder"),

> > > > +    .priv_data_size = sizeof(SvtContext),

> > > > +    .type           = AVMEDIA_TYPE_VIDEO,

> > > > +    .id             = AV_CODEC_ID_HEVC,

> > > > +    .init           = eb_enc_init,

> > > > +    .encode2        = eb_encode_frame,

> > > > +    .close          = eb_enc_close,

> > > > +    .capabilities   = AV_CODEC_CAP_DELAY |

> > > AV_CODEC_CAP_AUTO_THREADS,

> > >

> > > The code don't support to configure thread_count, so I think you'll 

> > > get the same result without AV_CODEC_CAP_AUTO_THREADS.

> > 

> > > This was pointed out by Mark Thompson on patch V4.

> > > It is a problem how comment can be well addressed and avoid to be

> > pointed out again and again.

> > 

> > I got started based on V5 and V6 is my first submission. Thanks for 

> > showing me the information. I am looking into it.

>It was also mentioned in svt-av1 patch https://patchwork.ffmpeg.org/patch/13912/:

>* Expose threads setting since AV_CODEC_CAP_AUTO_THREADS declared _______________________________________________




I checked out the history in https://patchwork.ffmpeg.org/patch/11347/:

Mark's remarks:
> +    .capabilities   = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS,

Threads aren't actually mentioned at all above.  Does that mean the encoder will always make as many threads as it wants, and the user has no separate control?

And from the macro definition:
/**
 * Codec supports avctx->thread_count == 0 (auto).
 */
#define AV_CODEC_CAP_AUTO_THREADS        (1 << 15)

static void validate_thread_parameters(AVCodecContext *avctx)
{
    ...
    } else if (!(avctx->codec->capabilities & AV_CODEC_CAP_AUTO_THREADS)) {
        avctx->thread_count       = 1;
        avctx->active_thread_type = 0;
    }
    ...
}

I think it's right to declare the codec with that capability as long as the codec indeed supports the auto thread count. It's not wrong that we have declared that. And to Mark's question, the answer is "Yes, the SVT HEVC encoder always makes as many threads as it wants". It checks the CPU cores and decides the count of working threads based on the number of cores to ensure the best performance, and by now users have no separate control on it.

We have been considering if we shall add such a controlling interface to SVT HEVC lib and how. The code lines of handling avctx->thread_count in this avcodec is possible to get added in the future. Right now, adding an empty interface without implementation supported by SVT HEVC lib makes no sense.
 
Regards,
Sun, Jing
Jing SUN July 31, 2019, 8:26 a.m. UTC | #13
-----Original Message-----
From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf Of James Almer

Sent: Wednesday, July 31, 2019 11:40 AM
To: ffmpeg-devel@ffmpeg.org
Subject: Re: [FFmpeg-devel] [PATCH v15 1/2] lavc/svt_hevc: add libsvt hevc encoder wrapper

> Simply remove the void* cast in the memset() line. "avctx->extradata +

> avctx->extradata_size" is acceptable as an argument.


Thanks James! It's modified and submitted as V16.

Regards,
Sun, Jing
diff mbox

Patch

diff --git a/configure b/configure
index 7cea9d4..8f2f065 100755
--- a/configure
+++ b/configure
@@ -264,6 +264,7 @@  External library support:
   --enable-libspeex        enable Speex de/encoding via libspeex [no]
   --enable-libsrt          enable Haivision SRT protocol via libsrt [no]
   --enable-libssh          enable SFTP protocol via libssh [no]
+  --enable-libsvthevc      enable HEVC encoding via svt [no]
   --enable-libtensorflow   enable TensorFlow as a DNN module backend
                            for DNN based filters like sr [no]
   --enable-libtesseract    enable Tesseract, needed for ocr filter [no]
@@ -1787,6 +1788,7 @@  EXTERNAL_LIBRARY_LIST="
     libspeex
     libsrt
     libssh
+    libsvthevc
     libtensorflow
     libtesseract
     libtheora
@@ -3180,6 +3182,7 @@  libshine_encoder_select="audio_frame_queue"
 libspeex_decoder_deps="libspeex"
 libspeex_encoder_deps="libspeex"
 libspeex_encoder_select="audio_frame_queue"
+libsvt_hevc_encoder_deps="libsvthevc"
 libtheora_encoder_deps="libtheora"
 libtwolame_encoder_deps="libtwolame"
 libvo_amrwbenc_encoder_deps="libvo_amrwbenc"
@@ -6226,6 +6229,7 @@  enabled libsoxr           && require libsoxr soxr.h soxr_create -lsoxr
 enabled libssh            && require_pkg_config libssh libssh libssh/sftp.h sftp_init
 enabled libspeex          && require_pkg_config libspeex speex speex/speex.h speex_decoder_init
 enabled libsrt            && require_pkg_config libsrt "srt >= 1.3.0" srt/srt.h srt_socket
+enabled libsvthevc        && require_pkg_config libsvthevc SvtHevcEnc EbApi.h EbInitHandle
 enabled libtensorflow     && require libtensorflow tensorflow/c/c_api.h TF_Version -ltensorflow
 enabled libtesseract      && require_pkg_config libtesseract tesseract tesseract/capi.h TessBaseAPICreate
 enabled libtheora         && require libtheora theora/theoraenc.h th_info_init -ltheoraenc -ltheoradec -logg
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index edccd73..7eb13de 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -991,6 +991,7 @@  OBJS-$(CONFIG_LIBOPUS_ENCODER)            += libopusenc.o libopus.o     \
 OBJS-$(CONFIG_LIBSHINE_ENCODER)           += libshine.o
 OBJS-$(CONFIG_LIBSPEEX_DECODER)           += libspeexdec.o
 OBJS-$(CONFIG_LIBSPEEX_ENCODER)           += libspeexenc.o
+OBJS-$(CONFIG_LIBSVT_HEVC_ENCODER)        += libsvt_hevc.o
 OBJS-$(CONFIG_LIBTHEORA_ENCODER)          += libtheoraenc.o
 OBJS-$(CONFIG_LIBTWOLAME_ENCODER)         += libtwolame.o
 OBJS-$(CONFIG_LIBVO_AMRWBENC_ENCODER)     += libvo-amrwbenc.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index d2f9a39..d8788a7 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -707,6 +707,7 @@  extern AVCodec ff_librsvg_decoder;
 extern AVCodec ff_libshine_encoder;
 extern AVCodec ff_libspeex_encoder;
 extern AVCodec ff_libspeex_decoder;
+extern AVCodec ff_libsvt_hevc_encoder;
 extern AVCodec ff_libtheora_encoder;
 extern AVCodec ff_libtwolame_encoder;
 extern AVCodec ff_libvo_amrwbenc_encoder;
diff --git a/libavcodec/libsvt_hevc.c b/libavcodec/libsvt_hevc.c
new file mode 100644
index 0000000..d9ac04c
--- /dev/null
+++ b/libavcodec/libsvt_hevc.c
@@ -0,0 +1,501 @@ 
+/*
+* Scalable Video Technology for HEVC encoder library plugin
+*
+* Copyright (c) 2019 Intel Corporation
+*
+* This file is part of FFmpeg.
+*
+* FFmpeg is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* FFmpeg is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "EbErrorCodes.h"
+#include "EbTime.h"
+#include "EbApi.h"
+
+#include "libavutil/common.h"
+#include "libavutil/frame.h"
+#include "libavutil/opt.h"
+
+#include "internal.h"
+#include "avcodec.h"
+
+typedef enum eos_status {
+    EOS_NOT_REACHED = 0,
+    EOS_SENT,
+    EOS_RECEIVED
+}EOS_STATUS;
+
+typedef struct SvtContext {
+    AVClass *class;
+
+    EB_H265_ENC_CONFIGURATION enc_params;
+    EB_COMPONENTTYPE *svt_handle;
+    EB_BUFFERHEADERTYPE in_buf;
+    EOS_STATUS eos_flag;
+
+    // User options.
+    int profile;
+    int hierarchical_level;
+    int enc_mode;
+    int tier;
+    int level;
+    int rc_mode;
+    int scd;
+    int tune;
+    int base_layer_switch_mode;
+    int qp;
+    int aud;
+    int asm_type;
+    int forced_idr;
+    int la_depth;
+} SvtContext;
+
+static int error_mapping(EB_ERRORTYPE svt_ret)
+{
+    switch (svt_ret) {
+    case EB_ErrorInsufficientResources:
+        return AVERROR(ENOMEM);
+
+    case EB_ErrorUndefined:
+    case EB_ErrorInvalidComponent:
+    case EB_ErrorBadParameter:
+        return AVERROR(EINVAL);
+
+    case EB_ErrorDestroyThreadFailed:
+    case EB_ErrorSemaphoreUnresponsive:
+    case EB_ErrorDestroySemaphoreFailed:
+    case EB_ErrorCreateMutexFailed:
+    case EB_ErrorMutexUnresponsive:
+    case EB_ErrorDestroyMutexFailed:
+        return AVERROR_EXTERNAL;
+
+    case EB_NoErrorEmptyQueue:
+        return AVERROR(EAGAIN);
+
+    case EB_ErrorNone:
+        return 0;
+
+    default:
+        return AVERROR_UNKNOWN;
+    }
+}
+
+static void free_buffer(SvtContext *svt_enc)
+{
+    uint8_t *in_data = svt_enc->in_buf.pBuffer;
+
+    av_freep(&in_data);
+}
+
+static EB_ERRORTYPE alloc_buffer(SvtContext *svt_enc)
+{
+    EB_BUFFERHEADERTYPE *in_buf = &svt_enc->in_buf;
+    EB_H265_ENC_INPUT *in_data = NULL;
+
+    memset(in_buf, 0, sizeof(*in_buf));
+    in_buf->nSize = sizeof(*in_buf);
+    in_buf->sliceType = EB_INVALID_PICTURE;
+
+    in_data = (EB_H265_ENC_INPUT *)av_mallocz(sizeof(*in_data));
+    if (in_data) {
+        in_buf->pBuffer = (uint8_t *)in_data;
+        return EB_ErrorNone;
+    } else {
+        return EB_ErrorInsufficientResources;
+    }
+}
+
+static int config_enc_params(EB_H265_ENC_CONFIGURATION *param,
+                             AVCodecContext *avctx)
+{
+    SvtContext *svt_enc = avctx->priv_data;
+
+    param->sourceWidth = avctx->width;
+    param->sourceHeight = avctx->height;
+
+    if ((avctx->pix_fmt == AV_PIX_FMT_YUV420P10) ||
+        (avctx->pix_fmt == AV_PIX_FMT_YUV422P10) ||
+        (avctx->pix_fmt == AV_PIX_FMT_YUV444P10)) {
+        av_log(avctx, AV_LOG_DEBUG, "Set 10 bits depth input\n");
+        param->encoderBitDepth = 10;
+    } else {
+        av_log(avctx, AV_LOG_DEBUG, "Set 8 bits depth input\n");
+        param->encoderBitDepth = 8;
+    }
+
+    if ((avctx->pix_fmt == AV_PIX_FMT_YUV420P) ||
+        (avctx->pix_fmt == AV_PIX_FMT_YUV420P10))
+        param->encoderColorFormat = EB_YUV420;
+    else if ((avctx->pix_fmt == AV_PIX_FMT_YUV422P) ||
+             (avctx->pix_fmt == AV_PIX_FMT_YUV422P10))
+        param->encoderColorFormat = EB_YUV422;
+    else
+        param->encoderColorFormat = EB_YUV444;
+
+    param->profile = svt_enc->profile;
+
+    if (FF_PROFILE_HEVC_MAIN_STILL_PICTURE == param->profile) {
+        av_log(avctx, AV_LOG_ERROR, "Main Still Picture Profile not supported\n");
+        return EB_ErrorBadParameter;
+    }
+
+    if ((param->encoderColorFormat >= EB_YUV422) &&
+        (param->profile != FF_PROFILE_HEVC_REXT)) {
+        av_log(avctx, AV_LOG_WARNING, "Rext Profile forced for 422 or 444\n");
+        param->profile = FF_PROFILE_HEVC_REXT;
+    }
+
+    if ((FF_PROFILE_HEVC_MAIN == param->profile) &&
+        (param->encoderBitDepth > 8)) {
+        av_log(avctx, AV_LOG_WARNING, "Main10 Profile forced for 10 bits\n");
+        param->profile = FF_PROFILE_HEVC_MAIN_10;
+    }
+
+    param->targetBitRate = avctx->bit_rate;
+
+    if (avctx->gop_size > 0)
+        param->intraPeriodLength = avctx->gop_size - 1;
+
+    if ((avctx->framerate.num > 0) && (avctx->framerate.den > 0)) {
+        param->frameRateNumerator = avctx->framerate.num;
+        param->frameRateDenominator =
+            avctx->framerate.den * avctx->ticks_per_frame;
+    } else {
+        param->frameRateNumerator = avctx->time_base.den;
+        param->frameRateDenominator =
+            avctx->time_base.num * avctx->ticks_per_frame;
+    }
+
+    if (param->rateControlMode) {
+        param->maxQpAllowed = avctx->qmax;
+        param->minQpAllowed = avctx->qmin;
+    }
+
+    param->hierarchicalLevels = svt_enc->hierarchical_level;
+    param->encMode = svt_enc->enc_mode;
+    param->tier = svt_enc->tier;
+    param->level = svt_enc->level;
+    param->rateControlMode = svt_enc->rc_mode;
+    param->sceneChangeDetection = svt_enc->scd;
+    param->tune = svt_enc->tune;
+    param->baseLayerSwitchMode = svt_enc->base_layer_switch_mode;
+    param->qp = svt_enc->qp;
+    param->accessUnitDelimiter = svt_enc->aud;
+    param->asmType = svt_enc->asm_type;
+
+    param->intraRefreshType =  svt_enc->forced_idr + 1;
+
+    if (svt_enc->la_depth != -1)
+        param->lookAheadDistance = svt_enc->la_depth;
+
+    if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)
+        param->codeVpsSpsPps = 0;
+    else
+        param->codeVpsSpsPps = 1;
+
+    param->codeEosNal = 1;
+
+    return EB_ErrorNone;
+}
+
+static void read_in_data(EB_H265_ENC_CONFIGURATION *config,
+                         const AVFrame *frame,
+                         EB_BUFFERHEADERTYPE *header_ptr)
+{
+    uint8_t is16bit;
+    uint64_t frame_size;
+    EB_H265_ENC_INPUT *in_data = (EB_H265_ENC_INPUT *)header_ptr->pBuffer;
+
+    is16bit = config->encoderBitDepth > 8;
+    frame_size = (uint64_t)(config->sourceWidth * config->sourceHeight) << is16bit;
+
+    in_data->luma = frame->data[0];
+    in_data->cb = frame->data[1];
+    in_data->cr = frame->data[2];
+
+    in_data->yStride = frame->linesize[0] >> is16bit;
+    in_data->cbStride = frame->linesize[1] >> is16bit;
+    in_data->crStride = frame->linesize[2] >> is16bit;
+
+    if (config->encoderColorFormat == EB_YUV420)
+        frame_size *= 3/2u;
+    else if (config->encoderColorFormat == EB_YUV422)
+        frame_size *= 2u;
+    else
+        frame_size *= 3u;
+
+    header_ptr->nFilledLen += frame_size;
+}
+
+static av_cold int eb_enc_init(AVCodecContext *avctx)
+{
+    SvtContext *svt_enc = avctx->priv_data;
+    EB_ERRORTYPE svt_ret;
+
+    svt_enc->eos_flag = EOS_NOT_REACHED;
+
+    svt_ret = EbInitHandle(&svt_enc->svt_handle, svt_enc, &svt_enc->enc_params);
+    if (svt_ret != EB_ErrorNone) {
+        av_log(avctx, AV_LOG_ERROR, "Failed to init handle\n");
+        return error_mapping(svt_ret);
+    }
+
+    svt_ret = config_enc_params(&svt_enc->enc_params, avctx);
+    if (svt_ret != EB_ErrorNone) {
+        av_log(avctx, AV_LOG_ERROR, "Failed to config parameters\n");
+        goto failed_init_handle;
+    }
+
+    svt_ret = EbH265EncSetParameter(svt_enc->svt_handle, &svt_enc->enc_params);
+    if (svt_ret != EB_ErrorNone) {
+        av_log(avctx, AV_LOG_ERROR, "Failed to set parameters\n");
+        goto failed_init_handle;
+    }
+
+    svt_ret = EbInitEncoder(svt_enc->svt_handle);
+    if (svt_ret != EB_ErrorNone) {
+        av_log(avctx, AV_LOG_ERROR, "Failed to init encoder\n");
+        goto failed_init_handle;
+    }
+
+    if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
+        EB_BUFFERHEADERTYPE *header_ptr = NULL;
+
+        svt_ret = EbH265EncStreamHeader(svt_enc->svt_handle, &header_ptr);
+        if (svt_ret != EB_ErrorNone) {
+            av_log(avctx, AV_LOG_ERROR, "Failed to build stream header\n");
+            goto failed_init_encoder;
+        }
+
+        avctx->extradata_size = header_ptr->nFilledLen;
+        avctx->extradata = av_malloc(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
+        if (!avctx->extradata) {
+            av_log(avctx, AV_LOG_ERROR, "Failed to allocate extradata\n");
+            svt_ret = EB_ErrorInsufficientResources;
+            goto failed_init_encoder;
+        }
+        memcpy(avctx->extradata, header_ptr->pBuffer, avctx->extradata_size);
+        memset((void *)(avctx->extradata+avctx->extradata_size), 0, AV_INPUT_BUFFER_PADDING_SIZE);
+    }
+
+    svt_ret = alloc_buffer(svt_enc);
+    if (svt_ret != EB_ErrorNone) {
+        av_log(avctx, AV_LOG_ERROR, "Failed to alloc data buffer\n");
+        goto failed_init_encoder;
+    }
+    return 0;
+
+failed_init_encoder:
+    EbDeinitEncoder(svt_enc->svt_handle);
+failed_init_handle:
+    EbDeinitHandle(svt_enc->svt_handle);
+    svt_enc->svt_handle = NULL;
+    svt_enc = NULL;
+    return error_mapping(svt_ret);
+}
+
+static int eb_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+                           const AVFrame *frame, int *got_packet)
+{
+    SvtContext *svt_enc = avctx->priv_data;
+    EB_BUFFERHEADERTYPE *header_ptr = &svt_enc->in_buf;
+    EB_ERRORTYPE svt_ret;
+    int av_ret;
+
+    if (EOS_RECEIVED == svt_enc->eos_flag) {
+        *got_packet = 0;
+        return 0;
+    }
+
+    if (!frame) {
+        if (!svt_enc->eos_flag) {
+            svt_enc->eos_flag = EOS_SENT;
+
+            header_ptr->nAllocLen = 0;
+            header_ptr->nFilledLen = 0;
+            header_ptr->nTickCount = 0;
+            header_ptr->pBuffer = NULL;
+            header_ptr->nFlags = EB_BUFFERFLAG_EOS;
+
+            EbH265EncSendPicture(svt_enc->svt_handle, header_ptr);
+
+            av_log(avctx, AV_LOG_DEBUG, "Sent EOS\n");
+        }
+    } else {
+        read_in_data(&svt_enc->enc_params, frame, header_ptr);
+        header_ptr->pts = frame->pts;
+
+        EbH265EncSendPicture(svt_enc->svt_handle, header_ptr);
+
+        av_log(avctx, AV_LOG_DEBUG, "Sent PTS %"PRId64"\n", header_ptr->pts);
+    }
+
+    header_ptr = NULL;
+    svt_ret = EbH265GetPacket(svt_enc->svt_handle, &header_ptr, svt_enc->eos_flag);
+
+    if (svt_ret == EB_NoErrorEmptyQueue) {
+        *got_packet = 0;
+        av_log(avctx, AV_LOG_DEBUG, "Received none\n");
+        return 0;
+    }
+
+    av_log(avctx, AV_LOG_DEBUG, "Received PTS %"PRId64" packet\n", header_ptr->pts);
+
+    av_ret = ff_alloc_packet2(avctx, pkt, header_ptr->nFilledLen, 0);
+    if (av_ret) {
+        av_log(avctx, AV_LOG_ERROR, "Failed to allocate a packet\n");
+        EbH265ReleaseOutBuffer(&header_ptr);
+        return av_ret;
+    }
+
+    memcpy(pkt->data, header_ptr->pBuffer, header_ptr->nFilledLen);
+    pkt->size = header_ptr->nFilledLen;
+    pkt->pts  = header_ptr->pts;
+    pkt->dts  = header_ptr->dts;
+
+    if ((header_ptr->sliceType == EB_IDR_PICTURE) ||
+        (header_ptr->sliceType == EB_I_PICTURE))
+        pkt->flags |= AV_PKT_FLAG_KEY;
+    if (header_ptr->sliceType == EB_NON_REF_PICTURE)
+        pkt->flags |= AV_PKT_FLAG_DISPOSABLE;
+
+    EbH265ReleaseOutBuffer(&header_ptr);
+
+    *got_packet = 1;
+
+    if (EB_BUFFERFLAG_EOS == header_ptr->nFlags)
+       svt_enc->eos_flag = EOS_RECEIVED;
+
+    return 0;
+}
+
+static av_cold int eb_enc_close(AVCodecContext *avctx)
+{
+    SvtContext *svt_enc = avctx->priv_data;
+
+    if (svt_enc) {
+        free_buffer(svt_enc);
+
+        if (svt_enc->svt_handle) {
+            EbDeinitEncoder(svt_enc->svt_handle);
+            EbDeinitHandle(svt_enc->svt_handle);
+            svt_enc->svt_handle = NULL;
+        }
+
+        svt_enc = NULL;
+    }
+
+    return 0;
+}
+
+#define OFFSET(x) offsetof(SvtContext, x)
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+    { "asm_type", "Assembly instruction set type [0: C Only, 1: Auto]", OFFSET(asm_type),
+      AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE },
+
+    { "aud", "Include Access Unit Delimiter", OFFSET(aud),
+      AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE },
+
+    { "bl_mode", "Random Access Prediction Structure type setting", OFFSET(base_layer_switch_mode),
+      AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE },
+
+    { "forced-idr", "If forcing keyframes, force them as IDR frames.", OFFSET(forced_idr),
+      AV_OPT_TYPE_BOOL,   { .i64 = 0 }, 0, 1, VE },
+
+    { "hielevel", "Hierarchical prediction levels setting", OFFSET(hierarchical_level),
+      AV_OPT_TYPE_INT, { .i64 = 3 }, 0, 3, VE , "hielevel"},
+        { "flat",   NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 },  INT_MIN, INT_MAX, VE, "hielevel" },
+        { "1 level", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 },  INT_MIN, INT_MAX, VE, "hielevel" },
+        { "2 level", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 2 },  INT_MIN, INT_MAX, VE, "hielevel" },
+        { "3 level", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 3 },  INT_MIN, INT_MAX, VE, "hielevel" },
+
+    { "la_depth", "Look ahead distance [0, 256]", OFFSET(la_depth),
+      AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 256, VE },
+
+    { "level", "Set level (level_idc)", OFFSET(level),
+      AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 0xff, VE, "level" },
+
+    { "preset", "Encoding preset [0, 12]",
+      OFFSET(enc_mode), AV_OPT_TYPE_INT, { .i64 = 9 }, 0, 12, VE },
+
+    { "profile", "Profile setting, Main Still Picture Profile not supported", OFFSET(profile),
+      AV_OPT_TYPE_INT, { .i64 = FF_PROFILE_HEVC_MAIN }, FF_PROFILE_HEVC_MAIN, FF_PROFILE_HEVC_REXT, VE, "profile"},
+
+    { "qp", "QP value for intra frames", OFFSET(qp),
+      AV_OPT_TYPE_INT, { .i64 = 32 }, 0, 51, VE },
+
+    { "rc", "Bit rate control mode", OFFSET(rc_mode),
+      AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE , "rc"},
+        { "cqp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 },  INT_MIN, INT_MAX, VE, "rc" },
+        { "vbr", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 },  INT_MIN, INT_MAX, VE, "rc" },
+
+    { "sc_detection", "Scene change detection", OFFSET(scd),
+      AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE },
+
+    { "tier", "Set tier (general_tier_flag)", OFFSET(tier),
+      AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE, "tier" },
+        { "main", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, VE, "tier" },
+        { "high", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, VE, "tier" },
+
+    { "tune", "Quality tuning mode", OFFSET(tune), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 2, VE, "tune" },
+        { "sq", "Visually optimized mode", 0,
+          AV_OPT_TYPE_CONST, { .i64 = 0 },  INT_MIN, INT_MAX, VE, "tune" },
+        { "oq",  "PSNR / SSIM optimized mode",  0,
+          AV_OPT_TYPE_CONST, { .i64 = 1 },  INT_MIN, INT_MAX, VE, "tune" },
+        { "vmaf", "VMAF optimized mode", 0,
+          AV_OPT_TYPE_CONST, { .i64 = 2 },  INT_MIN, INT_MAX, VE, "tune" },
+
+    {NULL},
+};
+
+static const AVClass class = {
+    .class_name = "libsvt_hevc",
+    .item_name  = av_default_item_name,
+    .option     = options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
+static const AVCodecDefault eb_enc_defaults[] = {
+    { "b",         "7M"    },
+    { "flags",     "+cgop" },
+    { "qmin",      "10"    },
+    { "qmax",      "48"    },
+    { "g",         "-2"    },
+    { NULL },
+};
+
+AVCodec ff_libsvt_hevc_encoder = {
+    .name           = "libsvt_hevc",
+    .long_name      = NULL_IF_CONFIG_SMALL("SVT-HEVC(Scalable Video Technology for HEVC) encoder"),
+    .priv_data_size = sizeof(SvtContext),
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .id             = AV_CODEC_ID_HEVC,
+    .init           = eb_enc_init,
+    .encode2        = eb_encode_frame,
+    .close          = eb_enc_close,
+    .capabilities   = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS,
+    .pix_fmts       = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P,
+                                                    AV_PIX_FMT_YUV420P10,
+                                                    AV_PIX_FMT_YUV422P,
+                                                    AV_PIX_FMT_YUV422P10,
+                                                    AV_PIX_FMT_YUV444P,
+                                                    AV_PIX_FMT_YUV444P10,
+                                                    AV_PIX_FMT_NONE },
+    .priv_class     = &class,
+    .defaults       = eb_enc_defaults,
+    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
+    .wrapper_name   = "libsvt_hevc",
+};
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 2709163..3331d47 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -28,7 +28,7 @@ 
 #include "libavutil/version.h"
 
 #define LIBAVCODEC_VERSION_MAJOR  58
-#define LIBAVCODEC_VERSION_MINOR  53
+#define LIBAVCODEC_VERSION_MINOR  54
 #define LIBAVCODEC_VERSION_MICRO 100
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \