[FFmpeg-devel] [PATCH] Provided support for MPEG-5 EVC (Essential Video Coding) codec

Andreas Rheinhardt andreas.rheinhardt at outlook.com
Tue Apr 5 20:37:02 EEST 2022


Dawid Kozinski:
> #######################################
> 1. Genaral info
> #######################################
> 
> The patch provided below contains integration layer between ffmpeg framework and EVC codec implementation.
> In nutshell it enable using EVC codec (encoding, decoding)  by the means of ffmpeg API. 
> I'd like to emphasize one more time, that (as mentioned before) that it isn't codec implementation. The provided implementation serves as integration layer between ffmpeg framework and EVC codec.
> 
> EVC codec has been published as two separate libraries. 
> The first one called XEVE (eXtra-fast Essential Video Encoder) is an opensource MPEG-5 EVC encoder.
> The second one called XEVD (eXtra-fast Essential Video Decoder ) is an opensource MPEG-5 EVC decoder.
> For more information on both libraries please follow the links below:
> * https://github.com/mpeg5/xeve 
> * https://github.com/mpeg5/xevd 

Patches for decoder and encoder should be separated; and the changes to
libavformat should also be in a separate patch (or even patches).

> 
> The patch provided below should be apply to FFmpeg 5.0 release (commit 911d7f167c30f27a042b8558dfcf012b3c20e858 release/5.0)

There is zero chance that new components are added to an already
released branch. You need to rebase this patch on top of master if you
want it mainlined.

> 
> #######################################
> 2. Building
> #######################################
> 
> 3.1. Download, build and install dependencies

There is no need to duplicate the build instructions for external
libraries in this commit message; providing the link to where the
library can be found is enough. (This is not marked as WIP, so I am
reviewing this as if you wanted this to be applied as is (with this
commit message); if this is not the intention of this submission and you
never intended for this to be part of the actually applied commit
message, you can ignore this comment and the next comments.)

> ---------------------------------------
> 2.2. Build ffmpeg with libxeve and libxevd
> ---------------------------------------
> It is required ffmpeg to be configfured with --enable-libxeve and --enable-libxevd

Mentioning this in the commit message is unnecessary (the reader of
ffmpeg commit messages is supposed to know a bit about ffmpeg).

> #######################################
> 3. Examples
> #######################################
> 
> Please find below examples on how to use EVC coded with ffmpeg commandline tool.
> 
> (All samples are available in https://drive.google.com/drive/folders/1YtCLlSuTAjpLziTKI_QBuQrIOm2ss9LB?usp=sharing )
> 
> #!/bin/bash
> #=======================================
> #(YUV420P) -> (EVC)
> #=======================================
> ffmpeg -f rawvideo -pix_fmt yuv420p -s:v 352x288 -r 30 -i Test_Video_cif.yuv -c:v libxeve -f rawvideo Test_Video_cif.yuv.evc
> ffplay -autoexit Test_Video_cif.yuv.evc

These examples are excessive; and they are completely unnecessary, as
they don't really provide anything useful given that a reader of
ffmpeg's commit messages is supposed to know trivial ffmpeg command line
usage.

> 
> #=======================================
> #(YUV420P10LE) -> (EVC)
> #=======================================
> ffmpeg -f rawvideo -pix_fmt yuv420p10le -s:v 352x288 -r 30 -i Test_Video_cif_10le.yuv -c:v libxeve -f rawvideo Test_Video_cif_10le.yuv.evc
> ffplay -autoexit Test_Video_cif_10le.yuv.evc
> 
> #=======================================
> #(EVC) -> (YUV420P)
> #=======================================
> ffmpeg -i Test_Video_cif.yuv.evc -pix_fmt yuv420p Test_Video_cif.evc.yuv
> ffplay -autoexit -f rawvideo -pixel_format yuv420p -video_size 352x288  Test_Video_cif.evc.yuv
> 
> #=======================================
> #(EVC) -> (YUV420Pi10LE)
> #=======================================
> ffmpeg -i Test_Video_cif_10le.yuv.evc -pix_fmt yuv420p10le Test_Video_cif_10le.evc.yuv
> ffplay -autoexit -f rawvideo -pixel_format yuv420p10le -video_size 352x288  Test_Video_cif_10le.evc.yuv
> 
> #=======================================
> #(YUV420P) -> (MP4)
> #=======================================
> ffmpeg -f rawvideo -pix_fmt yuv420p -s:v 352x288 -r 30 -i Test_Video_cif.yuv -c:v libxeve -f rawvideo Test_Video_cif.yuv.mp4
> ffplay -autoexit Test_Video_cif.yuv.mp4
> 
> #=======================================
> #(YUV420P10LE) -> (MP4)
> #=======================================
> ffmpeg -f rawvideo -pix_fmt yuv420p10le -s:v 352x288 -r 30 -i Test_Video_cif_10le.yuv -c:v libxeve -f rawvideo Test_Video_cif_10le.yuv.mp4
> ffplay -autoexit Test_Video_cif_10le.yuv.mp4
> 
> #=======================================
> #(MP4) -> (YUV420P)
> #=======================================
> ffmpeg -i Test_Video_cif.yuv.mp4 -f rawvideo -pix_fmt yuv420p Test_Video_cif.mp4.yuv
> ffplay -autoexit -f rawvideo -pixel_format yuv420p -video_size 352x288 Test_Video_cif.mp4.yuv
> 
> #=======================================
> #(MP4) ->  (YUV420P10LE)
> #=======================================
> ffmpeg -i Test_Video_cif_10le.yuv.mp4 -f rawvideo -pix_fmt yuv420p10le Test_Video_cif_10le.mp4.yuv
> ffplay -autoexit -f rawvideo -pixel_format yuv420p10le -video_size 352x288 Test_Video_cif_10le.mp4.yuv
> 
> #=======================================
> #(EVC) ->  (MP4)
> #=======================================
> ffmpeg -i Test_Video_cif.yuv.evc -c:v copy Test_Video_cif.evc.mp4
> ffplay -autoexit Test_Video_cif.evc.mp4
> 
> #=======================================
> #(MP4) ->  (EVC)
> #=======================================
> ffmpeg -i Test_Video_cif.evc.mp4 -vcodec copy -an -f rawvideo Test_Video_cif.evc.mp4.evc
> ffplay -autoexit Test_Video_cif.evc.mp4.evc
> 
> #=======================================
> #(MP4 [h264,aac]) ->  (MP4 [evc,aac])
> #=======================================
> ffmpeg -i Test_Video_cif.mp4 -c:v libxeve Test_Video_cif_evc.mp4
> ffplay -autoexit Test_Video_cif_evc.mp4
> 
> Signed-off-by: Dawid Kozinski <d.kozinski at samsung.com>
> ---
>  Changelog                |    3 +-
>  configure                |   10 +
>  libavcodec/Makefile      |    4 +
>  libavcodec/allcodecs.c   |    2 +
>  libavcodec/avcodec.h     |    3 +
>  libavcodec/codec_desc.c  |    8 +
>  libavcodec/codec_id.h    |    1 +
>  libavcodec/evc_parser.c  |  452 +++++++++++++++
>  libavcodec/libxevd.c     |  724 +++++++++++++++++++++++
>  libavcodec/libxeve.c     | 1185 ++++++++++++++++++++++++++++++++++++++
>  libavcodec/parsers.c     |    1 +
>  libavcodec/profiles.c    |    6 +
>  libavcodec/profiles.h    |    1 +
>  libavcodec/version.h     |    2 +-
>  libavformat/Makefile     |    2 +
>  libavformat/allformats.c |    2 +
>  libavformat/evcdec.c     |  136 +++++
>  libavformat/isom_tags.c  |    2 +
>  libavformat/mov.c        |    2 +-
>  libavformat/movenc.c     |   30 +
>  libavformat/rawenc.c     |   14 +
>  21 files changed, 2587 insertions(+), 3 deletions(-)
>  create mode 100644 libavcodec/evc_parser.c
>  create mode 100644 libavcodec/libxevd.c
>  create mode 100644 libavcodec/libxeve.c
>  create mode 100644 libavformat/evcdec.c
> 
> diff --git a/Changelog b/Changelog
> index 5a32cf0d5c..21ebc11ff4 100644
> --- a/Changelog
> +++ b/Changelog
> @@ -106,7 +106,8 @@ version 5.0:
>  - VideoToolbox ProRes encoder
>  - anlmf audio filter
>  - IMF demuxer (experimental)
> -
> +- eXtra-fast Essential Video Encoder (XEVE)
> +- eXtra-fast Essential Video Decoder (XEVD)
>  
>  version 4.4:
>  - AudioToolbox output device
> diff --git a/configure b/configure
> index 7a62f0c248..7491d3af6b 100755
> --- a/configure
> +++ b/configure
> @@ -289,6 +289,8 @@ External library support:
>    --enable-libwebp         enable WebP encoding via libwebp [no]
>    --enable-libx264         enable H.264 encoding via x264 [no]
>    --enable-libx265         enable HEVC encoding via x265 [no]
> +  --enable-libxeve         enable XEVE encoding via xeve [no]
> +  --enable-libxevd         enable XEVD decoding via xevd [no]
>    --enable-libxavs         enable AVS encoding via xavs [no]
>    --enable-libxavs2        enable AVS2 encoding via xavs2 [no]
>    --enable-libxcb          enable X11 grabbing using XCB [autodetect]
> @@ -1880,6 +1882,8 @@ EXTERNAL_LIBRARY_LIST="
>      openssl
>      pocketsphinx
>      vapoursynth
> +    libxeve
> +    libxevd

Keep the list in alphabetical order.

>  "
>  
>  HWACCEL_AUTODETECT_LIBRARY_LIST="
> @@ -2453,6 +2457,7 @@ CONFIG_EXTRA="
>      h264pred
>      h264qpel
>      hevcparse
> +    evcparse

Keep the list in alphabetical order.

>      hpeldsp
>      huffman
>      huffyuvdsp
> @@ -3252,6 +3257,7 @@ mpegaudio_parser_select="mpegaudioheader"
>  mpegvideo_parser_select="mpegvideo"
>  mpeg4video_parser_select="h263dsp mpegvideo qpeldsp"
>  vc1_parser_select="vc1dsp"
> +evc_parser_select="evcparse"

Keep the alphabetical order.

>  
>  # bitstream_filters
>  aac_adtstoasc_bsf_select="adts_header mpeg4audio"
> @@ -3377,6 +3383,8 @@ libx264_encoder_select="atsc_a53"
>  libx264rgb_encoder_deps="libx264"
>  libx264rgb_encoder_select="libx264_encoder"
>  libx265_encoder_deps="libx265"
> +libxeve_encoder_deps="libxeve"
> +libxevd_decoder_deps="libxevd"

Alphabetical order.

>  libxavs_encoder_deps="libxavs"
>  libxavs2_encoder_deps="libxavs2"
>  libxvid_encoder_deps="libxvid"
> @@ -6659,6 +6667,8 @@ enabled libx264           && { check_pkg_config libx264 x264 "stdint.h x264.h" x
>                               check_cpp_condition libx262 x264.h "X264_MPEG2"
>  enabled libx265           && require_pkg_config libx265 x265 x265.h x265_api_get &&
>                               require_cpp_condition libx265 x265.h "X265_BUILD >= 70"
> +enabled libxeve           && require_pkg_config libxeve "xeve >= 1.0.0" "xeve.h" xeve_encode
> +enabled libxevd           && require_pkg_config libxevd "xevd >= 1.0.0" "xevd.h" xevd_decode

Ditto.

>  enabled libxavs           && require libxavs "stdint.h xavs.h" xavs_encoder_encode "-lxavs $pthreads_extralibs $libm_extralibs"
>  enabled libxavs2          && require_pkg_config libxavs2 "xavs2 >= 1.3.0" "stdint.h xavs2.h" xavs2_api_get
>  enabled libxvid           && require libxvid xvid.h xvid_global -lxvidcore
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index 3adf1536d8..ab38b0127f 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -1087,6 +1087,8 @@ OBJS-$(CONFIG_LIBWEBP_ANIM_ENCODER)       += libwebpenc_common.o libwebpenc_anim
>  OBJS-$(CONFIG_LIBX262_ENCODER)            += libx264.o
>  OBJS-$(CONFIG_LIBX264_ENCODER)            += libx264.o
>  OBJS-$(CONFIG_LIBX265_ENCODER)            += libx265.o
> +OBJS-$(CONFIG_LIBXEVE_ENCODER)            += libxeve.o
> +OBJS-$(CONFIG_LIBXEVD_DECODER)            += libxevd.o

Ditto.

>  OBJS-$(CONFIG_LIBXAVS_ENCODER)            += libxavs.o
>  OBJS-$(CONFIG_LIBXAVS2_ENCODER)           += libxavs2.o
>  OBJS-$(CONFIG_LIBXVID_ENCODER)            += libxvid.o
> @@ -1152,6 +1154,8 @@ OBJS-$(CONFIG_VP9_PARSER)              += vp9_parser.o
>  OBJS-$(CONFIG_WEBP_PARSER)             += webp_parser.o
>  OBJS-$(CONFIG_XBM_PARSER)              += xbm_parser.o
>  OBJS-$(CONFIG_XMA_PARSER)              += xma_parser.o
> +OBJS-$(CONFIG_EVC_PARSER)              += evc_parser.o

Ditto.

> +
>  
>  # bitstream filters
>  OBJS-$(CONFIG_AAC_ADTSTOASC_BSF)          += aac_adtstoasc_bsf.o
> diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
> index d1e10197de..12e6c92f65 100644
> --- a/libavcodec/allcodecs.c
> +++ b/libavcodec/allcodecs.c
> @@ -783,6 +783,8 @@ extern LIBX264_CONST AVCodec ff_libx264_encoder;
>  #endif
>  extern const AVCodec ff_libx264rgb_encoder;
>  extern AVCodec ff_libx265_encoder;
> +extern const AVCodec ff_libxeve_encoder;
> +extern const AVCodec ff_libxevd_decoder;
>  extern const AVCodec ff_libxavs_encoder;
>  extern const AVCodec ff_libxavs2_encoder;
>  extern const AVCodec ff_libxvid_encoder;
> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> index 7ee8bc2b7c..a070e0f1d7 100644
> --- a/libavcodec/avcodec.h
> +++ b/libavcodec/avcodec.h
> @@ -1643,6 +1643,9 @@ typedef struct AVCodecContext {
>  #define FF_PROFILE_KLVA_SYNC 0
>  #define FF_PROFILE_KLVA_ASYNC 1
>  
> +#define FF_PROFILE_EVC_BASELINE             0
> +#define FF_PROFILE_EVC_MAIN                 1
> +
>      /**
>       * level
>       * - encoding: Set by user.
> diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
> index 0974ee03de..058f28bd67 100644
> --- a/libavcodec/codec_desc.c
> +++ b/libavcodec/codec_desc.c
> @@ -1269,6 +1269,14 @@ static const AVCodecDescriptor codec_descriptors[] = {
>          .props     = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER,
>          .profiles  = NULL_IF_CONFIG_SMALL(ff_hevc_profiles),
>      },
> +    {
> +        .id        = AV_CODEC_ID_EVC,
> +        .type      = AVMEDIA_TYPE_VIDEO,
> +        .name      = "evc",
> +        .long_name = NULL_IF_CONFIG_SMALL("MPEG-5 EVC (Essential Video Coding)"),
> +        .props     = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER,
> +        .profiles  = NULL_IF_CONFIG_SMALL(ff_evc_profiles),
> +    },
>      {
>          .id        = AV_CODEC_ID_FIC,
>          .type      = AVMEDIA_TYPE_VIDEO,
> diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h
> index ab265ec584..597a2bc4a0 100644
> --- a/libavcodec/codec_id.h
> +++ b/libavcodec/codec_id.h
> @@ -222,6 +222,7 @@ enum AVCodecID {
>      AV_CODEC_ID_WEBP,
>      AV_CODEC_ID_HNM4_VIDEO,
>      AV_CODEC_ID_HEVC,
> +    AV_CODEC_ID_EVC,

This breaks ABI and is invalid; there is a gap between the last video
and the first audio codec id where this value should be added.
(The entry in codec_descriptors above then needs to be moved so that the
list is sorted by AVCodecDescriptor.id.)

>  #define AV_CODEC_ID_H265 AV_CODEC_ID_HEVC
>      AV_CODEC_ID_FIC,
>      AV_CODEC_ID_ALIAS_PIX,
> diff --git a/libavcodec/evc_parser.c b/libavcodec/evc_parser.c
> new file mode 100644
> index 0000000000..f68c4cc3a0
> --- /dev/null
> +++ b/libavcodec/evc_parser.c
> @@ -0,0 +1,452 @@

...

> +
> +// Split after the parameter sets at the beginning of the stream if they exist.
> +static int evc_split(AVCodecContext *ctx, const uint8_t *bs, int bs_size)
> +{
> +    return 0;
> +}
> +
> +static av_cold void evc_parser_close(AVCodecParserContext *s)
> +{
> +    /* EVCParserContext *ctx = s->priv_data; */
> +}

Don't add unnecessary functions; but notice that you are using
ff_combine_frame() and therefore you need to call ff_parse_close() in
your close function or use it directly as your close function.

> +
> +AVCodecParser ff_evc_parser = {

Should be const.

> +    .codec_ids      = { AV_CODEC_ID_EVC },
> +    .priv_data_size = sizeof(EVCParserContext),
> +    .parser_init    = evc_parser_init,
> +    .parser_parse   = evc_parse,
> +    .parser_close   = evc_parser_close,
> +    .split          = evc_split,
> +};
> diff --git a/libavcodec/libxevd.c b/libavcodec/libxevd.c
> new file mode 100644
> index 0000000000..ff9ee5c16f
> --- /dev/null
> +++ b/libavcodec/libxevd.c
> @@ -0,0 +1,724 @@
> +/*
> + * libxevd decoder
> + * EVC (MPEG-5 Essential Video Coding) decoding using XEVD MPEG-5 EVC decoder library
> + *
> + * Copyright (C) 2021 Dawid Kozinski <d.kozinski at samsung.com>
> + *
> + * 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 FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#if defined(_MSC_VER)
> +#define XEVD_API_IMPORTS 1
> +#endif
> +
> +#include <xevd.h>
> +
> +#include <float.h>
> +#include <stdlib.h>
> +
> +#include "libavutil/internal.h"
> +#include "libavutil/common.h"
> +#include "libavutil/opt.h"
> +#include "libavutil/pixdesc.h"
> +#include "libavutil/pixfmt.h"
> +#include "libavutil/imgutils.h"
> +
> +// #define USE_EXP_GOLOMB_STUFF
> +#ifdef USE_EXP_GOLOMB_STUFF 
> +#include "golomb.h"
> +#endif
> +
> +#include "avcodec.h"
> +#include "internal.h"
> +#include "packet_internal.h"
> +
> +#define UNUSED(x) (void)(x)
> +
> +#define XEVD_PARAM_BAD_NAME -1
> +#define XEVD_PARAM_BAD_VALUE -2
> +
> +/**
> + * The structure stores all the state associated with the instance of Xeve MPEG-5 EVC decoder
> + * The first field is a pointer to an AVClass struct (@see https://ffmpeg.org/doxygen/trunk/structAVClass.html#details).
> + */

Such comments are unnecessary (

> +typedef struct XevdContext {
> +    const AVClass *class;
> +
> +    XEVD id;        // XEVD instance identifier @see xevd.h
> +    XEVD_CDSC cdsc; // decoding parameters @see xevd.h
> +
> +    int decod_frames; // number of decoded frames
> +    int packet_count; // number of packets created by decoder
> +
> +    // configuration parameters
> +    AVDictionary *xevd_opts; // xevd configuration read from a :-separated list of key=value parameters
> +
> +} XevdContext;
> +
> +static int  op_threads = 1; // Default value

No global state! (And anyway, this value seems to be write-only.)

> +
> +#ifdef USE_EXP_GOLOMB_STUFF 
> +static int get_nalu_type(const uint8_t *bs, int bs_size)
> +{
> +    GetBitContext gb;
> +    int fzb, nut;
> +    init_get_bits(&gb, bs, bs_size * 8);
> +    fzb = get_bits1(&gb);
> +    if(fzb != 0) {
> +        av_log(NULL, AV_LOG_DEBUG, "forbidden_zero_bit is not clear\n");
> +    }
> +    nut = get_bits(&gb, 6); /* nal_unit_type_plus1 */
> +    return nut - 1;
> +}
> +#endif
> +
> +#ifdef PRINT_NALU_INFO
> +static void print_nalu_info(XEVD_STAT * stat)
> +{
> +    if(stat->nalu_type < XEVD_NUT_SPS) {
> +        av_log(NULL, AV_LOG_DEBUG, "XEVD_NUT_SPS \n");
> +
> +        av_log(NULL, AV_LOG_DEBUG, "%c-slice\n", stat->stype == XEVD_ST_I ? 'I' : stat->stype == XEVD_ST_P ? 'P' : 'B');
> +
> +        av_log(NULL, AV_LOG_DEBUG, " %d bytes\n", stat->read);
> +        av_log(NULL, AV_LOG_DEBUG, ", poc=%d, tid=%d, ", (int)stat->poc, (int)stat->tid);
> +
> +        for (int i = 0; i < 2; i++) {
> +            av_log(NULL, AV_LOG_DEBUG, "[L%d ", i);
> +            for (int j = 0; j < stat->refpic_num[i]; j++) av_log(NULL, AV_LOG_DEBUG,"%d ", stat->refpic[i][j]);
> +            av_log(NULL, AV_LOG_DEBUG,"] \n");
> +        }
> +    } else if(stat->nalu_type == XEVD_NUT_SPS) {
> +        av_log(NULL, AV_LOG_DEBUG, "XEVD_NUT_SPS \n");
> +    } else if (stat->nalu_type == XEVD_NUT_PPS) {
> +        av_log(NULL, AV_LOG_DEBUG, "XEVD_NUT_PPS \n");
> +    } else if (stat->nalu_type == XEVD_NUT_SEI) {
> +        av_log(NULL, AV_LOG_DEBUG, "XEVD_NUT_SEI \n");
> +    } else {
> +        av_log(NULL, AV_LOG_DEBUG, "Unknown bitstream !!!! \n");
> +    }
> +}
> +#endif
> +
> +// @todo consider moving following function to separate file containing helper functions for EVC decoder
> +#ifdef PRINT_FRAME_INFO
> +static void print_frame_info(const AVFrame* f)
> +{
> +    int level = AV_LOG_DEBUG;
> +    av_log(NULL, level, "frame->width: %d\n", f->width);
> +    av_log(NULL, level, "frame->height: %d\n", f->height);
> +
> +    av_log(NULL, level, "frame->linesize[0]: %d\n", f->linesize[0]);
> +    av_log(NULL, level, "frame->linesize[1]: %d\n", f->linesize[1]);
> +    av_log(NULL, level, "frame->linesize[2]: %d\n", f->linesize[2]);
> +    av_log(NULL, level, "frame->buf[0]: %p\n", f->buf[0]);
> +    av_log(NULL, level, "frame->buf[1]: %p\n", f->buf[1]);
> +    av_log(NULL, level, "frame->buf[2]: %p\n", f->buf[2]);
> +    av_log(NULL, level, "frame->data[0]: %p\n", f->data[0]);
> +    av_log(NULL, level, "frame->data[1]: %p\n", f->data[1]);
> +    av_log(NULL, level, "frame->data[2]: %p\n", f->data[2]);
> +}
> +#endif
> +
> +// @todo consider moving following function to separate file containing helper functions for EVC decoder
> +#ifdef PRINT_XEVD_IMGB_INFO
> +static void print_xevd_imgb_info(const XEVD_IMGB* imgb)
> +{
> +    av_log(NULL, AV_LOG_DEBUG, "imgb->np: %d\n", imgb->np);
> +    av_log(NULL, AV_LOG_DEBUG, "imgb->bsize[0]: %d\n", imgb->bsize[0]);
> +    av_log(NULL, AV_LOG_DEBUG, "imgb->bsize[1]: %d\n", imgb->bsize[1]);
> +    av_log(NULL, AV_LOG_DEBUG, "imgb->bsize[2]: %d\n", imgb->bsize[2]);
> +}
> +#endif
> +
> +// @todo consider moving following function to separate file containing helper functions for EVC decoder
> +#ifdef PRINT_AVCTX
> +static void print_avctx(const AVCodecContext *avctx)
> +{
> +    if( AVMEDIA_TYPE_UNKNOWN == avctx->codec_type) {
> +        av_log(NULL, AV_LOG_DEBUG, "avctx->codec_type: AVMEDIA_TYPE_UNKNOWN\n");
> +    } else if(AVMEDIA_TYPE_VIDEO  == avctx->codec_type)
> +        av_log(NULL, AV_LOG_DEBUG, "avctx->codec_type: AVMEDIA_TYPE_VIDEO \n");
> +    else {
> +        av_log(NULL, AV_LOG_DEBUG, "avctx->codec_type: AVMEDIA_TYPE_UNKNOWN\n");
> +    }
> +
> +    av_log(NULL, AV_LOG_DEBUG, "avctx->codec_id: %s\n",avcodec_get_name(avctx->codec_id));
> +    av_log(NULL, AV_LOG_DEBUG, "avctx->width: %d\n", avctx->width);
> +    av_log(NULL, AV_LOG_DEBUG, "avctx->height: %d\n", avctx->height);
> +    av_log(NULL, AV_LOG_DEBUG, "avctx->pix_fmt: %d\n", avctx->pix_fmt);
> +}
> +#endif
> +
> +/**
> + * Read options
> + *
> + * @param avctx codec context
> + * @return 0 on success
> + */
> +static int read_options(const AVCodecContext* avctx)
> +{
> +
> +    op_threads = (avctx->thread_count>0)?avctx->thread_count:1;
> +
> +    return 0;
> +}
> +
> +/**
> + * Parse :-separated list of key=value parameters
> + *
> + * @param key
> + * @param value
> + *
> + * @return 0 on success, negative value on failure
> + *
> + * @todo Consider removing the function
> + */
> +static int xevd_params_parse(const char* key, const char* value)
> +{
> +    if(!key) {
> +        av_log(NULL, AV_LOG_ERROR, "Ivalid argument: key string is NULL\n");
> +        return XEVD_ERR_INVALID_ARGUMENT;
> +    }
> +    if(!value) {
> +        av_log(NULL, AV_LOG_ERROR, "Ivalid argument: value string is NULL\n");
> +        return XEVD_ERR_INVALID_ARGUMENT;
> +    }
> +
> +    else {
> +        av_log(NULL, AV_LOG_ERROR, "Unknown xevd codec option: %s\n", key);
> +        return XEVD_PARAM_BAD_NAME;
> +    }
> +    return 0;
> +}
> +
> +/**
> + *  The function returns a pointer to variable of type XEVD_CDSC.
> + * XEVD_CDSC contains all decoder parameters that should be initialized before its use.
> + *
> + * The field values of the XEVD_CDSC structure are populated based on:
> + * - the corresponding field values of the AvCodecConetxt structure,
> + * - the xevd decoder specific option values,
> + *   (the full list of options available for xevd encoder is displayed after executing the command ./ffmpeg --help decoder = libxevd)
> + * - and the xevd encoder options specified as a list of key value pairs following xevd-params option
> + *
> + * Order of input processing and populating the XEVD_CDSC structure
> + * 1. first, the corresponding fields of the AVCodecContext structure are processed, (i.e -threads 4)
> + * 2. then xevd-specific options added as AVOption to the xevd AVCodec implementation (i.e -threads 3)
> + * 3. finally, the options specified after the xevd-params option as the parameter list of type key value are processed (i.e -xevd-params "m=2")
> + *
> + * There are options that can be set in different ways. In this case, please follow the above-mentioned order of processing.
> + * The most recent assignments overwrite the previous values.
> + *
> + * @param avctx codec context
> + * @param cdsc contains all encoder parameters that should be initialized before its use.
> + *
> + * @return 0 on success, negative error code on failure
> + */
> +static int get_conf(const AVCodecContext* avctx, XEVD_CDSC* cdsc)
> +{
> +    int cpu_count = av_cpu_count();
> +
> +    /* read options from AVCodecContext & from XEVD_CDSC */
> +    read_options(avctx);
> +
> +    /* parse :-separated list of key=value parameters and set values for created descriptor (XEVD_CDSC) */
> +    {
> +        XevdContext *ctx = avctx->priv_data;
> +        AVDictionaryEntry *en = NULL;
> +        while ((en = av_dict_get(ctx->xevd_opts, "", en, AV_DICT_IGNORE_SUFFIX))) {
> +            int parse_ret = xevd_params_parse(en->key, en->value);
> +
> +            switch (parse_ret) {
> +            case XEVD_PARAM_BAD_NAME:
> +                av_log((AVCodecContext*)avctx, AV_LOG_WARNING,
> +                       "Unknown option: %s.\n", en->key);
> +                break;
> +            case XEVD_PARAM_BAD_VALUE:
> +                av_log((AVCodecContext*)avctx, AV_LOG_WARNING,
> +                       "Invalid value for %s: %s.\n", en->key, en->value);
> +                break;
> +            default:
> +                break;
> +            }
> +        }
> +    }
> +
> +    /* clear XEVS_CDSC structure */
> +    memset(cdsc, 0, sizeof(XEVD_CDSC));
> +
> +    /* init XEVD_CDSC */
> +    if(avctx->thread_count <= 0) {
> +        cdsc->threads = (cpu_count<XEVD_MAX_TASK_CNT)?cpu_count:XEVD_MAX_TASK_CNT;
> +    } else if(avctx->thread_count > XEVD_MAX_TASK_CNT) {
> +        cdsc->threads = XEVD_MAX_TASK_CNT;
> +    } else {
> +        cdsc->threads = avctx->thread_count;
> +    }
> +
> +    return XEVD_OK;
> +}
> +
> +/**
> + * Read NAL unit length
> + * @param bs input data (bitstream)
> + * @return the lenghth of NAL unit on success, 0 value on failure
> + */
> +static uint32_t read_nal_unit_length(const uint8_t *bs, int bs_size)
> +{
> +    uint32_t len = 0;
> +    XEVD_INFO info;
> +    int ret;
> +
> +    if(bs_size==XEVD_NAL_UNIT_LENGTH_BYTE) {
> +        ret = xevd_info((void*)bs, XEVD_NAL_UNIT_LENGTH_BYTE, 1, &info);
> +        if (XEVD_FAILED(ret)) {
> +            av_log(NULL, AV_LOG_ERROR, "Cannot get bitstream information\n");
> +            return 0;
> +        }
> +        len = info.nalu_len;
> +        if(len == 0)
> +        {
> +            av_log(NULL, AV_LOG_ERROR, "Invalid bitstream size! [%d]\n", bs_size);
> +            return 0;
> +        }
> +    }
> +    return len;
> +}
> +
> +/**
> + * @param avctx codec context
> + * @param ctx the structure that stores all the state associated with the instance of Xeve MPEG-5 EVC decoder
> + * @return 0 on success, negative value on failure
> + */
> +static int export_stream_params(AVCodecContext *avctx, const XevdContext *ctx)
> +{
> +    // unsigned int num = 0, den = 0;
> +    // @todo support other formats
> +
> +    int ret;
> +    int size;
> +    int color_space;
> +
> +    avctx->pix_fmt = AV_PIX_FMT_YUV420P10;
> +
> +    // @todo The AVCodecContext should be initialized here using data from the object of XEVD_SPS type.
> +    //
> +    // It seems to be impossible right now since XEVD API limitation.
> +    // The extension for the XEVD API is needed.
> +    // To be more precise, what we need is access to the object of XEVD_SPS type being a part of XEVD_CTX object.
> +    // The object of XEVD_CTX type is created while the function xevd_create() being a part of public API is called.
> +    //
> +    // @todo remove the following hardoced has_b_frames; consider using sps->num_reorder_pics value instead
> +    //
> +    // avctx->has_b_frames        = 1; // (sps->num_reorder_pics)?1:0;
> +    size = 4;
> +    ret = xevd_config(ctx->id, XEVD_CFG_GET_CODED_WIDTH, &avctx->coded_width, &size);
> +    if (XEVD_FAILED(ret)) {
> +        av_log(NULL, AV_LOG_ERROR, "failed to get coded_width\n");
> +        return -1;
> +    }
> +
> +    ret = xevd_config(ctx->id, XEVD_CFG_GET_CODED_HEIGHT, &avctx->coded_height, &size);
> +    if (XEVD_FAILED(ret)) {
> +        av_log(NULL, AV_LOG_ERROR, "failed to get coded_height\n");
> +        return -1;
> +    }
> +
> +    ret = xevd_config(ctx->id, XEVD_CFG_GET_WIDTH, &avctx->width, &size);
> +    if (XEVD_FAILED(ret)) {
> +        av_log(NULL, AV_LOG_ERROR, "failed to get width\n");
> +        return -1;
> +    }
> +
> +    ret = xevd_config(ctx->id, XEVD_CFG_GET_HEIGHT, &avctx->height, &size);
> +    if (XEVD_FAILED(ret)) {
> +        av_log(NULL, AV_LOG_ERROR, "failed to get height\n");
> +        return -1;
> +    }
> +
> +    ret = xevd_config(ctx->id, XEVD_CFG_GET_COLOR_SPACE, &color_space, &size);
> +    if (XEVD_FAILED(ret)) {
> +        av_log(NULL, AV_LOG_ERROR, "failed to get color_space\n");
> +        return -1;
> +    }
> +    switch(color_space) {
> +    case XEVD_CS_YCBCR400_10LE:
> +        av_log(NULL, AV_LOG_DEBUG, "color_space = XEVD_CS_YCBCR400_10LE\n");
> +        avctx->pix_fmt = AV_PIX_FMT_GRAY10LE;
> +        break;
> +    case XEVD_CS_YCBCR420_10LE:
> +        av_log(NULL, AV_LOG_DEBUG, "color_space = XEVD_CS_YCBCR420_10LE\n");
> +        avctx->pix_fmt = AV_PIX_FMT_YUV420P10LE;
> +        break;
> +    case XEVD_CS_YCBCR422_10LE:
> +        av_log(NULL, AV_LOG_DEBUG, "color_space = XEVD_CS_YCBCR422_10LE\n");
> +        avctx->pix_fmt = AV_PIX_FMT_YUV422P10LE;
> +        break;
> +    case XEVD_CS_YCBCR444_10LE:
> +        av_log(NULL, AV_LOG_DEBUG, "color_space = XEVD_CS_YCBCR444_10LE\n");
> +        avctx->pix_fmt = AV_PIX_FMT_YUV444P10LE;
> +        break;
> +    default:
> +        av_log(NULL, AV_LOG_ERROR, "unknown color space\n");
> +        avctx->pix_fmt = AV_PIX_FMT_NONE;
> +        return -1;
> +    }
> +
> +// @todo Use _XEVD_SPS fields to initialize AVCodecContext when it is possible
> +#ifdef USE_XEVD_SPS_FIELDS
> +    avctx->profile = sps->profile_idc;
> +    avctx->level = sps->level_idc;
> +
> +    ff_set_sar(avctx, sps->vui_parameters.sar);
> +
> +    if (sps->vui_parametersvui.video_signal_type_present_flag)
> +        avctx->color_range = sps->vui_parameters.video_full_range_flag ? AVCOL_RANGE_JPEG
> +                             : AVCOL_RANGE_MPEG;
> +    else
> +        avctx->color_range = AVCOL_RANGE_MPEG;
> +
> +    if (sps->vui_parameters.colour_description_present_flag) {
> +        avctx->color_primaries = sps->vui_parameters.colour_primaries;
> +        avctx->color_trc       = sps->vui_parameters.transfer_characteristic;
> +        avctx->colorspace      = sps->vui_parameters.matrix_coeffs;
> +    } else {
> +        avctx->color_primaries = AVCOL_PRI_UNSPECIFIED;
> +        avctx->color_trc       = AVCOL_TRC_UNSPECIFIED;
> +        avctx->colorspace      = AVCOL_SPC_UNSPECIFIED;
> +    }
> +
> +    if (sps->vui_parameters.timing_info_present_flag) {
> +        num = sps->vui_parameters.num_units_in_tick;
> +        den = sps->vui_parameters.time_scale;
> +    }
> +
> +    if (s->sei.alternative_transfer.present &&
> +            av_color_transfer_name(s->sei.alternative_transfer.preferred_transfer_characteristics) &&
> +            s->sei.alternative_transfer.preferred_transfer_characteristics != AVCOL_TRC_UNSPECIFIED) {
> +        avctx->color_trc = s->sei.alternative_transfer.preferred_transfer_characteristics;
> +    }
> +#else
> +    avctx->color_primaries = AVCOL_PRI_UNSPECIFIED;
> +    avctx->color_trc       = AVCOL_TRC_UNSPECIFIED;
> +    avctx->colorspace      = AVCOL_SPC_UNSPECIFIED;
> +
> +#endif
> +    return 0;
> +}
> +
> +/**
> + * Initialize decoder static data
> + *
> + * @todo Consider removing unused function

Indeed, remove it.

> + */
> +static av_cold void libxevd_init_static_data(AVCodec *codec)
> +{
> +    UNUSED(codec);
> +}
> +
> +/**
> + * Initialize decoder
> + * Create decoder instance and allocate all the needed resources
> + *
> + * @param avctx codec context
> + * @return 0 on success, negative error code on failure
> + */
> +static av_cold int libxevd_init(AVCodecContext *avctx)
> +{
> +    XevdContext *ctx = avctx->priv_data;
> +    int val = 0;
> +    XEVD_CDSC *cdsc = &(ctx->cdsc);
> +
> +    av_log(NULL, AV_LOG_DEBUG, "eXtra-fast Essential Video Decoder\n");
> +#ifdef PRINT_AVCTX
> +    print_avctx(avctx);
> +#endif
> +
> +    /* read configurations and set values for created descriptor (XEVD_CDSC) */
> +    val = get_conf(avctx, cdsc);
> +    if (val != XEVD_OK) {
> +        av_log(NULL, AV_LOG_ERROR,"Cannot get configuration\n");
> +        return -1;
> +    }
> +
> +    /* create decoder */
> +    ctx->id = xevd_create(&(ctx->cdsc), NULL);
> +    if(ctx->id == NULL) {
> +        av_log(NULL, AV_LOG_ERROR, "cannot create XEVD encoder\n");
> +        return -1;
> +    }
> +
> +    ctx->packet_count = 0;
> +    ctx->decod_frames = 0;
> +    return 0;
> +}
> +
> +/**
> +  * Dncode picture
> +  *
> +  * @param      avctx          codec context
> +  * @param      data           codec type dependent output struct
> +  * @param[out] got_frame      decoder sets to 0 or 1 to indicate that a
> +  *                            non-empty frame or subtitle was returned in
> +  *                            outdata.
> +  * @param[in]  pkt            AVPacket containing the data to be decoded
> +  * @return amount of bytes read from the packet on success, negative error
> +  *         code on failure
> +  */
> +static int libxevd_decode(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *pkt)
> +{
> +    AVFrame *frame = data;
> +    XevdContext *ctx = NULL;
> +    XEVD_IMGB * imgb = NULL;
> +    XEVD_STAT stat;
> +    XEVD_BITB bitb;
> +    int ret, nalu_size, bs_read_pos;
> +
> +    if(avctx == NULL) {
> +        av_log(NULL, AV_LOG_ERROR, "Invalid input parameter: AVCodecContext\n");
> +        return -1;
> +    }
> +    ctx = avctx->priv_data;
> +    if(ctx == NULL) {
> +        av_log(avctx, AV_LOG_ERROR, "Invalid XEVD context\n");
> +        return -1;
> +    }
> +
> +    if(pkt->size > 0) {
> +        bs_read_pos = 0;
> +        imgb = NULL;
> +        while(pkt->size > (bs_read_pos + XEVD_NAL_UNIT_LENGTH_BYTE)) {
> +            int nal_type = 0;
> +            
> +            memset(&stat, 0, sizeof(XEVD_STAT));
> +            memset(&bitb, 0, sizeof(XEVD_BITB));
> +
> +            nalu_size = read_nal_unit_length(pkt->data + bs_read_pos, XEVD_NAL_UNIT_LENGTH_BYTE);
> +            if(nalu_size == 0) {
> +                av_log(avctx, AV_LOG_ERROR, "Invalid bitstream\n");
> +                goto ERR;
> +            }
> +            bs_read_pos += XEVD_NAL_UNIT_LENGTH_BYTE;
> +
> +            bitb.addr = pkt->data + bs_read_pos;
> +            bitb.ssize = nalu_size;
> +
> +            // Read NAL Unit Type from  NAL Unit Header
> +            //
> +            // The structure of NAL Unit Header looks like follows
> +            //
> +            //Â +---------------+---------------+
> +            //Â |0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|
> +            //Â +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> +            //Â |F|   Type    | TID | Reserve |E|
> +            //Â +-------------+-----------------+
> +            //
> +            // F:       1 bit   - forbidden_zero_bit.  Required to be zero in [EVC].
> +            // Type:    6 bits  - nal_unit_type_plus1 (This field specifies the NAL unit type as defined in Table 4 of [EVC])
> +            // TID:     3 bits  - nuh_temporal_id.  This field specifies the temporal identifier of the NAL unit.
> +            // Reserve: 5 bits  - nuh_reserved_zero_5bits.  This field shall be equal to the version of the [EVC] specification.
> +            // E:       1 bit   - nuh_extension_flag.  This field shall be equal the version of the [EVC] specification.
> +            //
> +            // @see https://datatracker.ietf.org/doc/html/draft-ietf-avtcore-rtp-evc-01#section-1.1.4
> +            
> +#ifdef USE_EXP_GOLOMB_STUFF 
> +            nal_type = get_nalu_type(bitb.addr, 1);
> +            av_log(avctx, AV_LOG_DEBUG, "NALU Type: %d\n", nal_type);
> +#else
> +            memcpy(&nal_type,bitb.addr,1);
> +            nal_type = nal_type & 0x7E;
> +            nal_type = nal_type >> 1;
> +            nal_type -= 1;
> +            av_log(avctx, AV_LOG_DEBUG, "NALU Type: %d\n", nal_type);
> +#endif
> +
> +            /* main decoding block */
> +            ret = xevd_decode(ctx->id, &bitb, &stat);
> +            if(XEVD_FAILED(ret)) {
> +                av_log(avctx, AV_LOG_ERROR, "failed to decode bitstream\n");
> +                goto ERR;
> +            }
> +
> +            bs_read_pos += nalu_size;
> +
> +#ifdef PRINT_NALU_INFO
> +            print_nalu_info(ctx);
> +#endif
> +
> +            if(stat.nalu_type == XEVD_NUT_SPS) {
> +                av_log(avctx, AV_LOG_DEBUG, "EVC stream parameters changed\n");
> +
> +                if(export_stream_params(avctx, ctx)!=0) {
> +                    goto ERR;
> +                }
> +                av_log(avctx, AV_LOG_DEBUG, "width: %d\n",avctx->width);
> +                av_log(avctx, AV_LOG_DEBUG, "height: %d\n",avctx->height);
> +
> +            }
> +
> +            if(stat.read != nalu_size) {
> +                av_log(avctx, AV_LOG_INFO, "different reading of bitstream (in:%d, read:%d)\n,", nalu_size, stat.read);
> +            }
> +            if(stat.fnum >= 0) {
> +                if (imgb) { /* already has a decoded image */
> +                    imgb->release(imgb);
> +                    imgb = NULL;
> +                }
> +                ret = xevd_pull(ctx->id, &imgb);
> +                if(XEVD_FAILED(ret)) {
> +                    av_log(avctx, AV_LOG_ERROR, "failed to pull the decoded image (err:%d, frame#=%d)\n", ret, stat.fnum);
> +                    goto ERR;
> +                } else if (ret == XEVD_OK_FRM_DELAYED) {
> +                    av_log(avctx, AV_LOG_DEBUG, "delayed frame\n");
> +                    if(imgb) {
> +                        imgb->release(imgb);
> +                        imgb = NULL;
> +                    }
> +                }
> +            }
> +        }
> +    } else {
> +        av_log(NULL, AV_LOG_DEBUG, "bumping ...\n");
> +        ret = xevd_pull(ctx->id, &(imgb));
> +        if(ret == XEVD_ERR_UNEXPECTED) {
> +            av_log(avctx, AV_LOG_DEBUG, "Bumping process completed\n");
> +            *got_frame = 0;
> +            return 0;
> +        } else if(XEVD_FAILED(ret)) {
> +            av_log(avctx, AV_LOG_ERROR, "failed to pull the decoded image (err:%d)\n", ret);
> +            goto ERR;
> +        } else {
> +            av_log(avctx, AV_LOG_DEBUG, "bumping success\n");
> +        }
> +    }
> +
> +    if(imgb) {
> +        /* @todo supports other color space and bit depth */
> +        if(imgb->cs != XEVD_CS_YCBCR420_10LE) {
> +            av_log(avctx, AV_LOG_ERROR, "Not supported pixel format: %s\n", av_get_pix_fmt_name(avctx->pix_fmt));
> +            goto ERR;
> +        }
> +
> +        if (imgb->w[0] != avctx->width || imgb->h[0] != avctx->height) {
> +            av_log(avctx, AV_LOG_DEBUG, "resolution changed %dx%d -> %dx%d\n",
> +                   avctx->width, avctx->height, imgb->w[0], imgb->h[0]);
> +            if(ff_set_dimensions(avctx, imgb->w[0], imgb->h[0]) < 0) {
> +                av_log(avctx, AV_LOG_ERROR, "cannot set new dimension\n");
> +                goto ERR;
> +            }
> +        }
> +
> +        frame->coded_picture_number++;
> +        frame->display_picture_number++;
> +        frame->format = AV_PIX_FMT_YUV420P10LE;
> +
> +#ifdef PRINT_XEVD_IMGB_INFO
> +        print_xevd_imgb_info(imgb);
> +#endif
> +
> +        if (ff_get_buffer(avctx, frame, 0) < 0) {
> +            av_log(avctx, AV_LOG_ERROR, "cannot get AV buffer\n");
> +            goto ERR;
> +        }
> +
> +        frame->pts = pkt->pts;
> +        av_log(avctx, AV_LOG_DEBUG, "frame->pts = %ld\n", frame->pts);
> +
> +        av_image_copy(frame->data, frame->linesize, (const uint8_t **)imgb->a,
> +                      imgb->s, avctx->pix_fmt,
> +                      imgb->w[0], imgb->h[0]);
> +
> +        ctx->decod_frames++;
> +        *got_frame = 1;
> +
> +#ifdef PRINT_FRAME_INFO
> +        print_frame_info(frame);
> +#endif
> +        imgb->release(imgb);
> +        imgb = NULL;
> +    } else {
> +        *got_frame = 0;
> +    }
> + 
> +    ctx->packet_count++;
> +    return pkt->size;
> +
> +ERR:
> +    if(imgb) {
> +        imgb->release(imgb);
> +        imgb = NULL;
> +    }
> +    *got_frame = 0;
> +    return -1;
> +}
> +
> +/**
> + * Destroy decoder
> + *
> + * @param avctx codec context
> + * @return 0 on success
> + */
> +static av_cold int libxevd_close(AVCodecContext *avctx)
> +{
> +    XevdContext *ctx = avctx->priv_data;
> +    if(ctx->id) {
> +        xevd_delete(ctx->id);
> +        ctx->id = NULL;
> +    }
> +
> +    return 0;
> +}
> +
> +#define OFFSET(x) offsetof(XevdContext, x)
> +#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
> +
> +// @todo consider using following options (./ffmpeg --help decoder=libxevd)
> +//
> +static const AVOption options[] = {
> +    { "xevd-params",                "override the xevd configuration using a :-separated list of key=value parameters", OFFSET(xevd_opts), AV_OPT_TYPE_DICT,   { 0 }, 0, 0, VD },

What options for xevd make sense at all? Most decoders don't use
codec-specific options at all, as a decoders job is generally very easy
(namely: "decode what it gets fed").
(According to https://github.com/mpeg5/xevd the only option that makes
sense is the number of threads, but for this you don't need xevd-params;
AVCodecContext.thread_count is enough.)

> +    { NULL }
> +};
> +
> +static const AVClass xevd_class = {
> +    .class_name = "libxevd",
> +    .item_name  = av_default_item_name,
> +    .option     = options,
> +    .version    = LIBAVUTIL_VERSION_INT,
> +};
> +
> +/// @todo provide implementation
> +static const AVCodecDefault xevd_defaults[] = {
> +    { "b", "0" },
> +    { NULL },
> +};

Using AVCodecDefault for a decoder generally makes no sense. This
certainly applies to setting a bitrate for a decoder.

> +
> +AVCodec ff_libxevd_decoder = {
> +    .name             = "evc",
> +    .long_name        = NULL_IF_CONFIG_SMALL("EVC / MPEG-5 Essential Video Coding (EVC)"),
> +    .type             = AVMEDIA_TYPE_VIDEO,
> +    .id               = AV_CODEC_ID_EVC,
> +    .init             = libxevd_init,
> +    .init_static_data = libxevd_init_static_data,

If you don't use libxevd_init_static_data, you should constify
ff_libxevd_decoder; if you need init_static_data, you need to deconstify
the declaration in libavcodec/allcodecs.c to match the definition.

> +    .decode           = libxevd_decode,
> +    .close            = libxevd_close,
> +    .priv_data_size   = sizeof(XevdContext),
> +    .priv_class       = &xevd_class,
> +    .defaults         = xevd_defaults,
> +    .capabilities     = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS | AV_CODEC_CAP_AVOID_PROBING,
> +    .wrapper_name     = "libxevd",
> +};
> diff --git a/libavcodec/libxeve.c b/libavcodec/libxeve.c
> new file mode 100644
> index 0000000000..f34a1d6efd
> --- /dev/null
> +++ b/libavcodec/libxeve.c
> @@ -0,0 +1,1185 @@
> +/*
> + * libxeve encoder
> + * EVC (MPEG-5 Essential Video Coding) encoding using XEVE MPEG-5 EVC encoder library
> + *
> + * Copyright (C) 2021 Dawid Kozinski <d.kozinski at samsung.com>
> + *
> + * 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 FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#if defined(_MSC_VER)
> +#define XEVE_API_IMPORTS 1
> +#endif
> +
> +#include <xeve.h>
> +
> +#include <float.h>
> +#include <stdlib.h>
> +
> +#include "libavutil/internal.h"
> +#include "libavutil/common.h"
> +#include "libavutil/opt.h"
> +#include "libavutil/pixdesc.h"
> +#include "libavutil/pixfmt.h"
> +#include "libavutil/time.h"
> +
> +#include "avcodec.h"
> +#include "internal.h"
> +#include "packet_internal.h"
> +
> +#define MAX_BS_BUF (16*1024*1024)
> +
> +/**
> + * Error codes
> + */
> +#define XEVE_PARAM_BAD_NAME -100
> +#define XEVE_PARAM_BAD_VALUE -200
> +
> +/**
> + * Macro for eliminating the unused variable warning
> + */
> +#define UNUSED(x) (void)(x)
> +
> +/**
> + * Encoder states
> + *
> + * STATE_ENCODING - the encoder receives and processes input frames
> + * STATE_BUMPING  - there are no more input frames, however the encoder still processes previously received data
> + * STATE_SKIPPING - skipping input frames
> + */
> +typedef enum State {
> +    STATE_ENCODING,
> +    STATE_BUMPING,
> +    STATE_SKIPPING
> +} State;
> +
> +/**
> + * The structure stores all the state associated with the instance of Xeve MPEG-5 EVC encoder
> + * The first field is a pointer to an AVClass struct (@see https://ffmpeg.org/doxygen/trunk/structAVClass.html#details).
> + */
> +typedef struct XeveContext {
> +    const AVClass *class;
> +
> +    XEVE id;        // XEVE instance identifier
> +    XEVE_CDSC cdsc; // coding parameters i.e profile, width & height of input frame, num of therads, frame rate ...
> +    XEVE_BITB bitb; // bitstream buffer (output)
> +    XEVE_STAT stat; // encoding status (output)
> +    XEVE_IMGB imgb; // image buffer (input)
> +
> +    State state; // encoder state (skipping, encoding, bumping)
> +
> +    int encod_frames;   // num of encoded frames
> +    double bytes_total; // encoded bitstream byte size
> +    double bitrate;     // bits per second
> +    int packet_count;   // num of packets created by encoder
> +
> +    // Chroma subsampling
> +    int width_luma;
> +    int height_luma;
> +    int width_chroma;
> +    int height_chroma;
> +
> +    int profile_id;  // encoder profile (main, baseline)
> +    int preset_id;   // preset of xeve ( fast, medium, slow, placebo)
> +    int tune_id;     // tune of xeve (psnr, zerolatency)
> +    int input_depth; // input bit-depth: 8bit, 10bit
> +    int hash;
> +
> +    /* variables for input parameter */
> +    char * op_preset;
> +    char * op_tune;
> +    int    op_qp;
> +    int    op_crf;
> +
> +    // configuration parameters
> +    // xeve configuration read from a :-separated list of key=value parameters
> +    AVDictionary *xeve_params;
> +} XeveContext;
> +
> +/**
> + * Gets Xeve encoder pre-defined profile
> + *
> + * @param profile string describing Xeve encoder profile (baseline, main)
> + * @return XEVE pre-defined profile on success, negative value on failure
> + */
> +static int get_profile_id(const char * profile)
> +{
> +    if (!strcmp(profile, "baseline")) {
> +        return XEVE_PROFILE_BASELINE;
> +    } else if (!strcmp(profile, "main")) {
> +        return XEVE_PROFILE_MAIN;
> +    } else {
> +        return -1;
> +    }
> +}
> +
> +/**
> + * Gets Xeve pre-defined preset
> + *
> + * @param preset string describing Xeve encoder preset (fast, medium, slow, placebo )
> + * @return XEVE pre-defined profile on success, negative value on failure
> + */
> +static int get_preset_id(const char * preset)
> +{
> +    if((!strcmp(preset, "fast"))) {
> +        return XEVE_PRESET_FAST;
> +    } else if (!strcmp(preset, "medium")) {
> +        return XEVE_PRESET_MEDIUM;
> +    } else if (!strcmp(preset, "slow")) {
> +        return XEVE_PRESET_SLOW;
> +    } else if (!strcmp(preset, "placebo")) {
> +        return XEVE_PRESET_PLACEBO;
> +    } else {
> +        return -1;
> +    }
> +}
> +
> +/**
> + * Gets Xeve pre-defined tune id
> + *
> + * @param preset string describing Xeve encoder preset (fast, medium, slow, placebo )
> + * @return XEVE pre-defined profile on success, negative value on failure
> + */
> +static int get_tune_id(const char * tune)
> +{
> +    if((!strcmp(tune, "psnr"))) {
> +        return XEVE_TUNE_PSNR;
> +    } else if (!strcmp(tune, "zerolatency")) {
> +        return XEVE_TUNE_ZEROLATENCY;
> +    } else {
> +        return -1;
> +    }
> +}
> +
> +static int kbps_str_to_int(char *str)
> +{
> +    int kbps = 0;
> +    if (strchr(str, 'K') || strchr(str, 'k')) {
> +        char *tmp = strtok(str, "Kk ");
> +        kbps = (int)(atof(tmp));
> +    } else if (strchr(str, 'M') || strchr(str, 'm')) {
> +        char *tmp = strtok(str, "Mm ");
> +        kbps = (int)(atof(tmp) * 1000);
> +    } else {
> +        kbps = atoi(str);
> +    }
> +    return kbps;
> +}
> +
> +/**
> + * Parse :-separated list of key=value parameters
> + *
> + * @param key
> + * @param value
> + * @param xe pointer to the structure that stores all the state associated with
> + *           the instance of Xeve MPEG-5 EVC encoder
> + * @param param coding parameters
> + *
> + * @return 0 on success, negative value on failure
> + */
> +static int parse_xeve_params(const char* key, const char* value, XeveContext* xe, XEVE_PARAM* param)
> +{
> +    if(!key) {
> +        av_log(NULL, AV_LOG_ERROR, "Ivalid argument: key string is NULL\n");
> +        return XEVE_PARAM_BAD_VALUE;
> +    }
> +    if(!value) {
> +        if (strcmp(key, "hash") == 0) {
> +            xe->hash = 1;
> +            av_log(NULL, AV_LOG_INFO, "embedding signature is enabled\n");
> +        } else {
> +            av_log(NULL, AV_LOG_ERROR, "Ivalid argument: value string is NULL\n");
> +            return XEVE_PARAM_BAD_VALUE;
> +        }
> +    } else if (strcmp(key, "vbv-bufsize") == 0 ) {
> +        param->vbv_bufsize = kbps_str_to_int((char*)value);
> +        av_log(NULL, AV_LOG_INFO, "VBV buffer size: %dkbits\n", param->vbv_bufsize);
> +    } else if (strcmp(key, "rc-type") == 0 ) {
> +        int rc_type = atoi(value);
> +        if(rc_type < 0 || rc_type > 2) {
> +            av_log(NULL, AV_LOG_ERROR, "Rate control type [ 0(rc_off) / 1(CBR) ] bad value: %d\n", rc_type);
> +            return XEVE_PARAM_BAD_VALUE;
> +        }
> +        param->rc_type = rc_type;
> +        av_log(NULL, AV_LOG_INFO, "Rate control type [ 0(rc_off) / 1(CBR) ] : %d\n", rc_type);
> +    } else if (strcmp(key, "bframes") == 0 ) {
> +        int bframes = atoi(value);
> +        if(bframes < 0) {
> +            av_log(NULL, AV_LOG_ERROR, "bframes: bad value: %d\n", bframes);
> +            return XEVE_PARAM_BAD_VALUE;
> +        }
> +        param->bframes = bframes;
> +        av_log(NULL, AV_LOG_INFO, "bframes : %d\n", bframes);
> +    } else if (strcmp(key, "profile") == 0 ) {
> +        const char* profile = value;
> +        int profile_id;
> +        av_log(NULL, AV_LOG_INFO, "profile (baseline, main): %s\n", profile);
> +        profile_id = get_profile_id(profile);
> +        if (profile_id < 0) {
> +            av_log(NULL, AV_LOG_ERROR, "Invalid xeve param: profile(%s)\n", profile);
> +            return XEVE_PARAM_BAD_VALUE;
> +        }
> +        xe->profile_id = profile_id;
> +    } else if (strcmp(key, "preset") == 0 ) {
> +        const char* preset = value;
> +        int preset_id;
> +        av_log(NULL, AV_LOG_INFO, "Preset of xeve (fast, medium, slow, placebo): %s\n", preset);
> +        preset_id = get_preset_id(preset);
> +        if( preset_id < 0) {
> +            av_log(NULL, AV_LOG_ERROR, "Invalid xeve param: preset(%s)\n", preset);
> +            return XEVE_PARAM_BAD_VALUE;
> +        }
> +        xe->preset_id = preset_id;
> +    } else if (strcmp(key, "tune") == 0 ) {
> +        const char* tune = value;
> +        int tune_id;
> +        av_log(NULL, AV_LOG_INFO, "Tune of xeve (psnr, zerolatency): %s\n", tune);
> +        tune_id= get_tune_id(tune);
> +        if( tune_id < 0) {
> +            av_log(NULL, AV_LOG_ERROR, "Invalid xeve param: tune(%s)\n", tune);
> +            return XEVE_PARAM_BAD_VALUE;
> +        }
> +        xe->tune_id = tune_id;
> +    } else if (strcmp(key, "bitrate") == 0 ) {
> +        param->bitrate = kbps_str_to_int((char *)value);
> +        av_log(NULL, AV_LOG_INFO, "Bitrate = %dkbps\n", param->bitrate);
> +    } else if (strcmp(key, "q") == 0 || strcmp(key, "qp") == 0) {
> +        int qp = atoi(value);
> +        if(qp < 0 || qp > 51) {
> +            av_log(NULL, AV_LOG_ERROR, "Invalid QP value (0~51) :%d\n", qp);
> +            return XEVE_PARAM_BAD_VALUE;
> +        }
> +        param->qp = qp;
> +        av_log(NULL, AV_LOG_INFO, "QP value (0~51): %d\n", param->qp);
> +    } else {
> +        av_log(NULL, AV_LOG_ERROR, "Unknown xeve codec option: %s\n", key);
> +        return XEVE_PARAM_BAD_NAME;
> +    }
> +    return 0;
> +}
> +
> +/**
> + * Convert ffmpeg pixel format (AVPixelFormat) to XEVE pre-defined color format
> + *
> + * @param[in]  px_fmt pixel format (@see https://ffmpeg.org/doxygen/trunk/pixfmt_8h.html#a9a8e335cf3be472042bc9f0cf80cd4c5)
> + * @param[out] color_format XEVE pre-defined color format (@see xeve.h)
> + * @param[out] bit_depth bit depth
> + *
> + * @return 0 on success, negative value on failure
> + */
> +static int get_pix_fmt(enum AVPixelFormat pix_fmt, int *color_format, int *bit_depth)
> +{
> +    switch (pix_fmt) {
> +    case AV_PIX_FMT_YUV420P:
> +        *color_format = XEVE_CF_YCBCR420;
> +        *bit_depth = 8;
> +        break;
> +    case AV_PIX_FMT_YUV422P:
> +        *color_format = XEVE_CF_YCBCR422;
> +        *bit_depth = 8;
> +        break;
> +    case AV_PIX_FMT_YUV444P:
> +        *color_format = XEVE_CF_YCBCR444;
> +        *bit_depth = 8;
> +        break;
> +    case AV_PIX_FMT_YUV420P10:
> +        *color_format = XEVE_CF_YCBCR420;
> +        *bit_depth = 10;
> +        break;
> +    case AV_PIX_FMT_YUV422P10:
> +        *color_format = XEVE_CF_YCBCR422;
> +        *bit_depth = 10;
> +        break;
> +    case AV_PIX_FMT_YUV444P10:
> +        *color_format = XEVE_CF_YCBCR444;
> +        *bit_depth = 10;
> +        break;
> +    default:
> +        *color_format = XEVE_CF_UNKNOWN;
> +        return -1;
> +    }
> +    return 0;
> +}
> +
> +/**
> + * The function returns a pointer to variable of type XEVE_CDSC.
> + * XEVE_CDSC contains all encoder parameters that should be initialized before its use.
> + *
> + * The field values of the XEVE_CDSC structure are populated based on:
> + * - the corresponding field values of the AvCodecConetxt structure,
> + * - the xeve encoder specific option values,
> + *   (the full list of options available for xeve encoder is displayed after executing the command ./ffmpeg --help encoder = libxeve)
> + * - and the xeve encoder options specified as a list of key value pairs following xeve-params option
> + *
> + * Order of input processing and populating the XEVE_CDSC structure
> + * 1. first, the corresponding fields of the AVCodecContext structure are processed, (i.e -pix_fmt yuv420p -s:v 1920x1080 -r 30 -profile:v 0)
> + * 2. then xeve-specific options added as AVOption to the xeve AVCodec implementation (i.e -threads_cnt 3 -preset 0)
> + * 3. finally, the options specified after the xeve-params option as the parameter list of type key value are processed (i.e -xeve-params "m=2:q=17")
> + *
> + * There are options that can be set in different ways. In this case, please follow the above-mentioned order of processing.
> + * The most recent assignments overwrite the previous values.
> + *
> + * @param ctx codec context
> + * @param cdsc contains all encoder parameters that should be initialized before its use.
> + *
> + * @return 0 on success, negative error code on failure
> + */
> +static int get_conf(const AVCodecContext *ctx, XEVE_CDSC *cdsc)
> +{
> +    XEVE_PARAM * param = NULL;
> +    XeveContext *xe = NULL;
> +    int color_format;
> +    int cpu_count = av_cpu_count();
> +    int ret;
> +
> +    xe = ctx->priv_data;
> +    param = &cdsc->param;
> +
> +    /* set defualt value in priv_data */
> +    memset(cdsc, 0, sizeof(XEVE_CDSC));
> +    xe->hash = 0;
> +
> +    /* set default parameters */
> +    ret = xeve_param_default(param);
> +    if (XEVE_FAILED(ret)) {
> +        av_log(NULL, AV_LOG_ERROR, "cannot set_default parameter\n");
> +        goto ERR;
> +    }
> +
> +    /* read options from AVCodecContext  */
> +    if(ctx->width > 0) {
> +        param->w = ctx->width;
> +        xe->width_luma = ctx->width;
> +    }
> +
> +    if(ctx->height > 0) {
> +        param->h = ctx->height;
> +        xe->height_luma = ctx->height;
> +    }
> +
> +    if(ctx->framerate.num > 0) {
> +        /* @todo: fps can be float number, but xeve API doesn't support it */
> +        param->fps = (int)(((float)ctx->framerate.num / ctx->framerate.den) + 0.5);
> +    }
> +
> +    if(ctx->gop_size >= 0) { /* key-frame interval */
> +        param->keyint = ctx->gop_size; // 0: only one I-frame at the first time; 1: every frame is coded in I-frame
> +        av_log(NULL, AV_LOG_INFO, "GOP size (key-frame interval): %d\n", ctx->gop_size);
> +    }
> +    if (ctx->max_b_frames == 0 || ctx->max_b_frames == 1 || ctx->max_b_frames == 3 ||
> +            ctx->max_b_frames == 7 || ctx->max_b_frames == 15) { /* number of b-frame */
> +        param->bframes = ctx->max_b_frames;
> +        av_log(NULL, AV_LOG_INFO, "Number of max b-frames: %d\n", ctx->max_b_frames);
> +    } else {
> +        av_log(NULL, AV_LOG_ERROR, "Incorrect value for maximum number of B frames: (%d) \n"
> +               "Acceptable values for bf option (maximum number of B frames) are 0,1,3,7 or 15\n", ctx->max_b_frames);
> +        goto ERR;
> +    }
> +
> +    if (ctx->level >= 0) {
> +        param->level_idc = ctx->level;
> +    }
> +    ret = get_pix_fmt(ctx->pix_fmt, &color_format, &xe->input_depth);
> +    if (ret!=0) {
> +        av_log((AVCodecContext*)ctx, AV_LOG_ERROR, "Unsupported pixel format.\n");
> +        goto ERR;
> +    }
> +    param->cs = XEVE_CS_SET(color_format, xe->input_depth, 0);
> +
> +    if (ctx->rc_buffer_size > 0) {
> +        param->vbv_bufsize = (int)(ctx->rc_buffer_size/ 1000);
> +        av_log(NULL, AV_LOG_INFO, "VBV buf size: %d\n", ctx->rc_buffer_size);
> +    }
> +    if (ctx->bit_rate > 0) {
> +        if (ctx->bit_rate / 1000 > INT_MAX || ctx->rc_max_rate / 1000 > INT_MAX) {
> +            av_log(NULL, AV_LOG_ERROR, "not supported bitrate bit_rate and rc_max_rate > %d000\n", INT_MAX);
> +            goto ERR;
> +        }
> +        param->bitrate = (int)(ctx->bit_rate / 1000);
> +        param->rc_type = XEVE_RC_ABR;
> +    }
> +    if (xe->op_crf >= 0) {
> +        param->crf = xe->op_crf;
> +        param->rc_type = XEVE_RC_CRF;
> +    }
> +
> +    if(ctx->thread_count <= 0) {
> +        av_log(NULL, AV_LOG_DEBUG, "cpu_count: %d\n", cpu_count);
> +        param->threads = (cpu_count < XEVE_MAX_THREADS)? cpu_count: XEVE_MAX_THREADS;
> +    } else if(ctx->thread_count > XEVE_MAX_THREADS) {
> +        param->threads = XEVE_MAX_THREADS;
> +    } else {
> +        param->threads = ctx->thread_count;
> +    }
> +    av_log(NULL, AV_LOG_INFO, "param->threads: %d\n", param->threads);
> +
> +    cdsc->param.cs = XEVE_CS_SET(color_format, param->codec_bit_depth, 0);
> +    cdsc->max_bs_buf_size = MAX_BS_BUF;
> +
> +    if(ctx->profile == FF_PROFILE_EVC_BASELINE) {
> +        xe->profile_id = XEVE_PROFILE_BASELINE;
> +    } else if(ctx->profile == FF_PROFILE_EVC_MAIN) {
> +        xe->profile_id = XEVE_PROFILE_MAIN;
> +    } else {
> +        av_log(NULL, AV_LOG_ERROR, "Unknown encoder profile (%d)\n"
> +               "Acceptable values for profile option are 0 and 1 (0: baseline profile; 1: main profile)\n", ctx->profile);
> +        goto ERR;
> +    }
> +    if (xe->op_preset) {
> +        xe->preset_id = get_preset_id(xe->op_preset);
> +        av_log(NULL, AV_LOG_INFO, "Preset  : %s\n", xe->op_preset);
> +    }
> +    if (xe->op_tune) {
> +        xe->tune_id = get_tune_id(xe->op_tune);
> +        av_log(NULL, AV_LOG_INFO, "Tune    : %s\n", xe->op_tune);
> +    }
> +    
> +    ret = xeve_param_ppt(param, xe->profile_id, xe->preset_id, xe->tune_id);
> +    if (XEVE_FAILED(ret)) {
> +        av_log(NULL, AV_LOG_ERROR, "cannot set profile(%d), preset(%d), tune(%d)\n", xe->profile_id, xe->preset_id, xe->tune_id);
> +        goto ERR;
> +    }
> +
> +    /* parse :-separated list of key=value parameters and set values for created descriptor (XEVE_CDSC) */
> +    {
> +        AVDictionaryEntry *en = NULL;
> +        av_log(NULL, AV_LOG_INFO, "### Start to parse xeve_params ###\n");
> +        while ((en = av_dict_get(xe->xeve_params, "", en, AV_DICT_IGNORE_SUFFIX))) {
> +            int parse_ret = parse_xeve_params(en->key, en->value, xe, param);
> +
> +            switch (parse_ret) {
> +            case XEVE_PARAM_BAD_NAME:
> +                av_log((AVCodecContext*)ctx, AV_LOG_WARNING,
> +                       "Unknown option: %s.\n", en->key);
> +                break;
> +            case XEVE_PARAM_BAD_VALUE:
> +                av_log((AVCodecContext*)ctx, AV_LOG_WARNING,
> +                       "Invalid value for %s: %s.\n", en->key, en->value);
> +                break;
> +            default:
> +                break;
> +            }
> +        }
> +        av_log(NULL, AV_LOG_INFO, "### End of parsing xeve_params ###\n");
> +    }
> +
> +    av_log(NULL, AV_LOG_INFO, "Rate control type [ 0(CQP) / 1(ABR) / 2(CRF) ] : %d\n", param->rc_type);
> +    av_log(NULL, AV_LOG_INFO, "crf=%d, bitrate=%d, vbv_bufsize=%d, fps=%d\n", param->crf, param->bitrate, param->vbv_bufsize, param->fps);
> +
> +    return 0;
> +
> +ERR:
> +    return AVERROR(EINVAL);
> +}
> +
> +/**
> + * Check codec configuration
> + *
> + * @param ctx codec context
> + * @param cdsc contains all encoder parameters that should be initialized before its use.
> + *
> + * @return 0 on success, negative error code on failure
> + */
> +static int check_conf(AVCodecContext *ctx,  XEVE_CDSC *cdsc)
> +{
> +    int ret = 0;
> +    int min_block_size = 4;
> +    int pic_m;
> +
> +    if(cdsc->param.profile == XEVE_PROFILE_BASELINE) {
> +        if (cdsc->param.tool_amvr    == 1) {
> +            av_log(ctx, AV_LOG_ERROR, "AMVR cannot be on in base profile\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.tool_mmvd    == 1) {
> +            av_log(ctx, AV_LOG_ERROR, "MMVD cannot be on in base profile\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.tool_affine  == 1) {
> +            av_log(ctx, AV_LOG_ERROR, "Affine cannot be on in base profile\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.tool_dmvr    == 1) {
> +            av_log(ctx, AV_LOG_ERROR, "DMVR cannot be on in base profile\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.tool_admvp   == 1) {
> +            av_log(ctx, AV_LOG_ERROR, "ADMVP cannot be on in base profile\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.tool_hmvp    == 1) {
> +            av_log(ctx, AV_LOG_ERROR, "HMVP cannot be on in base profile\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.tool_addb    == 1) {
> +            av_log(ctx, AV_LOG_ERROR, "ADDB cannot be on in base profile\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.tool_alf     == 1) {
> +            av_log(ctx, AV_LOG_ERROR, "ALF cannot be on in base profile\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.tool_htdf    == 1) {
> +            av_log(ctx, AV_LOG_ERROR, "HTDF cannot be on in base profile\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.btt          == 1) {
> +            av_log(ctx, AV_LOG_ERROR, "BTT cannot be on in base profile\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.suco         == 1) {
> +            av_log(ctx, AV_LOG_ERROR, "SUCO cannot be on in base profile\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.tool_eipd    == 1) {
> +            av_log(ctx, AV_LOG_ERROR, "EIPD cannot be on in base profile\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.tool_iqt     == 1) {
> +            av_log(ctx, AV_LOG_ERROR, "IQT cannot be on in base profile\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.tool_cm_init == 1) {
> +            av_log(ctx, AV_LOG_ERROR, "CM_INIT cannot be on in base profile\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.tool_adcc    == 1) {
> +            av_log(ctx, AV_LOG_ERROR, "ADCC cannot be on in base profile\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.tool_ats     == 1) {
> +            av_log(ctx, AV_LOG_ERROR, "ATS_INTRA cannot be on in base profile\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.ibc_flag     == 1) {
> +            av_log(ctx, AV_LOG_ERROR, "IBC cannot be on in base profile\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.tool_rpl     == 1) {
> +            av_log(ctx, AV_LOG_ERROR, "RPL cannot be on in base profile\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.tool_pocs    == 1) {
> +            av_log(ctx, AV_LOG_ERROR, "POCS cannot be on in base profile\n");
> +            ret = -1;
> +        }
> +    } else {
> +        if (cdsc->param.tool_admvp   == 0 && cdsc->param.tool_affine == 1) {
> +            av_log(ctx, AV_LOG_ERROR, "AFFINE cannot be on when ADMVP is off\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.tool_admvp   == 0 && cdsc->param.tool_amvr   == 1) {
> +            av_log(ctx, AV_LOG_ERROR, "AMVR cannot be on when ADMVP is off\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.tool_admvp   == 0 && cdsc->param.tool_dmvr   == 1) {
> +            av_log(ctx, AV_LOG_ERROR, "DMVR cannot be on when ADMVP is off\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.tool_admvp   == 0 && cdsc->param.tool_mmvd   == 1) {
> +            av_log(ctx, AV_LOG_ERROR, "MMVD cannot be on when ADMVP is off\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.tool_eipd    == 0 && cdsc->param.ibc_flag    == 1) {
> +            av_log(ctx, AV_LOG_ERROR, "IBC cannot be on when EIPD is off\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.tool_iqt     == 0 && cdsc->param.tool_ats    == 1) {
> +            av_log(ctx, AV_LOG_ERROR, "ATS cannot be on when IQT is off\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.tool_cm_init == 0 && cdsc->param.tool_adcc   == 1) {
> +            av_log(ctx, AV_LOG_ERROR, "ADCC cannot be on when CM_INIT is off\n");
> +            ret = -1;
> +        }
> +    }

These lists are horribly long. Doesn't the encoder error out in case of
invalid parameters?

> +
> +    if (cdsc->param.btt == 1) {
> +        if (cdsc->param.framework_cb_max && cdsc->param.framework_cb_max < 5) {
> +            av_log(NULL, AV_LOG_ERROR, "Maximun Coding Block size cannot be smaller than 5\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.framework_cb_max > 7) {
> +            av_log(NULL, AV_LOG_ERROR, "Maximun Coding Block size cannot be greater than 7\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.framework_cb_min && cdsc->param.framework_cb_min < 2) {
> +            av_log(NULL, AV_LOG_ERROR, "Minimum Coding Block size cannot be smaller than 2\n");
> +            ret = -1;
> +        }
> +        if ((cdsc->param.framework_cb_max || cdsc->param.framework_cb_min) &&
> +                cdsc->param.framework_cb_min > cdsc->param.framework_cb_max) {
> +            av_log(NULL, AV_LOG_ERROR, "Minimum Coding Block size cannot be greater than Maximum coding Block size\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.framework_cu14_max > 6) {
> +            av_log(NULL, AV_LOG_ERROR, "Maximun 1:4 Coding Block size cannot be greater than 6\n");
> +            ret = -1;
> +        }
> +        if ((cdsc->param.framework_cb_max || cdsc->param.framework_cu14_max) &&
> +                cdsc->param.framework_cu14_max > cdsc->param.framework_cb_max) {
> +            av_log(NULL, AV_LOG_ERROR, "Maximun 1:4 Coding Block size cannot be greater than Maximum coding Block size\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.framework_tris_max > 6) {
> +            av_log(NULL, AV_LOG_ERROR, "Maximun Tri-split Block size be greater than 6\n");
> +            ret = -1;
> +        }
> +        if ((cdsc->param.framework_tris_max || cdsc->param.framework_cb_max) &&
> +                cdsc->param.framework_tris_max > cdsc->param.framework_cb_max) {
> +            av_log(NULL, AV_LOG_ERROR, "Maximun Tri-split Block size cannot be greater than Maximum coding Block size\n");
> +            ret = -1;
> +        }
> +        if ((cdsc->param.framework_tris_min || cdsc->param.framework_cb_min) &&
> +                cdsc->param.framework_tris_min < cdsc->param.framework_cb_min + 2) {
> +            av_log(NULL, AV_LOG_ERROR, "Maximun Tri-split Block size cannot be smaller than Minimum Coding Block size plus two\n");
> +            ret = -1;
> +        }
> +        if(cdsc->param.framework_cb_min) min_block_size = 1 << cdsc->param.framework_cb_min;
> +        else min_block_size = 8;
> +    }
> +
> +    if (cdsc->param.suco == 1) {
> +        if (cdsc->param.framework_suco_max > 6) {
> +            av_log(NULL, AV_LOG_ERROR, "Maximun SUCO size cannot be greater than 6\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.framework_cb_max && cdsc->param.framework_suco_max > cdsc->param.framework_cb_max) {
> +            av_log(NULL, AV_LOG_ERROR,"Maximun SUCO size cannot be greater than Maximum coding Block size\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.framework_suco_min < 4) {
> +            av_log(NULL, AV_LOG_ERROR, "Minimun SUCO size cannot be smaller than 4\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.framework_cb_min && cdsc->param.framework_suco_min < cdsc->param.framework_cb_min) {
> +            av_log(NULL, AV_LOG_ERROR,"Minimun SUCO size cannot be smaller than Minimum coding Block size\n");
> +            ret = -1;
> +        }
> +        if (cdsc->param.framework_suco_min > cdsc->param.framework_suco_max) {
> +            av_log(NULL, AV_LOG_ERROR, "Minimum SUCO size cannot be greater than Maximum SUCO size\n");
> +            ret = -1;
> +        }
> +    }
> +
> +    pic_m = (8 > min_block_size) ? min_block_size : 8;
> +    if ((cdsc->param.w & (pic_m - 1)) != 0) {
> +        av_log(NULL, AV_LOG_ERROR, "Current encoder does not support picture width, not multiple of max(8, minimum CU size)\n");
> +        ret = -1;
> +    }
> +    if ((cdsc->param.h & (pic_m - 1)) != 0) {
> +        av_log(NULL, AV_LOG_ERROR, "Current encoder does not support picture height, not multiple of max(8, minimum CU size)\n");
> +        ret = -1;
> +    }
> +
> +    return ret;
> +}
> +
> +/**
> + * Set XEVE_CFG_SET_USE_PIC_SIGNATURE for encoder
> + *
> + * @param id XEVE instance identifier
> + * @param ctx the structure stores all the state associated with the instance of Xeve MPEG-5 EVC encoder
> + * @return XEVE pre-defined color space (@see xeve.h) on success, XEVE_CF_UNKNOWN on failure
> + *
> + * @todo consider removing the function
> + */
> +static int set_extra_config(XEVE id, XeveContext *ctx)
> +{
> +    int ret, size, value;
> +
> +    if(ctx->hash) {
> +        value = 1;
> +        size = 4;
> +        ret = xeve_config(id, XEVE_CFG_SET_USE_PIC_SIGNATURE, &value, &size);
> +        if(XEVE_FAILED(ret)) {
> +            av_log(NULL, AV_LOG_ERROR, "failed to set config for picture signature\n");
> +            return -1;
> +        }
> +    }
> +
> +    return 0;
> +}
> +
> +/**
> + * Convert ffmpeg pixel format (AVPixelFormat) into XEVE pre-defined color space
> + *
> + * @param px_fmt pixel format (@see https://ffmpeg.org/doxygen/trunk/pixfmt_8h.html#a9a8e335cf3be472042bc9f0cf80cd4c5)
> + * @return XEVE pre-defined color space (@see xeve.h) on success, XEVE_CF_UNKNOWN on failure
> + */
> +static int xeve_color_space(enum AVPixelFormat pix_fmt)
> +{
> +    /* color space of input image */
> +    int cs = XEVE_CF_UNKNOWN;
> +
> +    switch (pix_fmt) {
> +    case AV_PIX_FMT_YUV420P:
> +        cs = XEVE_CS_YCBCR420;
> +        break;
> +    case AV_PIX_FMT_YUV420P10:
> +#if AV_HAVE_BIGENDIAN
> +        cs = XEVE_CS_SET(XEVE_CF_YCBCR420, 10, 1);
> +#else
> +        cs = XEVE_CS_YCBCR420_10LE;
> +#endif
> +
> +        break;
> +    case AV_PIX_FMT_YUV420P12:
> +#if AV_HAVE_BIGENDIAN
> +        cs = XEVE_CS_SET(XEVE_CF_YCBCR420, 12, 1);
> +#else
> +        cs = XEVE_CS_YCBCR420_12LE;
> +#endif
> +
> +        break;
> +    case AV_PIX_FMT_YUV422P:
> +        cs = XEVE_CS_YCBCR422;
> +        break;
> +    case AV_PIX_FMT_YUV422P10:
> +#if AV_HAVE_BIGENDIAN
> +        cs = XEVE_CS_SET(XEVE_CF_YCBCR422, 10, 1);
> +#else
> +        cs = XEVE_CS_YCBCR422_10LE;
> +#endif
> +
> +        break;
> +    case AV_PIX_FMT_YUV422P12:
> +#if AV_HAVE_BIGENDIAN
> +        cs = XEVE_CS_SET(XEVE_CF_YCBCR422, 12, 1);
> +#else
> +        cs = XEVE_CS_SET(XEVE_CF_YCBCR422, 12, 0);
> +#endif
> +
> +        break;
> +    case AV_PIX_FMT_GBRP:
> +    case AV_PIX_FMT_GBRP10:
> +    case AV_PIX_FMT_GBRP12:
> +        cs = XEVE_CF_UNKNOWN;
> +        break;
> +    case AV_PIX_FMT_YUV444P:
> +        cs = XEVE_CF_YCBCR444;
> +        break;
> +    case AV_PIX_FMT_YUV444P10:
> +#if AV_HAVE_BIGENDIAN
> +        cs = XEVE_CS_SET(XEVE_CF_YCBCR444, 10, 1);
> +#else
> +        cs = XEVE_CS_YCBCR444_10LE;
> +#endif
> +
> +        break;
> +    case AV_PIX_FMT_YUV444P12:
> +#if AV_HAVE_BIGENDIAN
> +        cs = XEVE_CS_SET(XEVE_CF_YCBCR444, 12, 1);
> +#else
> +        cs = XEVE_CS_SET(XEVE_CF_YCBCR444, 12, 0);
> +#endif
> +
> +        break;
> +    case AV_PIX_FMT_GRAY8:
> +        cs = XEVE_CF_YCBCR400;
> +        break;
> +    case AV_PIX_FMT_GRAY10:
> +#if AV_HAVE_BIGENDIAN
> +        cs = XEVE_CS_SET(XEVE_CF_YCBCR400, 10, 1);
> +#else
> +        cs = XEVE_CS_YCBCR400_10LE;
> +#endif
> +
> +        break;
> +    case AV_PIX_FMT_GRAY12:
> +#if AV_HAVE_BIGENDIAN
> +        cs = XEVE_CS_SET(XEVE_CF_YCBCR400, 12, 1);
> +#else
> +        cs = XEVE_CS_YCBCR400_12LE;
> +#endif
> +
> +        break;
> +    default:
> +        cs = XEVE_CF_UNKNOWN;
> +        break;
> +    }
> +    return cs;
> +}
> +
> +static int setup_bumping(XEVE id)
> +{
> +    int val, size;
> +    val  = 1;
> +    size = sizeof(int);
> +    if(XEVE_FAILED(xeve_config(id, XEVE_CFG_SET_FORCE_OUT, (void *)(&val), &size))) {
> +        return -1;
> +    }
> +    return 0;
> +}
> +
> +static const char* slice_type(enum AVPictureType av_pic_type)
> +{
> +    if(av_pic_type == AV_PICTURE_TYPE_I) {
> +        return "Slice Type I";
> +    } else if(av_pic_type == AV_PICTURE_TYPE_P) {
> +        return "Slice Type P";
> +    } else if(av_pic_type == AV_PICTURE_TYPE_B) {
> +        return "Slice Type B";
> +    } 
> +    return "Slice Type UNDEFINED";
> +}
> +
> +/**
> + * Initialize codec static data
> + *
> + * @todo consider removing unused function
> + */
> +static av_cold void libxeve_init_static_data(AVCodec *codec)
> +{
> +    UNUSED(codec);
> +}
> +
> +/**
> + * Initialize codec
> + * Create encoder instance and allocate all the needed resources
> + *
> + * @param ctx codec context
> + * @return 0 on success, negative error code on failure
> + */
> +static av_cold int libxeve_init(AVCodecContext *ctx)
> +{
> +    XeveContext *xe = ctx->priv_data;
> +    unsigned char *bs_buf = NULL;
> +    int i, val = 0;
> +    int shift_h = 0;
> +    int shift_v = 0;
> +    XEVE_IMGB * imgb = NULL;
> +
> +    XEVE_CDSC *cdsc = &(xe->cdsc);
> +    
> +    av_log(NULL, AV_LOG_DEBUG, "eXtra-fast Essential Video Encoder\n");
> +
> +    if(ctx->pix_fmt != AV_PIX_FMT_YUV420P && ctx->pix_fmt != AV_PIX_FMT_YUV420P10) {
> +        av_log(ctx, AV_LOG_ERROR, "Invalid pixel format: %s\n", av_get_pix_fmt_name(ctx->pix_fmt));
> +        goto ERR;
> +    }
> +
> +    /* allocate bitstream buffer */
> +    bs_buf = (unsigned char*)malloc(MAX_BS_BUF);

av_malloc (and use av_free to free it).
But if you always need exactly that amount, then you can just put an
array of that size into XeveContext.

> +    if(bs_buf == NULL) {
> +        av_log(NULL, AV_LOG_ERROR, "cannot allocate bitstream buffer, size=%d", MAX_BS_BUF);
> +        goto ERR;
> +    }
> +
> +    /* read configurations and set values for created descriptor (XEVE_CDSC) */
> +    val = get_conf(ctx, cdsc);
> +    if (val != XEVE_OK) {
> +        av_log(NULL, AV_LOG_ERROR,"cannot get configuration\n");
> +        goto ERR;
> +    }
> +
> +    if (check_conf(ctx, cdsc) != 0) {
> +        av_log(NULL, AV_LOG_ERROR,"invalid configuration\n");
> +        goto ERR;
> +    }
> +
> +    /* create encoder */
> +    xe->id = xeve_create(cdsc, NULL);
> +    if(xe->id == NULL) {
> +        av_log(NULL, AV_LOG_ERROR, "cannot create XEVE encoder\n");
> +        goto ERR;
> +    }
> +
> +    if(set_extra_config(xe->id, xe)) {
> +        av_log(NULL, AV_LOG_ERROR, "cannot set extra configurations\n");
> +        goto ERR;
> +    }
> +
> +    xe->bitb.addr = bs_buf;
> +    xe->bitb.bsize = MAX_BS_BUF;
> +
> +    if(av_pix_fmt_get_chroma_sub_sample(ctx->pix_fmt, &shift_h, &shift_v)) {
> +        av_log(ctx, AV_LOG_ERROR, "failed to get  chroma shift\n");
> +        goto ERR;
> +    }
> +    // YUV format explanation
> +    // shift_h == 1 && shift_v == 1 : YUV420
> +    // shift_h == 1 && shift_v == 0 : YUV422
> +    // shift_h == 0 && shift_v == 0 : YUV444
> +    //
> +    xe->width_chroma = AV_CEIL_RSHIFT(ctx->width, shift_h);
> +    xe->height_chroma = AV_CEIL_RSHIFT(ctx->height, shift_v);
> +
> +    /* set default values for input image buffer */
> +    imgb = &xe->imgb;
> +    imgb->cs = xeve_color_space(ctx->pix_fmt);
> +    imgb->np = 3; /* only for yuv420p, yuv420ple */
> +    for (i=0; i<imgb->np; i++) {
> +        imgb->x[i] = imgb->y[i] = 0;
> +    }
> +    imgb->w[0] = imgb->aw[0] = xe->width_luma;
> +    imgb->w[1] = imgb->w[2] = imgb->aw[1]= imgb->aw[2] = xe->width_chroma;
> +    imgb->h[0] = imgb->ah[0] = xe->height_luma;
> +    imgb->h[1] = imgb->h[2] = imgb->ah[1] = imgb->ah[2] = xe->height_chroma;
> +
> +    xe->encod_frames = 0;
> +    xe->bytes_total = 0;
> +    xe->state = STATE_ENCODING;
> +    xe->packet_count = 0;
> +    xe->bitrate = 0;
> +    return 0;
> +
> +ERR:
> +    if(bs_buf) free(bs_buf);
> +    return -1;
> +}
> +
> +/**
> +  * Encode data to an AVPacket.
> +  *
> +  * @param      ctx            codec context
> +  * @param      pkt            output AVPacket
> +  * @param[in]  frame          AVFrame containing the raw data to be encoded
> +  * @param[out] got_packet     encoder sets to 0 or 1 to indicate that a
> +  *                            non-empty packet was returned in avpkt.
> +  * @return 0 on success, negative error code on failure
> +  */
> +static int libxeve_encode(AVCodecContext *ctx, AVPacket *pkt,
> +                          const AVFrame *frame, int *got_packet)
> +{
> +    XeveContext *xe = NULL;
> +    int  ret = -1;
> +    int xeve_cs;
> +    if(ctx == NULL || pkt == NULL || got_packet==NULL) {
> +        av_log(ctx, AV_LOG_ERROR, "Invalid arguments\n");
> +        return -1;
> +    }
> +    xe = ctx->priv_data;
> +    if(xe == NULL) {
> +        av_log(ctx, AV_LOG_ERROR, "Invalid XEVE context\n");
> +        return -1;
> +    }
> +    if(xe->state == STATE_SKIPPING && frame ) {
> +        av_log(ctx, AV_LOG_DEBUG, "Empty frame -> Entering encoding process...\n");
> +        xe->state = STATE_ENCODING;
> +    } else if(xe->state == STATE_ENCODING && frame == NULL) {
> +        av_log(ctx, AV_LOG_DEBUG, "Empty frame -> Entering bumping process...\n");
> +        if (setup_bumping(xe->id) == 0) {
> +            xe->state = STATE_BUMPING;
> +        } else {
> +            av_log(ctx, AV_LOG_ERROR,"Failed to setup bumping\n");
> +            xe->state = STATE_SKIPPING;
> +        }
> +    }
> +
> +    if(xe->state == STATE_ENCODING) {
> +        const AVPixFmtDescriptor *pixel_fmt_desc = av_pix_fmt_desc_get (frame->format);
> +        if(!pixel_fmt_desc) {
> +            av_log(NULL, AV_LOG_ERROR, "Invalid pixel format descriptor for pixel format: %s\n", av_get_pix_fmt_name(ctx->pix_fmt));
> +            return -1;
> +        }
> +
> +        xeve_cs = xeve_color_space(ctx->pix_fmt);
> +        if(xeve_cs != XEVE_CS_YCBCR420 && xeve_cs != XEVE_CS_YCBCR420_10LE) {
> +            av_log(ctx, AV_LOG_ERROR, "Invalid pixel format: %s\n", av_get_pix_fmt_name(ctx->pix_fmt));
> +            return -1;
> +        }
> +
> +        {
> +            int i;
> +            XEVE_IMGB * imgb = NULL;
> +            int xeve_byte_depth = 0;
> +
> +            imgb = &xe->imgb;
> +
> +            xeve_byte_depth = XEVE_CS_GET_BYTE_DEPTH(xeve_cs);
> +            av_log(ctx, AV_LOG_DEBUG, "byte depth: %d\n",xeve_byte_depth);
> +
> +            for (i=0; i<imgb->np; i++) {
> +                imgb->a[i] = frame->data[i];
> +                imgb->s[i] = frame->linesize[i];
> +            }
> +
> +            if(xe->id == NULL) {
> +                av_log(ctx, AV_LOG_ERROR, "Invalid XEVE encoder\n");
> +                return -1;
> +            }
> +
> +            imgb->ts[0] = frame->pts;
> +            imgb->ts[1] = 0;
> +            imgb->ts[2] = 0;
> +            imgb->ts[3] = 0;
> +
> +            /* push image to encoder */
> +            av_log(ctx, AV_LOG_DEBUG, "INPUT | RAW frame | timestamps | %lld | %lld | %lld | %lld |\n", imgb->ts[0], imgb->ts[1], imgb->ts[2], imgb->ts[3]);
> +
> +            ret = xeve_push(xe->id, imgb);
> +            if(XEVE_FAILED(ret)) {
> +                av_log(ctx, AV_LOG_ERROR, "xeve_push() failed\n");
> +                return -1;
> +            }
> +        }
> +    } 
> +    if(xe->state == STATE_ENCODING || xe->state == STATE_BUMPING) {
> +        
> +        /* encoding */
> +        ret = xeve_encode(xe->id, &(xe->bitb), &(xe->stat));
> +        if(XEVE_FAILED(ret)) {
> +            av_log(ctx, AV_LOG_ERROR, "xeve_encode() failed\n");
> +            return -1;
> +        }
> +
> +        xe->encod_frames++;
> +
> +        /* store bitstream */
> +        if (ret == XEVE_OK_OUT_NOT_AVAILABLE) {
> +            av_log(ctx, AV_LOG_DEBUG, "RETURN OK BUT PICTURE IS NOT AVAILABLE YET (%d) frame: %d\n", ret, xe->encod_frames);
> +            *got_packet = 0;
> +            return 0;
> +        } else if(ret == XEVE_OK) {
> +            int av_pic_type;
> +
> +            if(xe->stat.write > 0) {
> +                xe->bytes_total+=xe->stat.write;
> +                // av_log(ctx, AV_LOG_DEBUG, "frame: %d | Bytes written:  %d | bytes total: %f | fnum %d | %lld | %lld | %lld | %lld |\n", xe->encod_frames, xe->stat.write, xe->bytes_total, xe->stat.fnum, xe->bitb.ts[0],xe->bitb.ts[1],xe->bitb.ts[2],xe->bitb.ts[3]);
> +
> +                ret = av_grow_packet(pkt, xe->stat.write);
> +                if (ret < 0) {
> +                    av_log(ctx, AV_LOG_ERROR, "Can't allocate memory for AVPacket data\n");
> +                    return ret;
> +                }
> +
> +                memcpy(pkt->data, xe->bitb.addr, xe->stat.write);
> +
> +                pkt->pts = xe->bitb.ts[0];
> +                pkt->dts = xe->bitb.ts[1];
> +                
> +                av_log(NULL, AV_LOG_DEBUG, "PTS: %ld | DTS: %ld\n", pkt->pts, pkt->dts);
> +
> +                xe->bitrate += (xe->stat.write - xe->stat.sei_size);
> +
> +                switch(xe->stat.stype) {
> +                case XEVE_ST_I:
> +                    av_pic_type = AV_PICTURE_TYPE_I;
> +                    pkt->flags |= AV_PKT_FLAG_KEY;
> +                    break;
> +                case XEVE_ST_P:
> +                    av_pic_type = AV_PICTURE_TYPE_P;
> +                    break;
> +                case XEVE_ST_B:
> +                    av_pic_type = AV_PICTURE_TYPE_B;
> +                    break;
> +                case XEVE_ST_UNKNOWN:
> +                    av_log(NULL, AV_LOG_ERROR, "unknown slice type\n");
> +                    return -1;
> +                }
> +
> +                av_log(ctx, AV_LOG_DEBUG, "OUTPUT | Encoded | slice type: %s | fnum: %ld | poc: %d | Bytes written:  %d | bytes total: %f | timestamps | %lld | %lld | %lld | %lld |\n", 
> +                    slice_type(av_pic_type),
> +                    xe->stat.fnum,
> +                    xe->stat.poc,
> +                    xe->stat.write,
> +                    xe->bytes_total,
> +                    xe->bitb.ts[0],
> +                    xe->bitb.ts[1],
> +                    xe->bitb.ts[2],
> +                    xe->bitb.ts[3]);
> +                    
> +                ff_side_data_set_encoder_stats(pkt, xe->stat.qp*FF_QP2LAMBDA, NULL, 0, av_pic_type);
> +                
> +                xe->bitrate += (xe->stat.write - xe->stat.sei_size);
> +
> +                *got_packet = 1;
> +                xe->packet_count++;
> +            }
> +        } else if (ret == XEVE_OK_NO_MORE_FRM) {
> +            av_log(ctx, AV_LOG_INFO, "Return OK but no more frames (%d)\n", ret);
> +            return 0;
> +        } else {
> +            av_log(ctx, AV_LOG_DEBUG, "Invalid return value (%d)\n", ret);
> +            return -1;
> +        }
> +    } else {
> +        av_log(NULL, AV_LOG_ERROR, "Udefined state: %d\n", xe->state);
> +        return -1;
> +    }
> +    return 0;
> +}
> +
> +/**
> + * Destroy encoder and release all the allocated resources
> + *
> + * @param ctx codec context
> + * @return 0 on success, negative error code on failure
> + */
> +static av_cold int libxeve_close(AVCodecContext *ctx)
> +{
> +    XeveContext *xe = ctx->priv_data;
> +
> +    xeve_delete(xe->id);
> +
> +    if(xe->bitb.addr) free(xe->bitb.addr); /* release bitstream buffer */
> +
> +    return 0;
> +}
> +
> +#define OFFSET(x) offsetof(XeveContext, x)
> +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
> +
> +// Example of using: ./ffmpeg -xeve-params "m=2:q=17"
> +// Consider using following options (./ffmpeg --help encoder=libxeve)
> +//
> +static const AVOption xeve_options[] = {
> +    { "preset", "Encoding preset for setting encoding speed [fast, medium, slow, placebo]", OFFSET(op_preset), AV_OPT_TYPE_STRING, { .str = "medium" }, 0, 0, VE },
> +    { "tune", "Tuneing parameter for special purpose operation [psnr, zerolatency]", OFFSET(op_tune), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE},
> +    { "qp", "quantization parameter qp <0..51> [default: 32]", OFFSET(op_qp), AV_OPT_TYPE_INT, { .i64 = 32 }, 0, 51, VE },
> +    { "crf", "constant rate factor <-1..51> [default: 32]", OFFSET(op_crf), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE },
> +    { "xeve-params", "override the xeve configuration using a :-separated list of key=value parameters", OFFSET(xeve_params), AV_OPT_TYPE_DICT,   { 0 }, 0, 0, VE },
> +    { NULL }
> +};
> +
> +static const AVClass xeve_class = {
> +    .class_name = "libxeve",
> +    .item_name  = av_default_item_name,
> +    .option     = xeve_options,
> +    .version    = LIBAVUTIL_VERSION_INT,
> +};
> +
> +/**
> + *  libavcodec generic global options, which can be set on all the encoders and decoders
> + *  @see https://www.ffmpeg.org/ffmpeg-codecs.html#Codec-Options
> + */
> +static const AVCodecDefault xeve_defaults[] = {
> +    { "b", "0" },       // bitrate
> +    { "g", "0" },       // gop_size (key-frame interval 0: only one I-frame at the first time; 1: every frame is coded in I-frame)
> +    { "bf", "15"},      // bframes (0: no B-frames)
> +    { "profile", "0"},  // encoder codec profile (0: baselie; 1: main)
> +    { "threads", "0"},  // number of threads to be used (0: automatically select the number of threads to set)
> +    { NULL },
> +};
> +
> +AVCodec ff_libxeve_encoder = {
> +    .name             = "libxeve",
> +    .long_name        = NULL_IF_CONFIG_SMALL("libxeve MPEG-5 EVC"),
> +    .type             = AVMEDIA_TYPE_VIDEO,
> +    .id               = AV_CODEC_ID_EVC,
> +    .init             = libxeve_init,
> +    .init_static_data = libxeve_init_static_data,
> +    .encode2          = libxeve_encode,
> +    .close            = libxeve_close,
> +    .priv_data_size   = sizeof(XeveContext),
> +    .priv_class       = &xeve_class,
> +    .defaults         = xeve_defaults,
> +    .capabilities     = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS |
> +    AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE,
> +    .wrapper_name     = "libxeve",
> +};
> diff --git a/libavcodec/parsers.c b/libavcodec/parsers.c
> index 6b40c18d80..295fa33f52 100644
> --- a/libavcodec/parsers.c
> +++ b/libavcodec/parsers.c
> @@ -73,6 +73,7 @@ extern const AVCodecParser ff_vp9_parser;
>  extern const AVCodecParser ff_webp_parser;
>  extern const AVCodecParser ff_xbm_parser;
>  extern const AVCodecParser ff_xma_parser;
> +extern const AVCodecParser ff_evc_parser;

alphabetical order

>  
>  #include "libavcodec/parser_list.c"
>  
> diff --git a/libavcodec/profiles.c b/libavcodec/profiles.c
> index 7af7fbeb13..a31244e0db 100644
> --- a/libavcodec/profiles.c
> +++ b/libavcodec/profiles.c
> @@ -181,4 +181,10 @@ const AVProfile ff_arib_caption_profiles[] = {
>      { FF_PROFILE_UNKNOWN }
>  };
>  
> +const AVProfile ff_evc_profiles[] = {
> +    { FF_PROFILE_EVC_BASELINE,             "Baseline"              },
> +    { FF_PROFILE_EVC_MAIN,                 "Main"                  },
> +    { FF_PROFILE_UNKNOWN },
> +};
> +
>  #endif /* !CONFIG_SMALL */
> diff --git a/libavcodec/profiles.h b/libavcodec/profiles.h
> index 41a19aa9ad..cf92b5f126 100644
> --- a/libavcodec/profiles.h
> +++ b/libavcodec/profiles.h
> @@ -72,5 +72,6 @@ extern const AVProfile ff_sbc_profiles[];
>  extern const AVProfile ff_prores_profiles[];
>  extern const AVProfile ff_mjpeg_profiles[];
>  extern const AVProfile ff_arib_caption_profiles[];
> +extern const AVProfile ff_evc_profiles[];
>  
>  #endif /* AVCODEC_PROFILES_H */
> diff --git a/libavcodec/version.h b/libavcodec/version.h
> index 4d77431842..fb1a0feec6 100644
> --- a/libavcodec/version.h
> +++ b/libavcodec/version.h
> @@ -28,7 +28,7 @@
>  #include "libavutil/version.h"
>  
>  #define LIBAVCODEC_VERSION_MAJOR  59
> -#define LIBAVCODEC_VERSION_MINOR  18
> +#define LIBAVCODEC_VERSION_MINOR  19
>  #define LIBAVCODEC_VERSION_MICRO 100
>  
>  #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
> diff --git a/libavformat/Makefile b/libavformat/Makefile
> index 84e73e3c63..db461e79b7 100644
> --- a/libavformat/Makefile
> +++ b/libavformat/Makefile
> @@ -241,6 +241,8 @@ OBJS-$(CONFIG_HCOM_DEMUXER)              += hcom.o pcm.o
>  OBJS-$(CONFIG_HDS_MUXER)                 += hdsenc.o
>  OBJS-$(CONFIG_HEVC_DEMUXER)              += hevcdec.o rawdec.o
>  OBJS-$(CONFIG_HEVC_MUXER)                += rawenc.o
> +OBJS-$(CONFIG_EVC_DEMUXER)               += evcdec.o rawdec.o
> +OBJS-$(CONFIG_EVC_MUXER)                 += rawenc.o
>  OBJS-$(CONFIG_HLS_DEMUXER)               += hls.o hls_sample_encryption.o
>  OBJS-$(CONFIG_HLS_MUXER)                 += hlsenc.o hlsplaylist.o avc.o
>  OBJS-$(CONFIG_HNM_DEMUXER)               += hnm.o
> diff --git a/libavformat/allformats.c b/libavformat/allformats.c
> index d066a7745b..1148024e71 100644
> --- a/libavformat/allformats.c
> +++ b/libavformat/allformats.c
> @@ -145,6 +145,8 @@ extern const AVInputFormat  ff_ea_cdata_demuxer;
>  extern const AVInputFormat  ff_eac3_demuxer;
>  extern const AVOutputFormat ff_eac3_muxer;
>  extern const AVInputFormat  ff_epaf_demuxer;
> +extern const AVInputFormat  ff_evc_demuxer;
> +extern const AVOutputFormat ff_evc_muxer;
>  extern const AVOutputFormat ff_f4v_muxer;
>  extern const AVInputFormat  ff_ffmetadata_demuxer;
>  extern const AVOutputFormat ff_ffmetadata_muxer;
> diff --git a/libavformat/evcdec.c b/libavformat/evcdec.c
> new file mode 100644
> index 0000000000..dd9102cdd4
> --- /dev/null
> +++ b/libavformat/evcdec.c
> @@ -0,0 +1,136 @@
> +/*
> + * RAW EVC video demuxer
> + *
> + * Copyright (c) 2021 Dawid Kozinski <d.kozinski at samsung.com>
> + *
> + * 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 FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include "libavcodec/get_bits.h"
> +#include "libavcodec/golomb.h"
> +#include "avformat.h"
> +#include "rawdec.h"
> +#include "libavcodec/internal.h"
> +#include "xevd.h"
> +
> +typedef struct EVCParserContext {
> +    int got_sps;
> +    int got_pps;
> +    int got_idr;
> +    int got_nonidr;
> +} EVCParserContext;
> +
> +static int get_nalu_type(const uint8_t *bs, int bs_size)
> +{
> +    GetBitContext gb;
> +    int fzb, nut;
> +    init_get_bits(&gb, bs, bs_size * 8);
> +    fzb = get_bits1(&gb);
> +    if(fzb != 0) {
> +        av_log(NULL, AV_LOG_DEBUG, "forbidden_zero_bit is not clear\n");
> +    }
> +    nut = get_bits(&gb, 6); /* nal_unit_type_plus1 */
> +    return nut - 1;
> +}
> +
> +/**
> + * Read NAL unit length
> + * @param bs input data (bitstream)
> + * @return the lenghth of NAL unit on success, 0 value on failure
> + */
> +static uint32_t read_nal_unit_length(const uint8_t *bs, int bs_size)
> +{
> +    uint32_t len = 0;
> +    XEVD_INFO info;
> +    int ret;
> +
> +    if(bs_size>=XEVD_NAL_UNIT_LENGTH_BYTE) {
> +        ret = xevd_info((void*)bs, XEVD_NAL_UNIT_LENGTH_BYTE, 1, &info);
> +        if (XEVD_FAILED(ret)) {
> +            av_log(NULL, AV_LOG_ERROR, "Cannot get bitstream information\n");
> +            return 0;
> +        }
> +        len = info.nalu_len;
> +        if(len == 0)
> +        {
> +            av_log(NULL, AV_LOG_ERROR, "Invalid bitstream size! [%d]\n", bs_size);
> +            return 0;
> +        }
> +    }
> +    return len;
> +}
> +
> +static int parse_nal_units(const AVProbeData *p, EVCParserContext *ev)
> +{
> +    int nalu_type;
> +    size_t nalu_size;
> +    unsigned char* bits = (unsigned char *)p->buf;
> +    int bytes_to_read = p->buf_size;
> +    
> +    av_log(NULL, AV_LOG_DEBUG, "bytes_to_read: %d \n", bytes_to_read);
> +
> +    while(bytes_to_read > XEVD_NAL_UNIT_LENGTH_BYTE) {
> +    
> +        nalu_size = read_nal_unit_length(bits, XEVD_NAL_UNIT_LENGTH_BYTE);
> +        if(nalu_size == 0) break;
> +
> +        bits += XEVD_NAL_UNIT_LENGTH_BYTE;
> +        bytes_to_read -= XEVD_NAL_UNIT_LENGTH_BYTE;
> +
> +        av_log(NULL, AV_LOG_DEBUG, "nalu_size: %ld \n", nalu_size);
> +
> +        if(bytes_to_read < nalu_size) break;
> +
> +        nalu_type = get_nalu_type(bits, bytes_to_read);
> +
> +        bits += nalu_size;
> +        bytes_to_read -= nalu_size;
> +
> +        if (nalu_type == XEVD_NUT_SPS) {
> +            av_log(NULL, AV_LOG_DEBUG, "XEVD_NUT_SPS \n");
> +            ev->got_sps++;
> +        }
> +        else if (nalu_type == XEVD_NUT_PPS) {
> +            av_log(NULL, AV_LOG_DEBUG, "XEVD_NUT_PPS \n");
> +            ev->got_pps++;
> +        }
> +        else if (nalu_type == XEVD_NUT_IDR ) {
> +            av_log(NULL, AV_LOG_DEBUG, "XEVD_NUT_IDR\n");
> +            ev->got_idr++;
> +        }
> +        else if (nalu_type == XEVD_NUT_NONIDR) {
> +            av_log(NULL, AV_LOG_DEBUG, "XEVD_NUT_NONIDR\n");
> +            ev->got_nonidr++;
> +        }
> +    }
> +    return 0;
> +}
> +
> +static int evc_probe(const AVProbeData *p)
> +{
> +    EVCParserContext ev = {};
> +    int ret = parse_nal_units(p, &ev);
> +
> +    av_log(NULL, AV_LOG_DEBUG, "sps:%d pps:%d idr:%d sli:%d\n", ev.got_sps, ev.got_pps, ev.got_idr, ev.got_nonidr);
> +    
> +    if (ret == 0 && ev.got_sps && ev.got_pps && (ev.got_idr || ev.got_nonidr > 3)) 
> +        return AVPROBE_SCORE_EXTENSION + 1;  // 1 more than .mpg
> +
> +    return 0;
> +}
> +
> +FF_DEF_RAWVIDEO_DEMUXER(evc, "raw EVC video", evc_probe, "evc", AV_CODEC_ID_EVC)
> diff --git a/libavformat/isom_tags.c b/libavformat/isom_tags.c
> index 62e60470a8..0245cfb999 100644
> --- a/libavformat/isom_tags.c
> +++ b/libavformat/isom_tags.c
> @@ -145,6 +145,8 @@ const AVCodecTag ff_codec_movvideo_tags[] = {
>      { AV_CODEC_ID_H264, MKTAG('d', 'v', 'a', '1') }, /* AVC-based Dolby Vision derived from avc1 */
>      { AV_CODEC_ID_H264, MKTAG('d', 'v', 'a', 'v') }, /* AVC-based Dolby Vision derived from avc3 */
>  
> +    { AV_CODEC_ID_EVC,  MKTAG('e', 'v', 'c', '1') }, /* EVC/MPEG-5 */
> +
>      { AV_CODEC_ID_VP8,  MKTAG('v', 'p', '0', '8') }, /* VP8 */
>      { AV_CODEC_ID_VP9,  MKTAG('v', 'p', '0', '9') }, /* VP9 */
>      { AV_CODEC_ID_AV1,  MKTAG('a', 'v', '0', '1') }, /* AV1 */
> diff --git a/libavformat/mov.c b/libavformat/mov.c
> index 6fb09df7e1..e83872fbe2 100644
> --- a/libavformat/mov.c
> +++ b/libavformat/mov.c
> @@ -8568,7 +8568,7 @@ const AVInputFormat ff_mov_demuxer = {
>      .long_name      = NULL_IF_CONFIG_SMALL("QuickTime / MOV"),
>      .priv_class     = &mov_class,
>      .priv_data_size = sizeof(MOVContext),
> -    .extensions     = "mov,mp4,m4a,3gp,3g2,mj2,psp,m4b,ism,ismv,isma,f4v",
> +    .extensions     = "mov,mp4,m4a,3gp,3g2,mj2,psp,m4b,ism,ismv,isma,f4v,evc",
>      .flags_internal = FF_FMT_INIT_CLEANUP,
>      .read_probe     = mov_probe,
>      .read_header    = mov_read_header,
> diff --git a/libavformat/movenc.c b/libavformat/movenc.c
> index 4c868919ae..30e5037f06 100644
> --- a/libavformat/movenc.c
> +++ b/libavformat/movenc.c
> @@ -1342,6 +1342,16 @@ static int mov_write_hvcc_tag(AVIOContext *pb, MOVTrack *track)
>      return update_size(pb, pos);
>  }
>  
> +static int mov_write_evcc_tag(AVIOContext *pb, MOVTrack *track)
> +{
> +    int64_t pos = avio_tell(pb);
> +
> +    avio_wb32(pb, 0);
> +    ffio_wfourcc(pb, "evcC");
> +    ff_isom_write_avcc(pb, track->vos_data, track->vos_len);
> +    return update_size(pb, pos);
> +}
> +
>  /* also used by all avid codecs (dv, imx, meridien) and their variants */
>  static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track)
>  {
> @@ -1591,6 +1601,19 @@ static int mov_get_h264_codec_tag(AVFormatContext *s, MOVTrack *track)
>      return tag;
>  }
>  
> +static int mov_get_evc_codec_tag(AVFormatContext *s, MOVTrack *track)
> +{
> +    int tag = track->par->codec_tag;
> +    int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
> +    AVStream *st = track->st;
> +    int rate = defined_frame_rate(s, st);
> +
> +    if (!tag)
> +        tag = MKTAG('e', 'v', 'c', 'i'); //fallback tag
> +
> +    return tag;
> +}
> +
>  static const struct {
>      enum AVPixelFormat pix_fmt;
>      uint32_t tag;
> @@ -1672,6 +1695,8 @@ static unsigned int mov_get_codec_tag(AVFormatContext *s, MOVTrack *track)
>              tag = mov_get_mpeg2_xdcam_codec_tag(s, track);
>          else if (track->par->codec_id == AV_CODEC_ID_H264)
>              tag = mov_get_h264_codec_tag(s, track);
> +        else if (track->par->codec_id == AV_CODEC_ID_EVC)
> +            tag = mov_get_evc_codec_tag(s, track);    
>          else if (track->par->codec_id == AV_CODEC_ID_DNXHD)
>              tag = mov_get_dnxhd_codec_tag(s, track);
>          else if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
> @@ -2208,6 +2233,9 @@ static int mov_write_video_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContex
>          mov_write_avcc_tag(pb, track);
>          if (track->mode == MODE_IPOD)
>              mov_write_uuid_tag_ipod(pb);
> +    }
> +    else if (track->par->codec_id ==AV_CODEC_ID_EVC) {
> +        mov_write_evcc_tag(pb, track);        
>      } else if (track->par->codec_id == AV_CODEC_ID_VP9) {
>          mov_write_vpcc_tag(mov->fc, pb, track);
>      } else if (track->par->codec_id == AV_CODEC_ID_AV1) {
> @@ -5737,6 +5765,7 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
>      if ((par->codec_id == AV_CODEC_ID_DNXHD ||
>           par->codec_id == AV_CODEC_ID_H264 ||
>           par->codec_id == AV_CODEC_ID_HEVC ||
> +         par->codec_id == AV_CODEC_ID_EVC ||
>           par->codec_id == AV_CODEC_ID_TRUEHD ||
>           par->codec_id == AV_CODEC_ID_AC3) && !trk->vos_len &&
>           !TAG_IS_AVCI(trk->tag)) {
> @@ -7311,6 +7340,7 @@ static const AVCodecTag codec_mp4_tags[] = {
>      { AV_CODEC_ID_H264,            MKTAG('a', 'v', 'c', '3') },
>      { AV_CODEC_ID_HEVC,            MKTAG('h', 'e', 'v', '1') },
>      { AV_CODEC_ID_HEVC,            MKTAG('h', 'v', 'c', '1') },
> +    { AV_CODEC_ID_EVC,             MKTAG('e', 'v', 'c', '1') },
>      { AV_CODEC_ID_MPEG2VIDEO,      MKTAG('m', 'p', '4', 'v') },
>      { AV_CODEC_ID_MPEG1VIDEO,      MKTAG('m', 'p', '4', 'v') },
>      { AV_CODEC_ID_MJPEG,           MKTAG('m', 'p', '4', 'v') },
> diff --git a/libavformat/rawenc.c b/libavformat/rawenc.c
> index 4bbae7717b..322ab583ab 100644
> --- a/libavformat/rawenc.c
> +++ b/libavformat/rawenc.c
> @@ -386,6 +386,20 @@ const AVOutputFormat ff_hevc_muxer = {
>  };
>  #endif
>  
> +#if CONFIG_EVC_MUXER
> +AVOutputFormat ff_evc_muxer = {
> +    .name              = "evc",
> +    .long_name         = NULL_IF_CONFIG_SMALL("raw EVC video"),
> +    .extensions        = "evc",
> +    .audio_codec       = AV_CODEC_ID_NONE,
> +    .video_codec       = AV_CODEC_ID_EVC,
> +    .write_header      = force_one_stream,
> +    .write_packet      = ff_raw_write_packet,
> +    .flags             = AVFMT_NOTIMESTAMPS,
> +};
> +#endif
> +
> +
>  #if CONFIG_M4V_MUXER
>  const AVOutputFormat ff_m4v_muxer = {
>      .name              = "m4v",



More information about the ffmpeg-devel mailing list