Skip to content

Support display size override for layered image - #1069

Open
tongyuantongyu wants to merge 8 commits into
AOMediaCodec:mainfrom
tongyuantongyu:var-frame-size
Open

Support display size override for layered image#1069
tongyuantongyu wants to merge 8 commits into
AOMediaCodec:mainfrom
tongyuantongyu:var-frame-size

Conversation

@tongyuantongyu

@tongyuantongyu tongyuantongyu commented Aug 26, 2022

Copy link
Copy Markdown
Contributor

A layered image may use different frame for each layer, like using a small and blurred version as the first layer. It is more efficient and flexible to directly encode the small image, instead of scale it up only for the encoder to scale it back down; and it allows the scale ratio to be smaller than 1/8 as well.

Only single cell layered image is supported in this version. Layered grid may be revisited in the future.

@wantehchang

Copy link
Copy Markdown
Member

Yuan: I just merged my cleanup pull request #1070. Please rebase this pull request and then I will take a look at the crash. Thanks.

@tongyuantongyu
tongyuantongyu force-pushed the var-frame-size branch 2 times, most recently from 054b138 to 864c34e Compare August 30, 2022 02:45
@tongyuantongyu

tongyuantongyu commented Aug 31, 2022

Copy link
Copy Markdown
Contributor Author
Legacy content

I tried to run asan and here is the report:

=================================================================
==6200==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x121cbf221290 at pc 0x7ff65da76b28 bp 0x0026a0dedb00 sp 0x0026a0dedb48
WRITE of size 8 at 0x121cbf221290 thread T0
    #0 0x7ff65da76b27 in av1_set_mb_ssim_rdmult_scaling D:/Cpp/libavif/ext/aom/av1/encoder/encoder_utils.c:1304:47
    #1 0x7ff65da3f157 in encode_frame_to_data_rate D:/Cpp/libavif/ext/aom/av1/encoder/encoder.c:3581:5
    #2 0x7ff65da3f157 in av1_encode D:/Cpp/libavif/ext/aom/av1/encoder/encoder.c:3830:9
    #3 0x7ff65e36e4d5 in av1_encode_strategy D:/Cpp/libavif/ext/aom/av1/encoder/encode_strategy.c:1605:9
    #4 0x7ff65da48d65 in av1_get_compressed_data D:/Cpp/libavif/ext/aom/av1/encoder/encoder.c:4532:22
    #5 0x7ff65d946785 in encoder_encode D:/Cpp/libavif/ext/aom/av1/av1_cx_iface.c:3029:20
    #6 0x7ff65d938bdb in aom_codec_encode D:/Cpp/libavif/ext/aom/aom/src/aom_encoder.c:176:11
    #7 0x7ff65d90d423 in aomCodecEncodeImage D:/Cpp/libavif/src/codec_aom.c:974:33
    #8 0x7ff65d8fd2d4 in avifEncoderAddImageInternal D:/Cpp/libavif/src/write.c:915:17
    #9 0x7ff65d8fb670 in avifEncoderAddImage D:/Cpp/libavif/src/write.c:934:12
    #10 0x7ff65d8d42b3 in libavif::(anonymous namespace)::ChangeSettingTest_DISABLED_ChangeDimension_Test::TestBody() D:/Cpp/libavif/tests/gtest/avifchangesettingtest.cc:186:5
    #11 0x7ffbebd58308 in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) (D:\Tools\msys64\clang64\bin\libgtest.dll+0x180038308)
    #12 0x7ffbebd3ce8a in testing::Test::Run() (D:\Tools\msys64\clang64\bin\libgtest.dll+0x18001ce8a)
    #13 0x7ffbebd3e16e in testing::TestInfo::Run() (D:\Tools\msys64\clang64\bin\libgtest.dll+0x18001e16e)
    #14 0x7ffbebd3ec57 in testing::TestSuite::Run() (D:\Tools\msys64\clang64\bin\libgtest.dll+0x18001ec57)
    #15 0x7ffbebd4f2ab in testing::internal::UnitTestImpl::RunAllTests() (D:\Tools\msys64\clang64\bin\libgtest.dll+0x18002f2ab)
    #16 0x7ffbebd59168 in bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) (D:\Tools\msys64\clang64\bin\libgtest.dll+0x180039168)
    #17 0x7ffbebd4eadf in testing::UnitTest::Run() (D:\Tools\msys64\clang64\bin\libgtest.dll+0x18002eadf)
    #18 0x7ffbefab1434 in main (D:\Tools\msys64\clang64\bin\libgtest_main.dll+0x180001434)
    #19 0x7ff65d8d13ad in __tmainCRTStartup C:/M/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/crtexe.c:329:15
    #20 0x7ff65d8d14e5 in mainCRTStartup C:/M/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/crtexe.c:206:9
    #21 0x7ffc008f54df  (C:\WINDOWS\System32\KERNEL32.DLL+0x1800154df)
    #22 0x7ffc0224485a  (C:\WINDOWS\SYSTEM32\ntdll.dll+0x18000485a)

0x121cbf221297 is located 0 bytes to the right of 2071-byte region [0x121cbf220a80,0x121cbf221297)
allocated by thread T0 here:
    #0 0x7ffb7dec100d in malloc (D:\Tools\msys64\clang64\bin\libclang_rt.asan_dynamic-x86_64.dll+0x18004100d)
    #1 0x7ff65d9ab06a in aom_memalign D:/Cpp/libavif/ext/aom/aom_mem/aom_mem.c:59:22
    #2 0x7ff65d9ab06a in aom_malloc D:/Cpp/libavif/ext/aom/aom_mem/aom_mem.c:67:40
    #3 0x7ff65d9ab06a in aom_calloc D:/Cpp/libavif/ext/aom/aom_mem/aom_mem.c:72:19
    #4 0x7ff65da38265 in av1_create_compressor D:/Cpp/libavif/ext/aom/av1/encoder/encoder.c:1400:5
    #5 0x7ff65d94389e in av1_create_context_and_bufferpool D:/Cpp/libavif/ext/aom/av1/av1_cx_iface.c:2487:12
    #6 0x7ff65d94389e in encoder_init D:/Cpp/libavif/ext/aom/av1/av1_cx_iface.c:2600:13
    #7 0x7ff65d938732 in aom_codec_enc_init_ver D:/Cpp/libavif/ext/aom/aom/src/aom_encoder.c:80:11
    #8 0x7ff65d90bcb0 in aomCodecEncodeImage D:/Cpp/libavif/src/codec_aom.c:726:13
    #9 0x7ff65d8fd2d4 in avifEncoderAddImageInternal D:/Cpp/libavif/src/write.c:915:17
    #10 0x7ff65d8fb670 in avifEncoderAddImage D:/Cpp/libavif/src/write.c:934:12
    #11 0x7ff65d8d4158 in libavif::(anonymous namespace)::ChangeSettingTest_DISABLED_ChangeDimension_Test::TestBody() D:/Cpp/libavif/tests/gtest/avifchangesettingtest.cc:183:5
    #12 0x7ffbebd58308 in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) (D:\Tools\msys64\clang64\bin\libgtest.dll+0x180038308)
    #13 0x7ffbebd3ce8a in testing::Test::Run() (D:\Tools\msys64\clang64\bin\libgtest.dll+0x18001ce8a)
    #14 0x7ffbebd3e16e in testing::TestInfo::Run() (D:\Tools\msys64\clang64\bin\libgtest.dll+0x18001e16e)
    #15 0x7ffbebd3ec57 in testing::TestSuite::Run() (D:\Tools\msys64\clang64\bin\libgtest.dll+0x18001ec57)
    #16 0x7ffbebd4f2ab in testing::internal::UnitTestImpl::RunAllTests() (D:\Tools\msys64\clang64\bin\libgtest.dll+0x18002f2ab)
    #17 0x7ffbebd59168 in bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) (D:\Tools\msys64\clang64\bin\libgtest.dll+0x180039168)
    #18 0x7ffbebd4eadf in testing::UnitTest::Run() (D:\Tools\msys64\clang64\bin\libgtest.dll+0x18002eadf)
    #19 0x7ffbefab1434 in main (D:\Tools\msys64\clang64\bin\libgtest_main.dll+0x180001434)
    #20 0x7ff65d8d13ad in __tmainCRTStartup C:/M/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/crtexe.c:329:15
    #21 0x7ff65d8d14e5 in mainCRTStartup C:/M/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/crtexe.c:206:9
    #22 0x7ffc008f54df  (C:\WINDOWS\System32\KERNEL32.DLL+0x1800154df)
    #23 0x7ffc0224485a  (C:\WINDOWS\SYSTEM32\ntdll.dll+0x18000485a)

SUMMARY: AddressSanitizer: heap-buffer-overflow D:/Cpp/libavif/ext/aom/av1/encoder/encoder_utils.c:1304:47 in av1_set_mb_ssim_rdmult_scaling
Shadow bytes around the buggy address:
  0x042657044200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x042657044210: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x042657044220: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x042657044230: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x042657044240: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x042657044250: 00 00[07]fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x042657044260: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x042657044270: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x042657044280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x042657044290: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0426570442a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==6200==ABORTING

The function in question seems related to ssim, but if I set tune to psnr, it fails in another function:

=================================================================
==62176==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x126071520997 at pc 0x7ffb7dec0b8c bp 0x00cb7aefcb00 sp 0x00cb7aefcb40
WRITE of size 4096 at 0x126071520997 thread T0
    #0 0x7ffb7dec0b8b in __asan_memset (D:\Tools\msys64\clang64\bin\libclang_rt.asan_dynamic-x86_64.dll+0x180040b8b)
    #1 0x7ff7eabdef80 in encode_without_recode D:/Cpp/libavif/ext/aom/av1/encoder/encoder.c:2406:5
    #2 0x7ff7eabdef80 in encode_with_recode_loop_and_filter D:/Cpp/libavif/ext/aom/av1/encoder/encoder.c:3014:11
    #3 0x7ff7eabc0d05 in encode_frame_to_data_rate D:/Cpp/libavif/ext/aom/av1/encoder/encoder.c:3678:9
    #4 0x7ff7eabc0d05 in av1_encode D:/Cpp/libavif/ext/aom/av1/encoder/encoder.c:3830:9
    #5 0x7ff7eb4ee4f5 in av1_encode_strategy D:/Cpp/libavif/ext/aom/av1/encoder/encode_strategy.c:1605:9
    #6 0x7ff7eabc8d85 in av1_get_compressed_data D:/Cpp/libavif/ext/aom/av1/encoder/encoder.c:4532:22
    #7 0x7ff7eaac67a5 in encoder_encode D:/Cpp/libavif/ext/aom/av1/av1_cx_iface.c:3029:20
    #8 0x7ff7eaab8bfb in aom_codec_encode D:/Cpp/libavif/ext/aom/aom/src/aom_encoder.c:176:11
    #9 0x7ff7eaa8d443 in aomCodecEncodeImage D:/Cpp/libavif/src/codec_aom.c:974:33
    #10 0x7ff7eaa7d2f4 in avifEncoderAddImageInternal D:/Cpp/libavif/src/write.c:915:17
    #11 0x7ff7eaa7b690 in avifEncoderAddImage D:/Cpp/libavif/src/write.c:934:12
    #12 0x7ff7eaa542cb in libavif::(anonymous namespace)::ChangeSettingTest_DISABLED_ChangeDimension_Test::TestBody() D:/Cpp/libavif/tests/gtest/avifchangesettingtest.cc:186:5
    #13 0x7ffbebd58308 in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) (D:\Tools\msys64\clang64\bin\libgtest.dll+0x180038308)
    #14 0x7ffbebd3ce8a in testing::Test::Run() (D:\Tools\msys64\clang64\bin\libgtest.dll+0x18001ce8a)
    #15 0x7ffbebd3e16e in testing::TestInfo::Run() (D:\Tools\msys64\clang64\bin\libgtest.dll+0x18001e16e)
    #16 0x7ffbebd3ec57 in testing::TestSuite::Run() (D:\Tools\msys64\clang64\bin\libgtest.dll+0x18001ec57)
    #17 0x7ffbebd4f2ab in testing::internal::UnitTestImpl::RunAllTests() (D:\Tools\msys64\clang64\bin\libgtest.dll+0x18002f2ab)
    #18 0x7ffbebd59168 in bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) (D:\Tools\msys64\clang64\bin\libgtest.dll+0x180039168)
    #19 0x7ffbebd4eadf in testing::UnitTest::Run() (D:\Tools\msys64\clang64\bin\libgtest.dll+0x18002eadf)
    #20 0x7ffbefab1434 in main (D:\Tools\msys64\clang64\bin\libgtest_main.dll+0x180001434)
    #21 0x7ff7eaa513ad in __tmainCRTStartup C:/M/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/crtexe.c:329:15
    #22 0x7ff7eaa514e5 in mainCRTStartup C:/M/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/crtexe.c:206:9
    #23 0x7ffc008f54df  (C:\WINDOWS\System32\KERNEL32.DLL+0x1800154df)
    #24 0x7ffc0224485a  (C:\WINDOWS\SYSTEM32\ntdll.dll+0x18000485a)

0x126071520997 is located 0 bytes to the right of 1047-byte region [0x126071520580,0x126071520997)
allocated by thread T0 here:
    #0 0x7ffb7dec100d in malloc (D:\Tools\msys64\clang64\bin\libclang_rt.asan_dynamic-x86_64.dll+0x18004100d)
    #1 0x7ff7eab2b08a in aom_memalign D:/Cpp/libavif/ext/aom/aom_mem/aom_mem.c:59:22
    #2 0x7ff7eab2b08a in aom_malloc D:/Cpp/libavif/ext/aom/aom_mem/aom_mem.c:67:40
    #3 0x7ff7eab2b08a in aom_calloc D:/Cpp/libavif/ext/aom/aom_mem/aom_mem.c:72:19
    #4 0x7ff7eabb8152 in av1_create_compressor D:/Cpp/libavif/ext/aom/av1/encoder/encoder.c:1387:3
    #5 0x7ff7eaac38be in av1_create_context_and_bufferpool D:/Cpp/libavif/ext/aom/av1/av1_cx_iface.c:2487:12
    #6 0x7ff7eaac38be in encoder_init D:/Cpp/libavif/ext/aom/av1/av1_cx_iface.c:2600:13
    #7 0x7ff7eaab8752 in aom_codec_enc_init_ver D:/Cpp/libavif/ext/aom/aom/src/aom_encoder.c:80:11
    #8 0x7ff7eaa8bcd0 in aomCodecEncodeImage D:/Cpp/libavif/src/codec_aom.c:726:13
    #9 0x7ff7eaa7d2f4 in avifEncoderAddImageInternal D:/Cpp/libavif/src/write.c:915:17
    #10 0x7ff7eaa7b690 in avifEncoderAddImage D:/Cpp/libavif/src/write.c:934:12
    #11 0x7ff7eaa54170 in libavif::(anonymous namespace)::ChangeSettingTest_DISABLED_ChangeDimension_Test::TestBody() D:/Cpp/libavif/tests/gtest/avifchangesettingtest.cc:183:5
    #12 0x7ffbebd58308 in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) (D:\Tools\msys64\clang64\bin\libgtest.dll+0x180038308)
    #13 0x7ffbebd3ce8a in testing::Test::Run() (D:\Tools\msys64\clang64\bin\libgtest.dll+0x18001ce8a)
    #14 0x7ffbebd3e16e in testing::TestInfo::Run() (D:\Tools\msys64\clang64\bin\libgtest.dll+0x18001e16e)
    #15 0x7ffbebd3ec57 in testing::TestSuite::Run() (D:\Tools\msys64\clang64\bin\libgtest.dll+0x18001ec57)
    #16 0x7ffbebd4f2ab in testing::internal::UnitTestImpl::RunAllTests() (D:\Tools\msys64\clang64\bin\libgtest.dll+0x18002f2ab)
    #17 0x7ffbebd59168 in bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) (D:\Tools\msys64\clang64\bin\libgtest.dll+0x180039168)
    #18 0x7ffbebd4eadf in testing::UnitTest::Run() (D:\Tools\msys64\clang64\bin\libgtest.dll+0x18002eadf)
    #19 0x7ffbefab1434 in main (D:\Tools\msys64\clang64\bin\libgtest_main.dll+0x180001434)
    #20 0x7ff7eaa513ad in __tmainCRTStartup C:/M/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/crtexe.c:329:15
    #21 0x7ff7eaa514e5 in mainCRTStartup C:/M/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/crtexe.c:206:9
    #22 0x7ffc008f54df  (C:\WINDOWS\System32\KERNEL32.DLL+0x1800154df)
    #23 0x7ffc0224485a  (C:\WINDOWS\SYSTEM32\ntdll.dll+0x18000485a)

SUMMARY: AddressSanitizer: heap-buffer-overflow (D:\Tools\msys64\clang64\bin\libclang_rt.asan_dynamic-x86_64.dll+0x180040b8b) in __asan_memset
Shadow bytes around the buggy address:
  0x047a7f7a40e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x047a7f7a40f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x047a7f7a4100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x047a7f7a4110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x047a7f7a4120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x047a7f7a4130: 00 00[07]fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x047a7f7a4140: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x047a7f7a4150: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x047a7f7a4160: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x047a7f7a4170: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x047a7f7a4180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==62176==ABORTING

@wantehchang wantehchang left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yuan: I reviewed everything except the avifRWStreamWrite parts of src/write.c and the decoder part of the new test in avifchangesettingtest.cc. I believe your changes to src/codec_aom.c. So this looks like a libaom bug that certain arrays are allocated to the size of the initial values of cfg.g_w and cfg.g_h.

Comment thread src/write.c Outdated
Comment thread include/avif/avif.h Outdated
Comment thread src/write.c Outdated
@wantehchang

Copy link
Copy Markdown
Member

Yuan: Please test this libaom patch. It is likely to be incomplete (e.g., the VMAF and BUTTERAUGLI code may also need the same changes).

diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 65d3a10..8e866a4 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -1355,8 +1355,21 @@ AV1_COMP *av1_create_compressor(AV1_PRIMARY *ppi, const AV1EncoderConfig *oxcf,
   av1_set_speed_features_framesize_independent(cpi, oxcf->speed);
   av1_set_speed_features_framesize_dependent(cpi, oxcf->speed);
 
+  int max_mi_cols = mi_params->mi_cols;
+  int max_mi_rows = mi_params->mi_rows;
+  if (oxcf->frm_dim_cfg.forced_max_frame_width) {
+    const int aligned_width =
+        ALIGN_POWER_OF_TWO(oxcf->frm_dim_cfg.forced_max_frame_width, 3);
+    max_mi_cols = aligned_width >> MI_SIZE_LOG2;
+  }
+  if (oxcf->frm_dim_cfg.forced_max_frame_height) {
+    const int aligned_height =
+        ALIGN_POWER_OF_TWO(oxcf->frm_dim_cfg.forced_max_frame_height, 3);
+    max_mi_rows = aligned_height >> MI_SIZE_LOG2;
+  }
+
   CHECK_MEM_ERROR(cm, cpi->consec_zero_mv,
-                  aom_calloc((mi_params->mi_rows * mi_params->mi_cols) >> 2,
+                  aom_calloc((max_mi_rows * max_mi_cols) >> 2,
                              sizeof(*cpi->consec_zero_mv)));
 
   cpi->mb_weber_stats = NULL;
@@ -1366,8 +1379,8 @@ AV1_COMP *av1_create_compressor(AV1_PRIMARY *ppi, const AV1EncoderConfig *oxcf,
     const int bsize = BLOCK_16X16;
     const int w = mi_size_wide[bsize];
     const int h = mi_size_high[bsize];
-    const int num_cols = (mi_params->mi_cols + w - 1) / w;
-    const int num_rows = (mi_params->mi_rows + h - 1) / h;
+    const int num_cols = (max_mi_cols + w - 1) / w;
+    const int num_rows = (max_mi_rows + h - 1) / h;
     CHECK_MEM_ERROR(cm, cpi->ssim_rdmult_scaling_factors,
                     aom_calloc(num_rows * num_cols,
                                sizeof(*cpi->ssim_rdmult_scaling_factors)));

@wantehchang

Copy link
Copy Markdown
Member

I discussed this issue with my colleague Marco Paniconi, who works on real-time encoding and SVC in libaom. Marco told me that they don't use g_forced_max_frame_width and g_forced_max_frame_height. Instead, they set g_w and g_h to the fixed size of the frames (the frames come from the camera and therefore have the same size) and then let libaom downscale the frames internally for certain spatial layers. Please see examples/svc_encoder_rtc.c in libaom. We should switch to this approach.

Although AVIF allows the images in an image sequence to have different sizes, the libavif encoder does not need to support that. (The libavif decoder supports that.)

@tongyuantongyu tongyuantongyu left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please test this libaom patch

Thaks for the patch. I confirm that after patch libaom encodes correctly.

let libaom downscale the frames internally for certain spatial layers

Actually I'm planning to support both. Use libaom internal scaler is more convenient for basic usage with only one input image, but if user wants more flexibility (e.g. using small blurred "thumbnail" as first layer) input image of different size can be both more efficient and convenient.

Earlier this year I reported two bugs in libaom's internal scaler. I see aomedia:3210 is fixed by a recent commit https://aomedia-review.googlesource.com/c/aom/+/161961. For aomedia:3203 I have an old CL, but I can't figure out how to update it because it's targeting master branch, so I created a new one instead.

Comment thread include/avif/avif.h Outdated
@tongyuantongyu

Copy link
Copy Markdown
Contributor Author

With the latest tip of libaom all added test cases passes.

to the fixed size of the frames (the frames come from the camera and therefore have the same size) then let libaom downscale the frames internally for certain spatial layers. Please see examples/svc_encoder_rtc.c in libaom. We should switch to this approach.

AVIF use case is different here: we want to use different images for each layer (like the low resolution blurry preview example I mentioned) - instead of sending the same frame many times to encode scalable video. So the SVC approach puts user into an awkward situation: they need to upscale the first layer to match frame size, and then libaom downscales it back. This is inefficient, and upscale-downscale roundtrip can be lossy.

@tongyuantongyu
tongyuantongyu force-pushed the var-frame-size branch 2 times, most recently from 4761eb5 to 5e208db Compare January 15, 2023 12:50
@tongyuantongyu
tongyuantongyu marked this pull request as ready for review January 15, 2023 13:25
@tongyuantongyu
tongyuantongyu marked this pull request as draft September 13, 2023 14:25
cyh5272 pushed a commit to cyh5272/aom that referenced this pull request May 6, 2024
Based on the libavif avifchangedimensiontest
AOMDecreasing/ChangeDimensionTest.EncodeDecode/0 in
AOMediaCodec/libavif#1069
by Yuan Tong.

Test:
test_libaom --gtest_filter=*DimensionDecreasing \
    --gtest_also_run_disabled_tests

Bug: aomedia:3348
Change-Id: I8be3c092234f99402c02aa03340c916f629ce0f2
cyh5272 pushed a commit to cyh5272/aom that referenced this pull request May 6, 2024
Based on the libavif avifchangedimensiontest
AOMDecreasing/ChangeDimensionTest.EncodeDecode/0 in
AOMediaCodec/libavif#1069
by Yuan Tong.

Test:
test_libaom --gtest_filter=*DimensionDecreasing \
    --gtest_also_run_disabled_tests

Bug: aomedia:3348
Change-Id: I79aea87012cc3bea43d565911ac88816c860e737
cyh5272 pushed a commit to cyh5272/aom that referenced this pull request May 6, 2024
Based on the libavif avifchangedimensiontest
AOMDecreasing/ChangeDimensionTest.EncodeDecode/0 in
AOMediaCodec/libavif#1069
by Yuan Tong.

Test:
test_libaom --gtest_filter=*DimensionDecreasing \
    --gtest_also_run_disabled_tests

Bug: aomedia:3348
Change-Id: I79aea87012cc3bea43d565911ac88816c860e737
@tongyuantongyu
tongyuantongyu force-pushed the var-frame-size branch 6 times, most recently from 7958220 to c2a0f52 Compare March 19, 2026 15:36
@tongyuantongyu tongyuantongyu changed the title Support changing frame size during encoding Support different sizes for each image layer Mar 19, 2026
@tongyuantongyu

Copy link
Copy Markdown
Contributor Author

@wantehchang I'm reviving this PR as recent development in AOM seem to have fixed the crash.

@juliobbv-p Thank you for your hard work!

@tongyuantongyu
tongyuantongyu marked this pull request as ready for review March 23, 2026 13:26
@tongyuantongyu

Copy link
Copy Markdown
Contributor Author

@juliobbv-p

Sorry for the late reply. I tested against many resolution sets and verified that:

  • aom and dav1d always decode to exactly the same output
  • Quality=100 is always lossless
  • Quality=95 PSNR always > 45
  • 8 and 10 bit, YUV420, 422, 444 all passed

Test code: https://gist.github.com/tongyuantongyu/61f9910ffdaf26a384342cbde4abf718

@tongyuantongyu tongyuantongyu changed the title Support different sizes for each image layer Support rendered size override for layered image Aug 8, 2026
@tongyuantongyu

Copy link
Copy Markdown
Contributor Author

@wantehchang @juliobbv-p Is there anything I'm missing, or we can move forward the review of this PR?

@wantehchang

Copy link
Copy Markdown
Member

Yuan: I have started reviewing this PR. I created a copy of this PR in https://aomedia-review.googlesource.com/c/libavif/+/216021 so that I can view it using Gerrit. I will post my review comments here.

Comment thread src/codec_svt.c Outdated
Comment thread src/write.c
Comment thread src/write.c Outdated
Comment thread src/write.c
Comment thread apps/avifenc.c
Comment thread apps/avifenc.c
Comment thread include/avif/avif.h Outdated
Comment thread src/codec_aom.c Outdated
Comment thread src/codec_aom.c
Comment thread src/write.c
if (avifEncoderUsesRenderedSizeOverride(encoder)) {
encoder->data->imageMetadata->width = encoder->width;
encoder->data->imageMetadata->height = encoder->height;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMPORTANT: Doing it this way is convenient, but it will break the code that assumes imageMetadata->width/height is firstCell->width/height, and it is difficult to track down all such code and verify nothing is broken.

For example, imageMetadata is passed to avifRWStreamWriteProperties(), which has the following code:

            // 'clap' is treated as 'irot'/'imir', although it could differ between the base and
            // gain map image items if these have different dimensions.
            if (imageMetadata->transformFlags & AVIF_TRANSFORM_CLAP) {
                AVIF_CHECKERR(imageMetadata->width != itemMetadata->width || imageMetadata->height != itemMetadata->height,
                              AVIF_RESULT_NOT_IMPLEMENTED);
            }

It is not clear to me whether that code is still correct if imageMetadata->width/height is equal to encoder->width/height.

So I recommend using encoder->width/height explicitly even though it will require more changes.

@tongyuantongyu tongyuantongyu Aug 30, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My reasoning is:

It is equivalent (maybe there are some nuances in AV1 bitstream, but I expect no difference in AVIF container level) between

  • adding a full-size image and set encoder->scalingMode, and
  • adding a scaled image and set encoder->width/height:

either way the AV1 bitstream encodes, and will be decoded into a scaled frame. During decode the first thing to do is scaling it back to what the AVIF container declares (which I call it "rendered size"):

libavif/src/read.c

Lines 6898 to 6908 in cbb391c

// Scale the decoded image so that it corresponds to this tile's output dimensions
if ((tile->width != tile->image->width) || (tile->height != tile->image->height)) {
if (avifImageScaleWithLimit(tile->image,
tile->width,
tile->height,
decoder->imageSizeLimit,
decoder->imageDimensionLimit,
&decoder->diag) != AVIF_RESULT_OK) {
return avifGetErrorForItemCategory(tile->input->itemCategory);
}
}

So if it's an imageMetadata, or in another word AVIF container level thing, using encoder->width/height should always be the correct answer, otherwise using firstCell->width/height would also be wrong if encoder->scalingMode is used.

And I have checked that all read to imageMetadata is for image metadata, and nobody is using its value to access pixels.

@tongyuantongyu tongyuantongyu changed the title Support rendered size override for layered image Support display size override for layered image Aug 30, 2026
@tongyuantongyu

Copy link
Copy Markdown
Contributor Author

@wantehchang the fuzztest failure is due to a general issue about how we handle quality and quantize settings: #3344.

@wantehchang

Copy link
Copy Markdown
Member

Yuan: I will review this pull request today.

Comment thread apps/avifenc.c
uint64_t creationTime;
uint64_t modificationTime;
uint32_t width;
uint32_t height;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yuan: Please apply the patch below and review my proposed changes. I moved some code around and edited some comments.

In places where my comment edits may not be easy to see, I also added review comments to describe my edits. In those places my review comments will say "(See patch.)"

Here is my proposed patch:

diff --git a/apps/avifenc.c b/apps/avifenc.c
index b45094e9..d8dad2cc 100644
--- a/apps/avifenc.c
+++ b/apps/avifenc.c
@@ -2230,7 +2230,7 @@ int main(int argc, char * argv[])
         goto cleanup;
     }
     if (avifSettingsUsesDisplaySizeOverride(&settings) && (settings.layers == 1) && (input.filesCount > 1)) {
-        fprintf(stderr, "ERROR: --display-size is not supported with image sequences. Use --layered for multiple still inputs.\n");
+        fprintf(stderr, "ERROR: --display-size is not supported with image sequences. Use --layered for multiple still image inputs.\n");
         goto cleanup;
     }
 
diff --git a/include/avif/avif.h b/include/avif/avif.h
index 231b8550..556359cb 100644
--- a/include/avif/avif.h
+++ b/include/avif/avif.h
@@ -822,10 +822,11 @@ typedef struct avifImage
     // transformFlags. On decode, only honor the values in boxes with the associated transform flag set.
     // These also apply to gainMap->image, if any.
     //
-    // When encoding with avifEncoder.width/height set (see its comment), these values are interpreted
-    // relative to that overridden display size rather than to this avifImage's own width/height.
-    // No special handling is needed during decode: the decoded avifImage is automatically scaled to
-    // the display size, so these values are relative to its width/height as usual.
+    // When encoding with avifEncoder.width/height set (see their comment), these transformations
+    // are interpreted relative to that overridden display size rather than to this avifImage's own
+    // width/height. No special handling is needed during decode: the decoded avifImage is
+    // automatically scaled to the display size, so these transformations are relative to the
+    // decoded avifImage's width/height as usual.
     avifTransformFlags transformFlags;
     avifPixelAspectRatioBox pasp;
     avifCleanApertureBox clap;
@@ -1638,7 +1639,7 @@ typedef struct avifEncoder
     // Overrides the image's display size (the width and height AVIF declares this image is meant
     // to be shown at) independent of the pixel dimensions actually encoded. Any image passed to
     // avifEncoderAddImage()/avifEncoderAddImageGrid() that is encoded smaller than the display size
-    // is upscaled to it on decode.
+    // is upscaled to the display size on decode.
     //
     // Defaults to 0 (disabled). When 0, the display size is the size of the first added image.
     // When set, both width and height must be nonzero, and neither can be smaller than the coded
@@ -1661,9 +1662,9 @@ typedef struct avifEncoder
     // decoder is required to honor; a coded image smaller than it is upscaled by the decoder to
     // match. Separately, an AV1 encoder session declares a maximum frame size once, up front, and
     // every later frame must fit within it; by default that maximum is simply the size of the first
-    // frame encoded. Setting width/height also declares that AV1-level maximum explicitly, in
-    // addition to the ispe box, so that later, larger layers stay within it. This is why it must be
-    // at least as large as every layer's coded size.
+    // frame encoded. Setting width/height also declares that AV1-level maximum frame size
+    // explicitly, in addition to the ispe box, so that later, larger layers stay within it. This is
+    // why it must be at least as large as every layer's coded size.
     uint32_t width;
     uint32_t height;
 } avifEncoder;
diff --git a/src/codec_aom.c b/src/codec_aom.c
index 9f23c620..8edd3f8a 100644
--- a/src/codec_aom.c
+++ b/src/codec_aom.c
@@ -893,14 +893,20 @@ static avifResult aomCodecEncodeImage(avifCodec * codec,
             }
         }
 
-        if ((addImageFlags & AVIF_ADD_IMAGE_FLAG_SINGLE) && (encoder->width == 0) && (encoder->height == 0)) {
+        if (addImageFlags & AVIF_ADD_IMAGE_FLAG_SINGLE) {
             // Set the maximum number of frames to encode to 1. This instructs
             // libaom to set still_picture and reduced_still_picture_header to
             // 1 in AV1 sequence headers.
-            // Still picture header requires frame size to match
-            // max_frame_width and max_frame_height,
-            // so we can't use it if frame can have a different size.
             cfg->g_limit = 1;
+            // Reduced still picture header requires frame size to match max
+            // frame size, so we can't use reduced still picture header if frame
+            // size is different from max frame size.
+            if (cfg->g_forced_max_frame_width > image->width) {
+                cfg->g_forced_max_frame_width = image->width;
+            }
+            if (cfg->g_forced_max_frame_height > image->height) {
+                cfg->g_forced_max_frame_height = image->height;
+            }
         }
         if (useAllIntra) {
 #if !defined(AOM_USAGE_ALL_INTRA)
@@ -939,7 +945,7 @@ static avifResult aomCodecEncodeImage(avifCodec * codec,
             cfg->g_lag_in_frames = 0;
         }
         if ((encoder->width || encoder->height) && (cfg->g_lag_in_frames > 1)) {
-            // libaom does not allow changing frame dimension if
+            // aom_codec_enc_config_set() does not allow changing frame dimensions if
             // g_lag_in_frames > 1.
             cfg->g_lag_in_frames = 1;
         }
diff --git a/src/codec_avm.c b/src/codec_avm.c
index adf26990..ad829fc8 100644
--- a/src/codec_avm.c
+++ b/src/codec_avm.c
@@ -444,6 +444,11 @@ static avifResult avmCodecEncodeImage(avifCodec * codec,
                                       avifAddImageFlags addImageFlags,
                                       avifCodecEncodeOutput * output)
 {
+    if (encoder->width || encoder->height) {
+        avifDiagnosticsPrintf(codec->diag, "AVM does not support display-size override");
+        return AVIF_RESULT_NOT_IMPLEMENTED;
+    }
+
     struct avm_codec_enc_cfg * cfg = &codec->internal->cfg;
     avifBool quantizerUpdated = AVIF_FALSE;
     const int quantizer = avmQualityToQuantizer(quality, image->depth);
@@ -453,11 +458,6 @@ static avifResult avmCodecEncodeImage(avifCodec * codec,
     // two fields.
     encoderChanges &= ~AVIF_ENCODER_CHANGE_SCALING_MODE;
 
-    if (encoder->width || encoder->height) {
-        avifDiagnosticsPrintf(codec->diag, "AVM does not support display-size override");
-        return AVIF_RESULT_NOT_IMPLEMENTED;
-    }
-
     if (!codec->internal->encoderInitialized) {
         int avmCpuUsed = -1;
         if (encoder->speed != AVIF_SPEED_DEFAULT) {
diff --git a/src/codec_rav1e.c b/src/codec_rav1e.c
index 4b41bfeb..d94553d2 100644
--- a/src/codec_rav1e.c
+++ b/src/codec_rav1e.c
@@ -82,6 +82,12 @@ static avifResult rav1eCodecEncodeImage(avifCodec * codec,
         return AVIF_RESULT_NOT_IMPLEMENTED;
     }
 
+    // rav1e does not support overriding maximum frame width/height in sequence header
+    if (encoder->width || encoder->height) {
+        avifDiagnosticsPrintf(codec->diag, "rav1e does not support display-size override");
+        return AVIF_RESULT_NOT_IMPLEMENTED;
+    }
+
     // rav1e does not support encoding layered image.
     if (encoder->extraLayerCount > 0) {
         return AVIF_RESULT_NOT_IMPLEMENTED;
@@ -90,12 +96,6 @@ static avifResult rav1eCodecEncodeImage(avifCodec * codec,
     // rav1e does not support disabling lagged output. See https://github.com/xiph/rav1e/issues/2267. Ignore this setting.
     (void)disableLaggedOutput;
 
-    // rav1e does not support overriding maximum frame width/height in sequence header
-    if (encoder->width || encoder->height) {
-        avifDiagnosticsPrintf(codec->diag, "rav1e does not support display-size override");
-        return AVIF_RESULT_NOT_IMPLEMENTED;
-    }
-
     avifResult result = AVIF_RESULT_UNKNOWN_ERROR;
 
     RaConfig * rav1eConfig = NULL;
diff --git a/src/codec_svt.c b/src/codec_svt.c
index 70be13fa..71bdac06 100644
--- a/src/codec_svt.c
+++ b/src/codec_svt.c
@@ -75,6 +75,11 @@ static avifResult svtCodecEncodeImage(avifCodec * codec,
         }
     }
 
+    if (encoder->width || encoder->height) {
+        avifDiagnosticsPrintf(codec->diag, "SVT-AV1 does not support display-size override");
+        return AVIF_RESULT_NOT_IMPLEMENTED;
+    }
+
     // SVT-AV1 does not support encoding layered image.
     if (encoder->extraLayerCount > 0) {
         return AVIF_RESULT_NOT_IMPLEMENTED;
@@ -83,11 +88,6 @@ static avifResult svtCodecEncodeImage(avifCodec * codec,
     // SVT-AV1 does not support disabling lagged output. Ignore this setting.
     (void)disableLaggedOutput;
 
-    if (encoder->width || encoder->height) {
-        avifDiagnosticsPrintf(codec->diag, "SVT-AV1 does not support display-size override");
-        return AVIF_RESULT_NOT_IMPLEMENTED;
-    }
-
     avifResult result = AVIF_RESULT_UNKNOWN_ERROR;
     EbColorFormat color_format = EB_YUV420;
     uint8_t * uvPlanes = NULL; // 4:2:0 U and V placeholder for alpha because SVT-AV1 does not support 4:0:0.
diff --git a/src/write.c b/src/write.c
index 59095ac5..3da38e2a 100644
--- a/src/write.c
+++ b/src/write.c
@@ -525,8 +525,6 @@ avifEncoder * avifEncoderCreate(void)
     encoder->maxQuantizer = AVIF_QUANTIZER_WORST_QUALITY;
     encoder->minQuantizerAlpha = AVIF_QUANTIZER_BEST_QUALITY;
     encoder->maxQuantizerAlpha = AVIF_QUANTIZER_WORST_QUALITY;
-    encoder->width = 0;
-    encoder->height = 0;
     encoder->tileRowsLog2 = 0;
     encoder->tileColsLog2 = 0;
     encoder->autoTiling = AVIF_FALSE;
@@ -541,6 +539,8 @@ avifEncoder * avifEncoderCreate(void)
     encoder->creationTime = 0;
     encoder->modificationTime = 0;
     encoder->sampleTransformRecipe = AVIF_SAMPLE_TRANSFORM_NONE;
+    encoder->width = 0;
+    encoder->height = 0;
     return encoder;
 }
 
@@ -574,8 +574,6 @@ static void avifEncoderBackupSettings(avifEncoder * encoder)
     lastEncoder->timescale = encoder->timescale;
     lastEncoder->repetitionCount = encoder->repetitionCount;
     lastEncoder->extraLayerCount = encoder->extraLayerCount;
-    lastEncoder->width = encoder->width;
-    lastEncoder->height = encoder->height;
     lastEncoder->minQuantizer = encoder->minQuantizer;
     lastEncoder->maxQuantizer = encoder->maxQuantizer;
     lastEncoder->minQuantizerAlpha = encoder->minQuantizerAlpha;
@@ -586,6 +584,8 @@ static void avifEncoderBackupSettings(avifEncoder * encoder)
     encoder->data->lastTileColsLog2 = encoder->data->tileColsLog2;
     lastEncoder->scalingMode = encoder->scalingMode;
     lastEncoder->sampleTransformRecipe = encoder->sampleTransformRecipe;
+    lastEncoder->width = encoder->width;
+    lastEncoder->height = encoder->height;
 }
 
 // This function detects changes made on avifEncoder. It returns true on success (i.e., if every
@@ -1598,7 +1598,7 @@ static avifCodecType avifEncoderGetCodecType(const avifEncoder * encoder)
     return avifCodecTypeFromChoice(encoder->codecChoice, AVIF_CODEC_FLAG_CAN_ENCODE);
 }
 
-static avifResult avifEncoderValidateDisplaySizeOverride(avifEncoder * encoder, uint32_t gridCols, uint32_t gridRows, const avifImage * firstCell)
+static avifResult avifEncoderValidateDisplaySizeOverride(const avifEncoder * encoder, uint32_t gridCols, uint32_t gridRows, const avifImage * firstCell)
 {
     if (!avifEncoderUsesDisplaySizeOverride(encoder)) {
         return AVIF_RESULT_OK;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. I have to revert the addition of const to avifEncoderValidateDisplaySizeOverride because this function need to write to the diag struct when it found some unsupported config.

Comment thread apps/avifenc.c Outdated
printf(" --layered : Encode a layered AVIF. Each input is encoded as one layer and at most %d layers can be encoded.\n",
AVIF_MAX_AV1_LAYER_COUNT);
printf(" --display-size WxH : Set the size at which the AVIF image is displayed, independent of the encoded pixel dimensions.\n");
printf(" Supported for still images and layered still images only.\n");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add an entry to CHANGELOG to summarize the new features in this PR (both the avifenc command-line option and the public header changes).

Comment thread apps/avifenc.c Outdated
Comment thread include/avif/avif.h Outdated
Comment thread include/avif/avif.h Outdated
// Version 1.4.0 ends here. Add any new members after this line.
// --------------------------------------------------------------------------------------------

// Overrides the image's display size (the width and height AVIF declares this image is meant

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[This is just a comment, not a request for change.] Display size is a good name for the new encoder setting. I studied the relevant standards. I found that this is called the "visual presentation size" in ISOBMFF. Also, the AV1 spec defines the render size as the "desired display size". So these terms are all equivalent. But presentation size is a little long, and the AV1 spec does not define whether a frame should be scaled or cropped to the render size. So let's go with display size.

Comment thread include/avif/avif.h Outdated
// than to the coded size of whichever layer they came from.
//
// Implementation note: the display size is stored as the ispe box, the dimensions an AVIF
// decoder is required to honor; a coded image smaller than it is upscaled by the decoder to

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[This is a comment, not a request for change. But this comment is noteworthy.] I found that scaling a coded image to the dispay size is only specified for tracks (which are used for AVIF image sequences) in ISOBMFF. But I did not find any standard that says image items (which are used for AVIF still images) should be scaled to the size in the ispe box. So the scaling of image items to the size in the ispe box seems to be a nonstandard behavior of libavif. If you have spare time, could you also research this?

I think it is too late to change libavif's behavior. I just wanted to verify my understanding.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realized ourselves - the AVIF standard - has a stricter rule:

https://aomediacodec.github.io/av1-avif/v1.2.0.html#image-spatial-extents-property

More specifically, for [AV1] images, the values of image_width and image_height shall respectively equal the values of UpscaledWidth and FrameHeight ... for a specific frame ...

NOTE: The dimensions of possible intermediate output images might not match the ones given in the 'ispe' property. If renderers display these intermediate images, they are expected to scale the output image to match the 'ispe' property.

This means we can get rid of the "display size" concept. It's just the size, but for layered image that size must be informed beforehand.

On the decoder side, I'm not sure if we should tighten the checks, but on the encoder side I'm changing to follow the rules.

Comment thread include/avif/avif.h Outdated
Comment thread include/avif/avif.h Outdated
// every later frame must fit within it; by default that maximum is simply the size of the first
// frame encoded. Setting width/height also declares that AV1-level maximum explicitly, in
// addition to the ispe box, so that later, larger layers stay within it. This is why it must be
// at least as large as every layer's coded size.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[This is just a comment, not a request for change.] Nit: Thank you for adding details I requested. The new comment is longer than I expected. We can try to make it more concise later.

Comment thread src/codec_aom.c Outdated
// 1 in AV1 sequence headers.
// Still picture header requires frame size to match
// max_frame_width and max_frame_height,
// so we can't use it if frame can have a different size.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pleae see if you like how I proposed to handle this issue in the patch.

(See patch.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is indeed better. I didn't realize that if there's only one image, there's no chance for a later larger image, so we don't need the sequence header max_frame_width thing.

Comment thread tests/gtest/avif_fuzztest_enc_dec_layered.cc Outdated
@tongyuantongyu

Copy link
Copy Markdown
Contributor Author

@wantehchang as stated I'm simplifying & tightening the implementation according to the AVIF spec. I need some more time to reimplement the avifenc support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants