Bump avm dependency to tag research-v13.0.0 (#2959)

diff --git a/.github/workflows/ci-unix-static-av2.yml b/.github/workflows/ci-unix-static-av2.yml
index 0407b85..27bfc9b 100644
--- a/.github/workflows/ci-unix-static-av2.yml
+++ b/.github/workflows/ci-unix-static-av2.yml
@@ -48,6 +48,7 @@
           -DCMAKE_POLICY_VERSION_MINIMUM=3.5
           -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF
           -DAVIF_CODEC_AVM=LOCAL
+          -DAVIF_CODEC_AOM=${{ matrix.also-enable-av1-codecs }}
           -DAVIF_CODEC_DAV1D=${{ matrix.also-enable-av1-codecs }}
           -DAVIF_CODEC_RAV1E=${{ matrix.also-enable-av1-codecs }}
           -DAVIF_CODEC_SVT=${{ matrix.also-enable-av1-codecs }}
diff --git a/.gitignore b/.gitignore
index 797db2e..d0e38c4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,6 @@
 /build*
 /obj*
 /ext/aom
-/ext/avm
 /ext/ComplianceWarden
 /ext/dav1d
 /ext/fuzztest
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e1c012a..9b84587 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -37,7 +37,7 @@
 * Update libjpeg.cmd/LocalJpeg.cmake: 3.1.1
 * Update libxml2.cmd/LocalLibXml2.cmake: v2.14.4
 * Update aom.cmd/LocalAom.cmake: v3.13.1
-* Update LocalAom.cmake: AVM research-v12.0.0
+* Update LocalAvm.cmake: research-v13.0.0
 * Update rav1e.cmd/LocalRav1e.cmake: cargo-c v0.10.14, corrosion v0.5.2,
   rav1e v0.8.1
 * Update svt.cmd/svt.sh/LocalSvt.cmake: v3.1.2
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b33c7cd..9e20b5e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -503,6 +503,15 @@
     set(AVIF_PKG_CONFIG_EXTRA_REQUIRES_PRIVATE "${AVIF_PKG_CONFIG_EXTRA_REQUIRES_PRIVATE} SvtAv1Enc")
 endif()
 
+if(AVIF_CODEC_AVM)
+    # Avoid the following error:
+    #   CMake Error: Error required internal CMake variable not set, cmake may not be built correctly.
+    #   Missing variable is: CMAKE_ASM_COMPILE_OBJECT
+    # For some reason this must be done before check_avif_option(AVIF_CODEC_AOM TARGET aom PKG_NAME aom).
+    # See also https://gitlab.kitware.com/cmake/cmake/-/issues/25042.
+    enable_language(ASM)
+endif()
+
 check_avif_option(AVIF_CODEC_AOM TARGET aom PKG_NAME aom)
 if(AVIF_CODEC_AOM_ENABLED)
     target_compile_definitions(avif_obj PRIVATE -DAVIF_CODEC_AOM=1)
@@ -534,20 +543,14 @@
     endif()
 endif()
 
-check_avif_option(AVIF_CODEC_AVM TARGET aom PKG_NAME avm)
+check_avif_option(AVIF_CODEC_AVM TARGET avm PKG_NAME avm)
 if(AVIF_CODEC_AVM_ENABLED)
     message(WARNING "libavif: AV2 support with avm is experimental. Only use for testing.")
 
-    # The avm repository is a fork of aom and inherited a lot of folders, files and build artifacts named the same way.
-    # Having both dependencies at the same time generates conflicts in includes, binary lookups etc.
-    if(AVIF_CODEC_AOM_ENABLED)
-        message(FATAL_ERROR "libavif: aom conflicts with avm, bailing out")
-    endif()
-
     target_compile_definitions(avif_obj PUBLIC -DAVIF_CODEC_AVM=1)
     target_sources(avif_obj PRIVATE src/codec_avm.c)
 
-    avif_target_link_library(aom)
+    avif_target_link_library(avm)
     # C++ is needed because of tensorflow-lite.
     set(AVIF_LIB_USE_CXX ON)
 
diff --git a/cmake/Modules/LocalAom.cmake b/cmake/Modules/LocalAom.cmake
index 6809d15..c2a0100 100644
--- a/cmake/Modules/LocalAom.cmake
+++ b/cmake/Modules/LocalAom.cmake
@@ -1,30 +1,15 @@
 set(AVIF_AOM_GIT_TAG v3.13.1)
-set(AVIF_AVM_GIT_TAG e3b7bd426c282494c07eaa3e559e461a3e96f823)
 
-if(AVIF_CODEC_AVM)
-    # Building the avm repository generates files such as "libaom.a" because it is a fork of aom,
-    # so its build can be treated the same as aom
-    set(AOM_PACKAGE_NAME avm)
-    set(AOM_MESSAGE_PREFIX "libavif(AVIF_CODEC_AVM=LOCAL)")
-else()
-    set(AOM_PACKAGE_NAME aom)
-    set(AOM_MESSAGE_PREFIX "libavif(AVIF_CODEC_AOM=LOCAL)")
-endif()
-
-set(AOM_EXT_SOURCE_DIR "${AVIF_SOURCE_DIR}/ext/${AOM_PACKAGE_NAME}")
+set(AOM_EXT_SOURCE_DIR "${AVIF_SOURCE_DIR}/ext/aom")
 set(LIB_FILENAME "${AOM_EXT_SOURCE_DIR}/build.libavif/${CMAKE_STATIC_LIBRARY_PREFIX}aom${CMAKE_STATIC_LIBRARY_SUFFIX}")
 
 if(EXISTS "${LIB_FILENAME}")
-    message(STATUS "${AOM_MESSAGE_PREFIX}: compiled library found at ${LIB_FILENAME}")
+    message(STATUS "libavif(AVIF_CODEC_AOM=LOCAL): compiled library found at ${LIB_FILENAME}")
     add_library(aom STATIC IMPORTED GLOBAL)
     set_target_properties(aom PROPERTIES IMPORTED_LOCATION "${LIB_FILENAME}" AVIF_LOCAL ON)
     target_include_directories(aom INTERFACE $<BUILD_INTERFACE:${AOM_EXT_SOURCE_DIR}>)
-    if(AVIF_CODEC_AVM)
-        # avm/aom/aom_encoder.h includes config/aom_config.h which is generated by the local build of avm.
-        target_include_directories(aom INTERFACE $<BUILD_INTERFACE:${AOM_EXT_SOURCE_DIR}/build.libavif>)
-    endif()
 
-    # Add link dependency flags from the aom.pc file in ext/aom or ext/avm
+    # Add link dependency flags from the aom.pc file in ext/aom
     # by prepending the build directory to PKG_CONFIG_PATH and then calling
     # pkg_check_modules
     if(WIN32)
@@ -50,13 +35,13 @@
         target_link_libraries(aom INTERFACE ${_aom_dep_lib_${_lib}})
     endforeach()
 else()
-    message(STATUS "${AOM_MESSAGE_PREFIX}: compiled library not found at ${LIB_FILENAME}, using FetchContent")
+    message(STATUS "libavif(AVIF_CODEC_AOM=LOCAL): compiled library not found at ${LIB_FILENAME}, using FetchContent")
     if(EXISTS "${AOM_EXT_SOURCE_DIR}")
-        message(STATUS "${AOM_MESSAGE_PREFIX}: ext/${AOM_PACKAGE_NAME} found; using as FetchContent SOURCE_DIR")
+        message(STATUS "libavif(AVIF_CODEC_AOM=LOCAL): ext/aom found; using as FetchContent SOURCE_DIR")
         set(FETCHCONTENT_SOURCE_DIR_AOM "${AOM_EXT_SOURCE_DIR}")
-        message(CHECK_START "${AOM_MESSAGE_PREFIX}: configuring ${AOM_PACKAGE_NAME}")
+        message(CHECK_START "libavif(AVIF_CODEC_AOM=LOCAL): configuring aom")
     else()
-        message(CHECK_START "${AOM_MESSAGE_PREFIX}: fetching and configuring ${AOM_PACKAGE_NAME}")
+        message(CHECK_START "libavif(AVIF_CODEC_AOM=LOCAL): fetching and configuring aom")
     endif()
 
     # aom sets its compile options by setting variables like CMAKE_C_FLAGS_RELEASE using
@@ -82,40 +67,22 @@
         endforeach()
     endfunction()
 
-    set(AOM_BINARY_DIR "${FETCHCONTENT_BASE_DIR}/${AOM_PACKAGE_NAME}-build")
+    set(AOM_BINARY_DIR "${FETCHCONTENT_BASE_DIR}/aom-build")
 
     if(ANDROID_ABI)
         set(AOM_BINARY_DIR "${AOM_BINARY_DIR}/${ANDROID_ABI}")
     endif()
 
-    if(AVIF_CODEC_AVM)
-        FetchContent_Declare(
-            libaom
-            GIT_REPOSITORY "https://gitlab.com/AOMediaCodec/avm.git"
-            BINARY_DIR "${AOM_BINARY_DIR}"
-            GIT_TAG ${AVIF_AVM_GIT_TAG}
-            GIT_PROGRESS ON
-            GIT_SHALLOW OFF
-            UPDATE_COMMAND ""
-        )
-        # There can be a duplicate cpuinfo in SVT so find_package has to be used.
-        set(RUY_FIND_CPUINFO ON CACHE INTERNAL "")
-        # TODO(vrabaud) Remove once libavm properly depends on flatbuffers.
-        include_directories(${CMAKE_CURRENT_BINARY_DIR}/flatbuffers/include/)
-    else()
-        FetchContent_Declare(
-            libaom URL "https://aomedia.googlesource.com/aom/+archive/${AVIF_AOM_GIT_TAG}.tar.gz" BINARY_DIR "${AOM_BINARY_DIR}"
-            UPDATE_COMMAND ""
-        )
-    endif()
+    FetchContent_Declare(
+        libaom URL "https://aomedia.googlesource.com/aom/+archive/${AVIF_AOM_GIT_TAG}.tar.gz" BINARY_DIR "${AOM_BINARY_DIR}"
+        UPDATE_COMMAND ""
+    )
 
-    if(NOT AVIF_CODEC_AVM)
-        if(NOT AVIF_CODEC_AOM_DECODE)
-            set(CONFIG_AV1_DECODER 0 CACHE INTERNAL "")
-        endif()
-        if(NOT AVIF_CODEC_AOM_ENCODE)
-            set(CONFIG_AV1_ENCODER 0 CACHE INTERNAL "")
-        endif()
+    if(NOT AVIF_CODEC_AOM_DECODE)
+        set(CONFIG_AV1_DECODER 0 CACHE INTERNAL "")
+    endif()
+    if(NOT AVIF_CODEC_AOM_ENCODE)
+        set(CONFIG_AV1_ENCODER 0 CACHE INTERNAL "")
     endif()
     set(CONFIG_PIC 1 CACHE INTERNAL "")
     if(libyuv_FOUND)
@@ -179,17 +146,9 @@
         endif()
         target_link_libraries(aom PRIVATE $<TARGET_FILE:yuv::yuv>)
     endif()
-    if(AVIF_CODEC_AVM)
-        # TODO(vrabaud) Remove once libavm properly depends on tensorflow-lite.
-        target_link_libraries(aom PRIVATE tensorflow-lite)
-    endif()
 
     set_property(TARGET aom PROPERTY AVIF_LOCAL ON)
     target_include_directories(aom INTERFACE $<BUILD_INTERFACE:$<PATH:ABSOLUTE_PATH,${libaom_SOURCE_DIR},/>>)
-    if(AVIF_CODEC_AVM)
-        # avm/aom/aom_encoder.h includes config/aom_config.h which is generated by the local build of avm.
-        target_include_directories(aom INTERFACE $<BUILD_INTERFACE:${AOM_BINARY_DIR}>)
-    endif()
 
     message(CHECK_PASS "complete")
 endif()
diff --git a/cmake/Modules/LocalAvm.cmake b/cmake/Modules/LocalAvm.cmake
index f641d7f..001b01e 100644
--- a/cmake/Modules/LocalAvm.cmake
+++ b/cmake/Modules/LocalAvm.cmake
@@ -1 +1,131 @@
-include(LocalAom)
+set(AVIF_AVM_GIT_TAG research-v13.0.0)
+
+message(CHECK_START "libavif(AVIF_CODEC_AVM=LOCAL): fetching and configuring avm")
+
+# avm sets its compile options by setting variables like CMAKE_C_FLAGS_RELEASE using
+# CACHE FORCE, which effectively adds those flags to all targets. We stash and restore
+# the original values and call avif_set_avm_compile_options to instead set the flags on all avm
+# targets
+function(avif_set_avm_compile_options target config)
+    string(REPLACE " " ";" AVM_C_FLAGS_LIST "${CMAKE_C_FLAGS_${config}}")
+    string(REPLACE " " ";" AVM_CXX_FLAGS_LIST "${CMAKE_CXX_FLAGS_${config}}")
+    foreach(flag ${AVM_C_FLAGS_LIST})
+        target_compile_options(${target} PRIVATE $<$<COMPILE_LANGUAGE:C>:${flag}>)
+    endforeach()
+    foreach(flag ${AVM_CXX_FLAGS_LIST})
+        target_compile_options(${target} PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${flag}>)
+    endforeach()
+
+    get_target_property(sources ${target} SOURCES)
+    foreach(src ${sources})
+        if(src MATCHES "TARGET_OBJECTS:")
+            string(REGEX REPLACE "\\$<TARGET_OBJECTS:(.*)>" "\\1" source_target ${src})
+            avif_set_avm_compile_options(${source_target} ${config})
+        endif()
+    endforeach()
+endfunction()
+
+set(AVM_BINARY_DIR "${FETCHCONTENT_BASE_DIR}/avm-build")
+
+if(ANDROID_ABI)
+    set(AVM_BINARY_DIR "${AVM_BINARY_DIR}/${ANDROID_ABI}")
+endif()
+
+FetchContent_Declare(
+    libavm
+    GIT_REPOSITORY "https://gitlab.com/AOMediaCodec/avm.git"
+    BINARY_DIR "${AVM_BINARY_DIR}"
+    GIT_TAG ${AVIF_AVM_GIT_TAG}
+    GIT_PROGRESS ON
+    GIT_SHALLOW OFF
+    UPDATE_COMMAND ""
+    # Avoid the following error when both aom and avm are built:
+    #   CMake Error at build/_deps/libavm-src/CMakeLists.txt:1103 (add_custom_target):
+    #     add_custom_target cannot create target "dist" because another target with
+    #     the same name already exists.  The existing target is a custom target
+    #     created in source directory "libavif/build/_deps/libaom-src". See CMP0002.
+    # The patch LocalAvm.diff was generated by running:
+    #   git clone -b research-v13.0.0 https://gitlab.com/AOMediaCodec/avm.git
+    #   cd avm
+    #   sed -i -e 's/  dist/  avm_dist/g' CMakeLists.txt
+    #   git diff > LocalAvm.diff
+    # TODO: b/398931194 - Remove the patch when using a libavm version past
+    #                     https://gitlab.com/AOMediaCodec/avm/-/merge_requests/2985
+    PATCH_COMMAND git apply ${AVIF_SOURCE_DIR}/cmake/Modules/LocalAvm.diff
+)
+# There can be a duplicate cpuinfo in SVT so find_package has to be used.
+set(RUY_FIND_CPUINFO ON CACHE INTERNAL "")
+# TODO(vrabaud) Remove once libavm properly depends on flatbuffers.
+include_directories(${CMAKE_CURRENT_BINARY_DIR}/flatbuffers/include/)
+
+set(CONFIG_PIC 1 CACHE INTERNAL "")
+if(libyuv_FOUND)
+    set(CONFIG_LIBYUV 0 CACHE INTERNAL "")
+else()
+    set(CONFIG_LIBYUV 1 CACHE INTERNAL "")
+endif()
+set(CONFIG_WEBM_IO 0 CACHE INTERNAL "")
+set(ENABLE_DOCS 0 CACHE INTERNAL "")
+set(ENABLE_EXAMPLES 0 CACHE INTERNAL "")
+set(ENABLE_TESTDATA 0 CACHE INTERNAL "")
+set(ENABLE_TESTS 0 CACHE INTERNAL "")
+set(ENABLE_TOOLS 0 CACHE INTERNAL "")
+if(CMAKE_OSX_ARCHITECTURES STREQUAL "arm64")
+    set(AVM_TARGET_CPU "arm64")
+endif()
+
+if(NOT libavm_POPULATED)
+    # Guard against the project setting cmake variables that would affect the parent build
+    # See comment above for avif_set_avm_compile_options
+    foreach(_config_setting CMAKE_C_FLAGS CMAKE_CXX_FLAGS CMAKE_EXE_LINKER_FLAGS)
+        foreach(_config_type DEBUG RELEASE MINSIZEREL RELWITHDEBINFO)
+            set(${_config_setting}_${_config_type}_ORIG ${${_config_setting}_${_config_type}})
+        endforeach()
+    endforeach()
+
+    avif_fetchcontent_populate_cmake(libavm)
+
+    set(_avm_config RELEASE)
+    if(CMAKE_BUILD_TYPE)
+        string(TOUPPER ${CMAKE_BUILD_TYPE} _avm_config)
+    endif()
+    list(LENGTH CMAKE_CONFIGURATION_TYPES num_configs)
+    if(${num_configs} GREATER 0)
+        list(GET CMAKE_CONFIGURATION_TYPES 0 _avm_config_type)
+        string(TOUPPER ${_avm_config_type} _avm_config)
+    endif()
+    avif_set_avm_compile_options(avm ${_avm_config})
+
+    # Restore the variables.
+    foreach(_config_setting CMAKE_C_FLAGS CMAKE_CXX_FLAGS CMAKE_EXE_LINKER_FLAGS)
+        foreach(_config_type DEBUG RELEASE MINSIZEREL RELWITHDEBINFO)
+            unset(${_config_setting}_${_config_type} CACHE)
+            set(${_config_setting}_${_config_type} ${${_config_setting}_${_config_type}_ORIG} CACHE STRING "" FORCE)
+            unset(${_config_setting}_${_config_type}_ORIG)
+        endforeach()
+    endforeach()
+    unset(_config_type)
+    unset(_config_setting)
+endif()
+
+# If we have libyuv, we disable CONFIG_LIBYUV so that avm does not include the libyuv
+# sources from its third-party vendor library. But we still want AVM to have libyuv, only
+# linked against this project's target. Here we update the value in avm_config.h and add libyuv
+# to AVM's link libraries
+if(libyuv_FOUND)
+    file(READ ${AVM_BINARY_DIR}/config/avm_config.h AVM_CONFIG_H)
+    if("${AVM_CONFIG_H}" MATCHES "CONFIG_LIBYUV 0")
+        string(REPLACE "CONFIG_LIBYUV 0" "CONFIG_LIBYUV 1" AVM_CONFIG_H "${AVM_CONFIG_H}")
+        file(WRITE ${AVM_BINARY_DIR}/config/avm_config.h "${AVM_CONFIG_H}")
+    endif()
+    target_link_libraries(avm PRIVATE $<TARGET_FILE:yuv::yuv>)
+endif()
+# TODO(vrabaud) Remove once libavm properly depends on tensorflow-lite.
+target_link_libraries(avm PRIVATE tensorflow-lite)
+
+set_property(TARGET avm PROPERTY AVIF_LOCAL ON)
+target_include_directories(avm INTERFACE $<BUILD_INTERFACE:$<PATH:ABSOLUTE_PATH,${libavm_SOURCE_DIR},/>>)
+# libavm-src/avm/avm_encoder.h includes config/avm_config.h which is generated by the local build of avm.
+target_include_directories(avm INTERFACE $<BUILD_INTERFACE:${AVM_BINARY_DIR}>)
+
+message(CHECK_PASS "complete")
diff --git a/cmake/Modules/LocalAvm.diff b/cmake/Modules/LocalAvm.diff
new file mode 100644
index 0000000..faeceb9
--- /dev/null
+++ b/cmake/Modules/LocalAvm.diff
@@ -0,0 +1,13 @@
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index b70f5a9f31..81b801d509 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -1101,7 +1101,7 @@ if(NOT AVM_DIST_DIR)
+ endif()
+ 
+ add_custom_target(
+-  dist
++  avm_dist
+   COMMAND
+     ${CMAKE_COMMAND} -DAVM_ROOT=${AVM_ROOT} -DAVM_CONFIG_DIR=${AVM_CONFIG_DIR}
+     -DAVM_DIST_DIR=${AVM_DIST_DIR} -DAVM_DIST_APPS="${AVM_DIST_APPS}"
diff --git a/src/codec_avm.c b/src/codec_avm.c
index acf16bf..937ed54 100644
--- a/src/codec_avm.c
+++ b/src/codec_avm.c
@@ -3,28 +3,29 @@
 
 #include "avif/internal.h"
 
-#include "aom/aom_decoder.h"
-#include "aom/aom_encoder.h"
-#include "aom/aomcx.h"
-#include "aom/aomdx.h"
+#include "avm/avm_decoder.h"
+#include "avm/avm_encoder.h"
+#include "avm/avmcx.h"
+#include "avm/avmdx.h"
 
 #include <assert.h>
 #include <limits.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 
 struct avifCodecInternal
 {
     avifBool decoderInitialized;
-    aom_codec_ctx_t decoder;
-    aom_codec_iter_t iter;
-    aom_image_t * image;
+    avm_codec_ctx_t decoder;
+    avm_codec_iter_t iter;
+    avm_image_t * image;
 
     avifBool encoderInitialized;
-    aom_codec_ctx_t encoder;
-    struct aom_codec_enc_cfg cfg;
+    avm_codec_ctx_t encoder;
+    struct avm_codec_enc_cfg cfg;
     avifPixelFormatInfo formatInfo;
-    aom_img_fmt_t aomFormat;
+    avm_img_fmt_t avmFormat;
     avifBool monochromeEnabled;
     // Whether 'tuning' (of the specified distortion metric) was set with an
     // avifEncoderSetCodecSpecificOption(encoder, "tune", value) call.
@@ -35,11 +36,11 @@
 static void avmCodecDestroyInternal(avifCodec * codec)
 {
     if (codec->internal->decoderInitialized) {
-        aom_codec_destroy(&codec->internal->decoder);
+        avm_codec_destroy(&codec->internal->decoder);
     }
 
     if (codec->internal->encoderInitialized) {
-        aom_codec_destroy(&codec->internal->encoder);
+        avm_codec_destroy(&codec->internal->encoder);
     }
 
     avifFree(codec->internal);
@@ -48,8 +49,8 @@
 static avifResult avifCheckCodecVersionAVM()
 {
     // The minimum supported version of avm is the anchor 4.0.0.
-    // aom_codec.h says: aom_codec_version() == (major<<16 | minor<<8 | patch)
-    AVIF_CHECKERR((aom_codec_version() >> 16) >= 4, AVIF_RESULT_NO_CODEC_AVAILABLE);
+    // avm_codec.h says: avm_codec_version() == (major<<16 | minor<<8 | patch)
+    AVIF_CHECKERR((avm_codec_version() >> 16) >= 4, AVIF_RESULT_NO_CODEC_AVAILABLE);
     return AVIF_RESULT_OK;
 }
 
@@ -64,30 +65,30 @@
     if (!codec->internal->decoderInitialized) {
         AVIF_CHECKRES(avifCheckCodecVersionAVM());
 
-        aom_codec_dec_cfg_t cfg;
-        memset(&cfg, 0, sizeof(aom_codec_dec_cfg_t));
+        avm_codec_dec_cfg_t cfg;
+        memset(&cfg, 0, sizeof(avm_codec_dec_cfg_t));
         cfg.threads = codec->maxThreads;
 
-        aom_codec_iface_t * decoder_interface = aom_codec_av1_dx();
-        if (aom_codec_dec_init(&codec->internal->decoder, decoder_interface, &cfg, 0)) {
+        avm_codec_iface_t * decoder_interface = avm_codec_av2_dx();
+        if (avm_codec_dec_init(&codec->internal->decoder, decoder_interface, &cfg, 0)) {
             return AVIF_FALSE;
         }
         codec->internal->decoderInitialized = AVIF_TRUE;
 
-        if (aom_codec_control(&codec->internal->decoder, AV1D_SET_OUTPUT_ALL_LAYERS, codec->allLayers)) {
+        if (avm_codec_control(&codec->internal->decoder, AV2D_SET_OUTPUT_ALL_LAYERS, codec->allLayers)) {
             return AVIF_FALSE;
         }
-        if (aom_codec_control(&codec->internal->decoder, AV1D_SET_OPERATING_POINT, codec->operatingPoint)) {
+        if (avm_codec_control(&codec->internal->decoder, AV2D_SET_OPERATING_POINT, codec->operatingPoint)) {
             return AVIF_FALSE;
         }
 
         codec->internal->iter = NULL;
     }
 
-    aom_image_t * nextFrame = NULL;
+    avm_image_t * nextFrame = NULL;
     uint8_t spatialID = AVIF_SPATIAL_ID_UNSET;
     for (;;) {
-        nextFrame = aom_codec_get_frame(&codec->internal->decoder, &codec->internal->iter);
+        nextFrame = avm_codec_get_frame(&codec->internal->decoder, &codec->internal->iter);
         if (nextFrame) {
             if (spatialID != AVIF_SPATIAL_ID_UNSET) {
                 if (spatialID == nextFrame->mlayer_id) {
@@ -100,7 +101,7 @@
             }
         } else if (sample) {
             codec->internal->iter = NULL;
-            if (aom_codec_decode(&codec->internal->decoder, sample->data.data, sample->data.size, NULL)) {
+            if (avm_codec_decode(&codec->internal->decoder, sample->data.data, sample->data.size, NULL)) {
                 return AVIF_FALSE;
             }
             spatialID = sample->spatialID;
@@ -126,23 +127,23 @@
 
         avifPixelFormat yuvFormat = AVIF_PIXEL_FORMAT_NONE;
         switch (codec->internal->image->fmt) {
-            case AOM_IMG_FMT_I420:
-            case AOM_IMG_FMT_AOMI420:
-            case AOM_IMG_FMT_I42016:
+            case AVM_IMG_FMT_I420:
+            case AVM_IMG_FMT_AVMI420:
+            case AVM_IMG_FMT_I42016:
                 yuvFormat = AVIF_PIXEL_FORMAT_YUV420;
                 break;
-            case AOM_IMG_FMT_I422:
-            case AOM_IMG_FMT_I42216:
+            case AVM_IMG_FMT_I422:
+            case AVM_IMG_FMT_I42216:
                 yuvFormat = AVIF_PIXEL_FORMAT_YUV422;
                 break;
-            case AOM_IMG_FMT_I444:
-            case AOM_IMG_FMT_I44416:
+            case AVM_IMG_FMT_I444:
+            case AVM_IMG_FMT_I44416:
                 yuvFormat = AVIF_PIXEL_FORMAT_YUV444;
                 break;
-            case AOM_IMG_FMT_NONE:
-            case AOM_IMG_FMT_YV12:
-            case AOM_IMG_FMT_AOMYV12:
-            case AOM_IMG_FMT_YV1216:
+            case AVM_IMG_FMT_NONE:
+            case AVM_IMG_FMT_YV12:
+            case AVM_IMG_FMT_AVMYV12:
+            case AVM_IMG_FMT_YV1216:
             default:
                 return AVIF_FALSE;
         }
@@ -162,14 +163,14 @@
         image->depth = codec->internal->image->bit_depth;
 
         image->yuvFormat = yuvFormat;
-        image->yuvRange = (codec->internal->image->range == AOM_CR_STUDIO_RANGE) ? AVIF_RANGE_LIMITED : AVIF_RANGE_FULL;
-        if (codec->internal->image->csp == AOM_CSP_LEFT) {
+        image->yuvRange = (codec->internal->image->range == AVM_CR_STUDIO_RANGE) ? AVIF_RANGE_LIMITED : AVIF_RANGE_FULL;
+        if (codec->internal->image->csp == AVM_CSP_LEFT) {
             // CSP_LEFT: Horizontal offset 0, vertical offset 0.5
             image->yuvChromaSamplePosition = AVIF_CHROMA_SAMPLE_POSITION_VERTICAL;
-        } else if (codec->internal->image->csp == AOM_CSP_CENTER) {
+        } else if (codec->internal->image->csp == AVM_CSP_CENTER) {
             // CSP_CENTER: Horizontal offset 0.5, vertical offset 0.5
             image->yuvChromaSamplePosition = AVIF_CHROMA_SAMPLE_POSITION_UNKNOWN;
-        } else if (codec->internal->image->csp == AOM_CSP_TOPLEFT) {
+        } else if (codec->internal->image->csp == AVM_CSP_TOPLEFT) {
             // CSP_TOPLEFT: Horizontal offset 0, vertical offset 0
             image->yuvChromaSamplePosition = AVIF_CHROMA_SAMPLE_POSITION_COLOCATED;
         } else {
@@ -184,8 +185,8 @@
         int yuvPlaneCount = (yuvFormat == AVIF_PIXEL_FORMAT_YUV400) ? 1 : 3;
 
         // avifImage assumes that a depth of 8 bits means an 8-bit buffer.
-        // aom_image does not. The buffer depth depends on fmt|AOM_IMG_FMT_HIGHBITDEPTH, even for 8-bit values.
-        if (!avifImageUsesU16(image) && (codec->internal->image->fmt & AOM_IMG_FMT_HIGHBITDEPTH)) {
+        // avm_image does not. The buffer depth depends on fmt|AVM_IMG_FMT_HIGHBITDEPTH, even for 8-bit values.
+        if (!avifImageUsesU16(image) && (codec->internal->image->fmt & AVM_IMG_FMT_HIGHBITDEPTH)) {
             AVIF_CHECK(avifImageAllocatePlanes(image, AVIF_PLANES_YUV) == AVIF_RESULT_OK);
             for (int yuvPlane = 0; yuvPlane < yuvPlaneCount; ++yuvPlane) {
                 const uint32_t planeWidth = avifImagePlaneWidth(image, yuvPlane);
@@ -226,7 +227,7 @@
 
         avifImageFreePlanes(image, AVIF_PLANES_A);
 
-        if (!avifImageUsesU16(image) && (codec->internal->image->fmt & AOM_IMG_FMT_HIGHBITDEPTH)) {
+        if (!avifImageUsesU16(image) && (codec->internal->image->fmt & AVM_IMG_FMT_HIGHBITDEPTH)) {
             AVIF_CHECK(avifImageAllocatePlanes(image, AVIF_PLANES_A) == AVIF_RESULT_OK);
             const uint8_t * srcRow = codec->internal->image->planes[0];
             uint8_t * dstRow = image->alphaPlane;
@@ -243,53 +244,53 @@
             image->alphaRowBytes = codec->internal->image->stride[0];
             image->imageOwnsAlphaPlane = AVIF_FALSE;
         }
-        *isLimitedRangeAlpha = (codec->internal->image->range == AOM_CR_STUDIO_RANGE);
+        *isLimitedRangeAlpha = (codec->internal->image->range == AVM_CR_STUDIO_RANGE);
     }
 
     return AVIF_TRUE;
 }
 
-static aom_img_fmt_t avifImageCalcAOMFmt(const avifImage * image, avifBool alpha)
+static avm_img_fmt_t avifImageCalcAVMFmt(const avifImage * image, avifBool alpha)
 {
-    aom_img_fmt_t fmt;
+    avm_img_fmt_t fmt;
     if (alpha) {
         // We're going monochrome, who cares about chroma quality
-        fmt = AOM_IMG_FMT_I420;
+        fmt = AVM_IMG_FMT_I420;
     } else {
         switch (image->yuvFormat) {
             case AVIF_PIXEL_FORMAT_YUV444:
-                fmt = AOM_IMG_FMT_I444;
+                fmt = AVM_IMG_FMT_I444;
                 break;
             case AVIF_PIXEL_FORMAT_YUV422:
-                fmt = AOM_IMG_FMT_I422;
+                fmt = AVM_IMG_FMT_I422;
                 break;
             case AVIF_PIXEL_FORMAT_YUV420:
             case AVIF_PIXEL_FORMAT_YUV400:
-                fmt = AOM_IMG_FMT_I420;
+                fmt = AVM_IMG_FMT_I420;
                 break;
             case AVIF_PIXEL_FORMAT_NONE:
             case AVIF_PIXEL_FORMAT_COUNT:
             default:
-                return AOM_IMG_FMT_NONE;
+                return AVM_IMG_FMT_NONE;
         }
     }
 
     if (image->depth > 8) {
-        fmt |= AOM_IMG_FMT_HIGHBITDEPTH;
+        fmt |= AVM_IMG_FMT_HIGHBITDEPTH;
     }
 
     return fmt;
 }
 
-struct aomOptionEnumList
+struct avmOptionEnumList
 {
     const char * name;
     int val;
 };
 
-static avifBool aomOptionParseEnum(const char * str, const struct aomOptionEnumList * enums, int * val)
+static avifBool avmOptionParseEnum(const char * str, const struct avmOptionEnumList * enums, int * val)
 {
-    const struct aomOptionEnumList * listptr;
+    const struct avmOptionEnumList * listptr;
     long int rawval;
     char * endptr;
 
@@ -315,11 +316,11 @@
     return AVIF_FALSE;
 }
 
-static const struct aomOptionEnumList endUsageEnum[] = { //
-    { "vbr", AOM_VBR },                                  // Variable Bit Rate (VBR) mode
-    { "cbr", AOM_CBR },                                  // Constant Bit Rate (CBR) mode
-    { "cq", AOM_CQ },                                    // Constrained Quality (CQ) mode
-    { "q", AOM_Q },                                      // Constant Quality (Q) mode
+static const struct avmOptionEnumList endUsageEnum[] = { //
+    { "vbr", AVM_VBR },                                  // Variable Bit Rate (VBR) mode
+    { "cbr", AVM_CBR },                                  // Constant Bit Rate (CBR) mode
+    { "cq", AVM_CQ },                                    // Constrained Quality (CQ) mode
+    { "q", AVM_Q },                                      // Constant Quality (Q) mode
     { NULL, 0 }
 };
 
@@ -335,13 +336,13 @@
            (!strncmp(key, shortPrefix, shortPrefixLen) && !strcmp(key + shortPrefixLen, name));
 }
 
-static avifBool avifProcessAOMOptionsPreInit(avifCodec * codec, avifBool alpha, struct aom_codec_enc_cfg * cfg)
+static avifBool avifProcessAVMOptionsPreInit(avifCodec * codec, avifBool alpha, struct avm_codec_enc_cfg * cfg)
 {
     for (uint32_t i = 0; i < codec->csOptions->count; ++i) {
         avifCodecSpecificOption * entry = &codec->csOptions->entries[i];
         int val;
         if (avifKeyEqualsName(entry->key, "end-usage", alpha)) { // Rate control mode
-            if (!aomOptionParseEnum(entry->value, endUsageEnum, &val)) {
+            if (!avmOptionParseEnum(entry->value, endUsageEnum, &val)) {
                 avifDiagnosticsPrintf(codec->diag, "Invalid value for end-usage: %s", entry->value);
                 return AVIF_FALSE;
             }
@@ -351,7 +352,7 @@
     return AVIF_TRUE;
 }
 
-static avifBool avifProcessAOMOptionsPostInit(avifCodec * codec, avifBool alpha)
+static avifBool avifProcessAVMOptionsPostInit(avifCodec * codec, avifBool alpha)
 {
     for (uint32_t i = 0; i < codec->csOptions->count; ++i) {
         avifCodecSpecificOption * entry = &codec->csOptions->entries[i];
@@ -364,7 +365,7 @@
             continue;
         }
 
-        // Skip options processed by avifProcessAOMOptionsPreInit.
+        // Skip options processed by avifProcessAVMOptionsPreInit.
         if (avifKeyEqualsName(entry->key, "end-usage", alpha)) {
             continue;
         }
@@ -379,13 +380,13 @@
         } else if (!strncmp(key, shortPrefix, shortPrefixLen)) {
             key += shortPrefixLen;
         }
-        if (aom_codec_set_option(&codec->internal->encoder, key, entry->value) != AOM_CODEC_OK) {
+        if (avm_codec_set_option(&codec->internal->encoder, key, entry->value) != AVM_CODEC_OK) {
             avifDiagnosticsPrintf(codec->diag,
-                                  "aom_codec_set_option(\"%s\", \"%s\") failed: %s: %s",
+                                  "avm_codec_set_option(\"%s\", \"%s\") failed: %s: %s",
                                   key,
                                   entry->value,
-                                  aom_codec_error(&codec->internal->encoder),
-                                  aom_codec_error_detail(&codec->internal->encoder));
+                                  avm_codec_error(&codec->internal->encoder),
+                                  avm_codec_error_detail(&codec->internal->encoder));
             return AVIF_FALSE;
         }
         if (!strcmp(key, "tune")) {
@@ -395,26 +396,26 @@
     return AVIF_TRUE;
 }
 
-struct aomScalingModeMapList
+struct avmScalingModeMapList
 {
     avifFraction avifMode;
-    AOM_SCALING_MODE aomMode;
+    AVM_SCALING_MODE avmMode;
 };
 
-static const struct aomScalingModeMapList scalingModeMap[] = {
-    { { 1, 1 }, AOME_NORMAL },    { { 1, 2 }, AOME_ONETWO },    { { 1, 4 }, AOME_ONEFOUR },  { { 1, 8 }, AOME_ONEEIGHT },
-    { { 3, 4 }, AOME_THREEFOUR }, { { 3, 5 }, AOME_THREEFIVE }, { { 4, 5 }, AOME_FOURFIVE },
+static const struct avmScalingModeMapList scalingModeMap[] = {
+    { { 1, 1 }, AVME_NORMAL },    { { 1, 2 }, AVME_ONETWO },    { { 1, 4 }, AVME_ONEFOUR },  { { 1, 8 }, AVME_ONEEIGHT },
+    { { 3, 4 }, AVME_THREEFOUR }, { { 3, 5 }, AVME_THREEFIVE }, { { 4, 5 }, AVME_FOURFIVE },
 };
 
 static const int scalingModeMapSize = sizeof(scalingModeMap) / sizeof(scalingModeMap[0]);
 
-static avifBool avifFindAOMScalingMode(const avifFraction * avifMode, AOM_SCALING_MODE * aomMode)
+static avifBool avifFindAVMScalingMode(const avifFraction * avifMode, AVM_SCALING_MODE * avmMode)
 {
     avifFraction simplifiedFraction = *avifMode;
     avifFractionSimplify(&simplifiedFraction);
     for (int i = 0; i < scalingModeMapSize; ++i) {
         if (scalingModeMap[i].avifMode.n == simplifiedFraction.n && scalingModeMap[i].avifMode.d == simplifiedFraction.d) {
-            *aomMode = scalingModeMap[i].aomMode;
+            *avmMode = scalingModeMap[i].avmMode;
             return AVIF_TRUE;
         }
     }
@@ -424,7 +425,7 @@
 
 // Scales from aom's [0:63] to avm's [M:255], where M=0/-48/-96 for 8/10/12 bit.
 // See --min-qp help in
-// https://gitlab.com/AOMediaCodec/avm/-/blob/main/apps/aomenc.c
+// https://gitlab.com/AOMediaCodec/avm/-/blob/main/apps/avmenc.c
 static int avmScaleQuantizer(int quantizer, uint32_t depth)
 {
     if (depth == 10) {
@@ -439,7 +440,7 @@
 
 // Converts quality to avm's quantizer in the range of [M:255], where M=0/-48/-96 for 8/10/12 bit.
 // See --min-qp help in
-// https://gitlab.com/AOMediaCodec/avm/-/blob/main/apps/aomenc.c
+// https://gitlab.com/AOMediaCodec/avm/-/blob/main/apps/avmenc.c
 static int avmQualityToQuantizer(int quality, uint32_t depth)
 {
     if (depth == 10) {
@@ -466,7 +467,7 @@
                                       avifAddImageFlags addImageFlags,
                                       avifCodecEncodeOutput * output)
 {
-    struct aom_codec_enc_cfg * cfg = &codec->internal->cfg;
+    struct avm_codec_enc_cfg * cfg = &codec->internal->cfg;
     avifBool quantizerUpdated = AVIF_FALSE;
     const int quantizer = avmQualityToQuantizer(quality, image->depth);
 
@@ -478,28 +479,28 @@
     if (!codec->internal->encoderInitialized) {
         AVIF_CHECKRES(avifCheckCodecVersionAVM());
 
-        int aomCpuUsed = -1;
+        int avmCpuUsed = -1;
         if (encoder->speed != AVIF_SPEED_DEFAULT) {
-            aomCpuUsed = AVIF_CLAMP(encoder->speed, 0, 9);
+            avmCpuUsed = AVIF_CLAMP(encoder->speed, 0, 9);
         }
 
-        codec->internal->aomFormat = avifImageCalcAOMFmt(image, alpha);
-        if (codec->internal->aomFormat == AOM_IMG_FMT_NONE) {
+        codec->internal->avmFormat = avifImageCalcAVMFmt(image, alpha);
+        if (codec->internal->avmFormat == AVM_IMG_FMT_NONE) {
             return AVIF_RESULT_UNKNOWN_ERROR;
         }
 
         avifGetPixelFormatInfo(image->yuvFormat, &codec->internal->formatInfo);
 
-        aom_codec_iface_t * encoderInterface = aom_codec_av1_cx();
-        aom_codec_err_t err = aom_codec_enc_config_default(encoderInterface, cfg, AOM_USAGE_GOOD_QUALITY);
-        if (err != AOM_CODEC_OK) {
-            avifDiagnosticsPrintf(codec->diag, "aom_codec_enc_config_default() failed: %s", aom_codec_err_to_string(err));
+        avm_codec_iface_t * encoderInterface = avm_codec_av2_cx();
+        avm_codec_err_t err = avm_codec_enc_config_default(encoderInterface, cfg, AVM_USAGE_GOOD_QUALITY);
+        if (err != AVM_CODEC_OK) {
+            avifDiagnosticsPrintf(codec->diag, "avm_codec_enc_config_default() failed: %s", avm_codec_err_to_string(err));
             return AVIF_RESULT_UNKNOWN_ERROR;
         }
 
-        // avm's default is AOM_VBR. Change the default to AOM_Q since we don't need to hit a certain target bit rate.
+        // avm's default is AVM_VBR. Change the default to AVM_Q since we don't need to hit a certain target bit rate.
         // It's easier to control the worst quality in Q mode.
-        cfg->rc_end_usage = AOM_Q;
+        cfg->rc_end_usage = AVM_Q;
 
         // Profile 0.  8-bit and 10-bit 4:2:0 and 4:0:0 only.
         // Profile 1.  8-bit and 10-bit 4:4:4
@@ -544,10 +545,10 @@
         if (addImageFlags & AVIF_ADD_IMAGE_FLAG_SINGLE) {
             // Set the maximum number of frames to encode to 1. This instructs
             // libavm to set still_picture and reduced_still_picture_header to
-            // 1 in AV1 sequence headers.
+            // 1 in AV2 sequence headers.
             cfg->g_limit = 1;
 
-            // Use the default settings of the new AOM_USAGE_ALL_INTRA (added in
+            // Use the default settings of the new AVM_USAGE_ALL_INTRA (added in
             // https://crbug.com/aomedia/2959).
             //
             // Set g_lag_in_frames to 0 to reduce the number of frame buffers
@@ -555,7 +556,7 @@
             // memory consumption when encoding a single image.
             cfg->g_lag_in_frames = 0;
             // Disable automatic placement of key frames by the encoder.
-            cfg->kf_mode = AOM_KF_DISABLED;
+            cfg->kf_mode = AVM_KF_DISABLED;
             // Tell libavm that all frames will be key frames.
             cfg->kf_max_dist = 0;
         }
@@ -570,7 +571,7 @@
         }
         if (encoder->maxThreads > 1) {
             // libavm fails if cfg->g_threads is greater than 64 threads. See MAX_NUM_THREADS in
-            // avm/aom_util/aom_thread.h.
+            // avm/avm_util/avm_thread.h.
             cfg->g_threads = AVIF_MIN(encoder->maxThreads, 64);
         }
 
@@ -580,7 +581,7 @@
             cfg->monochrome = 1;
         }
 
-        if (!avifProcessAOMOptionsPreInit(codec, alpha, cfg)) {
+        if (!avifProcessAVMOptionsPreInit(codec, alpha, cfg)) {
             return AVIF_RESULT_INVALID_CODEC_SPECIFIC_OPTION;
         }
 
@@ -595,7 +596,7 @@
         }
         minQuantizer = avmScaleQuantizer(minQuantizer, image->depth);
         maxQuantizer = avmScaleQuantizer(maxQuantizer, image->depth);
-        if ((cfg->rc_end_usage == AOM_VBR) || (cfg->rc_end_usage == AOM_CBR)) {
+        if ((cfg->rc_end_usage == AVM_VBR) || (cfg->rc_end_usage == AVM_CBR)) {
             // cq-level is ignored in these two end-usage modes, so adjust minQuantizer and
             // maxQuantizer to the target quantizer.
             if (quantizer == AVIF_QUANTIZER_LOSSLESS) {
@@ -610,39 +611,39 @@
         cfg->rc_max_quantizer = maxQuantizer;
         quantizerUpdated = AVIF_TRUE;
 
-        if (aom_codec_enc_init(&codec->internal->encoder, encoderInterface, cfg, /*flags=*/0) != AOM_CODEC_OK) {
+        if (avm_codec_enc_init(&codec->internal->encoder, encoderInterface, cfg, /*flags=*/0) != AVM_CODEC_OK) {
             avifDiagnosticsPrintf(codec->diag,
-                                  "aom_codec_enc_init() failed: %s: %s",
-                                  aom_codec_error(&codec->internal->encoder),
-                                  aom_codec_error_detail(&codec->internal->encoder));
+                                  "avm_codec_enc_init() failed: %s: %s",
+                                  avm_codec_error(&codec->internal->encoder),
+                                  avm_codec_error_detail(&codec->internal->encoder));
             return AVIF_RESULT_UNKNOWN_ERROR;
         }
         codec->internal->encoderInitialized = AVIF_TRUE;
 
-        if ((cfg->rc_end_usage == AOM_CQ) || (cfg->rc_end_usage == AOM_Q)) {
-            aom_codec_control(&codec->internal->encoder, AOME_SET_QP, quantizer);
+        if ((cfg->rc_end_usage == AVM_CQ) || (cfg->rc_end_usage == AVM_Q)) {
+            avm_codec_control(&codec->internal->encoder, AVME_SET_QP, quantizer);
         }
         avifBool lossless = (quantizer == AVIF_QUANTIZER_LOSSLESS);
         if (lossless) {
-            aom_codec_control(&codec->internal->encoder, AV1E_SET_LOSSLESS, 1);
+            avm_codec_control(&codec->internal->encoder, AV2E_SET_LOSSLESS, 1);
         }
         if (encoder->maxThreads > 1) {
-            aom_codec_control(&codec->internal->encoder, AV1E_SET_ROW_MT, 1);
+            avm_codec_control(&codec->internal->encoder, AV2E_SET_ROW_MT, 1);
         }
         if (tileRowsLog2 != 0) {
-            aom_codec_control(&codec->internal->encoder, AV1E_SET_TILE_ROWS, tileRowsLog2);
+            avm_codec_control(&codec->internal->encoder, AV2E_SET_TILE_ROWS, tileRowsLog2);
         }
         if (tileColsLog2 != 0) {
-            aom_codec_control(&codec->internal->encoder, AV1E_SET_TILE_COLUMNS, tileColsLog2);
+            avm_codec_control(&codec->internal->encoder, AV2E_SET_TILE_COLUMNS, tileColsLog2);
         }
         if (encoder->extraLayerCount > 0) {
             int layerCount = encoder->extraLayerCount + 1;
-            if (aom_codec_control(&codec->internal->encoder, AOME_SET_NUMBER_MLAYERS, layerCount) != AOM_CODEC_OK) {
+            if (avm_codec_control(&codec->internal->encoder, AVME_SET_NUMBER_MLAYERS, layerCount) != AVM_CODEC_OK) {
                 return AVIF_RESULT_UNKNOWN_ERROR;
             }
         }
-        if (aomCpuUsed != -1) {
-            if (aom_codec_control(&codec->internal->encoder, AOME_SET_CPUUSED, aomCpuUsed) != AOM_CODEC_OK) {
+        if (avmCpuUsed != -1) {
+            if (avm_codec_control(&codec->internal->encoder, AVME_SET_CPUUSED, avmCpuUsed) != AVM_CODEC_OK) {
                 return AVIF_RESULT_UNKNOWN_ERROR;
             }
         }
@@ -651,51 +652,49 @@
         if (alpha) {
             // AV1-AVIF specification, Section 4 "Auxiliary Image Items and Sequences":
             //   The color_range field in the Sequence Header OBU shall be set to 1.
-            aom_codec_control(&codec->internal->encoder, AV1E_SET_COLOR_RANGE, AOM_CR_FULL_RANGE);
+            avm_codec_control(&codec->internal->encoder, AV2E_SET_COLOR_RANGE, AVM_CR_FULL_RANGE);
 
-            // Keep the default AOM_CSP_UNKNOWN value.
+            // Keep the default AVM_CSP_UNKNOWN value.
 
             // CICP (CP/TC/MC) does not apply to the alpha auxiliary image.
             // Keep default Unspecified (2) colour primaries, transfer characteristics,
             // and matrix coefficients.
         } else {
-            // libaom's defaults are AOM_CSP_UNKNOWN and 0 (studio/limited range).
-            // Call aom_codec_control() only if the values are not the defaults.
+            // libavm's defaults are AVM_CSP_UNKNOWN and 0 (studio/limited range).
+            // Call avm_codec_control() only if the values are not the defaults.
 
             // AV1-AVIF specification, Section 2.2.1. "AV1 Item Configuration Property":
             //   The values of the fields in the AV1CodecConfigurationBox shall match those
             //   of the Sequence Header OBU in the AV1 Image Item Data.
             if (image->yuvChromaSamplePosition != AVIF_CHROMA_SAMPLE_POSITION_UNKNOWN) {
-                aom_codec_control(&codec->internal->encoder, AV1E_SET_CHROMA_SAMPLE_POSITION, (int)image->yuvChromaSamplePosition);
+                avm_codec_control(&codec->internal->encoder, AV2E_SET_CHROMA_SAMPLE_POSITION, (int)image->yuvChromaSamplePosition);
             }
 
             // AV1-ISOBMFF specification, Section 2.3.4:
             //   The value of full_range_flag in the 'colr' box SHALL match the color_range
             //   flag in the Sequence Header OBU.
             if (image->yuvRange != AVIF_RANGE_LIMITED) {
-                aom_codec_control(&codec->internal->encoder, AV1E_SET_COLOR_RANGE, (int)image->yuvRange);
+                avm_codec_control(&codec->internal->encoder, AV2E_SET_COLOR_RANGE, (int)image->yuvRange);
             }
 
             // Section 2.3.4 of AV1-ISOBMFF says 'colr' with 'nclx' should be present and shall match CICP
             // values in the Sequence Header OBU, unless the latter has 2/2/2 (Unspecified).
             // So set CICP values to 2/2/2 (Unspecified) in the Sequence Header OBU for simplicity.
-            // It may also save 3 bytes since the AV1 encoder can set color_description_present_flag to 0
-            // (see Section 5.5.2 "Color config syntax" of the AV1 specification).
-            // libaom's defaults are AOM_CICP_CP_UNSPECIFIED, AOM_CICP_TC_UNSPECIFIED, and
-            // AOM_CICP_MC_UNSPECIFIED. No need to call aom_codec_control().
-            // aom_image_t::cp, aom_image_t::tc and aom_image_t::mc are ignored by aom_codec_encode().
+            // libavm's defaults are AVM_CICP_CP_UNSPECIFIED, AVM_CICP_TC_UNSPECIFIED, and
+            // AVM_CICP_MC_UNSPECIFIED. No need to call avm_codec_control().
+            // avm_image_t::cp, avm_image_t::tc and avm_image_t::mc are ignored by avm_codec_encode().
         }
 
-        if (!avifProcessAOMOptionsPostInit(codec, alpha)) {
+        if (!avifProcessAVMOptionsPostInit(codec, alpha)) {
             return AVIF_RESULT_INVALID_CODEC_SPECIFIC_OPTION;
         }
         // Disabling these two gives 1.19% PSNR YUV loss in All-Intra config, but encode will be ~4X faster.
-        if (aom_codec_set_option(&codec->internal->encoder, "enable-ext-partitions", "0") != AOM_CODEC_OK ||
-            aom_codec_set_option(&codec->internal->encoder, "enable-uneven-4way-partitions", "0") != AOM_CODEC_OK) {
+        if (avm_codec_set_option(&codec->internal->encoder, "enable-ext-partitions", "0") != AVM_CODEC_OK ||
+            avm_codec_set_option(&codec->internal->encoder, "enable-uneven-4way-partitions", "0") != AVM_CODEC_OK) {
             return AVIF_RESULT_UNKNOWN_ERROR;
         }
         if (!codec->internal->tuningSet) {
-            if (aom_codec_control(&codec->internal->encoder, AOME_SET_TUNING, AOM_TUNE_SSIM) != AOM_CODEC_OK) {
+            if (avm_codec_control(&codec->internal->encoder, AVME_SET_TUNING, AVM_TUNE_SSIM) != AVM_CODEC_OK) {
                 return AVIF_RESULT_UNKNOWN_ERROR;
             }
         }
@@ -720,7 +719,7 @@
         }
         const int qualityChangedBit = alpha ? AVIF_ENCODER_CHANGE_QUALITY_ALPHA : AVIF_ENCODER_CHANGE_QUALITY;
         if (encoderChanges & qualityChangedBit) {
-            if ((cfg->rc_end_usage == AOM_VBR) || (cfg->rc_end_usage == AOM_CBR)) {
+            if ((cfg->rc_end_usage == AVM_VBR) || (cfg->rc_end_usage == AVM_CBR)) {
                 // cq-level is ignored in these two end-usage modes, so adjust minQuantizer and
                 // maxQuantizer to the target quantizer.
                 if (quantizer == AVIF_QUANTIZER_LOSSLESS) {
@@ -745,30 +744,30 @@
             }
         }
         if (quantizerUpdated || dimensionsChanged) {
-            aom_codec_err_t err = aom_codec_enc_config_set(&codec->internal->encoder, cfg);
-            if (err != AOM_CODEC_OK) {
+            avm_codec_err_t err = avm_codec_enc_config_set(&codec->internal->encoder, cfg);
+            if (err != AVM_CODEC_OK) {
                 avifDiagnosticsPrintf(codec->diag,
-                                      "aom_codec_enc_config_set() failed: %s: %s",
-                                      aom_codec_error(&codec->internal->encoder),
-                                      aom_codec_error_detail(&codec->internal->encoder));
+                                      "avm_codec_enc_config_set() failed: %s: %s",
+                                      avm_codec_error(&codec->internal->encoder),
+                                      avm_codec_error_detail(&codec->internal->encoder));
                 return AVIF_RESULT_UNKNOWN_ERROR;
             }
         }
         if (encoderChanges & AVIF_ENCODER_CHANGE_TILE_ROWS_LOG2) {
-            aom_codec_control(&codec->internal->encoder, AV1E_SET_TILE_ROWS, tileRowsLog2);
+            avm_codec_control(&codec->internal->encoder, AV2E_SET_TILE_ROWS, tileRowsLog2);
         }
         if (encoderChanges & AVIF_ENCODER_CHANGE_TILE_COLS_LOG2) {
-            aom_codec_control(&codec->internal->encoder, AV1E_SET_TILE_COLUMNS, tileColsLog2);
+            avm_codec_control(&codec->internal->encoder, AV2E_SET_TILE_COLUMNS, tileColsLog2);
         }
         if (encoderChanges & qualityChangedBit) {
-            if ((cfg->rc_end_usage == AOM_CQ) || (cfg->rc_end_usage == AOM_Q)) {
-                aom_codec_control(&codec->internal->encoder, AOME_SET_QP, quantizer);
+            if ((cfg->rc_end_usage == AVM_CQ) || (cfg->rc_end_usage == AVM_Q)) {
+                avm_codec_control(&codec->internal->encoder, AVME_SET_QP, quantizer);
             }
             avifBool lossless = (quantizer == AVIF_QUANTIZER_LOSSLESS);
-            aom_codec_control(&codec->internal->encoder, AV1E_SET_LOSSLESS, lossless);
+            avm_codec_control(&codec->internal->encoder, AV2E_SET_LOSSLESS, lossless);
         }
         if (encoderChanges & AVIF_ENCODER_CHANGE_CODEC_SPECIFIC) {
-            if (!avifProcessAOMOptionsPostInit(codec, alpha)) {
+            if (!avifProcessAVMOptionsPostInit(codec, alpha)) {
                 return AVIF_RESULT_INVALID_CODEC_SPECIFIC_OPTION;
             }
         }
@@ -782,27 +781,27 @@
         return AVIF_RESULT_INVALID_ARGUMENT;
     }
     if (encoder->extraLayerCount > 0) {
-        aom_codec_control(&codec->internal->encoder, AOME_SET_MLAYER_ID, codec->internal->currentLayer);
+        avm_codec_control(&codec->internal->encoder, AVME_SET_MLAYER_ID, codec->internal->currentLayer);
     }
 
-    aom_scaling_mode_t aomScalingMode;
-    if (!avifFindAOMScalingMode(&encoder->scalingMode.horizontal, &aomScalingMode.h_scaling_mode)) {
+    avm_scaling_mode_t avmScalingMode;
+    if (!avifFindAVMScalingMode(&encoder->scalingMode.horizontal, &avmScalingMode.h_scaling_mode)) {
         return AVIF_RESULT_NOT_IMPLEMENTED;
     }
-    if (!avifFindAOMScalingMode(&encoder->scalingMode.vertical, &aomScalingMode.v_scaling_mode)) {
+    if (!avifFindAVMScalingMode(&encoder->scalingMode.vertical, &avmScalingMode.v_scaling_mode)) {
         return AVIF_RESULT_NOT_IMPLEMENTED;
     }
-    if ((aomScalingMode.h_scaling_mode != AOME_NORMAL) || (aomScalingMode.v_scaling_mode != AOME_NORMAL)) {
-        // AOME_SET_SCALEMODE only applies to next frame (layer), so we have to set it every time.
-        aom_codec_control(&codec->internal->encoder, AOME_SET_SCALEMODE, &aomScalingMode);
+    if ((avmScalingMode.h_scaling_mode != AVME_NORMAL) || (avmScalingMode.v_scaling_mode != AVME_NORMAL)) {
+        // AVME_SET_SCALEMODE only applies to next frame (layer), so we have to set it every time.
+        avm_codec_control(&codec->internal->encoder, AVME_SET_SCALEMODE, &avmScalingMode);
     }
 
-    aom_image_t aomImage;
-    // We prefer to simply set the aomImage.planes[] pointers to the plane buffers in 'image'. When
-    // doing this, we set aomImage.w equal to aomImage.d_w and aomImage.h equal to aomImage.d_h and
-    // do not "align" aomImage.w and aomImage.h. Unfortunately this exposes a libaom bug in libavm
+    avm_image_t avmImage;
+    // We prefer to simply set the avmImage.planes[] pointers to the plane buffers in 'image'. When
+    // doing this, we set avmImage.w equal to avmImage.d_w and avmImage.h equal to avmImage.d_h and
+    // do not "align" avmImage.w and avmImage.h. Unfortunately this exposes a libaom bug in libavm
     // (https://crbug.com/aomedia/3113) if chroma is subsampled and image->width or image->height is
-    // equal to 1. To work around this libavm bug, we allocate the aomImage.planes[] buffers and
+    // equal to 1. To work around this libavm bug, we allocate the avmImage.planes[] buffers and
     // copy the image YUV data if image->width or image->height is equal to 1. This bug has been
     // fixed in libaom v3.1.3 but not in libavm.
     //
@@ -811,38 +810,38 @@
     //   ((image->height == 1) && (chroma is subsampled vertically))
     // Since an image width or height of 1 is uncommon in practice, we test an inexact but simpler
     // condition.
-    avifBool aomImageAllocated = (image->width == 1) || (image->height == 1);
-    if (aomImageAllocated) {
-        aom_img_alloc(&aomImage, codec->internal->aomFormat, image->width, image->height, 16);
+    avifBool avmImageAllocated = (image->width == 1) || (image->height == 1);
+    if (avmImageAllocated) {
+        avm_img_alloc(&avmImage, codec->internal->avmFormat, image->width, image->height, 16);
     } else {
-        memset(&aomImage, 0, sizeof(aomImage));
-        aomImage.fmt = codec->internal->aomFormat;
-        aomImage.bit_depth = (image->depth > 8) ? 16 : 8;
-        aomImage.w = image->width;
-        aomImage.h = image->height;
-        aomImage.d_w = image->width;
-        aomImage.d_h = image->height;
+        memset(&avmImage, 0, sizeof(avmImage));
+        avmImage.fmt = codec->internal->avmFormat;
+        avmImage.bit_depth = (image->depth > 8) ? 16 : 8;
+        avmImage.w = image->width;
+        avmImage.h = image->height;
+        avmImage.d_w = image->width;
+        avmImage.d_h = image->height;
         // Get sample size for this format.
         unsigned int bps;
-        if (codec->internal->aomFormat == AOM_IMG_FMT_I420) {
+        if (codec->internal->avmFormat == AVM_IMG_FMT_I420) {
             bps = 12;
-        } else if (codec->internal->aomFormat == AOM_IMG_FMT_I422) {
+        } else if (codec->internal->avmFormat == AVM_IMG_FMT_I422) {
             bps = 16;
-        } else if (codec->internal->aomFormat == AOM_IMG_FMT_I444) {
+        } else if (codec->internal->avmFormat == AVM_IMG_FMT_I444) {
             bps = 24;
-        } else if (codec->internal->aomFormat == AOM_IMG_FMT_I42016) {
+        } else if (codec->internal->avmFormat == AVM_IMG_FMT_I42016) {
             bps = 24;
-        } else if (codec->internal->aomFormat == AOM_IMG_FMT_I42216) {
+        } else if (codec->internal->avmFormat == AVM_IMG_FMT_I42216) {
             bps = 32;
-        } else if (codec->internal->aomFormat == AOM_IMG_FMT_I44416) {
+        } else if (codec->internal->avmFormat == AVM_IMG_FMT_I44416) {
             bps = 48;
         } else {
             bps = 16;
         }
-        aomImage.bps = bps;
-        // See avifImageCalcAOMFmt(). libavm doesn't have AOM_IMG_FMT_I400, so we use AOM_IMG_FMT_I420 as a substitute for monochrome.
-        aomImage.x_chroma_shift = (alpha || codec->internal->formatInfo.monochrome) ? 1 : codec->internal->formatInfo.chromaShiftX;
-        aomImage.y_chroma_shift = (alpha || codec->internal->formatInfo.monochrome) ? 1 : codec->internal->formatInfo.chromaShiftY;
+        avmImage.bps = bps;
+        // See avifImageCalcAVMFmt(). libavm doesn't have AVM_IMG_FMT_I400, so we use AVM_IMG_FMT_I420 as a substitute for monochrome.
+        avmImage.x_chroma_shift = (alpha || codec->internal->formatInfo.monochrome) ? 1 : codec->internal->formatInfo.chromaShiftX;
+        avmImage.y_chroma_shift = (alpha || codec->internal->formatInfo.monochrome) ? 1 : codec->internal->formatInfo.chromaShiftY;
     }
 
     avifBool monochromeRequested = AVIF_FALSE;
@@ -850,32 +849,32 @@
     if (alpha) {
         // AV1-AVIF specification, Section 4 "Auxiliary Image Items and Sequences":
         //   The color_range field in the Sequence Header OBU shall be set to 1.
-        aomImage.range = AOM_CR_FULL_RANGE;
+        avmImage.range = AVM_CR_FULL_RANGE;
 
         // AV1-AVIF specification, Section 4 "Auxiliary Image Items and Sequences":
         //   The mono_chrome field in the Sequence Header OBU shall be set to 1.
         // Some encoders do not support 4:0:0 and encode alpha as 4:2:0 so it is not always respected.
         monochromeRequested = AVIF_TRUE;
-        if (aomImageAllocated) {
+        if (avmImageAllocated) {
             const uint32_t bytesPerRow = ((image->depth > 8) ? 2 : 1) * image->width;
             for (uint32_t j = 0; j < image->height; ++j) {
                 const uint8_t * srcAlphaRow = &image->alphaPlane[j * image->alphaRowBytes];
-                uint8_t * dstAlphaRow = &aomImage.planes[0][j * aomImage.stride[0]];
+                uint8_t * dstAlphaRow = &avmImage.planes[0][j * avmImage.stride[0]];
                 memcpy(dstAlphaRow, srcAlphaRow, bytesPerRow);
             }
         } else {
-            aomImage.planes[0] = image->alphaPlane;
-            aomImage.stride[0] = image->alphaRowBytes;
+            avmImage.planes[0] = image->alphaPlane;
+            avmImage.stride[0] = image->alphaRowBytes;
         }
 
-        // Ignore UV planes when monochrome. Keep the default AOM_CSP_UNKNOWN value.
+        // Ignore UV planes when monochrome. Keep the default AVM_CSP_UNKNOWN value.
     } else {
         int yuvPlaneCount = 3;
         if (image->yuvFormat == AVIF_PIXEL_FORMAT_YUV400) {
             yuvPlaneCount = 1; // Ignore UV planes when monochrome
             monochromeRequested = AVIF_TRUE;
         }
-        if (aomImageAllocated) {
+        if (avmImageAllocated) {
             uint32_t bytesPerPixel = (image->depth > 8) ? 2 : 1;
             for (int yuvPlane = 0; yuvPlane < yuvPlaneCount; ++yuvPlane) {
                 uint32_t planeWidth = avifImagePlaneWidth(image, yuvPlane);
@@ -884,14 +883,14 @@
 
                 for (uint32_t j = 0; j < planeHeight; ++j) {
                     const uint8_t * srcRow = &image->yuvPlanes[yuvPlane][j * image->yuvRowBytes[yuvPlane]];
-                    uint8_t * dstRow = &aomImage.planes[yuvPlane][j * aomImage.stride[yuvPlane]];
+                    uint8_t * dstRow = &avmImage.planes[yuvPlane][j * avmImage.stride[yuvPlane]];
                     memcpy(dstRow, srcRow, bytesPerRow);
                 }
             }
         } else {
             for (int yuvPlane = 0; yuvPlane < yuvPlaneCount; ++yuvPlane) {
-                aomImage.planes[yuvPlane] = image->yuvPlanes[yuvPlane];
-                aomImage.stride[yuvPlane] = image->yuvRowBytes[yuvPlane];
+                avmImage.planes[yuvPlane] = image->yuvPlanes[yuvPlane];
+                avmImage.stride[yuvPlane] = image->yuvRowBytes[yuvPlane];
             }
         }
 
@@ -900,95 +899,95 @@
         //   of the Sequence Header OBU in the AV1 Image Item Data.
         if (image->yuvChromaSamplePosition == AVIF_CHROMA_SAMPLE_POSITION_VERTICAL) {
             // CSP_LEFT: Horizontal offset 0, vertical offset 0.5
-            aomImage.csp = AOM_CSP_LEFT;
+            avmImage.csp = AVM_CSP_LEFT;
         } else if (image->yuvChromaSamplePosition == AVIF_CHROMA_SAMPLE_POSITION_COLOCATED) {
             // CSP_TOPLEFT: Horizontal offset 0, vertical offset 0
-            aomImage.csp = AOM_CSP_TOPLEFT;
+            avmImage.csp = AVM_CSP_TOPLEFT;
         } else if (image->yuvChromaSamplePosition == AVIF_CHROMA_SAMPLE_POSITION_RESERVED) {
             // CSP_CENTER: Horizontal offset 0.5, vertical offset 0.5
-            aomImage.csp = AOM_CSP_CENTER;
+            avmImage.csp = AVM_CSP_CENTER;
         } else { // AVIF_CHROMA_SAMPLE_POSITION_UNKNOWN or invalid values
-            aomImage.csp = AOM_CSP_UNSPECIFIED;
+            avmImage.csp = AVM_CSP_UNSPECIFIED;
         }
 
         // AV1-ISOBMFF specification, Section 2.3.4:
         //   The value of full_range_flag in the 'colr' box SHALL match the color_range
         //   flag in the Sequence Header OBU.
-        aomImage.range = (aom_color_range_t)image->yuvRange;
+        avmImage.range = (avm_color_range_t)image->yuvRange;
     }
 
     unsigned char * monoUVPlane = NULL;
     if (monochromeRequested) {
         if (codec->internal->monochromeEnabled) {
-            aomImage.monochrome = 1;
+            avmImage.monochrome = 1;
         } else {
             // The user requested monochrome (via alpha or YUV400) but libavm does not support
             // monochrome. Manually set UV planes to 0.5.
 
-            // aomImage is always 420 when we're monochrome
+            // avmImage is always 420 when we're monochrome
             uint32_t monoUVWidth = (image->width + 1) >> 1;
             uint32_t monoUVHeight = (image->height + 1) >> 1;
 
             // Allocate the U plane if necessary.
-            if (!aomImageAllocated) {
+            if (!avmImageAllocated) {
                 uint32_t channelSize = avifImageUsesU16(image) ? 2 : 1;
                 uint32_t monoUVRowBytes = channelSize * monoUVWidth;
                 size_t monoUVSize = (size_t)monoUVHeight * monoUVRowBytes;
 
                 monoUVPlane = avifAlloc(monoUVSize);
-                AVIF_CHECKERR(monoUVPlane != NULL, AVIF_RESULT_OUT_OF_MEMORY); // No need for aom_img_free() because !aomImageAllocated
-                aomImage.planes[1] = monoUVPlane;
-                aomImage.stride[1] = monoUVRowBytes;
+                AVIF_CHECKERR(monoUVPlane != NULL, AVIF_RESULT_OUT_OF_MEMORY); // No need for avm_img_free() because !avmImageAllocated
+                avmImage.planes[1] = monoUVPlane;
+                avmImage.stride[1] = monoUVRowBytes;
             }
             // Set the U plane to 0.5.
             if (image->depth > 8) {
                 const uint16_t half = 1 << (image->depth - 1);
                 for (uint32_t j = 0; j < monoUVHeight; ++j) {
-                    uint16_t * dstRow = (uint16_t *)&aomImage.planes[1][(size_t)j * aomImage.stride[1]];
+                    uint16_t * dstRow = (uint16_t *)&avmImage.planes[1][(size_t)j * avmImage.stride[1]];
                     for (uint32_t i = 0; i < monoUVWidth; ++i) {
                         dstRow[i] = half;
                     }
                 }
             } else {
                 const uint8_t half = 128;
-                size_t planeSize = (size_t)monoUVHeight * aomImage.stride[1];
-                memset(aomImage.planes[1], half, planeSize);
+                size_t planeSize = (size_t)monoUVHeight * avmImage.stride[1];
+                memset(avmImage.planes[1], half, planeSize);
             }
             // Make the V plane the same as the U plane.
-            aomImage.planes[2] = aomImage.planes[1];
-            aomImage.stride[2] = aomImage.stride[1];
+            avmImage.planes[2] = avmImage.planes[1];
+            avmImage.stride[2] = avmImage.stride[1];
         }
     }
 
-    aom_enc_frame_flags_t encodeFlags = 0;
+    avm_enc_frame_flags_t encodeFlags = 0;
     if (addImageFlags & AVIF_ADD_IMAGE_FLAG_FORCE_KEYFRAME) {
-        encodeFlags |= AOM_EFLAG_FORCE_KF;
+        encodeFlags |= AVM_EFLAG_FORCE_KF;
     }
     if (codec->internal->currentLayer > 0) {
-        encodeFlags |= AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_REF_ARF | AOM_EFLAG_NO_REF_BWD | AOM_EFLAG_NO_REF_ARF2 | AOM_EFLAG_NO_UPD_ALL;
+        encodeFlags |= AVM_EFLAG_NO_REF_GF | AVM_EFLAG_NO_REF_ARF | AVM_EFLAG_NO_REF_BWD | AVM_EFLAG_NO_REF_ARF2 | AVM_EFLAG_NO_UPD_ALL;
     }
-    aom_codec_err_t encodeErr = aom_codec_encode(&codec->internal->encoder, &aomImage, 0, 1, encodeFlags);
+    avm_codec_err_t encodeErr = avm_codec_encode(&codec->internal->encoder, &avmImage, 0, 1, encodeFlags);
     avifFree(monoUVPlane);
-    if (aomImageAllocated) {
-        aom_img_free(&aomImage);
+    if (avmImageAllocated) {
+        avm_img_free(&avmImage);
     }
-    if (encodeErr != AOM_CODEC_OK) {
+    if (encodeErr != AVM_CODEC_OK) {
         avifDiagnosticsPrintf(codec->diag,
-                              "aom_codec_encode() failed: %s: %s",
-                              aom_codec_error(&codec->internal->encoder),
-                              aom_codec_error_detail(&codec->internal->encoder));
+                              "avm_codec_encode() failed: %s: %s",
+                              avm_codec_error(&codec->internal->encoder),
+                              avm_codec_error_detail(&codec->internal->encoder));
         return AVIF_RESULT_UNKNOWN_ERROR;
     }
 
-    aom_codec_iter_t iter = NULL;
+    avm_codec_iter_t iter = NULL;
     for (;;) {
-        const aom_codec_cx_pkt_t * pkt = aom_codec_get_cx_data(&codec->internal->encoder, &iter);
+        const avm_codec_cx_pkt_t * pkt = avm_codec_get_cx_data(&codec->internal->encoder, &iter);
         if (pkt == NULL) {
             break;
         }
-        if (pkt->kind == AOM_CODEC_CX_FRAME_PKT) {
+        if (pkt->kind == AVM_CODEC_CX_FRAME_PKT) {
             AVIF_CHECKRES(
-                avifCodecEncodeOutputAddSample(output, pkt->data.frame.buf, pkt->data.frame.sz, (pkt->data.frame.flags & AOM_FRAME_IS_KEY)));
+                avifCodecEncodeOutputAddSample(output, pkt->data.frame.buf, pkt->data.frame.sz, (pkt->data.frame.flags & AVM_FRAME_IS_KEY)));
         }
     }
 
@@ -1000,7 +999,7 @@
         if (!avmCodecEncodeFinish(codec, output)) {
             return AVIF_RESULT_UNKNOWN_ERROR;
         }
-        aom_codec_destroy(&codec->internal->encoder);
+        avm_codec_destroy(&codec->internal->encoder);
         codec->internal->encoderInitialized = AVIF_FALSE;
     }
     if (encoder->extraLayerCount > 0) {
@@ -1016,27 +1015,27 @@
     }
     for (;;) {
         // flush encoder
-        if (aom_codec_encode(&codec->internal->encoder, NULL, 0, 1, 0) != AOM_CODEC_OK) {
+        if (avm_codec_encode(&codec->internal->encoder, NULL, 0, 1, 0) != AVM_CODEC_OK) {
             avifDiagnosticsPrintf(codec->diag,
-                                  "aom_codec_encode() with img=NULL failed: %s: %s",
-                                  aom_codec_error(&codec->internal->encoder),
-                                  aom_codec_error_detail(&codec->internal->encoder));
+                                  "avm_codec_encode() with img=NULL failed: %s: %s",
+                                  avm_codec_error(&codec->internal->encoder),
+                                  avm_codec_error_detail(&codec->internal->encoder));
             return AVIF_FALSE;
         }
 
         avifBool gotPacket = AVIF_FALSE;
-        aom_codec_iter_t iter = NULL;
+        avm_codec_iter_t iter = NULL;
         for (;;) {
-            const aom_codec_cx_pkt_t * pkt = aom_codec_get_cx_data(&codec->internal->encoder, &iter);
+            const avm_codec_cx_pkt_t * pkt = avm_codec_get_cx_data(&codec->internal->encoder, &iter);
             if (pkt == NULL) {
                 break;
             }
-            if (pkt->kind == AOM_CODEC_CX_FRAME_PKT) {
+            if (pkt->kind == AVM_CODEC_CX_FRAME_PKT) {
                 gotPacket = AVIF_TRUE;
                 const avifResult result = avifCodecEncodeOutputAddSample(output,
                                                                          pkt->data.frame.buf,
                                                                          pkt->data.frame.sz,
-                                                                         (pkt->data.frame.flags & AOM_FRAME_IS_KEY));
+                                                                         (pkt->data.frame.flags & AVM_FRAME_IS_KEY));
                 if (result != AVIF_RESULT_OK) {
                     avifDiagnosticsPrintf(codec->diag, "avifCodecEncodeOutputAddSample() failed: %s", avifResultToString(result));
                     return AVIF_FALSE;
@@ -1053,7 +1052,7 @@
 
 const char * avifCodecVersionAVM(void)
 {
-    return aom_codec_version_str();
+    return avm_codec_version_str();
 }
 
 avifCodec * avifCodecCreateAVM(void)
diff --git a/src/obu.c b/src/obu.c
index 6afe1d3..2496898 100644
--- a/src/obu.c
+++ b/src/obu.c
@@ -40,7 +40,9 @@
 #include <string.h>
 
 #if defined(AVIF_CODEC_AVM)
-#include "config/aom_config.h"
+// TODO: b/398931194 - Remove specific codec includes once AV2 is released.
+#include "avm/avm_codec.h"
+#include "config/avm_config.h"
 #endif
 
 // ---------------------------------------------------------------------------
@@ -127,6 +129,21 @@
     return numBits ? ((1U << numBits) - 1) + avifBitsRead(bits, numBits) : 0;
 }
 
+#if defined(AVIF_CODEC_AVM)
+// Rice-Golomb coding with parameter n.
+static uint32_t avifBitsReadRG(avifBits * const bits, const uint32_t n)
+{
+    for (uint32_t q = 0; q < 32; q++) {
+        const uint32_t rgBit = avifBitsRead(bits, 1);
+        if (rgBit == 0) {
+            const uint32_t remainder = avifBitsRead(bits, n);
+            return (q << n) + remainder;
+        }
+    }
+    return 0xFFFFFFFFU;
+}
+#endif // defined(AVIF_CODEC_AVM)
+
 // ---------------------------------------------------------------------------
 // Variables in here use snake_case to self-document from the AV1 spec and the draft AV2 spec:
 //
@@ -349,21 +366,6 @@
 }
 
 #if defined(AVIF_CODEC_AVM)
-#if CONFIG_CROP_WIN_CWG_F220
-static avifBool parseAV2SequenceHeaderCroppingWindow(avifBits * bits)
-{
-    if (avifBitsRead(bits, 1)) {     // seq_cropping_window_present_flag
-        (void)avifBitsReadVLC(bits); // seq_cropping_win_left_offset
-        (void)avifBitsReadVLC(bits); // seq_cropping_win_right_offset
-        (void)avifBitsReadVLC(bits); // seq_cropping_win_top_offset
-        (void)avifBitsReadVLC(bits); // seq_cropping_win_bottom_offset
-    }
-
-    return !bits->error;
-}
-#endif // CONFIG_CROP_WIN_CWG_F220
-
-#if CONFIG_CWG_E242_CHROMA_FORMAT_IDC
 enum
 {
     AV2_CHROMA_FORMAT_420 = 0,
@@ -371,14 +373,46 @@
     AV2_CHROMA_FORMAT_444 = 2,
     AV2_CHROMA_FORMAT_422 = 3,
 };
-#endif // CONFIG_CWG_E242_CHROMA_FORMAT_IDC
 
-// Note: Does not parse separate_uv_delta_q.
-static avifBool parseAV2SequenceHeaderColorConfig(avifBits * bits, avifSequenceHeader * header)
+static avifChromaSamplePosition av2ChromaSamplePositionToAv1ChromaSamplePosition(uint32_t av2ChromaSamplePosition)
 {
-#if CONFIG_CWG_E242_CHROMA_FORMAT_IDC
+    if (av2ChromaSamplePosition == 0) {
+        // AVM_CSP_LEFT: Horizontal offset 0, vertical offset 0.5
+        return AVIF_CHROMA_SAMPLE_POSITION_VERTICAL;
+    } else if (av2ChromaSamplePosition == 1) {
+        // AVM_CSP_CENTER: Horizontal offset 0.5, vertical offset 0.5
+        return AVIF_CHROMA_SAMPLE_POSITION_UNKNOWN;
+    } else if (av2ChromaSamplePosition == 2) {
+        // AVM_CSP_TOPLEFT: Horizontal offset 0, vertical offset 0
+        return AVIF_CHROMA_SAMPLE_POSITION_COLOCATED;
+    } else {
+        return AVIF_CHROMA_SAMPLE_POSITION_UNKNOWN;
+    }
+}
+
+static avifBool parseAV2ChromaFormatBitdepth(avifBits * bits, avifSequenceHeader * header)
+{
     const uint32_t chromaFormatIdc = avifBitsReadVLC(bits);
-    if (chromaFormatIdc == AV2_CHROMA_FORMAT_420) {
+
+    const uint32_t bitdepthIdx = avifBitsReadVLC(bits);
+    if (bitdepthIdx == 0) {
+        header->bitDepth = 10;
+    } else if (bitdepthIdx == 1) {
+        header->bitDepth = 8;
+    } else if (bitdepthIdx == 2) {
+        header->bitDepth = 12;
+    } else {
+        return AVIF_FALSE;
+    }
+    header->av1C.highBitdepth = header->bitDepth > 8;
+    header->av1C.twelveBit = header->bitDepth == 12;
+    header->av1C.monochrome = chromaFormatIdc == AV2_CHROMA_FORMAT_400;
+
+    if (header->av1C.monochrome) {
+        header->av1C.chromaSubsamplingX = 1;
+        header->av1C.chromaSubsamplingY = 1;
+        header->yuvFormat = AVIF_PIXEL_FORMAT_YUV400;
+    } else if (chromaFormatIdc == AV2_CHROMA_FORMAT_420) {
         header->av1C.chromaSubsamplingX = 1;
         header->av1C.chromaSubsamplingY = 1;
         header->yuvFormat = AVIF_PIXEL_FORMAT_YUV420;
@@ -390,144 +424,9 @@
         header->av1C.chromaSubsamplingX = 1;
         header->av1C.chromaSubsamplingY = 0;
         header->yuvFormat = AVIF_PIXEL_FORMAT_YUV422;
-    } else if (chromaFormatIdc == AV2_CHROMA_FORMAT_400) {
-        header->av1C.chromaSubsamplingX = 1;
-        header->av1C.chromaSubsamplingY = 1;
-        header->yuvFormat = AVIF_PIXEL_FORMAT_YUV400;
     } else {
         return AVIF_FALSE;
     }
-#endif // CONFIG_CWG_E242_CHROMA_FORMAT_IDC
-
-    header->chromaSamplePosition = AVIF_CHROMA_SAMPLE_POSITION_UNKNOWN;
-    header->av1C.chromaSamplePosition = (uint8_t)header->chromaSamplePosition;
-#if CONFIG_CWG_E242_BITDEPTH
-    const uint32_t bitdepthLutIdx = avifBitsReadVLC(bits);
-    if (bitdepthLutIdx == 0) {
-        header->bitDepth = 10;
-    } else if (bitdepthLutIdx == 1) {
-        header->bitDepth = 8;
-    } else if (bitdepthLutIdx == 2) {
-        header->bitDepth = 12;
-    } else {
-        return AVIF_FALSE;
-    }
-    header->av1C.highBitdepth = header->bitDepth > 8;
-    header->av1C.twelveBit = header->bitDepth == 12;
-#else
-    header->bitDepth = 8;
-    uint32_t high_bitdepth = avifBitsRead(bits, 1);
-    header->av1C.highBitdepth = (uint8_t)high_bitdepth;
-    if ((header->av1C.seqProfile == 2) && high_bitdepth) {
-        uint32_t twelve_bit = avifBitsRead(bits, 1);
-        header->bitDepth = twelve_bit ? 12 : 10;
-        header->av1C.twelveBit = (uint8_t)twelve_bit;
-    } else /* if (seq_profile <= 2) */ {
-        header->bitDepth = high_bitdepth ? 10 : 8;
-        header->av1C.twelveBit = 0;
-    }
-#endif // CONFIG_CWG_E242_BITDEPTH
-#if CONFIG_CWG_E242_CHROMA_FORMAT_IDC
-    uint32_t mono_chrome = chromaFormatIdc == AV2_CHROMA_FORMAT_400;
-#else
-    uint32_t mono_chrome = 0;
-    if (header->av1C.seqProfile != 1) {
-        mono_chrome = avifBitsRead(bits, 1);
-    }
-#endif // CONFIG_CWG_E242_CHROMA_FORMAT_IDC
-    header->av1C.monochrome = (uint8_t)mono_chrome;
-    uint32_t color_description_present_flag = avifBitsRead(bits, 1);
-    if (color_description_present_flag) {
-        header->colorPrimaries = (avifColorPrimaries)avifBitsRead(bits, 8);                   // color_primaries
-        header->transferCharacteristics = (avifTransferCharacteristics)avifBitsRead(bits, 8); // transfer_characteristics
-        header->matrixCoefficients = (avifMatrixCoefficients)avifBitsRead(bits, 8);           // matrix_coefficients
-    } else {
-        header->colorPrimaries = AVIF_COLOR_PRIMARIES_UNSPECIFIED;
-        header->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED;
-        header->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_UNSPECIFIED;
-    }
-    if (mono_chrome) {
-        header->range = avifBitsRead(bits, 1) ? AVIF_RANGE_FULL : AVIF_RANGE_LIMITED; // color_range
-        header->av1C.chromaSubsamplingX = 1;
-        header->av1C.chromaSubsamplingY = 1;
-        header->yuvFormat = AVIF_PIXEL_FORMAT_YUV400;
-    } else if (header->colorPrimaries == AVIF_COLOR_PRIMARIES_BT709 &&
-               header->transferCharacteristics == AVIF_TRANSFER_CHARACTERISTICS_SRGB &&
-               header->matrixCoefficients == AVIF_MATRIX_COEFFICIENTS_IDENTITY) {
-        header->range = AVIF_RANGE_FULL;
-        header->av1C.chromaSubsamplingX = 0;
-        header->av1C.chromaSubsamplingY = 0;
-        header->yuvFormat = AVIF_PIXEL_FORMAT_YUV444;
-    } else {
-        header->range = avifBitsRead(bits, 1) ? AVIF_RANGE_FULL : AVIF_RANGE_LIMITED; // color_range
-#if !CONFIG_CWG_E242_CHROMA_FORMAT_IDC
-        uint32_t subsampling_x = 0;
-        uint32_t subsampling_y = 0;
-        switch (header->av1C.seqProfile) {
-            case 0:
-                subsampling_x = 1;
-                subsampling_y = 1;
-                header->yuvFormat = AVIF_PIXEL_FORMAT_YUV420;
-                break;
-            case 1:
-                subsampling_x = 0;
-                subsampling_y = 0;
-                header->yuvFormat = AVIF_PIXEL_FORMAT_YUV444;
-                break;
-            case 2:
-                if (header->bitDepth == 12) {
-                    subsampling_x = avifBitsRead(bits, 1);
-                    if (subsampling_x) {
-                        subsampling_y = avifBitsRead(bits, 1);
-                    }
-                } else {
-                    subsampling_x = 1;
-                    subsampling_y = 0;
-                }
-                if (subsampling_x) {
-                    header->yuvFormat = subsampling_y ? AVIF_PIXEL_FORMAT_YUV420 : AVIF_PIXEL_FORMAT_YUV422;
-                } else {
-                    header->yuvFormat = AVIF_PIXEL_FORMAT_YUV444;
-                }
-                break;
-            default:
-                return AVIF_FALSE;
-        }
-        header->av1C.chromaSubsamplingX = (uint8_t)subsampling_x;
-        header->av1C.chromaSubsamplingY = (uint8_t)subsampling_y;
-#endif // !CONFIG_CWG_E242_CHROMA_FORMAT_IDC
-
-        if (header->yuvFormat == AVIF_PIXEL_FORMAT_YUV422) {
-            uint8_t chromaSamplePosition = 6; // CSP_UNSPECIFIED
-            const int csp_present_flag = avifBitsRead(bits, 1);
-            if (csp_present_flag) {
-                chromaSamplePosition = avifBitsRead(bits, 1);
-            }
-        } else if (header->yuvFormat == AVIF_PIXEL_FORMAT_YUV420) {
-            uint8_t chromaSamplePosition = 6; // CSP_UNSPECIFIED
-            const int csp_present_flag = avifBitsRead(bits, 1);
-            if (csp_present_flag) {
-                chromaSamplePosition = avifBitsRead(bits, 3);
-                if (chromaSamplePosition > 5) {
-                    // Invalid chroma_sample_position.
-                    return AVIF_FALSE;
-                }
-            }
-            if (chromaSamplePosition == 0) {
-                // CSP_LEFT: Horizontal offset 0, vertical offset 0.5
-                header->chromaSamplePosition = AVIF_CHROMA_SAMPLE_POSITION_VERTICAL;
-            } else if (chromaSamplePosition == 1) {
-                // CSP_CENTER: Horizontal offset 0.5, vertical offset 0.5
-                header->chromaSamplePosition = AVIF_CHROMA_SAMPLE_POSITION_UNKNOWN;
-            } else if (chromaSamplePosition == 2) {
-                // CSP_TOPLEFT: Horizontal offset 0, vertical offset 0
-                header->chromaSamplePosition = AVIF_CHROMA_SAMPLE_POSITION_COLOCATED;
-            } else {
-                header->chromaSamplePosition = AVIF_CHROMA_SAMPLE_POSITION_UNKNOWN;
-            }
-            header->av1C.chromaSamplePosition = (uint8_t)header->chromaSamplePosition;
-        }
-    }
 
     return !bits->error;
 }
@@ -554,42 +453,121 @@
 }
 
 #if defined(AVIF_CODEC_AVM)
-// See https://gitlab.com/AOMediaCodec/avm/-/blob/main/av1/decoder/decodeframe.c
+// See read_sequence_header_obu() in av2/decoder/obu.c.
 static avifBool parseAV2SequenceHeader(avifBits * bits, avifSequenceHeader * header)
 {
-#if CONFIG_CWG_E242_SEQ_HDR_ID
     uint32_t seqHeaderId = avifBitsReadVLC(bits);
     if (seqHeaderId >= 16) {
         return AVIF_FALSE;
     }
-#endif // CONFIG_CWG_E242_SEQ_HDR_ID
-    // See read_sequence_header_obu() in avm.
+
     AVIF_CHECK(parseSequenceHeaderProfile(bits, header));
+    header->reduced_still_picture_header = (uint8_t)avifBitsRead(bits, 1); // single_picture_header_flag
+    if (!header->reduced_still_picture_header) {
+        avifBitsRead(bits, 3); // seq_lcr_id
+        avifBitsRead(bits, 1); // still_picture
+        return AVIF_FALSE;
+    }
+    header->av1C.seqLevelIdx0 = (uint8_t)avifBitsRead(bits, 5);
+    if (header->av1C.seqLevelIdx0 > 7 && !header->reduced_still_picture_header) {
+        avifBitsRead(bits, 1); // single_tier_0
+        header->av1C.seqTier0 = 0;
+    }
 
     uint32_t frame_width_bits = avifBitsRead(bits, 4) + 1;
     uint32_t frame_height_bits = avifBitsRead(bits, 4) + 1;
     header->maxWidth = avifBitsRead(bits, frame_width_bits) + 1;   // max_frame_width
     header->maxHeight = avifBitsRead(bits, frame_height_bits) + 1; // max_frame_height
 
-#if CONFIG_CROP_WIN_CWG_F220
-    AVIF_CHECK(parseAV2SequenceHeaderCroppingWindow(bits));
-#endif // CONFIG_CROP_WIN_CWG_F220
+    if (avifBitsRead(bits, 1)) { // conf_window_flag
+        avifBitsReadVLC(bits);   // conf_win_left_offset
+        avifBitsReadVLC(bits);   // conf_win_right_offset
+        avifBitsReadVLC(bits);   // conf_win_top_offset
+        avifBitsReadVLC(bits);   // conf_win_bottom_offset
+    }
 
-    // See av1_read_color_config() in avm.
-    AVIF_CHECK(parseAV2SequenceHeaderColorConfig(bits, header));
+    AVIF_CHECK(parseAV2ChromaFormatBitdepth(bits, header));
 
-    // See read_sequence_header_obu() in avm.
-    AVIF_CHECK(parseSequenceHeaderLevelIdxAndTier(bits, header));
+    header->colorPrimaries = AVIF_COLOR_PRIMARIES_UNSPECIFIED;
+    header->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED;
+    header->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_UNSPECIFIED;
+    header->range = AVIF_RANGE_LIMITED;
 
-    // See read_sequence_header_obu() in avm.
-    // Ignored field.
-    //   film_grain_params_present
+    header->chromaSamplePosition = AVIF_CHROMA_SAMPLE_POSITION_UNKNOWN;
+    header->av1C.chromaSamplePosition = (uint8_t)header->chromaSamplePosition;
 
-    // See av1_read_sequence_header_beyond_av1() in avm.
     // Other ignored fields.
     return !bits->error;
 }
-#endif
+
+// See av2_read_content_interpretation_obu() in av2/decoder/obu_ci.c.
+static avifBool parseAV2ContentInterpretation(avifBits * bits, avifSequenceHeader * header)
+{
+    const uint32_t scanTypeIdc = avifBitsRead(bits, 2);                 // ci_scan_type_idc
+    const uint32_t colorDescriptionPresent = avifBitsRead(bits, 1);     // ci_color_description_present_flag
+    const uint32_t chromaSamplePositionPresent = avifBitsRead(bits, 1); // ci_chroma_sample_position_present_flag
+    avifBitsRead(bits, 1);                                              // ci_aspect_ratio_info_present_flag
+    avifBitsRead(bits, 1);                                              // ci_timing_info_present_flag
+    avifBitsRead(bits, 1);                                              // ci_extension_present_flag
+    avifBitsRead(bits, 1);                                              // reserved_bit
+
+    if (colorDescriptionPresent) {
+        // Override the default CICP values.
+        const uint32_t colorDescriptionIdc = avifBitsReadRG(bits, 2); // color_description_idc
+        if (colorDescriptionIdc == 0xFFFFFFFFU) {
+            return AVIF_FALSE;
+        }
+        if (colorDescriptionIdc == 0) {
+            // Explicitly signaled
+            header->colorPrimaries = (avifColorPrimaries)avifBitsRead(bits, 8);                   // color_primaries
+            header->transferCharacteristics = (avifTransferCharacteristics)avifBitsRead(bits, 8); // transfer_characteristics
+            header->matrixCoefficients = (avifMatrixCoefficients)avifBitsRead(bits, 8);           // matrix_coefficients
+        } else if (colorDescriptionIdc == 1) {
+            // BT.709 SDR
+            header->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709;                   // 1
+            header->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_BT709; // 1
+            header->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT470BG;         // 5
+        } else if (colorDescriptionIdc == 2) {
+            // BT.2100 PQ
+            header->colorPrimaries = AVIF_COLOR_PRIMARIES_BT2100;               // 9
+            header->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_PQ; // 16
+            header->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT2020_NCL;   // 9
+        } else if (colorDescriptionIdc == 3) {
+            // BT.2100 HLG
+            header->colorPrimaries = AVIF_COLOR_PRIMARIES_BT2100;                         // 9
+            header->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_BT2020_10BIT; // 14
+            header->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT2020_NCL;             // 9
+        } else if (colorDescriptionIdc == 4) {
+            // sRGB
+            header->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709;                  // 1
+            header->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB; // 13
+            header->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_IDENTITY;       // 0
+        } else if (colorDescriptionIdc == 5) {
+            // sYCC
+            header->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709;                  // 1
+            header->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB; // 13
+            header->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT470BG;        // 5
+        } else {
+            // Reserved
+            header->colorPrimaries = AVIF_COLOR_PRIMARIES_UNSPECIFIED;                   // 2
+            header->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED; // 2
+            header->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_UNSPECIFIED;           // 2
+        }
+        header->range = avifBitsRead(bits, 1) ? AVIF_RANGE_FULL : AVIF_RANGE_LIMITED; // color_range
+    } else {
+        // Keep the default CICP values.
+    }
+
+    if (chromaSamplePositionPresent) {
+        const uint32_t chromaSamplePosition = avifBitsReadVLC(bits); // ci_chroma_sample_position_0
+        header->chromaSamplePosition = av2ChromaSamplePositionToAv1ChromaSamplePosition(chromaSamplePosition);
+        header->av1C.chromaSamplePosition = (uint8_t)header->chromaSamplePosition;
+    }
+
+    // Other ignored fields.
+    return !bits->error;
+}
+#endif // defined(AVIF_CODEC_AVM)
 
 static avifBool av1SequenceHeaderParse(avifSequenceHeader * header, const avifROData * sample)
 {
@@ -645,21 +623,22 @@
 #if defined(AVIF_CODEC_AVM)
 static avifBool av2SequenceHeaderParse(avifSequenceHeader * header, const avifROData * sample)
 {
+    avifBool sequenceHeaderFound = AVIF_FALSE;
     avifROData obus = *sample;
 
-    // Find the sequence header OBU
+    // Find the Sequence Header OBU, and the Content Interpretation OBU if any.
     while (obus.size > 0) {
         avifBits bits;
         avifBitsInit(&bits, obus.data, obus.size);
 
-        const uint32_t obu_size = avifBitsReadUleb128(&bits);
+        const uint32_t obuSize = avifBitsReadUleb128(&bits);
 
         // obu_header()
-        const uint32_t obu_extension_flag = avifBitsRead(&bits, 1);
-        const uint32_t obu_type = avifBitsRead(&bits, 5);
+        const uint32_t obuExtensionFlag = avifBitsRead(&bits, 1);
+        const uint32_t obuType = avifBitsRead(&bits, 5);
         avifBitsRead(&bits, 2); // obu_tlayer_id
 
-        if (obu_extension_flag) {
+        if (obuExtensionFlag) {
             avifBitsRead(&bits, 8); // obu_mlayer_id, obu_xlayer_id
         }
 
@@ -667,28 +646,42 @@
             return AVIF_FALSE;
         }
 
-        const uint32_t obu_header_size = 1 + obu_extension_flag;
-        if (obu_size < obu_header_size) {
+        const uint32_t obuHeaderSize = 1 + obuExtensionFlag;
+        if (obuSize < obuHeaderSize) {
             return AVIF_FALSE;
         }
-        const uint32_t obu_payload_size = obu_size - obu_header_size;
-        const uint32_t init_bit_pos = avifBitsReadPos(&bits);
-        const uint32_t init_byte_pos = init_bit_pos >> 3;
-        if (obu_payload_size > obus.size - init_byte_pos) {
+        const uint32_t obuPayloadSize = obuSize - obuHeaderSize;
+        const uint32_t initBitPos = avifBitsReadPos(&bits);
+        const uint32_t initBytePos = initBitPos >> 3;
+        if (obuPayloadSize > obus.size - initBytePos) {
             return AVIF_FALSE;
         }
 
-        if (obu_type == 1) { // Sequence Header
+        if (obuType == OBU_SEQUENCE_HEADER) {
+            if (sequenceHeaderFound) {
+                return AVIF_FALSE;
+            }
             avifBits seqHdrBits;
-            avifBitsInit(&seqHdrBits, obus.data + init_byte_pos, obu_payload_size);
-            return parseAV2SequenceHeader(&seqHdrBits, header);
+            avifBitsInit(&seqHdrBits, obus.data + initBytePos, obuPayloadSize);
+            if (!parseAV2SequenceHeader(&seqHdrBits, header)) {
+                return AVIF_FALSE;
+            }
+            sequenceHeaderFound = AVIF_TRUE;
+        } else if (obuType == OBU_CONTENT_INTERPRETATION) { // optional
+            if (!sequenceHeaderFound) {
+                return AVIF_FALSE;
+            }
+            avifBits ciBits;
+            avifBitsInit(&ciBits, obus.data + initBytePos, obuPayloadSize);
+            if (!parseAV2ContentInterpretation(&ciBits, header)) {
+                return AVIF_FALSE;
+            }
+            break;
         }
-
-        // Skip this OBU
-        obus.data += (size_t)obu_payload_size + init_byte_pos;
-        obus.size -= (size_t)obu_payload_size + init_byte_pos;
+        obus.data += (size_t)obuPayloadSize + initBytePos;
+        obus.size -= (size_t)obuPayloadSize + initBytePos;
     }
-    return AVIF_FALSE;
+    return sequenceHeaderFound;
 }
 #endif // defined(AVIF_CODEC_AVM)