-
Notifications
You must be signed in to change notification settings - Fork 280
Use Tune IQ for layered image inter-frame encoding #3068
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -666,16 +666,25 @@ static avifResult aomCodecEncodeImage(avifCodec * codec, | |
| codec->internal->qualityFirstLayer = quality; | ||
| } | ||
|
|
||
| // Determine whether the encoder should be configured to use intra frames only, either by setting aomUsage to AOM_USAGE_ALL_INTRA, | ||
| // or by manually configuring the encoder so all frames will be key frames (if AOM_USAGE_ALL_INTRA isn't available). | ||
| // Determine whether the encoder should be configured to use intra frames only, either by setting aomUsage to | ||
| // AOM_USAGE_ALL_INTRA, or by manually configuring the encoder so all frames will be key frames (if AOM_USAGE_ALL_INTRA isn't | ||
| // available). | ||
|
|
||
| // All-intra encoding is beneficial when encoding a two-layer image item and the quality of the first layer is very low. | ||
| // Switching to all-intra encoding comes with the following benefits: | ||
| // For libaom versions older than 3.14.0, all-intra encoding is beneficial when encoding a two-layer image item and the | ||
| // quality of the first layer is very low. Switching to all-intra encoding comes with the following benefits: | ||
| // - The first layer will be smaller than the second layer (which is often not the case with inter encoding) | ||
| // - Outputs have predictable file sizes: the sum of the first layer (quality <= 10) plus the second layer (quality set by the caller) | ||
| // - Because the first layer is very small, layered encoding overhead is also smaller and more stable (about 5-8% for quality 40 and 2-4% for quality 60) | ||
| // - Option of choosing tune IQ (which requires AOM_USAGE_ALL_INTRA) | ||
| avifBool useAllIntraForLayered = encoder->extraLayerCount == 1 && | ||
| // - Outputs have predictable file sizes: the sum of the first layer (quality <= 10) plus the second layer (quality set by | ||
| // the caller) | ||
| // - Because the first layer is very small, layered encoding overhead is also smaller and more stable (about 5-8% for quality | ||
| // 40 and 2-4% for quality 60) | ||
| // Note: libaom 3.14.0 introduces a mechanism to completely control each layer's QP, and extends tune IQ to inter-frame | ||
| // encoding modes (AOM_USAGE_GOOD_QUALITY and AOM_USAGE_REALTIME), so there's no need to use all-intra encoding for layered. | ||
|
|
||
| // aom_codec.h says: aom_codec_version() == (major<<16 | minor<<8 | patch) | ||
| // TODO(wtc): Update constant with the libaom version that contains the layered-encoding improvements | ||
| static const int aomVersion_3_14_0 = INT_MAX; | ||
| const int aomVersion = aom_codec_version(); | ||
juliobbv-p marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| avifBool useAllIntraForLayered = aomVersion < aomVersion_3_14_0 && encoder->extraLayerCount == 1 && | ||
| codec->internal->qualityFirstLayer <= TWO_LAYER_ALL_INTRA_QUALITY_THRESHOLD; | ||
| // Also use all-intra encoding when encoding still images. | ||
| avifBool useAllIntra = (addImageFlags & AVIF_ADD_IMAGE_FLAG_SINGLE) || useAllIntraForLayered; | ||
|
|
@@ -713,9 +722,7 @@ static avifResult aomCodecEncodeImage(avifCodec * codec, | |
| } | ||
| } | ||
|
|
||
| // aom_codec.h says: aom_codec_version() == (major<<16 | minor<<8 | patch) | ||
| static const int aomVersion_2_0_0 = (2 << 16); | ||
| const int aomVersion = aom_codec_version(); | ||
| if (aomVersion <= aomVersion_2_0_0) { | ||
| // Issue with v1.0.0-errata1-avif: https://github.com/AOMediaCodec/libavif/issues/56 | ||
| // Issue with v2.0.0: https://aomedia-review.googlesource.com/q/I26a39791f820b4d4e1d63ff7141f594c3c7181f5 | ||
|
|
@@ -752,13 +759,18 @@ static avifResult aomCodecEncodeImage(avifCodec * codec, | |
| // AOM_TUNE_IQ has been tuned for the YCbCr family of color spaces, and is favored for | ||
| // its low perceptual distortion. AOM_TUNE_IQ partially generalizes to, and benefits | ||
| // from other "YUV-like" spaces (e.g. YCgCo and ICtCp) including monochrome (luma only). | ||
| // AOM_TUNE_IQ sets --deltaq-mode=6 which can only be used in all intra mode. | ||
| // | ||
| // AOM_TUNE_IQ was introduced in libaom v3.12.0 but it has significantly different bit | ||
| // allocation characteristics compared to v3.13.0. AOM_TUNE_IQ is used by default | ||
| // starting with v3.13.0 for fewer behavior changes in libavif. | ||
| // | ||
| // Starting with libaom v3.14.0, AOM_TUNE_IQ supports all-intra, good-quality and | ||
| // realtime modes (for single and layered images). Prior to v3.14.0, AOM_TUNE_IQ is only | ||
| // supported in all-intra mode. | ||
| static const int aomVersion_3_13_0 = (3 << 16) | (13 << 8); | ||
| if (image->matrixCoefficients != AVIF_MATRIX_COEFFICIENTS_IDENTITY && aomUsage == AOM_USAGE_ALL_INTRA && | ||
| aomVersion >= aomVersion_3_13_0) { | ||
| if (image->matrixCoefficients != AVIF_MATRIX_COEFFICIENTS_IDENTITY && | ||
| ((aomUsage == AOM_USAGE_ALL_INTRA && aomVersion >= aomVersion_3_13_0) || | ||
| (encoder->extraLayerCount > 0 && aomVersion >= aomVersion_3_14_0))) { | ||
| libavifDefaultTuneMetric = AOM_TUNE_IQ; | ||
| } | ||
| #endif | ||
|
|
@@ -906,6 +918,14 @@ static avifResult aomCodecEncodeImage(avifCodec * codec, | |
| // For layered image, disable lagged encoding to always get output | ||
| // frame for each input frame. | ||
| cfg->g_lag_in_frames = 0; | ||
|
|
||
| if (aomVersion >= aomVersion_3_14_0) { | ||
| // Disable QP offsets, so CQ level = frame QP for every frame. | ||
| // This feature requires libaom 3.14.0 or later. | ||
| if (cfg->rc_end_usage == AOM_Q) { | ||
| cfg->use_fixed_qp_offsets = 2; | ||
| } | ||
| } | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had a meeting with @wantehchang to come up with a plan to best handle the two frame scaling bugs we recently found in libaom (targeting layered encoding scenarios):
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Julio: I found that the crash in loop restoration filtering is unrelated to frame scaling. It is, however, related to multithreading. We can avoid this crash by either setting the Setting the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks Wan-Teh for the investigation. What you said about loop restoration filter makes sense, given that the it was two parts of the code that disagreed on the number of actual LR workers during multithreading. Now that we don't know for certain we can't avoid the crash setting in
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd like to mention that without Not sure if the loop restoration filtering crash still happens with all intra usage, but this should avoid the
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The loop restoration filtering crash also occurs with all intra usage. I just wrote down more info on the loop restoration filtering crash in the libaom CL that fixed the crash. I found that this crash affects libaom versions as old as v3.2.0, but for some reason we have not received reports of this crash. Since the crash is unrelated to the encoding of layered images, I don't think libavif needs to avoid it by turnning off loop restoration or multithreading. Yuan: I believe we already do what you suggested: This already checks libaom < 3.14. Or are you suggesting we broaden the condition to the following?
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Julio: I can now characterize the condition under which the multithreading loop restoration crash occurs: the number of worker threads for loop restoration needs to decrease. For a fixed frame size, this can happen if we
Note: The number of worker threads for loop restoration is calculated by the libaom function When we use Therefore we don't need to defend against this crash for
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi @wantehchang, First of all, thanks for the analysis!
BTW, this isn't what I saw in practice. When I configured
If we're using all-intra mode for libaom < 3.14.0, (which protects us from the crash in
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. BTW, here's an image that crashes avifenc if you encode with a version of libaom that doesn't have the LR fix:
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Julio: Thank you very much for the steps to reproduce the bug. I can reproduce the crash now. I was mistaken. The libaom function To avoid this crash, we can disable either loop restoration or multithreading. It is also possible to avoid this crash by setting
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Julio: Please see pull request #3170. |
||
| } | ||
| if (disableLaggedOutput) { | ||
| cfg->g_lag_in_frames = 0; | ||
|
|
||

Uh oh!
There was an error while loading. Please reload this page.