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

Dawid Kozinski/Robot SDK (PLT) /SRPOL/Staff Engineer/삼성전자 d.kozinski at samsung.com
Thu May 12 09:07:02 EEST 2022


Thank you for your review. All your suggestions have been taken into account and new patches have just been put on the mailing list.

-----Original Message-----
From: ffmpeg-devel <ffmpeg-devel-bounces at ffmpeg.org> On Behalf Of James Almer
Sent: Tuesday, April 5, 2022 8:53 PM
To: ffmpeg-devel at ffmpeg.org
Subject: Re: [FFmpeg-devel] [PATCH] Provided support for MPEG-5 EVC (Essential Video Coding) codec

On 4/4/2022 9:29 AM, Dawid Kozinski wrote:
> 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
>   "
>   
>   HWACCEL_AUTODETECT_LIBRARY_LIST="
> @@ -2453,6 +2457,7 @@ CONFIG_EXTRA="
>       h264pred
>       h264qpel
>       hevcparse
> +    evcparse

This is unused, so remove it from here and below.

It has been FIXED

>       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"
>   
>   # 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"
>   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
>   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/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 @@
> +/*
> + * EVC AVC format parser
> + *
> + * 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 "libavutil/common.h"
> +
> +#include "golomb.h"
> +#include "parser.h"
> +#include "xevd.h"

A parser must not depend on external libraries or headers.

It has been FIXED. I removed dependency on XEVD library.

> +#include <stdint.h>
> +
> +#define EVC_NAL_HEADER_SIZE   2 /* byte */
> +#define MAX_SPS_CNT  16 /* defined value in EVC standard */
> +
> +typedef struct _EVCParserSPS {
> +    int sps_id;
> +    int profile_idc;
> +    int level_idc;
> +    int chroma_format_idc;
> +    int pic_width_in_luma_samples;
> +    int pic_height_in_luma_samples;
> +    int bit_depth_luma;
> +    int bit_depth_chroma;
> +
> +    int picture_cropping_flag;
> +    int picture_crop_left_offset;
> +    int picture_crop_right_offset;
> +    int picture_crop_top_offset;
> +    int picture_crop_bottom_offset;
> +} EVCParserSPS;
> +
> +typedef struct EVCParserContext {
> +    ParseContext pc;
> +    EVCParserSPS sps[MAX_SPS_CNT];
> +    int is_avc;
> +    int nal_length_size;
> +    int to_read;
> +    int incomplete_nalu_prefix_read; // The flag is set to 1 when incomplete NAL unit prefix has been read
> +
> +    int parsed_extradata;
> +
> +    int poc;
> +    int pocTid0;
> +
> +    int got_sps;
> +    int got_pps;
> +    int got_sei;
> +    int got_slice;
> +} 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;
> +}
> +
> +static int get_nalu_type2(const uint8_t *bs, int bs_size)
> +{
> +    int nalu_type = 0;
> +    XEVD_INFO info;
> +    int ret;
> +
> +    if(bs_size>=EVC_NAL_HEADER_SIZE) {
> +        ret = xevd_info((void*)bs, EVC_NAL_HEADER_SIZE, 1, &info);

You will need to implement this parsing in lavc.

I left the implementation of EVC parser in libavcode/evc_parser.c

I recommend you doing it as a CBS module, which can be reused by 
different components, and will make writing this parser easier.

See cbs_h2645.c and so.

> +        if (XEVD_FAILED(ret)) {
> +            av_log(NULL, AV_LOG_ERROR, "Cannot get bitstream information\n");
> +            return 0;
> +        }
> +        nalu_type = info.nalu_type;
> +
> +    }
> +    return nalu_type-1;
> +}
> +
> +static EVCParserSPS * parse_sps(const uint8_t *bs, int bs_size, EVCParserContext *ev)
> +{
> +    GetBitContext gb;
> +    EVCParserSPS *sps;
> +    int sps_id;
> +
> +    init_get_bits(&gb, bs, bs_size*8);
> +
> +    sps_id = get_ue_golomb(&gb);
> +    if(sps_id >= MAX_SPS_CNT) goto ERR;
> +    sps = &ev->sps[sps_id];
> +    sps->sps_id = sps_id;
> +    av_log(NULL, AV_LOG_DEBUG, "[EVC Parser] sps_id=%d\n", sps->sps_id);
> +
> +    sps->profile_idc = get_bits(&gb, 8);
> +    av_log(NULL, AV_LOG_DEBUG, "[EVC Parser] profile=%d\n", sps->profile_idc);
> +    sps->level_idc = get_bits(&gb, 8);
> +
> +    skip_bits_long(&gb, 32); /* skip toolset_idc_h */
> +    skip_bits_long(&gb, 32); /* skip toolset_idc_l */
> +
> +    sps->chroma_format_idc = get_ue_golomb(&gb);
> +    sps->pic_width_in_luma_samples = get_ue_golomb(&gb);
> +    av_log(NULL, AV_LOG_DEBUG, "[EVC Parser] width=%d\n", sps->pic_width_in_luma_samples);
> +    sps->pic_height_in_luma_samples = get_ue_golomb(&gb);
> +
> +    av_log(NULL, AV_LOG_DEBUG, "[EVC Parser] height=%d\n", sps->pic_height_in_luma_samples);
> +    sps->bit_depth_luma = get_ue_golomb(&gb);
> +    sps->bit_depth_chroma = get_ue_golomb(&gb);
> +
> +    // @todo we need to parse crop and vui information here
> +
> +    return sps;
> +
> +ERR:
> +    return NULL;
> +}
> +
> +/**
> + * 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! 1 [%d] [%d]\n", len, bs_size);
> +            return 0;
> +        }
> +    }
> +    return len;
> +}
> +
> +static int parse_nal_units(AVCodecParserContext *s, const uint8_t *bs,
> +                           int bs_size, AVCodecContext *ctx)
> +{
> +    EVCParserContext *ev = s->priv_data;
> +    int nalu_type, nalu_size;
> +    unsigned char * bits = (unsigned char *)bs;
> +    int bits_size = bs_size;
> +
> +    ctx->codec_id = AV_CODEC_ID_EVC;
> +
> +    nalu_size = read_nal_unit_length(bits, bits_size);
> +    if(nalu_size==0) {
> +        av_log(ctx, AV_LOG_ERROR, "Invalid NAL unit size: (%d)\n", nalu_size);
> +        return -1;
> +    }
> +
> +    bits += XEVD_NAL_UNIT_LENGTH_BYTE;
> +    bits_size -= XEVD_NAL_UNIT_LENGTH_BYTE;
> +
> +    nalu_type = get_nalu_type2(bits, bits_size);
> +
> +    bits += EVC_NAL_HEADER_SIZE;
> +    bits_size -= EVC_NAL_HEADER_SIZE;
> +
> +
> +    if (nalu_type == XEVD_NUT_SPS) {
> +        EVCParserSPS * sps;
> +
> +        sps = parse_sps(bits, bits_size, ev);
> +
> +        ctx->coded_width         = sps->pic_width_in_luma_samples;
> +        ctx->coded_height        = sps->pic_height_in_luma_samples;
> +        ctx->width               = sps->pic_width_in_luma_samples;
> +        ctx->height              = sps->pic_height_in_luma_samples;
> +
> +        if(sps->profile_idc == 0) ctx->profile = FF_PROFILE_EVC_BASELINE;
> +        else if (sps->profile_idc == 1) ctx->profile = FF_PROFILE_EVC_MAIN;
> +        else{
> +            av_log(ctx, AV_LOG_ERROR, "not supported profile (%d)\n", sps->profile_idc);
> +            return -1;
> +        }
> +
> +        switch(sps->chroma_format_idc)
> +        {
> +        case 0: /* YCBCR400_10LE */
> +            /* @todo support this */
> +            ctx->pix_fmt = AV_PIX_FMT_GRAY10LE;
> +            return -1;
> +            break;
> +        case 1: /* YCBCR420_10LE */
> +            ctx->pix_fmt = AV_PIX_FMT_YUV420P10LE;
> +            break;
> +        case 2: /* YCBCR422_10LE */
> +            /* @todo support this */
> +            ctx->pix_fmt = AV_PIX_FMT_YUV422P10LE;
> +            return -1;
> +            break;
> +        case 3: /* YCBCR444_10LE */
> +            /* @todo support this */
> +            ctx->pix_fmt = AV_PIX_FMT_YUV444P10LE;
> +            return -1;
> +            break;
> +        default:
> +            ctx->pix_fmt = AV_PIX_FMT_NONE;
> +            av_log(NULL, AV_LOG_ERROR, "unknown color space\n");
> +            return -1;
> +        }
> +
> +        //avctx->has_b_frames = 1; // @todo FIX-ME
> +
> +        ev->got_sps = 1;
> +
> +    }
> +    else if (nalu_type == XEVD_NUT_PPS) {
> +        av_log(NULL, AV_LOG_DEBUG, "XEVD_NUT_PPS \n");
> +        ev->got_pps = 1;
> +    }
> +    else if(nalu_type == XEVD_NUT_SEI) {
> +        av_log(NULL, AV_LOG_DEBUG, "XEVD_NUT_SEI \n");
> +        ev->got_sei = 1;

This is a write only field.

> +    }
> +    else if (nalu_type == XEVD_NUT_IDR || nalu_type == XEVD_NUT_NONIDR) {
> +        av_log(ctx, AV_LOG_DEBUG, "XEVD_NUT_NONIDR\n");
> +        ev->got_slice++;

This too. Maybe you meant to set ctx->pict_type based on nalu_type?

What do you mean? I don't get it. Seems I need more explanations.

> +    } else {
> +        av_log(ctx, AV_LOG_ERROR, "Invalid NAL unit type: %d\n", nalu_type);
> +        return -1;
> +    }
> +    return 0;
> +}
> +
> +
> +/**
> + * Find the end of the current frame in the bitstream.
> + * @return the position of the first byte of the next frame, or END_NOT_FOUND
> + */
> +static int evc_find_frame_end(AVCodecParserContext *s, const uint8_t *buf,
> +                               int buf_size)
> +{
> +    EVCParserContext *ev = s->priv_data;
> +
> +    if(!ev->to_read)
> +    {
> +        int nal_unit_size = 0;
> +        int next = END_NOT_FOUND;
> +
> +        // This is the case when buffer size is not enough for buffer to store NAL unit length
> +        if(buf_size < XEVD_NAL_UNIT_LENGTH_BYTE) {
> +            ev->to_read = XEVD_NAL_UNIT_LENGTH_BYTE;
> +            ev->nal_length_size = buf_size;
> +            ev->incomplete_nalu_prefix_read  = 1;
> +
> +            return END_NOT_FOUND;
> +        }
> +
> +        nal_unit_size = read_nal_unit_length(buf, buf_size);
> +        av_log(NULL, AV_LOG_DEBUG, "nal_unit_size: %d | buf_size: %d \n", nal_unit_size, buf_size);
> +        ev->nal_length_size = XEVD_NAL_UNIT_LENGTH_BYTE;
> +
> +        next = nal_unit_size + XEVD_NAL_UNIT_LENGTH_BYTE;
> +        ev->to_read = next;
> +        if(next<buf_size)
> +            return next;
> +        else
> +            return END_NOT_FOUND;
> +    } else if(ev->to_read > buf_size) {
> +        /// @todo Consider handling the following case
> +        // if(ev->incomplete_nalu_prefix_read  == 1) {
> +        // }
> +        return END_NOT_FOUND;
> +    } else  {
> +        if(ev->incomplete_nalu_prefix_read  == 1) {
> +            EVCParserContext *ev = s->priv_data;
> +            ParseContext *pc = &ev->pc;
> +            uint8_t nalu_len[XEVD_NAL_UNIT_LENGTH_BYTE] = {0};
> +            int nal_unit_size = 0;
> +
> +            // 1. pc->buffer contains previously read bytes of NALU prefix
> +            // 2. buf contains the rest of NAL unit prefix bytes
> +            //
> +            // ~~~~~~~
> +            // EXAMPLE
> +            // ~~~~~~~
> +            //
> +            // In the following example we assumed that the number of already read NAL Unit prefix bytes is equal 1
> +            //
> +            // ----------
> +            // pc->buffer -> conatins already read bytes
> +            // ----------
> +            //              __ pc->index == 1
> +            //             |
> +            //             V
> +            // -------------------------------------------------------
> +            // |   0   |   1   |   2   |   3   |   4   | ... |   N   |
> +            // -------------------------------------------------------
> +            // |  0x00 |  0xXX |  0xXX |  0xXX |  0xXX | ... |  0xXX |
> +            // -------------------------------------------------------
> +            //
> +            // ----------
> +            // buf -> contains newly read bytes
> +            // ----------
> +            // -------------------------------------------------------
> +            // |   0   |   1   |   2   |   3   |   4   | ... |   N   |
> +            // -------------------------------------------------------
> +            // |  0x00 |  0x00 |  0x3C |  0xXX |  0xXX | ... |  0xXX |
> +            // -------------------------------------------------------
> +            //
> +            for(int i=0;i<XEVD_NAL_UNIT_LENGTH_BYTE;i++) {
> +                if(i<pc->index) {
> +                    nalu_len[i] = pc->buffer[i];
> +                } else {
> +                    nalu_len[i] = buf[i-pc->index];
> +                }
> +            }
> +
> +            // ----------
> +            // nalu_len
> +            // ----------
> +            // ---------------------------------
> +            // |   0   |   1   |   2   |   3   |
> +            // ---------------------------------
> +            // |  0x00 |  0x00 |  0x00 |  0x3C |
> +            // ---------------------------------
> +            // | NALU LENGTH                   |
> +            // ---------------------------------
> +            // NAL Unit lenght =  60 (0x0000003C)
> +
> +            nal_unit_size = read_nal_unit_length(nalu_len, XEVD_NAL_UNIT_LENGTH_BYTE);
> +            av_log(NULL, AV_LOG_DEBUG, "nal_unit_size: %d | buf_size: %d \n", nal_unit_size, buf_size);
> +
> +            ev->to_read = nal_unit_size + XEVD_NAL_UNIT_LENGTH_BYTE - pc->index;
> +
> +            ev->incomplete_nalu_prefix_read = 0;
> +
> +            if(ev->to_read > buf_size) {
> +                return END_NOT_FOUND;
> +            } else  {
> +                return ev->to_read;
> +            }
> +        }
> +        return ev->to_read;
> +    }
> +    return END_NOT_FOUND;
> +}
> +
> +static int evc_parser_init(AVCodecParserContext *s) {
> +
> +    EVCParserContext *ev = s->priv_data;
> +
> +    av_log(NULL, AV_LOG_DEBUG, "eXtra-fast Essential Video Parser\n");

Unnecessary log message.

Fixed. It has been REMOVED.

> +
> +    ev->got_sps = 0;
> +    ev->got_pps = 0;
> +    ev->got_sei = 0;
> +    ev->got_slice = 0;
> +    ev->nal_length_size = XEVD_NAL_UNIT_LENGTH_BYTE;
> +    ev->incomplete_nalu_prefix_read = 0;
> +
> +    return 0;
> +}
> +
> +static int evc_parse(AVCodecParserContext *s, AVCodecContext *ctx,
> +                     const uint8_t **poutbuf, int *poutbuf_size,
> +                     const uint8_t *buf, int buf_size)
> +{
> +    int next;
> +    EVCParserContext *ev = s->priv_data;
> +    ParseContext *pc = &ev->pc;
> +    int is_dummy_buf = !buf_size;
> +    const uint8_t *dummy_buf = buf;
> +
> +    if (ctx->extradata && !ev->parsed_extradata) {
> +        // @todo consider handling extradata
> +        //
> +        // ff_evc_decode_extradata(avctx->extradata, avctx->extradata_size, &ctx->ps, &ctx->sei,
> +        //                         &ctx->is_avc, &ctx->nal_length_size, avctx->err_recognition,
> +        //                         1, avctx);
> +        ev->parsed_extradata = 1;
> +    }
> +
> +    if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
> +        next = buf_size;
> +    } else {
> +        next = evc_find_frame_end(s, buf, buf_size);
> +        if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
> +            *poutbuf      = NULL;
> +            *poutbuf_size = 0;
> +            ev->to_read -= buf_size;
> +            return buf_size;
> +        }
> +    }
> +#if 1
> +    is_dummy_buf &= (dummy_buf == buf);
> +
> +    if (!is_dummy_buf) {
> +        parse_nal_units(s, buf, buf_size, ctx);
> +    }
> +#else
> +    if(next != END_NOT_FOUND) {
> +        parse_nal_units(s, buf, buf_size, avctx);
> +    }
> +#endif
> +
> +    *poutbuf      = buf;
> +    *poutbuf_size = buf_size;
> +    ev->to_read -= next;
> +    return next;
> +}
> +
> +// 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)

Remove this, not only because it's a no-op the way you wrote it, but 
also because AVCodecParser.split() is unused.

Fixed. It has  been REMOVED.

> +{
> +    return 0;
> +}
> +
> +static av_cold void evc_parser_close(AVCodecParserContext *s)
> +{
> +    /* EVCParserContext *ctx = s->priv_data; */
> +}
> +
> +AVCodecParser ff_evc_parser = {
> +    .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

Is this a remnant of debuging code? Just remove it and either use golomb 
or not.

Fixed. It has  been REMOVED.

> +#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).
> + */
> +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
> +
> +#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

Again, no checks for defines that are not defined anywhere.

Fixed. It has  been REMOVED.

> +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);

Don't print to NULL.
Fixed.

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

Ditto.
Fixed. 


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

Ditto, and every other case below.
Fixed

> +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
> + */
> +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(https://protect2.fireeye.com/v1/url?k=61468a3d-00cd9f0b-61470172-74fe485fffe0-8ad78f2bb7ec061f&q=1&e=1d594a0a-a209-4595-9b25-d17e092078bc&u=http%3A%2F%2Fstat.read%2F != 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);

So if there's a decoded image and this loop is run again because 
bs_read_pos is still smaller than pkt->size, you just discard it?

You probably should write this decoder using the decoupled input/output 
API (AVCodec.receive_frame instead of AVCodec.decode)

RE:
xevd_pull uses pool of objects of type XEVD_IMGB.
The pool size is equal MAX_PB_SIZE (26), so release object when it is no more needed

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

ff_get_buffer() already fills fields like this.

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

Return proper AVERROR codes, here and everywhere else.

FIXED


> +}
> +
> +/**
> + * 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 },
> +    { 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 },
> +};
> +
> +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,
> +    .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,

Missing AV_CODEC_CAP_DR1 since you're using ff_get_buffer().

FIXED

> +    .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;
> +        }
> +    }
> +
> +    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);
> +    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) {

Unnecessary checks.

FIXED

> +        av_log(ctx, AV_LOG_ERROR, "Invalid arguments\n");
> +        return -1;
> +    }
> +    xe = ctx->priv_data;

Same.

FIXED

> +    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);

ff_get_encode_buffer().

Should I use ff_get_encode_buffer() instaead of av_grow_packet? Whats wrong wit av_grow_packet?

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

You're not setting reordered_opaque, so why signal this codec capability?

Also add AV_CODEC_CAP_DR1 if you use ff_get_encode_buffer().

> +    .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;
>   
>   #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"

Like with the parser, the demuxer and muxer can't depend on external 
libraries.

FIXED

> +
> +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);

Why are you writing h264 extradata? Especially when you did not define 
any as exported by the encoder or the mov demuxer.

FIXED

> +    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",
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel at ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request at ffmpeg.org with subject "unsubscribe".




More information about the ffmpeg-devel mailing list