Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update libavif #1381

Merged
merged 24 commits into from
Jan 24, 2024
Merged

Update libavif #1381

merged 24 commits into from
Jan 24, 2024

Conversation

aryanpingle
Copy link
Contributor

  • Update libavif for improved compression and speed
  • v1.0.0 deprecates usage of min and max-quantizers; we use quality and qualityAlpha instead
  • Renamed maxSpeed to MAX_EFFORT for better readability

* Update libavif for improved compression and speed
* v1.0.0 deprecates usage of min and max-quantizers; we use `quality` and `qualityAlpha` instead
* Renamed `maxSpeed` to `MAX_EFFORT` for better readability
@aryanpingle aryanpingle changed the title Update libavif (v1.0.0-main) Update libavif Sep 15, 2023
Copy link
Collaborator

@surma surma left a comment

Choose a reason for hiding this comment

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

Minor nit to avoid magic numbers, otherwise LGTM!

src/features/encoders/avif/client/index.tsx Outdated Show resolved Hide resolved
src/features/encoders/avif/client/index.tsx Outdated Show resolved Hide resolved
Copy link

@wantehchang wantehchang left a comment

Choose a reason for hiding this comment

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

Hi Aryan,

I will review this pull request tomorrow. Please wait for my review.

Copy link

@wantehchang wantehchang left a comment

Choose a reason for hiding this comment

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

Hi Aryan,

I reviewed all the files that look human readable. For avif_enc.cpp, I read the entire file.

I suggest some changes. Note that where I suggest the name qualityAlpha, you may replace it with alphaQuality. (qualityAlpha is the name used in avif/avif.h.)

codecs/avif/Makefile Outdated Show resolved Hide resolved
codecs/avif/enc/avif_enc.cpp Show resolved Hide resolved
codecs/avif/enc/avif_enc.cpp Show resolved Hide resolved
codecs/avif/enc/avif_enc.cpp Show resolved Hide resolved
codecs/avif/enc/avif_enc.cpp Show resolved Hide resolved
src/features/encoders/avif/client/index.tsx Outdated Show resolved Hide resolved
src/features/encoders/avif/client/index.tsx Outdated Show resolved Hide resolved
src/features/encoders/avif/client/index.tsx Outdated Show resolved Hide resolved
src/features/encoders/avif/client/index.tsx Outdated Show resolved Hide resolved
src/features/encoders/avif/client/index.tsx Outdated Show resolved Hide resolved
@aryanpingle
Copy link
Contributor Author

@wantehchang I'll go through your reviews now, thanks for replying so quickly 😄

@wantehchang
Copy link

Hi Aryan,

I am receiving notifications of changes to this pull request. I am afraid that I may miss something, so please ping me when you'd like me to review this pull request again. Thanks.

@aryanpingle
Copy link
Contributor Author

@wantehchang Yep I'm just resolving conversations as and when I push changes, maybe that's why you're getting so many notifications. My mid-terms just got over so I finally have some time to work on the PR - I'll send you a review request when I finish!

@aryanpingle
Copy link
Contributor Author

@wantehchang thanks for your reviews, I've fixed and refactored the code you suggested. Also, you mentioned on the AV1 Discussion forum:

Off the top of my head, I think you can expose the AVIF_CHROMA_DOWNSAMPLING_SHARP_YUV option for avifImageRGBToYUV()

I went through the avif.h documentation for the avifChromaDownsampling options, I didn't understand why the automatic / fastest / best quality downsampling options are marked as (same as AVERAGE). Does this mean they all serve the same purpose as of now?

If so, then maybe a checkbox called "Enable sharp YUV chroma downsampling" can be used to toggle between AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC and AVIF_CHROMA_DOWNSAMPLING_SHARP_YUV? Let me know what you think.

@aryanpingle
Copy link
Contributor Author

@wantehchang I think we got AVIF_CHROMA_DOWNSAMPLING_SHARP_YUV working now! Here's the deploy preview.

Copy link

@wantehchang wantehchang left a comment

Choose a reason for hiding this comment

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

Hi Aryan,

I read avif_enc.cpp carefully. I tried to read index.tsx and meta.ts as much as I could, but I only skimmed through the parts in index.tsx that you didn't modify.

codecs/avif/Makefile Show resolved Hide resolved
codecs/avif/Makefile Outdated Show resolved Hide resolved
$(OUT_NODE_ENC_JS) $(OUT_NODE_ENC_MT_JS): ENVIRONMENT=node
$(OUT_NODE_ENC_JS) $(OUT_ENC_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLists.txt
# ST-Encoding
$(OUT_ENC_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLists.txt $(LIBSHARPYUV)

Choose a reason for hiding this comment

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

I noticed you pass -DCONFIG_AV1_HIGHBITDEPTH=0 to libaom (e.g., in line 47). Do you only support bit depth 8 when encoding AVIF?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, for all codecs on Squoosh.

codecs/avif/enc/avif_enc.cpp Outdated Show resolved Hide resolved
codecs/avif/enc/avif_enc.cpp Outdated Show resolved Hide resolved
src/features/encoders/avif/client/index.tsx Outdated Show resolved Hide resolved
src/features/encoders/avif/client/index.tsx Outdated Show resolved Hide resolved
src/features/encoders/avif/client/index.tsx Outdated Show resolved Hide resolved
src/features/encoders/avif/client/index.tsx Outdated Show resolved Hide resolved
src/features/encoders/avif/client/index.tsx Outdated Show resolved Hide resolved
@wantehchang
Copy link

Aryan wrote:

I went through the avif.h documentation for the avifChromaDownsampling options, I didn't understand why the automatic / fastest / best quality downsampling options are marked as (same as AVERAGE). Does this mean they all serve the same purpose as of now?

Some of those "(same as AVERAGE)" should be changed to "(same as AVERAGE in the current implementation)". The reason is that the average filter is the only downsampling filter that libavif uses automatically. The Sharp YUV downsampling filter was added later and we are not sure if it should be one of the automatically-used downsampling filters.

NOTE: AVIF_CHROMA_DOWNSAMPLING_FASTEST will always be the same as AVERAGE.

If so, then maybe a checkbox called "Enable sharp YUV chroma downsampling" can be used to toggle between AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC and AVIF_CHROMA_DOWNSAMPLING_SHARP_YUV? Let me know what you think.

Agreed.

Copy link

@wantehchang wantehchang left a comment

Choose a reason for hiding this comment

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

LGTM! Just a few final minor issues.

do { \
if (val1 == val2) \
return val::null(); \
} while (false)

Choose a reason for hiding this comment

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

Optional: You can merge these two macros into RETURN_NULL_IF_FALSE that takes a conditional expression as the argument.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's so much better than the current macro LOL, thank you!

Choose a reason for hiding this comment

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

Note: I probably would not use a macro that saves only one line. But some people like to use this kind of macro so that the main flow of the code is not cluttered with error handling code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep that was my line of thinking. I'm pretty sure we'll be repeating that line again for other optimizations, so it's better to just have a macro for it.

codecs/avif/Makefile Outdated Show resolved Hide resolved
codecs/avif/enc/avif_enc.cpp Show resolved Hide resolved
codecs/avif/enc/avif_enc.cpp Show resolved Hide resolved
// 100 = lossless
int quality;
// As above, but -1 means 'use quality'
int qualityAlpha;

Choose a reason for hiding this comment

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

In a follow-up pull request, we should look into using the new autoTiling option of the AVIF encoder.

I suggest Squoosh set autoTiling to AVIF_TRUE by default. (The default of autoTiling in libavif is AVIF_FALSE for backward compatibility.) The Squoosh UI can have a "manual tiling" box, which when checked, shows the tileRowsLog2 and tileColsLog2 fields (both default to 0, meaning no tiling).

Copy link
Contributor Author

@aryanpingle aryanpingle Nov 2, 2023

Choose a reason for hiding this comment

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

Gotcha, I'll try to add it to this PR or at least make raise an issue for it. I assume autoTiling automatically chooses the best tileRowsLog2 and tileColsLog2, is there any more documentation about it that I can link to?

Choose a reason for hiding this comment

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

Unless this requires just simple changes, I suggest filing an issue for this and implementing this in a follow-up pull request. The review of this pull request has been going on for a while. We need to watch out for "code review fatigue."

You understand autoTiling correctly. The autoTiling algorithm may be tweaked in the future, so we didn't document the current algorithm in the public header avif/avif.h. You can find the current algorithm in libavif/src/write.c:

    if (encoder->autoTiling) {
        // Use as many tiles as allowed by the minimum tile area requirement and impose a maximum
        // of 8 tiles.
        const int threads = 8;
        avifSetTileConfiguration(threads, firstCell->width, firstCell->height, &encoder->data->tileRowsLog2, &encoder->data->tileColsLog2);
    }

I do think all the automatic tiling algorithms have some common elements, such as imposing a minimum tile area or tile width and height, and potentially imposing a maximum number of tiles. But I am not sure if you need to mention this. You can, however, say that the use of tiles makes it easier for the decoder to decode an AVIF image with multiple threads in parallel.

codecs/avif/enc/avif_enc.cpp Outdated Show resolved Hide resolved
@aryanpingle
Copy link
Contributor Author

@wantehchang implemented the changes, please give it a once-over if you find the time.
Totally agree about the code review fatigue so I've made a new issue referencing that comment thread.

@aryanpingle
Copy link
Contributor Author

aryanpingle commented Nov 3, 2023

Enabling the ERROR_ON_UNDEFINED_SYMBOLS=0 flag in the Makefile was a hacky solution to get rid of this error:

error: undefined symbol: setjmp (referenced by top-level compiled C/C++ code)
warning: Link with `-s LLD_REPORT_UNDEFINED` to get more information on undefined symbols
warning: To disable errors for undefined symbols use `-s ERROR_ON_UNDEFINED_SYMBOLS=0`
warning: _setjmp may need to be added to EXPORTED_FUNCTIONS if it arrives from a system library

It might be a compiler bug.
Regardless, @surma found that bumping the Emscripten version to 3.1.47 fixes this issue. Might be worth updating the version for all codec binaries.

Copy link

@wantehchang wantehchang left a comment

Choose a reason for hiding this comment

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

LGTM!

@z11h
Copy link

z11h commented Jan 3, 2024

any idea about when this will get merged and pushed to squoosh.app? thanks!

@grandpa1946
Copy link

any idea about when this will get merged and pushed to squoosh.app? thanks!

you can always check at the bottom of the page where it says "changes approved" & you should click on "Details" to the right of deploy/netlify

@jakearchibald
Copy link
Collaborator

jakearchibald commented Jan 24, 2024

@wantehchang it won't block this PR, but is the experimental progressive stuff in avifenc worth exposing? Also, is there any compression benefit to premultiplying alpha, or is it just an input option?

@jakearchibald jakearchibald merged commit e217740 into GoogleChromeLabs:dev Jan 24, 2024
7 checks passed
@wantehchang
Copy link

@jakearchibald Hi Jake,

You can expose the encoding of progressive (layered) images if it is clearly marked as experimental in the UI.

There could be compression benefit to premultiplying alpha (see Note below). But the main benefit that after the image is decoded, we don't need to multiply it with alpha. We just need to multiply the backgroud with 1 - alpha. So the decoder has less work to do.

Note: If the alpha channel has a lot of zero or near-zero values, the alpha-premultiplied image will have a lot of zero or near-zero values, so it should result in a smaller compressed file.

@jamsinclair
Copy link
Contributor

Seems like single threaded AVIF encoding may have broken with this change. From my limited debugging it looks like a memory issue. The output handle seems to be no longer available when passing the value back to JS? 🤔

TypeError: emval_handle_array[handle] is undefined

@jakearchibald
Copy link
Collaborator

@jamsinclair thank you. We'll look into it.

@jakearchibald
Copy link
Collaborator

@wantehchang Thanks for the details! Do any browsers support rendering of progressive AVIF? (as in, rendering before the file has fully downloaded)

@wantehchang
Copy link

@jakearchibald Jake: Chrome and Microsoft Edge (Edge 121 supports AVIF) support progressive rendering of AVIF layered images.

Firefox doesn't support progressive rendering of AVIF layered images, based on inspection of its source code (by searching for "layer" and "progressive" in image/decoders/nsAVIFDecoder.{h,cpp}).

I will get back to you on Safari's support.

@leo-barnes
Copy link

leo-barnes commented Jan 26, 2024

@jakearchibald Jake: Chrome and Microsoft Edge (Edge 121 supports AVIF) support progressive rendering of AVIF layered images.

Firefox doesn't support progressive rendering of AVIF layered images, based on inspection of its source code (by searching for "layer" and "progressive" in image/decoders/nsAVIFDecoder.{h,cpp}).

I will get back to you on Safari's support.

It should be supported in Safari to the best of my knowledge.

@jakearchibald
Copy link
Collaborator

Chrome support at least makes it interesting 😀

jamsinclair added a commit to jamsinclair/jSquash that referenced this pull request Apr 3, 2024
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.

8 participants