diff mbox

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

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

Commit Message

Jing SUN May 30, 2019, 11:04 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 | 510 +++++++++++++++++++++++++++++++++++++++++++++++
 libavcodec/version.h     |   2 +-
 5 files changed, 517 insertions(+), 1 deletion(-)
 create mode 100644 libavcodec/libsvt_hevc.c

Comments

James Almer May 30, 2019, 3:34 p.m. UTC | #1
On 5/30/2019 8:04 AM, 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 | 510 +++++++++++++++++++++++++++++++++++++++++++++++
>  libavcodec/version.h     |   2 +-
>  5 files changed, 517 insertions(+), 1 deletion(-)
>  create mode 100644 libavcodec/libsvt_hevc.c

[...]

> +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,

Why the switch to encode2? All previous versions were using the
send/receive API, and seeing SVT also uses a decoupled input/output API,
it was certainly the most adequate option.

Were you running into some issue? A quick look at v12 shows you were
using ff_alloc_packet2(), which afaik you shouldn't have. It's meant for
the encode2() API only, where user provided buffers are allowed, and it
alone does not ensure the packet will be reference counted, which is
required for the send/receive API.

> +    .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_YUV420P10,
> +                                                    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 7ed6071..8773fee 100644
> --- a/libavcodec/version.h
> +++ b/libavcodec/version.h
> @@ -29,7 +29,7 @@
>  
>  #define LIBAVCODEC_VERSION_MAJOR  58
>  #define LIBAVCODEC_VERSION_MINOR  52
> -#define LIBAVCODEC_VERSION_MICRO 102
> +#define LIBAVCODEC_VERSION_MICRO 103
>  
>  #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
>                                                 LIBAVCODEC_VERSION_MINOR, \
>
Jing SUN May 31, 2019, 2:16 a.m. UTC | #2
-----Original Message-----
From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf Of James Almer

Sent: Thursday, May 30, 2019 11:35 PM
To: ffmpeg-devel@ffmpeg.org
Subject: Re: [FFmpeg-devel] [PATCH v13 1/2] lavc/svt_hevc: add libsvt hevc encoder wrapper

>Why the switch to encode2? All previous versions were using the send/receive API, and seeing SVT also uses a decoupled input/output API, it was certainly the most adequate option.

>Were you running into some issue? A quick look at v12 shows you were using ff_alloc_packet2(), which afaik you shouldn't have. It's meant for the encode2() API only, where user provided buffers are allowed, and it alone does not ensure the packet will be reference counted, which is required for the send/receive API.


Hi James,

Yes I indeed was running into an issue. Although SVT uses a decoupled input/output API, it calls the two by the below method:
    while(not stopped) {
    send_frame(one frame);
    if (receive_packet(one frame’s pkt) != empty)
        save_bitstream;
    }
In one round, none or only one packet is receive.

However, if using v12's send_frame/receive_packet implementation, it is possible that multiple of receive_packet are executed in one round.
    while(not stopped) {
        send_frame(one frame);
        while(1) {
            if (receive_packet(one frame’s pkt) == empty)
                break;
            else
                save_bitstream;
        }
    }

The first calling method's sequence is like:
    Send 579
    Receive 487
    Send 580
    Receive 496
    Send 581
    Receive 492
    Send 582
    Receive 490
    Send 583
    Receive 489
    Send 584
    Receive 491
    Send 585
    Receive 494
    Send 586
    Receive 493
    Send 587
    Receive 495
And the second one's is:
    Send 579
    Receive empty
    Send 580
    Receive 489
    Receive 491
    Receive 494
    Receive 493
    Receive 495
    Receive empty
    Send 581
    Receive 504
    Receive empty
    Send 582
    Receive empty
    Send 583
    Receive empty
    Send 584
    Receive 500
    Receive empty
    Send 585
    Receive empty
    Send 586
    Receive empty
    Send 587

When we input the source frame at the constant frequency 60, the first one's each second's output frames are ~60, [59, 61], while the second one's tends to be like 64(63) ->57(58) ->64(63) ->57(58)… 
Besides the average FPS, the stableness of each second's FPS is also important to us. So I changed the API to encode2, because in encode2, I can control the SVT's send_frame/receive_packet calling sequence, and let it not do receive_packet more than once in one round.

And thanks for the information on ff_alloc_packet2. I changed to use av_new_packet in v13 and hope it's OK.

Regards,
Sun, Jing
James Almer May 31, 2019, 2:38 a.m. UTC | #3
On 5/30/2019 11:16 PM, Sun, Jing A wrote:
> -----Original Message-----
> From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf Of James Almer
> Sent: Thursday, May 30, 2019 11:35 PM
> To: ffmpeg-devel@ffmpeg.org
> Subject: Re: [FFmpeg-devel] [PATCH v13 1/2] lavc/svt_hevc: add libsvt hevc encoder wrapper
> 
>> Why the switch to encode2? All previous versions were using the send/receive API, and seeing SVT also uses a decoupled input/output API, it was certainly the most adequate option.
>> Were you running into some issue? A quick look at v12 shows you were using ff_alloc_packet2(), which afaik you shouldn't have. It's meant for the encode2() API only, where user provided buffers are allowed, and it alone does not ensure the packet will be reference counted, which is required for the send/receive API.
> 
> Hi James,
> 
> Yes I indeed was running into an issue. Although SVT uses a decoupled input/output API, it calls the two by the below method:
>     while(not stopped) {
>     send_frame(one frame);
>     if (receive_packet(one frame’s pkt) != empty)
>         save_bitstream;
>     }
> In one round, none or only one packet is receive.
> 
> However, if using v12's send_frame/receive_packet implementation, it is possible that multiple of receive_packet are executed in one round.
>     while(not stopped) {
>         send_frame(one frame);
>         while(1) {
>             if (receive_packet(one frame’s pkt) == empty)
>                 break;
>             else
>                 save_bitstream;
>         }
>     }
> 
> The first calling method's sequence is like:
>     Send 579
>     Receive 487
>     Send 580
>     Receive 496
>     Send 581
>     Receive 492
>     Send 582
>     Receive 490
>     Send 583
>     Receive 489
>     Send 584
>     Receive 491
>     Send 585
>     Receive 494
>     Send 586
>     Receive 493
>     Send 587
>     Receive 495
> And the second one's is:
>     Send 579
>     Receive empty
>     Send 580
>     Receive 489
>     Receive 491
>     Receive 494
>     Receive 493
>     Receive 495
>     Receive empty
>     Send 581
>     Receive 504
>     Receive empty
>     Send 582
>     Receive empty
>     Send 583
>     Receive empty
>     Send 584
>     Receive 500
>     Receive empty
>     Send 585
>     Receive empty
>     Send 586
>     Receive empty
>     Send 587
> 
> When we input the source frame at the constant frequency 60, the first one's each second's output frames are ~60, [59, 61], while the second one's tends to be like 64(63) ->57(58) ->64(63) ->57(58)… 
> Besides the average FPS, the stableness of each second's FPS is also important to us. So I changed the API to encode2, because in encode2, I can control the SVT's send_frame/receive_packet calling sequence, and let it not do receive_packet more than once in one round.

Yes, i can reproduce what you describe with the ffmpeg.c CLI, where
avcodec_receive_frame is called in a while(1) loop until it returns
EAGAIN after each avcodec_send_frame call.
In the end it depends on how an API user implements
avcodec_send_frame/avcodec_receive_frame, but using the encode2 API for
this purpose is ok.

> 
> And thanks for the information on ff_alloc_packet2. I changed to use av_new_packet in v13 and hope it's OK.

No, with the encode2 API you should be using ff_alloc_packet2() instead.
As i said, the API user may provide it's own buffer in the avpacket
passed to avcodec_encode_video2(), which av_new_packet() would ignore
and unconditionally allocate a new one.

> 
> Regards,
> Sun, Jing
> 
> _______________________________________________
> 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 May 31, 2019, 2:41 a.m. UTC | #4
-----Original Message-----
From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf Of James Almer

Sent: Friday, May 31, 2019 10:38 AM
To: ffmpeg-devel@ffmpeg.org
Subject: Re: [FFmpeg-devel] [PATCH v13 1/2] lavc/svt_hevc: add libsvt hevc encoder wrapper

>No, with the encode2 API you should be using ff_alloc_packet2() instead.

>As i said, the API user may provide it's own buffer in the avpacket passed to avcodec_encode_video2(), which av_new_packet() would ignore and unconditionally allocate a new one.


Thanks for the guidance! I am modifying it and will submit the modification soon.
 
Regards,
Sun, Jing
diff mbox

Patch

diff --git a/configure b/configure
index 32fc263..9e29ad3 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
@@ -3179,6 +3181,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"
@@ -6210,6 +6213,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 6178d31..e27a7b6 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -706,6 +706,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..1c740e6
--- /dev/null
+++ b/libavcodec/libsvt_hevc.c
@@ -0,0 +1,510 @@ 
+/*
+* 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);
+}
+
+typedef struct TIME_LOG{
+    unsigned int pts;
+    int64_t time;
+} TIME_LOG;
+
+#define START_LOG_POS   20000
+#define TOTAL_LOG_COUNT 8192
+static TIME_LOG logs[TOTAL_LOG_COUNT], sent_logs[TOTAL_LOG_COUNT];
+static unsigned int frame_count = 0, sent_frame_count = 0;
+static int64_t start_time = 0;
+
+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)
+        return AVERROR_EOF;
+
+    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 %ld\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 %ld packet\n", header_ptr->pts);
+
+    av_ret = av_new_packet(pkt, header_ptr->nFilledLen);
+    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_YUV420P10,
+                                                    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 7ed6071..8773fee 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -29,7 +29,7 @@ 
 
 #define LIBAVCODEC_VERSION_MAJOR  58
 #define LIBAVCODEC_VERSION_MINOR  52
-#define LIBAVCODEC_VERSION_MICRO 102
+#define LIBAVCODEC_VERSION_MICRO 103
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
                                                LIBAVCODEC_VERSION_MINOR, \