PR #23311 opened by Jamaika1
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23311
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23311.patch

# Summary of changes

Briefly describe what this PR does and why.

<!--
If this PR requires new FATE test samples, attach them to the PR and
list their target paths below (relative to the fate-suite root).

Attached filenames must match the sample's filename:

```fate-samples
# e.g. vorbis/new-sample.ogg
```
-->



>From 95ae8c1bf6d1d85b7de01eee80381ce811decd6c Mon Sep 17 00:00:00 2001
From: Jamaika1 <[email protected]>
Date: Tue, 2 Jun 2026 04:27:32 +0000
Subject: [PATCH 01/11] Added image codec AV2

---
 libavcodec/libavm.c    |   49 ++
 libavcodec/libavmdec.c |  315 +++++++++
 libavcodec/libavmenc.c | 1465 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1829 insertions(+)
 create mode 100644 libavcodec/libavm.c
 create mode 100644 libavcodec/libavmdec.c
 create mode 100644 libavcodec/libavmenc.c

diff --git a/libavcodec/libavm.c b/libavcodec/libavm.c
new file mode 100644
index 0000000000..4073fa9684
--- /dev/null
+++ b/libavcodec/libavm.c
@@ -0,0 +1,49 @@
+/*
+ * 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
+ */
+
+/**
+ * @file
+ * AOM common functions
+ */
+
+#include "libavutil/pixdesc.h"
+#include "libavm.h"
+
+void ff_avm_image_copy_16_to_8(AVFrame *pic, struct avm_image *img)
+{
+    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pic->format);
+    int i;
+
+    for (i = 0; i < desc->nb_components; i++) {
+        int w = img->d_w;
+        int h = img->d_h;
+        int x, y;
+
+        if (i) {
+            w = (w + img->x_chroma_shift) >> img->x_chroma_shift;
+            h = (h + img->y_chroma_shift) >> img->y_chroma_shift;
+        }
+
+        for (y = 0; y < h; y++) {
+            uint16_t *src = (uint16_t *)(img->planes[i] + y * img->stride[i]);
+            uint8_t *dst = pic->data[i] + y * pic->linesize[i];
+            for (x = 0; x < w; x++)
+                *dst++ = *src++;
+        }
+    }
+}
diff --git a/libavcodec/libavmdec.c b/libavcodec/libavmdec.c
new file mode 100644
index 0000000000..f1606b90f0
--- /dev/null
+++ b/libavcodec/libavmdec.c
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2010, Google, Inc.
+ *
+ * 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
+ */
+
+/**
+ * @file
+ * AV2 decoder support via libavm
+ */
+
+#include <avm/avm_decoder.h>
+#include <avm/avmdx.h>
+
+#include "libavutil/common.h"
+#include "libavutil/cpu.h"
+#include "libavutil/hdr_dynamic_metadata.h"
+#include "libavutil/imgutils.h"
+
+#include "avcodec.h"
+#include "bytestream.h"
+#include "codec_internal.h"
+#include "decode.h"
+#include "itut35.h"
+#include "libavm.h"
+#include "profiles.h"
+
+typedef struct AV2DecodeContext {
+    struct avm_codec_ctx decoder;
+} AV2DecodeContext;
+
+static av_cold int avm_init(AVCodecContext *avctx,
+                            const struct avm_codec_iface *iface)
+{
+    AV2DecodeContext *ctx           = avctx->priv_data;
+    struct avm_codec_dec_cfg deccfg = {
+        .threads = FFMIN(avctx->thread_count ? avctx->thread_count : 
av_cpu_count(), 16)
+    };
+
+    av_log(avctx, AV_LOG_VERBOSE, "%s\n", avm_codec_version_str());
+    av_log(avctx, AV_LOG_VERBOSE, "%s\n", avm_codec_build_config());
+
+    if (avm_codec_dec_init(&ctx->decoder, iface, &deccfg, 0) != AVM_CODEC_OK) {
+        const char *error = avm_codec_error(&ctx->decoder);
+        av_log(avctx, AV_LOG_ERROR, "Failed to initialize decoder: %s\n",
+               error);
+        return AVERROR(EINVAL);
+    }
+
+    return 0;
+}
+
+// returns 0 on success, AVERROR_INVALIDDATA otherwise
+static int set_pix_fmt(AVCodecContext *avctx, struct avm_image *img)
+{
+    static const enum AVColorRange color_ranges[] = {
+        AVCOL_RANGE_MPEG, AVCOL_RANGE_JPEG
+    };
+    avctx->color_range = color_ranges[img->range];
+    if (img->cp != AVM_CICP_CP_UNSPECIFIED)
+        avctx->color_primaries = (enum AVColorPrimaries)img->cp;
+    if (img->mc != AVM_CICP_MC_UNSPECIFIED)
+        avctx->colorspace  = (enum AVColorSpace)img->mc;
+    if (img->tc != AVM_CICP_TC_UNSPECIFIED)
+        avctx->color_trc   = (enum AVColorTransferCharacteristic)img->tc;
+
+    switch (img->fmt) {
+    case AVM_IMG_FMT_I420:
+    case AVM_IMG_FMT_I42016:
+        if (img->bit_depth == 8) {
+            avctx->pix_fmt = img->monochrome ?
+                             AV_PIX_FMT_GRAY8 : AV_PIX_FMT_YUV420P;
+            avctx->profile = AV_PROFILE_AV1_MAIN;
+            return 0;
+        } else if (img->bit_depth == 10) {
+            avctx->pix_fmt = img->monochrome ?
+                             AV_PIX_FMT_GRAY10 : AV_PIX_FMT_YUV420P10;
+            avctx->profile = AV_PROFILE_AV1_MAIN;
+            return 0;
+        } else if (img->bit_depth == 12) {
+            avctx->pix_fmt = img->monochrome ?
+                             AV_PIX_FMT_GRAY12 : AV_PIX_FMT_YUV420P12;
+            avctx->profile = AV_PROFILE_AV1_PROFESSIONAL;
+            return 0;
+        } else {
+            return AVERROR_INVALIDDATA;
+        }
+    case AVM_IMG_FMT_I422:
+    case AVM_IMG_FMT_I42216:
+        if (img->bit_depth == 8) {
+            avctx->pix_fmt = AV_PIX_FMT_YUV422P;
+            avctx->profile = AV_PROFILE_AV1_PROFESSIONAL;
+            return 0;
+        } else if (img->bit_depth == 10) {
+            avctx->pix_fmt = AV_PIX_FMT_YUV422P10;
+            avctx->profile = AV_PROFILE_AV1_PROFESSIONAL;
+            return 0;
+        } else if (img->bit_depth == 12) {
+            avctx->pix_fmt = AV_PIX_FMT_YUV422P12;
+            avctx->profile = AV_PROFILE_AV1_PROFESSIONAL;
+            return 0;
+        } else {
+            return AVERROR_INVALIDDATA;
+        }
+    case AVM_IMG_FMT_I444:
+    case AVM_IMG_FMT_I44416:
+        if (img->bit_depth == 8) {
+            avctx->pix_fmt = avctx->colorspace == AVCOL_SPC_RGB ?
+                             AV_PIX_FMT_GBRP : AV_PIX_FMT_YUV444P;
+            avctx->profile = AV_PROFILE_AV1_HIGH;
+            return 0;
+        } else if (img->bit_depth == 10) {
+            avctx->pix_fmt = AV_PIX_FMT_YUV444P10;
+            avctx->pix_fmt = avctx->colorspace == AVCOL_SPC_RGB ?
+                             AV_PIX_FMT_GBRP10 : AV_PIX_FMT_YUV444P10;
+            avctx->profile = AV_PROFILE_AV1_HIGH;
+            return 0;
+        } else if (img->bit_depth == 12) {
+            avctx->pix_fmt = avctx->colorspace == AVCOL_SPC_RGB ?
+                             AV_PIX_FMT_GBRP12 : AV_PIX_FMT_YUV444P12;
+            avctx->profile = AV_PROFILE_AV1_PROFESSIONAL;
+            return 0;
+        } else {
+            return AVERROR_INVALIDDATA;
+        }
+
+    default:
+        return AVERROR_INVALIDDATA;
+    }
+}
+
+static int decode_metadata_itu_t_t35(AVFrame *frame,
+                                     const uint8_t *buffer, size_t buffer_size)
+{
+    if (buffer_size < 6)
+        return AVERROR(EINVAL);
+
+    GetByteContext bc;
+    bytestream2_init(&bc, buffer, buffer_size);
+
+    const int country_code = bytestream2_get_byteu(&bc);
+    const int provider_code = bytestream2_get_be16u(&bc);
+    const int provider_oriented_code = bytestream2_get_be16u(&bc);
+    const int application_identifier = bytestream2_get_byteu(&bc);
+
+    // See "HDR10+ AV2 Metadata Handling Specification" v1.0.1, Section 2.1.
+    if (country_code == ITU_T_T35_COUNTRY_CODE_US
+        && provider_code == ITU_T_T35_PROVIDER_CODE_SAMSUNG
+        && provider_oriented_code == 0x0001
+        && application_identifier == 0x04) {
+        // HDR10+
+        AVDynamicHDRPlus *hdr_plus = 
av_dynamic_hdr_plus_create_side_data(frame);
+        if (!hdr_plus)
+            return AVERROR(ENOMEM);
+
+        int res = av_dynamic_hdr_plus_from_t35(hdr_plus, bc.buffer,
+                                               
bytestream2_get_bytes_left(&bc));
+        if (res < 0)
+            return res;
+    }
+
+    return 0;
+}
+
+static int decode_metadata(AVFrame *frame, const struct avm_image *img)
+{
+    const size_t num_metadata = avm_img_num_metadata(img);
+    for (size_t i = 0; i < num_metadata; ++i) {
+        const avm_metadata_t *metadata = avm_img_get_metadata(img, i);
+        if (!metadata)
+            continue;
+
+        switch (metadata->type) {
+        case OBU_METADATA_TYPE_ITUT_T35: {
+            int res = decode_metadata_itu_t_t35(frame, metadata->payload, 
metadata->sz);
+            if (res < 0)
+                return res;
+            break;
+        }
+        default:
+            break;
+        }
+    }
+    return 0;
+}
+
+static int avm_decode(AVCodecContext *avctx, AVFrame *picture,
+                      int *got_frame, AVPacket *avpkt)
+{
+    AV2DecodeContext *ctx = avctx->priv_data;
+    const void *iter      = NULL;
+    struct avm_image *img;
+    int ret;
+
+    if (avm_codec_decode(&ctx->decoder, avpkt->data, avpkt->size, NULL) !=
+        AVM_CODEC_OK) {
+        const char *error  = avm_codec_error(&ctx->decoder);
+        const char *detail = avm_codec_error_detail(&ctx->decoder);
+
+        av_log(avctx, AV_LOG_ERROR, "Failed to decode frame: %s\n", error);
+        if (detail)
+            av_log(avctx, AV_LOG_ERROR, "  Additional information: %s\n",
+                   detail);
+        return AVERROR_INVALIDDATA;
+    }
+
+    if ((img = avm_codec_get_frame(&ctx->decoder, &iter))) {
+        if (img->d_w > img->w || img->d_h > img->h) {
+            av_log(avctx, AV_LOG_ERROR, "Display dimensions %dx%d exceed 
storage %dx%d\n",
+                   img->d_w, img->d_h, img->w, img->h);
+            return AVERROR_EXTERNAL;
+        }
+
+        if ((ret = set_pix_fmt(avctx, img)) < 0) {
+            av_log(avctx, AV_LOG_ERROR, "Unsupported output colorspace (%d) / 
bit_depth (%d)\n",
+                   img->fmt, img->bit_depth);
+            return ret;
+        }
+
+        if ((int)img->d_w != avctx->width || (int)img->d_h != avctx->height) {
+            av_log(avctx, AV_LOG_INFO, "dimension change! %dx%d -> %dx%d\n",
+                   avctx->width, avctx->height, img->d_w, img->d_h);
+            ret = ff_set_dimensions(avctx, img->d_w, img->d_h);
+            if (ret < 0)
+                return ret;
+        }
+        if ((ret = ff_get_buffer(avctx, picture, 0)) < 0)
+            return ret;
+
+#ifdef AVM_CTRL_AVMD_GET_FRAME_FLAGS
+        {
+            avm_codec_frame_flags_t flags;
+            ret = avm_codec_control(&ctx->decoder, AVMD_GET_FRAME_FLAGS, 
&flags);
+            if (ret == AVM_CODEC_OK) {
+                if (flags & AVM_FRAME_IS_KEY)
+                    picture->flags |= AV_FRAME_FLAG_KEY;
+                else
+                    picture->flags &= ~AV_FRAME_FLAG_KEY;
+                if (flags & (AVM_FRAME_IS_KEY | AVM_FRAME_IS_INTRAONLY))
+                    picture->pict_type = AV_PICTURE_TYPE_I;
+                else if (flags & AVM_FRAME_IS_SWITCH)
+                    picture->pict_type = AV_PICTURE_TYPE_SP;
+                else
+                    picture->pict_type = AV_PICTURE_TYPE_P;
+            }
+        }
+#endif
+
+        av_reduce(&picture->sample_aspect_ratio.num,
+                  &picture->sample_aspect_ratio.den,
+                  picture->height * img->r_w,
+                  picture->width * img->r_h,
+                  INT_MAX);
+        ff_set_sar(avctx, picture->sample_aspect_ratio);
+
+        if ((img->fmt & AVM_IMG_FMT_HIGHBITDEPTH) && img->bit_depth == 8)
+            ff_avm_image_copy_16_to_8(picture, img);
+        else {
+            const uint8_t *planes[4] = { img->planes[0], img->planes[1], 
img->planes[2] };
+            const int      stride[4] = { img->stride[0], img->stride[1], 
img->stride[2] };
+
+            av_image_copy(picture->data, picture->linesize, planes,
+                          stride, avctx->pix_fmt, img->d_w, img->d_h);
+        }
+        ret = decode_metadata(picture, img);
+        if (ret < 0) {
+            av_log(avctx, AV_LOG_ERROR, "Failed to decode metadata\n");
+            return ret;
+        }
+        *got_frame = 1;
+    }
+    return avpkt->size;
+}
+
+static av_cold int avm_free(AVCodecContext *avctx)
+{
+    AV2DecodeContext *ctx = avctx->priv_data;
+    avm_codec_destroy(&ctx->decoder);
+    return 0;
+}
+
+static av_cold int av2_init(AVCodecContext *avctx)
+{
+    return avm_init(avctx, avm_codec_av2_dx());
+}
+
+const FFCodec ff_libavm_av2_decoder = {
+    .p.name         = "libavm-av2",
+    CODEC_LONG_NAME("libavm AV2"),
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_AV2,
+    .priv_data_size = sizeof(AV2DecodeContext),
+    .init           = av2_init,
+    .close          = avm_free,
+    FF_CODEC_DECODE_CB(avm_decode),
+    .p.capabilities = AV_CODEC_CAP_OTHER_THREADS | AV_CODEC_CAP_DR1,
+    .caps_internal  = FF_CODEC_CAP_NOT_INIT_THREADSAFE |
+                      FF_CODEC_CAP_AUTO_THREADS,
+    //.p.profiles     = NULL_IF_CONFIG_SMALL(ff_av1_profiles),
+    .p.wrapper_name = "libavm",
+};
diff --git a/libavcodec/libavmenc.c b/libavcodec/libavmenc.c
new file mode 100644
index 0000000000..bd5a22c213
--- /dev/null
+++ b/libavcodec/libavmenc.c
@@ -0,0 +1,1465 @@
+/*
+ * Copyright (c) 2010, Google, Inc.
+ *
+ * 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
+ */
+
+/**
+ * @file
+ * AV2 encoder support via libavm
+ */
+
+#include <limits.h>
+
+#define AVM_DISABLE_CTRL_TYPECHECKS 1
+#include <avm/avm_encoder.h>
+#include <avm/avmcx.h>
+
+#define MAX_TILE_WIDTH (4096)        // Max Tile width in pixels
+#define MAX_TILE_AREA (4096 * 2304)  // Maximum tile area in pixels
+#define MAX_TILE_ROWS 64
+#define MAX_TILE_COLS 64
+
+#include "libavutil/avassert.h"
+#include "libavutil/base64.h"
+#include "libavutil/cpu.h"
+#include "libavutil/hdr_dynamic_metadata.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/mathematics.h"
+#include "libavutil/mem.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+
+#include "avcodec.h"
+#include "bsf.h"
+#include "bytestream.h"
+#include "codec_internal.h"
+#include "dovi_rpu.h"
+#include "encode.h"
+#include "internal.h"
+#include "itut35.h"
+#include "libavm.h"
+#include "profiles.h"
+
+/*
+ * Portion of struct avm_codec_cx_pkt from avm_encoder.h.
+ * One encoded frame returned from the library.
+ */
+struct FrameListData {
+    void *buf;                       /**< compressed data buffer */
+    size_t sz;                       /**< length of compressed data */
+    int64_t pts;                     /**< time stamp to show frame
+                                          (in timebase units) */
+    unsigned long duration;          /**< duration to show frame
+                                          (in timebase units) */
+    uint32_t flags;                  /**< flags for this frame */
+    uint64_t sse[4];
+    int have_sse;                    /**< true if we have pending sse[] */
+    uint64_t frame_number;
+    struct FrameListData *next;
+};
+
+typedef struct AVMEncoderContext {
+    AVClass *class;
+    AVBSFContext *bsf;
+    DOVIContext dovi;
+    struct avm_codec_ctx encoder;
+    struct avm_image rawimg;
+    struct avm_fixed_buf twopass_stats;
+    unsigned twopass_stats_size;
+    struct FrameListData *coded_frame_list;
+    int cpu_used;
+    int auto_alt_ref;
+    int arnr_strength;
+    int aq_mode;
+    int lag_in_frames;
+    int qp;
+    int static_thresh;
+    int denoise_noise_level;
+    int denoise_block_size;
+    uint64_t sse[4];
+    int have_sse; /**< true if we have pending sse[] */
+    uint64_t frame_number;
+    int rc_undershoot_pct;
+    int rc_overshoot_pct;
+    int minsection_pct;
+    int maxsection_pct;
+    int frame_parallel;
+    int tile_cols, tile_rows;
+    int tile_cols_log2, tile_rows_log2;
+    avm_superblock_size_t superblock_size;
+    int uniform_tiles;
+    int row_mt;
+    int enable_cdef;
+    int enable_global_motion;
+    int enable_intrabc;
+    int enable_restoration;
+    int usage;
+    int tune;
+    int still_picture;
+    int enable_rect_partitions;
+    int enable_angle_delta;
+    int enable_cfl_intra;
+    int enable_paeth_intra;
+    int enable_smooth_intra;
+    int enable_intra_edge_filter;
+    int enable_palette;
+    int enable_flip_idtx;
+    int reduced_tx_type_set;
+    int use_intra_dct_only;
+    int use_inter_dct_only;
+    int use_intra_default_tx_only;
+    int enable_ref_frame_mvs;
+    int enable_interinter_wedge;
+    int enable_interintra_wedge;
+    int enable_interintra_comp;
+    int enable_masked_comp;
+    int enable_onesided_comp;
+    int enable_smooth_interintra;
+    int enable_diff_wtd_comp;
+    AVDictionary *avm_params;
+} AVMContext;
+
+#define OFFSET(x) offsetof(AVMContext, x)
+
+static const char *const ctlidstr[] = {
+    [AVME_SET_CPUUSED]          = "AVME_SET_CPUUSED",
+    [AVME_SET_QP]         = "AVME_SET_QP",
+    [AVME_SET_ENABLEAUTOALTREF] = "AVME_SET_ENABLEAUTOALTREF",
+    [AVME_SET_ARNR_MAXFRAMES]   = "AVME_SET_ARNR_MAXFRAMES",
+    [AVME_SET_ARNR_STRENGTH]    = "AVME_SET_ARNR_STRENGTH",
+    [AVME_SET_STATIC_THRESHOLD] = "AVME_SET_STATIC_THRESHOLD",
+    [AV2E_SET_COLOR_RANGE]      = "AV2E_SET_COLOR_RANGE",
+    [AV2E_SET_COLOR_PRIMARIES]  = "AV2E_SET_COLOR_PRIMARIES",
+    [AV2E_SET_MATRIX_COEFFICIENTS] = "AV2E_SET_MATRIX_COEFFICIENTS",
+    [AV2E_SET_TRANSFER_CHARACTERISTICS] = "AV2E_SET_TRANSFER_CHARACTERISTICS",
+    [AV2E_SET_AQ_MODE]          = "AV2E_SET_AQ_MODE",
+    [AV2E_SET_FRAME_PARALLEL_DECODING] = "AV2E_SET_FRAME_PARALLEL_DECODING",
+    [AV2E_SET_SUPERBLOCK_SIZE]  = "AV2E_SET_SUPERBLOCK_SIZE",
+    [AV2E_SET_TILE_COLUMNS]     = "AV2E_SET_TILE_COLUMNS",
+    [AV2E_SET_TILE_ROWS]        = "AV2E_SET_TILE_ROWS",
+    [AV2E_SET_ENABLE_RESTORATION] = "AV2E_SET_ENABLE_RESTORATION",
+    [AV2E_SET_ROW_MT]           = "AV2E_SET_ROW_MT",
+    [AV2E_SET_DENOISE_NOISE_LEVEL] =  "AV2E_SET_DENOISE_NOISE_LEVEL",
+    [AV2E_SET_DENOISE_BLOCK_SIZE] =   "AV2E_SET_DENOISE_BLOCK_SIZE",
+    [AV2E_SET_MAX_REFERENCE_FRAMES] = "AV2E_SET_MAX_REFERENCE_FRAMES",
+    [AV2E_SET_ENABLE_GLOBAL_MOTION] = "AV2E_SET_ENABLE_GLOBAL_MOTION",
+    [AV2E_SET_ENABLE_INTRABC]   = "AV2E_SET_ENABLE_INTRABC",
+    [AV2E_SET_ENABLE_CDEF]      = "AV2E_SET_ENABLE_CDEF",
+    [AVME_SET_TUNING]           = "AVME_SET_TUNING",
+    [AV2E_SET_ENABLE_1TO4_PARTITIONS] = "AV2E_SET_ENABLE_1TO4_PARTITIONS",
+    [AV2E_SET_ENABLE_RECT_PARTITIONS] = "AV2E_SET_ENABLE_RECT_PARTITIONS",
+    [AV2E_SET_ENABLE_ANGLE_DELTA]       = "AV2E_SET_ENABLE_ANGLE_DELTA",
+    [AV2E_SET_ENABLE_CFL_INTRA]         = "AV2E_SET_ENABLE_CFL_INTRA",
+    [AV2E_SET_ENABLE_INTRA_EDGE_FILTER] = "AV2E_SET_ENABLE_INTRA_EDGE_FILTER",
+    [AV2E_SET_ENABLE_PAETH_INTRA]       = "AV2E_SET_ENABLE_PAETH_INTRA",
+    [AV2E_SET_ENABLE_SMOOTH_INTRA]      = "AV2E_SET_ENABLE_SMOOTH_INTRA",
+    [AV2E_SET_ENABLE_PALETTE]           = "AV2E_SET_ENABLE_PALETTE",
+    [AV2E_SET_ENABLE_FLIP_IDTX]      = "AV2E_SET_ENABLE_FLIP_IDTX",
+    [AV2E_SET_INTRA_DCT_ONLY]        = "AV2E_SET_INTRA_DCT_ONLY",
+    [AV2E_SET_INTER_DCT_ONLY]        = "AV2E_SET_INTER_DCT_ONLY",
+    [AV2E_SET_INTRA_DEFAULT_TX_ONLY] = "AV2E_SET_INTRA_DEFAULT_TX_ONLY",
+    [AV2E_SET_REDUCED_TX_TYPE_SET]   = "AV2E_SET_REDUCED_TX_TYPE_SET",
+    [AV2E_SET_ENABLE_DIFF_WTD_COMP]     = "AV2E_SET_ENABLE_DIFF_WTD_COMP",
+    [AV2E_SET_ENABLE_INTERINTER_WEDGE]  = "AV2E_SET_ENABLE_INTERINTER_WEDGE",
+    [AV2E_SET_ENABLE_INTERINTRA_WEDGE]  = "AV2E_SET_ENABLE_INTERINTRA_WEDGE",
+    [AV2E_SET_ENABLE_MASKED_COMP]       = "AV2E_SET_ENABLE_MASKED_COMP",
+    [AV2E_SET_ENABLE_INTERINTRA_COMP]   = "AV2E_SET_ENABLE_INTERINTRA_COMP",
+    [AV2E_SET_ENABLE_ONESIDED_COMP]     = "AV2E_SET_ENABLE_ONESIDED_COMP",
+    [AV2E_SET_REDUCED_REFERENCE_SET]    = "AV2E_SET_REDUCED_REFERENCE_SET",
+    [AV2E_SET_ENABLE_SMOOTH_INTERINTRA] = "AV2E_SET_ENABLE_SMOOTH_INTERINTRA",
+    [AV2E_SET_ENABLE_REF_FRAME_MVS]     = "AV2E_SET_ENABLE_REF_FRAME_MVS",
+    [AV2E_GET_SEQ_LEVEL_IDX]            = "AV2E_GET_SEQ_LEVEL_IDX",
+    [AV2_GET_NEW_FRAME_IMAGE]           = "AV2_GET_NEW_FRAME_IMAGE",
+};
+
+static av_cold void log_encoder_error(AVCodecContext *avctx, const char *desc)
+{
+    AVMContext *ctx    = avctx->priv_data;
+    const char *error  = avm_codec_error(&ctx->encoder);
+    const char *detail = avm_codec_error_detail(&ctx->encoder);
+
+    av_log(avctx, AV_LOG_ERROR, "%s: %s\n", desc, error);
+    if (detail)
+        av_log(avctx, AV_LOG_ERROR, "  Additional information: %s\n", detail);
+}
+
+static av_cold void dump_enc_cfg(AVCodecContext *avctx,
+                                 const struct avm_codec_enc_cfg *cfg,
+                                 int level)
+{
+    int width = -30;
+
+    av_log(avctx, level, "avm_codec_enc_cfg\n");
+    av_log(avctx, level, "generic settings\n"
+                         "  %*s%u\n  %*s%u\n  %*s%u\n  %*s%u\n  %*s%u\n"
+                         "  %*s%u\n  %*s%u\n"
+                         "  %*s{%u/%u}\n  %*s%d\n  %*s%u\n",
+           width, "g_usage:",           cfg->g_usage,
+           width, "g_threads:",         cfg->g_threads,
+           width, "g_profile:",         cfg->g_profile,
+           width, "g_w:",               cfg->g_w,
+           width, "g_h:",               cfg->g_h,
+           width, "g_bit_depth:",       cfg->g_bit_depth,
+           width, "g_input_bit_depth:", cfg->g_input_bit_depth,
+           width, "g_timebase:",        cfg->g_timebase.num, 
cfg->g_timebase.den,
+           width, "g_pass:",            cfg->g_pass,
+           width, "g_lag_in_frames:",   cfg->g_lag_in_frames);
+    av_log(avctx, level, "rate control settings\n"
+                         "  %*s%d\n  %*s%u\n",
+           width, "rc_end_usage:",        cfg->rc_end_usage,
+           width, "rc_target_bitrate:",   cfg->rc_target_bitrate);
+    av_log(avctx, level, "quantizer settings\n"
+                         "  %*s%u\n  %*s%u\n",
+           width, "rc_min_quantizer:", cfg->rc_min_quantizer,
+           width, "rc_max_quantizer:", cfg->rc_max_quantizer);
+    av_log(avctx, level, "bitrate tolerance\n"
+                         "  %*s%u\n  %*s%u\n",
+           width, "rc_undershoot_pct:", cfg->rc_undershoot_pct,
+           width, "rc_overshoot_pct:",  cfg->rc_overshoot_pct);
+    av_log(avctx, level, "decoder buffer model\n"
+                         "  %*s%u\n  %*s%u\n  %*s%u\n",
+           width, "rc_buf_sz:",         cfg->rc_buf_sz,
+           width, "rc_buf_initial_sz:", cfg->rc_buf_initial_sz,
+           width, "rc_buf_optimal_sz:", cfg->rc_buf_optimal_sz);
+    av_log(avctx, level, "2 pass rate control settings\n"
+                         "  %*s%u\n  %*s%u\n",
+           width, "rc_2pass_vbr_minsection_pct:", 
cfg->rc_2pass_vbr_minsection_pct,
+           width, "rc_2pass_vbr_maxsection_pct:", 
cfg->rc_2pass_vbr_maxsection_pct);
+    av_log(avctx, level, "keyframing settings\n"
+                         "  %*s%d\n  %*s%u\n  %*s%u\n",
+           width, "kf_mode:",     cfg->kf_mode,
+           width, "kf_min_dist:", cfg->kf_min_dist,
+           width, "kf_max_dist:", cfg->kf_max_dist);
+    av_log(avctx, level, "tile settings\n"
+                         "  %*s%d\n  %*s%d\n",
+           width, "tile_width_count:",  cfg->tile_width_count,
+           width, "tile_height_count:", cfg->tile_height_count);
+    av_log(avctx, level, "\n");
+}
+
+static void coded_frame_add(void *list, struct FrameListData *cx_frame)
+{
+    struct FrameListData **p = list;
+
+    while (*p)
+        p = &(*p)->next;
+    *p = cx_frame;
+    cx_frame->next = NULL;
+}
+
+static av_cold void free_coded_frame(struct FrameListData *cx_frame)
+{
+    av_freep(&cx_frame->buf);
+    av_freep(&cx_frame);
+}
+
+static av_cold void free_frame_list(struct FrameListData *list)
+{
+    struct FrameListData *p = list;
+
+    while (p) {
+        list = list->next;
+        free_coded_frame(p);
+        p = list;
+    }
+}
+
+static av_cold int codecctl_int(AVCodecContext *avctx,
+                                int id,
+                                int val)
+{
+    AVMContext *ctx = avctx->priv_data;
+    char buf[80];
+    int width = -30;
+    int res;
+
+    snprintf(buf, sizeof(buf), "%s:", ctlidstr[id]);
+    av_log(avctx, AV_LOG_DEBUG, "  %*s%d\n", width, buf, val);
+
+    res = avm_codec_control(&ctx->encoder, id, val);
+    if (res != AVM_CODEC_OK) {
+        snprintf(buf, sizeof(buf), "Failed to set %s codec control",
+                 ctlidstr[id]);
+        log_encoder_error(avctx, buf);
+        return AVERROR(EINVAL);
+    }
+
+    return 0;
+}
+
+static int add_hdr_plus(AVCodecContext *avctx, struct avm_image *img, const 
AVFrame *frame)
+{
+    // Check for HDR10+
+    AVFrameSideData *side_data =
+        av_frame_get_side_data(frame, AV_FRAME_DATA_DYNAMIC_HDR_PLUS);
+    if (!side_data)
+        return 0;
+
+    size_t payload_size;
+    AVDynamicHDRPlus *hdr_plus = (AVDynamicHDRPlus *)side_data->buf->data;
+    int res = av_dynamic_hdr_plus_to_t35(hdr_plus, NULL, &payload_size);
+    if (res < 0) {
+        log_encoder_error(avctx, "Error finding the size of HDR10+");
+        return res;
+    }
+
+    uint8_t *hdr_plus_buf;
+    // Extra bytes for the country code, provider code, provider oriented code 
and app id.
+    const size_t hdr_plus_buf_size = payload_size + 6;
+    hdr_plus_buf = av_malloc(hdr_plus_buf_size);
+    if (!hdr_plus_buf)
+        return AVERROR(ENOMEM);
+
+    uint8_t *payload = hdr_plus_buf;
+    // See "HDR10+ AV2 Metadata Handling Specification" v1.0.1, Section 2.1.
+    bytestream_put_byte(&payload, ITU_T_T35_COUNTRY_CODE_US);
+    bytestream_put_be16(&payload, ITU_T_T35_PROVIDER_CODE_SAMSUNG);
+    bytestream_put_be16(&payload, 0x0001); // provider_oriented_code
+    bytestream_put_byte(&payload, 0x04);   // application_identifier
+
+    res = av_dynamic_hdr_plus_to_t35(hdr_plus, &payload, &payload_size);
+    if (res < 0) {
+        av_free(hdr_plus_buf);
+        log_encoder_error(avctx, "Error encoding HDR10+ from side data");
+        return res;
+    }
+
+    res = avm_img_add_metadata(img, OBU_METADATA_TYPE_ITUT_T35,
+                               hdr_plus_buf, hdr_plus_buf_size, 
AVM_MIF_ANY_FRAME);
+    av_free(hdr_plus_buf);
+    if (res < 0) {
+        log_encoder_error(avctx, "Error adding HDR10+ to avm_img");
+        return res;
+    }
+    return 0;
+}
+
+static int add_hdr_smpte2094_app5(AVCodecContext *avctx, struct avm_image *img,
+                                  const AVFrame *frame)
+{
+    AVFrameSideData *side_data =
+        av_frame_get_side_data(frame, 
AV_FRAME_DATA_DYNAMIC_HDR_SMPTE_2094_APP5);
+    if (!side_data)
+        return 0;
+
+    size_t payload_size;
+    AVDynamicHDRSmpte2094App5 *hdr = (AVDynamicHDRSmpte2094App5 
*)side_data->buf->data;
+    int res = av_dynamic_hdr_smpte2094_app5_to_t35(hdr, NULL, &payload_size);
+    if (res < 0) {
+        log_encoder_error(avctx, "Error finding the size of HDR 
SMPTE-2094-50");
+        return res;
+    }
+
+    uint8_t *hdr_buf;
+    // Extra bytes for the country code, provider code, provider oriented code.
+    const size_t hdr_buf_size = payload_size + 5;
+    hdr_buf = av_malloc(hdr_buf_size);
+    if (!hdr_buf)
+        return AVERROR(ENOMEM);
+
+    uint8_t *payload = hdr_buf;
+    bytestream_put_byte(&payload, ITU_T_T35_COUNTRY_CODE_US);
+    bytestream_put_be16(&payload, ITU_T_T35_PROVIDER_CODE_SMPTE);
+    bytestream_put_be16(&payload, 0x0001); // provider_oriented_code
+
+    res = av_dynamic_hdr_smpte2094_app5_to_t35(hdr, &payload, &payload_size);
+    if (res < 0) {
+        av_free(hdr_buf);
+        log_encoder_error(avctx, "Error encoding HDR SMPTE-2094-50 from side 
data");
+        return res;
+    }
+
+    res = avm_img_add_metadata(img, OBU_METADATA_TYPE_ITUT_T35,
+                               hdr_buf, hdr_buf_size, AVM_MIF_ANY_FRAME);
+    av_free(hdr_buf);
+    if (res < 0) {
+        log_encoder_error(avctx, "Error adding HDR SMPTE-2094-50 to avm_img");
+        return res;
+    }
+    return 0;
+}
+
+static av_cold int codecctl_imgp(AVCodecContext *avctx,
+                                 int id,
+                                 struct avm_image *img)
+{
+    AVMContext *ctx = avctx->priv_data;
+    char buf[80];
+    int res;
+
+    snprintf(buf, sizeof(buf), "%s:", ctlidstr[id]);
+
+    res = avm_codec_control(&ctx->encoder, id, img);
+    if (res != AVM_CODEC_OK) {
+        snprintf(buf, sizeof(buf), "Failed to get %s codec control",
+                 ctlidstr[id]);
+        log_encoder_error(avctx, buf);
+        return AVERROR(EINVAL);
+    }
+
+    return 0;
+}
+
+static av_cold int avm_free(AVCodecContext *avctx)
+{
+    AVMContext *ctx = avctx->priv_data;
+    avm_codec_destroy(&ctx->encoder);
+    avm_img_remove_metadata(&ctx->rawimg);
+    av_freep(&ctx->twopass_stats.buf);
+    av_freep(&avctx->stats_out);
+    free_frame_list(ctx->coded_frame_list);
+    av_bsf_free(&ctx->bsf);
+    ff_dovi_ctx_unref(&ctx->dovi);
+    return 0;
+}
+
+static int set_pix_fmt(AVCodecContext *avctx, avm_codec_caps_t codec_caps,
+                       struct avm_codec_enc_cfg *enccfg, avm_codec_flags_t 
*flags,
+                       avm_img_fmt_t *img_fmt)
+{
+    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
+    enccfg->g_bit_depth = enccfg->g_input_bit_depth = desc->comp[0].depth;
+    switch (avctx->pix_fmt) {
+    case AV_PIX_FMT_GRAY8:
+        enccfg->monochrome = 1;
+        av_fallthrough;
+    case AV_PIX_FMT_YUV420P:
+        enccfg->g_profile = 1;
+        *img_fmt = AVM_IMG_FMT_I420;
+        return 0;
+    case AV_PIX_FMT_YUV422P:
+        enccfg->g_profile = 3;
+        *img_fmt = AVM_IMG_FMT_I422;
+        return 0;
+    case AV_PIX_FMT_YUV444P:
+    case AV_PIX_FMT_GBRP:
+        enccfg->g_profile = 4;
+        *img_fmt = AVM_IMG_FMT_I444;
+        return 0;
+    case AV_PIX_FMT_GRAY10:
+    case AV_PIX_FMT_GRAY12:
+        enccfg->monochrome = 1;
+        av_fallthrough;
+    case AV_PIX_FMT_YUV420P10:
+    case AV_PIX_FMT_YUV420P12:
+        enccfg->g_profile =
+            enccfg->g_bit_depth > 10 ? 5 : 1;
+        *img_fmt = AVM_IMG_FMT_I42016;
+        return 0;
+        break;
+    case AV_PIX_FMT_YUV422P10:
+    case AV_PIX_FMT_YUV422P12:
+        enccfg->g_profile =
+            enccfg->g_bit_depth > 10 ? 5 : 3;
+        *img_fmt = AVM_IMG_FMT_I42216;
+        return 0;
+        break;
+    case AV_PIX_FMT_YUV444P10:
+    case AV_PIX_FMT_YUV444P12:
+    case AV_PIX_FMT_GBRP10:
+    case AV_PIX_FMT_GBRP12:
+        enccfg->g_profile =
+            enccfg->g_bit_depth > 10 ? 5 : 4;
+        *img_fmt = AVM_IMG_FMT_I44416;
+        return 0;
+        break;
+    default:
+        break;
+    }
+    av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format.\n");
+    return AVERROR_INVALIDDATA;
+}
+
+static void set_color_range(AVCodecContext *avctx)
+{
+    avm_color_range_t avm_cr;
+    switch (avctx->color_range) {
+    case AVCOL_RANGE_UNSPECIFIED:
+    case AVCOL_RANGE_MPEG:       avm_cr = AVM_CR_STUDIO_RANGE; break;
+    case AVCOL_RANGE_JPEG:       avm_cr = AVM_CR_FULL_RANGE;   break;
+    default:
+        av_log(avctx, AV_LOG_WARNING, "Unsupported color range (%d)\n",
+               avctx->color_range);
+        return;
+    }
+
+    codecctl_int(avctx, AV2E_SET_COLOR_RANGE, avm_cr);
+}
+
+static int count_uniform_tiling(int dim, int sb_size, int tiles_log2)
+{
+    int sb_dim   = (dim + sb_size - 1) / sb_size;
+    int tile_dim = (sb_dim + (1 << tiles_log2) - 1) >> tiles_log2;
+    av_assert0(tile_dim > 0);
+    return (sb_dim + tile_dim - 1) / tile_dim;
+}
+
+static int choose_tiling(AVCodecContext *avctx,
+                         struct avm_codec_enc_cfg *enccfg)
+{
+    AVMContext *ctx = avctx->priv_data;
+    int sb_256x256_possible, sb_128x128_possible, sb_size, sb_width, sb_height;
+    int uniform_rows, uniform_cols;
+    int uniform_64x64_possible, uniform_128x128_possible, 
uniform_256x256_possible;
+    int tile_size, rounding, i;
+
+    if (ctx->tile_cols_log2 >= 0)
+        ctx->tile_cols = 1 << ctx->tile_cols_log2;
+    if (ctx->tile_rows_log2 >= 0)
+        ctx->tile_rows = 1 << ctx->tile_rows_log2;
+
+    if (ctx->tile_cols == 0) {
+        ctx->tile_cols = (avctx->width + MAX_TILE_WIDTH - 1) /
+            MAX_TILE_WIDTH;
+        if (ctx->tile_cols > 1) {
+            av_log(avctx, AV_LOG_DEBUG, "Automatically using %d tile "
+                   "columns to fill width.\n", ctx->tile_cols);
+        }
+    }
+    av_assert0(ctx->tile_cols > 0);
+    if (ctx->tile_rows == 0) {
+        int max_tile_width =
+            FFALIGN((FFALIGN(avctx->width, 128) +
+                     ctx->tile_cols - 1) / ctx->tile_cols, 128);
+        ctx->tile_rows =
+            (max_tile_width * FFALIGN(avctx->height, 128) +
+             MAX_TILE_AREA - 1) / MAX_TILE_AREA;
+        if (ctx->tile_rows > 1) {
+            av_log(avctx, AV_LOG_DEBUG, "Automatically using %d tile "
+                   "rows to fill area.\n", ctx->tile_rows);
+        }
+    }
+    av_assert0(ctx->tile_rows > 0);
+
+    if ((avctx->width  + 63) / 64 < ctx->tile_cols ||
+        (avctx->height + 63) / 64 < ctx->tile_rows) {
+        av_log(avctx, AV_LOG_ERROR, "Invalid tile sizing: frame not "
+               "large enough to fit specified tile arrangement.\n");
+        return AVERROR(EINVAL);
+    }
+    if (ctx->tile_cols > MAX_TILE_COLS ||
+        ctx->tile_rows > MAX_TILE_ROWS) {
+        av_log(avctx, AV_LOG_ERROR, "Invalid tile sizing: AV2 does "
+               "not allow more than %dx%d tiles.\n",
+               MAX_TILE_COLS, MAX_TILE_ROWS);
+        return AVERROR(EINVAL);
+    }
+    if (avctx->width / ctx->tile_cols > MAX_TILE_WIDTH) {
+        av_log(avctx, AV_LOG_ERROR, "Invalid tile sizing: AV2 does "
+               "not allow tiles of width greater than %d.\n",
+               MAX_TILE_WIDTH);
+        return AVERROR(EINVAL);
+    }
+
+    ctx->superblock_size = AVM_SUPERBLOCK_SIZE_DYNAMIC;
+
+    if (ctx->tile_cols == 1 && ctx->tile_rows == 1) {
+        av_log(avctx, AV_LOG_DEBUG, "Using a single tile.\n");
+        return 0;
+    }
+
+    sb_256x256_possible =
+        (avctx->width  + 255) / 256 >= ctx->tile_cols &&
+        (avctx->height + 255) / 256 >= ctx->tile_rows;
+
+    sb_128x128_possible =
+        (avctx->width  + 127) / 128 >= ctx->tile_cols &&
+        (avctx->height + 127) / 128 >= ctx->tile_rows;
+
+    ctx->tile_cols_log2 = ctx->tile_cols == 1 ? 0 :
+        av_log2(ctx->tile_cols - 1) + 1;
+    ctx->tile_rows_log2 = ctx->tile_rows == 1 ? 0 :
+        av_log2(ctx->tile_rows - 1) + 1;
+
+    uniform_cols = count_uniform_tiling(avctx->width,
+                                        64, ctx->tile_cols_log2);
+    uniform_rows = count_uniform_tiling(avctx->height,
+                                        64, ctx->tile_rows_log2);
+    av_log(avctx, AV_LOG_DEBUG, "Uniform with 64x64 superblocks "
+           "-> %dx%d tiles.\n", uniform_cols, uniform_rows);
+    uniform_64x64_possible = uniform_cols == ctx->tile_cols &&
+                             uniform_rows == ctx->tile_rows;
+
+    if (sb_256x256_possible) {
+        uniform_cols = count_uniform_tiling(avctx->width,
+                                            256, ctx->tile_cols_log2);
+        uniform_rows = count_uniform_tiling(avctx->height,
+                                            256, ctx->tile_rows_log2);
+        av_log(avctx, AV_LOG_DEBUG, "Uniform with 256x256 superblocks "
+               "-> %dx%d tiles.\n", uniform_cols, uniform_rows);
+        uniform_256x256_possible = uniform_cols == ctx->tile_cols &&
+                                   uniform_rows == ctx->tile_rows;
+    } else {
+        av_log(avctx, AV_LOG_DEBUG, "256x256 superblocks not possible.\n");
+        uniform_256x256_possible = 0;
+    }
+
+    if (sb_128x128_possible) {
+        uniform_cols = count_uniform_tiling(avctx->width,
+                                            128, ctx->tile_cols_log2);
+        uniform_rows = count_uniform_tiling(avctx->height,
+                                            128, ctx->tile_rows_log2);
+        av_log(avctx, AV_LOG_DEBUG, "Uniform with 128x128 superblocks "
+               "-> %dx%d tiles.\n", uniform_cols, uniform_rows);
+        uniform_128x128_possible = uniform_cols == ctx->tile_cols &&
+                                   uniform_rows == ctx->tile_rows;
+    } else {
+        av_log(avctx, AV_LOG_DEBUG, "128x128 superblocks not possible.\n");
+        uniform_128x128_possible = 0;
+    }
+
+    ctx->uniform_tiles = 1;
+    if (uniform_64x64_possible && uniform_128x128_possible) {
+        av_log(avctx, AV_LOG_DEBUG, "Using uniform tiling with dynamic "
+               "superblocks (tile_cols_log2 = %d, tile_rows_log2 = %d).\n",
+               ctx->tile_cols_log2, ctx->tile_rows_log2);
+        return 0;
+    }
+    if (uniform_64x64_possible && !sb_128x128_possible) {
+        av_log(avctx, AV_LOG_DEBUG, "Using uniform tiling with 64x64 "
+               "superblocks (tile_cols_log2 = %d, tile_rows_log2 = %d).\n",
+               ctx->tile_cols_log2, ctx->tile_rows_log2);
+        ctx->superblock_size = AVM_SUPERBLOCK_SIZE_64X64;
+        return 0;
+    }
+    if (uniform_128x128_possible && !sb_256x256_possible) {
+        av_log(avctx, AV_LOG_DEBUG, "Using uniform tiling with 128x128 "
+               "superblocks (tile_cols_log2 = %d, tile_rows_log2 = %d).\n",
+               ctx->tile_cols_log2, ctx->tile_rows_log2);
+        ctx->superblock_size = AVM_SUPERBLOCK_SIZE_128X128;
+        return 0;
+    }
+    if (uniform_256x256_possible) {
+        av_log(avctx, AV_LOG_DEBUG, "Using uniform tiling with 256x256 "
+               "superblocks (tile_cols_log2 = %d, tile_rows_log2 = %d).\n",
+               ctx->tile_cols_log2, ctx->tile_rows_log2);
+        ctx->superblock_size = AVM_SUPERBLOCK_SIZE_256X256;
+        return 0;
+    }
+    ctx->uniform_tiles = 0;
+
+    if (sb_256x256_possible) {
+        sb_size = 256;
+        ctx->superblock_size = AVM_SUPERBLOCK_SIZE_256X256;
+    } else if (sb_128x128_possible) {
+        sb_size = 128;
+        ctx->superblock_size = AVM_SUPERBLOCK_SIZE_128X128;
+    } else {
+        sb_size = 64;
+        ctx->superblock_size = AVM_SUPERBLOCK_SIZE_64X64;
+    }
+    av_log(avctx, AV_LOG_DEBUG, "Using fixed tiling with %dx%d "
+           "superblocks (tile_cols = %d, tile_rows = %d).\n",
+           sb_size, sb_size, ctx->tile_cols, ctx->tile_rows);
+
+    enccfg->tile_width_count  = ctx->tile_cols;
+    enccfg->tile_height_count = ctx->tile_rows;
+
+    sb_width  = (avctx->width  + sb_size - 1) / sb_size;
+    sb_height = (avctx->height + sb_size - 1) / sb_size;
+
+    tile_size = sb_width / ctx->tile_cols;
+    rounding  = sb_width % ctx->tile_cols;
+    for (i = 0; i < ctx->tile_cols; i++) {
+        enccfg->tile_widths[i] = tile_size +
+            (i < rounding / 2 ||
+             i > ctx->tile_cols - 1 - (rounding + 1) / 2);
+    }
+
+    tile_size = sb_height / ctx->tile_rows;
+    rounding  = sb_height % ctx->tile_rows;
+    for (i = 0; i < ctx->tile_rows; i++) {
+        enccfg->tile_heights[i] = tile_size +
+            (i < rounding / 2 ||
+             i > ctx->tile_rows - 1 - (rounding + 1) / 2);
+    }
+
+    return 0;
+}
+
+
+static const struct {
+    int avm_enum;
+    unsigned offset;
+} option_map[] = {
+    { AVME_SET_ENABLEAUTOALTREF,          OFFSET(auto_alt_ref) },
+    { AVME_SET_ARNR_STRENGTH,             OFFSET(arnr_strength) },
+    { AV2E_SET_ENABLE_CDEF,               OFFSET(enable_cdef) },
+    { AV2E_SET_ENABLE_RESTORATION,        OFFSET(enable_restoration) },
+    { AV2E_SET_ENABLE_RECT_PARTITIONS,    OFFSET(enable_rect_partitions) },
+    { AV2E_SET_ENABLE_ANGLE_DELTA,        OFFSET(enable_angle_delta) },
+    { AV2E_SET_ENABLE_CFL_INTRA,          OFFSET(enable_cfl_intra) },
+    { AV2E_SET_ENABLE_INTRA_EDGE_FILTER,  OFFSET(enable_intra_edge_filter) },
+    { AV2E_SET_ENABLE_PAETH_INTRA,        OFFSET(enable_paeth_intra) },
+    { AV2E_SET_ENABLE_SMOOTH_INTRA,       OFFSET(enable_smooth_intra) },
+    { AV2E_SET_ENABLE_PALETTE,            OFFSET(enable_palette) },
+    { AV2E_SET_ENABLE_FLIP_IDTX,          OFFSET(enable_flip_idtx) },
+    { AV2E_SET_INTRA_DCT_ONLY,            OFFSET(use_intra_dct_only) },
+    { AV2E_SET_INTER_DCT_ONLY,            OFFSET(use_inter_dct_only) },
+    { AV2E_SET_INTRA_DEFAULT_TX_ONLY,     OFFSET(use_intra_default_tx_only) },
+    { AV2E_SET_REDUCED_TX_TYPE_SET,       OFFSET(reduced_tx_type_set) },
+    { AV2E_SET_ENABLE_REF_FRAME_MVS,      OFFSET(enable_ref_frame_mvs) },
+    { AV2E_SET_ENABLE_DIFF_WTD_COMP,      OFFSET(enable_diff_wtd_comp) },
+    { AV2E_SET_ENABLE_INTERINTER_WEDGE,   OFFSET(enable_interinter_wedge) },
+    { AV2E_SET_ENABLE_MASKED_COMP,        OFFSET(enable_masked_comp) },
+    { AV2E_SET_ENABLE_INTERINTRA_COMP,    OFFSET(enable_interintra_comp) },
+    { AV2E_SET_ENABLE_INTERINTRA_WEDGE,   OFFSET(enable_interintra_wedge) },
+    { AV2E_SET_ENABLE_ONESIDED_COMP,      OFFSET(enable_onesided_comp) },
+    { AV2E_SET_ENABLE_SMOOTH_INTERINTRA,  OFFSET(enable_smooth_interintra) },
+};
+
+static av_cold int avm_init(AVCodecContext *avctx,
+                            const struct avm_codec_iface *iface)
+{
+    AVMContext *ctx = avctx->priv_data;
+    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
+    struct avm_codec_enc_cfg enccfg = { 0 };
+    avm_codec_flags_t flags =
+        (avctx->flags & AV_CODEC_FLAG_PSNR) ? AVM_CODEC_USE_PSNR : 0;
+    int res;
+    avm_img_fmt_t img_fmt;
+    avm_codec_caps_t codec_caps = avm_codec_get_caps(iface);
+
+    av_log(avctx, AV_LOG_INFO, "%s\n", avm_codec_version_str());
+    av_log(avctx, AV_LOG_VERBOSE, "%s\n", avm_codec_build_config());
+
+    if ((res = avm_codec_enc_config_default(iface, &enccfg, ctx->usage)) != 
AVM_CODEC_OK) {
+        av_log(avctx, AV_LOG_ERROR, "Failed to get config: %s\n",
+               avm_codec_err_to_string(res));
+        return AVERROR(EINVAL);
+    }
+
+    if (set_pix_fmt(avctx, codec_caps, &enccfg, &flags, &img_fmt))
+        return AVERROR(EINVAL);
+
+    if(!avctx->bit_rate)
+        if(avctx->rc_max_rate || avctx->rc_buffer_size || 
avctx->rc_initial_buffer_occupancy) {
+            av_log( avctx, AV_LOG_ERROR, "Rate control parameters set without 
a bitrate\n");
+            return AVERROR(EINVAL);
+        }
+
+    dump_enc_cfg(avctx, &enccfg, AV_LOG_DEBUG);
+
+    enccfg.g_w            = avctx->width;
+    enccfg.g_h            = avctx->height;
+    enccfg.g_timebase.num = avctx->time_base.num;
+    enccfg.g_timebase.den = avctx->time_base.den;
+    enccfg.g_threads      =
+        FFMIN(avctx->thread_count ? avctx->thread_count : av_cpu_count(), 64);
+
+    if (ctx->lag_in_frames >= 0)
+        enccfg.g_lag_in_frames = ctx->lag_in_frames;
+
+    if (avctx->flags & AV_CODEC_FLAG_PASS1)
+        enccfg.g_pass = AVM_RC_FIRST_PASS;
+    else if (avctx->flags & AV_CODEC_FLAG_PASS2)
+        enccfg.g_pass = AVM_RC_LAST_PASS;
+    else
+        enccfg.g_pass = AVM_RC_ONE_PASS;
+
+    if (avctx->rc_min_rate == avctx->rc_max_rate &&
+        avctx->rc_min_rate == avctx->bit_rate && avctx->bit_rate) {
+        enccfg.rc_end_usage = AVM_CBR;
+    } else if (ctx->qp >= 0) {
+        enccfg.rc_end_usage = AVM_CQ;
+        if (!avctx->bit_rate)
+            enccfg.rc_end_usage = AVM_Q;
+    }
+
+    if (avctx->bit_rate) {
+        enccfg.rc_target_bitrate = av_rescale_rnd(avctx->bit_rate, 1, 1000,
+                                                  AV_ROUND_NEAR_INF);
+    } else if (enccfg.rc_end_usage != AVM_Q) {
+        enccfg.rc_end_usage = AVM_Q;
+        ctx->qp = 40;
+        av_log(avctx, AV_LOG_WARNING,
+               "Neither bitrate nor constrained quality specified, using 
default QP of %d\n",
+               ctx->qp);
+    }
+
+    if (avctx->qmin >= 0)
+        enccfg.rc_min_quantizer = avctx->qmin;
+    if (avctx->qmax >= 0) {
+        enccfg.rc_max_quantizer = avctx->qmax;
+    } else if (!ctx->qp) {
+        enccfg.rc_max_quantizer = 0;
+    }
+
+    if (enccfg.rc_end_usage == AVM_CQ || enccfg.rc_end_usage == AVM_Q) {
+        if (ctx->qp < enccfg.rc_min_quantizer || ctx->qp > 
enccfg.rc_max_quantizer) {
+            av_log(avctx, AV_LOG_ERROR,
+                   "CQ level %d must be between minimum and maximum quantizer 
value (%d-%d)\n",
+                   ctx->qp, enccfg.rc_min_quantizer, enccfg.rc_max_quantizer);
+            return AVERROR(EINVAL);
+        }
+    }
+
+    //enccfg.rc_dropframe_thresh = 0;
+
+    // 0-100 (0 => CBR, 100 => VBR)
+    if (ctx->minsection_pct >= 0)
+        enccfg.rc_2pass_vbr_minsection_pct = ctx->minsection_pct;
+    else if (avctx->bit_rate)
+        enccfg.rc_2pass_vbr_minsection_pct =
+            avctx->rc_min_rate * 100LL / avctx->bit_rate;
+    if (ctx->maxsection_pct >= 0)
+        enccfg.rc_2pass_vbr_maxsection_pct = ctx->maxsection_pct;
+    else if (avctx->rc_max_rate)
+        enccfg.rc_2pass_vbr_maxsection_pct =
+            avctx->rc_max_rate * 100LL / avctx->bit_rate;
+
+    if (avctx->rc_buffer_size)
+        enccfg.rc_buf_sz =
+            avctx->rc_buffer_size * 1000LL / avctx->bit_rate;
+    if (avctx->rc_initial_buffer_occupancy)
+        enccfg.rc_buf_initial_sz =
+            avctx->rc_initial_buffer_occupancy * 1000LL / avctx->bit_rate;
+    enccfg.rc_buf_optimal_sz = enccfg.rc_buf_sz * 5 / 6;
+
+    if (ctx->rc_undershoot_pct >= 0)
+        enccfg.rc_undershoot_pct = ctx->rc_undershoot_pct;
+    if (ctx->rc_overshoot_pct >= 0)
+        enccfg.rc_overshoot_pct = ctx->rc_overshoot_pct;
+
+    // _enc_init() will balk if kf_min_dist differs from max w/AVM_KF_AUTO
+    if (avctx->keyint_min >= 0 && avctx->keyint_min == avctx->gop_size)
+        enccfg.kf_min_dist = avctx->keyint_min;
+    if (avctx->gop_size >= 0)
+        enccfg.kf_max_dist = avctx->gop_size;
+
+    if (enccfg.g_pass == AVM_RC_FIRST_PASS)
+        enccfg.g_lag_in_frames = 0;
+    else if (enccfg.g_pass == AVM_RC_LAST_PASS) {
+        int decode_size, ret;
+
+        if (!avctx->stats_in) {
+            av_log(avctx, AV_LOG_ERROR, "No stats file for second pass\n");
+            return AVERROR_INVALIDDATA;
+        }
+
+        ctx->twopass_stats.sz = strlen(avctx->stats_in) * 3 / 4;
+        ret                   = av_reallocp(&ctx->twopass_stats.buf, 
ctx->twopass_stats.sz);
+        if (ret < 0) {
+            av_log(avctx, AV_LOG_ERROR,
+                   "Stat buffer alloc (%zu bytes) failed\n",
+                   ctx->twopass_stats.sz);
+            ctx->twopass_stats.sz = 0;
+            return ret;
+        }
+        decode_size = av_base64_decode(ctx->twopass_stats.buf, avctx->stats_in,
+                                       ctx->twopass_stats.sz);
+        if (decode_size < 0) {
+            av_log(avctx, AV_LOG_ERROR, "Stat buffer decode failed\n");
+            return AVERROR_INVALIDDATA;
+        }
+
+        ctx->twopass_stats.sz      = decode_size;
+    }
+
+    /* 0-3: For non-zero values the encoder increasingly optimizes for reduced
+     * complexity playback on low powered devices at the expense of encode
+     * quality. */
+    if (avctx->profile != AV_PROFILE_UNKNOWN)
+        enccfg.g_profile = avctx->profile;
+
+    enccfg.g_error_resilient = 0;
+
+    res = choose_tiling(avctx, &enccfg);
+    if (res < 0)
+        return res;
+
+    if (ctx->still_picture) {
+        // Set the maximum number of frames to 1. This will let libavm set
+        // still_picture and reduced_still_picture_header to 1 in the Sequence
+        // Header as required by AVIF still images.
+        enccfg.g_limit = 1;
+        // Reduce memory usage for still images.
+        enccfg.g_lag_in_frames = 0;
+        // All frames will be key frames.
+        enccfg.kf_max_dist = AVM_KF_DISABLED;
+        enccfg.kf_mode = AVM_KF_DISABLED;
+    }
+
+    /* Construct Encoder Context */
+    res = avm_codec_enc_init(&ctx->encoder, iface, &enccfg, flags);
+    if (res != AVM_CODEC_OK) {
+        dump_enc_cfg(avctx, &enccfg, AV_LOG_WARNING);
+        log_encoder_error(avctx, "Failed to initialize encoder");
+        return AVERROR(EINVAL);
+    }
+    dump_enc_cfg(avctx, &enccfg, AV_LOG_DEBUG);
+
+    // codec control failures are currently treated only as warnings
+    av_log(avctx, AV_LOG_DEBUG, "avm_codec_control\n");
+    codecctl_int(avctx, AVME_SET_CPUUSED, ctx->cpu_used);
+
+    for (size_t i = 0; i < FF_ARRAY_ELEMS(option_map); ++i) {
+        int val = *(int*)((char*)ctx + option_map[i].offset);
+        if (val >= 0)
+            codecctl_int(avctx, option_map[i].avm_enum, val);
+    }
+    codecctl_int(avctx, AVME_SET_STATIC_THRESHOLD, ctx->static_thresh);
+    if ((enccfg.rc_end_usage == AVM_CQ) || (enccfg.rc_end_usage == AVM_Q))
+        codecctl_int(avctx, AVME_SET_QP,          ctx->qp);
+    if (ctx->tune >= 0)
+        codecctl_int(avctx, AVME_SET_TUNING, ctx->tune);
+
+    if (desc->flags & AV_PIX_FMT_FLAG_RGB) {
+        codecctl_int(avctx, AV2E_SET_COLOR_PRIMARIES, AVCOL_PRI_BT709);
+        codecctl_int(avctx, AV2E_SET_MATRIX_COEFFICIENTS, AVCOL_SPC_RGB);
+        codecctl_int(avctx, AV2E_SET_TRANSFER_CHARACTERISTICS, 
AVCOL_TRC_IEC61966_2_1);
+    } else {
+        codecctl_int(avctx, AV2E_SET_COLOR_PRIMARIES, avctx->color_primaries);
+        codecctl_int(avctx, AV2E_SET_MATRIX_COEFFICIENTS, avctx->colorspace);
+        codecctl_int(avctx, AV2E_SET_TRANSFER_CHARACTERISTICS, 
avctx->color_trc);
+    }
+    if (ctx->aq_mode >= 0)
+        codecctl_int(avctx, AV2E_SET_AQ_MODE, ctx->aq_mode);
+    if (ctx->frame_parallel >= 0)
+        codecctl_int(avctx, AV2E_SET_FRAME_PARALLEL_DECODING, 
ctx->frame_parallel);
+    set_color_range(avctx);
+
+    codecctl_int(avctx, AV2E_SET_SUPERBLOCK_SIZE, ctx->superblock_size);
+    if (ctx->uniform_tiles) {
+        codecctl_int(avctx, AV2E_SET_TILE_COLUMNS, ctx->tile_cols_log2);
+        codecctl_int(avctx, AV2E_SET_TILE_ROWS,    ctx->tile_rows_log2);
+    }
+
+    if (ctx->denoise_noise_level >= 0)
+        codecctl_int(avctx, AV2E_SET_DENOISE_NOISE_LEVEL, 
ctx->denoise_noise_level);
+    if (ctx->denoise_block_size >= 0)
+        codecctl_int(avctx, AV2E_SET_DENOISE_BLOCK_SIZE, 
ctx->denoise_block_size);
+    if (ctx->enable_global_motion >= 0)
+        codecctl_int(avctx, AV2E_SET_ENABLE_GLOBAL_MOTION, 
ctx->enable_global_motion);
+    if (avctx->refs >= 3) {
+        codecctl_int(avctx, AV2E_SET_MAX_REFERENCE_FRAMES, avctx->refs);
+    }
+    if (ctx->row_mt >= 0)
+        codecctl_int(avctx, AV2E_SET_ROW_MT, ctx->row_mt);
+    if (ctx->enable_intrabc >= 0)
+        codecctl_int(avctx, AV2E_SET_ENABLE_INTRABC, ctx->enable_intrabc);
+
+    {
+        const AVDictionaryEntry *en = NULL;
+
+        while ((en = av_dict_iterate(ctx->avm_params, en))) {
+            int ret = avm_codec_set_option(&ctx->encoder, en->key, en->value);
+            if (ret != AVM_CODEC_OK) {
+                log_encoder_error(avctx, en->key);
+                return AVERROR_EXTERNAL;
+            }
+        }
+    }
+
+    // provide dummy value to initialize wrapper, values will be updated each 
_encode()
+    avm_img_wrap(&ctx->rawimg, img_fmt, avctx->width, avctx->height, 1,
+                 (unsigned char*)1);
+
+    if (enccfg.g_bit_depth >= 10)
+        ctx->rawimg.bit_depth = enccfg.g_bit_depth;
+
+    ctx->dovi.logctx = avctx;
+    if ((res = ff_dovi_configure(&ctx->dovi, avctx)) < 0)
+        return res;
+
+    AVCPBProperties *cpb_props = ff_encode_add_cpb_side_data(avctx);
+    if (!cpb_props)
+        return AVERROR(ENOMEM);
+
+    if (enccfg.rc_end_usage == AVM_CBR ||
+        enccfg.g_pass != AVM_RC_ONE_PASS) {
+        cpb_props->max_bitrate = avctx->rc_max_rate;
+        cpb_props->min_bitrate = avctx->rc_min_rate;
+        cpb_props->avg_bitrate = avctx->bit_rate;
+    }
+    cpb_props->buffer_size = avctx->rc_buffer_size;
+
+    return 0;
+}
+
+static inline void cx_pktcpy(AVMContext *ctx,
+                             struct FrameListData *dst,
+                             const struct avm_codec_cx_pkt *src)
+{
+    dst->pts      = src->data.frame.pts;
+    dst->duration = src->data.frame.duration;
+    dst->flags    = src->data.frame.flags;
+    dst->sz       = src->data.frame.sz;
+    dst->buf      = src->data.frame.buf;
+    dst->frame_number = ++ctx->frame_number;
+    dst->have_sse = ctx->have_sse;
+    if (ctx->have_sse) {
+        /* associate last-seen SSE to the frame. */
+        /* Transfers ownership from ctx to dst. */
+        memcpy(dst->sse, ctx->sse, sizeof(dst->sse));
+        ctx->have_sse = 0;
+    }
+}
+
+/**
+ * Store coded frame information in format suitable for return from encode2().
+ *
+ * Write information from @a cx_frame to @a pkt
+ * @return packet data size on success
+ * @return a negative AVERROR on error
+ */
+static int storeframe(AVCodecContext *avctx, struct FrameListData *cx_frame,
+                      AVPacket *pkt)
+{
+    AVMContext *ctx = avctx->priv_data;
+    enum AVPictureType pict_type;
+    int ret = ff_get_encode_buffer(avctx, pkt, cx_frame->sz, 0);
+    if (ret < 0) {
+        av_log(avctx, AV_LOG_ERROR,
+               "Error getting output packet of size %zu.\n", cx_frame->sz);
+        return ret;
+    }
+    memcpy(pkt->data, cx_frame->buf, pkt->size);
+    pkt->pts = pkt->dts = cx_frame->pts;
+    pkt->duration = cx_frame->duration;
+
+    if (!!(cx_frame->flags & AVM_FRAME_IS_KEY)) {
+        pkt->flags |= AV_PKT_FLAG_KEY;
+        pict_type = AV_PICTURE_TYPE_I;
+    } else if (cx_frame->flags & AVM_FRAME_IS_INTRAONLY) {
+        pict_type = AV_PICTURE_TYPE_I;
+    } else {
+        pict_type = AV_PICTURE_TYPE_P;
+    }
+
+    ff_encode_add_stats_side_data(pkt, 0, cx_frame->sse + 1,
+                                  cx_frame->have_sse ? 3 : 0, pict_type);
+
+    if (cx_frame->have_sse) {
+        int i;
+        for (i = 0; i < 3; ++i) {
+            avctx->error[i] += cx_frame->sse[i + 1];
+        }
+        cx_frame->have_sse = 0;
+    }
+
+    if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
+        ret = av_bsf_send_packet(ctx->bsf, pkt);
+        if (ret < 0) {
+            av_log(avctx, AV_LOG_ERROR, "extract_extradata filter "
+                   "failed to send input packet\n");
+            return ret;
+        }
+        ret = av_bsf_receive_packet(ctx->bsf, pkt);
+
+        if (ret < 0) {
+            av_log(avctx, AV_LOG_ERROR, "extract_extradata filter "
+                   "failed to receive output packet\n");
+            return ret;
+        }
+    }
+    return pkt->size;
+}
+
+/**
+ * Queue multiple output frames from the encoder, returning the front-most.
+ * In cases where avm_codec_get_cx_data() returns more than 1 frame append
+ * the frame queue. Return the head frame if available.
+ * @return Stored frame size
+ * @return AVERROR(EINVAL) on output size error
+ * @return AVERROR(ENOMEM) on coded frame queue data allocation error
+ */
+static int queue_frames(AVCodecContext *avctx, AVPacket *pkt_out)
+{
+    AVMContext *ctx = avctx->priv_data;
+    const struct avm_codec_cx_pkt *pkt;
+    const void *iter = NULL;
+    int size = 0;
+
+    if (ctx->coded_frame_list) {
+        struct FrameListData *cx_frame = ctx->coded_frame_list;
+        /* return the leading frame if we've already begun queueing */
+        size = storeframe(avctx, cx_frame, pkt_out);
+        if (size < 0)
+            return size;
+        ctx->coded_frame_list = cx_frame->next;
+        free_coded_frame(cx_frame);
+    }
+
+    /* consume all available output from the encoder before returning. buffers
+     * are only good through the next avm_codec call */
+    while ((pkt = avm_codec_get_cx_data(&ctx->encoder, &iter))) {
+        switch (pkt->kind) {
+        case AVM_CODEC_CX_FRAME_PKT:
+            if (!size) {
+                struct FrameListData cx_frame;
+
+                /* avoid storing the frame when the list is empty and we 
haven't yet
+                 * provided a frame for output */
+                av_assert0(!ctx->coded_frame_list);
+                cx_pktcpy(ctx, &cx_frame, pkt);
+                size = storeframe(avctx, &cx_frame, pkt_out);
+                if (size < 0)
+                    return size;
+            } else {
+                struct FrameListData *cx_frame =
+                    av_malloc(sizeof(struct FrameListData));
+
+                if (!cx_frame) {
+                    av_log(avctx, AV_LOG_ERROR,
+                           "Frame queue element alloc failed\n");
+                    return AVERROR(ENOMEM);
+                }
+                cx_pktcpy(ctx, cx_frame, pkt);
+                cx_frame->buf = av_malloc(cx_frame->sz);
+
+                if (!cx_frame->buf) {
+                    av_log(avctx, AV_LOG_ERROR,
+                           "Data buffer alloc (%zu bytes) failed\n",
+                           cx_frame->sz);
+                    av_freep(&cx_frame);
+                    return AVERROR(ENOMEM);
+                }
+                memcpy(cx_frame->buf, pkt->data.frame.buf, pkt->data.frame.sz);
+                coded_frame_add(&ctx->coded_frame_list, cx_frame);
+            }
+            break;
+        case AVM_CODEC_STATS_PKT:
+        {
+            struct avm_fixed_buf *stats = &ctx->twopass_stats;
+            uint8_t *tmp = av_fast_realloc(stats->buf,
+                                           &ctx->twopass_stats_size,
+                                           stats->sz +
+                                           pkt->data.twopass_stats.sz);
+            if (!tmp) {
+                av_freep(&stats->buf);
+                stats->sz = 0;
+                av_log(avctx, AV_LOG_ERROR, "Stat buffer realloc failed\n");
+                return AVERROR(ENOMEM);
+            }
+            stats->buf = tmp;
+            memcpy((uint8_t *)stats->buf + stats->sz,
+                   pkt->data.twopass_stats.buf, pkt->data.twopass_stats.sz);
+            stats->sz += pkt->data.twopass_stats.sz;
+            break;
+        }
+        case AVM_CODEC_PSNR_PKT:
+        {
+            av_assert0(!ctx->have_sse);
+            ctx->sse[0] = pkt->data.psnr.sse[0];
+            ctx->sse[1] = pkt->data.psnr.sse[1];
+            ctx->sse[2] = pkt->data.psnr.sse[2];
+            ctx->sse[3] = pkt->data.psnr.sse[3];
+            ctx->have_sse = 1;
+            break;
+        }
+        case AVM_CODEC_CUSTOM_PKT:
+            // ignore unsupported/unrecognized packet types
+            break;
+        }
+    }
+
+    return size;
+}
+
+static enum AVPixelFormat avmfmt_to_pixfmt(struct avm_image *img)
+{
+    switch (img->fmt) {
+    case AVM_IMG_FMT_I420:
+    case AVM_IMG_FMT_I42016:
+        if (img->bit_depth == 8)
+            return img->monochrome ? AV_PIX_FMT_GRAY8 : AV_PIX_FMT_YUV420P;
+        else if (img->bit_depth == 10)
+            return img->monochrome ? AV_PIX_FMT_GRAY10 : AV_PIX_FMT_YUV420P10;
+        else
+            return img->monochrome ? AV_PIX_FMT_GRAY12 : AV_PIX_FMT_YUV420P12;
+    case AVM_IMG_FMT_I422:
+    case AVM_IMG_FMT_I42216:
+        if (img->bit_depth == 8)
+            return AV_PIX_FMT_YUV422P;
+        else if (img->bit_depth == 10)
+            return AV_PIX_FMT_YUV422P10;
+        else
+            return AV_PIX_FMT_YUV422P12;
+    case AVM_IMG_FMT_I444:
+    case AVM_IMG_FMT_I44416:
+        if (img->bit_depth == 8)
+            return AV_PIX_FMT_YUV444P;
+        else if (img->bit_depth == 10)
+            return AV_PIX_FMT_YUV444P10;
+        else
+            return AV_PIX_FMT_YUV444P12;
+    };
+    return AV_PIX_FMT_NONE;
+}
+
+static int avm_encode(AVCodecContext *avctx, AVPacket *pkt,
+                      const AVFrame *frame, int *got_packet)
+{
+    AVMContext *ctx = avctx->priv_data;
+    struct avm_image *rawimg = NULL;
+    int64_t timestamp = 0;
+    unsigned long duration = 0;
+    int res, coded_size;
+    avm_enc_frame_flags_t flags = 0;
+    AVFrameSideData *sd;
+
+    if (frame) {
+        rawimg                      = &ctx->rawimg;
+        avm_img_remove_metadata(rawimg);
+        rawimg->planes[AVM_PLANE_Y] = frame->data[0];
+        rawimg->planes[AVM_PLANE_U] = frame->data[1];
+        rawimg->planes[AVM_PLANE_V] = frame->data[2];
+        rawimg->stride[AVM_PLANE_Y] = frame->linesize[0];
+        rawimg->stride[AVM_PLANE_U] = frame->linesize[1];
+        rawimg->stride[AVM_PLANE_V] = frame->linesize[2];
+        timestamp                   = frame->pts;
+
+        if (frame->duration > ULONG_MAX) {
+            av_log(avctx, AV_LOG_WARNING,
+                   "Frame duration too large: %"PRId64"\n", frame->duration);
+        } else if (frame->duration)
+            duration = frame->duration;
+        else if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
+            duration = av_rescale_q(1, av_inv_q(avctx->framerate), 
avctx->time_base);
+        else {
+            duration = 1;
+        }
+
+        switch (frame->color_range) {
+        case AVCOL_RANGE_MPEG:
+            rawimg->range = AVM_CR_STUDIO_RANGE;
+            break;
+        case AVCOL_RANGE_JPEG:
+            rawimg->range = AVM_CR_FULL_RANGE;
+            break;
+        }
+
+        avm_img_remove_metadata(rawimg);
+        sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DOVI_METADATA);
+        if (ctx->dovi.cfg.dv_profile && sd) {
+            const AVDOVIMetadata *metadata = (const AVDOVIMetadata *)sd->data;
+            uint8_t *t35;
+            int size;
+            if ((res = ff_dovi_rpu_generate(&ctx->dovi, metadata, 
FF_DOVI_WRAP_T35,
+                                            &t35, &size)) < 0)
+                return res;
+            res = avm_img_add_metadata(rawimg, OBU_METADATA_TYPE_ITUT_T35,
+                                       t35, size, AVM_MIF_ANY_FRAME);
+            av_free(t35);
+            if (res != AVM_CODEC_OK)
+                return AVERROR(ENOMEM);
+        } else if (ctx->dovi.cfg.dv_profile) {
+            av_log(avctx, AV_LOG_ERROR, "Dolby Vision enabled, but received 
frame "
+                   "without AV_FRAME_DATA_DOVI_METADATA\n");
+            return AVERROR_INVALIDDATA;
+        }
+
+        if (frame->pict_type == AV_PICTURE_TYPE_I)
+            flags |= AVM_EFLAG_FORCE_KF;
+
+        res = add_hdr_plus(avctx, rawimg, frame);
+        if (res < 0)
+            return res;
+
+        res = add_hdr_smpte2094_app5(avctx, rawimg, frame);
+        if (res < 0)
+            return res;
+    }
+
+    res = avm_codec_encode(&ctx->encoder, rawimg, timestamp, duration, flags);
+    if (res != AVM_CODEC_OK) {
+        log_encoder_error(avctx, "Error encoding frame");
+        return AVERROR_INVALIDDATA;
+    }
+    coded_size = queue_frames(avctx, pkt);
+    if (coded_size < 0)
+        return coded_size;
+
+    if (!frame && avctx->flags & AV_CODEC_FLAG_PASS1) {
+        size_t b64_size = AV_BASE64_SIZE(ctx->twopass_stats.sz);
+
+        avctx->stats_out = av_malloc(b64_size);
+        if (!avctx->stats_out) {
+            av_log(avctx, AV_LOG_ERROR, "Stat buffer alloc (%zu bytes) 
failed\n",
+                   b64_size);
+            return AVERROR(ENOMEM);
+        }
+        av_base64_encode(avctx->stats_out, b64_size, ctx->twopass_stats.buf,
+                         ctx->twopass_stats.sz);
+    }
+
+    *got_packet = !!coded_size;
+
+    if (*got_packet && avctx->flags & AV_CODEC_FLAG_RECON_FRAME) {
+        AVCodecInternal *avci = avctx->internal;
+        struct avm_image img;
+
+        av_frame_unref(avci->recon_frame);
+
+        res = codecctl_imgp(avctx, AV2_GET_NEW_FRAME_IMAGE, &img);
+        if (res < 0)
+            return res;
+
+        avci->recon_frame->format = avmfmt_to_pixfmt(&img);
+        if (avci->recon_frame->format == AV_PIX_FMT_NONE) {
+            av_log(ctx, AV_LOG_ERROR,
+                   "Unhandled reconstructed frame colorspace: %d\n",
+                   img.fmt);
+            return AVERROR(ENOSYS);
+        }
+
+        avci->recon_frame->width  = img.d_w;
+        avci->recon_frame->height = img.d_h;
+
+        res = av_frame_get_buffer(avci->recon_frame, 0);
+        if (res < 0)
+            return res;
+
+        if ((img.fmt & AVM_IMG_FMT_HIGHBITDEPTH) && img.bit_depth == 8)
+            ff_avm_image_copy_16_to_8(avci->recon_frame, &img);
+        else {
+            const uint8_t *planes[4] = { img.planes[0], img.planes[1], 
img.planes[2] };
+            const int      stride[4] = { img.stride[0], img.stride[1], 
img.stride[2] };
+
+            av_image_copy(avci->recon_frame->data, 
avci->recon_frame->linesize, planes,
+                          stride, avci->recon_frame->format, img.d_w, img.d_h);
+        }
+    }
+
+    return 0;
+}
+
+static const enum AVPixelFormat av2_pix_fmts_highbd_with_gray[] = {
+    AV_PIX_FMT_YUV420P,
+    AV_PIX_FMT_YUV422P,
+    AV_PIX_FMT_YUV444P,
+    AV_PIX_FMT_GBRP,
+    AV_PIX_FMT_YUV420P10,
+    AV_PIX_FMT_YUV422P10,
+    AV_PIX_FMT_YUV444P10,
+    AV_PIX_FMT_YUV420P12,
+    AV_PIX_FMT_YUV422P12,
+    AV_PIX_FMT_YUV444P12,
+    AV_PIX_FMT_GBRP10,
+    AV_PIX_FMT_GBRP12,
+    AV_PIX_FMT_GRAY8,
+    AV_PIX_FMT_GRAY10,
+    AV_PIX_FMT_GRAY12,
+    AV_PIX_FMT_NONE
+};
+
+static av_cold int av2_init(AVCodecContext *avctx)
+{
+    return avm_init(avctx, avm_codec_av2_cx());
+}
+
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+    { "cpu-used",        "Quality/Speed ratio modifier",           
OFFSET(cpu_used),        AV_OPT_TYPE_INT, {.i64 = 1}, 0, 8, VE},
+    { "auto-alt-ref",    "Enable use of alternate reference "
+                         "frames (2-pass only)",                   
OFFSET(auto_alt_ref),    AV_OPT_TYPE_INT, {.i64 = -1},      -1,      2,       
VE},
+    { "lag-in-frames",   "Number of frames to look ahead at for "
+                         "alternate reference frame selection",    
OFFSET(lag_in_frames),   AV_OPT_TYPE_INT, {.i64 = -1},      -1,      INT_MAX, 
VE},
+    { "arnr-strength",   "altref noise reduction filter strength", 
OFFSET(arnr_strength),   AV_OPT_TYPE_INT, {.i64 = -1},      -1,      6,       
VE},
+    { "aq-mode",         "adaptive quantization mode",             
OFFSET(aq_mode),         AV_OPT_TYPE_INT, {.i64 = -1},      -1,      4, VE, 
.unit = "aq_mode"},
+    { "none",            "Aq not used",         0, AV_OPT_TYPE_CONST, {.i64 = 
0}, 0, 0, VE, .unit = "aq_mode"},
+    { "variance",        "Variance based Aq",   0, AV_OPT_TYPE_CONST, {.i64 = 
1}, 0, 0, VE, .unit = "aq_mode"},
+    { "complexity",      "Complexity based Aq", 0, AV_OPT_TYPE_CONST, {.i64 = 
2}, 0, 0, VE, .unit = "aq_mode"},
+    { "cyclic",          "Cyclic Refresh Aq",   0, AV_OPT_TYPE_CONST, {.i64 = 
3}, 0, 0, VE, .unit = "aq_mode"},
+    { "qp",              "Select the quality for constant quality mode", 
offsetof(AVMContext, qp), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 255, VE },
+    { "static-thresh",    "A change threshold on blocks below which they will 
be skipped by the encoder", OFFSET(static_thresh), AV_OPT_TYPE_INT, { .i64 = 0 
}, 0, INT_MAX, VE },
+    { "denoise-noise-level", "Amount of noise to be removed", 
OFFSET(denoise_noise_level), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE},
+    { "denoise-block-size", "Denoise block size ", OFFSET(denoise_block_size), 
AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE},
+    { "undershoot-pct",   "Datarate undershoot (min) target (%)", 
OFFSET(rc_undershoot_pct), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 100, VE},
+    { "overshoot-pct",    "Datarate overshoot (max) target (%)", 
OFFSET(rc_overshoot_pct), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1000, VE},
+    { "minsection-pct",   "GOP min bitrate (% of target)", 
OFFSET(minsection_pct), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 100, VE},
+    { "maxsection-pct",   "GOP max bitrate (% of target)", 
OFFSET(maxsection_pct), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 5000, VE},
+    { "frame-parallel",   "Enable frame parallel decodability features", 
OFFSET(frame_parallel),  AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE},
+    { "tiles",            "Tile columns x rows", OFFSET(tile_cols), 
AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, 0, VE },
+    { "tile-columns",     "Log2 of number of tile columns to use", 
OFFSET(tile_cols_log2), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 6, VE},
+    { "tile-rows",        "Log2 of number of tile rows to use",    
OFFSET(tile_rows_log2), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 6, VE},
+    { "row-mt",           "Enable row based multi-threading",      
OFFSET(row_mt),         AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE},
+    { "enable-cdef",      "Enable CDEF filtering",                 
OFFSET(enable_cdef),    AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE},
+    { "enable-global-motion",  "Enable global motion",             
OFFSET(enable_global_motion), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE},
+    { "enable-intrabc",  "Enable intra block copy prediction mode", 
OFFSET(enable_intrabc), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE},
+    { "enable-restoration", "Enable Loop Restoration filtering", 
OFFSET(enable_restoration), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE},
+    { "usage",           "Quality and compression efficiency vs speed 
trade-off", OFFSET(usage), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, VE, .unit = 
"usage"},
+    { "good",            "Good quality",      0, AV_OPT_TYPE_CONST, {.i64 = 0 
/* AVM_USAGE_GOOD_QUALITY */}, 0, 0, VE, .unit = "usage"},
+    { "tune",            "The metric that the encoder tunes for. Automatically 
chosen by the encoder by default", OFFSET(tune), AV_OPT_TYPE_INT, {.i64 = -1}, 
-1, AVM_TUNE_SSIM, VE, .unit = "tune"},
+    { "psnr",            NULL,         0, AV_OPT_TYPE_CONST, {.i64 = 
AVM_TUNE_PSNR}, 0, 0, VE, .unit = "tune"},
+    { "ssim",            NULL,         0, AV_OPT_TYPE_CONST, {.i64 = 
AVM_TUNE_SSIM}, 0, 0, VE, .unit = "tune"},
+    { "still-picture", "Encode in single frame mode (typically used for still 
AVIF images).", OFFSET(still_picture), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, VE 
},
+    { "dolbyvision",     "Enable Dolby Vision RPU coding", 
OFFSET(dovi.enable), AV_OPT_TYPE_BOOL, {.i64 = FF_DOVI_AUTOMATIC }, -1, 1, VE, 
.unit = "dovi" },
+    {   "auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DOVI_AUTOMATIC}, .flags 
= VE, .unit = "dovi" },
+    { "enable-rect-partitions", "Enable rectangular partitions", 
OFFSET(enable_rect_partitions), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE},
+    { "enable-angle-delta",       "Enable angle delta intra prediction",       
         OFFSET(enable_angle_delta),       AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 
1, VE},
+    { "enable-cfl-intra",         "Enable chroma predicted from luma intra 
prediction", OFFSET(enable_cfl_intra),         AV_OPT_TYPE_BOOL, {.i64 = -1}, 
-1, 1, VE},
+    { "enable-intra-edge-filter", "Enable intra edge filter",                  
         OFFSET(enable_intra_edge_filter), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 
1, VE},
+    { "enable-smooth-intra",      "Enable smooth intra prediction mode",       
         OFFSET(enable_smooth_intra),      AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 
1, VE},
+    { "enable-paeth-intra",       "Enable paeth predictor in intra 
prediction",         OFFSET(enable_paeth_intra),       AV_OPT_TYPE_BOOL, {.i64 
= -1}, -1, 1, VE},
+    { "enable-palette",           "Enable palette prediction mode",            
         OFFSET(enable_palette),           AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 
1, VE},
+    { "enable-flip-idtx",          "Enable extended transform type",           
  OFFSET(enable_flip_idtx),          AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE},
+    { "reduced-tx-type-set",       "Use reduced set of transform types",       
  OFFSET(reduced_tx_type_set),       AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE},
+    { "use-intra-dct-only",        "Use DCT only for INTRA modes",             
  OFFSET(use_intra_dct_only),        AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE},
+    { "use-inter-dct-only",        "Use DCT only for INTER modes",             
  OFFSET(use_inter_dct_only),        AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE},
+    { "use-intra-default-tx-only", "Use default-transform only for INTRA 
modes", OFFSET(use_intra_default_tx_only), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 
1, VE},
+    { "enable-ref-frame-mvs",         "Enable temporal mv prediction",         
            OFFSET(enable_ref_frame_mvs),         AV_OPT_TYPE_BOOL, {.i64 = 
-1}, -1, 1, VE},
+    { "enable-diff-wtd-comp",         "Enable difference-weighted compound",   
            OFFSET(enable_diff_wtd_comp),         AV_OPT_TYPE_BOOL, {.i64 = 
-1}, -1, 1, VE},
+    { "enable-onesided-comp",         "Enable one sided compound",             
            OFFSET(enable_onesided_comp),         AV_OPT_TYPE_BOOL, {.i64 = 
-1}, -1, 1, VE},
+    { "enable-interinter-wedge",      "Enable interinter wedge compound",      
            OFFSET(enable_interinter_wedge),      AV_OPT_TYPE_BOOL, {.i64 = 
-1}, -1, 1, VE},
+    { "enable-interintra-wedge",      "Enable interintra wedge compound",      
            OFFSET(enable_interintra_wedge),      AV_OPT_TYPE_BOOL, {.i64 = 
-1}, -1, 1, VE},
+    { "enable-masked-comp",           "Enable masked compound",                
            OFFSET(enable_masked_comp),           AV_OPT_TYPE_BOOL, {.i64 = 
-1}, -1, 1, VE},
+    { "enable-interintra-comp",       "Enable interintra compound",            
            OFFSET(enable_interintra_comp),       AV_OPT_TYPE_BOOL, {.i64 = 
-1}, -1, 1, VE},
+    { "enable-smooth-interintra",     "Enable smooth interintra mode",         
            OFFSET(enable_smooth_interintra),     AV_OPT_TYPE_BOOL, {.i64 = 
-1}, -1, 1, VE},
+    { "avm-params",                   "Set libavm options using a :-separated 
list of key=value pairs", OFFSET(avm_params), AV_OPT_TYPE_DICT, { 0 }, 0, 0, VE 
},
+    { NULL },
+};
+
+static const FFCodecDefault defaults[] = {
+    { "b",                 "0" },
+    { "qmin",             "-1" },
+    { "qmax",             "-1" },
+    { "g",                "-1" },
+    { "keyint_min",       "-1" },
+    { NULL },
+};
+
+static const AVClass class_avm = {
+    .class_name = "libavm-av2 encoder",
+    .item_name  = av_default_item_name,
+    .option     = options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
+FFCodec ff_libavm_av2_encoder = {
+    .p.name         = "libavm-av2",
+    CODEC_LONG_NAME("libavm AV2"),
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_AV2,
+    .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY |
+                      AV_CODEC_CAP_ENCODER_RECON_FRAME |
+                      AV_CODEC_CAP_OTHER_THREADS,
+    .color_ranges   = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG,
+    .p.priv_class   = &class_avm,
+    .p.wrapper_name = "libavm",
+    .priv_data_size = sizeof(AVMContext),
+    .init           = av2_init,
+    FF_CODEC_ENCODE_CB(avm_encode),
+    .close          = avm_free,
+    .caps_internal  = FF_CODEC_CAP_NOT_INIT_THREADSAFE |
+                      FF_CODEC_CAP_INIT_CLEANUP |
+                      FF_CODEC_CAP_AUTO_THREADS,
+    CODEC_PIXFMTS_ARRAY(av2_pix_fmts_highbd_with_gray),
+    .defaults       = defaults,
+};
-- 
2.52.0


>From 631a14d93da56aa504d924ad0cdb667c1eacb0c4 Mon Sep 17 00:00:00 2001
From: Jamaika1 <[email protected]>
Date: Tue, 2 Jun 2026 04:30:51 +0000
Subject: [PATCH 02/11] Added image codec AV2

---
 libavformat/img2enc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavformat/img2enc.c b/libavformat/img2enc.c
index b11f62d85d..176cee69a9 100644
--- a/libavformat/img2enc.c
+++ b/libavformat/img2enc.c
@@ -297,7 +297,7 @@ const FFOutputFormat ff_image2_muxer = {
     .p.long_name    = NULL_IF_CONFIG_SMALL("image2 sequence"),
     .p.extensions   = 
"bmp,dpx,exr,jls,jpeg,jpg,jxs,jxl,ljpg,pam,pbm,pcx,pfm,pgm,pgmyuv,phm,"
                       
"png,ppm,sgi,tga,tif,tiff,jp2,j2c,j2k,xwd,sun,ras,rs,im1,im8,"
-                      "im24,sunras,vbn,xbm,xface,pix,y,avif,qoi,hdr,wbmp",
+                      "im24,sunras,vbn,xbm,xface,pix,y,av2,avif,qoi,hdr,wbmp",
     .priv_data_size = sizeof(VideoMuxData),
     .p.video_codec  = AV_CODEC_ID_MJPEG,
     .write_header   = write_header,
-- 
2.52.0


>From 16a1694cf642d4fb883b2582aca03239a4288c38 Mon Sep 17 00:00:00 2001
From: Jamaika1 <[email protected]>
Date: Tue, 2 Jun 2026 04:32:36 +0000
Subject: [PATCH 03/11] Added image codec AV2

---
 libavformat/demux.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libavformat/demux.c b/libavformat/demux.c
index 55085210de..336d0c7dd8 100644
--- a/libavformat/demux.c
+++ b/libavformat/demux.c
@@ -112,6 +112,7 @@ static int set_codec_from_probe_data(AVFormatContext *s, 
AVStream *st,
         { "ac3",        AV_CODEC_ID_AC3,          AVMEDIA_TYPE_AUDIO    },
         { "aptx",       AV_CODEC_ID_APTX,         AVMEDIA_TYPE_AUDIO    },
         { "av1",        AV_CODEC_ID_AV1,          AVMEDIA_TYPE_VIDEO    },
+        { "av2",        AV_CODEC_ID_AV2,          AVMEDIA_TYPE_VIDEO    },
         { "dts",        AV_CODEC_ID_DTS,          AVMEDIA_TYPE_AUDIO    },
         { "dvbsub",     AV_CODEC_ID_DVB_SUBTITLE, AVMEDIA_TYPE_SUBTITLE },
         { "dvbtxt",     AV_CODEC_ID_DVB_TELETEXT, AVMEDIA_TYPE_SUBTITLE },
-- 
2.52.0


>From 0a8296d674f8ab4a794cb0cf2a7216133a31a427 Mon Sep 17 00:00:00 2001
From: Jamaika1 <[email protected]>
Date: Tue, 2 Jun 2026 04:33:45 +0000
Subject: [PATCH 04/11] Added image codec AV2

---
 libavformat/img2.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libavformat/img2.c b/libavformat/img2.c
index 2c69a932da..78b4018b08 100644
--- a/libavformat/img2.c
+++ b/libavformat/img2.c
@@ -27,6 +27,7 @@
 #include "img2.h"
 
 #define IMG_TAGS(TAG)               \
+    TAG(AV2,             av2     ) \
     TAG(MJPEG,           jpeg     ) \
     TAG(MJPEG,           jpg      ) \
     TAG(MJPEG,           jps      ) \
-- 
2.52.0


>From e9835babcfa1fc33e15136b8ba842659d364527f Mon Sep 17 00:00:00 2001
From: Jamaika1 <[email protected]>
Date: Tue, 2 Jun 2026 04:36:39 +0000
Subject: [PATCH 05/11] Added image codec AV2

---
 libavformat/isom_tags.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libavformat/isom_tags.c b/libavformat/isom_tags.c
index 1cd655b06c..5e63f9f7b5 100644
--- a/libavformat/isom_tags.c
+++ b/libavformat/isom_tags.c
@@ -160,6 +160,7 @@ const AVCodecTag ff_codec_movvideo_tags[] = {
     { 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 */
+       { AV_CODEC_ID_AV2,  MKTAG('a', 'v', '0', '2') }, /* AV2 */
 
     { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', '1', 'v', ' ') },
     { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', '1', 'v', '1') }, /* Apple MPEG-1 
Camcorder */
-- 
2.52.0


>From 47e5a35e388fca7672e24eaa28f2a6026074ce79 Mon Sep 17 00:00:00 2001
From: Jamaika1 <[email protected]>
Date: Tue, 2 Jun 2026 04:38:08 +0000
Subject: [PATCH 06/11] Added image codec AV2

---
 libavformat/ivfenc.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/libavformat/ivfenc.c b/libavformat/ivfenc.c
index 9feaea3516..50a8a6c039 100644
--- a/libavformat/ivfenc.c
+++ b/libavformat/ivfenc.c
@@ -31,10 +31,11 @@ static int ivf_init(AVFormatContext *s)
 {
     AVCodecParameters *par = s->streams[0]->codecpar;
 
-    if (!(par->codec_id == AV_CODEC_ID_AV1 ||
+    if (!(par->codec_id == AV_CODEC_ID_AV2 ||
+          par->codec_id == AV_CODEC_ID_AV1 ||
           par->codec_id == AV_CODEC_ID_VP8 ||
           par->codec_id == AV_CODEC_ID_VP9)) {
-        av_log(s, AV_LOG_ERROR, "Currently only VP8, VP9 and AV1 are 
supported!\n");
+        av_log(s, AV_LOG_ERROR, "Currently only VP8, VP9, AV1 and AV2 are 
supported!\n");
         return AVERROR(EINVAL);
     }
 
@@ -61,7 +62,8 @@ static int ivf_write_header(AVFormatContext *s)
     avio_wl16(pb, 32); // header length
     avio_wl32(pb,
               par->codec_id == AV_CODEC_ID_VP9 ? AV_RL32("VP90") :
-              par->codec_id == AV_CODEC_ID_VP8 ? AV_RL32("VP80") : 
AV_RL32("AV01"));
+              par->codec_id == AV_CODEC_ID_VP8 ? AV_RL32("VP80") :
+              par->codec_id == AV_CODEC_ID_AV1 ? AV_RL32("AV01") : 
AV_RL32("AV02"));
     avio_wl16(pb, par->width);
     avio_wl16(pb, par->height);
     avio_wl32(pb, s->streams[0]->time_base.den);
@@ -108,6 +110,7 @@ static const AVCodecTag codec_ivf_tags[] = {
     { AV_CODEC_ID_VP8,  MKTAG('V', 'P', '8', '0') },
     { AV_CODEC_ID_VP9,  MKTAG('V', 'P', '9', '0') },
     { AV_CODEC_ID_AV1,  MKTAG('A', 'V', '0', '1') },
+    { AV_CODEC_ID_AV2,  MKTAG('A', 'V', '0', '2') },
     { AV_CODEC_ID_NONE, 0 }
 };
 
-- 
2.52.0


>From 518aa6b3771aeef6537dc3518b4b0bb4ecd4ea2b Mon Sep 17 00:00:00 2001
From: Jamaika1 <[email protected]>
Date: Tue, 2 Jun 2026 04:38:59 +0000
Subject: [PATCH 07/11] Added image codec AV2

---
 libavcodec/libavm.h | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)
 create mode 100644 libavcodec/libavm.h

diff --git a/libavcodec/libavm.h b/libavcodec/libavm.h
new file mode 100644
index 0000000000..c2c66eb8bf
--- /dev/null
+++ b/libavcodec/libavm.h
@@ -0,0 +1,33 @@
+/*
+ * 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
+ */
+
+/**
+ * @file
+ * AOM common functions
+ */
+
+#ifndef AVCODEC_LIBAOM_H
+#define AVCODEC_LIBAOM_H
+
+#include <avm/avm_image.h>
+
+#include "libavutil/frame.h"
+
+void ff_avm_image_copy_16_to_8(AVFrame *pic, struct avm_image *img);
+
+#endif /* AVCODEC_LIBAOM_H */
-- 
2.52.0


>From 040e215269eb310522c0c1806edc2e05a811a0dd Mon Sep 17 00:00:00 2001
From: Jamaika1 <[email protected]>
Date: Tue, 2 Jun 2026 04:40:33 +0000
Subject: [PATCH 08/11] Added image codec AV2

---
 libavcodec/codec_desc.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index 99e7c0de3d..b56726d7e0 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -2017,6 +2017,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
         .props     = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_LOSSLESS,
         .mime_types= MT("image/webp"),
     },
+    {
+        .id        = AV_CODEC_ID_AV2,
+        .type      = AVMEDIA_TYPE_VIDEO,
+        .name      = "av2",
+        .long_name = NULL_IF_CONFIG_SMALL("Alliance for Open Media AV2"),
+        .props     = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_LOSSLESS,
+    },
 
     /* various PCM "codecs" */
     {
-- 
2.52.0


>From b071c5939eb38283887c34d67c66071433215f3f Mon Sep 17 00:00:00 2001
From: Jamaika1 <[email protected]>
Date: Tue, 2 Jun 2026 04:41:39 +0000
Subject: [PATCH 09/11] Added image codec AV2

---
 libavcodec/codec_id.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h
index bb2c16a958..d7b8b909f0 100644
--- a/libavcodec/codec_id.h
+++ b/libavcodec/codec_id.h
@@ -333,6 +333,7 @@ enum AVCodecID {
     AV_CODEC_ID_PRORES_RAW,
     AV_CODEC_ID_JPEGXS,
     AV_CODEC_ID_WEBP_ANIM,
+    AV_CODEC_ID_AV2,
 
     /* various PCM "codecs" */
     AV_CODEC_ID_FIRST_AUDIO = 0x10000,     ///< A dummy id pointing at the 
start of audio codecs
-- 
2.52.0


>From c11054bcae132ecf04aeb18a66cafa695af23e31 Mon Sep 17 00:00:00 2001
From: Jamaika1 <[email protected]>
Date: Tue, 2 Jun 2026 04:48:37 +0000
Subject: [PATCH 10/11] Added image codec AV2

---
 libavcodec/Makefile | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index ac3c4d1978..50244fe67f 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -1172,6 +1172,8 @@ OBJS-$(CONFIG_PCM_ALAW_AT_ENCODER)        += 
audiotoolboxenc.o
 OBJS-$(CONFIG_PCM_MULAW_AT_ENCODER)       += audiotoolboxenc.o
 OBJS-$(CONFIG_LIBAOM_AV1_DECODER)         += libaomdec.o libaom.o
 OBJS-$(CONFIG_LIBAOM_AV1_ENCODER)         += libaomenc.o libaom.o
+OBJS-$(CONFIG_LIBAVM_AV2_DECODER)         += libavmdec.o libavm.o
+OBJS-$(CONFIG_LIBAVM_AV2_ENCODER)         += libavmenc.o libavm.o
 OBJS-$(CONFIG_LIBARIBB24_DECODER)         += libaribb24.o ass.o
 OBJS-$(CONFIG_LIBARIBCAPTION_DECODER)     += libaribcaption.o ass.o
 OBJS-$(CONFIG_LIBCODEC2_DECODER)          += libcodec2.o
@@ -1346,6 +1348,7 @@ SKIPHEADERS-$(CONFIG_DXVA2)            += dxva2.h 
dxva2_internal.h
 SKIPHEADERS-$(CONFIG_JNI)              += ffjni.h
 SKIPHEADERS-$(CONFIG_LCMS2)            += fflcms2.h
 SKIPHEADERS-$(CONFIG_LIBAOM)           += libaom.h
+SKIPHEADERS-$(CONFIG_LIBAVM)           += libavm.h
 SKIPHEADERS-$(CONFIG_LIBJXL)           += libjxl.h
 SKIPHEADERS-$(CONFIG_LIBVPX)           += libvpx.h
 SKIPHEADERS-$(CONFIG_LIBWEBP_ENCODER)  += libwebpenc_common.h
-- 
2.52.0


>From 63320c65a49953f97af93ae68388b8fb2171a248 Mon Sep 17 00:00:00 2001
From: Jamaika1 <[email protected]>
Date: Tue, 2 Jun 2026 04:50:25 +0000
Subject: [PATCH 11/11] Added image codec AV2

---
 libavcodec/allcodecs.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 0815d46f79..2fd9880b5d 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -783,6 +783,7 @@ extern const FFCodec ff_pcm_mulaw_at_decoder;
 extern const FFCodec ff_qdmc_at_decoder;
 extern const FFCodec ff_qdm2_at_decoder;
 extern FFCodec ff_libaom_av1_encoder;
+extern FFCodec ff_libavm_av2_encoder;
 /* preferred over libaribb24 */
 extern const FFCodec ff_libaribcaption_decoder;
 extern const FFCodec ff_libaribb24_decoder;
@@ -860,6 +861,7 @@ extern const FFCodec ff_amrnb_mediacodec_decoder;
 extern const FFCodec ff_amrwb_mediacodec_decoder;
 extern const FFCodec ff_h263_v4l2m2m_encoder;
 extern const FFCodec ff_libaom_av1_decoder;
+extern const FFCodec ff_libavm_av2_decoder;
 /* hwaccel hooks only, so prefer external decoders */
 extern const FFCodec ff_av1_decoder;
 extern const FFCodec ff_av1_cuvid_decoder;
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to