Update LocalAom.cmake to AVM research-v12.0.0
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 859860f..af7027f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -552,6 +552,8 @@
     endif()
 
     target_compile_definitions(avif_obj PUBLIC -DAVIF_CODEC_AVM=1)
+    # TODO(wtc): Remove after research-v12.0.0 has been imported into Google's internal repository.
+    target_compile_definitions(avif_obj PRIVATE -DCONFIG_NEW_CSP=1 -DCONFIG_NEW_OBU_HEADER=1)
     target_sources(avif_obj PRIVATE src/codec_avm.c)
 
     avif_target_link_library(aom)
diff --git a/cmake/Modules/LocalAom.cmake b/cmake/Modules/LocalAom.cmake
index befdc73..7bfc572 100644
--- a/cmake/Modules/LocalAom.cmake
+++ b/cmake/Modules/LocalAom.cmake
@@ -1,5 +1,5 @@
 set(AVIF_AOM_GIT_TAG v3.13.1)
-set(AVIF_AVM_GIT_TAG research-v11.0.0)
+set(AVIF_AVM_GIT_TAG research-v12.0.0)
 
 if(AVIF_CODEC_AVM)
     # Building the avm repository generates files such as "libaom.a" because it is a fork of aom,
diff --git a/src/obu.c b/src/obu.c
index 497d7bb..48ce9b6 100644
--- a/src/obu.c
+++ b/src/obu.c
@@ -349,12 +349,73 @@
 }
 
 #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,
+    AV2_CHROMA_FORMAT_400 = 1,
+    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)
 {
-    header->bitDepth = 8;
+#if CONFIG_CWG_E242_CHROMA_FORMAT_IDC
+    const uint32_t chromaFormatIdc = avifBitsReadVLC(bits);
+    if (chromaFormatIdc == AV2_CHROMA_FORMAT_420) {
+        header->av1C.chromaSubsamplingX = 1;
+        header->av1C.chromaSubsamplingY = 1;
+        header->yuvFormat = AVIF_PIXEL_FORMAT_YUV420;
+    } else if (chromaFormatIdc == AV2_CHROMA_FORMAT_444) {
+        header->av1C.chromaSubsamplingX = 0;
+        header->av1C.chromaSubsamplingY = 0;
+        header->yuvFormat = AVIF_PIXEL_FORMAT_YUV444;
+    } else if (chromaFormatIdc == AV2_CHROMA_FORMAT_422) {
+        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) {
@@ -365,10 +426,15 @@
         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) {
@@ -393,9 +459,10 @@
         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;
-        header->range = avifBitsRead(bits, 1) ? AVIF_RANGE_FULL : AVIF_RANGE_LIMITED; // color_range
         switch (header->av1C.seqProfile) {
             case 0:
                 subsampling_x = 1;
@@ -426,17 +493,18 @@
             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 CONFIG_NEW_CSP
-        if (subsampling_x && !subsampling_y) {
-            // YUV 4:2:2
+        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 (subsampling_x && subsampling_y) {
-            // YUV 4:2:0
+        } 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) {
@@ -461,13 +529,11 @@
             header->av1C.chromaSamplePosition = (uint8_t)header->chromaSamplePosition;
         }
 #else  // !CONFIG_NEW_CSP
-        if (subsampling_x && subsampling_y) {
+        if (header->yuvFormat == AVIF_PIXEL_FORMAT_YUV420) {
             header->chromaSamplePosition = (avifChromaSamplePosition)avifBitsRead(bits, 2); // chroma_sample_position
             header->av1C.chromaSamplePosition = (uint8_t)header->chromaSamplePosition;
         }
 #endif // CONFIG_NEW_CSP
-        header->av1C.chromaSubsamplingX = (uint8_t)subsampling_x;
-        header->av1C.chromaSubsamplingY = (uint8_t)subsampling_y;
     }
 
     return !bits->error;
@@ -498,6 +564,12 @@
 // See https://gitlab.com/AOMediaCodec/avm/-/blob/main/av1/decoder/decodeframe.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));
 
@@ -506,6 +578,10 @@
     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
+
     // See av1_read_color_config() in avm.
     AVIF_CHECK(parseAV2SequenceHeaderColorConfig(bits, header));